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