/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// disable data conversion warnings

#pragma once

class idRenderProg;
class idVertexBuffer;


struct idRenderMatrix
{
	XMMATRIX mView;
	XMMATRIX mProjection;
    XMMATRIX mWorld;
};

struct idCurrentFrameData {
	float rendertime;
	float notUsed;
	float notUsed1;
	float notUsed2;
	
};

extern idCurrentFrameData			frameData;

#define ID_INLINE					__forceinline

#pragma warning(disable : 4244)     // MIPS
#pragma warning(disable : 4136)     // X86
#pragma warning(disable : 4051)     // ALPHA


void GL_BeginRendering (int *x, int *y, int *width, int *height);
void GL_EndRendering (void);

extern	int texture_extension_number;
extern	int		texture_mode;

extern	float	gldepthmin, gldepthmax;
void GL_DrawImage2D( float x, float y, float width, float height, float red = 1, float green = 1, float blue = 1, float alpha = 1 );

void GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap, qboolean alpha);
void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha);
int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha);
int GL_FindTexture (char *identifier);

void GL_Translate( float x, float y, float z );
void GL_Rotate( float angle, float yaw, float pitch, float roll );
void GL_Identity( void );

enum GL_MatrixMode {
	GL_MATRIX_PROJECTION = 0,
	GL_MATRIX_VIEW
};

enum GL_DepthFunc {
	GL_DEPTHFUNC_LEQUAL = 0,
	GL_DEPTHFUNC_EQUAL,
	GL_DEPTHFUNC_GEQUAL
};

void GL_SetMatrixMode( GL_MatrixMode mode );
void GL_Viewport( float x, float y, float width, float height ) ;
void GL_Scale( float x, float y, float z );

void GL_SetAddBlend( bool enable );
void GL_SetAlphaBlend( bool enable );

void GL_GetMatrix( GL_MatrixMode mode, idRenderMatrix &m );
void GL_GetMatrix( GL_MatrixMode mode, float *m );
void GL_DepthTest( bool active, GL_DepthFunc depthFunc = GL_DEPTHFUNC_LEQUAL );

void GL_Clear( bool colorBuffer, bool depthBuffer, bool stencilBuffer, float stencil, float r, float g, float b, float a );
void GL_SetMatrix( float *m );
void GL_SetMatrix( idRenderMatrix &m );
void GL_Finish( void ) ;


struct idDrawVert {
	idDrawVert();
	float		xyz[3];
	float		st[2];
	float		lightmapST[2];
	float		color[4];

	static ID3D11InputLayout * CreateDeviceVert( ID3DBlob* pVSBlob );

	void		SetPosition( float x, float y, float z) { xyz[0] = x; xyz[1] = y; xyz[2] = z; }
	void		SetST( float s, float t ) { st[0] = s; st[1] = t; }
	void		SetLightmapST(float s, float t) {lightmapST[0] = s; lightmapST[1] = t; }
	void		SetColor( float r, float g, float b ) { color[0] = r; color[1] = g; color[2] = b; color[3] = 1; }
	void		SetColorAlpha( float r, float g, float b, float a ) { color[0] = r; color[1] = g; color[2] = b; color[3] = a; }
};

ID_INLINE idDrawVert::idDrawVert() {
	xyz[0] = xyz[1] = xyz[2] = 0;
	//st[0] = st[1] = 0;
	color[0] = color[1] = color[2] = color[3] = 1;
}

void GL_DrawImageWithVerts2D( idDrawVert verts[4] );

void GL_DrawQuad( idDrawVert *verts );
void GL_DrawBuffer( idDrawVert *verts, int numVerts, idRenderProg *renderProg = NULL, idVertexBuffer *vertexpool = NULL, idIndexBuffer *indexbuffer = NULL,int startVertex = 0, int numIndexes = 0 );
void GL_DrawBufferTri( idDrawVert *verts, int numVerts );
enum GL_CullType {
	CULL_NONE,
	CULL_FRONT,
	CULL_BACK
};

void GL_Cull( GL_CullType cullType );

typedef struct
{
	float	x, y, z;
	float	s, t;
	float	r, g, b;
} glvert_t;

extern glvert_t glv;

extern	int glx, gly, glwidth, glheight;

#ifdef _WIN32
extern	PROC glArrayElementEXT;
extern	PROC glColorPointerEXT;
extern	PROC glTexturePointerEXT;
extern	PROC glVertexPointerEXT;
#endif

// r_local.h -- private refresh defs

#define ALIAS_BASE_SIZE_RATIO		(1.0 / 11.0)
					// normalizing factor so player model works out to about
					//  1 pixel per triangle
#define	MAX_LBM_HEIGHT		480

#define TILE_SIZE		128		// size of textures generated by R_GenTiledSurf

#define SKYSHIFT		7
#define	SKYSIZE			(1 << SKYSHIFT)
#define SKYMASK			(SKYSIZE - 1)

#define BACKFACE_EPSILON	0.01


void R_TimeRefresh_f (void);
void R_ReadPointFile_f (void);
texture_t *R_TextureAnimation (texture_t *base);

typedef struct surfcache_s
{
	struct surfcache_s	*next;
	struct surfcache_s 	**owner;		// NULL is an empty chunk of memory
	int					lightadj[MAXLIGHTMAPS]; // checked for strobe flush
	int					dlight;
	int					size;		// including header
	unsigned			width;
	unsigned			height;		// DEBUG only needed for debug
	float				mipscale;
	struct texture_s	*texture;	// checked for animating textures
	byte				data[4];	// width*height elements
} surfcache_t;


typedef struct
{
	pixel_t		*surfdat;	// destination for generated surface
	int			rowbytes;	// destination logical width in bytes
	msurface_t	*surf;		// description for surface to generate
	fixed8_t	lightadj[MAXLIGHTMAPS];
							// adjust for lightmap levels for dynamic lighting
	texture_t	*texture;	// corrected for animating textures
	int			surfmip;	// mipmapped ratio of surface texels / world pixels
	int			surfwidth;	// in mipmapped texels
	int			surfheight;	// in mipmapped texels
} drawsurf_t;


typedef enum {
	pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2
} ptype_t;

// !!! if this is changed, it must be changed in d_ifacea.h too !!!
typedef struct particle_s
{
// driver-usable fields
	vec3_t		org;
	float		color;
// drivers never touch the following fields
	struct particle_s	*next;
	vec3_t		vel;
	float		ramp;
	float		die;
	ptype_t		type;
} particle_t;

class idRender {
public:
	void					Init( unsigned char *palette );
	void					SetPalette (unsigned char *palette);
	void					ShiftPalette (unsigned char *palette);
#ifdef ID_PC
	HWND					GetWindowHandle( void ) { return hwnd; }
#endif

	idRenderProg			*GetAlbedo2DRenderProgram( void ) { return albedo2DRenderProgram; }
	idRenderProg			*GetLightmapRenderProgram( void ) { return lightmapRenderProgram; }
	idRenderProg			*GetAlbedoRenderProgram( void ) { return albedoRenderProgram; }
	idRenderProg			*GetLiquidRenderProgram( void ) { return liquidRenderProgram; }
	idRenderProg			*GetSkyRenderProgram( void ) { return skyRenderProgram; }

	class idImage *				GetFrameBufferImage( void ) { return frameBufferImage; }

	class idRenderTexture *GetNativeRenderDestination() { return nativeRenderDestination; }
	class idRenderTexture *GetNativeRenderDestinationReal() { return nativeRenderDestinationReal; }
public:
	ID3D11Device1			*GetDevice( void ) { return g_pd3dDevice.Get(); }
	ID3D11DeviceContext1		*GetDeviceContext( void ) { return (ID3D11DeviceContext1 *)g_pImmediateContext.Get(); }
	IDXGISwapChain1*			 GetSwapChain( void ) { return g_pSwapChain.Get(); }
private:
#ifdef ID_PC
	void					InitWindow( void );
#endif

	void					InitDevice( void );
	void					CreateRenderProgs( void );
#ifdef ID_PC
	HWND					hwnd;
#endif
#ifdef ID_PC
	ID3D11Device*           g_pd3dDevice;
#else
	Microsoft::WRL::ComPtr<ID3D11Device1>           g_pd3dDevice;
#endif
	Microsoft::WRL::ComPtr<ID3D11DeviceContext1>    g_pImmediateContext;
#ifdef ID_PC
	IDXGISwapChain*         g_pSwapChain;
#else
	Microsoft::WRL::ComPtr<IDXGISwapChain1>         g_pSwapChain;
#endif
	ID3D11RenderTargetView* g_pRenderTargetView;
	D3D_FEATURE_LEVEL       g_featureLevel;
	class idRenderTexture		*nativeRenderDestination;
	class idRenderTexture		*nativeRenderDestinationReal;
	class idImage					*depthImage;
private:
	unsigned char			*vidpalette;

private:
	idImage					*frameBufferImage;
	idRenderProg			*albedo2DRenderProgram;
	idRenderProg			*lightmapRenderProgram;
	idRenderProg			*albedoRenderProgram;
	idRenderProg			*liquidRenderProgram;
	idRenderProg			*skyRenderProgram;
};

enum ImageFormat_t {
	FMT_RGBA = 0,
	FMT_RGB = 1,
	FMT_DEPTH_STENCIL,
	FMT_RGBA_RT
};

//
// idImage
//
class idImage {
public:
	idImage();
	~idImage();

	void					Init( int width, int height, ImageFormat_t format = FMT_RGBA );
	void					UploadBuffer( byte *buffer );
	void					UploadBuffer( byte *buffer, float width, float height );
	void					SetUploadCrop( float x, float y ) { _xcrop = x; _ycrop = y; };
	void					Resize( int width, int height );

	int						GetWidth() { return _width; }
	int						GetHeight() { return _height; }

	ID3D11Texture2D			*GetTextureHandle( void ) { return textureHandle; }

	void					Bind( int texNum );
private:
	void					Release( void );

	int						_width;
	int						_height;
	float					_xcrop;
	float					_ycrop;
	ID3D11Texture2D			*textureHandle;
	ID3D11ShaderResourceView *textureHandleRV;
	ID3D11SamplerState*      g_pSamplerLinear;
};

class idRenderTexture {
public:
	void					CreateFromImages( idImage *colorImage, idImage *depthStencilImage );
	void					MakeCurrent( void );

	static idRenderTexture		*GetCurrentRenderTarget( void ) { return currentRenderDestination; }

	ID3D11RenderTargetView  *GetRenderTargetView( void ) { return pRenderTargetView; }

	ID3D11DepthStencilView  *GetDepthStencilView( void ) { return pDepthStencilView; }
private:
	ID3D11RenderTargetView* pRenderTargetView;
	ID3D11DepthStencilView* pDepthStencilView;

	static idRenderTexture		*currentRenderDestination;
};

//
// idRenderProg
//
class idRenderProg {
public:
#ifdef ID_PC
	void				InitFromFile( const char *path );
#else
	void				InitFromFile( const char *vertpath, const char *pixelpath );
#endif
	void				Bind( void );

	void				Set2DViewProjectionMatrix( void );
private:
	ID3D11VertexShader*                 g_pVertexShader;
	ID3D11PixelShader*                  g_pPixelShader;

	ID3D11InputLayout *					inputLayout;

	static idRenderProg					*currentRenderProg;
};




//
// idConstantBuffer
//
class idConstantBuffer {
public:
	void					Init( int size, int num );

	void					Upload( void *buffer, int num );

	void					VSBind( int constantBufferSlot );
private:
	ID3D11Buffer*			g_pBuffer;
	int						_size;
};


extern idRender render;


//====================================================


extern	entity_t	r_worldentity;
extern	qboolean	r_cache_thrash;		// compatability
extern	vec3_t		modelorg, r_entorigin;
extern	entity_t	*currententity;
extern	int			r_visframecount;	// ??? what difs?
extern	int			r_framecount;
extern	mplane_t	frustum[4];
extern	int		c_brush_polys, c_alias_polys;


//
// view origin
//
extern	vec3_t	vup;
extern	vec3_t	vpn;
extern	vec3_t	vright;
extern	vec3_t	r_origin;

//
// screen size info
//
extern	refdef_t	r_refdef;
extern	mleaf_t		*r_viewleaf, *r_oldviewleaf;
extern	texture_t	*r_notexture_mip;
extern	int		d_lightstylevalue[256];	// 8.8 fraction of base light value

extern	qboolean	envmap;
extern	int	currenttexture;
extern	int	cnttextures[2];
extern	int	particletexture;
extern	int	playertextures;

extern	int	skytexturenum;		// index in cl.loadmodel, not gl texture object

extern	cvar_t	r_norefresh;
extern	cvar_t	r_drawentities;
extern	cvar_t	r_drawworld;
extern	cvar_t	r_drawviewmodel;
extern	cvar_t	r_speeds;
extern	cvar_t	r_waterwarp;
extern	cvar_t	r_fullbright;
extern	cvar_t	r_lightmap;
extern	cvar_t	r_shadows;
extern	cvar_t	r_mirroralpha;
extern	cvar_t	r_wateralpha;
extern	cvar_t	r_dynamic;
extern	cvar_t	r_novis;

extern	cvar_t	gl_clear;
extern	cvar_t	gl_cull;
extern	cvar_t	gl_poly;
extern	cvar_t	gl_texsort;
extern	cvar_t	gl_smoothmodels;
extern	cvar_t	gl_affinemodels;
extern	cvar_t	gl_polyblend;
extern	cvar_t	gl_keeptjunctions;
extern	cvar_t	gl_reporttjunctions;
extern	cvar_t	gl_flashblend;
extern	cvar_t	gl_nocolors;
extern	cvar_t	gl_doubleeyes;

extern	int		gl_lightmap_format;
extern	int		gl_solid_format;
extern	int		gl_alpha_format;

extern	cvar_t	gl_max_size;
extern	cvar_t	gl_playermip;

extern	int			mirrortexturenum;	// quake texturenum, not gltexturenum
extern	qboolean	mirror;
extern	mplane_t	*mirror_plane;

extern	float	r_world_matrix[16];

extern	const char *gl_vendor;
extern	const char *gl_renderer;
extern	const char *gl_version;
extern	const char *gl_extensions;

void R_TranslatePlayerSkin (int playernum);
void GL_Bind (int texnum);
idImage *GL_GetImage( void );
void GL_SetCropForImage( float x, float y );

// Multitexture
#define    TEXTURE0_SGIS				0x00
#define    TEXTURE1_SGIS				0x01

#ifndef _WIN32
#define APIENTRY /* */
#endif

void GL_DisableMultitexture(void);
void GL_EnableMultitexture(void);

