// @(#)root/gl:$Name:  $:$Id: TGLScene.cxx,v 1.12 2005/06/23 15:08:45 brun Exp $
// Author:  Richard Maunder  25/05/2005
// Parts taken from original TGLRender by Timur Pocheptsov

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

// TODO: Function descriptions
// TODO: Class def - same as header

#include "TGLScene.h"
#include "TGLCamera.h"
#include "TGLLogicalShape.h"
#include "TGLPhysicalShape.h"
#include "TGLStopwatch.h"
#include "TGLDisplayListCache.h"
#include "TGLIncludes.h"
#include "TError.h"
#include "TString.h"
#include "Riostream.h"

#include <algorithm>

ClassImp(TGLScene)

//______________________________________________________________________________
 TGLScene::TGLScene() :
   fLock(kUnlocked), fDrawList(1000), 
   fDrawListValid(kFALSE), fBoundingBox(), fBoundingBoxValid(kFALSE), 
   fLastDrawLOD(kHigh), fDrawMode(kFill), fSelectedPhysical(0)
{
}

//______________________________________________________________________________
 TGLScene::~TGLScene()
{
   TakeLock(kModifyLock);
   DestroyPhysicals(kTRUE); // including modified
   DestroyLogicals();
   ReleaseLock(kModifyLock);

   // Purge out the DL cache - when per drawable done no longer required
   TGLDisplayListCache::Instance().Purge();
}

//TODO: Inline
//______________________________________________________________________________
 void TGLScene::AdoptLogical(TGLLogicalShape & shape)
{
   if (fLock != kModifyLock) {
      Error("TGLScene::AdoptLogical", "expected ModifyLock");
      return;
   }

   // TODO: Very inefficient check - disable
   assert(fLogicalShapes.find(shape.ID()) == fLogicalShapes.end());
   fLogicalShapes.insert(LogicalShapeMapValueType_t(shape.ID(), &shape));
}

//______________________________________________________________________________
 Bool_t TGLScene::DestroyLogical(ULong_t ID)
{
   if (fLock != kModifyLock) {
      Error("TGLScene::DestroyLogical", "expected ModifyLock");
      return kFALSE;
   }

   LogicalShapeMapIt_t logicalIt = fLogicalShapes.find(ID);
   if (logicalIt != fLogicalShapes.end()) {
      const TGLLogicalShape * logical = logicalIt->second;
      if (logical->Ref() == 0) {
         fLogicalShapes.erase(logicalIt);
         delete logical;
         return kTRUE;
      } else {
         assert(kFALSE);
      }
   }

   return kFALSE;
}

//______________________________________________________________________________
 UInt_t TGLScene::DestroyLogicals()
{
   UInt_t count = 0;
   if (fLock != kModifyLock) {
      Error("TGLScene::DestroyAllLogicals", "expected ModifyLock");
      return count;
   }

   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;
}

//TODO: Inline
//______________________________________________________________________________
 TGLLogicalShape * TGLScene::FindLogical(ULong_t ID) const
{
   LogicalShapeMapCIt_t it = fLogicalShapes.find(ID);
   if (it != fLogicalShapes.end()) {
      return it->second;
   } else {
      return 0;
   }
}

//TODO: Inline
//______________________________________________________________________________
 void TGLScene::AdoptPhysical(TGLPhysicalShape & shape)
{
   if (fLock != kModifyLock) {
      Error("TGLScene::AdoptPhysical", "expected ModifyLock");
      return;
   }
   // TODO: Very inefficient check - disable
   assert(fPhysicalShapes.find(shape.ID()) == fPhysicalShapes.end());

   fPhysicalShapes.insert(PhysicalShapeMapValueType_t(shape.ID(), &shape));
   fBoundingBoxValid = kFALSE;

   // Add into draw list and mark for sorting
   fDrawList.push_back(&shape);
   fDrawListValid = kFALSE;
}

//______________________________________________________________________________
 Bool_t TGLScene::DestroyPhysical(ULong_t ID)
{
   if (fLock != kModifyLock) {
      Error("TGLScene::DestroyPhysical", "expected ModifyLock");
      return kFALSE;
   }
   PhysicalShapeMapIt_t physicalIt = fPhysicalShapes.find(ID);
   if (physicalIt != fPhysicalShapes.end()) {
      TGLPhysicalShape * physical = physicalIt->second;
      if (fSelectedPhysical == physical) {
         fSelectedPhysical = 0;
      }
      fPhysicalShapes.erase(physicalIt);
      fBoundingBoxValid = kFALSE;
  
      // Zero the draw list entry - will be erased as part of sorting
      DrawListIt_t drawIt = find(fDrawList.begin(), fDrawList.end(), physical);
      if (drawIt != fDrawList.end()) {
         *drawIt = 0;
         fDrawListValid = kFALSE;
      } else {
         assert(kFALSE);
      }
      delete physical;
      return kTRUE;
   }

   return kFALSE;
}

//______________________________________________________________________________
 UInt_t TGLScene::DestroyPhysicals(Bool_t incModified, const TGLCamera * camera)
{
   if (fLock != kModifyLock) {
      Error("TGLScene::DestroyPhysicals", "expected ModifyLock");
      return kFALSE;
   }
   UInt_t count = 0;
   PhysicalShapeMapIt_t physicalShapeIt = fPhysicalShapes.begin();
   const TGLPhysicalShape * physical;
   while (physicalShapeIt != fPhysicalShapes.end()) {
      physical = physicalShapeIt->second;
      if (physical) {
         // Destroy any physical shape no longer of interest to camera
         // If modified options allow this physical to be destoyed
         if (incModified || (!incModified && !physical->IsModified())) {
            // and no camera is passed, or it is no longer of interest
            // to camera
            if (!camera || (camera && !camera->OfInterest(physical->BoundingBox()))) {

               // Then we can destroy it - remove from map
               fPhysicalShapes.erase(physicalShapeIt++);

               // Zero the draw list entry - will be erased as part of sorting
               DrawListIt_t drawIt = find(fDrawList.begin(), fDrawList.end(), physical);
               if (drawIt != fDrawList.end()) {
                  *drawIt = 0;
               } else {
                  assert(kFALSE);
               }

               // Ensure if selected object this is cleared
               if (fSelectedPhysical == physical) {
                  fSelectedPhysical = 0;
               }
               // Finally destroy actual object
               delete physical;
               ++count;
               continue; // Incremented the iterator during erase()
            }
         }
      } else {
         assert(kFALSE);
      }
      ++physicalShapeIt;
   }

   if (count > 0) {
      fBoundingBoxValid = kFALSE;
      fDrawListValid = kFALSE;
   }

   return count;
}

//TODO: Inline
//______________________________________________________________________________
 TGLPhysicalShape * TGLScene::FindPhysical(ULong_t ID) const
{
   PhysicalShapeMapCIt_t it = fPhysicalShapes.find(ID);
   if (it != fPhysicalShapes.end()) {
      return it->second;
   } else {
      return 0;
   }
}

//______________________________________________________________________________
 void TGLScene::SetPhysicalsColorByLogical(ULong_t logicalID, const Float_t rgba[4])
{
   if (fLock != kModifyLock) {
      Error("TGLScene::SetPhysicalsColorByLogical", "expected ModifyLock");
      return;
   }
   PhysicalShapeMapIt_t physicalShapeIt = fPhysicalShapes.begin();
   TGLPhysicalShape * physical;
   while (physicalShapeIt != fPhysicalShapes.end()) {
      physical = physicalShapeIt->second;
      if (physical) {
         if (physical->GetLogical().ID() == logicalID) {
            physical->SetColor(rgba);
         }
      } else {
         assert(kFALSE);
      }
      ++physicalShapeIt;
   }
}

//______________________________________________________________________________
//TODO: Merge axes flag and LOD into general draw flag
 UInt_t TGLScene::Draw(const TGLCamera & camera, UInt_t sceneLOD, Double_t timeout)
{
   UInt_t drawn = 0;
   if (fLock != kDrawLock && fLock != kSelectLock) {
      Error("TGLScene::Draw", "expected Draw or Select Lock");
   }

   void (TGLPhysicalShape::*drawPtr)(UInt_t)const = &TGLPhysicalShape::Draw;

   if (fDrawMode)
      fDrawMode == kWireFrame ? drawPtr = &TGLPhysicalShape::DrawWireFrame :
                                drawPtr = &TGLPhysicalShape::DrawOutline;

   TGLStopwatch stopwatch;
   stopwatch.Start();

   // If the scene bounding box is inside the camera frustum then
   // no need to check individual shapes - everything is visible
   Bool_t doFrustumCheck = (camera.FrustumOverlap(BoundingBox()) != kInside);

   if (!fDrawListValid) {
      SortDrawList();
   }

   // TODO: Tidy up draw loop to make this less complicated

   // Step 1: Loop through the main sorted draw list 
   Bool_t                   run = kTRUE;
   const TGLPhysicalShape * drawShape;

   // Transparent list built on fly
   static DrawList_t transDrawList;
   transDrawList.reserve(fDrawList.size() / 10); // assume less 10% of total
   transDrawList.clear();

   // Opaque only objects drawn in first loop
   // TODO: Sort front -> back for better performance
   glDepthMask(GL_TRUE);
   glDisable(GL_BLEND);

   DrawListIt_t drawIt;
   for (drawIt = fDrawList.begin(); drawIt != fDrawList.end() && run;
        drawIt++) {
      drawShape = *drawIt;
      if (!drawShape)
      {
         assert(kFALSE);
         continue;
      }

      // TODO: Do small skipping first? Probably cheaper than frustum check
      // Profile relative costs? The frustum check could be done implictly 
      // from the LOD as we project all 8 verticies of the BB onto viewport
      EOverlap frustumOverlap = kInside;
      if (doFrustumCheck)
      {
         frustumOverlap = camera.FrustumOverlap(drawShape->BoundingBox());
      }

      if (frustumOverlap == kInside || frustumOverlap == kPartial)
      {
         // Collect transparent shapes for drawing at end
         if (drawShape->IsTransparent()) {
            transDrawList.push_back(drawShape);
            continue;
         }

         // Get the shape draw quality
         UInt_t shapeLOD = CalcPhysicalLOD(*drawShape, camera, sceneLOD);

         //Draw, DrawWireFrame, DrawOutline
         (drawShape->*drawPtr)(shapeLOD);
         ++drawn;
      }

      // Terminate the draw is over timeout
      if (timeout > 0.0 && stopwatch.Lap() > timeout) {
         run = kFALSE;
      }
   }

   // Step 2: Deal with selected physical
   if (fSelectedPhysical) {
      // Draw now if non-transparent (may already have been done)
      if (!fSelectedPhysical->IsTransparent()) {
         UInt_t shapeLOD = CalcPhysicalLOD(*fSelectedPhysical, camera, sceneLOD);
         (fSelectedPhysical->*drawPtr)(shapeLOD);
         ++drawn;
      } else {
         // Ensure transparent selected physical will get drawn
         transDrawList.push_back(fSelectedPhysical);
      }
   }

   // Step 3: Draw the filtered transparent objects with GL depth writing off
   // blending on
   // TODO: Sort to draw back to front with depth test off for better blending
   glDepthMask(GL_FALSE);
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

   // We assume there are <<< of these than opaque so time will be negligible
   // TODO: Record transparent % and reserve time for these 
   for (drawIt = transDrawList.begin(); drawIt != transDrawList.end(); drawIt++) {
      drawShape = *drawIt;

      UInt_t shapeLOD = CalcPhysicalLOD(*drawShape, camera, sceneLOD);

      //Draw, DrawWireFrame, DrawOutline
      (drawShape->*drawPtr)(shapeLOD);
      ++drawn;
   }

   // Reset these after transparent done
   glDepthMask(GL_TRUE);
   glDisable(GL_BLEND);

   // Finally: Draw selected object bounding box
   if (fSelectedPhysical) {

      //BBOX is white for wireframe mode and fill,
      //red for outlines
      switch (fDrawMode) {
      case kFill:
      case kWireFrame :
         glColor3d(1., 1., 1.);

         break;
      case kOutline:
         glColor3d(1., 0., 0.);
         
         break;
      }

      if (fDrawMode == kFill || fDrawMode == kOutline) {
         glDisable(GL_LIGHTING);
      }
      glDisable(GL_DEPTH_TEST);

      fSelectedPhysical->BoundingBox().Draw();

      if (fDrawMode == kFill || fDrawMode == kOutline) {
         glEnable(GL_LIGHTING);
      }
      glEnable(GL_DEPTH_TEST);
   }

   // Record this so that any Select() draw can be redone at same quality and ensure
   // accuracy of picking
   fLastDrawLOD = sceneLOD;

   // TODO: Should record if full scene can be drawn at 100% in a target time (set on scene)
   // Then timeout should not be passed - just bool if termination is permitted - which may
   // be ignored if all can be done. Pass back bool to indicate if whole scene could be drawn
   // at desired quality. Need a fixed target time so valid across multiple draws

   return drawn;
}

//______________________________________________________________________________
 void TGLScene::SortDrawList()
{
   assert(!fDrawListValid);

   TGLStopwatch stopwatch;

   if (gDebug>2) {
      stopwatch.Start();
   }

   fDrawList.reserve(fPhysicalShapes.size());

   // Delete all zero (to-be-deleted) objects
   fDrawList.erase(remove(fDrawList.begin(), fDrawList.end(), static_cast<const TGLPhysicalShape *>(0)), fDrawList.end());
   
   assert(fDrawList.size() == fPhysicalShapes.size());

   //TODO: partition the selected to front

   // Sort by volume of shape bounding box
   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());
}

//______________________________________________________________________________
 void TGLScene::DrawAxes() const
{
   if (fLock != kDrawLock && fLock != kSelectLock) {
      Error("TGLScene::Draw", "expected Draw or Select Lock");
   }
   // Draw out the scene axes
   // Taken directly from TGLRender by Timur Pocheptsov
   static const UChar_t xyz[][8] = {{0x44, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0x44},
                                     {0x10, 0x10, 0x10, 0x10, 0x10, 0x28, 0x44, 0x44},
                                     {0x7c, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x7c}};

   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   glPushAttrib(GL_DEPTH_BUFFER_BIT);
   glDisable(GL_DEPTH_TEST);
   glDisable(GL_LIGHTING);

   const Double_t axeColors[][3] = {{1., 0., 0.}, // X axis red
                                    {0., 1., 0.}, // Y axis green
                                    {0., 0., 1.}};// Z axis blue
   //glColor3dv(axeColors[3]);

   const TGLBoundingBox & box = BoundingBox();
   Double_t xmin = box.XMin(), xmax = box.XMax();
   Double_t ymin = box.YMin(), ymax = box.YMax();
   Double_t zmin = box.ZMin(), zmax = box.ZMax();

   glBegin(GL_LINES);
   glColor3dv(axeColors[0]);
   glVertex3d(xmin, ymin, zmin);
   glVertex3d(xmax, ymin, zmin);
   glColor3dv(axeColors[1]);
   glVertex3d(xmin, ymin, zmin);
   glVertex3d(xmin, ymax, zmin);
   glColor3dv(axeColors[2]);
   glVertex3d(xmin, ymin, zmin);
   glVertex3d(xmin, ymin, zmax);
   glEnd();

   // X label
   glColor3dv(axeColors[0]);
   glRasterPos3d(xmax, ymin + 12, zmin);
   glBitmap(8, 8, 0., 0., 0., 0., xyz[0]);
   DrawNumber(xmax, xmax, ymin, zmin, 9.);
   DrawNumber(xmin, xmin, ymin, zmin, 0.);

   // Y label
   glColor3dv(axeColors[1]);
   glRasterPos3d(xmin, ymax + 12, zmin);
   glBitmap(8, 8, 0, 0, 12., 0, xyz[1]);
   DrawNumber(ymax, xmin, ymax, zmin, 9.);
   DrawNumber(ymin, xmin, ymin, zmin, 9.);

   // Z label
   glColor3dv(axeColors[2]);
   glRasterPos3d(xmin, ymin, zmax);
   glBitmap(8, 8, 0, 0, 0., 0, xyz[2]);
   DrawNumber(zmax, xmin, ymin, zmax, 9.);
   DrawNumber(zmin, xmin, ymin, zmin, -9.);

   glEnable(GL_LIGHTING);
   glEnable(GL_DEPTH_TEST);
   glPopAttrib();
}

//______________________________________________________________________________
 void TGLScene::DrawNumber(Double_t num, Double_t x, Double_t y, Double_t z, Double_t yorig) const
{
   if (fLock != kDrawLock && fLock != kSelectLock) {
      Error("TGLScene::Draw", "expected Draw or Select Lock");
   }
   static const UChar_t
      digits[][8] = {{0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38},//0
                     {0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x10, 0x10},//1
                     {0x7c, 0x44, 0x20, 0x18, 0x04, 0x04, 0x44, 0x38},//2
                     {0x38, 0x44, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38},//3
                     {0x04, 0x04, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x44},//4
                     {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x40, 0x40, 0x7c},//5
                     {0x7c, 0x44, 0x44, 0x44, 0x7c, 0x40, 0x40, 0x7c},//6
                     {0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x44, 0x7c},//7
                     {0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38},//8
                     {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x7c},//9
                     {0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//.
                     {0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00}};//-

   TString str;
   str+=Long_t(num);

   glRasterPos3i(Int_t(x), Int_t(y), Int_t(z));
   for (Ssiz_t i = 0, e = str.Length(); i < e; ++i) {
      if (str[i] == '.') {
         glBitmap(8, 8, 0., yorig, 7., 0., digits[10]);
         if (i + 1 < e)
            glBitmap(8, 8, 0., yorig, 7., 0., digits[str[i + 1] - '0']);
         break;
      } else if (str[i] == '-') {
         glBitmap(8, 8, 0., yorig, 7., 0., digits[11]);
      } else {
         glBitmap(8, 8, 0., yorig, 7., 0., digits[str[i] - '0']);
      }
   }
}

//______________________________________________________________________________
 UInt_t TGLScene::CalcPhysicalLOD(const TGLPhysicalShape & shape, const TGLCamera & camera,
                                 UInt_t sceneLOD) const
{
   // Find diagonal pixel size of projected drawable BB, using camera
   Double_t diagonal = static_cast<Double_t>(camera.ViewportSize(shape.BoundingBox()).Diagonal());

   // TODO: Get real screen size - assuming 2000 pixel screen at present
   // Calculate a non-linear sizing hint for this shape. Needs more experimenting with...
   UInt_t sizeLOD = static_cast<UInt_t>(pow(diagonal,0.4) * 100.0 / pow(2000.0,0.4));

   // Factor in scene quality
   UInt_t shapeLOD = (sceneLOD * sizeLOD) / 100;

   if (shapeLOD > 10) {
      Double_t quant = ((static_cast<Double_t>(shapeLOD)) + 0.3) / 10;
      shapeLOD = static_cast<UInt_t>(quant)*10;
   } else {
      Double_t quant = ((static_cast<Double_t>(shapeLOD)) + 0.3) / 3;
      shapeLOD = static_cast<UInt_t>(quant)*3;
   }

   if (shapeLOD > 100) {
      shapeLOD = 100;
   }

   return shapeLOD;
}

//______________________________________________________________________________
 Bool_t TGLScene::Select(const TGLCamera & camera)
{
   Bool_t redrawReq = kFALSE;
   if (fLock != kSelectLock) {
      Error("TGLScene::Draw", "expected SelectLock");
   }

   // Create the select buffer. This will work as we have a flat set of physical shapes.
   // We only ever load a single name in TGLPhysicalShape::DirectDraw so any hit record always
   // has same 4 GLuint format
   static std::vector<GLuint> selectBuffer(fPhysicalShapes.size()*4);
   glSelectBuffer(selectBuffer.size(), &selectBuffer[0]);

   // Enter picking mode
   glRenderMode(GL_SELECT);
   glInitNames();
   glPushName(0);

   // Draw out scene at last visible quality
   Draw(camera, kHigh, kFALSE); // No axes

   // Retrieve the hit count and return to render
   GLint hits = glRenderMode(GL_RENDER);

   if (hits < 0) {
      Error("TGLScene::Select", "selection buffer overflow");
   } else if (hits > 0) {
      // Every hit record has format (GLuint per item) - see above for selectBuffer
      // for reason. Format is:
      //
      // no of names in name block (1 always)
      // minDepth
      // maxDepth
      // name(s) (1 always)
      assert(selectBuffer[0] == 1);
      UInt_t minDepth = selectBuffer[1];
      UInt_t minDepthName = selectBuffer[3];

      // Find the nearest picked object
      // TODO: Put back transparency picking stuff
      for (Int_t i = 1; i < hits; ++i) {
         assert(selectBuffer[i*4] == 1); // Single name per record
         if (selectBuffer[i*4 + 1] < minDepth) {
            minDepth = selectBuffer[i*4 + 1];
            minDepthName = selectBuffer[i*4 + 3];
         }
      }

      TGLPhysicalShape * selected = FindPhysical(minDepthName);
      if (!selected) {
         assert(kFALSE);
      }

      // Swap any selection
      if (selected != fSelectedPhysical) {
         if (fSelectedPhysical) {
            fSelectedPhysical->Select(kFALSE);
         }
         fSelectedPhysical = selected;
         fSelectedPhysical->Select(kTRUE);
         redrawReq = kTRUE;
      }
   } else { // 0 hits
      if (fSelectedPhysical) {
         fSelectedPhysical->Select(kFALSE);
         fSelectedPhysical = 0;
         redrawReq = kTRUE;
      }
   }

   return redrawReq;
}

//______________________________________________________________________________
 void TGLScene::SelectedModified() 
{
   // External modification - no locking

   // The selected object was modified external - our bounding box
   // is potentially invalid
   if (fSelectedPhysical && !BoundingBox().AlignedContains(fSelectedPhysical->BoundingBox())) {
      fBoundingBoxValid = kFALSE;
   }
}

//______________________________________________________________________________
 const TGLBoundingBox & TGLScene::BoundingBox() const
{
   if (!fBoundingBoxValid) {
      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;
   }
   return fBoundingBox;
}

//______________________________________________________________________________
 void TGLScene::Dump() const
{
   std::cout << "Scene: " << fLogicalShapes.size() << " Logicals / " << fPhysicalShapes.size() << " Physicals " << std::endl;
}

//______________________________________________________________________________
 UInt_t TGLScene::SizeOf() const
{
   UInt_t size = sizeof(this);

   std::cout << "Size: Scene Only " << size << std::endl;

   LogicalShapeMapCIt_t logicalShapeIt = fLogicalShapes.begin();
   const TGLLogicalShape * logicalShape;
   while (logicalShapeIt != fLogicalShapes.end()) {
      logicalShape = logicalShapeIt->second;
      size += sizeof(*logicalShape);
      ++logicalShapeIt;
   }

   std::cout << "Size: Scene + Logical Shapes " << size << std::endl;

   PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
   const TGLPhysicalShape * physicalShape;
   while (physicalShapeIt != fPhysicalShapes.end()) {
      physicalShape = physicalShapeIt->second;
      size += sizeof(*physicalShape);
      ++physicalShapeIt;
   }

   std::cout << "Size: Scene + Logical Shapes + Physical Shapes " << size << std::endl;

   return size;
}


ROOT page - Class index - Class Hierarchy - Top of the page

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.