/*
gl_draw.c - orthogonal drawing stuff
Copyright (C) 2010 Uncle Mike

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 3 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.
*/

#include "r_local.h"

/*
=============
R_GetImageParms
=============
*/
void R_GetTextureParms( int *w, int *h, int texnum )
{
	image_t	*glt;

	glt = R_GetTexture( texnum );
	if( w ) *w = glt->srcWidth;
	if( h ) *h = glt->srcHeight;
}

/*
=============
R_GetSpriteParms

same as GetImageParms but used
for sprite models
=============
*/
void GAME_EXPORT R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
{
	mspriteframe_t	*pFrame;

	if( !pSprite || pSprite->type != mod_sprite ) return; // bad model ?
	pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f );

	if( frameWidth ) *frameWidth = pFrame->width;
	if( frameHeight ) *frameHeight = pFrame->height;
	if( numFrames ) *numFrames = pSprite->numframes;
}

int GAME_EXPORT R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
{
	if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data )
		return 0;

	return R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum;
}


/*
=============
Draw_StretchPicImplementation
=============
*/
void R_DrawStretchPicImplementation( int x, int y, int w, int h, int s1, int t1, int s2, int t2, image_t	*pic )
{
	pixel_t *source, *dest;
	unsigned int				v, u, sv;
	unsigned int				height;
	unsigned int				f, fstep;
	int				skip;
	qboolean transparent = false;
	pixel_t *buffer;

	if( x < 0 )
	{
		s1 += (-x)*(s2-s1) / w;
		x = 0;
	}
	if( x + w > vid.width )
	{
		s2 -= (x + w - vid.width) * (s2 - s1)/ w ;
		w = vid.width - x;
	}
	if( y + h > vid.height )
	{
		t2 -= (y + h - vid.height) * (t2 - t1) / h;
		h = vid.height - y;
	}

	if( !pic->pixels[0] || s1 >= s2 || t1 >= t2 )
		return;

	//gEngfuncs.Con_Printf ("pixels is %p\n", pic->pixels[0] );

	height = h;
	if (y < 0)
	{
		skip = -y;
		height += y;
		y = 0;
	}
	else
		skip = 0;

	dest = vid.buffer + y * vid.rowbytes + x;

	if( pic->alpha_pixels )
	{
		buffer = pic->alpha_pixels;
		transparent = true;
	}
	else
		buffer = pic->pixels[0];


	#pragma omp parallel for schedule(static)
	for (v=0 ; v<height ; v++)
	{
		int alpha1 = vid.alpha;
#ifdef	_OPENMP
		pixel_t			*dest = vid.buffer + (y + v) * vid.rowbytes + x;
#endif
		sv = (skip + v)*(t2-t1)/h + t1;
		source = buffer + sv*pic->width + s1;

		{
			f = 0;
			fstep = ((s2-s1) << 16)/w;

#if 0
			for (u=0 ; u<w ; u+=4)
			{
				dest[u] = source[f>>16];
				f += fstep;
				dest[u+1] = source[f>>16];
				f += fstep;
				dest[u+2] = source[f>>16];
				f += fstep;
				dest[u+3] = source[f>>16];
				f += fstep;
			}
#else
			for (u=0 ; u<w ; u++)
			{
				pixel_t src = source[f>>16];
				int alpha = alpha1;
				f += fstep;

				if( transparent )
				{
					alpha &= src >> ( 16 - 3 );
					src = src << 3;
				}

				if( alpha == 0 )
					continue;

				if( vid.color != COLOR_WHITE )
					src = vid.modmap[(src & 0xff00)|(vid.color>>8)] << 8 | (src & vid.color & 0xff) | ((src & 0xff) >> 3);

				if( vid.rendermode == kRenderTransAdd)
				{
					pixel_t screen = dest[u];
					dest[u] = vid.addmap[(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) | ((src & 0xff) >> 0);
				}
				else if( alpha < 7) // && (vid.rendermode == kRenderTransAlpha || vid.rendermode == kRenderTransTexture ) )
				{
					pixel_t screen = dest[u]; //  | 0xff & screen & src ;
					dest[u] = BLEND_ALPHA( alpha, src, screen);//vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) >> 3 | ((src & 0xff) >> 3);

				}
				else
					dest[u] = src;

			}
#endif
		}
		dest += vid.rowbytes;
	}
}


/*
=============
R_DrawStretchPic
=============
*/
void GAME_EXPORT R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum )
{
	image_t *pic = R_GetTexture(texnum);
	int width = pic->width, height = pic->height;
//	GL_Bind( XASH_TEXTURE0, texnum );
	if( s2 > 1.0f || t2 > 1.0f )
		return;
	if( s1 < 0.0f || t1 < 0.0f )
		return;
	if( w < 1.0f || h < 1.0f )
		return;
	R_DrawStretchPicImplementation(x,y,w,h, width * s1, height * t1, width * s2, height * t2, pic);
}

void Draw_Fill (int x, int y, int w, int h)
{
	pixel_t *dest;
	unsigned int				v, u;
	unsigned int				height;
	int				skip;
	pixel_t src = vid.color;
	int alpha = vid.alpha;

	if( x < 0 )
		x = 0;

	if( x + w > vid.width )
		w = vid.width - x;

	if( w <= 0 )
		return;

	if( y + h > vid.height )
		h = vid.height - y;

	if( h <= 0 )
		return;

	height = h;
	if( y < 0 )
	{
		if( h <= -y )
			return;
		skip = -y;
		height += y;
		y = 0;
	}
	else
		skip = 0;

	dest = vid.buffer + y * vid.rowbytes + x;

	#pragma omp parallel for schedule(static)
	for (v=0 ; v<height ; v++)
	{
#ifdef	_OPENMP
		pixel_t			*dest = vid.buffer + (y + v) * vid.rowbytes + x;
#endif

		{

#if 0
			for (u=0 ; u<w ; u+=4)
			{
				dest[u] = source[f>>16];
				f += fstep;
				dest[u+1] = source[f>>16];
				f += fstep;
				dest[u+2] = source[f>>16];
				f += fstep;
				dest[u+3] = source[f>>16];
				f += fstep;
			}
#else
			for (u=0 ; u<w ; u++)
			{
				if( alpha == 0 )
					continue;

				if( vid.rendermode == kRenderTransAdd)
				{
					pixel_t screen = dest[u];
					dest[u] = vid.addmap[(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) | ((src & 0xff) >> 0);
				}
				else if( alpha < 7) // && (vid.rendermode == kRenderTransAlpha || vid.rendermode == kRenderTransTexture ) )
				{
					pixel_t screen = dest[u]; //  | 0xff & screen & src ;
					dest[u] = BLEND_ALPHA( alpha, src, screen);//vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0xff) >> 3 | ((src & 0xff) >> 3);

				}
				else
					dest[u] = src;

			}
#endif
		}
		dest += vid.rowbytes;
	}
}

/*
=============
Draw_TileClear

This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void GAME_EXPORT R_DrawTileClear( int texnum, int x, int y, int w, int h )
{
	int		tw, th, x2, i, j;
	image_t	*pic;
	pixel_t *psrc, *pdest;

	GL_SetRenderMode( kRenderNormal );
	_TriColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
	GL_Bind( XASH_TEXTURE0, texnum );

	pic = R_GetTexture( texnum );

	tw = pic->width;
	th = pic->height;
	if (x < 0)
	{
		w += x;
		x = 0;
	}
	if (y < 0)
	{
		h += y;
		y = 0;
	}
	if (x + w > vid.width)
		w = vid.width - x;
	if (y + h > vid.height)
		h = vid.height - y;
	if (w <= 0 || h <= 0)
		return;

	x2 = x + w;
	pdest = vid.buffer + y*vid.rowbytes;
	for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
	{
		psrc = pic->pixels[0] + tw * ((i+y)&63);
		for (j=x ; j<x2 ; j++)
			pdest[j] = psrc[j&63];
	}
}

/*
=============
R_DrawStretchRaw
=============
*/
void GAME_EXPORT R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
{
	byte		*raw = NULL;
	image_t	*tex;

	raw = (byte *)data;

	//pglDisable( GL_BLEND );
	//pglDisable( GL_ALPHA_TEST );
	//pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

	tex = R_GetTexture( tr.cinTexture );
	GL_Bind( XASH_TEXTURE0, tr.cinTexture );
}

/*
=============
R_UploadStretchRaw
=============
*/
void GAME_EXPORT R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data )
{
	byte		*raw = NULL;
	image_t	*tex;
	raw = (byte *)data;

	tex = R_GetTexture( texture );
	GL_Bind( GL_KEEP_UNIT, texture );
	tex->width = cols;
	tex->height = rows;
}

/*
===============
R_Set2DMode
===============
*/
void GAME_EXPORT R_Set2DMode( qboolean enable )
{
	vid.color = COLOR_WHITE;
	vid.is2d = enable;
	vid.alpha = 7;

	if( enable )
	{
//		if( glState.in2DMode )
	//		return;
#if 0
		// set 2D virtual screen size
		pglViewport( 0, 0, gpGlobals->width, gpGlobals->height );
		pglMatrixMode( GL_PROJECTION );
		pglLoadIdentity();
		pglOrtho( 0, gpGlobals->width, gpGlobals->height, 0, -99999, 99999 );
		pglMatrixMode( GL_MODELVIEW );
		pglLoadIdentity();

		GL_Cull( GL_NONE );

		pglDepthMask( GL_FALSE );
		pglDisable( GL_DEPTH_TEST );
		pglEnable( GL_ALPHA_TEST );
		pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
#endif

	//	glState.in2DMode = true;
		RI.currententity = NULL;
		RI.currentmodel = NULL;
	}
	else
	{
#if 0
		pglDepthMask( GL_TRUE );
		pglEnable( GL_DEPTH_TEST );
		glState.in2DMode = false;

		pglMatrixMode( GL_PROJECTION );
		GL_LoadMatrix( RI.projectionMatrix );

		pglMatrixMode( GL_MODELVIEW );
		GL_LoadMatrix( RI.worldviewMatrix );

		GL_Cull( GL_FRONT );
#endif
	}
}