// // ******************************************************************** // * 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: G4OpenGLSceneHandler.cc,v 1.15 2002/02/24 01:48:09 johna Exp $ // GEANT4 tag $Name: geant4-04-01 $ // // // Andrew Walkden 27th March 1996 // OpenGL stored scene - creates OpenGL display lists. // OpenGL immediate scene - draws immediately to buffer // (saving space on server). #ifdef G4VIS_BUILD_OPENGL_DRIVER // Included here - problems with HP compiler if not before other includes? #include "G4NURBS.hh" // Here follows a special for Mesa, the OpenGL emulator. Does not affect // other OpenGL's, as far as I'm aware. John Allison 18/9/96. #define CENTERLINE_CLPP /* CenterLine C++ workaround: */ // Also seems to be required for HP's CC and AIX xlC, at least. #include #include #include "G4OpenGLSceneHandler.hh" #include "G4OpenGLViewer.hh" #include "G4OpenGLTransform3D.hh" #include "G4Point3D.hh" #include "G4Normal3D.hh" #include "G4Transform3D.hh" #include "G4Polyline.hh" #include "G4Text.hh" #include "G4Circle.hh" #include "G4Square.hh" #include "G4VMarker.hh" #include "G4Polyhedron.hh" #include "G4VisAttributes.hh" G4OpenGLSceneHandler::G4OpenGLSceneHandler (G4VGraphicsSystem& system, G4int id, const G4String& name): G4VSceneHandler (system, id, name) { initialize_hlr = true; // glPolygonOffset (1.0, 2); } G4OpenGLSceneHandler::~G4OpenGLSceneHandler () { ClearStore (); } const GLubyte G4OpenGLSceneHandler::fStippleMaskHashed [128] = { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 }; //Method for handling G4Polyline objects (from tracking or wireframe). void G4OpenGLSceneHandler::AddPrimitive (const G4Polyline& line) { const G4Colour& c = GetColour (line); glColor3d (c.GetRed (), c.GetGreen (), c.GetBlue ()); if (fpViewer -> GetViewParameters ().IsMarkerNotHidden ()) glDisable (GL_DEPTH_TEST); else glEnable (GL_DEPTH_TEST); glDisable (GL_LIGHTING); glBegin (GL_LINE_STRIP); G4int nPoints = line.size (); for (G4int iPoint = 0; iPoint < nPoints; iPoint++) { G4double x, y, z; x = line[iPoint].x(); y = line[iPoint].y(); z = line[iPoint].z(); glVertex3d (x, y, z); } glEnd (); } void G4OpenGLSceneHandler::AddPrimitive (const G4Text& text) { static G4int callCount (0); ++callCount; MarkerSizeType sizeType; G4double size = GetMarkerSize (text, sizeType); G4ThreeVector position (*fpObjectTransformation * text.GetPosition ()); if (callCount <= 10 || callCount%100 == 0) { G4cout << "G4OpenGLSceneHandler::AddPrimitive (const G4Text&) call count " << callCount << "\n Not implemented yet. Called with text \"" << text.GetText () << "\"\n at " << position << ", size " << size << ", offsets " << text.GetXOffset () << ", " << text.GetYOffset () << ", type " << G4int(sizeType) << G4endl; } } void G4OpenGLSceneHandler::AddPrimitive (const G4Circle& circle) { glEnable (GL_POINT_SMOOTH); AddCircleSquare (circle, 24); } void G4OpenGLSceneHandler::AddPrimitive (const G4Square& square) { glDisable (GL_POINT_SMOOTH); AddCircleSquare (square, 4); } void G4OpenGLSceneHandler::AddCircleSquare (const G4VMarker& marker, G4int nSides) { const G4Colour& c = GetColour (marker); glColor3d (c.GetRed (), c.GetGreen (), c.GetBlue ()); if (fpViewer -> GetViewParameters ().IsMarkerNotHidden ()) glDisable (GL_DEPTH_TEST); else glEnable (GL_DEPTH_TEST); glDisable (GL_LIGHTING); G4VMarker::FillStyle style = marker.GetFillStyle(); switch (style) { case G4VMarker::noFill: glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); break; case G4VMarker::hashed: /* G4cout << "Hashed fill style in G4OpenGLSceneHandler." << "\n Not implemented. Using G4VMarker::filled." << G4endl; */ glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glPolygonStipple (fStippleMaskHashed); // See also: // if (style == G4VMarker::filled || style == G4VMarker::hashed)... // (twice) below. break; case G4VMarker::filled: glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); break; default: G4cout << "Unrecognised fill style in G4OpenGLSceneHandler." << "\n Using G4VMarker::filled." << G4endl; glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); break; } // A few useful quantities... G4Point3D centre = marker.GetPosition(); G4bool userSpecified = (marker.GetWorldSize() || marker.GetScreenSize()); const G4VMarker& def = fpViewer -> GetViewParameters().GetDefaultMarker(); const G4Vector3D& viewpointDirection = fpViewer -> GetViewParameters().GetViewpointDirection(); const G4Vector3D& up = fpViewer->GetViewParameters().GetUpVector(); G4double scale = fpViewer -> GetViewParameters().GetGlobalMarkerScale(); G4double size = scale * userSpecified ? marker.GetWorldSize() : def.GetWorldSize(); // Find "size" of marker in world space (but see note below)... G4double worldSize; if (size) { // Size specified in world coordinates. worldSize = size; } else { // Size specified in screen (window) coordinates. // Find window coordinates of centre... GLdouble modelMatrix[16]; glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix); G4double projectionMatrix[16]; glGetDoublev (GL_PROJECTION_MATRIX, projectionMatrix); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); GLdouble winx, winy, winz; gluProject(centre.x(), centre.y(), centre.z(), modelMatrix, projectionMatrix, viewport, &winx, &winy, &winz); // Determine ratio window:world... const G4Vector3D inScreen = (up.cross(viewpointDirection)).unit(); const G4Vector3D p = centre + inScreen; GLdouble winDx, winDy, winDz; gluProject(p.x(), p.y(), p.z(), modelMatrix, projectionMatrix, viewport, &winDx, &winDy, &winDz); G4double winWorldRatio = sqrt(pow(winx - winDx, 2) + pow(winy - winDy, 2)); G4double winSize = scale * userSpecified ? marker.GetScreenSize() : def.GetScreenSize(); worldSize = winSize / winWorldRatio; } // Draw... DrawXYPolygon (worldSize, centre, nSides); } /*************************************************** Note: We have to do it this way round so that when a global transformation is applied, such as with /vis/viewer/set/viewpoint, the markers follow the world coordinates without having to recreate the display lists. The down side is that the markers rotate. The only way to avoid this is to play with the modelview and projection matrices of OpenGL - which I need to think about. For future reference, here is the code to draw in window coordinates; its down side is that markers do not follow global transformations. Some clever stuff is needed. ... // Find window coordinates of centre... GLdouble modelMatrix[16]; glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix); G4double projectionMatrix[16]; glGetDoublev (GL_PROJECTION_MATRIX, projectionMatrix); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); GLdouble winx, winy, winz; gluProject(centre.x(), centre.y(), centre.z(), modelMatrix, projectionMatrix, viewport, &winx, &winy, &winz); // Find window size... G4double winSize; if (size) { // Size specified in world coordinates. // Determine size in window coordinates... (Note: improve this by using an inScreen vector as above.) GLdouble winx1, winy1, winz1; gluProject(centre.x() + size, centre.y() + size, centre.z() + size, modelMatrix, projectionMatrix, viewport, &winx1, &winy1, &winz1); winSize = sqrt((pow(winx - winx1, 2) + pow(winy - winy1, 2) + pow(winz - winz1, 2)) / 3.); } else { winSize = scale * userSpecified ? marker.GetScreenSize() : def.GetScreenSize(); } // Prepare to draw in window coordinates... glMatrixMode (GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(GLdouble(viewport[0]), GLdouble(viewport[0] + viewport[2]), GLdouble(viewport[1]), GLdouble(viewport[1] + viewport[3])); glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // Draw in window coordinates... DrawScreenPolygon (winSize, G4Point3D(winx, winy, winz), nSides); // Re-instate matrices... glMatrixMode (GL_PROJECTION); glPopMatrix(); glMatrixMode (GL_MODELVIEW); glPopMatrix(); ... void G4OpenGLSceneHandler::DrawScreenPolygon (G4double size, const G4Point3D& centre, G4int nSides) { glBegin (GL_POLYGON); const G4double dPhi = 2. * M_PI / nSides; const G4double r = size / 2.; G4double phi; G4int i; for (i = 0, phi = -dPhi / 2.; i < nSides; i++, phi += dPhi) { G4double x, y, z; x = centre.x() + r * cos(phi); y = centre.y() + r * sin(phi); z = centre.z(); glVertex3d (x, y, z); } glEnd (); } **********************************************/ void G4OpenGLSceneHandler::DrawXYPolygon (G4double size, const G4Point3D& centre, G4int nSides) { const G4Vector3D& viewpointDirection = fpViewer -> GetViewParameters().GetViewpointDirection(); const G4Vector3D& up = fpViewer->GetViewParameters().GetUpVector(); const G4double dPhi = 2. * M_PI / nSides; const G4double radius = size / 2.; G4Vector3D start = radius * (up.cross(viewpointDirection)).unit(); G4double phi; G4int i; glBegin (GL_POLYGON); for (i = 0, phi = -dPhi / 2.; i < nSides; i++, phi += dPhi) { G4Vector3D r = start; r.rotate(phi, viewpointDirection); G4Vector3D p = centre + r; glVertex3d (p.x(), p.y(), p.z()); } glEnd (); } //Method for handling G4Polyhedron objects for drawing solids. void G4OpenGLSceneHandler::AddPrimitive (const G4Polyhedron& polyhedron) { //Assume all facets are convex quadrilaterals. //Draw each G4Facet individually if (polyhedron.GetNoFacets() == 0) return; G4ViewParameters::DrawingStyle drawing_style = GetDrawingStyle (polyhedron); //Get colour, etc.. const G4Colour& c = GetColour (polyhedron); switch (drawing_style) { // case (G4ViewParameters::hlhsr): // cout << "Hidden edge not implememented in G4OpenGL.\n" // << "Using hidden surface removal." << G4endl; case (G4ViewParameters::hsr): { glPolygonMode (GL_FRONT, GL_FILL); glCullFace (GL_BACK); //glEnable (GL_CULL_FACE); glEnable (GL_LIGHTING); glEnable (GL_DEPTH_TEST); GLfloat materialColour [4]; materialColour [0] = c.GetRed (); materialColour [1] = c.GetGreen (); materialColour [2] = c.GetBlue (); materialColour [3] = 1.0; glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materialColour); break; } case (G4ViewParameters::hlr): if (initialize_hlr) { glEnable (GL_STENCIL_TEST); glClear (GL_STENCIL_BUFFER_BIT); glStencilFunc (GL_ALWAYS, 0, 1); glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT); glGetDoublev (GL_COLOR_CLEAR_VALUE, clear_colour); initialize_hlr = false; // glEnable (GL_POLYGON_OFFSET_FILL); } glDepthFunc (GL_LESS); //drop through to wireframe for first pass... case (G4ViewParameters::wireframe): default: glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); glDisable (GL_CULL_FACE); glDisable (GL_LIGHTING); glEnable (GL_DEPTH_TEST); glColor3d (c.GetRed (), c.GetGreen (), c.GetBlue ()); break; } glBegin (GL_QUADS); //Loop through all the facets... G4bool notLastFace; G4Normal3D SurfaceUnitNormal; do { //First, find surface normal for the facet... notLastFace = polyhedron.GetNextUnitNormal (SurfaceUnitNormal); glNormal3d(SurfaceUnitNormal.x(), SurfaceUnitNormal.y(), SurfaceUnitNormal.z()); //Loop through the four edges of each G4Facet... G4bool notLastEdge; G4Point3D vertex[4]; G4int edgeFlag[4], lastEdgeFlag (true); edgeFlag[0] = G4int (true); G4int edgeCount = 0; glEdgeFlag (GL_TRUE); do { notLastEdge = polyhedron.GetNextVertex (vertex[edgeCount], edgeFlag[edgeCount]); // Check to see if edge is visible or not... if (edgeFlag[edgeCount] != lastEdgeFlag) { lastEdgeFlag = edgeFlag[edgeCount]; if (edgeFlag[edgeCount]) { glEdgeFlag (GL_TRUE); } else { glEdgeFlag (GL_FALSE); } } glVertex3d (vertex[edgeCount].x(), vertex[edgeCount].y(), vertex[edgeCount].z()); edgeCount++; } while (notLastEdge); while (edgeCount < 4) { // duplicate last real vertex. vertex[edgeCount] = vertex[edgeCount-1]; glVertex3d (vertex[edgeCount].x(), vertex[edgeCount].y(), vertex[edgeCount].z()); edgeCount++; } //do it all over again for hlr 2nd pass... if (drawing_style == G4ViewParameters::hlr) { glEnd(); //glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, clear_colour); glStencilFunc (GL_EQUAL, 0, 1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); glPolygonMode (GL_FRONT, GL_FILL); glColor4dv (clear_colour); edgeCount=0; glBegin (GL_QUADS); do { if (edgeFlag[edgeCount] != lastEdgeFlag) { lastEdgeFlag = edgeFlag[edgeCount]; if (edgeFlag[edgeCount]) { glEdgeFlag (GL_TRUE); } else { glEdgeFlag (GL_FALSE); } } glVertex3d (vertex[edgeCount].x(), vertex[edgeCount].y(), vertex[edgeCount].z()); } while (++edgeCount < 4); glEnd(); //and once more to reset the stencil bits... glStencilFunc (GL_ALWAYS, 0, 1); glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT); glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); glColor3d (c.GetRed (), c.GetGreen (), c.GetBlue ()); edgeCount=0; glBegin(GL_QUADS); do { if (edgeFlag[edgeCount] != lastEdgeFlag) { lastEdgeFlag = edgeFlag[edgeCount]; if (edgeFlag[edgeCount]) { glEdgeFlag (GL_TRUE); } else { glEdgeFlag (GL_FALSE); } } glVertex3d (vertex[edgeCount].x(), vertex[edgeCount].y(), vertex[edgeCount].z()); } while (++edgeCount < 4); } } while (notLastFace); glEnd (); } //Method for handling G4NURBS objects for drawing solids. //Knots and Ctrl Pnts MUST be arrays of GLfloats. void G4OpenGLSceneHandler::AddPrimitive (const G4NURBS& nurb) { GLUnurbsObj *gl_nurb; gl_nurb = gluNewNurbsRenderer (); GLfloat *u_knot_array, *u_knot_array_ptr; u_knot_array = u_knot_array_ptr = new GLfloat [nurb.GetnbrKnots(G4NURBS::U)]; G4NURBS::KnotsIterator u_iterator (nurb, G4NURBS::U); while (u_iterator.pick (u_knot_array_ptr++)); GLfloat *v_knot_array, *v_knot_array_ptr; v_knot_array = v_knot_array_ptr = new GLfloat [nurb.GetnbrKnots(G4NURBS::V)]; G4NURBS::KnotsIterator v_iterator (nurb, G4NURBS::V); while (v_iterator.pick (v_knot_array_ptr++)); GLfloat *ctrl_pnt_array, *ctrl_pnt_array_ptr; ctrl_pnt_array = ctrl_pnt_array_ptr = new GLfloat [nurb.GettotalnbrCtrlPts () * G4NURBS::NofC]; G4NURBS::CtrlPtsCoordsIterator c_p_iterator (nurb); while (c_p_iterator.pick (ctrl_pnt_array_ptr++)); const G4Colour& c = GetColour (nurb); switch (GetDrawingStyle(nurb)) { case (G4ViewParameters::hlhsr): // G4cout << "Hidden line removal not implememented in G4OpenGL.\n" // << "Using hidden surface removal." << G4endl; case (G4ViewParameters::hsr): { glEnable (GL_LIGHTING); glEnable (GL_DEPTH_TEST); glEnable (GL_AUTO_NORMAL); glEnable (GL_NORMALIZE); gluNurbsProperty (gl_nurb, GLU_DISPLAY_MODE, GLU_FILL); gluNurbsProperty (gl_nurb, GLU_SAMPLING_TOLERANCE, 50.0); GLfloat materialColour [4]; materialColour [0] = c.GetRed (); materialColour [1] = c.GetGreen (); materialColour [2] = c.GetBlue (); materialColour [3] = 1.0; glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materialColour); break; } case (G4ViewParameters::hlr): // G4cout << "Hidden line removal not implememented in G4OpenGL.\n" // << "Using wireframe." << G4endl; case (G4ViewParameters::wireframe): default: glDisable (GL_LIGHTING); // glDisable (GL_DEPTH_TEST); glEnable (GL_DEPTH_TEST); glDisable (GL_AUTO_NORMAL); glDisable (GL_NORMALIZE); gluNurbsProperty (gl_nurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON); gluNurbsProperty (gl_nurb, GLU_SAMPLING_TOLERANCE, 50.0); glColor3d (c.GetRed (), c.GetGreen (), c.GetBlue ()); break; } gluBeginSurface (gl_nurb); G4int u_stride = 4; G4int v_stride = nurb.GetnbrCtrlPts(G4NURBS::U) * 4; gluNurbsSurface (gl_nurb, nurb.GetnbrKnots (G4NURBS::U), (GLfloat*)u_knot_array, nurb.GetnbrKnots (G4NURBS::V), (GLfloat*)v_knot_array, u_stride, v_stride, ctrl_pnt_array, nurb.GetUorder (), nurb.GetVorder (), GL_MAP2_VERTEX_4); gluEndSurface (gl_nurb); delete [] u_knot_array; // These should be allocated with smart allocators delete [] v_knot_array; // to avoid memory explosion. delete [] ctrl_pnt_array; gluDeleteNurbsRenderer (gl_nurb); } #endif