diff --git a/src/osgPlugins/bsp/VBSPGeometry.cpp b/src/osgPlugins/bsp/VBSPGeometry.cpp index 4e6f4017a..980c03775 100644 --- a/src/osgPlugins/bsp/VBSPGeometry.cpp +++ b/src/osgPlugins/bsp/VBSPGeometry.cpp @@ -29,7 +29,7 @@ VBSPGeometry::VBSPGeometry(VBSPData * bspData) disp_vertex_array = new Vec3Array(); disp_normal_array = new Vec3Array(); disp_texcoord_array = new Vec2Array(); - disp_vertex_attr_array = new FloatArray(); + disp_vertex_attr_array = new Vec4Array(); // Create a second primitive set for drawing indexed triangles, which is // the quickest method for drawing the displacement surfaces @@ -276,6 +276,7 @@ void VBSPGeometry::createDispSurface(Face & face, DisplaceInfo & dispInfo) osg::Vec3 normal; float u, v; osg::Vec2 texCoord; + float alphaBlend; unsigned char edgeBits; @@ -422,9 +423,12 @@ void VBSPGeometry::createDispSurface(Face & face, DisplaceInfo & dispInfo) // Add the texture coordinate to the array disp_texcoord_array->push_back(texCoord); - // Get the texture blend parameter for this vertex as well - disp_vertex_attr_array-> - push_back(dispVertInfo.alpha_blend / 255.0); + // Get the texture blend parameter for this vertex as well, and + // assign it as the alpha channel for the primary vertex color. + // We'll use a combiner operation to do the texture blending + alphaBlend = dispVertInfo.alpha_blend / 255.0; + disp_vertex_attr_array->push_back( + osg::Vec4f(1.0, 1.0, 1.0, 1.0 - alphaBlend)); } } @@ -667,14 +671,9 @@ ref_ptr VBSPGeometry::createGeometry() geometry->setNormalArray(disp_normal_array.get()); geometry->setNormalBinding(Geometry::BIND_PER_VERTEX); geometry->setTexCoordArray(0, disp_texcoord_array.get()); - geometry->setVertexAttribArray(1, disp_vertex_attr_array.get()); - geometry->setVertexAttribBinding(1, Geometry::BIND_PER_VERTEX); - - // Add an overall color - color.set(1.0, 1.0, 1.0, 1.0); - colorArray = new Vec4Array(1, &color); - geometry->setColorArray(colorArray.get()); - geometry->setColorBinding(Geometry::BIND_OVERALL); + geometry->setTexCoordArray(1, disp_texcoord_array.get()); + geometry->setColorArray(disp_vertex_attr_array.get()); + geometry->setColorBinding(Geometry::BIND_PER_VERTEX); // Add our primitive set to the geometry geometry->addPrimitiveSet(disp_primitive_set.get()); diff --git a/src/osgPlugins/bsp/VBSPGeometry.h b/src/osgPlugins/bsp/VBSPGeometry.h index 8bc46d432..367592faa 100644 --- a/src/osgPlugins/bsp/VBSPGeometry.h +++ b/src/osgPlugins/bsp/VBSPGeometry.h @@ -27,7 +27,7 @@ class VBSPGeometry osg::ref_ptr disp_vertex_array; osg::ref_ptr disp_normal_array; osg::ref_ptr disp_texcoord_array; - osg::ref_ptr disp_vertex_attr_array; + osg::ref_ptr disp_vertex_attr_array; osg::ref_ptr disp_primitive_set; bool doesEdgeExist(int row, int col, int direction, diff --git a/src/osgPlugins/bsp/VBSPReader.cpp b/src/osgPlugins/bsp/VBSPReader.cpp index 94313ab53..157173e08 100644 --- a/src/osgPlugins/bsp/VBSPReader.cpp +++ b/src/osgPlugins/bsp/VBSPReader.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -636,100 +638,6 @@ ref_ptr VBSPReader::readTextureFile(std::string textureName) } -ref_ptr VBSPReader::createBlendShader(Texture * tex1, Texture * tex2) -{ - const char * blendVtxShaderCode = - { - "attribute float vBlendParam;\n" - "\n" - "varying float fBlendParam;\n" - "\n" - "void main(void)\n" - "{\n" - " vec3 normal, lightDir;\n" - " vec4 ambient, diffuse;\n" - " float nDotL;\n" - "\n" - " // Simple directional lighting (for now). We're assuming a\n" - " // single light source\n" - " // TODO: This is only used for terrain geometry, so it should be\n" - " // lightmapped\n" - " normal = normalize(gl_NormalMatrix * gl_Normal);\n" - " lightDir = normalize(vec3(gl_LightSource[0].position));\n" - " nDotL = max(dot(normal, lightDir), 0.0);\n" - " ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;\n" - " diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;\n" - "\n" - " // Calculate the vertex color\n" - " gl_FrontColor = 0.1 + ambient + nDotL * diffuse;\n" - "\n" - " // Pass the texture blend parameter through to the fragment\n" - " // shader\n" - " fBlendParam = vBlendParam;\n" - "\n" - " // The basic transforms\n" - " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" - " gl_TexCoord[0] = vec4(gl_MultiTexCoord0.st, 0.0, 0.0);\n" - "}\n" - }; - - const char * blendFrgShaderCode = - { - "uniform sampler2D tex1;\n" - "uniform sampler2D tex2;\n" - "\n" - "varying float fBlendParam;\n" - "\n" - "void main(void)\n" - "{\n" - " vec4 tex1Color;\n" - " vec4 tex2Color;\n" - "\n" - " tex1Color = texture2D(tex1, gl_TexCoord[0].st) *\n" - " (1.0 - fBlendParam);\n" - " tex2Color = texture2D(tex2, gl_TexCoord[0].st) * fBlendParam;\n" - "\n" - " gl_FragColor = gl_Color * (tex1Color + tex2Color);\n" - "}\n" - }; - - // Create the stateset - StateSet * stateSet = new StateSet(); - - // Add the two textures - stateSet->setTextureAttributeAndModes(0, tex1, StateAttribute::ON); - stateSet->setTextureAttributeAndModes(1, tex2, StateAttribute::ON); - - // Create the vertex and fragment shaders - Shader * blendVtxShader = new Shader(Shader::VERTEX); - blendVtxShader->setShaderSource(blendVtxShaderCode); - Shader * blendFrgShader = new Shader(Shader::FRAGMENT); - blendFrgShader->setShaderSource(blendFrgShaderCode); - - // Create the two texture uniforms - Uniform * tex1Sampler = new Uniform(Uniform::SAMPLER_2D, "tex1"); - tex1Sampler->set(0); - Uniform * tex2Sampler = new Uniform(Uniform::SAMPLER_2D, "tex2"); - tex2Sampler->set(1); - - // Create the program - Program * blendProgram = new Program(); - blendProgram->addShader(blendVtxShader); - blendProgram->addShader(blendFrgShader); - - // The texture blending parameter will be on vertex attribute 1 - blendProgram->addBindAttribLocation("vBlendParam", (GLuint) 1); - - // Add everything to the StateSet - stateSet->addUniform(tex1Sampler); - stateSet->addUniform(tex2Sampler); - stateSet->setAttributeAndModes(blendProgram, StateAttribute::ON); - - // Return the StateSet - return stateSet; -} - - ref_ptr VBSPReader::readMaterialFile(std::string materialName) { std::string mtlFileName; @@ -745,6 +653,8 @@ ref_ptr VBSPReader::readMaterialFile(std::string materialName) std::string tex2Name; ref_ptr texture; ref_ptr texture2; + ref_ptr combiner0; + ref_ptr combiner1; ref_ptr material; ref_ptr blend; bool translucent; @@ -886,23 +796,80 @@ ref_ptr VBSPReader::readMaterialFile(std::string materialName) // Check the shader's name if (equalCaseInsensitive(shaderName, "WorldVertexTransition")) { - // This shader blends between two textures based on a per-vertex - // attribute. This is used for displaced terrain surfaces in HL2 maps. - stateSet = createBlendShader(texture.get(), texture2.get()); + // Make sure we have both textures + if (texture.valid() && texture2.valid()) + { + // Create a StateSet for the following state + stateSet = new osg::StateSet(); - // Add a material to the state set - material = new Material(); - material->setAmbient(Material::FRONT_AND_BACK, - Vec4(1.0, 1.0, 1.0, 1.0) ); - material->setDiffuse(Material::FRONT_AND_BACK, - Vec4(1.0, 1.0, 1.0, 1.0) ); - material->setSpecular(Material::FRONT_AND_BACK, + // Attach the two textures + stateSet->setTextureAttributeAndModes(0, texture.get(), + osg::StateAttribute::ON); + stateSet->setTextureAttributeAndModes(1, texture2.get(), + osg::StateAttribute::ON); + + // On the first texture unit, set up a combiner operation to + // interpolate between the textures on units 0 and 1, using + // the fragment's primary alpha color as the interpolation + // parameter (NOTE: we need ARB_texture_env_crossbar for this) + combiner0 = new osg::TexEnvCombine(); + combiner0->setConstantColor(osg::Vec4f(1.0, 1.0, 1.0, 1.0)); + + combiner0->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + combiner0->setSource0_RGB(osg::TexEnvCombine::TEXTURE0); + combiner0->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); + combiner0->setSource1_RGB(osg::TexEnvCombine::TEXTURE1); + combiner0->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); + combiner0->setSource2_RGB(osg::TexEnvCombine::PRIMARY_COLOR); + combiner0->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); + + combiner0->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + combiner0->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); + combiner0->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); + + combiner0->setScale_RGB(1.0); + combiner0->setScale_Alpha(1.0); + + stateSet->setTextureAttributeAndModes(0, combiner0.get(), + osg::StateAttribute::ON); + + // On the second texture unit, do a typical modulate operation + // between the interpolated texture color from the previous + // unit and the fragment's primary (lit) RGB color. Force the + // alpha to be 1.0, since this HL2 shader is never transparent + combiner1 = new osg::TexEnvCombine(); + combiner1->setConstantColor(osg::Vec4f(1.0, 1.0, 1.0, 1.0)); + + combiner1->setCombine_RGB(osg::TexEnvCombine::MODULATE); + combiner1->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + combiner1->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); + combiner1->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR); + combiner1->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); + + combiner1->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + combiner1->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); + combiner1->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); + + combiner1->setScale_RGB(1.0); + combiner1->setScale_Alpha(1.0); + + stateSet->setTextureAttributeAndModes(1, combiner1.get(), + osg::StateAttribute::ON); + + // Add a material to the state set + material = new Material(); + material->setAmbient(Material::FRONT_AND_BACK, + Vec4(1.0, 1.0, 1.0, 1.0) ); + material->setDiffuse(Material::FRONT_AND_BACK, + Vec4(1.0, 1.0, 1.0, 1.0) ); + material->setSpecular(Material::FRONT_AND_BACK, + Vec4(0.0, 0.0, 0.0, 1.0) ); + material->setShininess(Material::FRONT_AND_BACK, 1.0); + material->setEmission(Material::FRONT_AND_BACK, Vec4(0.0, 0.0, 0.0, 1.0) ); - material->setShininess(Material::FRONT_AND_BACK, 1.0); - material->setEmission(Material::FRONT_AND_BACK, - Vec4(0.0, 0.0, 0.0, 1.0) ); - material->setAlpha(Material::FRONT_AND_BACK, alpha); - stateSet->setAttributeAndModes(material.get(), StateAttribute::ON); + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + stateSet->setAttributeAndModes(material.get(), StateAttribute::ON); + } } else if (equalCaseInsensitive(shaderName, "UnlitGeneric")) { @@ -917,6 +884,9 @@ ref_ptr VBSPReader::readMaterialFile(std::string materialName) { stateSet->setTextureAttributeAndModes(0, texture.get(), StateAttribute::ON); + stateSet->setTextureAttributeAndModes(0, + new TexEnv(TexEnv::MODULATE), + StateAttribute::ON); // See if the material is translucent if (translucent) @@ -965,6 +935,9 @@ ref_ptr VBSPReader::readMaterialFile(std::string materialName) { stateSet->setTextureAttributeAndModes(0, texture.get(), StateAttribute::ON); + stateSet->setTextureAttributeAndModes(0, + new TexEnv(TexEnv::MODULATE), + StateAttribute::ON); // See if the material is translucent if (translucent)