Add the notion of render paths and an appropriate configuration option.
Add Ogl_Shader and Ogl_Program handle types for shaders/programs loaded from files. In the vertexshader render path, use a vertex program for lighting for optimization. This was SVN commit r2853.
This commit is contained in:
parent
539460abd8
commit
f1ee2cd66d
@ -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.
|
||||
|
8
binaries/data/mods/official/shaders/model_light.vs
Normal file
8
binaries/data/mods/official/shaders/model_light.vs
Normal file
@ -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();
|
||||
}
|
8
binaries/data/mods/official/shaders/model_light.xml
Normal file
8
binaries/data/mods/official/shaders/model_light.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
|
||||
|
||||
<Program>
|
||||
<Shaders>
|
||||
<Shader type="VERTEX_SHADER">shaders/model_light.vs</Shader>
|
||||
<Shader type="VERTEX_SHADER">shaders/shlight.vs</Shader>
|
||||
</Shaders>
|
||||
</Program>
|
16
binaries/data/mods/official/shaders/shlight.vs
Normal file
16
binaries/data/mods/official/shaders/shlight.vs
Normal file
@ -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;
|
||||
}
|
@ -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
|
||||
};
|
||||
|
425
source/lib/res/graphics/ogl_shader.cpp
Normal file
425
source/lib/res/graphics/ogl_shader.cpp
Normal file
@ -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);
|
||||
}
|
50
source/lib/res/graphics/ogl_shader.h
Normal file
50
source/lib/res/graphics/ogl_shader.h
Normal file
@ -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__
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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<float[2]> UVit = m_UV.GetIterator<float[2]>();
|
||||
|
||||
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<float[2]> UVit = m_UV.GetIterator<float[2]>();
|
||||
|
||||
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();
|
||||
|
@ -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;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <algorithm>
|
||||
#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<float[]> UVit = m_UV.GetIterator<float[]>();
|
||||
|
||||
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<float[2]> UVit = m_UV.GetIterator<float[2]>();
|
||||
|
||||
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<CVector3D> Position = m_Position.GetIterator<CVector3D>();
|
||||
VertexArrayIterator<SColor3ub> Color = m_Color.GetIterator<SColor3ub>();
|
||||
VertexArrayIterator<CVector3D> Normal;
|
||||
|
||||
if (m_Normal.type)
|
||||
{
|
||||
Normal = m_Normal.GetIterator<CVector3D>();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_TempNormals)
|
||||
m_TempNormals = new CVector3D[numVertices];
|
||||
Normal = VertexArrayIterator<CVector3D>((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; j<numVertices; j++) {
|
||||
SkinPoint(vertices[j],bonematrices,Position[j]);
|
||||
SkinNormal(vertices[j],invbonematrices,m_Normals[j]);
|
||||
SkinNormal(vertices[j],invbonematrices,Normal[j]);
|
||||
}
|
||||
} else {
|
||||
PROFILE( "software transform" );
|
||||
// just copy regular positions, transform normals to world space
|
||||
const CMatrix3D& transform=m_Model->GetTransform();
|
||||
const CMatrix3D& invtransform=m_Model->GetInvTransform();
|
||||
for (uint j=0; j<numVertices; j++) {
|
||||
transform.Transform(vertices[j].m_Coords,Position[j]);
|
||||
invtransform.RotateTransposed(vertices[j].m_Norm,m_Normals[j]);
|
||||
invtransform.RotateTransposed(vertices[j].m_Norm,Normal[j]);
|
||||
}
|
||||
}
|
||||
|
||||
PROFILE_START( "lighting vertices" );
|
||||
// now fill in UV and vertex colour data
|
||||
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; j<numVertices; j++) {
|
||||
shcoeffs.Evaluate(m_Normals[j], tempcolor, shadingcolor);
|
||||
*(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor);
|
||||
if (m_Color.type)
|
||||
{
|
||||
PROFILE( "lighting vertices" );
|
||||
// now fill in vertex colour data
|
||||
VertexArrayIterator<SColor3ub> Color = m_Color.GetIterator<SColor3ub>();
|
||||
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; j<numVertices; j++) {
|
||||
shcoeffs.Evaluate(Normal[j], tempcolor, shadingcolor);
|
||||
*(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor);
|
||||
}
|
||||
}
|
||||
PROFILE_END( "lighting vertices" );
|
||||
|
||||
// upload everything to vertex buffer
|
||||
m_DynamicArray.Upload();
|
||||
}
|
||||
|
||||
|
||||
// prepare for rendering of models
|
||||
void CModelRData::SetupRender(u32 streamflags)
|
||||
{
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_COLOR)
|
||||
{
|
||||
if (g_Renderer.GetRenderPath() == CRenderer::RP_VERTEXSHADER)
|
||||
{
|
||||
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
|
||||
int idx;
|
||||
|
||||
ogl_program_use(g_Renderer.m_VertexShader->m_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(),
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
48
source/renderer/RenderPathVertexShader.cpp
Normal file
48
source/renderer/RenderPathVertexShader.cpp
Normal file
@ -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");
|
||||
}
|
21
source/renderer/RenderPathVertexShader.h
Normal file
21
source/renderer/RenderPathVertexShader.h
Normal file
@ -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__
|
@ -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;i<MaxTextureUnits;i++) {
|
||||
m_ActiveTextures[i]=0;
|
||||
@ -132,6 +137,31 @@ void CRenderer::EnumCaps()
|
||||
}
|
||||
|
||||
|
||||
// Select the render path we're going to use based on config preferrences and
|
||||
// on available extensions.
|
||||
void CRenderer::InitRenderPath()
|
||||
{
|
||||
RenderPath desired = m_Options.m_RenderPath;
|
||||
|
||||
if (m_Options.m_RenderPath == RP_DEFAULT)
|
||||
m_Options.m_RenderPath = RP_VERTEXSHADER;
|
||||
|
||||
if (m_Options.m_RenderPath == RP_VERTEXSHADER)
|
||||
{
|
||||
m_VertexShader = new RenderPathVertexShader;
|
||||
if (!m_VertexShader->Init())
|
||||
{
|
||||
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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user