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 10th February 1997 30 // OpenGL stored scene - creates OpenGL display lists. 31 32 #include "G4OpenGLStoredSceneHandler.hh" 33 34 #include "G4PhysicalVolumeModel.hh" 35 #include "G4LogicalVolumeModel.hh" 36 #include "G4VPhysicalVolume.hh" 37 #include "G4LogicalVolume.hh" 38 #include "G4Polyline.hh" 39 #include "G4Polymarker.hh" 40 #include "G4Text.hh" 41 #include "G4Circle.hh" 42 #include "G4Square.hh" 43 #include "G4Polyhedron.hh" 44 #include "G4AttHolder.hh" 45 #include "G4OpenGLTransform3D.hh" 46 #include "G4OpenGLViewer.hh" 47 #include "G4AttHolder.hh" 48 49 #include <typeinfo> 50 51 G4int G4OpenGLStoredSceneHandler::fSceneIdCount = 0; 52 53 G4int G4OpenGLStoredSceneHandler::fDisplayListId = 0; 54 55 G4OpenGLStoredSceneHandler::PO::PO(): 56 fDisplayListId(0), 57 fPickName(0), 58 fpG4TextPlus(0), 59 fMarkerOrPolyline(false) 60 {} 61 62 G4OpenGLStoredSceneHandler::PO::PO(const G4OpenGLStoredSceneHandler::PO& po): 63 fDisplayListId(po.fDisplayListId), 64 fTransform(po.fTransform), 65 fPickName(po.fPickName), 66 fColour(po.fColour), 67 fpG4TextPlus(po.fpG4TextPlus? new G4TextPlus(*po.fpG4TextPlus): 0), 68 fMarkerOrPolyline(po.fMarkerOrPolyline) 69 {} 70 71 G4OpenGLStoredSceneHandler::PO::PO(G4int id, const G4Transform3D& tr): 72 fDisplayListId(id), 73 fTransform(tr), 74 fPickName(0), 75 fpG4TextPlus(0), 76 fMarkerOrPolyline(false) 77 {} 78 79 G4OpenGLStoredSceneHandler::PO::~PO() 80 { 81 delete fpG4TextPlus; 82 } 83 84 G4OpenGLStoredSceneHandler::PO& G4OpenGLStoredSceneHandler::PO::operator= 85 (const G4OpenGLStoredSceneHandler::PO& rhs) 86 { 87 if (&rhs == this) return *this; 88 fDisplayListId = rhs.fDisplayListId; 89 fTransform = rhs.fTransform; 90 fPickName = rhs.fPickName; 91 fColour = rhs.fColour; 92 fpG4TextPlus = rhs.fpG4TextPlus? new G4TextPlus(*rhs.fpG4TextPlus): 0; 93 fMarkerOrPolyline = rhs.fMarkerOrPolyline; 94 return *this; 95 } 96 97 G4OpenGLStoredSceneHandler::TO::TO(): 98 fDisplayListId(0), 99 fPickName(0), 100 fStartTime(-G4VisAttributes::fVeryLongTime), 101 fEndTime(G4VisAttributes::fVeryLongTime), 102 fpG4TextPlus(0), 103 fMarkerOrPolyline(false) 104 {} 105 106 G4OpenGLStoredSceneHandler::TO::TO(const G4OpenGLStoredSceneHandler::TO& to): 107 fDisplayListId(to.fDisplayListId), 108 fTransform(to.fTransform), 109 fPickName(to.fPickName), 110 fStartTime(to.fStartTime), 111 fEndTime(to.fEndTime), 112 fColour(to.fColour), 113 fpG4TextPlus(to.fpG4TextPlus? new G4TextPlus(*to.fpG4TextPlus): 0), 114 fMarkerOrPolyline(to.fMarkerOrPolyline) 115 {} 116 117 G4OpenGLStoredSceneHandler::TO::TO(G4int id, const G4Transform3D& tr): 118 fDisplayListId(id), 119 fTransform(tr), 120 fPickName(0), 121 fStartTime(-G4VisAttributes::fVeryLongTime), 122 fEndTime(G4VisAttributes::fVeryLongTime), 123 fpG4TextPlus(0), 124 fMarkerOrPolyline(false) 125 {} 126 127 G4OpenGLStoredSceneHandler::TO::~TO() 128 { 129 delete fpG4TextPlus; 130 } 131 132 G4OpenGLStoredSceneHandler::TO& G4OpenGLStoredSceneHandler::TO::operator= 133 (const G4OpenGLStoredSceneHandler::TO& rhs) 134 { 135 if (&rhs == this) return *this; 136 fDisplayListId = rhs.fDisplayListId; 137 fTransform = rhs.fTransform; 138 fPickName = rhs.fPickName; 139 fStartTime = rhs.fStartTime; 140 fEndTime = rhs.fEndTime; 141 fColour = rhs.fColour; 142 fpG4TextPlus = rhs.fpG4TextPlus? new G4TextPlus(*rhs.fpG4TextPlus): 0; 143 fMarkerOrPolyline = rhs.fMarkerOrPolyline; 144 return *this; 145 } 146 147 G4OpenGLStoredSceneHandler::G4OpenGLStoredSceneHandler 148 (G4VGraphicsSystem& system, 149 const G4String& name): 150 G4OpenGLSceneHandler (system, fSceneIdCount++, name), 151 fDoNotUseDisplayList(false), 152 fTopPODL (0) 153 {} 154 155 G4OpenGLStoredSceneHandler::~G4OpenGLStoredSceneHandler () 156 {} 157 158 void G4OpenGLStoredSceneHandler::BeginPrimitives 159 (const G4Transform3D& objectTransformation) 160 { 161 G4OpenGLSceneHandler::BeginPrimitives (objectTransformation); 162 if (fReadyForTransients) glDrawBuffer (GL_FRONT); 163 // Display list setup moved to AddPrimitivePreamble. See notes there. 164 } 165 166 void G4OpenGLStoredSceneHandler::EndPrimitives () 167 { 168 // See all primitives immediately... At least soon... 169 ScaledFlush(); 170 glDrawBuffer (GL_BACK); 171 G4OpenGLSceneHandler::EndPrimitives (); 172 } 173 174 void G4OpenGLStoredSceneHandler::BeginPrimitives2D 175 (const G4Transform3D& objectTransformation) 176 { 177 G4OpenGLSceneHandler::BeginPrimitives2D(objectTransformation); 178 if (fReadyForTransients) glDrawBuffer (GL_FRONT); 179 } 180 181 void G4OpenGLStoredSceneHandler::EndPrimitives2D () 182 { 183 // See all primitives immediately... At least soon... 184 ScaledFlush(); 185 glDrawBuffer (GL_BACK); 186 G4OpenGLSceneHandler::EndPrimitives2D (); 187 } 188 189 G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreamble(const G4VMarker& visible) 190 { 191 return AddPrimitivePreambleInternal(visible, true, false); 192 } 193 G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreamble(const G4Polyline& visible) 194 { 195 return AddPrimitivePreambleInternal(visible, false, true); 196 } 197 G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreamble(const G4Polyhedron& visible) 198 { 199 return AddPrimitivePreambleInternal(visible, false, false); 200 } 201 202 G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreambleInternal 203 (const G4Visible& visible, bool isMarker, bool isPolyline) 204 { 205 // Get applicable vis attributes for all primitives. 206 fpVisAttribs = fpViewer->GetApplicableVisAttributes(visible.GetVisAttributes()); 207 const G4Colour& c = GetColour (); 208 G4double opacity = c.GetAlpha (); 209 210 G4bool transparency_enabled = true; 211 G4bool isMarkerNotHidden = true; 212 G4OpenGLViewer* pOGLViewer = dynamic_cast<G4OpenGLViewer*>(fpViewer); 213 if (pOGLViewer) { 214 transparency_enabled = pOGLViewer->transparency_enabled; 215 isMarkerNotHidden = pOGLViewer->fVP.IsMarkerNotHidden(); 216 } 217 218 G4bool isTransparent = opacity < 1.; 219 G4bool isMarkerOrPolyline = isMarker || isPolyline; 220 G4bool treatAsTransparent = transparency_enabled && isTransparent; 221 G4bool treatAsNotHidden = isMarkerNotHidden && isMarkerOrPolyline; 222 223 if (fProcessing2D) glDisable (GL_DEPTH_TEST); 224 else { 225 if (isMarkerOrPolyline && isMarkerNotHidden) 226 glDisable (GL_DEPTH_TEST); 227 else {glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LEQUAL);} 228 } 229 230 if (fThreePassCapable) { 231 232 // Ensure transparent objects are drawn *after* opaque ones and before 233 // non-hidden markers. The problem of blending/transparency/alpha 234 // is quite a tricky one - see History of opengl-V07-01-01/2/3. 235 if (!(fSecondPassForTransparency || fThirdPassForNonHiddenMarkers)) { 236 // First pass... 237 if (treatAsTransparent) { // Request pass for transparent objects... 238 fSecondPassForTransparencyRequested = true; 239 } 240 if (treatAsNotHidden) { // Request pass for non-hidden markers... 241 fThirdPassForNonHiddenMarkersRequested = true; 242 } 243 // On first pass, transparent objects and non-hidden markers are not drawn... 244 if (treatAsTransparent || treatAsNotHidden) { 245 return false; // No further processing. 246 } 247 } 248 249 // On second pass, only transparent objects are drawn... 250 if (fSecondPassForTransparency) { 251 if (!treatAsTransparent) { 252 return false; // No further processing. 253 } 254 } 255 256 // On third pass, only non-hidden markers are drawn... 257 if (fThirdPassForNonHiddenMarkers) { 258 if (!treatAsNotHidden) { 259 return false; // No further processing. 260 } 261 } 262 } // fThreePassCapable 263 264 // Loads G4Atts for picking... 265 G4bool isPicking = false; 266 if (fpViewer->GetViewParameters().IsPicking()) { 267 isPicking = true; 268 glLoadName(++fPickName); 269 G4AttHolder* holder = new G4AttHolder; 270 LoadAtts(visible, holder); 271 fPickMap[fPickName] = holder; 272 } 273 274 // Because of our need to control colour of transients (display by 275 // time fading), display lists may only cover a single primitive. 276 // So display list setup is here. 277 278 if (fDoNotUseDisplayList) { 279 280 glPushMatrix(); 281 G4OpenGLTransform3D oglt (fObjectTransformation); 282 glMultMatrixd (oglt.GetGLMatrix ()); 283 if (transparency_enabled) { 284 glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha()); 285 } else { 286 glColor3d(c.GetRed(),c.GetGreen(),c.GetBlue()); 287 } 288 289 } else { 290 291 fDisplayListId = glGenLists (1); 292 if (glGetError() == GL_OUT_OF_MEMORY) { 293 static G4int errorCount = 0; 294 if (errorCount < 5) { 295 errorCount++; 296 G4ExceptionDescription ed; 297 ed << 298 "Error attempting to create an OpenGL display list." 299 "\nCurrent display list id: " << fDisplayListId << 300 "\nMaybe out of memory?"; 301 G4Exception 302 ("G4OpenGLStoredSceneHandler::AddPrimitivePreambleInternal","opengl1001", 303 JustWarning,ed); 304 } 305 return false; 306 } 307 if (fReadyForTransients) { 308 TO to(fDisplayListId, fObjectTransformation); 309 if (isPicking) to.fPickName = fPickName; 310 to.fColour = c; 311 to.fStartTime = fpVisAttribs->GetStartTime(); 312 to.fEndTime = fpVisAttribs->GetEndTime(); 313 to.fMarkerOrPolyline = isMarkerOrPolyline; 314 fTOList.push_back(to); 315 // For transient objects, colour, transformation, are kept in 316 // the TO, so should *not* be in the display list. As mentioned 317 // above, in some cases (display-by-time fading) we need to have 318 // independent control of colour. But for now transform and set 319 // colour for immediate display. 320 glPushMatrix(); 321 G4OpenGLTransform3D oglt (fObjectTransformation); 322 glMultMatrixd (oglt.GetGLMatrix ()); 323 if (transparency_enabled) { 324 glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha()); 325 } else { 326 glColor3d(c.GetRed(),c.GetGreen(),c.GetBlue()); 327 } 328 (void) ExtraTOProcessing(visible, fTOList.size() - 1); 329 // Ignore return value of the above. If this visible does not use 330 // gl commands, a display list is created that is empty and not 331 // used. 332 glNewList (fDisplayListId, GL_COMPILE_AND_EXECUTE); 333 } else { 334 PO po(fDisplayListId, fObjectTransformation); 335 if (isPicking) po.fPickName = fPickName; 336 po.fColour = c; 337 po.fMarkerOrPolyline = isMarkerOrPolyline; 338 fPOList.push_back(po); 339 // For permanent objects, colour is kept in the PO, so should 340 // *not* be in the display list. This is so that sub-classes 341 // may implement colour modifications according to their own 342 // criteria, e.g., scene tree slider in Qt. But for now set 343 // colour for immediate display. 344 if (transparency_enabled) { 345 glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha()); 346 } else { 347 glColor3d(c.GetRed(),c.GetGreen(),c.GetBlue()); 348 } 349 G4bool usesGLCommands = ExtraPOProcessing(visible, fPOList.size() - 1); 350 // Transients are displayed as they come (GL_COMPILE_AND_EXECUTE 351 // above) but persistents are compiled into display lists 352 // (GL_COMPILE only) and then drawn from the display lists with 353 // their fObjectTransformation as stored in fPOList. Thus, 354 // there is no need to do glMultMatrixd here. If 355 // ExtraPOProcessing says the visible object does not use gl 356 // commands, simply return and abandon further processing. It 357 // is assumed that all relevant information is kept in the 358 // POList. 359 if (!usesGLCommands) return false; 360 glNewList (fDisplayListId, GL_COMPILE); 361 } 362 } 363 364 if (fProcessing2D) { 365 // Push current 3D world matrices and load identity to define screen 366 // coordinates... 367 glMatrixMode (GL_PROJECTION); 368 glPushMatrix(); 369 glLoadIdentity(); 370 if (pOGLViewer) { 371 pOGLViewer->g4GlOrtho (-1., 1., -1., 1., -G4OPENGL_FLT_BIG, G4OPENGL_FLT_BIG); 372 } 373 glMatrixMode (GL_MODELVIEW); 374 glPushMatrix(); 375 glLoadIdentity(); 376 G4OpenGLTransform3D oglt (fObjectTransformation); 377 glMultMatrixd (oglt.GetGLMatrix ()); 378 glDisable (GL_LIGHTING); 379 } else { 380 if (isMarker) { 381 glDisable (GL_LIGHTING); 382 } else { 383 glEnable (GL_LIGHTING); 384 } 385 } 386 387 return true; 388 } 389 390 void G4OpenGLStoredSceneHandler::AddPrimitivePostamble() 391 { 392 if (fProcessing2D) { 393 // Pop current 3D world matrices back again... 394 glMatrixMode (GL_PROJECTION); 395 glPopMatrix(); 396 glMatrixMode (GL_MODELVIEW); 397 glPopMatrix(); 398 } 399 400 // if ((glGetError() == GL_TABLE_TOO_LARGE) || (glGetError() == GL_OUT_OF_MEMORY)) { // Could close? 401 if (glGetError() == GL_OUT_OF_MEMORY) { // Could close? 402 G4cerr << 403 "ERROR: G4OpenGLStoredSceneHandler::AddPrimitivePostamble: Failure" 404 " to allocate display List for fTopPODL - try OpenGL Immediated mode." 405 << G4endl; 406 } 407 if (!fDoNotUseDisplayList) { 408 glEndList(); 409 if (glGetError() == GL_OUT_OF_MEMORY) { // Could close? 410 G4cerr << 411 "ERROR: G4OpenGLStoredSceneHandler::AddPrimitivePostamble: Failure" 412 " to allocate display List for fTopPODL - try OpenGL Immediated mode." 413 << G4endl; 414 } 415 } 416 if (fReadyForTransients || fDoNotUseDisplayList) { 417 glPopMatrix(); 418 } 419 } 420 421 void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Polyline& polyline) 422 { 423 G4bool furtherprocessing = AddPrimitivePreamble(polyline); 424 if (furtherprocessing) { 425 G4OpenGLSceneHandler::AddPrimitive(polyline); 426 AddPrimitivePostamble(); 427 } 428 } 429 430 void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Polymarker& polymarker) 431 { 432 G4bool furtherprocessing = AddPrimitivePreamble(polymarker); 433 if (furtherprocessing) { 434 G4OpenGLSceneHandler::AddPrimitive(polymarker); 435 AddPrimitivePostamble(); 436 } 437 } 438 439 void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Text& text) 440 { 441 // Note: colour is still handled in 442 // G4OpenGLSceneHandler::AddPrimitive(const G4Text&), so it still 443 // gets into the display list 444 G4bool furtherprocessing = AddPrimitivePreamble(text); 445 if (furtherprocessing) { 446 G4OpenGLSceneHandler::AddPrimitive(text); 447 AddPrimitivePostamble(); 448 } 449 } 450 451 void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Circle& circle) 452 { 453 G4bool furtherprocessing = AddPrimitivePreamble(circle); 454 if (furtherprocessing) { 455 G4OpenGLSceneHandler::AddPrimitive(circle); 456 AddPrimitivePostamble(); 457 } 458 } 459 460 void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Square& square) 461 { 462 G4bool furtherprocessing = AddPrimitivePreamble(square); 463 if (furtherprocessing) { 464 G4OpenGLSceneHandler::AddPrimitive(square); 465 AddPrimitivePostamble(); 466 } 467 } 468 469 void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Polyhedron& polyhedron) 470 { 471 // Note: colour is still handled in 472 // G4OpenGLSceneHandler::AddPrimitive(const G4Polyhedron&), so it still 473 // gets into the display list 474 G4bool furtherprocessing = AddPrimitivePreamble(polyhedron); 475 if (furtherprocessing) { 476 G4OpenGLSceneHandler::AddPrimitive(polyhedron); 477 AddPrimitivePostamble(); 478 } 479 } 480 481 void G4OpenGLStoredSceneHandler::BeginModeling () { 482 G4VSceneHandler::BeginModeling(); 483 /* Debug... 484 fDisplayListId = glGenLists (1); 485 G4cout << "OGL::fDisplayListId (start): " << fDisplayListId << G4endl; 486 */ 487 } 488 489 void G4OpenGLStoredSceneHandler::EndModeling () { 490 // Make a List which calls the other lists. 491 fTopPODL = glGenLists (1); 492 if (glGetError() == GL_OUT_OF_MEMORY) { // Could pre-allocate? 493 G4cerr << 494 "ERROR: G4OpenGLStoredSceneHandler::EndModeling: Failure to allocate" 495 " display List for fTopPODL - try OpenGL Immediated mode." 496 << G4endl; 497 } else { 498 499 glNewList (fTopPODL, GL_COMPILE); { 500 for (size_t i = 0; i < fPOList.size (); i++) { 501 glPushMatrix(); 502 G4OpenGLTransform3D oglt (fPOList[i].fTransform); 503 glMultMatrixd (oglt.GetGLMatrix ()); 504 if (fpViewer->GetViewParameters().IsPicking()) 505 glLoadName(fPOList[i].fPickName); 506 glCallList (fPOList[i].fDisplayListId); 507 glPopMatrix(); 508 } 509 } 510 glEndList (); 511 512 if (glGetError() == GL_OUT_OF_MEMORY) { // Could close? 513 G4cerr << 514 "ERROR: G4OpenGLStoredSceneHandler::EndModeling: Failure to allocate" 515 " display List for fTopPODL - try OpenGL Immediated mode." 516 << G4endl; 517 } 518 } 519 520 G4VSceneHandler::EndModeling (); 521 } 522 523 void G4OpenGLStoredSceneHandler::ClearStore () { 524 525 //G4cout << "G4OpenGLStoredSceneHandler::ClearStore" << G4endl; 526 527 G4VSceneHandler::ClearStore (); // Sets need kernel visit, etc. 528 529 // Delete OpenGL permanent display lists. 530 for (size_t i = 0; i < fPOList.size (); i++) 531 glDeleteLists (fPOList[i].fDisplayListId, 1); 532 if (fTopPODL) glDeleteLists (fTopPODL, 1); 533 fTopPODL = 0; 534 535 // Clear other lists, dictionary, etc. 536 fPOList.clear (); 537 fSolidMap.clear (); 538 ClearAndDestroyAtts(); 539 540 // ...and clear transient store... 541 for (size_t i = 0; i < fTOList.size (); i++) 542 glDeleteLists(fTOList[i].fDisplayListId, 1); 543 fTOList.clear (); 544 } 545 546 void G4OpenGLStoredSceneHandler::ClearTransientStore () 547 { 548 //G4cout << "G4OpenGLStoredSceneHandler::ClearTransientStore" << G4endl; 549 550 // Delete OpenGL transient display lists and Transient Objects themselves. 551 for (size_t i = 0; i < fTOList.size (); i++) 552 glDeleteLists(fTOList[i].fDisplayListId, 1); 553 fTOList.clear (); 554 555 // Redraw the scene ready for the next event. 556 if (fpViewer) { 557 fpViewer -> SetView (); 558 fpViewer -> ClearView (); 559 fpViewer -> DrawView (); 560 } 561 } 562