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

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

juste pour sauver le boulot ....ne compile pas....

  • Property svn:mime-type set to text/cpp
File size: 35.9 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  WritePostScript("AAAAAAAAAAAAAAA.ps");
815
816  pixels = grabPixels (inColour, width, height);
817
818  if (pixels == NULL)
819    return 1;
820  if (inColour) {
821    components = 3;
822  } else {
823    components = 1;
824  }
825 
826  fp = fopen (filnam, "w");
827  if (fp == NULL) {
828    return 2;
829  }
830 
831  fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
832  fprintf (fp, "%%%%Title: %s\n", filnam);
833  fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n");
834  fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
835  fprintf (fp, "%%%%EndComments\n");
836  fprintf (fp, "gsave\n");
837  fprintf (fp, "/bwproc {\n");
838  fprintf (fp, "    rgbproc\n");
839  fprintf (fp, "    dup length 3 idiv string 0 3 0 \n");
840  fprintf (fp, "    5 -1 roll {\n");
841  fprintf (fp, "    add 2 1 roll 1 sub dup 0 eq\n");
842  fprintf (fp, "    { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n");
843  fprintf (fp, "       3 1 roll 5 -1 roll } put 1 add 3 0 \n");
844  fprintf (fp, "    { 2 1 roll } ifelse\n");
845  fprintf (fp, "    }forall\n");
846  fprintf (fp, "    pop pop pop\n");
847  fprintf (fp, "} def\n");
848  fprintf (fp, "systemdict /colorimage known not {\n");
849  fprintf (fp, "   /colorimage {\n");
850  fprintf (fp, "       pop\n");
851  fprintf (fp, "       pop\n");
852  fprintf (fp, "       /rgbproc exch def\n");
853  fprintf (fp, "       { bwproc } image\n");
854  fprintf (fp, "   }  def\n");
855  fprintf (fp, "} if\n");
856  fprintf (fp, "/picstr %d string def\n", width * components);
857  fprintf (fp, "%d %d scale\n", width, height);
858  fprintf (fp, "%d %d %d\n", width, height, 8);
859  fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height);
860  fprintf (fp, "{currentfile picstr readhexstring pop}\n");
861  fprintf (fp, "false %d\n", components);
862  fprintf (fp, "colorimage\n");
863 
864  curpix = (GLubyte*) pixels;
865  pos = 0;
866  for (i = width*height*components; i>0; i--) {
867    fprintf (fp, "%02hx ", *(curpix++));
868    if (++pos >= 32) {
869      fprintf (fp, "\n");
870      pos = 0;
871    }
872  }
873  if (pos)
874    fprintf (fp, "\n");
875
876  fprintf (fp, "grestore\n");
877  fprintf (fp, "showpage\n");
878  delete pixels;
879  fclose (fp);
880  return 0;
881}
882
883
884void G4OpenGLViewer::WritePostScript(const char *aFile) {
885
886
887  if (!fGL2PSAction) return;
888
889  // FIXME : TEST
890  G4VMarker defaultMarker = GetViewParameters().GetDefaultMarker();
891  defaultMarker.SetWorldSize(defaultMarker.GetScreenSize());
892  defaultMarker.SetWorldDiameter(defaultMarker.GetScreenDiameter());
893  defaultMarker.SetWorldRadius(defaultMarker.GetScreenRadius());
894
895  fGL2PSAction->setFileName("PostScriptViaGL2PS.ps");
896  if (fGL2PSAction->enableFileWriting()) {
897    ShowView();
898    ProcessView();
899    DrawView();
900    fGL2PSAction->disableFileWriting();
901  }
902//   defaultMarker.SetScreenSize(defaultMarker.GetWorldSize());
903//   defaultMarker.SetScreenDiameter(defaultMarker.GetWorldDiameter());
904//   defaultMarker.SetScreenRadius(defaultMarker.GetWorldRadius());
905  // FIXME : TEST
906
907
908
909  FILE *fFile = fopen(aFile,"w");
910  if(!fFile) {
911    G4cout << "G4OpenGLViewer::WritePostScript. Cannot open file " <<aFile << G4endl;
912    return;
913  }
914 
915  // Get the viewport
916  GLint viewport[4];
917  glGetIntegerv(GL_VIEWPORT, viewport);
918
919
920
921  int psformat;
922  //  psformat = GL2PS_PDF;
923  psformat = GL2PS_PS;
924  //  psformat = GL2PS_SVG;
925  //  psformat = GL2PS_EPS;
926 
927  //  int old_bg_gradient = CTX.bg_gradient;
928  //  if(!CTX.print.eps_background) CTX.bg_gradient = 0;
929 
930//   PixelBuffer buffer(width, height, GL_RGB, GL_FLOAT);
931 
932//   if(CTX.print.eps_quality == 0)
933//     buffer.Fill(CTX.batch);
934 
935  int pssort = GL2PS_SIMPLE_SORT;
936  //       int pssort =
937  //         (CTX.print.eps_quality == 3) ? GL2PS_NO_SORT :
938  //         (CTX.print.eps_quality == 2) ? GL2PS_BSP_SORT :
939  //         GL2PS_SIMPLE_SORT;
940  int psoptions = GL2PS_SIMPLE_LINE_OFFSET | GL2PS_DRAW_BACKGROUND;
941  //         GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT |
942  //         (CTX.print.eps_occlusion_culling ? GL2PS_OCCLUSION_CULL : 0) |
943  //         (CTX.print.eps_best_root ? GL2PS_BEST_ROOT : 0) |
944  //         (CTX.print.eps_background ? GL2PS_DRAW_BACKGROUND : 0) |
945  //         (CTX.print.eps_compress ? GL2PS_COMPRESS : 0) |
946  //         (CTX.print.eps_ps3shading ? 0 : GL2PS_NO_PS3_SHADING);
947 
948  GLint buffsize = 0;
949  int res = GL2PS_OVERFLOW;
950  while(res == GL2PS_OVERFLOW) {
951    buffsize += 2048 * 2048;
952    gl2psBeginPage("MyTitle", "Geant4", viewport,
953                   psformat, pssort, psoptions, GL_RGBA, 0, NULL,
954                   15, 20, 10, buffsize, fFile, aFile);
955    DrawView();
956    res = gl2psEndPage();
957  }
958 
959  //  CTX.bg_gradient = old_bg_gradient;
960  fclose(fFile);
961
962}
963
964GLdouble G4OpenGLViewer::getSceneNearWidth()
965{
966  const G4Point3D targetPoint
967    = fSceneHandler.GetScene()->GetStandardTargetPoint()
968    + fVP.GetCurrentTargetPoint ();
969  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
970  if(radius<=0.) radius = 1.;
971  const G4double cameraDistance = fVP.GetCameraDistance (radius);
972  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
973  return 2 * fVP.GetFrontHalfHeight (pnear, radius);
974}
975
976GLdouble G4OpenGLViewer::getSceneFarWidth()
977{
978  const G4Point3D targetPoint
979    = fSceneHandler.GetScene()->GetStandardTargetPoint()
980    + fVP.GetCurrentTargetPoint ();
981  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
982  if(radius<=0.) radius = 1.;
983  const G4double cameraDistance = fVP.GetCameraDistance (radius);
984  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
985  const GLdouble pfar    = fVP.GetFarDistance  (cameraDistance, pnear, radius);
986  return 2 * fVP.GetFrontHalfHeight (pfar, radius);
987}
988
989
990GLdouble G4OpenGLViewer::getSceneDepth()
991{
992  const G4Point3D targetPoint
993    = fSceneHandler.GetScene()->GetStandardTargetPoint()
994    + fVP.GetCurrentTargetPoint ();
995  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
996  if(radius<=0.) radius = 1.;
997  const G4double cameraDistance = fVP.GetCameraDistance (radius);
998  const GLdouble pnear   = fVP.GetNearDistance (cameraDistance, radius);
999  return fVP.GetFarDistance  (cameraDistance, pnear, radius)- pnear;
1000}
1001
1002
1003void G4OpenGLViewer::spewSortedFeedback(FILE * file, GLint size, GLfloat * buffer)
1004{
1005  int token;
1006  GLfloat *loc, *end;
1007  Feedback3Dcolor *vertex;
1008  GLfloat depthSum;
1009  int nprimitives, item;
1010  DepthIndex *prims;
1011  int nvertices, i;
1012
1013  end = buffer + size;
1014
1015  /* Count how many primitives there are. */
1016  nprimitives = 0;
1017  loc = buffer;
1018  while (loc < end) {
1019    token = int (*loc);
1020    loc++;
1021    switch (token) {
1022    case GL_LINE_TOKEN:
1023    case GL_LINE_RESET_TOKEN:
1024      loc += 14;
1025      nprimitives++;
1026      break;
1027    case GL_POLYGON_TOKEN:
1028      nvertices = int (*loc);
1029      loc++;
1030      loc += (7 * nvertices);
1031      nprimitives++;
1032      break;
1033    case GL_POINT_TOKEN:
1034      loc += 7;
1035      nprimitives++;
1036      break;
1037    default:
1038      /* XXX Left as an excersie to the reader. */
1039      static G4bool spewSortedFeedbackWarned = false;
1040      if (!spewSortedFeedbackWarned) {
1041        std::ostringstream oss;
1042        oss <<
1043          "Incomplete implementation.  Unexpected token (" << token << ")."
1044          "\n  (Seems to be caused by text.)";
1045        G4Exception("G4OpenGLViewer::spewSortedFeedback",
1046                    "Unexpected token",
1047                    JustWarning,
1048                    oss.str().c_str());
1049        spewSortedFeedbackWarned = true;
1050      }
1051      nprimitives++;
1052    }
1053  }
1054
1055  /* Allocate an array of pointers that will point back at
1056     primitives in the feedback buffer.  There will be one
1057     entry per primitive.  This array is also where we keep the
1058     primitive's average depth.  There is one entry per
1059     primitive  in the feedback buffer. */
1060  prims = (DepthIndex *) malloc(sizeof(DepthIndex) * nprimitives);
1061
1062  item = 0;
1063  loc = buffer;
1064  while (loc < end) {
1065    prims[item].ptr = loc;  /* Save this primitive's location. */
1066    token = int (*loc);
1067    loc++;
1068    switch (token) {
1069    case GL_LINE_TOKEN:
1070    case GL_LINE_RESET_TOKEN:
1071      vertex = (Feedback3Dcolor *) loc;
1072      depthSum = vertex[0].z + vertex[1].z;
1073      prims[item].depth = depthSum / 2.0;
1074      loc += 14;
1075      break;
1076    case GL_POLYGON_TOKEN:
1077      nvertices = int (*loc);
1078      loc++;
1079      vertex = (Feedback3Dcolor *) loc;
1080      depthSum = vertex[0].z;
1081      for (i = 1; i < nvertices; i++) {
1082        depthSum += vertex[i].z;
1083      }
1084      prims[item].depth = depthSum / nvertices;
1085      loc += (7 * nvertices);
1086      break;
1087    case GL_POINT_TOKEN:
1088      vertex = (Feedback3Dcolor *) loc;
1089      prims[item].depth = vertex[0].z;
1090      loc += 7;
1091      break;
1092    default:
1093      /* XXX Left as an excersie to the reader. */
1094      assert(1);
1095    }
1096    item++;
1097  }
1098  assert(item == nprimitives);
1099
1100  /* Sort the primitives back to front. */
1101  qsort(prims, nprimitives, sizeof(DepthIndex), G4OpenGLViewercompare);
1102
1103  /* Understand that sorting by a primitives average depth
1104     doesn't allow us to disambiguate some cases like self
1105     intersecting polygons.  Handling these cases would require
1106     breaking up the primitives.  That's too involved for this
1107     example.  Sorting by depth is good enough for lots of
1108     applications. */
1109
1110  /* Emit the Encapsulated PostScript for the primitives in
1111     back to front order. */
1112  for (item = 0; item < nprimitives; item++) {
1113    (void) spewPrimitiveEPS(file, prims[item].ptr);
1114  }
1115
1116  free(prims);
1117}
1118
1119void G4OpenGLViewer::rotateScene(G4double dx, G4double dy,G4double deltaRotation)
1120{
1121
1122  G4Vector3D vp;
1123  G4Vector3D up;
1124 
1125  G4Vector3D xprime;
1126  G4Vector3D yprime;
1127  G4Vector3D zprime;
1128 
1129  G4double delta_alpha;
1130  G4double delta_theta;
1131 
1132  G4Vector3D new_vp;
1133  G4Vector3D new_up;
1134 
1135  G4double cosalpha;
1136  G4double sinalpha;
1137 
1138  G4Vector3D a1;
1139  G4Vector3D a2;
1140  G4Vector3D delta;
1141  G4Vector3D viewPoint;
1142
1143   
1144  //phi spin stuff here
1145 
1146  vp = fVP.GetViewpointDirection ().unit ();
1147  up = fVP.GetUpVector ().unit ();
1148 
1149  yprime = (up.cross(vp)).unit();
1150  zprime = (vp.cross(yprime)).unit();
1151 
1152  if (fVP.GetLightsMoveWithCamera()) {
1153    delta_alpha = dy * deltaRotation;
1154    delta_theta = -dx * deltaRotation;
1155  } else {
1156    delta_alpha = -dy * deltaRotation;
1157    delta_theta = dx * deltaRotation;
1158  }   
1159 
1160  delta_alpha *= deg;
1161  delta_theta *= deg;
1162 
1163  new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime;
1164 
1165  // to avoid z rotation flipping
1166  // to allow more than 360° rotation
1167
1168  const G4Point3D targetPoint
1169    = fSceneHandler.GetScene()->GetStandardTargetPoint()
1170    + fVP.GetCurrentTargetPoint ();
1171  G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
1172  if(radius<=0.) radius = 1.;
1173  const G4double cameraDistance = fVP.GetCameraDistance (radius);
1174  const G4Point3D cameraPosition =
1175    targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
1176
1177  if (fVP.GetLightsMoveWithCamera()) {
1178    new_up = (new_vp.cross(yprime)).unit();
1179    if (new_vp.z()*vp.z() <0) {
1180      new_up.set(new_up.x(),-new_up.y(),new_up.z());
1181    }
1182  } else {
1183    new_up = up;
1184    if (new_vp.z()*vp.z() <0) {
1185      new_up.set(new_up.x(),-new_up.y(),new_up.z());
1186    }
1187  }
1188  fVP.SetUpVector(new_up);
1189  ////////////////
1190  // Rotates by fixed azimuthal angle delta_theta.
1191 
1192  cosalpha = new_up.dot (new_vp.unit());
1193  sinalpha = std::sqrt (1. - std::pow (cosalpha, 2));
1194  yprime = (new_up.cross (new_vp.unit())).unit ();
1195  xprime = yprime.cross (new_up);
1196  // Projection of vp on plane perpendicular to up...
1197  a1 = sinalpha * xprime;
1198  // Required new projection...
1199  a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime);
1200  // Required Increment vector...
1201  delta = a2 - a1;
1202  // So new viewpoint is...
1203  viewPoint = new_vp.unit() + delta;
1204 
1205  fVP.SetViewAndLights (viewPoint);
1206}
1207
1208#endif
Note: See TracBrowser for help on using the repository browser.