#include "TGLScene.h"
#include "TGLRnrCtx.h"
#include "TGLObject.h"
#include "TGLSelectRecord.h"
#include "TGLLogicalShape.h"
#include "TGLPhysicalShape.h"
#include "TGLCamera.h"
#include "TGLContext.h"
#include "TGLIncludes.h"
#include <TColor.h>
#include <TROOT.h>
#include <TClass.h>
#include <algorithm>
TGLScene::TSceneInfo::TSceneInfo(TGLViewerBase* view, TGLScene* scene) :
TGLSceneInfo (view, scene),
fMinorStamp (0),
fOpaqueCnt (0),
fTranspCnt (0),
fAsPixelCnt (0)
{
}
TGLScene::TSceneInfo::~TSceneInfo()
{
}
void TGLScene::TSceneInfo::ClearDrawElementVec(DrawElementVec_t& vec,
Int_t maxSize)
{
if (vec.capacity() > (size_t) maxSize) {
DrawElementVec_t foo;
foo.reserve((size_t) maxSize);
vec.swap(foo);
} else {
vec.clear();
}
}
void TGLScene::TSceneInfo::ClearDrawElementPtrVec(DrawElementPtrVec_t& vec,
Int_t maxSize)
{
if (vec.capacity() > (size_t) maxSize) {
DrawElementPtrVec_t foo;
foo.reserve((size_t) maxSize);
vec.swap(foo);
} else {
vec.clear();
}
}
void TGLScene::TSceneInfo::ClearAfterRebuild()
{
Int_t maxSize = (Int_t) fShapesOfInterest.size();
ClearDrawElementVec(fVisibleElements, maxSize);
}
void TGLScene::TSceneInfo::ClearAfterUpdate()
{
Int_t maxSize = (Int_t) fShapesOfInterest.size();
ClearDrawElementPtrVec(fOpaqueElements, maxSize);
ClearDrawElementPtrVec(fTranspElements, maxSize);
ClearDrawElementPtrVec(fSelOpaqueElements, maxSize);
ClearDrawElementPtrVec(fSelTranspElements, maxSize);
fMinorStamp = 0;
}
void TGLScene::TSceneInfo::Lodify(TGLRnrCtx& ctx)
{
for (DrawElementVec_i i = fVisibleElements.begin(); i != fVisibleElements.end(); ++i)
i->fPhysical->QuantizeShapeLOD(i->fPixelLOD, ctx.CombiLOD(), i->fFinalLOD);
}
void TGLScene::TSceneInfo::PreDraw()
{
if (fMinorStamp < fScene->GetMinorStamp())
{
fOpaqueElements.clear();
fTranspElements.clear();
fSelOpaqueElements.clear();
fSelTranspElements.clear();
for (DrawElementVec_i i = fVisibleElements.begin(); i != fVisibleElements.end(); ++i)
{
if (i->fPhysical->IsSelected())
{
if (i->fPhysical->IsTransparent())
fSelTranspElements.push_back(&*i);
else
fSelOpaqueElements.push_back(&*i);
} else {
if (i->fPhysical->IsTransparent())
fTranspElements.push_back(&*i);
else
fOpaqueElements.push_back(&*i);
}
}
fMinorStamp = fScene->GetMinorStamp();
}
}
void TGLScene::TSceneInfo::PostDraw()
{
}
void TGLScene::TSceneInfo::ResetDrawStats()
{
fOpaqueCnt = 0;
fTranspCnt = 0;
fAsPixelCnt = 0;
fByShapeCnt.clear();
}
void TGLScene::TSceneInfo::UpdateDrawStats(const TGLPhysicalShape& shape,
Short_t lod)
{
if (shape.IsTransparent()) {
++fTranspCnt;
} else {
++fOpaqueCnt;
}
if (lod == TGLRnrCtx::kLODPixel) {
++fAsPixelCnt;
}
if (gDebug>3) {
TClass* logIsA = shape.GetLogical()->IsA();
std::map<TClass*, UInt_t>::iterator it = fByShapeCnt.find(logIsA);
if (it == fByShapeCnt.end()) {
it = fByShapeCnt.insert(std::make_pair(logIsA, 0u)).first;
}
it->second++;
}
}
void TGLScene::TSceneInfo::DumpDrawStats()
{
if (gDebug>2)
{
TString out;
out += Form("Drew scene (%s / %i LOD) - %i (Op %i Trans %i) %i pixel\n",
TGLRnrCtx::StyleName(LastStyle()), LastLOD(),
fOpaqueCnt + fTranspCnt, fOpaqueCnt, fTranspCnt, fAsPixelCnt);
out += Form("\tInner phys nums: physicals=%d, of_interest=%lu, visible=%lu, op=%lu, trans=%lu",
((TGLScene*)fScene)->GetMaxPhysicalID(),
(ULong_t)fShapesOfInterest.size(), (ULong_t)fVisibleElements.size(),
(ULong_t)fOpaqueElements.size(), (ULong_t)fTranspElements.size());
if (gDebug>3)
{
out += "\n\tStatistics by shape:\n";
std::map<TClass*, UInt_t>::const_iterator it = fByShapeCnt.begin();
while (it != fByShapeCnt.end()) {
out += Form("\t%-20s %u\n", it->first->GetName(), it->second);
it++;
}
}
Info("TGLScene::DumpDrawStats()", "%s",out.Data());
}
}
ClassImp(TGLScene);
TGLScene::TGLScene() :
TGLSceneBase(),
fGLCtxIdentity(0),
fInSmartRefresh(kFALSE),
fLastPointSizeScale (0),
fLastLineWidthScale (0)
{}
TGLScene::~TGLScene()
{
TakeLock(kModifyLock);
ReleaseGLCtxIdentity();
DestroyPhysicals();
DestroyLogicals();
if (fGLCtxIdentity)
fGLCtxIdentity->ReleaseClient();
ReleaseLock(kModifyLock);
}
void TGLScene::ReleaseGLCtxIdentity()
{
if (fGLCtxIdentity == 0) return;
if (fGLCtxIdentity->IsValid())
{
LogicalShapeMapIt_t lit = fLogicalShapes.begin();
while (lit != fLogicalShapes.end()) {
lit->second->DLCachePurge();
++lit;
}
}
else
{
LogicalShapeMapIt_t lit = fLogicalShapes.begin();
while (lit != fLogicalShapes.end()) {
lit->second->DLCacheDrop();
++lit;
}
}
fGLCtxIdentity->ReleaseClient();
fGLCtxIdentity = 0;
}
TGLScene::TSceneInfo* TGLScene::CreateSceneInfo(TGLViewerBase* view)
{
return new TSceneInfo(view, this);
}
inline Bool_t TGLScene::ComparePhysicalVolumes(const TGLPhysicalShape* shape1,
const TGLPhysicalShape* shape2)
{
return (shape1->BoundingBox().Volume() > shape2->BoundingBox().Volume());
}
inline Bool_t TGLScene::ComparePhysicalDiagonals(const TGLPhysicalShape* shape1,
const TGLPhysicalShape* shape2)
{
return (shape1->BoundingBox().Diagonal() > shape2->BoundingBox().Diagonal());
}
void TGLScene::RebuildSceneInfo(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (sinfo == 0 || sinfo->GetScene() != this) {
Error("TGLScene::RebuildSceneInfo", "Scene mismatch.");
return;
}
TGLSceneBase::RebuildSceneInfo(rnrCtx);
if (sinfo->fShapesOfInterest.capacity() > fPhysicalShapes.size()) {
ShapeVec_t foo;
foo.reserve(fPhysicalShapes.size());
sinfo->fShapesOfInterest.swap(foo);
} else {
sinfo->fShapesOfInterest.clear();
}
PhysicalShapeMapIt_t pit = fPhysicalShapes.begin();
while (pit != fPhysicalShapes.end())
{
TGLPhysicalShape * pshp = pit->second;
const TGLLogicalShape * lshp = pshp->GetLogical();
if (rnrCtx.GetCamera()->OfInterest(pshp->BoundingBox(),
lshp->IgnoreSizeForOfInterest()))
{
sinfo->fShapesOfInterest.push_back(pshp);
}
++pit;
}
std::sort(sinfo->fShapesOfInterest.begin(), sinfo->fShapesOfInterest.end(),
TGLScene::ComparePhysicalDiagonals);
sinfo->ClearAfterRebuild();
}
void TGLScene::UpdateSceneInfo(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (sinfo == 0 || sinfo->GetScene() != this) {
Error("TGLScene::UpdateSceneInfo", "Scene mismatch.");
return;
}
TGLSceneBase::UpdateSceneInfo(rnrCtx);
if (!sinfo->IsVisible())
return;
sinfo->fVisibleElements.clear();
Int_t checkCount = 0;
Bool_t timerp = rnrCtx.IsStopwatchRunning();
sinfo->ResetUpdateTimeouted();
for (ShapeVec_i phys=sinfo->fShapesOfInterest.begin();
phys!=sinfo->fShapesOfInterest.end();
++phys, ++checkCount)
{
const TGLPhysicalShape * drawShape = *phys;
Bool_t drawNeeded = kTRUE;
if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
{
std::vector<TGLPlane>::iterator pi = sinfo->ClipPlanes().begin();
while (pi != sinfo->ClipPlanes().end())
{
if (drawShape->BoundingBox().Overlap(*pi) == Rgl::kOutside)
{
drawNeeded = kFALSE;
break;
}
++pi;
}
}
else if (sinfo->ClipMode() == TGLSceneInfo::kClipInside)
{
std::vector<TGLPlane>::iterator pi = sinfo->ClipPlanes().begin();
size_t cnt = 0;
while (pi != sinfo->ClipPlanes().end())
{
Rgl::EOverlap ovlp = drawShape->BoundingBox().Overlap(*pi);
if (ovlp == Rgl::kOutside)
break;
else if (ovlp == Rgl::kInside)
++cnt;
++pi;
}
if (cnt == sinfo->ClipPlanes().size())
drawNeeded = kFALSE;
}
if (drawNeeded)
{
std::vector<TGLPlane>::iterator pi = sinfo->FrustumPlanes().begin();
while (pi != sinfo->FrustumPlanes().end())
{
if (drawShape->BoundingBox().Overlap(*pi) == Rgl::kOutside)
{
drawNeeded = kFALSE;
break;
}
++pi;
}
}
if (drawNeeded)
{
DrawElement_t de(drawShape);
drawShape->CalculateShapeLOD(rnrCtx, de.fPixelSize, de.fPixelLOD);
sinfo->fVisibleElements.push_back(de);
}
if (timerp && (checkCount % 5000) == 0 && rnrCtx.HasStopwatchTimedOut())
{
sinfo->UpdateTimeouted();
if (rnrCtx.ViewerLOD() == TGLRnrCtx::kLODHigh)
Warning("TGLScene::UpdateSceneInfo",
"Timeout reached, not all elements processed.");
break;
}
}
sinfo->ClearAfterUpdate();
}
void TGLScene::LodifySceneInfo(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (sinfo == 0 || sinfo->GetScene() != this) {
Error("TGLScene::LodifySceneInfo", "Scene mismatch.");
return;
}
TGLSceneBase::LodifySceneInfo(rnrCtx);
sinfo->Lodify(rnrCtx);
}
void TGLScene::PreDraw(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (sinfo == 0 || sinfo->GetScene() != this) {
TGLSceneInfo* si = rnrCtx.GetSceneInfo();
Error("TGLScene::PreDraw", "%s", Form("SceneInfo mismatch (0x%lx, '%s').",
(ULong_t)si, si ? si->IsA()->GetName() : "<>"));
return;
}
TGLSceneBase::PreDraw(rnrCtx);
TGLContextIdentity* cid = rnrCtx.GetGLCtxIdentity();
if (cid != fGLCtxIdentity)
{
ReleaseGLCtxIdentity();
fGLCtxIdentity = cid;
fGLCtxIdentity->AddClientRef();
}
else
{
if (fLastPointSizeScale != TGLUtil::GetPointSizeScale() ||
fLastLineWidthScale != TGLUtil::GetLineWidthScale())
{
LogicalShapeMapIt_t lit = fLogicalShapes.begin();
while (lit != fLogicalShapes.end()) {
lit->second->DLCacheClear();
++lit;
}
}
}
fLastPointSizeScale = TGLUtil::GetPointSizeScale();
fLastLineWidthScale = TGLUtil::GetLineWidthScale();
sinfo->PreDraw();
sinfo->ResetDrawStats();
}
void TGLScene::RenderOpaque(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (!sinfo->fOpaqueElements.empty())
RenderAllPasses(rnrCtx, sinfo->fOpaqueElements, kTRUE);
}
void TGLScene::RenderTransp(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (!sinfo->fTranspElements.empty())
RenderAllPasses(rnrCtx, sinfo->fTranspElements, kTRUE);
}
void TGLScene::RenderSelOpaque(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if ( ! sinfo->fSelOpaqueElements.empty())
RenderAllPasses(rnrCtx, sinfo->fSelOpaqueElements, kFALSE);
}
void TGLScene::RenderSelTransp(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (!sinfo->fSelTranspElements.empty())
RenderAllPasses(rnrCtx, sinfo->fSelTranspElements, kFALSE);
}
void TGLScene::RenderSelOpaqueForHighlight(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if ( ! sinfo->fSelOpaqueElements.empty())
RenderHighlight(rnrCtx, sinfo->fSelOpaqueElements);
}
void TGLScene::RenderSelTranspForHighlight(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (!sinfo->fSelTranspElements.empty())
RenderHighlight(rnrCtx, sinfo->fSelTranspElements);
}
void TGLScene::RenderHighlight(TGLRnrCtx& rnrCtx,
DrawElementPtrVec_t& elVec)
{
DrawElementPtrVec_t svec(1);
glEnable(GL_STENCIL_TEST);
for (DrawElementPtrVec_i i = elVec.begin(); i != elVec.end(); ++i)
{
svec[0] = *i;
glStencilFunc(GL_ALWAYS, 0x1, 0x1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glClear(GL_STENCIL_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
RenderAllPasses(rnrCtx, svec, kFALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
rnrCtx.SetHighlightOutline(kTRUE);
RenderAllPasses(rnrCtx, svec, kFALSE);
rnrCtx.SetHighlightOutline(kFALSE);
}
glDisable(GL_STENCIL_TEST);
}
void TGLScene::PostDraw(TGLRnrCtx& rnrCtx)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
if (gDebug)
sinfo->DumpDrawStats();
sinfo->PostDraw();
TGLSceneBase::PostDraw(rnrCtx);
}
void TGLScene::RenderAllPasses(TGLRnrCtx& rnrCtx,
DrawElementPtrVec_t& elVec,
Bool_t check_timeout)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
assert(sinfo != 0);
Short_t sceneStyle = rnrCtx.SceneStyle();
Int_t reqPasses = 1;
Short_t rnrPass[2];
rnrPass[0] = rnrPass[1] = TGLRnrCtx::kPassUndef;
switch (sceneStyle)
{
case TGLRnrCtx::kFill:
case TGLRnrCtx::kOutline:
{
glEnable(GL_LIGHTING);
if (sinfo->ShouldClip())
{
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_CULL_FACE);
}
if (sceneStyle == TGLRnrCtx::kOutline && ! (rnrCtx.Selection() || rnrCtx.Highlight()))
{
reqPasses = 2;
rnrPass[0] = TGLRnrCtx::kPassOutlineFill;
rnrPass[1] = TGLRnrCtx::kPassOutlineLine;
}
else
{
rnrPass[0] = TGLRnrCtx::kPassFill;
}
break;
}
case TGLRnrCtx::kWireFrame:
{
rnrPass[0] = TGLRnrCtx::kPassWireFrame;
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
}
default:
{
assert(kFALSE);
}
}
for (Int_t i = 0; i < reqPasses; ++i)
{
Short_t pass = rnrPass[i];
rnrCtx.SetDrawPass(pass);
if (pass == TGLRnrCtx::kPassOutlineFill)
{
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.5f, 0.5f);
}
else if (pass == TGLRnrCtx::kPassOutlineLine)
{
TGLUtil::LineWidth(rnrCtx.SceneOLLineW());
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
else if (pass == TGLRnrCtx::kPassWireFrame)
{
TGLUtil::LineWidth(rnrCtx.SceneWFLineW());
}
if ( ! sinfo->ShouldClip())
{
RenderElements(rnrCtx, elVec, check_timeout);
}
else
{
TGLPlaneSet_t & planeSet = sinfo->ClipPlanes();
if (gDebug > 3)
{
Info("TGLScene::RenderAllPasses()",
"%ld active clip planes", (Long_t)planeSet.size());
}
Int_t maxGLPlanes;
glGetIntegerv(GL_MAX_CLIP_PLANES, &maxGLPlanes);
UInt_t maxPlanes = maxGLPlanes;
UInt_t planeInd;
if (planeSet.size() < maxPlanes) {
maxPlanes = planeSet.size();
}
if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
{
for (UInt_t ii=0; ii<maxPlanes; ii++) {
glClipPlane(GL_CLIP_PLANE0+ii, planeSet[ii].CArr());
glEnable(GL_CLIP_PLANE0+ii);
}
RenderElements(rnrCtx, elVec, check_timeout);
}
else
{
std::vector<TGLPlane> activePlanes;
for (planeInd=0; planeInd<maxPlanes; planeInd++)
{
activePlanes.push_back(planeSet[planeInd]);
TGLPlane& p = activePlanes.back();
p.Negate();
glClipPlane(GL_CLIP_PLANE0+planeInd, p.CArr());
glEnable(GL_CLIP_PLANE0+planeInd);
RenderElements(rnrCtx, elVec, check_timeout, &activePlanes);
p.Negate();
glClipPlane(GL_CLIP_PLANE0+planeInd, p.CArr());
}
}
for (planeInd=0; planeInd<maxPlanes; planeInd++) {
glDisable(GL_CLIP_PLANE0+planeInd);
}
}
}
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
}
void TGLScene::RenderElements(TGLRnrCtx& rnrCtx,
DrawElementPtrVec_t& elVec,
Bool_t check_timeout,
const TGLPlaneSet_t* clipPlanes)
{
TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
assert(sinfo != 0);
Int_t drawCount = 0;
for (DrawElementPtrVec_i i = elVec.begin(); i != elVec.end(); ++i)
{
const TGLPhysicalShape * drawShape = (*i)->fPhysical;
Bool_t drawNeeded = kTRUE;
if (clipPlanes && IsOutside(drawShape->BoundingBox(), *clipPlanes))
drawNeeded = kFALSE;
if (drawNeeded)
{
rnrCtx.SetShapeLOD((*i)->fFinalLOD);
rnrCtx.SetShapePixSize((*i)->fPixelSize);
glPushName(drawShape->ID());
drawShape->Draw(rnrCtx);
glPopName();
++drawCount;
sinfo->UpdateDrawStats(*drawShape, rnrCtx.ShapeLOD());
}
if (check_timeout && (drawCount % 2000) == 0 &&
rnrCtx.HasStopwatchTimedOut())
{
if (rnrCtx.ViewerLOD() == TGLRnrCtx::kLODHigh)
Warning("TGLScene::RenderElements",
"Timeout reached, not all elements rendered.");
break;
}
}
}
Bool_t TGLScene::ResolveSelectRecord(TGLSelectRecord& rec, Int_t curIdx)
{
if (curIdx >= rec.GetN())
return kFALSE;
TGLPhysicalShape* pshp = FindPhysical(rec.GetItem(curIdx));
if (pshp)
{
rec.SetTransparent(pshp->IsTransparent());
rec.SetPhysShape(pshp);
rec.SetLogShape(const_cast<TGLLogicalShape*>(pshp->GetLogical()));
rec.SetObject(pshp->GetLogical()->GetExternal());
rec.SetSpecific(0);
return kTRUE;
}
return kFALSE;
}
void TGLScene::CalcBoundingBox() const
{
Double_t xMin, xMax, yMin, yMax, zMin, zMax;
xMin = xMax = yMin = yMax = zMin = zMax = 0.0;
PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
const TGLPhysicalShape * physicalShape;
while (physicalShapeIt != fPhysicalShapes.end())
{
physicalShape = physicalShapeIt->second;
if (!physicalShape)
{
assert(kFALSE);
continue;
}
const TGLBoundingBox& box = physicalShape->BoundingBox();
if (physicalShapeIt == fPhysicalShapes.begin()) {
xMin = box.XMin(); xMax = box.XMax();
yMin = box.YMin(); yMax = box.YMax();
zMin = box.ZMin(); zMax = box.ZMax();
} else {
if (box.XMin() < xMin) { xMin = box.XMin(); }
if (box.XMax() > xMax) { xMax = box.XMax(); }
if (box.YMin() < yMin) { yMin = box.YMin(); }
if (box.YMax() > yMax) { yMax = box.YMax(); }
if (box.ZMin() < zMin) { zMin = box.ZMin(); }
if (box.ZMax() > zMax) { zMax = box.ZMax(); }
}
++physicalShapeIt;
}
fBoundingBox.SetAligned(TGLVertex3(xMin,yMin,zMin), TGLVertex3(xMax,yMax,zMax));
fBoundingBoxValid = kTRUE;
}
void TGLScene::AdoptLogical(TGLLogicalShape& shape)
{
if (fLock != kModifyLock) {
Error("TGLScene::AdoptLogical", "expected ModifyLock");
return;
}
shape.fScene = this;
fLogicalShapes.insert(LogicalShapeMapValueType_t(shape.ID(), &shape));
}
Bool_t TGLScene::DestroyLogical(TObject* logid, Bool_t mustFind)
{
if (fLock != kModifyLock) {
Error("TGLScene::DestroyLogical", "expected ModifyLock");
return kFALSE;
}
LogicalShapeMapIt_t lit = fLogicalShapes.find(logid);
if (lit == fLogicalShapes.end()) {
if (mustFind)
Error("TGLScene::DestroyLogical", "logical not found in map.");
return kFALSE;
}
TGLLogicalShape * logical = lit->second;
UInt_t phid;
while ((phid = logical->UnrefFirstPhysical()) != 0)
{
PhysicalShapeMapIt_t pit = fPhysicalShapes.find(phid);
if (pit != fPhysicalShapes.end())
DestroyPhysicalInternal(pit);
else
Warning("TGLScene::DestroyLogical", "an attached physical not found in map.");
}
assert(logical->Ref() == 0);
fLogicalShapes.erase(lit);
delete logical;
InvalidateBoundingBox();
IncTimeStamp();
return kTRUE;
}
Int_t TGLScene::DestroyLogicals()
{
if (fLock != kModifyLock) {
Error("TGLScene::DestroyLogicals", "expected ModifyLock");
return 0;
}
Int_t count = 0;
LogicalShapeMapIt_t logicalShapeIt = fLogicalShapes.begin();
const TGLLogicalShape * logicalShape;
while (logicalShapeIt != fLogicalShapes.end()) {
logicalShape = logicalShapeIt->second;
if (logicalShape) {
if (logicalShape->Ref() == 0) {
fLogicalShapes.erase(logicalShapeIt++);
delete logicalShape;
++count;
continue;
} else {
assert(kFALSE);
}
} else {
assert(kFALSE);
}
++logicalShapeIt;
}
return count;
}
TGLLogicalShape * TGLScene::FindLogical(TObject* logid) const
{
LogicalShapeMapCIt_t lit = fLogicalShapes.find(logid);
if (lit != fLogicalShapes.end()) {
return lit->second;
} else {
if (fInSmartRefresh)
return FindLogicalSmartRefresh(logid);
else
return 0;
}
}
void TGLScene::AdoptPhysical(TGLPhysicalShape & shape)
{
if (fLock != kModifyLock) {
Error("TGLScene::AdoptPhysical", "expected ModifyLock");
return;
}
assert(fPhysicalShapes.find(shape.ID()) == fPhysicalShapes.end());
fPhysicalShapes.insert(PhysicalShapeMapValueType_t(shape.ID(), &shape));
InvalidateBoundingBox();
IncTimeStamp();
}
void TGLScene::DestroyPhysicalInternal(PhysicalShapeMapIt_t pit)
{
delete pit->second;
fPhysicalShapes.erase(pit);
}
Bool_t TGLScene::DestroyPhysical(UInt_t phid)
{
if (fLock != kModifyLock) {
Error("TGLScene::DestroyPhysical", "expected ModifyLock.");
return kFALSE;
}
PhysicalShapeMapIt_t pit = fPhysicalShapes.find(phid);
if (pit == fPhysicalShapes.end()) {
Error("TGLScene::DestroyPhysical::UpdatePhysical", "physical not found.");
return kFALSE;
}
DestroyPhysicalInternal(pit);
InvalidateBoundingBox();
return kTRUE;
}
Int_t TGLScene::DestroyPhysicals()
{
if (fLock != kModifyLock) {
Error("TGLScene::DestroyPhysicals", "expected ModifyLock");
return 0;
}
UInt_t count = 0;
LogicalShapeMapIt_t lit = fLogicalShapes.begin();
while (lit != fLogicalShapes.end())
{
TGLLogicalShape *lshp = lit->second;
if (lshp && lshp->Ref() != 0)
{
count += lshp->Ref();
lshp->DestroyPhysicals();
}
++lit;
}
assert (count == fPhysicalShapes.size());
fPhysicalShapes.clear();
if (count > 0) {
InvalidateBoundingBox();
IncTimeStamp();
}
return count;
}
TGLPhysicalShape* TGLScene::FindPhysical(UInt_t phid) const
{
PhysicalShapeMapCIt_t pit = fPhysicalShapes.find(phid);
return (pit != fPhysicalShapes.end()) ? pit->second : 0;
}
UInt_t TGLScene::GetMaxPhysicalID()
{
if (fPhysicalShapes.empty()) return 0;
return (--fPhysicalShapes.end())->first;
}
Bool_t TGLScene::BeginUpdate()
{
Bool_t ok = TakeLock(kModifyLock);
return ok;
}
void TGLScene::EndUpdate(Bool_t minorChange, Bool_t sceneChanged, Bool_t updateViewers)
{
if (minorChange)
IncMinorStamp();
if (sceneChanged)
IncTimeStamp();
ReleaseLock(kModifyLock);
if (updateViewers)
TagViewersChanged();
}
void TGLScene::UpdateLogical(TObject* logid)
{
if (fLock != kModifyLock) {
Error("TGLScene::UpdateLogical", "expected ModifyLock");
return;
}
TGLLogicalShape* log = FindLogical(logid);
if (log == 0) {
Error("TGLScene::UpdateLogical", "logical not found");
return;
}
log->DLCacheClear();
log->UpdateBoundingBox();
}
void TGLScene::UpdatePhysical(UInt_t phid, Double_t* trans, UChar_t* col)
{
if (fLock != kModifyLock) {
Error("TGLScene::UpdatePhysical", "expected ModifyLock");
return;
}
TGLPhysicalShape* phys = FindPhysical(phid);
if (phys == 0) {
Error("TGLScene::UpdatePhysical", "physical not found");
return;
}
if (trans) phys->SetTransform(trans);
if (col) phys->SetDiffuseColor(col);
}
void TGLScene::UpdatePhysical(UInt_t phid, Double_t* trans, Color_t cidx, UChar_t transp)
{
if (fLock != kModifyLock) {
Error("TGLScene::UpdatePhysical", "expected ModifyLock");
return;
}
TGLPhysicalShape* phys = FindPhysical(phid);
if (phys == 0) {
Error("TGLScene::UpdatePhysical", "physical not found");
return;
}
if (trans)
phys->SetTransform(trans);
if (cidx >= 0) {
Float_t rgba[4];
RGBAFromColorIdx(rgba, cidx, transp);
phys->SetDiffuseColor(rgba);
}
}
void TGLScene::UpdatePhysioLogical(TObject* logid, Double_t* trans, UChar_t* col)
{
if (fLock != kModifyLock) {
Error("TGLScene::UpdatePhysioLogical", "expected ModifyLock");
return;
}
TGLLogicalShape* log = FindLogical(logid);
if (log == 0) {
Error("TGLScene::UpdatePhysioLogical", "logical not found");
return;
}
if (log->Ref() != 1) {
Warning("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
}
TGLPhysicalShape* phys = log->fFirstPhysical;
if (trans) phys->SetTransform(trans);
if (col) phys->SetDiffuseColor(col);
}
void TGLScene::UpdatePhysioLogical(TObject* logid, Double_t* trans, Color_t cidx, UChar_t transp)
{
if (fLock != kModifyLock) {
Error("TGLScene::UpdatePhysioLogical", "expected ModifyLock");
return;
}
TGLLogicalShape* log = FindLogical(logid);
if (log == 0) {
Error("TGLScene::UpdatePhysioLogical", "logical not found");
return;
}
if (log->Ref() != 1) {
Warning("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
}
TGLPhysicalShape* phys = log->fFirstPhysical;
if (trans)
phys->SetTransform(trans);
if (cidx >= 0) {
Float_t rgba[4];
RGBAFromColorIdx(rgba, cidx, transp);
phys->SetDiffuseColor(rgba);
}
}
UInt_t TGLScene::BeginSmartRefresh()
{
fSmartRefreshCache.swap(fLogicalShapes);
UInt_t count = 0;
LogicalShapeMapIt_t i = fSmartRefreshCache.begin();
while (i != fSmartRefreshCache.end()) {
if (i->second->KeepDuringSmartRefresh() == kFALSE) {
LogicalShapeMapIt_t j = i++;
delete j->second;
fSmartRefreshCache.erase(j);
++count;
} else {
++i;
}
}
fInSmartRefresh = kTRUE;
return count;
}
void TGLScene::EndSmartRefresh()
{
fInSmartRefresh = kFALSE;
LogicalShapeMapIt_t i = fSmartRefreshCache.begin();
while (i != fSmartRefreshCache.end()) {
delete i->second;
++i;
}
fSmartRefreshCache.clear();
}
TGLLogicalShape * TGLScene::FindLogicalSmartRefresh(TObject* ID) const
{
LogicalShapeMapIt_t it = fSmartRefreshCache.find(ID);
if (it != fSmartRefreshCache.end())
{
TGLLogicalShape* l_shape = it->second;
fSmartRefreshCache.erase(it);
if (l_shape->IsA() != TGLObject::GetGLRenderer(ID->IsA()))
{
Warning("TGLScene::FindLogicalSmartRefresh", "Wrong renderer-type found in cache.");
delete l_shape;
return 0;
}
LogicalShapeMap_t* lsm = const_cast<LogicalShapeMap_t*>(&fLogicalShapes);
lsm->insert(LogicalShapeMapValueType_t(l_shape->ID(), l_shape));
l_shape->DLCacheClear();
l_shape->UpdateBoundingBox();
return l_shape;
} else {
return 0;
}
}
UInt_t TGLScene::SizeOfScene() const
{
UInt_t size = sizeof(*this);
printf("Size: Scene Only %u\n", size);
LogicalShapeMapCIt_t logicalShapeIt = fLogicalShapes.begin();
const TGLLogicalShape * logicalShape;
while (logicalShapeIt != fLogicalShapes.end()) {
logicalShape = logicalShapeIt->second;
size += sizeof(*logicalShape);
++logicalShapeIt;
}
printf("Size: Scene + Logical Shapes %u\n", size);
PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
const TGLPhysicalShape * physicalShape;
while (physicalShapeIt != fPhysicalShapes.end()) {
physicalShape = physicalShapeIt->second;
size += sizeof(*physicalShape);
++physicalShapeIt;
}
printf("Size: Scene + Logical Shapes + Physical Shapes %u\n", size);
return size;
}
void TGLScene::DumpMapSizes() const
{
printf("Scene: %u Logicals / %u Physicals\n",
(UInt_t) fLogicalShapes.size(), (UInt_t) fPhysicalShapes.size());
}
void TGLScene::RGBAFromColorIdx(Float_t rgba[4], Color_t ci, Char_t transp)
{
TColor* c = gROOT->GetColor(ci);
if(c) c->GetRGB(rgba[0], rgba[1], rgba[2]);
else rgba[0] = rgba[1] = rgba[2] = 0.5;
rgba[3] = 1.0f - transp/100.0f;
}
Bool_t TGLScene::IsOutside(const TGLBoundingBox & box,
const TGLPlaneSet_t & planes)
{
for (TGLPlaneSet_ci p=planes.begin(); p!=planes.end(); ++p)
if (box.Overlap(*p) == Rgl::kOutside)
return kTRUE;
return kFALSE;
}