mirror of
https://github.com/blawar/GLideN64.git
synced 2024-06-24 21:39:35 +00:00
Code refactor: add abstract class UniformCollection.
Implement it for desktop GL: OGL3X/UniformBlock and for GLES2: GLES2/UniformSet GLES3 and above must use OGL3X/UniformBlock.
This commit is contained in:
parent
ed4271e60e
commit
e73cee3a58
|
@ -287,6 +287,7 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\N64.cpp" />
|
||||
<ClCompile Include="..\..\src\OGL3X\UniformBlock.cpp" />
|
||||
<ClCompile Include="..\..\src\OpenGL.cpp" />
|
||||
<ClCompile Include="..\..\src\PostProcessor.cpp" />
|
||||
<ClCompile Include="..\..\src\RDP.CPP" />
|
||||
|
@ -358,6 +359,7 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\N64.h" />
|
||||
<ClInclude Include="..\..\src\OGL3X\UniformBlock.h" />
|
||||
<ClInclude Include="..\..\src\OpenGL.h" />
|
||||
<ClInclude Include="..\..\src\PluginAPI.h" />
|
||||
<ClInclude Include="..\..\src\PostProcessor.h" />
|
||||
|
@ -368,6 +370,7 @@
|
|||
<ClInclude Include="..\..\src\Textures.h" />
|
||||
<ClInclude Include="..\..\src\Turbo3D.h" />
|
||||
<ClInclude Include="..\..\src\Types.h" />
|
||||
<ClInclude Include="..\..\src\UniformCollection.h" />
|
||||
<ClInclude Include="..\..\src\VI.h" />
|
||||
<ClInclude Include="..\..\src\F3D.h" />
|
||||
<ClInclude Include="..\..\src\F3DDKR.h" />
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
<Filter Include="Source Files\mupenplus">
|
||||
<UniqueIdentifier>{b10a85f0-0fbb-4f8e-b6d8-78ee2a6394bf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="OGL3X">
|
||||
<UniqueIdentifier>{b3016e90-1a88-4a28-9ca4-fbebf41e10ee}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\OGL3X">
|
||||
<UniqueIdentifier>{32bbb389-ea50-4ac9-bb55-84e4f066fe94}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\Combiner.cpp">
|
||||
|
@ -188,6 +194,9 @@
|
|||
<ClCompile Include="..\..\src\windows\GLFunctions_windows.cpp">
|
||||
<Filter>Source Files\windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\OGL3X\UniformBlock.cpp">
|
||||
<Filter>Source Files\OGL3X</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\3DMath.h">
|
||||
|
@ -331,5 +340,11 @@
|
|||
<ClInclude Include="..\..\src\Keys.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\UniformCollection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\OGL3X\UniformBlock.h">
|
||||
<Filter>OGL3X</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -41,6 +41,7 @@ set(GLideN64_SOURCES
|
|||
PostProcessor.cpp
|
||||
VI.cpp
|
||||
common/CommonAPIImpl_common.cpp
|
||||
OGL3X/UniformBlock.cpp
|
||||
)
|
||||
|
||||
if(MUPENPLUSAPI)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "OpenGL.h"
|
||||
#include "Combiner.h"
|
||||
#include "GLSLCombiner.h"
|
||||
#include "UniformCollection.h"
|
||||
#include "Debug.h"
|
||||
#include "gDP.h"
|
||||
|
||||
|
@ -85,13 +86,13 @@ CombinerInfo & CombinerInfo::get()
|
|||
void CombinerInfo::init()
|
||||
{
|
||||
m_pCurrent = NULL;
|
||||
m_pUniformBlock = new UniformBlock;
|
||||
m_pUniformCollection = createUniformCollection();
|
||||
}
|
||||
|
||||
void CombinerInfo::destroy()
|
||||
{
|
||||
delete m_pUniformBlock;
|
||||
m_pUniformBlock = NULL;
|
||||
delete m_pUniformCollection;
|
||||
m_pUniformCollection = NULL;
|
||||
m_pCurrent = NULL;
|
||||
for (Combiners::iterator cur = m_combiners.begin(); cur != m_combiners.end(); ++cur)
|
||||
delete cur->second;
|
||||
|
@ -237,7 +238,7 @@ void CombinerInfo::setCombine(u64 _mux )
|
|||
} else {
|
||||
m_pCurrent = _compile(_mux);
|
||||
m_pCurrent->update(true);
|
||||
m_pUniformBlock->bindWithShaderCombiner(m_pCurrent);
|
||||
m_pUniformCollection->bindWithShaderCombiner(m_pCurrent);
|
||||
m_combiners[_mux] = m_pCurrent;
|
||||
}
|
||||
m_bChanged = true;
|
||||
|
@ -245,57 +246,57 @@ void CombinerInfo::setCombine(u64 _mux )
|
|||
|
||||
void CombinerInfo::updatePrimColor()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->setColorData(UniformBlock::cuPrimColor, sizeof(f32)* 5, &gDP.primColor.r);
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->setColorData(UniformCollection::cuPrimColor, sizeof(f32)* 5, &gDP.primColor.r);
|
||||
}
|
||||
|
||||
void CombinerInfo::updateEnvColor()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->setColorData(UniformBlock::cuEnvColor, sizeof(f32)* 4, &gDP.envColor.r);
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->setColorData(UniformCollection::cuEnvColor, sizeof(f32)* 4, &gDP.envColor.r);
|
||||
}
|
||||
|
||||
void CombinerInfo::updateFogColor()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->setColorData(UniformBlock::cuFogColor, sizeof(f32)* 4, &gDP.fogColor.r);
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->setColorData(UniformCollection::cuFogColor, sizeof(f32)* 4, &gDP.fogColor.r);
|
||||
}
|
||||
|
||||
void CombinerInfo::updateBlendColor()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->setColorData(UniformBlock::cuBlendColor, sizeof(f32)* 4, &gDP.blendColor.r);
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->setColorData(UniformCollection::cuBlendColor, sizeof(f32)* 4, &gDP.blendColor.r);
|
||||
}
|
||||
|
||||
void CombinerInfo::updateKeyColor()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->setColorData(UniformBlock::cuCenterColor, sizeof(f32)* 8, &gDP.key.center.r);
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->setColorData(UniformCollection::cuCenterColor, sizeof(f32)* 8, &gDP.key.center.r);
|
||||
}
|
||||
|
||||
void CombinerInfo::updateConvertColor()
|
||||
{
|
||||
if (m_pUniformBlock == NULL)
|
||||
if (m_pUniformCollection == NULL)
|
||||
return;
|
||||
f32 convert[2] = { gDP.convert.k4*0.0039215689f, gDP.convert.k5*0.0039215689f };
|
||||
m_pUniformBlock->setColorData(UniformBlock::cuK4, sizeof(convert), convert);
|
||||
m_pUniformCollection->setColorData(UniformCollection::cuK4, sizeof(convert), convert);
|
||||
}
|
||||
|
||||
void CombinerInfo::updateTextureParameters()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->updateTextureParameters();
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->updateTextureParameters();
|
||||
}
|
||||
|
||||
void CombinerInfo::updateLightParameters()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->updateLightParameters();
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->updateLightParameters();
|
||||
gSP.changed &= ~CHANGED_LIGHT;
|
||||
}
|
||||
|
||||
void CombinerInfo::updateParameters()
|
||||
{
|
||||
if (m_pUniformBlock != NULL)
|
||||
m_pUniformBlock->updateUniforms(m_pCurrent);
|
||||
if (m_pUniformCollection != NULL)
|
||||
m_pUniformCollection->updateUniforms(m_pCurrent);
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ struct CombineCycle
|
|||
};
|
||||
|
||||
class ShaderCombiner;
|
||||
class UniformBlock;
|
||||
class UniformCollection;
|
||||
class CombinerInfo
|
||||
{
|
||||
public:
|
||||
|
@ -150,7 +150,7 @@ private:
|
|||
ShaderCombiner * m_pCurrent;
|
||||
typedef std::map<u64, ShaderCombiner *> Combiners;
|
||||
Combiners m_combiners;
|
||||
UniformBlock * m_pUniformBlock;
|
||||
UniformCollection * m_pUniformCollection;
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
138
src/GLES2/UniformSet.cpp
Normal file
138
src/GLES2/UniformSet.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
#include "UniformSet.h"
|
||||
#include "../Config.h"
|
||||
#include "../Textures.h"
|
||||
|
||||
#define LocateUniform2(A) \
|
||||
location.A.loc = glGetUniformLocation(program, #A);
|
||||
|
||||
void UniformSet::bindWithShaderCombiner(ShaderCombiner * _pCombiner)
|
||||
{
|
||||
const u64 mux = _pCombiner->getMux();
|
||||
const GLuint program = _pCombiner->m_program;
|
||||
m_uniforms.emplace(mux, program);
|
||||
UniformSetLocation & location = m_uniforms.at(mux);
|
||||
|
||||
// Texture parameters
|
||||
if (_pCombiner->usesTexture()) {
|
||||
LocateUniform2(uTexScale);
|
||||
LocateUniform2(uTexMask[0]);
|
||||
LocateUniform2(uTexMask[1]);
|
||||
LocateUniform2(uTexOffset[0]);
|
||||
LocateUniform2(uTexOffset[1]);
|
||||
LocateUniform2(uCacheScale[0]);
|
||||
LocateUniform2(uCacheScale[1]);
|
||||
LocateUniform2(uCacheOffset[0]);
|
||||
LocateUniform2(uCacheOffset[1]);
|
||||
LocateUniform2(uCacheShiftScale[0]);
|
||||
LocateUniform2(uCacheShiftScale[1]);
|
||||
LocateUniform2(uCacheFrameBuffer);
|
||||
LocateUniform2(uTextureSize[0]);
|
||||
LocateUniform2(uTextureSize[1]);
|
||||
_updateTextureUniforms(location, _pCombiner->usesTile(0), _pCombiner->usesTile(1), true);
|
||||
}
|
||||
|
||||
// Colors
|
||||
LocateUniform2(uFogColor);
|
||||
LocateUniform2(uCenterColor);
|
||||
LocateUniform2(uScaleColor);
|
||||
LocateUniform2(uBlendColor);
|
||||
LocateUniform2(uEnvColor);
|
||||
LocateUniform2(uPrimColor);
|
||||
LocateUniform2(uPrimLod);
|
||||
LocateUniform2(uK4);
|
||||
LocateUniform2(uK5);
|
||||
_updateColorUniforms(location, true);
|
||||
|
||||
// Lights
|
||||
if (config.generalEmulation.enableHWLighting != 0 && GBI.isHWLSupported() && _pCombiner->usesShadeColor()) {
|
||||
// locate lights uniforms
|
||||
char buf[32];
|
||||
for (s32 i = 0; i < 8; ++i) {
|
||||
sprintf(buf, "uLightDirection[%d]", i);
|
||||
location.uLightDirection[i].loc = glGetUniformLocation(program, buf);
|
||||
sprintf(buf, "uLightColor[%d]", i);
|
||||
location.uLightColor[i].loc = glGetUniformLocation(program, buf);
|
||||
}
|
||||
_updateLightUniforms(location, true);
|
||||
}
|
||||
}
|
||||
|
||||
void UniformSet::_updateColorUniforms(UniformSetLocation & _location, bool _bForce)
|
||||
{
|
||||
_location.uFogColor.set(&gDP.fogColor.r, _bForce);
|
||||
_location.uCenterColor.set(&gDP.key.center.r, _bForce);
|
||||
_location.uScaleColor.set(&gDP.key.scale.r, _bForce);
|
||||
_location.uBlendColor.set(&gDP.blendColor.r, _bForce);
|
||||
_location.uEnvColor.set(&gDP.envColor.r, _bForce);
|
||||
_location.uPrimColor.set(&gDP.primColor.r, _bForce);
|
||||
_location.uPrimLod.set(gDP.primColor.l, _bForce);
|
||||
_location.uK4.set(gDP.convert.k4*0.0039215689f, _bForce);
|
||||
_location.uK5.set(gDP.convert.k5*0.0039215689f, _bForce);
|
||||
}
|
||||
|
||||
|
||||
void UniformSet::_updateTextureUniforms(UniformSetLocation & _location, bool _bUsesT0, bool _bUsesT1, bool _bForce)
|
||||
{
|
||||
int nFB[2] = { 0, 0 };
|
||||
const bool bUsesTile[2] = { _bUsesT0, _bUsesT1 };
|
||||
TextureCache & cache = textureCache();
|
||||
for (u32 t = 0; t < 2; ++t) {
|
||||
if (!bUsesTile[t])
|
||||
continue;
|
||||
|
||||
if (gSP.textureTile[t] != NULL) {
|
||||
if (gSP.textureTile[t]->textureMode == TEXTUREMODE_BGIMAGE || gSP.textureTile[t]->textureMode == TEXTUREMODE_FRAMEBUFFER_BG) {
|
||||
_location.uTexOffset[t].set(0.0f, 0.0f, _bForce);
|
||||
_location.uTexMask[t].set(0.0f, 0.0f, _bForce);
|
||||
}
|
||||
else {
|
||||
_location.uTexOffset[t].set(gSP.textureTile[t]->fuls, gSP.textureTile[t]->fult, _bForce);
|
||||
_location.uTexMask[t].set(
|
||||
gSP.textureTile[t]->masks > 0 ? (float)(1 << gSP.textureTile[t]->masks) : 0.0f,
|
||||
gSP.textureTile[t]->maskt > 0 ? (float)(1 << gSP.textureTile[t]->maskt) : 0.0f,
|
||||
_bForce);
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.current[t] != NULL) {
|
||||
f32 shiftScaleS = 1.0f;
|
||||
f32 shiftScaleT = 1.0f;
|
||||
getTextureShiftScale(t, cache, shiftScaleS, shiftScaleT);
|
||||
_location.uCacheShiftScale[t].set(shiftScaleS, shiftScaleT, _bForce);
|
||||
_location.uCacheScale[t].set(cache.current[t]->scaleS, cache.current[t]->scaleT, _bForce);
|
||||
_location.uCacheOffset[t].set(cache.current[t]->offsetS, cache.current[t]->offsetT, _bForce);
|
||||
_location.uTextureSize[t].set(cache.current[t]->realWidth, cache.current[t]->realHeight, _bForce);
|
||||
nFB[t] = cache.current[t]->frameBufferTexture;
|
||||
}
|
||||
}
|
||||
|
||||
_location.uCacheFrameBuffer.set(nFB[0], nFB[1], _bForce);
|
||||
_location.uTexScale.set(gSP.texture.scales, gSP.texture.scalet, _bForce);
|
||||
}
|
||||
|
||||
void UniformSet::_updateLightUniforms(UniformSetLocation & _location, bool _bForce)
|
||||
{
|
||||
for (s32 i = 0; i <= gSP.numLights; ++i) {
|
||||
_location.uLightDirection[i].set(&gSP.lights[i].x, _bForce);
|
||||
_location.uLightColor[i].set(&gSP.lights[i].r, _bForce);
|
||||
}
|
||||
}
|
||||
|
||||
void UniformSet::updateUniforms(ShaderCombiner * _pCombiner)
|
||||
{
|
||||
UniformSetLocation & location = m_uniforms.at(_pCombiner->getMux());
|
||||
|
||||
_updateColorUniforms(location, false);
|
||||
|
||||
OGLRender::RENDER_STATE rs = video().getRender().getRenderState();
|
||||
if ((rs == OGLRender::rsTriangle || rs == OGLRender::rsLine) && _pCombiner->usesTexture())
|
||||
_updateTextureUniforms(location, _pCombiner->usesTile(0), _pCombiner->usesTile(1), false);
|
||||
|
||||
if (config.generalEmulation.enableHWLighting != 0 && GBI.isHWLSupported() && _pCombiner->usesShadeColor())
|
||||
_updateLightUniforms(location, false);
|
||||
}
|
||||
|
||||
UniformCollection * createUniformCollection()
|
||||
{
|
||||
return new UniformSet();
|
||||
}
|
70
src/GLES2/UniformSet.h
Normal file
70
src/GLES2/UniformSet.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef UNIFORM_SET_H
|
||||
#define UNIFORM_SET_H
|
||||
|
||||
#include "../UniformCollection.h"
|
||||
|
||||
class UniformSet : public UniformCollection
|
||||
{
|
||||
public:
|
||||
|
||||
UniformSet() {}
|
||||
~UniformSet() {}
|
||||
|
||||
virtual void bindWithShaderCombiner(ShaderCombiner * _pCombiner);
|
||||
virtual void setColorData(ColorUniforms _index, u32 _dataSize, const void * _data) {}
|
||||
virtual void updateTextureParameters() {}
|
||||
virtual void updateLightParameters() {}
|
||||
virtual void updateUniforms(ShaderCombiner * _pCombiner);
|
||||
|
||||
private:
|
||||
struct fv3Uniform {
|
||||
GLint loc;
|
||||
float val[3];
|
||||
void set(float * _pVal, bool _force) {
|
||||
const size_t szData = sizeof(float)* 3;
|
||||
if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) {
|
||||
memcpy(val, _pVal, szData);
|
||||
glUniform3fv(loc, 1, _pVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct fv4Uniform {
|
||||
GLint loc;
|
||||
float val[4];
|
||||
void set(float * _pVal, bool _force) {
|
||||
const size_t szData = sizeof(float)* 4;
|
||||
if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) {
|
||||
memcpy(val, _pVal, szData);
|
||||
glUniform4fv(loc, 1, _pVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct UniformSetLocation
|
||||
{
|
||||
UniformSetLocation(GLuint _program) : m_program(_program) {}
|
||||
|
||||
GLuint m_program;
|
||||
|
||||
// Texture parameters
|
||||
ShaderCombiner::fv2Uniform uTexScale, uTexMask[2], uTexOffset[2], uCacheScale[2], uCacheOffset[2], uCacheShiftScale[2];
|
||||
ShaderCombiner::iv2Uniform uCacheFrameBuffer, uTextureSize[2];
|
||||
|
||||
// Colors
|
||||
fv4Uniform uFogColor, uCenterColor, uScaleColor, uBlendColor, uEnvColor, uPrimColor;
|
||||
ShaderCombiner::fUniform uPrimLod, uK4, uK5;
|
||||
|
||||
// Lights
|
||||
fv3Uniform uLightDirection[8], uLightColor[8];
|
||||
};
|
||||
|
||||
void _updateColorUniforms(UniformSetLocation & _location, bool _bForce);
|
||||
void _updateTextureUniforms(UniformSetLocation & _location, bool _bUsesT0, bool _bUsesT1, bool _bForce);
|
||||
void _updateLightUniforms(UniformSetLocation & _location, bool _bForce);
|
||||
|
||||
typedef std::map<u64, UniformSetLocation> Uniforms;
|
||||
Uniforms m_uniforms;
|
||||
};
|
||||
|
||||
#endif // UNIFORM_SET_H
|
|
@ -1016,379 +1016,3 @@ void SetMonochromeCombiner() {
|
|||
glUseProgram(g_monochrome_image_program);
|
||||
gDP.changed |= CHANGED_COMBINE;
|
||||
}
|
||||
|
||||
/*======================UniformBlock==========================*/
|
||||
#ifdef GL_UNIFORMBLOCK_SUPPORT
|
||||
|
||||
static
|
||||
const char * strTextureUniforms[UniformBlock::tuTotal] = {
|
||||
"uTexScale",
|
||||
"uTexMask",
|
||||
"uTexOffset",
|
||||
"uCacheScale",
|
||||
"uCacheOffset",
|
||||
"uCacheShiftScale",
|
||||
"uCacheFrameBuffer"
|
||||
};
|
||||
|
||||
static
|
||||
const char * strColorUniforms[UniformBlock::cuTotal] = {
|
||||
"uFogColor",
|
||||
"uCenterColor",
|
||||
"uScaleColor",
|
||||
"uBlendColor",
|
||||
"uEnvColor",
|
||||
"uPrimColor",
|
||||
"uPrimLod",
|
||||
"uK4",
|
||||
"uK5"
|
||||
};
|
||||
|
||||
static
|
||||
const char * strLightUniforms[UniformBlock::luTotal] = {
|
||||
"uLightDirection",
|
||||
"uLightColor"
|
||||
};
|
||||
|
||||
UniformBlock::UniformBlock() : m_currentBuffer(0)
|
||||
{
|
||||
}
|
||||
|
||||
UniformBlock::~UniformBlock()
|
||||
{
|
||||
}
|
||||
|
||||
void UniformBlock::_initTextureBuffer(GLuint _program)
|
||||
{
|
||||
const GLint blockSize = m_textureBlock.initBuffer(_program, "TextureBlock", strTextureUniforms);
|
||||
if (blockSize == 0)
|
||||
return;
|
||||
m_textureBlockData.resize(blockSize);
|
||||
GLbyte * pData = m_textureBlockData.data();
|
||||
memset(pData, 0, blockSize);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_textureBlock.m_buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, blockSize, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, m_textureBlock.m_blockBindingPoint, m_textureBlock.m_buffer);
|
||||
updateTextureParameters();
|
||||
}
|
||||
|
||||
void UniformBlock::_initColorsBuffer(GLuint _program)
|
||||
{
|
||||
const GLint blockSize = m_colorsBlock.initBuffer(_program, "ColorsBlock", strColorUniforms);
|
||||
if (blockSize == 0)
|
||||
return;
|
||||
m_colorsBlockData.resize(blockSize);
|
||||
GLbyte * pData = m_colorsBlockData.data();
|
||||
memset(pData, 0, blockSize);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuFogColor], &gDP.fogColor.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuCenterColor], &gDP.key.center.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuScaleColor], &gDP.key.scale.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuEnvColor], &gDP.envColor.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuPrimColor], &gDP.primColor.r, sizeof(f32)* 4);
|
||||
*(f32*)(pData + m_colorsBlock.m_offsets[cuPrimLod]) = gDP.primColor.l;
|
||||
*(f32*)(pData + m_colorsBlock.m_offsets[cuK4]) = gDP.convert.k4*0.0039215689f;
|
||||
*(f32*)(pData + m_colorsBlock.m_offsets[cuK5]) = gDP.convert.k5*0.0039215689f;
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_colorsBlock.m_buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, blockSize, pData, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, m_colorsBlock.m_blockBindingPoint, m_colorsBlock.m_buffer);
|
||||
m_currentBuffer = m_colorsBlock.m_buffer;
|
||||
}
|
||||
|
||||
void UniformBlock::_initLightBuffer(GLuint _program)
|
||||
{
|
||||
const GLint blockSize = m_lightBlock.initBuffer(_program, "LightBlock", strLightUniforms);
|
||||
if (blockSize == 0)
|
||||
return;
|
||||
m_lightBlockData.resize(blockSize);
|
||||
GLbyte * pData = m_lightBlockData.data();
|
||||
memset(pData, 0, blockSize);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_lightBlock.m_buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, blockSize, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, m_lightBlock.m_blockBindingPoint, m_lightBlock.m_buffer);
|
||||
updateLightParameters();
|
||||
}
|
||||
|
||||
bool UniformBlock::_isDataChanged(void * _pBuffer, const void * _pData, u32 _dataSize)
|
||||
{
|
||||
u32 * pSrc = (u32*)_pData;
|
||||
u32 * pDst = (u32*)_pBuffer;
|
||||
u32 cnt = _dataSize / 4;
|
||||
for (u32 i = 0; i < cnt; ++i) {
|
||||
if (pSrc[i] != pDst[i]) {
|
||||
memcpy(_pBuffer, _pData, _dataSize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UniformBlock::bindWithShaderCombiner(ShaderCombiner * _pCombiner)
|
||||
{
|
||||
const GLuint program = _pCombiner->m_program;
|
||||
if (_pCombiner->usesTexture()) {
|
||||
if (m_textureBlock.m_buffer == 0)
|
||||
_initTextureBuffer(program);
|
||||
else {
|
||||
const GLint blockIndex = glGetUniformBlockIndex(program, "TextureBlock");
|
||||
if (blockIndex != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(program, blockIndex, m_textureBlock.m_blockBindingPoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_colorsBlock.m_buffer == 0)
|
||||
_initColorsBuffer(program);
|
||||
else {
|
||||
const GLint blockIndex = glGetUniformBlockIndex(program, "ColorsBlock");
|
||||
if (blockIndex != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(program, blockIndex, m_colorsBlock.m_blockBindingPoint);
|
||||
}
|
||||
|
||||
if (_pCombiner->usesShadeColor() && config.generalEmulation.enableHWLighting != 0) {
|
||||
if (m_lightBlock.m_buffer == 0)
|
||||
_initLightBuffer(program);
|
||||
else {
|
||||
const GLint blockIndex = glGetUniformBlockIndex(program, "LightBlock");
|
||||
if (blockIndex != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(program, blockIndex, m_lightBlock.m_blockBindingPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBlock::setColorData(ColorUniforms _index, u32 _dataSize, const void * _data)
|
||||
{
|
||||
if (m_colorsBlock.m_buffer == 0)
|
||||
return;
|
||||
if (!_isDataChanged(m_colorsBlockData.data() + m_colorsBlock.m_offsets[_index], _data, _dataSize))
|
||||
return;
|
||||
|
||||
if (m_currentBuffer != m_colorsBlock.m_buffer) {
|
||||
m_currentBuffer = m_colorsBlock.m_buffer;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_colorsBlock.m_buffer);
|
||||
}
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, m_colorsBlock.m_offsets[_index], _dataSize, _data);
|
||||
}
|
||||
|
||||
void UniformBlock::updateTextureParameters()
|
||||
{
|
||||
if (m_textureBlock.m_buffer == 0)
|
||||
return;
|
||||
|
||||
GLbyte * pData = m_textureBlockData.data();
|
||||
f32 texScale[4] = { gSP.texture.scales, gSP.texture.scalet, 0, 0 };
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuTexScale], texScale, m_textureBlock.m_offsets[tuTexMask] - m_textureBlock.m_offsets[tuTexScale]);
|
||||
|
||||
f32 texOffset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
f32 texMask[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
if (gSP.textureTile[0] != NULL) {
|
||||
if (gSP.textureTile[0]->textureMode != TEXTUREMODE_BGIMAGE && gSP.textureTile[0]->textureMode != TEXTUREMODE_FRAMEBUFFER_BG) {
|
||||
texOffset[0] = gSP.textureTile[0]->fuls;
|
||||
texOffset[1] = gSP.textureTile[0]->fult;
|
||||
texMask[0] = gSP.textureTile[0]->masks > 0 ? (float)(1 << gSP.textureTile[0]->masks) : 0.0f;
|
||||
texMask[1] = gSP.textureTile[0]->maskt > 0 ? (float)(1 << gSP.textureTile[0]->maskt) : 0.0f;
|
||||
}
|
||||
}
|
||||
if (gSP.textureTile[1] != 0) {
|
||||
texOffset[4] = gSP.textureTile[1]->fuls;
|
||||
texOffset[5] = gSP.textureTile[1]->fult;
|
||||
texMask[4] = gSP.textureTile[1]->masks > 0 ? (float)(1 << gSP.textureTile[1]->masks) : 0.0f;
|
||||
texMask[5] = gSP.textureTile[1]->maskt > 0 ? (float)(1 << gSP.textureTile[1]->maskt) : 0.0f;
|
||||
}
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuTexMask], texMask, m_textureBlock.m_offsets[tuTexOffset] - m_textureBlock.m_offsets[tuTexMask]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuTexOffset], texOffset, m_textureBlock.m_offsets[tuCacheScale] - m_textureBlock.m_offsets[tuTexOffset]);
|
||||
|
||||
f32 texCacheScale[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
f32 texCacheOffset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
f32 texCacheShiftScale[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
GLint texCacheFrameBuffer[4] = { 0, 0, 0, 0 };
|
||||
TextureCache & cache = textureCache();
|
||||
if (cache.current[0]) {
|
||||
texCacheScale[0] = cache.current[0]->scaleS;
|
||||
texCacheScale[1] = cache.current[0]->scaleT;
|
||||
texCacheOffset[0] = cache.current[0]->offsetS;
|
||||
texCacheOffset[1] = cache.current[0]->offsetT;
|
||||
|
||||
f32 shiftScaleS = 1.0f;
|
||||
f32 shiftScaleT = 1.0f;
|
||||
getTextureShiftScale(0, cache, shiftScaleS, shiftScaleT);
|
||||
texCacheShiftScale[0] = shiftScaleS;
|
||||
texCacheShiftScale[1] = shiftScaleT;
|
||||
texCacheFrameBuffer[0] = cache.current[0]->frameBufferTexture;
|
||||
}
|
||||
if (cache.current[1]) {
|
||||
texCacheScale[4] = cache.current[1]->scaleS;
|
||||
texCacheScale[5] = cache.current[1]->scaleT;
|
||||
texCacheOffset[4] = cache.current[1]->offsetS;
|
||||
texCacheOffset[5] = cache.current[1]->offsetT;
|
||||
|
||||
f32 shiftScaleS = 1.0f;
|
||||
f32 shiftScaleT = 1.0f;
|
||||
getTextureShiftScale(1, cache, shiftScaleS, shiftScaleT);
|
||||
texCacheShiftScale[4] = shiftScaleS;
|
||||
texCacheShiftScale[5] = shiftScaleT;
|
||||
texCacheFrameBuffer[1] = cache.current[1]->frameBufferTexture;
|
||||
}
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheScale], texCacheScale, m_textureBlock.m_offsets[tuCacheOffset] - m_textureBlock.m_offsets[tuCacheScale]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheOffset], texCacheOffset, m_textureBlock.m_offsets[tuCacheShiftScale] - m_textureBlock.m_offsets[tuCacheOffset]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheShiftScale], texCacheShiftScale, m_textureBlock.m_offsets[tuCacheFrameBuffer] - m_textureBlock.m_offsets[tuCacheShiftScale]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheFrameBuffer], texCacheFrameBuffer, m_textureBlockData.size() - m_textureBlock.m_offsets[tuCacheFrameBuffer]);
|
||||
|
||||
if (m_currentBuffer != m_textureBlock.m_buffer) {
|
||||
m_currentBuffer = m_textureBlock.m_buffer;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_textureBlock.m_buffer);
|
||||
}
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, m_textureBlock.m_offsets[tuTexScale], m_textureBlockData.size(), pData);
|
||||
}
|
||||
|
||||
void UniformBlock::updateLightParameters()
|
||||
{
|
||||
if (m_lightBlock.m_buffer == 0)
|
||||
return;
|
||||
|
||||
GLbyte * pData = m_lightBlockData.data();
|
||||
const u32 arraySize = m_lightBlock.m_offsets[luLightColor] / 8;
|
||||
for (s32 i = 0; i <= gSP.numLights; ++i) {
|
||||
memcpy(pData + m_lightBlock.m_offsets[luLightDirection] + arraySize*i, &gSP.lights[i].x, arraySize);
|
||||
memcpy(pData + m_lightBlock.m_offsets[luLightColor] + arraySize*i, &gSP.lights[i].r, arraySize);
|
||||
}
|
||||
if (m_currentBuffer != m_lightBlock.m_buffer) {
|
||||
m_currentBuffer = m_lightBlock.m_buffer;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_lightBlock.m_buffer);
|
||||
}
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, m_lightBlock.m_offsets[luLightDirection], m_lightBlockData.size(), pData);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define LocateUniform2(A) \
|
||||
location.A.loc = glGetUniformLocation(program, #A);
|
||||
|
||||
void UniformBlock::bindWithShaderCombiner(ShaderCombiner * _pCombiner)
|
||||
{
|
||||
const u64 mux = _pCombiner->getMux();
|
||||
const GLuint program = _pCombiner->m_program;
|
||||
m_uniforms.emplace(mux, program);
|
||||
UniformBlockLocation & location = m_uniforms.at(mux);
|
||||
|
||||
// Texture parameters
|
||||
if (_pCombiner->usesTexture()) {
|
||||
LocateUniform2(uTexScale);
|
||||
LocateUniform2(uTexMask[0]);
|
||||
LocateUniform2(uTexMask[1]);
|
||||
LocateUniform2(uTexOffset[0]);
|
||||
LocateUniform2(uTexOffset[1]);
|
||||
LocateUniform2(uCacheScale[0]);
|
||||
LocateUniform2(uCacheScale[1]);
|
||||
LocateUniform2(uCacheOffset[0]);
|
||||
LocateUniform2(uCacheOffset[1]);
|
||||
LocateUniform2(uCacheShiftScale[0]);
|
||||
LocateUniform2(uCacheShiftScale[1]);
|
||||
LocateUniform2(uCacheFrameBuffer);
|
||||
LocateUniform2(uTextureSize[0]);
|
||||
LocateUniform2(uTextureSize[1]);
|
||||
_updateTextureUniforms(location, _pCombiner->usesTile(0), _pCombiner->usesTile(1), true);
|
||||
}
|
||||
|
||||
// Colors
|
||||
LocateUniform2(uFogColor);
|
||||
LocateUniform2(uCenterColor);
|
||||
LocateUniform2(uScaleColor);
|
||||
LocateUniform2(uBlendColor);
|
||||
LocateUniform2(uEnvColor);
|
||||
LocateUniform2(uPrimColor);
|
||||
LocateUniform2(uPrimLod);
|
||||
LocateUniform2(uK4);
|
||||
LocateUniform2(uK5);
|
||||
_updateColorUniforms(location, true);
|
||||
|
||||
// Lights
|
||||
if (config.generalEmulation.enableHWLighting != 0 && GBI.isHWLSupported() && _pCombiner->usesShadeColor()) {
|
||||
// locate lights uniforms
|
||||
char buf[32];
|
||||
for (s32 i = 0; i < 8; ++i) {
|
||||
sprintf(buf, "uLightDirection[%d]", i);
|
||||
location.uLightDirection[i].loc = glGetUniformLocation(program, buf);
|
||||
sprintf(buf, "uLightColor[%d]", i);
|
||||
location.uLightColor[i].loc = glGetUniformLocation(program, buf);
|
||||
}
|
||||
_updateLightUniforms(location, true);
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBlock::_updateColorUniforms(UniformBlockLocation & _location, bool _bForce)
|
||||
{
|
||||
_location.uFogColor.set(&gDP.fogColor.r, _bForce);
|
||||
_location.uCenterColor.set(&gDP.key.center.r, _bForce);
|
||||
_location.uScaleColor.set(&gDP.key.scale.r, _bForce);
|
||||
_location.uBlendColor.set(&gDP.blendColor.r, _bForce);
|
||||
_location.uEnvColor.set(&gDP.envColor.r, _bForce);
|
||||
_location.uPrimColor.set(&gDP.primColor.r, _bForce);
|
||||
_location.uPrimLod.set(gDP.primColor.l, _bForce);
|
||||
_location.uK4.set(gDP.convert.k4*0.0039215689f, _bForce);
|
||||
_location.uK5.set(gDP.convert.k5*0.0039215689f, _bForce);
|
||||
}
|
||||
|
||||
|
||||
void UniformBlock::_updateTextureUniforms(UniformBlockLocation & _location, bool _bUsesT0, bool _bUsesT1, bool _bForce)
|
||||
{
|
||||
int nFB[2] = { 0, 0 };
|
||||
const bool bUsesTile[2] = { _bUsesT0, _bUsesT1 };
|
||||
TextureCache & cache = textureCache();
|
||||
for (u32 t = 0; t < 2; ++t) {
|
||||
if (!bUsesTile[t])
|
||||
continue;
|
||||
|
||||
if (gSP.textureTile[t] != NULL) {
|
||||
if (gSP.textureTile[t]->textureMode == TEXTUREMODE_BGIMAGE || gSP.textureTile[t]->textureMode == TEXTUREMODE_FRAMEBUFFER_BG) {
|
||||
_location.uTexOffset[t].set(0.0f, 0.0f, _bForce);
|
||||
_location.uTexMask[t].set(0.0f, 0.0f, _bForce);
|
||||
}
|
||||
else {
|
||||
_location.uTexOffset[t].set(gSP.textureTile[t]->fuls, gSP.textureTile[t]->fult, _bForce);
|
||||
_location.uTexMask[t].set(
|
||||
gSP.textureTile[t]->masks > 0 ? (float)(1 << gSP.textureTile[t]->masks) : 0.0f,
|
||||
gSP.textureTile[t]->maskt > 0 ? (float)(1 << gSP.textureTile[t]->maskt) : 0.0f,
|
||||
_bForce);
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.current[t] != NULL) {
|
||||
f32 shiftScaleS = 1.0f;
|
||||
f32 shiftScaleT = 1.0f;
|
||||
getTextureShiftScale(t, cache, shiftScaleS, shiftScaleT);
|
||||
_location.uCacheShiftScale[t].set(shiftScaleS, shiftScaleT, _bForce);
|
||||
_location.uCacheScale[t].set(cache.current[t]->scaleS, cache.current[t]->scaleT, _bForce);
|
||||
_location.uCacheOffset[t].set(cache.current[t]->offsetS, cache.current[t]->offsetT, _bForce);
|
||||
_location.uTextureSize[t].set(cache.current[t]->realWidth, cache.current[t]->realHeight, _bForce);
|
||||
nFB[t] = cache.current[t]->frameBufferTexture;
|
||||
}
|
||||
}
|
||||
|
||||
_location.uCacheFrameBuffer.set(nFB[0], nFB[1], _bForce);
|
||||
_location.uTexScale.set(gSP.texture.scales, gSP.texture.scalet, _bForce);
|
||||
}
|
||||
|
||||
void UniformBlock::_updateLightUniforms(UniformBlockLocation & _location, bool _bForce)
|
||||
{
|
||||
for (s32 i = 0; i <= gSP.numLights; ++i) {
|
||||
_location.uLightDirection[i].set(&gSP.lights[i].x, _bForce);
|
||||
_location.uLightColor[i].set(&gSP.lights[i].r, _bForce);
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBlock::updateUniforms(ShaderCombiner * _pCombiner)
|
||||
{
|
||||
UniformBlockLocation & location = m_uniforms.at(_pCombiner->getMux());
|
||||
|
||||
_updateColorUniforms(location, false);
|
||||
|
||||
OGLRender::RENDER_STATE rs = video().getRender().getRenderState();
|
||||
if ((rs == OGLRender::rsTriangle || rs == OGLRender::rsLine) && _pCombiner->usesTexture())
|
||||
_updateTextureUniforms(location, _pCombiner->usesTile(0), _pCombiner->usesTile(1), false);
|
||||
|
||||
if (config.generalEmulation.enableHWLighting != 0 && GBI.isHWLSupported() && _pCombiner->usesShadeColor())
|
||||
_updateLightUniforms(location, false);
|
||||
}
|
||||
|
||||
#endif // GL_UNIFORMBLOCK_SUPPORT
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class UniformBlock;
|
||||
friend class UniformSet;
|
||||
|
||||
struct iUniform {
|
||||
GLint loc;
|
||||
|
@ -116,185 +117,6 @@ private:
|
|||
int m_nInputs;
|
||||
};
|
||||
|
||||
#ifdef GL_UNIFORMBLOCK_SUPPORT
|
||||
class UniformBlock
|
||||
{
|
||||
public:
|
||||
enum TextureUniforms {
|
||||
tuTexScale,
|
||||
tuTexMask,
|
||||
tuTexOffset,
|
||||
tuCacheScale,
|
||||
tuCacheOffset,
|
||||
tuCacheShiftScale,
|
||||
tuCacheFrameBuffer,
|
||||
tuTotal
|
||||
};
|
||||
|
||||
enum ColorUniforms {
|
||||
cuFogColor,
|
||||
cuCenterColor,
|
||||
cuScaleColor,
|
||||
cuBlendColor,
|
||||
cuEnvColor,
|
||||
cuPrimColor,
|
||||
cuPrimLod,
|
||||
cuK4,
|
||||
cuK5,
|
||||
cuTotal
|
||||
};
|
||||
|
||||
enum LightUniforms {
|
||||
luLightDirection,
|
||||
luLightColor,
|
||||
luTotal
|
||||
};
|
||||
|
||||
UniformBlock();
|
||||
~UniformBlock();
|
||||
|
||||
void bindWithShaderCombiner(ShaderCombiner * _pCombiner);
|
||||
void setColorData(ColorUniforms _index, u32 _dataSize, const void * _data);
|
||||
void updateTextureParameters();
|
||||
void updateLightParameters();
|
||||
void updateUniforms(ShaderCombiner * _pCombiner) {}
|
||||
|
||||
private:
|
||||
void _initTextureBuffer(GLuint _program);
|
||||
void _initColorsBuffer(GLuint _program);
|
||||
void _initLightBuffer(GLuint _program);
|
||||
|
||||
bool _isDataChanged(void * _pBuffer, const void * _pData, u32 _dataSize);
|
||||
|
||||
template <u32 _numUniforms, u32 _bindingPoint>
|
||||
struct UniformBlockData
|
||||
{
|
||||
UniformBlockData() : m_buffer(0), m_blockBindingPoint(_bindingPoint)
|
||||
{
|
||||
memset(m_indices, 0, sizeof(m_indices));
|
||||
memset(m_offsets, 0, sizeof(m_offsets));
|
||||
}
|
||||
~UniformBlockData()
|
||||
{
|
||||
if (m_buffer != 0) {
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
m_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GLint initBuffer(GLuint _program, const char * _strBlockName, const char ** _strUniformNames)
|
||||
{
|
||||
GLuint blockIndex = glGetUniformBlockIndex(_program, _strBlockName);
|
||||
if (blockIndex == GL_INVALID_INDEX)
|
||||
return 0;
|
||||
|
||||
GLint blockSize, numUniforms;
|
||||
glGetActiveUniformBlockiv(_program, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
|
||||
glGetActiveUniformBlockiv(_program, blockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numUniforms);
|
||||
|
||||
glGetUniformIndices(_program, numUniforms, _strUniformNames, m_indices);
|
||||
glGetActiveUniformsiv(_program, numUniforms, m_indices, GL_UNIFORM_OFFSET, m_offsets);
|
||||
|
||||
glUniformBlockBinding(_program, blockIndex, m_blockBindingPoint);
|
||||
glGenBuffers(1, &m_buffer);
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
GLuint m_buffer;
|
||||
GLuint m_blockBindingPoint;
|
||||
GLuint m_indices[_numUniforms];
|
||||
GLint m_offsets[_numUniforms];
|
||||
};
|
||||
|
||||
GLuint m_currentBuffer;
|
||||
|
||||
UniformBlockData<tuTotal, 1> m_textureBlock;
|
||||
UniformBlockData<cuTotal, 2> m_colorsBlock;
|
||||
UniformBlockData<luTotal, 3> m_lightBlock;
|
||||
|
||||
std::vector<GLbyte> m_textureBlockData;
|
||||
std::vector<GLbyte> m_colorsBlockData;
|
||||
std::vector<GLbyte> m_lightBlockData;
|
||||
};
|
||||
#else
|
||||
class UniformBlock
|
||||
{
|
||||
public:
|
||||
|
||||
UniformBlock() {}
|
||||
~UniformBlock() {}
|
||||
|
||||
enum ColorUniforms {
|
||||
cuFogColor,
|
||||
cuCenterColor,
|
||||
cuScaleColor,
|
||||
cuBlendColor,
|
||||
cuEnvColor,
|
||||
cuPrimColor,
|
||||
cuPrimLod,
|
||||
cuK4,
|
||||
cuK5,
|
||||
cuTotal
|
||||
};
|
||||
|
||||
void bindWithShaderCombiner(ShaderCombiner * _pCombiner);
|
||||
void setColorData(ColorUniforms _index, u32 _dataSize, const void * _data) {}
|
||||
void updateTextureParameters() {}
|
||||
void updateLightParameters() {}
|
||||
void updateUniforms(ShaderCombiner * _pCombiner);
|
||||
|
||||
private:
|
||||
struct fv3Uniform {
|
||||
GLint loc;
|
||||
float val[3];
|
||||
void set(float * _pVal, bool _force) {
|
||||
const size_t szData = sizeof(float)* 3;
|
||||
if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) {
|
||||
memcpy(val, _pVal, szData);
|
||||
glUniform3fv(loc, 1, _pVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct fv4Uniform {
|
||||
GLint loc;
|
||||
float val[4];
|
||||
void set(float * _pVal, bool _force) {
|
||||
const size_t szData = sizeof(float)* 4;
|
||||
if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) {
|
||||
memcpy(val, _pVal, szData);
|
||||
glUniform4fv(loc, 1, _pVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct UniformBlockLocation
|
||||
{
|
||||
UniformBlockLocation(GLuint _program) : m_program(_program) {}
|
||||
|
||||
GLuint m_program;
|
||||
|
||||
// Texture parameters
|
||||
ShaderCombiner::fv2Uniform uTexScale, uTexMask[2], uTexOffset[2], uCacheScale[2], uCacheOffset[2], uCacheShiftScale[2];
|
||||
ShaderCombiner::iv2Uniform uCacheFrameBuffer, uTextureSize[2];
|
||||
|
||||
// Colors
|
||||
fv4Uniform uFogColor, uCenterColor, uScaleColor, uBlendColor, uEnvColor, uPrimColor;
|
||||
ShaderCombiner::fUniform uPrimLod, uK4, uK5;
|
||||
|
||||
// Lights
|
||||
fv3Uniform uLightDirection[8], uLightColor[8];
|
||||
};
|
||||
|
||||
void _updateColorUniforms(UniformBlockLocation & _location, bool _bForce);
|
||||
void _updateTextureUniforms(UniformBlockLocation & _location, bool _bUsesT0, bool _bUsesT1, bool _bForce);
|
||||
void _updateLightUniforms(UniformBlockLocation & _location, bool _bForce);
|
||||
|
||||
typedef std::map<u64, UniformBlockLocation> Uniforms;
|
||||
Uniforms m_uniforms;
|
||||
};
|
||||
#endif // GL_UNIFORMBLOCK_SUPPORT
|
||||
|
||||
void InitShaderCombiner();
|
||||
void DestroyShaderCombiner();
|
||||
|
||||
|
|
246
src/OGL3X/UniformBlock.cpp
Normal file
246
src/OGL3X/UniformBlock.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
#include "UniformBlock.h"
|
||||
#include "../Config.h"
|
||||
#include "../Textures.h"
|
||||
|
||||
static
|
||||
const char * strTextureUniforms[UniformBlock::tuTotal] = {
|
||||
"uTexScale",
|
||||
"uTexMask",
|
||||
"uTexOffset",
|
||||
"uCacheScale",
|
||||
"uCacheOffset",
|
||||
"uCacheShiftScale",
|
||||
"uCacheFrameBuffer"
|
||||
};
|
||||
|
||||
static
|
||||
const char * strColorUniforms[UniformBlock::cuTotal] = {
|
||||
"uFogColor",
|
||||
"uCenterColor",
|
||||
"uScaleColor",
|
||||
"uBlendColor",
|
||||
"uEnvColor",
|
||||
"uPrimColor",
|
||||
"uPrimLod",
|
||||
"uK4",
|
||||
"uK5"
|
||||
};
|
||||
|
||||
static
|
||||
const char * strLightUniforms[UniformBlock::luTotal] = {
|
||||
"uLightDirection",
|
||||
"uLightColor"
|
||||
};
|
||||
|
||||
UniformBlock::UniformBlock() : m_currentBuffer(0)
|
||||
{
|
||||
}
|
||||
|
||||
UniformBlock::~UniformBlock()
|
||||
{
|
||||
}
|
||||
|
||||
void UniformBlock::_initTextureBuffer(GLuint _program)
|
||||
{
|
||||
const GLint blockSize = m_textureBlock.initBuffer(_program, "TextureBlock", strTextureUniforms);
|
||||
if (blockSize == 0)
|
||||
return;
|
||||
m_textureBlockData.resize(blockSize);
|
||||
GLbyte * pData = m_textureBlockData.data();
|
||||
memset(pData, 0, blockSize);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_textureBlock.m_buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, blockSize, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, m_textureBlock.m_blockBindingPoint, m_textureBlock.m_buffer);
|
||||
updateTextureParameters();
|
||||
}
|
||||
|
||||
void UniformBlock::_initColorsBuffer(GLuint _program)
|
||||
{
|
||||
const GLint blockSize = m_colorsBlock.initBuffer(_program, "ColorsBlock", strColorUniforms);
|
||||
if (blockSize == 0)
|
||||
return;
|
||||
m_colorsBlockData.resize(blockSize);
|
||||
GLbyte * pData = m_colorsBlockData.data();
|
||||
memset(pData, 0, blockSize);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuFogColor], &gDP.fogColor.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuCenterColor], &gDP.key.center.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuScaleColor], &gDP.key.scale.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuEnvColor], &gDP.envColor.r, sizeof(f32)* 4);
|
||||
memcpy(pData + m_colorsBlock.m_offsets[cuPrimColor], &gDP.primColor.r, sizeof(f32)* 4);
|
||||
*(f32*)(pData + m_colorsBlock.m_offsets[cuPrimLod]) = gDP.primColor.l;
|
||||
*(f32*)(pData + m_colorsBlock.m_offsets[cuK4]) = gDP.convert.k4*0.0039215689f;
|
||||
*(f32*)(pData + m_colorsBlock.m_offsets[cuK5]) = gDP.convert.k5*0.0039215689f;
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_colorsBlock.m_buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, blockSize, pData, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, m_colorsBlock.m_blockBindingPoint, m_colorsBlock.m_buffer);
|
||||
m_currentBuffer = m_colorsBlock.m_buffer;
|
||||
}
|
||||
|
||||
void UniformBlock::_initLightBuffer(GLuint _program)
|
||||
{
|
||||
const GLint blockSize = m_lightBlock.initBuffer(_program, "LightBlock", strLightUniforms);
|
||||
if (blockSize == 0)
|
||||
return;
|
||||
m_lightBlockData.resize(blockSize);
|
||||
GLbyte * pData = m_lightBlockData.data();
|
||||
memset(pData, 0, blockSize);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_lightBlock.m_buffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, blockSize, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, m_lightBlock.m_blockBindingPoint, m_lightBlock.m_buffer);
|
||||
updateLightParameters();
|
||||
}
|
||||
|
||||
bool UniformBlock::_isDataChanged(void * _pBuffer, const void * _pData, u32 _dataSize)
|
||||
{
|
||||
u32 * pSrc = (u32*)_pData;
|
||||
u32 * pDst = (u32*)_pBuffer;
|
||||
u32 cnt = _dataSize / 4;
|
||||
for (u32 i = 0; i < cnt; ++i) {
|
||||
if (pSrc[i] != pDst[i]) {
|
||||
memcpy(_pBuffer, _pData, _dataSize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UniformBlock::bindWithShaderCombiner(ShaderCombiner * _pCombiner)
|
||||
{
|
||||
const GLuint program = _pCombiner->m_program;
|
||||
if (_pCombiner->usesTexture()) {
|
||||
if (m_textureBlock.m_buffer == 0)
|
||||
_initTextureBuffer(program);
|
||||
else {
|
||||
const GLint blockIndex = glGetUniformBlockIndex(program, "TextureBlock");
|
||||
if (blockIndex != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(program, blockIndex, m_textureBlock.m_blockBindingPoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_colorsBlock.m_buffer == 0)
|
||||
_initColorsBuffer(program);
|
||||
else {
|
||||
const GLint blockIndex = glGetUniformBlockIndex(program, "ColorsBlock");
|
||||
if (blockIndex != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(program, blockIndex, m_colorsBlock.m_blockBindingPoint);
|
||||
}
|
||||
|
||||
if (_pCombiner->usesShadeColor() && config.generalEmulation.enableHWLighting != 0) {
|
||||
if (m_lightBlock.m_buffer == 0)
|
||||
_initLightBuffer(program);
|
||||
else {
|
||||
const GLint blockIndex = glGetUniformBlockIndex(program, "LightBlock");
|
||||
if (blockIndex != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(program, blockIndex, m_lightBlock.m_blockBindingPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBlock::setColorData(ColorUniforms _index, u32 _dataSize, const void * _data)
|
||||
{
|
||||
if (m_colorsBlock.m_buffer == 0)
|
||||
return;
|
||||
if (!_isDataChanged(m_colorsBlockData.data() + m_colorsBlock.m_offsets[_index], _data, _dataSize))
|
||||
return;
|
||||
|
||||
if (m_currentBuffer != m_colorsBlock.m_buffer) {
|
||||
m_currentBuffer = m_colorsBlock.m_buffer;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_colorsBlock.m_buffer);
|
||||
}
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, m_colorsBlock.m_offsets[_index], _dataSize, _data);
|
||||
}
|
||||
|
||||
void UniformBlock::updateTextureParameters()
|
||||
{
|
||||
if (m_textureBlock.m_buffer == 0)
|
||||
return;
|
||||
|
||||
GLbyte * pData = m_textureBlockData.data();
|
||||
f32 texScale[4] = { gSP.texture.scales, gSP.texture.scalet, 0, 0 };
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuTexScale], texScale, m_textureBlock.m_offsets[tuTexMask] - m_textureBlock.m_offsets[tuTexScale]);
|
||||
|
||||
f32 texOffset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
f32 texMask[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
if (gSP.textureTile[0] != NULL) {
|
||||
if (gSP.textureTile[0]->textureMode != TEXTUREMODE_BGIMAGE && gSP.textureTile[0]->textureMode != TEXTUREMODE_FRAMEBUFFER_BG) {
|
||||
texOffset[0] = gSP.textureTile[0]->fuls;
|
||||
texOffset[1] = gSP.textureTile[0]->fult;
|
||||
texMask[0] = gSP.textureTile[0]->masks > 0 ? (float)(1 << gSP.textureTile[0]->masks) : 0.0f;
|
||||
texMask[1] = gSP.textureTile[0]->maskt > 0 ? (float)(1 << gSP.textureTile[0]->maskt) : 0.0f;
|
||||
}
|
||||
}
|
||||
if (gSP.textureTile[1] != 0) {
|
||||
texOffset[4] = gSP.textureTile[1]->fuls;
|
||||
texOffset[5] = gSP.textureTile[1]->fult;
|
||||
texMask[4] = gSP.textureTile[1]->masks > 0 ? (float)(1 << gSP.textureTile[1]->masks) : 0.0f;
|
||||
texMask[5] = gSP.textureTile[1]->maskt > 0 ? (float)(1 << gSP.textureTile[1]->maskt) : 0.0f;
|
||||
}
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuTexMask], texMask, m_textureBlock.m_offsets[tuTexOffset] - m_textureBlock.m_offsets[tuTexMask]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuTexOffset], texOffset, m_textureBlock.m_offsets[tuCacheScale] - m_textureBlock.m_offsets[tuTexOffset]);
|
||||
|
||||
f32 texCacheScale[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
f32 texCacheOffset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
f32 texCacheShiftScale[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
GLint texCacheFrameBuffer[4] = { 0, 0, 0, 0 };
|
||||
TextureCache & cache = textureCache();
|
||||
if (cache.current[0]) {
|
||||
texCacheScale[0] = cache.current[0]->scaleS;
|
||||
texCacheScale[1] = cache.current[0]->scaleT;
|
||||
texCacheOffset[0] = cache.current[0]->offsetS;
|
||||
texCacheOffset[1] = cache.current[0]->offsetT;
|
||||
|
||||
f32 shiftScaleS = 1.0f;
|
||||
f32 shiftScaleT = 1.0f;
|
||||
getTextureShiftScale(0, cache, shiftScaleS, shiftScaleT);
|
||||
texCacheShiftScale[0] = shiftScaleS;
|
||||
texCacheShiftScale[1] = shiftScaleT;
|
||||
texCacheFrameBuffer[0] = cache.current[0]->frameBufferTexture;
|
||||
}
|
||||
if (cache.current[1]) {
|
||||
texCacheScale[4] = cache.current[1]->scaleS;
|
||||
texCacheScale[5] = cache.current[1]->scaleT;
|
||||
texCacheOffset[4] = cache.current[1]->offsetS;
|
||||
texCacheOffset[5] = cache.current[1]->offsetT;
|
||||
|
||||
f32 shiftScaleS = 1.0f;
|
||||
f32 shiftScaleT = 1.0f;
|
||||
getTextureShiftScale(1, cache, shiftScaleS, shiftScaleT);
|
||||
texCacheShiftScale[4] = shiftScaleS;
|
||||
texCacheShiftScale[5] = shiftScaleT;
|
||||
texCacheFrameBuffer[1] = cache.current[1]->frameBufferTexture;
|
||||
}
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheScale], texCacheScale, m_textureBlock.m_offsets[tuCacheOffset] - m_textureBlock.m_offsets[tuCacheScale]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheOffset], texCacheOffset, m_textureBlock.m_offsets[tuCacheShiftScale] - m_textureBlock.m_offsets[tuCacheOffset]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheShiftScale], texCacheShiftScale, m_textureBlock.m_offsets[tuCacheFrameBuffer] - m_textureBlock.m_offsets[tuCacheShiftScale]);
|
||||
memcpy(pData + m_textureBlock.m_offsets[tuCacheFrameBuffer], texCacheFrameBuffer, m_textureBlockData.size() - m_textureBlock.m_offsets[tuCacheFrameBuffer]);
|
||||
|
||||
if (m_currentBuffer != m_textureBlock.m_buffer) {
|
||||
m_currentBuffer = m_textureBlock.m_buffer;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_textureBlock.m_buffer);
|
||||
}
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, m_textureBlock.m_offsets[tuTexScale], m_textureBlockData.size(), pData);
|
||||
}
|
||||
|
||||
void UniformBlock::updateLightParameters()
|
||||
{
|
||||
if (m_lightBlock.m_buffer == 0)
|
||||
return;
|
||||
|
||||
GLbyte * pData = m_lightBlockData.data();
|
||||
const u32 arraySize = m_lightBlock.m_offsets[luLightColor] / 8;
|
||||
for (s32 i = 0; i <= gSP.numLights; ++i) {
|
||||
memcpy(pData + m_lightBlock.m_offsets[luLightDirection] + arraySize*i, &gSP.lights[i].x, arraySize);
|
||||
memcpy(pData + m_lightBlock.m_offsets[luLightColor] + arraySize*i, &gSP.lights[i].r, arraySize);
|
||||
}
|
||||
if (m_currentBuffer != m_lightBlock.m_buffer) {
|
||||
m_currentBuffer = m_lightBlock.m_buffer;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, m_lightBlock.m_buffer);
|
||||
}
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, m_lightBlock.m_offsets[luLightDirection], m_lightBlockData.size(), pData);
|
||||
}
|
||||
|
||||
UniformCollection * createUniformCollection()
|
||||
{
|
||||
return new UniformBlock();
|
||||
}
|
76
src/OGL3X/UniformBlock.h
Normal file
76
src/OGL3X/UniformBlock.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
#ifndef UNIFORM_BLOCK_H
|
||||
#define UNIFORM_BLOCK_H
|
||||
|
||||
#include "../UniformCollection.h"
|
||||
|
||||
class UniformBlock : public UniformCollection
|
||||
{
|
||||
public:
|
||||
UniformBlock();
|
||||
~UniformBlock();
|
||||
|
||||
virtual void bindWithShaderCombiner(ShaderCombiner * _pCombiner);
|
||||
virtual void setColorData(ColorUniforms _index, u32 _dataSize, const void * _data);
|
||||
virtual void updateTextureParameters();
|
||||
virtual void updateLightParameters();
|
||||
virtual void updateUniforms(ShaderCombiner * _pCombiner) {}
|
||||
|
||||
private:
|
||||
void _initTextureBuffer(GLuint _program);
|
||||
void _initColorsBuffer(GLuint _program);
|
||||
void _initLightBuffer(GLuint _program);
|
||||
|
||||
bool _isDataChanged(void * _pBuffer, const void * _pData, u32 _dataSize);
|
||||
|
||||
template <u32 _numUniforms, u32 _bindingPoint>
|
||||
struct UniformBlockData
|
||||
{
|
||||
UniformBlockData() : m_buffer(0), m_blockBindingPoint(_bindingPoint)
|
||||
{
|
||||
memset(m_indices, 0, sizeof(m_indices));
|
||||
memset(m_offsets, 0, sizeof(m_offsets));
|
||||
}
|
||||
~UniformBlockData()
|
||||
{
|
||||
if (m_buffer != 0) {
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
m_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GLint initBuffer(GLuint _program, const char * _strBlockName, const char ** _strUniformNames)
|
||||
{
|
||||
GLuint blockIndex = glGetUniformBlockIndex(_program, _strBlockName);
|
||||
if (blockIndex == GL_INVALID_INDEX)
|
||||
return 0;
|
||||
|
||||
GLint blockSize, numUniforms;
|
||||
glGetActiveUniformBlockiv(_program, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
|
||||
glGetActiveUniformBlockiv(_program, blockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numUniforms);
|
||||
|
||||
glGetUniformIndices(_program, numUniforms, _strUniformNames, m_indices);
|
||||
glGetActiveUniformsiv(_program, numUniforms, m_indices, GL_UNIFORM_OFFSET, m_offsets);
|
||||
|
||||
glUniformBlockBinding(_program, blockIndex, m_blockBindingPoint);
|
||||
glGenBuffers(1, &m_buffer);
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
GLuint m_buffer;
|
||||
GLuint m_blockBindingPoint;
|
||||
GLuint m_indices[_numUniforms];
|
||||
GLint m_offsets[_numUniforms];
|
||||
};
|
||||
|
||||
GLuint m_currentBuffer;
|
||||
|
||||
UniformBlockData<tuTotal, 1> m_textureBlock;
|
||||
UniformBlockData<cuTotal, 2> m_colorsBlock;
|
||||
UniformBlockData<luTotal, 3> m_lightBlock;
|
||||
|
||||
std::vector<GLbyte> m_textureBlockData;
|
||||
std::vector<GLbyte> m_colorsBlockData;
|
||||
std::vector<GLbyte> m_lightBlockData;
|
||||
};
|
||||
|
||||
#endif // UNIFORM_BLOCK_H
|
47
src/UniformCollection.h
Normal file
47
src/UniformCollection.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef UNIFORM_COLLECTION_H
|
||||
#define UNIFORM_COLLECTION_H
|
||||
|
||||
#include "GLSLCombiner.h"
|
||||
|
||||
class UniformCollection {
|
||||
public:
|
||||
enum TextureUniforms {
|
||||
tuTexScale,
|
||||
tuTexMask,
|
||||
tuTexOffset,
|
||||
tuCacheScale,
|
||||
tuCacheOffset,
|
||||
tuCacheShiftScale,
|
||||
tuCacheFrameBuffer,
|
||||
tuTotal
|
||||
};
|
||||
|
||||
enum ColorUniforms {
|
||||
cuFogColor,
|
||||
cuCenterColor,
|
||||
cuScaleColor,
|
||||
cuBlendColor,
|
||||
cuEnvColor,
|
||||
cuPrimColor,
|
||||
cuPrimLod,
|
||||
cuK4,
|
||||
cuK5,
|
||||
cuTotal
|
||||
};
|
||||
|
||||
enum LightUniforms {
|
||||
luLightDirection,
|
||||
luLightColor,
|
||||
luTotal
|
||||
};
|
||||
|
||||
virtual void bindWithShaderCombiner(ShaderCombiner * _pCombiner) = 0;
|
||||
virtual void setColorData(ColorUniforms _index, u32 _dataSize, const void * _data) = 0;
|
||||
virtual void updateTextureParameters() = 0;
|
||||
virtual void updateLightParameters() = 0;
|
||||
virtual void updateUniforms(ShaderCombiner * _pCombiner) = 0;
|
||||
};
|
||||
|
||||
UniformCollection * createUniformCollection();
|
||||
|
||||
#endif // UNIFORM_COLLECTION_H
|
Loading…
Reference in New Issue
Block a user