1454 lines
40 KiB
C++
1454 lines
40 KiB
C++
//
|
|
// ********************************************************************
|
|
// * License and Disclaimer *
|
|
// * *
|
|
// * The Geant4 software is copyright of the Copyright Holders of *
|
|
// * the Geant4 Collaboration. It is provided under the terms and *
|
|
// * conditions of the Geant4 Software License, included in the file *
|
|
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
|
// * include a list of copyright holders. *
|
|
// * *
|
|
// * 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. Please see the license in the file LICENSE and URL above *
|
|
// * for the full disclaimer and the limitation of liability. *
|
|
// * *
|
|
// * This code implementation is the result of the scientific and *
|
|
// * technical work of the GEANT4 collaboration. *
|
|
// * By using, copying, modifying or distributing the software (or *
|
|
// * any work based on the software) you agree to acknowledge its *
|
|
// * use in resulting scientific publications, and indicate your *
|
|
// * acceptance of all terms of the Geant4 Software license. *
|
|
// ********************************************************************
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// Andrew Walkden 27th March 1996
|
|
// OpenGL view - opens window, hard copy, etc.
|
|
|
|
#include "G4OpenGLViewer.hh"
|
|
#include "G4OpenGLSceneHandler.hh"
|
|
#include "G4OpenGLTransform3D.hh"
|
|
|
|
#include "G4gl2ps.hh"
|
|
#define GL2PS_TEXT_B TOOLS_GL2PS_TEXT_B
|
|
#define GL2PS_TEXT_BL TOOLS_GL2PS_TEXT_BL
|
|
#define GL2PS_TEXT_BR TOOLS_GL2PS_TEXT_BR
|
|
|
|
#include "G4Scene.hh"
|
|
#include "G4VisExtent.hh"
|
|
#include "G4LogicalVolume.hh"
|
|
#include "G4VSolid.hh"
|
|
#include "G4Point3D.hh"
|
|
#include "G4Normal3D.hh"
|
|
#include "G4Plane3D.hh"
|
|
#include "G4AttHolder.hh"
|
|
#include "G4AttCheck.hh"
|
|
#include "G4Text.hh"
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <iomanip>
|
|
|
|
G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene):
|
|
G4VViewer (scene, -1),
|
|
fPrintColour (true),
|
|
fVectoredPs (true),
|
|
fOpenGLSceneHandler(scene),
|
|
background (G4Colour(0.,0.,0.)),
|
|
transparency_enabled (true),
|
|
antialiasing_enabled (false),
|
|
haloing_enabled (false),
|
|
fRot_sens(1.),
|
|
fPan_sens(0.01),
|
|
fWinSize_x(0),
|
|
fWinSize_y(0),
|
|
fDefaultExportImageFormat("pdf"),
|
|
fExportImageFormat("pdf"),
|
|
fExportFilenameIndex(0),
|
|
fPrintSizeX(-1),
|
|
fPrintSizeY(-1),
|
|
fPointSize (0),
|
|
fDefaultExportFilename("G4OpenGL"),
|
|
fSizeHasChanged(0),
|
|
fGl2psDefaultLineWith(1),
|
|
fGl2psDefaultPointSize(2),
|
|
fGlViewInitialized(false),
|
|
fIsGettingPickInfos(false)
|
|
{
|
|
// Make changes to view parameters for OpenGL...
|
|
fVP.SetAutoRefresh(true);
|
|
fDefaultVP.SetAutoRefresh(true);
|
|
fGL2PSAction = new G4gl2ps();
|
|
tools_gl2ps_gl_funcs_t _funcs = {
|
|
(tools_glIsEnabled_func)glIsEnabled,
|
|
(tools_glBegin_func)glBegin,
|
|
(tools_glEnd_func)glEnd,
|
|
(tools_glGetFloatv_func)glGetFloatv,
|
|
(tools_glVertex3f_func)glVertex3f,
|
|
(tools_glGetBooleanv_func)glGetBooleanv,
|
|
(tools_glGetIntegerv_func)glGetIntegerv,
|
|
(tools_glRenderMode_func)glRenderMode,
|
|
(tools_glFeedbackBuffer_func)glFeedbackBuffer,
|
|
(tools_glPassThrough_func)glPassThrough
|
|
};
|
|
fGL2PSAction->setOpenGLFunctions(&_funcs);
|
|
|
|
// add supported export image format
|
|
addExportImageFormat("eps");
|
|
addExportImageFormat("ps");
|
|
addExportImageFormat("pdf");
|
|
addExportImageFormat("svg");
|
|
|
|
// Change the default name
|
|
fExportFilename += fDefaultExportFilename + "_" + GetShortName().data();
|
|
|
|
// glClearColor (0.0, 0.0, 0.0, 0.0);
|
|
// glClearDepth (1.0);
|
|
// glDisable (GL_BLEND);
|
|
// glDisable (GL_LINE_SMOOTH);
|
|
// glDisable (GL_POLYGON_SMOOTH);
|
|
|
|
}
|
|
|
|
G4OpenGLViewer::~G4OpenGLViewer ()
|
|
{
|
|
delete fGL2PSAction;
|
|
}
|
|
|
|
void G4OpenGLViewer::InitializeGLView ()
|
|
{
|
|
if (fWinSize_x == 0) {
|
|
fWinSize_x = fVP.GetWindowSizeHintX();
|
|
}
|
|
if (fWinSize_y == 0) {
|
|
fWinSize_y = fVP.GetWindowSizeHintY();
|
|
}
|
|
|
|
glClearColor (0.0, 0.0, 0.0, 0.0);
|
|
glClearDepth (1.0);
|
|
glDisable (GL_LINE_SMOOTH);
|
|
glDisable (GL_POLYGON_SMOOTH);
|
|
glDisable (GL_POINT_SMOOTH);
|
|
|
|
// clear the buffers and window?
|
|
ClearView ();
|
|
FinishView ();
|
|
|
|
glDepthFunc (GL_LEQUAL);
|
|
glDepthMask (GL_TRUE);
|
|
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
void G4OpenGLViewer::ClearView () {
|
|
ClearViewWithoutFlush();
|
|
|
|
if(!isFramebufferReady()) {
|
|
return;
|
|
}
|
|
|
|
glFlush();
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::ClearViewWithoutFlush () {
|
|
// Ready for clear ?
|
|
// See : http://lists.apple.com/archives/mac-opengl/2012/Jul/msg00038.html
|
|
if(!isFramebufferReady()) {
|
|
return;
|
|
}
|
|
|
|
glClearColor (background.GetRed(),
|
|
background.GetGreen(),
|
|
background.GetBlue(),
|
|
1.);
|
|
glClearDepth (1.0);
|
|
//Below line does not compile with Mesa includes.
|
|
//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glClear (GL_COLOR_BUFFER_BIT);
|
|
glClear (GL_DEPTH_BUFFER_BIT);
|
|
glClear (GL_STENCIL_BUFFER_BIT);
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::ResizeWindow(unsigned int aWidth, unsigned int aHeight) {
|
|
if ((fWinSize_x != aWidth) || (fWinSize_y != aHeight)) {
|
|
fWinSize_x = aWidth;
|
|
fWinSize_y = aHeight;
|
|
fSizeHasChanged = true;
|
|
} else {
|
|
fSizeHasChanged = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the viewport of the scene
|
|
* MAXIMUM SIZE is :
|
|
* GLint dims[2];
|
|
* glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
|
|
*/
|
|
void G4OpenGLViewer::ResizeGLView()
|
|
{
|
|
// Check size
|
|
GLint dims[2];
|
|
dims[0] = 0;
|
|
dims[1] = 0;
|
|
|
|
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
|
|
|
|
if ((dims[0] !=0 ) && (dims[1] !=0)) {
|
|
|
|
if (fWinSize_x > (unsigned)dims[0]) {
|
|
G4cerr << "Try to resize view greater than max X viewport dimension. Desired size "<<fWinSize_x <<" is resize to "<< dims[0] << G4endl;
|
|
fWinSize_x = dims[0];
|
|
}
|
|
if (fWinSize_y > (unsigned)dims[1]) {
|
|
G4cerr << "Try to resize view greater than max Y viewport dimension. Desired size "<<fWinSize_y <<" is resize to "<< dims[1] << G4endl;
|
|
fWinSize_y = dims[1];
|
|
}
|
|
}
|
|
|
|
glViewport(0, 0, fWinSize_x,fWinSize_y);
|
|
|
|
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::SetView () {
|
|
// if getting pick infos, should not resize the view.
|
|
if (fIsGettingPickInfos) return;
|
|
|
|
if (!fSceneHandler.GetScene()) {
|
|
return;
|
|
}
|
|
// Calculates view representation based on extent of object being
|
|
// viewed and (initial) viewpoint. (Note: it can change later due
|
|
// to user interaction via visualization system's GUI.)
|
|
|
|
// Lighting.
|
|
GLfloat lightPosition [4];
|
|
lightPosition [0] = fVP.GetActualLightpointDirection().x();
|
|
lightPosition [1] = fVP.GetActualLightpointDirection().y();
|
|
lightPosition [2] = fVP.GetActualLightpointDirection().z();
|
|
lightPosition [3] = 0.;
|
|
// Light position is "true" light direction, so must come after gluLookAt.
|
|
GLfloat ambient [] = { 0.2f, 0.2f, 0.2f, 1.f};
|
|
GLfloat diffuse [] = { 0.8f, 0.8f, 0.8f, 1.f};
|
|
glEnable (GL_LIGHT0);
|
|
glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
|
|
glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
|
|
|
|
G4double ratioX = 1;
|
|
G4double ratioY = 1;
|
|
if (fWinSize_y > fWinSize_x) {
|
|
ratioX = ((G4double)fWinSize_y) / ((G4double)fWinSize_x);
|
|
}
|
|
if (fWinSize_x > fWinSize_y) {
|
|
ratioY = ((G4double)fWinSize_x) / ((G4double)fWinSize_y);
|
|
}
|
|
|
|
// Get radius of scene, etc.
|
|
// Note that this procedure properly takes into account zoom, dolly and pan.
|
|
const G4Point3D targetPoint
|
|
= fSceneHandler.GetScene()->GetStandardTargetPoint()
|
|
+ fVP.GetCurrentTargetPoint ();
|
|
G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
|
|
if(radius<=0.) radius = 1.;
|
|
const G4double cameraDistance = fVP.GetCameraDistance (radius);
|
|
const G4Point3D cameraPosition =
|
|
targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
|
|
const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius);
|
|
const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius);
|
|
const GLdouble right = fVP.GetFrontHalfHeight (pnear, radius) * ratioY;
|
|
const GLdouble left = -right;
|
|
const GLdouble top = fVP.GetFrontHalfHeight (pnear, radius) * ratioX;
|
|
const GLdouble bottom = -top;
|
|
|
|
// FIXME
|
|
ResizeGLView();
|
|
//SHOULD SetWindowsSizeHint()...
|
|
|
|
glMatrixMode (GL_PROJECTION); // set up Frustum.
|
|
glLoadIdentity();
|
|
|
|
const G4Vector3D scaleFactor = fVP.GetScaleFactor();
|
|
glScaled(scaleFactor.x(),scaleFactor.y(),scaleFactor.z());
|
|
|
|
if (fVP.GetFieldHalfAngle() == 0.) {
|
|
g4GlOrtho (left, right, bottom, top, pnear, pfar);
|
|
}
|
|
else {
|
|
g4GlFrustum (left, right, bottom, top, pnear, pfar);
|
|
}
|
|
|
|
glMatrixMode (GL_MODELVIEW); // apply further transformations to scene.
|
|
glLoadIdentity();
|
|
|
|
const G4Normal3D& upVector = fVP.GetUpVector ();
|
|
G4Point3D gltarget;
|
|
if (cameraDistance > 1.e-6 * radius) {
|
|
gltarget = targetPoint;
|
|
}
|
|
else {
|
|
gltarget = targetPoint - radius * fVP.GetViewpointDirection().unit();
|
|
}
|
|
|
|
const G4Point3D& pCamera = cameraPosition; // An alias for brevity.
|
|
|
|
g4GluLookAt (pCamera.x(), pCamera.y(), pCamera.z(), // Viewpoint.
|
|
gltarget.x(), gltarget.y(), gltarget.z(), // Target point.
|
|
upVector.x(), upVector.y(), upVector.z()); // Up vector.
|
|
// Light position is "true" light direction, so must come after gluLookAt.
|
|
glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
|
|
|
|
// The idea is to use back-to-back clipping planes. This can cut an object
|
|
// down to just a few pixels, which can make it difficult to see. So, for
|
|
// now, comment this out and use the generic (Boolean) method, via
|
|
// G4VSolid* G4OpenGLSceneHandler::CreateSectionSolid ()
|
|
// { return G4VSceneHandler::CreateSectionSolid(); }
|
|
// if (fVP.IsSection () ) { // pair of back to back clip planes.
|
|
// const G4Plane3D& sp = fVP.GetSectionPlane ();
|
|
// double sArray[4];
|
|
// sArray[0] = sp.a();
|
|
// sArray[1] = sp.b();
|
|
// sArray[2] = sp.c();
|
|
// sArray[3] = sp.d() + radius * 1.e-05;
|
|
// glClipPlane (GL_CLIP_PLANE0, sArray);
|
|
// glEnable (GL_CLIP_PLANE0);
|
|
// sArray[0] = -sp.a();
|
|
// sArray[1] = -sp.b();
|
|
// sArray[2] = -sp.c();
|
|
// sArray[3] = -sp.d() + radius * 1.e-05;
|
|
// glClipPlane (GL_CLIP_PLANE1, sArray);
|
|
// glEnable (GL_CLIP_PLANE1);
|
|
// } else {
|
|
// glDisable (GL_CLIP_PLANE0);
|
|
// glDisable (GL_CLIP_PLANE1);
|
|
// }
|
|
|
|
// What we call intersection of cutaways is easy in OpenGL. You
|
|
// just keep cutting. Unions are more tricky - you have to have
|
|
// multiple passes and this is handled in
|
|
// G4OpenGLImmediate/StoredViewer::ProcessView.
|
|
const G4Planes& cutaways = fVP.GetCutawayPlanes();
|
|
size_t nPlanes = cutaways.size();
|
|
if (fVP.IsCutaway() &&
|
|
fVP.GetCutawayMode() == G4ViewParameters::cutawayIntersection) {
|
|
double a[4];
|
|
a[0] = cutaways[0].a();
|
|
a[1] = cutaways[0].b();
|
|
a[2] = cutaways[0].c();
|
|
a[3] = cutaways[0].d();
|
|
glClipPlane (GL_CLIP_PLANE2, a);
|
|
glEnable (GL_CLIP_PLANE2);
|
|
if (nPlanes > 1) {
|
|
a[0] = cutaways[1].a();
|
|
a[1] = cutaways[1].b();
|
|
a[2] = cutaways[1].c();
|
|
a[3] = cutaways[1].d();
|
|
glClipPlane (GL_CLIP_PLANE3, a);
|
|
glEnable (GL_CLIP_PLANE3);
|
|
}
|
|
if (nPlanes > 2) {
|
|
a[0] = cutaways[2].a();
|
|
a[1] = cutaways[2].b();
|
|
a[2] = cutaways[2].c();
|
|
a[3] = cutaways[2].d();
|
|
glClipPlane (GL_CLIP_PLANE4, a);
|
|
glEnable (GL_CLIP_PLANE4);
|
|
}
|
|
} else {
|
|
glDisable (GL_CLIP_PLANE2);
|
|
glDisable (GL_CLIP_PLANE3);
|
|
glDisable (GL_CLIP_PLANE4);
|
|
}
|
|
|
|
// Background.
|
|
background = fVP.GetBackgroundColour ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void G4OpenGLViewer::ResetView () {
|
|
G4VViewer::ResetView();
|
|
fRot_sens = 1;
|
|
fPan_sens = 0.01;
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::HaloingFirstPass () {
|
|
|
|
//To perform haloing, first Draw all information to the depth buffer
|
|
//alone, using a chunky line width, and then Draw all info again, to
|
|
//the colour buffer, setting a thinner line width an the depth testing
|
|
//function to less than or equal, so if two lines cross, the one
|
|
//passing behind the other will not pass the depth test, and so not
|
|
//get rendered either side of the infront line for a short distance.
|
|
|
|
//First, disable writing to the colo(u)r buffer...
|
|
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
|
|
//Now enable writing to the depth buffer...
|
|
glDepthMask (GL_TRUE);
|
|
glDepthFunc (GL_LESS);
|
|
glClearDepth (1.0);
|
|
|
|
//Finally, set the line width to something wide...
|
|
ChangeLineWidth(3.0);
|
|
|
|
}
|
|
|
|
void G4OpenGLViewer::HaloingSecondPass () {
|
|
|
|
//And finally, turn the colour buffer back on with a sesible line width...
|
|
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDepthFunc (GL_LEQUAL);
|
|
ChangeLineWidth(1.0);
|
|
|
|
}
|
|
|
|
G4String G4OpenGLViewer::Pick(GLdouble x, GLdouble y)
|
|
{
|
|
const std::vector < G4OpenGLViewerPickMap* > & pickMap = GetPickDetails(x,y);
|
|
G4String txt = "";
|
|
if (pickMap.size() == 0) {
|
|
// txt += "No hits recorded.";;
|
|
} else {
|
|
for (unsigned int a=0; a < pickMap.size(); a++) {
|
|
if (pickMap[a]->getAttributes().size() > 0) {
|
|
txt += pickMap[a]->print();
|
|
}
|
|
}
|
|
}
|
|
return txt;
|
|
}
|
|
|
|
const std::vector < G4OpenGLViewerPickMap* > & G4OpenGLViewer::GetPickDetails(GLdouble x, GLdouble y)
|
|
{
|
|
static std::vector < G4OpenGLViewerPickMap* > pickMapVector;
|
|
for (auto pickMap: pickMapVector) {
|
|
delete pickMap;
|
|
}
|
|
pickMapVector.clear();
|
|
|
|
const G4int BUFSIZE = 512;
|
|
GLuint selectBuffer[BUFSIZE];
|
|
glSelectBuffer(BUFSIZE, selectBuffer);
|
|
glRenderMode(GL_SELECT);
|
|
glInitNames();
|
|
glPushName(0);
|
|
glMatrixMode(GL_PROJECTION);
|
|
G4double currentProjectionMatrix[16];
|
|
glGetDoublev(GL_PROJECTION_MATRIX, currentProjectionMatrix);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
GLint viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
/* G4cout
|
|
<< "viewport, x,y: "
|
|
<< viewport[0] << ',' << viewport[1] << ',' << viewport[2] << ',' << viewport[3]
|
|
<< ", " << x << ',' << y
|
|
<< G4endl;
|
|
*/
|
|
fIsGettingPickInfos = true;
|
|
// Define 5x5 pixel pick area
|
|
g4GluPickMatrix(x, viewport[3] - y, 5., 5., viewport);
|
|
glMultMatrixd(currentProjectionMatrix);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
DrawView();
|
|
GLint hits = glRenderMode(GL_RENDER);
|
|
fIsGettingPickInfos = false;
|
|
if (hits < 0) {
|
|
G4cout << "Too many hits. Zoom in to reduce overlaps." << G4endl;
|
|
goto restoreMatrices;
|
|
}
|
|
if (hits > 0) {
|
|
GLuint* p = selectBuffer;
|
|
for (GLint i = 0; i < hits; ++i) {
|
|
GLuint nnames = *p++;
|
|
// This bit of debug code or...
|
|
//GLuint zmin = *p++;
|
|
//GLuint zmax = *p++;
|
|
//G4cout << "Hit " << i << ": " << nnames << " names"
|
|
// << "\nzmin: " << zmin << ", zmax: " << zmax << G4endl;
|
|
// ...just increment the pointer
|
|
p++;
|
|
p++;
|
|
for (GLuint j = 0; j < nnames; ++j) {
|
|
GLuint name = *p++;
|
|
std::map<GLuint, G4AttHolder*>::iterator iter =
|
|
fOpenGLSceneHandler.fPickMap.find(name);
|
|
if (iter != fOpenGLSceneHandler.fPickMap.end()) {
|
|
G4AttHolder* attHolder = iter->second;
|
|
if(attHolder && attHolder->GetAttDefs().size()) {
|
|
for (size_t iAtt = 0;
|
|
iAtt < attHolder->GetAttDefs().size(); ++iAtt) {
|
|
std::ostringstream oss;
|
|
oss << G4AttCheck(attHolder->GetAttValues()[iAtt],
|
|
attHolder->GetAttDefs()[iAtt]);
|
|
G4OpenGLViewerPickMap* pickMap = new G4OpenGLViewerPickMap();
|
|
// G4cout
|
|
// << "i,j, attHolder->GetAttDefs().size(): "
|
|
// << i << ',' << j
|
|
// << ", " << attHolder->GetAttDefs().size()
|
|
// << G4endl;
|
|
// G4cout << "G4OpenGLViewer::GetPickDetails: " << oss.str() << G4endl;
|
|
pickMap->addAttributes(oss.str());
|
|
pickMap->setHitNumber(i);
|
|
pickMap->setSubHitNumber(j);
|
|
pickMap->setPickName(name);
|
|
pickMapVector.push_back(pickMap);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
restoreMatrices:
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
return pickMapVector;
|
|
}
|
|
|
|
GLubyte* G4OpenGLViewer::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);
|
|
|
|
glReadBuffer(GL_FRONT);
|
|
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;
|
|
}
|
|
|
|
bool G4OpenGLViewer::printVectoredEPS() {
|
|
return printGl2PS();
|
|
}
|
|
|
|
bool G4OpenGLViewer::printNonVectoredEPS () {
|
|
|
|
int width = getRealExportWidth();
|
|
int height = getRealExportHeight();
|
|
|
|
FILE* fp;
|
|
GLubyte* pixels;
|
|
GLubyte* curpix;
|
|
int components, pos, i;
|
|
|
|
pixels = grabPixels (fPrintColour, width, height);
|
|
|
|
if (pixels == NULL) {
|
|
G4cerr << "Failed to get pixels from OpenGl viewport" << G4endl;
|
|
return false;
|
|
}
|
|
if (fPrintColour) {
|
|
components = 3;
|
|
} else {
|
|
components = 1;
|
|
}
|
|
std::string name = getRealPrintFilename();
|
|
fp = fopen (name.c_str(), "w");
|
|
if (fp == NULL) {
|
|
G4cerr << "Can't open filename " << name.c_str() << G4endl;
|
|
return false;
|
|
}
|
|
|
|
fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n");
|
|
fprintf (fp, "%%%%Title: %s\n", name.c_str());
|
|
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 ", (unsigned short)(*(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);
|
|
|
|
// Reset for next time (useful if size change)
|
|
// fPrintSizeX = -1;
|
|
// fPrintSizeY = -1;
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Return if gl2ps is currently writing
|
|
*/
|
|
bool G4OpenGLViewer::isGl2psWriting() {
|
|
|
|
if (!fGL2PSAction) return false;
|
|
if (fGL2PSAction->fileWritingEnabled()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
G4bool G4OpenGLViewer::isFramebufferReady() {
|
|
bool check = false;
|
|
#ifdef G4VIS_BUILD_OPENGLQT_DRIVER
|
|
check = true;
|
|
#endif
|
|
#ifdef G4VIS_BUILD_OPENGLX_DRIVER
|
|
check = false;
|
|
#endif
|
|
#ifdef G4VIS_BUILD_OPENGLXM_DRIVER
|
|
check = false;
|
|
#endif
|
|
#ifdef G4VIS_BUILD_OPENGLWIN32_DRIVER
|
|
check = false;
|
|
#endif
|
|
|
|
#if GL_ARB_framebuffer_object
|
|
if (check) {
|
|
// if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_UNDEFINED) {
|
|
// return false;
|
|
// }
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
|
|
/* Draw Gl2Ps text if needed
|
|
*/
|
|
void G4OpenGLViewer::DrawText(const G4Text& g4text)
|
|
{
|
|
// gl2ps or GL window ?
|
|
if (isGl2psWriting()) {
|
|
|
|
G4VSceneHandler::MarkerSizeType sizeType;
|
|
G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType);
|
|
G4Point3D position = g4text.GetPosition();
|
|
|
|
G4String textString = g4text.GetText();
|
|
|
|
glRasterPos3d(position.x(),position.y(),position.z());
|
|
GLint align = GL2PS_TEXT_B;
|
|
|
|
switch (g4text.GetLayout()) {
|
|
case G4Text::left: align = GL2PS_TEXT_BL; break;
|
|
case G4Text::centre: align = GL2PS_TEXT_B; break;
|
|
case G4Text::right: align = GL2PS_TEXT_BR;
|
|
}
|
|
|
|
fGL2PSAction->addTextOpt(textString.c_str(),"Times-Roman",GLshort(size),align,0);
|
|
|
|
} else {
|
|
|
|
static G4int callCount = 0;
|
|
++callCount;
|
|
//if (callCount <= 10 || callCount%100 == 0) {
|
|
if (callCount <= 1) {
|
|
G4cout <<
|
|
"G4OpenGLViewer::DrawText: Not implemented for \""
|
|
<< fName <<
|
|
"\"\n Called with "
|
|
<< g4text
|
|
<< G4endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Change PointSize on gl2ps if needed
|
|
*/
|
|
void G4OpenGLViewer::ChangePointSize(G4double size) {
|
|
|
|
if (isGl2psWriting()) {
|
|
fGL2PSAction->setPointSize(int(size));
|
|
} else {
|
|
glPointSize (size);
|
|
}
|
|
}
|
|
|
|
|
|
/** Change LineSize on gl2ps if needed
|
|
*/
|
|
void G4OpenGLViewer::ChangeLineWidth(G4double width) {
|
|
|
|
if (isGl2psWriting()) {
|
|
fGL2PSAction->setLineWidth(int(width));
|
|
} else {
|
|
glLineWidth (width);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Export image with the given name with width and height
|
|
Several cases :
|
|
If name is "", filename will have the default value
|
|
If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added.
|
|
If name is "toto", set the name to "toto" and the format to default (or current format if specify).
|
|
Will also add an incremented suffix at the end of the file
|
|
*/
|
|
bool G4OpenGLViewer::exportImage(std::string name, int width, int height) {
|
|
|
|
if (! setExportFilename(name)) {
|
|
return false;
|
|
}
|
|
|
|
if ((width != -1) && (height != -1)) {
|
|
setExportSize(width, height);
|
|
}
|
|
|
|
if (fExportImageFormat == "eps") {
|
|
fGL2PSAction->setExportImageFormat_EPS();
|
|
} else if (fExportImageFormat == "ps") {
|
|
fGL2PSAction->setExportImageFormat_PS();
|
|
} else if (fExportImageFormat == "svg") {
|
|
fGL2PSAction->setExportImageFormat_SVG();
|
|
} else if (fExportImageFormat == "pdf") {
|
|
fGL2PSAction->setExportImageFormat_PDF();
|
|
} else {
|
|
setExportImageFormat(fExportImageFormat,true); // will display a message if this format is not correct for the current viewer
|
|
return false;
|
|
}
|
|
|
|
bool res;
|
|
|
|
// Change the LC_NUMERIC value in order to have "." separtor and not ","
|
|
// This case is only useful for French, Canadien...
|
|
size_t len = strlen(setlocale(LC_NUMERIC,NULL));
|
|
char* oldLocale = (char*)(malloc(len+1));
|
|
if(oldLocale!=NULL) strncpy(oldLocale,setlocale(LC_NUMERIC,NULL),len);
|
|
setlocale(LC_NUMERIC,"C");
|
|
|
|
if (((fExportImageFormat == "eps") || (fExportImageFormat == "ps")) && (!fVectoredPs)) {
|
|
res = printNonVectoredEPS();
|
|
} else {
|
|
res = printVectoredEPS();
|
|
}
|
|
|
|
// restore the local
|
|
if (oldLocale) {
|
|
setlocale(LC_NUMERIC,oldLocale);
|
|
free(oldLocale);
|
|
}
|
|
|
|
if (res == false) {
|
|
G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl;
|
|
} else {
|
|
G4cout << "File " << getRealPrintFilename().c_str() << " size: " << getRealExportWidth() << "x" << getRealExportHeight() << " has been saved " << G4endl;
|
|
|
|
// increment index if necessary
|
|
if ( fExportFilenameIndex != -1) {
|
|
fExportFilenameIndex++;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
bool G4OpenGLViewer::printGl2PS() {
|
|
|
|
int width = getRealExportWidth();
|
|
int height = getRealExportHeight();
|
|
bool res = true;
|
|
|
|
// no need to redraw at each new primitive for printgl2PS
|
|
G4OpenGLSceneHandler& oglSceneHandler = dynamic_cast<G4OpenGLSceneHandler&>(fSceneHandler);
|
|
G4OpenGLSceneHandler::FlushAction originalFlushAction = oglSceneHandler.GetFlushAction();
|
|
oglSceneHandler.SetFlushAction(G4OpenGLSceneHandler::never);
|
|
|
|
if (!fGL2PSAction) return false;
|
|
|
|
fGL2PSAction->setFileName(getRealPrintFilename().c_str());
|
|
// try to resize
|
|
int X = fWinSize_x;
|
|
int Y = fWinSize_y;
|
|
|
|
fWinSize_x = width;
|
|
fWinSize_y = height;
|
|
// Laurent G. 16/03/10 : Not the good way to do.
|
|
// We should draw in a new offscreen context instead of
|
|
// resizing and drawing in current window...
|
|
// This should be solve when we will do an offscreen method
|
|
// to render OpenGL
|
|
// See :
|
|
// http://developer.apple.com/Mac/library/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_offscreen/opengl_offscreen.html
|
|
// http://www.songho.ca/opengl/gl_fbo.html
|
|
|
|
ResizeGLView();
|
|
bool extendBuffer = true;
|
|
bool endWriteAction = false;
|
|
bool beginWriteAction = true;
|
|
bool filePointerOk = true;
|
|
while ((extendBuffer) && (! endWriteAction) && (filePointerOk)) {
|
|
|
|
beginWriteAction = fGL2PSAction->enableFileWriting();
|
|
if(beginWriteAction) {
|
|
GLint vp[4];
|
|
::glGetIntegerv(GL_VIEWPORT,vp);
|
|
fGL2PSAction->setViewport(vp[0],vp[1],vp[2],vp[3]);
|
|
beginWriteAction = fGL2PSAction->beginPage();
|
|
}
|
|
|
|
// 3 cases :
|
|
// - true
|
|
// - false && ! fGL2PSAction->fileWritingEnabled() => bad file name
|
|
// - false && fGL2PSAction->fileWritingEnabled() => buffer size problem ?
|
|
|
|
filePointerOk = fGL2PSAction->fileWritingEnabled();
|
|
|
|
if (beginWriteAction) {
|
|
|
|
// Set the viewport
|
|
// By default, we choose the line width (trajectories...)
|
|
fGL2PSAction->setLineWidth(fGl2psDefaultLineWith);
|
|
// By default, we choose the point size (markers...)
|
|
fGL2PSAction->setPointSize(fGl2psDefaultPointSize);
|
|
|
|
DrawView ();
|
|
|
|
endWriteAction = fGL2PSAction->endPage();
|
|
fGL2PSAction->disableFileWriting();
|
|
}
|
|
if (filePointerOk) {
|
|
if ((! endWriteAction) || (! beginWriteAction)) {
|
|
extendBuffer = fGL2PSAction->extendBufferSize();
|
|
}
|
|
}
|
|
}
|
|
fGL2PSAction->resetBufferSizeParameters();
|
|
|
|
if (!extendBuffer ) {
|
|
G4cerr << "ERROR: gl2ps buffer size is not big enough to print this geometry. Try to extend it. No output produced"<< G4endl;
|
|
res = false;
|
|
}
|
|
if (!beginWriteAction ) {
|
|
G4cerr << "ERROR: saving file "<<getRealPrintFilename().c_str()<<". Check read/write access. No output produced" << G4endl;
|
|
res = false;
|
|
}
|
|
if (!endWriteAction ) {
|
|
G4cerr << "gl2ps error. No output produced" << G4endl;
|
|
res = false;
|
|
}
|
|
fWinSize_x = X;
|
|
fWinSize_y = Y;
|
|
|
|
oglSceneHandler.SetFlushAction(originalFlushAction);
|
|
|
|
// Reset for next time (useful is size change)
|
|
// fPrintSizeX = 0;
|
|
// fPrintSizeY = 0;
|
|
|
|
return res;
|
|
}
|
|
|
|
unsigned int G4OpenGLViewer::getWinWidth() const{
|
|
return fWinSize_x;
|
|
}
|
|
|
|
unsigned int G4OpenGLViewer::getWinHeight() const{
|
|
return fWinSize_y;
|
|
}
|
|
|
|
G4bool G4OpenGLViewer::sizeHasChanged() {
|
|
return fSizeHasChanged;
|
|
}
|
|
|
|
G4int G4OpenGLViewer::getRealExportWidth() {
|
|
if (fPrintSizeX == -1) {
|
|
return fWinSize_x;
|
|
}
|
|
GLint dims[2];
|
|
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
|
|
|
|
// L.Garnier 01-2010: Some problems with mac 10.6
|
|
if ((dims[0] !=0 ) && (dims[1] !=0)) {
|
|
if (fPrintSizeX > dims[0]){
|
|
return dims[0];
|
|
}
|
|
}
|
|
if (fPrintSizeX < -1){
|
|
return 0;
|
|
}
|
|
return fPrintSizeX;
|
|
}
|
|
|
|
G4int G4OpenGLViewer::getRealExportHeight() {
|
|
if (fPrintSizeY == -1) {
|
|
return fWinSize_y;
|
|
}
|
|
GLint dims[2];
|
|
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
|
|
|
|
// L.Garnier 01-2010: Some problems with mac 10.6
|
|
if ((dims[0] !=0 ) && (dims[1] !=0)) {
|
|
if (fPrintSizeY > dims[1]){
|
|
return dims[1];
|
|
}
|
|
}
|
|
if (fPrintSizeY < -1){
|
|
return 0;
|
|
}
|
|
return fPrintSizeY;
|
|
}
|
|
|
|
void G4OpenGLViewer::setExportSize(G4int X, G4int Y) {
|
|
fPrintSizeX = X;
|
|
fPrintSizeY = Y;
|
|
}
|
|
|
|
/**
|
|
If name is "" or "!", filename and extension will have the default value.
|
|
If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added.
|
|
If name is "toto", set the name to "toto" and the format to default (or current format if specify).
|
|
If name is the same as previous, do not reset incremented suffix.
|
|
*/
|
|
bool G4OpenGLViewer::setExportFilename(G4String name,G4bool inc) {
|
|
if (name == "!") {
|
|
name = "";
|
|
}
|
|
|
|
if (inc) {
|
|
if ((name != "") && (fExportFilename != name)) {
|
|
fExportFilenameIndex=0;
|
|
}
|
|
} else {
|
|
fExportFilenameIndex=-1;
|
|
}
|
|
|
|
if (name.size() == 0) {
|
|
name = getRealPrintFilename().c_str();
|
|
} else {
|
|
// guess format by extention
|
|
std::string extension = name.substr(name.find_last_of(".") + 1);
|
|
// If there is a dot in the name the above might find rubbish, so...
|
|
if (extension.size() >= 3 && extension.size() <= 4) { // Possible extension
|
|
if (setExportImageFormat(extension, false)) { // Extension found
|
|
fExportFilename = name.substr(0,name.find_last_of("."));
|
|
} else { // No viable extension found
|
|
return false;
|
|
}
|
|
} else { // Assume name is already the required without-extension part
|
|
fExportFilename = name;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::string G4OpenGLViewer::getRealPrintFilename() {
|
|
std::string temp = fExportFilename;
|
|
if (fExportFilenameIndex != -1) {
|
|
temp += std::string("_");
|
|
std::ostringstream os;
|
|
os << std::setw(4) << std::setfill('0') << fExportFilenameIndex;
|
|
std::string nb_str = os.str();
|
|
temp += nb_str;
|
|
}
|
|
temp += "."+fExportImageFormat;
|
|
return temp;
|
|
}
|
|
|
|
G4double G4OpenGLViewer::GetSceneNearWidth()
|
|
{
|
|
if (!fSceneHandler.GetScene()) {
|
|
return 0;
|
|
}
|
|
const G4Point3D targetPoint
|
|
= fSceneHandler.GetScene()->GetStandardTargetPoint()
|
|
+ fVP.GetCurrentTargetPoint ();
|
|
G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
|
|
if(radius<=0.) radius = 1.;
|
|
const G4double cameraDistance = fVP.GetCameraDistance (radius);
|
|
const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius);
|
|
return 2 * fVP.GetFrontHalfHeight (pnear, radius);
|
|
}
|
|
|
|
GLdouble G4OpenGLViewer::getSceneFarWidth()
|
|
{
|
|
if (!fSceneHandler.GetScene()) {
|
|
return 0;
|
|
}
|
|
const G4Point3D targetPoint
|
|
= fSceneHandler.GetScene()->GetStandardTargetPoint()
|
|
+ fVP.GetCurrentTargetPoint ();
|
|
G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
|
|
if(radius<=0.) radius = 1.;
|
|
const G4double cameraDistance = fVP.GetCameraDistance (radius);
|
|
const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius);
|
|
const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius);
|
|
return 2 * fVP.GetFrontHalfHeight (pfar, radius);
|
|
}
|
|
|
|
|
|
GLdouble G4OpenGLViewer::getSceneDepth()
|
|
{
|
|
if (!fSceneHandler.GetScene()) {
|
|
return 0;
|
|
}
|
|
const G4Point3D targetPoint
|
|
= fSceneHandler.GetScene()->GetStandardTargetPoint()
|
|
+ fVP.GetCurrentTargetPoint ();
|
|
G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
|
|
if(radius<=0.) radius = 1.;
|
|
const G4double cameraDistance = fVP.GetCameraDistance (radius);
|
|
const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius);
|
|
return fVP.GetFarDistance (cameraDistance, pnear, radius)- pnear;
|
|
}
|
|
|
|
|
|
|
|
void G4OpenGLViewer::rotateScene(G4double dx, G4double dy)
|
|
{
|
|
if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) {
|
|
rotateSceneInViewDirection(dx,dy);
|
|
} else {
|
|
if( dx != 0) {
|
|
rotateSceneThetaPhi(dx,0);
|
|
}
|
|
if( dy != 0) {
|
|
rotateSceneThetaPhi(0,dy);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::rotateSceneToggle(G4double dx, G4double dy)
|
|
{
|
|
if (fVP.GetRotationStyle() != G4ViewParameters::freeRotation) {
|
|
rotateSceneInViewDirection(dx,dy);
|
|
} else {
|
|
if( dx != 0) {
|
|
rotateSceneThetaPhi(dx,0);
|
|
}
|
|
if( dy != 0) {
|
|
rotateSceneThetaPhi(0,dy);
|
|
}
|
|
}
|
|
}
|
|
|
|
void G4OpenGLViewer::rotateSceneThetaPhi(G4double dx, G4double dy)
|
|
{
|
|
if (!fSceneHandler.GetScene()) {
|
|
return;
|
|
}
|
|
|
|
G4Vector3D vp;
|
|
G4Vector3D up;
|
|
|
|
G4Vector3D xprime;
|
|
G4Vector3D yprime;
|
|
G4Vector3D zprime;
|
|
|
|
G4double delta_alpha;
|
|
G4double delta_theta;
|
|
|
|
G4Vector3D new_vp;
|
|
G4Vector3D new_up;
|
|
|
|
G4double cosalpha;
|
|
G4double sinalpha;
|
|
|
|
G4Vector3D a1;
|
|
G4Vector3D a2;
|
|
G4Vector3D delta;
|
|
G4Vector3D viewPoint;
|
|
|
|
|
|
//phi spin stuff here
|
|
|
|
vp = fVP.GetViewpointDirection ().unit ();
|
|
up = fVP.GetUpVector ().unit ();
|
|
|
|
yprime = (up.cross(vp)).unit();
|
|
zprime = (vp.cross(yprime)).unit();
|
|
|
|
if (fVP.GetLightsMoveWithCamera()) {
|
|
delta_alpha = dy * fRot_sens;
|
|
delta_theta = -dx * fRot_sens;
|
|
} else {
|
|
delta_alpha = -dy * fRot_sens;
|
|
delta_theta = dx * fRot_sens;
|
|
}
|
|
|
|
delta_alpha *= CLHEP::deg;
|
|
delta_theta *= CLHEP::deg;
|
|
|
|
new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime;
|
|
|
|
// to avoid z rotation flipping
|
|
// to allow more than 360° rotation
|
|
|
|
if (fVP.GetLightsMoveWithCamera()) {
|
|
new_up = (new_vp.cross(yprime)).unit();
|
|
if (new_vp.z()*vp.z() <0) {
|
|
new_up.set(new_up.x(),-new_up.y(),new_up.z());
|
|
}
|
|
} else {
|
|
new_up = up;
|
|
if (new_vp.z()*vp.z() <0) {
|
|
new_up.set(new_up.x(),-new_up.y(),new_up.z());
|
|
}
|
|
}
|
|
fVP.SetUpVector(new_up);
|
|
////////////////
|
|
// Rotates by fixed azimuthal angle delta_theta.
|
|
|
|
cosalpha = new_up.dot (new_vp.unit());
|
|
sinalpha = std::sqrt (1. - std::pow (cosalpha, 2));
|
|
yprime = (new_up.cross (new_vp.unit())).unit ();
|
|
xprime = yprime.cross (new_up);
|
|
// Projection of vp on plane perpendicular to up...
|
|
a1 = sinalpha * xprime;
|
|
// Required new projection...
|
|
a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime);
|
|
// Required Increment vector...
|
|
delta = a2 - a1;
|
|
// So new viewpoint is...
|
|
viewPoint = new_vp.unit() + delta;
|
|
|
|
fVP.SetViewAndLights (viewPoint);
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::rotateSceneInViewDirection(G4double dx, G4double dy)
|
|
{
|
|
if (!fSceneHandler.GetScene()) {
|
|
return;
|
|
}
|
|
|
|
G4Vector3D vp;
|
|
G4Vector3D up;
|
|
|
|
G4Vector3D xprime;
|
|
G4Vector3D yprime;
|
|
G4Vector3D zprime;
|
|
|
|
G4Vector3D new_vp;
|
|
G4Vector3D new_up;
|
|
|
|
G4Vector3D a1;
|
|
G4Vector3D a2;
|
|
G4Vector3D delta;
|
|
G4Vector3D viewPoint;
|
|
|
|
dx = dx/100;
|
|
dy = dy/100;
|
|
|
|
//phi spin stuff here
|
|
|
|
vp = fVP.GetViewpointDirection ().unit();
|
|
up = fVP.GetUpVector ().unit();
|
|
|
|
G4Vector3D zPrimeVector = G4Vector3D(up.y()*vp.z()-up.z()*vp.y(),
|
|
up.z()*vp.x()-up.x()*vp.z(),
|
|
up.x()*vp.y()-up.y()*vp.x());
|
|
|
|
viewPoint = vp/fRot_sens + (zPrimeVector*dx - up*dy) ;
|
|
new_up = G4Vector3D(viewPoint.y()*zPrimeVector.z()-viewPoint.z()*zPrimeVector.y(),
|
|
viewPoint.z()*zPrimeVector.x()-viewPoint.x()*zPrimeVector.z(),
|
|
viewPoint.x()*zPrimeVector.y()-viewPoint.y()*zPrimeVector.x());
|
|
|
|
G4Vector3D new_upUnit = new_up.unit();
|
|
|
|
|
|
|
|
fVP.SetUpVector(new_upUnit);
|
|
fVP.SetViewAndLights (viewPoint);
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::addExportImageFormat(std::string format) {
|
|
fExportImageFormatVector.push_back(format);
|
|
}
|
|
|
|
bool G4OpenGLViewer::setExportImageFormat(std::string format, bool quiet) {
|
|
bool found = false;
|
|
std::string list;
|
|
for (unsigned int a=0; a<fExportImageFormatVector.size(); a++) {
|
|
list +=fExportImageFormatVector.at(a) + " ";
|
|
|
|
if (fExportImageFormatVector.at(a) == format) {
|
|
if (! quiet) {
|
|
G4cout << " Changing export format to \"" << format << "\"" << G4endl;
|
|
}
|
|
if (format != fExportImageFormat) {
|
|
fExportFilenameIndex = 0;
|
|
fExportImageFormat = format;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
if (! found) {
|
|
if (format.size() == 0) {
|
|
G4cout << " Current formats availables are : " << list << G4endl;
|
|
} else {
|
|
G4cerr << " Format \"" << format << "\" is not available for the selected viewer. Current formats availables are : " << list << G4endl;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// From MESA implementation :
|
|
// http://www.techques.com/question/1-8660454/gluPickMatrix-code-from-Mesa
|
|
|
|
void G4OpenGLViewer::g4GluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height,
|
|
GLint viewport[4])
|
|
{
|
|
GLdouble mat[16];
|
|
GLdouble sx, sy;
|
|
GLdouble tx, ty;
|
|
|
|
sx = viewport[2] / width;
|
|
sy = viewport[3] / height;
|
|
tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
|
|
ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
|
|
|
|
#define M(row, col) mat[col*4+row]
|
|
M(0, 0) = sx;
|
|
M(0, 1) = 0.0;
|
|
M(0, 2) = 0.0;
|
|
M(0, 3) = tx;
|
|
M(1, 0) = 0.0;
|
|
M(1, 1) = sy;
|
|
M(1, 2) = 0.0;
|
|
M(1, 3) = ty;
|
|
M(2, 0) = 0.0;
|
|
M(2, 1) = 0.0;
|
|
M(2, 2) = 1.0;
|
|
M(2, 3) = 0.0;
|
|
M(3, 0) = 0.0;
|
|
M(3, 1) = 0.0;
|
|
M(3, 2) = 0.0;
|
|
M(3, 3) = 1.0;
|
|
#undef M
|
|
|
|
glMultMatrixd(mat);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// From MESA implementation :
|
|
// https://github.com/jlamarche/iOS-OpenGLES-Stuff/blob/master/Wavefront%20OBJ%20Loader/Classes/gluLookAt.m
|
|
// or http://www.daniweb.com/software-development/game-development/threads/308901/lookat-matrix-source-code
|
|
|
|
void G4OpenGLViewer::g4GluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
|
|
GLdouble centerx, GLdouble centery, GLdouble
|
|
centerz,
|
|
GLdouble upx, GLdouble upy, GLdouble upz )
|
|
{
|
|
GLdouble mat[16];
|
|
GLdouble x[3], y[3], z[3];
|
|
GLdouble mag;
|
|
|
|
/* Make rotation matrix */
|
|
|
|
/* Z vector */
|
|
z[0] = eyex - centerx;
|
|
z[1] = eyey - centery;
|
|
z[2] = eyez - centerz;
|
|
mag = std::sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
|
|
if (mag) { /* mpichler, 19950515 */
|
|
z[0] /= mag;
|
|
z[1] /= mag;
|
|
z[2] /= mag;
|
|
}
|
|
|
|
/* Y vector */
|
|
y[0] = upx;
|
|
y[1] = upy;
|
|
y[2] = upz;
|
|
|
|
/* X vector = Y cross Z */
|
|
x[0] = y[1] * z[2] - y[2] * z[1];
|
|
x[1] = -y[0] * z[2] + y[2] * z[0];
|
|
x[2] = y[0] * z[1] - y[1] * z[0];
|
|
|
|
/* Recompute Y = Z cross X */
|
|
y[0] = z[1] * x[2] - z[2] * x[1];
|
|
y[1] = -z[0] * x[2] + z[2] * x[0];
|
|
y[2] = z[0] * x[1] - z[1] * x[0];
|
|
|
|
/* mpichler, 19950515 */
|
|
/* cross product gives area of parallelogram, which is < 1.0 for
|
|
* non-perpendicular unit-length vectors; so normalize x, y here
|
|
*/
|
|
|
|
mag = std::sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
|
|
if (mag) {
|
|
x[0] /= mag;
|
|
x[1] /= mag;
|
|
x[2] /= mag;
|
|
}
|
|
|
|
mag = std::sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
|
|
if (mag) {
|
|
y[0] /= mag;
|
|
y[1] /= mag;
|
|
y[2] /= mag;
|
|
}
|
|
|
|
#define M(row,col) mat[col*4+row]
|
|
M(0, 0) = x[0];
|
|
M(0, 1) = x[1];
|
|
M(0, 2) = x[2];
|
|
M(0, 3) = 0.0;
|
|
M(1, 0) = y[0];
|
|
M(1, 1) = y[1];
|
|
M(1, 2) = y[2];
|
|
M(1, 3) = 0.0;
|
|
M(2, 0) = z[0];
|
|
M(2, 1) = z[1];
|
|
M(2, 2) = z[2];
|
|
M(2, 3) = 0.0;
|
|
M(3, 0) = 0.0;
|
|
M(3, 1) = 0.0;
|
|
M(3, 2) = 0.0;
|
|
M(3, 3) = 1.0;
|
|
#undef M
|
|
glMultMatrixd(mat);
|
|
|
|
/* Translate Eye to Origin */
|
|
glTranslated(-eyex, -eyey, -eyez);
|
|
}
|
|
|
|
void G4OpenGLViewer::g4GlOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {
|
|
// glOrtho (left, right, bottom, top, near, far);
|
|
|
|
GLdouble a = 2.0 / (right - left);
|
|
GLdouble b = 2.0 / (top - bottom);
|
|
GLdouble c = -2.0 / (zFar - zNear);
|
|
|
|
GLdouble tx = - (right + left)/(right - left);
|
|
GLdouble ty = - (top + bottom)/(top - bottom);
|
|
GLdouble tz = - (zFar + zNear)/(zFar - zNear);
|
|
|
|
GLdouble ortho[16] = {
|
|
a, 0, 0, 0,
|
|
0, b, 0, 0,
|
|
0, 0, c, 0,
|
|
tx, ty, tz, 1
|
|
};
|
|
glMultMatrixd(ortho);
|
|
|
|
}
|
|
|
|
|
|
void G4OpenGLViewer::g4GlFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {
|
|
// glFrustum (left, right, bottom, top, near, far);
|
|
|
|
GLdouble deltaX = right - left;
|
|
GLdouble deltaY = top - bottom;
|
|
GLdouble deltaZ = zFar - zNear;
|
|
|
|
GLdouble a = 2.0f * zNear / deltaX;
|
|
GLdouble b = 2.0f * zNear / deltaY;
|
|
GLdouble c = (right + left) / deltaX;
|
|
GLdouble d = (top + bottom) / deltaY;
|
|
GLdouble e = -(zFar + zNear) / (zFar - zNear);
|
|
GLdouble f = -2.0f * zFar * zNear / deltaZ;
|
|
|
|
GLdouble proj[16] = {
|
|
a, 0, 0, 0,
|
|
0, b, 0, 0,
|
|
c, d, e, -1.0f,
|
|
0, 0, f, 0
|
|
};
|
|
|
|
glMultMatrixd(proj);
|
|
|
|
}
|
|
|
|
G4String G4OpenGLViewerPickMap::print() {
|
|
std::ostringstream txt;
|
|
for (unsigned int a=0; a<fAttributes.size(); a++) {
|
|
txt << fAttributes[a];
|
|
if (a < fAttributes.size() - 1) txt << "\n";
|
|
}
|
|
return txt.str();
|
|
}
|