diff --git a/binaries/data/config/system.cfg b/binaries/data/config/system.cfg
index 1e3991024d..8189266817 100644
--- a/binaries/data/config/system.cfg
+++ b/binaries/data/config/system.cfg
@@ -27,6 +27,14 @@ novbo=false
shadows=true
vsync=false
+; Specify the render path. This can be one of:
+; default Automatically select one of the below, depending on system capabilities
+; fixed Only use OpenGL fixed function pipeline
+; vertexshader Use vertex shaders for transform and lighting where possible
+; Using 'fixed' instead of 'default' may work around some graphics-related problems,
+; but will reduce performance when a modern graphics card is available.
+renderpath=default
+
; Adjusts how OpenGL calculates mipmap level of detail. 0.0f is the default (blurry) value.
; Lower values sharpen/extend, and higher values blur/decrease. Clamped at -3.0 to 3.0.
; -1.0 to -1.5 recommended for good results.
diff --git a/binaries/data/mods/official/shaders/model_light.vs b/binaries/data/mods/official/shaders/model_light.vs
new file mode 100644
index 0000000000..b487e12dfe
--- /dev/null
+++ b/binaries/data/mods/official/shaders/model_light.vs
@@ -0,0 +1,8 @@
+vec3 lighting(vec3 normal);
+
+void main()
+{
+ gl_FrontColor = gl_BackColor = vec4(lighting(gl_Normal),1.0) * gl_Color;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = ftransform();
+}
diff --git a/binaries/data/mods/official/shaders/model_light.xml b/binaries/data/mods/official/shaders/model_light.xml
new file mode 100644
index 0000000000..a5059cff01
--- /dev/null
+++ b/binaries/data/mods/official/shaders/model_light.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ shaders/model_light.vs
+ shaders/shlight.vs
+
+
diff --git a/binaries/data/mods/official/shaders/shlight.vs b/binaries/data/mods/official/shaders/shlight.vs
new file mode 100644
index 0000000000..9b45a523f9
--- /dev/null
+++ b/binaries/data/mods/official/shaders/shlight.vs
@@ -0,0 +1,16 @@
+uniform vec3 SHCoefficients[9];
+
+vec3 lighting(vec3 normal)
+{
+ vec3 color = SHCoefficients[0];
+ vec3 normalsq = normal*normal;
+ color += SHCoefficients[1]*normal.x;
+ color += SHCoefficients[2]*normal.y;
+ color += SHCoefficients[3]*normal.z;
+ color += SHCoefficients[4]*(normal.x*normal.z);
+ color += SHCoefficients[5]*(normal.z*normal.y);
+ color += SHCoefficients[6]*(normal.y*normal.x);
+ color += SHCoefficients[7]*(3*normalsq.z-1);
+ color += SHCoefficients[8]*(normalsq.x-normalsq.y);
+ return color;
+}
diff --git a/source/lib/lib.h b/source/lib/lib.h
index c0e427bb5a..c039b6ef89 100755
--- a/source/lib/lib.h
+++ b/source/lib/lib.h
@@ -273,6 +273,12 @@ enum LibError
ERR_CPU_FEATURE_MISSING = -1600,
+ // shaders
+ ERR_SHDR_CREATE = -1700,
+ ERR_SHDR_COMPILE = -1701,
+ ERR_SHDR_NO_SHADER = -1702,
+ ERR_SHDR_LINK = -1703,
+ ERR_SHDR_NO_PROGRAM = -1704,
ERR_LAST
};
diff --git a/source/lib/res/graphics/ogl_shader.cpp b/source/lib/res/graphics/ogl_shader.cpp
new file mode 100644
index 0000000000..2cd2224d1c
--- /dev/null
+++ b/source/lib/res/graphics/ogl_shader.cpp
@@ -0,0 +1,425 @@
+#include "precompiled.h"
+
+#include "lib.h"
+#include "../res.h"
+#include "lib/ogl.h"
+
+#include "ps/CLogger.h"
+#include "ps/XML/Xeromyces.h"
+
+#include "ogl_shader.h"
+
+#define LOG_CATEGORY "shaders"
+
+
+// Convert a shader object type into a descriptive string.
+// If the type enum is not known, the given buffer is used as scratch space
+// to format the type number. If buf is null, a generic string is returned.
+static const char* shader_type_to_string(GLenum type, char* buf, size_t buflen)
+{
+ switch(type)
+ {
+ case GL_VERTEX_SHADER_ARB: return "VERTEX_SHADER";
+ case GL_FRAGMENT_SHADER_ARB: return "FRAGMENT_SHADER";
+ }
+
+ if (!buf)
+ return "unknown type enum";
+
+ snprintf(buf, buflen, "%u", type);
+ return buf;
+}
+
+// Return the OpenGL shader type enum for the given string,
+// or 0 if the shader type is not known.
+static GLenum string_to_shader_type(const char* name)
+{
+ if (!stricmp(name, "VERTEX_SHADER"))
+ return GL_VERTEX_SHADER_ARB;
+ if (!stricmp(name, "FRAGMENT_SHADER"))
+ return GL_FRAGMENT_SHADER_ARB;
+ return 0;
+}
+
+
+//----------------------------------------------------------------------------
+// Handle type implementation
+
+// Data for an Ogl_Shader object
+struct Ogl_Shader {
+ // Type of shader (e.g. GL_VERTEX_SHADER_ARB)
+ GLenum type;
+
+ // ID of the OpenGL shader object
+ GLhandleARB id;
+};
+
+
+H_TYPE_DEFINE(Ogl_Shader);
+
+
+// One-time initialization, called once by h_alloc, which is
+// in turn called by ogl_shader_load
+static void Ogl_Shader_init(Ogl_Shader* shdr, va_list args)
+{
+ shdr->type = va_arg(args, GLenum);
+}
+
+
+// Reload the shader object from the source file.
+//
+// TODO: The OpenGL specification says that all changes to shader objects
+// have absolutely no effect on a program object that contains these shaders
+// when the program object is already linked.
+// So, how can we inform the "parent object" (i.e. the program object) of our change?
+static int Ogl_Shader_reload(Ogl_Shader* shdr, const char* filename, Handle h)
+{
+ int err = -666;
+
+ if (shdr->id)
+ return 0;
+
+ void* file;
+ size_t file_size;
+ GLint log_length;
+ GLint compile_success;
+ Handle hm;
+
+ hm = vfs_load(filename, file, file_size);
+ RETURN_ERR(hm);
+
+ oglCheck();
+
+ shdr->id = glCreateShaderObjectARB(shdr->type);
+ if (!shdr->id)
+ {
+ // May be out of memory, but bad shdr->type is also possible.
+ // In any case, checking OpenGL error state will help spot
+ // bad code.
+ oglCheck();
+
+ err = ERR_SHDR_CREATE;
+ goto fail_fileloaded;
+ }
+
+ glShaderSourceARB(shdr->id, 1, (const char**)&file, (const GLint*)&file_size);
+ glCompileShaderARB(shdr->id);
+
+ glGetObjectParameterivARB(shdr->id, GL_OBJECT_COMPILE_STATUS_ARB, &compile_success);
+ glGetObjectParameterivARB(shdr->id, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length);
+ if (log_length > 1)
+ {
+ char typenamebuf[32];
+ char* infolog = new char[log_length];
+
+ glGetInfoLogARB(shdr->id, log_length, 0, infolog);
+
+ debug_printf("Compile log for shader %hs (type %hs):\n%hs",
+ filename,
+ shader_type_to_string(shdr->type, typenamebuf, ARRAY_SIZE(typenamebuf)),
+ infolog);
+
+ delete[] infolog;
+ }
+
+ if (!compile_success)
+ {
+ // Compilation failure caused by syntax errors and similar
+ // errors at the GLSL level does not set OpenGL error state
+ // according to the spec, but this might still prove to be
+ // useful some time.
+ oglCheck();
+
+ char typenamebuf[32];
+ debug_printf("Failed to compile shader %hs (type %hs)\n",
+ filename,
+ shader_type_to_string(shdr->type, typenamebuf, ARRAY_SIZE(typenamebuf)));
+
+ err = ERR_SHDR_COMPILE;
+ goto fail_shadercreated;
+ }
+
+ mem_free_h(hm);
+ return 0;
+
+fail_shadercreated:
+ glDeleteObjectARB(shdr->id);
+ shdr->id = 0;
+fail_fileloaded:
+ mem_free_h(hm);
+ return err;
+}
+
+
+// Free associated resources
+static void Ogl_Shader_dtor(Ogl_Shader* shdr)
+{
+ // shdr->id is 0 when reload has failed
+ if (shdr->id)
+ {
+ glDeleteObjectARB(shdr->id);
+ shdr->id = 0;
+ }
+}
+
+
+
+//----------------------------------------------------------------------------
+// Public API
+
+// Create, load and compile a shader object of the given type
+// (e.g. GL_VERTEX_SHADER_ARB). The given file will be used as
+// source code for the shader.
+Handle ogl_shader_load(const char* fn, GLenum type)
+{
+ return h_alloc(H_Ogl_Shader, fn, 0, type);
+}
+
+
+// Free all resources associated with the given handle (subject
+// to refcounting).
+void ogl_shader_free(Handle& h)
+{
+ h_free(h, H_Ogl_Shader);
+}
+
+// Attach a shader to the given OpenGL program.
+int ogl_shader_attach(GLhandleARB program, Handle& h)
+{
+ H_DEREF(h, Ogl_Shader, shdr);
+
+ if (!shdr->id)
+ return ERR_SHDR_NO_SHADER;
+
+ glAttachObjectARB(program, shdr->id);
+
+ return 0;
+}
+
+
+
+//----------------------------------------------------------------------------
+// Program type implementation
+
+struct Ogl_Program {
+ // ID of the OpenGL program object
+ GLhandleARB id;
+};
+
+
+H_TYPE_DEFINE(Ogl_Program);
+
+
+// One-time initialization, called once by h_alloc, which is
+// in turn called by ogl_program_load
+static void Ogl_Program_init(Ogl_Program* p, va_list args)
+{
+}
+
+
+// Load the shader associated with one Shader element,
+// and attach it to our program object.
+static int do_load_shader(
+ Ogl_Program* p, const char* filename, Handle h,
+ const CXeromyces& XeroFile, const XMBElement& Shader)
+{
+#define AT(x) int at_##x = XeroFile.getAttributeID(#x)
+ AT(type);
+#undef AT
+
+ CStr Type = Shader.getAttributes().getNamedItem(at_type);
+
+ if (!Type.Length())
+ {
+ LOG(ERROR, LOG_CATEGORY, "%hs: Missing attribute \"type\" in element \"Shader\".",
+ filename);
+ return ERR_CORRUPTED;
+ }
+
+ GLenum shadertype = string_to_shader_type(Type.c_str());
+
+ if (!shadertype)
+ {
+ LOG(ERROR, LOG_CATEGORY, "%hs: Unknown shader type \"%hs\" (valid are: VERTEX_SHADER, FRAGMENT_SHADER).",
+ filename, Type.c_str());
+ return ERR_CORRUPTED;
+ }
+
+ CStr Name = Shader.getText();
+
+ if (!Name.Length())
+ {
+ LOG(ERROR, LOG_CATEGORY, "%hs: Missing shader name.", filename);
+ return ERR_CORRUPTED;
+ }
+
+ Handle hshader = ogl_shader_load(Name.c_str(), shadertype);
+ RETURN_ERR(hshader);
+
+ ogl_shader_attach(p->id, hshader);
+
+ // According to the OpenGL specification, a shader object's deletion
+ // will not be final as long as the shader object is attached to a
+ // container object.
+ // TODO: How will this work with automatic reload?
+ ogl_shader_free(hshader);
+
+ return 0;
+}
+
+
+// Reload the program object from the source file.
+static int Ogl_Program_reload(Ogl_Program* p, const char* filename, Handle h)
+{
+ if (p->id)
+ return 0;
+
+ oglCheck();
+
+ p->id = glCreateProgramObjectARB();
+ if (!p->id)
+ {
+ // The spec doesn't mention any error state that can be set
+ // here, but it may still help spot bad code.
+ oglCheck();
+
+ return ERR_SHDR_CREATE;
+ }
+
+ CXeromyces XeroFile;
+ if (XeroFile.Load(filename) != PSRETURN_OK)
+ return ERR_CORRUPTED; // more informative error message?
+
+ // Define all the elements and attributes used in the XML file
+#define EL(x) int el_##x = XeroFile.getElementID(#x)
+ EL(program);
+ EL(shaders);
+ EL(shader);
+#undef EL
+
+ XMBElement Root = XeroFile.getRoot();
+
+ if (Root.getNodeName() != el_program)
+ {
+ LOG(ERROR, LOG_CATEGORY, "%hs: XML root was not \"Program\".", filename);
+ return ERR_CORRUPTED;
+ }
+
+ XMBElementList RootChildren = Root.getChildNodes();
+
+ for(int i = 0; i < RootChildren.Count; ++i)
+ {
+ XMBElement Child = RootChildren.item(i);
+
+ int ChildName = Child.getNodeName();
+ if (ChildName == el_shaders)
+ {
+ XMBElementList Shaders = Child.getChildNodes();
+
+ for(int j = 0; j < Shaders.Count; ++j)
+ {
+ XMBElement Shader = Shaders.item(j);
+
+ if (Shader.getNodeName() != el_shader)
+ {
+ LOG(ERROR, LOG_CATEGORY, "%hs: Only \"Shader\" may be child of \"Shaders\".",
+ filename);
+ return ERR_CORRUPTED;
+ }
+
+ int ret = do_load_shader(p, filename, h, XeroFile, Shader);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ else
+ {
+ LOG(WARNING, LOG_CATEGORY, "%hs: Unknown child of \"Program\".", filename);
+ }
+ }
+
+ glLinkProgramARB(p->id);
+
+ GLint log_length;
+ GLint linked;
+
+ glGetObjectParameterivARB(p->id, GL_OBJECT_LINK_STATUS_ARB, &linked);
+ glGetObjectParameterivARB(p->id, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length);
+ if (log_length > 1)
+ {
+ char* infolog = new char[log_length];
+ glGetInfoLogARB(p->id, log_length, 0, infolog);
+
+ debug_printf("Linker log for %hs:\n%hs\n", filename, infolog);
+ delete[] infolog;
+ }
+
+ if (!linked)
+ {
+ debug_printf("Link failed for %hs\n", filename);
+ return ERR_SHDR_LINK;
+ }
+
+ return 0;
+}
+
+
+// Free associated resources
+static void Ogl_Program_dtor(Ogl_Program* p)
+{
+ if (p->id)
+ {
+ glDeleteObjectARB(p->id);
+ p->id = 0;
+ }
+}
+
+
+
+//----------------------------------------------------------------------------
+// Public API
+
+// Load a program object based on the given XML file description.
+// Shader objects are loaded and attached automatically.
+Handle ogl_program_load(const char* fn)
+{
+ return h_alloc(H_Ogl_Program, fn, 0);
+}
+
+// Free all resources associated with the given program handle.
+void ogl_program_free(Handle& h)
+{
+ h_free(h, H_Ogl_Program);
+}
+
+
+// Activate the program (glUseProgramObjectARB).
+// h may be 0, in which case program objects are disabled.
+int ogl_program_use(Handle h)
+{
+ if (!h)
+ {
+ glUseProgramObjectARB(0);
+ return 0;
+ }
+
+ Ogl_Program* p = H_USER_DATA(h, Ogl_Program);
+ if (!p || !p->id)
+ {
+ glUseProgramObjectARB(0);
+ CHECK_ERR(ERR_INVALID_HANDLE);
+ UNREACHABLE;
+ }
+
+ glUseProgramObjectARB(p->id);
+ return 0;
+}
+
+
+// Query uniform information
+GLint ogl_program_get_uniform_location(Handle h, const char* name)
+{
+ H_DEREF(h, Ogl_Program, p);
+
+ return glGetUniformLocationARB(p->id, name);
+}
diff --git a/source/lib/res/graphics/ogl_shader.h b/source/lib/res/graphics/ogl_shader.h
new file mode 100644
index 0000000000..4cb9c6cee9
--- /dev/null
+++ b/source/lib/res/graphics/ogl_shader.h
@@ -0,0 +1,50 @@
+#ifndef OGL_SHADER_H__
+#define OGL_SHADER_H__
+
+#include "../handle.h"
+
+#include "lib/types.h"
+#include "lib/ogl.h"
+
+/*
+Encapsulate shader objects into handles, which transparently enables sharing
+of shader source files between programs as well as reloading shaders at
+runtime.
+
+NOTE: Only use functions form this module after verifying that the required
+extensions are available, or all bets are off.
+*/
+
+// Create, load and compile a shader object of the given type
+// (e.g. GL_VERTEX_SHADER_ARB). The given file will be used as
+// source code for the shader.
+Handle ogl_shader_load(const char* fn, GLenum type);
+
+// Free all resources associated with the given handle (subject
+// to refcounting).
+void ogl_shader_free(Handle& h);
+
+// Attach a shader to the given OpenGL program.
+// Returns 0 on success and a negative error code otherwise.
+int ogl_shader_attach(GLhandleARB program, Handle& h);
+
+
+/*
+Encapsulate program objects into handles.
+*/
+
+// Load a program object based on the given XML file description.
+// Shader objects are loaded and attached automatically.
+Handle ogl_program_load(const char* fn);
+
+// Free all resources associated with the given program handle.
+void ogl_program_free(Handle& h);
+
+// Activate the program (glUseProgramObjectARB).
+// h may be 0, in which case program objects are disabled.
+int ogl_program_use(Handle h);
+
+// Query uniform information
+GLint ogl_program_get_uniform_location(Handle h, const char* name);
+
+#endif // OGL_SHADER_H__
diff --git a/source/ps/GameSetup/Config.cpp b/source/ps/GameSetup/Config.cpp
index 59ef72e3dc..0ea0a9aa92 100644
--- a/source/ps/GameSetup/Config.cpp
+++ b/source/ps/GameSetup/Config.cpp
@@ -26,6 +26,7 @@ bool g_VSync = false;
float g_LodBias = 0.0f;
float g_Gamma = 1.0f;
bool g_EntGraph = false;
+CStr g_RenderPath = "default";
// graphics mode
int g_xres, g_yres;
@@ -67,6 +68,7 @@ static void LoadGlobals()
CFG_GET_USER_VAL("vsync", Bool, g_VSync);
CFG_GET_USER_VAL("novbo", Bool, g_NoGLVBO);
CFG_GET_USER_VAL("shadows", Bool, g_Shadows);
+ CFG_GET_USER_VAL("renderpath", String, g_RenderPath);
CFG_GET_USER_VAL("lodbias", Float, g_LodBias);
diff --git a/source/ps/GameSetup/Config.h b/source/ps/GameSetup/Config.h
index 0485fc9e13..85273fae71 100644
--- a/source/ps/GameSetup/Config.h
+++ b/source/ps/GameSetup/Config.h
@@ -13,6 +13,9 @@ extern bool g_VSync;
extern float g_LodBias;
extern float g_Gamma;
extern bool g_EntGraph;
+// name of configured render path (depending on OpenGL extensions, this may not be
+// the render path that is actually in use right now)
+extern CStr g_RenderPath;
extern int g_xres, g_yres;
diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp
index 09114c08dd..fa880cd2e0 100644
--- a/source/ps/GameSetup/GameSetup.cpp
+++ b/source/ps/GameSetup/GameSetup.cpp
@@ -543,6 +543,7 @@ static void InitRenderer()
g_Renderer.SetOptionBool(CRenderer::OPT_NOVBO,g_NoGLVBO);
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS,g_Shadows);
g_Renderer.SetOptionBool(CRenderer::OPT_NOPBUFFER,g_NoPBuffer);
+ g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath));
g_Renderer.SetOptionFloat(CRenderer::OPT_LODBIAS, g_LodBias);
// create terrain related stuff
diff --git a/source/renderer/ModelDefRData.cpp b/source/renderer/ModelDefRData.cpp
index c4437dbcec..2357e5b385 100644
--- a/source/renderer/ModelDefRData.cpp
+++ b/source/renderer/ModelDefRData.cpp
@@ -32,34 +32,42 @@ CModelDefRData::~CModelDefRData()
// Create and upload shared vertex arrays
+//
+// UV is only shared for fixed function at the moment.
+// Rationale: The non-shared vertex structure has enough space left for UV
+// coordinates due to alignment, so we slightly *reduce* vertex buffer space by
+// not sharing UV.
void CModelDefRData::Build()
{
- size_t numVertices = m_ModelDef->GetNumVertices();
-
- m_UV.type = GL_FLOAT;
- m_UV.elems = 2;
- m_Array.AddAttribute(&m_UV);
+ if (g_Renderer.GetRenderPath() == CRenderer::RP_FIXED)
+ {
+ size_t numVertices = m_ModelDef->GetNumVertices();
- m_Array.SetNumVertices(numVertices);
- m_Array.Layout();
+ m_UV.type = GL_FLOAT;
+ m_UV.elems = 2;
+ m_Array.AddAttribute(&m_UV);
+
+ m_Array.SetNumVertices(numVertices);
+ m_Array.Layout();
+
+ SModelVertex* vertices = m_ModelDef->GetVertices();
+ VertexArrayIterator UVit = m_UV.GetIterator();
+
+ for (uint j=0; j < numVertices; ++j, ++UVit) {
+ (*UVit)[0] = vertices[j].m_U;
+ (*UVit)[1] = 1.0-vertices[j].m_V;
+ }
- SModelVertex* vertices = m_ModelDef->GetVertices();
- VertexArrayIterator UVit = m_UV.GetIterator();
-
- for (uint j=0; j < numVertices; ++j, ++UVit) {
- (*UVit)[0] = vertices[j].m_U;
- (*UVit)[1] = 1.0-vertices[j].m_V;
+ m_Array.Upload();
+ m_Array.FreeBackingStore();
}
-
- m_Array.Upload();
- m_Array.FreeBackingStore();
}
// Setup shared vertex arrays as needed.
void CModelDefRData::PrepareStream(uint streamflags)
{
- if (!(streamflags & STREAM_UV0))
+ if (!(streamflags & STREAM_UV0) || !m_UV.type)
return;
u8* base = m_Array.Bind();
diff --git a/source/renderer/ModelDefRData.h b/source/renderer/ModelDefRData.h
index 0203a64243..dd1c50ea55 100644
--- a/source/renderer/ModelDefRData.h
+++ b/source/renderer/ModelDefRData.h
@@ -34,7 +34,7 @@ private:
CModelDef* m_ModelDef;
VertexArray m_Array;
- VertexArray::Attribute m_UV;
+ VertexArray::Attribute m_UV; // only used in RP_FIXED
CModelDefRData* m_SubmissionNext;
uint m_SubmissionSlots;
diff --git a/source/renderer/ModelRData.cpp b/source/renderer/ModelRData.cpp
index 28b0b44215..6b1613f1f1 100755
--- a/source/renderer/ModelRData.cpp
+++ b/source/renderer/ModelRData.cpp
@@ -4,6 +4,7 @@
#include
#include "MathUtil.h"
#include "lib/res/graphics/ogl_tex.h"
+#include "lib/res/graphics/ogl_shader.h"
#include "Renderer.h"
#include "TransparencyRenderer.h"
#include "PlayerRenderer.h"
@@ -13,13 +14,14 @@
#include "MaterialManager.h"
#include "Profile.h"
#include "renderer/ModelDefRData.h"
+#include "renderer/RenderPathVertexShader.h"
///////////////////////////////////////////////////////////////////
// CModelRData constructor
CModelRData::CModelRData(CModel* model)
- : m_Model(model), m_Normals(0), m_DynamicArray(true), m_Indices(0), m_Flags(0)
+ : m_Model(model), m_TempNormals(0), m_DynamicArray(true), m_Indices(0), m_Flags(0)
{
debug_assert(model);
// build all data now
@@ -32,7 +34,7 @@ CModelRData::~CModelRData()
{
// clean up system copies of data
delete[] m_Indices;
- delete[] m_Normals;
+ delete[] m_TempNormals;
}
void CModelRData::Build()
@@ -47,14 +49,23 @@ void CModelRData::Build()
m_Position.type = GL_FLOAT;
m_Position.elems = 3;
m_DynamicArray.AddAttribute(&m_Position);
-/*
- m_UV.type = GL_FLOAT;
- m_UV.elems = 2;
- m_DynamicArray.AddAttribute(&m_UV);
-*/
- m_Color.type = GL_UNSIGNED_BYTE;
- m_Color.elems = 3;
- m_DynamicArray.AddAttribute(&m_Color);
+
+ if (g_Renderer.GetRenderPath() == CRenderer::RP_VERTEXSHADER)
+ {
+ m_UV.type = GL_FLOAT;
+ m_UV.elems = 2;
+ m_DynamicArray.AddAttribute(&m_UV);
+
+ m_Normal.type = GL_FLOAT;
+ m_Normal.elems = 3;
+ m_DynamicArray.AddAttribute(&m_Normal);
+ }
+ else
+ {
+ m_Color.type = GL_UNSIGNED_BYTE;
+ m_Color.elems = 3;
+ m_DynamicArray.AddAttribute(&m_Color);
+ }
m_DynamicArray.SetNumVertices(mdef->GetNumVertices());
m_DynamicArray.Layout();
@@ -146,17 +157,18 @@ static void SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices,C
void CModelRData::BuildStaticVertices()
{
-/*
- CModelDefPtr mdef = m_Model->GetModelDef();
- size_t numVertices = mdef->GetNumVertices();
- SModelVertex* vertices = mdef->GetVertices();
- VertexArrayIterator UVit = m_UV.GetIterator();
-
- for (uint j=0; j < numVertices; ++j, ++UVit) {
- (*UVit)[0] = vertices[j].m_U;
- (*UVit)[1] = 1.0-vertices[j].m_V;
+ if (m_UV.type)
+ {
+ CModelDefPtr mdef = m_Model->GetModelDef();
+ size_t numVertices = mdef->GetNumVertices();
+ SModelVertex* vertices = mdef->GetVertices();
+ VertexArrayIterator UVit = m_UV.GetIterator();
+
+ for (uint j=0; j < numVertices; ++j, ++UVit) {
+ (*UVit)[0] = vertices[j].m_U;
+ (*UVit)[1] = 1.0-vertices[j].m_V;
+ }
}
-*/
}
void CModelRData::BuildVertices()
@@ -165,14 +177,21 @@ void CModelRData::BuildVertices()
size_t numVertices=mdef->GetNumVertices();
SModelVertex* vertices=mdef->GetVertices();
- // allocate vertices if we haven't got any already and
- // fill in data that never changes
- if (!m_Normals)
- m_Normals=new CVector3D[mdef->GetNumVertices()];
-
// build vertices
VertexArrayIterator Position = m_Position.GetIterator();
- VertexArrayIterator Color = m_Color.GetIterator();
+ VertexArrayIterator Normal;
+
+ if (m_Normal.type)
+ {
+ Normal = m_Normal.GetIterator();
+ }
+ else
+ {
+ if (!m_TempNormals)
+ m_TempNormals = new CVector3D[numVertices];
+ Normal = VertexArrayIterator((char*)m_TempNormals, sizeof(CVector3D));
+ }
+
const CMatrix3D* bonematrices=m_Model->GetBoneMatrices();
if (bonematrices) {
// boned model - calculate skinned vertex positions/normals
@@ -180,35 +199,90 @@ void CModelRData::BuildVertices()
const CMatrix3D* invbonematrices=m_Model->GetInvBoneMatrices();
for (size_t j=0; jGetTransform();
const CMatrix3D& invtransform=m_Model->GetInvTransform();
for (uint j=0; jGetShadingColor();
- RGBColor shadingcolor(sc.r, sc.g, sc.b);
- RGBColor tempcolor;
- for (uint j=0; j Color = m_Color.GetIterator();
+ CSHCoeffs& shcoeffs = g_Renderer.m_SHCoeffsUnits;
+ CColor sc = m_Model->GetShadingColor();
+ RGBColor shadingcolor(sc.r, sc.g, sc.b);
+ RGBColor tempcolor;
+ for (uint j=0; jm_ModelLight);
+ idx = g_Renderer.m_VertexShader->m_ModelLight_SHCoefficients;
+ glUniform3fvARB(idx, 9, (float*)coeffs);
+
+ glEnableClientState(GL_NORMAL_ARRAY);
+ }
+ else
+ {
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+ }
+}
+
+// reset state prepared by SetupRender
+void CModelRData::FinishRender(u32 streamflags)
+{
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ if (streamflags & STREAM_COLOR)
+ {
+ if (g_Renderer.GetRenderPath() == CRenderer::RP_VERTEXSHADER)
+ {
+ glUseProgramObjectARB(0);
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ }
+ else
+ {
+ glDisableClientState(GL_COLOR_ARRAY);
+ }
+ }
+}
+
+
+// Render one indiviual model.
+// Try to use RenderModels instead wherever possible.
+// Must be bracketed by calls to CModelRData::SetupRender/FinishRender
void CModelRData::RenderStreams(u32 streamflags, bool isplayer)
{
CModelDefPtr mdldef=m_Model->GetModelDef();
@@ -223,24 +297,29 @@ void CModelRData::RenderStreams(u32 streamflags, bool isplayer)
g_Renderer.SetTexture(0,m_Model->GetTexture());
}
- ((CModelDefRData*)mdldef->GetRenderData())->PrepareStream(streamflags);
-
u8* base = m_DynamicArray.Bind();
size_t stride = m_DynamicArray.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + m_Position.offset);
- if (streamflags & STREAM_COLOR) glColorPointer(3, m_Color.type, stride, base + m_Color.offset);
-#if 0
+ if (streamflags & STREAM_COLOR)
{
- uint a = (uint)this;
- uint b = (uint)m_Model->GetTexture();
- uint hash = ((a >> 16) ^ (b & 0xffff)) | ((a & 0xffff0000) ^ (b << 16));
- hash = (hash * 65537) + 17;
- hash |= 0xff000000;
- glColor4ubv((GLubyte*)&hash);
- glDisableClientState(GL_COLOR_ARRAY);
+ if (m_Normal.type)
+ {
+ CColor sc = m_Model->GetShadingColor();
+ glColor3f(sc.r, sc.g, sc.b);
+
+ glNormalPointer(GL_FLOAT, stride, base + m_Normal.offset);
+ }
+ else
+ glColorPointer(3, m_Color.type, stride, base + m_Color.offset);
+ }
+ if (streamflags & STREAM_UV0)
+ {
+ if (m_UV.type)
+ glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset);
+ else
+ ((CModelDefRData*)mdldef->GetRenderData())->PrepareStream(streamflags);
}
-#endif
// render the lot
size_t numFaces=mdldef->GetNumFaces();
@@ -331,6 +410,7 @@ float CModelRData::BackToFrontIndexSort(CMatrix3D& objToCam)
/////////////////////////////////////////////////////////////////////////////////////////////////////
// RenderModels: render all submitted models; assumes necessary client states already enabled,
// and texture environment already setup as required
+// Must be bracketed by calls to CModelRData::SetupRender/FinishRender
void CModelRData::RenderModels(u32 streamflags, u32 flags)
{
for(CModelDefRData* mdefdata = CModelDefRData::m_Submissions;
@@ -359,9 +439,27 @@ void CModelRData::RenderModels(u32 streamflags, u32 flags)
glVertexPointer(3, GL_FLOAT, stride,
base + modeldata->m_Position.offset);
if (streamflags & STREAM_COLOR)
- glColorPointer(3, modeldata->m_Color.type, stride,
- base + modeldata->m_Color.offset);
-
+ {
+ if (modeldata->m_Normal.type)
+ {
+ CColor sc = modeldata->GetModel()->GetShadingColor();
+
+ glColor3f(sc.r, sc.g, sc.b);
+
+ glNormalPointer(GL_FLOAT, stride, base + modeldata->m_Normal.offset);
+ }
+ else
+ {
+ glColorPointer(3, modeldata->m_Color.type, stride,
+ base + modeldata->m_Color.offset);
+ }
+ }
+ if (streamflags & STREAM_UV0 && modeldata->m_UV.type)
+ {
+ glTexCoordPointer(2, GL_FLOAT, stride,
+ base + modeldata->m_UV.offset);
+ }
+
// render the lot
size_t numFaces=mdldef->GetNumFaces();
glDrawRangeElementsEXT(GL_TRIANGLES, 0, mdldef->GetNumVertices(),
diff --git a/source/renderer/ModelRData.h b/source/renderer/ModelRData.h
index 2faae32d98..bdd83f419f 100755
--- a/source/renderer/ModelRData.h
+++ b/source/renderer/ModelRData.h
@@ -38,6 +38,11 @@ public:
// clear per frame model list
static void ClearSubmissions();
+ // prepare for rendering of models
+ static void SetupRender(u32 streamflags);
+ // reset state prepared by SetupRender
+ static void FinishRender(u32 streamflags);
+
// render all submitted models
static void RenderModels(u32 streamflags,u32 flags=0);
@@ -52,12 +57,14 @@ private:
// owner model
CModel* m_Model;
// transformed vertex normals - required for recalculating lighting on skinned models
- CVector3D* m_Normals;
+ // only used in render path RP_FIXED
+ CVector3D* m_TempNormals;
// vertex array
VertexArray m_DynamicArray;
VertexArray::Attribute m_Position;
- VertexArray::Attribute m_UV;
- VertexArray::Attribute m_Color;
+ VertexArray::Attribute m_UV; // only used in RP_VERTEXSHADER (shared otherwise)
+ VertexArray::Attribute m_Color; // only used in RP_FIXED
+ VertexArray::Attribute m_Normal; // only used in RP_VERTEXSHADER
// model render indices
u16* m_Indices;
// model render flags
diff --git a/source/renderer/PlayerRenderer.cpp b/source/renderer/PlayerRenderer.cpp
index 941dd483a1..25f7f280e8 100644
--- a/source/renderer/PlayerRenderer.cpp
+++ b/source/renderer/PlayerRenderer.cpp
@@ -89,9 +89,7 @@ void CPlayerRenderer::Render()
// supports register combiners / fragment programs / etc (since it
// would only need a single pass and no blending)
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
+ CModelRData::SetupRender(STREAM_POS|STREAM_COLOR|STREAM_UV0);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT);
@@ -122,10 +120,7 @@ void CPlayerRenderer::Render()
glActiveTextureARB(GL_TEXTURE0);
- // switch off client states
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
+ CModelRData::FinishRender(STREAM_POS|STREAM_COLOR|STREAM_UV0);
if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
@@ -144,14 +139,10 @@ void CPlayerRenderer::Render()
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- // .. and some client states
- glEnableClientState(GL_VERTEX_ARRAY);
-
// render each model
+ CModelRData::SetupRender(STREAM_POS);
RenderObjectsStreams(STREAM_POS);
-
- // .. and switch off the client states
- glDisableClientState(GL_VERTEX_ARRAY);
+ CModelRData::FinishRender(STREAM_POS);
// .. and restore the renderstates
glDisable(GL_BLEND);
@@ -211,4 +202,4 @@ void CPlayerRenderer::RenderObjectsStreams(u32 streamflags, bool iscolorpass, u3
modeldata->RenderStreams(streamflags, iscolorpass);
}
}
-}
+}
diff --git a/source/renderer/RenderPathVertexShader.cpp b/source/renderer/RenderPathVertexShader.cpp
new file mode 100644
index 0000000000..0727e3ab98
--- /dev/null
+++ b/source/renderer/RenderPathVertexShader.cpp
@@ -0,0 +1,48 @@
+#include "precompiled.h"
+
+#include "ogl.h"
+#include "lib/res/graphics/ogl_shader.h"
+#include "ps/CLogger.h"
+#include "renderer/Renderer.h"
+#include "renderer/RenderPathVertexShader.h"
+
+#define LOG_CATEGORY "graphics"
+
+
+RenderPathVertexShader::RenderPathVertexShader()
+{
+ m_ModelLight = 0;
+ m_ModelLight_SHCoefficients = -1;
+}
+
+RenderPathVertexShader::~RenderPathVertexShader()
+{
+ if (m_ModelLight)
+ ogl_program_free(m_ModelLight);
+}
+
+// Initialize this render path.
+// Use delayed initialization so that we can fallback to a different render path
+// if anything went wrong and use the destructor to clean things up.
+bool RenderPathVertexShader::Init()
+{
+ if (!g_Renderer.m_Caps.m_VertexShader)
+ return false;
+
+ m_ModelLight = ogl_program_load("shaders/model_light.xml");
+ if (m_ModelLight < 0)
+ {
+ LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/model_light.xml: %i\n", (int)m_ModelLight);
+ return false;
+ }
+
+ return true;
+}
+
+
+// This is quite the hack, but due to shader reloads,
+// the uniform locations might have changed under us.
+void RenderPathVertexShader::BeginFrame()
+{
+ m_ModelLight_SHCoefficients = ogl_program_get_uniform_location(m_ModelLight, "SHCoefficients");
+}
diff --git a/source/renderer/RenderPathVertexShader.h b/source/renderer/RenderPathVertexShader.h
new file mode 100644
index 0000000000..2aa3460868
--- /dev/null
+++ b/source/renderer/RenderPathVertexShader.h
@@ -0,0 +1,21 @@
+#ifndef __RENDERPATHVERTEXSHADER_H__
+#define __RENDERPATHVERTEXSHADER_H__
+
+class RenderPathVertexShader
+{
+public:
+ RenderPathVertexShader();
+ ~RenderPathVertexShader();
+
+ // Initialize this render path.
+ bool Init();
+
+ // Call once per frame to update program stuff
+ void BeginFrame();
+
+public:
+ Handle m_ModelLight;
+ GLint m_ModelLight_SHCoefficients;
+};
+
+#endif // __RENDERPATHVERTEXSHADER_H__
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp
index 13b88ad858..ff153cefef 100755
--- a/source/renderer/Renderer.cpp
+++ b/source/renderer/Renderer.cpp
@@ -41,6 +41,8 @@
#include "lib/res/graphics/ogl_tex.h"
#include "timer.h"
+#include "renderer/RenderPathVertexShader.h"
+
#define LOG_CATEGORY "graphics"
///////////////////////////////////////////////////////////////////////////////////
@@ -56,9 +58,12 @@ CRenderer::CRenderer()
m_ClearColor[0]=m_ClearColor[1]=m_ClearColor[2]=m_ClearColor[3]=0;
m_ShadowMap=0;
+ m_VertexShader = 0;
+
m_Options.m_NoVBO=false;
m_Options.m_Shadows=true;
m_Options.m_ShadowColor=RGBAColor(0.4f,0.4f,0.4f,1.0f);
+ m_Options.m_RenderPath = RP_DEFAULT;
for (uint i=0;iInit())
+ {
+ delete m_VertexShader;
+ m_VertexShader = 0;
+ m_Options.m_RenderPath = RP_FIXED;
+ }
+ }
+
+ LOG(NORMAL, LOG_CATEGORY, "Selected render path: %hs (configuration value: %hs)",
+ GetRenderPathName(m_Options.m_RenderPath).c_str(),
+ GetRenderPathName(desired).c_str());
+}
+
bool CRenderer::Open(int width, int height, int depth)
{
m_Width = width;
@@ -160,11 +190,15 @@ bool CRenderer::Open(int width, int height, int depth)
glGetIntegerv(GL_ALPHA_BITS,&bits);
LOG(NORMAL, LOG_CATEGORY, "CRenderer::Open: alpha bits %d",bits);
+ InitRenderPath();
+
return true;
}
void CRenderer::Close()
{
+ delete m_VertexShader;
+ m_VertexShader = 0;
}
// resize renderer view
@@ -241,6 +275,47 @@ const RGBAColor& CRenderer::GetOptionColor(enum Option opt) const
return defaultColor;
}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// SetRenderPath: Select the preferred render path.
+// This may only be called before Open(), because the layout of vertex arrays and other
+// data may depend on the chosen render path.
+void CRenderer::SetRenderPath(RenderPath rp)
+{
+ if (m_Options.m_RenderPath != RP_DEFAULT && rp != m_Options.m_RenderPath)
+ {
+ debug_warn("Cannot change RenderPath after the fact");
+ return;
+ }
+
+ m_Options.m_RenderPath = rp;
+}
+
+
+CStr CRenderer::GetRenderPathName(RenderPath rp)
+{
+ switch(rp) {
+ case RP_DEFAULT: return "default";
+ case RP_FIXED: return "fixed";
+ case RP_VERTEXSHADER: return "vertexshader";
+ default: return "(invalid)";
+ }
+}
+
+CRenderer::RenderPath CRenderer::GetRenderPathByName(CStr name)
+{
+ if (name == "fixed")
+ return RP_FIXED;
+ if (name == "vertexshader")
+ return RP_VERTEXSHADER;
+ if (name == "default")
+ return RP_DEFAULT;
+
+ LOG(WARNING, LOG_CATEGORY, "Unknown render path name '%hs', assuming 'default'", name.c_str());
+ return RP_DEFAULT;
+}
+
+
//////////////////////////////////////////////////////////////////////////////////////////
// BeginFrame: signal frame start
void CRenderer::BeginFrame()
@@ -253,9 +328,12 @@ void CRenderer::BeginFrame()
// bump frame counter
m_FrameCounter++;
+ if (m_VertexShader)
+ m_VertexShader->BeginFrame();
+
// zero out all the per-frame stats
m_Stats.Reset();
-
+
// calculate coefficients for terrain and unit lighting
m_SHCoeffsUnits.Clear();
m_SHCoeffsTerrain.Clear();
@@ -628,9 +706,6 @@ void CRenderer::RenderShadowMap()
glEnd();
#endif // 0
- // setup client states
- glEnableClientState(GL_VERTEX_ARRAY);
-
glEnable(GL_SCISSOR_TEST);
glScissor(1,1,m_Width-2,m_Height-2);
@@ -650,6 +725,8 @@ void CRenderer::RenderShadowMap()
glDisable(GL_CULL_FACE);
+ CModelRData::SetupRender(STREAM_POS);
+
// render models
CModelRData::RenderModels(STREAM_POS,MODELFLAG_CASTSHADOWS);
@@ -659,12 +736,13 @@ void CRenderer::RenderShadowMap()
// call on the transparency renderer to render all the transparent stuff
g_TransparencyRenderer.RenderShadows();
+ CModelRData::FinishRender(STREAM_POS);
+
glEnable(GL_CULL_FACE);
glColor3f(1.0f,1.0f,1.0f);
glDisable(GL_SCISSOR_TEST);
- glDisableClientState(GL_VERTEX_ARRAY);
// copy result into shadow map texture
BindTexture(0,m_ShadowMap);
@@ -938,18 +1016,10 @@ void CRenderer::RenderModelSubmissions()
float color[] = { 1.0, 1.0, 1.0, 1.0 };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
- // setup client states
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
// render models
+ CModelRData::SetupRender(STREAM_POS|STREAM_COLOR|STREAM_UV0);
CModelRData::RenderModels(STREAM_POS|STREAM_COLOR|STREAM_UV0);
-
- // switch off client states
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
+ CModelRData::FinishRender(STREAM_POS|STREAM_COLOR|STREAM_UV0);
}
void CRenderer::RenderModels()
@@ -981,14 +1051,10 @@ void CRenderer::RenderModels()
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- // .. and some client states
- glEnableClientState(GL_VERTEX_ARRAY);
-
- // render each model
+ // render all non-transparent, non-player models
+ CModelRData::SetupRender(STREAM_POS);
CModelRData::RenderModels(STREAM_POS);
-
- // .. and switch off the client states
- glDisableClientState(GL_VERTEX_ARRAY);
+ CModelRData::FinishRender(STREAM_POS);
// .. and restore the renderstates
glDisable(GL_BLEND);
diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h
index f07004229c..db21a1dd94 100755
--- a/source/renderer/Renderer.h
+++ b/source/renderer/Renderer.h
@@ -34,6 +34,7 @@ class CMaterial;
class CLightEnv;
class CTexture;
class CTerrain;
+class RenderPathVertexShader;
// rendering modes
@@ -107,7 +108,19 @@ public:
OPT_SHADOWCOLOR,
OPT_LODBIAS
};
-
+
+ enum RenderPath {
+ // If no rendering path is configured explicitly, the renderer
+ // will choose the path when Open() is called.
+ RP_DEFAULT,
+
+ // Classic fixed function.
+ RP_FIXED,
+
+ // Use (GL 2.0) vertex shaders for T&L when possible.
+ RP_VERTEXSHADER
+ };
+
// stats class - per frame counts of number of draw calls, poly counts etc
struct Stats {
// set all stats to zero
@@ -153,7 +166,11 @@ public:
void SetOptionColor(enum Option opt,const RGBAColor& value);
void SetOptionFloat(enum Option opt, float val);
const RGBAColor& GetOptionColor(enum Option opt) const;
-
+ void SetRenderPath(RenderPath rp);
+ RenderPath GetRenderPath() const { return m_Options.m_RenderPath; }
+ static CStr GetRenderPathName(RenderPath rp);
+ static RenderPath GetRenderPathByName(CStr name);
+
// return view width
int GetWidth() const { return m_Width; }
// return view height
@@ -238,14 +255,15 @@ public:
// return stats accumulated for current frame
const Stats& GetStats() { return m_Stats; }
- // return the current light environment
- const CLightEnv &GetLightEnv() { return *m_LightEnv; }
+ // return the current light environment
+ const CLightEnv &GetLightEnv() { return *m_LightEnv; }
protected:
friend class CVertexBuffer;
friend class CPatchRData;
friend class CModelRData;
friend class CTransparencyRenderer;
friend class CPlayerRenderer;
+ friend class RenderPathVertexShader;
// patch rendering stuff
void RenderPatchSubmissions();
@@ -266,6 +284,11 @@ protected:
void CalcShadowMatrices();
void CalcShadowBounds(CBound& bounds);
+ // render path stuff
+ bool InitRenderPathVertexShader();
+ void ShutdownRenderPathVertexShader();
+ void InitRenderPath();
+
// RENDERER DATA:
// view width
int m_Width;
@@ -324,6 +347,7 @@ protected:
bool m_Shadows;
RGBAColor m_ShadowColor;
float m_LodBias;
+ RenderPath m_RenderPath;
} m_Options;
// build card cap bits
void EnumCaps();
@@ -331,6 +355,10 @@ protected:
Stats m_Stats;
// active textures on each unit
GLuint m_ActiveTextures[MaxTextureUnits];
+
+ // Additional state that is only available when the vertex shader
+ // render path is used (according to m_Options.m_RenderPath)
+ RenderPathVertexShader* m_VertexShader;
};
diff --git a/source/renderer/TransparencyRenderer.cpp b/source/renderer/TransparencyRenderer.cpp
index eac9cf23f7..7849059bf3 100755
--- a/source/renderer/TransparencyRenderer.cpp
+++ b/source/renderer/TransparencyRenderer.cpp
@@ -49,11 +49,6 @@ void CTransparencyRenderer::Render()
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
- // switch on client states
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT);
@@ -69,7 +64,9 @@ void CTransparencyRenderer::Render()
// render everything with color writes off to setup depth buffer correctly
glColorMask(0,0,0,0);
+ CModelRData::SetupRender(STREAM_POS|STREAM_UV0);
RenderObjectsStreams(STREAM_POS|STREAM_UV0);
+ CModelRData::FinishRender(STREAM_POS|STREAM_UV0);
glColorMask(1,1,1,1);
glEnable(GL_BLEND);
@@ -88,7 +85,9 @@ void CTransparencyRenderer::Render()
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
+ CModelRData::SetupRender(STREAM_POS|STREAM_COLOR|STREAM_UV0);
RenderObjectsStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0);
+ CModelRData::FinishRender(STREAM_POS|STREAM_COLOR|STREAM_UV0);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
@@ -116,11 +115,10 @@ void CTransparencyRenderer::Render()
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- // .. and some client states
- glEnableClientState(GL_VERTEX_ARRAY);
-
// render each model
+ CModelRData::SetupRender(STREAM_POS);
RenderObjectsStreams(STREAM_POS);
+ CModelRData::FinishRender(STREAM_POS);
// .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY);
@@ -163,9 +161,6 @@ void CTransparencyRenderer::RenderShadows()
{
if (m_Objects.size()==0) return;
- // switch on client states
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
glDepthMask(0);
glEnable(GL_BLEND);
@@ -182,13 +177,12 @@ void CTransparencyRenderer::RenderShadows()
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
+ CModelRData::SetupRender(STREAM_POS|STREAM_UV0);
RenderObjectsStreams(STREAM_POS|STREAM_UV0,MODELFLAG_CASTSHADOWS);
+ CModelRData::FinishRender(STREAM_POS|STREAM_UV0);
glDepthMask(1);
glDisable(GL_BLEND);
-
- // switch off client states
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/source/renderer/VertexArray.h b/source/renderer/VertexArray.h
index bc43af3949..f89cbe7c9f 100644
--- a/source/renderer/VertexArray.h
+++ b/source/renderer/VertexArray.h
@@ -11,6 +11,11 @@ public:
typedef T Type;
public:
+ VertexArrayIterator() :
+ m_Data(0), m_Stride(0)
+ {
+ }
+
VertexArrayIterator(char* data, size_t stride) :
m_Data(data), m_Stride(stride)
{