Blob Blame Raw
#pragma once

#ifndef TGLDISPLAYLISTSMANAGER_H
#define TGLDISPLAYLISTSMANAGER_H

// TnzCore includes
#include "tgl.h"

// tcg includes
#include "tcg/tcg_observer_notifier.h"

// Qt includes
#include <QMutex>

#undef DVAPI
#undef DVVAR

#ifdef TGL_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

//**************************************************************************************************
//    TGLDisplayListsProxy  declaration
//**************************************************************************************************

//! TGLDisplayListsProxy is a wrapper to a dummy OpenGL context attached to a specific display lists space.
/*!
  TGLDisplayListsProxy implements the basic functionalities necessary to address a display lists
  space without having to access any actual associated OpenGL context. This is equivalent to
  making a hidden OpenGL context (the display lists proxy) the \a current one.

\note Implementations of the TGLDisplayListsProxy must take ownership of the proxy.
*/

class TGLDisplayListsProxy
{
	QMutex m_mutex;

public:
	virtual ~TGLDisplayListsProxy() {}

	virtual void makeCurrent() = 0;
	virtual void doneCurrent() = 0;

	QMutex *mutex() { return &m_mutex; }
};

//**************************************************************************************************
//    TGLDisplayListsProxy  template specializations
//**************************************************************************************************

template <typename Context>
class TGLDisplayListsProxyT : public TGLDisplayListsProxy
{
	Context *m_proxy;

public:
	TGLDisplayListsProxyT(Context *proxy) : m_proxy(proxy) {}
	~TGLDisplayListsProxyT() { delete m_proxy; }

	void makeCurrent() { m_proxy->makeCurrent(); }
	void doneCurrent() { m_proxy->doneCurrent(); }
};

//**************************************************************************************************
//    TGLDisplayListsManager  declaration
//**************************************************************************************************

//! TGLDisplayListsManager is a singleton class used to track OpenGL shared display lists spaces.
/*!
  OpenGL contexts can share their display lists space (in particular, this includes texture
  objects) with other contexts. Typically, sharing specification happens when a new context
  is created - at that point, the new context is allowed to share the lists space of another
  known context, pretty much the same way a shared smart pointer does.
\n\n
  However, OpenGL provides access to the display lists space \a only through their attached
  OpenGL contexts; meaning that an external object has to know at least one associated context
  to operate on a display lists space.
\n\n
  We'll call such an associated context  a \a proxy of the display lists space. It is a dummy
  OpenGL context that shares the display lists spaces with those that are attached to it.
\n\n
  Observe that the use of one such dummy context, rather than one of the originally
  attached ones, is strictly necessary in a multithreaded environment, since <I> an OpenGL
  context can be active in exactly one thread at a given time <\I> - and any of the attached
  contexts could always be current in another thread.
\n\n
  However, the use of a single proxy per display lists space means that multiple threads
  could try to access it at the same time. Synchronization in this case must be handled by
  the user by accessing the proxy's built-in mutex.

  \warning TGLDisplayListsManager relies on the user to attach a context to the \b correct
           display lists id.
*/

class DVAPI TGLDisplayListsManager : public tcg::notifier<>
{
public:
	struct Observer : public tcg::observer<TGLDisplayListsManager> {
		virtual void onDisplayListDestroyed(int dlSpaceId) = 0;
	};

public:
	static TGLDisplayListsManager *instance();

	int storeProxy(TGLDisplayListsProxy *proxy);		   //!< Stores the specified proxy, returning its associated display
														   //!< lists id. Context attaches should follow.
	void attachContext(int dlSpaceId, TGlContext context); //!< Attaches the specified context to a display lists space
	void releaseContext(TGlContext context);			   //!< Releases a context reference to its display lists space
	int displayListsSpaceId(TGlContext context);		   //!< Returns the display lists space id of a known context, or
														   //!< -1 if it did not attach to any known space.
	TGLDisplayListsProxy *dlProxy(int dlSpaceId);		   //!< Returns the display lists space proxy associated to the
														   //!< specified id.
};

#endif // TGLDISPLAYLISTSMANAGER_H