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