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