/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "DLLInterface.h"
#include "Pimpl.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx.LFR
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class COpenGlInterop_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Provides methods for using OpenGL contexts and textures.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API COpenGlInterop : public CPimpl<COpenGlInterop_Impl, Interfaces::EOpenGlInterop::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Default constructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			COpenGlInterop();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move constructor.
			/// </summary>
			///
			/// <param name="xOpenGlInterop"> [in,out] The open gl interop instance. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			COpenGlInterop(COpenGlInterop&& xOpenGlInterop);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Destructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			~COpenGlInterop();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the OpenGL texture ID of the image defined by the given ID.
			///
			/// 	If the desired texture has not been created yet, the returned texture ID is 0.
			///
			/// 	Attention: An OpenGL context must be stored before by calling StoreCurrentContext.
			/// </summary>
			///
			/// <param name="eImgID"> The image ID. </param>
			///
			/// <returns> The texture ID or 0. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			unsigned GetTextureID(EImage::ID eImgID) const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Destroys the OpenGL texture of the image defined by the given ID.
			///
			/// 	Attention: An OpenGL context must be stored before by calling StoreCurrentContext.
			/// </summary>
			///
			/// <param name="eImgID"> The image ID. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void DestroyTexture(EImage::ID eImgID);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Destroys all OpenGL textures.
			///
			/// 	Attention: An OpenGL context must be stored before by calling StoreCurrentContext.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void DestroyTextures();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Query if this object has a valid OpenGL context stored.
			/// </summary>
			///
			/// <returns> True if OpenGL context stored, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool HasStoredContext() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Stores the current OpenGL context. Throws an exception if the calling thread hasn't a current OpenGL context.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void StoreCurrentContext();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates an OpenGL context that is shared with the current OpenGL context. This requires a current OpenGL context.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void CreateContextSharedWithCurrent();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Makes the stored OpenGL rendering context the calling thread's current rendering context.
			/// </summary>
			///
			/// <returns> Returns true if the calling thread hadn't the context BEFORE the call. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool MakeStoredContextCurrent() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Releases the OpenGL context. Changes the calling thread's current rendering context so it's no longer current. This
			/// 	method does not delete the stored OpenGL context.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void ReleaseContext() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Deletes the stored context (if it has been created by CreateContextSharedWithCurrent).
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void DeleteStoredContext();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the OpenGL version.
			/// </summary>
			///
			/// <param name="iMajor"> [out] The major part of the version. </param>
			/// <param name="iMinor"> [out] The minor part of the version. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetVersion(int& iMajor, int& iMinor);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move assignment operator.
			/// </summary>
			///
			/// <param name="xOpenGlInterop"> [in,out] The openGl instance. </param>
			///
			/// <returns> The instance. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			COpenGlInterop& operator=(COpenGlInterop&& xOpenGlInterop);
		};
	}
}
