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

Last change on this file since 907 was 906, checked in by garnier, 17 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
RevLine 
[529]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//
[906]27// $Id: G4OpenGLViewer.cc,v 1.43 2009/01/13 09:47:05 lgarnier Exp $
[873]28// GEANT4 tag $Name: $
[529]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"
[593]48#include "G4AttHolder.hh"
49#include "G4AttCheck.hh"
50#include <sstream>
[529]51
[593]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
[529]82G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene):
83G4VViewer (scene, -1),
[593]84pointSize (0),
85print_colour (true),
86vectored_ps (true),
87fOpenGLSceneHandler(scene),
[529]88background (G4Colour(0.,0.,0.)),
89transparency_enabled (true),
90antialiasing_enabled (false),
91haloing_enabled (false),
[789]92fStartTime(-DBL_MAX),
93fEndTime(DBL_MAX),
[529]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);
[897]114 fWinSize_x = fVP.GetWindowSizeHintX();
115 fWinSize_y = fVP.GetWindowSizeHintY();
[529]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
[593]123 strcpy (print_string, "G4OpenGL.eps");
[529]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
[906]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
[529]167void G4OpenGLViewer::SetView () {
[858]168
[906]169#ifdef G4DEBUG
170 printf("G4OpenGLViewer::SetView ------------\n");
171#endif
[858]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 }
[529]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();
[906]204 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius);
205 const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius);
[529]206 const GLdouble right = fVP.GetFrontHalfHeight (pnear, radius);
207 const GLdouble left = -right;
208 const GLdouble bottom = left;
209 const GLdouble top = right;
210
[906]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
[529]219 glMatrixMode (GL_PROJECTION); // set up Frustum.
220 glLoadIdentity();
221
[906]222 const G4Vector3D scaleFactor = fVP.GetScaleFactor();
223 glScaled(scaleFactor.x(),scaleFactor.y(),scaleFactor.z());
[529]224
225 if (fVP.GetFieldHalfAngle() == 0.) {
226 glOrtho (left, right, bottom, top, pnear, pfar);
[906]227#ifdef G4DEBUG
228 printf("G4OpenGLViewer::SetView ------------rescale\n");
229#endif
[529]230 }
231 else {
232 glFrustum (left, right, bottom, top, pnear, pfar);
[906]233#ifdef G4DEBUG
234 printf("G4OpenGLViewer::SetView ------------Frustum\n");
235#endif
[529]236 }
237
[906]238
[529]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.
[906]255
[529]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
[593]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;
[754]415 GLfloat* feedback_buffer = new GLfloat[size];
[593]416 glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
417 glRenderMode (GL_FEEDBACK);
418
419 DrawView();
[754]420
421 GLint returned;
[593]422 returned = glRenderMode (GL_RENDER);
423
[754]424 FILE* file;
[593]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
[712]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
[593]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
[798]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
[847]968
[801]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
[798]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
[529]1009#endif
Note: See TracBrowser for help on using the repository browser.