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

*/
/*
RScript 2
*/

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

int loadtextureimage (int texnum, char* filename, qboolean complain, int matchwidth, int matchheight);
void GL_SelectTexture (GLenum target);

rscript_t	*rootscript = NULL;

#define Q_SINE(x) sin(x)
#define Q_COSINE(x) cos(x)
//#define Q_SINE(x) turbsin[(int)floor(x * 100)]

int		caustics_stage, rs_num = 0, texnum = 0;
cvar_t	gl_caustics = {"gl_caustics","1", true};

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

typedef struct
{
	int		texnum;
	float	sl, tl, sh, th;
} glpic_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];

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;
}

void ClearStage(stage_t *stage)
{
	stage->blenddst=stage->blendsrc=0;
	stage->movx=stage->movy=0;
	stage->nolightmap=false;
	stage->alphafunc=false;
	stage->spheremap=false;
	stage->cullback=true;
	stage->scroll.speedY=stage->scroll.speedX=0;
	stage->anim=NULL;
	stage->animwait=0.2f;
	stage->animcount=0;
	stage->animtime=0;
	stage->texnum=0;
	strcpy(stage->texture,"");
}

int NameToInt(char *text)
{
	if (!_stricmp(text,"static"))		// static
		return 0;
	else if (!_stricmp(text,"sine"))	// sine wave
		return 1;
	else if (!_stricmp(text,"cosine"))	// cosine wave
		return 2;
	return 0;
}

void NukeStages(rscript_t *rs)
{
	int i,o; stage_t *stage,*st;
	anim_stage_t *anim, *tmp;

	stage = rs->stage;
	for (i=0;i<rs->stagecount;i++) {
		if (stage->anim != NULL) {
			anim=stage->anim;
			for (o=0;o<stage->animcount;o++) {
				tmp=anim->next;
				free(anim);
				anim=tmp;
			}
		}
		st=stage->next;
		free(stage);
		stage=st;
	}
	rs->stagecount=0;
}

rscript_t *FindScript(char name[48])
{
	int i,c = 0;
	rscript_t *rs; stage_t *stage;
	char *fn; anim_stage_t *anim;

	rs=rootscript;
	while (rs) {
		if (c > rs_num) return NULL;
		if (!_stricmp(rs->name,name)) {
			if (rs->ready) return rs;
			fn=malloc(256);
			stage=rs->stage;
			for (i=0;i<rs->stagecount;i++) {
				if (!_stricmp(stage->texture,"")) {
					sprintf(fn,"textures/%s",name);
				} else {
					if (!strstr(stage->texture,"/"))
						sprintf(fn,"textures/%s",stage->texture);
					else
						strcpy(fn,stage->texture);
				}
				stage->texnum = loadtextureimage(9000+texnum,fn,true,0,0);
				texnum++;
				anim=stage->anim;
				while (anim != NULL) {
					stage->animcount++;
					if (!strstr(anim->texture,"/"))
						sprintf(fn,"textures/%s",anim->texture);
					else
						strcpy(fn,anim->texture);
					anim->texnum = loadtextureimage(9000+texnum,fn,true,0,0);
					stage->anim_current=anim->texnum;
					texnum++;
					anim=anim->next;
				}
				stage=stage->next;
			}
			free(fn);
			rs->ready=true;
			return rs;
		}
		rs=rs->next;
		c++;
	}
	return NULL;
}

void LoadRScript(char *script, rscript_t *nullscript)
{
    char *t, *str; float fp;
	FILE *f; int i, stagenum, num, instagenum;
	BOOL comment = false, inscript, skipit = false;
	rscript_t *rs,*rep; stage_t *stage;
	anim_stage_t	*anim;

	t=(char *)malloc(1024); str=(char *)malloc(1024);
	COM_FOpenFile(script, &f); fp=0; nullscript->stagecount=0; nullscript->next=NULL;
	instagenum=num=i=stagenum=0; inscript=false;
	if (!f) {
		Con_Printf(">> ^3Tried to open non-existant script: %s\n",script);
		free(nullscript);
		return;
	}

	rs = nullscript;

	while (!feof(f)) {
		fscanf(f,"%s",t);
		if (!_stricmp(t,"/*")) {
			comment=true;
			while (comment) {
				if (feof(f)) {
					fclose(f);
					free(t); free(str);
					rs_num+=num;
					Con_Printf(">> Error: Script terminated inside comment");
					Con_Printf(">> RS: ^3%i^0 script(s) loaded from ^3%s\n",num,script);
					return;
				}
				fscanf(f,"%s",t);
				if (!_stricmp(t,"*/"))
					comment=false;
			}
			if (feof(f)) {
				fclose(f);
				free(t); free(str);
				rs_num+=num;
				Con_Printf(">> RS: ^3%i^0 script(s) loaded from ^3%s\n",num,script);
				return;
			}
		}
		if (!inscript) {
			if (!_stricmp(t,"{")) {
				inscript=true;
				stagenum=0;instagenum=0;
			} else {
				if (FindScript(t) != NULL) {
					skipit=true;
					rep=rs;
					rs=FindScript(t);
					NukeStages(rs);
					stage=malloc(sizeof(stage_t));
					rs->stage=stage;
				}
				strcpy(rs->name,t);
				rs->ready=false;
			}
		} else {
			if (!_stricmp(t,"{")) {
				stagenum++;instagenum++;
				if (stagenum > 1) {
					stage->next=(stage_t *)malloc(sizeof(stage_t));
					stage=stage->next;
					ClearStage(stage);
				} else {
					rs->stage=(stage_t *)malloc(sizeof(stage_t));
					stage=rs->stage;
					ClearStage(stage);
				}
			} else if (!_stricmp(t,"}")) {
				if (instagenum) {
					instagenum--;
				} else {
					if (!skipit) {
						rs->stagecount=stagenum;
						rs->next=(rscript_t *)malloc(sizeof(rscript_t));
						rs=rs->next; rs->stage=(stage_t *)malloc(sizeof(stage_t));
						rs->next = NULL;
						stage=rs->stage;

						inscript=false;
						num++; stagenum=instagenum=0;
					} else {
						skipit=false;
						rs->stagecount=stagenum;
						rs=rep;
						inscript=false;
						stagenum=instagenum=0;
					}
				}
			// flag parsing
			} else if (!_stricmp(t,"map")) {			// texture map
				fscanf(f,"%s",str);						// map texturename
				strcpy(stage->texture,str);
			} else if (!_stricmp(t,"nolightmap")) {			// no lightmap
				stage->nolightmap=true;						// nolightmap
			} else if (!_stricmp(t,"blendfunc")) {		// blend func
				fscanf(f,"%s",str); stage->blendsrc=GetBlendForName(str);	// blendfunc source dest
				fscanf(f,"%s",str); stage->blenddst=GetBlendForName(str);
			} else if (!_stricmp(t,"alphamask")) {		// alpha mask
				stage->alphafunc=true;					// alphamask
			} else if (!_stricmp(t,"spheremap")) {		// spheremapping
				stage->spheremap=true;					// spheremap
			} else if (!_stricmp(t,"nocull")) {			// disable backface culling
				stage->cullback=false;					// nocull
			} else if (!_stricmp(t,"alpha")) {			// alpha
				fscanf(f,"%s",str);						// alpha style speed min max
				stage->alpha.type = NameToInt(str);
				fscanf(f,"%f",&fp); stage->alpha.speed=fp;
				fscanf(f,"%f",&fp); stage->alpha.min=fp;
				fscanf(f,"%f",&fp); stage->alpha.max=fp;
			} else if (!_stricmp(t,"scroll")) {			// scroll
				fscanf(f,"%s",str);						// scroll Xtype Xspeed Ytype Yspeed
				stage->scroll.typeX=NameToInt(str);
				fscanf(f,"%f",&fp); stage->scroll.speedX=fp;
		
				fscanf(f,"%s",str);
				stage->scroll.typeY=NameToInt(str);
				fscanf(f,"%f",&fp); stage->scroll.speedY=fp;
			} else if (!_stricmp(t, "anim")) {			// texture animation
				fscanf(f,"%f",&fp);	stage->animwait=fp;
				anim=malloc(sizeof(anim_stage_t));
				stage->anim=anim;
				fscanf(f,"%s",str);
				while (_stricmp(str,"end")) {
					strcpy(anim->texture,str);
					fscanf(f,"%s",str);
					if (!_stricmp(str,"end")) {
						anim->next = NULL;
						break;
					}
					anim->next = malloc(sizeof(anim_stage_t));
					anim = anim->next;
				}
			}
		}
		strcpy(t,""); i=0;
	}
	free(t); free(str);
	rs_num+=num;
	Con_Printf(">> RS: ^3%i^0 script(s) loaded from ^3%s\n",num,script);
}

void ScanPathForScripts(char *dir)
{
	char			script[MAX_OSPATH];
	char			dirstring[1024], *c;
	int				handle;
	unsigned int	i;
	struct _finddata_t fileinfo;
	rscript_t *rs;

	if (rootscript == NULL) {
		rootscript=malloc(sizeof(rscript_t));
		LoadRScript("scripts/main.rscript",rootscript);
	}

	sprintf (dirstring, "%s/scripts/*.rscript", dir);
	handle = _findfirst (dirstring, &fileinfo);
	if (handle != -1) {
		do {
			if (fileinfo.name[0] == '.')
				continue;
			c=COM_SkipPath(fileinfo.name);
			sprintf(script,"scripts/%s", c);
			rs=rootscript;
			for (i=0;i<rs_num;i++) {
				if (i<rs_num-1)
					rs=rs->next;
			}
			if (rs->next != NULL)
				free(rs->next);
			rs->next=malloc(sizeof(rscript_t));
			LoadRScript(script,rs->next);
		} while (_findnext( handle, &fileinfo ) != -1);
		_findclose (handle);
	}
}

void ScanForScripts()
{
	int i;
	ScanPathForScripts(GAMENAME);

	i = COM_CheckParm ("-game");
	if (i && i < com_argc-1)
		ScanPathForScripts(va("%s", com_argv[i+1]));
}

void Print_RS_f()
{
	int i;
	rscript_t *rs;
	rs=rootscript;
	for (i=0;i<rs_num;i++) {
		Con_Printf(">>^3 %s\n",rs->name);
		rs=rs->next;
	}
}

void RS_UnloadAll()
{
	int i;
	rscript_t *rs,*tmp;

	rs=rootscript;
	for (i=0;i<rs_num;i++) {
		tmp=rs->next;
		NukeStages(rs);
		free(rs);
		rs=tmp;
	}
}

void RS_DrawUnscriptedSurface(msurface_t *s)
{
	float		*v;
	glpoly_t	*p;
	int			i;
	glRect_t	*theRect;

	p = s->polys;
	GL_SelectTexture(GL_TEXTURE0_ARB);
	GL_Bind (s->texinfo->texture->gl_texturenum);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	GL_EnableMultitexture();
	glEnable(GL_TEXTURE_2D);
	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 (s->texinfo->texture->transparent) {
		glAlphaFunc(GL_GEQUAL, 0.05f);
		glEnable(GL_ALPHA_TEST);
	}
	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)
	{
		qglMTexCoord2f (GL_TEXTURE0_ARB, v[3], v[4]);
		qglMTexCoord2f (GL_TEXTURE1_ARB, v[5], v[6]);
		glVertex3fv (v);
	}
	glEnd ();
	glDisable(GL_ALPHA_TEST);

	// 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);
	}
}

int RS_Animate(stage_t *stage)
{
	int i,o, rt;
	anim_stage_t *anim;

	rt = realtime * 1000;
	anim=stage->anim;
	if (rt < (stage->animtime+stage->animwait))
		return stage->anim_current;
	i = (int)(rt / stage->animwait) % stage->animcount;
	for (o=0;o<i;o++)
		anim=anim->next;
	stage->anim_current=anim->texnum;
	stage->animtime=rt;
	return anim->texnum;
}

void RS_DrawSurface (msurface_t *s)
{
	float		*v;
	glpoly_t	*p;
	int			i,o; rscript_t *rs; stage_t *stage;
	float		txm = 0, tym = 0;
	glRect_t	*theRect;
	float a;

	if (!s->texinfo->texture->rs) {
		RS_DrawUnscriptedSurface(s);
		return;
	}

	p = s->polys;
	rs = s->texinfo->texture->rs;
	stage=rs->stage;
	for (o=0;o<rs->stagecount;o++) {
		GL_SelectTexture(GL_TEXTURE0_ARB);
		if (stage->anim == NULL)
			GL_Bind(stage->texnum);
		else
			GL_Bind (RS_Animate(stage));
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		GL_EnableMultitexture();
		if (!stage->nolightmap) {
			glEnable(GL_TEXTURE_2D);
			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;
			}
		} else
			glDisable(GL_TEXTURE_2D);
		GL_SelectTexture(GL_TEXTURE0_ARB);

		if (stage->alpha.max > 0) {
			if (stage->alpha.type == 0)
				glColor4f(1,1,1,stage->alpha.min);
			else if (stage->alpha.type == 1) {
				a=Q_SINE(realtime * stage->alpha.speed);
				if (a > stage->alpha.max) a=stage->alpha.max;
				if (a < stage->alpha.min) a=stage->alpha.min;
				glColor4f(1,1,1,a);
			} else if (stage->alpha.type == 2) {
				a=Q_COSINE(realtime * stage->alpha.speed);
				if (a > stage->alpha.max) a=stage->alpha.max;
				if (a < stage->alpha.min) a=stage->alpha.min;
				glColor4f(1,1,1,a);
			}
		}
		if (stage->blendsrc > 0) {
			glEnable(GL_BLEND);
			glBlendFunc(stage->blendsrc,stage->blenddst);
		}
		if (stage->alphafunc) {
			glAlphaFunc(GL_GEQUAL, 0.05f);
			glEnable(GL_ALPHA_TEST);
		}

		if (stage->spheremap) {
			glTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
			glTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
			glEnable(GL_TEXTURE_GEN_S);
			glEnable(GL_TEXTURE_GEN_T);
		}

		if ((stage->scroll.speedX != 0) || (stage->scroll.speedY != 0)) {
			if (stage->scroll.typeX == 0)
				txm=stage->scroll.speedX*realtime;
			else if (stage->scroll.typeX == 1)
				txm=Q_SINE(realtime)*stage->scroll.speedX;
			else if (stage->scroll.typeX == 2)
				txm=Q_COSINE(realtime)*stage->scroll.speedX;

			if (stage->scroll.typeY == 0)
				tym=stage->scroll.speedY*realtime;
			else if (stage->scroll.typeY == 1)
				tym=Q_SINE(realtime)*stage->scroll.speedY;
			else if (stage->scroll.typeY == 2)
				tym=Q_COSINE(realtime)*stage->scroll.speedY;
		}
		if (stage->cullback=false)
			glDisable(GL_CULL_FACE);

		glBegin(GL_POLYGON);
		v = p->verts[0];
		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
		{
			qglMTexCoord2f (GL_TEXTURE0_ARB, v[3]+txm, v[4]+tym);
			qglMTexCoord2f (GL_TEXTURE1_ARB, v[5], v[6]);
			glVertex3fv (v);
		}
		glEnd ();

		GL_SelectTexture(GL_TEXTURE0_ARB);

		glColor3f(1,1,1);
		glDisable(GL_BLEND);
		glDisable(GL_ALPHA_TEST);
		glDisable(GL_TEXTURE_GEN_S);
		glDisable(GL_TEXTURE_GEN_T);
		glEnable(GL_CULL_FACE);

		GL_EnableMultitexture();
		stage=stage->next;
	}
	
	// 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);
	}
}

void RS_Draw_Pic (int x, int y, qpic_t *pic)
{
	stage_t *stage; rscript_t *rs;
	float a; int o; float txm, tym;
	glpic_t	*gl;

	if (!pic->rs) {
		Draw_Pic(x,y,pic);
		return;
	}
	rs = pic->rs;
	stage=rs->stage;
	gl = (glpic_t *)pic->data;
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	for (o=0;o<rs->stagecount;o++) {
		if (stage->anim == NULL)
			GL_Bind(stage->texnum);
		else
			GL_Bind (RS_Animate(stage));
		if (stage->alpha.max > 0) {
			if (stage->alpha.type == 0)
				glColor4f(1,1,1,stage->alpha.min);
			else if (stage->alpha.type == 1) {
				a=Q_SINE(realtime * stage->alpha.speed);
				if (a > stage->alpha.max) a=stage->alpha.max;
				if (a < stage->alpha.min) a=stage->alpha.min;
				glColor4f(1,1,1,a);
			} else if (stage->alpha.type == 2) {
				a=Q_COSINE(realtime * stage->alpha.speed);
				if (a > stage->alpha.max) a=stage->alpha.max;
				if (a < stage->alpha.min) a=stage->alpha.min;
				glColor4f(1,1,1,a);
			}
		}
		if (stage->blendsrc > 0) {
			glEnable(GL_BLEND);
			glBlendFunc(stage->blendsrc,stage->blenddst);
		}
		if (stage->alphafunc) {
			glAlphaFunc(GL_GEQUAL, 0.05f);
			glEnable(GL_ALPHA_TEST);
		} else
			glDisable(GL_ALPHA_TEST);

		if (stage->spheremap) {
			glTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
			glTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
			glEnable(GL_TEXTURE_GEN_S);
			glEnable(GL_TEXTURE_GEN_T);
		}
		if ((stage->scroll.speedX != 0) || (stage->scroll.speedY != 0)) {
			if (stage->scroll.typeX == 0)
				txm=stage->scroll.speedX*realtime;
			else if (stage->scroll.typeX == 1)
				txm=Q_SINE(realtime)*stage->scroll.speedX;
			else if (stage->scroll.typeX == 2)
				txm=Q_COSINE(realtime)*stage->scroll.speedX;

			if (stage->scroll.typeY == 0)
				tym=stage->scroll.speedY*realtime;
			else if (stage->scroll.typeY == 1)
				tym=Q_SINE(realtime)*stage->scroll.speedY;
			else if (stage->scroll.typeY == 2)
				tym=Q_COSINE(realtime)*stage->scroll.speedY;
		}
		if (stage->cullback=false)
			glDisable(GL_CULL_FACE);

		glBegin (GL_QUADS);
		glTexCoord2f (gl->sl+txm, gl->tl+tym);
		glVertex2f (x, y);
		glTexCoord2f (gl->sh+txm, gl->tl+tym);
		glVertex2f (x+pic->width, y);
		glTexCoord2f (gl->sh+txm, gl->th+tym);
		glVertex2f (x+pic->width, y+pic->height);
		glTexCoord2f (gl->sl+txm, gl->th+tym);
		glVertex2f (x, y+pic->height);
		glEnd ();

		glColor3f(1,1,1);
		glDisable(GL_BLEND);
		glDisable(GL_TEXTURE_GEN_S);
		glDisable(GL_TEXTURE_GEN_T);
		glEnable(GL_CULL_FACE);
		glEnable(GL_ALPHA_TEST);
		stage=stage->next;
	}	
}