Geant4-11
G4OpenGLXViewer.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27//
28//
29// Andrew Walkden 7th February 1997
30// G4OpenGLXViewer : Class to provide XWindows specific
31// functionality for OpenGL in GEANT4
32
33#include "G4OpenGLXViewer.hh"
34
37
38#include "G4VisExtent.hh"
39#include "G4LogicalVolume.hh"
40#include "G4VSolid.hh"
41#include "G4Point3D.hh"
42#include "G4Normal3D.hh"
43#include "G4StateManager.hh"
44#include "G4VisManager.hh"
45#include "G4Text.hh"
46#include "G4Threading.hh"
47
48#include <X11/Xatom.h>
49#include <X11/Xutil.h>
50#include <X11/Xmu/StdCmap.h>
51
52#include <assert.h>
53#include <sstream>
54#include <chrono>
55#include <thread>
56
58{ GLX_RGBA,
59 GLX_RED_SIZE, 1,
60 GLX_GREEN_SIZE, 1,
61 GLX_BLUE_SIZE, 1,
62 GLX_DEPTH_SIZE, 1,
63 GLX_STENCIL_SIZE, 1,
64 None };
65
67{ GLX_RGBA,
68 GLX_RED_SIZE, 1,
69 GLX_GREEN_SIZE, 1,
70 GLX_BLUE_SIZE, 1,
71 GLX_DOUBLEBUFFER,
72 GLX_DEPTH_SIZE, 1,
73 GLX_STENCIL_SIZE, 1,
74 None };
75
76#define NewString(str) \
77 ((str) != 0 ? (strncpy((char*)malloc((unsigned)strlen(str) + 1), str, (unsigned)strlen(str) + 1)) : (char*)0)
78
79#define USE_DEFAULT_COLORMAP 1
80#define USE_STANDARD_COLORMAP 0
81
84
85extern "C" {
86 static Bool G4OpenGLXViewerWaitForNotify (Display*, XEvent* e, char* arg) {
87 return (e->type == MapNotify) && (e->xmap.window == (Window) arg);
88 }
89}
90
92#ifdef G4MULTITHREADED
94 glXMakeCurrent (dpy, win, cxMaster);
95 } else {
96 glXMakeCurrent (dpy, win, cxVisSubThread);
97 }
98#else
99 glXMakeCurrent (dpy, win, cxMaster);
100#endif
102}
103
105#ifdef G4MULTITHREADED
106// G4int thread_id = G4Threading::G4GetThreadId();
107// G4cout << "G4OpenGLXViewer::ShowView: thread " << thread_id << G4endl;
108#endif
109
110// glXWaitGL (); //Wait for effects of all previous OpenGL commands to
111 //be propagated before progressing.
112// JA: Commented out July 2021 - slows rendering down in some cases and I
113// don't see any adverse effects.
114
115 glFlush ();
116
117 if (fVP.IsPicking()) {
118 G4cout <<
119 "Window activated for picking (left-mouse), exit (middle-mouse)."
120 << G4endl;
121 while (true) {
122 if (XPending(dpy)) {
123 XNextEvent(dpy, &event);
124 if (event.type == ButtonPress && event.xbutton.button == 1) {
125 G4cout << Pick(event.xbutton.x, event.xbutton.y) << G4endl;
126 }
127 else if (event.type == ButtonPress && event.xbutton.button == 2) break;
128 }
129 std::this_thread::sleep_for(std::chrono::milliseconds(100));
130 }
131 }
132}
133
134#ifdef G4MULTITHREADED
135
136void G4OpenGLXViewer::SwitchToVisSubThread()
137{
138// G4cout << "G4OpenGLXViewer::SwitchToVisSubThread" << G4endl;
139 cxVisSubThread = glXCreateContext (dpy, vi, cxMaster, true);
140 glXMakeCurrent (dpy, win, cxVisSubThread);
141}
142
143void G4OpenGLXViewer::SwitchToMasterThread()
144{
145// G4cout << "G4OpenGLXViewer::SwitchToMasterThread" << G4endl;
146 glXMakeCurrent (dpy, win, cxMaster);
147 // and destroy sub-thread context
148 glXDestroyContext (dpy, cxVisSubThread);
149}
150
151#endif
152
154// get a connection.
155 dpy = XOpenDisplay (0); // Uses DISPLAY environment variable.
156 if (!dpy) {
157 fViewId = -1; // This flags an error.
158 G4cerr << "G4OpenGLXViewer::G4OpenGLXViewer couldn't open display." << G4endl;
159 return;
160 }
161
162// make sure OpenGL is supported and installed properly.
163 if (!glXQueryExtension (dpy, &errorBase, &eventBase)) {
164 fViewId = -1; // This flags an error.
165 G4cerr << "G4OpenGLXViewer::G4OpenGLXViewer X Server has no GLX extension."
166 << G4endl;
167 return;
168 }
169
170}
171
173
174 vi = v;
175// get window's attributes
176 if (!XGetWindowAttributes(dpy, XRootWindow (dpy, vi -> screen), &xwa)) {
177 fViewId = -1; // This flags an error.
178 G4cerr << "G4OpenGLXViewer::G4OpenGLXViewer couldn't return window attributes"
179 << G4endl;
180 return;
181 }
182
183// create the master GLX context
184 cxMaster = glXCreateContext (dpy, vi, 0, true);
185 if (!cxMaster) {
186 fViewId = -1; // This flags an error.
187 G4cerr << "G4OpenGLXViewer::G4OpenGLXViewer couldn't create context."
188 << G4endl;
189 return;
190 }
191
192// New stab at getting a colormap
193
194 Status status;
195 int i, numCmaps;
196
197 status = XmuLookupStandardColormap (dpy,
198 vi -> screen,
199 vi -> visualid,
200 vi -> depth,
201 XA_RGB_BEST_MAP,
202 False,
203 True);
204
205 if (status == 1) {
206 cmap = 0;
207 XStandardColormap* standardCmaps = XAllocStandardColormap ();
208 status = XGetRGBColormaps (dpy,
209 XRootWindow (dpy, vi -> screen),
210 &standardCmaps,
211 &numCmaps,
212 XA_RGB_BEST_MAP);
213 if (status == 1) {
214 for (i = 0; i < numCmaps; i++) {
215 if (standardCmaps[i].visualid == vi -> visualid) {
216 cmap = standardCmaps[i].colormap;
217 break;
218 }
219 }
220 }
221 XFree (standardCmaps);
222 if(cmap) {
224 G4cout << "Got standard cmap" << G4endl;
225 } else {
226 //if (G4VisManager::GetVerbosity() >= G4VisManager::errors)
227 // G4cerr << "G4OpenGLXViewer::G4OpenGLXViewer failed to allocate a standard colormap."
228 // << G4endl;
229 cmap = XCreateColormap (dpy,
230 XRootWindow(dpy, vi -> screen),
231 vi -> visual,
232 AllocNone);
233 if(cmap) {
235 G4cout << "Created own cmap" << G4endl;
236 }
237 //G.Barrand : at end, we should do a XFreeColormap(dpy,cmap) when cmap is no more used.
238 }
239 } else {
240 cmap = XCreateColormap (dpy,
241 XRootWindow(dpy, vi -> screen),
242 vi -> visual,
243 AllocNone);
244 if(cmap) {
246 G4cout << "Created own cmap" << G4endl;
247 }
248 //G.Barrand : at end, we should do a XFreeColormap(dpy,cmap) when cmap is no more used.
249 }
250
251 if (!cmap) {
252 fViewId = -1; // This flags an error.
254 G4cout << "G4OpenGLXViewer::G4OpenGLXViewer failed to allocate a Colormap."
255 << G4endl;
256 return;
257 }
258
259}
260
262
263// create a window
264 swa.colormap = cmap;
265 swa.border_pixel = 0;
266 swa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask;
267 swa.backing_store = WhenMapped;
268
269 // Window size and position...
270 size_hints = XAllocSizeHints();
271
273
274 G4int x_origin = fVP.GetWindowAbsoluteLocationHintX(DisplayWidth(dpy, vi -> screen));
275
276 // FIXME, screen size != window size on MAC, but I don't know have to get the menuBar
277 // size on MAC. L.Garnier 01/2009
278 G4int y_origin = fVP.GetWindowAbsoluteLocationHintY(DisplayHeight(dpy, vi -> screen));
279
280 size_hints->base_width = getWinWidth();
281 size_hints->base_height = getWinHeight();
282 size_hints->x = x_origin;
283 size_hints->y = y_origin;
285 size_hints->flags |= PSize | PPosition;
287 size_hints->flags |= PSize;
289 size_hints->flags |= PPosition;
290 }
292 G4cout << "Window name: " << fName << G4endl;
293 strncpy (charViewName, fName, 99); charViewName[99] = '\0';
294 char *window_name = charViewName;
295 char *icon_name = charViewName;
296 //char tmpatom[] = "XA_WM_NORMAL_HINTS";
297 wm_hints = XAllocWMHints();
298 class_hints = XAllocClassHint();
299
300 XStringListToTextProperty (&window_name, 1, &windowName);
301 XStringListToTextProperty (&icon_name, 1, &iconName);
302
303 wm_hints -> initial_state = NormalState;
304 wm_hints -> input = True;
306 wm_hints -> flags = StateHint | IconPixmapHint | InputHint;
307
308 class_hints -> res_name = NewString("G4OpenGL");
309 class_hints -> res_class = NewString("G4OpenGL");
310
311 win = XCreateWindow (dpy, XRootWindow (dpy, vi -> screen), x_origin,
312 y_origin, getWinWidth(), getWinHeight(), 0, vi -> depth,
313 InputOutput, vi -> visual,
314 CWBorderPixel | CWColormap |
315 CWEventMask | CWBackingStore,
316 &swa);
317
318 XSetWMProperties (dpy, win, &windowName, &iconName, 0, 0,
320
321// request X to Draw window on screen.
322 XMapWindow (dpy, win);
323
324// Wait for window to appear (wait for an "expose" event).
325 XIfEvent (dpy, &event, G4OpenGLXViewerWaitForNotify, (char*) win);
326
327// connect the context to a window
328 Bool success = glXMakeCurrent (dpy, win, cxMaster);
329 if (!success) {
330 fViewId = -1; // This flags an error.
331 G4cerr << "G4OpenGLXViewer::G4OpenGLXViewer failed to attach a GLX context."
332 << G4endl;
333 GLint error = GL_NO_ERROR;
334 while ((error = glGetError()) != GL_NO_ERROR) {
335 switch (error) {
336 case GL_INVALID_ENUM :
337 G4cout << "GL Error: GL_INVALID_ENUM" << G4endl;break;
338 case GL_INVALID_VALUE :
339 G4cout << "GL Error: GL_INVALID_VALUE" << G4endl;break;
340 case GL_INVALID_OPERATION :
341 G4cout << "GL Error: GL_INVALID_OPERATION" << G4endl;break;
342 case GL_OUT_OF_MEMORY :
343 G4cout << "GL Error: GL_OUT_OF_MEMORY" << G4endl;break;
344 case GL_STACK_UNDERFLOW :
345 G4cout << "GL Error: GL_STACK_UNDERFLOW" << G4endl;break;
346 case GL_STACK_OVERFLOW :
347 G4cout << "GL Error: GL_STACK_OVERFLOW" << G4endl;break;
348 default :
349 G4cout << "GL Error: " << error << G4endl;break;
350 }
351 }
352 return;
353 }
354}
355
357{
358 std::map<G4double,G4String> fonts; // G4VMarker screen size and font name.
359 fonts[10.] = "-adobe-courier-bold-r-normal--10-100-75-75-m-60-iso8859-1";
360 fonts[11.] = "-adobe-courier-bold-r-normal--11-80-100-100-m-60-iso8859-1";
361 fonts[12.] = "-adobe-courier-bold-r-normal--12-120-75-75-m-70-iso8859-1";
362 fonts[13.] = "fixed";
363 fonts[14.] = "-adobe-courier-bold-r-normal--14-100-100-100-m-90-iso8859-1";
364 fonts[17.] = "-adobe-courier-bold-r-normal--17-120-100-100-m-100-iso8859-1";
365 fonts[18.] = "-adobe-courier-bold-r-normal--18-180-75-75-m-110-iso8859-1";
366 fonts[20.] = "-adobe-courier-bold-r-normal--20-140-100-100-m-110-iso8859-1";
367 fonts[24.] = "-adobe-courier-bold-r-normal--24-240-75-75-m-150-iso8859-1";
368 fonts[25.] = "-adobe-courier-bold-r-normal--25-180-100-100-m-150-iso8859-1";
369 fonts[34.] = "-adobe-courier-bold-r-normal--34-240-100-100-m-200-iso8859-1";
370 std::map<G4double,G4String>::const_iterator i;
371 for (i = fonts.begin(); i != fonts.end(); ++i) {
372 XFontStruct* font_info = XLoadQueryFont(dpy, i->second);
373 if (!font_info) {
374 G4cerr <<
375 "G4OpenGLXViewer::CreateFontLists XLoadQueryFont failed for font\n "
376 << i->second
377 << G4endl;
378 continue;
379 }
380 G4int font_base = glGenLists(256);
381 if (!font_base) {
382 G4cerr <<
383 "G4OpenGLXViewer::CreateFontLists out of display lists for fonts."
384 << G4endl;
385 continue;
386 }
387 G4int first = font_info->min_char_or_byte2;
388 G4int last = font_info->max_char_or_byte2;
389 glXUseXFont(font_info->fid, first, last-first+1, font_base + first);
390 G4int width = font_info->max_bounds.width;
392 (this, font_base, i->first, i->second, width);
393 }
394}
395
397{
398 if (isGl2psWriting()) {
399
401
402 } else {
403
405 G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType);
406
407 const G4OpenGLFontBaseStore::FontInfo& fontInfo =
409 if (fontInfo.fFontBase < 0) {
410 static G4int callCount = 0;
411 ++callCount;
412 //if (callCount <= 10 || callCount%100 == 0) {
413 if (callCount <= 1) {
414 G4cout <<
415 "G4OpenGLXViewer::DrawText: No fonts available for \""
416 << fName <<
417 "\"\n Called with "
418 << g4text
419 << G4endl;
420 }
421 return;
422 }
423
424 const G4Colour& c = fSceneHandler.GetTextColour(g4text);
425 glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha());
426
427 G4Point3D position = g4text.GetPosition();
428
429 G4String textString = g4text.GetText();
430 const char* textCString = textString.c_str();
431
432 // Set position for raster-style drawers (X, Xm)
433 glRasterPos3d(position.x(),position.y(),position.z());
434
435 glPushAttrib(GL_LIST_BIT);
436
437 // Calculate move for centre and right adjustment
438 G4double span = textString.size() * fontInfo.fWidth;
439 G4double xmove = 0., ymove = 0.;
440 switch (g4text.GetLayout()) {
441 case G4Text::left: break;
442 case G4Text::centre: xmove -= span / 2.; break;
443 case G4Text::right: xmove -= span;
444 }
445
446 //Add offsets
447 xmove += g4text.GetXOffset();
448 ymove += g4text.GetYOffset();
449
450 // Do move
451 glBitmap(0,0,0,0,xmove,ymove,0);
452
453 // Write characters
454 glListBase(fontInfo.fFontBase);
455 glCallLists(strlen(textCString),GL_UNSIGNED_BYTE,(GLubyte*)textCString);
456 glPopAttrib();
457 }
458}
459
460
462G4VViewer (scene, -1),
463G4OpenGLViewer (scene),
464vi_immediate (0),
465vi_stored (0),
466vi (0),
467cmap (0)
468{
469 // To satisfy Coverity
470 xwa.visual = 0;
471 iconName.value = 0;
472 xwa.screen = 0;
473 windowName.value = 0;
474
476 if (fViewId < 0) return;
477
478 // Try for a visual suitable for OpenGLImmediate..
479 // first try for a single buffered RGB window
480 if (!vi_single_buffer) {
482 glXChooseVisual (dpy, XDefaultScreen (dpy), snglBuf_RGBA);
483 //G.Barrand : we should do a XFree(vi_single_buffer) at end;
484 }
485 if (!vi_double_buffer) {
487 glXChooseVisual (dpy, XDefaultScreen (dpy), dblBuf_RGBA);
488 //G.Barrand : we should do a XFree(vi_double_buffer) at end;
489 }
490
492 if (!vi_double_buffer) {
493 G4cout <<
494 "G4OpenGLXViewer::G4OpenGLXViewer: unable to get a double buffer visual."
495 "\n Working with a single buffer."
496 << G4endl;
497 }
498 } else {
499 if (!vi_single_buffer) {
500 G4cout <<
501 "G4OpenGLXViewer::G4OpenGLXViewer: unable to get a single buffer visual."
502 << G4endl;
503 }
504 if (!vi_double_buffer) {
505 G4cout <<
506 "G4OpenGLXViewer::G4OpenGLXViewer: unable to get a double buffer visual."
507 << G4endl;
508 }
509 }
510
511 if (vi_single_buffer) {
514 }
515
516 if (!vi_immediate){
517 // next try for a double buffered RGB, but Draw to top buffer
518 if (vi_double_buffer) {
521 }
522 }
523
524 // Now try for a visual suitable for OpenGLStored...
525 // Try for a double buffered RGB window
526 if (vi_double_buffer) {
529 }
530
531 if (!vi_immediate || !vi_stored) {
532 G4cout <<
533 "G4OpenGLXViewer::G4OpenGLXViewer: unable to get required visuals."
534 << G4endl;
535 fViewId = -1; // This flags an error.
536 }
537
538 // glClearColor (0., 0., 0., 0.);
539 // glClearDepth (1.);
540}
541
543 if (fViewId >= 0) {
544 //Close a window from here
545 glXMakeCurrent (dpy, None, NULL);
546 glXDestroyContext (dpy, cxMaster);
547 if (win) XDestroyWindow (dpy, win); // ...if already deleted in
548 // sub-class G4OpenGLXmViewer.
549 // We should do a XFreeColormap(dpy,cmap); if cmap had been get with XCreateColormap.
550 XFlush (dpy);
551 }
552}
553
static Bool G4OpenGLXViewerWaitForNotify(Display *, XEvent *e, char *arg)
#define NewString(str)
static G4String Status(G4StepStatus stps)
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
G4double GetBlue() const
Definition: G4Colour.hh:154
G4double GetAlpha() const
Definition: G4Colour.hh:155
G4double GetRed() const
Definition: G4Colour.hh:152
G4double GetGreen() const
Definition: G4Colour.hh:153
static void AddFontBase(G4VViewer *, G4int fontBase, G4double size, const G4String &fontName, G4int width)
static const FontInfo & GetFontInfo(G4VViewer *, G4double size)
unsigned int getWinHeight() const
void ResizeWindow(unsigned int, unsigned int)
unsigned int getWinWidth() const
virtual void DrawText(const G4Text &)
virtual G4String Pick(GLdouble x, GLdouble y)
G4bool isGl2psWriting()
XTextProperty windowName
static int snglBuf_RGBA[12]
XVisualInfo * vi
static int dblBuf_RGBA[13]
XClassHint * class_hints
virtual ~G4OpenGLXViewer()
static XVisualInfo * vi_double_buffer
XTextProperty iconName
void CreateGLXContext(XVisualInfo *vi)
XSizeHints * size_hints
XWindowAttributes xwa
virtual void CreateFontLists()
XSetWindowAttributes swa
GLXContext cxMaster
XWMHints * wm_hints
char charViewName[100]
XVisualInfo * vi_stored
void DrawText(const G4Text &)
static XVisualInfo * vi_single_buffer
XVisualInfo * vi_immediate
G4OpenGLXViewer(G4OpenGLSceneHandler &scene)
virtual void CreateMainWindow()
Definition: G4Text.hh:72
Layout GetLayout() const
G4double GetYOffset() const
G4double GetXOffset() const
G4String GetText() const
@ centre
Definition: G4Text.hh:76
@ right
Definition: G4Text.hh:76
@ left
Definition: G4Text.hh:76
G4Point3D GetPosition() const
const G4Colour & GetTextColour(const G4Text &)
G4double GetMarkerSize(const G4VMarker &, MarkerSizeType &)
G4VSceneHandler & fSceneHandler
Definition: G4VViewer.hh:215
G4String fName
Definition: G4VViewer.hh:217
G4int fViewId
Definition: G4VViewer.hh:216
G4ViewParameters fVP
Definition: G4VViewer.hh:219
bool IsWindowLocationHintY() const
G4int GetWindowAbsoluteLocationHintY(G4int) const
bool IsWindowLocationHintX() const
unsigned int GetWindowSizeHintX() const
bool IsWindowSizeHintX() const
G4bool IsPicking() const
G4int GetWindowAbsoluteLocationHintX(G4int) const
unsigned int GetWindowSizeHintY() const
static Verbosity GetVerbosity()
G4bool IsMasterThread()
Definition: G4Threading.cc:124
static PROLOG_HANDLER error
Definition: xmlrole.cc:127