#include "TGLScene.h"
#include "TGLRnrCtx.h"
#include "TGLSelectRecord.h"
#include "TGLLogicalShape.h"
#include "TGLPhysicalShape.h"
#include "TGLCamera.h"
#include "TGLStopwatch.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),
   fOpaqueCnt   (0),
   fTranspCnt   (0),
   fAsPixelCnt  (0)
{}
TGLScene::TSceneInfo::~TSceneInfo()
{}
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: scene=%d, op=%d, trans=%d",
                  ((TGLScene*)fScene)->fDrawList.size(),
                  fOpaqueElements.size(), 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()", out.Data());
   }
}
ClassImp(TGLScene)
TGLScene::TGLScene() :
   TGLSceneBase(),
   fDrawList(1000),
   fDrawListValid(kFALSE),
   fGLCtxIdentity(0),
   fInSmartRefresh(kFALSE)
{}
TGLScene::~TGLScene()
{
   
   TakeLock(kModifyLock);
   ReleaseGLCtxIdentity();
   DestroyPhysicals(kTRUE); 
   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);
}
void TGLScene::UpdateSceneInfo(TGLRnrCtx& ctx)
{
   
   
   
   
   
   TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(ctx.GetSceneInfo());
   if (sinfo == 0 || sinfo->GetScene() != this) {
      Error("TGLScene::UpdateSceneInfo", "Scene mismatch.");
      return;
   }
   
   
   TGLSceneBase::UpdateSceneInfo(ctx);
   if ( ! sinfo->IsVisible() )
      return;
   if ( ! fDrawListValid )
      SortDrawList();
   if (sinfo->fOpaqueElements.capacity() > 1.4*fDrawList.size())
   {
      DrawElementVec_t foo;
      foo.reserve( (size_t) (1.2*fDrawList.size()));
      sinfo->fOpaqueElements.swap(foo);
   } else {
      sinfo->fOpaqueElements.clear();
   }
   if (sinfo->fTranspElements.capacity() > 1.4*fDrawList.size())
   {
      DrawElementVec_t foo;
      foo.reserve( (size_t) (1.2*fDrawList.size()));
      sinfo->fTranspElements.swap(foo);
   } else {
      sinfo->fTranspElements.clear();
   }
   
   for (ShapeVec_i phys=fDrawList.begin(); phys!=fDrawList.end(); ++phys)
   {
      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) == 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())
         {
            EOverlap ovlp = drawShape->BoundingBox().Overlap(*pi);
            if (ovlp == kOutside)
               break;
            else if (ovlp == 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) == kOutside)
            {
               drawNeeded = kFALSE;
               break;
            }
            ++pi;
         }
      }
      
      if (drawNeeded)
      {
         DrawElement_t de;
         de.fPhysical = drawShape;
         drawShape->CalculateShapeLOD(ctx, de.fPixelSize, de.fPixelLOD);
         if (drawShape->IsTransparent())
            sinfo->fTranspElements.push_back(de);
         else
            sinfo->fOpaqueElements.push_back(de);
      }
   }
   
   
   
}
void TGLScene::LodifySceneInfo(TGLRnrCtx& ctx)
{
   
   
   TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(ctx.GetSceneInfo());
   if (sinfo == 0 || sinfo->GetScene() != this) {
      Error("TGLScene::LodifySceneInfo", "Scene mismatch.");
      return;
   }
   TGLSceneBase::LodifySceneInfo(ctx);
   DrawElementVec_t& ode = sinfo->fOpaqueElements;
   for (DrawElementVec_i i=ode.begin(); i!=ode.end(); ++i)
      i->fPhysical->QuantizeShapeLOD(i->fPixelLOD, ctx.CombiLOD(), i->fFinalLOD);
   DrawElementVec_t& tde = sinfo->fTranspElements;
   for (DrawElementVec_i i=tde.begin(); i!=tde.end(); ++i)
      i->fPhysical->QuantizeShapeLOD(i->fPixelLOD, ctx.CombiLOD(), i->fFinalLOD);
}
void TGLScene::PreRender(TGLRnrCtx & rnrCtx)
{
   
   
   
   
   TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
   if (sinfo == 0 || sinfo->GetScene() != this) {
      Error("TGLScene::Render", "SceneInfo mismatch.");
      return;
   }
   
   TGLSceneBase::PreRender(rnrCtx);
   TGLContextIdentity* cid = rnrCtx.GetGLCtxIdentity();
   if (cid != fGLCtxIdentity)
   {
      ReleaseGLCtxIdentity();
      fGLCtxIdentity = cid;
      fGLCtxIdentity->AddClientRef();
   }
   
   sinfo->ResetDrawStats();
}
void TGLScene::Render(TGLRnrCtx & rnrCtx)
{
   
   TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
   assert(sinfo != 0);
   if ( ! sinfo->IsVisible() )
      return;
   RenderAllPasses(rnrCtx, rnrCtx.RenderTimeout());
}
void TGLScene::PostRender(TGLRnrCtx & rnrCtx)
{
   
   
   
   if (gDebug)
   {
      TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
      assert(sinfo != 0);
      sinfo->DumpDrawStats();
   }
   TGLSceneBase::PostRender(rnrCtx);
}
Double_t TGLScene::RenderAllPasses(TGLRnrCtx & rnrCtx,
                                   Double_t    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) {
            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);
      }
   }
   
   Double_t renderPassTimeout = timeout/reqPasses;
   Double_t totalTime         = 0.0;
   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(1.f, 1.f);
      }
      else if (pass == TGLRnrCtx::kPassOutlineLine)
      {
         
         glDisable(GL_POLYGON_OFFSET_FILL);
         glDisable(GL_LIGHTING);
         
         
         
         
         
         
         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      }
      
      if ( ! sinfo->ShouldClip())
      {
         totalTime += RenderOnePass(rnrCtx, renderPassTimeout);
      }
      else
      {
         
         TGLPlaneSet_t & planeSet = sinfo->ClipPlanes();
         if (gDebug > 3)
         {
            Info("TGLScene::RenderAllPasses()",
                 "%d active clip planes", 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 i=0; i<maxPlanes; i++) {
               glClipPlane(GL_CLIP_PLANE0+i, planeSet[i].CArr());
               glEnable(GL_CLIP_PLANE0+i);
            }
            
            
            totalTime += RenderOnePass(rnrCtx, renderPassTimeout, 0);
         }
         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);
               
               
               totalTime += RenderOnePass(rnrCtx, renderPassTimeout/maxPlanes, &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);
   return totalTime;
}
Double_t TGLScene::RenderOnePass(TGLRnrCtx           & rnrCtx,
                                 Double_t              timeout,
                                 const TGLPlaneSet_t * clipPlanes)
{
   
   
   
   TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
   assert(sinfo != 0);
   
   DrawElementVec_t& ode = sinfo->fOpaqueElements;
   DrawElementVec_t& tde = sinfo->fTranspElements;
   Double_t          oto = 0.0;
   Double_t          tto = 0.0;
   if (timeout > 0.0)
   {
      Double_t fac = timeout / (ode.size() + tde.size());
      oto = fac * ode.size();
      tto = fac * tde.size();
   }
   
   if (ode.size() > 0)
   {
      oto = RenderElements(rnrCtx, ode, oto, clipPlanes);
   }
   
   if (tde.size() > 0)
   {
      glDepthMask(GL_FALSE);
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      tto = RenderElements(rnrCtx, tde, tto, clipPlanes);
      glDepthMask(GL_TRUE);
      glDisable(GL_BLEND);
   }
   if (gDebug > 4)
   {
      Info("TGLScene::RenderOnePass",
           "requested %.2f ms, took %.2f ms (opaque=%f, transp=%f)",
           timeout, oto + tto, oto, tto);
   }
   return oto + tto;
}
Double_t TGLScene::RenderElements(TGLRnrCtx           & rnrCtx,
                                  DrawElementVec_t    & elementVec,
                                  Double_t              timeout,
                                  const TGLPlaneSet_t * clipPlanes)
{
   
   
   
   TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
   assert(sinfo != 0);
   Bool_t timerp  = (timeout > 0.0);
   TGLStopwatch stopwatch;
   stopwatch.Start();
   Int_t drawCount = 0;
   for (DrawElementVec_i i=elementVec.begin(); i!=elementVec.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);
         glPushName(drawShape->ID());
         drawShape->Draw(rnrCtx);
         glPopName();
         ++drawCount;
         sinfo->UpdateDrawStats(*drawShape, rnrCtx.ShapeLOD());
      }
      
      
      if (timerp && (drawCount % 50) == 49 &&
          stopwatch.Lap() > timeout)
      {
         break;
      }
   }
   return stopwatch.End();
}
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.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;
      }
      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)
{
   
   
   if (fLock != kModifyLock) {
      Error("TGLScene::DestroyLogical", "expected ModifyLock");
      return kFALSE;
   }
   LogicalShapeMapIt_t lit = fLogicalShapes.find(logid);
   if (lit == fLogicalShapes.end()) {
      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;
   fBoundingBoxValid = kFALSE;
   fDrawListValid    = kFALSE;
   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));
   fBoundingBoxValid = kFALSE;
   
   fDrawList.push_back(&shape);
   fDrawListValid = kFALSE;
}
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);
   fBoundingBoxValid = kFALSE;
   fDrawListValid    = kFALSE;
   return kTRUE;
}
Int_t TGLScene::DestroyPhysicals(Bool_t incModified, const TGLCamera* camera)
{
   
   
   
   
   
   
   
   if (fLock != kModifyLock) {
      Error("TGLScene::DestroyPhysicals", "expected ModifyLock");
      return 0;
   }
   Int_t count = 0;
   PhysicalShapeMapIt_t pit = fPhysicalShapes.begin();
   while (pit != fPhysicalShapes.end())
   {
      const TGLPhysicalShape * physical = pit->second;
      if (physical) {
         
         if (incModified || (!incModified && !physical->IsModified())) {
            
            
            Bool_t ignoreSize = physical->GetLogical()->IgnoreSizeForOfInterest();
            if (!camera || (camera && !camera->OfInterest(physical->BoundingBox(), ignoreSize)))
            {
               DestroyPhysicalInternal(pit++);
               ++count;
               continue; 
            }
         }
      } else {
         assert(kFALSE);
      }
      ++pit;
   }
   if (count > 0) {
      fBoundingBoxValid = kFALSE;
      fDrawListValid    = kFALSE;
   }
   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;
}
void TGLScene::BeginUpdate()
{
   
   TakeLock(kModifyLock);
}
void TGLScene::EndUpdate()
{
   
   IncTimeStamp();
   ReleaseLock(kModifyLock);
   
   
}
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();
   fDrawListValid = kFALSE;
}
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) {
      Error("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
      return;
   }
   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) {
      Error("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
      return;
   }
   TGLPhysicalShape* phys = log->fFirstPhysical;
   if (trans)
      phys->SetTransform(trans);
   if (cidx >= 0) {
      Float_t rgba[4];
      RGBAFromColorIdx(rgba, cidx, transp);
      phys->SetDiffuseColor(rgba);
   }
}
void TGLScene::BeginSmartRefresh()
{
   
   fSmartRefreshCache.swap(fLogicalShapes);
   
   LogicalShapeMapIt_t i = fSmartRefreshCache.begin();
   while (i != fSmartRefreshCache.end()) {
      if (i->second->KeepDuringSmartRefresh() == kFALSE) {
         LogicalShapeMapIt_t j = i++;
         delete j->second;
         fSmartRefreshCache.erase(j);
      } else {
         ++i;
      }
   }
   fInSmartRefresh = kTRUE;
}
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);
      
      
      
      LogicalShapeMap_t* lsm = const_cast<LogicalShapeMap_t*>(&fLogicalShapes);
      lsm->insert(LogicalShapeMapValueType_t(l_shape->ID(), l_shape));
      
      
      
      l_shape->DLCacheClear();
      return l_shape;
   } else {
      return 0;
   }
}
void TGLScene::SortDrawList()
{
   
   
   
   
   
   assert(!fDrawListValid);
   TGLStopwatch stopwatch;
   if (gDebug>2) {
      stopwatch.Start();
   }
   fDrawList.resize(fPhysicalShapes.size());
   {
      ShapeVec_i           dit = fDrawList.begin();
      PhysicalShapeMapIt_t pit = fPhysicalShapes.begin();
      while (dit != fDrawList.end())
         *(dit++) = (pit++)->second;
   }
   
   
   std::sort(fDrawList.begin(), fDrawList.end(), TGLScene::ComparePhysicalVolumes);
   if (gDebug>2) {
      Info("TGLScene::SortDrawList", "sorting took %f msec", stopwatch.End());
   }
   fDrawListValid = kTRUE;
}
Bool_t TGLScene::ComparePhysicalVolumes(const TGLPhysicalShape* shape1,
                                         const TGLPhysicalShape* shape2)
{
   
   
   
   
   return (shape1->BoundingBox().Volume() > shape2->BoundingBox().Volume());
}
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 ",  fLogicalShapes.size(), 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) == kOutside)
         return kTRUE;
   return kFALSE;
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.