1011 lines
28 KiB
C++
1011 lines
28 KiB
C++
//
|
|
// ********************************************************************
|
|
// * DISCLAIMER *
|
|
// * *
|
|
// * The following disclaimer summarizes all the specific disclaimers *
|
|
// * of contributors to this software. The specific disclaimers,which *
|
|
// * govern, are listed with their locations in: *
|
|
// * http://cern.ch/geant4/license *
|
|
// * *
|
|
// * Neither the authors of this software system, nor their employing *
|
|
// * institutes,nor the agencies providing financial support for this *
|
|
// * work make any representation or warranty, express or implied, *
|
|
// * regarding this software system or assume any liability for its *
|
|
// * use. *
|
|
// * *
|
|
// * This code implementation is the intellectual property of the *
|
|
// * GEANT4 collaboration. *
|
|
// * By copying, distributing or modifying the Program (or any work *
|
|
// * based on the Program) you indicate your acceptance of this *
|
|
// * statement, and all its terms. *
|
|
// ********************************************************************
|
|
//
|
|
//
|
|
// $Id: G4OpenGLXViewer.cc,v 1.18 2002/11/11 18:12:03 johna Exp $
|
|
// GEANT4 tag $Name: geant4-05-02 $
|
|
//
|
|
//
|
|
// Andrew Walkden 7th February 1997
|
|
// G4OpenGLXViewer : Class to provide XWindows specific
|
|
// functionality for OpenGL in GEANT4
|
|
|
|
#ifdef G4VIS_BUILD_OPENGLX_DRIVER
|
|
|
|
#include "G4OpenGLXViewer.hh"
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glx.h>
|
|
#include <GL/glu.h>
|
|
|
|
#include "G4ios.hh"
|
|
|
|
#include "G4VisExtent.hh"
|
|
#include "G4LogicalVolume.hh"
|
|
#include "G4VSolid.hh"
|
|
#include "G4Point3D.hh"
|
|
#include "G4Normal3D.hh"
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <assert.h>
|
|
|
|
int G4OpenGLXViewer::snglBuf_RGBA[10] =
|
|
{ GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
|
|
GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 1, None };
|
|
|
|
int G4OpenGLXViewer::dblBuf_RGBA[11] =
|
|
{ GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
|
|
GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None };
|
|
|
|
#define NewString(str) \
|
|
((str) != NULL ? (strcpy((char*)malloc((unsigned)strlen(str) + 1), str)) : (char*)NULL)
|
|
|
|
#define USE_DEFAULT_COLORMAP 1
|
|
#define USE_STANDARD_COLORMAP 0
|
|
|
|
static const char* gouraudtriangleEPS[] =
|
|
{
|
|
"/bd{bind def}bind def /triangle { aload pop setrgbcolor aload pop 5 3",
|
|
"roll 4 2 roll 3 2 roll exch moveto lineto lineto closepath fill } bd",
|
|
"/computediff1 { 2 copy sub abs threshold ge {pop pop pop true} { exch 2",
|
|
"index sub abs threshold ge { pop pop true} { sub abs threshold ge } ifelse",
|
|
"} ifelse } bd /computediff3 { 3 copy 0 get 3 1 roll 0 get 3 1 roll 0 get",
|
|
"computediff1 {true} { 3 copy 1 get 3 1 roll 1 get 3 1 roll 1 get",
|
|
"computediff1 {true} { 3 copy 2 get 3 1 roll 2 get 3 1 roll 2 get",
|
|
"computediff1 } ifelse } ifelse } bd /middlecolor { aload pop 4 -1 roll",
|
|
"aload pop 4 -1 roll add 2 div 5 1 roll 3 -1 roll add 2 div 3 1 roll add 2",
|
|
"div 3 1 roll exch 3 array astore } bd /gouraudtriangle { computediff3 { 4",
|
|
"-1 roll aload 7 1 roll 6 -1 roll pop 3 -1 roll pop add 2 div 3 1 roll add",
|
|
"2 div exch 3 -1 roll aload 7 1 roll exch pop 4 -1 roll pop add 2 div 3 1",
|
|
"roll add 2 div exch 3 -1 roll aload 7 1 roll pop 3 -1 roll pop add 2 div 3",
|
|
"1 roll add 2 div exch 7 3 roll 10 -3 roll dup 3 index middlecolor 4 1 roll",
|
|
"2 copy middlecolor 4 1 roll 3 copy pop middlecolor 4 1 roll 13 -1 roll",
|
|
"aload pop 17 index 6 index 15 index 19 index 6 index 17 index 6 array",
|
|
"astore 10 index 10 index 14 index gouraudtriangle 17 index 5 index 17",
|
|
"index 19 index 5 index 19 index 6 array astore 10 index 9 index 13 index",
|
|
"gouraudtriangle 13 index 16 index 5 index 15 index 18 index 5 index 6",
|
|
"array astore 12 index 12 index 9 index gouraudtriangle 17 index 16 index",
|
|
"15 index 19 index 18 index 17 index 6 array astore 10 index 12 index 14",
|
|
"index gouraudtriangle 18 {pop} repeat } { aload pop 5 3 roll aload pop 7 3",
|
|
"roll aload pop 9 3 roll 4 index 6 index 4 index add add 3 div 10 1 roll 7",
|
|
"index 5 index 3 index add add 3 div 10 1 roll 6 index 4 index 2 index add",
|
|
"add 3 div 10 1 roll 9 {pop} repeat 3 array astore triangle } ifelse } bd",
|
|
NULL
|
|
};
|
|
|
|
XVisualInfo* G4OpenGLXViewer::vi_single_buffer = 0;
|
|
XVisualInfo* G4OpenGLXViewer::vi_double_buffer = 0;
|
|
|
|
extern "C" {
|
|
Bool G4OpenGLXViewerWaitForNotify (Display*, XEvent* e, char* arg) {
|
|
return (e->type == MapNotify) && (e->xmap.window == (Window) arg);
|
|
}
|
|
}
|
|
|
|
void G4OpenGLXViewer::SetView () {
|
|
glXMakeCurrent (dpy, win, cx);
|
|
G4OpenGLViewer::SetView ();
|
|
}
|
|
|
|
void G4OpenGLXViewer::ShowView () {
|
|
glXWaitGL (); //Wait for effects of all previous OpenGL commands to
|
|
//be propogated before progressing.
|
|
glFlush ();
|
|
}
|
|
|
|
void G4OpenGLXViewer::FinishView () {
|
|
glXWaitGL (); //Wait for effects of all previous OpenGL commands to
|
|
//be propogated before progressing.
|
|
if (doublebuffer == true) {
|
|
glXSwapBuffers (dpy, win);
|
|
}
|
|
else glFlush ();
|
|
}
|
|
|
|
void G4OpenGLXViewer::GetXConnection () {
|
|
// get a connection.
|
|
dpy = XOpenDisplay (0);
|
|
if (!dpy) {
|
|
fViewId = -1; // This flags an error.
|
|
G4cerr << "G4OpenGLViewer::G4OpenGLViewer couldn't open display." << G4endl;
|
|
return;
|
|
}
|
|
|
|
// make sure OpenGL is supported and installed properly.
|
|
if (!glXQueryExtension (dpy, &errorBase, &eventBase)) {
|
|
fViewId = -1; // This flags an error.
|
|
G4cerr << "G4OpenGLViewer::G4OpenGLViewer X Server has no GLX extension."
|
|
<< G4endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void G4OpenGLXViewer::CreateGLXContext (XVisualInfo* v) {
|
|
|
|
vi = v;
|
|
// get window's attributes
|
|
if (!XGetWindowAttributes(dpy, XRootWindow (dpy, vi -> screen), &xwa)) {
|
|
fViewId = -1; // This flags an error.
|
|
G4cerr << "G4OpenGLViewer::G4OpenGLViewer couldn't return window attributes"
|
|
<< G4endl;
|
|
return;
|
|
}
|
|
|
|
// create a GLX context
|
|
cx = glXCreateContext (dpy, vi, 0, true);
|
|
if (!cx) {
|
|
fViewId = -1; // This flags an error.
|
|
G4cerr << "G4OpenGLViewer::G4OpenGLViewer couldn't create context."
|
|
<< G4endl;
|
|
return;
|
|
}
|
|
|
|
// New stab at getting a colormap
|
|
|
|
Status status;
|
|
XStandardColormap *standardCmaps = XAllocStandardColormap ();
|
|
int i, numCmaps;
|
|
|
|
status = XmuLookupStandardColormap (dpy,
|
|
vi -> screen,
|
|
vi -> visualid,
|
|
vi -> depth,
|
|
XA_RGB_DEFAULT_MAP,
|
|
False,
|
|
True);
|
|
|
|
if (status == 1) {
|
|
status = XGetRGBColormaps (dpy,
|
|
XRootWindow (dpy, vi -> screen),
|
|
&standardCmaps,
|
|
&numCmaps,
|
|
XA_RGB_DEFAULT_MAP);
|
|
if (status == 1)
|
|
for (i = 0; i < numCmaps; i++)
|
|
if (standardCmaps[i].visualid == vi -> visualid) {
|
|
cmap = standardCmaps[i].colormap;
|
|
XFree (standardCmaps);
|
|
}
|
|
G4cout << "Got standard cmap" << G4endl;
|
|
} else {
|
|
cmap = XCreateColormap (dpy,
|
|
XRootWindow(dpy, vi -> screen),
|
|
vi -> visual,
|
|
AllocNone);
|
|
G4cout << "Created own cmap" << G4endl;
|
|
}
|
|
|
|
if (!cmap) {
|
|
fViewId = -1; // This flags an error.
|
|
G4cerr << "G4OpenGLViewer::G4OpenGLViewer failed to allocate a Colormap."
|
|
<< G4endl;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void G4OpenGLXViewer::CreateMainWindow () {
|
|
|
|
// create a window
|
|
swa.colormap = cmap;
|
|
swa.border_pixel = 0;
|
|
swa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask;
|
|
swa.backing_store = WhenMapped;
|
|
|
|
// G4int WinSize_x;
|
|
// G4int WinSize_y;
|
|
if (xwa.width > xwa.height) {
|
|
WinSize_x = (xwa.height)/2;
|
|
WinSize_y = (xwa.height)/2;
|
|
}
|
|
else {
|
|
WinSize_x = (xwa.width)/2;
|
|
WinSize_y = (xwa.width)/2;
|
|
}
|
|
if (WinSize_x < fVP.GetWindowSizeHintX ())
|
|
WinSize_x = fVP.GetWindowSizeHintX ();
|
|
if (WinSize_y < fVP.GetWindowSizeHintY ())
|
|
WinSize_y = fVP.GetWindowSizeHintY ();
|
|
x_origin = xwa.x;
|
|
y_origin = xwa.y;
|
|
G4cout << "Window name: " << fName << G4endl;
|
|
strncpy (charViewName, fName, 100);
|
|
char *window_name = charViewName;
|
|
char *icon_name = charViewName;
|
|
//char tmpatom[] = "XA_WM_NORMAL_HINTS";
|
|
size_hints = XAllocSizeHints();
|
|
wm_hints = XAllocWMHints();
|
|
class_hints = XAllocClassHint();
|
|
|
|
size_hints -> flags = PPosition | PSize | PMinSize;
|
|
size_hints -> min_width = 300;
|
|
size_hints -> min_height = 200;
|
|
|
|
XStringListToTextProperty (&window_name, 1, &windowName);
|
|
XStringListToTextProperty (&icon_name, 1, &iconName);
|
|
|
|
wm_hints -> initial_state = NormalState;
|
|
wm_hints -> input = True;
|
|
wm_hints -> icon_pixmap = icon_pixmap;
|
|
wm_hints -> flags = StateHint | IconPixmapHint | InputHint;
|
|
|
|
class_hints -> res_name = NewString("G4OpenGL");
|
|
class_hints -> res_class = NewString("G4OpenGL");
|
|
|
|
win = XCreateWindow (dpy, XRootWindow (dpy, vi -> screen), x_origin,
|
|
y_origin, WinSize_x, WinSize_y, 0, vi -> depth,
|
|
InputOutput, vi -> visual,
|
|
CWBorderPixel | CWColormap |
|
|
CWEventMask | CWBackingStore,
|
|
&swa);
|
|
|
|
XSetWMProperties (dpy, win, &windowName, &iconName, 0, 0,
|
|
size_hints, wm_hints, class_hints);
|
|
|
|
// request X to Draw window on screen.
|
|
XMapWindow (dpy, win);
|
|
|
|
// Wait for window to appear (wait for an "expose" event).
|
|
XIfEvent (dpy, &event, G4OpenGLXViewerWaitForNotify, (char*) win);
|
|
|
|
// connect the context to a window
|
|
glXMakeCurrent (dpy, win, cx);
|
|
}
|
|
|
|
G4OpenGLXViewer::G4OpenGLXViewer (G4OpenGLSceneHandler& scene):
|
|
G4VViewer (scene, -1),
|
|
G4OpenGLViewer (scene),
|
|
print_colour (true),
|
|
vectored_ps (true),
|
|
vi_immediate (0),
|
|
vi_stored (0)
|
|
{
|
|
|
|
strcpy (print_string, "G4OpenGL.eps");
|
|
|
|
GetXConnection ();
|
|
if (fViewId < 0) return;
|
|
|
|
// Try for a visual suitable for OpenGLImmediate..
|
|
// first try for a single buffered RGB window
|
|
if (!vi_single_buffer) {
|
|
vi_single_buffer =
|
|
glXChooseVisual (dpy, XDefaultScreen (dpy), snglBuf_RGBA);
|
|
}
|
|
if (!vi_single_buffer) {
|
|
G4cout <<
|
|
"G4OpenGLXViewer::G4OpenGLXViewer: unable to get a single buffer visual."
|
|
<< G4endl;
|
|
}
|
|
|
|
if (!vi_double_buffer) {
|
|
vi_double_buffer =
|
|
glXChooseVisual (dpy, XDefaultScreen (dpy), dblBuf_RGBA);
|
|
}
|
|
if (!vi_double_buffer) {
|
|
G4cout <<
|
|
"G4OpenGLXViewer::G4OpenGLXViewer: unable to get a double buffer visual."
|
|
<< G4endl;
|
|
}
|
|
|
|
if (vi_single_buffer) {
|
|
vi_immediate = vi_single_buffer;
|
|
attributeList = snglBuf_RGBA;
|
|
doublebuffer = false;
|
|
}
|
|
|
|
if (!vi_immediate){
|
|
// next try for a double buffered RGB, but Draw to top buffer
|
|
if (vi_double_buffer) {
|
|
vi_immediate = vi_double_buffer;
|
|
attributeList = dblBuf_RGBA;
|
|
doublebuffer = true;
|
|
}
|
|
}
|
|
|
|
// Now try for a visual suitable for OpenGLStored...
|
|
// Try for a double buffered RGB window
|
|
if (vi_double_buffer) {
|
|
vi_stored = vi_double_buffer;
|
|
attributeList = dblBuf_RGBA;
|
|
doublebuffer = true;
|
|
}
|
|
|
|
if (!vi_immediate || !vi_stored) {
|
|
G4cout <<
|
|
"G4OpenGLXViewer::G4OpenGLXViewer: unable to get required visuals."
|
|
<< G4endl;
|
|
fViewId = -1; // This flags an error.
|
|
}
|
|
|
|
// glClearColor (0., 0., 0., 0.);
|
|
// glClearDepth (1.);
|
|
|
|
}
|
|
|
|
G4OpenGLXViewer::~G4OpenGLXViewer () {
|
|
if (fViewId >= 0) {
|
|
//Close a window from here
|
|
glXDestroyContext (dpy, cx);
|
|
glXMakeCurrent (dpy, None, NULL);
|
|
if (win) XDestroyWindow (dpy, win); // ...if already deleted in
|
|
// sub-class G4OpenGLXmViewer.
|
|
XFlush (dpy);
|
|
}
|
|
}
|
|
|
|
void G4OpenGLXViewer::print() {
|
|
|
|
//cout << "print_col_callback requested with file name: " << print_string << G4endl;
|
|
|
|
if (vectored_ps) {
|
|
G4int size = 5000000;
|
|
|
|
GLfloat* feedback_buffer;
|
|
GLint returned;
|
|
FILE* file;
|
|
|
|
feedback_buffer = new GLfloat[size];
|
|
glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
|
|
glRenderMode (GL_FEEDBACK);
|
|
|
|
DrawView();
|
|
returned = glRenderMode (GL_RENDER);
|
|
|
|
if (print_string) {
|
|
file = fopen (print_string, "w");
|
|
if (file) {
|
|
spewWireframeEPS (file, returned, feedback_buffer, "rendereps");
|
|
} else {
|
|
printf("Could not open %s\n", print_string);
|
|
}
|
|
} else {
|
|
printBuffer (returned, feedback_buffer);
|
|
}
|
|
// free (feedback_buffer);
|
|
delete[] feedback_buffer;
|
|
|
|
} else {
|
|
|
|
XVisualInfo* pvi;
|
|
G4bool new_db;
|
|
G4bool last_db;
|
|
GLXContext pcx = create_GL_print_context(pvi, new_db);
|
|
GLXContext tmp_cx;
|
|
tmp_cx = cx;
|
|
cx=pcx;
|
|
last_db=doublebuffer;
|
|
doublebuffer=new_db;
|
|
|
|
Pixmap pmap = XCreatePixmap (dpy,
|
|
XRootWindow (dpy, pvi->screen),
|
|
WinSize_x, WinSize_y,
|
|
pvi->depth);
|
|
|
|
GLXPixmap glxpmap = glXCreateGLXPixmap (dpy,
|
|
pvi,
|
|
pmap);
|
|
|
|
GLXDrawable tmp_win;
|
|
tmp_win=win;
|
|
win=glxpmap;
|
|
|
|
glXMakeCurrent (dpy,
|
|
glxpmap,
|
|
cx);
|
|
|
|
glViewport (0, 0, WinSize_x, WinSize_y);
|
|
|
|
ClearView ();
|
|
DrawView ();
|
|
|
|
generateEPS (print_string,
|
|
print_colour,
|
|
WinSize_x, WinSize_y);
|
|
|
|
win=tmp_win;
|
|
cx=tmp_cx;
|
|
doublebuffer=last_db;
|
|
|
|
glXMakeCurrent (dpy,
|
|
glxpmap,
|
|
cx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void G4OpenGLXViewer::print3DcolorVertex(GLint size, GLint * count, GLfloat * buffer)
|
|
{
|
|
G4int i;
|
|
|
|
printf(" ");
|
|
for (i = 0; i < 7; i++) {
|
|
printf("%4.2f ", buffer[size - (*count)]);
|
|
*count = *count - 1;
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void G4OpenGLXViewer::spewWireframeEPS (FILE* file, GLint size, GLfloat* buffer, const char* cr) {
|
|
|
|
GLfloat EPS_GOURAUD_THRESHOLD=0.1;
|
|
|
|
GLfloat clearColor[4], viewport[4];
|
|
GLfloat lineWidth;
|
|
G4int i;
|
|
|
|
glGetFloatv (GL_VIEWPORT, viewport);
|
|
glGetFloatv (GL_COLOR_CLEAR_VALUE, clearColor);
|
|
glGetFloatv (GL_LINE_WIDTH, &lineWidth);
|
|
glGetFloatv (GL_POINT_SIZE, &pointSize);
|
|
|
|
fputs ("%!PS-Adobe-2.0 EPSF-2.0\n", file);
|
|
fprintf (file, "%%%%Creator: %s (using OpenGL feedback)\n", cr);
|
|
fprintf (file, "%%%%BoundingBox: %g %g %g %g\n", viewport[0], viewport[1], viewport[2], viewport[3]);
|
|
fputs ("%%EndComments\n", file);
|
|
fputs ("\n", file);
|
|
fputs ("gsave\n", file);
|
|
fputs ("\n", file);
|
|
|
|
fputs ("% the gouraudtriangle PostScript fragment below is free\n", file);
|
|
fputs ("% written by Frederic Delhoume (delhoume@ilog.fr)\n", file);
|
|
fprintf (file, "/threshold %g def\n", EPS_GOURAUD_THRESHOLD);
|
|
for (i=0; gouraudtriangleEPS[i]; i++) {
|
|
fprintf (file, "%s\n", gouraudtriangleEPS[i]);
|
|
}
|
|
|
|
fprintf(file, "\n%g setlinewidth\n", lineWidth);
|
|
|
|
fprintf (file, "%g %g %g setrgbcolor\n", clearColor[0], clearColor[1], clearColor[2]);
|
|
fprintf (file, "%g %g %g %g rectfill\n\n", viewport[0], viewport[1], viewport[2], viewport[3]);
|
|
|
|
spewSortedFeedback (file, size, buffer);
|
|
|
|
fputs ("grestore\n\n", file);
|
|
fputs ("showpage\n", file);
|
|
|
|
fclose(file);
|
|
}
|
|
|
|
void G4OpenGLXViewer::printBuffer (GLint size, GLfloat* buffer) {
|
|
|
|
GLint count;
|
|
G4int token, nvertices;
|
|
|
|
count=size;
|
|
while(count) {
|
|
token=G4int (buffer[size-count]);
|
|
count--;
|
|
switch (token) {
|
|
|
|
case GL_PASS_THROUGH_TOKEN:
|
|
printf ("GL_PASS_THROUGH_TOKEN\n");
|
|
printf (" %4.2f\n", buffer[size-count]);
|
|
count--;
|
|
break;
|
|
|
|
case GL_POINT_TOKEN:
|
|
printf ("GL_POINT_TOKEN\n");
|
|
print3DcolorVertex (size, &count, buffer);
|
|
break;
|
|
|
|
case GL_LINE_TOKEN:
|
|
printf ("GL_LINE_TOKEN\n");
|
|
print3DcolorVertex (size, &count, buffer);
|
|
print3DcolorVertex (size, &count, buffer);
|
|
break;
|
|
|
|
case GL_LINE_RESET_TOKEN:
|
|
printf ("GL_LINE_RESET_TOKEN\n");
|
|
print3DcolorVertex (size, &count, buffer);
|
|
print3DcolorVertex (size, &count, buffer);
|
|
break;
|
|
|
|
case GL_POLYGON_TOKEN:
|
|
printf ("GL_POLYGON_TOKEN\n");
|
|
nvertices=G4int (buffer[size-count]);
|
|
count--;
|
|
for (; nvertices>0; nvertices--) {
|
|
print3DcolorVertex (size, &count, buffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
G4float* G4OpenGLXViewer::spewPrimitiveEPS (FILE* file, GLfloat* loc) {
|
|
|
|
G4int token;
|
|
G4int nvertices, i;
|
|
GLfloat red, green, blue, intensity;
|
|
G4int smooth;
|
|
GLfloat dx, dy, dr, dg, db, absR, absG, absB, colormax;
|
|
G4int steps;
|
|
Feedback3Dcolor *vertex;
|
|
GLfloat xstep(0.), ystep(0.), rstep(0.), gstep(0.), bstep(0.);
|
|
GLfloat xnext(0.), ynext(0.), rnext(0.), gnext(0.), bnext(0.), distance(0.);
|
|
|
|
token=G4int (*loc);
|
|
loc++;
|
|
switch (token) {
|
|
case GL_LINE_RESET_TOKEN:
|
|
case GL_LINE_TOKEN:
|
|
vertex=(Feedback3Dcolor*)loc;
|
|
dr=vertex[1].red - vertex[0].red;
|
|
dg=vertex[1].green - vertex[0].green;
|
|
db=vertex[1].blue - vertex[0].blue;
|
|
|
|
if (!print_colour) {
|
|
dr+=(dg+db);
|
|
dr/=3.0;
|
|
dg=dr;
|
|
db=dr;
|
|
}
|
|
|
|
if (dr!=0 || dg!=0 || db!=0) {
|
|
dx=vertex[1].x - vertex[0].x;
|
|
dy=vertex[1].y - vertex[0].y;
|
|
distance=sqrt(dx*dx + dy*dy);
|
|
|
|
absR=fabs(dr);
|
|
absG=fabs(dg);
|
|
absB=fabs(db);
|
|
|
|
#define Max(a, b) (((a)>(b))?(a):(b))
|
|
|
|
#define EPS_SMOOTH_LINE_FACTOR 0.06
|
|
|
|
colormax=Max(absR, Max(absG, absB));
|
|
steps=Max(1, G4int (colormax*distance*EPS_SMOOTH_LINE_FACTOR));
|
|
|
|
xstep=dx/steps;
|
|
ystep=dy/steps;
|
|
|
|
rstep=dr/steps;
|
|
gstep=dg/steps;
|
|
bstep=db/steps;
|
|
|
|
xnext=vertex[0].x;
|
|
ynext=vertex[0].y;
|
|
rnext=vertex[0].red;
|
|
gnext=vertex[0].green;
|
|
bnext=vertex[0].blue;
|
|
|
|
if (!print_colour) {
|
|
rnext+=(gnext+bnext);
|
|
rnext/=3.0;
|
|
gnext=rnext;
|
|
bnext=rnext;
|
|
}
|
|
|
|
xnext -= xstep/2.0;
|
|
ynext -= ystep/2.0;
|
|
rnext -= rstep/2.0;
|
|
gnext -= gstep/2.0;
|
|
bnext -= bstep/2.0;
|
|
} else {
|
|
steps=0;
|
|
}
|
|
if (print_colour) {
|
|
fprintf (file, "%g %g %g setrgbcolor\n",
|
|
vertex[0].red, vertex[0].green, vertex[0].blue);
|
|
} else {
|
|
intensity = (vertex[0].red + vertex[0].green + vertex[0].blue) / 3.0;
|
|
fprintf (file, "%g %g %g setrgbcolor\n",
|
|
intensity, intensity, intensity);
|
|
}
|
|
fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
|
|
|
|
for (i=0; i<steps; i++) {
|
|
|
|
xnext += xstep;
|
|
ynext += ystep;
|
|
rnext += rstep;
|
|
gnext += gstep;
|
|
bnext += bstep;
|
|
|
|
fprintf (file, "%g %g lineto stroke\n", xnext, ynext);
|
|
fprintf (file, "%g %g %g setrgbcolor\n", rnext, gnext, bnext);
|
|
fprintf (file, "%g %g moveto\n", xnext, ynext);
|
|
}
|
|
fprintf (file, "%g %g lineto stroke\n", vertex[1].x, vertex[1].y);
|
|
|
|
loc += 14;
|
|
break;
|
|
|
|
case GL_POLYGON_TOKEN:
|
|
nvertices = G4int (*loc);
|
|
loc++;
|
|
vertex=(Feedback3Dcolor*)loc;
|
|
if (nvertices>0) {
|
|
red=vertex[0].red;
|
|
green=vertex[0].green;
|
|
blue=vertex[0].blue;
|
|
smooth=0;
|
|
|
|
if (!print_colour) {
|
|
red+=(green+blue);
|
|
red/=3.0;
|
|
green=red;
|
|
blue=red;
|
|
}
|
|
|
|
if (print_colour) {
|
|
for (i=1; i<nvertices; i++) {
|
|
if (red!=vertex[i].red || green!=vertex[i].green || blue!=vertex[i].blue) {
|
|
smooth=1;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (i=1; i<nvertices; i++) {
|
|
intensity = vertex[i].red + vertex[i].green + vertex[i].blue;
|
|
intensity/=3.0;
|
|
if (red!=intensity) {
|
|
smooth=1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (smooth) {
|
|
G4int triOffset;
|
|
for (i=0; i<nvertices-2; i++) {
|
|
triOffset = i*7;
|
|
fprintf (file, "[%g %g %g %g %g %g]",
|
|
vertex[0].x, vertex[i+1].x, vertex[i+2].x,
|
|
vertex[0].y, vertex[i+1].y, vertex[i+2].y);
|
|
if (print_colour) {
|
|
fprintf (file, " [%g %g %g] [%g %g %g] [%g %g %g] gouraudtriangle\n",
|
|
vertex[0].red, vertex[0].green, vertex[0].blue,
|
|
vertex[i+1].red, vertex[i+1].green, vertex[i+1].blue,
|
|
vertex[i+2].red, vertex[i+2].green, vertex[i+2].blue);
|
|
} else {
|
|
|
|
intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
|
|
intensity/=3.0;
|
|
fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
|
|
|
|
intensity = vertex[1].red + vertex[1].green + vertex[1].blue;
|
|
intensity/=3.0;
|
|
fprintf (file, " [%g %g %g]", intensity, intensity, intensity);
|
|
|
|
intensity = vertex[2].red + vertex[2].green + vertex[2].blue;
|
|
intensity/=3.0;
|
|
fprintf (file, " [%g %g %g] gouraudtriangle\n", intensity, intensity, intensity);
|
|
}
|
|
}
|
|
} else {
|
|
fprintf (file, "newpath\n");
|
|
fprintf (file, "%g %g %g setrgbcolor\n", red, green, blue);
|
|
fprintf (file, "%g %g moveto\n", vertex[0].x, vertex[0].y);
|
|
for (i=1; i<nvertices; i++) {
|
|
fprintf (file, "%g %g lineto\n", vertex[i].x, vertex[i].y);
|
|
}
|
|
fprintf (file, "closepath fill\n\n");
|
|
}
|
|
}
|
|
loc += nvertices*7;
|
|
break;
|
|
|
|
case GL_POINT_TOKEN:
|
|
vertex=(Feedback3Dcolor*)loc;
|
|
if (print_colour) {
|
|
fprintf (file, "%g %g %g setrgbcolor\n", vertex[0].red, vertex[0].green, vertex[0].blue);
|
|
} else {
|
|
intensity = vertex[0].red + vertex[0].green + vertex[0].blue;
|
|
intensity/=3.0;
|
|
fprintf (file, "%g %g %g setrgbcolor\n", intensity, intensity, intensity);
|
|
}
|
|
fprintf(file, "%g %g %g 0 360 arc fill\n\n", vertex[0].x, vertex[0].y, pointSize / 2.0);
|
|
loc += 7; /* Each vertex element in the feedback
|
|
buffer is 7 GLfloats. */
|
|
break;
|
|
default:
|
|
/* XXX Left as an excersie to the reader. */
|
|
printf("Incomplete implementation. Unexpected token (%d).\n", token);
|
|
exit(1);
|
|
}
|
|
return loc;
|
|
}
|
|
|
|
typedef struct _DepthIndex {
|
|
GLfloat *ptr;
|
|
GLfloat depth;
|
|
} DepthIndex;
|
|
|
|
extern "C" {
|
|
int G4OpenGLXViewercompare(const void *a, const void *b)
|
|
{
|
|
const DepthIndex *p1 = (DepthIndex *) a;
|
|
const DepthIndex *p2 = (DepthIndex *) b;
|
|
GLfloat diff = p2->depth - p1->depth;
|
|
|
|
if (diff > 0.0) {
|
|
return 1;
|
|
} else if (diff < 0.0) {
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void G4OpenGLXViewer::spewSortedFeedback(FILE * file, GLint size, GLfloat * buffer)
|
|
{
|
|
int token;
|
|
GLfloat *loc, *end;
|
|
Feedback3Dcolor *vertex;
|
|
GLfloat depthSum;
|
|
int nprimitives, item;
|
|
DepthIndex *prims;
|
|
int nvertices, i;
|
|
|
|
end = buffer + size;
|
|
|
|
/* Count how many primitives there are. */
|
|
nprimitives = 0;
|
|
loc = buffer;
|
|
while (loc < end) {
|
|
token = int (*loc);
|
|
loc++;
|
|
switch (token) {
|
|
case GL_LINE_TOKEN:
|
|
case GL_LINE_RESET_TOKEN:
|
|
loc += 14;
|
|
nprimitives++;
|
|
break;
|
|
case GL_POLYGON_TOKEN:
|
|
nvertices = int (*loc);
|
|
loc++;
|
|
loc += (7 * nvertices);
|
|
nprimitives++;
|
|
break;
|
|
case GL_POINT_TOKEN:
|
|
loc += 7;
|
|
nprimitives++;
|
|
break;
|
|
default:
|
|
/* XXX Left as an excersie to the reader. */
|
|
printf("Incomplete implementation. Unexpected token (%d).\n",
|
|
token);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* Allocate an array of pointers that will point back at
|
|
primitives in the feedback buffer. There will be one
|
|
entry per primitive. This array is also where we keep the
|
|
primitive's average depth. There is one entry per
|
|
primitive in the feedback buffer. */
|
|
prims = (DepthIndex *) malloc(sizeof(DepthIndex) * nprimitives);
|
|
|
|
item = 0;
|
|
loc = buffer;
|
|
while (loc < end) {
|
|
prims[item].ptr = loc; /* Save this primitive's location. */
|
|
token = int (*loc);
|
|
loc++;
|
|
switch (token) {
|
|
case GL_LINE_TOKEN:
|
|
case GL_LINE_RESET_TOKEN:
|
|
vertex = (Feedback3Dcolor *) loc;
|
|
depthSum = vertex[0].z + vertex[1].z;
|
|
prims[item].depth = depthSum / 2.0;
|
|
loc += 14;
|
|
break;
|
|
case GL_POLYGON_TOKEN:
|
|
nvertices = int (*loc);
|
|
loc++;
|
|
vertex = (Feedback3Dcolor *) loc;
|
|
depthSum = vertex[0].z;
|
|
for (i = 1; i < nvertices; i++) {
|
|
depthSum += vertex[i].z;
|
|
}
|
|
prims[item].depth = depthSum / nvertices;
|
|
loc += (7 * nvertices);
|
|
break;
|
|
case GL_POINT_TOKEN:
|
|
vertex = (Feedback3Dcolor *) loc;
|
|
prims[item].depth = vertex[0].z;
|
|
loc += 7;
|
|
break;
|
|
default:
|
|
/* XXX Left as an excersie to the reader. */
|
|
assert(1);
|
|
}
|
|
item++;
|
|
}
|
|
assert(item == nprimitives);
|
|
|
|
/* Sort the primitives back to front. */
|
|
qsort(prims, nprimitives, sizeof(DepthIndex), G4OpenGLXViewercompare);
|
|
|
|
/* Understand that sorting by a primitives average depth
|
|
doesn't allow us to disambiguate some cases like self
|
|
intersecting polygons. Handling these cases would require
|
|
breaking up the primitives. That's too involved for this
|
|
example. Sorting by depth is good enough for lots of
|
|
applications. */
|
|
|
|
/* Emit the Encapsulated PostScript for the primitives in
|
|
back to front order. */
|
|
for (item = 0; item < nprimitives; item++) {
|
|
(void) spewPrimitiveEPS(file, prims[item].ptr);
|
|
}
|
|
|
|
free(prims);
|
|
}
|
|
|
|
GLXContext G4OpenGLXViewer::create_GL_print_context(XVisualInfo*& pvi, G4bool& db) {
|
|
|
|
pvi = glXChooseVisual (dpy,
|
|
XDefaultScreen (dpy),
|
|
snglBuf_RGBA);
|
|
|
|
if (pvi) {
|
|
db=false;
|
|
} else {
|
|
pvi = glXChooseVisual (dpy,
|
|
XDefaultScreen (dpy),
|
|
dblBuf_RGBA);
|
|
if (!pvi) {
|
|
db=true;
|
|
}
|
|
}
|
|
|
|
return glXCreateContext (dpy,
|
|
pvi,
|
|
NULL,
|
|
False);
|
|
}
|
|
|
|
int G4OpenGLXViewer::generateEPS (char* filnam,
|
|
int inColour,
|
|
unsigned int width,
|
|
unsigned int height) {
|
|
|
|
FILE* fp;
|
|
GLubyte* pixels;
|
|
GLubyte* curpix;
|
|
int components, pos, i;
|
|
|
|
pixels = grabPixels (inColour, width, height);
|
|
|
|
if (pixels == NULL)
|
|
return 1;
|
|
if (inColour) {
|
|
components = 3;
|
|
} else {
|
|
components = 1;
|
|
}
|
|
|
|
fp = fopen (filnam, "w");
|
|
if (fp == NULL) {
|
|
return 2;
|
|
}
|
|
|
|
fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
|
|
fprintf (fp, "%%%%Title: %s\n", filnam);
|
|
fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n");
|
|
fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
|
|
fprintf (fp, "%%%%EndComments\n");
|
|
fprintf (fp, "gsave\n");
|
|
fprintf (fp, "/bwproc {\n");
|
|
fprintf (fp, " rgbproc\n");
|
|
fprintf (fp, " dup length 3 idiv string 0 3 0 \n");
|
|
fprintf (fp, " 5 -1 roll {\n");
|
|
fprintf (fp, " add 2 1 roll 1 sub dup 0 eq\n");
|
|
fprintf (fp, " { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n");
|
|
fprintf (fp, " 3 1 roll 5 -1 roll } put 1 add 3 0 \n");
|
|
fprintf (fp, " { 2 1 roll } ifelse\n");
|
|
fprintf (fp, " }forall\n");
|
|
fprintf (fp, " pop pop pop\n");
|
|
fprintf (fp, "} def\n");
|
|
fprintf (fp, "systemdict /colorimage known not {\n");
|
|
fprintf (fp, " /colorimage {\n");
|
|
fprintf (fp, " pop\n");
|
|
fprintf (fp, " pop\n");
|
|
fprintf (fp, " /rgbproc exch def\n");
|
|
fprintf (fp, " { bwproc } image\n");
|
|
fprintf (fp, " } def\n");
|
|
fprintf (fp, "} if\n");
|
|
fprintf (fp, "/picstr %d string def\n", width * components);
|
|
fprintf (fp, "%d %d scale\n", width, height);
|
|
fprintf (fp, "%d %d %d\n", width, height, 8);
|
|
fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height);
|
|
fprintf (fp, "{currentfile picstr readhexstring pop}\n");
|
|
fprintf (fp, "false %d\n", components);
|
|
fprintf (fp, "colorimage\n");
|
|
|
|
curpix = (GLubyte*) pixels;
|
|
pos = 0;
|
|
for (i = width*height*components; i>0; i--) {
|
|
fprintf (fp, "%02hx ", *(curpix++));
|
|
if (++pos >= 32) {
|
|
fprintf (fp, "\n");
|
|
pos = 0;
|
|
}
|
|
}
|
|
if (pos)
|
|
fprintf (fp, "\n");
|
|
|
|
fprintf (fp, "grestore\n");
|
|
fprintf (fp, "showpage\n");
|
|
delete pixels;
|
|
fclose (fp);
|
|
return 0;
|
|
}
|
|
|
|
GLubyte* G4OpenGLXViewer::grabPixels (int inColor, unsigned int width, unsigned int height) {
|
|
|
|
GLubyte* buffer;
|
|
GLint swapbytes, lsbfirst, rowlength;
|
|
GLint skiprows, skippixels, alignment;
|
|
GLenum format;
|
|
int size;
|
|
|
|
if (inColor) {
|
|
format = GL_RGB;
|
|
size = width*height*3;
|
|
} else {
|
|
format = GL_LUMINANCE;
|
|
size = width*height*1;
|
|
}
|
|
|
|
buffer = new GLubyte[size];
|
|
if (buffer == NULL)
|
|
return NULL;
|
|
|
|
glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes);
|
|
glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst);
|
|
glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength);
|
|
|
|
glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows);
|
|
glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels);
|
|
glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
|
|
|
|
glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
|
|
glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
|
|
|
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
|
|
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
|
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
glReadPixels (0, 0, (GLsizei)width, (GLsizei)height, format, GL_UNSIGNED_BYTE, (GLvoid*) buffer);
|
|
|
|
glPixelStorei (GL_UNPACK_SWAP_BYTES, swapbytes);
|
|
glPixelStorei (GL_UNPACK_LSB_FIRST, lsbfirst);
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, rowlength);
|
|
|
|
glPixelStorei (GL_UNPACK_SKIP_ROWS, skiprows);
|
|
glPixelStorei (GL_UNPACK_SKIP_PIXELS, skippixels);
|
|
glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
#endif
|