Geant4 Cross Reference |
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 // 28 // 29 // Andrew Walkden 27th March 1996 30 // OpenGL view - opens window, hard copy, etc. 31 32 #include "G4ios.hh" 33 #include <CLHEP/Units/SystemOfUnits.h> 34 #include "G4OpenGLViewer.hh" 35 #include "G4OpenGLSceneHandler.hh" 36 #include "G4OpenGLTransform3D.hh" 37 38 #include "G4gl2ps.hh" 39 #define GL2PS_TEXT_B TOOLS_GL2PS_TEXT_B 40 #define GL2PS_TEXT_BL TOOLS_GL2PS_TEXT_BL 41 #define GL2PS_TEXT_BR TOOLS_GL2PS_TEXT_BR 42 43 #include "G4Scene.hh" 44 #include "G4VisExtent.hh" 45 #include "G4LogicalVolume.hh" 46 #include "G4VSolid.hh" 47 #include "G4Point3D.hh" 48 #include "G4Normal3D.hh" 49 #include "G4Plane3D.hh" 50 #include "G4AttHolder.hh" 51 #include "G4AttCheck.hh" 52 #include "G4Text.hh" 53 54 #include <sstream> 55 #include <string> 56 #include <iomanip> 57 58 G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene): 59 G4VViewer (scene, -1), 60 fPrintColour (true), 61 fVectoredPs (true), 62 fOpenGLSceneHandler(scene), 63 background (G4Colour(0.,0.,0.)), 64 transparency_enabled (true), 65 antialiasing_enabled (false), 66 haloing_enabled (false), 67 fRot_sens(1.), 68 fPan_sens(0.01), 69 fWinSize_x(0), 70 fWinSize_y(0), 71 fDefaultExportImageFormat("pdf"), 72 fExportImageFormat("pdf"), 73 fExportFilenameIndex(0), 74 fPrintSizeX(-1), 75 fPrintSizeY(-1), 76 fPointSize (0), 77 fDefaultExportFilename("G4OpenGL"), 78 fSizeHasChanged(0), 79 fGl2psDefaultLineWith(1), 80 fGl2psDefaultPointSize(2), 81 fGlViewInitialized(false), 82 fIsGettingPickInfos(false) 83 { 84 // Make changes to view parameters for OpenGL... 85 fVP.SetAutoRefresh(true); 86 fDefaultVP.SetAutoRefresh(true); 87 fGL2PSAction = new G4gl2ps(); 88 tools_gl2ps_gl_funcs_t _funcs = { 89 (tools_glIsEnabled_func)glIsEnabled, 90 (tools_glBegin_func)glBegin, 91 (tools_glEnd_func)glEnd, 92 (tools_glGetFloatv_func)glGetFloatv, 93 (tools_glVertex3f_func)glVertex3f, 94 (tools_glGetBooleanv_func)glGetBooleanv, 95 (tools_glGetIntegerv_func)glGetIntegerv, 96 (tools_glRenderMode_func)glRenderMode, 97 (tools_glFeedbackBuffer_func)glFeedbackBuffer, 98 (tools_glPassThrough_func)glPassThrough 99 }; 100 fGL2PSAction->setOpenGLFunctions(&_funcs); 101 102 // add supported export image format 103 addExportImageFormat("eps"); 104 addExportImageFormat("ps"); 105 addExportImageFormat("pdf"); 106 addExportImageFormat("svg"); 107 108 // Change the default name 109 fExportFilename += fDefaultExportFilename + "_" + GetShortName().data(); 110 111 // glClearColor (0.0, 0.0, 0.0, 0.0); 112 // glClearDepth (1.0); 113 // glDisable (GL_BLEND); 114 // glDisable (GL_LINE_SMOOTH); 115 // glDisable (GL_POLYGON_SMOOTH); 116 117 } 118 119 G4OpenGLViewer::~G4OpenGLViewer () 120 { 121 delete fGL2PSAction; 122 } 123 124 void G4OpenGLViewer::InitializeGLView () 125 { 126 if (fWinSize_x == 0) { 127 fWinSize_x = fVP.GetWindowSizeHintX(); 128 } 129 if (fWinSize_y == 0) { 130 fWinSize_y = fVP.GetWindowSizeHintY(); 131 } 132 133 glClearColor (0.0, 0.0, 0.0, 0.0); 134 glClearDepth (1.0); 135 glDisable (GL_LINE_SMOOTH); 136 glDisable (GL_POLYGON_SMOOTH); 137 138 // clear the buffers and window? 139 ClearView (); 140 FinishView (); 141 142 glDepthFunc (GL_LEQUAL); 143 glDepthMask (GL_TRUE); 144 145 glEnable (GL_BLEND); 146 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 147 148 } 149 150 void G4OpenGLViewer::ClearView () { 151 ClearViewWithoutFlush(); 152 153 if(!isFramebufferReady()) { 154 return; 155 } 156 157 glFlush(); 158 } 159 160 161 void G4OpenGLViewer::ClearViewWithoutFlush () { 162 // Ready for clear ? 163 // See : http://lists.apple.com/archives/mac-opengl/2012/Jul/msg00038.html 164 if(!isFramebufferReady()) { 165 return; 166 } 167 168 glClearColor (background.GetRed(), 169 background.GetGreen(), 170 background.GetBlue(), 171 1.); 172 glClearDepth (1.0); 173 //Below line does not compile with Mesa includes. 174 //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 175 glClear (GL_COLOR_BUFFER_BIT); 176 glClear (GL_DEPTH_BUFFER_BIT); 177 glClear (GL_STENCIL_BUFFER_BIT); 178 } 179 180 181 void G4OpenGLViewer::ResizeWindow(unsigned int aWidth, unsigned int aHeight) { 182 if ((fWinSize_x != aWidth) || (fWinSize_y != aHeight)) { 183 fWinSize_x = aWidth; 184 fWinSize_y = aHeight; 185 fSizeHasChanged = true; 186 } else { 187 fSizeHasChanged = false; 188 } 189 } 190 191 /** 192 * Set the viewport of the scene 193 * MAXIMUM SIZE is : 194 * GLint dims[2]; 195 * glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); 196 */ 197 void G4OpenGLViewer::ResizeGLView() 198 { 199 // Check size 200 GLint dims[2]; 201 dims[0] = 0; 202 dims[1] = 0; 203 204 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); 205 206 if ((dims[0] !=0 ) && (dims[1] !=0)) { 207 208 if (fWinSize_x > (unsigned)dims[0]) { 209 G4cerr << "Try to resize view greater than max X viewport dimension. Desired size "<<fWinSize_x <<" is resize to "<< dims[0] << G4endl; 210 fWinSize_x = dims[0]; 211 } 212 if (fWinSize_y > (unsigned)dims[1]) { 213 G4cerr << "Try to resize view greater than max Y viewport dimension. Desired size "<<fWinSize_y <<" is resize to "<< dims[1] << G4endl; 214 fWinSize_y = dims[1]; 215 } 216 } 217 218 glViewport(0, 0, fWinSize_x,fWinSize_y); 219 220 221 } 222 223 224 void G4OpenGLViewer::SetView () { 225 // if getting pick infos, should not resize the view. 226 if (fIsGettingPickInfos) return; 227 228 if (!fSceneHandler.GetScene()) { 229 return; 230 } 231 // Calculates view representation based on extent of object being 232 // viewed and (initial) viewpoint. (Note: it can change later due 233 // to user interaction via visualization system's GUI.) 234 235 // Lighting. 236 GLfloat lightPosition [4]; 237 lightPosition [0] = fVP.GetActualLightpointDirection().x(); 238 lightPosition [1] = fVP.GetActualLightpointDirection().y(); 239 lightPosition [2] = fVP.GetActualLightpointDirection().z(); 240 lightPosition [3] = 0.; 241 // Light position is "true" light direction, so must come after gluLookAt. 242 GLfloat ambient [] = { 0.2f, 0.2f, 0.2f, 1.f}; 243 GLfloat diffuse [] = { 0.8f, 0.8f, 0.8f, 1.f}; 244 glEnable (GL_LIGHT0); 245 glLightfv (GL_LIGHT0, GL_AMBIENT, ambient); 246 glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse); 247 248 G4double ratioX = 1; 249 G4double ratioY = 1; 250 if (fWinSize_y > fWinSize_x) { 251 ratioX = ((G4double)fWinSize_y) / ((G4double)fWinSize_x); 252 } 253 if (fWinSize_x > fWinSize_y) { 254 ratioY = ((G4double)fWinSize_x) / ((G4double)fWinSize_y); 255 } 256 257 // Get radius of scene, etc. 258 // Note that this procedure properly takes into account zoom, dolly and pan. 259 const G4Point3D targetPoint 260 = fSceneHandler.GetScene()->GetStandardTargetPoint() 261 + fVP.GetCurrentTargetPoint (); 262 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); 263 if(radius<=0.) radius = 1.; 264 const G4double cameraDistance = fVP.GetCameraDistance (radius); 265 const G4Point3D cameraPosition = 266 targetPoint + cameraDistance * fVP.GetViewpointDirection().unit(); 267 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); 268 const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius); 269 const GLdouble right = fVP.GetFrontHalfHeight (pnear, radius) * ratioY; 270 const GLdouble left = -right; 271 const GLdouble top = fVP.GetFrontHalfHeight (pnear, radius) * ratioX; 272 const GLdouble bottom = -top; 273 274 // FIXME 275 ResizeGLView(); 276 //SHOULD SetWindowsSizeHint()... 277 278 glMatrixMode (GL_PROJECTION); // set up Frustum. 279 glLoadIdentity(); 280 281 const G4Vector3D scaleFactor = fVP.GetScaleFactor(); 282 glScaled(scaleFactor.x(),scaleFactor.y(),scaleFactor.z()); 283 284 if (fVP.GetFieldHalfAngle() == 0.) { 285 g4GlOrtho (left, right, bottom, top, pnear, pfar); 286 } 287 else { 288 g4GlFrustum (left, right, bottom, top, pnear, pfar); 289 } 290 291 glMatrixMode (GL_MODELVIEW); // apply further transformations to scene. 292 glLoadIdentity(); 293 294 const G4Normal3D& upVector = fVP.GetUpVector (); 295 G4Point3D gltarget; 296 if (cameraDistance > 1.e-6 * radius) { 297 gltarget = targetPoint; 298 } 299 else { 300 gltarget = targetPoint - radius * fVP.GetViewpointDirection().unit(); 301 } 302 303 const G4Point3D& pCamera = cameraPosition; // An alias for brevity. 304 305 g4GluLookAt (pCamera.x(), pCamera.y(), pCamera.z(), // Viewpoint. 306 gltarget.x(), gltarget.y(), gltarget.z(), // Target point. 307 upVector.x(), upVector.y(), upVector.z()); // Up vector. 308 // Light position is "true" light direction, so must come after gluLookAt. 309 glLightfv (GL_LIGHT0, GL_POSITION, lightPosition); 310 311 // The idea is to use back-to-back clipping planes. This can cut an object 312 // down to just a few pixels, which can make it difficult to see. So, for 313 // now, comment this out and use the generic (Boolean) method, via 314 // G4VSolid* G4OpenGLSceneHandler::CreateSectionSolid () 315 // { return G4VSceneHandler::CreateSectionSolid(); } 316 // if (fVP.IsSection () ) { // pair of back to back clip planes. 317 // const G4Plane3D& sp = fVP.GetSectionPlane (); 318 // double sArray[4]; 319 // sArray[0] = sp.a(); 320 // sArray[1] = sp.b(); 321 // sArray[2] = sp.c(); 322 // sArray[3] = sp.d() + radius * 1.e-05; 323 // glClipPlane (GL_CLIP_PLANE0, sArray); 324 // glEnable (GL_CLIP_PLANE0); 325 // sArray[0] = -sp.a(); 326 // sArray[1] = -sp.b(); 327 // sArray[2] = -sp.c(); 328 // sArray[3] = -sp.d() + radius * 1.e-05; 329 // glClipPlane (GL_CLIP_PLANE1, sArray); 330 // glEnable (GL_CLIP_PLANE1); 331 // } else { 332 // glDisable (GL_CLIP_PLANE0); 333 // glDisable (GL_CLIP_PLANE1); 334 // } 335 336 // What we call intersection of cutaways is easy in OpenGL. You 337 // just keep cutting. Unions are more tricky - you have to have 338 // multiple passes and this is handled in 339 // G4OpenGLImmediate/StoredViewer::ProcessView. 340 const G4Planes& cutaways = fVP.GetCutawayPlanes(); 341 size_t nPlanes = cutaways.size(); 342 if (fVP.IsCutaway() && 343 fVP.GetCutawayMode() == G4ViewParameters::cutawayIntersection) { 344 double a[4]; 345 a[0] = cutaways[0].a(); 346 a[1] = cutaways[0].b(); 347 a[2] = cutaways[0].c(); 348 a[3] = cutaways[0].d(); 349 glClipPlane (GL_CLIP_PLANE2, a); 350 glEnable (GL_CLIP_PLANE2); 351 if (nPlanes > 1) { 352 a[0] = cutaways[1].a(); 353 a[1] = cutaways[1].b(); 354 a[2] = cutaways[1].c(); 355 a[3] = cutaways[1].d(); 356 glClipPlane (GL_CLIP_PLANE3, a); 357 glEnable (GL_CLIP_PLANE3); 358 } 359 if (nPlanes > 2) { 360 a[0] = cutaways[2].a(); 361 a[1] = cutaways[2].b(); 362 a[2] = cutaways[2].c(); 363 a[3] = cutaways[2].d(); 364 glClipPlane (GL_CLIP_PLANE4, a); 365 glEnable (GL_CLIP_PLANE4); 366 } 367 } else { 368 glDisable (GL_CLIP_PLANE2); 369 glDisable (GL_CLIP_PLANE3); 370 glDisable (GL_CLIP_PLANE4); 371 } 372 373 // Background. 374 background = fVP.GetBackgroundColour (); 375 376 } 377 378 379 380 void G4OpenGLViewer::ResetView () { 381 G4VViewer::ResetView(); 382 fRot_sens = 1; 383 fPan_sens = 0.01; 384 } 385 386 387 void G4OpenGLViewer::HaloingFirstPass () { 388 389 //To perform haloing, first Draw all information to the depth buffer 390 //alone, using a chunky line width, and then Draw all info again, to 391 //the colour buffer, setting a thinner line width an the depth testing 392 //function to less than or equal, so if two lines cross, the one 393 //passing behind the other will not pass the depth test, and so not 394 //get rendered either side of the infront line for a short distance. 395 396 //First, disable writing to the colo(u)r buffer... 397 glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 398 399 //Now enable writing to the depth buffer... 400 glDepthMask (GL_TRUE); 401 glDepthFunc (GL_LESS); 402 glClearDepth (1.0); 403 404 //Finally, set the line width to something wide... 405 ChangeLineWidth(3.0); 406 407 } 408 409 void G4OpenGLViewer::HaloingSecondPass () { 410 411 //And finally, turn the colour buffer back on with a sesible line width... 412 glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 413 glDepthFunc (GL_LEQUAL); 414 ChangeLineWidth(1.0); 415 416 } 417 418 G4String G4OpenGLViewer::Pick(GLdouble x, GLdouble y) 419 { 420 const std::vector < G4OpenGLViewerPickMap* > & pickMap = GetPickDetails(x,y); 421 G4String txt = ""; 422 if (pickMap.size() == 0) { 423 // txt += "No hits recorded.";; 424 } else { 425 for (unsigned int a=0; a < pickMap.size(); a++) { 426 if (pickMap[a]->getAttributes().size() > 0) { 427 txt += pickMap[a]->print(); 428 } 429 } 430 } 431 return txt; 432 } 433 434 const std::vector < G4OpenGLViewerPickMap* > & G4OpenGLViewer::GetPickDetails(GLdouble x, GLdouble y) 435 { 436 static std::vector < G4OpenGLViewerPickMap* > pickMapVector; 437 for (auto pickMap: pickMapVector) { 438 delete pickMap; 439 } 440 pickMapVector.clear(); 441 442 const G4int BUFSIZE = 512; 443 GLuint selectBuffer[BUFSIZE]; 444 glSelectBuffer(BUFSIZE, selectBuffer); 445 glRenderMode(GL_SELECT); 446 glInitNames(); 447 glPushName(0); 448 glMatrixMode(GL_PROJECTION); 449 G4double currentProjectionMatrix[16]; 450 glGetDoublev(GL_PROJECTION_MATRIX, currentProjectionMatrix); 451 glPushMatrix(); 452 glLoadIdentity(); 453 GLint viewport[4]; 454 glGetIntegerv(GL_VIEWPORT, viewport); 455 /* G4cout 456 << "viewport, x,y: " 457 << viewport[0] << ',' << viewport[1] << ',' << viewport[2] << ',' << viewport[3] 458 << ", " << x << ',' << y 459 << G4endl; 460 */ 461 fIsGettingPickInfos = true; 462 // Define 5x5 pixel pick area 463 g4GluPickMatrix(x, viewport[3] - y, 5., 5., viewport); 464 glMultMatrixd(currentProjectionMatrix); 465 glMatrixMode(GL_MODELVIEW); 466 DrawView(); 467 GLint hits = glRenderMode(GL_RENDER); 468 fIsGettingPickInfos = false; 469 if (hits < 0) { 470 G4cout << "Too many hits. Zoom in to reduce overlaps." << G4endl; 471 goto restoreMatrices; 472 } 473 if (hits > 0) { 474 GLuint* p = selectBuffer; 475 for (GLint i = 0; i < hits; ++i) { 476 GLuint nnames = *p++; 477 // This bit of debug code or... 478 //GLuint zmin = *p++; 479 //GLuint zmax = *p++; 480 //G4cout << "Hit " << i << ": " << nnames << " names" 481 // << "\nzmin: " << zmin << ", zmax: " << zmax << G4endl; 482 // ...just increment the pointer 483 p++; 484 p++; 485 for (GLuint j = 0; j < nnames; ++j) { 486 GLuint name = *p++; 487 std::map<GLuint, G4AttHolder*>::iterator iter = 488 fOpenGLSceneHandler.fPickMap.find(name); 489 if (iter != fOpenGLSceneHandler.fPickMap.end()) { 490 G4AttHolder* attHolder = iter->second; 491 if(attHolder && attHolder->GetAttDefs().size()) { 492 for (size_t iAtt = 0; 493 iAtt < attHolder->GetAttDefs().size(); ++iAtt) { 494 std::ostringstream oss; 495 oss << G4AttCheck(attHolder->GetAttValues()[iAtt], 496 attHolder->GetAttDefs()[iAtt]); 497 G4OpenGLViewerPickMap* pickMap = new G4OpenGLViewerPickMap(); 498 // G4cout 499 // << "i,j, attHolder->GetAttDefs().size(): " 500 // << i << ',' << j 501 // << ", " << attHolder->GetAttDefs().size() 502 // << G4endl; 503 // G4cout << "G4OpenGLViewer::GetPickDetails: " << oss.str() << G4endl; 504 pickMap->addAttributes(oss.str()); 505 pickMap->setHitNumber(i); 506 pickMap->setSubHitNumber(j); 507 pickMap->setPickName(name); 508 pickMapVector.push_back(pickMap); 509 } 510 } 511 } 512 } 513 } 514 } 515 516 restoreMatrices: 517 glMatrixMode(GL_PROJECTION); 518 glPopMatrix(); 519 glMatrixMode(GL_MODELVIEW); 520 521 return pickMapVector; 522 } 523 524 GLubyte* G4OpenGLViewer::grabPixels 525 (int inColor, unsigned int width, unsigned int height) { 526 527 GLubyte* buffer; 528 GLint swapbytes, lsbfirst, rowlength; 529 GLint skiprows, skippixels, alignment; 530 GLenum format; 531 int size; 532 533 if (inColor) { 534 format = GL_RGB; 535 size = width*height*3; 536 } else { 537 format = GL_LUMINANCE; 538 size = width*height*1; 539 } 540 541 buffer = new GLubyte[size]; 542 if (buffer == NULL) 543 return NULL; 544 545 glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes); 546 glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst); 547 glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength); 548 549 glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows); 550 glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels); 551 glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment); 552 553 glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); 554 glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); 555 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); 556 557 glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); 558 glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); 559 glPixelStorei (GL_UNPACK_ALIGNMENT, 1); 560 561 glReadBuffer(GL_FRONT); 562 glReadPixels (0, 0, (GLsizei)width, (GLsizei)height, format, GL_UNSIGNED_BYTE, (GLvoid*) buffer); 563 564 glPixelStorei (GL_UNPACK_SWAP_BYTES, swapbytes); 565 glPixelStorei (GL_UNPACK_LSB_FIRST, lsbfirst); 566 glPixelStorei (GL_UNPACK_ROW_LENGTH, rowlength); 567 568 glPixelStorei (GL_UNPACK_SKIP_ROWS, skiprows); 569 glPixelStorei (GL_UNPACK_SKIP_PIXELS, skippixels); 570 glPixelStorei (GL_UNPACK_ALIGNMENT, alignment); 571 572 return buffer; 573 } 574 575 bool G4OpenGLViewer::printVectoredEPS() { 576 return printGl2PS(); 577 } 578 579 bool G4OpenGLViewer::printNonVectoredEPS () { 580 581 int width = getRealExportWidth(); 582 int height = getRealExportHeight(); 583 584 FILE* fp; 585 GLubyte* pixels; 586 GLubyte* curpix; 587 int components, pos, i; 588 589 pixels = grabPixels (fPrintColour, width, height); 590 591 if (pixels == NULL) { 592 G4cerr << "Failed to get pixels from OpenGl viewport" << G4endl; 593 return false; 594 } 595 if (fPrintColour) { 596 components = 3; 597 } else { 598 components = 1; 599 } 600 std::string name = getRealPrintFilename(); 601 fp = fopen (name.c_str(), "w"); 602 if (fp == NULL) { 603 G4cerr << "Can't open filename " << name.c_str() << G4endl; 604 return false; 605 } 606 607 fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n"); 608 fprintf (fp, "%%%%Title: %s\n", name.c_str()); 609 fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n"); 610 fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height); 611 fprintf (fp, "%%%%EndComments\n"); 612 fprintf (fp, "gsave\n"); 613 fprintf (fp, "/bwproc {\n"); 614 fprintf (fp, " rgbproc\n"); 615 fprintf (fp, " dup length 3 idiv string 0 3 0 \n"); 616 fprintf (fp, " 5 -1 roll {\n"); 617 fprintf (fp, " add 2 1 roll 1 sub dup 0 eq\n"); 618 fprintf (fp, " { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n"); 619 fprintf (fp, " 3 1 roll 5 -1 roll } put 1 add 3 0 \n"); 620 fprintf (fp, " { 2 1 roll } ifelse\n"); 621 fprintf (fp, " }forall\n"); 622 fprintf (fp, " pop pop pop\n"); 623 fprintf (fp, "} def\n"); 624 fprintf (fp, "systemdict /colorimage known not {\n"); 625 fprintf (fp, " /colorimage {\n"); 626 fprintf (fp, " pop\n"); 627 fprintf (fp, " pop\n"); 628 fprintf (fp, " /rgbproc exch def\n"); 629 fprintf (fp, " { bwproc } image\n"); 630 fprintf (fp, " } def\n"); 631 fprintf (fp, "} if\n"); 632 fprintf (fp, "/picstr %d string def\n", width * components); 633 fprintf (fp, "%d %d scale\n", width, height); 634 fprintf (fp, "%d %d %d\n", width, height, 8); 635 fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height); 636 fprintf (fp, "{currentfile picstr readhexstring pop}\n"); 637 fprintf (fp, "false %d\n", components); 638 fprintf (fp, "colorimage\n"); 639 640 curpix = (GLubyte*) pixels; 641 pos = 0; 642 for (i = width*height*components; i>0; i--) { 643 fprintf (fp, "%02hx ", (unsigned short)(*(curpix++))); 644 if (++pos >= 32) { 645 fprintf (fp, "\n"); 646 pos = 0; 647 } 648 } 649 if (pos) 650 fprintf (fp, "\n"); 651 652 fprintf (fp, "grestore\n"); 653 fprintf (fp, "showpage\n"); 654 delete [] pixels; 655 fclose (fp); 656 657 // Reset for next time (useful if size change) 658 // fPrintSizeX = -1; 659 // fPrintSizeY = -1; 660 661 return true; 662 } 663 664 /** Return if gl2ps is currently writing 665 */ 666 bool G4OpenGLViewer::isGl2psWriting() { 667 668 if (!fGL2PSAction) return false; 669 if (fGL2PSAction->fileWritingEnabled()) { 670 return true; 671 } 672 return false; 673 } 674 675 676 G4bool G4OpenGLViewer::isFramebufferReady() { 677 bool check = false; 678 #ifdef G4VIS_BUILD_OPENGLQT_DRIVER 679 check = true; 680 #endif 681 #ifdef G4VIS_BUILD_OPENGLX_DRIVER 682 check = false; 683 #endif 684 #ifdef G4VIS_BUILD_OPENGLXM_DRIVER 685 check = false; 686 #endif 687 #ifdef G4VIS_BUILD_OPENGLWIN32_DRIVER 688 check = false; 689 #endif 690 691 #if GL_ARB_framebuffer_object 692 if (check) { 693 // if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_UNDEFINED) { 694 // return false; 695 // } 696 } 697 #endif 698 return true; 699 } 700 701 702 /* Draw Gl2Ps text if needed 703 */ 704 void G4OpenGLViewer::DrawText(const G4Text& g4text) 705 { 706 // gl2ps or GL window ? 707 if (isGl2psWriting()) { 708 709 G4VSceneHandler::MarkerSizeType sizeType; 710 G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType); 711 G4Point3D position = g4text.GetPosition(); 712 713 G4String textString = g4text.GetText(); 714 715 glRasterPos3d(position.x(),position.y(),position.z()); 716 GLint align = GL2PS_TEXT_B; 717 718 switch (g4text.GetLayout()) { 719 case G4Text::left: align = GL2PS_TEXT_BL; break; 720 case G4Text::centre: align = GL2PS_TEXT_B; break; 721 case G4Text::right: align = GL2PS_TEXT_BR; 722 } 723 724 fGL2PSAction->addTextOpt(textString.c_str(),"Times-Roman",GLshort(size),align,0); 725 726 } else { 727 728 static G4int callCount = 0; 729 ++callCount; 730 //if (callCount <= 10 || callCount%100 == 0) { 731 if (callCount <= 1) { 732 G4cout << 733 "G4OpenGLViewer::DrawText: Not implemented for \"" 734 << fName << 735 "\"\n Called with " 736 << g4text 737 << G4endl; 738 } 739 } 740 } 741 742 /** Change PointSize on gl2ps if needed 743 */ 744 void G4OpenGLViewer::ChangePointSize(G4double size) { 745 746 if (isGl2psWriting()) { 747 fGL2PSAction->setPointSize(int(size)); 748 } else { 749 glPointSize (size); 750 } 751 } 752 753 754 /** Change LineSize on gl2ps if needed 755 */ 756 void G4OpenGLViewer::ChangeLineWidth(G4double width) { 757 758 if (isGl2psWriting()) { 759 fGL2PSAction->setLineWidth(int(width)); 760 } else { 761 glLineWidth (width); 762 } 763 } 764 765 /** 766 Export image with the given name with width and height 767 Several cases : 768 If name is "", filename will have the default value 769 If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added. 770 If name is "toto", set the name to "toto" and the format to default (or current format if specify). 771 Will also add an incremented suffix at the end of the file 772 */ 773 bool G4OpenGLViewer::exportImage(std::string name, int width, int height) { 774 775 if (! setExportFilename(name)) { 776 return false; 777 } 778 779 if ((width != -1) && (height != -1)) { 780 setExportSize(width, height); 781 } 782 783 if (fExportImageFormat == "eps") { 784 fGL2PSAction->setExportImageFormat_EPS(); 785 } else if (fExportImageFormat == "ps") { 786 fGL2PSAction->setExportImageFormat_PS(); 787 } else if (fExportImageFormat == "svg") { 788 fGL2PSAction->setExportImageFormat_SVG(); 789 } else if (fExportImageFormat == "pdf") { 790 fGL2PSAction->setExportImageFormat_PDF(); 791 } else { 792 setExportImageFormat(fExportImageFormat,true); // will display a message if this format is not correct for the current viewer 793 return false; 794 } 795 796 bool res; 797 798 // Change the LC_NUMERIC value in order to have "." separtor and not "," 799 // This case is only useful for French, Canadien... 800 size_t len = strlen(setlocale(LC_NUMERIC,NULL)); 801 char* oldLocale = (char*)(malloc(len+1)); 802 if(oldLocale!=NULL) strncpy(oldLocale,setlocale(LC_NUMERIC,NULL),len); 803 setlocale(LC_NUMERIC,"C"); 804 805 if (((fExportImageFormat == "eps") || (fExportImageFormat == "ps")) && (!fVectoredPs)) { 806 res = printNonVectoredEPS(); 807 } else { 808 res = printVectoredEPS(); 809 } 810 811 // restore the local 812 if (oldLocale) { 813 setlocale(LC_NUMERIC,oldLocale); 814 free(oldLocale); 815 } 816 817 if (res == false) { 818 G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl; 819 } else { 820 G4cout << "File " << getRealPrintFilename().c_str() << " size: " << getRealExportWidth() << "x" << getRealExportHeight() << " has been saved " << G4endl; 821 822 // increment index if necessary 823 if ( fExportFilenameIndex != -1) { 824 fExportFilenameIndex++; 825 } 826 } 827 828 return res; 829 } 830 831 832 bool G4OpenGLViewer::printGl2PS() { 833 834 int width = getRealExportWidth(); 835 int height = getRealExportHeight(); 836 bool res = true; 837 838 // no need to redraw at each new primitive for printgl2PS 839 G4OpenGLSceneHandler& oglSceneHandler = dynamic_cast<G4OpenGLSceneHandler&>(fSceneHandler); 840 G4OpenGLSceneHandler::FlushAction originalFlushAction = oglSceneHandler.GetFlushAction(); 841 oglSceneHandler.SetFlushAction(G4OpenGLSceneHandler::never); 842 843 if (!fGL2PSAction) return false; 844 845 fGL2PSAction->setFileName(getRealPrintFilename().c_str()); 846 // try to resize 847 int X = fWinSize_x; 848 int Y = fWinSize_y; 849 850 fWinSize_x = width; 851 fWinSize_y = height; 852 // Laurent G. 16/03/10 : Not the good way to do. 853 // We should draw in a new offscreen context instead of 854 // resizing and drawing in current window... 855 // This should be solve when we will do an offscreen method 856 // to render OpenGL 857 // See : 858 // http://developer.apple.com/Mac/library/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_offscreen/opengl_offscreen.html 859 // http://www.songho.ca/opengl/gl_fbo.html 860 861 ResizeGLView(); 862 bool extendBuffer = true; 863 bool endWriteAction = false; 864 bool beginWriteAction = true; 865 bool filePointerOk = true; 866 while ((extendBuffer) && (! endWriteAction) && (filePointerOk)) { 867 868 beginWriteAction = fGL2PSAction->enableFileWriting(); 869 if(beginWriteAction) { 870 GLint vp[4]; 871 ::glGetIntegerv(GL_VIEWPORT,vp); 872 fGL2PSAction->setViewport(vp[0],vp[1],vp[2],vp[3]); 873 beginWriteAction = fGL2PSAction->beginPage(); 874 } 875 876 // 3 cases : 877 // - true 878 // - false && ! fGL2PSAction->fileWritingEnabled() => bad file name 879 // - false && fGL2PSAction->fileWritingEnabled() => buffer size problem ? 880 881 filePointerOk = fGL2PSAction->fileWritingEnabled(); 882 883 if (beginWriteAction) { 884 885 // Set the viewport 886 // By default, we choose the line width (trajectories...) 887 fGL2PSAction->setLineWidth(fGl2psDefaultLineWith); 888 // By default, we choose the point size (markers...) 889 fGL2PSAction->setPointSize(fGl2psDefaultPointSize); 890 891 DrawView (); 892 893 endWriteAction = fGL2PSAction->endPage(); 894 fGL2PSAction->disableFileWriting(); 895 } 896 if (filePointerOk) { 897 if ((! endWriteAction) || (! beginWriteAction)) { 898 extendBuffer = fGL2PSAction->extendBufferSize(); 899 } 900 } 901 } 902 fGL2PSAction->resetBufferSizeParameters(); 903 904 if (!extendBuffer ) { 905 G4cerr << "ERROR: gl2ps buffer size is not big enough to print this geometry. Try to extend it. No output produced"<< G4endl; 906 res = false; 907 } 908 if (!beginWriteAction ) { 909 G4cerr << "ERROR: saving file "<<getRealPrintFilename().c_str()<<". Check read/write access. No output produced" << G4endl; 910 res = false; 911 } 912 if (!endWriteAction ) { 913 G4cerr << "gl2ps error. No output produced" << G4endl; 914 res = false; 915 } 916 fWinSize_x = X; 917 fWinSize_y = Y; 918 919 oglSceneHandler.SetFlushAction(originalFlushAction); 920 921 // Reset for next time (useful is size change) 922 // fPrintSizeX = 0; 923 // fPrintSizeY = 0; 924 925 return res; 926 } 927 928 unsigned int G4OpenGLViewer::getWinWidth() const{ 929 return fWinSize_x; 930 } 931 932 unsigned int G4OpenGLViewer::getWinHeight() const{ 933 return fWinSize_y; 934 } 935 936 G4bool G4OpenGLViewer::sizeHasChanged() { 937 return fSizeHasChanged; 938 } 939 940 G4int G4OpenGLViewer::getRealExportWidth() { 941 if (fPrintSizeX == -1) { 942 return fWinSize_x; 943 } 944 GLint dims[2]; 945 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); 946 947 // L.Garnier 01-2010: Some problems with mac 10.6 948 if ((dims[0] !=0 ) && (dims[1] !=0)) { 949 if (fPrintSizeX > dims[0]){ 950 return dims[0]; 951 } 952 } 953 if (fPrintSizeX < -1){ 954 return 0; 955 } 956 return fPrintSizeX; 957 } 958 959 G4int G4OpenGLViewer::getRealExportHeight() { 960 if (fPrintSizeY == -1) { 961 return fWinSize_y; 962 } 963 GLint dims[2]; 964 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); 965 966 // L.Garnier 01-2010: Some problems with mac 10.6 967 if ((dims[0] !=0 ) && (dims[1] !=0)) { 968 if (fPrintSizeY > dims[1]){ 969 return dims[1]; 970 } 971 } 972 if (fPrintSizeY < -1){ 973 return 0; 974 } 975 return fPrintSizeY; 976 } 977 978 void G4OpenGLViewer::setExportSize(G4int X, G4int Y) { 979 fPrintSizeX = X; 980 fPrintSizeY = Y; 981 } 982 983 /** 984 If name is "" or "!", filename and extension will have the default value. 985 If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added. 986 If name is "toto", set the name to "toto" and the format to default (or current format if specify). 987 If name is the same as previous, do not reset incremented suffix. 988 */ 989 bool G4OpenGLViewer::setExportFilename(G4String name,G4bool inc) { 990 if (name == "!") { 991 name = ""; 992 } 993 994 if (inc) { 995 if ((name != "") && (fExportFilename != name)) { 996 fExportFilenameIndex=0; 997 } 998 } else { 999 fExportFilenameIndex=-1; 1000 } 1001 1002 if (name.size() == 0) { 1003 name = getRealPrintFilename().c_str(); 1004 } else { 1005 // guess format by extention 1006 std::string extension = name.substr(name.find_last_of(".") + 1); 1007 // If there is a dot in the name the above might find rubbish, so... 1008 if (extension.size() >= 3 && extension.size() <= 4) { // Possible extension 1009 if (setExportImageFormat(extension, false)) { // Extension found 1010 fExportFilename = name.substr(0,name.find_last_of(".")); 1011 } else { // No viable extension found 1012 return false; 1013 } 1014 } else { // Assume name is already the required without-extension part 1015 fExportFilename = name; 1016 } 1017 } 1018 return true; 1019 } 1020 1021 std::string G4OpenGLViewer::getRealPrintFilename() { 1022 std::string temp = fExportFilename; 1023 if (fExportFilenameIndex != -1) { 1024 temp += std::string("_"); 1025 std::ostringstream os; 1026 os << std::setw(4) << std::setfill('0') << fExportFilenameIndex; 1027 std::string nb_str = os.str(); 1028 temp += nb_str; 1029 } 1030 temp += "."+fExportImageFormat; 1031 return temp; 1032 } 1033 1034 GLdouble G4OpenGLViewer::getSceneNearWidth() 1035 { 1036 if (!fSceneHandler.GetScene()) { 1037 return 0; 1038 } 1039 const G4Point3D targetPoint 1040 = fSceneHandler.GetScene()->GetStandardTargetPoint() 1041 + fVP.GetCurrentTargetPoint (); 1042 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); 1043 if(radius<=0.) radius = 1.; 1044 const G4double cameraDistance = fVP.GetCameraDistance (radius); 1045 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); 1046 return 2 * fVP.GetFrontHalfHeight (pnear, radius); 1047 } 1048 1049 GLdouble G4OpenGLViewer::getSceneFarWidth() 1050 { 1051 if (!fSceneHandler.GetScene()) { 1052 return 0; 1053 } 1054 const G4Point3D targetPoint 1055 = fSceneHandler.GetScene()->GetStandardTargetPoint() 1056 + fVP.GetCurrentTargetPoint (); 1057 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); 1058 if(radius<=0.) radius = 1.; 1059 const G4double cameraDistance = fVP.GetCameraDistance (radius); 1060 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); 1061 const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius); 1062 return 2 * fVP.GetFrontHalfHeight (pfar, radius); 1063 } 1064 1065 1066 GLdouble G4OpenGLViewer::getSceneDepth() 1067 { 1068 if (!fSceneHandler.GetScene()) { 1069 return 0; 1070 } 1071 const G4Point3D targetPoint 1072 = fSceneHandler.GetScene()->GetStandardTargetPoint() 1073 + fVP.GetCurrentTargetPoint (); 1074 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); 1075 if(radius<=0.) radius = 1.; 1076 const G4double cameraDistance = fVP.GetCameraDistance (radius); 1077 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); 1078 return fVP.GetFarDistance (cameraDistance, pnear, radius)- pnear; 1079 } 1080 1081 1082 1083 void G4OpenGLViewer::rotateScene(G4double dx, G4double dy) 1084 { 1085 if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) { 1086 rotateSceneInViewDirection(dx,dy); 1087 } else { 1088 if( dx != 0) { 1089 rotateSceneThetaPhi(dx,0); 1090 } 1091 if( dy != 0) { 1092 rotateSceneThetaPhi(0,dy); 1093 } 1094 } 1095 } 1096 1097 1098 void G4OpenGLViewer::rotateSceneToggle(G4double dx, G4double dy) 1099 { 1100 if (fVP.GetRotationStyle() != G4ViewParameters::freeRotation) { 1101 rotateSceneInViewDirection(dx,dy); 1102 } else { 1103 if( dx != 0) { 1104 rotateSceneThetaPhi(dx,0); 1105 } 1106 if( dy != 0) { 1107 rotateSceneThetaPhi(0,dy); 1108 } 1109 } 1110 } 1111 1112 void G4OpenGLViewer::rotateSceneThetaPhi(G4double dx, G4double dy) 1113 { 1114 if (!fSceneHandler.GetScene()) { 1115 return; 1116 } 1117 1118 G4Vector3D vp; 1119 G4Vector3D up; 1120 1121 G4Vector3D xprime; 1122 G4Vector3D yprime; 1123 G4Vector3D zprime; 1124 1125 G4double delta_alpha; 1126 G4double delta_theta; 1127 1128 G4Vector3D new_vp; 1129 G4Vector3D new_up; 1130 1131 G4double cosalpha; 1132 G4double sinalpha; 1133 1134 G4Vector3D a1; 1135 G4Vector3D a2; 1136 G4Vector3D delta; 1137 G4Vector3D viewPoint; 1138 1139 1140 //phi spin stuff here 1141 1142 vp = fVP.GetViewpointDirection ().unit (); 1143 up = fVP.GetUpVector ().unit (); 1144 1145 yprime = (up.cross(vp)).unit(); 1146 zprime = (vp.cross(yprime)).unit(); 1147 1148 if (fVP.GetLightsMoveWithCamera()) { 1149 delta_alpha = dy * fRot_sens; 1150 delta_theta = -dx * fRot_sens; 1151 } else { 1152 delta_alpha = -dy * fRot_sens; 1153 delta_theta = dx * fRot_sens; 1154 } 1155 1156 delta_alpha *= CLHEP::deg; 1157 delta_theta *= CLHEP::deg; 1158 1159 new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime; 1160 1161 // to avoid z rotation flipping 1162 // to allow more than 360° rotation 1163 1164 if (fVP.GetLightsMoveWithCamera()) { 1165 new_up = (new_vp.cross(yprime)).unit(); 1166 if (new_vp.z()*vp.z() <0) { 1167 new_up.set(new_up.x(),-new_up.y(),new_up.z()); 1168 } 1169 } else { 1170 new_up = up; 1171 if (new_vp.z()*vp.z() <0) { 1172 new_up.set(new_up.x(),-new_up.y(),new_up.z()); 1173 } 1174 } 1175 fVP.SetUpVector(new_up); 1176 //////////////// 1177 // Rotates by fixed azimuthal angle delta_theta. 1178 1179 cosalpha = new_up.dot (new_vp.unit()); 1180 sinalpha = std::sqrt (1. - std::pow (cosalpha, 2)); 1181 yprime = (new_up.cross (new_vp.unit())).unit (); 1182 xprime = yprime.cross (new_up); 1183 // Projection of vp on plane perpendicular to up... 1184 a1 = sinalpha * xprime; 1185 // Required new projection... 1186 a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime); 1187 // Required Increment vector... 1188 delta = a2 - a1; 1189 // So new viewpoint is... 1190 viewPoint = new_vp.unit() + delta; 1191 1192 fVP.SetViewAndLights (viewPoint); 1193 } 1194 1195 1196 void G4OpenGLViewer::rotateSceneInViewDirection(G4double dx, G4double dy) 1197 { 1198 if (!fSceneHandler.GetScene()) { 1199 return; 1200 } 1201 1202 G4Vector3D vp; 1203 G4Vector3D up; 1204 1205 G4Vector3D xprime; 1206 G4Vector3D yprime; 1207 G4Vector3D zprime; 1208 1209 G4Vector3D new_vp; 1210 G4Vector3D new_up; 1211 1212 G4Vector3D a1; 1213 G4Vector3D a2; 1214 G4Vector3D delta; 1215 G4Vector3D viewPoint; 1216 1217 dx = dx/100; 1218 dy = dy/100; 1219 1220 //phi spin stuff here 1221 1222 vp = fVP.GetViewpointDirection ().unit(); 1223 up = fVP.GetUpVector ().unit(); 1224 1225 G4Vector3D zPrimeVector = G4Vector3D(up.y()*vp.z()-up.z()*vp.y(), 1226 up.z()*vp.x()-up.x()*vp.z(), 1227 up.x()*vp.y()-up.y()*vp.x()); 1228 1229 viewPoint = vp/fRot_sens + (zPrimeVector*dx - up*dy) ; 1230 new_up = G4Vector3D(viewPoint.y()*zPrimeVector.z()-viewPoint.z()*zPrimeVector.y(), 1231 viewPoint.z()*zPrimeVector.x()-viewPoint.x()*zPrimeVector.z(), 1232 viewPoint.x()*zPrimeVector.y()-viewPoint.y()*zPrimeVector.x()); 1233 1234 G4Vector3D new_upUnit = new_up.unit(); 1235 1236 1237 1238 fVP.SetUpVector(new_upUnit); 1239 fVP.SetViewAndLights (viewPoint); 1240 } 1241 1242 1243 void G4OpenGLViewer::addExportImageFormat(std::string format) { 1244 fExportImageFormatVector.push_back(format); 1245 } 1246 1247 bool G4OpenGLViewer::setExportImageFormat(std::string format, bool quiet) { 1248 bool found = false; 1249 std::string list; 1250 for (unsigned int a=0; a<fExportImageFormatVector.size(); a++) { 1251 list +=fExportImageFormatVector.at(a) + " "; 1252 1253 if (fExportImageFormatVector.at(a) == format) { 1254 if (! quiet) { 1255 G4cout << " Changing export format to \"" << format << "\"" << G4endl; 1256 } 1257 if (format != fExportImageFormat) { 1258 fExportFilenameIndex = 0; 1259 fExportImageFormat = format; 1260 } 1261 return true; 1262 } 1263 } 1264 if (! found) { 1265 if (format.size() == 0) { 1266 G4cout << " Current formats availables are : " << list << G4endl; 1267 } else { 1268 G4cerr << " Format \"" << format << "\" is not available for the selected viewer. Current formats availables are : " << list << G4endl; 1269 } 1270 } 1271 return false; 1272 } 1273 1274 1275 // From MESA implementation : 1276 // http://www.techques.com/question/1-8660454/gluPickMatrix-code-from-Mesa 1277 1278 void G4OpenGLViewer::g4GluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, 1279 GLint viewport[4]) 1280 { 1281 GLdouble mat[16]; 1282 GLdouble sx, sy; 1283 GLdouble tx, ty; 1284 1285 sx = viewport[2] / width; 1286 sy = viewport[3] / height; 1287 tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width; 1288 ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height; 1289 1290 #define M(row, col) mat[col*4+row] 1291 M(0, 0) = sx; 1292 M(0, 1) = 0.0; 1293 M(0, 2) = 0.0; 1294 M(0, 3) = tx; 1295 M(1, 0) = 0.0; 1296 M(1, 1) = sy; 1297 M(1, 2) = 0.0; 1298 M(1, 3) = ty; 1299 M(2, 0) = 0.0; 1300 M(2, 1) = 0.0; 1301 M(2, 2) = 1.0; 1302 M(2, 3) = 0.0; 1303 M(3, 0) = 0.0; 1304 M(3, 1) = 0.0; 1305 M(3, 2) = 0.0; 1306 M(3, 3) = 1.0; 1307 #undef M 1308 1309 glMultMatrixd(mat); 1310 } 1311 1312 1313 1314 1315 1316 // From MESA implementation : 1317 // https://github.com/jlamarche/iOS-OpenGLES-Stuff/blob/master/Wavefront%20OBJ%20Loader/Classes/gluLookAt.m 1318 // or http://www.daniweb.com/software-development/game-development/threads/308901/lookat-matrix-source-code 1319 1320 void G4OpenGLViewer::g4GluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, 1321 GLdouble centerx, GLdouble centery, GLdouble 1322 centerz, 1323 GLdouble upx, GLdouble upy, GLdouble upz ) 1324 { 1325 GLdouble mat[16]; 1326 GLdouble x[3], y[3], z[3]; 1327 GLdouble mag; 1328 1329 /* Make rotation matrix */ 1330 1331 /* Z vector */ 1332 z[0] = eyex - centerx; 1333 z[1] = eyey - centery; 1334 z[2] = eyez - centerz; 1335 mag = std::sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); 1336 if (mag) { /* mpichler, 19950515 */ 1337 z[0] /= mag; 1338 z[1] /= mag; 1339 z[2] /= mag; 1340 } 1341 1342 /* Y vector */ 1343 y[0] = upx; 1344 y[1] = upy; 1345 y[2] = upz; 1346 1347 /* X vector = Y cross Z */ 1348 x[0] = y[1] * z[2] - y[2] * z[1]; 1349 x[1] = -y[0] * z[2] + y[2] * z[0]; 1350 x[2] = y[0] * z[1] - y[1] * z[0]; 1351 1352 /* Recompute Y = Z cross X */ 1353 y[0] = z[1] * x[2] - z[2] * x[1]; 1354 y[1] = -z[0] * x[2] + z[2] * x[0]; 1355 y[2] = z[0] * x[1] - z[1] * x[0]; 1356 1357 /* mpichler, 19950515 */ 1358 /* cross product gives area of parallelogram, which is < 1.0 for 1359 * non-perpendicular unit-length vectors; so normalize x, y here 1360 */ 1361 1362 mag = std::sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); 1363 if (mag) { 1364 x[0] /= mag; 1365 x[1] /= mag; 1366 x[2] /= mag; 1367 } 1368 1369 mag = std::sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); 1370 if (mag) { 1371 y[0] /= mag; 1372 y[1] /= mag; 1373 y[2] /= mag; 1374 } 1375 1376 #define M(row,col) mat[col*4+row] 1377 M(0, 0) = x[0]; 1378 M(0, 1) = x[1]; 1379 M(0, 2) = x[2]; 1380 M(0, 3) = 0.0; 1381 M(1, 0) = y[0]; 1382 M(1, 1) = y[1]; 1383 M(1, 2) = y[2]; 1384 M(1, 3) = 0.0; 1385 M(2, 0) = z[0]; 1386 M(2, 1) = z[1]; 1387 M(2, 2) = z[2]; 1388 M(2, 3) = 0.0; 1389 M(3, 0) = 0.0; 1390 M(3, 1) = 0.0; 1391 M(3, 2) = 0.0; 1392 M(3, 3) = 1.0; 1393 #undef M 1394 glMultMatrixd(mat); 1395 1396 /* Translate Eye to Origin */ 1397 glTranslated(-eyex, -eyey, -eyez); 1398 } 1399 1400 void G4OpenGLViewer::g4GlOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) { 1401 // glOrtho (left, right, bottom, top, near, far); 1402 1403 GLdouble a = 2.0 / (right - left); 1404 GLdouble b = 2.0 / (top - bottom); 1405 GLdouble c = -2.0 / (zFar - zNear); 1406 1407 GLdouble tx = - (right + left)/(right - left); 1408 GLdouble ty = - (top + bottom)/(top - bottom); 1409 GLdouble tz = - (zFar + zNear)/(zFar - zNear); 1410 1411 GLdouble ortho[16] = { 1412 a, 0, 0, 0, 1413 0, b, 0, 0, 1414 0, 0, c, 0, 1415 tx, ty, tz, 1 1416 }; 1417 glMultMatrixd(ortho); 1418 1419 } 1420 1421 1422 void G4OpenGLViewer::g4GlFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) { 1423 // glFrustum (left, right, bottom, top, near, far); 1424 1425 GLdouble deltaX = right - left; 1426 GLdouble deltaY = top - bottom; 1427 GLdouble deltaZ = zFar - zNear; 1428 1429 GLdouble a = 2.0f * zNear / deltaX; 1430 GLdouble b = 2.0f * zNear / deltaY; 1431 GLdouble c = (right + left) / deltaX; 1432 GLdouble d = (top + bottom) / deltaY; 1433 GLdouble e = -(zFar + zNear) / (zFar - zNear); 1434 GLdouble f = -2.0f * zFar * zNear / deltaZ; 1435 1436 GLdouble proj[16] = { 1437 a, 0, 0, 0, 1438 0, b, 0, 0, 1439 c, d, e, -1.0f, 1440 0, 0, f, 0 1441 }; 1442 1443 glMultMatrixd(proj); 1444 1445 } 1446 1447 G4String G4OpenGLViewerPickMap::print() { 1448 std::ostringstream txt; 1449 for (unsigned int a=0; a<fAttributes.size(); a++) { 1450 txt << fAttributes[a]; 1451 if (a < fAttributes.size() - 1) txt << "\n"; 1452 } 1453 return txt.str(); 1454 } 1455