// @(#)root/gl:$Name:  $:$Id: TGLDisplayListCache.cxx,v 1.13 2006/12/09 23:01:54 rdm Exp $
// Author:  Richard Maunder  25/05/2005

/*************************************************************************
 * 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.             *
 *************************************************************************/

#include "TGLDisplayListCache.h"
#include "TGLDrawFlags.h"
#include "TGLUtil.h"
#include "TGLIncludes.h"

#include "Riostream.h"
#include "TError.h"

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGLDisplayListCache                                                  //
//                                                                      //
// Singleton cache of GL display lists. Provides lazy automatic GL      //
// display list capture of draws by a TGLDrawable at a certain 'LOD'    //
// which can be disable on a global, per drawable or LOD basis.         //
//                                                                      //
// Internally the cache creates a block of GL display lists of fSize,   // 
// and maintains a stl::map, mapping CacheID_t ids (created from        //
// TGLDrawable and LOD draw flag) to 'name' entries in the GL display   //
// list block.                                                          //
//                                                                      //
// See TGLDrawable::Draw() for use.                                     //
// NOTE: Purging of individual TGLDrawables not currently implemented:  //
//       Purge(const TGLDrawable & drawable)                            //    
//       Purge(const TGLDrawable & drawable, UInt_t LOD)                // 
//////////////////////////////////////////////////////////////////////////

ClassImp(TGLDisplayListCache)

TGLDisplayListCache * TGLDisplayListCache::fgInstance = 0;
const UInt_t TGLDisplayListCache::fgInvalidDLName = 0;

//______________________________________________________________________________
TGLDisplayListCache & TGLDisplayListCache::Instance()
{
   // Create (if required) and return the singleton display list cache
   if (!fgInstance) {
      fgInstance = new TGLDisplayListCache();
   }

   return *fgInstance;
}

//______________________________________________________________________________
TGLDisplayListCache::TGLDisplayListCache(Bool_t enable, UInt_t size) :
      fSize(size), fInit(kFALSE), fEnabled(enable), fCaptureOpen(kFALSE),
      fDLBase(fgInvalidDLName), fDLNextFree(fgInvalidDLName),
      fCaptureFullReported(kFALSE)
{
   // Construct display list cache.
   // Private constructor - cache is singleton obtained through 
   // TGLDisplayListCache::Instance()
}

//______________________________________________________________________________
TGLDisplayListCache::~TGLDisplayListCache()
{
   // Destroy display list cache - deleting internal GL display list block
   glDeleteLists(fDLBase,fSize);
}

//______________________________________________________________________________
void TGLDisplayListCache::Init()
{
   // Initialise the cache - create the internal GL display list block of size
   // fSize
   fDLBase = glGenLists(fSize);
   fDLNextFree = fDLBase;
   TGLUtil::CheckError("TGLDisplayListCache::Init");
   fInit = kTRUE;
}

//______________________________________________________________________________
Bool_t TGLDisplayListCache::Draw(const TGLDrawable & drawable, const TGLDrawFlags & flags) const
{
   // Draw (call) the GL dislay list entry associated with the drawable / LOD
   // flag pair, and return kTRUE. If no list item associated, return KFALSE.
   if (!fEnabled) {
      return kFALSE;
   }

   // TODO: Cache the lookup here ? As may have many calls of same draw/qual in a row
   UInt_t drawList = Find(MakeCacheID(drawable, flags));

   if (drawList == fgInvalidDLName) {
      if (gDebug>4) {
         Info("TGLDisplayListCache::Draw", "no cache for drawable %d LOD %d", &drawable, flags.LOD());
      }
      return kFALSE;
   }

   if (gDebug>4) {
      Info("TGLDisplayListCache::Draw", "drawable %d LOD %d", &drawable, flags.LOD());
   }
   glCallList(drawList);
   return kTRUE;
}

//______________________________________________________________________________
Bool_t TGLDisplayListCache::OpenCapture(const TGLDrawable & drawable, const TGLDrawFlags & flags)
{
   // Open capture of GL draw commands into cache entry, associated with 
   // drawable / LOD pair. Capture is done in GL_COMPILE mode - so the cache 
   // entry has to be drawn using TGLDisplayListCache::Draw() after capture close.
   //
   // Return kTRUE if opened, kFALSE if not. Capture is not opened if cache not 
   // enabled or cache if full.
   // GL display lists can be nested at 'run' (draw) time, but cannot be nested
   // in capture - so attempting to nest captures is rejected.
   if (!fEnabled) {
      return kFALSE;
   }

   if (fCaptureOpen) {
      Error("TGLDisplayListCache::OpenCapture", "capture already ");
      return(kFALSE);
   }

   // Cache full?
   // TODO: Start to loop or recycle in another fashion?
   if (fDLNextFree > fDLBase + fSize) {
      if (!fCaptureFullReported) {
         Warning("TGLDisplayListCache::OpenCapture", "cache is full");
         fCaptureFullReported = kTRUE;
      }
      return kFALSE;
   }

   fCaptureOpen = kTRUE;

   if (!fInit)
   {
      Init();
   }

   if (gDebug>4) {
      Info("TGLDisplayListCache::OpenCapture", "for drawable %d LOD %d", &drawable, flags.LOD());
   }

   CacheID_t cacheID = MakeCacheID(drawable, flags);
   fCacheDLMap.insert(CacheDLMap_t::value_type(cacheID,fDLNextFree));
   //assert( Find(cacheID) == fDLNextFree );

   glNewList(fDLNextFree,GL_COMPILE);
   TGLUtil::CheckError("TGLDisplayListCache::OpenCapture");

   fDLNextFree++;
   return kTRUE;
}

//______________________________________________________________________________
Bool_t TGLDisplayListCache::CloseCapture()
{
   // Close currently open capture - return kTRUE if one open and successfully
   // closed.
   if (!fEnabled) {
      return kFALSE;
   }

   if (!fCaptureOpen) {
      Error("TGLDisplayListCache::CloseCapture", "no current capture open");
      return kFALSE;
   }

   glEndList();
   TGLUtil::CheckError("TGLDisplayListCache::CloseCapture");
   fCaptureOpen = kFALSE;

   if (gDebug>4) {
      Info("TGLDisplayListCache::CloseCapture","complete");
   }

   return kTRUE;
}

//______________________________________________________________________________
void TGLDisplayListCache::Purge()
{
   // Purge all entries for all drawable/LOD pairs from cache
   glDeleteLists(fDLBase,fSize);
   fCacheDLMap.erase(fCacheDLMap.begin(), fCacheDLMap.end());
   fInit = kFALSE;
   fCaptureFullReported = kFALSE;
}

//______________________________________________________________________________
void TGLDisplayListCache::Purge(const TGLDrawable & /* drawable */) 
{ 
   // Purge all entries for a drawable at any LOD from cache
   // NOTE: NOT IMPLEMENTED AT PRESENT!
   if(fCaptureOpen) {
      Error("TGLDisplayListCache::Purge", "attempt to purge while capture open");
      return;
   }

   // TODO
}

//______________________________________________________________________________
void TGLDisplayListCache::Purge(const TGLDrawable & /* drawable */, const TGLDrawFlags & /* flags */) 
{ 
   // Purge entry for a drawable/LOD from cache
   // NOTE: NOT IMPLEMENTED AT PRESENT!
   if(fCaptureOpen) {
      Error("TGLDisplayListCache::Purge", "attempt to purge while capture open");
      return;
   }

   // TODO
}

//______________________________________________________________________________
UInt_t TGLDisplayListCache::Find(CacheID_t cacheID) const
{
   // Return the GL display list block name associated with 'cacheID' 
   // cacheID is generated from drawable/flags pair - see 
   // TGLDisplayListCache::MakeCacheID()
   CacheDLMap_t::const_iterator cacheDLMapIt;
   cacheDLMapIt = fCacheDLMap.find(cacheID);

   if (cacheDLMapIt != fCacheDLMap.end()) {
      return (*cacheDLMapIt).second;
   }
   return fgInvalidDLName;

}

// TODO: Inline this
//______________________________________________________________________________
TGLDisplayListCache::CacheID_t TGLDisplayListCache::MakeCacheID(const TGLDrawable & drawable,
                                                                const TGLDrawFlags & flags) const
{
   // Create a CacheID_t from drawable/flags pair provided. 

   // NOTE: Display Lists CAN capture GL state changes as well as geometry, but will 
   // not capture the current state set BEFORE the DL is opened.

   // The CacheID_t returned is a std::pair<const TGLDrawable *, const UInt_t>, 
   // and used as key into fCacheDLMap - see TGLDisplayListCache::Find()
   return CacheID_t(&drawable, flags.LOD());
}

//______________________________________________________________________________
void TGLDisplayListCache::Dump() const
{
   // Dump usage count of cache
   Info("TGLDisplayListCache::Dump", "%d of %d used", (fDLNextFree - fDLBase), fSize);
}


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.