source: trunk/source/visualization/OpenGL/src/G4OpenGLViewer.cc @ 924

Last change on this file since 924 was 924, checked in by garnier, 15 years ago

add gl2ps library and changes to include it. See History file

  • Property svn:mime-type set to text/cpp
File size: 35.3 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer                                           *
4// *                                                                  *
5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7// * conditions of the Geant4 Software License,  included in the file *
8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9// * include a list of copyright holders.                             *
10// *                                                                  *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work  make  any representation or  warranty, express or implied, *
14// * regarding  this  software system or assume any liability for its *
15// * use.  Please see the license in the file  LICENSE  and URL above *
16// * for the full disclaimer and the limitation of liability.         *
17// *                                                                  *
18// * This  code  implementation is the result of  the  scientific and *
19// * technical work of the GEANT4 collaboration.                      *
20// * By using,  copying,  modifying or  distributing the software (or *
21// * any work based  on the software)  you  agree  to acknowledge its *
22// * use  in  resulting  scientific  publications,  and indicate your *
23// * acceptance of all terms of the Geant4 Software license.          *
24// ********************************************************************
25//
26//
27// $Id: G4OpenGLViewer.cc,v 1.48 2009/02/16 15:31:05 lgarnier Exp $
28// GEANT4 tag $Name:  $
29//
30//
31// Andrew Walkden  27th March 1996
32// OpenGL view - opens window, hard copy, etc.
33
34#ifdef G4VIS_BUILD_OPENGL_DRIVER
35
36#include "G4ios.hh"
37#include "G4OpenGLViewer.hh"
38#include "G4OpenGLSceneHandler.hh"
39#include "G4OpenGLTransform3D.hh"
40#include "G4OpenGL2PSAction.hh"
41
42#include "G4Scene.hh"
43#include "G4VisExtent.hh"
44#include "G4LogicalVolume.hh"
45#include "G4VSolid.hh"
46#include "G4Point3D.hh"
47#include "G4Normal3D.hh"
48#include "G4Plane3D.hh"
49#include "G4AttHolder.hh"
50#include "G4AttCheck.hh"
51
52// GL2PS
53#include "Geant4_gl2ps.h"
54
55#include <sstream>
56
57static const char* gouraudtriangleEPS[] =
58{
59  "/bd{bind def}bind def /triangle { aload pop   setrgbcolor  aload pop 5 3",
60  "roll 4 2 roll 3 2 roll exch moveto lineto lineto closepath fill } bd",
61  "/computediff1 { 2 copy sub abs threshold ge {pop pop pop true} { exch 2",
62  "index sub abs threshold ge { pop pop true} { sub abs threshold ge } ifelse",
63  "} ifelse } bd /computediff3 { 3 copy 0 get 3 1 roll 0 get 3 1 roll 0 get",
64  "computediff1 {true} { 3 copy 1 get 3 1 roll 1 get 3 1 roll 1 get",
65  "computediff1 {true} { 3 copy 2 get 3 1 roll  2 get 3 1 roll 2 get",
66  "computediff1 } ifelse } ifelse } bd /middlecolor { aload pop 4 -1 roll",
67  "aload pop 4 -1 roll add 2 div 5 1 roll 3 -1 roll add 2 div 3 1 roll add 2",
68  "div 3 1 roll exch 3 array astore } bd /gouraudtriangle { computediff3 { 4",
69  "-1 roll aload 7 1 roll 6 -1 roll pop 3 -1 roll pop add 2 div 3 1 roll add",
70  "2 div exch 3 -1 roll aload 7 1 roll exch pop 4 -1 roll pop add 2 div 3 1",
71  "roll add 2 div exch 3 -1 roll aload 7 1 roll pop 3 -1 roll pop add 2 div 3",
72  "1 roll add 2 div exch 7 3 roll 10 -3 roll dup 3 index middlecolor 4 1 roll",
73  "2 copy middlecolor 4 1 roll 3 copy pop middlecolor 4 1 roll 13 -1 roll",
74  "aload pop 17 index 6 index 15 index 19 index 6 index 17 index 6 array",
75  "astore 10 index 10 index 14 index gouraudtriangle 17 index 5 index 17",
76  "index 19 index 5 index 19 index 6 array astore 10 index 9 index 13 index",
77  "gouraudtriangle 13 index 16 index 5 index 15 index 18 index 5 index 6",
78  "array astore 12 index 12 index 9 index gouraudtriangle 17 index 16 index",
79  "15 index 19 index 18 index 17 index 6 array astore 10 index 12 index 14",
80  "index gouraudtriangle 18 {pop} repeat } { aload pop 5 3 roll aload pop 7 3",
81  "roll aload pop 9 3 roll 4 index 6 index 4 index add add 3 div 10 1 roll 7",
82  "index 5 index 3 index add add 3 div 10 1 roll 6 index 4 index 2 index add",
83  "add 3 div 10 1 roll 9 {pop} repeat 3 array astore triangle } ifelse } bd",
84  NULL
85};
86
87G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene):
88G4VViewer (scene, -1),
89fPrintFilename ("G4OpenGL.eps"),
90fPrintColour (true),
91fVectoredPs (true),
92fOpenGLSceneHandler(scene),
93background (G4Colour(0.,0.,0.)),
94transparency_enabled (true),
95antialiasing_enabled (false),
96haloing_enabled (false),
97fStartTime(-DBL_MAX),
98fEndTime(DBL_MAX),
99fFadeFactor(0.),
100fDisplayHeadTime(false),
101fDisplayHeadTimeX(-0.9),
102fDisplayHeadTimeY(-0.9),
103fDisplayHeadTimeSize(24.),
104fDisplayHeadTimeRed(0.),
105fDisplayHeadTimeGreen(1.),
106fDisplayHeadTimeBlue(1.),
107fDisplayLightFront(false),
108fDisplayLightFrontX(0.),
109fDisplayLightFrontY(0.),
110fDisplayLightFrontZ(0.),
111fDisplayLightFrontT(0.),
112fDisplayLightFrontRed(0.),
113fDisplayLightFrontGreen(1.),
114fDisplayLightFrontBlue(0.),
115fPointSize (0)
116{
117  // Make changes to view parameters for OpenGL...
118  fVP.SetAutoRefresh(true);
119  fDefaultVP.SetAutoRefresh(true);
120  fWinSize_x = fVP.GetWindowSizeHintX();
121  fWinSize_y = fVP.GetWindowSizeHintY();
122
123  fGL2PSAction = new G4OpenGL2PSAction();
124
125  //  glClearColor (0.0, 0.0, 0.0, 0.0);
126  //  glClearDepth (1.0);
127  //  glDisable (GL_BLEND);
128  //  glDisable (GL_LINE_SMOOTH);
129  //  glDisable (GL_POLYGON_SMOOTH);
130
131}
132
133G4OpenGLViewer::~G4OpenGLViewer () {}
134
135void G4OpenGLViewer::InitializeGLView ()
136{
137  glClearColor (0.0, 0.0, 0.0, 0.0);
138  glClearDepth (1.0);
139  glDisable (GL_BLEND);
140  glDisable (GL_LINE_SMOOTH);
141  glDisable (GL_POLYGON_SMOOTH);
142
143
144void G4OpenGLViewer::ClearView () {
145  glClearColor (background.GetRed(),
146                background.GetGreen(),
147                background.GetBlue(),
148                1.);
149  glClearDepth (1.0);
150  //Below line does not compile with Mesa includes.
151  //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
152  glClear (GL_COLOR_BUFFER_BIT);
153  glClear (GL_DEPTH_BUFFER_BIT);
154  glClear (GL_STENCIL_BUFFER_BIT);
155  glFlush ();
156}
157
158
159/**
160 * Set the viewport of the scene
161 */
162void G4OpenGLViewer::ResizeGLView()
163{
164  int side = fWinSize_x;
165  if (fWinSize_y < fWinSize_x) side = fWinSize_y;
166  glViewport((fWinSize_x - side) / 2, (fWinSize_y - side) / 2, side, side); 
167}
168
169
170void G4OpenGLViewer::SetView () {
171
172  if (!fSceneHandler.GetScene()) {
173    G4cerr << "G4OpenGLStoredViewer: Creating a Viewer without a scene is not allowed. \nPlease use /vis/scene/create before /vis/open/.... "
174           << G4endl;
175    return;
176  }
177  // Calculates view representation based on extent of object being
178  // viewed and (initial) viewpoint.  (Note: it can change later due
179  // to user interaction via visualization system's GUI.)
180 
181  // Lighting.
182  GLfloat lightPosition [4];
183  lightPosition [0] = fVP.GetActualLightpointDirection().x();
184  lightPosition [1] = fVP.GetActualLightpointDirection().y();
185  lightPosition [2] = fVP.GetActualLightpointDirection().z();
186  lightPosition [3] = 0.;
187  // Light position is "true" light direction, so must come after gluLookAt.
188  GLfloat ambient [] = { 0.2, 0.2, 0.2, 1.};
189  GLfloat diffuse [] = { 0.8, 0.8, 0.8, 1.};
190  glEnable (GL_LIGHT0);
191  glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
192  glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
193 
194  // Get radius of scene, etc.
195  // Note that this procedure properly takes into account zoom, dolly and pan.
196  const G4Point3D targetPoint
197    = fSceneHandler.GetScene()->GetStandardTargetPoint()
198    + fVP.GetCurrentTargetPoint ();
199  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
200  if(radius<=0.) radius = 1.;
201  const G4double cameraDistance = fVP.GetCameraDistance (radius);
202  const G4Point3D cameraPosition =
203    targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
204  const GLdouble pnear  = fVP.GetNearDistance (cameraDistance, radius);
205  const GLdouble pfar   = fVP.GetFarDistance  (cameraDistance, pnear, radius);
206  const GLdouble right  = fVP.GetFrontHalfHeight (pnear, radius);
207  const GLdouble left   = -right;
208  const GLdouble bottom = left;
209  const GLdouble top    = right;
210 
211  // FIXME
212  ResizeGLView();
213  //SHOULD SetWindowsSizeHint()...
214
215  glMatrixMode (GL_PROJECTION); // set up Frustum.
216  glLoadIdentity();
217
218  const G4Vector3D scaleFactor = fVP.GetScaleFactor();
219  glScaled(scaleFactor.x(),scaleFactor.y(),scaleFactor.z());
220 
221  if (fVP.GetFieldHalfAngle() == 0.) {
222    glOrtho (left, right, bottom, top, pnear, pfar);
223  }
224  else {
225    glFrustum (left, right, bottom, top, pnear, pfar);
226  } 
227
228  glMatrixMode (GL_MODELVIEW); // apply further transformations to scene.
229  glLoadIdentity();
230 
231  const G4Normal3D& upVector = fVP.GetUpVector (); 
232  G4Point3D gltarget;
233  if (cameraDistance > 1.e-6 * radius) {
234    gltarget = targetPoint;
235  }
236  else {
237    gltarget = targetPoint - radius * fVP.GetViewpointDirection().unit();
238  }
239
240  const G4Point3D& pCamera = cameraPosition;  // An alias for brevity.
241  gluLookAt (pCamera.x(),  pCamera.y(),  pCamera.z(),       // Viewpoint.
242             gltarget.x(), gltarget.y(), gltarget.z(),      // Target point.
243             upVector.x(), upVector.y(), upVector.z());     // Up vector.
244
245  // Light position is "true" light direction, so must come after gluLookAt.
246  glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
247
248  // OpenGL no longer seems to reconstruct clipped edges, so, when the
249  // BooleanProcessor is up to it, abandon this and use generic
250  // clipping in G4OpenGLSceneHandler::CreateSectionPolyhedron.  Also,
251  // force kernel visit on change of clipping plane in
252  // G4OpenGLStoredViewer::CompareForKernelVisit.
253  if (fVP.IsSection () ) {  // pair of back to back clip planes.
254    const G4Plane3D& s = fVP.GetSectionPlane ();
255    double sArray[4];
256    sArray[0] = s.a();
257    sArray[1] = s.b();
258    sArray[2] = s.c();
259    sArray[3] = s.d() + radius * 1.e-05;
260    glClipPlane (GL_CLIP_PLANE0, sArray);
261    glEnable (GL_CLIP_PLANE0);
262    sArray[0] = -s.a();
263    sArray[1] = -s.b();
264    sArray[2] = -s.c();
265    sArray[3] = -s.d() + radius * 1.e-05;
266    glClipPlane (GL_CLIP_PLANE1, sArray);
267    glEnable (GL_CLIP_PLANE1);
268  } else {
269    glDisable (GL_CLIP_PLANE0);
270    glDisable (GL_CLIP_PLANE1);
271  }
272
273  const G4Planes& cutaways = fVP.GetCutawayPlanes();
274  size_t nPlanes = cutaways.size();
275  if (fVP.IsCutaway() &&
276      fVP.GetCutawayMode() == G4ViewParameters::cutawayIntersection &&
277      nPlanes > 0) {
278    double a[4];
279    a[0] = cutaways[0].a();
280    a[1] = cutaways[0].b();
281    a[2] = cutaways[0].c();
282    a[3] = cutaways[0].d();
283    glClipPlane (GL_CLIP_PLANE2, a);
284    glEnable (GL_CLIP_PLANE2);
285    if (nPlanes > 1) {
286      a[0] = cutaways[1].a();
287      a[1] = cutaways[1].b();
288      a[2] = cutaways[1].c();
289      a[3] = cutaways[1].d();
290      glClipPlane (GL_CLIP_PLANE3, a);
291      glEnable (GL_CLIP_PLANE3);
292    }
293    if (nPlanes > 2) {
294      a[0] = cutaways[2].a();
295      a[1] = cutaways[2].b();
296      a[2] = cutaways[2].c();
297      a[3] = cutaways[2].d();
298      glClipPlane (GL_CLIP_PLANE4, a);
299      glEnable (GL_CLIP_PLANE4);
300    }
301  } else {
302    glDisable (GL_CLIP_PLANE2);
303    glDisable (GL_CLIP_PLANE3);
304    glDisable (GL_CLIP_PLANE4);
305  }
306
307  // Background.
308  background = fVP.GetBackgroundColour ();
309
310}
311
312void G4OpenGLViewer::HaloingFirstPass () {
313 
314  //To perform haloing, first Draw all information to the depth buffer
315  //alone, using a chunky line width, and then Draw all info again, to
316  //the colour buffer, setting a thinner line width an the depth testing
317  //function to less than or equal, so if two lines cross, the one
318  //passing behind the other will not pass the depth test, and so not
319  //get rendered either side of the infront line for a short distance.
320
321  //First, disable writing to the colo(u)r buffer...
322  glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
323
324  //Now enable writing to the depth buffer...
325  glDepthMask (GL_TRUE);
326  glDepthFunc (GL_LESS);
327  glClearDepth (1.0);
328
329  //Finally, set the line width to something wide...
330  glLineWidth (3.0);
331
332}
333
334void G4OpenGLViewer::HaloingSecondPass () {
335
336  //And finally, turn the colour buffer back on with a sesible line width...
337  glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
338  glDepthFunc (GL_LEQUAL);
339  glLineWidth (1.0);
340
341}
342
343void G4OpenGLViewer::Pick(GLdouble x, GLdouble y)
344{
345  //G4cout << "X: " << x << ", Y: " << y << G4endl;
346  const G4int BUFSIZE = 512;
347  GLuint selectBuffer[BUFSIZE];
348  glSelectBuffer(BUFSIZE, selectBuffer);
349  glRenderMode(GL_SELECT);
350  glInitNames();
351  glPushName(0);
352  glMatrixMode(GL_PROJECTION);
353  G4double currentProjectionMatrix[16];
354  glGetDoublev(GL_PROJECTION_MATRIX, currentProjectionMatrix);
355  glPushMatrix();
356  glLoadIdentity();
357  GLint viewport[4];
358  glGetIntegerv(GL_VIEWPORT, viewport);
359  // Define 5x5 pixel pick area
360  gluPickMatrix(x, viewport[3] - y, 5., 5., viewport);
361  glMultMatrixd(currentProjectionMatrix);
362  glMatrixMode(GL_MODELVIEW);
363  DrawView();
364  GLint hits = glRenderMode(GL_RENDER);
365  if (hits < 0)
366    G4cout << "Too many hits.  Zoom in to reduce overlaps." << G4cout;
367  else if (hits > 0) {
368    //G4cout << hits << " hit(s)" << G4endl;
369    GLuint* p = selectBuffer;
370    for (GLint i = 0; i < hits; ++i) {
371      GLuint nnames = *p++;
372      *p++; //OR GLuint zmin = *p++;
373      *p++; //OR GLuint zmax = *p++;
374      //G4cout << "Hit " << i << ": " << nnames << " names"
375      //     << "\nzmin: " << zmin << ", zmax: " << zmax << G4endl;
376      for (GLuint j = 0; j < nnames; ++j) {
377        GLuint name = *p++;
378        //G4cout << "Name " << j << ": PickName: " << name << G4endl;
379        std::map<GLuint, G4AttHolder*>::iterator iter =
380          fOpenGLSceneHandler.fPickMap.find(name);
381        if (iter != fOpenGLSceneHandler.fPickMap.end()) {
382          G4AttHolder* attHolder = iter->second;
383          if(attHolder && attHolder->GetAttDefs().size()) {
384            for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) {
385              G4cout << G4AttCheck(attHolder->GetAttValues()[i],
386                                   attHolder->GetAttDefs()[i]);
387            }
388          }
389        }
390      }
391      G4cout << G4endl;
392    }
393  }
394  glMatrixMode(GL_PROJECTION);
395  glPopMatrix();
396  glMatrixMode(GL_MODELVIEW);
397}
398
399void G4OpenGLViewer::printVectoredEPS() {
400
401  // Print vectored PostScript
402 
403  G4int size = 5000000;
404  GLfloat* feedback_buffer = new GLfloat[size];
405  glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
406  glRenderMode (GL_FEEDBACK);
407 
408  DrawView();
409
410  GLint returned;
411  returned = glRenderMode (GL_RENDER);
412 
413  FILE* file;
414  if (!fPrintFilename.empty()) {
415    file = fopen (fPrintFilename.c_str(), "w");
416    if (file) {
417      spewWireframeEPS (file, returned, feedback_buffer, "rendereps");
418      fclose(file);
419    } else {
420      printf("Could not open %s\n", fPrintFilename.c_str());
421    }
422  } else {
423    printBuffer (returned, feedback_buffer);
424  }
425
426  delete[] feedback_buffer;
427}
428
429void G4OpenGLViewer::print3DcolorVertex(GLint size, GLint * count, GLfloat * buffer)
430{
431  G4int i;
432
433  printf("  ");
434  for (i = 0; i < 7; i++) {
435    printf("%4.2f ", buffer[size - (*count)]);
436    *count = *count - 1;
437  }
438  printf("\n");
439}
440
441void G4OpenGLViewer::spewWireframeEPS (FILE* file, GLint size, GLfloat* buffer, const char* cr) {
442
443  GLfloat EPS_GOURAUD_THRESHOLD=0.1;
444
445  GLfloat clearColor[4], viewport[4];
446  GLfloat lineWidth;
447  G4int i;
448
449  glGetFloatv (GL_VIEWPORT, viewport);
450  glGetFloatv (GL_COLOR_CLEAR_VALUE, clearColor);
451  glGetFloatv (GL_LINE_WIDTH, &lineWidth);
452  glGetFloatv (GL_POINT_SIZE, &fPointSize);
453
454  fputs ("%!PS-Adobe-2.0 EPSF-2.0\n", file);
455  fprintf (file, "%%%%Creator: %s (using OpenGL feedback)\n", cr);
456  fprintf (file, "%%%%BoundingBox: %g %g %g %g\n", viewport[0], viewport[1], viewport[2], viewport[3]);
457  fputs ("%%EndComments\n", file);
458  fputs ("\n", file);
459  fputs ("gsave\n", file);
460  fputs ("\n", file);
461
462  fputs ("% the gouraudtriangle PostScript fragment below is free\n", file);
463  fputs ("% written by Frederic Delhoume (delhoume@ilog.fr)\n", file);
464  fprintf (file, "/threshold %g def\n", EPS_GOURAUD_THRESHOLD);
465  for (i=0; gouraudtriangleEPS[i]; i++) {
466    fprintf (file, "%s\n", gouraudtriangleEPS[i]);
467  }
468
469  fprintf(file, "\n%g setlinewidth\n", lineWidth);
470 
471  fprintf (file, "%g %g %g setrgbcolor\n", clearColor[0], clearColor[1], clearColor[2]);
472  fprintf (file, "%g %g %g %g rectfill\n\n", viewport[0], viewport[1], viewport[2], viewport[3]);
473
474  spewSortedFeedback (file, size, buffer);
475
476  fputs ("grestore\n\n", file);
477  fputs ("showpage\n", file);
478
479  fclose(file);
480}
481
482void G4OpenGLViewer::printBuffer (GLint size, GLfloat* buffer) {
483
484  GLint count;
485  G4int token, nvertices;
486
487  count=size;
488  while(count) {
489    token=G4int (buffer[size-count]);
490    count--;
491    switch (token) {
492
493    case GL_PASS_THROUGH_TOKEN:
494      printf ("GL_PASS_THROUGH_TOKEN\n");
495      printf ("  %4.2f\n", buffer[size-count]);
496      count--;
497      break;
498
499    case GL_POINT_TOKEN:
500      printf ("GL_POINT_TOKEN\n");
501      print3DcolorVertex (size, &count, buffer);
502      break;
503
504    case GL_LINE_TOKEN:
505      printf ("GL_LINE_TOKEN\n");
506      print3DcolorVertex (size, &count, buffer);
507      print3DcolorVertex (size, &count, buffer);
508      break;
509     
510    case GL_LINE_RESET_TOKEN:
511      printf ("GL_LINE_RESET_TOKEN\n");
512      print3DcolorVertex (size, &count, buffer);
513      print3DcolorVertex (size, &count, buffer);
514      break;
515
516    case GL_POLYGON_TOKEN:
517      printf ("GL_POLYGON_TOKEN\n");
518      nvertices=G4int (buffer[size-count]);
519      count--;
520      for (; nvertices>0; nvertices--) {
521        print3DcolorVertex (size, &count, buffer);
522      }
523    }
524  }
525}
526
527G4float* G4OpenGLViewer::spewPrimitiveEPS (FILE* file, GLfloat* loc) {
528 
529  G4int token;
530  G4int nvertices, i;
531  GLfloat red, green, blue, intensity;
532  G4int smooth;
533  GLfloat dx, dy, dr, dg, db, absR, absG, absB, colormax;
534  G4int steps;
535  Feedback3Dcolor *vertex;
536  GLfloat xstep(0.), ystep(0.), rstep(0.), gstep(0.), bstep(0.);
537  GLfloat xnext(0.), ynext(0.), rnext(0.), gnext(0.), bnext(0.), distance(0.);
538
539  token=G4int (*loc);
540  loc++;
541  switch (token) {
542  case GL_LINE_RESET_TOKEN:
543  case GL_LINE_TOKEN:
544    vertex=(Feedback3Dcolor*)loc;
545    dr=vertex[1].red - vertex[0].red;
546    dg=vertex[1].green - vertex[0].green;
547    db=vertex[1].blue - vertex[0].blue;
548
549    if (!fPrintColour) {
550      dr+=(dg+db);
551      dr/=3.0;
552      dg=dr;
553      db=dr;
554    }
555
556    if (dr!=0 || dg!=0 || db!=0) {
557      dx=vertex[1].x - vertex[0].x;
558      dy=vertex[1].y - vertex[0].y;
559      distance=std::sqrt(dx*dx + dy*dy);
560
561      absR=std::fabs(dr);
562      absG=std::fabs(dg);
563      absB=std::fabs(db);
564
565      #define Max(a, b) (((a)>(b))?(a):(b))
566
567      #define EPS_SMOOTH_LINE_FACTOR 0.06
568
569      colormax=Max(absR, Max(absG, absB));
570      steps=Max(1, G4int (colormax*distance*EPS_SMOOTH_LINE_FACTOR));
571     
572      xstep=dx/steps;
573      ystep=dy/steps;
574
575      rstep=dr/steps;
576      gstep=dg/steps;
577      bstep=db/steps;
578
579      xnext=vertex[0].x;
580      ynext=vertex[0].y;
581      rnext=vertex[0].red;
582      gnext=vertex[0].green;
583      bnext=vertex[0].blue;
584
585      if (!fPrintColour) {
586        rnext+=(gnext+bnext);
587        rnext/=3.0;
588        gnext=rnext;
589        bnext=rnext;
590      }
591
592      xnext -= xstep/2.0;
593      ynext -= ystep/2.0;
594      rnext -= rstep/2.0;
595      gnext -= gstep/2.0;
596      bnext -= bstep/2.0;
597    } else {
598      steps=0;
599    }
600    if (fPrintColour) {
601      fprintf (file, "%g %g %g setrgbcolor\n",
602               vertex[0].red, vertex[0].green, vertex[0].blue);
603    } else {
604      intensity = (vertex[0].red + vertex[0].green + vertex[0].blue) / 3.0;
605      fprintf (file, "%g %g %g setrgbcolor\n",
606               intensity, intensity, intensity);
607    }     
608    fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
609
610    for (i=0; i<steps; i++) {
611
612      xnext += xstep;
613      ynext += ystep;
614      rnext += rstep;
615      gnext += gstep;
616      bnext += bstep;
617
618      fprintf (file, "%g %g lineto stroke\n", xnext, ynext);
619      fprintf (file, "%g %g %g setrgbcolor\n", rnext, gnext, bnext);
620      fprintf (file, "%g %g moveto\n", xnext, ynext);
621    }
622    fprintf (file, "%g %g lineto stroke\n", vertex[1].x, vertex[1].y);
623
624    loc += 14;
625    break;
626
627  case GL_POLYGON_TOKEN:
628    nvertices = G4int (*loc);
629    loc++;
630    vertex=(Feedback3Dcolor*)loc;
631    if (nvertices>0) {
632      red=vertex[0].red;
633      green=vertex[0].green;
634      blue=vertex[0].blue;
635      smooth=0;
636     
637      if (!fPrintColour) {
638        red+=(green+blue);
639        red/=3.0;
640        green=red;
641        blue=red;
642      }
643     
644      if (fPrintColour) {
645        for (i=1; i<nvertices; i++) {
646          if (red!=vertex[i].red || green!=vertex[i].green || blue!=vertex[i].blue) {
647            smooth=1;
648            break;
649          }
650        }
651      } else {
652        for (i=1; i<nvertices; i++) {
653          intensity = vertex[i].red + vertex[i].green + vertex[i].blue;
654          intensity/=3.0;
655          if (red!=intensity) {
656            smooth=1;
657            break;
658          }
659        }
660      }
661
662      if (smooth) {
663        G4int triOffset;
664        for (i=0; i<nvertices-2; i++) {
665          triOffset = i*7;
666          fprintf (file, "[%g %g %g %g %g %g]",
667                   vertex[0].x, vertex[i+1].x, vertex[i+2].x,
668                   vertex[0].y, vertex[i+1].y, vertex[i+2].y);
669          if (fPrintColour) {
670            fprintf (file, " [%g %g %g] [%g %g %g] [%g %g %g] gouraudtriangle\n",
671                     vertex[0].red, vertex[0].green, vertex[0].blue,
672                     vertex[i+1].red, vertex[i+1].green, vertex[i+1].blue,
673                     vertex[i+2].red, vertex[i+2].green, vertex[i+2].blue);
674          } else {
675
676            intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
677            intensity/=3.0;
678            fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
679
680            intensity = vertex[1].red + vertex[1].green + vertex[1].blue;
681            intensity/=3.0;
682            fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
683
684            intensity = vertex[2].red + vertex[2].green + vertex[2].blue;
685            intensity/=3.0;
686            fprintf (file, " [%g %g %g] gouraudtriangle\n", intensity, intensity, intensity);
687          }
688        }
689      } else {
690        fprintf (file, "newpath\n");
691        fprintf (file, "%g %g %g setrgbcolor\n", red, green, blue);
692        fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
693        for (i=1; i<nvertices; i++) {
694          fprintf (file, "%g %g lineto\n", vertex[i].x, vertex[i].y);
695        }
696        fprintf (file, "closepath fill\n\n");
697      }
698    }
699    loc += nvertices*7;
700    break;
701
702  case GL_POINT_TOKEN:
703    vertex=(Feedback3Dcolor*)loc;
704    if (fPrintColour) {
705      fprintf (file, "%g %g %g setrgbcolor\n", vertex[0].red, vertex[0].green, vertex[0].blue);
706    } else {
707      intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
708      intensity/=3.0;
709      fprintf (file, "%g %g %g setrgbcolor\n", intensity, intensity, intensity);
710    }     
711    fprintf(file, "%g %g %g 0 360 arc fill\n\n", vertex[0].x, vertex[0].y, fPointSize / 2.0);
712    loc += 7;           /* Each vertex element in the feedback
713                           buffer is 7 GLfloats. */
714    break;
715  default:
716    /* XXX Left as an excersie to the reader. */
717    static G4bool spewPrimitiveEPSWarned = false;
718    if (!spewPrimitiveEPSWarned) {
719      std::ostringstream oss;
720      oss <<
721        "Incomplete implementation.  Unexpected token (" << token << ")."
722        "\n  (Seems to be caused by text.)";
723      G4Exception("G4OpenGLViewer::spewPrimitiveEPS",
724                  "Unexpected token",
725                  JustWarning,
726                  oss.str().c_str());
727      spewPrimitiveEPSWarned = true;
728    }
729  }
730  return loc;
731}
732
733typedef struct G4OpenGLViewerDepthIndex {
734  GLfloat *ptr;
735  GLfloat depth;
736} DepthIndex;
737
738extern "C" {
739  int G4OpenGLViewercompare(const void *a, const void *b)
740  {
741    const DepthIndex *p1 = (DepthIndex *) a;
742    const DepthIndex *p2 = (DepthIndex *) b;
743    GLfloat diff = p2->depth - p1->depth;
744   
745    if (diff > 0.0) {
746      return 1;
747    } else if (diff < 0.0) {
748      return -1;
749    } else {
750      return 0;
751    }
752  }
753}
754
755GLubyte* G4OpenGLViewer::grabPixels (int inColor, unsigned int width, unsigned int height) {
756 
757  GLubyte* buffer;
758  GLint swapbytes, lsbfirst, rowlength;
759  GLint skiprows, skippixels, alignment;
760  GLenum format;
761  int size;
762
763  if (inColor) {
764    format = GL_RGB;
765    size = width*height*3;
766  } else {
767    format = GL_LUMINANCE;
768    size = width*height*1;
769  }
770
771  buffer = new GLubyte[size];
772  if (buffer == NULL)
773    return NULL;
774
775  glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes);
776  glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst);
777  glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength);
778
779  glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows);
780  glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels);
781  glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
782
783  glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
784  glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
785  glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
786
787  glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
788  glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
789  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
790
791  glReadPixels (0, 0, (GLsizei)width, (GLsizei)height, format, GL_UNSIGNED_BYTE, (GLvoid*) buffer);
792
793  glPixelStorei (GL_UNPACK_SWAP_BYTES, swapbytes);
794  glPixelStorei (GL_UNPACK_LSB_FIRST, lsbfirst);
795  glPixelStorei (GL_UNPACK_ROW_LENGTH, rowlength);
796 
797  glPixelStorei (GL_UNPACK_SKIP_ROWS, skiprows);
798  glPixelStorei (GL_UNPACK_SKIP_PIXELS, skippixels);
799  glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
800 
801  return buffer;
802}
803
804int G4OpenGLViewer::generateEPS (const char* filnam,
805                                int inColour,
806                                unsigned int width,
807                                unsigned int height) {
808
809  FILE* fp;
810  GLubyte* pixels;
811  GLubyte* curpix;
812  int components, pos, i;
813
814  pixels = grabPixels (inColour, width, height);
815
816  if (pixels == NULL)
817    return 1;
818  if (inColour) {
819    components = 3;
820  } else {
821    components = 1;
822  }
823 
824  fp = fopen (filnam, "w");
825  if (fp == NULL) {
826    return 2;
827  }
828 
829  fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
830  fprintf (fp, "%%%%Title: %s\n", filnam);
831  fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n");
832  fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
833  fprintf (fp, "%%%%EndComments\n");
834  fprintf (fp, "gsave\n");
835  fprintf (fp, "/bwproc {\n");
836  fprintf (fp, "    rgbproc\n");
837  fprintf (fp, "    dup length 3 idiv string 0 3 0 \n");
838  fprintf (fp, "    5 -1 roll {\n");
839  fprintf (fp, "    add 2 1 roll 1 sub dup 0 eq\n");
840  fprintf (fp, "    { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n");
841  fprintf (fp, "       3 1 roll 5 -1 roll } put 1 add 3 0 \n");
842  fprintf (fp, "    { 2 1 roll } ifelse\n");
843  fprintf (fp, "    }forall\n");
844  fprintf (fp, "    pop pop pop\n");
845  fprintf (fp, "} def\n");
846  fprintf (fp, "systemdict /colorimage known not {\n");
847  fprintf (fp, "   /colorimage {\n");
848  fprintf (fp, "       pop\n");
849  fprintf (fp, "       pop\n");
850  fprintf (fp, "       /rgbproc exch def\n");
851  fprintf (fp, "       { bwproc } image\n");
852  fprintf (fp, "   }  def\n");
853  fprintf (fp, "} if\n");
854  fprintf (fp, "/picstr %d string def\n", width * components);
855  fprintf (fp, "%d %d scale\n", width, height);
856  fprintf (fp, "%d %d %d\n", width, height, 8);
857  fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height);
858  fprintf (fp, "{currentfile picstr readhexstring pop}\n");
859  fprintf (fp, "false %d\n", components);
860  fprintf (fp, "colorimage\n");
861 
862  curpix = (GLubyte*) pixels;
863  pos = 0;
864  for (i = width*height*components; i>0; i--) {
865    fprintf (fp, "%02hx ", *(curpix++));
866    if (++pos >= 32) {
867      fprintf (fp, "\n");
868      pos = 0;
869    }
870  }
871  if (pos)
872    fprintf (fp, "\n");
873
874  fprintf (fp, "grestore\n");
875  fprintf (fp, "showpage\n");
876  delete pixels;
877  fclose (fp);
878  return 0;
879}
880
881
882void G4OpenGLViewer::WritePostScript(const char *aFile) {
883
884  if (!fGL2PSAction) return;
885
886  fGL2PSAction->setFileName("PostScriptViaGL2PS.ps");
887  if (fGL2PSAction->enableFileWriting()) {
888    DrawView();
889    fGL2PSAction->disableFileWriting();
890  }
891  FILE *fFile = fopen(aFile,"w");
892  if(!fFile) {
893    G4cout << "G4OpenGLViewer::WritePostScript. Cannot open file " <<aFile << G4endl;
894    return;
895  }
896 
897  // Get the viewport
898  GLint viewport[4];
899  glGetIntegerv(GL_VIEWPORT, viewport);
900
901
902
903  int psformat;
904  //  psformat = GL2PS_PDF;
905  psformat = GL2PS_PS;
906  //  psformat = GL2PS_SVG;
907  //  psformat = GL2PS_EPS;
908 
909  //  int old_bg_gradient = CTX.bg_gradient;
910  //  if(!CTX.print.eps_background) CTX.bg_gradient = 0;
911 
912//   PixelBuffer buffer(width, height, GL_RGB, GL_FLOAT);
913 
914//   if(CTX.print.eps_quality == 0)
915//     buffer.Fill(CTX.batch);
916 
917  int pssort = GL2PS_SIMPLE_SORT;
918  //       int pssort =
919  //         (CTX.print.eps_quality == 3) ? GL2PS_NO_SORT :
920  //         (CTX.print.eps_quality == 2) ? GL2PS_BSP_SORT :
921  //         GL2PS_SIMPLE_SORT;
922  int psoptions = GL2PS_SIMPLE_LINE_OFFSET | GL2PS_DRAW_BACKGROUND;
923  //         GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT |
924  //         (CTX.print.eps_occlusion_culling ? GL2PS_OCCLUSION_CULL : 0) |
925  //         (CTX.print.eps_best_root ? GL2PS_BEST_ROOT : 0) |
926  //         (CTX.print.eps_background ? GL2PS_DRAW_BACKGROUND : 0) |
927  //         (CTX.print.eps_compress ? GL2PS_COMPRESS : 0) |
928  //         (CTX.print.eps_ps3shading ? 0 : GL2PS_NO_PS3_SHADING);
929 
930  GLint buffsize = 0;
931  int res = GL2PS_OVERFLOW;
932  while(res == GL2PS_OVERFLOW) {
933    buffsize += 2048 * 2048;
934    gl2psBeginPage("MyTitle", "Geant4", viewport,
935                   psformat, pssort, psoptions, GL_RGBA, 0, NULL,
936                   15, 20, 10, buffsize, fFile, aFile);
937    DrawView();
938    res = gl2psEndPage();
939  }
940 
941  //  CTX.bg_gradient = old_bg_gradient;
942  fclose(fFile);
943
944}
945
946GLdouble G4OpenGLViewer::getSceneNearWidth()
947{
948  const G4Point3D targetPoint
949    = fSceneHandler.GetScene()->GetStandardTargetPoint()
950    + fVP.GetCurrentTargetPoint ();
951  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
952  if(radius<=0.) radius = 1.;
953  const G4double cameraDistance = fVP.GetCameraDistance (radius);
954  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
955  return 2 * fVP.GetFrontHalfHeight (pnear, radius);
956}
957
958GLdouble G4OpenGLViewer::getSceneFarWidth()
959{
960  const G4Point3D targetPoint
961    = fSceneHandler.GetScene()->GetStandardTargetPoint()
962    + fVP.GetCurrentTargetPoint ();
963  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
964  if(radius<=0.) radius = 1.;
965  const G4double cameraDistance = fVP.GetCameraDistance (radius);
966  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
967  const GLdouble pfar    = fVP.GetFarDistance  (cameraDistance, pnear, radius);
968  return 2 * fVP.GetFrontHalfHeight (pfar, radius);
969}
970
971
972GLdouble G4OpenGLViewer::getSceneDepth()
973{
974  const G4Point3D targetPoint
975    = fSceneHandler.GetScene()->GetStandardTargetPoint()
976    + fVP.GetCurrentTargetPoint ();
977  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
978  if(radius<=0.) radius = 1.;
979  const G4double cameraDistance = fVP.GetCameraDistance (radius);
980  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
981  return fVP.GetFarDistance  (cameraDistance, pnear, radius)- pnear;
982}
983
984
985void G4OpenGLViewer::spewSortedFeedback(FILE * file, GLint size, GLfloat * buffer)
986{
987  int token;
988  GLfloat *loc, *end;
989  Feedback3Dcolor *vertex;
990  GLfloat depthSum;
991  int nprimitives, item;
992  DepthIndex *prims;
993  int nvertices, i;
994
995  end = buffer + size;
996
997  /* Count how many primitives there are. */
998  nprimitives = 0;
999  loc = buffer;
1000  while (loc < end) {
1001    token = int (*loc);
1002    loc++;
1003    switch (token) {
1004    case GL_LINE_TOKEN:
1005    case GL_LINE_RESET_TOKEN:
1006      loc += 14;
1007      nprimitives++;
1008      break;
1009    case GL_POLYGON_TOKEN:
1010      nvertices = int (*loc);
1011      loc++;
1012      loc += (7 * nvertices);
1013      nprimitives++;
1014      break;
1015    case GL_POINT_TOKEN:
1016      loc += 7;
1017      nprimitives++;
1018      break;
1019    default:
1020      /* XXX Left as an excersie to the reader. */
1021      static G4bool spewSortedFeedbackWarned = false;
1022      if (!spewSortedFeedbackWarned) {
1023        std::ostringstream oss;
1024        oss <<
1025          "Incomplete implementation.  Unexpected token (" << token << ")."
1026          "\n  (Seems to be caused by text.)";
1027        G4Exception("G4OpenGLViewer::spewSortedFeedback",
1028                    "Unexpected token",
1029                    JustWarning,
1030                    oss.str().c_str());
1031        spewSortedFeedbackWarned = true;
1032      }
1033      nprimitives++;
1034    }
1035  }
1036
1037  /* Allocate an array of pointers that will point back at
1038     primitives in the feedback buffer.  There will be one
1039     entry per primitive.  This array is also where we keep the
1040     primitive's average depth.  There is one entry per
1041     primitive  in the feedback buffer. */
1042  prims = (DepthIndex *) malloc(sizeof(DepthIndex) * nprimitives);
1043
1044  item = 0;
1045  loc = buffer;
1046  while (loc < end) {
1047    prims[item].ptr = loc;  /* Save this primitive's location. */
1048    token = int (*loc);
1049    loc++;
1050    switch (token) {
1051    case GL_LINE_TOKEN:
1052    case GL_LINE_RESET_TOKEN:
1053      vertex = (Feedback3Dcolor *) loc;
1054      depthSum = vertex[0].z + vertex[1].z;
1055      prims[item].depth = depthSum / 2.0;
1056      loc += 14;
1057      break;
1058    case GL_POLYGON_TOKEN:
1059      nvertices = int (*loc);
1060      loc++;
1061      vertex = (Feedback3Dcolor *) loc;
1062      depthSum = vertex[0].z;
1063      for (i = 1; i < nvertices; i++) {
1064        depthSum += vertex[i].z;
1065      }
1066      prims[item].depth = depthSum / nvertices;
1067      loc += (7 * nvertices);
1068      break;
1069    case GL_POINT_TOKEN:
1070      vertex = (Feedback3Dcolor *) loc;
1071      prims[item].depth = vertex[0].z;
1072      loc += 7;
1073      break;
1074    default:
1075      /* XXX Left as an excersie to the reader. */
1076      assert(1);
1077    }
1078    item++;
1079  }
1080  assert(item == nprimitives);
1081
1082  /* Sort the primitives back to front. */
1083  qsort(prims, nprimitives, sizeof(DepthIndex), G4OpenGLViewercompare);
1084
1085  /* Understand that sorting by a primitives average depth
1086     doesn't allow us to disambiguate some cases like self
1087     intersecting polygons.  Handling these cases would require
1088     breaking up the primitives.  That's too involved for this
1089     example.  Sorting by depth is good enough for lots of
1090     applications. */
1091
1092  /* Emit the Encapsulated PostScript for the primitives in
1093     back to front order. */
1094  for (item = 0; item < nprimitives; item++) {
1095    (void) spewPrimitiveEPS(file, prims[item].ptr);
1096  }
1097
1098  free(prims);
1099}
1100
1101void G4OpenGLViewer::rotateScene(G4double dx, G4double dy,G4double deltaRotation)
1102{
1103
1104  G4Vector3D vp;
1105  G4Vector3D up;
1106 
1107  G4Vector3D xprime;
1108  G4Vector3D yprime;
1109  G4Vector3D zprime;
1110 
1111  G4double delta_alpha;
1112  G4double delta_theta;
1113 
1114  G4Vector3D new_vp;
1115  G4Vector3D new_up;
1116 
1117  G4double cosalpha;
1118  G4double sinalpha;
1119 
1120  G4Vector3D a1;
1121  G4Vector3D a2;
1122  G4Vector3D delta;
1123  G4Vector3D viewPoint;
1124
1125   
1126  //phi spin stuff here
1127 
1128  vp = fVP.GetViewpointDirection ().unit ();
1129  up = fVP.GetUpVector ().unit ();
1130 
1131  yprime = (up.cross(vp)).unit();
1132  zprime = (vp.cross(yprime)).unit();
1133 
1134  if (fVP.GetLightsMoveWithCamera()) {
1135    delta_alpha = dy * deltaRotation;
1136    delta_theta = -dx * deltaRotation;
1137  } else {
1138    delta_alpha = -dy * deltaRotation;
1139    delta_theta = dx * deltaRotation;
1140  }   
1141 
1142  delta_alpha *= deg;
1143  delta_theta *= deg;
1144 
1145  new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime;
1146 
1147  // to avoid z rotation flipping
1148  // to allow more than 360° rotation
1149
1150  const G4Point3D targetPoint
1151    = fSceneHandler.GetScene()->GetStandardTargetPoint()
1152    + fVP.GetCurrentTargetPoint ();
1153  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
1154  if(radius<=0.) radius = 1.;
1155  const G4double cameraDistance = fVP.GetCameraDistance (radius);
1156  const G4Point3D cameraPosition =
1157    targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
1158
1159  if (fVP.GetLightsMoveWithCamera()) {
1160    new_up = (new_vp.cross(yprime)).unit();
1161    if (new_vp.z()*vp.z() <0) {
1162      new_up.set(new_up.x(),-new_up.y(),new_up.z());
1163    }
1164  } else {
1165    new_up = up;
1166    if (new_vp.z()*vp.z() <0) {
1167      new_up.set(new_up.x(),-new_up.y(),new_up.z());
1168    }
1169  }
1170  fVP.SetUpVector(new_up);
1171  ////////////////
1172  // Rotates by fixed azimuthal angle delta_theta.
1173 
1174  cosalpha = new_up.dot (new_vp.unit());
1175  sinalpha = std::sqrt (1. - std::pow (cosalpha, 2));
1176  yprime = (new_up.cross (new_vp.unit())).unit ();
1177  xprime = yprime.cross (new_up);
1178  // Projection of vp on plane perpendicular to up...
1179  a1 = sinalpha * xprime;
1180  // Required new projection...
1181  a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime);
1182  // Required Increment vector...
1183  delta = a2 - a1;
1184  // So new viewpoint is...
1185  viewPoint = new_vp.unit() + delta;
1186 
1187  fVP.SetViewAndLights (viewPoint);
1188}
1189
1190#endif
Note: See TracBrowser for help on using the repository browser.