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

Last change on this file since 846 was 846, checked in by garnier, 16 years ago

last updates

  • Property svn:mime-type set to text/cpp
File size: 29.7 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.38 2008/06/20 13:55:06 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//#define GEANT4_QT_DEBUG
37
38#include "G4ios.hh"
39#include "G4OpenGLViewer.hh"
40#include "G4OpenGLSceneHandler.hh"
41#include "G4OpenGLTransform3D.hh"
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 <sstream>
53
54static const char* gouraudtriangleEPS[] =
55{
56  "/bd{bind def}bind def /triangle { aload pop   setrgbcolor  aload pop 5 3",
57  "roll 4 2 roll 3 2 roll exch moveto lineto lineto closepath fill } bd",
58  "/computediff1 { 2 copy sub abs threshold ge {pop pop pop true} { exch 2",
59  "index sub abs threshold ge { pop pop true} { sub abs threshold ge } ifelse",
60  "} ifelse } bd /computediff3 { 3 copy 0 get 3 1 roll 0 get 3 1 roll 0 get",
61  "computediff1 {true} { 3 copy 1 get 3 1 roll 1 get 3 1 roll 1 get",
62  "computediff1 {true} { 3 copy 2 get 3 1 roll  2 get 3 1 roll 2 get",
63  "computediff1 } ifelse } ifelse } bd /middlecolor { aload pop 4 -1 roll",
64  "aload pop 4 -1 roll add 2 div 5 1 roll 3 -1 roll add 2 div 3 1 roll add 2",
65  "div 3 1 roll exch 3 array astore } bd /gouraudtriangle { computediff3 { 4",
66  "-1 roll aload 7 1 roll 6 -1 roll pop 3 -1 roll pop add 2 div 3 1 roll add",
67  "2 div exch 3 -1 roll aload 7 1 roll exch pop 4 -1 roll pop add 2 div 3 1",
68  "roll add 2 div exch 3 -1 roll aload 7 1 roll pop 3 -1 roll pop add 2 div 3",
69  "1 roll add 2 div exch 7 3 roll 10 -3 roll dup 3 index middlecolor 4 1 roll",
70  "2 copy middlecolor 4 1 roll 3 copy pop middlecolor 4 1 roll 13 -1 roll",
71  "aload pop 17 index 6 index 15 index 19 index 6 index 17 index 6 array",
72  "astore 10 index 10 index 14 index gouraudtriangle 17 index 5 index 17",
73  "index 19 index 5 index 19 index 6 array astore 10 index 9 index 13 index",
74  "gouraudtriangle 13 index 16 index 5 index 15 index 18 index 5 index 6",
75  "array astore 12 index 12 index 9 index gouraudtriangle 17 index 16 index",
76  "15 index 19 index 18 index 17 index 6 array astore 10 index 12 index 14",
77  "index gouraudtriangle 18 {pop} repeat } { aload pop 5 3 roll aload pop 7 3",
78  "roll aload pop 9 3 roll 4 index 6 index 4 index add add 3 div 10 1 roll 7",
79  "index 5 index 3 index add add 3 div 10 1 roll 6 index 4 index 2 index add",
80  "add 3 div 10 1 roll 9 {pop} repeat 3 array astore triangle } ifelse } bd",
81  NULL
82};
83
84G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene):
85G4VViewer (scene, -1),
86pointSize (0),
87print_colour (true),
88vectored_ps (true),
89fOpenGLSceneHandler(scene),
90background (G4Colour(0.,0.,0.)),
91transparency_enabled (true),
92antialiasing_enabled (false),
93haloing_enabled (false),
94fStartTime(-DBL_MAX),
95fEndTime(DBL_MAX),
96fFadeFactor(0.),
97fDisplayHeadTime(false),
98fDisplayHeadTimeX(-0.9),
99fDisplayHeadTimeY(-0.9),
100fDisplayHeadTimeSize(24.),
101fDisplayHeadTimeRed(0.),
102fDisplayHeadTimeGreen(1.),
103fDisplayHeadTimeBlue(1.),
104fDisplayLightFront(false),
105fDisplayLightFrontX(0.),
106fDisplayLightFrontY(0.),
107fDisplayLightFrontZ(0.),
108fDisplayLightFrontT(0.),
109fDisplayLightFrontRed(0.),
110fDisplayLightFrontGreen(1.),
111fDisplayLightFrontBlue(0.)
112{
113  // Make changes to view parameters for OpenGL...
114  fVP.SetAutoRefresh(true);
115  fDefaultVP.SetAutoRefresh(true);
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  strcpy (print_string, "G4OpenGL.eps");
124}
125
126G4OpenGLViewer::~G4OpenGLViewer () {}
127
128void G4OpenGLViewer::InitializeGLView ()
129{
130  glClearColor (0.0, 0.0, 0.0, 0.0);
131  glClearDepth (1.0);
132  glDisable (GL_BLEND);
133  glDisable (GL_LINE_SMOOTH);
134  glDisable (GL_POLYGON_SMOOTH);
135
136
137void G4OpenGLViewer::ClearView () {
138  glClearColor (background.GetRed(),
139                background.GetGreen(),
140                background.GetBlue(),
141                1.);
142  glClearDepth (1.0);
143  //Below line does not compile with Mesa includes.
144  //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
145  glClear (GL_COLOR_BUFFER_BIT);
146  glClear (GL_DEPTH_BUFFER_BIT);
147  glClear (GL_STENCIL_BUFFER_BIT);
148  glFlush ();
149}
150
151void G4OpenGLViewer::SetView () {
152 
153  // Calculates view representation based on extent of object being
154  // viewed and (initial) viewpoint.  (Note: it can change later due
155  // to user interaction via visualization system's GUI.)
156 
157  // Lighting.
158  GLfloat lightPosition [4];
159  lightPosition [0] = fVP.GetActualLightpointDirection().x();
160  lightPosition [1] = fVP.GetActualLightpointDirection().y();
161  lightPosition [2] = fVP.GetActualLightpointDirection().z();
162  lightPosition [3] = 0.;
163  // Light position is "true" light direction, so must come after gluLookAt.
164  GLfloat ambient [] = { 0.2, 0.2, 0.2, 1.};
165  GLfloat diffuse [] = { 0.8, 0.8, 0.8, 1.};
166  glEnable (GL_LIGHT0);
167  glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
168  glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
169 
170  // Get radius of scene, etc.
171  // Note that this procedure properly takes into account zoom, dolly and pan.
172  const G4Point3D targetPoint
173    = fSceneHandler.GetScene()->GetStandardTargetPoint()
174    + fVP.GetCurrentTargetPoint ();
175  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
176  if(radius<=0.) radius = 1.;
177  const G4double cameraDistance = fVP.GetCameraDistance (radius);
178  const G4Point3D cameraPosition =
179    targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
180  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
181  const GLdouble pfar    = fVP.GetFarDistance  (cameraDistance, pnear, radius);
182  const GLdouble right  = fVP.GetFrontHalfHeight (pnear, radius);
183  const GLdouble left   = -right;
184  const GLdouble bottom = left;
185  const GLdouble top    = right;
186 
187  glMatrixMode (GL_PROJECTION); // set up Frustum.
188  glLoadIdentity();
189
190  const G4Vector3D scale = fVP.GetScaleFactor();
191  glScaled(scale.x(),scale.y(),scale.z());
192 
193  if (fVP.GetFieldHalfAngle() == 0.) {
194    glOrtho (left, right, bottom, top, pnear, pfar);
195  }
196  else {
197    glFrustum (left, right, bottom, top, pnear, pfar);
198  }
199 
200  glMatrixMode (GL_MODELVIEW); // apply further transformations to scene.
201  glLoadIdentity();
202 
203  const G4Normal3D& upVector = fVP.GetUpVector (); 
204  G4Point3D gltarget;
205  if (cameraDistance > 1.e-6 * radius) {
206    gltarget = targetPoint;
207  }
208  else {
209    gltarget = targetPoint - radius * fVP.GetViewpointDirection().unit();
210  }
211
212  const G4Point3D& pCamera = cameraPosition;  // An alias for brevity.
213  gluLookAt (pCamera.x(),  pCamera.y(),  pCamera.z(),       // Viewpoint.
214             gltarget.x(), gltarget.y(), gltarget.z(),      // Target point.
215             upVector.x(), upVector.y(), upVector.z());     // Up vector.
216 
217  // Light position is "true" light direction, so must come after gluLookAt.
218  glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
219
220  // OpenGL no longer seems to reconstruct clipped edges, so, when the
221  // BooleanProcessor is up to it, abandon this and use generic
222  // clipping in G4OpenGLSceneHandler::CreateSectionPolyhedron.  Also,
223  // force kernel visit on change of clipping plane in
224  // G4OpenGLStoredViewer::CompareForKernelVisit.
225  if (fVP.IsSection () ) {  // pair of back to back clip planes.
226    const G4Plane3D& s = fVP.GetSectionPlane ();
227    double sArray[4];
228    sArray[0] = s.a();
229    sArray[1] = s.b();
230    sArray[2] = s.c();
231    sArray[3] = s.d() + radius * 1.e-05;
232    glClipPlane (GL_CLIP_PLANE0, sArray);
233    glEnable (GL_CLIP_PLANE0);
234    sArray[0] = -s.a();
235    sArray[1] = -s.b();
236    sArray[2] = -s.c();
237    sArray[3] = -s.d() + radius * 1.e-05;
238    glClipPlane (GL_CLIP_PLANE1, sArray);
239    glEnable (GL_CLIP_PLANE1);
240  } else {
241    glDisable (GL_CLIP_PLANE0);
242    glDisable (GL_CLIP_PLANE1);
243  }
244
245  const G4Planes& cutaways = fVP.GetCutawayPlanes();
246  size_t nPlanes = cutaways.size();
247  if (fVP.IsCutaway() &&
248      fVP.GetCutawayMode() == G4ViewParameters::cutawayIntersection &&
249      nPlanes > 0) {
250    double a[4];
251    a[0] = cutaways[0].a();
252    a[1] = cutaways[0].b();
253    a[2] = cutaways[0].c();
254    a[3] = cutaways[0].d();
255    glClipPlane (GL_CLIP_PLANE2, a);
256    glEnable (GL_CLIP_PLANE2);
257    if (nPlanes > 1) {
258      a[0] = cutaways[1].a();
259      a[1] = cutaways[1].b();
260      a[2] = cutaways[1].c();
261      a[3] = cutaways[1].d();
262      glClipPlane (GL_CLIP_PLANE3, a);
263      glEnable (GL_CLIP_PLANE3);
264    }
265    if (nPlanes > 2) {
266      a[0] = cutaways[2].a();
267      a[1] = cutaways[2].b();
268      a[2] = cutaways[2].c();
269      a[3] = cutaways[2].d();
270      glClipPlane (GL_CLIP_PLANE4, a);
271      glEnable (GL_CLIP_PLANE4);
272    }
273  } else {
274    glDisable (GL_CLIP_PLANE2);
275    glDisable (GL_CLIP_PLANE3);
276    glDisable (GL_CLIP_PLANE4);
277  }
278
279  // Background.
280  background = fVP.GetBackgroundColour ();
281
282}
283
284void G4OpenGLViewer::HaloingFirstPass () {
285 
286  //To perform haloing, first Draw all information to the depth buffer
287  //alone, using a chunky line width, and then Draw all info again, to
288  //the colour buffer, setting a thinner line width an the depth testing
289  //function to less than or equal, so if two lines cross, the one
290  //passing behind the other will not pass the depth test, and so not
291  //get rendered either side of the infront line for a short distance.
292
293  //First, disable writing to the colo(u)r buffer...
294  glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
295
296  //Now enable writing to the depth buffer...
297  glDepthMask (GL_TRUE);
298  glDepthFunc (GL_LESS);
299  glClearDepth (1.0);
300
301  //Finally, set the line width to something wide...
302  glLineWidth (3.0);
303
304}
305
306void G4OpenGLViewer::HaloingSecondPass () {
307
308  //And finally, turn the colour buffer back on with a sesible line width...
309  glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
310  glDepthFunc (GL_LEQUAL);
311  glLineWidth (1.0);
312
313}
314
315void G4OpenGLViewer::Pick(GLdouble x, GLdouble y)
316{
317  //G4cout << "X: " << x << ", Y: " << y << G4endl;
318  const G4int BUFSIZE = 512;
319  GLuint selectBuffer[BUFSIZE];
320  glSelectBuffer(BUFSIZE, selectBuffer);
321  glRenderMode(GL_SELECT);
322  glInitNames();
323  glPushName(0);
324  glMatrixMode(GL_PROJECTION);
325  G4double currentProjectionMatrix[16];
326  glGetDoublev(GL_PROJECTION_MATRIX, currentProjectionMatrix);
327  glPushMatrix();
328  glLoadIdentity();
329  GLint viewport[4];
330  glGetIntegerv(GL_VIEWPORT, viewport);
331  // Define 5x5 pixel pick area
332  gluPickMatrix(x, viewport[3] - y, 5., 5., viewport);
333  glMultMatrixd(currentProjectionMatrix);
334  glMatrixMode(GL_MODELVIEW);
335  DrawView();
336  GLint hits = glRenderMode(GL_RENDER);
337  if (hits < 0)
338    G4cout << "Too many hits.  Zoom in to reduce overlaps." << G4cout;
339  else if (hits > 0) {
340    //G4cout << hits << " hit(s)" << G4endl;
341    GLuint* p = selectBuffer;
342    for (GLint i = 0; i < hits; ++i) {
343      GLuint nnames = *p++;
344      *p++; //OR GLuint zmin = *p++;
345      *p++; //OR GLuint zmax = *p++;
346      //G4cout << "Hit " << i << ": " << nnames << " names"
347      //     << "\nzmin: " << zmin << ", zmax: " << zmax << G4endl;
348      for (GLuint j = 0; j < nnames; ++j) {
349        GLuint name = *p++;
350        //G4cout << "Name " << j << ": PickName: " << name << G4endl;
351        std::map<GLuint, G4AttHolder*>::iterator iter =
352          fOpenGLSceneHandler.fPickMap.find(name);
353        if (iter != fOpenGLSceneHandler.fPickMap.end()) {
354          G4AttHolder* attHolder = iter->second;
355          if(attHolder && attHolder->GetAttDefs().size()) {
356            for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) {
357              G4cout << G4AttCheck(attHolder->GetAttValues()[i],
358                                   attHolder->GetAttDefs()[i]);
359            }
360          }
361        }
362      }
363      G4cout << G4endl;
364    }
365  }
366  glMatrixMode(GL_PROJECTION);
367  glPopMatrix();
368  glMatrixMode(GL_MODELVIEW);
369}
370
371void G4OpenGLViewer::print() {
372
373  // Print vectored PostScript
374 
375  G4int size = 5000000;
376  GLfloat* feedback_buffer = new GLfloat[size];
377  glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
378  glRenderMode (GL_FEEDBACK);
379 
380  DrawView();
381
382  GLint returned;
383  returned = glRenderMode (GL_RENDER);
384 
385  FILE* file;
386  if (print_string) {
387    file = fopen (print_string, "w");
388    if (file) {
389      spewWireframeEPS (file, returned, feedback_buffer, "rendereps");
390    } else {
391      printf("Could not open %s\n", print_string);
392    }
393  } else {
394    printBuffer (returned, feedback_buffer);
395  }
396
397  delete[] feedback_buffer;
398}
399
400void G4OpenGLViewer::print3DcolorVertex(GLint size, GLint * count, GLfloat * buffer)
401{
402  G4int i;
403
404  printf("  ");
405  for (i = 0; i < 7; i++) {
406    printf("%4.2f ", buffer[size - (*count)]);
407    *count = *count - 1;
408  }
409  printf("\n");
410}
411
412void G4OpenGLViewer::spewWireframeEPS (FILE* file, GLint size, GLfloat* buffer, const char* cr) {
413
414  GLfloat EPS_GOURAUD_THRESHOLD=0.1;
415
416  GLfloat clearColor[4], viewport[4];
417  GLfloat lineWidth;
418  G4int i;
419
420  glGetFloatv (GL_VIEWPORT, viewport);
421  glGetFloatv (GL_COLOR_CLEAR_VALUE, clearColor);
422  glGetFloatv (GL_LINE_WIDTH, &lineWidth);
423  glGetFloatv (GL_POINT_SIZE, &pointSize);
424
425  fputs ("%!PS-Adobe-2.0 EPSF-2.0\n", file);
426  fprintf (file, "%%%%Creator: %s (using OpenGL feedback)\n", cr);
427  fprintf (file, "%%%%BoundingBox: %g %g %g %g\n", viewport[0], viewport[1], viewport[2], viewport[3]);
428  fputs ("%%EndComments\n", file);
429  fputs ("\n", file);
430  fputs ("gsave\n", file);
431  fputs ("\n", file);
432
433  fputs ("% the gouraudtriangle PostScript fragment below is free\n", file);
434  fputs ("% written by Frederic Delhoume (delhoume@ilog.fr)\n", file);
435  fprintf (file, "/threshold %g def\n", EPS_GOURAUD_THRESHOLD);
436  for (i=0; gouraudtriangleEPS[i]; i++) {
437    fprintf (file, "%s\n", gouraudtriangleEPS[i]);
438  }
439
440  fprintf(file, "\n%g setlinewidth\n", lineWidth);
441 
442  fprintf (file, "%g %g %g setrgbcolor\n", clearColor[0], clearColor[1], clearColor[2]);
443  fprintf (file, "%g %g %g %g rectfill\n\n", viewport[0], viewport[1], viewport[2], viewport[3]);
444
445  spewSortedFeedback (file, size, buffer);
446
447  fputs ("grestore\n\n", file);
448  fputs ("showpage\n", file);
449
450  fclose(file);
451}
452
453void G4OpenGLViewer::printBuffer (GLint size, GLfloat* buffer) {
454
455  GLint count;
456  G4int token, nvertices;
457
458  count=size;
459  while(count) {
460    token=G4int (buffer[size-count]);
461    count--;
462    switch (token) {
463
464    case GL_PASS_THROUGH_TOKEN:
465      printf ("GL_PASS_THROUGH_TOKEN\n");
466      printf ("  %4.2f\n", buffer[size-count]);
467      count--;
468      break;
469
470    case GL_POINT_TOKEN:
471      printf ("GL_POINT_TOKEN\n");
472      print3DcolorVertex (size, &count, buffer);
473      break;
474
475    case GL_LINE_TOKEN:
476      printf ("GL_LINE_TOKEN\n");
477      print3DcolorVertex (size, &count, buffer);
478      print3DcolorVertex (size, &count, buffer);
479      break;
480     
481    case GL_LINE_RESET_TOKEN:
482      printf ("GL_LINE_RESET_TOKEN\n");
483      print3DcolorVertex (size, &count, buffer);
484      print3DcolorVertex (size, &count, buffer);
485      break;
486
487    case GL_POLYGON_TOKEN:
488      printf ("GL_POLYGON_TOKEN\n");
489      nvertices=G4int (buffer[size-count]);
490      count--;
491      for (; nvertices>0; nvertices--) {
492        print3DcolorVertex (size, &count, buffer);
493      }
494    }
495  }
496}
497
498G4float* G4OpenGLViewer::spewPrimitiveEPS (FILE* file, GLfloat* loc) {
499 
500  G4int token;
501  G4int nvertices, i;
502  GLfloat red, green, blue, intensity;
503  G4int smooth;
504  GLfloat dx, dy, dr, dg, db, absR, absG, absB, colormax;
505  G4int steps;
506  Feedback3Dcolor *vertex;
507  GLfloat xstep(0.), ystep(0.), rstep(0.), gstep(0.), bstep(0.);
508  GLfloat xnext(0.), ynext(0.), rnext(0.), gnext(0.), bnext(0.), distance(0.);
509
510  token=G4int (*loc);
511  loc++;
512  switch (token) {
513  case GL_LINE_RESET_TOKEN:
514  case GL_LINE_TOKEN:
515    vertex=(Feedback3Dcolor*)loc;
516    dr=vertex[1].red - vertex[0].red;
517    dg=vertex[1].green - vertex[0].green;
518    db=vertex[1].blue - vertex[0].blue;
519
520    if (!print_colour) {
521      dr+=(dg+db);
522      dr/=3.0;
523      dg=dr;
524      db=dr;
525    }
526
527    if (dr!=0 || dg!=0 || db!=0) {
528      dx=vertex[1].x - vertex[0].x;
529      dy=vertex[1].y - vertex[0].y;
530      distance=std::sqrt(dx*dx + dy*dy);
531
532      absR=std::fabs(dr);
533      absG=std::fabs(dg);
534      absB=std::fabs(db);
535
536      #define Max(a, b) (((a)>(b))?(a):(b))
537
538      #define EPS_SMOOTH_LINE_FACTOR 0.06
539
540      colormax=Max(absR, Max(absG, absB));
541      steps=Max(1, G4int (colormax*distance*EPS_SMOOTH_LINE_FACTOR));
542     
543      xstep=dx/steps;
544      ystep=dy/steps;
545
546      rstep=dr/steps;
547      gstep=dg/steps;
548      bstep=db/steps;
549
550      xnext=vertex[0].x;
551      ynext=vertex[0].y;
552      rnext=vertex[0].red;
553      gnext=vertex[0].green;
554      bnext=vertex[0].blue;
555
556      if (!print_colour) {
557        rnext+=(gnext+bnext);
558        rnext/=3.0;
559        gnext=rnext;
560        bnext=rnext;
561      }
562
563      xnext -= xstep/2.0;
564      ynext -= ystep/2.0;
565      rnext -= rstep/2.0;
566      gnext -= gstep/2.0;
567      bnext -= bstep/2.0;
568    } else {
569      steps=0;
570    }
571    if (print_colour) {
572      fprintf (file, "%g %g %g setrgbcolor\n",
573               vertex[0].red, vertex[0].green, vertex[0].blue);
574    } else {
575      intensity = (vertex[0].red + vertex[0].green + vertex[0].blue) / 3.0;
576      fprintf (file, "%g %g %g setrgbcolor\n",
577               intensity, intensity, intensity);
578    }     
579    fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
580
581    for (i=0; i<steps; i++) {
582
583      xnext += xstep;
584      ynext += ystep;
585      rnext += rstep;
586      gnext += gstep;
587      bnext += bstep;
588
589      fprintf (file, "%g %g lineto stroke\n", xnext, ynext);
590      fprintf (file, "%g %g %g setrgbcolor\n", rnext, gnext, bnext);
591      fprintf (file, "%g %g moveto\n", xnext, ynext);
592    }
593    fprintf (file, "%g %g lineto stroke\n", vertex[1].x, vertex[1].y);
594
595    loc += 14;
596    break;
597
598  case GL_POLYGON_TOKEN:
599    nvertices = G4int (*loc);
600    loc++;
601    vertex=(Feedback3Dcolor*)loc;
602    if (nvertices>0) {
603      red=vertex[0].red;
604      green=vertex[0].green;
605      blue=vertex[0].blue;
606      smooth=0;
607     
608      if (!print_colour) {
609        red+=(green+blue);
610        red/=3.0;
611        green=red;
612        blue=red;
613      }
614     
615      if (print_colour) {
616        for (i=1; i<nvertices; i++) {
617          if (red!=vertex[i].red || green!=vertex[i].green || blue!=vertex[i].blue) {
618            smooth=1;
619            break;
620          }
621        }
622      } else {
623        for (i=1; i<nvertices; i++) {
624          intensity = vertex[i].red + vertex[i].green + vertex[i].blue;
625          intensity/=3.0;
626          if (red!=intensity) {
627            smooth=1;
628            break;
629          }
630        }
631      }
632
633      if (smooth) {
634        G4int triOffset;
635        for (i=0; i<nvertices-2; i++) {
636          triOffset = i*7;
637          fprintf (file, "[%g %g %g %g %g %g]",
638                   vertex[0].x, vertex[i+1].x, vertex[i+2].x,
639                   vertex[0].y, vertex[i+1].y, vertex[i+2].y);
640          if (print_colour) {
641            fprintf (file, " [%g %g %g] [%g %g %g] [%g %g %g] gouraudtriangle\n",
642                     vertex[0].red, vertex[0].green, vertex[0].blue,
643                     vertex[i+1].red, vertex[i+1].green, vertex[i+1].blue,
644                     vertex[i+2].red, vertex[i+2].green, vertex[i+2].blue);
645          } else {
646
647            intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
648            intensity/=3.0;
649            fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
650
651            intensity = vertex[1].red + vertex[1].green + vertex[1].blue;
652            intensity/=3.0;
653            fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
654
655            intensity = vertex[2].red + vertex[2].green + vertex[2].blue;
656            intensity/=3.0;
657            fprintf (file, " [%g %g %g] gouraudtriangle\n", intensity, intensity, intensity);
658          }
659        }
660      } else {
661        fprintf (file, "newpath\n");
662        fprintf (file, "%g %g %g setrgbcolor\n", red, green, blue);
663        fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
664        for (i=1; i<nvertices; i++) {
665          fprintf (file, "%g %g lineto\n", vertex[i].x, vertex[i].y);
666        }
667        fprintf (file, "closepath fill\n\n");
668      }
669    }
670    loc += nvertices*7;
671    break;
672
673  case GL_POINT_TOKEN:
674    vertex=(Feedback3Dcolor*)loc;
675    if (print_colour) {
676      fprintf (file, "%g %g %g setrgbcolor\n", vertex[0].red, vertex[0].green, vertex[0].blue);
677    } else {
678      intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
679      intensity/=3.0;
680      fprintf (file, "%g %g %g setrgbcolor\n", intensity, intensity, intensity);
681    }     
682    fprintf(file, "%g %g %g 0 360 arc fill\n\n", vertex[0].x, vertex[0].y, pointSize / 2.0);
683    loc += 7;           /* Each vertex element in the feedback
684                           buffer is 7 GLfloats. */
685    break;
686  default:
687    /* XXX Left as an excersie to the reader. */
688    static G4bool spewPrimitiveEPSWarned = false;
689    if (!spewPrimitiveEPSWarned) {
690      std::ostringstream oss;
691      oss <<
692        "Incomplete implementation.  Unexpected token (" << token << ")."
693        "\n  (Seems to be caused by text.)";
694      G4Exception("G4OpenGLViewer::spewPrimitiveEPS",
695                  "Unexpected token",
696                  JustWarning,
697                  oss.str().c_str());
698      spewPrimitiveEPSWarned = true;
699    }
700  }
701  return loc;
702}
703
704typedef struct G4OpenGLViewerDepthIndex {
705  GLfloat *ptr;
706  GLfloat depth;
707} DepthIndex;
708
709extern "C" {
710  int G4OpenGLViewercompare(const void *a, const void *b)
711  {
712    const DepthIndex *p1 = (DepthIndex *) a;
713    const DepthIndex *p2 = (DepthIndex *) b;
714    GLfloat diff = p2->depth - p1->depth;
715   
716    if (diff > 0.0) {
717      return 1;
718    } else if (diff < 0.0) {
719      return -1;
720    } else {
721      return 0;
722    }
723  }
724}
725
726GLdouble G4OpenGLViewer::getSceneNearWidth()
727{
728  const G4Point3D targetPoint
729    = fSceneHandler.GetScene()->GetStandardTargetPoint()
730    + fVP.GetCurrentTargetPoint ();
731  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
732  if(radius<=0.) radius = 1.;
733  const G4double cameraDistance = fVP.GetCameraDistance (radius);
734  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
735  return 2 * fVP.GetFrontHalfHeight (pnear, radius);
736}
737
738GLdouble G4OpenGLViewer::getSceneFarWidth()
739{
740  const G4Point3D targetPoint
741    = fSceneHandler.GetScene()->GetStandardTargetPoint()
742    + fVP.GetCurrentTargetPoint ();
743  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
744  if(radius<=0.) radius = 1.;
745  const G4double cameraDistance = fVP.GetCameraDistance (radius);
746  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
747  const GLdouble pfar    = fVP.GetFarDistance  (cameraDistance, pnear, radius);
748  return 2 * fVP.GetFrontHalfHeight (pfar, radius);
749}
750
751
752GLdouble G4OpenGLViewer::getSceneDepth()
753{
754  const G4Point3D targetPoint
755    = fSceneHandler.GetScene()->GetStandardTargetPoint()
756    + fVP.GetCurrentTargetPoint ();
757  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
758  if(radius<=0.) radius = 1.;
759  const G4double cameraDistance = fVP.GetCameraDistance (radius);
760  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
761  return fVP.GetFarDistance  (cameraDistance, pnear, radius)- pnear;
762}
763
764
765void G4OpenGLViewer::spewSortedFeedback(FILE * file, GLint size, GLfloat * buffer)
766{
767  int token;
768  GLfloat *loc, *end;
769  Feedback3Dcolor *vertex;
770  GLfloat depthSum;
771  int nprimitives, item;
772  DepthIndex *prims;
773  int nvertices, i;
774
775  end = buffer + size;
776
777  /* Count how many primitives there are. */
778  nprimitives = 0;
779  loc = buffer;
780  while (loc < end) {
781    token = int (*loc);
782    loc++;
783    switch (token) {
784    case GL_LINE_TOKEN:
785    case GL_LINE_RESET_TOKEN:
786      loc += 14;
787      nprimitives++;
788      break;
789    case GL_POLYGON_TOKEN:
790      nvertices = int (*loc);
791      loc++;
792      loc += (7 * nvertices);
793      nprimitives++;
794      break;
795    case GL_POINT_TOKEN:
796      loc += 7;
797      nprimitives++;
798      break;
799    default:
800      /* XXX Left as an excersie to the reader. */
801      static G4bool spewSortedFeedbackWarned = false;
802      if (!spewSortedFeedbackWarned) {
803        std::ostringstream oss;
804        oss <<
805          "Incomplete implementation.  Unexpected token (" << token << ")."
806          "\n  (Seems to be caused by text.)";
807        G4Exception("G4OpenGLViewer::spewSortedFeedback",
808                    "Unexpected token",
809                    JustWarning,
810                    oss.str().c_str());
811        spewSortedFeedbackWarned = true;
812      }
813      nprimitives++;
814    }
815  }
816
817  /* Allocate an array of pointers that will point back at
818     primitives in the feedback buffer.  There will be one
819     entry per primitive.  This array is also where we keep the
820     primitive's average depth.  There is one entry per
821     primitive  in the feedback buffer. */
822  prims = (DepthIndex *) malloc(sizeof(DepthIndex) * nprimitives);
823
824  item = 0;
825  loc = buffer;
826  while (loc < end) {
827    prims[item].ptr = loc;  /* Save this primitive's location. */
828    token = int (*loc);
829    loc++;
830    switch (token) {
831    case GL_LINE_TOKEN:
832    case GL_LINE_RESET_TOKEN:
833      vertex = (Feedback3Dcolor *) loc;
834      depthSum = vertex[0].z + vertex[1].z;
835      prims[item].depth = depthSum / 2.0;
836      loc += 14;
837      break;
838    case GL_POLYGON_TOKEN:
839      nvertices = int (*loc);
840      loc++;
841      vertex = (Feedback3Dcolor *) loc;
842      depthSum = vertex[0].z;
843      for (i = 1; i < nvertices; i++) {
844        depthSum += vertex[i].z;
845      }
846      prims[item].depth = depthSum / nvertices;
847      loc += (7 * nvertices);
848      break;
849    case GL_POINT_TOKEN:
850      vertex = (Feedback3Dcolor *) loc;
851      prims[item].depth = vertex[0].z;
852      loc += 7;
853      break;
854    default:
855      /* XXX Left as an excersie to the reader. */
856      assert(1);
857    }
858    item++;
859  }
860  assert(item == nprimitives);
861
862  /* Sort the primitives back to front. */
863  qsort(prims, nprimitives, sizeof(DepthIndex), G4OpenGLViewercompare);
864
865  /* Understand that sorting by a primitives average depth
866     doesn't allow us to disambiguate some cases like self
867     intersecting polygons.  Handling these cases would require
868     breaking up the primitives.  That's too involved for this
869     example.  Sorting by depth is good enough for lots of
870     applications. */
871
872  /* Emit the Encapsulated PostScript for the primitives in
873     back to front order. */
874  for (item = 0; item < nprimitives; item++) {
875    (void) spewPrimitiveEPS(file, prims[item].ptr);
876  }
877
878  free(prims);
879}
880
881void G4OpenGLViewer::rotateScene(G4double dx, G4double dy,G4double deltaRotation)
882{
883
884  G4Vector3D vp;
885  G4Vector3D up;
886 
887  G4Vector3D xprime;
888  G4Vector3D yprime;
889  G4Vector3D zprime;
890 
891  G4double delta_alpha;
892  G4double delta_theta;
893 
894  G4Vector3D new_vp;
895  G4Vector3D new_up;
896 
897  G4double cosalpha;
898  G4double sinalpha;
899 
900  G4Vector3D a1;
901  G4Vector3D a2;
902  G4Vector3D delta;
903  G4Vector3D viewPoint;
904
905   
906  //phi spin stuff here
907 
908  vp = fVP.GetViewpointDirection ().unit ();
909  up = fVP.GetUpVector ().unit ();
910 
911  yprime = (up.cross(vp)).unit();
912  zprime = (vp.cross(yprime)).unit();
913 
914  if (fVP.GetLightsMoveWithCamera()) {
915    delta_alpha = dy * deltaRotation;
916    delta_theta = -dx * deltaRotation;
917  } else {
918    delta_alpha = -dy * deltaRotation;
919    delta_theta = dx * deltaRotation;
920  }   
921 
922  delta_alpha *= deg;
923  delta_theta *= deg;
924 
925  new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime;
926 
927  // to avoid z rotation flipping
928  // to allow more than 360° rotation
929#ifdef GEANT4_QT_DEBUG
930  const G4Point3D targetPoint
931    = fSceneHandler.GetScene()->GetStandardTargetPoint()
932    + fVP.GetCurrentTargetPoint ();
933  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
934  if(radius<=0.) radius = 1.;
935  const G4double cameraDistance = fVP.GetCameraDistance (radius);
936  const G4Point3D cameraPosition =
937    targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
938
939
940  printf("G4OpenGLViewer:: Tp: %f %f %f Vpd:%f %f %f - Up:%f %f %f Cp:%f %f %f\n",
941         targetPoint[0],targetPoint[1],targetPoint[2],
942         vp.x(),vp.y(),vp.z(),
943         up.x(),up.y(),up.z(),
944         cameraPosition[0],cameraPosition[1],cameraPosition[2]);
945#endif
946
947  if (fVP.GetLightsMoveWithCamera()) {
948    new_up = (new_vp.cross(yprime)).unit();
949    if (new_vp.z()*vp.z() <0) {
950      new_up.set(new_up.x(),-new_up.y(),new_up.z());
951    }
952  } else {
953    new_up = up;
954    if (new_vp.z()*vp.z() <0) {
955#ifdef GEANT4_QT_DEBUG
956      //      printf("G4OpenGLViewer:: ***********************************************************\n");
957#endif
958      new_up.set(new_up.x(),-new_up.y(),new_up.z());
959      //      new_vp.set(-new_vp.x(),new_vp.y(),new_vp.z());
960    }
961  }
962  new_up.set(new_up.x(),-new_up.y(),new_up.z());
963  fVP.SetUpVector(new_up);
964  ////////////////
965  // Rotates by fixed azimuthal angle delta_theta.
966 
967  cosalpha = new_up.dot (new_vp.unit());
968  sinalpha = std::sqrt (1. - std::pow (cosalpha, 2));
969  yprime = (new_up.cross (new_vp.unit())).unit ();
970  xprime = yprime.cross (new_up);
971  // Projection of vp on plane perpendicular to up...
972  a1 = sinalpha * xprime;
973  // Required new projection...
974  a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime);
975  // Required Increment vector...
976  delta = a2 - a1;
977  // So new viewpoint is...
978  viewPoint = new_vp.unit() + delta;
979 
980  fVP.SetViewAndLights (viewPoint);
981}
982
983#endif
Note: See TracBrowser for help on using the repository browser.