diff --git a/ACG/GL/IRenderer.cc b/ACG/GL/IRenderer.cc index f90fb4a4074dbdc0f41e4154da79016296c10640..59d7655f0cae823a990cfecb6e2186cf1376e74e 100644 --- a/ACG/GL/IRenderer.cc +++ b/ACG/GL/IRenderer.cc @@ -441,7 +441,7 @@ void IRenderer::traverseRenderableNodes( ACG::GLState* _glState, ACG::SceneGraph { if ( _node->status() != ACG::SceneGraph::BaseNode::HideNode ) - _node->enter(*_glState, _drawMode); + _node->enter(*_glState, nodeDM); // fetch material (Node itself can be a material node, so we have to diff --git a/ACG/GL/RenderObject.cc b/ACG/GL/RenderObject.cc index a203a0f0f27e5ca779124521ee285468ba70f06a..9947d5b4fdcd1aaea5b0200ec4ca64ffc2fe93c5 100644 --- a/ACG/GL/RenderObject.cc +++ b/ACG/GL/RenderObject.cc @@ -91,6 +91,7 @@ void RenderObject::initFromState( GLState* _glState ) alpha = 1.0f; + if (_glState) { modelview = _glState->modelview(); @@ -120,6 +121,24 @@ void RenderObject::initFromState( GLState* _glState ) } shininess = _glState->shininess(); } + + + // get texcoord generation params + if (glIsEnabled(GL_TEXTURE_GEN_Q)) + shaderDesc.texGenDim = 4; + else if (glIsEnabled(GL_TEXTURE_GEN_R)) + shaderDesc.texGenDim = 3; + else if (glIsEnabled(GL_TEXTURE_GEN_T)) + shaderDesc.texGenDim = 2; + else if (glIsEnabled(GL_TEXTURE_GEN_S)) + shaderDesc.texGenDim = 1; + + if (shaderDesc.texGenDim) + { + GLint genMode = 0; + glGetTexGeniv(GL_S, GL_TEXTURE_GEN_MODE, &genMode); + shaderDesc.texGenMode = genMode; + } } void RenderObject::setupShaderGenFromDrawmode( const SceneGraph::DrawModes::DrawModeProperties* _props ) diff --git a/ACG/GL/ShaderGenerator.cc b/ACG/GL/ShaderGenerator.cc index 7797f1a431a309f1484d9490da6b6ad6cc41802a..80f614e8bd633d7044ddb8a5b5f14eb20c4f8e1e 100644 --- a/ACG/GL/ShaderGenerator.cc +++ b/ACG/GL/ShaderGenerator.cc @@ -196,9 +196,19 @@ void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc, const Defau if (_iodesc->passTexCoord_ && !_desc->textured()) { - // assume 2d texcoords - addInput("vec2 inTexCoord"); - addOutput("vec2 outVertexTexCoord"); + // assume 2d texcoords as default + int texdim = 2; + + if (_desc->texGenMode && _desc->texGenDim > 0 && _desc->texGenDim <= 4) + texdim = _desc->texGenDim; + + + QString inTexCoordString, outTexCoordString; + inTexCoordString.sprintf("vec%i inTexCoord", texdim); + outTexCoordString.sprintf("vec%i outVertexTexCoord", texdim); + + addInput(inTexCoordString); + addOutput(outTexCoordString); } @@ -1177,6 +1187,7 @@ void ShaderProgGenerator::addVertexBeginCode(QStringList* _code) } } + if (desc_.vertexColors && (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE)) _code->push_back("vec4 sg_cColor = vec4(g_cEmissive + g_cLightModelAmbient * " SG_INPUT_VERTEXCOLOR ".xyz, SG_ALPHA);"); else @@ -1192,6 +1203,84 @@ void ShaderProgGenerator::addVertexBeginCode(QStringList* _code) _code->push_back("sg_cColor = " SG_INPUT_VERTEXCOLOR ";"); + // texcoord generation + if (desc_.texGenDim && desc_.texGenMode) + { + // https://www.opengl.org/wiki/Mathematics_of_glTexGen + + if (!ioDesc_.inputTexCoord_) + { + // declare variable if it has not been allocated yet + QString texGenString; + texGenString.sprintf("vec%i sg_vTexCoord; // glTexGen emulation", desc_.texGenDim); + _code->push_back(texGenString); + } + + const char* texGenCoordString[] = { "x", "y", "z", "w" }; + + switch (desc_.texGenMode) + { + case GL_OBJECT_LINEAR: + { + for (int i = 0; i < desc_.texGenDim; ++i) + { + QString assignmentInstrString; + assignmentInstrString.sprintf("sg_vTexCoord.%s = dot(inPosition, g_vTexGenPlane[%i]);", texGenCoordString[i], i); + _code->push_back(assignmentInstrString); + } + } break; + + case GL_EYE_LINEAR: + { + for (int i = 0; i < desc_.texGenDim; ++i) + { + QString assignmentInstrString; + assignmentInstrString.sprintf("sg_vTexCoord.%s = dot(sg_vPosVS, g_vTexGenPlane[%i]);", texGenCoordString[i], i); + _code->push_back(assignmentInstrString); + } + } break; + + case GL_SPHERE_MAP: + { + _code->push_back("vec3 sg_vPosVS_unit = normalize(sg_vPosVS.xyz);"); + _code->push_back("vec3 sg_TexGenRefl = reflect(sg_vPosVS_unit, sg_vNormalVS);"); + _code->push_back("vec3 sg_TexGenRefl2 = sg_TexGenRefl; sg_TexGenRefl2.z += 1.0;"); + _code->push_back("float sg_TexGenMRcp = 0.5 * inversesqrt(dot(sg_TexGenRefl2, sg_TexGenRefl2));"); + for (int i = 0; i < desc_.texGenDim; ++i) + { + QString assignmentInstrString; + assignmentInstrString.sprintf("sg_vTexCoord.%s = sg_TexGenRefl.%s * sg_TexGenMRcp + 0.5;", texGenCoordString[i], texGenCoordString[i]); + _code->push_back(assignmentInstrString); + } + } break; + + case GL_NORMAL_MAP: + { + for (int i = 0; i < desc_.texGenDim; ++i) + { + QString assignmentInstrString; + assignmentInstrString.sprintf("sg_vTexCoord.%s = sg_vNormalVS.%s;", texGenCoordString[i], texGenCoordString[i]); + _code->push_back(assignmentInstrString); + } + } break; + + case GL_REFLECTION_MAP: + { + _code->push_back("vec3 sg_vPosVS_unit = normalize(sg_vPosVS.xyz);"); + _code->push_back("vec3 sg_TexGenRefl = reflect(sg_vPosVS_unit, sg_vNormalVS);"); + for (int i = 0; i < desc_.texGenDim; ++i) + { + QString assignmentInstrString; + assignmentInstrString.sprintf("sg_vTexCoord.%s = sg_TexGenRefl.%s;", texGenCoordString[i], texGenCoordString[i]); + _code->push_back(assignmentInstrString); + } + } break; + + default: break; + } + } + + // apply modifiers for (size_t i = 0; i < activeMods_.size(); ++i) activeMods_[i]->modifyVertexBeginCode(_code); @@ -1943,6 +2032,31 @@ void ShaderProgGenerator::generateShaders() ioDesc_.passTexCoord_ = true; } + // clamp generated texcoord dimension + int maxTexGenDim = 4; + + switch (desc_.texGenMode) + { + case GL_EYE_LINEAR: + case GL_OBJECT_LINEAR: maxTexGenDim = 4; break; + + case GL_SPHERE_MAP: maxTexGenDim = 2; break; + + case GL_NORMAL_MAP: + case GL_REFLECTION_MAP: maxTexGenDim = 3; break; + + default: maxTexGenDim = 0; break; + } + + desc_.texGenDim = std::max(std::min(desc_.texGenDim, maxTexGenDim), 0); + + if (desc_.texGenMode == GL_REFLECTION_MAP || desc_.texGenMode == GL_SPHERE_MAP || desc_.texGenMode == GL_NORMAL_MAP) + ioDesc_.inputNormal_ = true; + + if (desc_.texGenDim && desc_.texGenMode) + ioDesc_.passTexCoord_ = true; // no input, but texcoords are generated + + if (desc_.vertexColors) ioDesc_.inputColor_ = true; @@ -2574,6 +2688,19 @@ QString ShaderGenDesc::toString() const resStrm << "\nShadowTexture: " << iter->second.shadow; } + resStrm << "\nshaderDesc.texGenDim: " << texGenDim; + + switch (texGenMode) + { + case GL_OBJECT_LINEAR: resStrm << "\nshaderDesc.texGenMode: GL_OBJECT_LINEAR"; break; + case GL_EYE_LINEAR: resStrm << "\nshaderDesc.texGenMode: GL_EYE_LINEAR"; break; + case GL_SPHERE_MAP: resStrm << "\nshaderDesc.texGenMode: GL_SPHERE_MAP"; break; + case GL_NORMAL_MAP: resStrm << "\nshaderDesc.texGenMode: GL_NORMAL_MAP"; break; + case GL_REFLECTION_MAP: resStrm << "\nshaderDesc.texGenMode: GL_REFLECTION_MAP"; break; + default: resStrm << "\nshaderDesc.texGenMode: unknown"; break; + } + + if (!vertexTemplateFile.isEmpty()) resStrm << "\nshaderDesc.vertexTemplateFile: " << vertexTemplateFile; diff --git a/ACG/GL/ShaderGenerator.hh b/ACG/GL/ShaderGenerator.hh index fc83ddd81f5c28daaff85392c34c2b31117a0fe9..d8a655c5dbe2789c4da90085fca3751140324268 100644 --- a/ACG/GL/ShaderGenerator.hh +++ b/ACG/GL/ShaderGenerator.hh @@ -102,11 +102,12 @@ public: fragmentTemplateFile(""), normalizeTexColors(true), colorMaterialMode(GL_AMBIENT_AND_DIFFUSE), - textureTypes_() + textureTypes_(), + texGenDim(0), + texGenMode(GL_EYE_LINEAR) { for ( unsigned int i = 0 ; i < SG_MAX_SHADER_LIGHTS ; ++i) lightTypes[i] = SG_LIGHT_DIRECTIONAL; - } //In case, something crashes with the light types, try this hammer ;-) @@ -201,6 +202,48 @@ public: + // automatic texture coordinate generation, emulation of glTexGen + // this takes priority over any texcoords provided via addTextureType + + // dimension of generated texture coordinate: 0,1,2,3,4 (default: 0 - disabled) + int texGenDim; + + // texture generation mode: GL_OBJECT_LINEAR, GL_EYE_LINEAR, GL_SPHERE_MAP, GL_NORMAL_MAP, GL_REFLECTION_MAP + GLenum texGenMode; + + void enableTexGenObjectLinear(int _dim = 2) + { + texGenDim = std::max(std::min(_dim, 4), 0); + texGenMode = GL_OBJECT_LINEAR; + } + + void enableTexGenEyeLinear(int _dim = 2) + { + texGenDim = std::max(std::min(_dim, 4), 0); + texGenMode = GL_EYE_LINEAR; + } + + void enableTexGenSphericalMap(int _dim = 2) + { + texGenDim = std::max(std::min(_dim, 2), 0); + texGenMode = GL_SPHERE_MAP; + } + + void enableTexGenNormalMap(int _dim = 3) + { + texGenDim = std::max(std::min(_dim, 3), 0); + texGenMode = GL_NORMAL_MAP; + } + + void enableTexGenReflectionMap(int _dim = 3) + { + texGenDim = std::max(std::min(_dim, 3), 0); + texGenMode = GL_REFLECTION_MAP; + } + + void disableTexGen() { texGenDim = 0; } + + // comparison operator bool operator == (const ShaderGenDesc& _rhs) const { @@ -243,6 +286,15 @@ public: if (macros != _rhs.macros) return false; + if (texGenDim != _rhs.texGenDim) + return false; + + if (texGenDim) + { + if (texGenMode != _rhs.texGenMode) + return false; + } + if (numLights) return memcmp(lightTypes, _rhs.lightTypes, numLights * sizeof(ShaderGenLightType)) == 0; diff --git a/ACG/Scenegraph/MeshNode2T.cc b/ACG/Scenegraph/MeshNode2T.cc index 7490306289cef399caf88924a6ee53e49bb030c5..9745fe8aa50b2a0b26869a9321212ea6b8c73cc6 100644 --- a/ACG/Scenegraph/MeshNode2T.cc +++ b/ACG/Scenegraph/MeshNode2T.cc @@ -553,8 +553,29 @@ draw(GLState& _state, const DrawModes::DrawMode& _drawMode) { if ( ( _drawMode & DrawModes::SOLID_TEXTURED ) && mesh_.has_vertex_texcoords2D()) { - ///\todo enableTexCoords_ -// enable_arrays(VERTEX_ARRAY | TEXCOORD_VERTEX_ARRAY ); + ACG::GLState::enable(GL_TEXTURE_2D); + ACG::GLState::disable(GL_LIGHTING); + ACG::GLState::shadeModel(GL_FLAT); + ACG::GLState::depthRange(0.01, 1.0); + + drawMesh_->disableColors(); + drawMesh_->usePerVertexTexcoords(); + + + // texture environment: fragment color = texture sample + GLint prevTexEnvMode = 0; + glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &prevTexEnvMode); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + draw_faces(); + ACG::GLState::depthRange(0.0, 1.0); + ACG::GLState::disable(GL_TEXTURE_2D); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, prevTexEnvMode); + } + + if ((_drawMode & DrawModes::SOLID_ENV_MAPPED) && mesh_.has_vertex_normals()) + { ACG::GLState::enable(GL_TEXTURE_2D); ACG::GLState::disable(GL_LIGHTING); ACG::GLState::shadeModel(GL_FLAT);