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