/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/include/sgx/graphics/graphicsctx.hpp

*/

#ifndef SGX_GRAPHICS_GRAPHICS_CTX_HPP
#define SGX_GRAPHICS_GRAPHICS_CTX_HPP	1

#include "domains/graphics/graphics.hpp"
#include "utils/imagelib/imagelib.hpp"

#if SGX_FINAL_BUILD==1
#define SGX_ENGINE_STATS(id)	sizeof(id)
#else
#define SGX_ENGINE_STATS(id)	m_EngineStats.incOption(id)
#endif

#define SGX_CLEAR_FRAME_BUFFER		1
#define SGX_CLEAR_Z_BUFFER			2

#define SGX_FOG_LOGARITHMIC			0
#define SGX_FOG_LINEAR				1

typedef enum {
	eWireframe = 1,
	eSolid
} tPrimitiveMode;

/*
** Classes 
*/
class CImageData;

class sgxViewportSettings {
public:
	tREAL32 origin_x, origin_y;
	tREAL32 width, height;

	sgxViewportSettings() { origin_x=origin_y=0; width=height=1.0f; }
	sgxViewportSettings(const tREAL32 ox, const tREAL32 oy, const tREAL32 pw, const tREAL32 ph) { origin_x=ox; origin_y=oy; width=pw; height=ph; }
};

class sgxViewport
{
public:
	tINT32 origin_x, origin_y;
	tUINT32 width, height;

	sgxViewport() {}
	sgxViewport(const sgxViewportSettings &vps, tUINT32 w, tUINT32 h) {
		origin_x = (tINT32)(vps.origin_x*w);
		origin_y = (tINT32)(vps.origin_y*h);
		width = (tUINT32)(vps.width*w);
		height = (tUINT32)(vps.height*h);
	}

	sgxViewport(const tINT32 ox, const tINT32 oy, const tUINT32 pw, const tUINT32 ph) { origin_x=(ox); origin_y=(oy); width=(pw); height=(ph); }

	SGX_INLINE	bool operator!=(const sgxViewport &rhs) const { return (origin_x!=rhs.origin_x || origin_y!=rhs.origin_y || width!=rhs.width || height!=rhs.height)?TRUE:FALSE; }
};


class sgxFogging {
public:
	tBOOL	bActive;
	tUINT32	iMode;
	tREAL32	fRed, fBlue, fGreen, fAlpha;
	tREAL32	fStart, fEnd;
	tREAL32	fDensity;

	sgxFogging();
	sgxFogging &operator=(const sgxFogging &ref);
	bool operator!=(const sgxFogging &other);
};

#define SGX_RENDERMODE_2D		0
#define SGX_RENDERMODE_3D		1

class sgxStateRenderMode : public sgxStateTemplate<tBOOL> {
public:
	virtual tBOOL doApply(); 
};



// TODO: Make this a template in CORE
class sgxRefCache {
public:
	tULONG		iCount;
	CSGXSurface *pSurface;

	sgxRefCache()
	{
		iCount = 0;
		pSurface = NULL;
	}

	sgxRefCache(CSGXSurface *pSurface_)
	{
		iCount = 0;
		pSurface = pSurface_;
	}
};

typedef sgxMap<sgxString, sgxRefCache> SurfaceCacheMap;

// TODO: typedef this in the class
typedef sgxString SurfaceCacheID;

class SurfaceCache {
public:
	void		getCacheID(SurfaceCacheID &id, const sgxString &filename);
	void		getCacheID(SurfaceCacheID &id, const sgxString &filename, const sgxString &alpha_filename);
	
	CSGXSurface	*getSurface(const sgxString &filename);
	CSGXSurface	*getSurface(const sgxString &filename, const sgxString &alpha_filename);
	
	void		addSurface(const SurfaceCacheID &id, CSGXSurface *);

	SurfaceCacheMap m_Cache;
};



class CSGXTextureManager  : public CSGXEngine {
public:
	static CSGXTextureManager *create();
	static CSGXTextureManager *get();

	CSGXTextureManager();
	virtual ~CSGXTextureManager();
	
	virtual void		initialize();
	virtual CSGXTexture *createTexture(const CImageData &img, const CSGXSurface::tReason reason=CSGXSurface::eReasonDefault);
	virtual CSGXSurface *createSurface(const CImageData &img, const CSGXSurface::tReason reason=CSGXSurface::eReasonDefault);

	virtual CSGXTexture *registerScenarioTexture(const sgxString &filename);
	virtual CSGXTexture *registerGlobalTexture(const sgxString &filename);

	virtual	CSGXTexture *loadTexture(const sgxString &filename, const CImageData::Mask &mask=CImageData::Mask());
	virtual	CSGXTexture *loadTexture(const sgxString &filename, const sgxString &alpha_filename);
	virtual tUINT32		loadTexture(const sgxString &filename, sgxVector<CSGXTexture *> &textureList);
	virtual CSGXTexture *loadTexture(const sgxString &filename, const sgxColorRGB &maskColor);

	virtual CSGXTexture *setCurrentTexture(const CSGXTexture *pTexture);
	virtual CSGXTexture *setCurrentTexture(const CSGXTexture &texture);
	virtual void		setCurrentRegion(const tUINT32 region);
	virtual void		applyTexture(const CSGXTexture *pTexture);
	virtual void		applyTexture(const CSGXTexture &Texture);
	virtual void		applyTextureRegion(const sgxUV &uv);

	virtual CSGXTexture *getCurrentTexture();
	virtual void		getCurrentUV(sgxUV &uv);

	virtual void		evaluateUV(sgxVector2 &uv);
	virtual void		evaluateUV(sgxVector2 &uv, const CSGXTexture *pTxt);

protected:
	static CSGXTextureManager	*m_pSingleton;
	SurfaceCache				m_SurfaceCache;

private:
	static CSGXSurface			ms_NullSurface;
	static CSGXTexture			ms_NullTexture;
	sgxStatePtr					m_TextureState;
	sgxUV						m_TextureUV;
	sgxVector2					m_MainRegion;
	sgxVector2					m_SubRegionDelta;

};


class CGraphicSprite : public sgxPrimitiveBase
{
public:
	class sgxSpriteVtx
	{
	public:
		sgxVector2		vect;
		tREAL32			u, v;
		sgxColorRGBA	color;
	};

	typedef enum {
		eCentre = 0,
		eCenter = eCentre,
		eTopLeft,
		eBottomCentre,
		eBottomCenter = eBottomCentre,
	} tSpriteOrigin;

	const CSGXTexture		*pTexture;
	sgxSpriteVtx			vtx[4];
	tREAL32					rotation;

	CGraphicSprite();
	void			unit();
	void			setUV(const sgxUV &uv);
	void			setSize(const tREAL32 size) { setSize(size, size); }
	void			setSize(const tREAL32 width, const tREAL32 height);
	void			setOrigin(const tSpriteOrigin origin);
	tSpriteOrigin	getOrigin() const;
	void			getCentre(sgxVector2 &centre) const;

	void			draw(const sgxVector3 &pos) const;

private:
	tSpriteOrigin			m_Origin;
	tREAL32					m_OriginMulX;
	tREAL32					m_OriginMulY;

};

//
// Template state instances
//
typedef sgxStateTemplate<sgxColorRGB>	sgxStateColorRGB;
typedef sgxStateTemplate<sgxColorRGBA>	sgxStateColorRGBA;
typedef sgxStateTemplate<sgxViewport>	sgxStateViewport;
typedef sgxStateTemplate<CSGXCamera>	sgxStateCamera;
typedef sgxStateTemplate<tPrimitiveMode>sgxStatePrimitiveMode;
typedef sgxStateTemplate<sgxFogging>	sgxStateFogging;

typedef sgxStateTemplate<sgxVector3>	sgxStateVector3;

class CViewFrustum;
//
class sgxGraphicsEngineCallbackHandler {
public:
	virtual tBOOL	onGraphicsEngineClosed();
};


class CSGXGraphicsEngine : public CSGXEngine
{
public:
	typedef enum {
		eSceneSplitHorizontal,
		eSceneSplitVertical,
	} tMultiSceneSplit;

	static CSGXGraphicsEngine *get();
	static CSGXGraphicsEngine *create();
	virtual void initialize();

	virtual void showSystemCursor(const tBOOL show);
	virtual void hideSystemCursor();

	virtual void setCallbackHandler(sgxGraphicsEngineCallbackHandler *pHandler);

	// Frame
	virtual void set2DMode();
	virtual void set3DMode();

	virtual tUINT32 getScreenWidth() const;
	virtual tUINT32 getScreenHeight() const;
	virtual tUINT32 getViewportWidth() const;
	virtual tUINT32 getViewportHeight() const;

	virtual void setDisplaySurface(CSGXDrawSurface *pSurface);
	virtual void setExtendedSurface(CSGXDrawSurface *pSurface);
	
	virtual CSGXDrawSurface *getDisplaySurface() const;
	virtual CSGXDrawSurface *getExtendedSurface() const;

	virtual void setScreenSize(const tINT32 width, const tINT32 height);
	virtual void setBackgroundColor(const sgxColorRGB &col);

	virtual tBOOL transformToScreen(sgxVector2 &screen, const sgxVector3 &world);

	virtual void renderScene();
	virtual void refresh();

	virtual void beginScene();
	virtual void drawScene();
	virtual void endScene();
	virtual void preBeginScene();
	virtual void doBeginScene();
	virtual void postBeginScene();
	virtual void preDrawScene();
	virtual void doDrawScene();
	virtual void postDrawScene();
	virtual void preEndScene();
	virtual void doEndScene();
	virtual void postEndScene();
	virtual void blit();
	virtual void setMultiScene(tUINT32 split, tMultiSceneSplit orientation=eSceneSplitHorizontal);
	virtual tUINT32 getMultiSceneWindows();
	virtual void updateViewports();

	virtual void release();

	// Frame
	virtual void clearFrameBuffer();
	virtual void clearZBuffer();
	virtual void refreshZBuffer();
	virtual void flushClearBuffer();
	virtual void setRenderBuffer(tUINT32 id);

	virtual tUINT32	getCurrentScene() const;

	virtual CSGXTexture *grabFrame(const tBOOL resizeToSquarePowerOf2=FALSE);
	virtual void *frameAlloc(tMEM_SIZE size);

	// Clip
	virtual void clearClipRect();
	virtual void setClipRect(const tPOINT x1, const tPOINT y1, const tPOINT x2, const tPOINT y2);
	virtual void setClipRect(const sgxRect2i &rc);
	virtual void getClipRect(sgxRect2i &rc);

	// update scene
	virtual void update(const tREAL32 telaps);

	virtual void preUpdateScene(const tREAL32 telaps);
	virtual void doUpdateScene(const tREAL32 telaps);
	virtual void postUpdateScene(const tREAL32 telaps);

	// Camera
	virtual void setCamera(const sgxVector3 &from, const sgxVector3 &to);
	virtual void setCamera(const CSGXCamera &camera);
	virtual void setCamera(tUINT32 camera_view, const CSGXCamera &camera);
	virtual void getCamera(CSGXCamera &camera) const;
	virtual void getCamera(tUINT32 camera_view, CSGXCamera &camera) const;

	virtual void set2DCamera(const sgxVector2 &atPosition, const sgxVector2 &upVector=sgxVector2::UnitMinusY);

	// Frustum
	SGX_INLINE CViewFrustum *Frustum() { return m_pFrustum; }
	SGX_INLINE const CViewFrustum *Frustum() const { return m_pFrustum; }

	virtual void updateViewTransform(const sgxMatrix44 &view);
	virtual void updateProjectionTransform(const sgxMatrix44 &projection);
	virtual void updateViewProjectionTransform();


	// Polygon
	virtual void drawPolygon(const sgxGfxPolygon &poly, const sgxMatrix43 &transform);
	virtual void drawMesh(const CStaticMesh &mesh, const sgxMatrix43 &transform);
	virtual void drawPolygonImpl(const sgxGfxPolygon &poly, const sgxMatrix43 &transform);
	virtual void drawAlphaPolygonImpl(const sgxGfxPolygon &poly, const sgxMatrix43 &transform);
	virtual void drawPrimitiveCuboidImpl(const sgxGfxCuboid &cuboid, const sgxMatrix43 &transform);
	virtual void drawPrimitiveSphereImpl(const sgxGfxSphere &sphere, const sgxMatrix43 &transform);

	// Animations
	virtual void updateAnimatedMesh(CAnimatedMesh &animmesh, const tREAL32 telaps);
	virtual void drawAnimatedMesh(const CAnimatedMesh &animmesh, const sgxMatrix43 &transform);

	// Lights
	virtual CSGXLight &	getLight(const tUINT32 &idx) const;
	virtual void		destroyLights();
	virtual tUINT32		getMaxLights() const;
	virtual tUINT32		getLightsInRange(const sgxVector<CSGXLight *> lights, const sgxVector3 &pos) const;

	// Sprites (billboards)
	virtual void drawSprite(const CGraphicSprite &sprite, const sgxVector3 &pos);
	virtual void drawSprite(const CGraphicSprite &sprite, const sgxMatrix43 &transform);


	// Frame (additional helpers)
	virtual void drawSky();
	virtual void drawWorldSceneGraph();
	virtual void drawObjectsInWorld();
	virtual void drawOverlays();

	virtual void preDrawObjectsInWorld();
	virtual void postDrawObjectsInWorld();

	// Primitives
	virtual tBOOL isAlphaSortable(const CSGXTexture *pTexture);
	virtual tBOOL isAlphaSortable(const sgxColorRGBA &col);
	virtual tBOOL isAlphaSortable(const sgxGfxPolygon &poly);

	// States
	virtual void setColor(const sgxColorRGB &col);
	virtual void getColor(sgxColorRGB &col) const;
	virtual void setColor(const sgxColorRGBA &col);
	virtual void getColor(sgxColorRGBA &col) const;
	virtual void setPrimitiveMode(const tPrimitiveMode &mode);
	virtual tPrimitiveMode getPrimitiveMode() const;
	virtual void setFoggingMode(const sgxFogging &fog);
	virtual sgxFogging	getFoggingMode() const;
	
	// Transforms
	virtual void clearTransformStack();
	virtual void setTransform(const sgxMatrix43 &m);
	virtual void getTransform(sgxMatrix43 &m) const;
	virtual void pushTransform(const sgxMatrix43 &m);
	virtual void popTransform();

	// Primitive rendering
	virtual void drawPrimitiveCuboid(const sgxGfxCuboid &cuboid, const sgxMatrix43 &transform);
	virtual void drawPrimitiveCuboid(const CSGXTexture **pTextures, const sgxMatrix43 &transform, const sgxVector3 &minpos, const sgxVector3 &maxpos);
	virtual void drawPrimitiveSphere(const sgxGfxSphere &sphere, const sgxMatrix43 &transform);
	virtual void drawLine3D(const sgxVector3 &from, const sgxVector3 &to);
	virtual void drawTriStrip(const CSGXTexture	*pTexture, const sgxVector<sgxPolyVtx> &vtx);
	virtual void drawQuadStrip(const CSGXTexture *pTexture, const sgxVector<sgxPolyVtx> &vtx);

	virtual void drawSkyBox(const CSGXTexture **pTextures,const sgxMatrix43 &transform, const sgxVector3 &minpos, const sgxVector3 &maxpos);
	virtual void drawAlphaFaces();

	// 2D functions
	virtual void drawLine2D(const tINT32 fromX, const tINT32 fromY, const tINT32 toX, const tINT32 toY);
	virtual void drawLine2D(const sgxPoint2i &from, const sgxPoint2i &to);
	virtual void drawRect2D(const sgxPoint2i &from, const sgxPoint2i &to);
	virtual void drawRect2D(const sgxPoint2i &center, const tINT32 size);

	virtual void drawRect2D(const tREAL32 x1, const tREAL32 y1, const tREAL32 x2, const tREAL32 y2, const tREAL32 x3, const tREAL32 y3, const tREAL32 x4, const tREAL32 y4);
	virtual void drawRect2D(const tPOINT x1, const tPOINT y1, const tPOINT x2, const tPOINT y2, const tPOINT x3, const tPOINT y3, const tPOINT x4, const tPOINT y4);

	virtual void drawPolygon2D(const sgxVector<sgxPoint2i> &ptList);
	// We use the system 'char' here, because that's the way the compiler will produce "quoted strings"
	virtual void drawFont(const char *pString, const tPOINT x, const tPOINT y);
	virtual void drawFont(const char *pString, const tPOINT x, const tPOINT y, const CSGXFontFormatting &formatting);

	// Platform-specific data builders: convert generic data into optimal versions
	// (these should be moved off-line)
	virtual void convertMesh(CStaticMesh &mesh);
	virtual void convertPolygon(sgxGfxPolygon &poly);
	virtual void convertAnimatedMesh(CAnimatedMesh &animmesh);

protected:
	virtual void  addAlphaSorter(const CSGXAlphaSortData *pData);
	virtual void  addAlphaSorter(const sgxGfxPolygon &poly, const sgxMatrix43 &transform);
	virtual void  addAlphaSorter(const sgxGfxSphere &sphere, const sgxMatrix43 &transform);
	virtual void  addAlphaSorter(const sgxGfxCuboid &cuboid, const sgxMatrix43 &transform);

	static CSGXGraphicsEngine *		m_pSingleton;
	
	sgxGraphicsEngineCallbackHandler *	m_pHandler;

	CFaceBuffer *					m_pAlphaFaces;
	CFrameBlock *					m_pFrameBlock;
	CViewFrustum *					m_pFrustum;

	CSGXDrawSurface *				m_pDisplaySurface;
	CSGXDrawSurface *				m_pExtendedSurface;
	tINT32							m_ScreenWidth;
	tINT32							m_ScreenHeight;
	//
	sgxRect2i						m_CurrentClipArea;

	tUINT32							m_CurrentScene;

	tBOOL							m_bProjectViewDirty;
	sgxMatrix44						m_ViewTransform;
	sgxMatrix44						m_ProjectionTransform;
	sgxMatrix44						m_ProjectViewTransform;

	sgxVector<sgxStateViewport>		m_Viewport;
	sgxVector<sgxStateCamera>		m_ViewCamera;

	sgxVector<sgxMatrix43>			m_MatrixStack;

	sgxStateColorRGB		m_BackgroundColor;

	sgxStateBool			m_ClearZBuffer;
	sgxStateColorRGB		m_ClearBufferColor;

	sgxStatePrimitiveMode	m_PrimitiveMode;
	sgxStateColorRGBA		m_PrimitiveColor;
	sgxStateFogging			m_Fogging;
	sgxStateRenderMode		m_RenderMode;

	sgxVector<CSGXLight *>	m_Lights;

	CStatisticsOptions		m_EngineStats;

	sgxViewportSettings		m_ViewportData[15];
	tUINT32					m_SplitScreenWindows;
	tMultiSceneSplit		m_SplitScreenOrientation;

	// Members
	CSGXGraphicsEngine();

	// Class creation
	virtual CSGXLight	*CreateLight();

};




//CTextureManager::setMemoryHandler(m_pGlobalMemory);



//CSGXGraphicsEngine::get()->CreateEffect("shadow", (void *)&parameters);



#endif /* SGX_GRAPHICS_GRAPHICS_CTX_HPP */

