/****************************************************************************** @File OGLES2/PVRTPFXParserAPI.cpp @Title OGLES2/PVRTPFXParserAPI @Version @Copyright Copyright (c) Imagination Technologies Limited. @Platform ANSI compatible @Description PFX file parser. ******************************************************************************/ /***************************************************************************** ** Includes *****************************************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "PVRTContext.h" #include "PVRTMatrix.h" #include "PVRTFixedPoint.h" #include "PVRTString.h" #include "PVRTShader.h" #include "PVRTPFXParser.h" #include "PVRTPFXParserAPI.h" #include "PVRTPFXSemantics.h" #include "PVRTTexture.h" #include "PVRTTextureAPI.h" /*!*************************************************************************** @Function CPVRTPFXEffect Constructor @Description Sets the context and initialises the member variables to zero. *****************************************************************************/ CPVRTPFXEffect::CPVRTPFXEffect(): m_bLoaded(false), m_psContext(NULL), m_pParser(NULL), m_nEffect(0), m_uiProgram(0), m_Semantics(PVRTPFXSemanticsGetSemanticList(), ePVRTPFX_NumSemantics) { } /*!*************************************************************************** @Function CPVRTPFXEffect Constructor @Description Sets the context and initialises the member variables to zero. *****************************************************************************/ CPVRTPFXEffect::CPVRTPFXEffect(SPVRTContext &sContext): m_bLoaded(false), m_psContext(&sContext), m_pParser(NULL), m_nEffect(0), m_uiProgram(0), m_Semantics(PVRTPFXSemanticsGetSemanticList(), ePVRTPFX_NumSemantics) { } /*!*************************************************************************** @Function CPVRTPFXEffect Destructor @Description Calls Destroy(). *****************************************************************************/ CPVRTPFXEffect::~CPVRTPFXEffect() { Destroy(); // Free allocated strings for(unsigned int uiIndex = ePVRTPFX_NumSemantics; uiIndex < m_Semantics.GetSize(); ++uiIndex) { delete [] m_Semantics[uiIndex].p; m_Semantics[uiIndex].p = NULL; } } /*!*************************************************************************** @Function Load @Input src PFX Parser Object @Input pszEffect Effect name @Input pszFileName Effect file name @Output pReturnError Error string @Returns EPVRTError PVR_SUCCESS if load succeeded @Description Loads the specified effect from the CPVRTPFXParser object. Compiles and links the shaders. Initialises texture data. *****************************************************************************/ EPVRTError CPVRTPFXEffect::Load(CPVRTPFXParser &src, const char * const pszEffect, const char * const pszFileName, PVRTPFXEffectDelegate* pDelegate, unsigned int& uiUnknownUniforms, CPVRTString *pReturnError) { unsigned int i; if(!src.GetNumberEffects()) return PVR_FAIL; // --- First find the named effect from the effect file if(pszEffect) { int iEffect = src.FindEffectByName(CPVRTStringHash(pszEffect)); if(iEffect == -1) return PVR_FAIL; m_nEffect = (unsigned int)iEffect; } else { m_nEffect = 0; } // --- Now load the effect m_pParser = &src; const SPVRTPFXParserEffect &ParserEffect = src.GetEffect(m_nEffect); // Create room for per-texture data const CPVRTArray<SPVRTPFXParserEffectTexture>& EffectTextures = src.GetEffect(m_nEffect).Textures; unsigned int uiNumTexturesForEffect = EffectTextures.GetSize(); m_Textures.SetCapacity(uiNumTexturesForEffect); // Initialise each Texture for(i = 0; i < uiNumTexturesForEffect; ++i) { int iTexIdx = src.FindTextureByName(EffectTextures[i].Name); if(iTexIdx < 0) { *pReturnError += PVRTStringFromFormattedStr("ERROR: Effect '%s' requests non-existent texture: %s\n", ParserEffect.Name.c_str(), EffectTextures[i].Name.c_str()); return PVR_FAIL; } unsigned int uiTexIdx = m_Textures.Append(); m_Textures[uiTexIdx].Name = src.GetTexture((unsigned int)iTexIdx)->Name; m_Textures[uiTexIdx].ui = 0xFFFFFFFF; m_Textures[uiTexIdx].flags = 0; m_Textures[uiTexIdx].unit = 0; } // Load the shaders if(LoadShadersForEffect(src, pszFileName, pReturnError) != PVR_SUCCESS) return PVR_FAIL; // Build uniform table if(RebuildUniformTable(uiUnknownUniforms, pReturnError) != PVR_SUCCESS) return PVR_FAIL; // Load the requested textures if(pDelegate) { if(LoadTexturesForEffect(pDelegate, pReturnError) != PVR_SUCCESS) return PVR_FAIL; } m_bLoaded = true; return PVR_SUCCESS; } /*!*************************************************************************** @Function LoadTexturesForEffect @Output pReturnError @Return EPVRTError @Description Loads all of the textures for this effect. *****************************************************************************/ EPVRTError CPVRTPFXEffect::LoadTexturesForEffect(PVRTPFXEffectDelegate* pDelegate, CPVRTString *pReturnError) { GLuint uiHandle; unsigned int uiFlags; for(unsigned int i = 0; i < m_Textures.GetSize(); ++i) { int iTexID = m_pParser->FindTextureByName(m_Textures[i].Name); if(iTexID == -1) { *pReturnError += PVRTStringFromFormattedStr("ERROR: Cannot find texture '%s' in any TEXTURE block.\n", m_Textures[i].Name.c_str()); return PVR_FAIL; } const SPVRTPFXParserTexture* pTexDesc = m_pParser->GetTexture(iTexID); uiHandle = 0xBADF00D; uiFlags = 0; if(pDelegate->PVRTPFXOnLoadTexture(pTexDesc->FileName, uiHandle, uiFlags) != PVR_SUCCESS) { *pReturnError += PVRTStringFromFormattedStr("ERROR: Failed to load texture: %s.\n", pTexDesc->FileName.c_str()); return PVR_FAIL; } // Make sure uiHandle was written. if(uiHandle == 0xBADF00D) { *pReturnError += PVRTStringFromFormattedStr("ERROR: GL handle for texture '%s' not set!\n", pTexDesc->FileName.c_str()); return PVR_FAIL; } SetTexture(i, uiHandle, uiFlags); } return PVR_SUCCESS; } /*!*************************************************************************** @Function LoadShadersForEffect @Input pszFileName @Output pReturnError @Return EPVRTError @Description Loads all of the GLSL shaders for an effect. *****************************************************************************/ EPVRTError CPVRTPFXEffect::LoadShadersForEffect(CPVRTPFXParser &src, const char * const pszFileName, CPVRTString *pReturnError) { // initialise attributes to default values char *pszVertexShader = NULL; char *pszFragmentShader = NULL; bool bFreeVertexShader = false; bool bFreeFragmentShader = false; unsigned int uiVertIdx = 0; unsigned int uiFragIdx = 0; unsigned int uiVertexShader = 0; unsigned int uiFragShader = 0; const SPVRTPFXParserEffect &ParserEffect = src.GetEffect(m_nEffect); // find shaders requested for(uiVertIdx = 0; uiVertIdx < src.GetNumberVertexShaders(); ++uiVertIdx) { const SPVRTPFXParserShader& VertexShader = src.GetVertexShader(uiVertIdx); if(ParserEffect.VertexShaderName == VertexShader.Name) { if(VertexShader.bUseFileName) { pszVertexShader = VertexShader.pszGLSLcode; } else { if(!VertexShader.pszGLSLcode) continue; // No code specified. #if 0 // offset glsl code by nFirstLineNumber pszVertexShader = (char *)malloc((strlen(VertexShader.pszGLSLcode) + (VertexShader.nFirstLineNumber) + 1) * sizeof(char)); pszVertexShader[0] = '\0'; for(unsigned int n = 0; n < VertexShader.nFirstLineNumber; n++) strcat(pszVertexShader, "\n"); strcat(pszVertexShader, VertexShader.pszGLSLcode); #else pszVertexShader = (char *)malloc(strlen(VertexShader.pszGLSLcode) + 1); pszVertexShader[0] = '\0'; strcat(pszVertexShader, VertexShader.pszGLSLcode); #endif bFreeVertexShader = true; } break; } } for(uiFragIdx = 0; uiFragIdx < src.GetNumberFragmentShaders(); ++uiFragIdx) { const SPVRTPFXParserShader& FragmentShader = src.GetFragmentShader(uiFragIdx); if(ParserEffect.FragmentShaderName == FragmentShader.Name) { if(FragmentShader.bUseFileName) { pszFragmentShader = FragmentShader.pszGLSLcode; } else { if(!FragmentShader.pszGLSLcode) continue; // No code specified. #if 0 // offset glsl code by nFirstLineNumber pszFragmentShader = (char *)malloc((strlen(FragmentShader.pszGLSLcode) + (FragmentShader.nFirstLineNumber) + 1) * sizeof(char)); pszFragmentShader[0] = '\0'; for(unsigned int n = 0; n < FragmentShader.nFirstLineNumber; n++) strcat(pszFragmentShader, "\n"); strcat(pszFragmentShader, FragmentShader.pszGLSLcode); #else pszFragmentShader = (char *)malloc(strlen(FragmentShader.pszGLSLcode) + 1); pszFragmentShader[0] = '\0'; strcat(pszFragmentShader, FragmentShader.pszGLSLcode); #endif bFreeFragmentShader = true; } break; } } CPVRTString error; bool bLoadSource = 1; // Try first to load from the binary block if (src.GetVertexShader(uiVertIdx).pbGLSLBinary!=NULL) { #if defined(GL_SGX_BINARY_IMG) if (PVRTShaderLoadBinaryFromMemory(src.GetVertexShader(uiVertIdx).pbGLSLBinary, src.GetVertexShader(uiVertIdx).nGLSLBinarySize, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &uiVertexShader, &error) == PVR_SUCCESS) { // success loading the binary block so we do not need to load the source bLoadSource = 0; } else #endif { bLoadSource = 1; } } // If it fails, load from source if (bLoadSource) { if(pszVertexShader) { if (PVRTShaderLoadSourceFromMemory(pszVertexShader, GL_VERTEX_SHADER, &uiVertexShader, &error) != PVR_SUCCESS) { *pReturnError = CPVRTString("ERROR: Vertex Shader compile error in file '") + pszFileName + "':\n" + error; if(bFreeVertexShader) FREE(pszVertexShader); if(bFreeFragmentShader) FREE(pszFragmentShader); return PVR_FAIL; } } else // Shader not found or failed binary block { if (src.GetVertexShader(uiVertIdx).pbGLSLBinary==NULL) { *pReturnError = CPVRTString("ERROR: Vertex shader ") + ParserEffect.VertexShaderName.String() + " not found in " + pszFileName + ".\n"; } else { *pReturnError = CPVRTString("ERROR: Binary vertex shader ") + ParserEffect.VertexShaderName.String() + " not supported.\n"; } if(bFreeVertexShader) FREE(pszVertexShader); if(bFreeFragmentShader) FREE(pszFragmentShader); return PVR_FAIL; } } // Try first to load from the binary block if (src.GetFragmentShader(uiFragIdx).pbGLSLBinary!=NULL) { #if defined(GL_SGX_BINARY_IMG) if (PVRTShaderLoadBinaryFromMemory(src.GetFragmentShader(uiFragIdx).pbGLSLBinary, src.GetFragmentShader(uiFragIdx).nGLSLBinarySize, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &uiFragShader, &error) == PVR_SUCCESS) { // success loading the binary block so we do not need to load the source bLoadSource = 0; } else #endif { bLoadSource = 1; } } // If it fails, load from source if (bLoadSource) { if(pszFragmentShader) { if (PVRTShaderLoadSourceFromMemory(pszFragmentShader, GL_FRAGMENT_SHADER, &uiFragShader, &error) != PVR_SUCCESS) { *pReturnError = CPVRTString("ERROR: Fragment Shader compile error in file '") + pszFileName + "':\n" + error; if(bFreeVertexShader) FREE(pszVertexShader); if(bFreeFragmentShader) FREE(pszFragmentShader); return PVR_FAIL; } } else // Shader not found or failed binary block { if (src.GetFragmentShader(uiFragIdx).pbGLSLBinary==NULL) { *pReturnError = CPVRTString("ERROR: Fragment shader ") + ParserEffect.FragmentShaderName.String() + " not found in " + pszFileName + ".\n"; } else { *pReturnError = CPVRTString("ERROR: Binary Fragment shader ") + ParserEffect.FragmentShaderName.String() + " not supported.\n"; } if(bFreeVertexShader) FREE(pszVertexShader); if(bFreeFragmentShader) FREE(pszFragmentShader); return PVR_FAIL; } } if(bFreeVertexShader) FREE(pszVertexShader); if(bFreeFragmentShader) FREE(pszFragmentShader); // Create the shader program m_uiProgram = glCreateProgram(); // Attach the fragment and vertex shaders to it glAttachShader(m_uiProgram, uiFragShader); glAttachShader(m_uiProgram, uiVertexShader); glDeleteShader(uiVertexShader); glDeleteShader(uiFragShader); // Bind vertex attributes for(unsigned int i = 0; i < ParserEffect.Attributes.GetSize(); ++i) { glBindAttribLocation(m_uiProgram, i, ParserEffect.Attributes[i].pszName); } // Link the program. glLinkProgram(m_uiProgram); GLint Linked; glGetProgramiv(m_uiProgram, GL_LINK_STATUS, &Linked); if (!Linked) { int i32InfoLogLength, i32CharsWritten; glGetProgramiv(m_uiProgram, GL_INFO_LOG_LENGTH, &i32InfoLogLength); char* pszInfoLog = new char[i32InfoLogLength]; glGetProgramInfoLog(m_uiProgram, i32InfoLogLength, &i32CharsWritten, pszInfoLog); *pReturnError = CPVRTString("ERROR: Linking shaders in file '") + pszFileName + "':\n\n" + CPVRTString("Failed to link: ") + pszInfoLog + "\n"; delete [] pszInfoLog; return PVR_FAIL; } return PVR_SUCCESS; } /*!*************************************************************************** @Function Destroy @Description Deletes the gl program object and texture data. *****************************************************************************/ void CPVRTPFXEffect::Destroy() { { if(m_uiProgram != 0) { GLint val; glGetProgramiv(m_uiProgram, GL_DELETE_STATUS, &val); if(val == GL_FALSE) { glDeleteProgram(m_uiProgram); } m_uiProgram = 0; } } m_bLoaded = false; } /*!*************************************************************************** @Function Activate @Returns PVR_SUCCESS if activate succeeded @Description Selects the gl program object and binds the textures. *****************************************************************************/ EPVRTError CPVRTPFXEffect::Activate(const int i32RenderTextureId, const unsigned int ui32ReplacementTexture) { GLuint uiTextureId; GLenum eTarget; // Set the program glUseProgram(m_uiProgram); // Set the textures for(unsigned int uiTex = 0; uiTex < m_Textures.GetSize(); ++uiTex) { uiTextureId = m_Textures[uiTex].ui; if(i32RenderTextureId != -1 && (uiTextureId == (unsigned int)i32RenderTextureId)) uiTextureId = ui32ReplacementTexture; // Set active texture unit. glActiveTexture(GL_TEXTURE0 + m_Textures[uiTex].unit); // Bind texture eTarget = (m_Textures[uiTex].flags & PVRTEX_CUBEMAP ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); glBindTexture(eTarget, uiTextureId); } return PVR_SUCCESS; } /*!*************************************************************************** @Function GetSemantics @Output aUniforms an array of uniform data @Output pnUnknownUniformCount unknown uniform count @Input psParams pointer to semantic data array @Input nParamCount number of samantic items @Input psUniformSemantics pointer to uniform semantics array @Input nUniformSemantics number of uniform semantic items @Input pglesExt opengl extensions object @Input uiProgram program object index @Input bIsAttribue true if getting attribute semantics @Output errorMsg error string @Returns unsigned int number of successful semantics @Description Get the data array for the semantics. *****************************************************************************/ static unsigned int GetSemantics( CPVRTArray<SPVRTPFXUniform>& aUniforms, const CPVRTArray<SPVRTPFXParserSemantic>& aParams, const CPVRTArray<SPVRTPFXUniformSemantic>& aUniformSemantics, unsigned int* const pnUnknownUniformCount, const GLuint uiProgram, bool bIsAttribue, CPVRTString* const errorMsg) { unsigned int i, j, nCount, nCountUnused; int nLocation; /* Loop over the parameters searching for their semantics. If found/recognised, it should be placed in the output array. */ nCount = 0; nCountUnused = 0; char szTmpUniformName[2048]; // Temporary buffer to use for building uniform names. for(j = 0; j < aParams.GetSize(); ++j) { for(i = 0; i < aUniformSemantics.GetSize(); ++i) { if(strcmp(aParams[j].pszValue, aUniformSemantics[i].p) != 0) { continue; } // Semantic found for this parameter if(bIsAttribue) { nLocation = glGetAttribLocation(uiProgram, aParams[j].pszName); } else { nLocation = glGetUniformLocation(uiProgram, aParams[j].pszName); // Check for array. Workaround for some OpenGL:ES implementations which require array element appended to uniform name // in order to return the correct location. if(nLocation == -1) { strcpy(szTmpUniformName, aParams[j].pszName); strcat(szTmpUniformName, "[0]"); nLocation = glGetUniformLocation(uiProgram, szTmpUniformName); } } if(nLocation != -1) { unsigned int uiIdx = aUniforms.Append(); aUniforms[uiIdx].nSemantic = aUniformSemantics[i].n; aUniforms[uiIdx].nLocation = nLocation; aUniforms[uiIdx].nIdx = aParams[j].nIdx; aUniforms[uiIdx].sValueName = aParams[j].pszName; ++nCount; } else { *errorMsg += "WARNING: Variable not used by GLSL code: "; *errorMsg += CPVRTString(aParams[j].pszName) + " "; *errorMsg += CPVRTString(aParams[j].pszValue) + "\n"; ++nCountUnused; } // Skip to the next parameter break; } if(i == aUniformSemantics.GetSize()) { *errorMsg += "WARNING: Semantic unknown to application: "; *errorMsg += CPVRTString(aParams[j].pszValue) + "\n"; } } *pnUnknownUniformCount = aParams.GetSize() - nCount - nCountUnused; return nCount; } /*!*************************************************************************** @Function GetUniformArray @Return const CPVRTArray<SPVRTPFXUniform>& @Description Returns a list of known semantics. *****************************************************************************/ const CPVRTArray<SPVRTPFXUniform>& CPVRTPFXEffect::GetUniformArray() const { return m_Uniforms; } /*!*************************************************************************** @Function BuildUniformTable @Output uiUnknownSemantics @Output pReturnError @Return EPVRTError @Description Builds the uniform table from a list of known semantics. *****************************************************************************/ EPVRTError CPVRTPFXEffect::RebuildUniformTable(unsigned int& uiUnknownSemantics, CPVRTString* pReturnError) { unsigned int nUnknownCount; const SPVRTPFXParserEffect& ParserEffect = m_pParser->GetEffect(m_nEffect); GetSemantics(m_Uniforms, ParserEffect.Uniforms, m_Semantics, &nUnknownCount, m_uiProgram, false, pReturnError); uiUnknownSemantics = nUnknownCount; GetSemantics(m_Uniforms, ParserEffect.Attributes, m_Semantics, &nUnknownCount, m_uiProgram, true, pReturnError); uiUnknownSemantics += nUnknownCount; return PVR_SUCCESS; } /*!*************************************************************************** @Function RegisterUniformSemantic @Input psUniforms @Input uiNumUniforms @Return EPVRTError @Description Registers a user-provided uniform semantic. *****************************************************************************/ EPVRTError CPVRTPFXEffect::RegisterUniformSemantic(const SPVRTPFXUniformSemantic* const psUniforms, unsigned int uiNumUniforms, CPVRTString* pReturnError) { for(unsigned int uiIndex = 0; uiIndex < uiNumUniforms; ++uiIndex) { // Check that this doesn't already exist. if(m_Semantics.Contains(psUniforms[uiIndex])) { *pReturnError += PVRTStringFromFormattedStr("ERROR: Uniform semantic with ID '%u' already exists.\n", psUniforms[uiIndex].n); return PVR_FAIL; } // Make copy as we need to manage the memory. char* pSemName = new char[strlen(psUniforms[uiIndex].p)+1]; strcpy(pSemName, psUniforms[uiIndex].p); unsigned int uiIdx = m_Semantics.Append(); m_Semantics[uiIdx].n = psUniforms[uiIndex].n; m_Semantics[uiIdx].p = pSemName; } // Check if the effect has already been loaded. If it hasn't, great. If it has, we need to rebuild the uniform table. if(m_bLoaded) { // Clear the current list. m_Uniforms.Clear(); unsigned int uiUnknownSemantics; return RebuildUniformTable(uiUnknownSemantics, pReturnError); } return PVR_SUCCESS; } /*!*************************************************************************** @Function RemoveUniformSemantic @Input uiSemanticID @Output pReturnError @Return PVR_SUCCESS on success @Description Removes a given semantic ID from the 'known' semantic list and re-parses the effect to update the uniform table. *****************************************************************************/ EPVRTError CPVRTPFXEffect::RemoveUniformSemantic(unsigned int uiSemanticID, CPVRTString* pReturnError) { // Make sure that the given ID isn't a PFX semantic if(uiSemanticID < ePVRTPFX_NumSemantics) { *pReturnError += "ERROR: Cannot remove a default PFX semantic."; return PVR_FAIL; } // Find the index in the array unsigned int uiSemanticIndex = 0; while(uiSemanticIndex < m_Semantics.GetSize() && m_Semantics[uiSemanticIndex].n != uiSemanticID) ++uiSemanticIndex; if(uiSemanticIndex == m_Semantics.GetSize()) { *pReturnError += PVRTStringFromFormattedStr("ERROR: Semantic with ID %d does not exist.", uiSemanticID); return PVR_FAIL; } m_Semantics.Remove(uiSemanticIndex); // Check if the effect has already been loaded. If it hasn't, great. If it has, we need to rebuild the uniform table. if(m_bLoaded) { // Clear the current list. m_Uniforms.Clear(); unsigned int uiUnknownSemantics; return RebuildUniformTable(uiUnknownSemantics, pReturnError); } return PVR_SUCCESS; } /*!*************************************************************************** @Function GetTextureArray @Output nCount number of textures @Returns SPVRTPFXTexture* pointer to the texture data array @Description Gets the texture data array. *****************************************************************************/ const CPVRTArray<SPVRTPFXTexture>& CPVRTPFXEffect::GetTextureArray() const { return m_Textures; } /*!*************************************************************************** @Function SetTexture @Input nIdx texture number @Input ui opengl texture handle @Input u32flags texture flags @Description Sets the textrue and applys the filtering. *****************************************************************************/ void CPVRTPFXEffect::SetTexture(const unsigned int nIdx, const GLuint ui, const unsigned int u32flags) { if(nIdx < (unsigned int) m_Textures.GetSize()) { GLenum u32Target = GL_TEXTURE_2D; // Check if texture is a cubemap if((u32flags & PVRTEX_CUBEMAP) != 0) u32Target = GL_TEXTURE_CUBE_MAP; // Get the texture details from the PFX Parser. This contains details such as mipmapping and filter modes. const CPVRTStringHash& TexName = m_pParser->GetEffect(m_nEffect).Textures[nIdx].Name; int iTexIdx = m_pParser->FindTextureByName(TexName); if(iTexIdx == -1) return; const SPVRTPFXParserTexture* pPFXTex = m_pParser->GetTexture(iTexIdx); // Only change parameters if ui (handle is > 0) if(ui > 0) { glBindTexture(u32Target, ui); // Set default filter from PFX file // --- Mipmapping/Minification switch(pPFXTex->nMIP) { case eFilter_None: // No mipmapping switch(pPFXTex->nMin) { case eFilter_Nearest: glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Off break; case eFilter_Linear: glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Bilinear - no Mipmap break; } break; case eFilter_Nearest: // Standard mipmapping switch(pPFXTex->nMin) { case eFilter_Nearest: glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); // Nearest - std. Mipmap break; case eFilter_Linear: glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); // Bilinear - std. Mipmap break; } break; case eFilter_Linear: // Trilinear mipmapping switch(pPFXTex->nMin) { case eFilter_Nearest: glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); // Nearest - Trilinear break; case eFilter_Linear: glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Bilinear - Trilinear break; } break; } // --- Magnification switch(pPFXTex->nMag) { case eFilter_Nearest: glTexParameteri(u32Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case eFilter_Linear: glTexParameteri(u32Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; } // --- Wrapping S switch(pPFXTex->nWrapS) { case eWrap_Clamp: glTexParameteri(u32Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); break; case eWrap_Repeat: glTexParameteri(u32Target, GL_TEXTURE_WRAP_S, GL_REPEAT); break; } // --- Wrapping T switch(pPFXTex->nWrapT) { case eWrap_Clamp: glTexParameteri(u32Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); break; case eWrap_Repeat: glTexParameteri(u32Target, GL_TEXTURE_WRAP_T, GL_REPEAT); break; } // --- Wrapping R #ifdef GL_TEXTURE_WRAP_R switch(pPFXTex->nWrapR) { case eWrap_Clamp: glTexParameteri(u32Target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); break; case eWrap_Repeat: glTexParameteri(u32Target, GL_TEXTURE_WRAP_R, GL_REPEAT); break; } #endif } // Store the texture details m_Textures[nIdx].ui = ui; m_Textures[nIdx].flags = u32flags; // Find the texture unit from the parser unsigned int uiIndex = m_pParser->FindTextureIndex(pPFXTex->Name, m_nEffect); if(uiIndex != 0xFFFFFFFF) { m_Textures[nIdx].unit = m_pParser->GetEffect(m_nEffect).Textures[uiIndex].nNumber; } } } /*!*************************************************************************** @Function SetDefaultSemanticValue @Input pszName name of uniform @Input psDefaultValue pointer to default value @Description Sets the default value for the uniform semantic. *****************************************************************************/ void CPVRTPFXEffect::SetDefaultUniformValue(const char *const pszName, const SPVRTSemanticDefaultData *psDefaultValue) { GLint nLocation = glGetUniformLocation(m_uiProgram, pszName); // Check for array. Workaround for some OpenGL:ES implementations which require array element appended to uniform name // in order to return the correct location. if(nLocation == -1) { char szTmpUniformName[2048]; strcpy(szTmpUniformName, pszName); strcat(szTmpUniformName, "[0]"); nLocation = glGetUniformLocation(m_uiProgram, szTmpUniformName); } switch(psDefaultValue->eType) { case eDataTypeMat2: glUniformMatrix2fv(nLocation, 1, GL_FALSE, psDefaultValue->pfData); break; case eDataTypeMat3: glUniformMatrix3fv(nLocation, 1, GL_FALSE, psDefaultValue->pfData); break; case eDataTypeMat4: glUniformMatrix4fv(nLocation, 1, GL_FALSE, psDefaultValue->pfData); break; case eDataTypeVec2: glUniform2fv(nLocation, 1, psDefaultValue->pfData); break; case eDataTypeRGB: case eDataTypeVec3: glUniform3fv(nLocation, 1, psDefaultValue->pfData); break; case eDataTypeRGBA: case eDataTypeVec4: glUniform4fv(nLocation, 1, psDefaultValue->pfData); break; case eDataTypeIvec2: glUniform2iv(nLocation, 1, psDefaultValue->pnData); break; case eDataTypeIvec3: glUniform3iv(nLocation, 1, psDefaultValue->pnData); break; case eDataTypeIvec4: glUniform4iv(nLocation, 1, psDefaultValue->pnData); break; case eDataTypeBvec2: glUniform2i(nLocation, psDefaultValue->pbData[0] ? 1 : 0, psDefaultValue->pbData[1] ? 1 : 0); break; case eDataTypeBvec3: glUniform3i(nLocation, psDefaultValue->pbData[0] ? 1 : 0, psDefaultValue->pbData[1] ? 1 : 0, psDefaultValue->pbData[2] ? 1 : 0); break; case eDataTypeBvec4: glUniform4i(nLocation, psDefaultValue->pbData[0] ? 1 : 0, psDefaultValue->pbData[1] ? 1 : 0, psDefaultValue->pbData[2] ? 1 : 0, psDefaultValue->pbData[3] ? 1 : 0); break; case eDataTypeFloat: glUniform1f(nLocation, psDefaultValue->pfData[0]); break; case eDataTypeInt: glUniform1i(nLocation, psDefaultValue->pnData[0]); break; case eDataTypeBool: glUniform1i(nLocation, psDefaultValue->pbData[0] ? 1 : 0); break; case eNumDefaultDataTypes: case eDataTypeNone: default: break; } } /*!*************************************************************************** @Function SetContext @Input pContext @Description *****************************************************************************/ void CPVRTPFXEffect::SetContext(SPVRTContext *const pContext) { m_psContext = pContext; } /*!*************************************************************************** @Function GetProgramHandle @Return unsigned int @Description Returns the OGL program handle. *****************************************************************************/ unsigned int CPVRTPFXEffect::GetProgramHandle() const { return m_uiProgram; } /*!*************************************************************************** @Function GetEffectIndex @Return unsigned int @Description Gets the active effect index within the PFX file. *****************************************************************************/ unsigned int CPVRTPFXEffect::GetEffectIndex() const { return m_nEffect; } /*!*************************************************************************** @Function GetSemanticArray @Return const CPVRTArray<SPVRTPFXUniformSemantic>& @Description Gets the array of registered semantics which will be used to match PFX code. *****************************************************************************/ const CPVRTArray<SPVRTPFXUniformSemantic>& CPVRTPFXEffect::GetSemanticArray() const { return m_Semantics; } /***************************************************************************** End of file (PVRTPFXParserAPI.cpp) *****************************************************************************/