/*
RScript loading, parsing, and rendering.

Code syntax is similar to that of shaders
No reference to any shader material was used whilst
making this code, hence the weak and buggy state of it :)
*/

#include "quakedef.h"
#include "gl_shaders.h"

typedef struct glRect_s {
	unsigned char l,t,w,h;
} glRect_t;

#define	MAX_LIGHTMAPS	1024 // 64
#define	BLOCK_WIDTH		128
#define	BLOCK_HEIGHT	128

extern	int			lightmap_bytes;
extern	int			lightmap_textures;
extern	glpoly_t	*lightmap_polys[MAX_LIGHTMAPS];
extern	qboolean	lightmap_modified[MAX_LIGHTMAPS];
extern	glRect_t	lightmap_rectchange[MAX_LIGHTMAPS];
extern	byte		lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];

void DrawPolygon (msurface_t *s)
{
	glpoly_t	*p;
	float		*v, vt[3], os, ot;
	texture_t	*t;
	vec3_t		nv, dir;
	int			i, rs;
	float		tx,ty;
	glRect_t	*theRect;
	float		txm, tym;
	BOOL		stage;

	p = s->polys;
	t = R_TextureAnimation (s->texinfo->texture);
	rs = t->rs;
	stage=true;

	while (stage)
	{
		// Binds world to texture env 0
		if (!rscripts[rs].flags.nolightmap)
		{
				GL_SelectTexture(TEXTURE0_SGIS);
				if (rs > 0)
					GL_Bind (rscripts[rs].texnum);
				else
					GL_Bind (t->gl_texturenum);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
				// Binds lightmap to texenv 1
				GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
				GL_Bind (lightmap_textures + s->lightmaptexturenum);
				i = s->lightmaptexturenum;
				if (lightmap_modified[i])
				{
					lightmap_modified[i] = false;
					theRect = &lightmap_rectchange[i];
					glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, 
						BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
						lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
					theRect->l = BLOCK_WIDTH;
					theRect->t = BLOCK_HEIGHT;
					theRect->h = 0;
					theRect->w = 0;
				}
			if (rscripts[rs].flags.blendfunc)
				glEnable(GL_BLEND);
			else
				glDisable(GL_BLEND);
			if (rscripts[rs].flags.alphafunc) {
				glAlphaFunc(GL_GEQUAL, 0.05f);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
				glEnable(GL_ALPHA_TEST);
			}
			else
				glDisable(GL_ALPHA_TEST);

			if (!rs) {
				if (t->transparent) {
					glEnable(GL_ALPHA_TEST);
					glAlphaFunc(GL_GEQUAL, 0.05f);
					glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
				}
			}

			glBegin (GL_POLYGON);
			v = p->verts[0];
			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
			{
				txm=0; tym=0;
				if (rscripts[rs].usescroll) {
					txm=realtime*rscripts[rs].scroll.xspeed; while (txm > 1 && (1-txm) > 0) txm=1-txm;
					tym=realtime*rscripts[rs].scroll.yspeed; while (tym > 1 && (1-tym) > 0) tym=1-tym;
				}
				if (rscripts[rs].useturb) {
					float power;

					power = rscripts[rs].turb.power / 20;
					os=v[3]; ot = v[4];
					vt[0] = os + sin((os*0.1+realtime) * power) * sin((ot*0.1+realtime));
					vt[1] = ot + sin((ot*0.1+realtime) * power) * sin((os*0.1+realtime));

				} else {
					vt[0] = v[3];
					vt[1] = v[4];
				}
				if (rscripts[rs].usevturb)
				{
					float power;

					power = rscripts[rs].vturb.power;
					nv[0] = v[0] + power*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
					nv[1] = v[1] + power*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
					nv[2] = v[2];
				} else {
					nv[0] = v[0];
					nv[1] = v[1];
					nv[2] = v[2];
				}

				qglMTexCoord2fSGIS (TEXTURE0_SGIS, vt[0]+txm, vt[1]+tym);
				qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);

				glVertex3fv (nv);
			}
			glEnd ();
		} else {
			GL_DisableMultitexture();
			GL_Bind (rscripts[rs].texnum);

			if (rscripts[rs].flags.blendfunc)
				glEnable(GL_BLEND);
			else
				glDisable(GL_BLEND);
			if (rscripts[rs].flags.alphafunc) {
				glAlphaFunc(GL_GEQUAL, 0.05f);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
				glEnable(GL_ALPHA_TEST);
			}
			else
				glDisable(GL_ALPHA_TEST);
			glColor4f(1,1,1,rscripts[rs].flags.alpha);
			glBegin (GL_POLYGON);
			v = p->verts[0];
			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
			{
				txm=0; tym=0;
				if (rscripts[rs].usescroll) {
					txm=realtime*rscripts[rs].scroll.xspeed; while (txm > 1 && (1-txm) > 0) txm=1-txm;
					tym=realtime*rscripts[rs].scroll.yspeed; while (tym > 1 && (1-tym) > 0) tym=1-tym;
				}
				if (rscripts[rs].useturb) {
					float power;

					power = rscripts[rs].turb.power / 20;
					os=v[3]; ot = v[4];
					vt[0] = os + sin((os*0.1+realtime) * power) * sin((ot*0.1+realtime));
					vt[1] = ot + sin((ot*0.1+realtime) * power) * sin((os*0.1+realtime));
				} else {
					vt[0] = v[3];
					vt[1] = v[4];
				}
				if (rscripts[rs].usevturb)
				{
					float power;

					power = rscripts[rs].vturb.power;
					nv[0] = v[0] + power*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
					nv[1] = v[1] + power*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
					nv[2] = v[2];
				} else {
					nv[0] = v[0];
					nv[1] = v[1];
					nv[2] = v[2];
				}

				glTexCoord2f (vt[0]+txm, vt[1]+tym);
				glVertex3fv (nv);
			}
			glEnd ();
			glColor4f(1,1,1,1);
			glDisable(GL_BLEND);
			glDisable(GL_ALPHA_TEST);
		}
		rs=rscripts[rs].nextstage;
		if (!rs)
			stage=false;
	}

	// Show BSP cuts
	if (gl_showcuts.value)
	{
		GL_DisableMultitexture();
		glDisable(GL_TEXTURE_2D);
		glLineWidth(1.5f);
		glBegin(GL_LINE_LOOP);
		glColor4f(1,1,1,1);
		v = p->verts[0];
		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
			glVertex3fv (v);
		glEnd ();
		glEnable(GL_TEXTURE_2D);
	}

	if (t->transparent)
		glDisable(GL_ALPHA_TEST);
}

void FinishScripts(int i)
{
	if (!strcmp(rscripts[i].scriptname,""))
		return;
	if (rscripts[i].nextname)
		rscripts[i].nextstage=GetRSForName(rscripts[i].nextname);
	if (!_stricmp(rscripts[i].texname, "$lightmap"))
		return;
	if (!strcmp(rscripts[i].texname,""))
		strcpy(rscripts[i].texname,rscripts[i].scriptname);
	rscripts[i].texnum = loadtextureimage(5000+i,rscripts[i].texname,false,0,0);
}

int GetRSForName(char name[56])
{
	int i;

	for (i=0;i<500;i++)
	{
		if (!_stricmp(name,rscripts[i].scriptname))
		{
			FinishScripts(i);
			return i;
		}
	}
	return 0;
}

float GetBlendForName(char *blend)
{
	if (!strcmp(blend,""))
		return 0;
	if (!_stricmp(blend,"GL_ZERO"))
		return GL_ZERO;
	if (!_stricmp(blend,"GL_ONE"))
		return GL_ONE;
	if (!_stricmp(blend,"GL_DST_COLOR"))
		return GL_DST_COLOR;
	if (!_stricmp(blend,"GL_ONE_MINUS_DST_COLOR"))
		return GL_ONE_MINUS_DST_COLOR;
	if (!_stricmp(blend,"GL_SRC_ALPHA"))
		return GL_SRC_ALPHA;
	if (!_stricmp(blend,"GL_ONE_MINUS_SRC_ALPHA"))
		return GL_ONE_MINUS_SRC_ALPHA;
	if (!_stricmp(blend,"GL_DST_ALPHA"))
		return GL_DST_ALPHA;
	if (!_stricmp(blend,"GL_ONE_MINUS_DST_ALPHA"))
		return GL_ONE_MINUS_DST_ALPHA;
	if (!_stricmp(blend,"GL_SRC_ALPHA_SATURATE"))
		return GL_SRC_ALPHA_SATURATE;
	if (!_stricmp(blend,"GL_SRC_COLOR"))
		return GL_SRC_COLOR;
	if (!_stricmp(blend,"GL_ONE_MINUS_SRC_COLOR"))
		return GL_ONE_MINUS_SRC_COLOR;
	return 0;
}

BOOL torf(float i)
{
	if (i == 1)
		return true;
	else
		return false;
}

void InitRenderScripts()
{
	FILE		*f;
	char		*ch, *sp1,*sp2, *output;
	int			ip1,ip2;
	float		fp1,fp2,fp3,fp4;
	int			inscript, num;

	inscript=0; num=1; output=malloc(56);
	ch=malloc(1024); sp1=malloc(1024); sp2=malloc(1024);
	if (!COM_FOpenFile("textures.rs",&f))
		return;

	do {
		fscanf(f,"%s",ch);
		if (inscript) {
			if (!_stricmp(ch,"turb")) { // turb effect
				fscanf(f,"%f",&fp1); fscanf(f,"%f",&fp2); fscanf(f,"%f",&fp3); fscanf(f,"%f",&fp4);
				rscripts[num].turb.power = fp1;
				rscripts[num].useturb=true;
			} else if (!_stricmp(ch,"turbvert")) { // vertex turb effect
				fscanf(f,"%f",&fp1); fscanf(f,"%f",&fp2); fscanf(f,"%f",&fp3); fscanf(f,"%f",&fp4);
				rscripts[num].vturb.power = fp1;
				rscripts[num].usevturb=true;
			} else if (!_stricmp(ch,"scroll")) { // scrolling texture
				fscanf(f,"%f",&fp1); fscanf(f,"%f",&fp2);
				rscripts[num].scroll.xspeed = fp1;
				rscripts[num].scroll.yspeed = fp2;
				rscripts[num].usescroll=true;
			} else if (!_stricmp(ch,"blend")) { // blendmodes
				fscanf(f,"%s",sp1); fscanf(f,"%s",sp2);
				rscripts[num].blendmode.srcmode = GetBlendForName(sp1);
				rscripts[num].blendmode.dstmode = GetBlendForName(sp2);
				rscripts[num].useblendmode=true;
			} else if (!_stricmp(ch,"stage")) { // next stage
				fscanf(f,"%s",sp1);
				strcpy(rscripts[num].nextname, sp1);
			} else if (!_stricmp(ch,"map")) { // texture
				fscanf(f,"%s",sp1);
				strcpy(rscripts[num].texname, sp1);
			} else if (!_stricmp(ch,"set")) { // set texture flags
				fscanf(f,"%s",sp1); fscanf(f,"%f",&fp1);
				if (!_stricmp(sp1, "alpha"))
					rscripts[num].flags.alpha=fp1;
				else if (!_stricmp(sp1, "blendfunc"))
					rscripts[num].flags.blendfunc=torf(fp1);
				else if (!_stricmp(sp1, "alphafunc"))
					rscripts[num].flags.alphafunc=torf(fp1);
				else if (!_stricmp(sp1, "nolightmap"))
					rscripts[num].flags.nolightmap=torf(fp1);
			} else if (!_stricmp(ch,"}")) {
				inscript=0;
				num++;
			}
		} else {
			if (_stricmp(ch,"{"))
			{
				strcpy(rscripts[num].scriptname,ch);
			} else {
				rscripts[num].flags.alpha=1;
				inscript=1;
			}
		}
	} while (!feof(f));
	fclose(f);
}