mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-25 23:25:40 +00:00
Composite the alpha layers at the end of rendering. To do this we need to mask the alpha pixels with the opaque pixels from the next priority layer. Fixes some overlapping shadows in vf3tb that have different priority layers. I assume that was a game bug, but it works on the real h/w.
This commit is contained in:
parent
c171356f7d
commit
8094c2e2b7
|
@ -98,7 +98,7 @@ struct FVertex : Vertex // full vertex including face attributes
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Layer { colour, trans1, trans2, all, none };
|
enum class Layer { colour, trans1, trans2, trans12 /*both 1&2*/, all, none };
|
||||||
|
|
||||||
struct Mesh
|
struct Mesh
|
||||||
{
|
{
|
||||||
|
|
|
@ -226,8 +226,6 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
return hasOverlay;
|
return hasOverlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +266,8 @@ void CNew3D::SetRenderStates()
|
||||||
glEnable (GL_DEPTH_TEST);
|
glEnable (GL_DEPTH_TEST);
|
||||||
glDepthMask (GL_TRUE);
|
glDepthMask (GL_TRUE);
|
||||||
glActiveTexture (GL_TEXTURE0);
|
glActiveTexture (GL_TEXTURE0);
|
||||||
glDisable (GL_CULL_FACE); // we'll emulate this in the shader
|
glDisable (GL_CULL_FACE); // we'll emulate this in the shader
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
|
||||||
glStencilFunc (GL_EQUAL, 0, 0xFF); // basically stencil test passes if the value is zero
|
glStencilFunc (GL_EQUAL, 0, 0xFF); // basically stencil test passes if the value is zero
|
||||||
glStencilOp (GL_KEEP, GL_INCR, GL_INCR); // if the stencil test passes, we incriment the value
|
glStencilOp (GL_KEEP, GL_INCR, GL_INCR); // if the stencil test passes, we incriment the value
|
||||||
|
@ -308,7 +307,6 @@ void CNew3D::RenderFrame(void)
|
||||||
m_nodeAttribs.Reset();
|
m_nodeAttribs.Reset();
|
||||||
|
|
||||||
RenderViewport(0x800000); // build model structure
|
RenderViewport(0x800000); // build model structure
|
||||||
|
|
||||||
DrawScrollFog(); // fog layer if applicable must be drawn here
|
DrawScrollFog(); // fog layer if applicable must be drawn here
|
||||||
|
|
||||||
m_vbo.Bind(true);
|
m_vbo.Bind(true);
|
||||||
|
@ -335,6 +333,9 @@ void CNew3D::RenderFrame(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_r3dFrameBuffers.SetFBO(Layer::trans12);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT); // wipe both trans layers
|
||||||
|
|
||||||
for (int pri = 0; pri <= 3; pri++) {
|
for (int pri = 0; pri <= 3; pri++) {
|
||||||
|
|
||||||
//==============
|
//==============
|
||||||
|
@ -347,8 +348,9 @@ void CNew3D::RenderFrame(void)
|
||||||
|
|
||||||
bool renderOverlay = (i == 1);
|
bool renderOverlay = (i == 1);
|
||||||
|
|
||||||
m_r3dFrameBuffers.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
m_r3dFrameBuffers.SetFBO(Layer::colour);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
SetRenderStates();
|
SetRenderStates();
|
||||||
|
|
||||||
m_r3dShader.DiscardAlpha(true); // discard all translucent pixels in opaque pass
|
m_r3dShader.DiscardAlpha(true); // discard all translucent pixels in opaque pass
|
||||||
|
@ -358,26 +360,32 @@ void CNew3D::RenderFrame(void)
|
||||||
if (!renderOverlay && ProcessLos(pri)) {
|
if (!renderOverlay && ProcessLos(pri)) {
|
||||||
ProcessLos(pri);
|
ProcessLos(pri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DisableRenderStates();
|
||||||
|
|
||||||
|
m_r3dFrameBuffers.DrawOverTransLayers(); // mask trans layer with opaque pixels
|
||||||
|
m_r3dFrameBuffers.CompositeBaseLayer(); // copy opaque pixels to back buffer
|
||||||
|
|
||||||
|
SetRenderStates();
|
||||||
|
|
||||||
glDepthFunc(GL_LESS); // alpha polys seem to use gl_less (ocean hunter)
|
glDepthFunc(GL_LESS); // alpha polys seem to use gl_less (ocean hunter)
|
||||||
|
|
||||||
m_r3dShader.DiscardAlpha(false); // render only translucent pixels
|
m_r3dShader.DiscardAlpha (false); // render only translucent pixels
|
||||||
m_r3dFrameBuffers.StoreDepth(); // save depth buffer for 1st trans pass
|
m_r3dFrameBuffers.StoreDepth (); // save depth buffer for 1st trans pass
|
||||||
m_r3dFrameBuffers.SetFBO(Layer::trans1);
|
m_r3dFrameBuffers.SetFBO (Layer::trans1);
|
||||||
RenderScene(pri, renderOverlay, Layer::trans1);
|
RenderScene (pri, renderOverlay, Layer::trans1);
|
||||||
|
|
||||||
m_r3dFrameBuffers.RestoreDepth(); // restore depth buffer, trans layers don't seem to depth test against each other
|
m_r3dFrameBuffers.RestoreDepth (); // restore depth buffer, trans layers don't seem to depth test against each other
|
||||||
m_r3dFrameBuffers.SetFBO(Layer::trans2);
|
m_r3dFrameBuffers.SetFBO (Layer::trans2);
|
||||||
RenderScene(pri, renderOverlay, Layer::trans2);
|
RenderScene (pri, renderOverlay, Layer::trans2);
|
||||||
|
|
||||||
DisableRenderStates();
|
DisableRenderStates();
|
||||||
m_r3dFrameBuffers.Draw(); // draw current layer to back buffer
|
|
||||||
|
|
||||||
if (!hasOverlay) break; // no high priority polys
|
if (!hasOverlay) break; // no high priority polys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_r3dFrameBuffers.DisableFBO(); // draw to back buffer normally
|
m_r3dFrameBuffers.CompositeAlphaLayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNew3D::BeginFrame(void)
|
void CNew3D::BeginFrame(void)
|
||||||
|
|
|
@ -22,6 +22,7 @@ R3DFrameBuffers::R3DFrameBuffers()
|
||||||
|
|
||||||
AllocShaderTrans();
|
AllocShaderTrans();
|
||||||
AllocShaderBase();
|
AllocShaderBase();
|
||||||
|
AllocShaderWipe();
|
||||||
|
|
||||||
FBVertex vertices[4];
|
FBVertex vertices[4];
|
||||||
vertices[0].Set(-1,-1, 0, 0);
|
vertices[0].Set(-1,-1, 0, 0);
|
||||||
|
@ -36,6 +37,8 @@ R3DFrameBuffers::~R3DFrameBuffers()
|
||||||
{
|
{
|
||||||
DestroyFBO();
|
DestroyFBO();
|
||||||
m_shaderTrans.UnloadShaders();
|
m_shaderTrans.UnloadShaders();
|
||||||
|
m_shaderBase.UnloadShaders();
|
||||||
|
m_shaderWipe.UnloadShaders();
|
||||||
m_vbo.Destroy();
|
m_vbo.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,30 +161,40 @@ void R3DFrameBuffers::SetFBO(Layer layer)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID);
|
switch (layer)
|
||||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 + (GLenum)layer };
|
{
|
||||||
glDrawBuffers(countof(buffers), buffers);
|
case Layer::colour:
|
||||||
m_lastLayer = layer;
|
case Layer::trans1:
|
||||||
}
|
case Layer::trans2:
|
||||||
|
{
|
||||||
void R3DFrameBuffers::DisableFBO()
|
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID);
|
||||||
{
|
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 + (GLenum)layer };
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glDrawBuffers(countof(buffers), buffers);
|
||||||
glDrawBuffer(GL_BACK);
|
break;
|
||||||
m_lastLayer = Layer::none;
|
}
|
||||||
}
|
case Layer::trans12:
|
||||||
|
{
|
||||||
void R3DFrameBuffers::Clear(GLbitfield mask)
|
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID);
|
||||||
{
|
GLenum buffers[] = { GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
|
||||||
if (m_lastLayer != Layer::all) {
|
glDrawBuffers(countof(buffers), buffers);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID); // bind frame buffer
|
break;
|
||||||
|
}
|
||||||
|
case Layer::all:
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID);
|
||||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
|
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
|
||||||
glDrawBuffers(countof(buffers), buffers);
|
glDrawBuffers(countof(buffers), buffers);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Layer::none:
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glDrawBuffer(GL_BACK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glViewport(0, 0, m_width, m_height);
|
m_lastLayer = layer;
|
||||||
glClear(mask);
|
|
||||||
m_lastLayer = Layer::all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void R3DFrameBuffers::AllocShaderBase()
|
void R3DFrameBuffers::AllocShaderBase()
|
||||||
|
@ -276,12 +289,59 @@ void R3DFrameBuffers::AllocShaderTrans()
|
||||||
m_shaderTrans.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
|
m_shaderTrans.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void R3DFrameBuffers::AllocShaderWipe()
|
||||||
|
{
|
||||||
|
const char *vertexShader = R"glsl(
|
||||||
|
|
||||||
|
// inputs
|
||||||
|
attribute vec3 inVertex;
|
||||||
|
attribute vec2 inTexCoord;
|
||||||
|
|
||||||
|
// outputs
|
||||||
|
varying vec2 fsTexCoord;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
fsTexCoord = inTexCoord;
|
||||||
|
gl_Position = vec4(inVertex,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
const char *fragmentShader = R"glsl(
|
||||||
|
|
||||||
|
uniform sampler2D texColor; // base colour layer
|
||||||
|
varying vec2 fsTexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 colBase = texture2D( texColor, fsTexCoord);
|
||||||
|
|
||||||
|
if(colBase == 0.0) {
|
||||||
|
discard; // no colour pixels have been written
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragData[0] = vec4(0.0); // wipe these parts of the alpha buffer
|
||||||
|
gl_FragData[1] = vec4(0.0); // since they have been overwritten by the next priority layer
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
m_shaderWipe.LoadShaders(vertexShader, fragmentShader);
|
||||||
|
|
||||||
|
m_shaderWipe.uniformLoc[0] = m_shaderTrans.GetUniformLocation("texColor");
|
||||||
|
|
||||||
|
m_shaderWipe.attribLoc[0] = m_shaderTrans.GetAttributeLocation("inVertex");
|
||||||
|
m_shaderWipe.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
|
||||||
|
}
|
||||||
|
|
||||||
void R3DFrameBuffers::Draw()
|
void R3DFrameBuffers::Draw()
|
||||||
{
|
{
|
||||||
DisableFBO (); // make sure to draw on the back buffer
|
SetFBO (Layer::none); // make sure to draw on the back buffer
|
||||||
glViewport (0, 0, m_width, m_height); // cover the entire screen
|
glViewport (0, 0, m_width, m_height); // cover the entire screen
|
||||||
glDisable (GL_DEPTH_TEST); // disable depth testing / writing
|
glDisable (GL_DEPTH_TEST); // disable depth testing / writing
|
||||||
glDisable (GL_CULL_FACE);
|
glDisable (GL_CULL_FACE);
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
|
||||||
for (int i = 0; i < countof(m_texIDs); i++) { // bind our textures to correct texture units
|
for (int i = 0; i < countof(m_texIDs); i++) { // bind our textures to correct texture units
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
@ -302,6 +362,84 @@ void R3DFrameBuffers::Draw()
|
||||||
m_vbo.Bind (false);
|
m_vbo.Bind (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void R3DFrameBuffers::CompositeBaseLayer()
|
||||||
|
{
|
||||||
|
SetFBO(Layer::none); // make sure to draw on the back buffer
|
||||||
|
glViewport(0, 0, m_width, m_height); // cover the entire screen
|
||||||
|
glDisable(GL_DEPTH_TEST); // disable depth testing / writing
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
for (int i = 0; i < countof(m_texIDs); i++) { // bind our textures to correct texture units
|
||||||
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_texIDs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
m_vbo.Bind(true);
|
||||||
|
|
||||||
|
DrawBaseLayer();
|
||||||
|
|
||||||
|
m_vbo.Bind(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void R3DFrameBuffers::CompositeAlphaLayer()
|
||||||
|
{
|
||||||
|
SetFBO(Layer::none); // make sure to draw on the back buffer
|
||||||
|
glViewport(0, 0, m_width, m_height); // cover the entire screen
|
||||||
|
glDisable(GL_DEPTH_TEST); // disable depth testing / writing
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
for (int i = 0; i < countof(m_texIDs); i++) { // bind our textures to correct texture units
|
||||||
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_texIDs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
m_vbo.Bind(true);
|
||||||
|
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
DrawAlphaLayer();
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
m_vbo.Bind(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void R3DFrameBuffers::DrawOverTransLayers()
|
||||||
|
{
|
||||||
|
SetFBO(Layer::trans12); // need to write to both layers
|
||||||
|
|
||||||
|
glViewport (0, 0, m_width, m_height); // cover the entire screen
|
||||||
|
glDisable (GL_DEPTH_TEST); // disable depth testing / writing
|
||||||
|
glDisable (GL_CULL_FACE);
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
|
||||||
|
glActiveTexture (GL_TEXTURE0);
|
||||||
|
glBindTexture (GL_TEXTURE_2D, m_texIDs[0]);
|
||||||
|
|
||||||
|
m_vbo.Bind(true);
|
||||||
|
|
||||||
|
m_shaderWipe.EnableShader();
|
||||||
|
glUniform1i(m_shaderWipe.uniformLoc[0], 0);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
glVertexAttribPointer(m_shaderWipe.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
|
||||||
|
glVertexAttribPointer(m_shaderWipe.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
|
||||||
|
m_shaderWipe.DisableShader();
|
||||||
|
|
||||||
|
m_vbo.Bind(false);
|
||||||
|
}
|
||||||
|
|
||||||
void R3DFrameBuffers::DrawBaseLayer()
|
void R3DFrameBuffers::DrawBaseLayer()
|
||||||
{
|
{
|
||||||
m_shaderBase.EnableShader();
|
m_shaderBase.EnableShader();
|
||||||
|
|
|
@ -14,15 +14,16 @@ public:
|
||||||
R3DFrameBuffers();
|
R3DFrameBuffers();
|
||||||
~R3DFrameBuffers();
|
~R3DFrameBuffers();
|
||||||
|
|
||||||
void Draw(); // draw and composite the transparent layers
|
void Draw(); // draw and composite the transparent layers
|
||||||
|
void CompositeBaseLayer();
|
||||||
|
void CompositeAlphaLayer();
|
||||||
|
void DrawOverTransLayers(); // opaque pixels in next priority layer need to wipe trans pixels
|
||||||
|
|
||||||
bool CreateFBO(int width, int height);
|
bool CreateFBO(int width, int height);
|
||||||
void DestroyFBO();
|
void DestroyFBO();
|
||||||
|
|
||||||
void BindTexture(Layer layer);
|
void BindTexture(Layer layer);
|
||||||
void SetFBO(Layer layer);
|
void SetFBO(Layer layer);
|
||||||
void DisableFBO();
|
|
||||||
void Clear(GLbitfield mask);
|
|
||||||
void StoreDepth();
|
void StoreDepth();
|
||||||
void RestoreDepth();
|
void RestoreDepth();
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ private:
|
||||||
GLuint CreateTexture(int width, int height);
|
GLuint CreateTexture(int width, int height);
|
||||||
void AllocShaderTrans();
|
void AllocShaderTrans();
|
||||||
void AllocShaderBase();
|
void AllocShaderBase();
|
||||||
|
void AllocShaderWipe();
|
||||||
|
|
||||||
void DrawBaseLayer();
|
void DrawBaseLayer();
|
||||||
void DrawAlphaLayer();
|
void DrawAlphaLayer();
|
||||||
|
@ -63,6 +65,7 @@ private:
|
||||||
// shaders
|
// shaders
|
||||||
GLSLShader m_shaderBase;
|
GLSLShader m_shaderBase;
|
||||||
GLSLShader m_shaderTrans;
|
GLSLShader m_shaderTrans;
|
||||||
|
GLSLShader m_shaderWipe;
|
||||||
|
|
||||||
// vertices for fbo
|
// vertices for fbo
|
||||||
VBO m_vbo;
|
VBO m_vbo;
|
||||||
|
|
|
@ -127,9 +127,14 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint R3DShader::GetVertexAttribPos(const char* attrib)
|
GLint R3DShader::GetVertexAttribPos(const std::string& attrib)
|
||||||
{
|
{
|
||||||
return glGetAttribLocation(m_shaderProgram, attrib); // probably should cache this but only called 1x per frame anyway
|
if (m_vertexLocCache.count(attrib)==0) {
|
||||||
|
auto pos = glGetAttribLocation(m_shaderProgram, attrib.c_str());
|
||||||
|
m_vertexLocCache[attrib] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_vertexLocCache[attrib];
|
||||||
}
|
}
|
||||||
|
|
||||||
void R3DShader::SetShader(bool enable)
|
void R3DShader::SetShader(bool enable)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "Pkgs/glew.h"
|
#include "Pkgs/glew.h"
|
||||||
#include "Util/NewConfig.h"
|
#include "Util/NewConfig.h"
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace New3D {
|
namespace New3D {
|
||||||
|
|
||||||
|
@ -18,7 +20,7 @@ public:
|
||||||
void SetViewportUniforms (const Viewport *vp);
|
void SetViewportUniforms (const Viewport *vp);
|
||||||
void Start ();
|
void Start ();
|
||||||
void SetShader (bool enable = true);
|
void SetShader (bool enable = true);
|
||||||
GLint GetVertexAttribPos (const char* attrib);
|
GLint GetVertexAttribPos (const std::string& attrib);
|
||||||
void DiscardAlpha (bool discard); // use to remove alpha from texture alpha only polys for 1st pass
|
void DiscardAlpha (bool discard); // use to remove alpha from texture alpha only polys for 1st pass
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -103,6 +105,10 @@ private:
|
||||||
// global uniforms
|
// global uniforms
|
||||||
GLint m_locHardwareStep;
|
GLint m_locHardwareStep;
|
||||||
GLint m_locDiscardAlpha;
|
GLint m_locDiscardAlpha;
|
||||||
|
|
||||||
|
// vertex attribute position cache
|
||||||
|
std::map<std::string, GLint> m_vertexLocCache;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue