#ifndef _RENDERER_H
#define _RENDERER_H

#include "common.h"

#include "core.h"
#include "core_opengl.h"
#include "core_d3d9.h"

#include "ravenmath.h"
#include "vector.h"
#include "frustum.h"

#include "vertexbuffer.h"
#include "light.h"
#include "material.h"
#include "font.h"
#include "texture.h"
#include "rendertarget.h"

// maximums
#define RAVEN_PROJECTION_STACK_DEPTH		1024
#define RAVEN_MODELVIEW_STACK_DEPTH			1024
#define RAVEN_MAXIMUM_LIGHTS				  32

// state flags
#define RAVEN_STATE_NODEPTH					0x01
#define RAVEN_STATE_LIGHT					0x02
#define RAVEN_STATE_MATERIAL				0x04
#define RAVEN_STATE_TEXTURE					0x08
#define RAVEN_STATE_USE_HW_VERTEX_MEMORY	0x10
#define RAVEN_STATE_USE_HW_PIXEL_MEMORY		0x20
#define RAVEN_STATE_GPU_PROGRAM				0x40
#define RAVEN_STATE_WIREFRAME				0x80

class Renderer;

// geometry renderer cull mode.  WHAT DO YOU WANT TO CULL TODAY JONNY?
enum CullMode
{
	RAVEN_CULL_NONE=0,
	RAVEN_CULL_BACK=1,
	RAVEN_CULL_FRONT=2
};

// renderer blend mode
enum BlendMode
{
	RAVEN_BLEND_NONE,
	RAVEN_BLEND_ALPHA,
	RAVEN_BLEND_ADD,
	RAVEN_BLEND_MULT,
	RAVEN_BLEND_LIGHT,
	RAVEN_BLEND_MASK_LOW,
	RAVEN_BLEND_MASK_HI
};

Renderer *__create_renderer(Core *core);

struct Viewport
{
	float left,top,right,bottom;
	Viewport(float left=0,float top=0,float right=0,float bottom=0);
	Viewport(RenderTarget *target);
};

class Renderer
{
protected:
	Core *core;

	unsigned int proj_stack_ptr,mdvw_stack_ptr;
	Matrix4x4 proj_stack[RAVEN_PROJECTION_STACK_DEPTH];
	Matrix4x4 mdvw_stack[RAVEN_MODELVIEW_STACK_DEPTH];

	RenderTarget *main_fb;
	RenderTarget *curr_target;

	BlendMode blend;
	float blendmask;

	CullMode cullmode;
	int stateflags;

	RenderMaterial material;

	Viewport viewport;

	Light **active_lights;
public:
	static Renderer *Create(Core *core)
	{
		return __create_renderer(core);
	}

	Renderer(Core *core);
	virtual ~Renderer();

	virtual Core *GetCore() {return core;}

	virtual void TargetViewport(const Viewport &vp);
	virtual Viewport TargetViewport();

	virtual void PushProjection();
	virtual void LoadProjection(const Matrix4x4 &mat);
	virtual void LoadProjection(const Projection &proj);
	virtual void MultProjection(Matrix4x4 &mat);
	virtual void PopProjection();
	virtual Matrix4x4 GetProjection();
	virtual Frustum GetProjectionFrustum();
	virtual unsigned int GetProjectionStackDepth();

	virtual void PushModelView();
	virtual void LoadModelView(const Matrix4x4 &mat);
	virtual void MultModelView(const Matrix4x4 &mat);
	virtual void PopModelView();
	virtual Matrix4x4 GetModelView();
	virtual unsigned int GetModelViewStackDepth();

	virtual bool BeginScene(bool clearcolor,bool cleardepth,Vector4 color)=0;
	virtual bool EndScene(bool flip)=0;

	virtual void SetCullMode(CullMode mode);
	virtual CullMode GetCullMode();

	virtual void State(int state,bool on);
	virtual bool State(int state);

	virtual void Blend(BlendMode mode,float mask=0.5f);
	virtual BlendMode Blend();
	virtual void BlendMask(float mask);
	virtual float BlendMask();

	virtual void Material(const RenderMaterial &material);
	virtual RenderMaterial Material();

	virtual bool EnableLight(int slot,Light *light);
	virtual bool DisableLight(int slot);

	virtual VertexBuffer *CreateVertexBuffer(int attribs);
	virtual bool RenderVertexBuffer(VertexBuffer *buf,GeometryType geomtype)=0;

	virtual bool BeginGeometry(int attribs,int numtextures,GeometryType geomtype)=0;
	virtual void GeometryVertex(const Vector3 &vert)=0;
	virtual void GeometryNormal(const Vector3 &norm)=0;
	virtual void GeometryColor(const Vector4 &color)=0;
	virtual void GeometryTexCoord(const Vector2 &texcoord,int idx)=0;
	virtual bool EndGeometry()=0;

	virtual RenderTarget *CreateRenderTargetColorTexture(SamplerState samp,int po2lev,bool floatformat=false)=0;
	virtual RenderTarget *CreateRenderTargetDepthTexture(SamplerState samp,int po2lev)=0;
	virtual RenderTarget *FrameBufferTarget() {return main_fb;}
	virtual RenderTarget *BoundRenderTarget() {return curr_target;}
	virtual bool BindRenderTarget(RenderTarget *target)=0;

	virtual Texture *CreateTexture(Pixelmap *image,SamplerState samp,unsigned int flags)=0;

	virtual FontBase *LoadFont(const char *file,int pt)=0; // load a truetype/freetype font
	virtual FontBase *LoadFont(const char *file)=0;		// load a  bitmap font

	virtual ShaderProgram *LoadShader(const char *dir,const char *name,bool hasfrag)=0;

	virtual bool RenderText(FontBase *font,int x,int y,const char *text)=0;
};

#endif
