diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_material.cpp b/code/nel/src/3d/driver/opengl3/driver_opengl_material.cpp index f6941e80c..68a55a5ff 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_material.cpp +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_material.cpp @@ -317,7 +317,7 @@ bool CDriverGL3::setupMaterial(CMaterial& mat) } // Optimize: reset all flags at the end. - mat.clearTouched(0xFFFFFFFF); + // mat.clearTouched(0xFFFFFFFF); // FIXME GL3 THIS IS NOW DONE IN GENERATE OF PP DESC, THIS NEED RESTRUCTURING } // 2b. User supplied pixel shader overrides material diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_pixel_program.cpp b/code/nel/src/3d/driver/opengl3/driver_opengl_pixel_program.cpp index e5c703144..f63dde297 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_pixel_program.cpp +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_pixel_program.cpp @@ -31,9 +31,52 @@ namespace NL3D { namespace NLDRIVERGL3 { #endif +namespace /* anonymous */ { + +CMaterial::TShader getSupportedShader(CMaterial::TShader shader) +{ + switch (shader) + { + case CMaterial::UserColor: + case CMaterial::Normal: + case CMaterial::Specular: + return shader; + default: + return CMaterial::Normal; + } +} + +uint maxTextures(CMaterial::TShader shader) +{ + switch (shader) + { + case CMaterial::Specular: + return 2; + default: + return IDRV_MAT_MAXTEXTURES; + } +} + +bool useTexEnv(CMaterial::TShader shader) +{ + return shader == CMaterial::Normal + || shader == CMaterial::UserColor; +} + +} /* anonymous namespace */ + bool operator<(const CPPBuiltin &left, const CPPBuiltin &right) { // Material state + if (left.Shader != right.Shader) + return left.Shader < right.Shader; + if (left.TextureActive != right.TextureActive) + return left.TextureActive < right.TextureActive; + uint maxTex = maxTextures(left.Shader); + if (useTexEnv(left.Shader)) + for (uint stage = 0; stage < maxTex; ++stage) + if (left.TexEnvMode[stage] != right.TexEnvMode[stage]) + return left.TexEnvMode[stage] < right.TexEnvMode[stage]; // Driver state if (left.VertexFormat != right.VertexFormat) @@ -45,7 +88,219 @@ bool operator<(const CPPBuiltin &left, const CPPBuiltin &right) } namespace /* anonymous */ { + +bool useTex(CPPBuiltin &desc, uint stage) +{ + return (desc.TextureActive & (1 << stage)) != 0; +} +void ppTexEnv(std::stringstream &ss, CPPBuiltin &desc) +{ + uint maxTex = maxTextures(desc.Shader); + CMaterial::CTexEnv texEnv; + for (uint stage = 0; stage < maxTex; ++stage) + { + if (useTex(desc, stage)) + { + texEnv.EnvPacked = desc.TexEnvMode[stage]; + for (uint arg = 0; arg < 3; ++arg) + { + // Texop arg + ss << "vec4 texop" << stage << "arg" << arg << ";" << std::endl; + + // RGB + uint rgbArg = texEnv.getColorArg(arg); + uint rgbOp = texEnv.getColorOperand(arg); + std::stringstream rgbArgVec; + switch (rgbArg) + { + case CMaterial::Texture: + rgbArgVec << "texel" << stage; + break; + case CMaterial::Previous: + if (stage > 0) + { + rgbArgVec << "texop" << (stage - 1); + break; + } + case CMaterial::Diffuse: + rgbArgVec << "diffuse"; + break; + case CMaterial::Constant: + rgbArgVec << "constant" << stage; + break; + } + ss << "texop" << stage << "arg" << arg << ".rgb = "; + switch (rgbOp) // SrcColor=0, InvSrcColor, SrcAlpha, InvSrcAlpha + { + case CMaterial::SrcColor: + ss << rgbArgVec.str() << ".rgb"; + break; + case CMaterial::InvSrcColor: + ss << "vec3(1.0, 1.0, 1.0) - " << rgbArgVec.str() << ".rgb"; + break; + case CMaterial::SrcAlpha: + ss << rgbArgVec.str() << ".aaa"; + break; + case CMaterial::InvSrcAlpha: + ss << "(1.0 - " << rgbArgVec.str() << ").aaa"; + break; + } + ss << ";" << std::endl; + + // Alpha + uint alphaArg = texEnv.getAlphaArg(arg); + uint alphaOp = texEnv.getAlphaOperand(arg); + std::stringstream alphaArgVec; + switch (alphaArg) + { + case CMaterial::Texture: + alphaArgVec << "texel" << stage; + break; + case CMaterial::Previous: + if (stage > 0) + { + alphaArgVec << "texop" << (stage - 1); + break; + } + case CMaterial::Diffuse: + alphaArgVec << "diffuse"; + break; + case CMaterial::Constant: + alphaArgVec << "constant" << stage; + break; + } + ss << "texop" << stage << "arg" << arg << ".a = "; + switch (alphaOp) // SrcColor=0, InvSrcColor, SrcAlpha, InvSrcAlpha + { + case CMaterial::SrcColor: + ss << alphaArgVec.str() << ".r"; + break; + case CMaterial::InvSrcColor: + ss << "1.0 - " << alphaArgVec.str() << ".r"; + break; + case CMaterial::SrcAlpha: + ss << alphaArgVec.str() << ".a"; + break; + case CMaterial::InvSrcAlpha: + ss << "1.0 - " << alphaArgVec.str() << ".a"; + break; + } + ss << ";" << std::endl; + } + ss << "vec4 texop" << stage << ";" << std::endl; + + // RGB + switch (texEnv.Env.OpRGB) + { + case CMaterial::InterpolateConstant: + ss << "float texop" << stage << "rgbAs = constant" << stage << ".a;" << std::endl; + break; + case CMaterial::InterpolatePrevious: + if (stage > 0) + { + ss << "float texop" << stage << "rgbAs = texop" << stage << ".a;" << std::endl; + break; + } + case CMaterial::InterpolateDiffuse: + ss << "float texop" << stage << "rgbAs = diffuse.a;" << std::endl; + break; + case CMaterial::InterpolateTexture: + ss << "float texop" << stage << "rgbAs = texel" << stage << ".a;" << std::endl; + break; + } + ss << "texop" << stage << ".rgb = "; + switch (texEnv.Env.OpRGB) + { + case CMaterial::Replace: + ss << "texop" << stage << "arg0.rgb"; + break; + case CMaterial::Modulate: + ss << "texop" << stage << "arg0.rgb * texop" << stage << "arg1.rgb"; + break; + case CMaterial::Add: + ss << "texop" << stage << "arg0.rgb + texop" << stage << "arg1.rgb"; + break; + case CMaterial::AddSigned: + ss << "texop" << stage << "arg0.rgb + texop" << stage << "arg1.rgb - vec3(0.5, 0.5, 0.5)"; + break; + case CMaterial::InterpolateConstant: + case CMaterial::InterpolateDiffuse: + case CMaterial::InterpolatePrevious: + case CMaterial::InterpolateTexture: + ss << "texop" << stage << "arg0.rgb * texop" << stage << "rgbAs + texop" << stage << "arg1.rgb * (1.0 - texop" << stage << "rgbAs)"; + break; + case CMaterial::Mad: + ss << "texop" << stage << "arg0.rgb * texop" << stage << "arg1.rgb + texop" << stage << "arg2.rgb"; + break; + } + ss << ";" << std::endl; + + // Alpha + switch (texEnv.Env.OpAlpha) + { + case CMaterial::InterpolateConstant: + ss << "float texop" << stage << "alphaAs = constant" << stage << ".a;" << std::endl; + break; + case CMaterial::InterpolatePrevious: + if (stage > 0) + { + ss << "float texop" << stage << "alphaAs = texop" << stage << ".a;" << std::endl; + break; + } + case CMaterial::InterpolateDiffuse: + ss << "float texop" << stage << "alphaAs = diffuse.a;" << std::endl; + break; + case CMaterial::InterpolateTexture: + ss << "float texop" << stage << "alphaAs = texel" << stage << ".a;" << std::endl; + break; + } + ss << "texop" << stage << ".a = "; + switch (texEnv.Env.OpAlpha) + { + case CMaterial::Replace: + ss << "texop" << stage << "arg0.a"; + break; + case CMaterial::Modulate: + ss << "texop" << stage << "arg0.a * texop" << stage << "arg1.a"; + break; + case CMaterial::Add: + ss << "texop" << stage << "arg0.a + texop" << stage << "arg1.a"; + break; + case CMaterial::AddSigned: + ss << "texop" << stage << "arg0.a + texop" << stage << "arg1.a - 0.5"; + break; + case CMaterial::InterpolateConstant: + case CMaterial::InterpolateDiffuse: + case CMaterial::InterpolatePrevious: + case CMaterial::InterpolateTexture: + ss << "texop" << stage << "arg0.a * texop" << stage << "rgbAs + texop" << stage << "arg1.a * (1.0 - texop" << stage << "rgbAs)"; + break; + case CMaterial::Mad: + ss << "texop" << stage << "arg0.a * texop" << stage << "arg1.a + texop" << stage << "arg2.a"; + break; + } + ss << ";" << std::endl; + } + else if (stage == 0) + { + ss << "vec4 texop" << stage << " = diffuse; // no active texture in stage" << std::endl; + } + else + { + ss << "vec4 texop" << stage << " = texop" << (stage - 1) << "; // no active texture in stage" << std::endl; + } + } + ss << "fragColor = texop" << (maxTex - 1) << ";" << std::endl; +} + +void ppSpecular(std::stringstream &ss, CPPBuiltin &desc) +{ + ss << "vec3 specop0 = texel0.rgb * diffuse.rgb;" << std::endl; + ss << "vec4 specop1 = vec4(texel1.rgb * texel0.a + specop0, diffuse.a);" << std::endl; + ss << "fragColor = specop1;" << std::endl; +} + void ppGenerate(std::string &result, CPPBuiltin &desc) { @@ -87,11 +342,18 @@ void CDriverGL3::generateBuiltinPixelProgram(CMaterial &mat) m_PPBuiltinCache.insert(matDrv->PPBuiltin); } -void CPPBuiltin::checkDriverStateTouched(CDriverGL3 *driver) +void CPPBuiltin::checkDriverStateTouched(CDriverGL3 *driver) // MUST NOT depend on any state set by checkMaterialStateTouched { - if (VertexFormat != driver->m_VPBuiltinCurrent.VertexFormat) + // Add generated texture coordinates to vertex format + uint16 vertexFormat = driver->m_VPBuiltinCurrent.VertexFormat; + for (sint stage = 0; stage < IDRV_MAT_MAXTEXTURES; ++stage) + if (driver->m_VPBuiltinCurrent.TexGenMode[stage] >= 0) + vertexFormat |= g_VertexFlags[TexCoord0 + stage]; + + // Compare values + if (VertexFormat != vertexFormat) { - VertexFormat = driver->m_VPBuiltinCurrent.VertexFormat; + VertexFormat = vertexFormat; Touched = true; } if (Fog != driver->m_VPBuiltinCurrent.Fog) @@ -101,9 +363,43 @@ void CPPBuiltin::checkDriverStateTouched(CDriverGL3 *driver) } } -void CPPBuiltin::checkMaterialStateTouched(CMaterial &mat) +void CPPBuiltin::checkMaterialStateTouched(CMaterial &mat) // MUST NOT depend on any state set by checkDriverStateTouched { - + // Optimize + uint32 touched = !PixelProgram ? IDRV_TOUCHED_ALL : mat.getTouched(); + if (touched == 0) return; + + // Compare values + CMaterial::TShader shader = getSupportedShader(mat.getShader()); + if (Shader != shader) + { + Shader = shader; + Touched = true; + } + uint maxTex = maxTextures(shader); + if (touched & IDRV_TOUCHED_ALLTEX) // Note: There is a case where textures are provided where no texture coordinates are provided, this is handled gracefully by the pixel program generation (it will use a vec(0) texture coordinate). The inverse is an optimization issue. + { + uint8 textureActive = 0x00; + for (uint i = 0; i < maxTex; ++i) + if (mat.getTexture(i)) + textureActive |= (1 << i); + TextureActive = textureActive; + Touched = true; + } + if (useTexEnv(shader) && (touched & IDRV_TOUCHED_TEXENV)) + { + for (uint stage = 0; stage < maxTex; ++stage) + { + if (TexEnvMode[stage] != mat.getTexEnvMode(stage)) + { + TexEnvMode[stage] = mat.getTexEnvMode(stage); + Touched = true; + } + } + } + + // Optimize + mat.clearTouched(0xFFFFFFFF); } #ifdef NL_STATIC diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_program.cpp b/code/nel/src/3d/driver/opengl3/driver_opengl_program.cpp index 455ee9651..5a28941ce 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_program.cpp +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_program.cpp @@ -691,6 +691,28 @@ bool CDriverGL3::setupBuiltinPixelProgram(CMaterial &mat) { if (m_UserPixelProgram) return true; + CMaterialDrvInfosGL3 *matDrv = static_cast((IMaterialDrvInfos *)(mat._MatDrvInfo)); + nlassert(matDrv); + + matDrv->PPBuiltin.checkDriverStateTouched(this); + matDrv->PPBuiltin.checkMaterialStateTouched(mat); + + if (matDrv->PPBuiltin.Touched) + { + generateBuiltinPixelProgram(mat); + nlassert(matDrv->PPBuiltin.PixelProgram); + matDrv->PPBuiltin.Touched = false; + } + + if (!activePixelProgram(matDrv->PPBuiltin.PixelProgram, true)) + return false; + + // GL3 TODO: Here we set the uniforms of the vertex program! + + return true; + + +#if 0 // nlassert(!m_UserVertexProgram); // TEMP // nlassert(!m_UserPixelProgram); // TEMP @@ -811,6 +833,7 @@ bool CDriverGL3::setupBuiltinPixelProgram(CMaterial &mat) } return true; +#endif } bool CDriverGL3::setupDynMatProgram(CMaterial& mat, uint pass) diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_program.h b/code/nel/src/3d/driver/opengl3/driver_opengl_program.h index 2a50af642..b9ce913bd 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_program.h +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_program.h @@ -55,6 +55,10 @@ struct CPPBuiltin uint16 VertexFormat; bool Fog; + CMaterial::TShader Shader; + uint8 TextureActive; + uint32 TexEnvMode[IDRV_MAT_MAXTEXTURES]; // Normal, UserColor + CPixelProgram *PixelProgram; bool Touched;