Draw transparent polys to separate layers and composite at the end. This solves a tonne of transparency errors we had been battling with for a long time. The model3 is strange in the fact it only supports a max of two translucent overlapped polys. They are not blended into the frame normally. Doing this means the topmost translucent polys only are visible in the scene, the equivalent of doing a depth pass first, but without the added cost.

This commit is contained in:
Ian Curtis 2018-06-16 21:31:29 +00:00
parent 7497e3f1a6
commit c7ffd0a808
11 changed files with 738 additions and 111 deletions

View file

@ -0,0 +1,112 @@
#include "GLSLShader.h"
#include <stdio.h>
GLSLShader::GLSLShader() {
m_vShader = 0;
m_fShader = 0;
m_program = 0;
for (auto &i : uniformLoc) {
i = 0;
}
for (auto &i : attribLoc) {
i = 0;
}
}
GLSLShader::~GLSLShader() {
UnloadShaders();
}
bool GLSLShader::LoadShaders(const char *vertexShader, const char *fragmentShader) {
m_program = glCreateProgram();
m_vShader = glCreateShader(GL_VERTEX_SHADER);
m_fShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(m_vShader, 1, &vertexShader, NULL);
glShaderSource(m_fShader, 1, &fragmentShader, NULL);
glCompileShader(m_vShader);
glCompileShader(m_fShader);
glAttachShader(m_program, m_vShader);
glAttachShader(m_program, m_fShader);
glLinkProgram(m_program);
PrintShaderInfoLog(m_vShader);
PrintShaderInfoLog(m_fShader);
PrintProgramInfoLog(m_program);
return true;
}
void GLSLShader::UnloadShaders()
{
if (m_program) {
glDeleteShader(m_vShader);
glDeleteShader(m_fShader);
glDeleteProgram(m_program);
}
m_vShader = 0;
m_fShader = 0;
m_program = 0;
}
void GLSLShader::EnableShader() {
glUseProgram(m_program);
}
void GLSLShader::DisableShader() {
glUseProgram(0);
}
void GLSLShader::PrintShaderInfoLog(GLuint obj) {
int infologLength = 0;
int charsWritten = 0;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
if (infologLength > 0) {
char *infoLog = new char[infologLength];
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n", infoLog);
delete[] infoLog;
}
}
void GLSLShader::PrintProgramInfoLog(GLuint obj) {
int infologLength = 0;
int charsWritten = 0;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
if (infologLength > 0) {
char *infoLog = new char[infologLength];
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n", infoLog);
delete[] infoLog;
}
}
int GLSLShader::GetUniformLocation(const char *str)
{
return glGetUniformLocation(m_program, str);
}
int GLSLShader::GetAttributeLocation(const char *str)
{
return glGetAttribLocation(m_program, str);
}

View file

@ -0,0 +1,34 @@
#ifndef _GLSLSHADER_H_
#define _GLSLSHADER_H_
#include "Pkgs/glew.h"
class GLSLShader {
public:
GLSLShader();
~GLSLShader();
bool LoadShaders(const char *vertexShader, const char *fragmentShader);
void UnloadShaders();
void EnableShader();
void DisableShader();
int GetUniformLocation(const char *str);
int GetAttributeLocation(const char *str);
int uniformLoc[64];
int attribLoc[16];
private:
void PrintShaderInfoLog(GLuint obj);
void PrintProgramInfoLog(GLuint obj);
GLuint m_program;
GLuint m_vShader;
GLuint m_fShader;
};
#endif

View file

@ -86,20 +86,32 @@ struct Poly // our polys are always 3 triangles, unlike the real h/w
FVertex p3;
};
enum class Layer { colour, trans1, trans2, all, none };
struct Mesh
{
//helper funcs
bool Render(bool alpha)
bool Render(Layer layer)
{
if (alpha) {
if (!textureAlpha && !polyAlpha) {
return false;
}
}
else {
switch (layer)
{
case Layer::colour:
if (polyAlpha) {
return false;
}
break;
case Layer::trans1:
if (!textureAlpha && !polyAlpha || transLSelect) {
return false;
}
break;
case Layer::trans2:
if (!textureAlpha && !polyAlpha || !transLSelect) {
return false;
}
break;
default: // not using these types
return false;
}
return true;
@ -117,7 +129,6 @@ struct Mesh
float microTextureScale = 0;
// attributes
bool doubleSided = false;
bool textured = false;
bool polyAlpha = false; // specified in the rgba colour
bool textureAlpha = false; // use alpha in texture

View file

@ -79,6 +79,8 @@ bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yR
m_r3dShader.LoadShader();
m_r3dFrameBuffers.CreateFBO(totalXResParam, totalYResParam);
glUseProgram(0);
return OKAY; // OKAY ? wtf ..
@ -147,14 +149,10 @@ void CNew3D::DrawScrollFog()
}
}
bool CNew3D::RenderScene(int priority, bool renderOverlay, bool alpha)
bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
{
bool hasOverlay = false; // (high priority polys)
if (alpha) {
glEnable(GL_BLEND);
}
for (auto &n : m_nodes) {
if (n.viewport.priority != priority || n.models.empty()) {
@ -188,7 +186,7 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, bool alpha)
hasOverlay = true;
}
if (!mesh.Render(alpha)) continue;
if (!mesh.Render(layer)) continue;
if (mesh.highPriority != renderOverlay) continue;
if (!matrixLoaded) {
@ -236,6 +234,65 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, bool alpha)
return hasOverlay;
}
bool CNew3D::SkipLayer(int layer)
{
for (const auto &n : m_nodes) {
if (n.viewport.priority == layer) {
if (n.models.size()) {
return false;
}
}
}
return true;
}
void CNew3D::SetRenderStates()
{
m_vbo.Bind(true);
m_r3dShader.SetShader(true);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 4, GL_FLOAT, GL_FALSE, sizeof(FVertex), 0);
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, normal));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inTexCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, texcoords));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FVertex), (void*)offsetof(FVertex, faceColour));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFaceNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, faceNormal));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFixedShade"), 1, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, fixedShade));
glDepthFunc (GL_LESS);
glEnable (GL_DEPTH_TEST);
glDepthMask (GL_TRUE);
glActiveTexture (GL_TEXTURE0);
glDisable (GL_CULL_FACE); // we'll emulate this in the shader
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
glStencilMask (0xFF);
}
void CNew3D::DisableRenderStates()
{
m_vbo.Bind(false);
m_r3dShader.SetShader(false);
glDisable(GL_STENCIL_TEST);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
glDisableVertexAttribArray(5);
}
void CNew3D::RenderFrame(void)
{
for (int i = 0; i < 4; i++) {
@ -253,17 +310,6 @@ void CNew3D::RenderFrame(void)
DrawScrollFog(); // fog layer if applicable must be drawn here
glDepthFunc (GL_LEQUAL);
glEnable (GL_DEPTH_TEST);
glDepthMask (GL_TRUE);
glActiveTexture (GL_TEXTURE0);
glDisable (GL_CULL_FACE); // we'll emulate this in the shader
glFrontFace (GL_CW);
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
glStencilMask (0xFF);
m_vbo.Bind(true);
m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go
@ -288,59 +334,43 @@ void CNew3D::RenderFrame(void)
}
}
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 4, GL_FLOAT, GL_FALSE, sizeof(FVertex), 0);
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, normal));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inTexCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, texcoords));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FVertex), (void*)offsetof(FVertex, faceColour));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFaceNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, faceNormal));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFixedShade"), 1, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, fixedShade));
m_r3dShader.SetShader(true);
for (int pri = 0; pri <= 3; pri++) {
//==============
bool hasOverlay;
//==============
glViewport (0, 0, m_totalXRes, m_totalYRes); // clear whole viewport
glClear (GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
if (SkipLayer(pri)) continue;
m_r3dShader.DiscardAlpha(true); // chuck out alpha pixels in texture alpha only polys
hasOverlay = RenderScene(pri, false, false);
m_r3dShader.DiscardAlpha(false);
hasOverlay = RenderScene(pri, false, true);
for (int i = 0; i < 2; i++) {
if (hasOverlay) {
//clear depth buffer and render high priority polys
glViewport(0, 0, m_totalXRes, m_totalYRes); // clear whole viewport
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_r3dShader.DiscardAlpha(true);
RenderScene(pri, true, false);
m_r3dShader.DiscardAlpha(false);
RenderScene(pri, true, true);
bool renderOverlay = (i == 1);
m_r3dFrameBuffers.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
SetRenderStates();
m_r3dShader.DiscardAlpha(true); // discard all translucent pixels in opaque pass
m_r3dFrameBuffers.SetFBO(Layer::colour);
hasOverlay = RenderScene(pri, renderOverlay, Layer::colour);
m_r3dShader.DiscardAlpha(false); // render only translucent pixels
m_r3dFrameBuffers.StoreDepth(); // save depth buffer for 1st trans pass
m_r3dFrameBuffers.SetFBO(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.SetFBO(Layer::trans2);
RenderScene(pri, renderOverlay, Layer::trans2);
DisableRenderStates();
m_r3dFrameBuffers.Draw(); // draw current layer to back buffer
if (!hasOverlay) break; // no high priority polys
}
}
m_r3dShader.SetShader(false); // unbind shader
m_vbo.Bind(false);
glDisable(GL_STENCIL_TEST);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
glDisableVertexAttribArray(5);
m_r3dFrameBuffers.DisableFBO(); // draw to back buffer normally
}
void CNew3D::BeginFrame(void)
@ -469,6 +499,13 @@ void CNew3D::DescendCullingNode(UINT32 addr)
matrixOffset = node[0x03 - m_offset] & 0xFFF;
lodTablePointer = (node[0x03 - m_offset] >> 12) & 0x7F;
// parse siblings
if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings
if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) {
DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero
}
}
if ((node[0x00] & 0x04)) {
m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17);
m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range
@ -558,13 +595,6 @@ void CNew3D::DescendCullingNode(UINT32 addr)
// Restore old texture offsets
m_nodeAttribs.Pop();
// parse siblings
if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings
if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) {
DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero
}
}
}
void CNew3D::DescendNodePtr(UINT32 nodeAddr)
@ -954,7 +984,6 @@ void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2])
void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
{
//copy attributes
currentMesh->doubleSided = false; // we will double up polys
currentMesh->textured = ph.TexEnabled();
currentMesh->alphaTest = ph.AlphaTest();
currentMesh->textureAlpha = ph.TextureAlpha();
@ -963,15 +992,10 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
currentMesh->fixedShading = ph.FixedShading() && !ph.SmoothShading();
currentMesh->highPriority = ph.HighPriority();
currentMesh->transLSelect = ph.TranslucencyPatternSelect();
if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) {
currentMesh->layered = true;
}
currentMesh->layered = ph.Layered();
currentMesh->specular = ph.SpecularEnabled();
currentMesh->shininess = ph.Shininess();
currentMesh->specularValue = ph.SpecularValue();
currentMesh->fogIntensity = ph.LightModifier();
if (currentMesh->textured) {

View file

@ -1,3 +1,4 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
@ -41,6 +42,7 @@
#include "Vec.h"
#include "R3DScrollFog.h"
#include "PolyHeader.h"
#include "R3DFrameBuffers.h"
namespace New3D {
@ -199,11 +201,14 @@ private:
void CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
bool RenderScene(int priority, bool renderOverlay, bool alpha); // returns if has overlay plane
bool RenderScene(int priority, bool renderOverlay, Layer layer); // returns if has overlay plane
float Determinant3x3(const float m[16]);
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
bool IsVROMModel(UINT32 modelAddr);
void DrawScrollFog();
bool SkipLayer(int layer);
void SetRenderStates();
void DisableRenderStates();
void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);
@ -253,6 +258,7 @@ private:
VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
R3DShader m_r3dShader;
R3DScrollFog m_r3dScrollFog;
R3DFrameBuffers m_r3dFrameBuffers;
Plane m_planes[4];

View file

@ -0,0 +1,344 @@
#include "R3DFrameBuffers.h"
#include "Mat4.h"
#define countof(a) (sizeof(a)/sizeof(*(a)))
namespace New3D {
R3DFrameBuffers::R3DFrameBuffers()
{
m_frameBufferID = 0;
m_renderBufferID = 0;
m_frameBufferIDCopy = 0;
m_renderBufferIDCopy = 0;
m_width = 0;
m_height = 0;
for (auto &i : m_texIDs) {
i = 0;
}
m_lastLayer = Layer::none;
AllocShaderTrans();
AllocShaderBase();
FBVertex vertices[4];
vertices[0].Set(-1,-1, 0, 0);
vertices[1].Set(-1, 1, 0, 1);
vertices[2].Set( 1,-1, 1, 0);
vertices[3].Set( 1, 1, 1, 1);
m_vbo.Create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(vertices), vertices);
}
R3DFrameBuffers::~R3DFrameBuffers()
{
DestroyFBO();
m_shaderTrans.UnloadShaders();
m_vbo.Destroy();
}
bool R3DFrameBuffers::CreateFBO(int width, int height)
{
m_width = width;
m_height = height;
m_texIDs[0] = CreateTexture(width, height); // colour buffer
m_texIDs[1] = CreateTexture(width, height); // trans layer1
m_texIDs[2] = CreateTexture(width, height); // trans layer2
glGenFramebuffers(1, &m_frameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID);
// colour attachments
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texIDs[0], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_texIDs[1], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, m_texIDs[2], 0);
// depth/stencil attachment
glGenRenderbuffers(1, &m_renderBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferID);
// check setup was successful
auto fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0); //created R3DFrameBuffers now disable it
CreateFBODepthCopy(width, height);
return (fboStatus == GL_FRAMEBUFFER_COMPLETE);
}
bool R3DFrameBuffers::CreateFBODepthCopy(int width, int height)
{
glGenFramebuffers(1, &m_frameBufferIDCopy);
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferIDCopy);
glGenRenderbuffers(1, &m_renderBufferIDCopy);
glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferIDCopy);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferIDCopy);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferIDCopy);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// check setup was successful
auto fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
return (fboStatus == GL_FRAMEBUFFER_COMPLETE);
}
void R3DFrameBuffers::StoreDepth()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_frameBufferID);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBufferIDCopy);
glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
}
void R3DFrameBuffers::RestoreDepth()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_frameBufferIDCopy);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBufferID);
glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
}
void R3DFrameBuffers::DestroyFBO()
{
if (m_frameBufferID) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteRenderbuffers(1, &m_renderBufferID);
glDeleteFramebuffers(1, &m_frameBufferID);
}
if (m_frameBufferIDCopy) {
glDeleteRenderbuffers(1, &m_renderBufferIDCopy);
glDeleteFramebuffers(1, &m_frameBufferIDCopy);
}
for (auto &i : m_texIDs) {
if (i) {
glDeleteTextures(1, &i);
i = 0;
}
}
m_frameBufferID = 0;
m_renderBufferID = 0;
m_frameBufferIDCopy = 0;
m_renderBufferIDCopy = 0;
m_width = 0;
m_height = 0;
}
GLuint R3DFrameBuffers::CreateTexture(int width, int height)
{
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
return texId;
}
void R3DFrameBuffers::BindTexture(Layer layer)
{
glBindTexture(GL_TEXTURE_2D, m_texIDs[(int)layer]);
}
void R3DFrameBuffers::SetFBO(Layer layer)
{
if (m_lastLayer == layer) {
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID);
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 + (int)layer };
glDrawBuffers(countof(buffers), buffers);
m_lastLayer = layer;
}
void R3DFrameBuffers::DisableFBO()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
m_lastLayer = Layer::none;
}
void R3DFrameBuffers::Clear(GLbitfield mask)
{
if (m_lastLayer != Layer::all) {
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferID); // bind frame buffer
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(countof(buffers), buffers);
}
glViewport(0, 0, m_width, m_height);
glClear(mask);
m_lastLayer = Layer::all;
}
void R3DFrameBuffers::AllocShaderBase()
{
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 tex1; // base tex
varying vec2 fsTexCoord;
void main()
{
vec4 colBase = texture2D( tex1, fsTexCoord);
if(colBase.a < 1.0) discard;
gl_FragColor = colBase;
};
)glsl";
m_shaderBase.LoadShaders(vertexShader, fragmentShader);
m_shaderBase.uniformLoc[0] = m_shaderTrans.GetUniformLocation("tex1");
m_shaderBase.attribLoc[0] = m_shaderTrans.GetAttributeLocation("inVertex");
m_shaderBase.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
}
void R3DFrameBuffers::AllocShaderTrans()
{
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 tex1; // trans layer 1
uniform sampler2D tex2; // trans layer 2
varying vec2 fsTexCoord;
void main()
{
vec4 colTrans1 = texture2D( tex1, fsTexCoord);
vec4 colTrans2 = texture2D( tex2, fsTexCoord);
if(colTrans1.a+colTrans2.a > 0.0) {
vec3 col1 = (colTrans1.rgb * colTrans1.a) / ( colTrans1.a + colTrans2.a); // this is my best guess at the blending between the layers
vec3 col2 = (colTrans2.rgb * colTrans2.a) / ( colTrans1.a + colTrans2.a);
colTrans1 = vec4(col1+col2,colTrans1.a+colTrans2.a);
}
gl_FragColor = colTrans1;
};
)glsl";
m_shaderTrans.LoadShaders(vertexShader, fragmentShader);
m_shaderTrans.uniformLoc[0] = m_shaderTrans.GetUniformLocation("tex1");
m_shaderTrans.uniformLoc[1] = m_shaderTrans.GetUniformLocation("tex2");
m_shaderTrans.attribLoc[0] = m_shaderTrans.GetAttributeLocation("inVertex");
m_shaderTrans.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
}
void R3DFrameBuffers::Draw()
{
DisableFBO (); // 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);
DrawBaseLayer ();
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
DrawAlphaLayer ();
glDisable (GL_BLEND);
m_vbo.Bind (false);
}
void R3DFrameBuffers::DrawBaseLayer()
{
m_shaderBase.EnableShader();
glUniform1i(m_shaderTrans.uniformLoc[0], 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(m_shaderTrans.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
glVertexAttribPointer(m_shaderTrans.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
m_shaderBase.DisableShader();
}
void R3DFrameBuffers::DrawAlphaLayer()
{
m_shaderTrans.EnableShader();
glUniform1i(m_shaderTrans.uniformLoc[0], 1); // tex unit 1
glUniform1i(m_shaderTrans.uniformLoc[1], 2); // tex unit 2
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(m_shaderTrans.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
glVertexAttribPointer(m_shaderTrans.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
m_shaderTrans.DisableShader();
}
}

View file

@ -0,0 +1,73 @@
#ifndef FBO_H
#define FBO_H
#include "Pkgs/glew.h"
#include "VBO.h"
#include "GLSLShader.h"
#include "Model.h"
namespace New3D {
class R3DFrameBuffers {
public:
R3DFrameBuffers();
~R3DFrameBuffers();
void Draw(); // draw and composite the transparent layers
bool CreateFBO(int width, int height);
void DestroyFBO();
void BindTexture(Layer layer);
void SetFBO(Layer layer);
void DisableFBO();
void Clear(GLbitfield mask);
void StoreDepth();
void RestoreDepth();
private:
struct FBVertex
{
void Set(float x, float y, float s, float t)
{
texCoords[0] = s;
texCoords[1] = t;
verts[0] = x;
verts[1] = y;
verts[2] = 0; // z = 0
}
float texCoords[2];
float verts[3];
};
bool CreateFBODepthCopy(int width, int height);
GLuint CreateTexture(int width, int height);
void AllocShaderTrans();
void AllocShaderBase();
void DrawBaseLayer();
void DrawAlphaLayer();
GLuint m_frameBufferID;
GLuint m_renderBufferID;
GLuint m_texIDs[3];
GLuint m_frameBufferIDCopy;
GLuint m_renderBufferIDCopy;
Layer m_lastLayer;
int m_width;
int m_height;
// shaders
GLSLShader m_shaderBase;
GLSLShader m_shaderTrans;
// vertices for fbo
VBO m_vbo;
};
}
#endif

View file

@ -114,11 +114,18 @@ vec4 GetTextureValue()
}
}
if(discardAlpha && textureAlpha) {
if(textureAlpha) {
if(discardAlpha) { // opaque 1st pass
if (tex1Data.a < 1.0) {
discard;
}
}
else { // transparent 2nd pass
if ((tex1Data.a * fsColor.a) >= 1.0) {
discard;
}
}
}
if (textureAlpha == false) {
tex1Data.a = 1.0;

View file

@ -311,11 +311,13 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi
<ClCompile Include="..\Src\Graphics\Legacy3D\Legacy3D.cpp" />
<ClCompile Include="..\Src\Graphics\Legacy3D\Models.cpp" />
<ClCompile Include="..\Src\Graphics\Legacy3D\TextureRefs.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\GLSLShader.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\Mat4.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\Model.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\New3D.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\PolyHeader.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DFloat.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DFrameBuffers.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DScrollFog.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\Texture.cpp" />
@ -537,6 +539,7 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi
<ClInclude Include="..\Src\Graphics\Legacy3D\Legacy3D.h" />
<ClInclude Include="..\Src\Graphics\Legacy3D\Shaders3D.h" />
<ClInclude Include="..\Src\Graphics\Legacy3D\TextureRefs.h" />
<ClInclude Include="..\Src\Graphics\New3D\GLSLShader.h" />
<ClInclude Include="..\Src\Graphics\New3D\Mat4.h" />
<ClInclude Include="..\Src\Graphics\New3D\Model.h" />
<ClInclude Include="..\Src\Graphics\New3D\New3D.h" />
@ -544,6 +547,7 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi
<ClInclude Include="..\Src\Graphics\New3D\PolyHeader.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DData.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DFloat.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DFrameBuffers.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DScrollFog.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DShader.h" />
<ClInclude Include="..\Src\Graphics\New3D\Texture.h" />

View file

@ -464,6 +464,12 @@
<ClCompile Include="..\Src\Debugger\DebuggerIO.cpp">
<Filter>Source Files\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\Src\Graphics\New3D\R3DFrameBuffers.cpp">
<Filter>Source Files\Graphics\New</Filter>
</ClCompile>
<ClCompile Include="..\Src\Graphics\New3D\GLSLShader.cpp">
<Filter>Source Files\Graphics\New</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="..\Src\CPU\68K\Turbo68K\Turbo68K.asm">
@ -862,6 +868,12 @@
<ClInclude Include="..\Src\Debugger\DebuggerIO.h">
<Filter>Header Files\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\R3DFrameBuffers.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\GLSLShader.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\Src\Debugger\ReadMe.txt">