Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/OpenGL/src/G4OpenGLViewer.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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  27th March 1996
 30 // OpenGL view - opens window, hard copy, etc.
 31 
 32 #include "G4ios.hh"
 33 #include <CLHEP/Units/SystemOfUnits.h>
 34 #include "G4OpenGLViewer.hh"
 35 #include "G4OpenGLSceneHandler.hh"
 36 #include "G4OpenGLTransform3D.hh"
 37 
 38 #include "G4gl2ps.hh"
 39 #define GL2PS_TEXT_B  TOOLS_GL2PS_TEXT_B
 40 #define GL2PS_TEXT_BL TOOLS_GL2PS_TEXT_BL
 41 #define GL2PS_TEXT_BR TOOLS_GL2PS_TEXT_BR
 42 
 43 #include "G4Scene.hh"
 44 #include "G4VisExtent.hh"
 45 #include "G4LogicalVolume.hh"
 46 #include "G4VSolid.hh"
 47 #include "G4Point3D.hh"
 48 #include "G4Normal3D.hh"
 49 #include "G4Plane3D.hh"
 50 #include "G4AttHolder.hh"
 51 #include "G4AttCheck.hh"
 52 #include "G4Text.hh"
 53 
 54 #include <sstream>
 55 #include <string>
 56 #include <iomanip>
 57 
 58 G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene):
 59 G4VViewer (scene, -1),
 60 fPrintColour (true),
 61 fVectoredPs (true),
 62 fOpenGLSceneHandler(scene),
 63 background (G4Colour(0.,0.,0.)),
 64 transparency_enabled (true),
 65 antialiasing_enabled (false),
 66 haloing_enabled (false),
 67 fRot_sens(1.),
 68 fPan_sens(0.01),
 69 fWinSize_x(0),
 70 fWinSize_y(0),
 71 fDefaultExportImageFormat("pdf"),
 72 fExportImageFormat("pdf"),
 73 fExportFilenameIndex(0),
 74 fPrintSizeX(-1),
 75 fPrintSizeY(-1),
 76 fPointSize (0),
 77 fDefaultExportFilename("G4OpenGL"),
 78 fSizeHasChanged(0),
 79 fGl2psDefaultLineWith(1),
 80 fGl2psDefaultPointSize(2),
 81 fGlViewInitialized(false),
 82 fIsGettingPickInfos(false)
 83 {
 84   // Make changes to view parameters for OpenGL...
 85   fVP.SetAutoRefresh(true);
 86   fDefaultVP.SetAutoRefresh(true);
 87   fGL2PSAction = new G4gl2ps();
 88   tools_gl2ps_gl_funcs_t _funcs = {
 89     (tools_glIsEnabled_func)glIsEnabled,
 90     (tools_glBegin_func)glBegin,
 91     (tools_glEnd_func)glEnd,
 92     (tools_glGetFloatv_func)glGetFloatv,
 93     (tools_glVertex3f_func)glVertex3f,
 94     (tools_glGetBooleanv_func)glGetBooleanv,
 95     (tools_glGetIntegerv_func)glGetIntegerv,
 96     (tools_glRenderMode_func)glRenderMode,
 97     (tools_glFeedbackBuffer_func)glFeedbackBuffer,
 98     (tools_glPassThrough_func)glPassThrough
 99   };
100   fGL2PSAction->setOpenGLFunctions(&_funcs);
101   
102   // add supported export image format
103   addExportImageFormat("eps");
104   addExportImageFormat("ps");
105   addExportImageFormat("pdf");
106   addExportImageFormat("svg");
107 
108   // Change the default name
109   fExportFilename += fDefaultExportFilename + "_" + GetShortName().data();
110   
111   //  glClearColor (0.0, 0.0, 0.0, 0.0);
112   //  glClearDepth (1.0);
113   //  glDisable (GL_BLEND);
114   //  glDisable (GL_LINE_SMOOTH);
115   //  glDisable (GL_POLYGON_SMOOTH);
116 
117 }
118 
119 G4OpenGLViewer::~G4OpenGLViewer ()
120 {
121   delete fGL2PSAction;
122 }
123 
124 void G4OpenGLViewer::InitializeGLView () 
125 {
126   if (fWinSize_x == 0) {
127     fWinSize_x = fVP.GetWindowSizeHintX();
128   }
129   if (fWinSize_y == 0) {
130     fWinSize_y = fVP.GetWindowSizeHintY();
131   }
132 
133   glClearColor (0.0, 0.0, 0.0, 0.0);
134   glClearDepth (1.0);
135   glDisable (GL_LINE_SMOOTH);
136   glDisable (GL_POLYGON_SMOOTH);
137 
138 // clear the buffers and window?
139   ClearView ();
140   FinishView ();
141   
142   glDepthFunc (GL_LEQUAL);
143   glDepthMask (GL_TRUE);
144   
145   glEnable (GL_BLEND);
146   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
147   
148 }
149 
150 void G4OpenGLViewer::ClearView () {
151   ClearViewWithoutFlush();
152 
153   if(!isFramebufferReady()) {
154     return;
155   }
156 
157   glFlush();
158 }
159 
160 
161 void G4OpenGLViewer::ClearViewWithoutFlush () {
162   // Ready for clear ?
163   // See : http://lists.apple.com/archives/mac-opengl/2012/Jul/msg00038.html
164   if(!isFramebufferReady()) {
165     return;
166   }
167   
168   glClearColor (background.GetRed(),
169                 background.GetGreen(),
170                 background.GetBlue(),
171                 1.);
172   glClearDepth (1.0);
173   //Below line does not compile with Mesa includes.
174   //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
175   glClear (GL_COLOR_BUFFER_BIT);
176   glClear (GL_DEPTH_BUFFER_BIT);
177   glClear (GL_STENCIL_BUFFER_BIT);
178 }
179 
180 
181 void G4OpenGLViewer::ResizeWindow(unsigned int aWidth, unsigned int aHeight) {
182   if ((fWinSize_x != aWidth) || (fWinSize_y != aHeight)) {
183     fWinSize_x = aWidth;
184     fWinSize_y = aHeight;
185     fSizeHasChanged = true;
186   } else {
187     fSizeHasChanged = false;
188   }
189 }
190 
191 /**
192  * Set the viewport of the scene
193  * MAXIMUM SIZE is :
194  * GLint dims[2];
195  * glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
196  */
197 void G4OpenGLViewer::ResizeGLView()
198 {
199   // Check size
200   GLint dims[2];
201   dims[0] = 0;
202   dims[1] = 0;
203 
204   glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
205 
206   if ((dims[0] !=0 ) && (dims[1] !=0)) {
207 
208     if (fWinSize_x > (unsigned)dims[0]) {
209       G4cerr << "Try to resize view greater than max X viewport dimension. Desired size "<<fWinSize_x <<" is resize to "<<  dims[0] << G4endl;
210       fWinSize_x = dims[0];
211     }
212     if (fWinSize_y > (unsigned)dims[1]) {
213       G4cerr << "Try to resize view greater than max Y viewport dimension. Desired size "<<fWinSize_y <<" is resize to "<<  dims[1] << G4endl;
214       fWinSize_y = dims[1];
215     }
216   }
217     
218   glViewport(0, 0, fWinSize_x,fWinSize_y);   
219 
220 
221 }
222 
223 
224 void G4OpenGLViewer::SetView () {
225   // if getting pick infos, should not resize the view.
226   if (fIsGettingPickInfos) return;
227   
228   if (!fSceneHandler.GetScene()) {
229     return;
230   }
231   // Calculates view representation based on extent of object being
232   // viewed and (initial) viewpoint.  (Note: it can change later due
233   // to user interaction via visualization system's GUI.)
234   
235   // Lighting.
236   GLfloat lightPosition [4];
237   lightPosition [0] = fVP.GetActualLightpointDirection().x();
238   lightPosition [1] = fVP.GetActualLightpointDirection().y();
239   lightPosition [2] = fVP.GetActualLightpointDirection().z();
240   lightPosition [3] = 0.;
241   // Light position is "true" light direction, so must come after gluLookAt.
242   GLfloat ambient [] = { 0.2f, 0.2f, 0.2f, 1.f};
243   GLfloat diffuse [] = { 0.8f, 0.8f, 0.8f, 1.f};
244   glEnable (GL_LIGHT0);
245   glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
246   glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
247   
248   G4double ratioX = 1;
249   G4double ratioY = 1;
250   if (fWinSize_y > fWinSize_x) {
251     ratioX = ((G4double)fWinSize_y) / ((G4double)fWinSize_x);
252   }
253   if (fWinSize_x > fWinSize_y) {
254     ratioY = ((G4double)fWinSize_x) / ((G4double)fWinSize_y);
255   }
256   
257   // Get radius of scene, etc.
258   // Note that this procedure properly takes into account zoom, dolly and pan.
259   const G4Point3D targetPoint
260     = fSceneHandler.GetScene()->GetStandardTargetPoint()
261     + fVP.GetCurrentTargetPoint ();
262   G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
263   if(radius<=0.) radius = 1.;
264   const G4double cameraDistance = fVP.GetCameraDistance (radius);
265   const G4Point3D cameraPosition =
266     targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
267   const GLdouble pnear  = fVP.GetNearDistance (cameraDistance, radius);
268   const GLdouble pfar   = fVP.GetFarDistance  (cameraDistance, pnear, radius);
269   const GLdouble right  = fVP.GetFrontHalfHeight (pnear, radius) * ratioY;
270   const GLdouble left   = -right;
271   const GLdouble top    = fVP.GetFrontHalfHeight (pnear, radius) * ratioX;
272   const GLdouble bottom = -top;
273   
274   // FIXME
275   ResizeGLView();
276   //SHOULD SetWindowsSizeHint()...
277 
278   glMatrixMode (GL_PROJECTION); // set up Frustum.
279   glLoadIdentity();
280 
281   const G4Vector3D scaleFactor = fVP.GetScaleFactor();
282   glScaled(scaleFactor.x(),scaleFactor.y(),scaleFactor.z());
283   
284   if (fVP.GetFieldHalfAngle() == 0.) {
285     g4GlOrtho (left, right, bottom, top, pnear, pfar);
286   }
287   else {
288     g4GlFrustum (left, right, bottom, top, pnear, pfar);
289   }  
290 
291   glMatrixMode (GL_MODELVIEW); // apply further transformations to scene.
292   glLoadIdentity();
293   
294   const G4Normal3D& upVector = fVP.GetUpVector ();  
295   G4Point3D gltarget;
296   if (cameraDistance > 1.e-6 * radius) {
297     gltarget = targetPoint;
298   }
299   else {
300     gltarget = targetPoint - radius * fVP.GetViewpointDirection().unit();
301   }
302 
303   const G4Point3D& pCamera = cameraPosition;  // An alias for brevity.
304 
305   g4GluLookAt (pCamera.x(),  pCamera.y(),  pCamera.z(),       // Viewpoint.
306              gltarget.x(), gltarget.y(), gltarget.z(),      // Target point.
307              upVector.x(), upVector.y(), upVector.z());     // Up vector.
308   // Light position is "true" light direction, so must come after gluLookAt.
309   glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
310 
311   // The idea is to use back-to-back clipping planes.  This can cut an object
312   // down to just a few pixels, which can make it difficult to see.  So, for
313   // now, comment this out and use the generic (Boolean) method, via
314   // G4VSolid* G4OpenGLSceneHandler::CreateSectionSolid ()
315   // { return G4VSceneHandler::CreateSectionSolid(); }
316 //  if (fVP.IsSection () ) {  // pair of back to back clip planes.
317 //    const G4Plane3D& sp = fVP.GetSectionPlane ();
318 //    double sArray[4];
319 //    sArray[0] = sp.a();
320 //    sArray[1] = sp.b();
321 //    sArray[2] = sp.c();
322 //    sArray[3] = sp.d() + radius * 1.e-05;
323 //    glClipPlane (GL_CLIP_PLANE0, sArray);
324 //    glEnable (GL_CLIP_PLANE0);
325 //    sArray[0] = -sp.a();
326 //    sArray[1] = -sp.b();
327 //    sArray[2] = -sp.c();
328 //    sArray[3] = -sp.d() + radius * 1.e-05;
329 //    glClipPlane (GL_CLIP_PLANE1, sArray);
330 //    glEnable (GL_CLIP_PLANE1);
331 //  } else {
332 //    glDisable (GL_CLIP_PLANE0);
333 //    glDisable (GL_CLIP_PLANE1);
334 //  }
335 
336   // What we call intersection of cutaways is easy in OpenGL.  You
337   // just keep cutting.  Unions are more tricky - you have to have
338   // multiple passes and this is handled in
339   // G4OpenGLImmediate/StoredViewer::ProcessView.
340   const G4Planes& cutaways = fVP.GetCutawayPlanes();
341   size_t nPlanes = cutaways.size();
342   if (fVP.IsCutaway() &&
343       fVP.GetCutawayMode() == G4ViewParameters::cutawayIntersection) {
344     double a[4];
345     a[0] = cutaways[0].a();
346     a[1] = cutaways[0].b();
347     a[2] = cutaways[0].c();
348     a[3] = cutaways[0].d();
349     glClipPlane (GL_CLIP_PLANE2, a);
350     glEnable (GL_CLIP_PLANE2);
351     if (nPlanes > 1) {
352       a[0] = cutaways[1].a();
353       a[1] = cutaways[1].b();
354       a[2] = cutaways[1].c();
355       a[3] = cutaways[1].d();
356       glClipPlane (GL_CLIP_PLANE3, a);
357       glEnable (GL_CLIP_PLANE3);
358     }
359     if (nPlanes > 2) {
360       a[0] = cutaways[2].a();
361       a[1] = cutaways[2].b();
362       a[2] = cutaways[2].c();
363       a[3] = cutaways[2].d();
364       glClipPlane (GL_CLIP_PLANE4, a);
365       glEnable (GL_CLIP_PLANE4);
366     }
367   } else {
368     glDisable (GL_CLIP_PLANE2);
369     glDisable (GL_CLIP_PLANE3);
370     glDisable (GL_CLIP_PLANE4);
371   }
372 
373   // Background.
374   background = fVP.GetBackgroundColour ();
375 
376 }
377 
378 
379 
380 void G4OpenGLViewer::ResetView () {
381   G4VViewer::ResetView();
382   fRot_sens = 1;
383   fPan_sens = 0.01;
384 }
385 
386 
387 void G4OpenGLViewer::HaloingFirstPass () {
388   
389   //To perform haloing, first Draw all information to the depth buffer
390   //alone, using a chunky line width, and then Draw all info again, to
391   //the colour buffer, setting a thinner line width an the depth testing 
392   //function to less than or equal, so if two lines cross, the one 
393   //passing behind the other will not pass the depth test, and so not
394   //get rendered either side of the infront line for a short distance.
395 
396   //First, disable writing to the colo(u)r buffer...
397   glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
398 
399   //Now enable writing to the depth buffer...
400   glDepthMask (GL_TRUE);
401   glDepthFunc (GL_LESS);
402   glClearDepth (1.0);
403 
404   //Finally, set the line width to something wide...
405   ChangeLineWidth(3.0);
406 
407 }
408 
409 void G4OpenGLViewer::HaloingSecondPass () {
410 
411   //And finally, turn the colour buffer back on with a sesible line width...
412   glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
413   glDepthFunc (GL_LEQUAL);
414   ChangeLineWidth(1.0);
415 
416 }
417 
418 G4String G4OpenGLViewer::Pick(GLdouble x, GLdouble y)
419 {
420   const std::vector < G4OpenGLViewerPickMap* > & pickMap = GetPickDetails(x,y);
421   G4String txt = "";
422   if (pickMap.size() == 0) {
423 //        txt += "No hits recorded.";;
424   } else {
425     for (unsigned int a=0; a < pickMap.size(); a++) {
426       if (pickMap[a]->getAttributes().size() > 0) {
427         txt += pickMap[a]->print();
428       }
429     }
430   }
431   return txt;
432 }
433 
434 const std::vector < G4OpenGLViewerPickMap* > & G4OpenGLViewer::GetPickDetails(GLdouble x, GLdouble y)
435 {
436   static std::vector < G4OpenGLViewerPickMap* > pickMapVector;
437   for (auto pickMap: pickMapVector) {
438     delete pickMap;
439   }
440   pickMapVector.clear();
441   
442   const G4int BUFSIZE = 512;
443   GLuint selectBuffer[BUFSIZE];
444   glSelectBuffer(BUFSIZE, selectBuffer);
445   glRenderMode(GL_SELECT);
446   glInitNames();
447   glPushName(0);
448   glMatrixMode(GL_PROJECTION);
449   G4double currentProjectionMatrix[16];
450   glGetDoublev(GL_PROJECTION_MATRIX, currentProjectionMatrix);
451   glPushMatrix();
452   glLoadIdentity();
453   GLint viewport[4];
454   glGetIntegerv(GL_VIEWPORT, viewport);
455 /*  G4cout
456   << "viewport, x,y: "
457   << viewport[0] << ',' << viewport[1] << ',' << viewport[2] << ',' << viewport[3]
458   << ", " << x << ',' << y
459   << G4endl;
460 */
461   fIsGettingPickInfos = true;
462   // Define 5x5 pixel pick area
463   g4GluPickMatrix(x, viewport[3] - y, 5., 5., viewport);
464   glMultMatrixd(currentProjectionMatrix);
465   glMatrixMode(GL_MODELVIEW);
466   DrawView();
467   GLint hits = glRenderMode(GL_RENDER);
468   fIsGettingPickInfos = false;
469   if (hits < 0) {
470     G4cout << "Too many hits.  Zoom in to reduce overlaps." << G4endl;
471     goto restoreMatrices;
472   }
473   if (hits > 0) {
474     GLuint* p = selectBuffer;
475     for (GLint i = 0; i < hits; ++i) {
476       GLuint nnames = *p++;
477       // This bit of debug code or...
478       //GLuint zmin = *p++;
479       //GLuint zmax = *p++;
480       //G4cout << "Hit " << i << ": " << nnames << " names"
481       //       << "\nzmin: " << zmin << ", zmax: " << zmax << G4endl;
482       // ...just increment the pointer
483       p++;
484       p++;
485       for (GLuint j = 0; j < nnames; ++j) {
486         GLuint name = *p++;
487   std::map<GLuint, G4AttHolder*>::iterator iter =
488     fOpenGLSceneHandler.fPickMap.find(name);
489   if (iter != fOpenGLSceneHandler.fPickMap.end()) {
490     G4AttHolder* attHolder = iter->second;
491     if(attHolder && attHolder->GetAttDefs().size()) {
492       for (size_t iAtt = 0;
493      iAtt < attHolder->GetAttDefs().size(); ++iAtt) {
494               std::ostringstream oss;
495         oss << G4AttCheck(attHolder->GetAttValues()[iAtt],
496                                 attHolder->GetAttDefs()[iAtt]);
497               G4OpenGLViewerPickMap* pickMap = new G4OpenGLViewerPickMap();
498 //              G4cout
499 //              << "i,j, attHolder->GetAttDefs().size(): "
500 //              << i << ',' << j
501 //              << ", " << attHolder->GetAttDefs().size()
502 //              << G4endl;
503 //              G4cout << "G4OpenGLViewer::GetPickDetails: " << oss.str() << G4endl;
504               pickMap->addAttributes(oss.str());
505               pickMap->setHitNumber(i);
506               pickMap->setSubHitNumber(j);
507               pickMap->setPickName(name);
508               pickMapVector.push_back(pickMap);
509             }
510           }
511         }
512       }
513     }
514   }
515 
516 restoreMatrices:
517   glMatrixMode(GL_PROJECTION);
518   glPopMatrix();
519   glMatrixMode(GL_MODELVIEW);
520 
521   return pickMapVector;
522 }
523 
524 GLubyte* G4OpenGLViewer::grabPixels
525 (int inColor, unsigned int width, unsigned int height) {
526   
527   GLubyte* buffer;
528   GLint swapbytes, lsbfirst, rowlength;
529   GLint skiprows, skippixels, alignment;
530   GLenum format;
531   int size;
532 
533   if (inColor) {
534     format = GL_RGB;
535     size = width*height*3;
536   } else {
537     format = GL_LUMINANCE;
538     size = width*height*1;
539   }
540 
541   buffer = new GLubyte[size];
542   if (buffer == NULL)
543     return NULL;
544 
545   glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes);
546   glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst);
547   glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength);
548 
549   glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows);
550   glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels);
551   glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
552 
553   glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
554   glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
555   glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
556 
557   glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
558   glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
559   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
560 
561   glReadBuffer(GL_FRONT);
562   glReadPixels (0, 0, (GLsizei)width, (GLsizei)height, format, GL_UNSIGNED_BYTE, (GLvoid*) buffer);
563 
564   glPixelStorei (GL_UNPACK_SWAP_BYTES, swapbytes);
565   glPixelStorei (GL_UNPACK_LSB_FIRST, lsbfirst);
566   glPixelStorei (GL_UNPACK_ROW_LENGTH, rowlength);
567   
568   glPixelStorei (GL_UNPACK_SKIP_ROWS, skiprows);
569   glPixelStorei (GL_UNPACK_SKIP_PIXELS, skippixels);
570   glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
571   
572   return buffer;
573 }
574 
575 bool G4OpenGLViewer::printVectoredEPS() {
576   return printGl2PS();
577 }
578 
579 bool G4OpenGLViewer::printNonVectoredEPS () {
580 
581   int width = getRealExportWidth();
582   int height = getRealExportHeight();
583 
584   FILE* fp;
585   GLubyte* pixels;
586   GLubyte* curpix;
587   int components, pos, i;
588 
589   pixels = grabPixels (fPrintColour, width, height);
590 
591   if (pixels == NULL) {
592       G4cerr << "Failed to get pixels from OpenGl viewport" << G4endl;
593     return false;
594   }
595   if (fPrintColour) {
596     components = 3;
597   } else {
598     components = 1;
599   }
600   std::string name = getRealPrintFilename();
601   fp = fopen (name.c_str(), "w");
602   if (fp == NULL) {
603     G4cerr << "Can't open filename " << name.c_str() << G4endl;
604     return false;
605   }
606   
607   fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
608   fprintf (fp, "%%%%Title: %s\n", name.c_str());
609   fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n");
610   fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
611   fprintf (fp, "%%%%EndComments\n");
612   fprintf (fp, "gsave\n");
613   fprintf (fp, "/bwproc {\n");
614   fprintf (fp, "    rgbproc\n");
615   fprintf (fp, "    dup length 3 idiv string 0 3 0 \n");
616   fprintf (fp, "    5 -1 roll {\n");
617   fprintf (fp, "    add 2 1 roll 1 sub dup 0 eq\n");
618   fprintf (fp, "    { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n");
619   fprintf (fp, "       3 1 roll 5 -1 roll } put 1 add 3 0 \n");
620   fprintf (fp, "    { 2 1 roll } ifelse\n");
621   fprintf (fp, "    }forall\n");
622   fprintf (fp, "    pop pop pop\n");
623   fprintf (fp, "} def\n");
624   fprintf (fp, "systemdict /colorimage known not {\n");
625   fprintf (fp, "   /colorimage {\n");
626   fprintf (fp, "       pop\n");
627   fprintf (fp, "       pop\n");
628   fprintf (fp, "       /rgbproc exch def\n");
629   fprintf (fp, "       { bwproc } image\n");
630   fprintf (fp, "   }  def\n");
631   fprintf (fp, "} if\n");
632   fprintf (fp, "/picstr %d string def\n", width * components);
633   fprintf (fp, "%d %d scale\n", width, height);
634   fprintf (fp, "%d %d %d\n", width, height, 8);
635   fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height);
636   fprintf (fp, "{currentfile picstr readhexstring pop}\n");
637   fprintf (fp, "false %d\n", components);
638   fprintf (fp, "colorimage\n");
639   
640   curpix = (GLubyte*) pixels;
641   pos = 0;
642   for (i = width*height*components; i>0; i--) {
643     fprintf (fp, "%02hx ", (unsigned short)(*(curpix++)));
644     if (++pos >= 32) {
645       fprintf (fp, "\n");
646       pos = 0; 
647     }
648   }
649   if (pos)
650     fprintf (fp, "\n");
651 
652   fprintf (fp, "grestore\n");
653   fprintf (fp, "showpage\n");
654   delete [] pixels;
655   fclose (fp);
656 
657   // Reset for next time (useful if size change)
658   //  fPrintSizeX = -1;
659   //  fPrintSizeY = -1;
660 
661   return true;
662 }
663 
664 /** Return if gl2ps is currently writing
665  */
666 bool G4OpenGLViewer::isGl2psWriting() {
667 
668   if (!fGL2PSAction) return false;
669   if (fGL2PSAction->fileWritingEnabled()) {
670     return true;
671   }
672   return false;
673 }
674 
675 
676 G4bool G4OpenGLViewer::isFramebufferReady() {
677   bool check = false;
678 #ifdef G4VIS_BUILD_OPENGLQT_DRIVER
679   check = true;
680 #endif
681 #ifdef G4VIS_BUILD_OPENGLX_DRIVER
682   check = false;
683 #endif
684 #ifdef G4VIS_BUILD_OPENGLXM_DRIVER
685   check = false;
686 #endif
687 #ifdef G4VIS_BUILD_OPENGLWIN32_DRIVER
688   check = false;
689 #endif
690 
691 #if GL_ARB_framebuffer_object
692   if (check) {
693 //    if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_UNDEFINED) {
694 //      return false;
695 //    }
696   }
697 #endif
698     return true;
699 }
700 
701 
702 /* Draw Gl2Ps text if needed
703  */
704 void G4OpenGLViewer::DrawText(const G4Text& g4text)
705 {
706   // gl2ps or GL window ?
707   if (isGl2psWriting()) {
708 
709     G4VSceneHandler::MarkerSizeType sizeType;
710     G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType);
711     G4Point3D position = g4text.GetPosition();
712 
713     G4String textString = g4text.GetText();
714     
715     glRasterPos3d(position.x(),position.y(),position.z());
716     GLint align = GL2PS_TEXT_B;
717 
718     switch (g4text.GetLayout()) {
719     case G4Text::left: align = GL2PS_TEXT_BL; break;
720     case G4Text::centre: align = GL2PS_TEXT_B; break;
721     case G4Text::right: align = GL2PS_TEXT_BR;
722     }
723     
724     fGL2PSAction->addTextOpt(textString.c_str(),"Times-Roman",GLshort(size),align,0);
725 
726   } else {
727 
728     static G4int callCount = 0;
729     ++callCount;
730     //if (callCount <= 10 || callCount%100 == 0) {
731     if (callCount <= 1) {
732       G4cout <<
733   "G4OpenGLViewer::DrawText: Not implemented for \""
734        << fName <<
735   "\"\n  Called with "
736        << g4text
737        << G4endl;
738     }
739   }
740 }
741 
742 /** Change PointSize on gl2ps if needed
743  */
744 void G4OpenGLViewer::ChangePointSize(G4double size) {
745 
746   if (isGl2psWriting()) {
747     fGL2PSAction->setPointSize(int(size));
748   } else {
749     glPointSize (size);
750   }
751 }
752 
753 
754 /** Change LineSize on gl2ps if needed
755  */
756 void G4OpenGLViewer::ChangeLineWidth(G4double width) {
757 
758   if (isGl2psWriting()) {
759     fGL2PSAction->setLineWidth(int(width));
760   } else {
761     glLineWidth (width);
762   }
763 }
764 
765 /**
766  Export image with the given name with width and height
767  Several cases :
768  If name is "", filename will have the default value
769  If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added.
770  If name is "toto", set the name to "toto" and the format to default (or current format if specify).
771    Will also add an incremented suffix at the end of the file
772 */
773 bool G4OpenGLViewer::exportImage(std::string name, int width, int height) {
774 
775   if (! setExportFilename(name)) {
776     return false;
777   }
778 
779   if ((width != -1) && (height != -1)) {
780     setExportSize(width, height);
781   }
782 
783   if (fExportImageFormat == "eps") {
784     fGL2PSAction->setExportImageFormat_EPS();
785   } else if (fExportImageFormat == "ps") {
786     fGL2PSAction->setExportImageFormat_PS();
787   } else if (fExportImageFormat == "svg") {
788     fGL2PSAction->setExportImageFormat_SVG();
789   } else if (fExportImageFormat == "pdf") {
790     fGL2PSAction->setExportImageFormat_PDF();
791   } else {
792     setExportImageFormat(fExportImageFormat,true); // will display a message if this format is not correct for the current viewer
793     return false;
794   }
795 
796   bool res;
797 
798   // Change the LC_NUMERIC value in order to have "." separtor and not ","
799   // This case is only useful for French, Canadien...
800   size_t len = strlen(setlocale(LC_NUMERIC,NULL));
801   char* oldLocale = (char*)(malloc(len+1));
802   if(oldLocale!=NULL) strncpy(oldLocale,setlocale(LC_NUMERIC,NULL),len);
803   setlocale(LC_NUMERIC,"C");
804 
805   if (((fExportImageFormat == "eps") || (fExportImageFormat == "ps")) && (!fVectoredPs)) {
806     res = printNonVectoredEPS();
807   } else {
808     res = printVectoredEPS();
809   }
810 
811   // restore the local
812   if (oldLocale) {
813     setlocale(LC_NUMERIC,oldLocale);
814     free(oldLocale);
815   }
816 
817   if (res == false) {
818     G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl;
819   } else {
820     G4cout << "File " << getRealPrintFilename().c_str() << " size: " << getRealExportWidth() << "x" << getRealExportHeight() << " has been saved " << G4endl;
821 
822     // increment index if necessary
823     if ( fExportFilenameIndex != -1) {
824       fExportFilenameIndex++;
825     }
826   }
827 
828   return res;
829 }
830 
831 
832 bool G4OpenGLViewer::printGl2PS() {
833 
834   int width = getRealExportWidth();
835   int height = getRealExportHeight();
836   bool res = true;
837 
838   // no need to redraw at each new primitive for printgl2PS
839   G4OpenGLSceneHandler& oglSceneHandler = dynamic_cast<G4OpenGLSceneHandler&>(fSceneHandler);
840   G4OpenGLSceneHandler::FlushAction originalFlushAction = oglSceneHandler.GetFlushAction();
841   oglSceneHandler.SetFlushAction(G4OpenGLSceneHandler::never);
842 
843   if (!fGL2PSAction) return false;
844 
845   fGL2PSAction->setFileName(getRealPrintFilename().c_str());
846   // try to resize
847   int X = fWinSize_x;
848   int Y = fWinSize_y;
849 
850   fWinSize_x = width;
851   fWinSize_y = height;
852   // Laurent G. 16/03/10 : Not the good way to do. 
853   // We should draw in a new offscreen context instead of
854   // resizing and drawing in current window...
855   // This should be solve when we will do an offscreen method
856   // to render OpenGL
857   // See : 
858   // http://developer.apple.com/Mac/library/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_offscreen/opengl_offscreen.html
859   // http://www.songho.ca/opengl/gl_fbo.html
860 
861    ResizeGLView();
862    bool extendBuffer = true;
863    bool endWriteAction = false;
864    bool beginWriteAction = true;
865    bool filePointerOk = true;
866    while ((extendBuffer) && (! endWriteAction) && (filePointerOk)) {
867 
868      beginWriteAction = fGL2PSAction->enableFileWriting();
869      if(beginWriteAction) {
870        GLint vp[4];
871        ::glGetIntegerv(GL_VIEWPORT,vp);
872        fGL2PSAction->setViewport(vp[0],vp[1],vp[2],vp[3]);
873        beginWriteAction = fGL2PSAction->beginPage();
874      }
875 
876      // 3 cases :
877      // - true
878      // - false && ! fGL2PSAction->fileWritingEnabled() => bad file name
879      // - false && fGL2PSAction->fileWritingEnabled() => buffer size problem ?
880 
881      filePointerOk = fGL2PSAction->fileWritingEnabled();
882        
883      if (beginWriteAction) {
884 
885        // Set the viewport
886        // By default, we choose the line width (trajectories...)
887        fGL2PSAction->setLineWidth(fGl2psDefaultLineWith);
888        // By default, we choose the point size (markers...)
889        fGL2PSAction->setPointSize(fGl2psDefaultPointSize);
890        
891        DrawView ();
892        
893        endWriteAction = fGL2PSAction->endPage();
894        fGL2PSAction->disableFileWriting();
895      }
896      if (filePointerOk) {
897        if ((! endWriteAction) || (! beginWriteAction)) {
898          extendBuffer = fGL2PSAction->extendBufferSize();
899        }
900      }
901    }
902    fGL2PSAction->resetBufferSizeParameters();
903 
904    if (!extendBuffer ) {
905      G4cerr << "ERROR: gl2ps buffer size is not big enough to print this geometry. Try to extend it. No output produced"<< G4endl;
906      res = false;
907    }
908    if (!beginWriteAction ) {
909      G4cerr << "ERROR: saving file "<<getRealPrintFilename().c_str()<<". Check read/write access. No output produced" << G4endl;
910      res = false;
911    }
912    if (!endWriteAction ) {
913      G4cerr << "gl2ps error. No output produced" << G4endl;
914      res = false;
915    }
916   fWinSize_x = X;
917   fWinSize_y = Y;
918 
919   oglSceneHandler.SetFlushAction(originalFlushAction);
920 
921   // Reset for next time (useful is size change)
922   //  fPrintSizeX = 0;
923   //  fPrintSizeY = 0;
924 
925   return res;
926 }
927 
928 unsigned int G4OpenGLViewer::getWinWidth() const{
929   return fWinSize_x;
930 }
931 
932 unsigned int G4OpenGLViewer::getWinHeight() const{
933   return fWinSize_y;
934 }
935 
936 G4bool G4OpenGLViewer::sizeHasChanged() {
937   return fSizeHasChanged;
938 }
939 
940 G4int G4OpenGLViewer::getRealExportWidth() {
941   if (fPrintSizeX == -1) {
942     return fWinSize_x;
943   }
944   GLint dims[2];
945   glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
946 
947   // L.Garnier 01-2010: Some problems with mac 10.6
948   if ((dims[0] !=0 ) && (dims[1] !=0)) {
949     if (fPrintSizeX > dims[0]){
950       return dims[0];
951     }
952   }
953   if (fPrintSizeX < -1){
954     return 0;
955   }
956   return fPrintSizeX;
957 }
958 
959 G4int G4OpenGLViewer::getRealExportHeight() {
960   if (fPrintSizeY == -1) {
961     return fWinSize_y;
962   }
963   GLint dims[2];
964   glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
965 
966   // L.Garnier 01-2010: Some problems with mac 10.6
967   if ((dims[0] !=0 ) && (dims[1] !=0)) {
968     if (fPrintSizeY > dims[1]){
969       return dims[1];
970     }
971   }
972   if (fPrintSizeY < -1){
973     return 0;
974   }
975   return fPrintSizeY;
976 }
977 
978 void G4OpenGLViewer::setExportSize(G4int X, G4int Y) {
979   fPrintSizeX = X;
980   fPrintSizeY = Y;
981 }
982 
983 /**
984  If name is "" or "!", filename and extension will have the default value.
985  If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added.
986  If name is "toto", set the name to "toto" and the format to default (or current format if specify).
987  If name is the same as previous, do not reset incremented suffix.
988 */
989 bool G4OpenGLViewer::setExportFilename(G4String name,G4bool inc) {
990   if (name == "!") {
991     name = "";
992   }
993 
994   if (inc) {
995     if ((name != "") && (fExportFilename != name)) {
996       fExportFilenameIndex=0;
997     }
998   } else {
999     fExportFilenameIndex=-1;
1000   }
1001 
1002   if (name.size() == 0) {
1003     name = getRealPrintFilename().c_str();
1004   } else {
1005     // guess format by extention
1006     std::string extension = name.substr(name.find_last_of(".") + 1);
1007     // If there is a dot in the name the above might find rubbish, so...
1008     if (extension.size() >= 3 && extension.size() <= 4) {  // Possible extension
1009       if (setExportImageFormat(extension, false)) {  // Extension found
1010         fExportFilename = name.substr(0,name.find_last_of("."));
1011       } else {  // No viable extension found
1012         return false;
1013       }
1014     } else {  // Assume name is already the required without-extension part
1015         fExportFilename = name;
1016     }
1017   }
1018   return true;
1019 }
1020 
1021 std::string G4OpenGLViewer::getRealPrintFilename() {
1022   std::string temp = fExportFilename;
1023   if (fExportFilenameIndex != -1) {
1024     temp += std::string("_");
1025     std::ostringstream os;
1026     os << std::setw(4) << std::setfill('0') << fExportFilenameIndex;
1027     std::string nb_str = os.str();
1028     temp += nb_str;
1029   }
1030   temp += "."+fExportImageFormat;
1031   return temp;
1032 }
1033 
1034 GLdouble G4OpenGLViewer::getSceneNearWidth()
1035 {
1036   if (!fSceneHandler.GetScene()) {
1037     return 0;
1038   }
1039   const G4Point3D targetPoint
1040     = fSceneHandler.GetScene()->GetStandardTargetPoint()
1041     + fVP.GetCurrentTargetPoint ();
1042   G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
1043   if(radius<=0.) radius = 1.;
1044   const G4double cameraDistance = fVP.GetCameraDistance (radius);
1045   const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
1046   return 2 * fVP.GetFrontHalfHeight (pnear, radius);
1047 }
1048 
1049 GLdouble G4OpenGLViewer::getSceneFarWidth()
1050 {
1051   if (!fSceneHandler.GetScene()) {
1052     return 0;
1053   }
1054   const G4Point3D targetPoint
1055     = fSceneHandler.GetScene()->GetStandardTargetPoint()
1056     + fVP.GetCurrentTargetPoint ();
1057   G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
1058   if(radius<=0.) radius = 1.;
1059   const G4double cameraDistance = fVP.GetCameraDistance (radius);
1060   const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
1061   const GLdouble pfar    = fVP.GetFarDistance  (cameraDistance, pnear, radius);
1062   return 2 * fVP.GetFrontHalfHeight (pfar, radius);
1063 }
1064 
1065 
1066 GLdouble G4OpenGLViewer::getSceneDepth()
1067 {
1068   if (!fSceneHandler.GetScene()) {
1069     return 0;
1070   }
1071   const G4Point3D targetPoint
1072     = fSceneHandler.GetScene()->GetStandardTargetPoint()
1073     + fVP.GetCurrentTargetPoint ();
1074   G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
1075   if(radius<=0.) radius = 1.;
1076   const G4double cameraDistance = fVP.GetCameraDistance (radius);
1077   const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
1078   return fVP.GetFarDistance  (cameraDistance, pnear, radius)- pnear;
1079 }
1080 
1081 
1082 
1083 void G4OpenGLViewer::rotateScene(G4double dx, G4double dy)
1084 {
1085   if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) {
1086     rotateSceneInViewDirection(dx,dy);
1087   } else {
1088     if( dx != 0) {
1089       rotateSceneThetaPhi(dx,0);
1090     }
1091     if( dy != 0) {
1092       rotateSceneThetaPhi(0,dy);
1093     }
1094   }
1095 }
1096 
1097 
1098 void G4OpenGLViewer::rotateSceneToggle(G4double dx, G4double dy)
1099 {
1100   if (fVP.GetRotationStyle() != G4ViewParameters::freeRotation) {
1101     rotateSceneInViewDirection(dx,dy);
1102   } else {
1103     if( dx != 0) {
1104       rotateSceneThetaPhi(dx,0);
1105     }
1106     if( dy != 0) {
1107       rotateSceneThetaPhi(0,dy);
1108     }
1109   }
1110 }
1111 
1112 void G4OpenGLViewer::rotateSceneThetaPhi(G4double dx, G4double dy)
1113 {
1114   if (!fSceneHandler.GetScene()) {
1115     return;
1116   }
1117 
1118   G4Vector3D vp;
1119   G4Vector3D up;
1120   
1121   G4Vector3D xprime;
1122   G4Vector3D yprime;
1123   G4Vector3D zprime;
1124   
1125   G4double delta_alpha;
1126   G4double delta_theta;
1127   
1128   G4Vector3D new_vp;
1129   G4Vector3D new_up;
1130   
1131   G4double cosalpha;
1132   G4double sinalpha;
1133   
1134   G4Vector3D a1;
1135   G4Vector3D a2;
1136   G4Vector3D delta;
1137   G4Vector3D viewPoint;
1138 
1139     
1140   //phi spin stuff here
1141   
1142   vp = fVP.GetViewpointDirection ().unit ();
1143   up = fVP.GetUpVector ().unit ();
1144   
1145   yprime = (up.cross(vp)).unit();
1146   zprime = (vp.cross(yprime)).unit();
1147   
1148   if (fVP.GetLightsMoveWithCamera()) {
1149     delta_alpha = dy * fRot_sens;
1150     delta_theta = -dx * fRot_sens;
1151   } else {
1152     delta_alpha = -dy * fRot_sens;
1153     delta_theta = dx * fRot_sens;
1154   }    
1155   
1156   delta_alpha *= CLHEP::deg;
1157   delta_theta *= CLHEP::deg;
1158   
1159   new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime;
1160   
1161   // to avoid z rotation flipping
1162   // to allow more than 360° rotation
1163 
1164   if (fVP.GetLightsMoveWithCamera()) {
1165     new_up = (new_vp.cross(yprime)).unit();
1166     if (new_vp.z()*vp.z() <0) {
1167       new_up.set(new_up.x(),-new_up.y(),new_up.z());
1168     }
1169   } else {
1170     new_up = up;
1171     if (new_vp.z()*vp.z() <0) {
1172       new_up.set(new_up.x(),-new_up.y(),new_up.z());
1173     }
1174   }
1175   fVP.SetUpVector(new_up);
1176   ////////////////
1177   // Rotates by fixed azimuthal angle delta_theta.
1178   
1179   cosalpha = new_up.dot (new_vp.unit());
1180   sinalpha = std::sqrt (1. - std::pow (cosalpha, 2));
1181   yprime = (new_up.cross (new_vp.unit())).unit ();
1182   xprime = yprime.cross (new_up);
1183   // Projection of vp on plane perpendicular to up...
1184   a1 = sinalpha * xprime;
1185   // Required new projection...
1186   a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime);
1187   // Required Increment vector...
1188   delta = a2 - a1;
1189   // So new viewpoint is...
1190   viewPoint = new_vp.unit() + delta;
1191   
1192   fVP.SetViewAndLights (viewPoint);
1193 }
1194 
1195 
1196 void G4OpenGLViewer::rotateSceneInViewDirection(G4double dx, G4double dy)
1197 {
1198   if (!fSceneHandler.GetScene()) {
1199     return;
1200   }
1201 
1202   G4Vector3D vp;
1203   G4Vector3D up;
1204   
1205   G4Vector3D xprime;
1206   G4Vector3D yprime;
1207   G4Vector3D zprime;
1208   
1209   G4Vector3D new_vp;
1210   G4Vector3D new_up;
1211   
1212   G4Vector3D a1;
1213   G4Vector3D a2;
1214   G4Vector3D delta;
1215   G4Vector3D viewPoint;
1216 
1217   dx = dx/100;
1218   dy = dy/100;
1219 
1220   //phi spin stuff here
1221   
1222   vp = fVP.GetViewpointDirection ().unit();
1223   up = fVP.GetUpVector ().unit();
1224 
1225   G4Vector3D zPrimeVector = G4Vector3D(up.y()*vp.z()-up.z()*vp.y(),
1226                              up.z()*vp.x()-up.x()*vp.z(),
1227                              up.x()*vp.y()-up.y()*vp.x());
1228 
1229   viewPoint = vp/fRot_sens + (zPrimeVector*dx - up*dy) ;
1230   new_up = G4Vector3D(viewPoint.y()*zPrimeVector.z()-viewPoint.z()*zPrimeVector.y(),
1231                        viewPoint.z()*zPrimeVector.x()-viewPoint.x()*zPrimeVector.z(),
1232                        viewPoint.x()*zPrimeVector.y()-viewPoint.y()*zPrimeVector.x());
1233 
1234   G4Vector3D new_upUnit = new_up.unit();
1235   
1236   
1237 
1238    fVP.SetUpVector(new_upUnit);
1239    fVP.SetViewAndLights (viewPoint);
1240 }
1241 
1242 
1243 void G4OpenGLViewer::addExportImageFormat(std::string format) {
1244   fExportImageFormatVector.push_back(format);
1245 }
1246 
1247 bool G4OpenGLViewer::setExportImageFormat(std::string format, bool quiet) {
1248   bool found = false;
1249   std::string list;
1250   for (unsigned int a=0; a<fExportImageFormatVector.size(); a++) {
1251     list +=fExportImageFormatVector.at(a) + " ";
1252 
1253     if (fExportImageFormatVector.at(a) == format) {
1254       if (! quiet) {
1255         G4cout << " Changing export format to \"" << format << "\"" << G4endl;
1256       }
1257       if (format != fExportImageFormat) {
1258         fExportFilenameIndex = 0;
1259         fExportImageFormat = format;
1260       }
1261       return true;
1262     }
1263   }
1264   if (! found) {
1265     if (format.size() == 0) {
1266       G4cout << " Current formats availables are : " << list << G4endl;
1267     } else {
1268       G4cerr << " Format \"" << format << "\" is not available for the selected viewer. Current formats availables are : " << list << G4endl;
1269     }
1270   }
1271   return false;
1272 }
1273 
1274 
1275 // From MESA implementation :
1276 // http://www.techques.com/question/1-8660454/gluPickMatrix-code-from-Mesa
1277 
1278 void G4OpenGLViewer::g4GluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height,
1279                      GLint viewport[4])
1280   {
1281     GLdouble mat[16];
1282     GLdouble sx, sy;
1283     GLdouble tx, ty;
1284     
1285     sx = viewport[2] / width;
1286     sy = viewport[3] / height;
1287     tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
1288     ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
1289     
1290 #define M(row, col) mat[col*4+row]
1291     M(0, 0) = sx;
1292     M(0, 1) = 0.0;
1293     M(0, 2) = 0.0;
1294     M(0, 3) = tx;
1295     M(1, 0) = 0.0;
1296     M(1, 1) = sy;
1297     M(1, 2) = 0.0;
1298     M(1, 3) = ty;
1299     M(2, 0) = 0.0;
1300     M(2, 1) = 0.0;
1301     M(2, 2) = 1.0;
1302     M(2, 3) = 0.0;
1303     M(3, 0) = 0.0;
1304     M(3, 1) = 0.0;
1305     M(3, 2) = 0.0;
1306     M(3, 3) = 1.0;
1307 #undef M
1308     
1309     glMultMatrixd(mat);
1310 }
1311 
1312 
1313 
1314 
1315 
1316 // From MESA implementation :
1317 // https://github.com/jlamarche/iOS-OpenGLES-Stuff/blob/master/Wavefront%20OBJ%20Loader/Classes/gluLookAt.m
1318 // or http://www.daniweb.com/software-development/game-development/threads/308901/lookat-matrix-source-code
1319 
1320 void G4OpenGLViewer::g4GluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
1321                         GLdouble centerx, GLdouble centery, GLdouble
1322                         centerz,
1323                         GLdouble upx, GLdouble upy, GLdouble upz )
1324 {
1325   GLdouble mat[16];
1326   GLdouble x[3], y[3], z[3];
1327   GLdouble mag;
1328   
1329   /* Make rotation matrix */
1330   
1331   /* Z vector */
1332   z[0] = eyex - centerx;
1333   z[1] = eyey - centery;
1334   z[2] = eyez - centerz;
1335   mag = std::sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
1336   if (mag) {      /* mpichler, 19950515 */
1337     z[0] /= mag;
1338     z[1] /= mag;
1339     z[2] /= mag;
1340   }
1341   
1342   /* Y vector */
1343   y[0] = upx;
1344   y[1] = upy;
1345   y[2] = upz;
1346   
1347   /* X vector = Y cross Z */
1348   x[0] = y[1] * z[2] - y[2] * z[1];
1349   x[1] = -y[0] * z[2] + y[2] * z[0];
1350   x[2] = y[0] * z[1] - y[1] * z[0];
1351   
1352   /* Recompute Y = Z cross X */
1353   y[0] = z[1] * x[2] - z[2] * x[1];
1354   y[1] = -z[0] * x[2] + z[2] * x[0];
1355   y[2] = z[0] * x[1] - z[1] * x[0];
1356   
1357   /* mpichler, 19950515 */
1358   /* cross product gives area of parallelogram, which is < 1.0 for
1359    * non-perpendicular unit-length vectors; so normalize x, y here
1360    */
1361   
1362   mag = std::sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
1363   if (mag) {
1364     x[0] /= mag;
1365     x[1] /= mag;
1366     x[2] /= mag;
1367   }
1368   
1369   mag = std::sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
1370   if (mag) {
1371     y[0] /= mag;
1372     y[1] /= mag;
1373     y[2] /= mag;
1374   }
1375   
1376 #define M(row,col)  mat[col*4+row]
1377   M(0, 0) = x[0];
1378   M(0, 1) = x[1];
1379   M(0, 2) = x[2];
1380   M(0, 3) = 0.0;
1381   M(1, 0) = y[0];
1382   M(1, 1) = y[1];
1383   M(1, 2) = y[2];
1384   M(1, 3) = 0.0;
1385   M(2, 0) = z[0];
1386   M(2, 1) = z[1];
1387   M(2, 2) = z[2];
1388   M(2, 3) = 0.0;
1389   M(3, 0) = 0.0;
1390   M(3, 1) = 0.0;
1391   M(3, 2) = 0.0;
1392   M(3, 3) = 1.0;
1393 #undef M
1394   glMultMatrixd(mat);
1395   
1396   /* Translate Eye to Origin */
1397   glTranslated(-eyex, -eyey, -eyez);
1398 }
1399 
1400 void G4OpenGLViewer::g4GlOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {
1401   //  glOrtho (left, right, bottom, top, near, far);
1402   
1403   GLdouble a = 2.0 / (right - left);
1404   GLdouble b = 2.0 / (top - bottom);
1405   GLdouble c = -2.0 / (zFar - zNear);
1406   
1407   GLdouble tx = - (right + left)/(right - left);
1408   GLdouble ty = - (top + bottom)/(top - bottom);
1409   GLdouble tz = - (zFar + zNear)/(zFar - zNear);
1410   
1411   GLdouble ortho[16] = {
1412     a, 0, 0, 0,
1413     0, b, 0, 0,
1414     0, 0, c, 0,
1415     tx, ty, tz, 1
1416   };
1417   glMultMatrixd(ortho);
1418   
1419 }
1420 
1421 
1422 void G4OpenGLViewer::g4GlFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {
1423   //  glFrustum (left, right, bottom, top, near, far);
1424   
1425   GLdouble deltaX = right - left;
1426   GLdouble deltaY = top - bottom;
1427   GLdouble deltaZ = zFar - zNear;
1428   
1429   GLdouble a = 2.0f * zNear / deltaX;
1430   GLdouble b = 2.0f * zNear / deltaY;
1431   GLdouble c = (right + left) / deltaX;
1432   GLdouble d = (top + bottom) / deltaY;
1433   GLdouble e = -(zFar + zNear) / (zFar - zNear);
1434   GLdouble f = -2.0f * zFar * zNear / deltaZ;
1435   
1436   GLdouble proj[16] = {
1437     a, 0, 0, 0,
1438     0, b, 0, 0,
1439     c, d, e, -1.0f,
1440     0, 0, f, 0
1441   };
1442   
1443   glMultMatrixd(proj);
1444   
1445 }
1446 
1447 G4String G4OpenGLViewerPickMap::print() {
1448   std::ostringstream txt;
1449   for (unsigned int a=0; a<fAttributes.size(); a++) {
1450     txt << fAttributes[a];
1451     if (a < fAttributes.size() - 1) txt << "\n";
1452   }
1453   return txt.str();
1454 }
1455