source: trunk/geant4/visualization/OpenGL/src/G4OpenGLXViewer.cc @ 529

Last change on this file since 529 was 529, checked in by garnier, 17 years ago

r658@mac-90108: laurentgarnier | 2007-06-25 12:02:16 +0200
import de visualisation

  • Property svn:mime-type set to text/cpp
File size: 31.0 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: G4OpenGLXViewer.cc,v 1.34 2006/11/01 11:22:26 allison Exp $
28// GEANT4 tag $Name: geant4-08-02-patch-01 $
29//
30//
31// Andrew Walkden  7th February 1997
32// G4OpenGLXViewer : Class to provide XWindows specific
33//                 functionality for OpenGL in GEANT4
34
35#ifdef G4VIS_BUILD_OPENGLX_DRIVER
36
37#include "G4OpenGLXViewer.hh"
38
39#include "G4OpenGLFontBaseStore.hh"
40
41#include <sstream>
42
43#include "G4VisExtent.hh"
44#include "G4LogicalVolume.hh"
45#include "G4VSolid.hh"
46#include "G4Point3D.hh"
47#include "G4Normal3D.hh"
48
49#include <X11/Xatom.h>
50#include <X11/Xutil.h>
51
52#include <assert.h>
53
54int G4OpenGLXViewer::snglBuf_RGBA[12] =
55{ GLX_RGBA,
56  GLX_RED_SIZE, 1,
57  GLX_GREEN_SIZE, 1,
58  GLX_BLUE_SIZE, 1,
59  GLX_DEPTH_SIZE, 1,
60  GLX_STENCIL_SIZE, 1,
61  None };
62
63int G4OpenGLXViewer::dblBuf_RGBA[13] =
64{ GLX_RGBA,
65  GLX_RED_SIZE, 1,
66  GLX_GREEN_SIZE, 1,
67  GLX_BLUE_SIZE, 1,
68  GLX_DOUBLEBUFFER,
69  GLX_DEPTH_SIZE, 1,
70  GLX_STENCIL_SIZE, 1,
71  None };
72
73#define NewString(str) \
74 ((str) != NULL ? (strcpy((char*)malloc((unsigned)strlen(str) + 1), str)) : (char*)NULL)
75
76#define USE_DEFAULT_COLORMAP 1
77#define USE_STANDARD_COLORMAP 0
78
79static const char* gouraudtriangleEPS[] =
80{
81  "/bd{bind def}bind def /triangle { aload pop   setrgbcolor  aload pop 5 3",
82  "roll 4 2 roll 3 2 roll exch moveto lineto lineto closepath fill } bd",
83  "/computediff1 { 2 copy sub abs threshold ge {pop pop pop true} { exch 2",
84  "index sub abs threshold ge { pop pop true} { sub abs threshold ge } ifelse",
85  "} ifelse } bd /computediff3 { 3 copy 0 get 3 1 roll 0 get 3 1 roll 0 get",
86  "computediff1 {true} { 3 copy 1 get 3 1 roll 1 get 3 1 roll 1 get",
87  "computediff1 {true} { 3 copy 2 get 3 1 roll  2 get 3 1 roll 2 get",
88  "computediff1 } ifelse } ifelse } bd /middlecolor { aload pop 4 -1 roll",
89  "aload pop 4 -1 roll add 2 div 5 1 roll 3 -1 roll add 2 div 3 1 roll add 2",
90  "div 3 1 roll exch 3 array astore } bd /gouraudtriangle { computediff3 { 4",
91  "-1 roll aload 7 1 roll 6 -1 roll pop 3 -1 roll pop add 2 div 3 1 roll add",
92  "2 div exch 3 -1 roll aload 7 1 roll exch pop 4 -1 roll pop add 2 div 3 1",
93  "roll add 2 div exch 3 -1 roll aload 7 1 roll pop 3 -1 roll pop add 2 div 3",
94  "1 roll add 2 div exch 7 3 roll 10 -3 roll dup 3 index middlecolor 4 1 roll",
95  "2 copy middlecolor 4 1 roll 3 copy pop middlecolor 4 1 roll 13 -1 roll",
96  "aload pop 17 index 6 index 15 index 19 index 6 index 17 index 6 array",
97  "astore 10 index 10 index 14 index gouraudtriangle 17 index 5 index 17",
98  "index 19 index 5 index 19 index 6 array astore 10 index 9 index 13 index",
99  "gouraudtriangle 13 index 16 index 5 index 15 index 18 index 5 index 6",
100  "array astore 12 index 12 index 9 index gouraudtriangle 17 index 16 index",
101  "15 index 19 index 18 index 17 index 6 array astore 10 index 12 index 14",
102  "index gouraudtriangle 18 {pop} repeat } { aload pop 5 3 roll aload pop 7 3",
103  "roll aload pop 9 3 roll 4 index 6 index 4 index add add 3 div 10 1 roll 7",
104  "index 5 index 3 index add add 3 div 10 1 roll 6 index 4 index 2 index add",
105  "add 3 div 10 1 roll 9 {pop} repeat 3 array astore triangle } ifelse } bd",
106  NULL
107};
108
109XVisualInfo*  G4OpenGLXViewer::vi_single_buffer = 0;
110XVisualInfo*  G4OpenGLXViewer::vi_double_buffer = 0;
111
112extern "C" {
113  Bool G4OpenGLXViewerWaitForNotify (Display*, XEvent* e, char* arg) {
114    return (e->type == MapNotify) && (e->xmap.window == (Window) arg);
115  }
116}
117
118void G4OpenGLXViewer::SetView () {
119  glXMakeCurrent (dpy, win, cx);
120  G4OpenGLViewer::SetView (); 
121}
122
123void G4OpenGLXViewer::ShowView () {
124  glXWaitGL (); //Wait for effects of all previous OpenGL commands to
125                //be propagated before progressing.
126  glFlush ();
127}
128
129void G4OpenGLXViewer::GetXConnection () {
130// get a connection.
131  dpy = XOpenDisplay (0);
132  if (!dpy) {
133    fViewId = -1;  // This flags an error.
134    G4cerr << "G4OpenGLViewer::G4OpenGLViewer couldn't open display." << G4endl;
135    return;
136  }
137
138// make sure OpenGL is supported and installed properly.
139  if (!glXQueryExtension (dpy, &errorBase, &eventBase)) {
140    fViewId = -1;  // This flags an error.
141    G4cerr << "G4OpenGLViewer::G4OpenGLViewer X Server has no GLX extension."
142         << G4endl;
143    return;
144  }
145
146}
147
148void G4OpenGLXViewer::CreateGLXContext (XVisualInfo* v) {
149
150  vi = v;
151// get window's attributes
152  if (!XGetWindowAttributes(dpy, XRootWindow (dpy, vi -> screen), &xwa)) {
153    fViewId = -1;  // This flags an error.
154    G4cerr << "G4OpenGLViewer::G4OpenGLViewer couldn't return window attributes"
155         << G4endl;
156    return;
157  }
158 
159// create a GLX context
160  cx = glXCreateContext (dpy, vi, 0, true);
161  if (!cx) {
162    fViewId = -1;  // This flags an error.
163    G4cerr << "G4OpenGLViewer::G4OpenGLViewer couldn't create context."
164         << G4endl;
165    return;
166  }
167
168// New stab at getting a colormap
169
170  Status status;
171  XStandardColormap *standardCmaps = XAllocStandardColormap ();
172  int i, numCmaps;
173
174  status = XmuLookupStandardColormap (dpy,
175                                      vi -> screen,
176                                      vi -> visualid,
177                                      vi -> depth,
178                                      XA_RGB_DEFAULT_MAP,
179                                      False,
180                                      True);
181 
182  if (status == 1) {
183    status = XGetRGBColormaps (dpy,
184                               XRootWindow (dpy, vi -> screen),
185                               &standardCmaps,
186                               &numCmaps,
187                               XA_RGB_DEFAULT_MAP);
188    if (status == 1)
189      for (i = 0; i < numCmaps; i++)
190        if (standardCmaps[i].visualid == vi -> visualid) {
191          cmap = standardCmaps[i].colormap;
192          XFree (standardCmaps);
193        }
194    G4cout << "Got standard cmap" << G4endl;
195  } else {
196    cmap = XCreateColormap (dpy,
197                            XRootWindow(dpy, vi -> screen),
198                            vi -> visual,
199                            AllocNone);
200    G4cout << "Created own cmap" << G4endl;
201  }
202
203  if (!cmap) {
204    fViewId = -1;  // This flags an error.
205    G4cerr << "G4OpenGLViewer::G4OpenGLViewer failed to allocate a Colormap."
206         << G4endl;
207    return;
208  }
209
210}
211 
212void G4OpenGLXViewer::CreateMainWindow () {
213 
214// create a window
215  swa.colormap = cmap;
216  swa.border_pixel = 0;
217  swa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask;
218  swa.backing_store = WhenMapped;
219
220  // Window size and position...
221  unsigned int width, height;
222  x_origin = 0;
223  y_origin = 0;
224  size_hints = XAllocSizeHints();
225  const G4String& XGeometryString = fVP.GetXGeometryString();
226  int screen_num = DefaultScreen(dpy);
227  if (!XGeometryString.empty()) {
228    G4int geometryResultMask = XParseGeometry
229      ((char*)XGeometryString.c_str(),
230       &x_origin, &y_origin, &width, &height);
231    if (geometryResultMask & (WidthValue | HeightValue)) {
232      if (geometryResultMask & XValue) {
233        if (geometryResultMask & XNegative) {
234          x_origin = DisplayWidth(dpy, screen_num) + x_origin - width;
235        }
236        size_hints->flags |= PPosition;
237        size_hints->x = x_origin;
238      }
239      if (geometryResultMask & YValue) {
240        if (geometryResultMask & YNegative) {
241          y_origin = DisplayHeight(dpy, screen_num) + y_origin - height;
242        }
243        size_hints->flags |= PPosition;
244        size_hints->y = y_origin;
245      }
246    } else {
247      G4cout << "ERROR: Geometry string \""
248             << XGeometryString
249             << "\" invalid.  Using \"600x600\"."
250             << G4endl;
251      width = 600;
252      height = 600;
253    }
254  }
255  size_hints->width = width;
256  size_hints->height = height;
257  size_hints->flags |= PSize;
258
259  //  G4int                             WinSize_x;
260  //  G4int                             WinSize_y;
261  WinSize_x = width;
262  WinSize_y = height;
263
264  G4cout << "Window name: " << fName << G4endl;
265  strncpy (charViewName, fName, 100);
266  char *window_name = charViewName;
267  char *icon_name = charViewName;
268  //char tmpatom[] = "XA_WM_NORMAL_HINTS";
269  wm_hints = XAllocWMHints();
270  class_hints = XAllocClassHint();
271
272  XStringListToTextProperty (&window_name, 1, &windowName);
273  XStringListToTextProperty (&icon_name, 1, &iconName);
274
275  wm_hints -> initial_state = NormalState;
276  wm_hints -> input = True;
277  wm_hints -> icon_pixmap = icon_pixmap;
278  wm_hints -> flags = StateHint | IconPixmapHint | InputHint;
279
280  class_hints -> res_name  = NewString("G4OpenGL");
281  class_hints -> res_class = NewString("G4OpenGL");
282
283  win = XCreateWindow (dpy, XRootWindow (dpy, vi -> screen), x_origin,
284                       y_origin, WinSize_x, WinSize_y, 0, vi -> depth,
285                       InputOutput, vi -> visual, 
286                       CWBorderPixel | CWColormap |
287                       CWEventMask | CWBackingStore,
288                       &swa);
289 
290  XSetWMProperties (dpy, win, &windowName, &iconName, 0, 0,
291                    size_hints, wm_hints, class_hints);
292 
293// request X to Draw window on screen.
294  XMapWindow (dpy, win);
295
296// Wait for window to appear (wait for an "expose" event).
297  XIfEvent (dpy, &event, G4OpenGLXViewerWaitForNotify, (char*) win);
298
299// connect the context to a window
300  glXMakeCurrent (dpy, win, cx);
301
302}
303
304void G4OpenGLXViewer::CreateFontLists () {
305
306  std::map<G4double,G4String> fonts;  // G4VMarker screen size and font name.
307  fonts[10.] = "-adobe-courier-bold-r-normal--10-100-75-75-m-60-iso8859-1";
308  fonts[11.] = "-adobe-courier-bold-r-normal--11-80-100-100-m-60-iso8859-1";
309  fonts[12.] = "-adobe-courier-bold-r-normal--12-120-75-75-m-70-iso8859-1";
310  fonts[13.] = "fixed";
311  fonts[14.] = "-adobe-courier-bold-r-normal--14-100-100-100-m-90-iso8859-1";
312  fonts[17.] = "-adobe-courier-bold-r-normal--17-120-100-100-m-100-iso8859-1";
313  fonts[18.] = "-adobe-courier-bold-r-normal--18-180-75-75-m-110-iso8859-1";
314  fonts[20.] = "-adobe-courier-bold-r-normal--20-140-100-100-m-110-iso8859-1";
315  fonts[24.] = "-adobe-courier-bold-r-normal--24-240-75-75-m-150-iso8859-1";
316  fonts[25.] = "-adobe-courier-bold-r-normal--25-180-100-100-m-150-iso8859-1";
317  fonts[34.] = "-adobe-courier-bold-r-normal--34-240-100-100-m-200-iso8859-1";
318  std::map<G4double,G4String>::const_iterator i;
319  for (i = fonts.begin(); i != fonts.end(); ++i) {
320    XFontStruct* font_info = XLoadQueryFont(dpy, i->second);
321    if (!font_info) {
322      G4cerr <<
323        "G4OpenGLXViewer: XLoadQueryFont failed for font\n  "
324             << i->second
325             << G4endl;
326      continue;
327    }
328    G4int font_base = glGenLists(256);
329    if (!font_base) {
330      G4cerr << "G4OpenGLXViewer: out of display lists for fonts."
331             << G4endl;
332      continue;
333    }
334    G4int first = font_info->min_char_or_byte2;
335    G4int last  = font_info->max_char_or_byte2;
336    glXUseXFont(font_info->fid, first, last-first+1,font_base+first);
337    G4OpenGLFontBaseStore::AddFontBase(this,font_base,i->first,i->second);
338  }
339}
340
341G4OpenGLXViewer::G4OpenGLXViewer (G4OpenGLSceneHandler& scene):
342G4VViewer (scene, -1),
343G4OpenGLViewer (scene),
344print_colour (true),
345vectored_ps (true),
346vi_immediate (0),
347vi_stored (0)
348{
349
350  strcpy (print_string, "G4OpenGL.eps");
351
352  GetXConnection ();
353  if (fViewId < 0) return;
354 
355  // Try for a visual suitable for OpenGLImmediate..
356  // first try for a single buffered RGB window
357  if (!vi_single_buffer) {
358    vi_single_buffer =
359      glXChooseVisual (dpy, XDefaultScreen (dpy), snglBuf_RGBA);
360  }
361  if (!vi_double_buffer) {
362    vi_double_buffer =
363      glXChooseVisual (dpy, XDefaultScreen (dpy), dblBuf_RGBA);
364  }
365
366  if (vi_single_buffer || vi_double_buffer) {
367    if (!vi_double_buffer) {
368      G4cout <<
369        "G4OpenGLXViewer::G4OpenGLXViewer: unable to get a double buffer visual."
370        "\n  Working with a single buffer."
371             << G4endl;
372    }
373  } else {
374    if (!vi_single_buffer) {
375      G4cout <<
376        "G4OpenGLXViewer::G4OpenGLXViewer: unable to get a single buffer visual."
377             << G4endl;
378    }
379    if (!vi_double_buffer) {
380      G4cout <<
381        "G4OpenGLXViewer::G4OpenGLXViewer: unable to get a double buffer visual."
382             << G4endl;
383    }
384  }
385
386  if (vi_single_buffer) {
387    vi_immediate = vi_single_buffer;
388    attributeList = snglBuf_RGBA;
389  }
390 
391  if (!vi_immediate){
392    // next try for a double buffered RGB, but Draw to top buffer
393    if (vi_double_buffer) {
394      vi_immediate = vi_double_buffer;
395      attributeList = dblBuf_RGBA;
396    }
397  }
398
399  // Now try for a visual suitable for OpenGLStored...
400  // Try for a double buffered RGB window
401  if (vi_double_buffer) {
402    vi_stored = vi_double_buffer;
403    attributeList = dblBuf_RGBA;
404  }
405
406  if (!vi_immediate || !vi_stored) {
407    G4cout <<
408    "G4OpenGLXViewer::G4OpenGLXViewer: unable to get required visuals."
409           << G4endl;
410    fViewId = -1;  // This flags an error.
411  }
412
413  //  glClearColor (0., 0., 0., 0.);
414  //  glClearDepth (1.);
415}
416
417G4OpenGLXViewer::~G4OpenGLXViewer () {
418  if (fViewId >= 0) {
419    //Close a window from here
420    glXMakeCurrent (dpy, None, NULL);
421    glXDestroyContext (dpy, cx);
422    if (win) XDestroyWindow (dpy, win); // ...if already deleted in
423    // sub-class G4OpenGLXmViewer.
424    XFlush (dpy);
425  }
426}
427
428void G4OpenGLXViewer::print() {
429 
430  //using namespace std;
431  //cout << "print_col_callback requested with file name: " << print_string << G4endl;
432 
433  if (vectored_ps) {
434    G4int size = 5000000;
435   
436    GLfloat* feedback_buffer;
437    GLint returned;
438    FILE* file;
439   
440    feedback_buffer = new GLfloat[size];
441    glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
442    glRenderMode (GL_FEEDBACK);
443   
444    DrawView();
445    returned = glRenderMode (GL_RENDER);
446   
447    if (print_string) {
448      file = fopen (print_string, "w");
449      if (file) {
450        spewWireframeEPS (file, returned, feedback_buffer, "rendereps");
451      } else {
452        printf("Could not open %s\n", print_string);
453      }
454    } else {
455      printBuffer (returned, feedback_buffer);
456    }
457    //  free (feedback_buffer);
458    delete[] feedback_buffer;
459
460  } else {
461
462    XVisualInfo* pvi;
463    GLXContext pcx = create_GL_print_context(pvi);
464    GLXContext tmp_cx;
465    tmp_cx = cx;
466    cx=pcx;
467   
468    Pixmap pmap = XCreatePixmap (dpy,
469                                 XRootWindow (dpy, pvi->screen),
470                                 WinSize_x, WinSize_y,
471                                 pvi->depth);
472   
473    GLXPixmap glxpmap = glXCreateGLXPixmap (dpy,
474                                            pvi,
475                                            pmap);
476   
477    GLXDrawable tmp_win;
478    tmp_win=win;
479    win=glxpmap;
480   
481    glXMakeCurrent (dpy,
482                    glxpmap,
483                    cx);
484   
485    glViewport (0, 0, WinSize_x, WinSize_y);
486   
487    ClearView ();
488    DrawView ();
489   
490    generateEPS (print_string,
491                 print_colour,
492                 WinSize_x, WinSize_y);
493   
494    win=tmp_win;
495    cx=tmp_cx;
496   
497    glXMakeCurrent (dpy,
498                    glxpmap,
499                    cx);
500   
501  }
502
503}
504
505void G4OpenGLXViewer::print3DcolorVertex(GLint size, GLint * count, GLfloat * buffer)
506{
507  G4int i;
508
509  printf("  ");
510  for (i = 0; i < 7; i++) {
511    printf("%4.2f ", buffer[size - (*count)]);
512    *count = *count - 1;
513  }
514  printf("\n");
515}
516
517void G4OpenGLXViewer::spewWireframeEPS (FILE* file, GLint size, GLfloat* buffer, const char* cr) {
518
519  GLfloat EPS_GOURAUD_THRESHOLD=0.1;
520
521  GLfloat clearColor[4], viewport[4];
522  GLfloat lineWidth;
523  G4int i;
524
525  glGetFloatv (GL_VIEWPORT, viewport);
526  glGetFloatv (GL_COLOR_CLEAR_VALUE, clearColor);
527  glGetFloatv (GL_LINE_WIDTH, &lineWidth);
528  glGetFloatv (GL_POINT_SIZE, &pointSize);
529
530  fputs ("%!PS-Adobe-2.0 EPSF-2.0\n", file);
531  fprintf (file, "%%%%Creator: %s (using OpenGL feedback)\n", cr);
532  fprintf (file, "%%%%BoundingBox: %g %g %g %g\n", viewport[0], viewport[1], viewport[2], viewport[3]);
533  fputs ("%%EndComments\n", file);
534  fputs ("\n", file);
535  fputs ("gsave\n", file);
536  fputs ("\n", file);
537
538  fputs ("% the gouraudtriangle PostScript fragment below is free\n", file);
539  fputs ("% written by Frederic Delhoume (delhoume@ilog.fr)\n", file);
540  fprintf (file, "/threshold %g def\n", EPS_GOURAUD_THRESHOLD);
541  for (i=0; gouraudtriangleEPS[i]; i++) {
542    fprintf (file, "%s\n", gouraudtriangleEPS[i]);
543  }
544
545  fprintf(file, "\n%g setlinewidth\n", lineWidth);
546 
547  fprintf (file, "%g %g %g setrgbcolor\n", clearColor[0], clearColor[1], clearColor[2]);
548  fprintf (file, "%g %g %g %g rectfill\n\n", viewport[0], viewport[1], viewport[2], viewport[3]);
549
550  spewSortedFeedback (file, size, buffer);
551
552  fputs ("grestore\n\n", file);
553  fputs ("showpage\n", file);
554
555  fclose(file);
556}
557
558void G4OpenGLXViewer::printBuffer (GLint size, GLfloat* buffer) {
559
560  GLint count;
561  G4int token, nvertices;
562
563  count=size;
564  while(count) {
565    token=G4int (buffer[size-count]);
566    count--;
567    switch (token) {
568
569    case GL_PASS_THROUGH_TOKEN:
570      printf ("GL_PASS_THROUGH_TOKEN\n");
571      printf ("  %4.2f\n", buffer[size-count]);
572      count--;
573      break;
574
575    case GL_POINT_TOKEN:
576      printf ("GL_POINT_TOKEN\n");
577      print3DcolorVertex (size, &count, buffer);
578      break;
579
580    case GL_LINE_TOKEN:
581      printf ("GL_LINE_TOKEN\n");
582      print3DcolorVertex (size, &count, buffer);
583      print3DcolorVertex (size, &count, buffer);
584      break;
585     
586    case GL_LINE_RESET_TOKEN:
587      printf ("GL_LINE_RESET_TOKEN\n");
588      print3DcolorVertex (size, &count, buffer);
589      print3DcolorVertex (size, &count, buffer);
590      break;
591
592    case GL_POLYGON_TOKEN:
593      printf ("GL_POLYGON_TOKEN\n");
594      nvertices=G4int (buffer[size-count]);
595      count--;
596      for (; nvertices>0; nvertices--) {
597        print3DcolorVertex (size, &count, buffer);
598      }
599    }
600  }
601}
602
603G4float* G4OpenGLXViewer::spewPrimitiveEPS (FILE* file, GLfloat* loc) {
604 
605  G4int token;
606  G4int nvertices, i;
607  GLfloat red, green, blue, intensity;
608  G4int smooth;
609  GLfloat dx, dy, dr, dg, db, absR, absG, absB, colormax;
610  G4int steps;
611  Feedback3Dcolor *vertex;
612  GLfloat xstep(0.), ystep(0.), rstep(0.), gstep(0.), bstep(0.);
613  GLfloat xnext(0.), ynext(0.), rnext(0.), gnext(0.), bnext(0.), distance(0.);
614
615  token=G4int (*loc);
616  loc++;
617  switch (token) {
618  case GL_LINE_RESET_TOKEN:
619  case GL_LINE_TOKEN:
620    vertex=(Feedback3Dcolor*)loc;
621    dr=vertex[1].red - vertex[0].red;
622    dg=vertex[1].green - vertex[0].green;
623    db=vertex[1].blue - vertex[0].blue;
624
625    if (!print_colour) {
626      dr+=(dg+db);
627      dr/=3.0;
628      dg=dr;
629      db=dr;
630    }
631
632    if (dr!=0 || dg!=0 || db!=0) {
633      dx=vertex[1].x - vertex[0].x;
634      dy=vertex[1].y - vertex[0].y;
635      distance=std::sqrt(dx*dx + dy*dy);
636
637      absR=std::fabs(dr);
638      absG=std::fabs(dg);
639      absB=std::fabs(db);
640
641      #define Max(a, b) (((a)>(b))?(a):(b))
642
643      #define EPS_SMOOTH_LINE_FACTOR 0.06
644
645      colormax=Max(absR, Max(absG, absB));
646      steps=Max(1, G4int (colormax*distance*EPS_SMOOTH_LINE_FACTOR));
647     
648      xstep=dx/steps;
649      ystep=dy/steps;
650
651      rstep=dr/steps;
652      gstep=dg/steps;
653      bstep=db/steps;
654
655      xnext=vertex[0].x;
656      ynext=vertex[0].y;
657      rnext=vertex[0].red;
658      gnext=vertex[0].green;
659      bnext=vertex[0].blue;
660
661      if (!print_colour) {
662        rnext+=(gnext+bnext);
663        rnext/=3.0;
664        gnext=rnext;
665        bnext=rnext;
666      }
667
668      xnext -= xstep/2.0;
669      ynext -= ystep/2.0;
670      rnext -= rstep/2.0;
671      gnext -= gstep/2.0;
672      bnext -= bstep/2.0;
673    } else {
674      steps=0;
675    }
676    if (print_colour) {
677      fprintf (file, "%g %g %g setrgbcolor\n",
678               vertex[0].red, vertex[0].green, vertex[0].blue);
679    } else {
680      intensity = (vertex[0].red + vertex[0].green + vertex[0].blue) / 3.0;
681      fprintf (file, "%g %g %g setrgbcolor\n",
682               intensity, intensity, intensity);
683    }     
684    fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
685
686    for (i=0; i<steps; i++) {
687
688      xnext += xstep;
689      ynext += ystep;
690      rnext += rstep;
691      gnext += gstep;
692      bnext += bstep;
693
694      fprintf (file, "%g %g lineto stroke\n", xnext, ynext);
695      fprintf (file, "%g %g %g setrgbcolor\n", rnext, gnext, bnext);
696      fprintf (file, "%g %g moveto\n", xnext, ynext);
697    }
698    fprintf (file, "%g %g lineto stroke\n", vertex[1].x, vertex[1].y);
699
700    loc += 14;
701    break;
702
703  case GL_POLYGON_TOKEN:
704    nvertices = G4int (*loc);
705    loc++;
706    vertex=(Feedback3Dcolor*)loc;
707    if (nvertices>0) {
708      red=vertex[0].red;
709      green=vertex[0].green;
710      blue=vertex[0].blue;
711      smooth=0;
712     
713      if (!print_colour) {
714        red+=(green+blue);
715        red/=3.0;
716        green=red;
717        blue=red;
718      }
719     
720      if (print_colour) {
721        for (i=1; i<nvertices; i++) {
722          if (red!=vertex[i].red || green!=vertex[i].green || blue!=vertex[i].blue) {
723            smooth=1;
724            break;
725          }
726        }
727      } else {
728        for (i=1; i<nvertices; i++) {
729          intensity = vertex[i].red + vertex[i].green + vertex[i].blue;
730          intensity/=3.0;
731          if (red!=intensity) {
732            smooth=1;
733            break;
734          }
735        }
736      }
737
738      if (smooth) {
739        G4int triOffset;
740        for (i=0; i<nvertices-2; i++) {
741          triOffset = i*7;
742          fprintf (file, "[%g %g %g %g %g %g]",
743                   vertex[0].x, vertex[i+1].x, vertex[i+2].x,
744                   vertex[0].y, vertex[i+1].y, vertex[i+2].y);
745          if (print_colour) {
746            fprintf (file, " [%g %g %g] [%g %g %g] [%g %g %g] gouraudtriangle\n",
747                     vertex[0].red, vertex[0].green, vertex[0].blue,
748                     vertex[i+1].red, vertex[i+1].green, vertex[i+1].blue,
749                     vertex[i+2].red, vertex[i+2].green, vertex[i+2].blue);
750          } else {
751
752            intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
753            intensity/=3.0;
754            fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
755
756            intensity = vertex[1].red + vertex[1].green + vertex[1].blue;
757            intensity/=3.0;
758            fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
759
760            intensity = vertex[2].red + vertex[2].green + vertex[2].blue;
761            intensity/=3.0;
762            fprintf (file, " [%g %g %g] gouraudtriangle\n", intensity, intensity, intensity);
763          }
764        }
765      } else {
766        fprintf (file, "newpath\n");
767        fprintf (file, "%g %g %g setrgbcolor\n", red, green, blue);
768        fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
769        for (i=1; i<nvertices; i++) {
770          fprintf (file, "%g %g lineto\n", vertex[i].x, vertex[i].y);
771        }
772        fprintf (file, "closepath fill\n\n");
773      }
774    }
775    loc += nvertices*7;
776    break;
777
778  case GL_POINT_TOKEN:
779    vertex=(Feedback3Dcolor*)loc;
780    if (print_colour) {
781      fprintf (file, "%g %g %g setrgbcolor\n", vertex[0].red, vertex[0].green, vertex[0].blue);
782    } else {
783      intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
784      intensity/=3.0;
785      fprintf (file, "%g %g %g setrgbcolor\n", intensity, intensity, intensity);
786    }     
787    fprintf(file, "%g %g %g 0 360 arc fill\n\n", vertex[0].x, vertex[0].y, pointSize / 2.0);
788    loc += 7;           /* Each vertex element in the feedback
789                           buffer is 7 GLfloats. */
790    break;
791  default:
792    /* XXX Left as an excersie to the reader. */
793    static G4bool spewPrimitiveEPSWarned = false;
794    if (!spewPrimitiveEPSWarned) {
795      std::ostringstream oss;
796      oss <<
797        "Incomplete implementation.  Unexpected token (" << token << ")."
798        "\n  (Seems to be caused by text.)";
799      G4Exception("G4OpenGLXViewer::spewPrimitiveEPS",
800                  "Unexpected token",
801                  JustWarning,
802                  oss.str().c_str());
803      spewPrimitiveEPSWarned = true;
804    }
805  }
806  return loc;
807}
808
809typedef struct G4OpenGLXViewerDepthIndex {
810  GLfloat *ptr;
811  GLfloat depth;
812} DepthIndex;
813
814extern "C" {
815  int G4OpenGLXViewercompare(const void *a, const void *b)
816  {
817    const DepthIndex *p1 = (DepthIndex *) a;
818    const DepthIndex *p2 = (DepthIndex *) b;
819    GLfloat diff = p2->depth - p1->depth;
820   
821    if (diff > 0.0) {
822      return 1;
823    } else if (diff < 0.0) {
824      return -1;
825    } else {
826      return 0;
827    }
828  }
829}
830
831void G4OpenGLXViewer::spewSortedFeedback(FILE * file, GLint size, GLfloat * buffer)
832{
833  int token;
834  GLfloat *loc, *end;
835  Feedback3Dcolor *vertex;
836  GLfloat depthSum;
837  int nprimitives, item;
838  DepthIndex *prims;
839  int nvertices, i;
840
841  end = buffer + size;
842
843  /* Count how many primitives there are. */
844  nprimitives = 0;
845  loc = buffer;
846  while (loc < end) {
847    token = int (*loc);
848    loc++;
849    switch (token) {
850    case GL_LINE_TOKEN:
851    case GL_LINE_RESET_TOKEN:
852      loc += 14;
853      nprimitives++;
854      break;
855    case GL_POLYGON_TOKEN:
856      nvertices = int (*loc);
857      loc++;
858      loc += (7 * nvertices);
859      nprimitives++;
860      break;
861    case GL_POINT_TOKEN:
862      loc += 7;
863      nprimitives++;
864      break;
865    default:
866      /* XXX Left as an excersie to the reader. */
867      static G4bool spewSortedFeedbackWarned = false;
868      if (!spewSortedFeedbackWarned) {
869        std::ostringstream oss;
870        oss <<
871          "Incomplete implementation.  Unexpected token (" << token << ")."
872          "\n  (Seems to be caused by text.)";
873        G4Exception("G4OpenGLXViewer::spewSortedFeedback",
874                    "Unexpected token",
875                    JustWarning,
876                    oss.str().c_str());
877        spewSortedFeedbackWarned = true;
878      }
879      nprimitives++;
880    }
881  }
882
883  /* Allocate an array of pointers that will point back at
884     primitives in the feedback buffer.  There will be one
885     entry per primitive.  This array is also where we keep the
886     primitive's average depth.  There is one entry per
887     primitive  in the feedback buffer. */
888  prims = (DepthIndex *) malloc(sizeof(DepthIndex) * nprimitives);
889
890  item = 0;
891  loc = buffer;
892  while (loc < end) {
893    prims[item].ptr = loc;  /* Save this primitive's location. */
894    token = int (*loc);
895    loc++;
896    switch (token) {
897    case GL_LINE_TOKEN:
898    case GL_LINE_RESET_TOKEN:
899      vertex = (Feedback3Dcolor *) loc;
900      depthSum = vertex[0].z + vertex[1].z;
901      prims[item].depth = depthSum / 2.0;
902      loc += 14;
903      break;
904    case GL_POLYGON_TOKEN:
905      nvertices = int (*loc);
906      loc++;
907      vertex = (Feedback3Dcolor *) loc;
908      depthSum = vertex[0].z;
909      for (i = 1; i < nvertices; i++) {
910        depthSum += vertex[i].z;
911      }
912      prims[item].depth = depthSum / nvertices;
913      loc += (7 * nvertices);
914      break;
915    case GL_POINT_TOKEN:
916      vertex = (Feedback3Dcolor *) loc;
917      prims[item].depth = vertex[0].z;
918      loc += 7;
919      break;
920    default:
921      /* XXX Left as an excersie to the reader. */
922      assert(1);
923    }
924    item++;
925  }
926  assert(item == nprimitives);
927
928  /* Sort the primitives back to front. */
929  qsort(prims, nprimitives, sizeof(DepthIndex), G4OpenGLXViewercompare);
930
931  /* Understand that sorting by a primitives average depth
932     doesn't allow us to disambiguate some cases like self
933     intersecting polygons.  Handling these cases would require
934     breaking up the primitives.  That's too involved for this
935     example.  Sorting by depth is good enough for lots of
936     applications. */
937
938  /* Emit the Encapsulated PostScript for the primitives in
939     back to front order. */
940  for (item = 0; item < nprimitives; item++) {
941    (void) spewPrimitiveEPS(file, prims[item].ptr);
942  }
943
944  free(prims);
945}
946
947GLXContext G4OpenGLXViewer::create_GL_print_context(XVisualInfo*& pvi) {
948 
949  pvi = glXChooseVisual (dpy,
950                         XDefaultScreen (dpy),
951                         snglBuf_RGBA);
952
953  if (!pvi) {
954    pvi = glXChooseVisual (dpy,
955                           XDefaultScreen (dpy),
956                           dblBuf_RGBA);
957  }
958
959  return glXCreateContext (dpy,
960                           pvi,
961                           NULL,
962                           False);
963}
964
965int G4OpenGLXViewer::generateEPS (char* filnam,
966                                int inColour,
967                                unsigned int width,
968                                unsigned int height) {
969
970  FILE* fp;
971  GLubyte* pixels;
972  GLubyte* curpix;
973  int components, pos, i;
974
975  pixels = grabPixels (inColour, width, height);
976
977  if (pixels == NULL)
978    return 1;
979  if (inColour) {
980    components = 3;
981  } else {
982    components = 1;
983  }
984 
985  fp = fopen (filnam, "w");
986  if (fp == NULL) {
987    return 2;
988  }
989 
990  fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
991  fprintf (fp, "%%%%Title: %s\n", filnam);
992  fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n");
993  fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
994  fprintf (fp, "%%%%EndComments\n");
995  fprintf (fp, "gsave\n");
996  fprintf (fp, "/bwproc {\n");
997  fprintf (fp, "    rgbproc\n");
998  fprintf (fp, "    dup length 3 idiv string 0 3 0 \n");
999  fprintf (fp, "    5 -1 roll {\n");
1000  fprintf (fp, "    add 2 1 roll 1 sub dup 0 eq\n");
1001  fprintf (fp, "    { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n");
1002  fprintf (fp, "       3 1 roll 5 -1 roll } put 1 add 3 0 \n");
1003  fprintf (fp, "    { 2 1 roll } ifelse\n");
1004  fprintf (fp, "    }forall\n");
1005  fprintf (fp, "    pop pop pop\n");
1006  fprintf (fp, "} def\n");
1007  fprintf (fp, "systemdict /colorimage known not {\n");
1008  fprintf (fp, "   /colorimage {\n");
1009  fprintf (fp, "       pop\n");
1010  fprintf (fp, "       pop\n");
1011  fprintf (fp, "       /rgbproc exch def\n");
1012  fprintf (fp, "       { bwproc } image\n");
1013  fprintf (fp, "   }  def\n");
1014  fprintf (fp, "} if\n");
1015  fprintf (fp, "/picstr %d string def\n", width * components);
1016  fprintf (fp, "%d %d scale\n", width, height);
1017  fprintf (fp, "%d %d %d\n", width, height, 8);
1018  fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height);
1019  fprintf (fp, "{currentfile picstr readhexstring pop}\n");
1020  fprintf (fp, "false %d\n", components);
1021  fprintf (fp, "colorimage\n");
1022 
1023  curpix = (GLubyte*) pixels;
1024  pos = 0;
1025  for (i = width*height*components; i>0; i--) {
1026    fprintf (fp, "%02hx ", *(curpix++));
1027    if (++pos >= 32) {
1028      fprintf (fp, "\n");
1029      pos = 0;
1030    }
1031  }
1032  if (pos)
1033    fprintf (fp, "\n");
1034
1035  fprintf (fp, "grestore\n");
1036  fprintf (fp, "showpage\n");
1037  delete pixels;
1038  fclose (fp);
1039  return 0;
1040}
1041
1042GLubyte* G4OpenGLXViewer::grabPixels (int inColor, unsigned int width, unsigned int height) {
1043 
1044  GLubyte* buffer;
1045  GLint swapbytes, lsbfirst, rowlength;
1046  GLint skiprows, skippixels, alignment;
1047  GLenum format;
1048  int size;
1049
1050  if (inColor) {
1051    format = GL_RGB;
1052    size = width*height*3;
1053  } else {
1054    format = GL_LUMINANCE;
1055    size = width*height*1;
1056  }
1057
1058  buffer = new GLubyte[size];
1059  if (buffer == NULL)
1060    return NULL;
1061
1062  glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes);
1063  glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst);
1064  glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength);
1065
1066  glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows);
1067  glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels);
1068  glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
1069
1070  glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
1071  glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
1072  glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
1073
1074  glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
1075  glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
1076  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
1077
1078  glReadPixels (0, 0, (GLsizei)width, (GLsizei)height, format, GL_UNSIGNED_BYTE, (GLvoid*) buffer);
1079
1080  glPixelStorei (GL_UNPACK_SWAP_BYTES, swapbytes);
1081  glPixelStorei (GL_UNPACK_LSB_FIRST, lsbfirst);
1082  glPixelStorei (GL_UNPACK_ROW_LENGTH, rowlength);
1083 
1084  glPixelStorei (GL_UNPACK_SKIP_ROWS, skiprows);
1085  glPixelStorei (GL_UNPACK_SKIP_PIXELS, skippixels);
1086  glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
1087 
1088  return buffer;
1089}
1090
1091#endif
Note: See TracBrowser for help on using the repository browser.