1
0
forked from 0ad/0ad

Render territory borders in non-shader render path.

Add basic support for fixed-function implementations of shader API.

This was SVN commit r10106.
This commit is contained in:
Ykkrosh 2011-08-27 14:31:24 +00:00
parent 9d25dad969
commit 8729d1115d
6 changed files with 372 additions and 91 deletions

View File

@ -62,7 +62,7 @@ CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const std::map<C
return it->second;
CShaderProgramPtr program;
if (NewProgram(name, defines, program) != PSRETURN_OK)
if (!NewProgram(name, defines, program))
{
LOGERROR(L"Failed to load shader '%hs'", name);
program = CShaderProgramPtr();
@ -74,6 +74,15 @@ CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const std::map<C
bool CShaderManager::NewProgram(const char* name, const std::map<CStr, CStr>& baseDefines, CShaderProgramPtr& program)
{
if (strncmp(name, "fixed:", 6) == 0)
{
program = CShaderProgramPtr(CShaderProgram::ConstructFFP(name+6));
if (!program)
return false;
program->Reload();
return true;
}
VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml";
CXeromyces XeroFile;
@ -184,7 +193,7 @@ bool CShaderManager::NewProgram(const char* name, const std::map<CStr, CStr>& ba
m_HotloadFiles[vertexFile].insert(program);
m_HotloadFiles[fragmentFile].insert(program);
return PSRETURN_OK;
return true;
}
/*static*/ Status CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path)

View File

@ -197,31 +197,6 @@ public:
return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id));
}
virtual void Uniform(uniform_id_t id, int v)
{
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), (float)v, (float)v, (float)v, (float)v);
}
virtual void Uniform(Binding id, int v)
{
Uniform(id, (float)v, (float)v, (float)v, (float)v);
}
virtual void Uniform(uniform_id_t id, float v)
{
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v, v, v, v);
}
virtual void Uniform(Binding id, float v)
{
Uniform(id, v, v, v, v);
}
virtual void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3)
{
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v0, v1, v2, v3);
}
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
{
if (id.vertex != -1)
@ -231,31 +206,6 @@ public:
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment, v0, v1, v2, v3);
}
virtual void Uniform(uniform_id_t id, const CVector3D& v)
{
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v.X, v.Y, v.Z, 0.0f);
}
virtual void Uniform(Binding id, const CVector3D& v)
{
Uniform(id, v.X, v.Y, v.Z, 0.0f);
}
virtual void Uniform(uniform_id_t id, const CColor& v)
{
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v.r, v.g, v.b, v.a);
}
virtual void Uniform(Binding id, const CColor& v)
{
Uniform(id, v.r, v.g, v.b, v.a);
}
virtual void Uniform(uniform_id_t id, const CMatrix3D& v)
{
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v);
}
virtual void Uniform(Binding id, const CMatrix3D& v)
{
if (id.vertex != -1)
@ -311,3 +261,53 @@ int CShaderProgram::GetStreamFlags() const
{
return m_StreamFlags;
}
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, 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, 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);
}

View File

@ -29,6 +29,22 @@ struct CColor;
class CMatrix3D;
class CVector3D;
// 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 (assembly syntax)
@ -52,6 +68,11 @@ public:
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
int streamflags);
/**
* Construct an instance of a pre-defined fixed-function pipeline setup.
*/
static CShaderProgram* ConstructFFP(const std::string& id);
typedef const char* attrib_id_t;
typedef const char* texture_id_t;
typedef const char* uniform_id_t;
@ -61,12 +82,8 @@ public:
*/
struct Binding
{
friend class CShaderProgramARB;
private:
Binding(int v, int f) : vertex((i16)v), fragment((i16)f) { }
i16 vertex;
i16 fragment;
public:
Binding() : vertex(-1), fragment(-1) { }
/**
@ -74,6 +91,9 @@ public:
* If not then there's no point calling Uniform() to set its value.
*/
bool Active() { return vertex != -1 || fragment != -1; }
i16 vertex;
i16 fragment;
};
virtual ~CShaderProgram() { }
@ -116,20 +136,24 @@ public:
virtual Binding GetUniformBinding(uniform_id_t id) = 0;
virtual void Uniform(uniform_id_t id, int v) = 0;
virtual void Uniform(uniform_id_t id, float v) = 0;
virtual void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3) = 0;
virtual void Uniform(uniform_id_t id, const CVector3D& v) = 0;
virtual void Uniform(uniform_id_t id, const CColor& v) = 0;
virtual void Uniform(uniform_id_t id, const CMatrix3D& v) = 0;
virtual void Uniform(Binding id, int v) = 0;
virtual void Uniform(Binding id, float v) = 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 CVector3D& v) = 0;
virtual void Uniform(Binding id, const CColor& v) = 0;
virtual void Uniform(Binding id, const CMatrix3D& v) = 0;
// Convenient uniform-setting wrappers:
void Uniform(Binding id, int v);
void Uniform(Binding id, float v);
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, 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);
protected:
CShaderProgram(int streamflags);

View File

@ -0,0 +1,231 @@
/* Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ShaderProgram.h"
#include "lib/res/graphics/ogl_tex.h"
#include "maths/Vector3D.h"
#include "ps/CLogger.h"
#include "ps/Overlay.h"
/**
* 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(uniform_id_t id)
{
std::map<CStr, int>::iterator it = m_UniformIndexes.find(id);
if (it == m_UniformIndexes.end())
return -1;
return it->second;
}
virtual bool HasTexture(texture_id_t id)
{
if (GetUniformIndex(id) != -1)
return true;
return false;
}
virtual void BindTexture(texture_id_t id, Handle tex)
{
int index = GetUniformIndex(id);
if (index != -1)
ogl_tex_bind(tex, index);
}
virtual void BindTexture(texture_id_t id, GLuint tex)
{
int index = GetUniformIndex(id);
if (index != -1)
{
pglActiveTextureARB((int)(GL_TEXTURE0+index));
glBindTexture(GL_TEXTURE_2D, tex);
}
}
virtual Binding GetUniformBinding(uniform_id_t id)
{
return Binding(-1, GetUniformIndex(id));
}
protected:
std::map<CStr, int> m_UniformIndexes;
};
class CShaderProgramFFP_OverlayLine : public CShaderProgramFFP
{
// Uniforms
enum
{
ID_losTransform,
ID_objectColor
};
public:
CShaderProgramFFP_OverlayLine() :
CShaderProgramFFP(STREAM_POS | STREAM_UV0 | STREAM_UV1)
{
m_UniformIndexes["losTransform"] = ID_losTransform;
m_UniformIndexes["objectColor"] = ID_objectColor;
// Texture units:
m_UniformIndexes["baseTex"] = 0;
m_UniformIndexes["maskTex"] = 1;
m_UniformIndexes["losTex"] = 2;
}
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
{
if (id.fragment == 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.fragment == 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
// 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
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);
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);
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);
}
virtual void Unbind()
{
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);
}
};
/*static*/ CShaderProgram* CShaderProgram::ConstructFFP(const std::string& id)
{
if (id == "overlayline")
return new CShaderProgramFFP_OverlayLine();
LOGERROR(L"CShaderProgram::ConstructFFP: Invalid id '%hs'", id.c_str());
return NULL;
}

View File

@ -168,25 +168,40 @@ void OverlayRenderer::RenderOverlaysAfterWater()
{
PROFILE("render overlays (after water)");
// Only supported in shader modes
// (TODO: should support in non-shader too)
if (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER)
return;
if (!m->texlines.empty())
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glDepthMask(0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
const char* shaderName;
if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
shaderName = "overlayline";
else
shaderName = "fixed:overlayline";
CShaderManager& shaderManager = g_Renderer.GetShaderManager();
CShaderProgramPtr shaderTexLine(shaderManager.LoadProgram("overlayline", std::map<CStr, CStr>()));
CShaderProgramPtr shaderTexLine(shaderManager.LoadProgram(shaderName, std::map<CStr, CStr>()));
shaderTexLine->Bind();
int streamflags = shaderTexLine->GetStreamFlags();
if (streamflags & STREAM_POS)
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0)
{
pglClientActiveTextureARB(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (streamflags & STREAM_UV1)
{
pglClientActiveTextureARB(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
shaderTexLine->BindTexture("losTex", los.GetTexture());
shaderTexLine->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
@ -206,8 +221,20 @@ void OverlayRenderer::RenderOverlaysAfterWater()
GLsizei stride = sizeof(CTexturedLineRData::SVertex);
CTexturedLineRData::SVertex* base = reinterpret_cast<CTexturedLineRData::SVertex*>(rdata->m_VB->m_Owner->Bind());
glVertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
glTexCoordPointer(2, GL_SHORT, stride, &base->m_UVs[0]);
if (streamflags & STREAM_POS)
glVertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
if (streamflags & STREAM_UV0)
{
pglClientActiveTextureARB(GL_TEXTURE0);
glTexCoordPointer(2, GL_SHORT, stride, &base->m_UVs[0]);
}
if (streamflags & STREAM_UV1)
{
pglClientActiveTextureARB(GL_TEXTURE1);
glTexCoordPointer(2, GL_SHORT, stride, &base->m_UVs[0]);
}
u8* indexBase = rdata->m_VBIndices->m_Owner->Bind();
glDrawElements(GL_QUAD_STRIP, rdata->m_VBIndices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*rdata->m_VBIndices->m_Index);
@ -223,6 +250,9 @@ void OverlayRenderer::RenderOverlaysAfterWater()
CVertexBuffer::Unbind();
glDisableClientState(GL_VERTEX_ARRAY);
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
pglClientActiveTextureARB(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDepthMask(1);

View File

@ -51,19 +51,6 @@ enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
// transparency modes
enum ETransparentMode { TRANSPARENT, TRANSPARENT_OPAQUE, TRANSPARENT_BLEND };
// stream flags
#define STREAM_POS (1 << 0)
#define STREAM_NORMAL (1 << 1)
#define STREAM_COLOR (1 << 2)
#define STREAM_UV0 (1 << 3)
#define STREAM_UV1 (1 << 4)
#define STREAM_UV2 (1 << 5)
#define STREAM_UV3 (1 << 6)
#define STREAM_POSTOUV0 (1 << 7)
#define STREAM_POSTOUV1 (1 << 8)
#define STREAM_POSTOUV2 (1 << 9)
#define STREAM_POSTOUV3 (1 << 10)
// access to sole renderer object
#define g_Renderer CRenderer::GetSingleton()