| /****************************************************************************** |
| |
| @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) |
| *****************************************************************************/ |
| |