/*!**************************************************************************** @Function LoadShaders @Output pErrorStr A string describing the error on failure @Return bool true if no error occured @Description Loads and compiles the shaders and links the shader programs required for this training course ******************************************************************************/ bool OGLES2PVRScopeRemote::LoadShaders(CPVRTString* pErrorStr, const char * const pszFrag, const char * const pszVert) { CPPLProcessingScoped PPLProcessingScoped(m_psSPSCommsData, __FUNCTION__, static_cast<unsigned int>(strlen(__FUNCTION__)), m_i32FrameCounter); /* Load and compile the shaders from files. Binary shaders are tried first, source shaders are used as fallback. */ if (PVRTShaderLoadSourceFromMemory( pszVert, GL_VERTEX_SHADER, &m_uiVertShader, pErrorStr) != PVR_SUCCESS) { return false; } if (PVRTShaderLoadSourceFromMemory( pszFrag, GL_FRAGMENT_SHADER, &m_uiFragShader, pErrorStr) != PVR_SUCCESS) { return false; } /* Set up and link the shader program */ const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" }; if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr)) { PVRShellSet(prefExitMessage, pErrorStr->c_str()); return false; } // Set the sampler2D variable to the first texture unit glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sThicknessTex"), 0); // Store the location of uniforms for later use m_ShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix"); m_ShaderProgram.uiLightDirLoc = glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection"); m_ShaderProgram.uiEyePosLoc = glGetUniformLocation(m_ShaderProgram.uiId, "EyePosition"); m_ShaderProgram.uiMinThicknessLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MinThickness"); m_ShaderProgram.uiMaxVariationLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MaxVariation"); return true; }
unsigned createProgramFromSource( const char * vss, // vertex shader source const char * fss, // fragment shader source const char** attribs, // attribute list unsigned * attrLocal, // store attribute locations const unsigned num // attribute list size ) { unsigned id = 0; unsigned vs = 0; unsigned fs = 0; EPVRTError ret = PVR_SUCCESS; CPVRTString msg; int step = 0; do { if (!vss || !fss || (num && (!attribs || !attrLocal))) { Debug::logd("There's no shader source!!"); break; } // 1 Compile vertex shader. step = 1; if (PVR_SUCCESS != PVRTShaderLoadSourceFromMemory( vss, GL_VERTEX_SHADER, &vs, &msg, 0, 0)) break; // 2 Compile fragment shader. step = 2; if (PVR_SUCCESS != PVRTShaderLoadSourceFromMemory( fss, GL_FRAGMENT_SHADER, &fs, &msg, 0, 0)) break; // 3 Link two shaders to program, and bind attribs to specific locations. step = 3; if (PVR_SUCCESS != PVRTCreateProgram( &id, vs, fs, attribs, num, &msg)) break; for (unsigned i = 0; i < num; i++) *(attrLocal + i) = i; } while (false); if (! id) { Debug::logd("(step:%d)%s", step, msg.c_str()); } return id; }
/*!*************************************************************************** @Function PVRTShaderLoadFromFile @Input pszBinFile binary shader filename @Input pszSrcFile source shader filename @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) @Input Format shader binary format, or 0 for source shader @Output pObject the resulting shader object @Output pReturnError the error message if it failed @Input pContext Context @Input aszDefineArray Array of defines to be pre-appended to shader string @Input uiDefArraySize Size of the define array @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills pReturnError) @Description Loads a shader file into memory and passes it to the GL. It also passes defines that need to be pre-appended to the shader before compilation. *****************************************************************************/ EPVRTError PVRTShaderLoadFromFile( const char* const pszBinFile, const char* const pszSrcFile, const GLenum Type, const GLenum Format, GLuint* const pObject, CPVRTString* const pReturnError, const SPVRTContext* const pContext, const char* const* aszDefineArray, GLuint uiDefArraySize) { PVRT_UNREFERENCED_PARAMETER(pContext); *pReturnError = ""; /* Prepending defines relies on altering the source file that is loaded. For this reason, the function calls the source loader instead of the binary loader if defines have been passed in. */ if(Format && pszBinFile && uiDefArraySize == 0) { CPVRTResourceFile ShaderFile(pszBinFile); if (ShaderFile.IsOpen()) { if(PVRTShaderLoadBinaryFromMemory(ShaderFile.DataPtr(), ShaderFile.Size(), Type, Format, pObject, pReturnError) == PVR_SUCCESS) return PVR_SUCCESS; } *pReturnError += CPVRTString("Failed to open shader ") + pszBinFile + "\n"; } CPVRTResourceFile ShaderFile(pszSrcFile); if (!ShaderFile.IsOpen()) { *pReturnError += CPVRTString("Failed to open shader ") + pszSrcFile + "\n"; return PVR_FAIL; } CPVRTString ShaderFileString; const char* pShaderData = (const char*) ShaderFile.DataPtr(); // Is our shader resource file data null terminated? if(pShaderData[ShaderFile.Size()-1] != '\0') { // If not create a temporary null-terminated string ShaderFileString.assign(pShaderData, ShaderFile.Size()); pShaderData = ShaderFileString.c_str(); } return PVRTShaderLoadSourceFromMemory(pShaderData, Type, pObject, pReturnError, aszDefineArray, uiDefArraySize); }
/*!*************************************************************************** @Function Init @Input pContext A pointer to a PVRTContext @Input bRotate true to rotate texture 90 degrees. @Input pszError An option string for returning errors @Return PVR_SUCCESS on success @Description Initialises the background *****************************************************************************/ EPVRTError CPVRTBackground::Init(const SPVRTContext * const pContext, bool bRotate, CPVRTString *pszError) { Destroy(); m_pAPI = new SPVRTBackgroundAPI; if(!m_pAPI) { if(pszError) *pszError = "Error: Insufficient memory to allocate SCPVRTBackgroundAPI."; return PVR_FAIL; } m_pAPI->m_ui32VertexShader = 0; m_pAPI->m_ui32FragShader = 0; m_pAPI->m_ui32ProgramObject = 0; m_pAPI->m_ui32VertexBufferObject = 0; bool bResult; CPVRTString sTmpErrStr; // The shader loading code doesn't expect a null pointer for the error string if(!pszError) pszError = &sTmpErrStr; /* Compiles the shaders. For a more detailed explanation, see IntroducingPVRTools */ // Try binary shaders first bResult = (PVRTShaderLoadBinaryFromMemory(_BackgroundFragShader_fsc, _BackgroundFragShader_fsc_size, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_pAPI->m_ui32FragShader, pszError) == PVR_SUCCESS) && (PVRTShaderLoadBinaryFromMemory(_BackgroundVertShader_vsc, _BackgroundVertShader_vsc_size, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_pAPI->m_ui32VertexShader, pszError) == PVR_SUCCESS); if(!bResult) { // if binary shaders don't work, try source shaders bResult = (PVRTShaderLoadSourceFromMemory(_BackgroundFragShader_fsh, GL_FRAGMENT_SHADER, &m_pAPI->m_ui32FragShader, pszError) == PVR_SUCCESS) && (PVRTShaderLoadSourceFromMemory(_BackgroundVertShader_vsh, GL_VERTEX_SHADER, &m_pAPI->m_ui32VertexShader, pszError) == PVR_SUCCESS); } _ASSERT(bResult); if(!bResult) return PVR_FAIL; // Reset the error string if(pszError) *pszError = ""; // Create the shader program m_pAPI->m_ui32ProgramObject = glCreateProgram(); // Attach the fragment and vertex shaders to it glAttachShader(m_pAPI->m_ui32ProgramObject, m_pAPI->m_ui32FragShader); glAttachShader(m_pAPI->m_ui32ProgramObject, m_pAPI->m_ui32VertexShader); // Bind the custom vertex attribute "myVertex" to location VERTEX_ARRAY glBindAttribLocation(m_pAPI->m_ui32ProgramObject, VERTEX_ARRAY, "myVertex"); // Bind the custom vertex attribute "myUV" to location TEXCOORD_ARRAY glBindAttribLocation(m_pAPI->m_ui32ProgramObject, TEXCOORD_ARRAY, "myUV"); // Link the program glLinkProgram(m_pAPI->m_ui32ProgramObject); GLint Linked; glGetProgramiv(m_pAPI->m_ui32ProgramObject, GL_LINK_STATUS, &Linked); if (!Linked) { int i32InfoLogLength, i32CharsWritten; glGetProgramiv(m_pAPI->m_ui32ProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength); char* pszInfoLog = new char[i32InfoLogLength]; glGetProgramInfoLog(m_pAPI->m_ui32ProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog); *pszError = CPVRTString("Failed to link: ") + pszInfoLog + "\n"; delete [] pszInfoLog; bResult = false; } _ASSERT(bResult); if(!bResult) return PVR_FAIL; // Use the loaded shader program glUseProgram(m_pAPI->m_ui32ProgramObject); // Set the sampler2D variable to the first texture unit glUniform1i(glGetUniformLocation(m_pAPI->m_ui32ProgramObject, "sampler2d"), 0); // Create the vertex buffer object GLfloat *pVertexData = 0; // The vertex data for non-rotated GLfloat afVertexData[16] = { -1, -1, 1, -1, -1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1}; // The vertex data for rotated GLfloat afVertexDataRotated[16] = {-1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 0, 1, 1, 0, 0, 0}; if(!bRotate) pVertexData = &afVertexData[0]; else pVertexData = &afVertexDataRotated[0]; glGenBuffers(1, &m_pAPI->m_ui32VertexBufferObject); glBindBuffer(GL_ARRAY_BUFFER, m_pAPI->m_ui32VertexBufferObject); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, pVertexData, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); m_bInit = true; return PVR_SUCCESS; }
/*!**************************************************************************** @Function InitView @Return bool true if no error occured @Description Code in InitView() will be called by PVRShell upon initialization or after a change in the rendering context. Used to initialize variables that are dependant on the rendering context (e.g. textures, vertex buffers, etc.) ******************************************************************************/ bool OGLESIntroducingPVRTools::InitView() { /* Initialize the textures used by Print3D. To properly display text, Print3D needs to know the viewport dimensions and whether the text should be rotated. We get the dimensions using the shell function PVRShellGet(prefWidth/prefHeight). We can also get the rotate parameter by checking prefIsRotated and prefFullScreen. */ bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); if(m_Print3D.SetTextures(0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n"); return false; } // Sets the clear color glClearColor(0.6f, 0.8f, 1.0f, 1.0f); /* Loads the texture using the tool function PVRTTextureLoadFromPVR. The first parameter is the name of the file and the second parameter returns the resulting texture handle. The third parameter is a CPVRTString for error message output. This function can also be used to conveniently set the filter modes. If those parameters are not given, OpenGL ES defaults are used. Setting a mipmap filter on a mipmap-less texture will result in an error. */ if(PVRTTextureLoadFromPVR(c_szTextureFile, &m_uiTexture) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot load the texture\n"); return false; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* Compiles the shaders. First we use CPVRTResourceFile to load a file into memory. After construction with a file name, we just have to check whether the file is open or an error occured. We load both source and binary shaders, then try the binary shader first. The data of a CPVRTResourceFile will always be terminated with a 0 byte so it can safely be used as a C string. */ CPVRTResourceFile VertexShaderSrcFile(c_szVertShaderSrcFile); CPVRTResourceFile VertexShaderBinFile(c_szVertShaderBinFile); CPVRTString ErrorStr; /* PVRTShaderLoadBinaryFromMemory takes a pointer to the binary shader and the shader size as its first arguments. Then follows the shader type and binary format. On success, the handle to the new shader object is returned in the fifth parameter, while an error string is returned on failure. */ if (!VertexShaderBinFile.IsOpen() || (PVRTShaderLoadBinaryFromMemory(VertexShaderBinFile.DataPtr(), VertexShaderBinFile.Size(), GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertexShader, &ErrorStr) != PVR_SUCCESS)) { /* Fallback to source shader PVRTShaderLoadSourceFromMemory() takes the shader source code as its 1st argument. The shader type as 2nd argument (for now either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER. It returns the shader object in its 3rd argument. If an error occurs during compilation, the resulting log is returned in the 4th parameter. We could also use PVRTLoadAndCompileShaderFromFile() to load and compile a shader from an external text file */ CPVRTString vertexShaderSrc((const char*) VertexShaderSrcFile.DataPtr(), VertexShaderSrcFile.Size()); if (!VertexShaderSrcFile.IsOpen() || (PVRTShaderLoadSourceFromMemory(vertexShaderSrc.c_str(), GL_VERTEX_SHADER, &m_uiVertexShader, &ErrorStr) != PVR_SUCCESS)) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } } /* PVRTShaderLoadFromFile can be used to try compiling/loading shaders from files. In this variant, two files are tried before failing (usually binary and source files). The type of shader is determined from the file extension (.fsh and .vsh for source, .fsc and .vsc for SGX binary shaders) */ if (PVRTShaderLoadFromFile(c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, &ErrorStr) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } /* PVRTCreateProgram creates a new program object, attaches the shaders, binds attributes (given as an array of strings and the size thereof), and makes the program current - or it returns an error string on failure. */ if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertexShader, m_uiFragShader, g_aszAttribNames, eNumAttribs, &ErrorStr) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } // Store the location of uniforms for later use for (int i = 0; i < eNumUniforms; ++i) { m_ShaderProgram.auiLoc[i] = glGetUniformLocation(m_ShaderProgram.uiId, g_aszUniformNames[i]); } // Create VBO for the triangle from our data // Interleaved vertex data GLfloat afVertices[] = {-0.4f,-0.4f,0.0f, // Pos 0.0f,0.0f , // UVs 0.4f,-0.4f,0.0f, 1.0f,0.0f , 0.0f,0.4f ,0.0f, 0.5f,1.0f}; glGenBuffers(1, &m_ui32Vbo); m_ui32VertexStride = 5 * sizeof(GLfloat); // 3 floats for the pos, 2 for the UVs // Bind the VBO glBindBuffer(GL_ARRAY_BUFFER, m_ui32Vbo); // Set the buffer's data glBufferData(GL_ARRAY_BUFFER, 3 * m_ui32VertexStride, afVertices, GL_STATIC_DRAW); // Unbind the VBO glBindBuffer(GL_ARRAY_BUFFER, 0); return true; }
/*!*************************************************************************** @Function APIInit @Description Initialisation and texture upload. Should be called only once for a given context. *****************************************************************************/ bool CPVRTPrint3D::APIInit(const SPVRTContext * const pContext, bool bMakeCopy) { PVRT_UNREFERENCED_PARAMETER(pContext); m_pAPI = new SPVRTPrint3DAPI; if(!m_pAPI) return false; if(bMakeCopy) m_pAPI->m_pInstanceData = new SPVRTPrint3DAPI::SInstanceData(); SPVRTPrint3DAPI::SInstanceData& Data = (m_pAPI->m_pInstanceData ? *m_pAPI->m_pInstanceData : SPVRTPrint3DAPI::s_InstanceData); // Check to see if these shaders have already been loaded previously. Optimisation as we don't want to load many copies of the same shader! if( Data.uFragmentShaderLogo != UNDEFINED_HANDLE && Data.uVertexShaderLogo != UNDEFINED_HANDLE && Data.uProgramLogo != UNDEFINED_HANDLE && Data.uFragmentShaderFont != UNDEFINED_HANDLE && Data.uVertexShaderFont != UNDEFINED_HANDLE && Data.uProgramFont != UNDEFINED_HANDLE ) { ++SPVRTPrint3DAPI::s_iRefCount; return true; } // Compiles the shaders. For a more detailed explanation, see IntroducingPVRTools CPVRTString error; GLint Linked; bool bRes = true; bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DFragShaderLogo_fsh, GL_FRAGMENT_SHADER, &Data.uFragmentShaderLogo, &error) == PVR_SUCCESS); bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DVertShaderLogo_vsh, GL_VERTEX_SHADER, &Data.uVertexShaderLogo, &error) == PVR_SUCCESS); _ASSERT(bRes); // Create the 'text' program Data.uProgramLogo = glCreateProgram(); glAttachShader(Data.uProgramLogo, Data.uVertexShaderLogo); glAttachShader(Data.uProgramLogo, Data.uFragmentShaderLogo); glBindAttribLocation(Data.uProgramLogo, VERTEX_ARRAY, "myVertex"); glBindAttribLocation(Data.uProgramLogo, UV_ARRAY, "myUV"); glLinkProgram(Data.uProgramLogo); glGetProgramiv(Data.uProgramLogo, GL_LINK_STATUS, &Linked); if (!Linked) bRes = false; bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DFragShader_fsh, GL_FRAGMENT_SHADER, &Data.uFragmentShaderFont, &error) == PVR_SUCCESS); bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DVertShader_vsh, GL_VERTEX_SHADER, &Data.uVertexShaderFont, &error) == PVR_SUCCESS); _ASSERT(bRes); // Create the 'text' program Data.uProgramFont = glCreateProgram(); glAttachShader(Data.uProgramFont, Data.uVertexShaderFont); glAttachShader(Data.uProgramFont, Data.uFragmentShaderFont); glBindAttribLocation(Data.uProgramFont, VERTEX_ARRAY, "myVertex"); glBindAttribLocation(Data.uProgramFont, UV_ARRAY, "myUV"); glBindAttribLocation(Data.uProgramFont, COLOR_ARRAY, "myColour"); glLinkProgram(Data.uProgramFont); glGetProgramiv(Data.uProgramFont, GL_LINK_STATUS, &Linked); if (!Linked) bRes = false; Data.mvpLocationLogo = glGetUniformLocation(Data.uProgramFont, "myMVPMatrix"); Data.mvpLocationFont = glGetUniformLocation(Data.uProgramLogo, "myMVPMatrix"); _ASSERT(bRes && Data.mvpLocationLogo != -1 && Data.mvpLocationFont != -1); return bRes; }
/*!*************************************************************************** @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, CPVRTString *pReturnError) { GLuint uiVertexShader = 0, uiFragShader = 0; int i, j; if(!src.m_psEffect.GetSize()) return PVR_FAIL; /* First find the named effect from the effect file */ if(pszEffect) { for(i = 0; i < src.m_psEffect.GetSize(); ++i) { if(strcmp(src.m_psEffect[i].pszName, pszEffect) == 0) { m_nEffect = i; break; } } if(i == src.m_psEffect.GetSize()) { return PVR_FAIL; } } else { m_nEffect = 0; } /* Now load the effect */ m_pParser = &src; SPVRTPFXParserEffect *psParserEffect = &src.m_psEffect[m_nEffect]; // Create room for per-texture data m_psTextures = new SPVRTPFXTexture[src.m_psTexture.GetSize()]; // Initialise each Texture for(i = 0; i < src.m_psTexture.GetSize(); ++i) { m_psTextures[i].p = src.m_psTexture[i].pszFile; m_psTextures[i].ui = 0xFFFFFFFF; } // Initialise the effect { // initialise attributes to default values char *pszVertexShader = NULL; char *pszFragmentShader = NULL; bool bFreeVertexShader = false; bool bFreeFragmentShader = false; // find shaders requested for(i=0; i < src.m_psVertexShader.GetSize(); ++i) { if(strcmp(psParserEffect->pszVertexShaderName, src.m_psVertexShader[i].pszName) == 0) { if(src.m_psVertexShader[i].bUseFileName) { pszVertexShader = src.m_psVertexShader[i].pszGLSLcode; } else { // offset glsl code by nFirstLineNumber pszVertexShader = (char *)malloc((strlen(src.m_psVertexShader[i].pszGLSLcode) + (src.m_psVertexShader[i].nFirstLineNumber) + 1) * sizeof(char)); pszVertexShader[0] = '\0'; for(unsigned int n = 0; n < src.m_psVertexShader[i].nFirstLineNumber; n++) strcat(pszVertexShader, "\n"); strcat(pszVertexShader, src.m_psVertexShader[i].pszGLSLcode); bFreeVertexShader = true; } break; } } for(i=0; i<src.m_psFragmentShader.GetSize(); ++i) { if(strcmp(psParserEffect->pszFragmentShaderName, src.m_psFragmentShader[i].pszName) == 0) { if(src.m_psFragmentShader[i].bUseFileName) { pszFragmentShader = src.m_psFragmentShader[i].pszGLSLcode; } else { // offset glsl code by nFirstLineNumber pszFragmentShader = (char *)malloc((strlen(src.m_psFragmentShader[i].pszGLSLcode) + (src.m_psFragmentShader[i].nFirstLineNumber) + 1) * sizeof(char)); pszFragmentShader[0] = '\0'; for(unsigned int n = 0; n < src.m_psFragmentShader[i].nFirstLineNumber; n++) strcat(pszFragmentShader, "\n"); strcat(pszFragmentShader, src.m_psFragmentShader[i].pszGLSLcode); bFreeFragmentShader = true; } break; } } CPVRTString error; bool bLoadSource = 1; // Try first to load from the binary block if (src.m_psVertexShader[i].pbGLSLBinary!=NULL) { #if defined(GL_SGX_BINARY_IMG) if (PVRTShaderLoadBinaryFromMemory(src.m_psVertexShader[i].pbGLSLBinary, src.m_psVertexShader[i].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("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.m_psVertexShader[i].pbGLSLBinary==NULL) { *pReturnError = CPVRTString("Vertex shader ") + psParserEffect->pszVertexShaderName + " not found in " + pszFileName + ".\n"; } else { *pReturnError = CPVRTString("Binary vertex shader ") + psParserEffect->pszVertexShaderName + " not supported.\n"; } if(bFreeVertexShader) FREE(pszVertexShader); if(bFreeFragmentShader) FREE(pszFragmentShader); return PVR_FAIL; } } // Try first to load from the binary block if (src.m_psFragmentShader[i].pbGLSLBinary!=NULL) { #if defined(GL_SGX_BINARY_IMG) if (PVRTShaderLoadBinaryFromMemory(src.m_psFragmentShader[i].pbGLSLBinary, src.m_psVertexShader[i].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("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.m_psFragmentShader[i].pbGLSLBinary==NULL) { *pReturnError = CPVRTString("Fragment shader ") + psParserEffect->pszFragmentShaderName + " not found in " + pszFileName + ".\n"; } else { *pReturnError = CPVRTString("Binary Fragment shader ") + psParserEffect->pszFragmentShaderName + " 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(i = 0; i < (int) psParserEffect->nNumAttributes; ++i) { glBindAttribLocation(m_uiProgram, i, psParserEffect->psAttribute[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; } /* Textures */ m_pnTextureIdx = new unsigned int[psParserEffect->nNumTextures]; for(i = 0; i < (int) psParserEffect->nNumTextures; ++i) { for(j = 0; j < src.m_psTexture.GetSize(); ++j) { if(strcmp(psParserEffect->psTextures[i].pszName, src.m_psTexture[j].pszName) == 0) { m_pnTextureIdx[i] = j; break; } } if(j == src.m_psTexture.GetSize()) { *pReturnError = CPVRTString("Effect \"") + psParserEffect->pszName + "\", requested non-existent texture: \"" + psParserEffect->psTextures[i].pszName + "\"\n"; m_pnTextureIdx[i] = 0; } } } return PVR_SUCCESS; }