/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ #include "OgreGLSLExtSupport.h" #include "OgreGLSLLinkProgram.h" #include "OgreStringConverter.h" #include "OgreGLSLGpuProgram.h" #include "OgreGLSLProgram.h" #include "OgreGLSLLinkProgramManager.h" namespace Ogre { //----------------------------------------------------------------------- #define NO_ATTRIB 0xFFFF GLSLLinkProgram::GLSLLinkProgram(GLSLGpuProgram* vertexProgram, GLSLGpuProgram* fragmentProgram) : mVertexProgram(vertexProgram) , mFragmentProgram(fragmentProgram) , mUniformRefsBuilt(false) , mLinked(false) , mTangentAttrib(NO_ATTRIB) , mBinormalAttrib(NO_ATTRIB) , mBlendIndicesAttrib(NO_ATTRIB) , mBlendWeightsAttrib(NO_ATTRIB) { checkForGLSLError( "GLSLLinkProgram::GLSLLinkProgram", "Error prior to Creating GLSL Program Object", 0 ); mGLHandle = glCreateProgramObjectARB(); checkForGLSLError( "GLSLLinkProgram::GLSLLinkProgram", "Error Creating GLSL Program Object", 0 ); // tell shaders to attach themselves to the LinkProgram // let the shaders do the attaching since they may have several children to attach if (mVertexProgram) { mVertexProgram->getGLSLProgram()->attachToProgramObject(mGLHandle); setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded()); } if (mFragmentProgram) { mFragmentProgram->getGLSLProgram()->attachToProgramObject(mGLHandle); } } //----------------------------------------------------------------------- GLSLLinkProgram::~GLSLLinkProgram(void) { glDeleteObjectARB(mGLHandle); } //----------------------------------------------------------------------- void GLSLLinkProgram::activate(void) { if (!mLinked) { glLinkProgramARB( mGLHandle ); glGetObjectParameterivARB( mGLHandle, GL_OBJECT_LINK_STATUS_ARB, &mLinked ); // force logging and raise exception if not linked checkForGLSLError( "GLSLLinkProgram::Activate", "Error linking GLSL Program Object", mGLHandle, !mLinked, !mLinked ); if(mLinked) { logObjectInfo( String("GLSL link result : "), mGLHandle ); buildGLUniformReferences(); extractAttributes(); } } if (mLinked) { glUseProgramObjectARB( mGLHandle ); } } //----------------------------------------------------------------------- void GLSLLinkProgram::extractAttributes(void) { GLint attrib = glGetAttribLocationARB(mGLHandle, "tangent"); mTangentAttrib = (attrib == -1)? NO_ATTRIB : (GLuint)attrib; attrib = glGetAttribLocationARB(mGLHandle, "binormal"); mBinormalAttrib = (attrib == -1)? NO_ATTRIB : (GLuint)attrib; attrib = glGetAttribLocationARB(mGLHandle, "blendIndices"); mBlendIndicesAttrib = (attrib == -1)? NO_ATTRIB : (GLuint)attrib; attrib = glGetAttribLocationARB(mGLHandle, "blendWeights"); mBlendWeightsAttrib = (attrib == -1)? NO_ATTRIB : (GLuint)attrib; } //----------------------------------------------------------------------- GLuint GLSLLinkProgram::getAttributeIndex(VertexElementSemantic semantic) { switch(semantic) { case VES_TANGENT: return mTangentAttrib; case VES_BINORMAL: return mBinormalAttrib; case VES_BLEND_WEIGHTS: return mBlendWeightsAttrib; case VES_BLEND_INDICES: return mBlendIndicesAttrib; default: assert(false && "Shouldn't be calling this with standard attribs!"); return 0; }; } //----------------------------------------------------------------------- bool GLSLLinkProgram::isAttributeValid(VertexElementSemantic semantic) { switch(semantic) { case VES_TANGENT: return mTangentAttrib != NO_ATTRIB; case VES_BINORMAL: return mBinormalAttrib != NO_ATTRIB; case VES_BLEND_WEIGHTS: return mBlendWeightsAttrib != NO_ATTRIB; case VES_BLEND_INDICES: return mBlendIndicesAttrib != NO_ATTRIB; default: return false; }; } //----------------------------------------------------------------------- void GLSLLinkProgram::buildGLUniformReferences(void) { if (!mUniformRefsBuilt) { const GpuConstantDefinitionMap* vertParams = 0; const GpuConstantDefinitionMap* fragParams = 0; if (mVertexProgram) { vertParams = &(mVertexProgram->getGLSLProgram()->getConstantDefinitions().map); } if (mFragmentProgram) { fragParams = &(mFragmentProgram->getGLSLProgram()->getConstantDefinitions().map); } GLSLLinkProgramManager::getSingleton().extractUniforms( mGLHandle, vertParams, fragParams, mGLUniformReferences); mUniformRefsBuilt = true; } } //----------------------------------------------------------------------- void GLSLLinkProgram::updateUniforms(GpuProgramParametersSharedPtr params, GpuProgramType fromProgType) { // iterate through uniform reference list and update uniform values GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin(); GLUniformReferenceIterator endUniform = mGLUniformReferences.end(); for (;currentUniform != endUniform; ++currentUniform) { // Only pull values from buffer it's supposed to be in (vertex or fragment) // This method will be called twice, once for vertex program params, // and once for fragment program params. if (fromProgType == currentUniform->mSourceProgType) { const GpuConstantDefinition* def = currentUniform->mConstantDef; GLsizei glArraySize = (GLsizei)def->arraySize; // get the index in the parameter real list switch (def->constType) { case GCT_FLOAT1: glUniform1fvARB(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex)); break; case GCT_FLOAT2: glUniform2fvARB(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex)); break; case GCT_FLOAT3: glUniform3fvARB(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex)); break; case GCT_FLOAT4: glUniform4fvARB(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex)); break; case GCT_MATRIX_2X2: glUniformMatrix2fvARB(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); break; case GCT_MATRIX_2X3: if (GLEW_VERSION_2_1) { glUniformMatrix2x3fv(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); } break; case GCT_MATRIX_2X4: if (GLEW_VERSION_2_1) { glUniformMatrix2x4fv(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); } break; case GCT_MATRIX_3X2: if (GLEW_VERSION_2_1) { glUniformMatrix3x2fv(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); } break; case GCT_MATRIX_3X3: glUniformMatrix3fvARB(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); break; case GCT_MATRIX_3X4: if (GLEW_VERSION_2_1) { glUniformMatrix3x4fv(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); } break; case GCT_MATRIX_4X2: if (GLEW_VERSION_2_1) { glUniformMatrix4x2fv(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); } break; case GCT_MATRIX_4X3: if (GLEW_VERSION_2_1) { glUniformMatrix4x3fv(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); } break; case GCT_MATRIX_4X4: glUniformMatrix4fvARB(currentUniform->mLocation, glArraySize, GL_TRUE, params->getFloatPointer(def->physicalIndex)); break; case GCT_INT1: glUniform1ivARB(currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex)); break; case GCT_INT2: glUniform2ivARB(currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex)); break; case GCT_INT3: glUniform3ivARB(currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex)); break; case GCT_INT4: glUniform4ivARB(currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex)); break; case GCT_SAMPLER1D: case GCT_SAMPLER1DSHADOW: case GCT_SAMPLER2D: case GCT_SAMPLER2DSHADOW: case GCT_SAMPLER3D: case GCT_SAMPLERCUBE: // samplers handled like 1-element ints glUniform1ivARB(currentUniform->mLocation, 1, params->getIntPointer(def->physicalIndex)); break; } // end switch #if OGRE_DEBUG_MODE checkForGLSLError( "GLSLLinkProgram::updateUniforms", "Error updating uniform", 0 ); #endif } } // end for } //----------------------------------------------------------------------- void GLSLLinkProgram::updatePassIterationUniforms(GpuProgramParametersSharedPtr params) { if (params->hasPassIterationNumber()) { size_t index = params->getPassIterationNumberIndex(); GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin(); GLUniformReferenceIterator endUniform = mGLUniformReferences.end(); // need to find the uniform that matches the multi pass entry for (;currentUniform != endUniform; ++currentUniform) { // get the index in the parameter real list if (index == currentUniform->mConstantDef->physicalIndex) { glUniform1fvARB( currentUniform->mLocation, 1, params->getFloatPointer(index)); // there will only be one multipass entry return; } } } } } // namespace Ogre