Fixed up version of the OpenGL ARB shader "parallax map and normal map with fog" patch. The code requires little changes to the ShaderMaterial in order to reuse existing shader renders, as we now have an array instead of one shader handle. Also, vertex and pixel shaders need to be adapted for fog usage, namely by setting the fogcoord in the vertex shader and adding a comment into which Irrlicht will add the proper fog option. Documentation will follow once we have cleaned up the shader usage.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2467 dfc29bdd-3216-0410-991c-e03cc46cb475
master
hybrid 2009-07-11 23:47:00 +00:00
parent 8486bddd81
commit 63a3790722
4 changed files with 117 additions and 54 deletions

View File

@ -58,8 +58,10 @@ const char OPENGL_NORMAL_MAP_VSH[] =
"# transform position to clip space \n"\
"DP4 OutPos.x, MVP[0], InPos;\n"\
"DP4 OutPos.y, MVP[1], InPos;\n"\
"DP4 OutPos.z, MVP[2], InPos;\n"\
"DP4 Temp.z, MVP[2], InPos;\n"\
"DP4 OutPos.w, MVP[3], InPos;\n"\
"MOV OutPos.z, Temp.z;\n"\
"MOV result.fogcoord.x, Temp.z;\n"\
"\n"\
"# transform normal \n"\
"DP3 TempNormal.x, InNormal.x, program.local[0];\n"\
@ -136,6 +138,7 @@ const char OPENGL_NORMAL_MAP_VSH[] =
// transfered it 1:1 to OpenGL
const char OPENGL_NORMAL_MAP_PSH[] =
"!!ARBfp1.0\n"\
"#_IRR_FOG_MODE_\n"\
"\n"\
"#Input\n"\
"ATTRIB inTexCoord = fragment.texcoord[0]; \n"\
@ -236,7 +239,7 @@ COpenGLNormalMapRenderer::~COpenGLNormalMapRenderer()
{
// prevent this from deleting shaders we did not create
VertexShader = 0;
PixelShader = 0;
PixelShader.clear();
}
}

View File

@ -61,8 +61,10 @@ const char OPENGL_PARALLAX_MAP_VSH[] =
"# transform position to clip space \n"\
"DP4 OutPos.x, MVP[0], InPos;\n"\
"DP4 OutPos.y, MVP[1], InPos;\n"\
"DP4 OutPos.z, MVP[2], InPos;\n"\
"DP4 Temp.z, MVP[2], InPos;\n"\
"DP4 OutPos.w, MVP[3], InPos;\n"\
"MOV OutPos.z, Temp.z;\n"\
"MOV result.fogcoord.x, Temp.z;\n"\
"\n"\
"# transform normal \n"\
"DP3 TempNormal.x, InNormal.x, program.local[0];\n"\
@ -154,6 +156,7 @@ const char OPENGL_PARALLAX_MAP_VSH[] =
// transfered it 1:1 to OpenGL
const char OPENGL_PARALLAX_MAP_PSH[] =
"!!ARBfp1.0\n"\
"#_IRR_FOG_MODE_\n"\
"\n"\
"#Input\n"\
"ATTRIB inTexCoord = fragment.texcoord[0]; \n"\
@ -270,7 +273,7 @@ COpenGLParallaxMapRenderer::~COpenGLParallaxMapRenderer()
{
// prevent this from deleting shaders we did not create
VertexShader = 0;
PixelShader = 0;
PixelShader.clear();
}
}

View File

@ -23,13 +23,18 @@ COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(video::COpenGLDrive
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData)
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
VertexShader(0), PixelShader(0), UserData(userData)
VertexShader(0), UserData(userData)
{
#ifdef _DEBUG
setDebugName("COpenGLShaderMaterialRenderer");
#endif
PixelShader.set_used(4);
for (u32 i=0; i<4; ++i)
{
PixelShader[i]=0;
}
if (BaseMaterial)
BaseMaterial->grab();
@ -46,8 +51,14 @@ COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(COpenGLDriver* driv
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial, s32 userData)
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
VertexShader(0), PixelShader(0), UserData(userData)
VertexShader(0), UserData(userData)
{
PixelShader.set_used(4);
for (u32 i=0; i<4; ++i)
{
PixelShader[i]=0;
}
if (BaseMaterial)
BaseMaterial->grab();
@ -65,8 +76,9 @@ COpenGLShaderMaterialRenderer::~COpenGLShaderMaterialRenderer()
if (VertexShader)
Driver->extGlDeletePrograms(1, &VertexShader);
if (PixelShader)
Driver->extGlDeletePrograms(1, &PixelShader);
for (u32 i=0; i<PixelShader.size(); ++i)
if (PixelShader[i])
Driver->extGlDeletePrograms(1, &PixelShader[i]);
if (BaseMaterial)
BaseMaterial->drop();
@ -95,7 +107,7 @@ void COpenGLShaderMaterialRenderer::init(s32& outMaterialTypeNr, const c8* verte
bool COpenGLShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
// call callback to set shader constants
if (CallBack && (VertexShader || PixelShader))
if (CallBack && (VertexShader || PixelShader[0]))
CallBack->OnSetConstants(service, UserData);
return true;
@ -118,9 +130,27 @@ void COpenGLShaderMaterialRenderer::OnSetMaterial(const video::SMaterial& materi
// set new pixel shader
#ifdef GL_ARB_fragment_program
if (PixelShader)
if (PixelShader[0])
{
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader);
if (!material.FogEnable)
{
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[0]);
}
else
{
GLint curFogMode;
glGetIntegerv(GL_FOG_MODE, &curFogMode);
// if (Driver->LinearFog && PixelShader[1])
if (curFogMode==GL_LINEAR && PixelShader[1])
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[1]);
// else if (!Driver->LinearFog && PixelShader[2])
else if (curFogMode==GL_EXP && PixelShader[2])
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[2]);
else if (curFogMode==GL_EXP2 && PixelShader[3])
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[3]);
else
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[0]);
}
glEnable(GL_FRAGMENT_PROGRAM_ARB);
}
#endif
@ -148,7 +178,7 @@ void COpenGLShaderMaterialRenderer::OnUnsetMaterial()
#endif
#ifdef GL_ARB_fragment_program
if (PixelShader)
if (PixelShader[0])
glDisable(GL_FRAGMENT_PROGRAM_ARB);
#endif
@ -164,24 +194,9 @@ bool COpenGLShaderMaterialRenderer::isTransparent() const
}
bool COpenGLShaderMaterialRenderer::createPixelShader(const c8* pxsh)
// This method needs a properly cleaned error state before the checked instruction is called
bool COpenGLShaderMaterialRenderer::checkError(const irr::c8* type)
{
if (!pxsh)
return true;
Driver->extGlGenPrograms(1, &PixelShader);
#ifdef GL_ARB_fragment_program
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader);
// clear error buffer
while(glGetError() != GL_NO_ERROR)
{}
// compile
Driver->extGlProgramString(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
strlen(pxsh), pxsh);
#endif
#ifdef GL_ARB_vertex_program
GLenum g = glGetError();
if (g != GL_NO_ERROR)
@ -189,20 +204,69 @@ bool COpenGLShaderMaterialRenderer::createPixelShader(const c8* pxsh)
GLint errPos;
glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
const char* errString = reinterpret_cast<const char*>(glGetString(GL_PROGRAM_ERROR_STRING_ARB));
core::stringc errString = type;
errString += " compilation failed at position ";
errString += core::stringc(errPos);
errString += ":\n";
errString += reinterpret_cast<const char*>(glGetString(GL_PROGRAM_ERROR_STRING_ARB));
char tmp[2048];
sprintf(tmp, "Pixel shader compilation failed at position %d:\n%s", errPos, errString);
os::Printer::log(tmp, ELL_ERROR);
os::Printer::log(errString.c_str(), ELL_ERROR);
return true;
}
#endif
return false;
}
Driver->extGlDeletePrograms(1, &PixelShader);
PixelShader=0;
bool COpenGLShaderMaterialRenderer::createPixelShader(const c8* pxsh)
{
if (!pxsh)
return true;
const core::stringc inshdr(pxsh);
core::stringc shdr;
const s32 pos = inshdr.find("#_IRR_FOG_MODE_");
const u32 numShaders = (-1 != pos)?4:1;
for (u32 i=0; i<numShaders; ++i)
{
if (i==0)
{
shdr=inshdr;
}
else
{
shdr = inshdr.subString(0, pos);
switch (i) {
case 1: shdr += "OPTION ARB_fog_linear;"; break;
case 2: shdr += "OPTION ARB_fog_exp;"; break;
case 3: shdr += "OPTION ARB_fog_exp2;"; break;
}
shdr += inshdr.subString(pos+16, inshdr.size()-pos-16);
}
#ifdef GL_ARB_fragment_program
Driver->extGlGenPrograms(1, &PixelShader[i]);
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[i]);
// clear error buffer
while(glGetError() != GL_NO_ERROR)
{}
// compile
Driver->extGlProgramString(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
shdr.size(), shdr.c_str());
if (checkError("Pixel shader"))
{
Driver->extGlDeletePrograms(1, &PixelShader[i]);
PixelShader[i]=0;
return false;
}
#else
return false;
#endif
}
return true;
}
@ -225,18 +289,8 @@ bool COpenGLShaderMaterialRenderer::createVertexShader(const c8* vtxsh)
Driver->extGlProgramString(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
strlen(vtxsh), vtxsh);
GLenum g = glGetError();
if (g != GL_NO_ERROR)
if (checkError("Vertex shader"))
{
GLint errPos;
glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
const char* errString = reinterpret_cast<const char*>(glGetString(GL_PROGRAM_ERROR_STRING_ARB));
char tmp[2048];
sprintf(tmp, "Vertex shader compilation failed at position %d:\n%s", errPos, errString);
os::Printer::log(tmp, ELL_ERROR);
Driver->extGlDeletePrograms(1, &VertexShader);
VertexShader=0;
@ -255,4 +309,3 @@ bool COpenGLShaderMaterialRenderer::createVertexShader(const c8* vtxsh)
#endif

View File

@ -67,18 +67,22 @@ protected:
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial, s32 userData=0);
// must not be called more than once!
void init(s32& outMaterialTypeNr, const c8* vertexShaderProgram,
const c8* pixelShaderProgram, E_VERTEX_TYPE type);
bool createPixelShader(const c8* pxsh);
bool createVertexShader(const c8* vtxsh);
bool checkError(const irr::c8* type);
COpenGLDriver* Driver;
IShaderConstantSetCallBack* CallBack;
IMaterialRenderer* BaseMaterial;
GLuint VertexShader;
GLuint PixelShader;
// We have 4 values here, [0] is the non-fog version, the other three are
// ARB_fog_linear, ARB_fog_exp, and ARB_fog_exp2 in that order
core::array<GLuint> PixelShader;
s32 UserData;
};