<commit_before>// DXGL
// Copyright (C) 2012 <NAME>

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

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "common.h"
#include "glRenderer.h"
#include "glDirect3DDevice.h"
#include <string>
using namespace std;
#include "shadergen.h"
#include "shaders.h"

GenShader genshaders[256];
static __int64 current_shader = 0;
static __int64 current_texid[8];
static int shadercount = 0;
static int genindex = 0;
static bool initialized = false;
static bool isbuiltin = true;
GLuint current_prog;
int current_genshader;

/* Bits in Shader ID:
Bits 0-1 - Shading mode:  00=flat 01=gouraud 11=phong 10=flat per-pixel VS/FS
Bit 2 - Alpha test enable  FS
Bits 3-5 - Alpha test function:  FS
000=never  001=less  010=equal  011=lessequal
100=greater  101=notequal  110=lessequal  111=always
Bits 6-7 - Table fog:  FS
00 = none  01=exp  10=exp2  11=linear
Bits 8-9 - Vertex fog: same as table  VS
Bit 10 - Range based fog  VS/FS
Bit 11 - Specular highlights  VS/FS
Bit 12 - Stippled alpha  FS
Bit 13 - Color key transparency  FS
Bit 14-17 - Z bias  FS
Bits 18-20 - Number of lights  VS/FS
Bit 21 - Camera relative specular highlights  VS/FS
Bit 22 - Alpha blended color key  FS
Bits 23-24 - Diffuse material source  VS
Bits 25-26 - Specular material source  VS
Bits 27-28 - Ambient material source  VS
Bits 29-30 - Emissive material source  VS
Bits 31-33 - Number of textures  VS/FS
Bit 35 - Use diffuse color  VS
Bit 36 - Use specular color  VS
Bit 37 - Enable normals  VS
Bits 38-45 - Light types  VS/FS
Bits 46-48 - Number of blending weights  VS
Bit 49 - Normalize normals  VS
Bit 50 - Use transformed vertices  VS
*/

/* Bits in Texture Stage ID:
Bits 0-4: Texture color operation  FS
Bits 5-10: Texture color argument 1  FS
Bits 11-16: Texture color argument 2  FS
Bits 17-21: Texture alpha operation  FS
Bits 22-27: Texture alpha argument 1  FS
Bits 28-33: Texture alpha argument 2  FS
Bits 34-36: Texture coordinate index  VS
Bits 37-38: Texture coordinate flags  VS
Bits 39-40: U Texture address  GL
Bits 41-42: V Texture address  GL
Bits 43-45: Texture magnification filter  GL/FS
Bits 46-47: Texture minification filter  GL/FS
Bits 48-49: Texture mip filter  GL/FS
Bit 50: Enable texture coordinate transform  VS
Bits 51-52: Number of texcoord dimensions  VS
Bit 53: Projected texcoord  VS
Bits in texcoord ID:
00=2dim  01=3dim 10=4dim 11=1dim
Bits 54-56: Texture coordinate index  VS
Bits 57-58: Texture coordinate flags  VS
Bits in flags:
00=passthru 01=cameraspacenormal
10=cameraspaceposition 11=cameraspacereflectionvector
Bit 59: Texture image enabled
*/

/**
  * Clears the array of shaders.
  */
void ZeroShaderArray()
{
	ZeroMemory(genshaders,256*sizeof(GenShader));
	current_shader = 0;
	isbuiltin = true;
}

/**
  * Deletes all shader programs in the array.
  */
void ClearShaders()
{
	for(int i = 0; i < shadercount; i++)
	{
		genshaders[i].id = 0;
		ZeroMemory(genshaders[i].texids,8*sizeof(__int64));
		if(genshaders[i].shader.prog) glDeleteProgram(genshaders[i].shader.prog);
		if(genshaders[i].shader.fs) glDeleteShader(genshaders[i].shader.fs);
		if(genshaders[i].shader.vs) glDeleteShader(genshaders[i].shader.vs);
		if(genshaders[i].shader.fsrc) delete genshaders[i].shader.fsrc;
		if(genshaders[i].shader.vsrc) delete genshaders[i].shader.vsrc;
		ZeroMemory(&genshaders[i].shader,sizeof(_GENSHADER));
	}
	current_genshader = -1;
	shadercount = 0;
	genindex = 0;
}

/**
  * Sets a shader by render state.  If the shader does not exist, generates it.
  * @param id
  *  64-bit value containing current render states
  * @param texstate
  *  Pointer to the texture stage state array, containing 8 64-bit state values
  * @param texcoords
  *  Pointer to number of texture coordinates in each texture stage
  * @param builtin
  *  If true, the id parameter is an index to a built-in shader for 2D blitting
  */
void SetShader(__int64 id, TEXTURESTAGE *texstate, int *texcoords, bool builtin)
{
	int shaderindex = -1;
	if(builtin)
	{
		if(isbuiltin && (shaders[id].prog == current_shader)) return;
		glUseProgram(shaders[id].prog);
		current_shader = shaders[id].prog;
		isbuiltin=true;
		current_genshader = -1;
	}
	else
	{
		if(!isbuiltin && (id == current_shader))
		{
			if(!memcmp(current_texid,texstate,8*sizeof(__int64))) return;
		}
		current_shader = id;
		isbuiltin=false;
		for(int i = 0; i < shadercount; i++)
		{
			if(genshaders[i].id == id)
			{
				if(!memcmp(genshaders[i].texids,texstate,8*sizeof(__int64)))
				{
					if(!memcmp(genshaders[i].texcoords,texcoords,8*sizeof(int)))
					{
						shaderindex = i;
						break;
					}
				}
			}
		}
		if(shaderindex == -1)
		{
			shadercount++;
			if(shadercount > 256) shadercount = 256;
			if(genshaders[genindex].shader.prog)
			{
				glUseProgram(0);
				glDeleteProgram(genshaders[genindex].shader.prog);
				glDeleteShader(genshaders[genindex].shader.vs);
				glDeleteShader(genshaders[genindex].shader.fs);
				delete genshaders[genindex].shader.vsrc;
				delete genshaders[genindex].shader.fsrc;
				ZeroMemory(&genshaders[genindex],sizeof(GenShader));
			}
			CreateShader(genindex,id,texstate,texcoords);
			shaderindex = genindex;
			genindex++;
			if(genindex >= 256) genindex = 0;
		}
		genshaders[shaderindex].id = id;
		memcpy(genshaders[shaderindex].texids,texstate,8*sizeof(__int64));
		memcpy(genshaders[shaderindex].texcoords,texcoords,8*sizeof(int));
		glUseProgram(genshaders[shaderindex].shader.prog);
		current_prog = genshaders[shaderindex].shader.prog;
		current_genshader = shaderindex;
	}
}

/**
  * Retrieves the GLSL program currently in use
  * @return
  *  Number of the current GLSL program, or if using built-in shaders, the ID of
  *  the shader
  */
GLuint GetProgram()
{
	if(isbuiltin) return current_shader & 0xFFFFFFFF;
	else return current_prog;
}


#define REVISION 1
static const char header[] =
	"//REV" STR(REVISION) "\n\
#version 110\n";
static const char vertexshader[] = "//Vertex Shader\n";
static const char fragshader[] = "//Fragment Shader\n";
static const char idheader[] = "//ID: 0x";
static const char linefeed[] = "\n";
static const char mainstart[] = "void main()\n{\n";
static const char mainend[] = "} ";
// Attributes
static const char attr_xyz[] = "attribute vec3 xyz;\n";
static const char attr_rhw[] = "attribute float rhw;\n";
static const char attr_nxyz[] = "attribute vec3 nxyz;\n";
static const char const_nxyz[] = "const vec3 nxyz = vec3(0,0,0);\n";
static const char attr_blend[] = "attribute float blendX;\n";
static const char attr_rgba[] = "attribute vec4 rgbaX;\n";
static const char attr_s[] = "attribute float sX;\n";
static const char conv_s[] = "vec4 strqX = vec4(sX,0,0,1);\n";
static const char attr_st[] = "attribute vec2 stX;\n";
static const char conv_st[] = "vec4 strqX = vec4(stX[0],stX[1],0,1);\n";
static const char attr_str[] = "attribute vec3 strX;\n";
static const char conv_str[] = "vec4 strqX = vec4(strX[0],strX[1],strX[2],1);\n";
static const char attr_strq[] = "attribute vec4 strqX;\n";
// Uniforms
static const char unif_matrices[] = "uniform mat4 world;\n\
uniform mat4 view;\n\
uniform mat4 projection;\n\
uniform mat3 normalmat;\n";
static const char unif_material[] = "struct Material\n\
{\n\
vec4 diffuse;\n\
vec4 ambient;\n\
vec4 specular;\n\
vec4 emissive;\n\
float power;\n\
};\n\
uniform Material material;\n";
static const char lightstruct[] = "struct Light\n\
{\n\
vec4 diffuse;\n\
vec4 specular;\n\
vec4 ambient;\n\
vec3 position;\n\
vec3 direction;\n\
float range;\n\
float falloff;\n\
float constant;\n\
float linear;\n\
float quad;\n\
float theta;\n\
float phi;\n\
};\n";
static const char unif_light[] = "uniform Light lightX;\n";
static const char unif_ambient[] = "uniform vec4 ambientcolor;\n";
static const char unif_tex[] = "uniform sampler2D texX;\n";
// Variables
static const char var_common[] = "vec4 diffuse;\n\
vec4 specular;\n\
vec4 ambient;\n\
vec3 N;";
static const char var_color[] = "vec3 color;\n\
float alpha;\n";
static const char var_xyzw[] = "vec4 xyzw;\n";
// Operations
static const char op_transform[] = "xyzw = vec4(xyz,1);\n\
vec4 pos = (projection*(view*world))*xyzw;\n\
gl_Position = vec4(pos.x,-pos.y,pos.z,pos.w);\n";
static const char op_normalize[] = "N = normalize(normalmat*nxyz);\n";
static const char op_normalpassthru[] = "N = normalmat*nxyz;\n";
static const char op_passthru[] = "gl_Position = xyzw;\n";
static const char op_resetcolor[] = "diffuse = specular = vec4(0.0);\n\
ambient = ambientcolor / 255.0;\n";
static const char op_dirlight[] = "DirLight(lightX);\n";
static const char op_dirlightnospecular[] = "DirLightNoSpecular(lightX);\n";
static const char op_spotlight[] = "SpotLight(lightX);\n";
static const char op_colorout[] = "gl_FrontColor = (material.diffuse * diffuse) + (material.ambient * ambient) + material.emissive;\n\
gl_FrontSecondaryColor = (material.specular * specular);\n";
static const char op_colorvert[] = "gl_FrontColor = rgba0.bgra;\n";
static const char op_color2vert[] = "gl_FrontSecondaryColor = rgba1.bgra;\n";
static const char op_colorfragout[] = "gl_FragColor = vec4(color,alpha);\n";
static const char op_colorfragin[] = "color = gl_Color.rgb;\n\
alpha = gl_Color.a;\n";
static const char op_texpassthru1[] = "gl_TexCoord[x] = ";
static const char op_texpassthru2s[] = "vec4(sX,0,0,1);\n";
static const char op_texpassthru2st[] = "vec4(stX,0,1);\n";
static const char op_texpassthru2str[] = "vec4(strX,1);\n";
static const char op_texpassthru2strq[] = "strqX;\n";
static const char op_texpassthru2null[] = "vec4(0,0,0,1);\n";

// Functions
static const char func_dirlight[] = "void DirLight(in Light light)\n\
{\n\
float NdotHV = 0.0;\n\
vec3 dir = normalize(-light.direction);\n\
ambient += light.ambient;\n\
float NdotL = max(dot(N,dir),0.0);\n\
diffuse += light.diffuse*NdotL;\n\
if(NdotL > 0.0)\n\
{\n\
vec3 eye = (-view[3].xyz / view[3].w);\n\
vec3 P = vec3((view*world)*xyzw);\n\
vec3 L = normalize(-light.direction.xyz - P);\n\
vec3 V = normalize(eye - P);\n\
NdotHV = max(dot(N,L+V),0.0);\n\
specular += (pow(NdotHV,float(material.power))*light.specular);\n\
ambient += light.ambient;\n\
}\n\
}\n";
static const char func_dirlightnospecular[] = "void DirLightNoSpecular(in Light light)\n\
{\n\
float NdotHV = 0.0;\n\
vec3 dir = normalize(-light.direction);\n\
ambient += light.ambient;\n\
float NdotL = max(dot(N,dir),0.0);\n\
diffuse += light.diffuse*NdotL;\n\
}\n";


/**
  * Creates an OpenGL shader program
  * @param index
  *  Index of the shader in the array to generate
  * @param id
  *  64-bit value containing current render states
  * @param texstate
  *  Pointer to the texture stage state array, containing 8 64-bit state values
  * @param texcoords
  *  Pointer to number of texture coordinates in each texture stage
  */
void CreateShader(int index, __int64 id, TEXTURESTAGE *texstate, int *texcoords)
{
	string tmp;
	int i;
	bool hasdir = false;
	bool hasspot = false;
	int count;
	int numlights;
	char idstring[22];
	_snprintf(idstring,21,"%0.16I64X\n",id);
	idstring[21] = 0;
	genshaders[index].shader.vsrc = new string;
	genshaders[index].shader.fsrc = new string;
	// Create vertex shader
	//Header
	string *vsrc = genshaders[index].shader.vsrc;
	vsrc->append(header);
	vsrc->append(vertexshader);
	vsrc->append(idheader);
	vsrc->append(idstring);
	// Attributes
	vsrc->append(attr_xyz);
	if((id>>50)&1) vsrc->append(attr_rhw);
	tmp = attr_rgba;
	if((id>>35)&1)
	{
		tmp.replace(19,1,"0");
		vsrc->append(tmp);
	}
	if((id>>36)&1)
	{
		tmp.replace(19,1,"1");
		vsrc->append(tmp);
	}
	if((id>>37)&1) vsrc->append(attr_nxyz);
	else vsrc->append(const_nxyz);
	count = (id>>46)&7;
	if(count)
	{
		tmp = attr_blend;
		for(i = 0; i < count; i++)
		{
			tmp.replace(21,1,_itoa(i,idstring,10));
			vsrc->append(tmp);
		}
	}
	for(i = 0; i < 8; i++)
	{
		switch(texcoords[i])
		{
		case -1:
			continue;
		case 3:
			tmp = attr_s;
			tmp.replace(16,1,_itoa(i,idstring,10));
			break;
		case 0:
			tmp = attr_st;
			tmp.replace(17,1,_itoa(i,idstring,10));
			break;
		case 1:
			tmp = attr_str;
			tmp.replace(18,1,_itoa(i,idstring,10));
			break;
		case 2:
			tmp = attr_strq;
			tmp.replace(19,1,_itoa(i,idstring,10));
			break;
		}
		vsrc->append(tmp);
	}

	// Uniforms
	vsrc->append(unif_matrices); // Material
	vsrc->append(unif_material);
	vsrc->append(unif_ambient);
	numlights = (id>>18)&7;
	if(numlights) // Lighting
	{
		vsrc->append(lightstruct);
		tmp = unif_light;
		for(i = 0; i < numlights; i++)
		{
			tmp.replace(19,1,_itoa(i,idstring,10));
			vsrc->append(tmp);
		}
	}
	
	// Variables
	vsrc->append(var_common);
	if(!((id>>50)&1)) vsrc->append(var_xyzw);

	// Functions
	if(numlights)
	{
		for(i = 0; i < numlights; i++)
		{
			if(id>>(38+i)&1) hasspot = true;
			else hasdir = true;
		}
	}
	bool hasspecular = (id >> 11) & 1;
	if(hasspot) FIXME("Add spot lights");
	if(hasdir)
	{
		if(hasspecular) vsrc->append(func_dirlight);
		else vsrc->append(func_dirlightnospecular);
	}
	//Main
	vsrc->append(mainstart);
	if((id>>50)&1) vsrc->append(op_passthru);
	else vsrc->append(op_transform);
	if((id>>49)&1) vsrc->append(op_normalize);
	else vsrc->append(op_normalpassthru);
	if(numlights)
	{
		vsrc->append(op_resetcolor);
		for(i = 0; i < numlights; i++)
		{
			if(id>>(38+i)&1)
			{
				tmp = op_spotlight;
				tmp.replace(15,1,_itoa(i,idstring,10));
				vsrc->append(tmp);
			}
			else
			{
				if(hasspecular)
				{
					tmp = op_dirlight;
					tmp.replace(14,1,_itoa(i,idstring,10));
					vsrc->append(tmp);
				}
				else
				{
					tmp = op_dirlightnospecular;
					tmp.replace(24,1,_itoa(i,idstring,10));
					vsrc->append(tmp);
				}
			}
		}
		vsrc->append(op_colorout);
	}
	else
	{
		if((id>>35)&1) vsrc->append(op_colorvert);
		if((id>>36)&1) vsrc->append(op_color2vert);
	}
	int texindex;
	for(i = 0; i < 8; i++)<commit_msg>Consolidate directional lighting to single function.  Begin writing spot light function.<commit_after>// DXGL
// Copyright (C) 2012 <NAME>

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

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "common.h"
#include "glRenderer.h"
#include "glDirect3DDevice.h"
#include <string>
using namespace std;
#include "shadergen.h"
#include "shaders.h"

GenShader genshaders[256];
static __int64 current_shader = 0;
static __int64 current_texid[8];
static int shadercount = 0;
static int genindex = 0;
static bool initialized = false;
static bool isbuiltin = true;
GLuint current_prog;
int current_genshader;

/* Bits in Shader ID:
Bits 0-1 - Shading mode:  00=flat 01=gouraud 11=phong 10=flat per-pixel VS/FS
Bit 2 - Alpha test enable  FS
Bits 3-5 - Alpha test function:  FS
000=never  001=less  010=equal  011=lessequal
100=greater  101=notequal  110=lessequal  111=always
Bits 6-7 - Table fog:  FS
00 = none  01=exp  10=exp2  11=linear
Bits 8-9 - Vertex fog: same as table  VS
Bit 10 - Range based fog  VS/FS
Bit 11 - Specular highlights  VS/FS
Bit 12 - Stippled alpha  FS
Bit 13 - Color key transparency  FS
Bit 14-17 - Z bias  FS
Bits 18-20 - Number of lights  VS/FS
Bit 21 - Camera relative specular highlights  VS/FS
Bit 22 - Alpha blended color key  FS
Bits 23-24 - Diffuse material source  VS
Bits 25-26 - Specular material source  VS
Bits 27-28 - Ambient material source  VS
Bits 29-30 - Emissive material source  VS
Bits 31-33 - Number of textures  VS/FS
Bit 35 - Use diffuse color  VS
Bit 36 - Use specular color  VS
Bit 37 - Enable normals  VS
Bits 38-45 - Light types  VS/FS
Bits 46-48 - Number of blending weights  VS
Bit 49 - Normalize normals  VS
Bit 50 - Use transformed vertices  VS
*/

/* Bits in Texture Stage ID:
Bits 0-4: Texture color operation  FS
Bits 5-10: Texture color argument 1  FS
Bits 11-16: Texture color argument 2  FS
Bits 17-21: Texture alpha operation  FS
Bits 22-27: Texture alpha argument 1  FS
Bits 28-33: Texture alpha argument 2  FS
Bits 34-36: Texture coordinate index  VS
Bits 37-38: Texture coordinate flags  VS
Bits 39-40: U Texture address  GL
Bits 41-42: V Texture address  GL
Bits 43-45: Texture magnification filter  GL/FS
Bits 46-47: Texture minification filter  GL/FS
Bits 48-49: Texture mip filter  GL/FS
Bit 50: Enable texture coordinate transform  VS
Bits 51-52: Number of texcoord dimensions  VS
Bit 53: Projected texcoord  VS
Bits in texcoord ID:
00=2dim  01=3dim 10=4dim 11=1dim
Bits 54-56: Texture coordinate index  VS
Bits 57-58: Texture coordinate flags  VS
Bits in flags:
00=passthru 01=cameraspacenormal
10=cameraspaceposition 11=cameraspacereflectionvector
Bit 59: Texture image enabled
*/

/**
  * Clears the array of shaders.
  */
void ZeroShaderArray()
{
	ZeroMemory(genshaders,256*sizeof(GenShader));
	current_shader = 0;
	isbuiltin = true;
}

/**
  * Deletes all shader programs in the array.
  */
void ClearShaders()
{
	for(int i = 0; i < shadercount; i++)
	{
		genshaders[i].id = 0;
		ZeroMemory(genshaders[i].texids,8*sizeof(__int64));
		if(genshaders[i].shader.prog) glDeleteProgram(genshaders[i].shader.prog);
		if(genshaders[i].shader.fs) glDeleteShader(genshaders[i].shader.fs);
		if(genshaders[i].shader.vs) glDeleteShader(genshaders[i].shader.vs);
		if(genshaders[i].shader.fsrc) delete genshaders[i].shader.fsrc;
		if(genshaders[i].shader.vsrc) delete genshaders[i].shader.vsrc;
		ZeroMemory(&genshaders[i].shader,sizeof(_GENSHADER));
	}
	current_genshader = -1;
	shadercount = 0;
	genindex = 0;
}

/**
  * Sets a shader by render state.  If the shader does not exist, generates it.
  * @param id
  *  64-bit value containing current render states
  * @param texstate
  *  Pointer to the texture stage state array, containing 8 64-bit state values
  * @param texcoords
  *  Pointer to number of texture coordinates in each texture stage
  * @param builtin
  *  If true, the id parameter is an index to a built-in shader for 2D blitting
  */
void SetShader(__int64 id, TEXTURESTAGE *texstate, int *texcoords, bool builtin)
{
	int shaderindex = -1;
	if(builtin)
	{
		if(isbuiltin && (shaders[id].prog == current_shader)) return;
		glUseProgram(shaders[id].prog);
		current_shader = shaders[id].prog;
		isbuiltin=true;
		current_genshader = -1;
	}
	else
	{
		if(!isbuiltin && (id == current_shader))
		{
			if(!memcmp(current_texid,texstate,8*sizeof(__int64))) return;
		}
		current_shader = id;
		isbuiltin=false;
		for(int i = 0; i < shadercount; i++)
		{
			if(genshaders[i].id == id)
			{
				if(!memcmp(genshaders[i].texids,texstate,8*sizeof(__int64)))
				{
					if(!memcmp(genshaders[i].texcoords,texcoords,8*sizeof(int)))
					{
						shaderindex = i;
						break;
					}
				}
			}
		}
		if(shaderindex == -1)
		{
			shadercount++;
			if(shadercount > 256) shadercount = 256;
			if(genshaders[genindex].shader.prog)
			{
				glUseProgram(0);
				glDeleteProgram(genshaders[genindex].shader.prog);
				glDeleteShader(genshaders[genindex].shader.vs);
				glDeleteShader(genshaders[genindex].shader.fs);
				delete genshaders[genindex].shader.vsrc;
				delete genshaders[genindex].shader.fsrc;
				ZeroMemory(&genshaders[genindex],sizeof(GenShader));
			}
			CreateShader(genindex,id,texstate,texcoords);
			shaderindex = genindex;
			genindex++;
			if(genindex >= 256) genindex = 0;
		}
		genshaders[shaderindex].id = id;
		memcpy(genshaders[shaderindex].texids,texstate,8*sizeof(__int64));
		memcpy(genshaders[shaderindex].texcoords,texcoords,8*sizeof(int));
		glUseProgram(genshaders[shaderindex].shader.prog);
		current_prog = genshaders[shaderindex].shader.prog;
		current_genshader = shaderindex;
	}
}

/**
  * Retrieves the GLSL program currently in use
  * @return
  *  Number of the current GLSL program, or if using built-in shaders, the ID of
  *  the shader
  */
GLuint GetProgram()
{
	if(isbuiltin) return current_shader & 0xFFFFFFFF;
	else return current_prog;
}


#define REVISION 1
static const char header[] =
	"//REV" STR(REVISION) "\n\
#version 110\n";
static const char vertexshader[] = "//Vertex Shader\n";
static const char fragshader[] = "//Fragment Shader\n";
static const char idheader[] = "//ID: 0x";
static const char linefeed[] = "\n";
static const char mainstart[] = "void main()\n{\n";
static const char mainend[] = "} ";
// Attributes
static const char attr_xyz[] = "attribute vec3 xyz;\n";
static const char attr_rhw[] = "attribute float rhw;\n";
static const char attr_nxyz[] = "attribute vec3 nxyz;\n";
static const char const_nxyz[] = "const vec3 nxyz = vec3(0,0,0);\n";
static const char attr_blend[] = "attribute float blendX;\n";
static const char attr_rgba[] = "attribute vec4 rgbaX;\n";
static const char attr_s[] = "attribute float sX;\n";
static const char conv_s[] = "vec4 strqX = vec4(sX,0,0,1);\n";
static const char attr_st[] = "attribute vec2 stX;\n";
static const char conv_st[] = "vec4 strqX = vec4(stX[0],stX[1],0,1);\n";
static const char attr_str[] = "attribute vec3 strX;\n";
static const char conv_str[] = "vec4 strqX = vec4(strX[0],strX[1],strX[2],1);\n";
static const char attr_strq[] = "attribute vec4 strqX;\n";
// Uniforms
static const char unif_matrices[] = "uniform mat4 world;\n\
uniform mat4 view;\n\
uniform mat4 projection;\n\
uniform mat3 normalmat;\n";
static const char unif_material[] = "struct Material\n\
{\n\
vec4 diffuse;\n\
vec4 ambient;\n\
vec4 specular;\n\
vec4 emissive;\n\
float power;\n\
};\n\
uniform Material material;\n";
static const char lightstruct[] = "struct Light\n\
{\n\
vec4 diffuse;\n\
vec4 specular;\n\
vec4 ambient;\n\
vec3 position;\n\
vec3 direction;\n\
float range;\n\
float falloff;\n\
float constant;\n\
float linear;\n\
float quad;\n\
float theta;\n\
float phi;\n\
};\n";
static const char unif_light[] = "uniform Light lightX;\n";
static const char unif_ambient[] = "uniform vec4 ambientcolor;\n";
static const char unif_tex[] = "uniform sampler2D texX;\n";
// Variables
static const char var_common[] = "vec4 diffuse;\n\
vec4 specular;\n\
vec4 ambient;\n\
vec3 N;";
static const char var_color[] = "vec3 color;\n\
float alpha;\n";
static const char var_xyzw[] = "vec4 xyzw;\n";
// Operations
static const char op_transform[] = "xyzw = vec4(xyz,1);\n\
vec4 pos = (projection*(view*world))*xyzw;\n\
gl_Position = vec4(pos.x,-pos.y,pos.z,pos.w);\n";
static const char op_normalize[] = "N = normalize(normalmat*nxyz);\n";
static const char op_normalpassthru[] = "N = normalmat*nxyz;\n";
static const char op_passthru[] = "gl_Position = xyzw;\n";
static const char op_resetcolor[] = "diffuse = specular = vec4(0.0);\n\
ambient = ambientcolor / 255.0;\n";
static const char op_dirlight[] = "DirLight(lightX);\n";
static const char op_spotlight[] = "SpotLight(lightX);\n";
static const char op_colorout[] = "gl_FrontColor = (material.diffuse * diffuse) + (material.ambient * ambient) + material.emissive;\n\
gl_FrontSecondaryColor = (material.specular * specular);\n";
static const char op_colorvert[] = "gl_FrontColor = rgba0.bgra;\n";
static const char op_color2vert[] = "gl_FrontSecondaryColor = rgba1.bgra;\n";
static const char op_colorfragout[] = "gl_FragColor = vec4(color,alpha);\n";
static const char op_colorfragin[] = "color = gl_Color.rgb;\n\
alpha = gl_Color.a;\n";
static const char op_texpassthru1[] = "gl_TexCoord[x] = ";
static const char op_texpassthru2s[] = "vec4(sX,0,0,1);\n";
static const char op_texpassthru2st[] = "vec4(stX,0,1);\n";
static const char op_texpassthru2str[] = "vec4(strX,1);\n";
static const char op_texpassthru2strq[] = "strqX;\n";
static const char op_texpassthru2null[] = "vec4(0,0,0,1);\n";

// Functions
static const char func_dirlight[] = "void DirLight(in Light light)\n\
{\n\
float NdotHV = 0.0;\n\
vec3 dir = normalize(-light.direction);\n\
ambient += light.ambient;\n\
float NdotL = max(dot(N,dir),0.0);\n\
diffuse += light.diffuse*NdotL;\n\
if((NdotL > 0.0) && (material.power != 0.0))\n\
{\n\
vec3 eye = (-view[3].xyz / view[3].w);\n\
vec3 P = vec3((view*world)*xyzw);\n\
vec3 L = normalize(-light.direction.xyz - P);\n\
vec3 V = normalize(eye - P);\n\
NdotHV = max(dot(N,L+V),0.0);\n\
specular += (pow(NdotHV,float(material.power))*light.specular);\n\
ambient += light.ambient;\n\
}\n\
}\n";
static const char func_spotlight[] = "void SpotLight(in Light light)\n\
{\n\
float NdotHV = 0.0\n\
vec3 V = normalize(eye - P);\n\
float d = length( light.position - V );\n\
vec3  L = normalize( light.position - V );\n\
float NdotL = max(dot(N,L),0.0);\n\
float NdotH = max(dot(N,H),0.0);\n\
diffuse += light.diffuse*NdotL;\n\
ambient += light.ambient;\n\
}\n";



/**
  * Creates an OpenGL shader program
  * @param index
  *  Index of the shader in the array to generate
  * @param id
  *  64-bit value containing current render states
  * @param texstate
  *  Pointer to the texture stage state array, containing 8 64-bit state values
  * @param texcoords
  *  Pointer to number of texture coordinates in each texture stage
  */
void CreateShader(int index, __int64 id, TEXTURESTAGE *texstate, int *texcoords)
{
	string tmp;
	int i;
	bool hasdir = false;
	bool hasspot = false;
	int count;
	int numlights;
	char idstring[22];
	_snprintf(idstring,21,"%0.16I64X\n",id);
	idstring[21] = 0;
	genshaders[index].shader.vsrc = new string;
	genshaders[index].shader.fsrc = new string;
	// Create vertex shader
	//Header
	string *vsrc = genshaders[index].shader.vsrc;
	vsrc->append(header);
	vsrc->append(vertexshader);
	vsrc->append(idheader);
	vsrc->append(idstring);
	// Attributes
	vsrc->append(attr_xyz);
	if((id>>50)&1) vsrc->append(attr_rhw);
	tmp = attr_rgba;
	if((id>>35)&1)
	{
		tmp.replace(19,1,"0");
		vsrc->append(tmp);
	}
	if((id>>36)&1)
	{
		tmp.replace(19,1,"1");
		vsrc->append(tmp);
	}
	if((id>>37)&1) vsrc->append(attr_nxyz);
	else vsrc->append(const_nxyz);
	count = (id>>46)&7;
	if(count)
	{
		tmp = attr_blend;
		for(i = 0; i < count; i++)
		{
			tmp.replace(21,1,_itoa(i,idstring,10));
			vsrc->append(tmp);
		}
	}
	for(i = 0; i < 8; i++)
	{
		switch(texcoords[i])
		{
		case -1:
			continue;
		case 3:
			tmp = attr_s;
			tmp.replace(16,1,_itoa(i,idstring,10));
			break;
		case 0:
			tmp = attr_st;
			tmp.replace(17,1,_itoa(i,idstring,10));
			break;
		case 1:
			tmp = attr_str;
			tmp.replace(18,1,_itoa(i,idstring,10));
			break;
		case 2:
			tmp = attr_strq;
			tmp.replace(19,1,_itoa(i,idstring,10));
			break;
		}
		vsrc->append(tmp);
	}

	// Uniforms
	vsrc->append(unif_matrices); // Material
	vsrc->append(unif_material);
	vsrc->append(unif_ambient);
	numlights = (id>>18)&7;
	if(numlights) // Lighting
	{
		vsrc->append(lightstruct);
		tmp = unif_light;
		for(i = 0; i < numlights; i++)
		{
			tmp.replace(19,1,_itoa(i,idstring,10));
			vsrc->append(tmp);
		}
	}
	
	// Variables
	vsrc->append(var_common);
	if(!((id>>50)&1)) vsrc->append(var_xyzw);

	// Functions
	if(numlights)
	{
		for(i = 0; i < numlights; i++)
		{
			if(id>>(38+i)&1) hasspot = true;
			else hasdir = true;
		}
	}
	bool hasspecular = (id >> 11) & 1;
	if(hasspot) FIXME("Add spot lights");
	if(hasdir) vsrc->append(func_dirlight);
	//Main
	vsrc->append(mainstart);
	if((id>>50)&1) vsrc->append(op_passthru);
	else vsrc->append(op_transform);
	if((id>>49)&1) vsrc->append(op_normalize);
	else vsrc->append(op_normalpassthru);
	if(numlights)
	{
		vsrc->append(op_resetcolor);
		for(i = 0; i < numlights; i++)
		{
			if(id>>(38+i)&1)
			{
				tmp = op_spotlight;
				tmp.replace(15,1,_itoa(i,idstring,10));
				vsrc->append(tmp);
			}
			else
			{
				tmp = op_dirlight;
				tmp.replace(14,1,_itoa(i,idstring,10));
				vsrc->append(tmp);
			}
		}
		vsrc->append(op_colorout);
	}
	else
	{
		if((id>>35)&1) vsrc->append(op_colorvert);
		if((id>>36)&1) vsrc->append(op_color2vert);
	}
	int texindex;
	for(i = 0; i < 8; i++)
{'fraction_non_alphanumeric': 0.14496938491511271, 'fraction_numerical': 0.03569440578903423, 'mean_word_length': 4.129371877230549, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3350063', 'n_tokens_mistral': 11891, 'n_tokens_neox': 10707, 'n_words': 2821}