GL3: Refactoring vertex program generation

--HG--
branch : opengl3
hg/feature/opengl3
kaetemi 11 years ago
parent 7a960ed768
commit 5d80073c0f

@ -276,6 +276,20 @@ public:
void setupIndexBuffer(CIndexBuffer &vb);
};
/// Builtin vertex program description
struct CVPBuiltin
{
uint16 VertexFormat;
bool Lighting;
sint LightMode[NL_OPENGL3_MAX_LIGHT]; // -1 when disabled
bool Fog;
bool VertexColorLighted;
CVertexProgram *VertexProgram;
};
bool operator<(const CVPBuiltin &left, const CVPBuiltin &right);
class CGLSLShaderGenerator;
class CUsrShaderManager;
@ -377,11 +391,15 @@ public:
virtual bool setupMaterial(CMaterial& mat);
void generateShaderDesc(CShaderDesc &desc, CMaterial &mat);
bool setupProgram(CMaterial& mat);
bool setupBuiltinPrograms(CMaterial& mat);
bool setupBuiltinVertexProgram();
bool setupBuiltinPixelProgram(CMaterial& mat);
bool setupDynMatProgram(CMaterial& mat, uint pass);
void setupUniforms();
bool setupUniforms();
void setupUniforms(TProgram program);
CVertexProgram *generateBuiltinVertexProgram();
virtual void startSpecularBatch();
virtual void endSpecularBatch();
@ -1337,6 +1355,8 @@ private:
CGeometryProgram *m_DriverGeometryProgram;
CPixelProgram *m_DriverPixelProgram;
std::set<CVPBuiltin> m_VPBuiltinCache;
// init EMBM settings (set each stage to modify the next)
void initEMBM();

@ -437,7 +437,7 @@ bool CDriverGL3::setupMaterial(CMaterial& mat)
// Light Part.
// _DriverGLStates.enableLighting(mat.getFlags()&IDRV_MAT_LIGHTING); // FIXME GL3 VERTEX PROGRAM
_DriverGLStates.enableLighting(mat.getFlags() & IDRV_MAT_LIGHTING);
if ((mat.getFlags() & IDRV_MAT_LIGHTING) == 0)
disableAllLights();
@ -490,8 +490,7 @@ bool CDriverGL3::setupMaterial(CMaterial& mat)
// 5. Set up the program
// =====================
bool programOK = setupProgram(mat);
return programOK;
return setupBuiltinPrograms(mat);
}
// ***************************************************************************
@ -782,7 +781,7 @@ sint CDriverGL3::beginLightMapMultiPass ()
computeLightMapInfos (mat);
// always enable lighting for lightmap (because of dynamic light)
// _DriverGLStates.enableLighting(true); // FIXME GL3 VERTEX PROGRAM
_DriverGLStates.enableLighting(true);
// if the dynamic lightmap light has changed since the last render (should not happen), resetup
// normal way is that setupLightMapDynamicLighting() is called in setupMaterial() if shader different from prec

@ -590,16 +590,39 @@ namespace NL3D
desc.setLighting(enableLights);
}
bool CDriverGL3::setupBuiltinPrograms(CMaterial &mat)
{
return setupBuiltinVertexProgram()
&& setupBuiltinPixelProgram(mat)
&& setupUniforms();
}
bool CDriverGL3::setupBuiltinVertexProgram()
{
if (m_UserVertexProgram) return true;
CVertexProgram *vertexProgram = generateBuiltinVertexProgram();
nlassert(vertexProgram);
if (!activeVertexProgram(vertexProgram, true))
return false;
// GL3 TODO: Here we set the uniforms of the vertex program!
return true;
}
bool CDriverGL3::setupProgram(CMaterial &mat)
bool CDriverGL3::setupBuiltinPixelProgram(CMaterial &mat)
{
if (m_UserPixelProgram) return true;
// nlassert(!m_UserVertexProgram); // TEMP
// nlassert(!m_UserPixelProgram); // TEMP
if (mat.getDynMat() != NULL)
return true;
CVertexProgram *vp = NULL;
// CVertexProgram *vp = NULL; // REMOVED
CPixelProgram *pp = NULL;
SShaderPair sp;
@ -613,11 +636,11 @@ namespace NL3D
// Yes we have!
if (!sp.empty())
{
if (m_UserVertexProgram == NULL)
/*if (m_UserVertexProgram == NULL)
{
if (!activeVertexProgram(sp.vp, true))
return false;
}
}*/
if (m_UserPixelProgram == NULL)
{
@ -628,7 +651,7 @@ namespace NL3D
// No we need to generate it now
else
{
std::string vs;
// std::string vs;
std::string ps;
bool cacheShaders = true;
@ -638,7 +661,7 @@ namespace NL3D
shaderGenerator->setShaderDesc(&desc);
// If we don't already have a vertex program attached, we'll generate it now
if (m_UserVertexProgram == NULL)
/* if (m_UserVertexProgram == NULL)
{
shaderGenerator->generateVS(vs);
vp = new CVertexProgram();
@ -666,6 +689,7 @@ namespace NL3D
}
else
cacheShaders = false;
*/
// If we don't already have a pixel program attached, we'll generate it now
if (m_UserPixelProgram == NULL)
@ -682,8 +706,8 @@ namespace NL3D
if (!compilePixelProgram(pp))
{
delete vp;
vp = NULL;
// delete vp;
// vp = NULL;
delete pp;
pp = NULL;
return false;
@ -691,8 +715,8 @@ namespace NL3D
if (!activePixelProgram(pp, true))
{
delete vp;
vp = NULL;
// delete vp;
// vp = NULL;
delete pp;
pp = NULL;
return false;
@ -705,15 +729,13 @@ namespace NL3D
// If we already have a shader attached we won't cache this shaderpair, since we didn't generate it
if (cacheShaders)
{
sp.vp = vp;
sp.vp = NULL;
sp.pp = pp;
desc.setShaders(sp);
shaderCache.cacheShader(desc);
}
}
setupUniforms();
return true;
}
@ -806,11 +828,11 @@ namespace NL3D
return false;
}
void CDriverGL3::setupUniforms()
bool CDriverGL3::setupUniforms()
{
setupUniforms(IDriver::VertexProgram);
setupUniforms(IDriver::PixelProgram);
return true;
}
void CDriverGL3::setupUniforms(TProgram program)

@ -76,6 +76,7 @@ void CDriverGLStates3::forceDefaults(uint nbStages)
_CurBlend = false;
_CurCullFace = true;
_CurAlphaTest = false;
_CurLighting = false;
_CurZWrite = true;
_CurStencilTest =false;
@ -228,6 +229,14 @@ void CDriverGLStates3::enableAlphaTest(uint enable)
}
}
// ***************************************************************************
void CDriverGLStates3::enableLighting(uint enable)
{
H_AUTO_OGL(CDriverGLStates3_enableLighting)
_CurLighting = (enable != 0);
}
// ***************************************************************************
void CDriverGLStates3::enableZWrite(uint enable)
{

@ -85,10 +85,14 @@ public:
// @{
void enableBlend(uint enable);
void enableFog(uint enable);
bool isFogEnabled() const { return _CurFog; }
void enableCullFace(uint enable);
/// enable and set good AlphaFunc.
void enableAlphaTest(uint enable);
void enableZWrite(uint enable);
// overall lighting enabled
void enableLighting(uint enable);
bool isLightingEnabled() const { return _CurLighting; }
/// enable/disable stencil test
void enableStencilTest(bool enable);
bool isStencilTestEnabled() const { return _CurStencilTest; }
@ -164,6 +168,7 @@ private:
bool _CurFog;
bool _CurCullFace;
bool _CurAlphaTest;
bool _CurLighting;
bool _CurZWrite;
bool _CurStencilTest;

@ -0,0 +1,401 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2014 by authors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdopengl.h"
#include "driver_opengl_vertex_program.h"
#include <sstream>
#include "nel/3d/vertex_program.h"
#include "nel/3d/light.h"
#include "driver_opengl.h"
#include "driver_opengl_vertex_buffer_hard.h"
namespace NL3D {
#ifdef NL_STATIC
namespace NLDRIVERGL3 {
#endif
bool operator<(const CVPBuiltin &left, const CVPBuiltin &right)
{
if (left.VertexFormat != right.VertexFormat)
return left.VertexFormat < right.VertexFormat;
if (left.Lighting != right.Lighting)
return right.Lighting;
if (left.Lighting)
for (sint i = 0; i < NL_OPENGL3_MAX_LIGHT; ++i)
if (left.LightMode[i] != right.LightMode[i])
return left.LightMode[i] < right.LightMode[i];
if (left.Fog != right.Fog)
return right.Fog;
if (left.VertexColorLighted != right.VertexColorLighted)
return right.VertexColorLighted;
return false;
}
namespace
{
inline bool hasFlag(uint32 data, uint32 flag)
{
if ((data & flag) != 0)
return true;
else
return false;
}
enum TAttribOffset
{
Position,
Weight,
Normal,
PrimaryColor,
SecondaryColor,
Fog,
PaletteSkin,
Empty,
TexCoord0,
TexCoord1,
TexCoord2,
TexCoord3,
TexCoord4,
TexCoord5,
TexCoord6,
TexCoord7,
NumOffsets
};
const uint16 s_VertexFlags[CVertexBuffer::NumValue] =
{
CVertexBuffer::PositionFlag,
CVertexBuffer::WeightFlag,
CVertexBuffer::NormalFlag,
CVertexBuffer::PrimaryColorFlag,
CVertexBuffer::SecondaryColorFlag,
CVertexBuffer::FogFlag,
CVertexBuffer::PaletteSkinFlag,
0,
CVertexBuffer::TexCoord0Flag,
CVertexBuffer::TexCoord1Flag,
CVertexBuffer::TexCoord2Flag,
CVertexBuffer::TexCoord3Flag,
CVertexBuffer::TexCoord4Flag,
CVertexBuffer::TexCoord5Flag,
CVertexBuffer::TexCoord6Flag,
CVertexBuffer::TexCoord7Flag
};
const char *s_AttribNames[ CVertexBuffer::NumValue ] =
{
"position",
"weight",
"normal",
"color",
"color2",
"fog",
"paletteSkin",
"none",
"texCoord0",
"texCoord1",
"texCoord2",
"texCoord3",
"texCoord4",
"texCoord5",
"texCoord6",
"texCoord7"
};
const char *s_TexelNames[ SHADER_MAX_TEXTURES ] =
{
"texel0",
"texel1",
"texel2",
"texel3"
};
const char *s_ConstantNames[ 4 ] =
{
"constant0",
"constant1",
"constant2",
"constant3"
};
void vpLightUniforms(std::stringstream &ss, const CVPBuiltin &desc, int i)
{
switch (desc.LightMode[i])
{
case CLight::DirectionalLight:
ss << "uniform vec3 light" << i << "DirOrPos;" << std::endl;
ss << "uniform vec4 light" << i << "ColDiff;" << std::endl;
ss << "uniform vec4 light" << i << "ColAmb;" << std::endl;
ss << "uniform vec4 light" << i << "ColSpec;" << std::endl;
ss << "uniform float light" << i << "Shininess;" << std::endl;
break;
case CLight::PointLight:
ss << "uniform vec3 light" << i << "DirOrPos;" << std::endl;
ss << "uniform vec4 light" << i << "ColDiff;" << std::endl;
ss << "uniform vec4 light" << i << "ColAmb;" << std::endl;
ss << "uniform vec4 light" << i << "ColSpec;" << std::endl;
ss << "uniform float light" << i << "Shininess;" << std::endl;
ss << "uniform float light" << i << "ConstAttn;" << std::endl;
ss << "uniform float light" << i << "LinAttn;" << std::endl;
ss << "uniform float light" << i << "QuadAttn;" << std::endl;
break;
}
}
void vpLightFunctions(std::stringstream &ss, const CVPBuiltin &desc, int i)
{
switch (desc.LightMode[i])
{
case CLight::DirectionalLight:
ss << "float getIntensity" << i << "(vec3 normal3, vec3 lightDir)" << std::endl;
ss << "{" << std::endl;
ss << "float angle = dot(lightDir, normal3);" << std::endl;
ss << "angle = max(0.0, angle);" << std::endl;
ss << "return angle;" << std::endl;
ss << "}" << std::endl;
ss << std::endl;
ss << "float getSpecIntensity" << i << "(vec3 normal3, vec3 lightDir)" << std::endl;
ss << "{" << std::endl;
ss << "vec3 halfVector = normalize(lightDir + normal3);" << std::endl;
ss << "float angle = dot(normal3, halfVector);" << std::endl;
ss << "angle = max(0.0, angle);" << std::endl;
ss << "float si = pow(angle, light" << i << "Shininess);" << std::endl;
ss << "return si;" << std::endl;
ss << "}" << std::endl;
ss << std::endl;
ss << "vec4 getLight" << i << "Color()" << std::endl;
ss << "{" << std::endl;
ss << "vec4 lightDir4 = viewMatrix * vec4(light" << i << "DirOrPos, 1.0);" << std::endl;
ss << "vec3 lightDir = lightDir4.xyz / lightDir4.w;" << std::endl;
ss << "lightDir = normalize(lightDir);" << std::endl;
ss << "vec3 normal3 = vnormal.xyz / vnormal.w;" << std::endl;
ss << "normal3 = normalMatrix * normal3;" << std::endl;
ss << "normal3 = normalize(normal3);" << std::endl;
//if (desc->useTextures() || (material->getShader() == CMaterial::LightMap))
//{
ss << "vec4 lc = getIntensity" << i << "(normal3, lightDir) * light" << i << "ColDiff + ";
ss << "getSpecIntensity" << i << "(normal3, lightDir) * light" << i << "ColSpec + ";
ss << "light" << i << "ColAmb;" << std::endl;
//} // FIXME: Ambient color is not correctly implemented
/*else
{
ss << "vec4 lc = getIntensity" << num << "(normal3, lightDir) * light" << num << "ColDiff * diffuseColor + ";
ss << "getSpecIntensity" << num << "(normal3, lightDir) * light" << num << "ColSpec * specularColor + ";
ss << "light" << num << "ColAmb * ambientColor;" << std::endl;
}*/
ss << "return lc;" << std::endl;
ss << "}" << std::endl;
ss << std::endl;
break;
case CLight::PointLight:
ss << "float getIntensity" << i << "(vec3 normal3, vec3 direction3)" << std::endl;
ss << "{" << std::endl;
ss << "float angle = dot(direction3, normal3);" << std::endl;
ss << "angle = max(0.0, angle);" << std::endl;
ss << "return angle;" << std::endl;
ss << "}" << std::endl;
ss << std::endl;
ss << "float getSpecIntensity" << i << "(vec3 normal3, vec3 direction3)" << std::endl;
ss << "{" << std::endl;
ss << "vec3 halfVector = normalize(direction3 + normal3);" << std::endl;
ss << "float angle = dot(normal3, halfVector);" << std::endl;
ss << "angle = max(0.0, angle);" << std::endl;
ss << "float si = pow(angle, light" << i << "Shininess);" << std::endl;
ss << "return si;" << std::endl;
ss << "}" << std::endl;
ss << std::endl;
ss << "vec4 getLight" << i << "Color()" << std::endl;
ss << "{" << std::endl;
ss << "vec3 ecPos3 = ecPos4.xyz / ecPos4.w;" << std::endl;
ss << "vec4 lightPos4 = viewMatrix * vec4(light" << i << "DirOrPos, 1.0);" << std::endl;
ss << "vec3 lightPos = lightPos4.xyz / lightPos4.w;" << std::endl;
ss << "vec3 lightDirection = lightPos - ecPos3;" << std::endl;
ss << "float lightDistance = length(lightDirection);" << std::endl;
ss << "lightDirection = normalize(lightDirection);" << std::endl;
ss << "float attenuation = light" << i << "ConstAttn + ";
ss << "light" << i << "LinAttn * lightDistance +";
ss << "light" << i << "QuadAttn * lightDistance * lightDistance;" << std::endl;
ss << "vec3 normal3 = vnormal.xyz / vnormal.w;" << std::endl;
ss << "normal3 = normalMatrix * normal3;" << std::endl;
ss << "normal3 = normalize(normal3);" << std::endl;
/*if (desc->useTextures() || (material->getShader() == CMaterial::LightMap))
{*/
ss << "vec4 lc = getIntensity" << i << "(normal3, lightDirection) * light" << i << "ColDiff + ";
ss << "getSpecIntensity" << i << "(normal3, lightDirection) * light" << i << "ColSpec + ";
ss << "light" << i << "ColAmb;" << std::endl;
// FIXME: Ambient stuff
/*}
else
{
ss << "vec4 lc = getIntensity" << num << "(normal3, lightDirection) * light" << num << "ColDiff * diffuseColor+ ";
ss << "getSpecIntensity" << num << "(normal3, lightDirection) * light" << num << "ColSpec * specularColor + ";
ss << "light" << num << "ColAmb * ambientColor;" << std::endl;
}*/
ss << "lc = lc / attenuation;" << std::endl;
ss << "return lc;" << std::endl;
ss << "}" << std::endl;
ss << std::endl;
break;
}
}
void vsLighting(std::stringstream &ss, const CVPBuiltin &desc, int i)
{
}
void vpGenerate(std::string &result, const CVPBuiltin &desc)
{
std::stringstream ss;
ss << "// Builtin Vertex Shader" << std::endl;
ss << std::endl;
ss << "#version 330" << std::endl;
ss << "#extension GL_ARB_separate_shader_objects : enable" << std::endl;
ss << "out gl_PerVertex" << std::endl;
ss << "{" << std::endl;
ss << "vec4 gl_Position;" << std::endl;
ss << "};" << std::endl;
ss << std::endl;
ss << "uniform mat4 modelViewProjection;" << std::endl;
ss << std::endl;
for (int i = Position; i < NumOffsets; ++i)
if (hasFlag(desc.VertexFormat, s_VertexFlags[i]))
ss << "layout (location = " << i << ") " << "in vec4 " << "v" << s_AttribNames[i] << ";" << std::endl;
ss << std::endl;
for (int i = Weight; i < NumOffsets; ++i)
if (hasFlag(desc.VertexFormat, s_VertexFlags[i]))
ss << "smooth out vec4 " << s_AttribNames[i] << ";" << std::endl;
ss << std::endl;
// if (!useTextures) {
ss << "uniform vec4 ambientColor;" << std::endl;
ss << "uniform vec4 diffuseColor;" << std::endl;
ss << "uniform vec4 specularColor;" << std::endl; // }
if (desc.Fog || desc.Lighting)
ss << "uniform mat4 modelView;" << std::endl;
if (desc.Lighting)
ss << "uniform mat4 viewMatrix;" << std::endl;
if (desc.Fog || desc.Lighting)
ss << "vec4 ecPos4;" << std::endl;
if (desc.Fog)
ss << "smooth out vec4 ecPos;" << std::endl;
ss << std::endl;
if (desc.Lighting)
{
ss << "uniform mat3 normalMatrix;" << std::endl;
for (int i = 0; i < NL_OPENGL3_MAX_LIGHT; ++i)
vpLightUniforms(ss, desc, i);
ss << "smooth out vec4 lightColor;" << std::endl;
ss << std::endl;
for (int i = 0; i < NL_OPENGL3_MAX_LIGHT; ++i)
vpLightFunctions(ss, desc, i);
ss << std::endl;
}
ss << "void main(void)" << std::endl;
ss << "{" << std::endl;
ss << "gl_Position = modelViewProjection * " << "v" << s_AttribNames[0] << ";" << std::endl;
if (desc.Fog || desc.Lighting)
ss << "ecPos4 = modelView * v" << s_AttribNames[0] << ";" << std::endl;
if (desc.Fog)
ss << "ecPos = ecPos4;" << std::endl;
if (desc.Lighting)
{
ss << "lightColor = vec4(0.0, 0.0, 0.0, 1.0);" << std::endl;
for (int i = 0; i < NL_OPENGL3_MAX_LIGHT; i++)
if (desc.LightMode[i] == CLight::DirectionalLight || desc.LightMode[i] == CLight::PointLight)
ss << "lightColor = lightColor + getLight" << i << "Color();" << std::endl;
}
for (int i = Weight; i < NumOffsets; i++)
{
if (hasFlag(desc.VertexFormat, s_VertexFlags[i]))
{
ss << s_AttribNames[i] << " = " << "v" << s_AttribNames[i] << ";" << std::endl;
}
}
ss << "}" << std::endl;
result = ss.str();
}
}
CVertexProgram *CDriverGL3::generateBuiltinVertexProgram()
{
CVPBuiltin desc;
desc.VertexFormat = _CurrentVertexBufferHard->VB->getVertexFormat();
desc.Fog = _DriverGLStates.isFogEnabled();
desc.Lighting = _DriverGLStates.isLightingEnabled();
if (desc.Lighting)
for (sint i = 0; i < MaxLight; ++i)
desc.LightMode[i] = _UserLightEnable[i] ? _LightMode[i] : -1;
desc.VertexColorLighted = false; // _DriverGLStates._VertexColorLighted;
std::set<CVPBuiltin>::iterator it = m_VPBuiltinCache.find(desc);
if (it != m_VPBuiltinCache.end())
return it->VertexProgram;
std::string result;
vpGenerate(result, desc);
CVertexProgram *vertexProgram = new CVertexProgram();
IProgram::CSource *src = new IProgram::CSource();
src->Profile = IProgram::glsl330v;
src->DisplayName = "Builtin Vertex Program (" + NLMISC::toString(m_VPBuiltinCache.size()) + ")";
src->setSource(result);
vertexProgram->addSource(src);
nldebug("GL3: Generate '%s'", src->DisplayName.c_str());
if (!compileVertexProgram(vertexProgram))
{
delete vertexProgram; vertexProgram = NULL;
}
desc.VertexProgram = vertexProgram;
m_VPBuiltinCache.insert(desc);
return desc.VertexProgram;
}
#ifdef NL_STATIC
} // NLDRIVERGL3
#endif
} // NL3D

@ -0,0 +1,61 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2014 by authors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_DRIVER_OPENGL_VERTEX_PROGRAM_H
#define NL_DRIVER_OPENGL_VERTEX_PROGRAM_H
#include "nel/misc/types_nl.h"
namespace NL3D {
class CVertexProgram;
#ifdef NL_STATIC
namespace NLDRIVERGL3 {
#endif
class CDriverGL3;
// The default vertex program
class CDriverGL3VertexProgramDefault
{
struct CDesc
{
};
public:
CDriverGL3VertexProgramDefault();
~CDriverGL3VertexProgramDefault();
void setDriver(CDriverGL3 *driver);
CVertexProgram *generate();
private:
CDriverGL3 *m_Driver;
};
#ifdef NL_STATIC
} // NLDRIVERGL3
#endif
} // NL3D
#endif // NL_DRIVER_OPENGL_VERTEX_PROGRAM_H
/* end of file */
Loading…
Cancel
Save