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