Index: Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h
===================================================================
--- Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h	(revision 6916)
+++ Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h	(working copy)
@@ -123,6 +123,10 @@
 extern CGprofile g_cgvProf, g_cgfProf;
 #endif
 
+// Uncomment to use GLSL instead of CG
+// Experimental, doesn't work, and still requires CG for fragment shader
+#define USE_GLSL 1
+
 // XXX: Dual-source blending in OpenGL does not work correctly yet. To make it
 // work, we may need to use glBindFragDataLocation. To use that, we need to
 // use GLSL shaders across the whole pipeline. Yikes!
Index: Source/Plugins/Plugin_VideoOGL/Src/main.cpp
===================================================================
--- Source/Plugins/Plugin_VideoOGL/Src/main.cpp	(revision 6916)
+++ Source/Plugins/Plugin_VideoOGL/Src/main.cpp	(working copy)
@@ -95,6 +95,12 @@
 
 #include "VideoState.h"
 
+#ifdef USE_GLSL
+	#define PLUGIN_NAME "Dolphin OpenGL GLSL"
+#else
+	#define PLUGIN_NAME "Dolphin OpenGL"
+#endif
+
 // Logging
 int GLScissorX, GLScissorY, GLScissorW, GLScissorH;
 
@@ -173,12 +179,13 @@
 {
 	_PluginInfo->Version = 0x0100;
 	_PluginInfo->Type = PLUGIN_TYPE_VIDEO;
+
 #ifdef DEBUGFAST
-	sprintf(_PluginInfo->Name, "Dolphin OpenGL (DebugFast)");
+	sprintf(_PluginInfo->Name, PLUGIN_NAME " (DebugFast)");
 #elif defined _DEBUG
-	sprintf(_PluginInfo->Name, "Dolphin OpenGL (Debug)");
+	sprintf(_PluginInfo->Name, PLUGIN_NAME " (Debug)");
 #else
-	sprintf(_PluginInfo->Name, _trans("Dolphin OpenGL"));
+	sprintf(_PluginInfo->Name, _trans(PLUGIN_NAME));
 #endif
 }
 
@@ -281,7 +288,7 @@
 	// Now the window handle is written
 	_pVideoInitialize->pWindowHandle = g_VideoInitialize.pWindowHandle;
 
-	OSD::AddMessage("Dolphin OpenGL Video Plugin.", 5000);
+	OSD::AddMessage(PLUGIN_NAME " Video Plugin.", 5000);
 	s_PluginInitialized = true;
 }
 
Index: Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp
===================================================================
--- Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp	(revision 6916)
+++ Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp	(working copy)
@@ -38,6 +38,7 @@
 VertexShaderCache::VSCache VertexShaderCache::vshaders;
 bool VertexShaderCache::s_displayCompileAlert;
 GLuint VertexShaderCache::CurrentShader;
+GLuint VertexShaderCache::program = 0;
 bool VertexShaderCache::ShaderEnabled;
 
 static VERTEXSHADER *pShaderLast = NULL;
@@ -53,6 +54,27 @@
 	glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
 }
 
+void SetVSConstant4fvByName(const char * name, const float *f)
+{
+	GLint varLocation = glGetUniformLocation(VertexShaderCache::program, name);
+	if (varLocation > -1)
+		glUniform4fv(varLocation, 1, f);
+}
+
+void SetVSConstant3fvByName(const char * name, const float * f)
+{
+	float buf[4];
+	buf[0] = *f++;
+	buf[1] = *f++;
+	buf[2] = *f++;
+	buf[3] = 0.0f;
+
+	GLint varLocation = glGetUniformLocation(VertexShaderCache::program, name);
+	if (varLocation > -1)
+		glUniform4fv(varLocation, 1, buf);
+}
+
+
 void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
 {
     if(GLEW_EXT_gpu_program_parameters)
@@ -97,6 +119,8 @@
 
 void VertexShaderCache::Init()
 {
+	program = glCreateProgram();
+	
 	glEnable(GL_VERTEX_PROGRAM_ARB);
 	ShaderEnabled = true;
 	CurrentShader = 0;
@@ -104,7 +128,7 @@
 
 	s_displayCompileAlert = true;
 
-	glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);		
+	glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
 	if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096;
 #if CG_VERSION_NUM == 2100
 	if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
@@ -152,7 +176,18 @@
 	VSCacheEntry& entry = vshaders[uid];
 	entry.frameCount = frameCount;
 	pShaderLast = &entry.shader;
-	const char *code = GenerateVertexShaderCode(components, API_OPENGL);
+	
+	const char * code;
+#ifdef USE_GLSL
+		code = GenerateVertexShaderCode(components, API_OPENGL_GLSL);
+#else
+		code = GenerateVertexShaderCode(components, API_OPENGL);
+#endif
+	
+/*	code = GenerateVertexShaderCode(components, API_OPENGL);
+//	printf("%s\n----------\n", code);
+	code = GenerateVertexShaderCode(components, API_OPENGL_GLSL);
+	printf("%s\n\n", code); */
 
 #if defined(_DEBUG) || defined(DEBUGFAST)
 	if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
@@ -164,7 +199,16 @@
 	}
 #endif
 
-	if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) {
+	bool ret = false;
+	if (code) {
+#ifdef USE_GLSL
+			ret = VertexShaderCache::CompileVertexShaderGLSL(entry.shader, code);
+#else
+			ret = VertexShaderCache::CompileVertexShader(entry.shader, code);
+#endif
+	}
+
+	if (!ret) {
 		ERROR_LOG(VIDEO, "failed to create vertex shader");
 		GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
 		return NULL;
@@ -236,11 +280,132 @@
 	return true;
 }
 
+static GLenum checkForGLError(const char * situation)
+{
+	GLenum error = GL_REPORT_ERROR();
+	if (error != GL_NO_ERROR)
+		fprintf(stderr, "Error: %d -- %s\n", error, situation);
+	return error;
+}
+
+static void printProgramInfoLog(GLuint obj)
+{
+	int infologLength = 0;
+	int charsWritten  = 0;
+	char *infoLog;
+
+	glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
+
+	if (infologLength > 0)
+	{
+		infoLog = (char *)malloc(infologLength);
+		glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
+			fprintf(stderr, "%s", infoLog);
+		free(infoLog);
+	}
+}
+
+bool VertexShaderCache::CompileVertexShaderGLSL(VERTEXSHADER& vs, const char* pstrprogram)
+{
+	// Reset GL error before compiling shaders. Yeah, we need to investigate the causes of these.
+	checkForGLError("before VS!");
+			
+// Create program with options -- cgCreateProgram -- I think this compiles it
+// Make sure program is valid, and destroy it if it is not.
+// Ugly hack on compiled program (maybe not necessary for GLSL)
+// glGenProgramsARB
+// SetCurrentShader -- glBindProgramARB
+// glProgramStringARB
+// CGDestroyProgram and return true
+
+// Usually with CG:
+// cgCreateContext
+// ...
+// cgCreateProgram -- we start here in this function
+// cgGLLoadProgram
+// cgGLBindProgram
+// cgGLEnableProfile -- maybe this is done later
+// ...
+
+// Usually with GLSL:
+// glCreateProgram
+// glCreateShader *
+// glShaderSource
+// glCompileShader
+// glAttachShader
+// glLinkProgram
+// glUseProgram *
+// glDetachShader
+// glDeleteShader
+// glDeleteProgram
+
+// In CG, a program is a shader, in GLSL, a program is a container for shaders
+
+	GLuint shader = glCreateShader(GL_VERTEX_SHADER);
+	checkForGLError("creating vertex shader");
+	glShaderSource(shader, 1, &pstrprogram, NULL);
+	checkForGLError("submitting vertex shader source");
+	glCompileShader(shader);
+	checkForGLError("compiling vertex shader");
+
+	int x;
+	glGetShaderiv(shader, GL_COMPILE_STATUS, &x);
+	fprintf(stderr, "shader compile status: %d\n", x);
+
+	printProgramInfoLog(program);
+
+	if (CurrentShader) {
+		glDetachShader(program, CurrentShader);
+		glDeleteShader(CurrentShader);
+	}
+
+	glGetProgramiv(program, GL_ATTACHED_SHADERS, &x);
+	fprintf(stderr, "%d %d %d\n", glIsProgram(program), glIsShader(shader), x);
+	glGetProgramiv(program, GL_LINK_STATUS, &x);
+	fprintf(stderr, "program link status: %d\n", x);
+
+	glAttachShader(program, shader);
+	x = checkForGLError("attaching shader");
+
+	glLinkProgram(program);
+	checkForGLError("linking program");
+	glUseProgram(program);
+	checkForGLError("using program");
+
+	printProgramInfoLog(program);
+
+	glGetProgramiv(program, GL_LINK_STATUS, &x);
+	fprintf(stderr, "program link status: %d\n", x);
+
+/*	glDeleteShader(shader); -- make sure it still works OK before enabling this
+	glDeleteProgram(program); */
+
+/*	float f[4] = { 1.0f, 0.5f, 0.0f, 1.0f };
+	SetVSConstant4fvByName("myColor", f); */
+
+#if defined(_DEBUG) || defined(DEBUGFAST)
+	vs.strprog = pstrprogram;
+#endif
+
+	ShaderEnabled = true;
+	CurrentShader = shader;
+	vs.glprogid = shader;
+
+	if (shader)
+		return true;
+	else
+		return false;
+}
+
 void VertexShaderCache::DisableShader()
 {
 	if (ShaderEnabled)
 	{
+#ifdef USE_GLSL
+		glDetachShader(program, CurrentShader);
+#else
 		glDisable(GL_VERTEX_PROGRAM_ARB);
+#endif
 		ShaderEnabled = false;
 	}
 }
Index: Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h
===================================================================
--- Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h	(revision 6916)
+++ Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h	(working copy)
@@ -52,7 +52,7 @@
 
 	static VSCache vshaders;
 
-    static bool s_displayCompileAlert;
+	static bool s_displayCompileAlert;
 	
 	static GLuint CurrentShader;
 	static bool ShaderEnabled;
@@ -63,10 +63,12 @@
 
 	static VERTEXSHADER* SetShader(u32 components);
 	static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram);
-
+	static bool CompileVertexShaderGLSL(VERTEXSHADER& ps, const char* pstrprogram);
+	
 	static void SetCurrentShader(GLuint Shader);
 	static void DisableShader();
-	
+
+	static GLuint program;
 };
 
 #endif // _VERTEXSHADERCACHE_H_
Index: Source/Core/VideoCommon/Src/VertexShaderManager.cpp
===================================================================
--- Source/Core/VideoCommon/Src/VertexShaderManager.cpp	(revision 6916)
+++ Source/Core/VideoCommon/Src/VertexShaderManager.cpp	(working copy)
@@ -162,14 +162,24 @@
 
 // Syncs the shader constant buffers with xfmem
 // TODO: A cleaner way to control the matricies without making a mess in the parameters field
-void VertexShaderManager::SetConstants()
+void VertexShaderManager::SetConstants(bool glsl)
 {
+	int i, j;
+	char tmpstr[128];
+
 	if (nTransformMatricesChanged[0] >= 0)
 	{
 		int startn = nTransformMatricesChanged[0] / 4;
 		int endn = (nTransformMatricesChanged[1] + 3) / 4;
 		const float* pstart = (const float*)&xfmem[startn * 4];
-		SetMultiVSConstant4fv(C_TRANSFORMMATRICES + startn, endn - startn, pstart);
+		if (!glsl)
+			SetMultiVSConstant4fv(C_TRANSFORMMATRICES + startn, endn - startn, pstart);
+		else {
+			for (i = startn; i < endn; i++) {
+				sprintf(tmpstr, "ctrmtx.T[%d].t", i);
+				SetVSConstant4fvByName(tmpstr, pstart + i * 4);
+			}
+		}
 		nTransformMatricesChanged[0] = nTransformMatricesChanged[1] = -1;
 	}
 	if (nNormalMatricesChanged[0] >= 0)
@@ -177,7 +187,14 @@
 		int startn = nNormalMatricesChanged[0] / 3;
 		int endn = (nNormalMatricesChanged[1] + 2) / 3;
 		const float *pnstart = (const float*)&xfmem[XFMEM_NORMALMATRICES+3*startn];
-		SetMultiVSConstant3fv(C_NORMALMATRICES + startn, endn - startn, pnstart);
+		if (!glsl)
+			SetMultiVSConstant3fv(C_NORMALMATRICES + startn, endn - startn, pnstart);
+		else {
+			for (i = startn; i < endn; i++) {
+				sprintf(tmpstr, "cnmtx.T[%d].t", i);
+				SetVSConstant3fvByName(tmpstr, pnstart + i * 3);
+			}
+		}
 		nNormalMatricesChanged[0] = nNormalMatricesChanged[1] = -1;
 	}
 
@@ -186,7 +203,14 @@
 		int startn = nPostTransformMatricesChanged[0] / 4;
 		int endn = (nPostTransformMatricesChanged[1] + 3 ) / 4;
 		const float* pstart = (const float*)&xfmem[XFMEM_POSTMATRICES + startn * 4];
-		SetMultiVSConstant4fv(C_POSTTRANSFORMMATRICES + startn, endn - startn, pstart);
+		if (!glsl)
+			SetMultiVSConstant4fv(C_POSTTRANSFORMMATRICES + startn, endn - startn, pstart);
+		else {
+			for (i = startn; i < endn; i++) {
+				sprintf(tmpstr, "cpostmtx.T[%d].t", i);
+				SetVSConstant4fvByName(tmpstr, pstart + i * 4);
+			}
+		}
 	}
 
 	if (nLightsChanged[0] >= 0)
@@ -215,10 +239,16 @@
 					fabs(xfmemptr[2]) < 0.00001f)
 				{
 					// dist attenuation, make sure not equal to 0!!!
-					SetVSConstant4f(C_LIGHTS+5*i+j+1, 0.00001f, xfmemptr[1], xfmemptr[2], 0);
+					if (!glsl)
+						SetVSConstant4f(C_LIGHTS+5*i+j+1, 0.00001f, xfmemptr[1], xfmemptr[2], 0);
+					else
+						; // TODO: lights
 				}
 				else
-					SetVSConstant4fv(C_LIGHTS+5*i+j+1, xfmemptr);
+					if (!glsl)
+						SetVSConstant4fv(C_LIGHTS+5*i+j+1, xfmemptr);
+					else
+						; // TODO: lights
 			}
 		}
 
@@ -229,8 +259,14 @@
 	{
 		for (int i = 0; i < 4; ++i)
 			if (nMaterialsChanged & (1 << i))
-				SetVSConstant4fv(C_MATERIALS + i, &s_fMaterials[4 * i]);
-
+			{
+				if (!glsl)
+					SetVSConstant4fv(C_MATERIALS + i, &s_fMaterials[4 * i]);
+				else {
+					sprintf(tmpstr, I_MATERIALS".C%d", i);
+					SetVSConstant4fvByName(tmpstr, s_fMaterials + i * 4);
+				}
+			}
 		nMaterialsChanged = 0;
 	}
 
@@ -241,8 +277,18 @@
 		const float *pos = (const float *)xfmem + MatrixIndexA.PosNormalMtxIdx * 4;
 		const float *norm = (const float *)xfmem + XFMEM_NORMALMATRICES + 3 * (MatrixIndexA.PosNormalMtxIdx & 31);
 
-		SetMultiVSConstant4fv(C_POSNORMALMATRIX, 3, pos);
-		SetMultiVSConstant3fv(C_POSNORMALMATRIX + 3, 3, norm);
+		if (!glsl) {
+			SetMultiVSConstant4fv(C_POSNORMALMATRIX, 3, pos);
+			SetMultiVSConstant3fv(C_POSNORMALMATRIX + 3, 3, norm);
+		}
+		else {
+			for (i = 0; i < 3; i++) {
+				sprintf(tmpstr, I_POSNORMALMATRIX".T%d", i);
+				SetVSConstant4fvByName(tmpstr, pos + i * 4);
+				sprintf(tmpstr, I_POSNORMALMATRIX".N%d", i);
+				SetVSConstant3fvByName(tmpstr, norm + i * 3);
+			}
+		}
 	}
 
 	if (bTexMatricesChanged[0])
@@ -256,7 +302,14 @@
 
 		for (int i = 0; i < 4; ++i)
 		{
-			SetMultiVSConstant4fv(C_TEXMATRICES + 3 * i, 3, fptrs[i]);
+			if (!glsl)
+				SetMultiVSConstant4fv(C_TEXMATRICES + 3 * i, 3, fptrs[i]);
+			else {
+				for (j = 0; j < 3; j++) {
+					sprintf(tmpstr, I_TEXMATRICES".T[%d].t", i * 3 + j);
+					SetVSConstant4fvByName(tmpstr, fptrs[i] + j * 4);
+				}
+			}
 		}
 	}
 
@@ -270,14 +323,27 @@
 
 		for (int i = 0; i < 4; ++i)
 		{
-			SetMultiVSConstant4fv(C_TEXMATRICES+3 * i + 12, 3, fptrs[i]);
+			if (!glsl)
+				SetMultiVSConstant4fv(C_TEXMATRICES+3 * i + 12, 3, fptrs[i]);
+			else {
+				for (j = 0; j < 3; j++) {
+					sprintf(tmpstr, I_TEXMATRICES".T[%d].t", i * 3 + j + 12);
+					SetVSConstant4fvByName(tmpstr, fptrs[i] + j * 4);
+				}
+			}
 		}
 	}
 
 	if (bViewportChanged)
 	{
 		bViewportChanged = false;
-		SetVSConstant4f(C_DEPTHPARAMS,xfregs.rawViewport[5]/ 16777216.0f,xfregs.rawViewport[2]/ 16777216.0f,0.0f,0.0f);
+		if (!glsl)
+			SetVSConstant4f(C_DEPTHPARAMS,xfregs.rawViewport[5]/ 16777216.0f,xfregs.rawViewport[2]/ 16777216.0f,0.0f,0.0f);
+		else {
+			float depth_params[4] = { xfregs.rawViewport[5] / 16777216.0f, xfregs.rawViewport[2] / 16777216.0f, 0.0f, 0.0f };
+			SetVSConstant4fvByName(I_DEPTHPARAMS, depth_params);
+		}
+
 		// This is so implementation-dependent that we can't have it here.
 		UpdateViewport();
 	}
@@ -400,11 +466,25 @@
 			Matrix44::Set(mtxB, g_fProjectionMatrix);
 			Matrix44::Multiply(mtxB, viewMtx, mtxA); // mtxA = projection x view
 
-			SetMultiVSConstant4fv(C_PROJECTION, 4, &mtxA.data[0]);
+			if (!glsl)
+				SetMultiVSConstant4fv(C_PROJECTION, 4, &mtxA.data[0]);
+			else {
+				for (i = 0; i < 4; i++) {
+					sprintf(tmpstr, "cproj.T%d", i);
+					SetVSConstant4fvByName(tmpstr, &mtxA.data[i * 4]);
+				}
+			}
 		}
 		else
 		{
-			SetMultiVSConstant4fv(C_PROJECTION, 4, &g_fProjectionMatrix[0]);
+			if (!glsl)
+				SetMultiVSConstant4fv(C_PROJECTION, 4, &g_fProjectionMatrix[0]);
+			else {
+				for (i = 0; i < 4; i++) {
+					sprintf(tmpstr, "cproj.T%d", i);
+					SetVSConstant4fvByName(tmpstr, &g_fProjectionMatrix[i * 4]);
+				}
+			}
 		}
 	}
 }
Index: Source/Core/VideoCommon/Src/VertexShaderGen.cpp
===================================================================
--- Source/Core/VideoCommon/Src/VertexShaderGen.cpp	(revision 6916)
+++ Source/Core/VideoCommon/Src/VertexShaderGen.cpp	(working copy)
@@ -86,6 +86,9 @@
 	_assert_(bpmem.genMode.numtexgens == xfregs.numTexGens);
 	_assert_(bpmem.genMode.numcolchans == xfregs.nNumChans);
 	
+	if (api_type == API_OPENGL_GLSL)
+		return GenerateVertexShaderCodeGLSL(components, text);
+
 	bool is_d3d = (api_type == API_D3D9 || api_type == API_D3D11);
 	u32 lightMask = 0;
 	if (xfregs.nNumChans > 0)
Index: Source/Core/VideoCommon/Src/VertexShaderGen.h
===================================================================
--- Source/Core/VideoCommon/Src/VertexShaderGen.h	(revision 6916)
+++ Source/Core/VideoCommon/Src/VertexShaderGen.h	(working copy)
@@ -104,6 +104,7 @@
 
 // components is included in the uid.
 const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type);
+const char *GenerateVertexShaderCodeGLSL(u32 components, char * text);
 void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components);
 
 extern VERTEXSHADERUID  last_vertex_shader_uid;
Index: Source/Core/VideoCommon/Src/VertexShaderGenGLSL.cpp
===================================================================
--- Source/Core/VideoCommon/Src/VertexShaderGenGLSL.cpp	(revision 0)
+++ Source/Core/VideoCommon/Src/VertexShaderGenGLSL.cpp	(revision 0)
@@ -0,0 +1,529 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include <math.h>
+#include <locale.h>
+
+#include "Profiler.h"
+#include "NativeVertexFormat.h"
+
+#include "BPMemory.h"
+#include "CPMemory.h"
+#include "VertexShaderGen.h"
+#include "VideoConfig.h"
+
+#define WRITE p+=sprintf
+
+#include <ctime>
+
+const char *GenerateVertexShaderCodeGLSL(u32 components, char * text)
+{
+	u32 lightMask = 0;
+	if (xfregs.nNumChans > 0)
+		lightMask |= xfregs.colChans[0].color.GetFullLightMask() | xfregs.colChans[0].alpha.GetFullLightMask();
+	if (xfregs.nNumChans > 1)
+		lightMask |= xfregs.colChans[1].color.GetFullLightMask() | xfregs.colChans[1].alpha.GetFullLightMask();
+
+	char *p = text;
+
+/*	time_t mytime = time(NULL);
+
+	WRITE(p, "uniform vec4 myColor;\n");
+	WRITE(p, "void main() {\n");
+	WRITE(p, "gl_FrontColor = vec4(0.0, 0.3, 0.0, 1.0);\n");
+//	WRITE(p, "gl_FrontSecondaryColor = vec4(1.0, 0.0, 0.0, 1.0);\n");
+	WRITE(p, "gl_FrontSecondaryColor = vec4(%d.0, %d.0, %d.0, 1.0);\n", (mytime % 3 == 0), (mytime % 3 == 1), (mytime % 3 == 2));
+	WRITE(p, "gl_BackColor = vec4(0.0, 0.0, 1.0, 1.0);\n");
+	WRITE(p, "gl_BackSecondaryColor = vec4(0.5, 0.0, 1.0, 1.0);\n");
+	WRITE(p, "gl_Position = ftransform();\n");
+	WRITE(p, "}\n");
+	setlocale(LC_NUMERIC, "");
+	return text; */
+
+
+	WRITE(p, "//Vertex Shader: comp:%x, \n", components);
+
+	WRITE(p, "struct s_"I_POSNORMALMATRIX" { vec4 T0, T1, T2; vec4 N0, N1, N2; };\n"
+		"struct FLT4 { vec4 t; };\n"
+		"struct s_"I_TEXMATRICES" { FLT4 T[24]; };\n"
+		"struct s_"I_TRANSFORMMATRICES" { FLT4 T[64]; };\n"
+		"struct s_"I_NORMALMATRICES" { FLT4 T[32]; };\n"
+		"struct s_"I_POSTTRANSFORMMATRICES" { FLT4 T[64]; };\n"
+		"struct Light { vec4 col; vec4 cosatt; vec4 distatt; vec4 pos; vec4 dir; };\n"
+		"struct s_"I_LIGHTS" { Light lights[8]; };\n"
+		"struct s_"I_MATERIALS" { vec4 C0, C1, C2, C3; };\n"
+		"struct s_"I_PROJECTION" { vec4 T0, T1, T2, T3; };\n"
+		);
+
+/*	WRITE(p, "struct VS_OUTPUT {\n");
+	WRITE(p, "  float4 pos : POSITION;\n");
+	WRITE(p, "  float4 colors_0 : COLOR0;\n");
+	WRITE(p, "  float4 colors_1 : COLOR1;\n");
+
+	if (xfregs.numTexGens < 7) {
+		for (int i = 0; i < xfregs.numTexGens; ++i)
+			WRITE(p, "  float3 tex%d : TEXCOORD%d;\n", i, i);
+		WRITE(p, "  float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGens);
+		if(g_ActiveConfig.bEnablePixelLigting)
+			WRITE(p, "  float4 Normal : TEXCOORD%d;\n", xfregs.numTexGens + 1);
+	} else {
+		// clip position is in w of first 4 texcoords
+		if(g_ActiveConfig.bEnablePixelLigting)
+		{
+			for (int i = 0; i < 8; ++i)
+				WRITE(p, "  float4 tex%d : TEXCOORD%d;\n", i, i);
+		}
+		else
+		{
+			for (int i = 0; i < xfregs.numTexGens; ++i)
+				WRITE(p, "  float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i);
+		}
+	}	
+	WRITE(p, "};\n"); */
+
+	// uniforms
+
+	WRITE(p, "uniform s_"I_TRANSFORMMATRICES" "I_TRANSFORMMATRICES";\n");
+	WRITE(p, "uniform s_"I_TEXMATRICES" "I_TEXMATRICES";\n"); // also using tex matrices
+	WRITE(p, "uniform s_"I_NORMALMATRICES" "I_NORMALMATRICES";\n");
+	WRITE(p, "uniform s_"I_POSNORMALMATRIX" "I_POSNORMALMATRIX";\n");
+	WRITE(p, "uniform s_"I_POSTTRANSFORMMATRICES" "I_POSTTRANSFORMMATRICES";\n");
+	WRITE(p, "uniform s_"I_LIGHTS" "I_LIGHTS";\n");
+	WRITE(p, "uniform s_"I_MATERIALS" "I_MATERIALS";\n");
+	WRITE(p, "uniform s_"I_PROJECTION" "I_PROJECTION";\n");
+	WRITE(p, "uniform vec4 "I_DEPTHPARAMS";\n");
+
+//	WRITE(p, "uniform vec4 myColor;\n");
+
+	if (components & VB_HAS_NRM1)
+		WRITE(p, "attribute vec3 rawnorm1;\n");
+	if (components & VB_HAS_NRM2)
+		WRITE(p, "attribute vec3 rawnorm2;\n");
+	if (components & VB_HAS_POSMTXIDX)
+		WRITE(p, "attribute float fposmtx;\n");
+
+	WRITE(p, "void main() {\n");
+	
+	// inputs
+/*	if (components & VB_HAS_NRM0)
+		WRITE(p, "  float3 rawnorm0 : NORMAL0,\n");
+	if (components & VB_HAS_NRM1) {
+			WRITE(p, "  float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB);
+	}
+	if (components & VB_HAS_NRM2) {
+			WRITE(p, "  float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB);
+	}
+	if (components & VB_HAS_COL0)
+		WRITE(p, "  float4 color0 : COLOR0,\n");
+	if (components & VB_HAS_COL1)
+		WRITE(p, "  float4 color1 : COLOR1,\n");
+	for (int i = 0; i < 8; ++i) {
+		u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<<i));
+		if ((components & (VB_HAS_UV0<<i)) || hastexmtx)
+			WRITE(p, "  float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i);
+	}
+	if (components & VB_HAS_POSMTXIDX) {
+			WRITE(p, "  float fposmtx : ATTR%d,\n", SHADER_POSMTX_ATTRIB);
+	}
+	WRITE(p, "  float4 rawpos : POSITION) {\n");
+	WRITE(p, "VS_OUTPUT o;\n"); */
+	// transforms
+	/*
+	CG output variables:
+	pos, colors_0, colors_1, tex*, clipPos, Normal
+
+	CG input variables:
+	rawnorm0, rawnorm1 (attr), rawnrom2 (attr), color0, color1, tex*, fposmtx (attr), rawpos
+	
+	GLSL output variables:
+	gl_Position, gl_FrontColor, gl_FrontSecondaryColor, gl_TexCoord[*], (the rest are gl_TexCoord[6,7]?)
+	
+	GLSL input variables:
+	gl_Normal, x, x, gl_Color, gl_SecondaryColor, gl_MultiTexCoord0 (etc), x, gl_Vertex
+
+	*/
+
+
+	if (components & VB_HAS_POSMTXIDX) {
+		WRITE(p, "int posmtx = int(fposmtx);\n");
+
+		WRITE(p, "vec4 pos = vec4(dot("I_TRANSFORMMATRICES".T[posmtx].t, gl_Vertex), dot("I_TRANSFORMMATRICES".T[posmtx+1].t, gl_Vertex), dot("I_TRANSFORMMATRICES".T[posmtx+2].t, gl_Vertex), 1);\n");
+
+		if (components & VB_HAS_NRMALL) {
+			WRITE(p, "int normidx = posmtx >= 32 ? (posmtx-32) : posmtx;\n");
+			WRITE(p, "vec3 N0 = "I_NORMALMATRICES".T[normidx].t.xyz, N1 = "I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = "I_NORMALMATRICES".T[normidx+2].t.xyz;\n");
+		}
+
+		if (components & VB_HAS_NRM0)
+			WRITE(p, "vec3 _norm0 = normalize(vec3(dot(N0, gl_Normal), dot(N1, gl_Normal), dot(N2, gl_Normal)));\n");
+		if (components & VB_HAS_NRM1)
+			WRITE(p, "vec3 _norm1 = vec3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n");
+		if (components & VB_HAS_NRM2)
+			WRITE(p, "vec3 _norm2 = vec3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n");
+// ***
+	}
+	else
+	{
+		WRITE(p, "vec4 pos = vec4(dot("I_POSNORMALMATRIX".T0, gl_Vertex), dot("I_POSNORMALMATRIX".T1, gl_Vertex), dot("I_POSNORMALMATRIX".T2, gl_Vertex), 1.0);\n");
+		if (components & VB_HAS_NRM0)
+			WRITE(p, "vec3 _norm0 = normalize(vec3(dot("I_POSNORMALMATRIX".N0.xyz, gl_Normal), dot("I_POSNORMALMATRIX".N1.xyz, gl_Normal), dot("I_POSNORMALMATRIX".N2.xyz, gl_Normal)));\n");
+		if (components & VB_HAS_NRM1)
+			WRITE(p, "vec3 _norm1 = vec3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n");
+		if (components & VB_HAS_NRM2)
+			WRITE(p, "vec3 _norm2 = vec3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n");
+// ***
+	}
+
+	if (!(components & VB_HAS_NRM0))
+		WRITE(p, "vec3 _norm0 = vec3(0.0, 0.0, 0.0);\n");
+
+	// Break 1
+
+	WRITE(p, "gl_Position = vec4(dot("I_PROJECTION".T0, pos), dot("I_PROJECTION".T1, pos), dot("I_PROJECTION".T2, pos), dot("I_PROJECTION".T3, pos));\n");
+
+	WRITE(p, "vec4 mat, lacc;\n"
+	"vec3 ldir, h;\n"
+	"float dist, dist2, attn;\n");
+
+	if(xfregs.nNumChans == 0)
+	{
+		if (components & VB_HAS_COL0)
+			WRITE(p, "gl_FrontColor = gl_Color;\n");
+		else
+			WRITE(p, "gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0);\n");
+	}
+
+// ***
+
+	// lights/colors
+	for (int j = 0; j < xfregs.nNumChans; j++)
+	{
+		const LitChannel& color = xfregs.colChans[j].color;
+		const LitChannel& alpha = xfregs.colChans[j].alpha;
+
+		WRITE(p, "{\n");
+		
+		if (color.matsource) {// from vertex
+			if (components & (VB_HAS_COL0 << j)) {
+				if (j == 0)
+					WRITE(p, "mat = gl_Color;\n");
+				else if (j == 1)
+					WRITE(p, "mat = gl_SecondaryColor;\n");
+			}
+			else if (components & VB_HAS_COL0)
+				WRITE(p, "mat = gl_Color;\n");
+			else
+				WRITE(p, "mat = vec4(1.0, 1.0, 1.0, 1.0);\n");
+		}
+		else // from color
+			WRITE(p, "mat = "I_MATERIALS".C%d;\n", j+2);
+
+		if (color.enablelighting) {
+			if (color.ambsource) { // from vertex
+				if (components & (VB_HAS_COL0<<j) ) {
+					if (j == 0)
+						WRITE(p, "lacc = gl_Color;\n");
+					else if (j == 1)
+						WRITE(p, "lacc = gl_SecondaryColor;\n");
+				}
+				else if (components & VB_HAS_COL0 )
+					WRITE(p, "lacc = gl_Color;\n");
+				else
+					WRITE(p, "lacc = vec4(0.0, 0.0, 0.0, 0.0);\n");
+			}
+			else // from color
+				WRITE(p, "lacc = "I_MATERIALS".C%d;\n", j);
+		}
+		else
+		{
+			WRITE(p, "lacc = vec4(1.0, 1.0, 1.0, 1.0);\n");
+		}
+
+		// check if alpha is different
+		if (alpha.matsource != color.matsource) {
+			if (alpha.matsource) {// from vertex
+				if (components & (VB_HAS_COL0<<j)) {
+					if (j == 0)
+						WRITE(p, "mat.w = gl_Color.w;\n");
+					else if (j == 1)
+						WRITE(p, "mat.w = gl_SecondaryColor.w;\n");
+				}
+				else if (components & VB_HAS_COL0)
+					WRITE(p, "mat.w = gl_Color.w;\n");
+				else WRITE(p, "mat.w = 1.0;\n");
+			}
+			else // from color
+				WRITE(p, "mat.w = "I_MATERIALS".C%d.w;\n", j+2);
+		}
+
+		if (alpha.enablelighting)
+		{
+			if (alpha.ambsource) {// from vertex
+				if (components & (VB_HAS_COL0<<j) ) {
+					if (j == 0)
+						WRITE(p, "lacc.w = gl_Color.w;\n");
+					else if (j == 1)
+						WRITE(p, "lacc.w = gl_SecondaryColor.w;\n");
+				}
+				else if (components & VB_HAS_COL0 )
+					WRITE(p, "lacc.w = gl_Color.w;\n");
+				else
+					WRITE(p, "lacc.w = 0.0;\n");
+			}
+			else // from color
+				WRITE(p, "lacc.w = "I_MATERIALS".C%d.w;\n", j);
+		}
+		else
+		{
+			WRITE(p, "lacc.w = 1.0;\n");
+		}	
+		
+// TODO: Finish lighting
+/*		if(color.enablelighting && alpha.enablelighting)
+		{
+			// both have lighting, test if they use the same lights
+			int mask = 0;
+			if(color.lightparams == alpha.lightparams)
+			{
+				mask = color.GetFullLightMask() & alpha.GetFullLightMask();
+				if(mask)
+				{
+					for (int i = 0; i < 8; ++i)
+					{
+						if (mask & (1<<i))
+							p = GenerateLightShader(p, i, color, "lacc", 3);
+					}
+				}
+			}
+
+			// no shared lights
+			for (int i = 0; i < 8; ++i)
+			{
+				if (!(mask&(1<<i)) && (color.GetFullLightMask() & (1<<i)))
+					p = GenerateLightShader(p, i, color, "lacc", 1);
+				if (!(mask&(1<<i)) && (alpha.GetFullLightMask() & (1<<i)))
+					p = GenerateLightShader(p, i, alpha, "lacc", 2);
+			}
+		}
+		else if (color.enablelighting || alpha.enablelighting)
+		{
+			// lights are disabled on one channel so process only the active ones
+			LitChannel workingchannel = color.enablelighting ? color : alpha;
+			int coloralpha = color.enablelighting ? 1 : 2;
+			for (int i = 0; i < 8; ++i)
+			{
+				if (workingchannel.GetFullLightMask() & (1<<i))
+					p = GenerateLightShader(p, i, workingchannel, "lacc", coloralpha);
+			}
+		} */
+		// Note that GLSL does not have a saturate function, so we use clamp instead
+		if (j == 0)
+			WRITE(p, "gl_FrontColor = mat * clamp(lacc, 0.0, 1.0);\n");
+		else if (j == 1)
+			WRITE(p, "gl_FrontSecondaryColor = mat * clamp(lacc, 0.0, 1.0);\n");
+		WRITE(p, "}\n");
+	}
+	if(xfregs.nNumChans < 2)
+	{
+		if (components & VB_HAS_COL1)
+			WRITE(p, "gl_FrontSecondaryColor = gl_SecondaryColor;\n");
+		else
+			WRITE(p, "gl_FrontSecondaryColor = gl_FrontColor;\n");
+	}
+	// special case if only pos and tex coord 0 and tex coord input is AB11
+	// donko - this has caused problems in some games. removed for now.
+	bool texGenSpecialCase = false;
+	/*bool texGenSpecialCase =
+		((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0
+		(g_VtxDesc.Tex0Coord != NOT_PRESENT) &&
+		(xfregs.texcoords[0].texmtxinfo.inputform == XF_TEXINPUT_AB11);
+		*/
+
+	// transform texcoords
+	WRITE(p, "vec4 coord = vec4(0.0, 0.0, 1.0, 1.0);\n");
+	for (int i = 0; i < xfregs.numTexGens; ++i) {
+		TexMtxInfo& texinfo = xfregs.texcoords[i].texmtxinfo;
+
+		WRITE(p, "{\n");
+		WRITE(p, "coord = vec4(0.0, 0.0, 1.0, 1.0);\n");
+		switch (texinfo.sourcerow) {
+		case XF_SRCGEOM_INROW:
+			_assert_( texinfo.inputform == XF_TEXINPUT_ABC1 );
+			WRITE(p, "coord = gl_Vertex;\n"); // pos.w is 1
+			break;
+		case XF_SRCNORMAL_INROW:
+			if (components & VB_HAS_NRM0) {
+				_assert_( texinfo.inputform == XF_TEXINPUT_ABC1 );
+				WRITE(p, "coord = vec4(gl_Normal.xyz, 1.0);\n");
+			}
+			break;
+		case XF_SRCCOLORS_INROW:
+			_assert_( texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1 );
+			break;
+		case XF_SRCBINORMAL_T_INROW:
+			if (components & VB_HAS_NRM1) {
+				_assert_( texinfo.inputform == XF_TEXINPUT_ABC1 );
+				WRITE(p, "coord = vec4(rawnorm1.xyz, 1.0);\n");
+			}
+			break;
+		case XF_SRCBINORMAL_B_INROW:
+			if (components & VB_HAS_NRM2) {
+				_assert_( texinfo.inputform == XF_TEXINPUT_ABC1 );
+				WRITE(p, "coord = vec4(rawnorm2.xyz, 1.0);\n");
+			}
+			break;
+		default:
+			_assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW);
+			if (components & (VB_HAS_UV0<<(texinfo.sourcerow - XF_SRCTEX0_INROW)) )
+				WRITE(p, "coord = vec4(gl_MultiTexCoord%d.x, gl_MultiTexCoord%d.y, 1.0, 1.0);\n", texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW);
+			break;
+		}
+
+		// first transformation
+		switch (texinfo.texgentype) {
+			case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map
+
+				if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) {
+					// transform the light dir into tangent space
+					WRITE(p, "ldir = normalize("I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift);
+					WRITE(p, "gl_TexCoord[%d].xyz = gl_TexCoord[%d].xyz + vec3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0);\n", i, texinfo.embosssourceshift);
+				}
+
+				else _assert_(0); // should have normals
+
+				break;
+			case XF_TEXGEN_COLOR_STRGBC0:
+				_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
+				WRITE(p, "gl_TexCoord[%d].xyz = vec3(gl_FrontColor.x, gl_FrontColor.y, 1);\n", i);
+				break;
+			case XF_TEXGEN_COLOR_STRGBC1:
+				_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
+				WRITE(p, "gl_TexCoord[%d].xyz = vec3(gl_FrontSecondaryColor.x, gl_FrontSecondaryColor.y, 1);\n", i);
+				break;
+			case XF_TEXGEN_REGULAR:
+			default:
+				if (components & (VB_HAS_TEXMTXIDX0<<i)) {
+					if (texinfo.projection == XF_TEXPROJ_STQ)
+						WRITE(p, "gl_TexCoord[%d].xyz = vec3(dot(coord, "I_TRANSFORMMATRICES".T[gl_MultiTexCoord%d.z].t), dot(coord, "I_TRANSFORMMATRICES".T[gl_MultiTexCoord%d.z+1].t), dot(coord, "I_TRANSFORMMATRICES".T[gl_MultiTexCoord%d.z+2].t));\n", i, i, i, i);
+					else {
+						WRITE(p, "gl_TexCoord[%d].xyz = vec3(dot(coord, "I_TRANSFORMMATRICES".T[gl_MultiTexCoord%d.z].t), dot(coord, "I_TRANSFORMMATRICES".T[gl_MultiTexCoord%d.z+1].t), 1);\n", i, i, i);
+					}
+				}
+				else {
+					if (texinfo.projection == XF_TEXPROJ_STQ)
+						WRITE(p, "gl_TexCoord[%d].xyz = vec3(dot(coord, "I_TEXMATRICES".T[%d].t), dot(coord, "I_TEXMATRICES".T[%d].t), dot(coord, "I_TEXMATRICES".T[%d].t));\n", i, 3*i, 3*i+1, 3*i+2);
+					else
+						WRITE(p, "gl_TexCoord[%d].xyz = vec3(dot(coord, "I_TEXMATRICES".T[%d].t), dot(coord, "I_TEXMATRICES".T[%d].t), 1);\n", i, 3*i, 3*i+1);
+				}
+				break;
+		}
+
+		if (xfregs.bEnableDualTexTransform && texinfo.texgentype == XF_TEXGEN_REGULAR) { // only works for regular tex gen types?
+			int postidx = xfregs.texcoords[i].postmtxinfo.index;
+			WRITE(p, "vec4 P0 = "I_POSTTRANSFORMMATRICES".T[%d].t;\n"
+				"vec4 P1 = "I_POSTTRANSFORMMATRICES".T[%d].t;\n"
+				"vec4 P2 = "I_POSTTRANSFORMMATRICES".T[%d].t;\n",
+				postidx&0x3f, (postidx+1)&0x3f, (postidx+2)&0x3f);
+
+			if (texGenSpecialCase) {
+				// no normalization
+				// q of input is 1
+				// q of output is unknown
+
+				// multiply by postmatrix
+				WRITE(p, "gl_TexCoord[%d].xyz = vec3(dot(P0.xy, gl_TexCoord[%d].xy) + P0.z + P0.w, dot(P1.xy, gl_TexCoord[%d].xy) + P1.z + P1.w, 0.0);\n", i, i, i);
+			}
+			else
+			{
+				if (xfregs.texcoords[i].postmtxinfo.normalize)
+					WRITE(p, "gl_TexCoord[%d].xyz = normalize(gl_TexCoord[%d].xyz);\n", i, i);
+
+				// multiply by postmatrix
+				WRITE(p, "gl_TexCoord[%d].xyz = vec3(dot(P0.xyz, gl_TexCoord[%d].xyz) + P0.w, dot(P1.xyz, gl_TexCoord[%d].xyz) + P1.w, dot(P2.xyz, gl_TexCoord[%d].xyz) + P2.w);\n", i, i, i, i);
+			}
+		}
+
+		WRITE(p, "}\n");
+	}
+
+	// clipPos/w needs to be done in pixel shader, not here
+	if (xfregs.numTexGens < 7) {
+		WRITE(p, "gl_TexCoord[%d] = vec4(pos.x,pos.y,gl_Position.z,gl_Position.w);\n", xfregs.numTexGens);
+	} else {
+		WRITE(p, "gl_TexCoord[0].w = pos.x;\n");
+		WRITE(p, "gl_TexCoord[1].w = pos.y;\n");
+		WRITE(p, "gl_TexCoord[2].w = gl_Position.z;\n");
+		WRITE(p, "gl_TexCoord[3].w = gl_Position.w;\n");
+	}
+
+	if(g_ActiveConfig.bEnablePixelLigting)
+	{
+		if (xfregs.numTexGens < 7) {
+			WRITE(p, "gl_TexCoord[%d] = vec4(_norm0.x,_norm0.y,_norm0.z,pos.z);\n", xfregs.numTexGens + 1);
+		} else {
+			WRITE(p, "gl_TexCoord[4].w = _norm0.x;\n");
+			WRITE(p, "gl_TexCoord[5].w = _norm0.y;\n");
+			WRITE(p, "gl_TexCoord[6].w = _norm0.z;\n");
+			if (xfregs.numTexGens < 8)
+				WRITE(p, "gl_TexCoord[7] = pos.xyzz;\n");
+			else
+				WRITE(p, "gl_TexCoord[7].w = pos.z;\n");
+		}
+		if (components & VB_HAS_COL0)
+			WRITE(p, "gl_FrontColor = gl_Color;\n");		
+
+		if (components & VB_HAS_COL1)
+			WRITE(p, "gl_FrontSecondaryColor = gl_SecondaryColor;\n");
+	}
+
+	//write the true depth value, if the game uses depth textures pixel shaders will override with the correct values
+	//if not early z culling will improve speed
+
+    // this results in a scale from -1..0 to -1..1 after perspective
+    // divide
+    WRITE(p, "gl_Position.z = gl_Position.w + gl_Position.z * 2.0;\n");
+
+    // Sonic Unleashed puts its final rendering at the near or
+    // far plane of the viewing frustrum(actually box, they use
+    // orthogonal projection for that), and we end up putting it
+    // just beyond, and the rendering gets clipped away. (The
+    // primitive gets dropped)
+    WRITE(p, "gl_Position.z = gl_Position.z * 1048575.0/1048576.0;\n");
+
+    // the next steps of the OGL pipeline are:
+    // (x_c,y_c,z_c,w_c) = o.pos  //switch to OGL spec terminology
+    // clipping to -w_c <= (x_c,y_c,z_c) <= w_c
+    // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide
+    // z_w = (f-n)/2*z_d + (n+f)/2
+    // z_w now contains the value to go to the 0..1 depth buffer
+    
+    //trying to get the correct semantic while not using glDepthRange
+    //seems to get rather complicated
+
+//	WRITE(p, "return o;\n}\n");
+
+//	WRITE(p, "gl_FrontColor = myColor;\n");
+//	WRITE(p, "gl_FrontColor = vec4(1.0, 0.0, 0.0, 1.0);\n");
+
+	WRITE(p, "}\n");
+
+
+	if (text[16384 - 1] != 0x7C)
+		PanicAlert("VertexShader generator - buffer too small, canary has been eaten!");
+	setlocale(LC_NUMERIC, ""); // restore locale
+	return text;
+}
Index: Source/Core/VideoCommon/Src/VideoCommon.h
===================================================================
--- Source/Core/VideoCommon/Src/VideoCommon.h	(revision 6916)
+++ Source/Core/VideoCommon/Src/VideoCommon.h	(working copy)
@@ -152,6 +152,7 @@
 	API_D3D9,
 	API_D3D11,
 	API_GLSL,
+	API_OPENGL_GLSL,
 	API_NONE
 } API_TYPE;
 
Index: Source/Core/VideoCommon/Src/VertexShaderManager.h
===================================================================
--- Source/Core/VideoCommon/Src/VertexShaderManager.h	(revision 6916)
+++ Source/Core/VideoCommon/Src/VertexShaderManager.h	(working copy)
@@ -50,7 +50,7 @@
 	static void Shutdown();
 
 	// constant management
-	static void SetConstants();
+	static void SetConstants(bool glsl = false);
 
 	static void SetViewport(float* _Viewport, int constantIndex = -1);
 	static void SetViewportChanged();
@@ -67,8 +67,9 @@
 
 void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
 void SetVSConstant4fv(unsigned int const_number, const float *f);
+void SetVSConstant4fvByName(const char * name, const float *f);
+void SetVSConstant3fvByName(const char * name, const float *f);
 void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f);
 void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
 
-
 #endif // _VERTEXSHADERMANAGER_H
Index: Source/Core/VideoCommon/Src/SConscript
===================================================================
--- Source/Core/VideoCommon/Src/SConscript	(revision 6916)
+++ Source/Core/VideoCommon/Src/SConscript	(working copy)
@@ -36,6 +36,7 @@
 	'VertexLoader_TextCoord.cpp',
 	'VertexManagerBase.cpp',
 	'VertexShaderGen.cpp',
+	'VertexShaderGenGLSL.cpp',
 	'VertexShaderManager.cpp',
 	'VideoConfig.cpp',
 	'VideoState.cpp',
Index: Source/Core/VideoCommon/CMakeLists.txt
===================================================================
--- Source/Core/VideoCommon/CMakeLists.txt	(revision 6916)
+++ Source/Core/VideoCommon/CMakeLists.txt	(working copy)
@@ -31,6 +31,7 @@
 			Src/VertexLoader_TextCoord.cpp
 			Src/VertexManagerBase.cpp
 			Src/VertexShaderGen.cpp
+			Src/VertexShaderGenGLSL.cpp
 			Src/VertexShaderManager.cpp
 			Src/VideoConfig.cpp
 			Src/VideoState.cpp
