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