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