///////////////////////////////////////////////////////////////////////////////
/// @file DOpenGL.hpp
///
/// @brief Class for OpenGL driver
///
/// @author JesusFreak
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Feb 2002
/// @author JesusFreak
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DOPENGL_HPP
#define DOPENGL_HPP

#define DEDRIVER_DLL_EXPORTS
#define USING_DESTINY3D

// Include the driver headers we need
#include <windows.h>
#include "deDriver_priv.hpp"
#include "deShader_priv.hpp"
#include <gl\gl.h>
#include "glext.h"
#include "glh_genext.h"
#include "deHash.hpp"

// OpenGL Extensions we use
extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElementsEXT;

// The OpenGL class
class deOpenGL : public deDriver
{
		// Constructor/Destructor
public:
		deOpenGL(long ID);
		~deOpenGL();

		long Release();

		// Public member functions
public:
		deBoolean Init(HWND WindowHandle);

		//adapter and mode counts for adapters
		const deDriverCaps* GetCaps(long Adapter) const;
		long GetAdapterCount() const;
		long GetModeCount(long Adapter) const;
		deBoolean WindowedAllowed(long Adapter) const;

		//display settings
		deBoolean SetDisplay(deDisplay *Display);
		deBoolean Reset(deDisplay *Display);
		deBoolean GetCurrentDisplay(long Adapter, deDisplay * Display) const;
		deBoolean GetDisplayMode(long Adapter, long Mode, deDisplay *Display) const;
		deBoolean ValidFormat(long Adapter, Resource ResourceType, BPP BPPType, ZPP ZPPType, BPP FrontBuffer, long ExtraFlag=0) const;

		//vertex buffer functions
		deBoolean AddVertexBuffer(IdeVertexBuffer *Vertex);
		deBoolean RemoveVertexBuffer(IdeVertexBuffer *Vertex);
		deBoolean UpdateVertexBuffer(IdeVertexBuffer *Vertex);

		// Shader functions
		deBoolean AddShader(IdeShader * Shader);
		deBoolean RemoveShader(IdeShader * Shader);
		deBoolean SetShader(IdeShader * Shader);
/*
		deBoolean DisassembleShader(IdeShader * Shader,deString * Code);
		deBoolean DisassembleShaderArgument(DWORD Argument,deString * Code);
		void DisassembleShaderIndexAndOffset(DWORD IndexBase,DWORD Argument,deString * Code);
		deBoolean DisassembleShaderInstruction(IdeShader::deShaderInstruction * Instruction,deString * Code);
*/

		//frame functions
		deBoolean BeginFrame();
		deBoolean EndFrame();
		deBoolean ClearFrame(deARGB Color, deBoolean ClearTarget, deBoolean ClearZBuffer, deBoolean ClearStencil);
		deBoolean Render(IdeVertexBuffer *VBuffer, long IndexOffset, IdeVertexBuffer *IndexOverride = NULL);

		//viewport/FOV functions
		deBoolean SetViewport(long X, long Y, long Width, long Height, deFloat MinZ, deFloat MaxZ);
		deBoolean SetDepthRange(deFloat MinZ, deFloat MaxZ);
		deBoolean SetFOVClipping(deFloat FOV, deFloat Aspect, deFloat ClipNear, deFloat ClipFar);
		deBoolean SetOrthoClipping(deFloat Width, deFloat Height, deFloat ClipNear, deFloat ClipFar, deBoolean Invert = deFALSE);
		deBoolean SetFOVClippingSubRect(deFloat FOVY, deFloat Aspect, deFloat ClipNear, deFloat ClipFar, deRect SubRect);
		deBoolean SetFOVClippingSubRectFloat(deFloat FOVY, deFloat Aspect, deFloat ClipNear, deFloat ClipFar, deFloatRect SubRect);
		deBoolean SetOrthoClippingSubRect(deFloat Width, deFloat Height, deFloat ClipNear, deFloat ClipFar, deBoolean Invert, deRect SubRect);
		deBoolean SetOrthoClippingSubRectFloat(deFloat Width, deFloat Height, deFloat ClipNear, deFloat ClipFar, deBoolean Invert, deFloatRect SubRect);

		//camera translation functions
		deBoolean SetCameraTransform(deTransformInfo *M);
		deBoolean SetCameraTransform(deVertex *Eye, deVertex *At, deVertex *Up);
		deBoolean SetCameraTranslation(deVertex *Translation);
		deBoolean SetCameraRotation(deVertex *Rotation);
		deBoolean ResetCameraIdentity();

		//world translation functions
		deBoolean SetWorldTransform(deTransformInfo * M);
		deBoolean SetWorldTransform(deVertex *Eye, deVertex *At, deVertex *Up);
		deBoolean SetWorldTranslation(deVertex *Translation);
		deBoolean SetWorldRotation(deVertex *Rotation);
		deBoolean ResetWorldIdentity();

		deBoolean SetTextureTransform(long StageNum, deTransformInfo * Mat);

		//texture functions
		deBoolean AddBitmap(IdeBitmap *Bitmap);
		deBoolean AddBitmapProxy(IdeBitmapProxy *BitmapProxy);
		deBoolean RemoveBitmap(IdeBitmap *Bitmap);

		//render-to-texture functions
		deBoolean RenderTo(IdeBitmap *pBitmap, long CubeMapFace = 0);
		deBoolean ScreenShot(IdeBitmap * &pBitmap, deBoolean GrabWindow = deTRUE);
		deBoolean GetVideoTexture(IdeBitmap* pBitmap, long CubeMapFace = 0);
		
		//render states
		unsigned long GetRenderState(RenderState State);
		deBoolean SetRenderState(const IdeRenderState *State);
		deBoolean SetRenderState(RenderState State, unsigned long Value);
		deBoolean EnableLight(long LightID, deBoolean Enable);
		deBoolean DisableAllLights();
		
		//driver info
		deDriverInfo *deOpenGL::GetInfo() const;
		IdeDriver::Types GetType() const;

		void InvalidateRenderStates(deBoolean Valid);
		// Private member variables
private:
		HGLRC					RC; // Rendering Context
		HDC						DC;

		typedef struct VertexBufferEntry
		{
			long						ID;				//ID to verify the structure
			//long						UniqueID;		//For the display list
			unsigned long				VertexBuffer;	//the vertex Buffer ID
			long						EntrySize[IdeVertexBuffer::BUFFER_COUNT-1];		//size of each entry
			void						*Buffers[IdeVertexBuffer::BUFFER_COUNT-1];		//the actual buffers to render
			void						*IndexBuffer; 
			GLenum						IndexType;
			GLenum						RenderType;		//type of rendering to do
			long						PointCount;		//number of points
			long						TriCount;		//number of tris
			long						IndexCount;		//number of index entries
			long						PointStart;
			long						IndexStart;
			deBoolean					Dynamic;
			deBoolean					SubBuffer; // Remove if we don't need it
		} VertexBufferEntry;

		typedef struct TextureEntry
		{
			long				ID;			//ID to verify the struct
			GLuint				Texture;
		} TextureEntry;
			
		// Private member functions
private:
		void Present();
		void Shutdown();

		deBoolean EnumerateDisplayModes(); // To seperate platform specific code

		deBoolean SetTextureState(IdeRenderTexture *State);
		deBoolean SetLightState(IdeRenderLight *State);
		deBoolean SetMaterialState(IdeRenderMaterial *State);
		
		deBoolean FillBufferInfo(VertexBufferEntry *BufferEntry, IdeVertexBuffer *Vertex, IdeVertexBuffer::BufferType BufferType, deBoolean WipeBuffer);
		deBoolean ProcessVertexBuffer(IdeVertexBuffer *Vertex, VertexBufferEntry *VertexBufferInfo, long BufferFlags);
		void SetVertexBuffer(VertexBufferEntry * VertexBufferInfo);

		// To get information about BPP Type's and to convert them between Destiny,OpenGL and Window's types
		deBoolean ToGLBPP(IdeDriver::BPP BPPType,GLint * InternalFormat,GLenum * Format,GLenum * Type) const;
		unsigned char GetBPP(IdeDriver::BPP BPPType);
		IdeDriver::BPP GetDestinyBPP(long BPP) const;

		GLenum GetOGLTextureWrappingMode(IdeRenderTexture::TextureAddress Address);

		// Private member variables
private:
		deTHashInt <IdeVertexBuffer*>		m_VBufferList;
		deTHashInt <IdeBitmap*>				m_TexturesList;
		deDisplay							**m_Modes;
		deBoolean							RenderStatesValid;
		GLenum								AlphaFunction;
		GLclampf							AlphaRef;
		GLenum								SrcBlendFactor;
		GLenum								DestBlendFactor;
		GLenum								MirroredTextureWrapFlag;
		deBoolean							NVVertexProgramExt;
		int									m_AdapterCount;
		deBoolean							*m_WindowPossible;
		int									*m_ModeCount;
		deDriverCaps						*m_Caps;
};

extern "C"
{
	//include the all important APIs so that we can be used
#ifdef _DEBUG
	__declspec(dllexport) deBoolean IsDestiny3DDriverDebug();
#else
	__declspec(dllexport) deBoolean IsDestiny3DDriver();
#endif
	__declspec(dllexport) IdeDriver	*GetDriverInstance(long ID);
	__declspec(dllexport) const deDriverInfo *GetDriverInfo(long StructSize);
};

#endif