Index: ps/trunk/source/graphics/ShaderProgram.cpp =================================================================== --- ps/trunk/source/graphics/ShaderProgram.cpp (revision 11488) +++ ps/trunk/source/graphics/ShaderProgram.cpp (revision 11489) @@ -1,839 +1,891 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "ShaderProgram.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" #include "lib/res/graphics/ogl_tex.h" #include "maths/Matrix3D.h" #include "maths/Vector3D.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/Overlay.h" #include "ps/PreprocessorWrapper.h" #if !CONFIG2_GLES class CShaderProgramARB : public CShaderProgram { public: CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags) : CShaderProgram(streamflags), m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), m_Defines(defines), m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes) { pglGenProgramsARB(1, &m_VertexProgram); pglGenProgramsARB(1, &m_FragmentProgram); } ~CShaderProgramARB() { Unload(); pglDeleteProgramsARB(1, &m_VertexProgram); pglDeleteProgramsARB(1, &m_FragmentProgram); } bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code) { ogl_WarnIfError(); pglBindProgramARB(target, program); ogl_WarnIfError(); pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str()); if (ogl_SquelchError(GL_INVALID_OPERATION)) { GLint errPos = 0; glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1; char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); LOGERROR(L"Failed to compile %hs program '%ls' (line %d):\n%hs", targetName, file.string().c_str(), errLine, errStr); return false; } pglBindProgramARB(target, 0); ogl_WarnIfError(); return true; } virtual void Reload() { Unload(); CVFSFile vertexFile; if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) return; CVFSFile fragmentFile; if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) return; CPreprocessorWrapper preprocessor; preprocessor.AddDefines(m_Defines); CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); // printf(">>>\n%s<<<\n", vertexCode.c_str()); // printf(">>>\n%s<<<\n", fragmentCode.c_str()); if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode)) return; if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode)) return; m_IsValid = true; } void Unload() { m_IsValid = false; } virtual void Bind() { glEnable(GL_VERTEX_PROGRAM_ARB); glEnable(GL_FRAGMENT_PROGRAM_ARB); pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram); pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram); BindClientStates(); } virtual void Unbind() { glDisable(GL_VERTEX_PROGRAM_ARB); glDisable(GL_FRAGMENT_PROGRAM_ARB); pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); UnbindClientStates(); // TODO: should unbind textures, probably } int GetUniformVertexIndex(CStrIntern id) { std::map::iterator it = m_VertexIndexes.find(id); if (it == m_VertexIndexes.end()) return -1; return it->second; } int GetUniformFragmentIndex(CStrIntern id) { std::map::iterator it = m_FragmentIndexes.find(id); if (it == m_FragmentIndexes.end()) return -1; return it->second; } virtual Binding GetTextureBinding(texture_id_t id) { int index = GetUniformFragmentIndex(CStrIntern(id)); if (index == -1) return Binding(); else return Binding((int)GL_TEXTURE_2D, index); } virtual void BindTexture(texture_id_t id, Handle tex) { int index = GetUniformFragmentIndex(CStrIntern(id)); if (index != -1) { GLuint h; ogl_tex_get_texture_id(tex, &h); pglActiveTextureARB(GL_TEXTURE0+index); glBindTexture(GL_TEXTURE_2D, h); } } virtual void BindTexture(texture_id_t id, GLuint tex) { int index = GetUniformFragmentIndex(CStrIntern(id)); if (index != -1) { pglActiveTextureARB(GL_TEXTURE0+index); glBindTexture(GL_TEXTURE_2D, tex); } } virtual void BindTexture(Binding id, Handle tex) { int index = id.second; if (index != -1) ogl_tex_bind(tex, index); } virtual Binding GetUniformBinding(uniform_id_t id) { CStrIntern idIntern(id); return Binding(GetUniformVertexIndex(idIntern), GetUniformFragmentIndex(idIntern)); } virtual Binding GetUniformBinding(CStrIntern id) { return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)); } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.first != -1) pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3); if (id.second != -1) pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3); } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.first != -1) { pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+0, v._11, v._12, v._13, v._14); pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+1, v._21, v._22, v._23, v._24); pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+2, v._31, v._32, v._33, v._34); pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+3, v._41, v._42, v._43, v._44); } if (id.second != -1) { pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+0, v._11, v._12, v._13, v._14); pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+1, v._21, v._22, v._23, v._24); pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+2, v._31, v._32, v._33, v._34); pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+3, v._41, v._42, v._43, v._44); } } + virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) + { + ENSURE(count == 1); + Uniform(id, v[0]); + } + private: VfsPath m_VertexFile; VfsPath m_FragmentFile; CShaderDefines m_Defines; GLuint m_VertexProgram; GLuint m_FragmentProgram; std::map m_VertexIndexes; std::map m_FragmentIndexes; }; #endif // #if !CONFIG2_GLES ////////////////////////////////////////////////////////////////////////// TIMER_ADD_CLIENT(tc_ShaderGLSLCompile); TIMER_ADD_CLIENT(tc_ShaderGLSLLink); class CShaderProgramGLSL : public CShaderProgram { public: CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexAttribs, int streamflags) : CShaderProgram(streamflags), m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), m_Defines(defines), m_VertexAttribs(vertexAttribs) { m_Program = 0; m_VertexShader = pglCreateShaderObjectARB(GL_VERTEX_SHADER); m_FragmentShader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER); } ~CShaderProgramGLSL() { Unload(); pglDeleteShader(m_VertexShader); pglDeleteShader(m_FragmentShader); } bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code) { TIMER_ACCRUE(tc_ShaderGLSLCompile); ogl_WarnIfError(); const char* code_string = code.c_str(); GLint code_length = code.length(); pglShaderSourceARB(shader, 1, &code_string, &code_length); pglCompileShaderARB(shader); GLint ok = 0; pglGetShaderiv(shader, GL_COMPILE_STATUS, &ok); GLint length = 0; pglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0 // (http://code.google.com/p/android/issues/detail?id=9953) if (!ok && length == 0) length = 4096; if (length > 1) { char* infolog = new char[length]; pglGetShaderInfoLog(shader, length, NULL, infolog); if (ok) LOGMESSAGE(L"Info when compiling shader '%ls':\n%hs", file.string().c_str(), infolog); else LOGERROR(L"Failed to compile shader '%ls':\n%hs", file.string().c_str(), infolog); delete[] infolog; } ogl_WarnIfError(); return (ok ? true : false); } bool Link() { TIMER_ACCRUE(tc_ShaderGLSLLink); ENSURE(!m_Program); m_Program = pglCreateProgramObjectARB(); pglAttachObjectARB(m_Program, m_VertexShader); ogl_WarnIfError(); pglAttachObjectARB(m_Program, m_FragmentShader); ogl_WarnIfError(); // Set up the attribute bindings explicitly, since apparently drivers // don't always pick the most efficient bindings automatically, // and also this lets us hardcode indexes into VertexPointer etc for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglBindAttribLocationARB(m_Program, it->second, it->first.c_str()); pglLinkProgramARB(m_Program); GLint ok = 0; pglGetProgramiv(m_Program, GL_LINK_STATUS, &ok); GLint length = 0; pglGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length); if (!ok && length == 0) length = 4096; if (length > 1) { char* infolog = new char[length]; pglGetProgramInfoLog(m_Program, length, NULL, infolog); if (ok) LOGMESSAGE(L"Info when linking program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog); else LOGERROR(L"Failed to link program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog); delete[] infolog; } ogl_WarnIfError(); if (!ok) return false; m_Uniforms.clear(); m_Samplers.clear(); Bind(); ogl_WarnIfError(); GLint numUniforms = 0; pglGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); ogl_WarnIfError(); for (GLint i = 0; i < numUniforms; ++i) { char name[256] = {0}; GLsizei nameLength = 0; GLint size = 0; GLenum type = 0; pglGetActiveUniformARB(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name); ogl_WarnIfError(); GLint loc = pglGetUniformLocationARB(m_Program, name); CStrIntern nameIntern(name); m_Uniforms[nameIntern] = std::make_pair(loc, type); // Assign sampler uniforms to sequential texture units if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE #if !CONFIG2_GLES || type == GL_SAMPLER_2D_SHADOW #endif ) { int unit = (int)m_Samplers.size(); m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); m_Samplers[nameIntern].second = unit; pglUniform1iARB(loc, unit); // link uniform to unit ogl_WarnIfError(); } } // TODO: verify that we're not using more samplers than is supported Unbind(); ogl_WarnIfError(); return true; } virtual void Reload() { Unload(); CVFSFile vertexFile; if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) return; CVFSFile fragmentFile; if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) return; CPreprocessorWrapper preprocessor; preprocessor.AddDefines(m_Defines); #if CONFIG2_GLES // GLES defines the macro "GL_ES" in its GLSL preprocessor, // but since we run our own preprocessor first, we need to explicitly // define it here preprocessor.Define("GL_ES", "1"); #endif CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); #if CONFIG2_GLES // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00, // and also to set default float precision for fragment shaders vertexCode.Replace("#version 110\n", "#version 100\n"); vertexCode.Replace("#version 110\r\n", "#version 100\n"); vertexCode.Replace("#version 120\n", "#version 100\n"); vertexCode.Replace("#version 120\r\n", "#version 100\n"); fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n"); fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n"); fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n"); fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n"); #endif if (!Compile(m_VertexShader, m_VertexFile, vertexCode)) return; if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode)) return; if (!Link()) return; m_IsValid = true; } void Unload() { m_IsValid = false; if (m_Program) pglDeleteProgram(m_Program); m_Program = 0; // The shader objects can be reused and don't need to be deleted here } virtual void Bind() { pglUseProgramObjectARB(m_Program); for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglEnableVertexAttribArrayARB(it->second); } virtual void Unbind() { pglUseProgramObjectARB(0); for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglDisableVertexAttribArrayARB(it->second); // TODO: should unbind textures, probably } virtual Binding GetTextureBinding(texture_id_t id) { std::map >::iterator it = m_Samplers.find(CStrIntern(id)); if (it == m_Samplers.end()) return Binding(); else return Binding((int)it->second.first, it->second.second); } virtual void BindTexture(texture_id_t id, Handle tex) { std::map >::iterator it = m_Samplers.find(CStrIntern(id)); if (it == m_Samplers.end()) return; GLuint h; ogl_tex_get_texture_id(tex, &h); pglActiveTextureARB(GL_TEXTURE0 + it->second.second); glBindTexture(it->second.first, h); } virtual void BindTexture(texture_id_t id, GLuint tex) { std::map >::iterator it = m_Samplers.find(CStrIntern(id)); if (it == m_Samplers.end()) return; pglActiveTextureARB(GL_TEXTURE0 + it->second.second); glBindTexture(it->second.first, tex); } virtual void BindTexture(Binding id, Handle tex) { if (id.second == -1) return; GLuint h; ogl_tex_get_texture_id(tex, &h); pglActiveTextureARB(GL_TEXTURE0 + id.second); glBindTexture(id.first, h); } virtual Binding GetUniformBinding(uniform_id_t id) { std::map >::iterator it = m_Uniforms.find(CStrIntern(id)); if (it == m_Uniforms.end()) return Binding(); else return Binding(it->second.first, (int)it->second.second); } virtual Binding GetUniformBinding(CStrIntern id) { std::map >::iterator it = m_Uniforms.find(id); if (it == m_Uniforms.end()) return Binding(); else return Binding(it->second.first, (int)it->second.second); } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.first != -1) { if (id.second == GL_FLOAT) pglUniform1fARB(id.first, v0); else if (id.second == GL_FLOAT_VEC2) pglUniform2fARB(id.first, v0, v1); else if (id.second == GL_FLOAT_VEC3) pglUniform3fARB(id.first, v0, v1, v2); else if (id.second == GL_FLOAT_VEC4) pglUniform4fARB(id.first, v0, v1, v2, v3); else LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)"); } } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.first != -1) { if (id.second == GL_FLOAT_MAT4) pglUniformMatrix4fvARB(id.first, 1, GL_FALSE, &v._11); else LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); } } + virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) + { + if (id.first != -1) + { + if (id.second == GL_FLOAT_MAT4) + pglUniformMatrix4fvARB(id.first, count, GL_FALSE, &v->_11); + else + LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); + } + } + // Map the various fixed-function Pointer functions onto generic vertex attributes // (matching the attribute indexes from ShaderManager's ParseAttribSemantics): virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer) { pglVertexAttribPointerARB(0, size, type, GL_FALSE, stride, pointer); m_ValidStreams |= STREAM_POS; } virtual void NormalPointer(GLenum type, GLsizei stride, void* pointer) { pglVertexAttribPointerARB(2, 3, type, GL_TRUE, stride, pointer); m_ValidStreams |= STREAM_NORMAL; } virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer) { pglVertexAttribPointerARB(3, size, type, GL_TRUE, stride, pointer); m_ValidStreams |= STREAM_COLOR; } virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer) { pglVertexAttribPointerARB(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer); m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); } + virtual void VertexAttribPointer(const char* id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void* pointer) + { + std::map::iterator it = m_VertexAttribs.find(CStrIntern(id)); + if (it != m_VertexAttribs.end()) + { + pglVertexAttribPointerARB(it->second, size, type, normalized, stride, pointer); + } + } + + virtual void VertexAttribIPointer(const char* id, GLint size, GLenum type, GLsizei stride, void* pointer) + { + std::map::iterator it = m_VertexAttribs.find(CStrIntern(id)); + if (it != m_VertexAttribs.end()) + { + pglVertexAttribIPointerEXT(it->second, size, type, stride, pointer); + } + } + private: VfsPath m_VertexFile; VfsPath m_FragmentFile; CShaderDefines m_Defines; std::map m_VertexAttribs; GLhandleARB m_Program; GLhandleARB m_VertexShader; GLhandleARB m_FragmentShader; std::map > m_Uniforms; std::map > m_Samplers; // texture target & unit chosen for each uniform sampler }; ////////////////////////////////////////////////////////////////////////// CShaderProgram::CShaderProgram(int streamflags) : m_IsValid(false), m_StreamFlags(streamflags), m_ValidStreams(0) { } #if CONFIG2_GLES /*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& UNUSED(defines), const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes), int UNUSED(streamflags)) { LOGERROR(L"CShaderProgram::ConstructARB: '%ls'+'%ls': ARB shaders not supported on this device", vertexFile.string().c_str(), fragmentFile.string().c_str()); return NULL; } #else /*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags) { return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags); } #endif /*static*/ CShaderProgram* CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexAttribs, int streamflags) { return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags); } bool CShaderProgram::IsValid() const { return m_IsValid; } int CShaderProgram::GetStreamFlags() const { return m_StreamFlags; } void CShaderProgram::BindTexture(texture_id_t id, CTexturePtr tex) { BindTexture(id, tex->GetHandle()); } void CShaderProgram::Uniform(Binding id, int v) { Uniform(id, (float)v, (float)v, (float)v, (float)v); } void CShaderProgram::Uniform(Binding id, float v) { Uniform(id, v, v, v, v); } void CShaderProgram::Uniform(Binding id, float v0, float v1) { Uniform(id, v0, v1, 0.0f, 0.0f); } void CShaderProgram::Uniform(Binding id, const CVector3D& v) { Uniform(id, v.X, v.Y, v.Z, 0.0f); } void CShaderProgram::Uniform(Binding id, const CColor& v) { Uniform(id, v.r, v.g, v.b, v.a); } void CShaderProgram::Uniform(uniform_id_t id, int v) { Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v); } void CShaderProgram::Uniform(uniform_id_t id, float v) { Uniform(GetUniformBinding(id), v, v, v, v); } void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1) { Uniform(GetUniformBinding(id), v0, v1, 0.0f, 0.0f); } void CShaderProgram::Uniform(uniform_id_t id, const CVector3D& v) { Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f); } void CShaderProgram::Uniform(uniform_id_t id, const CColor& v) { Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a); } void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1, float v2, float v3) { Uniform(GetUniformBinding(id), v0, v1, v2, v3); } void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v) { Uniform(GetUniformBinding(id), v); } +void CShaderProgram::Uniform(uniform_id_t id, size_t count, const CMatrix3D* v) +{ + Uniform(GetUniformBinding(id), count, v); +} + #if CONFIG2_GLES // These should all be overridden by CShaderProgramGLSL void CShaderProgram::VertexPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer)) { debug_warn("CShaderProgram::VertexPointer should be overridden"); } void CShaderProgram::NormalPointer(GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer)) { debug_warn("CShaderProgram::NormalPointer should be overridden"); } void CShaderProgram::ColorPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer)) { debug_warn("CShaderProgram::ColorPointer should be overridden"); } void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer)) { debug_warn("CShaderProgram::TexCoordPointer should be overridden"); } #else // These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders // both use the fixed-function vertex attribute pointers: void CShaderProgram::VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer) { glVertexPointer(size, type, stride, pointer); m_ValidStreams |= STREAM_POS; } void CShaderProgram::NormalPointer(GLenum type, GLsizei stride, void* pointer) { glNormalPointer(type, stride, pointer); m_ValidStreams |= STREAM_NORMAL; } void CShaderProgram::ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer) { glColorPointer(size, type, stride, pointer); m_ValidStreams |= STREAM_COLOR; } void CShaderProgram::TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer) { pglClientActiveTextureARB(texture); glTexCoordPointer(size, type, stride, pointer); pglClientActiveTextureARB(GL_TEXTURE0); m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); } +void CShaderProgram::VertexAttribPointer(const char* UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type), + GLboolean UNUSED(normalized), GLsizei UNUSED(stride), void* UNUSED(pointer)) +{ + debug_warn("Shader type doesn't support VertexAttribPointer"); +} + +void CShaderProgram::VertexAttribIPointer(const char* UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type), + GLsizei UNUSED(stride), void* UNUSED(pointer)) +{ + debug_warn("Shader type doesn't support VertexAttribIPointer"); +} + void CShaderProgram::BindClientStates() { ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1))); // Enable all the desired client states for non-GLSL rendering if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY); if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY); if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); if (m_StreamFlags & STREAM_UV0) { pglClientActiveTextureARB(GL_TEXTURE0); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } if (m_StreamFlags & STREAM_UV1) { pglClientActiveTextureARB(GL_TEXTURE1); glEnableClientState(GL_TEXTURE_COORD_ARRAY); pglClientActiveTextureARB(GL_TEXTURE0); } // Rendering code must subsequently call VertexPointer etc for all of the streams // that were activated in this function, else AssertPointersBound will complain // that some arrays were unspecified m_ValidStreams = 0; } void CShaderProgram::UnbindClientStates() { if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY); if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY); if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); if (m_StreamFlags & STREAM_UV0) { pglClientActiveTextureARB(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (m_StreamFlags & STREAM_UV1) { pglClientActiveTextureARB(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); pglClientActiveTextureARB(GL_TEXTURE0); } } #endif // !CONFIG2_GLES void CShaderProgram::AssertPointersBound() { ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); } Index: ps/trunk/source/graphics/ShaderManager.cpp =================================================================== --- ps/trunk/source/graphics/ShaderManager.cpp (revision 11488) +++ ps/trunk/source/graphics/ShaderManager.cpp (revision 11489) @@ -1,560 +1,564 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "ShaderManager.h" #include "graphics/ShaderTechnique.h" #include "lib/timer.h" #include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/CStrIntern.h" #include "ps/Filesystem.h" #include "ps/PreprocessorWrapper.h" #include "ps/Profile.h" #include "ps/XML/Xeromyces.h" #include "ps/XML/XMLWriter.h" #include "renderer/Renderer.h" TIMER_ADD_CLIENT(tc_ShaderValidation); struct revcompare2nd { template bool operator()(const std::pair& a, const std::pair& b) const { return b.second < a.second; } }; CShaderManager::CShaderManager() { #if USE_SHADER_XML_VALIDATION { TIMER_ACCRUE(tc_ShaderValidation); CVFSFile grammar; if (grammar.Load(g_VFS, L"shaders/program.rng") != PSRETURN_OK) LOGERROR(L"Failed to read grammar shaders/program.rng"); else { if (!m_Validator.LoadGrammar(grammar.GetAsString())) LOGERROR(L"Failed to load grammar shaders/program.rng"); } } #endif // Allow hotloading of textures RegisterFileReloadFunc(ReloadChangedFileCB, this); } CShaderManager::~CShaderManager() { UnregisterFileReloadFunc(ReloadChangedFileCB, this); } CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const CShaderDefines& defines) { CacheKey key = { name, defines }; std::map::iterator it = m_ProgramCache.find(key); if (it != m_ProgramCache.end()) return it->second; CShaderProgramPtr program; if (!NewProgram(name, defines, program)) { LOGERROR(L"Failed to load shader '%hs'", name); program = CShaderProgramPtr(); } m_ProgramCache[key] = program; return program; } static GLenum ParseAttribSemantics(const CStr& str) { // Map known semantics onto the attribute locations documented by NVIDIA if (str == "gl_Vertex") return 0; if (str == "gl_Normal") return 2; if (str == "gl_Color") return 3; if (str == "gl_SecondaryColor") return 4; if (str == "gl_FogCoord") return 5; if (str == "gl_MultiTexCoord0") return 8; if (str == "gl_MultiTexCoord1") return 9; if (str == "gl_MultiTexCoord2") return 10; if (str == "gl_MultiTexCoord3") return 11; if (str == "gl_MultiTexCoord4") return 12; if (str == "gl_MultiTexCoord5") return 13; if (str == "gl_MultiTexCoord6") return 14; if (str == "gl_MultiTexCoord7") return 15; - // TODO: support user-defined semantics somehow + // Define some arbitrary names for user-defined attribute locations + // that won't conflict with any standard semantics + if (str == "CustomAttribute0") return 1; + if (str == "CustomAttribute1") return 6; + if (str == "CustomAttribute2") return 7; debug_warn("Invalid attribute semantics"); return 0; } bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefines, CShaderProgramPtr& program) { PROFILE2("loading shader"); PROFILE2_ATTR("name: %s", name); if (strncmp(name, "fixed:", 6) == 0) { program = CShaderProgramPtr(CShaderProgram::ConstructFFP(name+6, baseDefines)); if (!program) return false; program->Reload(); return true; } VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml"; CXeromyces XeroFile; PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); if (ret != PSRETURN_OK) return false; #if USE_SHADER_XML_VALIDATION { TIMER_ACCRUE(tc_ShaderValidation); // Serialize the XMB data and pass it to the validator XML_Start(); XML_SetPrettyPrint(false); XML_WriteXMB(XeroFile); bool ok = m_Validator.ValidateEncoded(wstring_from_utf8(name), XML_GetOutput()); if (!ok) return false; } #endif // Define all the elements and attributes used in the XML file #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) EL(attrib); EL(define); EL(fragment); EL(stream); EL(uniform); EL(vertex); AT(file); AT(if); AT(loc); AT(name); AT(semantics); AT(type); AT(value); #undef AT #undef EL CPreprocessorWrapper preprocessor; preprocessor.AddDefines(baseDefines); XMBElement Root = XeroFile.GetRoot(); bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl"); VfsPath vertexFile; VfsPath fragmentFile; CShaderDefines defines = baseDefines; std::map vertexUniforms; std::map fragmentUniforms; std::map vertexAttribs; int streamFlags = 0; XERO_ITER_EL(Root, Child) { if (Child.GetNodeName() == el_define) { defines.Add(Child.GetAttributes().GetNamedItem(at_name).c_str(), Child.GetAttributes().GetNamedItem(at_value).c_str()); } else if (Child.GetNodeName() == el_vertex) { vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); XERO_ITER_EL(Child, Param) { XMBAttributeList Attrs = Param.GetAttributes(); CStr cond = Attrs.GetNamedItem(at_if); if (!cond.empty() && !preprocessor.TestConditional(cond)) continue; if (Param.GetNodeName() == el_uniform) { vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt(); } else if (Param.GetNodeName() == el_stream) { CStr StreamName = Attrs.GetNamedItem(at_name); if (StreamName == "pos") streamFlags |= STREAM_POS; else if (StreamName == "normal") streamFlags |= STREAM_NORMAL; else if (StreamName == "color") streamFlags |= STREAM_COLOR; else if (StreamName == "uv0") streamFlags |= STREAM_UV0; else if (StreamName == "uv1") streamFlags |= STREAM_UV1; else if (StreamName == "uv2") streamFlags |= STREAM_UV2; else if (StreamName == "uv3") streamFlags |= STREAM_UV3; } else if (Param.GetNodeName() == el_attrib) { int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics)); vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc; } } } else if (Child.GetNodeName() == el_fragment) { fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); XERO_ITER_EL(Child, Param) { XMBAttributeList Attrs = Param.GetAttributes(); CStr cond = Attrs.GetNamedItem(at_if); if (!cond.empty() && !preprocessor.TestConditional(cond)) continue; if (Param.GetNodeName() == el_uniform) { fragmentUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt(); } } } } if (isGLSL) program = CShaderProgramPtr(CShaderProgram::ConstructGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamFlags)); else program = CShaderProgramPtr(CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags)); program->Reload(); // m_HotloadFiles[xmlFilename].insert(program); // TODO: should reload somehow when the XML changes m_HotloadFiles[vertexFile].insert(program); m_HotloadFiles[fragmentFile].insert(program); return true; } static GLenum ParseComparisonFunc(const CStr& str) { if (str == "never") return GL_NEVER; if (str == "always") return GL_ALWAYS; if (str == "less") return GL_LESS; if (str == "lequal") return GL_LEQUAL; if (str == "equal") return GL_EQUAL; if (str == "gequal") return GL_GEQUAL; if (str == "greater") return GL_GREATER; if (str == "notequal") return GL_NOTEQUAL; debug_warn("Invalid comparison func"); return GL_ALWAYS; } static GLenum ParseBlendFunc(const CStr& str) { if (str == "zero") return GL_ZERO; if (str == "one") return GL_ONE; if (str == "src_color") return GL_SRC_COLOR; if (str == "one_minus_src_color") return GL_ONE_MINUS_SRC_COLOR; if (str == "dst_color") return GL_DST_COLOR; if (str == "one_minus_dst_color") return GL_ONE_MINUS_DST_COLOR; if (str == "src_alpha") return GL_SRC_ALPHA; if (str == "one_minus_src_alpha") return GL_ONE_MINUS_SRC_ALPHA; if (str == "dst_alpha") return GL_DST_ALPHA; if (str == "one_minus_dst_alpha") return GL_ONE_MINUS_DST_ALPHA; if (str == "constant_color") return GL_CONSTANT_COLOR; if (str == "one_minus_constant_color") return GL_ONE_MINUS_CONSTANT_COLOR; if (str == "constant_alpha") return GL_CONSTANT_ALPHA; if (str == "one_minus_constant_alpha") return GL_ONE_MINUS_CONSTANT_ALPHA; if (str == "src_alpha_saturate") return GL_SRC_ALPHA_SATURATE; debug_warn("Invalid blend func"); return GL_ZERO; } size_t CShaderManager::EffectCacheKeyHash::operator()(const EffectCacheKey& key) const { size_t hash = 0; boost::hash_combine(hash, key.name.GetHash()); boost::hash_combine(hash, key.defines1.GetHash()); boost::hash_combine(hash, key.defines2.GetHash()); return hash; } bool CShaderManager::EffectCacheKey::operator==(const EffectCacheKey& b) const { return (name == b.name && defines1 == b.defines1 && defines2 == b.defines2); } CShaderTechniquePtr CShaderManager::LoadEffect(const char* name) { return LoadEffect(CStrIntern(name), CShaderDefines(), CShaderDefines()); } CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDefines& defines1, const CShaderDefines& defines2) { // Return the cached effect, if there is one EffectCacheKey key = { name, defines1, defines2 }; EffectCacheMap::iterator it = m_EffectCache.find(key); if (it != m_EffectCache.end()) return it->second; // First time we've seen this key, so construct a new effect: // Merge the two sets of defines, so NewEffect doesn't have to care about the split CShaderDefines defines(defines1); defines.SetMany(defines2); CShaderTechniquePtr tech(new CShaderTechnique()); if (!NewEffect(name.c_str(), defines, tech)) { LOGERROR(L"Failed to load effect '%hs'", name.c_str()); tech = CShaderTechniquePtr(); } m_EffectCache[key] = tech; return tech; } bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefines, CShaderTechniquePtr& tech) { PROFILE2("loading effect"); PROFILE2_ATTR("name: %s", name); // Shortcut syntax for effects that just contain a single shader if (strncmp(name, "shader:", 7) == 0) { CShaderProgramPtr program = LoadProgram(name+7, baseDefines); if (!program) return false; CShaderPass pass; pass.SetShader(program); tech->AddPass(pass); return true; } VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name) + L".xml"; CXeromyces XeroFile; PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); if (ret != PSRETURN_OK) return false; // Define all the elements and attributes used in the XML file #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) EL(alpha); EL(blend); EL(define); EL(depth); EL(pass); EL(require); EL(sort_by_distance); AT(context); AT(dst); AT(func); AT(ref); AT(shader); AT(shaders); AT(src); AT(mask); AT(name); AT(value); #undef AT #undef EL // Read some defines that influence how we pick techniques bool hasARB = (baseDefines.GetInt("SYS_HAS_ARB") != 0); bool hasGLSL = (baseDefines.GetInt("SYS_HAS_GLSL") != 0); bool preferGLSL = (baseDefines.GetInt("SYS_PREFER_GLSL") != 0); // Prepare the preprocessor for conditional tests CPreprocessorWrapper preprocessor; preprocessor.AddDefines(baseDefines); XMBElement Root = XeroFile.GetRoot(); // Find all the techniques that we can use, and their preference std::vector > usableTechs; XERO_ITER_EL(Root, Technique) { int preference = 0; bool isUsable = true; XERO_ITER_EL(Technique, Child) { XMBAttributeList Attrs = Child.GetAttributes(); if (Child.GetNodeName() == el_require) { if (Attrs.GetNamedItem(at_shaders) == "fixed") { // FFP not supported by OpenGL ES #if CONFIG2_GLES isUsable = false; #endif } else if (Attrs.GetNamedItem(at_shaders) == "arb") { if (!hasARB) isUsable = false; } else if (Attrs.GetNamedItem(at_shaders) == "glsl") { if (!hasGLSL) isUsable = false; if (preferGLSL) preference += 100; else preference -= 100; } else if (!Attrs.GetNamedItem(at_context).empty()) { CStr cond = Attrs.GetNamedItem(at_context); if (!preprocessor.TestConditional(cond)) isUsable = false; } } } if (isUsable) usableTechs.push_back(std::make_pair(Technique, preference)); } if (usableTechs.empty()) { debug_warn(L"Can't find a usable technique"); return false; } // Sort by preference, tie-break on order of specification std::stable_sort(usableTechs.begin(), usableTechs.end(), revcompare2nd()); CShaderDefines techDefines = baseDefines; XERO_ITER_EL(usableTechs[0].first, Child) { if (Child.GetNodeName() == el_define) { techDefines.Add(Child.GetAttributes().GetNamedItem(at_name).c_str(), Child.GetAttributes().GetNamedItem(at_value).c_str()); } else if (Child.GetNodeName() == el_sort_by_distance) { tech->SetSortByDistance(true); } else if (Child.GetNodeName() == el_pass) { CShaderDefines passDefines = techDefines; CShaderPass pass; XERO_ITER_EL(Child, Element) { if (Element.GetNodeName() == el_define) { passDefines.Add(Element.GetAttributes().GetNamedItem(at_name).c_str(), Element.GetAttributes().GetNamedItem(at_value).c_str()); } else if (Element.GetNodeName() == el_alpha) { GLenum func = ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func)); float ref = Element.GetAttributes().GetNamedItem(at_ref).ToFloat(); pass.AlphaFunc(func, ref); } else if (Element.GetNodeName() == el_blend) { GLenum src = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_src)); GLenum dst = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_dst)); pass.BlendFunc(src, dst); } else if (Element.GetNodeName() == el_depth) { if (!Element.GetAttributes().GetNamedItem(at_func).empty()) pass.DepthFunc(ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func))); if (!Element.GetAttributes().GetNamedItem(at_mask).empty()) pass.DepthMask(Element.GetAttributes().GetNamedItem(at_mask) == "true" ? 1 : 0); } } // Load the shader program after we've read all the possibly-relevant s pass.SetShader(LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines)); tech->AddPass(pass); } } return true; } size_t CShaderManager::GetNumEffectsLoaded() { return m_EffectCache.size(); } /*static*/ Status CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path) { return static_cast(param)->ReloadChangedFile(path); } Status CShaderManager::ReloadChangedFile(const VfsPath& path) { // Find all shaders using this file HotloadFilesMap::iterator files = m_HotloadFiles.find(path); if (files != m_HotloadFiles.end()) { // Reload all shaders using this file for (std::set >::iterator it = files->second.begin(); it != files->second.end(); ++it) { if (shared_ptr program = it->lock()) program->Reload(); } } // TODO: hotloading changes to shader XML files and effect XML files would be nice return INFO::OK; } Index: ps/trunk/source/graphics/ShaderProgram.h =================================================================== --- ps/trunk/source/graphics/ShaderProgram.h (revision 11488) +++ ps/trunk/source/graphics/ShaderProgram.h (revision 11489) @@ -1,206 +1,210 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_SHADERPROGRAM #define INCLUDED_SHADERPROGRAM #include "graphics/Texture.h" #include "lib/ogl.h" #include "lib/file/vfs/vfs_path.h" #include "lib/res/handle.h" #include "ps/CStr.h" #include struct CColor; class CMatrix3D; class CVector3D; class CShaderDefines; class CStrIntern; // Vertex data stream flags enum { STREAM_POS = (1 << 0), STREAM_NORMAL = (1 << 1), STREAM_COLOR = (1 << 2), STREAM_UV0 = (1 << 3), STREAM_UV1 = (1 << 4), STREAM_UV2 = (1 << 5), STREAM_UV3 = (1 << 6), STREAM_POSTOUV0 = (1 << 7), STREAM_POSTOUV1 = (1 << 8), STREAM_POSTOUV2 = (1 << 9), STREAM_POSTOUV3 = (1 << 10) }; /** * A compiled vertex+fragment shader program. * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax) * or GL_ARB_{vertex,fragment}_shader (GLSL), or may use hard-coded fixed-function * multitexturing setup code; the difference is hidden from the caller. * * Texture/uniform IDs are typically strings, corresponding to the names defined in * the shader .xml file. Alternatively (and more efficiently, if used very frequently), * call GetTextureBinding/GetUniformBinding and pass its return value as the ID. * Setting uniforms that the shader .xml doesn't support is harmless. */ class CShaderProgram { NONCOPYABLE(CShaderProgram); public: /** * Construct based on ARB vertex/fragment program files. */ static CShaderProgram* ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags); /** * Construct based on GLSL vertex/fragment shader files. */ static CShaderProgram* ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexAttribs, int streamflags); /** * Construct an instance of a pre-defined fixed-function pipeline setup. */ static CShaderProgram* ConstructFFP(const std::string& id, const CShaderDefines& defines); typedef const char* attrib_id_t; typedef const char* texture_id_t; typedef const char* uniform_id_t; /** * Represents a uniform attribute or texture binding. * For uniforms: * - ARB shaders store vertex location in 'first', fragment location in 'second'. * - GLSL shaders store uniform location in 'first', data type in 'second'. * - FFP shaders store -1 in 'first', index in 'second'. * For textures, all store texture target (e.g. GL_TEXTURE_2D) in 'first', texture unit in 'second'. * Non-existent bindings must store -1 in both. */ struct Binding { Binding(int a, int b) : first(a), second(b) { } Binding() : first(-1), second(-1) { } /** * Returns whether this uniform attribute is active in the shader. * If not then there's no point calling Uniform() to set its value. */ bool Active() { return first != -1 || second != -1; } int first; int second; }; virtual ~CShaderProgram() { } virtual void Reload() = 0; /** * Returns whether this shader was successfully loaded. */ bool IsValid() const; /** * Binds the shader into the GL context. Call this before calling Uniform() * or trying to render with it. */ virtual void Bind() = 0; /** * Unbinds the shader from the GL context. Call this after rendering with it. */ virtual void Unbind() = 0; /** * Returns bitset of STREAM_* value, indicating what vertex data streams the * vertex shader needs. */ int GetStreamFlags() const; // TODO: implement vertex attributes GLuint GetAttribIndex(attrib_id_t id); virtual Binding GetTextureBinding(texture_id_t id) = 0; // Variants of texture binding: void BindTexture(texture_id_t id, CTexturePtr tex); virtual void BindTexture(texture_id_t id, Handle tex) = 0; virtual void BindTexture(texture_id_t id, GLuint tex) = 0; virtual void BindTexture(Binding id, Handle tex) = 0; virtual Binding GetUniformBinding(uniform_id_t id) = 0; virtual Binding GetUniformBinding(CStrIntern id) = 0; // Uniform-setting methods that subclasses must define: virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) = 0; virtual void Uniform(Binding id, const CMatrix3D& v) = 0; + virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) = 0; // Convenient uniform-setting wrappers: void Uniform(Binding id, int v); void Uniform(Binding id, float v); void Uniform(Binding id, float v0, float v1); void Uniform(Binding id, const CVector3D& v); void Uniform(Binding id, const CColor& v); void Uniform(uniform_id_t id, int v); void Uniform(uniform_id_t id, float v); void Uniform(uniform_id_t id, float v0, float v1); void Uniform(uniform_id_t id, const CVector3D& v); void Uniform(uniform_id_t id, const CColor& v); void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3); void Uniform(uniform_id_t id, const CMatrix3D& v); + void Uniform(uniform_id_t id, size_t count, const CMatrix3D* v); // Vertex attribute pointers (equivalent to glVertexPointer etc): virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer); virtual void NormalPointer(GLenum type, GLsizei stride, void* pointer); virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer); virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer); + virtual void VertexAttribPointer(const char* id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void* pointer); + virtual void VertexAttribIPointer(const char* id, GLint size, GLenum type, GLsizei stride, void* pointer); /** * Checks that all the required vertex attributes have been set. * Call this before calling glDrawArrays/glDrawElements etc to avoid potential crashes. */ void AssertPointersBound(); protected: CShaderProgram(int streamflags); bool m_IsValid; int m_StreamFlags; // Non-GLSL client state handling: void BindClientStates(); void UnbindClientStates(); int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind }; typedef shared_ptr CShaderProgramPtr; #endif // INCLUDED_SHADERPROGRAM Index: ps/trunk/source/graphics/ShaderProgramFFP.cpp =================================================================== --- ps/trunk/source/graphics/ShaderProgramFFP.cpp (revision 11488) +++ ps/trunk/source/graphics/ShaderProgramFFP.cpp (revision 11489) @@ -1,968 +1,972 @@ /* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "ShaderProgram.h" #include "graphics/ShaderDefines.h" #include "graphics/TextureManager.h" #include "lib/res/graphics/ogl_tex.h" #include "maths/Matrix3D.h" #include "maths/Vector3D.h" #include "ps/CLogger.h" #include "ps/Overlay.h" #include "renderer/Renderer.h" #if !CONFIG2_GLES /** * CShaderProgramFFP allows rendering code to use the shader-based API * even if the 'shader' is actually implemented with the fixed-function * pipeline instead of anything programmable. * * Currently we just hard-code a number of FFP programs as subclasses of this. * If we have lots, it might be nicer to abstract out the common functionality * and load these from text files or something. */ class CShaderProgramFFP : public CShaderProgram { public: CShaderProgramFFP(int streamflags) : CShaderProgram(streamflags) { } ~CShaderProgramFFP() { } virtual void Reload() { m_IsValid = true; } int GetUniformIndex(CStrIntern id) { std::map::iterator it = m_UniformIndexes.find(id); if (it == m_UniformIndexes.end()) return -1; return it->second; } virtual Binding GetTextureBinding(uniform_id_t id) { int index = GetUniformIndex(CStrIntern(id)); if (index == -1) return Binding(); else return Binding((int)GL_TEXTURE_2D, index); } virtual void BindTexture(texture_id_t id, Handle tex) { int index = GetUniformIndex(CStrIntern(id)); if (index != -1) ogl_tex_bind(tex, index); } virtual void BindTexture(texture_id_t id, GLuint tex) { int index = GetUniformIndex(CStrIntern(id)); if (index != -1) { pglActiveTextureARB((int)(GL_TEXTURE0+index)); glBindTexture(GL_TEXTURE_2D, tex); } } virtual void BindTexture(Binding id, Handle tex) { int index = id.second; if (index != -1) ogl_tex_bind(tex, index); } virtual Binding GetUniformBinding(uniform_id_t id) { return Binding(-1, GetUniformIndex(CStrIntern(id))); } virtual Binding GetUniformBinding(CStrIntern id) { return Binding(-1, GetUniformIndex(id)); } virtual void Uniform(Binding UNUSED(id), float UNUSED(v0), float UNUSED(v1), float UNUSED(v2), float UNUSED(v3)) { } virtual void Uniform(Binding UNUSED(id), const CMatrix3D& UNUSED(v)) { } + virtual void Uniform(Binding UNUSED(id), size_t UNUSED(count), const CMatrix3D* UNUSED(v)) + { + } + protected: std::map m_UniformIndexes; void SetUniformIndex(const char* id, int value) { m_UniformIndexes[CStrIntern(id)] = value; } }; ////////////////////////////////////////////////////////////////////////// /** * A shader that does nothing but provide a shader-compatible interface to * fixed-function features, for compatibility with existing fixed-function * code that isn't fully ported to the shader API. */ class CShaderProgramFFP_Dummy : public CShaderProgramFFP { public: CShaderProgramFFP_Dummy() : CShaderProgramFFP(0) { // Texture units, for when this shader is used with terrain: SetUniformIndex("baseTex", 0); } virtual void Bind() { BindClientStates(); } virtual void Unbind() { UnbindClientStates(); } }; ////////////////////////////////////////////////////////////////////////// class CShaderProgramFFP_OverlayLine : public CShaderProgramFFP { // Uniforms enum { ID_losTransform, ID_objectColor }; bool m_IgnoreLos; public: CShaderProgramFFP_OverlayLine(const CShaderDefines& defines) : CShaderProgramFFP(STREAM_POS | STREAM_UV0 | STREAM_UV1) { SetUniformIndex("losTransform", ID_losTransform); SetUniformIndex("objectColor", ID_objectColor); // Texture units: SetUniformIndex("baseTex", 0); SetUniformIndex("maskTex", 1); SetUniformIndex("losTex", 2); m_IgnoreLos = (defines.GetInt("IGNORE_LOS") != 0); } bool IsIgnoreLos() { return m_IgnoreLos; } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.second == ID_losTransform) { pglActiveTextureARB(GL_TEXTURE2); GLfloat texgenS1[4] = { v0, 0, 0, v1 }; GLfloat texgenT1[4] = { 0, 0, v0, v1 }; glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1); glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1); } else if (id.second == ID_objectColor) { float c[] = { v0, v1, v2, v3 }; pglActiveTextureARB(GL_TEXTURE1); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, c); } else { debug_warn(L"Invalid id"); } } virtual void Uniform(Binding UNUSED(id), const CMatrix3D& UNUSED(v)) { debug_warn(L"Not implemented"); } virtual void Bind() { // RGB channels: // Unit 0: Load base texture // Unit 1: Load mask texture; interpolate with objectColor & base // Unit 2: (Load LOS texture; multiply) if not #IGNORE_LOS, pass through otherwise // Alpha channel: // Unit 0: Load base texture // Unit 1: Multiply by objectColor // Unit 2: Pass through pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); 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_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); // ----------------------------------------------------------------------------- pglActiveTextureARB(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); // Uniform() sets GL_TEXTURE_ENV_COLOR // load mask texture; interpolate with objectColor and base; GL_INTERPOLATE takes 3 arguments: // a0 * a2 + a1 * (1 - a2) glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA); // ----------------------------------------------------------------------------- pglActiveTextureARB(GL_TEXTURE2); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); bool ignoreLos = IsIgnoreLos(); if (ignoreLos) { // RGB pass through glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); } else { // multiply RGB with LoS texture alpha channel glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); // Uniform() sets GL_OBJECT_PLANE values glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA); } // alpha pass through glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); BindClientStates(); } virtual void Unbind() { UnbindClientStates(); pglActiveTextureARB(GL_TEXTURE2); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); pglActiveTextureARB(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); } }; ////////////////////////////////////////////////////////////////////////// class CShaderProgramFFP_GuiText : public CShaderProgramFFP { // Uniforms enum { ID_transform, ID_colorMul }; public: CShaderProgramFFP_GuiText() : CShaderProgramFFP(STREAM_POS | STREAM_UV0) { SetUniformIndex("transform", ID_transform); SetUniformIndex("colorMul", ID_colorMul); // Texture units: SetUniformIndex("tex", 0); } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.second == ID_colorMul) glColor4f(v0, v1, v2, v3); } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.second == ID_transform) glLoadMatrixf(&v._11); } virtual void Bind() { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); BindClientStates(); } virtual void Unbind() { UnbindClientStates(); pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } }; ////////////////////////////////////////////////////////////////////////// class CShaderProgramFFP_Gui_Base : public CShaderProgramFFP { protected: // Uniforms enum { ID_transform, ID_color }; public: CShaderProgramFFP_Gui_Base(int streamflags) : CShaderProgramFFP(streamflags) { SetUniformIndex("transform", ID_transform); SetUniformIndex("color", ID_color); // Texture units: SetUniformIndex("tex", 0); } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.second == ID_transform) glLoadMatrixf(&v._11); } virtual void Bind() { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); BindClientStates(); } virtual void Unbind() { UnbindClientStates(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } }; class CShaderProgramFFP_GuiBasic : public CShaderProgramFFP_Gui_Base { public: CShaderProgramFFP_GuiBasic() : CShaderProgramFFP_Gui_Base(STREAM_POS | STREAM_UV0) { } virtual void Bind() { CShaderProgramFFP_Gui_Base::Bind(); pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } virtual void Unbind() { pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); CShaderProgramFFP_Gui_Base::Unbind(); } }; class CShaderProgramFFP_GuiAdd : public CShaderProgramFFP_Gui_Base { public: CShaderProgramFFP_GuiAdd() : CShaderProgramFFP_Gui_Base(STREAM_POS | STREAM_UV0) { } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.second == ID_color) glColor4f(v0, v1, v2, v3); } virtual void Bind() { CShaderProgramFFP_Gui_Base::Bind(); pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); } virtual void Unbind() { glColor4f(1.f, 1.f, 1.f, 1.f); pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); CShaderProgramFFP_Gui_Base::Unbind(); } }; class CShaderProgramFFP_GuiGrayscale : public CShaderProgramFFP_Gui_Base { public: CShaderProgramFFP_GuiGrayscale() : CShaderProgramFFP_Gui_Base(STREAM_POS | STREAM_UV0) { } virtual void Bind() { CShaderProgramFFP_Gui_Base::Bind(); /* For the main conversion, use GL_DOT3_RGB, which is defined as L = 4 * ((Arg0r - 0.5) * (Arg1r - 0.5)+ (Arg0g - 0.5) * (Arg1g - 0.5)+ (Arg0b - 0.5) * (Arg1b - 0.5)) where each of the RGB components is given the value 'L'. Use the magical luminance formula L = 0.3R + 0.59G + 0.11B to calculate the greyscale value. But to work around the annoying "Arg0-0.5", we need to calculate Arg0+0.5. But we also need to scale it into the range 0.5-1.0, else Arg0>0.5 will be clamped to 1.0. So use GL_INTERPOLATE, which outputs: A0 * A2 + A1 * (1 - A2) and set A2 = 0.5, A1 = 1.0, and A0 = texture (i.e. interpolating halfway between the texture and {1,1,1}) giving A0/2 + 0.5 and use that as Arg0. So L = 4*(A0/2 * (Arg1-.5)) = 2 (Rx+Gy+Bz) (where Arg1 = {x+0.5, y+0.5, z+0.5}) = 2x R + 2y G + 2z B = 0.3R + 0.59G + 0.11B so e.g. 2y = 0.59 = 2(Arg1g-0.5) => Arg1g = 0.59/2+0.5 which fortunately doesn't get clamped. So, just implement that: */ static const float GreyscaleDotColor[4] = { 0.3f / 2.f + 0.5f, 0.59f / 2.f + 0.5f, 0.11f / 2.f + 0.5f, 1.0f }; static const float GreyscaleInterpColor0[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; static const float GreyscaleInterpColor1[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GreyscaleInterpColor0); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glColor4fv(GreyscaleInterpColor1); pglActiveTextureARB(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB); // GL_DOT3_RGB requires GL_(EXT|ARB)_texture_env_dot3. // We currently don't bother implementing a fallback because it's // only lacking on Riva-class HW, but at least want the rest of the // game to run there without errors. Therefore, squelch the // OpenGL error that's raised if they aren't actually present. // Note: higher-level code checks for this extension, but // allows users the choice of continuing even if not present. ogl_SquelchError(GL_INVALID_ENUM); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GreyscaleDotColor); // To activate the second texture unit, we have to have some kind // of texture bound into it, but we don't actually use the texture data, // so bind a dummy texture g_Renderer.GetTextureManager().GetErrorTexture()->Bind(1); } virtual void Unbind() { glColor4f(1.f, 1.f, 1.f, 1.f); pglActiveTextureARB(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); CShaderProgramFFP_Gui_Base::Unbind(); } }; class CShaderProgramFFP_GuiSolid : public CShaderProgramFFP_Gui_Base { public: CShaderProgramFFP_GuiSolid() : CShaderProgramFFP_Gui_Base(STREAM_POS) { } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.second == ID_color) glColor4f(v0, v1, v2, v3); } virtual void Bind() { CShaderProgramFFP_Gui_Base::Bind(); pglActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); } }; ////////////////////////////////////////////////////////////////////////// /** * Common functionality for model rendering in the fixed renderpath. */ class CShaderProgramFFP_Model_Base : public CShaderProgramFFP { protected: // Uniforms enum { ID_transform, ID_objectColor, ID_playerColor }; public: CShaderProgramFFP_Model_Base(const CShaderDefines& defines, int streamflags) : CShaderProgramFFP(streamflags) { SetUniformIndex("transform", ID_transform); if (defines.GetInt("USE_OBJECTCOLOR")) SetUniformIndex("objectColor", ID_objectColor); if (defines.GetInt("USE_PLAYERCOLOR")) SetUniformIndex("playerColor", ID_playerColor); // Texture units: SetUniformIndex("baseTex", 0); } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.second == ID_transform) glLoadMatrixf(&v._11); } virtual void Bind() { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); BindClientStates(); } virtual void Unbind() { UnbindClientStates(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } }; /** * Basic non-recolored diffuse-textured model rendering. */ class CShaderProgramFFP_Model : public CShaderProgramFFP_Model_Base { public: CShaderProgramFFP_Model(const CShaderDefines& defines) : CShaderProgramFFP_Model_Base(defines, STREAM_POS | STREAM_COLOR | STREAM_UV0) { } virtual void Bind() { // Set up texture environment for base pass - modulate texture and vertex color pglActiveTextureARB(GL_TEXTURE0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); // Copy alpha channel from texture glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); // The vertex color is scaled by 0.5 to permit overbrightness without clamping. // We therefore need to scale by 2.0 after the modulation, and before any // further clamping, to get the right color. float scale2[] = { 2.0f, 2.0f, 2.0f }; glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale2); CShaderProgramFFP_Model_Base::Bind(); } virtual void Unbind() { CShaderProgramFFP_Model_Base::Unbind(); pglActiveTextureARB(GL_TEXTURE0); // Revert the scaling to default float scale1[] = { 1.0f, 1.0f, 1.0f }; glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale1); } }; /** * Player-coloring diffuse-textured model rendering. */ class CShaderProgramFFP_ModelColor : public CShaderProgramFFP_Model_Base { public: CShaderProgramFFP_ModelColor(const CShaderDefines& defines) : CShaderProgramFFP_Model_Base(defines, STREAM_POS | STREAM_COLOR | STREAM_UV0) { } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.second == ID_objectColor || id.second == ID_playerColor) { // (Player color and object color are mutually exclusive) float color[] = { v0, v1, v2, v3 }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); } } virtual void Bind() { // Player color uses a single pass with three texture environments // Note: This uses ARB_texture_env_crossbar (which is checked in GameSetup), // and it requires MAX_TEXTURE_IMAGE_UNITS >= 3 (which only excludes GF2MX/GF4MX) // // We calculate: Result = Color*Texture*(PlayerColor*(1-Texture.a) + 1.0*Texture.a) // Algebra gives us: // Result = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture*Color // TexEnv #0 pglActiveTextureARB(GL_TEXTURE0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_ONE_MINUS_SRC_COLOR); // Don't care about alpha; set it to something harmless glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); // TexEnv #1 pglActiveTextureARB(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); // Don't care about alpha; set it to something harmless glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); // TexEnv #2 pglActiveTextureARB(GL_TEXTURE2); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); // Don't care about alpha; set it to something harmless glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); // Scale colors at the end of all the computation (see CShaderProgramFFP_Model::Bind) float scale[] = { 2.0f, 2.0f, 2.0f }; glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale); // Need to bind some kind of texture to enable the texture units. // Unit 0 has baseTex, but the others need a texture. g_Renderer.GetTextureManager().GetErrorTexture()->Bind(1); g_Renderer.GetTextureManager().GetErrorTexture()->Bind(2); CShaderProgramFFP_Model_Base::Bind(); } virtual void Unbind() { CShaderProgramFFP_Model_Base::Unbind(); pglActiveTextureARB(GL_TEXTURE2); glDisable(GL_TEXTURE_2D); float scale[] = { 1.0f, 1.0f, 1.0f }; glTexEnvfv(GL_TEXTURE_ENV, GL_RGB_SCALE, scale); pglActiveTextureARB(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); pglActiveTextureARB(GL_TEXTURE0); } }; /** * Optionally-player-colored untextured model rendering. */ class CShaderProgramFFP_ModelSolid : public CShaderProgramFFP_Model_Base { public: CShaderProgramFFP_ModelSolid(const CShaderDefines& defines) : CShaderProgramFFP_Model_Base(defines, STREAM_POS) { } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.second == ID_playerColor) { float color[] = { v0, v1, v2, v3 }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); } } virtual void Bind() { float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); CShaderProgramFFP_Model_Base::Bind(); } }; /** * Plain unlit texture model rendering, for e.g. alpha-blended shadow casters. */ class CShaderProgramFFP_ModelSolidTex : public CShaderProgramFFP_Model_Base { public: CShaderProgramFFP_ModelSolidTex(const CShaderDefines& defines) : CShaderProgramFFP_Model_Base(defines, STREAM_POS | STREAM_UV0) { } virtual void Bind() { pglActiveTextureARB(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); CShaderProgramFFP_Model_Base::Bind(); } }; ////////////////////////////////////////////////////////////////////////// /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& id, const CShaderDefines& defines) { if (id == "dummy") return new CShaderProgramFFP_Dummy(); if (id == "overlayline") return new CShaderProgramFFP_OverlayLine(defines); if (id == "gui_text") return new CShaderProgramFFP_GuiText(); if (id == "gui_basic") return new CShaderProgramFFP_GuiBasic(); if (id == "gui_add") return new CShaderProgramFFP_GuiAdd(); if (id == "gui_grayscale") return new CShaderProgramFFP_GuiGrayscale(); if (id == "gui_solid") return new CShaderProgramFFP_GuiSolid(); if (id == "solid") return new CShaderProgramFFP_GuiSolid(); // works for non-GUI objects too if (id == "model") return new CShaderProgramFFP_Model(defines); if (id == "model_color") return new CShaderProgramFFP_ModelColor(defines); if (id == "model_solid") return new CShaderProgramFFP_ModelSolid(defines); if (id == "model_solid_tex") return new CShaderProgramFFP_ModelSolidTex(defines); LOGERROR(L"CShaderProgram::ConstructFFP: '%hs': Invalid id", id.c_str()); debug_warn(L"CShaderProgram::ConstructFFP: Invalid id"); return NULL; } #else // CONFIG2_GLES /*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& UNUSED(id), const CShaderDefines& UNUSED(defines)) { debug_warn(L"CShaderProgram::ConstructFFP: FFP not supported on this device"); return NULL; } #endif // CONFIG2_GLES Index: ps/trunk/source/lib/external_libraries/glext_funcs.h =================================================================== --- ps/trunk/source/lib/external_libraries/glext_funcs.h (revision 11488) +++ ps/trunk/source/lib/external_libraries/glext_funcs.h (revision 11489) @@ -1,359 +1,395 @@ /* Copyright (c) 2011 Wildfire Games * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * OpenGL extension function declarations (X macros). */ #include "lib/config2.h" // CONFIG2_GLES #if CONFIG2_GLES # include #elif OS_MACOSX # include #else # include #endif #if OS_WIN # include #endif /* FUNC is used for functions that are only extensions. FUNC2 is used for functions that have been promoted to core features. FUNC3 is used for functions that have been promoted to core features but have slightly changed semantics and need to be referred to by their core name instead of extension name. The FUNC2/FUNC3 calls include the version of OpenGL in which the extension was promoted, and the pre- and post-promotion names (e.g. "glBindBufferARB" vs "glBindBuffer"). If the GL driver is advertising a sufficiently high version, we load the promoted name; otherwise we use the *ARB name. (The spec says: "GL implementations of such later revisions should continue to export the name strings of promoted extensions in the EXTENSIONS string, and continue to support the ARB-affixed versions of functions and enumerants as a transition aid." but some drivers might be stupid/buggy and fail to do that, so we don't just use the ARB names unconditionally.) The names are made accessible to engine code only via the ARB name, to make it obvious that care must be taken (i.e. by being certain that the extension is actually supported). */ #if CONFIG2_GLES // no GLES extensions used yet // some functions that are extensions in GL are core functions in GLES, // so we should use them without the function pointer indirection #define pglActiveTextureARB glActiveTexture #define pglBlendColorEXT glBlendColor #define pglBlendEquationEXT glBlendEquation #define pglClientActiveTextureARB glClientActiveTexture #define pglCompressedTexImage2DARB glCompressedTexImage2D #define pglAttachObjectARB glAttachShader #define pglBindAttribLocationARB glBindAttribLocation #define pglCompileShaderARB glCompileShader #define pglCreateProgramObjectARB glCreateProgram #define pglCreateShaderObjectARB glCreateShader #define pglDeleteProgram glDeleteProgram #define pglDeleteShader glDeleteShader #define pglDisableVertexAttribArrayARB glDisableVertexAttribArray #define pglEnableVertexAttribArrayARB glEnableVertexAttribArray #define pglGetActiveUniformARB glGetActiveUniform #define pglGetProgramiv glGetProgramiv #define pglGetProgramInfoLog glGetProgramInfoLog #define pglGetShaderiv glGetShaderiv #define pglGetShaderInfoLog glGetShaderInfoLog #define pglGetUniformLocationARB glGetUniformLocation #define pglLinkProgramARB glLinkProgram #define pglShaderSourceARB glShaderSource #define pglUniform1fARB glUniform1i #define pglUniform2fARB glUniform2f #define pglUniform3fARB glUniform3f #define pglUniform4fARB glUniform4f #define pglUniform1iARB glUniform1i #define pglUniformMatrix4fvARB glUniformMatrix4fv #define pglUseProgramObjectARB glUseProgram #define pglVertexAttribPointerARB glVertexAttribPointer #define pglBindBufferARB glBindBuffer #define pglBufferDataARB glBufferData #define pglBufferSubDataARB glBufferSubData #define pglDeleteBuffersARB glDeleteBuffers #define pglGenBuffersARB glGenBuffers #define pglBindFramebufferEXT glBindFramebuffer #define pglCheckFramebufferStatusEXT glCheckFramebufferStatus #define pglDeleteFramebuffersEXT glDeleteFramebuffers #define pglFramebufferTexture2DEXT glFramebufferTexture2D #define pglGenFramebuffersEXT glGenFramebuffers #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER #define GL_CLAMP_TO_BORDER GL_CLAMP_TO_EDGE // TODO: should fix code that relies on GL_CLAMP_TO_BORDER typedef GLuint GLhandleARB; #else // were these defined as real functions in gl.h already? // GL_EXT_draw_range_elements / GL1.2: FUNC2(void, glDrawRangeElementsEXT, glDrawRangeElements, "1.2", (GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoid*)) // GL_ARB_multitexture / GL1.3: FUNC2(void, glMultiTexCoord2fARB, glMultiTexCoord2f, "1.3", (int, float, float)) FUNC2(void, glMultiTexCoord3fARB, glMultiTexCoord3f, "1.3", (int, float, float, float)) FUNC2(void, glActiveTextureARB, glActiveTexture, "1.3", (int)) FUNC2(void, glClientActiveTextureARB, glClientActiveTexture, "1.3", (int)) // GL_EXT_blend_color / GL1.4 (optional in 1.2): FUNC2(void, glBlendColorEXT, glBlendColor, "1.4", (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) // GL_EXT_blend_minmax / GL1.4 (optional in 1.2): FUNC2(void, glBlendEquationEXT, glBlendEquation, "1.4", (GLenum mode)) // GL_ARB_vertex_buffer_object / GL1.5: FUNC2(void, glBindBufferARB, glBindBuffer, "1.5", (int target, GLuint buffer)) FUNC2(void, glDeleteBuffersARB, glDeleteBuffers, "1.5", (GLsizei n, const GLuint* buffers)) FUNC2(void, glGenBuffersARB, glGenBuffers, "1.5", (GLsizei n, GLuint* buffers)) FUNC2(bool, glIsBufferARB, glIsBuffer, "1.5", (GLuint buffer)) FUNC2(void, glBufferDataARB, glBufferData, "1.5", (int target, GLsizeiptrARB size, const void* data, int usage)) FUNC2(void, glBufferSubDataARB, glBufferSubData, "1.5", (int target, GLintptrARB offset, GLsizeiptrARB size, const void* data)) FUNC2(void, glGetBufferSubDataARB, glGetBufferSubData, "1.5", (int target, GLintptrARB offset, GLsizeiptrARB size, void* data)) FUNC2(void*, glMapBufferARB, glMapBuffer, "1.5", (int target, int access)) FUNC2(bool, glUnmapBufferARB, glUnmapBuffer, "1.5", (int target)) FUNC2(void, glGetBufferParameterivARB, glGetBufferParameteriv, "1.5", (int target, int pname, int* params)) FUNC2(void, glGetBufferPointervARB, glGetBufferPointerv, "1.5", (int target, int pname, void** params)) // GL_ARB_texture_compression / GL1.3 FUNC2(void, glCompressedTexImage3DARB, glCompressedTexImage3D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)) FUNC2(void, glCompressedTexImage2DARB, glCompressedTexImage2D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)) FUNC2(void, glCompressedTexImage1DARB, glCompressedTexImage1D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*)) FUNC2(void, glCompressedTexSubImage3DARB, glCompressedTexSubImage3D, "1.3", (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)) FUNC2(void, glCompressedTexSubImage2DARB, glCompressedTexSubImage2D, "1.3", (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)) FUNC2(void, glCompressedTexSubImage1DARB, glCompressedTexSubImage1D, "1.3", (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*)) FUNC2(void, glGetCompressedTexImageARB, glGetCompressedTexImage, "1.3", (GLenum, GLint, GLvoid*)) // GL_EXT_framebuffer_object FUNC(GLboolean, glIsRenderbufferEXT, (GLuint renderbuffer)) FUNC(void, glBindRenderbufferEXT, (GLenum target, GLuint renderbuffer)) FUNC(void, glDeleteRenderbuffersEXT, (GLsizei n, const GLuint *renderbuffers)) FUNC(void, glGenRenderbuffersEXT, (GLsizei n, GLuint *renderbuffers)) FUNC(void, glRenderbufferStorageEXT, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) FUNC(void, glGetRenderbufferParameterivEXT, (GLenum target, GLenum pname, GLint *params)) FUNC(GLboolean, glIsFramebufferEXT, (GLuint framebuffer)) FUNC(void, glBindFramebufferEXT, (GLenum target, GLuint framebuffer)) FUNC(void, glDeleteFramebuffersEXT, (GLsizei n, const GLuint *framebuffers)) FUNC(void, glGenFramebuffersEXT, (GLsizei n, GLuint *framebuffers)) FUNC(GLenum, glCheckFramebufferStatusEXT, (GLenum target)) FUNC(void, glFramebufferTexture1DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) FUNC(void, glFramebufferTexture2DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) FUNC(void, glFramebufferTexture3DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)) FUNC(void, glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum attachment, GLenum pname, GLint *params)) FUNC(void, glGenerateMipmapEXT, (GLenum target)) // GL_ARB_vertex_program, GL_ARB_fragment_program FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string)) FUNC(void, glBindProgramARB, (GLenum target, GLuint program)) FUNC(void, glDeleteProgramsARB, (GLsizei n, const GLuint *programs)) FUNC(void, glGenProgramsARB, (GLsizei n, GLuint *programs)) FUNC(void, glProgramEnvParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) FUNC(void, glProgramEnvParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params)) FUNC(void, glProgramEnvParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)) FUNC(void, glProgramEnvParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params)) FUNC(void, glProgramLocalParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) FUNC(void, glProgramLocalParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params)) FUNC(void, glProgramLocalParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)) FUNC(void, glProgramLocalParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params)) FUNC(void, glGetProgramEnvParameterdvARB, (GLenum target, GLuint index, GLdouble *params)) FUNC(void, glGetProgramEnvParameterfvARB, (GLenum target, GLuint index, GLfloat *params)) FUNC(void, glGetProgramLocalParameterdvARB, (GLenum target, GLuint index, GLdouble *params)) FUNC(void, glGetProgramLocalParameterfvARB, (GLenum target, GLuint index, GLfloat *params)) FUNC(void, glGetProgramivARB, (GLenum target, GLenum pname, GLint *params)) FUNC(void, glGetProgramStringARB, (GLenum target, GLenum pname, GLvoid *string)) FUNC(GLboolean, glIsProgramARB, (GLuint program)) // GL_ARB_shader_objects // (NOTE: Many of these have "Object" in their ARB names, but "Program" or "Shader" in their core names. // When both Program and Shader versions exist, we use FUNC3 here and the engine must call the specific // core name instead of the generic ARB name.) FUNC3(void, glDeleteObjectARB, glDeleteShader, "2.0", (GLhandleARB obj)) FUNC3(void, glDeleteObjectARB, glDeleteProgram, "2.0", (GLhandleARB obj)) // FUNC2(GLhandleARB, glGetHandleARB, glGetHandle, "2.0", (GLenum pname)) // there is no analog to the ARB function in GL 2.0 (the functionality is probably moved into glGetIntegerv(GL_CURRENT_PROGRAM)) // so we can't represent it in this FUNC2 system, so just pretend it doesn't exist FUNC2(void, glDetachObjectARB, glDetachShader, "2.0", (GLhandleARB containerObj, GLhandleARB attachedObj)) FUNC2(GLhandleARB, glCreateShaderObjectARB, glCreateShader, "2.0", (GLenum shaderType)) FUNC2(void, glShaderSourceARB, glShaderSource, "2.0", (GLhandleARB shaderObj, GLsizei count, const char **string, const GLint *length)) FUNC2(void, glCompileShaderARB, glCompileShader, "2.0", (GLhandleARB shaderObj)) FUNC2(GLhandleARB, glCreateProgramObjectARB, glCreateProgram, "2.0", (void)) FUNC2(void, glAttachObjectARB, glAttachShader, "2.0", (GLhandleARB containerObj, GLhandleARB obj)) FUNC2(void, glLinkProgramARB, glLinkProgram, "2.0", (GLhandleARB programObj)) FUNC2(void, glUseProgramObjectARB, glUseProgram, "2.0", (GLhandleARB programObj)) FUNC2(void, glValidateProgramARB, glValidateProgram, "2.0", (GLhandleARB programObj)) FUNC2(void, glUniform1fARB, glUniform1f, "2.0", (GLint location, GLfloat v0)) FUNC2(void, glUniform2fARB, glUniform2f, "2.0", (GLint location, GLfloat v0, GLfloat v1)) FUNC2(void, glUniform3fARB, glUniform3f, "2.0", (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)) FUNC2(void, glUniform4fARB, glUniform4f, "2.0", (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)) FUNC2(void, glUniform1iARB, glUniform1i, "2.0", (GLint location, GLint v0)) FUNC2(void, glUniform2iARB, glUniform2i, "2.0", (GLint location, GLint v0, GLint v1)) FUNC2(void, glUniform3iARB, glUniform3i, "2.0", (GLint location, GLint v0, GLint v1, GLint v2)) FUNC2(void, glUniform4iARB, glUniform4i, "2.0", (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)) FUNC2(void, glUniform1fvARB, glUniform1fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) FUNC2(void, glUniform2fvARB, glUniform2fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) FUNC2(void, glUniform3fvARB, glUniform3fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) FUNC2(void, glUniform4fvARB, glUniform4fv, "2.0", (GLint location, GLsizei count, const GLfloat *value)) FUNC2(void, glUniform1ivARB, glUniform1iv, "2.0", (GLint location, GLsizei count, const GLint *value)) FUNC2(void, glUniform2ivARB, glUniform2iv, "2.0", (GLint location, GLsizei count, const GLint *value)) FUNC2(void, glUniform3ivARB, glUniform3iv, "2.0", (GLint location, GLsizei count, const GLint *value)) FUNC2(void, glUniform4ivARB, glUniform4iv, "2.0", (GLint location, GLsizei count, const GLint *value)) FUNC2(void, glUniformMatrix2fvARB, glUniformMatrix2fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) FUNC2(void, glUniformMatrix3fvARB, glUniformMatrix3fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) FUNC2(void, glUniformMatrix4fvARB, glUniformMatrix4fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) FUNC3(void, glGetObjectParameterfvARB, glGetProgramfv, "2.0", (GLhandleARB obj, GLenum pname, GLfloat *params)) FUNC3(void, glGetObjectParameterfvARB, glGetShaderfv, "2.0", (GLhandleARB obj, GLenum pname, GLfloat *params)) FUNC3(void, glGetObjectParameterivARB, glGetProgramiv, "2.0", (GLhandleARB obj, GLenum pname, GLint *params)) FUNC3(void, glGetObjectParameterivARB, glGetShaderiv, "2.0", (GLhandleARB obj, GLenum pname, GLint *params)) FUNC3(void, glGetInfoLogARB, glGetProgramInfoLog, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, char *infoLog)) FUNC3(void, glGetInfoLogARB, glGetShaderInfoLog, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, char *infoLog)) FUNC2(void, glGetAttachedObjectsARB, glGetAttachedShaders, "2.0", (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj)) FUNC2(GLint, glGetUniformLocationARB, glGetUniformLocation, "2.0", (GLhandleARB programObj, const char *name)) FUNC2(void, glGetActiveUniformARB, glGetActiveUniform, "2.0", (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, char *name)) FUNC2(void, glGetUniformfvARB, glGetUniformfv, "2.0", (GLhandleARB programObj, GLint location, GLfloat *params)) FUNC2(void, glGetUniformivARB, glGetUniformiv, "2.0", (GLhandleARB programObj, GLint location, GLint *params)) FUNC2(void, glGetShaderSourceARB, glGetShaderSource, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source)) // GL_ARB_vertex_shader FUNC2(void, glVertexAttrib1fARB, glVertexAttrib1f, "2.0", (GLuint index, GLfloat v0)) FUNC2(void, glVertexAttrib1sARB, glVertexAttrib1s, "2.0", (GLuint index, GLshort v0)) FUNC2(void, glVertexAttrib1dARB, glVertexAttrib1d, "2.0", (GLuint index, GLdouble v0)) FUNC2(void, glVertexAttrib2fARB, glVertexAttrib2f, "2.0", (GLuint index, GLfloat v0, GLfloat v1)) FUNC2(void, glVertexAttrib2sARB, glVertexAttrib2s, "2.0", (GLuint index, GLshort v0, GLshort v1)) FUNC2(void, glVertexAttrib2dARB, glVertexAttrib2d, "2.0", (GLuint index, GLdouble v0, GLdouble v1)) FUNC2(void, glVertexAttrib3fARB, glVertexAttrib3f, "2.0", (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2)) FUNC2(void, glVertexAttrib3sARB, glVertexAttrib3s, "2.0", (GLuint index, GLshort v0, GLshort v1, GLshort v2)) FUNC2(void, glVertexAttrib3dARB, glVertexAttrib3d, "2.0", (GLuint index, GLdouble v0, GLdouble v1, GLdouble v2)) FUNC2(void, glVertexAttrib4fARB, glVertexAttrib4f, "2.0", (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)) FUNC2(void, glVertexAttrib4sARB, glVertexAttrib4s, "2.0", (GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3)) FUNC2(void, glVertexAttrib4dARB, glVertexAttrib4d, "2.0", (GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3)) FUNC2(void, glVertexAttrib4NubARB, glVertexAttrib4Nub, "2.0", (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w)) FUNC2(void, glVertexAttrib1fvARB, glVertexAttrib1fv, "2.0", (GLuint index, const GLfloat *v)) FUNC2(void, glVertexAttrib1svARB, glVertexAttrib1sv, "2.0", (GLuint index, const GLshort *v)) FUNC2(void, glVertexAttrib1dvARB, glVertexAttrib1dv, "2.0", (GLuint index, const GLdouble *v)) FUNC2(void, glVertexAttrib2fvARB, glVertexAttrib2fv, "2.0", (GLuint index, const GLfloat *v)) FUNC2(void, glVertexAttrib2svARB, glVertexAttrib2sv, "2.0", (GLuint index, const GLshort *v)) FUNC2(void, glVertexAttrib2dvARB, glVertexAttrib2dv, "2.0", (GLuint index, const GLdouble *v)) FUNC2(void, glVertexAttrib3fvARB, glVertexAttrib3fv, "2.0", (GLuint index, const GLfloat *v)) FUNC2(void, glVertexAttrib3svARB, glVertexAttrib3sv, "2.0", (GLuint index, const GLshort *v)) FUNC2(void, glVertexAttrib3dvARB, glVertexAttrib3dv, "2.0", (GLuint index, const GLdouble *v)) FUNC2(void, glVertexAttrib4fvARB, glVertexAttrib4fv, "2.0", (GLuint index, const GLfloat *v)) FUNC2(void, glVertexAttrib4svARB, glVertexAttrib4sv, "2.0", (GLuint index, const GLshort *v)) FUNC2(void, glVertexAttrib4dvARB, glVertexAttrib4dv, "2.0", (GLuint index, const GLdouble *v)) FUNC2(void, glVertexAttrib4ivARB, glVertexAttrib4iv, "2.0", (GLuint index, const GLint *v)) FUNC2(void, glVertexAttrib4bvARB, glVertexAttrib4bv, "2.0", (GLuint index, const GLbyte *v)) FUNC2(void, glVertexAttrib4ubvARB, glVertexAttrib4ubv, "2.0", (GLuint index, const GLubyte *v)) FUNC2(void, glVertexAttrib4usvARB, glVertexAttrib4usv, "2.0", (GLuint index, const GLushort *v)) FUNC2(void, glVertexAttrib4uivARB, glVertexAttrib4uiv, "2.0", (GLuint index, const GLuint *v)) FUNC2(void, glVertexAttrib4NbvARB, glVertexAttrib4Nbv, "2.0", (GLuint index, const GLbyte *v)) FUNC2(void, glVertexAttrib4NsvARB, glVertexAttrib4Nsv, "2.0", (GLuint index, const GLshort *v)) FUNC2(void, glVertexAttrib4NivARB, glVertexAttrib4Niv, "2.0", (GLuint index, const GLint *v)) FUNC2(void, glVertexAttrib4NubvARB, glVertexAttrib4Nubv, "2.0", (GLuint index, const GLubyte *v)) FUNC2(void, glVertexAttrib4NusvARB, glVertexAttrib4Nusv, "2.0", (GLuint index, const GLushort *v)) FUNC2(void, glVertexAttrib4NuivARB, glVertexAttrib4Nuiv, "2.0", (GLuint index, const GLuint *v)) FUNC2(void, glVertexAttribPointerARB, glVertexAttribPointer, "2.0", (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer)) FUNC2(void, glEnableVertexAttribArrayARB, glEnableVertexAttribArray, "2.0", (GLuint index)) FUNC2(void, glDisableVertexAttribArrayARB, glDisableVertexAttribArray, "2.0", (GLuint index)) FUNC2(void, glBindAttribLocationARB, glBindAttribLocation, "2.0", (GLhandleARB programObj, GLuint index, const char *name)) FUNC2(void, glGetActiveAttribARB, glGetActiveAttrib, "2.0", (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, int *size, GLenum *type, char *name)) FUNC2(GLint, glGetAttribLocationARB, glGetAttribLocation, "2.0", (GLhandleARB programObj, const char *name)) FUNC2(void, glGetVertexAttribdvARB, glGetVertexAttribdv, "2.0", (GLuint index, GLenum pname, GLdouble *params)) FUNC2(void, glGetVertexAttribfvARB, glGetVertexAttribfv, "2.0", (GLuint index, GLenum pname, GLfloat *params)) FUNC2(void, glGetVertexAttribivARB, glGetVertexAttribiv, "2.0", (GLuint index, GLenum pname, GLint *params)) FUNC2(void, glGetVertexAttribPointervARB, glGetVertexAttribPointerv, "2.0", (GLuint index, GLenum pname, void **pointer)) +// GL_EXT_gpu_shader4 / GL3.0: +FUNC2(void, glVertexAttribI1iEXT, glVertexAttribI1i, "3.0", (GLuint index, GLint x)) +FUNC2(void, glVertexAttribI2iEXT, glVertexAttribI2i, "3.0", (GLuint index, GLint x, GLint y)) +FUNC2(void, glVertexAttribI3iEXT, glVertexAttribI3i, "3.0", (GLuint index, GLint x, GLint y, GLint z)) +FUNC2(void, glVertexAttribI4iEXT, glVertexAttribI4i, "3.0", (GLuint index, GLint x, GLint y, GLint z, GLint w)) +FUNC2(void, glVertexAttribI1uiEXT, glVertexAttribI1ui, "3.0", (GLuint index, GLuint x)) +FUNC2(void, glVertexAttribI2uiEXT, glVertexAttribI2ui, "3.0", (GLuint index, GLuint x, GLuint y)) +FUNC2(void, glVertexAttribI3uiEXT, glVertexAttribI3ui, "3.0", (GLuint index, GLuint x, GLuint y, GLuint z)) +FUNC2(void, glVertexAttribI4uiEXT, glVertexAttribI4ui, "3.0", (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)) +FUNC2(void, glVertexAttribI1ivEXT, glVertexAttribI1iv, "3.0", (GLuint index, const GLint *v)) +FUNC2(void, glVertexAttribI2ivEXT, glVertexAttribI2iv, "3.0", (GLuint index, const GLint *v)) +FUNC2(void, glVertexAttribI3ivEXT, glVertexAttribI3iv, "3.0", (GLuint index, const GLint *v)) +FUNC2(void, glVertexAttribI4ivEXT, glVertexAttribI4iv, "3.0", (GLuint index, const GLint *v)) +FUNC2(void, glVertexAttribI1uivEXT, glVertexAttribI1uiv, "3.0", (GLuint index, const GLuint *v)) +FUNC2(void, glVertexAttribI2uivEXT, glVertexAttribI2uiv, "3.0", (GLuint index, const GLuint *v)) +FUNC2(void, glVertexAttribI3uivEXT, glVertexAttribI3uiv, "3.0", (GLuint index, const GLuint *v)) +FUNC2(void, glVertexAttribI4uivEXT, glVertexAttribI4uiv, "3.0", (GLuint index, const GLuint *v)) +FUNC2(void, glVertexAttribI4bvEXT, glVertexAttribI4bv, "3.0", (GLuint index, const GLbyte *v)) +FUNC2(void, glVertexAttribI4svEXT, glVertexAttribI4sv, "3.0", (GLuint index, const GLshort *v)) +FUNC2(void, glVertexAttribI4ubvEXT, glVertexAttribI4ubv, "3.0", (GLuint index, const GLubyte *v)) +FUNC2(void, glVertexAttribI4usvEXT, glVertexAttribI4usv, "3.0", (GLuint index, const GLushort *v)) +FUNC2(void, glVertexAttribIPointerEXT, glVertexAttribIPointer, "3.0", (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)) +FUNC2(void, glGetVertexAttribIivEXT, glGetVertexAttribIiv, "3.0", (GLuint index, GLenum pname, GLint *params)) +FUNC2(void, glGetVertexAttribIuivEXT, glGetVertexAttribIuiv, "3.0", (GLuint index, GLenum pname, GLuint *params)) +FUNC2(void, glUniform1uiEXT, glUniform1ui, "3.0", (GLint location, GLuint v0)) +FUNC2(void, glUniform2uiEXT, glUniform2ui, "3.0", (GLint location, GLuint v0, GLuint v1)) +FUNC2(void, glUniform3uiEXT, glUniform3ui, "3.0", (GLint location, GLuint v0, GLuint v1, GLuint v2)) +FUNC2(void, glUniform4uiEXT, glUniform4ui, "3.0", (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)) +FUNC2(void, glUniform1uivEXT, glUniform1uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) +FUNC2(void, glUniform2uivEXT, glUniform2uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) +FUNC2(void, glUniform3uivEXT, glUniform3uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) +FUNC2(void, glUniform4uivEXT, glUniform4uiv, "3.0", (GLint location, GLsizei count, const GLuint *value)) +FUNC2(void, glGetUniformuivEXT, glGetUniformuiv, "3.0", (GLuint program, GLint location, GLuint *params)) +FUNC2(void, glBindFragDataLocationEXT, glBindFragDataLocation, "3.0", (GLuint program, GLuint colorNumber, const char *name)) +FUNC2(GLint, glGetFragDataLocationEXT, glGetFragDataLocation, "3.0", (GLuint program, const char *name)) + // GL_ARB_occlusion_query / GL1.5: FUNC2(void, glGenQueriesARB, glGenQueries, "1.5", (GLsizei n, GLuint *ids)) FUNC2(void, glDeleteQueriesARB, glDeleteQueries, "1.5", (GLsizei n, const GLuint *ids)) FUNC2(GLboolean, glIsQueryARB, glIsQuery, "1.5", (GLuint id)) FUNC2(void, glBeginQueryARB, glBeginQuery, "1.5", (GLenum target, GLuint id)) FUNC2(void, glEndQueryARB, glEndQuery, "1.5", (GLenum target)) FUNC2(void, glGetQueryivARB, glGetQueryiv, "1.5", (GLenum target, GLenum pname, GLint *params)) FUNC2(void, glGetQueryObjectivARB, glGetQueryObjectiv, "1.5", (GLuint id, GLenum pname, GLint *params)) FUNC2(void, glGetQueryObjectuivARB, glGetQueryObjectuiv, "1.5", (GLuint id, GLenum pname, GLuint *params)) // GL_ARB_sync / GL3.2: FUNC2(void, glGetInteger64v, glGetInteger64v, "3.2", (GLenum pname, GLint64 *params)) // GL_EXT_timer_query: FUNC(void, glGetQueryObjecti64vEXT, (GLuint id, GLenum pname, GLint64 *params)) FUNC(void, glGetQueryObjectui64vEXT, (GLuint id, GLenum pname, GLuint64 *params)) // GL_ARB_timer_query / GL3.3: FUNC2(void, glQueryCounter, glQueryCounter, "3.3", (GLuint id, GLenum target)) FUNC2(void, glGetQueryObjecti64v, glGetQueryObjecti64v, "3.3", (GLuint id, GLenum pname, GLint64 *params)) FUNC2(void, glGetQueryObjectui64v, glGetQueryObjectui64v, "3.3", (GLuint id, GLenum pname, GLuint64 *params)) // GL_GREMEDY_string_marker (from gDEBugger) FUNC(int, glStringMarkerGREMEDY, (GLsizei len, const GLvoid *string)) // GL_INTEL_performance_queries (undocumented, may be unstable, use at own risk; // see http://zaynar.co.uk/docs/gl-intel-performance-queries.html) FUNC(void, glGetFirstPerfQueryIdINTEL, (GLuint *queryId)) FUNC(void, glGetNextPerfQueryIdINTEL, (GLuint prevQueryId, GLuint *queryId)) FUNC(void, glGetPerfQueryInfoINTEL, (GLuint queryId, GLuint nameMaxLength, char *name, GLuint *counterBufferSize, GLuint *numCounters, GLuint *maxQueries, GLuint *)) FUNC(void, glGetPerfCounterInfoINTEL, (GLuint queryId, GLuint counterId, GLuint nameMaxLength, char *name, GLuint descMaxLength, char *desc, GLuint *offset, GLuint *size, GLuint *usage, GLuint *type, GLuint64 *)) FUNC(void, glCreatePerfQueryINTEL, (GLuint queryId, GLuint *id)) FUNC(void, glBeginPerfQueryINTEL, (GLuint id)) FUNC(void, glEndPerfQueryINTEL, (GLuint id)) FUNC(void, glDeletePerfQueryINTEL, (GLuint id)) FUNC(void, glGetPerfQueryDataINTEL, (GLuint id, GLenum requestType, GLuint maxLength, char *buffer, GLuint *length)) #endif // #if CONFIG_GLES2 #if OS_WIN // WGL_EXT_swap_control FUNC(int, wglSwapIntervalEXT, (int)) // WGL_ARB_pbuffer FUNC(HPBUFFERARB, wglCreatePbufferARB, (HDC, int, int, int, const int*)) FUNC(HDC, wglGetPbufferDCARB, (HPBUFFERARB)) FUNC(int, wglReleasePbufferDCARB, (HPBUFFERARB, HDC)) FUNC(int, wglDestroyPbufferARB, (HPBUFFERARB)) FUNC(int, wglQueryPbufferARB, (HPBUFFERARB, int, int*)) // GL_ARB_pixel_format FUNC(int, wglGetPixelFormatAttribivARB, (HDC, int, int, unsigned int, const int*, int*)) FUNC(int, wglGetPixelFormatAttribfvARB, (HDC, int, int, unsigned int, const int*, float*)) FUNC(int, wglChoosePixelFormatARB, (HDC, const int *, const float*, unsigned int, int*, unsigned int*)) #endif // OS_WIN Index: ps/trunk/binaries/data/mods/public/shaders/program.rng =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/program.rng (revision 11488) +++ ps/trunk/binaries/data/mods/public/shaders/program.rng (revision 11489) @@ -1,131 +1,134 @@ arb glsl gl_Vertex gl_Normal gl_Color gl_SecondaryColor gl_FogCoord gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 + CustomAttribute0 + CustomAttribute1 + CustomAttribute2 float vec2 vec3 vec4 mat2 mat3 mat4 sampler2D sampler2DShadow samplerCube pos normal color uv0 uv1 uv2 uv3