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

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

for aspect radio. Ok for Qt, Xm, but not X. Debug mode

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