Rewrite the whole project for GL4+. I figured if we removed the limitation of a legacy rendering API we could improve things a bit. With GL4+ we can do unsigned integer math in the shaders. This allows us to upload a direct copy of the real3d texture sheet, and texture directly from this memory given the x/y pos and type. This massively simplifies the binding and invalidation code. Also the crazy corner cases will work because it essentially works the same way as the original hardware.

The standard triangle render requires gl 4.1 core, so should work on mac. The quad renderer runs on 4.5 core. The legacy renderer should still work, and when enabled a regular opengl context will be created, which allows functions marked depreciated in the core profiles to still work. This will only work in windows/linux I think. Apple doesn't support this.

A GL 4.1 GPU is now the min required spec. Sorry if you have an OLDER gpu. GL 4.1 is over 12 years old now.

This is a big update so I apologise in advance if I accidently broke something :]
This commit is contained in:
Ian Curtis 2022-11-07 21:33:01 +00:00
parent 121f81c742
commit 40c8259130
23 changed files with 941 additions and 1171 deletions

View file

@ -5,7 +5,7 @@
#include <unordered_map> #include <unordered_map>
#include <memory> #include <memory>
#include <cstring> #include <cstring>
#include "Texture.h" #include "Types.h"
#include "Mat4.h" #include "Mat4.h"
namespace New3D { namespace New3D {

View file

@ -1,5 +1,4 @@
#include "New3D.h" #include "New3D.h"
#include "Texture.h"
#include "Vec.h" #include "Vec.h"
#include <cmath> #include <cmath>
#include <algorithm> #include <algorithm>
@ -16,10 +15,12 @@
namespace New3D { namespace New3D {
CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) :
: m_r3dShader(config), m_r3dShader(config),
m_r3dScrollFog(config), m_r3dScrollFog(config),
m_gameName(gameName) m_gameName(gameName),
m_textureBuffer(0),
m_vao(0)
{ {
m_cullingRAMLo = nullptr; m_cullingRAMLo = nullptr;
m_cullingRAMHi = nullptr; m_cullingRAMHi = nullptr;
@ -40,6 +41,17 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName)
CNew3D::~CNew3D() CNew3D::~CNew3D()
{ {
m_vbo.Destroy(); m_vbo.Destroy();
if (m_vao) {
glDeleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_textureBuffer) {
glDeleteTextures(1, &m_textureBuffer);
m_textureBuffer = 0;
}
m_r3dShader.UnloadShader();
} }
void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
@ -67,8 +79,6 @@ void CNew3D::SetStepping(int stepping)
m_offset = 2; // 8 words m_offset = 2; // 8 words
m_vertexFactor = (1.0f / 128.0f); // 17.7 m_vertexFactor = (1.0f / 128.0f); // 17.7
} }
m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(FVertex) * (MAX_RAM_VERTS + MAX_ROM_VERTS));
} }
bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
@ -84,34 +94,55 @@ bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yR
m_totalYRes = totalYResParam; m_totalYRes = totalYResParam;
m_r3dShader.LoadShader(); m_r3dShader.LoadShader();
glUseProgram(0);
m_r3dFrameBuffers.CreateFBO(totalXResParam, totalYResParam); m_r3dFrameBuffers.CreateFBO(totalXResParam, totalYResParam);
glUseProgram(0); // setup our texture memory
return OKAY; // OKAY ? wtf .. glGenTextures(1, &m_textureBuffer);
glBindTexture(GL_TEXTURE_2D, m_textureBuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 2048, 2048, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, nullptr); // allocate storage
// setup up our vertex buffer memory
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(FVertex) * (MAX_RAM_VERTS + MAX_ROM_VERTS));
m_vbo.Bind(true);
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inVertex"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inNormal"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inTexCoord"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inColour"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inFaceNormal"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inFixedShade"));
// 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));
glBindVertexArray(0);
m_vbo.Bind(false);
return OKAY;
} }
void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned width, unsigned height) void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned width, unsigned height)
{ {
if (level == 0) { glBindTexture(GL_TEXTURE_2D, m_textureBuffer);
m_texSheet.Invalidate(x, y, width, height); // base textures only glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
}
else if (level == 1) {
// we want to work out what the base level is, and invalidate the entire texture
// the mipmap data in some cases is being sent later
int page = y / 1024; for (unsigned i = 0; i < height; i++) {
y -= (page * 1024); // remove page from tex y glTexSubImage2D(GL_TEXTURE_2D, 0, x, y + i, width, 1, GL_RED_INTEGER, GL_UNSIGNED_SHORT, m_textureRAM + ((y + i) * 2048) + x);
int xPos = (x - 1024) * 2;
int yPos = (y - 512) * 2;
yPos += page * 1024;
width *= 2;
height *= 2;
m_texSheet.Invalidate(xPos, yPos, width, height);
} }
} }
@ -170,6 +201,9 @@ CheckScroll:
bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer) bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
{ {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textureBuffer);
bool hasOverlay = false; // (high priority polys) bool hasOverlay = false; // (high priority polys)
for (auto &n : m_nodes) { for (auto &n : m_nodes) {
@ -178,8 +212,6 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
continue; continue;
} }
std::shared_ptr<Texture> tex1;
CalcViewport(&n.viewport, std::abs(m_nfPairs[priority].zNear*0.96f), std::abs(m_nfPairs[priority].zFar*1.05f)); // make planes 5% bigger CalcViewport(&n.viewport, std::abs(m_nfPairs[priority].zNear*0.96f), std::abs(m_nfPairs[priority].zFar*1.05f)); // make planes 5% bigger
glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
@ -207,34 +239,6 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
} }
if (mesh.textured) {
int x, y;
CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y);
if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) {
// texture already bound
}
else {
tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, x, y, mesh.width, mesh.height);
if (tex1) {
tex1->BindTexture();
}
}
if (mesh.microTexture) {
int mX, mY;
glActiveTexture(GL_TEXTURE1);
m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY);
auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, mX, mY, 128, 128);
if (tex2) {
tex2->BindTexture();
}
glActiveTexture(GL_TEXTURE0);
}
}
m_r3dShader.SetMeshUniforms(&mesh); m_r3dShader.SetMeshUniforms(&mesh);
glDrawArrays(m_primType, mesh.vboOffset, mesh.vertexCount); glDrawArrays(m_primType, mesh.vboOffset, mesh.vertexCount);
} }
@ -260,23 +264,10 @@ bool CNew3D::SkipLayer(int layer)
void CNew3D::SetRenderStates() void CNew3D::SetRenderStates()
{ {
m_vbo.Bind(true); m_vbo.Bind(true);
glBindVertexArray(m_vao);
m_r3dShader.SetShader(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_LEQUAL); glDepthFunc (GL_LEQUAL);
glEnable (GL_DEPTH_TEST); glEnable (GL_DEPTH_TEST);
glDepthMask (GL_TRUE); glDepthMask (GL_TRUE);
@ -292,16 +283,11 @@ void CNew3D::SetRenderStates()
void CNew3D::DisableRenderStates() void CNew3D::DisableRenderStates()
{ {
m_vbo.Bind(false); m_vbo.Bind(false);
glBindVertexArray(0);
m_r3dShader.SetShader(false); m_r3dShader.SetShader(false);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
glDisableVertexAttribArray(5);
} }
void CNew3D::RenderFrame(void) void CNew3D::RenderFrame(void)
@ -992,6 +978,30 @@ void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertex
} }
} }
void CNew3D::GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
{
uOut = (uIn * uvScale) / width;
vOut = (vIn * uvScale) / height;
}
int CNew3D::GetTexFormat(int originalFormat, bool contour)
{
if (!contour) {
return originalFormat; // the same
}
switch (originalFormat)
{
case 1:
case 2:
case 3:
case 4:
return originalFormat + 7; // these formats are identical to 1-4, except they lose the 4 bit alpha part when contour is enabled
default:
return originalFormat;
}
}
void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph) void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
{ {
//copy attributes //copy attributes
@ -1012,7 +1022,7 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
if (currentMesh->textured) { if (currentMesh->textured) {
currentMesh->format = m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest()); currentMesh->format = GetTexFormat(ph.TexFormat(), ph.AlphaTest());
if (currentMesh->format == 7) { if (currentMesh->format == 7) {
currentMesh->alphaTest = false; // alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency currentMesh->alphaTest = false; // alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency
@ -1127,7 +1137,7 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
//check if we need to recalc tex coords - will only happen if tex tiles are different + sharing vertices //check if we need to recalc tex coords - will only happen if tex tiles are different + sharing vertices
if (hash != lastHash) { if (hash != lastHash) {
if (currentMesh->textured) { if (currentMesh->textured) {
Texture::GetCoordinates(currentMesh->width, currentMesh->height, texCoords[j][0], texCoords[j][1], uvScale, p.v[j].texcoords[0], p.v[j].texcoords[1]); GetCoordinates(currentMesh->width, currentMesh->height, texCoords[j][0], texCoords[j][1], uvScale, p.v[j].texcoords[0], p.v[j].texcoords[1]);
} }
} }
@ -1209,7 +1219,7 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
// tex coords // tex coords
if (currentMesh->textured) { if (currentMesh->textured) {
Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
} }
p.v[j].texcoords[0] = texU; p.v[j].texcoords[0] = texU;

View file

@ -31,7 +31,6 @@
#include <GL/glew.h> #include <GL/glew.h>
#include "Types.h" #include "Types.h"
#include "TextureSheet.h"
#include "Graphics/IRender3D.h" #include "Graphics/IRender3D.h"
#include "Model.h" #include "Model.h"
#include "Mat4.h" #include "Mat4.h"
@ -207,9 +206,11 @@ private:
void RenderViewport(UINT32 addr); void RenderViewport(UINT32 addr);
// building the scene // building the scene
int GetTexFormat(int originalFormat, bool contour);
void SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph); void SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph);
void CacheModel(Model *m, const UINT32 *data); void CacheModel(Model *m, const UINT32 *data);
void CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertexArray); void CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertexArray);
void GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
bool RenderScene(int priority, bool renderOverlay, Layer layer); // returns if has overlay plane bool RenderScene(int priority, bool renderOverlay, Layer layer); // returns if has overlay plane
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
@ -259,7 +260,7 @@ private:
UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM
LODBlendTable* m_LODBlendTable; LODBlendTable* m_LODBlendTable;
TextureSheet m_texSheet; GLuint m_textureBuffer;
NodeAttributes m_nodeAttribs; NodeAttributes m_nodeAttribs;
Mat4 m_modelMat; // current modelview matrix Mat4 m_modelMat; // current modelview matrix
@ -280,6 +281,7 @@ private:
std::vector<FVertex> m_polyBufferRom; // rom polys std::vector<FVertex> m_polyBufferRom; // rom polys
std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
GLuint m_vao;
VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
R3DShader m_r3dShader; R3DShader m_r3dShader;
R3DScrollFog m_r3dScrollFog; R3DScrollFog m_r3dScrollFog;

View file

@ -13,6 +13,7 @@ R3DFrameBuffers::R3DFrameBuffers()
m_renderBufferIDCopy = 0; m_renderBufferIDCopy = 0;
m_width = 0; m_width = 0;
m_height = 0; m_height = 0;
m_vao = 0;
for (auto &i : m_texIDs) { for (auto &i : m_texIDs) {
i = 0; i = 0;
@ -24,13 +25,10 @@ R3DFrameBuffers::R3DFrameBuffers()
AllocShaderBase(); AllocShaderBase();
AllocShaderWipe(); AllocShaderWipe();
FBVertex vertices[4]; glGenVertexArrays(1, &m_vao);
vertices[0].Set(-1,-1, 0, 0); glBindVertexArray(m_vao);
vertices[1].Set(-1, 1, 0, 1); // no states needed since we do it in the shader
vertices[2].Set( 1,-1, 1, 0); glBindVertexArray(0);
vertices[3].Set( 1, 1, 1, 1);
m_vbo.Create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(vertices), vertices);
} }
R3DFrameBuffers::~R3DFrameBuffers() R3DFrameBuffers::~R3DFrameBuffers()
@ -39,7 +37,10 @@ R3DFrameBuffers::~R3DFrameBuffers()
m_shaderTrans.UnloadShaders(); m_shaderTrans.UnloadShaders();
m_shaderBase.UnloadShaders(); m_shaderBase.UnloadShaders();
m_shaderWipe.UnloadShaders(); m_shaderWipe.UnloadShaders();
m_vbo.Destroy(); if (m_vao) {
glDeleteVertexArrays(1, &m_vao);
m_vao = 0;
}
} }
bool R3DFrameBuffers::CreateFBO(int width, int height) bool R3DFrameBuffers::CreateFBO(int width, int height)
@ -201,80 +202,86 @@ void R3DFrameBuffers::AllocShaderBase()
{ {
const char *vertexShader = R"glsl( const char *vertexShader = R"glsl(
#version 120 #version 410 core
// inputs
attribute vec3 inVertex;
attribute vec2 inTexCoord;
// outputs // outputs
varying vec2 fsTexCoord; out vec2 fsTexCoord;
void main(void) void main(void)
{ {
fsTexCoord = inTexCoord; const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.0, 1.0),
gl_Position = vec4(inVertex,1.0); vec4(-1.0, 1.0, 0.0, 1.0),
vec4( 1.0, -1.0, 0.0, 1.0),
vec4( 1.0, 1.0, 0.0, 1.0));
fsTexCoord = (vertices[gl_VertexID % 4].xy + 1.0) / 2.0;
gl_Position = vertices[gl_VertexID % 4];
} }
)glsl"; )glsl";
const char *fragmentShader = R"glsl( const char *fragmentShader = R"glsl(
#version 120 #version 410 core
// inputs
uniform sampler2D tex1; // base tex uniform sampler2D tex1; // base tex
in vec2 fsTexCoord;
varying vec2 fsTexCoord; // outputs
out vec4 fragColor;
void main() void main()
{ {
vec4 colBase = texture2D( tex1, fsTexCoord); vec4 colBase = texture(tex1, fsTexCoord);
if(colBase.a < 1.0) discard; if(colBase.a < 1.0) discard;
gl_FragColor = colBase; fragColor = colBase;
} }
)glsl"; )glsl";
m_shaderBase.LoadShaders(vertexShader, fragmentShader); m_shaderBase.LoadShaders(vertexShader, fragmentShader);
m_shaderBase.uniformLoc[0] = m_shaderTrans.GetUniformLocation("tex1"); 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() void R3DFrameBuffers::AllocShaderTrans()
{ {
const char *vertexShader = R"glsl( const char *vertexShader = R"glsl(
#version 120 #version 410 core
// inputs
attribute vec3 inVertex;
attribute vec2 inTexCoord;
// outputs // outputs
varying vec2 fsTexCoord; out vec2 fsTexCoord;
void main(void) void main(void)
{ {
fsTexCoord = inTexCoord; const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.0, 1.0),
gl_Position = vec4(inVertex,1.0); vec4(-1.0, 1.0, 0.0, 1.0),
vec4( 1.0, -1.0, 0.0, 1.0),
vec4( 1.0, 1.0, 0.0, 1.0));
fsTexCoord = (vertices[gl_VertexID % 4].xy + 1.0) / 2.0;
gl_Position = vertices[gl_VertexID % 4];
} }
)glsl"; )glsl";
const char *fragmentShader = R"glsl( const char *fragmentShader = R"glsl(
#version 120 #version 410 core
uniform sampler2D tex1; // trans layer 1 uniform sampler2D tex1; // trans layer 1
uniform sampler2D tex2; // trans layer 2 uniform sampler2D tex2; // trans layer 2
varying vec2 fsTexCoord; in vec2 fsTexCoord;
// outputs
out vec4 fragColor;
void main() void main()
{ {
vec4 colTrans1 = texture2D( tex1, fsTexCoord); vec4 colTrans1 = texture( tex1, fsTexCoord);
vec4 colTrans2 = texture2D( tex2, fsTexCoord); vec4 colTrans2 = texture( tex2, fsTexCoord);
if(colTrans1.a+colTrans2.a > 0.0) { if(colTrans1.a+colTrans2.a > 0.0) {
vec3 col1 = colTrans1.rgb * colTrans1.a; vec3 col1 = colTrans1.rgb * colTrans1.a;
@ -284,7 +291,7 @@ void R3DFrameBuffers::AllocShaderTrans()
colTrans1.a+colTrans2.a); colTrans1.a+colTrans2.a);
} }
gl_FragColor = colTrans1; fragColor = colTrans1;
} }
)glsl"; )glsl";
@ -293,49 +300,51 @@ void R3DFrameBuffers::AllocShaderTrans()
m_shaderTrans.uniformLoc[0] = m_shaderTrans.GetUniformLocation("tex1"); m_shaderTrans.uniformLoc[0] = m_shaderTrans.GetUniformLocation("tex1");
m_shaderTrans.uniformLoc[1] = m_shaderTrans.GetUniformLocation("tex2"); 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::AllocShaderWipe() void R3DFrameBuffers::AllocShaderWipe()
{ {
const char *vertexShader = R"glsl( const char *vertexShader = R"glsl(
#version 120 #version 410 core
// inputs
attribute vec3 inVertex;
attribute vec2 inTexCoord;
// outputs // outputs
varying vec2 fsTexCoord; out vec2 fsTexCoord;
void main(void) void main(void)
{ {
fsTexCoord = inTexCoord; const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.0, 1.0),
gl_Position = vec4(inVertex,1.0); vec4(-1.0, 1.0, 0.0, 1.0),
vec4( 1.0, -1.0, 0.0, 1.0),
vec4( 1.0, 1.0, 0.0, 1.0));
fsTexCoord = (vertices[gl_VertexID % 4].xy + 1.0) / 2.0;
gl_Position = vertices[gl_VertexID % 4];
} }
)glsl"; )glsl";
const char *fragmentShader = R"glsl( const char *fragmentShader = R"glsl(
#version 120 #version 410 core
uniform sampler2D texColor; // base colour layer uniform sampler2D texColor; // base colour layer
varying vec2 fsTexCoord; in vec2 fsTexCoord;
// outputs
layout (location = 0) out vec4 fragColor0;
layout (location = 1) out vec4 fragColor1;
void main() void main()
{ {
vec4 colBase = texture2D( texColor, fsTexCoord); vec4 colBase = texture(texColor, fsTexCoord);
if(colBase.a == 0.0) { if(colBase.a == 0.0) {
discard; // no colour pixels have been written discard; // no colour pixels have been written
} }
gl_FragData[0] = vec4(0.0); // wipe these parts of the alpha buffer fragColor0 = 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 fragColor1 = vec4(0.0); // since they have been overwritten by the next priority layer
} }
)glsl"; )glsl";
@ -343,9 +352,6 @@ void R3DFrameBuffers::AllocShaderWipe()
m_shaderWipe.LoadShaders(vertexShader, fragmentShader); m_shaderWipe.LoadShaders(vertexShader, fragmentShader);
m_shaderWipe.uniformLoc[0] = m_shaderTrans.GetUniformLocation("texColor"); 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()
@ -362,7 +368,7 @@ void R3DFrameBuffers::Draw()
} }
glActiveTexture (GL_TEXTURE0); glActiveTexture (GL_TEXTURE0);
m_vbo.Bind (true); glBindVertexArray (m_vao);
DrawBaseLayer (); DrawBaseLayer ();
@ -372,7 +378,7 @@ void R3DFrameBuffers::Draw()
DrawAlphaLayer (); DrawAlphaLayer ();
glDisable (GL_BLEND); glDisable (GL_BLEND);
m_vbo.Bind (false); glBindVertexArray (0);
} }
void R3DFrameBuffers::CompositeBaseLayer() void R3DFrameBuffers::CompositeBaseLayer()
@ -389,11 +395,11 @@ void R3DFrameBuffers::CompositeBaseLayer()
} }
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
m_vbo.Bind(true); glBindVertexArray(m_vao);
DrawBaseLayer(); DrawBaseLayer();
m_vbo.Bind(false); glBindVertexArray(0);
} }
void R3DFrameBuffers::CompositeAlphaLayer() void R3DFrameBuffers::CompositeAlphaLayer()
@ -409,15 +415,15 @@ void R3DFrameBuffers::CompositeAlphaLayer()
} }
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
m_vbo.Bind(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBindVertexArray(m_vao);
DrawAlphaLayer(); DrawAlphaLayer();
glDisable(GL_BLEND); glDisable(GL_BLEND);
m_vbo.Bind(false); glBindVertexArray(0);
} }
void R3DFrameBuffers::DrawOverTransLayers() void R3DFrameBuffers::DrawOverTransLayers()
@ -432,43 +438,23 @@ void R3DFrameBuffers::DrawOverTransLayers()
glActiveTexture (GL_TEXTURE0); glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, m_texIDs[0]); glBindTexture (GL_TEXTURE_2D, m_texIDs[0]);
m_vbo.Bind(true); glBindVertexArray(m_vao);
m_shaderWipe.EnableShader(); m_shaderWipe.EnableShader();
glUniform1i(m_shaderWipe.uniformLoc[0], 0); 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); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
m_shaderWipe.DisableShader(); m_shaderWipe.DisableShader();
glBindVertexArray(0);
m_vbo.Bind(false);
} }
void R3DFrameBuffers::DrawBaseLayer() void R3DFrameBuffers::DrawBaseLayer()
{ {
m_shaderBase.EnableShader(); m_shaderBase.EnableShader();
glUniform1i(m_shaderTrans.uniformLoc[0], 0); glUniform1i(m_shaderTrans.uniformLoc[0], 0); // to do check this
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); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
m_shaderBase.DisableShader(); m_shaderBase.DisableShader();
} }
@ -478,17 +464,8 @@ void R3DFrameBuffers::DrawAlphaLayer()
glUniform1i(m_shaderTrans.uniformLoc[0], 1); // tex unit 1 glUniform1i(m_shaderTrans.uniformLoc[0], 1); // tex unit 1
glUniform1i(m_shaderTrans.uniformLoc[1], 2); // tex unit 2 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); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
m_shaderTrans.DisableShader(); m_shaderTrans.DisableShader();
} }

View file

@ -29,21 +29,6 @@ public:
private: 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.f; // z = 0
}
float texCoords[2];
float verts[3];
};
bool CreateFBODepthCopy(int width, int height); bool CreateFBODepthCopy(int width, int height);
GLuint CreateTexture(int width, int height); GLuint CreateTexture(int width, int height);
void AllocShaderTrans(); void AllocShaderTrans();
@ -67,8 +52,8 @@ private:
GLSLShader m_shaderTrans; GLSLShader m_shaderTrans;
GLSLShader m_shaderWipe; GLSLShader m_shaderWipe;
// vertices for fbo // vao
VBO m_vbo; GLuint m_vao; // this really needed if we don't actually use vertex attribs?
}; };
} }

View file

@ -1,26 +1,27 @@
#include "R3DScrollFog.h" #include "R3DScrollFog.h"
#include "Graphics/Shader.h" #include "Graphics/Shader.h"
#include "Mat4.h"
namespace New3D { namespace New3D {
static const char *vertexShaderFog = R"glsl( static const char *vertexShaderFog = R"glsl(
#version 120 #version 410 core
uniform mat4 mvp;
attribute vec3 inVertex;
void main(void) void main(void)
{ {
gl_Position = mvp * vec4(inVertex,1.0); const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.0, 1.0),
vec4(-1.0, 1.0, 0.0, 1.0),
vec4( 1.0, -1.0, 0.0, 1.0),
vec4( 1.0, 1.0, 0.0, 1.0));
gl_Position = vertices[gl_VertexID % 4];
} }
)glsl"; )glsl";
static const char *fragmentShaderFog = R"glsl( static const char *fragmentShaderFog = R"glsl(
#version 120 #version 410 core
uniform float fogAttenuation; uniform float fogAttenuation;
uniform float fogAmbient; uniform float fogAmbient;
@ -38,6 +39,9 @@ float lfogAttenuation;
vec3 lFogColor; vec3 lFogColor;
vec4 scrollFog; vec4 scrollFog;
// outputs
out vec4 fragColor;
void main() void main()
{ {
// Scroll fog base color // Scroll fog base color
@ -58,67 +62,59 @@ void main()
scrollFog = vec4(lFogColor + lSpotFogColor, fogColour.a); scrollFog = vec4(lFogColor + lSpotFogColor, fogColour.a);
// Final Color // Final Color
gl_FragColor = scrollFog; fragColor = scrollFog;
} }
)glsl"; )glsl";
R3DScrollFog::R3DScrollFog(const Util::Config::Node &config) R3DScrollFog::R3DScrollFog(const Util::Config::Node &config)
: m_config(config) : m_config(config),
m_vao(0)
{ {
//default coordinates are NDC -1,1 etc
m_triangles[0].p1.Set(-1,-1, 0);
m_triangles[0].p2.Set(-1, 1, 0);
m_triangles[0].p3.Set( 1, 1, 0);
m_triangles[1].p1.Set(-1,-1, 0);
m_triangles[1].p2.Set( 1, 1, 0);
m_triangles[1].p3.Set( 1,-1, 0);
m_shaderProgram = 0; m_shaderProgram = 0;
m_vertexShader = 0; m_vertexShader = 0;
m_fragmentShader = 0; m_fragmentShader = 0;
AllocResources(); AllocResources();
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
// no states needed since we do it in the shader
glBindVertexArray(0);
} }
R3DScrollFog::~R3DScrollFog() R3DScrollFog::~R3DScrollFog()
{ {
DeallocResources(); DeallocResources();
if (m_vao) {
glDeleteVertexArrays(1, &m_vao);
m_vao = 0;
}
} }
void R3DScrollFog::DrawScrollFog(float rgba[4], float attenuation, float ambient, float *spotRGB, float *spotEllipse) void R3DScrollFog::DrawScrollFog(float rgba[4], float attenuation, float ambient, float *spotRGB, float *spotEllipse)
{ {
//=======
Mat4 mvp;
//=======
// yeah this would have been much easier with immediate mode and fixed function .. >_<
// some ogl states // some ogl states
glDepthMask (GL_FALSE); // disable z writes glDepthMask (GL_FALSE); // disable z writes
glDisable (GL_DEPTH_TEST); // disable depth testing glDisable (GL_DEPTH_TEST); // disable depth testing
glEnable (GL_BLEND); glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_vbo.Bind (true); glBindVertexArray (m_vao);
glUseProgram (m_shaderProgram); glUseProgram (m_shaderProgram);
glUniform4f (m_locFogColour, rgba[0], rgba[1], rgba[2], rgba[3]); glUniform4fv (m_locFogColour, 1, rgba);
glUniform1f (m_locFogAttenuation, attenuation); glUniform1f (m_locFogAttenuation, attenuation);
glUniform1f (m_locFogAmbient, ambient); glUniform1f (m_locFogAmbient, ambient);
glUniform3f (m_locSpotFogColor, spotRGB[0], spotRGB[1], spotRGB[2]); glUniform3fv (m_locSpotFogColor, 1, spotRGB);
glUniform4f (m_locSpotEllipse, spotEllipse[0], spotEllipse[1], spotEllipse[2], spotEllipse[3]); glUniform4fv (m_locSpotEllipse, 1, spotEllipse);
glUniformMatrix4fv (m_locMVP, 1, GL_FALSE, mvp);
glEnableVertexAttribArray (0); glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
glVertexAttribPointer (m_locInVertex, 3, GL_FLOAT, GL_FALSE, sizeof(SFVertex), 0);
glDrawArrays (GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray (0);
glUseProgram (0); glUseProgram (0);
m_vbo.Bind (false); glBindVertexArray (0);
glDisable (GL_BLEND); glDisable (GL_BLEND);
glDepthMask (GL_TRUE); glDepthMask (GL_TRUE);
@ -128,16 +124,11 @@ void R3DScrollFog::AllocResources()
{ {
bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, m_config["VertexShaderFog"].ValueAs<std::string>(), m_config["FragmentShaderFog"].ValueAs<std::string>(), vertexShaderFog, fragmentShaderFog); bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, m_config["VertexShaderFog"].ValueAs<std::string>(), m_config["FragmentShaderFog"].ValueAs<std::string>(), vertexShaderFog, fragmentShaderFog);
m_locMVP = glGetUniformLocation(m_shaderProgram, "mvp");
m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour");
m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation"); m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation");
m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient"); m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient");
m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor"); m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor");
m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse"); m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse");
m_locInVertex = glGetAttribLocation(m_shaderProgram, "inVertex");
m_vbo.Create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(SFTriangle) * (2), m_triangles);
} }
void R3DScrollFog::DeallocResources() void R3DScrollFog::DeallocResources()
@ -149,8 +140,6 @@ void R3DScrollFog::DeallocResources()
m_shaderProgram = 0; m_shaderProgram = 0;
m_vertexShader = 0; m_vertexShader = 0;
m_fragmentShader = 0; m_fragmentShader = 0;
m_vbo.Destroy();
} }
} }

View file

@ -2,7 +2,7 @@
#define _R3DSCROLLFOG_H_ #define _R3DSCROLLFOG_H_
#include "Util/NewConfig.h" #include "Util/NewConfig.h"
#include "VBO.h" #include <GL/glew.h>
namespace New3D { namespace New3D {
@ -22,41 +22,17 @@ private:
const Util::Config::Node &m_config; const Util::Config::Node &m_config;
struct SFVertex
{
void Set(float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
}
float v[3];
};
struct SFTriangle
{
SFVertex p1;
SFVertex p2;
SFVertex p3;
};
SFTriangle m_triangles[2];
GLuint m_shaderProgram; GLuint m_shaderProgram;
GLuint m_vertexShader; GLuint m_vertexShader;
GLuint m_fragmentShader; GLuint m_fragmentShader;
GLint m_locFogColour; GLint m_locFogColour;
GLint m_locMVP;
GLint m_locFogAttenuation; GLint m_locFogAttenuation;
GLint m_locFogAmbient; GLint m_locFogAmbient;
GLint m_locSpotFogColor; GLint m_locSpotFogColor;
GLint m_locSpotEllipse; GLint m_locSpotEllipse;
// vertex attrib locs GLuint m_vao;
GLint m_locInVertex;
VBO m_vbo;
}; };
} }

View file

@ -34,9 +34,18 @@ void R3DShader::Start()
m_shininess = 0; m_shininess = 0;
m_specularValue = 0; m_specularValue = 0;
m_microTexScale = 0; m_microTexScale = 0;
m_microTexID = -1;
m_baseTexSize[0] = 0; m_baseTexInfo[0] = -1;
m_baseTexSize[1] = 0; m_baseTexInfo[1] = -1;
m_baseTexInfo[2] = -1;
m_baseTexInfo[3] = -1;
m_baseTexType = -1;
m_transX = -1;
m_transY = -1;
m_transPage = -1;
m_texWrapMode[0] = 0; m_texWrapMode[0] = 0;
m_texWrapMode[1] = 0; m_texWrapMode[1] = 0;
@ -53,10 +62,15 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
const char* gShader = ""; const char* gShader = "";
const char* fShader = fragmentShaderR3D; const char* fShader = fragmentShaderR3D;
std::string fragmentShaderCombined;
if (quads) { if (quads) {
vShader = vertexShaderR3DQuads; vShader = vertexShaderR3DQuads;
gShader = geometryShaderR3DQuads; gShader = geometryShaderR3DQuads;
fShader = fragmentShaderR3DQuads;
fragmentShaderCombined += fragmentShaderR3DQuads1;
fragmentShaderCombined += fragmentShaderR3DQuads2;
fShader = fragmentShaderCombined.c_str();
} }
m_shaderProgram = glCreateProgram(); m_shaderProgram = glCreateProgram();
@ -87,13 +101,14 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
PrintProgramResult(m_shaderProgram); PrintProgramResult(m_shaderProgram);
m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1"); m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1");
m_locTexture2 = glGetUniformLocation(m_shaderProgram, "tex2");
m_locTexture1Enabled = glGetUniformLocation(m_shaderProgram, "textureEnabled"); m_locTexture1Enabled = glGetUniformLocation(m_shaderProgram, "textureEnabled");
m_locTexture2Enabled = glGetUniformLocation(m_shaderProgram, "microTexture"); m_locTexture2Enabled = glGetUniformLocation(m_shaderProgram, "microTexture");
m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha"); m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha");
m_locAlphaTest = glGetUniformLocation(m_shaderProgram, "alphaTest"); m_locAlphaTest = glGetUniformLocation(m_shaderProgram, "alphaTest");
m_locMicroTexScale = glGetUniformLocation(m_shaderProgram, "microTextureScale"); m_locMicroTexScale = glGetUniformLocation(m_shaderProgram, "microTextureScale");
m_locBaseTexSize = glGetUniformLocation(m_shaderProgram, "baseTexSize"); m_locMicroTexID = glGetUniformLocation(m_shaderProgram, "microTextureID");
m_locBaseTexInfo = glGetUniformLocation(m_shaderProgram, "baseTexInfo");
m_locBaseTexType = glGetUniformLocation(m_shaderProgram, "baseTexType");
m_locTextureInverted = glGetUniformLocation(m_shaderProgram, "textureInverted"); m_locTextureInverted = glGetUniformLocation(m_shaderProgram, "textureInverted");
m_locTexWrapMode = glGetUniformLocation(m_shaderProgram, "textureWrapMode"); m_locTexWrapMode = glGetUniformLocation(m_shaderProgram, "textureWrapMode");
@ -129,12 +144,37 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
return true; return true;
} }
void R3DShader::UnloadShader()
{
// make sure no shader is bound
glUseProgram(0);
if (m_vertexShader) {
glDeleteShader(m_vertexShader);
m_vertexShader = 0;
}
if (m_geoShader) {
glDeleteShader(m_geoShader);
m_geoShader = 0;
}
if (m_fragmentShader) {
glDeleteShader(m_fragmentShader);
m_fragmentShader = 0;
}
if (m_shaderProgram) {
glDeleteProgram(m_shaderProgram);
m_shaderProgram = 0;
}
}
GLint R3DShader::GetVertexAttribPos(const std::string& attrib) GLint R3DShader::GetVertexAttribPos(const std::string& attrib)
{ {
if (m_vertexLocCache.count(attrib)==0) { if (m_vertexLocCache.count(attrib)==0) {
auto pos = glGetAttribLocation(m_shaderProgram, attrib.c_str()); auto pos = glGetAttribLocation(m_shaderProgram, attrib.c_str());
m_vertexLocCache[attrib] = pos; m_vertexLocCache[attrib] = pos;
return pos;
} }
return m_vertexLocCache[attrib]; return m_vertexLocCache[attrib];
@ -160,7 +200,6 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
if (m_dirtyMesh) { if (m_dirtyMesh) {
glUniform1i(m_locTexture1, 0); glUniform1i(m_locTexture1, 0);
glUniform1i(m_locTexture2, 1);
} }
if (m_dirtyMesh || m->textured != m_textured1) { if (m_dirtyMesh || m->textured != m_textured1) {
@ -178,10 +217,27 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
m_microTexScale = m->microTextureScale; m_microTexScale = m->microTextureScale;
} }
if (m_dirtyMesh || (m_baseTexSize[0] != m->width || m_baseTexSize[1] != m->height)) { if (m_dirtyMesh || m->microTextureID != m_microTexID) {
m_baseTexSize[0] = (float)m->width; glUniform1i(m_locMicroTexID, m->microTextureID);
m_baseTexSize[1] = (float)m->height; m_microTexID = m->microTextureID;
glUniform2fv(m_locBaseTexSize, 1, m_baseTexSize); }
if (m_dirtyMesh || (m_baseTexInfo[0] != m->x || m_baseTexInfo[1] != m->y) || m_baseTexInfo[2] != m->width || m_baseTexInfo[3] != m->height) {
m_baseTexInfo[0] = m->x;
m_baseTexInfo[1] = m->y;
m_baseTexInfo[2] = m->width;
m_baseTexInfo[3] = m->height;
int translatedX, translatedY;
CalcTexOffset(m_transX, m_transY, m_transPage, m->x, m->y, translatedX, translatedY); // need to apply model translation
glUniform4i(m_locBaseTexInfo, translatedX, translatedY, m->width, m->height);
}
if (m_dirtyMesh || m_baseTexType != m->format) {
m_baseTexType = m->format;
glUniform1i(m_locBaseTexType, m_baseTexType);
} }
if (m_dirtyMesh || m->inverted != m_textureInverted) { if (m_dirtyMesh || m->inverted != m_textureInverted) {
@ -282,6 +338,13 @@ void R3DShader::SetModelStates(const Model* model)
m_modelScale = model->scale; m_modelScale = model->scale;
} }
m_transX = model->textureOffsetX;
m_transY = model->textureOffsetY;
m_transPage = model->page;
// reset texture values
for (auto& i : m_baseTexInfo) { i = -1; }
glUniformMatrix4fv(m_locModelMat, 1, GL_FALSE, model->modelMat); glUniformMatrix4fv(m_locModelMat, 1, GL_FALSE, model->modelMat);
m_dirtyModel = false; m_dirtyModel = false;
@ -332,4 +395,22 @@ void R3DShader::PrintProgramResult(GLuint program)
printf("%s\n", infoLog.data()); printf("%s\n", infoLog.data());
} }
} }
void R3DShader::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY)
{
newX = (x + offX) & 2047; // wrap around 2048, shouldn't be required
int oldPage = y / 1024;
y -= (oldPage * 1024); // remove page from tex y
// calc newY with wrap around, wraps around in the same sheet, not into another memory sheet
newY = (y + offY) & 1023;
// add page to Y
newY += ((oldPage + page) & 1) * 1024; // max page 0-1
}
} // New3D } // New3D

View file

@ -4,7 +4,7 @@
#include <GL/glew.h> #include <GL/glew.h>
#include "Util/NewConfig.h" #include "Util/NewConfig.h"
#include "Model.h" #include "Model.h"
#include <unordered_map> #include <map>
#include <string> #include <string>
namespace New3D { namespace New3D {
@ -15,6 +15,7 @@ public:
R3DShader(const Util::Config::Node &config); R3DShader(const Util::Config::Node &config);
bool LoadShader (const char* vertexShader = nullptr, const char* fragmentShader = nullptr); bool LoadShader (const char* vertexShader = nullptr, const char* fragmentShader = nullptr);
void UnloadShader ();
void SetMeshUniforms (const Mesh* m); void SetMeshUniforms (const Mesh* m);
void SetModelStates (const Model* model); void SetModelStates (const Model* model);
void SetViewportUniforms (const Viewport *vp); void SetViewportUniforms (const Viewport *vp);
@ -28,6 +29,8 @@ private:
void PrintShaderResult(GLuint shader); void PrintShaderResult(GLuint shader);
void PrintProgramResult(GLuint program); void PrintProgramResult(GLuint program);
void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);
// run-time config // run-time config
const Util::Config::Node &m_config; const Util::Config::Node &m_config;
@ -39,13 +42,14 @@ private:
// mesh uniform locations // mesh uniform locations
GLint m_locTexture1; GLint m_locTexture1;
GLint m_locTexture2;
GLint m_locTexture1Enabled; GLint m_locTexture1Enabled;
GLint m_locTexture2Enabled; GLint m_locTexture2Enabled;
GLint m_locTextureAlpha; GLint m_locTextureAlpha;
GLint m_locAlphaTest; GLint m_locAlphaTest;
GLint m_locMicroTexScale; GLint m_locMicroTexScale;
GLint m_locBaseTexSize; GLint m_locMicroTexID;
GLint m_locBaseTexInfo;
GLint m_locBaseTexType;
GLint m_locTextureInverted; GLint m_locTextureInverted;
GLint m_locTexWrapMode; GLint m_locTexWrapMode;
GLint m_locTranslatorMap; GLint m_locTranslatorMap;
@ -65,12 +69,17 @@ private:
bool m_layered; bool m_layered;
float m_microTexScale; float m_microTexScale;
float m_baseTexSize[2]; int m_microTexID;
int m_baseTexInfo[4];
int m_baseTexType;
int m_texWrapMode[2]; int m_texWrapMode[2];
bool m_textureInverted; bool m_textureInverted;
// cached model values // cached model values
float m_modelScale; float m_modelScale;
int m_transX;
int m_transY;
int m_transPage;
// are our cache values dirty // are our cache values dirty
bool m_dirtyMesh; bool m_dirtyMesh;
@ -109,7 +118,7 @@ private:
GLint m_locDiscardAlpha; GLint m_locDiscardAlpha;
// vertex attribute position cache // vertex attribute position cache
std::unordered_map<std::string, GLint> m_vertexLocCache; std::map<std::string, GLint> m_vertexLocCache;
}; };

View file

@ -168,18 +168,19 @@ void main(void)
)glsl"; )glsl";
static const char *fragmentShaderR3DQuads = R"glsl( static const char *fragmentShaderR3DQuads1 = R"glsl(
#version 450 core #version 450 core
uniform sampler2D tex1; // base tex uniform usampler2D tex1; // entire texture sheet
uniform sampler2D tex2; // micro tex (optional)
// texturing // texturing
uniform bool textureEnabled; uniform bool textureEnabled;
uniform bool microTexture; uniform bool microTexture;
uniform float microTextureScale; uniform float microTextureScale;
uniform vec2 baseTexSize; uniform int microTextureID;
uniform ivec4 baseTexInfo; // x/y are x,y positions in the texture sheet. z/w are with and height
uniform int baseTexType;
uniform bool textureInverted; uniform bool textureInverted;
uniform bool textureAlpha; uniform bool textureAlpha;
uniform bool alphaTest; uniform bool alphaTest;
@ -207,7 +208,7 @@ uniform float fogAmbient;
uniform bool fixedShading; uniform bool fixedShading;
uniform int hardwareStep; uniform int hardwareStep;
// test // matrices (shared with vertex shader)
uniform mat4 projMat; uniform mat4 projMat;
//interpolated inputs from geometry shader //interpolated inputs from geometry shader
@ -340,6 +341,140 @@ void QuadraticInterpolation()
gl_FragDepth = depth * 0.5 + 0.5; gl_FragDepth = depth * 0.5 + 0.5;
} }
vec4 ExtractColour(int type, uint value)
{
vec4 c = vec4(0.0);
if(type==0) { // T1RGB5
c.r = float((value >> 10) & 0x1F) / 31.0;
c.g = float((value >> 5 ) & 0x1F) / 31.0;
c.b = float((value ) & 0x1F) / 31.0;
c.a = 1.0 - float((value >> 15) & 0x1);
}
else if(type==1) { // Interleaved A4L4 (low byte)
c.rgb = vec3(float(value&0xF) / 15.0);
c.a = float((value >> 4) & 0xF) / 15.0;
}
else if(type==2) {
c.a = float(value&0xF) / 15.0;
c.rgb = vec3(float((value >> 4) & 0xF) / 15.0);
}
else if(type==3) {
c.rgb = vec3(float((value>>8)&0xF) / 15.0);
c.a = float((value >> 12) & 0xF) / 15.0;
}
else if(type==4) {
c.a = float((value>>8)&0xF) / 15.0;
c.rgb = vec3(float((value >> 12) & 0xF) / 15.0);
}
else if(type==5) {
c = vec4(float(value&0xFF) / 255.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==6) {
c = vec4(float((value>>8)&0xFF) / 255.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==7) { // RGBA4
c.r = float((value>>12)&0xF) / 15.0;
c.g = float((value>> 8)&0xF) / 15.0;
c.b = float((value>> 4)&0xF) / 15.0;
c.a = float((value>> 0)&0xF) / 15.0;
}
else if(type==8) { // low byte, low nibble
c = vec4(float(value&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==9) { // low byte, high nibble
c = vec4(float((value>>4)&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==10) { // high byte, low nibble
c = vec4(float((value>>8)&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==11) { // high byte, high nibble
c = vec4(float((value>>12)&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
return c;
}
ivec2 GetTexturePosition(int level, ivec2 pos)
{
const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
int mipDivisor = 1 << level;
int page = pos.y / 1024;
pos.y -= (page * 1024); // remove page from tex y
ivec2 retPos;
retPos.x = mipXBase[level] + (pos.x / mipDivisor);
retPos.y = mipYBase[level] + (pos.y / mipDivisor);
retPos.y += (page * 1024); // add page back to tex y
return retPos;
}
ivec2 GetTextureSize(int level, ivec2 size)
{
int mipDivisor = 1 << level;
return size / mipDivisor;
}
ivec2 GetMicroTexturePos(int id)
{
int xCoords[8] = { 0, 0, 128, 128, 0, 0, 128, 128 };
int yCoords[8] = { 0, 128, 0, 128, 256, 384, 256, 384 };
return ivec2(xCoords[id],yCoords[id]);
}
int GetPage(int yCoord)
{
return yCoord / 1024;
}
int GetNextPage(int yCoord)
{
return (GetPage(yCoord) + 1) & 1;
}
int GetNextPageOffset(int yCoord)
{
return GetNextPage(yCoord) * 1024;
}
// wrapping tex coords would be super easy but we combined tex sheets so have to handle wrap around between sheets
// hardware testing would be useful because i don't know exactly what happens if you try to read outside the texture sheet
// wrap around is a good guess
ivec2 WrapTexCoords(ivec2 pos, ivec2 coordinate)
{
ivec2 newCoord;
newCoord.x = coordinate.x & 2047;
newCoord.y = coordinate.y;
int page = GetPage(pos.y);
newCoord.y -= (page * 1024); // remove page
newCoord.y &= 1023; // wrap around in the same sheet
newCoord.y += (page * 1024); // add page back
return newCoord;
}
float mip_map_level(in vec2 texture_coordinate) // in texel units float mip_map_level(in vec2 texture_coordinate) // in texel units
{ {
vec2 dx_vtc = dFdx(texture_coordinate); vec2 dx_vtc = dFdx(texture_coordinate);
@ -396,16 +531,16 @@ float LinearTexLocations(int wrapMode, float size, float u, out float u0, out fl
} }
} }
vec4 texBiLinear(sampler2D texSampler, float level, ivec2 wrapMode, vec2 texSize, vec2 texCoord) vec4 texBiLinear(usampler2D texSampler, ivec2 wrapMode, vec2 texSize, ivec2 texPos, vec2 texCoord)
{ {
float tx[2], ty[2]; float tx[2], ty[2];
float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]); float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]);
float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]); float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]);
vec4 p0q0 = textureLod(texSampler, vec2(tx[0],ty[0]), level); vec4 p0q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[0]) * texSize + texPos)), 0).r);
vec4 p1q0 = textureLod(texSampler, vec2(tx[1],ty[0]), level); vec4 p1q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[0]) * texSize + texPos)), 0).r);
vec4 p0q1 = textureLod(texSampler, vec2(tx[0],ty[1]), level); vec4 p0q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[1]) * texSize + texPos)), 0).r);
vec4 p1q1 = textureLod(texSampler, vec2(tx[1],ty[1]), level); vec4 p1q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[1]) * texSize + texPos)), 0).r);
if(alphaTest) { if(alphaTest) {
if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; } if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; }
@ -428,48 +563,59 @@ vec4 texBiLinear(sampler2D texSampler, float level, ivec2 wrapMode, vec2 texSize
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction. return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
} }
vec4 textureR3D(sampler2D texSampler, ivec2 wrapMode, vec2 texSize, vec2 texCoord) vec4 textureR3D(usampler2D texSampler, ivec2 wrapMode, ivec2 texSize, ivec2 texPos, vec2 texCoord)
{ {
float numLevels = floor(log2(min(texSize.x, texSize.y))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension float numLevels = floor(log2(min(float(texSize.x), float(texSize.y)))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension
float fLevel = min(mip_map_level(texCoord * texSize), numLevels); float fLevel = min(mip_map_level(texCoord * vec2(texSize)), numLevels);
fLevel *= alphaTest ? 0.5 : 0.8; if(alphaTest) fLevel *= 0.5;
else fLevel *= 0.8;
float iLevel = floor(fLevel); // value as an 'int' int iLevel = int(fLevel);
vec2 texSize0 = texSize / exp2(iLevel); ivec2 texPos0 = GetTexturePosition(iLevel,texPos);
vec2 texSize1 = texSize / exp2(iLevel+1.0); ivec2 texPos1 = GetTexturePosition(iLevel+1,texPos);
vec4 texLevel0 = texBiLinear(texSampler, iLevel, wrapMode, texSize0, texCoord); ivec2 texSize0 = GetTextureSize(iLevel, texSize);
vec4 texLevel1 = texBiLinear(texSampler, iLevel+1.0, wrapMode, texSize1, texCoord); ivec2 texSize1 = GetTextureSize(iLevel+1, texSize);
vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord);
vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord);
return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels
} }
vec4 GetTextureValue() vec4 GetTextureValue()
{ {
vec4 tex1Data = textureR3D(tex1, textureWrapMode, baseTexSize, fsTexCoord); vec4 tex1Data = textureR3D(tex1, textureWrapMode, ivec2(baseTexInfo.zw), ivec2(baseTexInfo.xy), fsTexCoord);
if(textureInverted) { if(textureInverted) {
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb); tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
} }
if (microTexture) { if (microTexture) {
vec2 scale = (baseTexSize / 128.0) * microTextureScale; vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * microTextureScale;
vec4 tex2Data = textureR3D( tex2, ivec2(0.0), vec2(128.0), fsTexCoord * scale); ivec2 pos = GetMicroTexturePos(microTextureID);
// add page offset to microtexture position
pos.y += GetNextPageOffset(baseTexInfo.y);
vec4 tex2Data = textureR3D(tex1, ivec2(0), ivec2(128), pos, fsTexCoord * scale);
float lod = mip_map_level(fsTexCoord * scale * vec2(128.0)); float lod = mip_map_level(fsTexCoord * scale * vec2(128.0));
float blendFactor = max(lod - 1.5, 0.0); // bias -1.5 float blendFactor = max(lod - 1.5, 0.0); // bias -1.5
blendFactor = min(blendFactor, 1.0); // clamp to max value 1 blendFactor = min(blendFactor, 1.0); // clamp to max value 1
blendFactor = blendFactor * 0.5 + 0.5; // 0.5 - 1 range blendFactor = (blendFactor + 1.0) / 2.0; // 0.5 - 1 range
tex1Data = mix(tex2Data, tex1Data, blendFactor); tex1Data = mix(tex2Data, tex1Data, blendFactor);
} }
if (alphaTest && (tex1Data.a < (32.0/255.0))) { if (alphaTest) {
if (tex1Data.a < (32.0/255.0)) {
discard; discard;
} }
}
if(textureAlpha) { if(textureAlpha) {
if(discardAlpha) { // opaque 1st pass if(discardAlpha) { // opaque 1st pass
@ -484,7 +630,7 @@ vec4 GetTextureValue()
} }
} }
if (!textureAlpha) { if (textureAlpha == false) {
tex1Data.a = 1.0; tex1Data.a = 1.0;
} }
@ -526,6 +672,10 @@ float sqr_length(vec2 a)
return a.x*a.x + a.y*a.y; return a.x*a.x + a.y*a.y;
} }
)glsl";
static const char* fragmentShaderR3DQuads2 = R"glsl(
void main() void main()
{ {
vec4 tex1Data; vec4 tex1Data;

View file

@ -3,7 +3,7 @@
static const char *vertexShaderR3D = R"glsl( static const char *vertexShaderR3D = R"glsl(
#version 120 #version 410 core
// uniforms // uniforms
uniform float modelScale; uniform float modelScale;
@ -12,20 +12,20 @@ uniform mat4 projMat;
uniform bool translatorMap; uniform bool translatorMap;
// attributes // attributes
attribute vec4 inVertex; in vec4 inVertex;
attribute vec3 inNormal; in vec3 inNormal;
attribute vec2 inTexCoord; in vec2 inTexCoord;
attribute vec4 inColour; in vec4 inColour;
attribute vec3 inFaceNormal; // used to emulate r3d culling in vec3 inFaceNormal; // used to emulate r3d culling
attribute float inFixedShade; in float inFixedShade;
// outputs to fragment shader // outputs to fragment shader
varying vec3 fsViewVertex; out vec3 fsViewVertex;
varying vec3 fsViewNormal; // per vertex normal vector out vec3 fsViewNormal; // per vertex normal vector
varying vec2 fsTexCoord; out vec2 fsTexCoord;
varying vec4 fsColor; out vec4 fsColor;
varying float fsDiscard; // can't have varying bool (glsl spec) out float fsDiscard; // can't have varying bool (glsl spec)
varying float fsFixedShade; out float fsFixedShade;
vec4 GetColour(vec4 colour) vec4 GetColour(vec4 colour)
{ {
@ -61,17 +61,17 @@ void main(void)
static const char *fragmentShaderR3D = R"glsl( static const char *fragmentShaderR3D = R"glsl(
#version 120 #version 410 core
#extension GL_ARB_shader_texture_lod : require
uniform sampler2D tex1; // base tex uniform usampler2D tex1; // entire texture sheet
uniform sampler2D tex2; // micro tex (optional)
// texturing // texturing
uniform bool textureEnabled; uniform bool textureEnabled;
uniform bool microTexture; uniform bool microTexture;
uniform float microTextureScale; uniform float microTextureScale;
uniform vec2 baseTexSize; uniform int microTextureID;
uniform ivec4 baseTexInfo; // x/y are x,y positions in the texture sheet. z/w are with and height
uniform int baseTexType;
uniform bool textureInverted; uniform bool textureInverted;
uniform bool textureAlpha; uniform bool textureAlpha;
uniform bool alphaTest; uniform bool alphaTest;
@ -100,12 +100,149 @@ uniform bool fixedShading;
uniform int hardwareStep; uniform int hardwareStep;
//interpolated inputs from vertex shader //interpolated inputs from vertex shader
varying vec3 fsViewVertex; in vec3 fsViewVertex;
varying vec3 fsViewNormal; // per vertex normal vector in vec3 fsViewNormal; // per vertex normal vector
varying vec4 fsColor; in vec4 fsColor;
varying vec2 fsTexCoord; in vec2 fsTexCoord;
varying float fsDiscard; in float fsDiscard;
varying float fsFixedShade; in float fsFixedShade;
//outputs
out vec4 outColor;
vec4 ExtractColour(int type, uint value)
{
vec4 c = vec4(0.0);
if(type==0) { // T1RGB5
c.r = float((value >> 10) & 0x1F) / 31.0;
c.g = float((value >> 5 ) & 0x1F) / 31.0;
c.b = float((value ) & 0x1F) / 31.0;
c.a = 1.0 - float((value >> 15) & 0x1);
}
else if(type==1) { // Interleaved A4L4 (low byte)
c.rgb = vec3(float(value&0xF) / 15.0);
c.a = float((value >> 4) & 0xF) / 15.0;
}
else if(type==2) {
c.a = float(value&0xF) / 15.0;
c.rgb = vec3(float((value >> 4) & 0xF) / 15.0);
}
else if(type==3) {
c.rgb = vec3(float((value>>8)&0xF) / 15.0);
c.a = float((value >> 12) & 0xF) / 15.0;
}
else if(type==4) {
c.a = float((value>>8)&0xF) / 15.0;
c.rgb = vec3(float((value >> 12) & 0xF) / 15.0);
}
else if(type==5) {
c = vec4(float(value&0xFF) / 255.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==6) {
c = vec4(float((value>>8)&0xFF) / 255.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==7) { // RGBA4
c.r = float((value>>12)&0xF) / 15.0;
c.g = float((value>> 8)&0xF) / 15.0;
c.b = float((value>> 4)&0xF) / 15.0;
c.a = float((value>> 0)&0xF) / 15.0;
}
else if(type==8) { // low byte, low nibble
c = vec4(float(value&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==9) { // low byte, high nibble
c = vec4(float((value>>4)&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==10) { // high byte, low nibble
c = vec4(float((value>>8)&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
else if(type==11) { // high byte, high nibble
c = vec4(float((value>>12)&0xF) / 15.0);
if(c.a==1.0) { c.a = 0.0; }
else { c.a = 1.0; }
}
return c;
}
ivec2 GetTexturePosition(int level, ivec2 pos)
{
const int mipXBase[] = int[](0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047);
const int mipYBase[] = int[](0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023);
int mipDivisor = 1 << level;
int page = pos.y / 1024;
pos.y -= (page * 1024); // remove page from tex y
ivec2 retPos;
retPos.x = mipXBase[level] + (pos.x / mipDivisor);
retPos.y = mipYBase[level] + (pos.y / mipDivisor);
retPos.y += (page * 1024); // add page back to tex y
return retPos;
}
ivec2 GetTextureSize(int level, ivec2 size)
{
int mipDivisor = 1 << level;
return size / mipDivisor;
}
ivec2 GetMicroTexturePos(int id)
{
const int xCoords[8] = int[](0, 0, 128, 128, 0, 0, 128, 128);
const int yCoords[8] = int[](0, 128, 0, 128, 256, 384, 256, 384);
return ivec2(xCoords[id],yCoords[id]);
}
int GetPage(int yCoord)
{
return yCoord / 1024;
}
int GetNextPage(int yCoord)
{
return (GetPage(yCoord) + 1) & 1;
}
int GetNextPageOffset(int yCoord)
{
return GetNextPage(yCoord) * 1024;
}
// wrapping tex coords would be super easy but we combined tex sheets so have to handle wrap around between sheets
// hardware testing would be useful because i don't know exactly what happens if you try to read outside the texture sheet
// wrap around is a good guess
ivec2 WrapTexCoords(ivec2 pos, ivec2 coordinate)
{
ivec2 newCoord;
newCoord.x = coordinate.x & 2047;
newCoord.y = coordinate.y;
int page = GetPage(pos.y);
newCoord.y -= (page * 1024); // remove page
newCoord.y &= 1023; // wrap around in the same sheet
newCoord.y += (page * 1024); // add page back
return newCoord;
}
float mip_map_level(in vec2 texture_coordinate) // in texel units float mip_map_level(in vec2 texture_coordinate) // in texel units
{ {
@ -163,16 +300,16 @@ float LinearTexLocations(int wrapMode, float size, float u, out float u0, out fl
} }
} }
vec4 texBiLinear(sampler2D texSampler, float level, ivec2 wrapMode, vec2 texSize, vec2 texCoord) vec4 texBiLinear(usampler2D texSampler, ivec2 wrapMode, vec2 texSize, ivec2 texPos, vec2 texCoord)
{ {
float tx[2], ty[2]; float tx[2], ty[2];
float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]); float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]);
float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]); float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]);
vec4 p0q0 = texture2DLod(texSampler, vec2(tx[0],ty[0]), level); vec4 p0q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[0]) * texSize + texPos)), 0).r);
vec4 p1q0 = texture2DLod(texSampler, vec2(tx[1],ty[0]), level); vec4 p1q0 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[0]) * texSize + texPos)), 0).r);
vec4 p0q1 = texture2DLod(texSampler, vec2(tx[0],ty[1]), level); vec4 p0q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[0],ty[1]) * texSize + texPos)), 0).r);
vec4 p1q1 = texture2DLod(texSampler, vec2(tx[1],ty[1]), level); vec4 p1q1 = ExtractColour(baseTexType,texelFetch(texSampler, WrapTexCoords(texPos,ivec2(vec2(tx[1],ty[1]) * texSize + texPos)), 0).r);
if(alphaTest) { if(alphaTest) {
if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; } if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; }
@ -195,36 +332,44 @@ vec4 texBiLinear(sampler2D texSampler, float level, ivec2 wrapMode, vec2 texSize
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction. return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
} }
vec4 textureR3D(sampler2D texSampler, ivec2 wrapMode, vec2 texSize, vec2 texCoord) vec4 textureR3D(usampler2D texSampler, ivec2 wrapMode, ivec2 texSize, ivec2 texPos, vec2 texCoord)
{ {
float numLevels = floor(log2(min(texSize.x, texSize.y))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension float numLevels = floor(log2(min(float(texSize.x), float(texSize.y)))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension
float fLevel = min(mip_map_level(texCoord * texSize), numLevels); float fLevel = min(mip_map_level(texCoord * vec2(texSize)), numLevels);
if(alphaTest) fLevel *= 0.5; if(alphaTest) fLevel *= 0.5;
else fLevel *= 0.8; else fLevel *= 0.8;
float iLevel = floor(fLevel); // value as an 'int' int iLevel = int(fLevel);
vec2 texSize0 = texSize / pow(2, iLevel); ivec2 texPos0 = GetTexturePosition(iLevel,texPos);
vec2 texSize1 = texSize / pow(2, iLevel+1.0); ivec2 texPos1 = GetTexturePosition(iLevel+1,texPos);
vec4 texLevel0 = texBiLinear(texSampler, iLevel, wrapMode, texSize0, texCoord); ivec2 texSize0 = GetTextureSize(iLevel, texSize);
vec4 texLevel1 = texBiLinear(texSampler, iLevel+1.0, wrapMode, texSize1, texCoord); ivec2 texSize1 = GetTextureSize(iLevel+1, texSize);
vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord);
vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord);
return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels
} }
vec4 GetTextureValue() vec4 GetTextureValue()
{ {
vec4 tex1Data = textureR3D(tex1, textureWrapMode, baseTexSize, fsTexCoord); vec4 tex1Data = textureR3D(tex1, textureWrapMode, ivec2(baseTexInfo.zw), ivec2(baseTexInfo.xy), fsTexCoord);
if(textureInverted) { if(textureInverted) {
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb); tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
} }
if (microTexture) { if (microTexture) {
vec2 scale = (baseTexSize / 128.0) * microTextureScale; vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * microTextureScale;
vec4 tex2Data = textureR3D( tex2, ivec2(0), vec2(128.0), fsTexCoord * scale); ivec2 pos = GetMicroTexturePos(microTextureID);
// add page offset to microtexture position
pos.y += GetNextPageOffset(baseTexInfo.y);
vec4 tex2Data = textureR3D(tex1, ivec2(0), ivec2(128), pos, fsTexCoord * scale);
float lod = mip_map_level(fsTexCoord * scale * vec2(128.0)); float lod = mip_map_level(fsTexCoord * scale * vec2(128.0));
@ -421,7 +566,7 @@ void main()
// Fog & spotlight applied // Fog & spotlight applied
finalData.rgb = mix(finalData.rgb, fogData.rgb + lSpotFogColor, fogData.a); finalData.rgb = mix(finalData.rgb, fogData.rgb + lSpotFogColor, fogData.a);
gl_FragColor = finalData; outColor = finalData;
} }
)glsl"; )glsl";

View file

@ -1,370 +0,0 @@
#include "Texture.h"
#include <stdio.h>
#include <math.h>
#include <algorithm>
namespace New3D {
Texture::Texture()
{
Reset();
}
Texture::~Texture()
{
DeleteTexture(); // make sure to have valid context before destroying
}
void Texture::DeleteTexture()
{
if (m_textureID) {
glDeleteTextures(1, &m_textureID);
Reset();
}
}
void Texture::Reset()
{
m_x = 0;
m_y = 0;
m_width = 0;
m_height = 0;
m_format = 0;
m_textureID = 0;
}
void Texture::BindTexture()
{
glBindTexture(GL_TEXTURE_2D, m_textureID);
}
void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
{
uOut = (uIn*uvScale) / m_width;
vOut = (vIn*uvScale) / m_height;
}
void Texture::GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
{
uOut = (uIn*uvScale) / width;
vOut = (vIn*uvScale) / height;
}
void Texture::UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height)
{
int xi, yi, i;
int subWidth, subHeight;
GLubyte texel;
GLubyte c, a;
i = 0;
subWidth = width;
subHeight = height;
if (subWidth + x > 2048) {
subWidth = 2048 - x;
}
if (subHeight + y > 2048) {
subHeight = 2048 - y;
}
switch (format)
{
default: // Debug texture
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
scratch[i++] = 255; // R
scratch[i++] = 0; // G
scratch[i++] = 0; // B
scratch[i++] = 255; // A
}
}
break;
case 0: // T1RGB5 <- correct
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
scratch[i++] = ((src[yi * 2048 + xi] >> 10) & 0x1F) * 255 / 0x1F; // R
scratch[i++] = ((src[yi * 2048 + xi] >> 5) & 0x1F) * 255 / 0x1F; // G
scratch[i++] = ((src[yi * 2048 + xi] >> 0) & 0x1F) * 255 / 0x1F; // B
scratch[i++] = ((src[yi * 2048 + xi] & 0x8000) ? 0 : 255); // T
}
}
break;
case 1: // Interleaved A4L4 (low byte)
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
// Interpret as A4L4
texel = src[yi * 2048 + xi] & 0xFF;
c = (texel & 0xF) * 17;
a = (texel >> 4) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = a;
}
}
break;
case 2: // luminance alpha texture <- this one is correct
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] & 0xFF;
c = ((texel >> 4) & 0xF) * 17;
a = (texel & 0xF) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = a;
}
}
break;
case 3: // 8-bit, A4L4 (high byte)
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] >> 8;
c = (texel & 0xF) * 17;
a = (texel >> 4) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = a;
}
}
break;
case 4: // 8-bit, L4A4 (high byte)
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] >> 8;
c = ((texel >> 4) & 0xF) * 17;
a = (texel & 0xF) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = a;
}
}
break;
case 5: // 8-bit grayscale
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] & 0xFF;
scratch[i++] = texel;
scratch[i++] = texel;
scratch[i++] = texel;
scratch[i++] = (texel == 255 ? 0 : 255);
}
}
break;
case 6: // 8-bit grayscale <-- this one is correct
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] >> 8;
scratch[i++] = texel;
scratch[i++] = texel;
scratch[i++] = texel;
scratch[i++] = (texel == 255 ? 0 : 255);
}
}
break;
case 7: // RGBA4
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
scratch[i++] = ((src[yi * 2048 + xi] >> 12) & 0xF) * 17;// R
scratch[i++] = ((src[yi * 2048 + xi] >> 8) & 0xF) * 17; // G
scratch[i++] = ((src[yi * 2048 + xi] >> 4) & 0xF) * 17; // B
scratch[i++] = ((src[yi * 2048 + xi] >> 0) & 0xF) * 17; // A
}
}
break;
//
// 4 bit texture types - all luminance textures (no alpha), only seem to be enabled when contour is enabled ( white = contour value )
//
case 8: // low byte, low nibble
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] & 0xFF;
c = (texel & 0xF) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = (c == 255 ? 0 : 255);
}
}
break;
case 9: // low byte, high nibble
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] & 0xFF;
c = ((texel >> 4) & 0xF) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = (c == 255 ? 0 : 255);
}
}
break;
case 10: // high byte, low nibble
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] >> 8;
c = (texel & 0xF) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = (c == 255 ? 0 : 255);
}
}
break;
case 11: // high byte, high nibble
for (yi = y; yi < (y + subHeight); yi++)
{
for (xi = x; xi < (x + subWidth); xi++)
{
texel = src[yi * 2048 + xi] >> 8;
c = ((texel >> 4) & 0xF) * 17;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = c;
scratch[i++] = (c == 255 ? 0 : 255);
}
}
break;
}
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, subWidth, subHeight, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
}
UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height)
{
const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
const int mipDivisor[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 };
if (!src || !scratch) {
return 0; // sanity checking
}
DeleteTexture(); // free any existing texture
CreateTextureObject(format, x, y, width, height);
int page = y / 1024;
y -= (page * 1024); // remove page from tex y
for (int i = 0; width > 0 && height > 0; i++) {
int xPos = mipXBase[i] + (x / mipDivisor[i]);
int yPos = mipYBase[i] + (y / mipDivisor[i]);
UploadTextureMip(i, src, scratch, format, xPos, yPos + (page * 1024), width, height);
width /= 2;
height /= 2;
}
return m_textureID;
}
void Texture::GetDetails(int& x, int&y, int& width, int& height, int& format)
{
x = m_x;
y = m_y;
width = m_width;
height = m_height;
format = m_format;
}
bool Texture::Compare(int x, int y, int width, int height, int format)
{
if (m_x == x && m_y == y && m_width == width && m_height == height && m_format == format) {
return true;
}
return false;
}
bool Texture::CheckMapPos(int ax1, int ax2, int ay1, int ay2)
{
int bx1 = m_x;
int bx2 = m_x + m_width;
int by1 = m_y;
int by2 = m_y + m_height;
if (ax1<bx2 && ax2>bx1 &&
ay1<by2 && ay2>by1) {
return true; // rectangles overlap
}
return false;
}
void Texture::CreateTextureObject(int format, int x, int y, int width, int height)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // rgba is always 4 byte aligned
glGenTextures(1, &m_textureID);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
int minD = std::min(width, height);
int count = 0;
while (minD > 1) {
minD /= 2;
count++;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count);
m_x = x;
m_y = y;
m_width = width;
m_height = height;
m_format = format;
}
} // New3D

View file

@ -1,42 +0,0 @@
#ifndef _TEXTURE_H_
#define _TEXTURE_H_
#include "Types.h"
#include <GL/glew.h>
namespace New3D {
class Texture
{
public:
Texture();
~Texture();
UINT32 UploadTexture (const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height);
void DeleteTexture ();
void BindTexture ();
void GetCoordinates (UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
void GetDetails (int& x, int&y, int& width, int& height, int& format);
bool Compare (int x, int y, int width, int height, int format);
bool CheckMapPos (int ax1, int ax2, int ay1, int ay2); //check to see if textures overlap
static void GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
private:
void CreateTextureObject(int format, int x, int y, int width, int height);
void UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height);
void Reset();
int m_x;
int m_y;
int m_width;
int m_height;
int m_format;
GLuint m_textureID;
};
} // New3D
#endif

View file

@ -1,181 +0,0 @@
#include "TextureSheet.h"
namespace New3D {
TextureSheet::TextureSheet()
{
m_temp.resize(1024 * 1024 * 4); // temporary buffer for textures
}
int TextureSheet::ToIndex(int x, int y)
{
return (y * 2048) + x;
}
std::shared_ptr<Texture> TextureSheet::BindTexture(const UINT16* src, int format, int x, int y, int width, int height)
{
//========
int index;
//========
x &= 2047;
y &= 2047;
if (width > 1024 || height > 1024) { // sanity checking
return nullptr;
}
index = ToIndex(x, y);
auto range = m_texMap.equal_range(index);
if (range.first == range.second) {
// nothing found so create a new texture
std::shared_ptr<Texture> t(new Texture());
m_texMap.insert(std::pair<int, std::shared_ptr<Texture>>(index, t));
t->UploadTexture(src, m_temp.data(), format, x, y, width, height);
return t;
}
else {
// iterate to try and find a match
for (auto it = range.first; it != range.second; ++it) {
int x2, y2, width2, height2, format2;
it->second->GetDetails(x2, y2, width2, height2, format2);
if (width == width2 && height == height2 && format == format2) {
return it->second;
}
}
// nothing found so create a new entry
std::shared_ptr<Texture> t(new Texture());
m_texMap.insert(std::pair<int, std::shared_ptr<Texture>>(index, t));
t->UploadTexture(src, m_temp.data(), format, x, y, width, height);
return t;
}
}
void TextureSheet::Release()
{
m_texMap.clear();
}
void TextureSheet::Invalidate(int x, int y, int width, int height)
{
//============
int newX;
int newY;
int newWidth;
int newHeight;
int count;
int sWidth; // sample width
int sHeight; // sample height
//============
if (width <= 512) {
newX = (x + width) - 512;
newWidth = 512;
}
else {
newX = x;
newWidth = width;
}
if (height <= 512) {
newY = (y + height) - 512;
newHeight = 512;
}
else {
newY = y;
newHeight = height;
}
CropTile(x, y, newX, newY, newWidth, newHeight);
sWidth = newWidth / 32;
sHeight = newHeight / 32;
count = sWidth * sHeight;
for (int i = 0; i < count; i++) {
int posX = newX + ((i%sWidth) * 32);
int posY = newY + ((i / sWidth) * 32);
int index = ToIndex(posX, posY);
if (posX >= x && posY >= y) { // invalidate this area of memory
m_texMap.erase(index);
}
else { // check for overlapping data tiles and invalidate as necessary
auto range = m_texMap.equal_range(index);
for (auto it = range.first; it != range.second; ++it) {
if (it->second->CheckMapPos(x, x + width, y, y + height)) {
m_texMap.erase(index);
break;
}
}
}
}
}
void TextureSheet::CropTile(int oldX, int oldY, int &newX, int &newY, int &newWidth, int &newHeight)
{
if (newX < 0) {
newWidth += newX;
newX = 0;
}
if (newY < 0) {
newHeight += newY;
newY = 0;
}
if (oldY >= 1024 && newY < 1024) { // gone into next memory page, limitation of our flat model
newHeight -= 1024 - newY;
newY = 1024;
}
}
int TextureSheet::GetTexFormat(int originalFormat, bool contour)
{
if (!contour) {
return originalFormat; // the same
}
switch (originalFormat)
{
case 1:
case 2:
case 3:
case 4:
return originalFormat + 7; // these formats are identical to 1-4, except they lose the 4 bit alpha part when contour is enabled
default:
return originalFormat;
}
}
void TextureSheet::GetMicrotexPos(int basePage, int id, int& x, int& y)
{
int xCoords[8] = { 0, 0, 128, 128, 0, 0, 128, 128 };
int yCoords[8] = { 0, 128, 0, 128, 256, 384, 256, 384 };
// i'm assuming .. the micro texture map is always on the other memory bank to the base texture
// this logic works for all our current games
// the microtextures are always on the top left of each texture sheet
basePage = (basePage + 1) & 1; // wrap around base page
x = xCoords[id];
y = yCoords[id] + (basePage * 1024);
}
} // New3D

View file

@ -1,38 +0,0 @@
#ifndef _TEXTURE_SHEET_H_
#define _TEXTURE_SHEET_H_
#include "Types.h"
#include <unordered_map>
#include <vector>
#include <memory>
#include "Texture.h"
namespace New3D {
class TextureSheet
{
public:
TextureSheet();
std::shared_ptr<Texture> BindTexture (const UINT16* src, int format, int x, int y, int width, int height);
void Invalidate (int x, int y, int width, int height); // release parts of the memory
void Release (); // release all texture objects and memory
int GetTexFormat (int originalFormat, bool contour);
void GetMicrotexPos (int basePage, int id, int& x, int& y);
private:
int ToIndex(int x, int y);
void CropTile(int oldX, int oldY, int &newX, int &newY, int &newWidth, int &newHeight);
std::unordered_multimap<int, std::shared_ptr<Texture>> m_texMap;
// the key for the above maps is the x/y position in the 2048x2048 texture
// array of 8 planes for each texture type
std::vector<UINT8> m_temp;
};
} // New3D
#endif

View file

@ -1,7 +1,5 @@
#include "VBO.h" #include "VBO.h"
namespace New3D {
VBO::VBO() VBO::VBO()
{ {
m_id = 0; m_id = 0;
@ -17,7 +15,7 @@ void VBO::Create(GLenum target, GLenum usage, GLsizeiptr size, const void* data)
glBufferData(target, size, data, usage); // upload data to video card glBufferData(target, size, data, usage); // upload data to video card
m_target = target; m_target = target;
m_capacity = size; m_capacity = (int)size;
m_size = 0; m_size = 0;
Bind(false); // unbind Bind(false); // unbind
@ -40,7 +38,7 @@ bool VBO::AppendData(GLsizeiptr size, const GLvoid* data)
BufferSubData(m_size, size, data); BufferSubData(m_size, size, data);
m_size += size; m_size += (int)size;
return true; return true;
} }
@ -80,5 +78,3 @@ int VBO::GetCapacity()
{ {
return m_capacity; return m_capacity;
} }
} // New3D

View file

@ -3,8 +3,6 @@
#include <GL/glew.h> #include <GL/glew.h>
namespace New3D {
class VBO class VBO
{ {
public: public:
@ -26,6 +24,4 @@ private:
int m_size; int m_size;
}; };
} // New3D
#endif #endif

View file

@ -495,15 +495,20 @@ std::pair<bool, bool> CRender2D::DrawTilemaps(uint32_t *pixelsBottom, uint32_t *
// Draws a surface to the screen (0 is top and 1 is bottom) // Draws a surface to the screen (0 is top and 1 is bottom)
void CRender2D::DisplaySurface(int surface) void CRender2D::DisplaySurface(int surface)
{ {
// Shader program
m_shader.EnableShader();
glBindVertexArray(m_vao);
// Draw the surface // Draw the surface
glActiveTexture(GL_TEXTURE0); // texture unit 0 glActiveTexture(GL_TEXTURE0); // texture unit 0
glBindTexture(GL_TEXTURE_2D, m_texID[surface]); glBindTexture(GL_TEXTURE_2D, m_texID[surface]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f); glBindVertexArray(0);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f);
glEnd(); m_shader.DisableShader();
} }
// Set up viewport and OpenGL state for 2D rendering (sets up blending function but disables blending) // Set up viewport and OpenGL state for 2D rendering (sets up blending function but disables blending)
@ -515,9 +520,6 @@ void CRender2D::Setup2D(bool isBottom)
// Disable Z-buffering // Disable Z-buffering
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
// Shader program
glUseProgram(m_shaderProgram);
// Clear everything if requested or just overscan areas for wide screen mode // Clear everything if requested or just overscan areas for wide screen mode
if (isBottom) if (isBottom)
{ {
@ -534,11 +536,6 @@ void CRender2D::Setup2D(bool isBottom)
{ {
glViewport(m_xOffset - m_correction, m_yOffset + m_correction, m_xPixels, m_yPixels); //Preserve aspect ratio of tile layer by constraining and centering viewport glViewport(m_xOffset - m_correction, m_yOffset + m_correction, m_xPixels, m_yPixels); //Preserve aspect ratio of tile layer by constraining and centering viewport
} }
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 1.0, 0.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
} }
void CRender2D::BeginFrame(void) void CRender2D::BeginFrame(void)
@ -626,15 +623,6 @@ void CRender2D::AttachVRAM(const uint8_t *vramPtr)
bool CRender2D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes) bool CRender2D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes)
{ {
// Load shaders
if (OKAY != LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, m_config["VertexShader2D"].ValueAs<std::string>(), m_config["FragmentShader2D"].ValueAs<std::string>(), s_vertexShaderSource, s_fragmentShaderSource))
return FAIL;
// Get locations of the uniforms
glUseProgram(m_shaderProgram); // bind program
m_textureMapLoc = glGetUniformLocation(m_shaderProgram, "textureMap");
glUniform1i(m_textureMapLoc, 0); // attach it to texture unit 0
// Allocate memory for layer surfaces // Allocate memory for layer surfaces
m_memoryPool = new(std::nothrow) uint8_t[MEMORY_POOL_SIZE]; m_memoryPool = new(std::nothrow) uint8_t[MEMORY_POOL_SIZE];
if (NULL == m_memoryPool) if (NULL == m_memoryPool)
@ -654,6 +642,25 @@ bool CRender2D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned
m_totalYPixels = totalYRes; m_totalYPixels = totalYRes;
m_correction = (UINT32)(((yRes / 384.f) * 2) + 0.5f); // for some reason the 2d layer is 2 pixels off the 3D m_correction = (UINT32)(((yRes / 384.f) * 2) + 0.5f); // for some reason the 2d layer is 2 pixels off the 3D
DebugLog("Render2D initialized (allocated %1.1f MB)\n", float(MEMORY_POOL_SIZE) / 0x100000);
return OKAY;
}
CRender2D::CRender2D(const Util::Config::Node& config)
: m_config(config),
m_vao(0)
{
DebugLog("Built Render2D\n");
m_shader.LoadShaders(s_vertexShaderSource, s_fragmentShaderSource);
m_shader.GetUniformLocationMap("tex1");
m_shader.EnableShader();
// update uniform memory
glUniform1i(m_shader.uniformLocMap["tex1"], 0); // bind to texture unit zero
m_shader.DisableShader();
// Create textures // Create textures
glActiveTexture(GL_TEXTURE0); // texture unit 0 glActiveTexture(GL_TEXTURE0); // texture unit 0
glGenTextures(2, m_texID); glGenTextures(2, m_texID);
@ -668,21 +675,22 @@ bool CRender2D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 496, 384, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 496, 384, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
} }
DebugLog("Render2D initialized (allocated %1.1f MB)\n", float(MEMORY_POOL_SIZE) / 0x100000); glGenVertexArrays(1, &m_vao);
return OKAY; glBindVertexArray(m_vao);
} // no states needed since we do it in the shader
glBindVertexArray(0);
CRender2D::CRender2D(const Util::Config::Node &config)
: m_config(config)
{
DebugLog("Built Render2D\n");
} }
CRender2D::~CRender2D(void) CRender2D::~CRender2D(void)
{ {
DestroyShaderProgram(m_shaderProgram, m_vertexShader, m_fragmentShader); m_shader.UnloadShaders();
glDeleteTextures(2, m_texID); glDeleteTextures(2, m_texID);
if (m_vao) {
glDeleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_memoryPool) if (m_memoryPool)
{ {
delete [] m_memoryPool; delete [] m_memoryPool;

View file

@ -30,6 +30,7 @@
#include <GL/glew.h> #include <GL/glew.h>
#include "Util/NewConfig.h" #include "Util/NewConfig.h"
#include "New3D/GLSLShader.h"
/* /*
@ -195,11 +196,8 @@ private:
unsigned m_totalYPixels; unsigned m_totalYPixels;
unsigned m_correction = 0; unsigned m_correction = 0;
// Shader programs and input data locations GLuint m_vao;
GLuint m_shaderProgram; // shader program object GLSLShader m_shader;
GLuint m_vertexShader; // vertex shader handle
GLuint m_fragmentShader; // fragment shader
GLuint m_textureMapLoc; // location of "textureMap" uniform
// PreRenderFrame() tracks which surfaces exist in current frame // PreRenderFrame() tracks which surfaces exist in current frame
std::pair<bool, bool> m_surfaces_present = std::pair<bool, bool>(false, false); std::pair<bool, bool> m_surfaces_present = std::pair<bool, bool>(false, false);

View file

@ -29,89 +29,46 @@
#define INCLUDED_SHADERS2D_H #define INCLUDED_SHADERS2D_H
// Vertex shader // Vertex shader
static const char s_vertexShaderSource[] = static const char s_vertexShaderSource[] = R"glsl(
{
"/**\n" #version 410 core
" ** Supermodel\n"
" ** A Sega Model 3 Arcade Emulator.\n" // outputs
" ** Copyright 2011-2012 Bart Trzynadlowski, Nik Henson \n" out vec2 fsTexCoord;
" **\n"
" ** This file is part of Supermodel.\n" void main(void)
" **\n" {
" ** Supermodel is free software: you can redistribute it and/or modify it under\n" const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.0, 1.0),
" ** the terms of the GNU General Public License as published by the Free \n" vec4(-1.0, 1.0, 0.0, 1.0),
" ** Software Foundation, either version 3 of the License, or (at your option)\n" vec4( 1.0, -1.0, 0.0, 1.0),
" ** any later version.\n" vec4( 1.0, 1.0, 0.0, 1.0));
" **\n"
" ** Supermodel is distributed in the hope that it will be useful, but WITHOUT\n" fsTexCoord = ((vertices[gl_VertexID % 4].xy + 1.0) / 2.0);
" ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" fsTexCoord.y = 1.0 - fsTexCoord.y; // flip upside down
" ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n" gl_Position = vertices[gl_VertexID % 4];
" ** more details.\n" }
" **\n"
" ** You should have received a copy of the GNU General Public License along\n" )glsl";
" ** with Supermodel. If not, see <http://www.gnu.org/licenses/>.\n"
" **/\n"
"\n"
"/*\n"
" * Vertex2D.glsl\n"
" *\n"
" * Vertex shader for 2D tilemap rendering.\n"
" */\n"
" \n"
"#version 120\n"
"\n"
"void main(void)\n"
"{\n"
"\tgl_TexCoord[0] = gl_MultiTexCoord0;\n"
"\tgl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;\n"
"}\n"
};
// Fragment shader // Fragment shader
static const char s_fragmentShaderSource[] = static const char s_fragmentShaderSource[] = R"glsl(
{
"/**\n" #version 410 core
" ** Supermodel\n"
" ** A Sega Model 3 Arcade Emulator.\n" // inputs
" ** Copyright 2011-2012 Bart Trzynadlowski, Nik Henson \n" uniform sampler2D tex1; // texture
" **\n" in vec2 fsTexCoord;
" ** This file is part of Supermodel.\n"
" **\n" // outputs
" ** Supermodel is free software: you can redistribute it and/or modify it under\n" out vec4 fragColor;
" ** the terms of the GNU General Public License as published by the Free \n"
" ** Software Foundation, either version 3 of the License, or (at your option)\n" void main()
" ** any later version.\n" {
" **\n" fragColor = texture(tex1, fsTexCoord);
" ** Supermodel is distributed in the hope that it will be useful, but WITHOUT\n" }
" ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n"
" ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n" )glsl";
" ** more details.\n"
" **\n"
" ** You should have received a copy of the GNU General Public License along\n"
" ** with Supermodel. If not, see <http://www.gnu.org/licenses/>.\n"
" **/\n"
" \n"
"/*\n"
" * Fragment2D.glsl\n"
" *\n"
" * Fragment shader for 2D tilemap rendering.\n"
" */\n"
"\n"
"#version 120\n"
"\n"
"// Global uniforms\n"
"uniform sampler2D\ttextureMap;\t\t// 512x512 layer surface\n"
"\n"
"/*\n"
" * main():\n"
" *\n"
" * Fragment shader entry point.\n"
" */\n"
"\n"
"void main(void)\n"
"{\t\n"
"\tgl_FragColor = texture2D(textureMap, gl_TexCoord[0].st);\n"
"}\n"
};
#endif // INCLUDED_SHADERS2D_H #endif // INCLUDED_SHADERS2D_H

View file

@ -75,6 +75,7 @@
#include "Model3/IEmulator.h" #include "Model3/IEmulator.h"
#include "Model3/Model3.h" #include "Model3/Model3.h"
#include "OSD/Audio.h" #include "OSD/Audio.h"
#include "Graphics/New3D/VBO.h"
#include <iostream> #include <iostream>
#include "Util/BMPFile.h" #include "Util/BMPFile.h"
@ -169,6 +170,11 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
return OKAY; return OKAY;
} }
static void GLAPIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
printf("OGLDebug:: 0x%X: %s\n", id, message);
}
/* /*
* CreateGLScreen(): * CreateGLScreen():
* *
@ -181,7 +187,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
* NOTE: keepAspectRatio should always be true. It has not yet been tested with * NOTE: keepAspectRatio should always be true. It has not yet been tested with
* the wide screen hack. * the wide screen hack.
*/ */
static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr, unsigned *totalXResPtr, unsigned *totalYResPtr, bool keepAspectRatio, bool fullScreen) static bool CreateGLScreen(bool coreContext, bool quadRendering, const std::string &caption, bool focusWindow, unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *xResPtr, unsigned *yResPtr, unsigned *totalXResPtr, unsigned *totalYResPtr, bool keepAspectRatio, bool fullScreen)
{ {
GLenum err; GLenum err;
@ -205,6 +211,19 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
if (coreContext) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
if (quadRendering) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
}
else {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
}
}
// Set video mode // Set video mode
s_window = SDL_CreateWindow(caption.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, *xResPtr, *yResPtr, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullScreen ? SDL_WINDOW_FULLSCREEN : 0)); s_window = SDL_CreateWindow(caption.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, *xResPtr, *yResPtr, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullScreen ? SDL_WINDOW_FULLSCREEN : 0));
if (nullptr == s_window) if (nullptr == s_window)
@ -240,6 +259,26 @@ static bool CreateGLScreen(const std::string &caption, bool focusWindow, unsigne
return FAIL; return FAIL;
} }
// print some basic GPU info
GLint profile = 0;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
printf("GPU info: %s ", glGetString(GL_VERSION));
if (profile & GL_CONTEXT_CORE_PROFILE_BIT) {
printf("(core profile)");
}
if (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) {
printf("(compatability profile)");
}
printf("\n\n");
//glDebugMessageCallback(DebugCallback, NULL);
//glDebugMessageControl(GL_DONT_CARE,GL_DONT_CARE,GL_DONT_CARE, 0, 0, GL_TRUE);
//glEnable(GL_DEBUG_OUTPUT);
return SetGLGeometry(xOffsetPtr, yOffsetPtr, xResPtr, yResPtr, totalXResPtr, totalYResPtr, keepAspectRatio); return SetGLGeometry(xOffsetPtr, yOffsetPtr, xResPtr, yResPtr, totalXResPtr, totalYResPtr, keepAspectRatio);
} }
@ -275,7 +314,7 @@ static void PrintGLInfo(bool createScreen, bool infoLog, bool printExtensions)
unsigned xOffset, yOffset, xRes=496, yRes=384, totalXRes, totalYRes; unsigned xOffset, yOffset, xRes=496, yRes=384, totalXRes, totalYRes;
if (createScreen) if (createScreen)
{ {
if (OKAY != CreateGLScreen("Supermodel - Querying OpenGL Information...", false, &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false)) if (OKAY != CreateGLScreen(false, false, "Supermodel - Querying OpenGL Information...", false, &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false))
{ {
ErrorLog("Unable to query OpenGL.\n"); ErrorLog("Unable to query OpenGL.\n");
return; return;
@ -694,31 +733,130 @@ static void LoadNVRAM(IEmulator *Model3)
Currently, only does crosshairs for light gun games. Currently, only does crosshairs for light gun games.
******************************************************************************/ ******************************************************************************/
struct BasicDraw
{
public:
struct BasicVertex
{
BasicVertex(float x, float y, float z) : x(x), y(y), z(z) {}
BasicVertex(float x, float y) : x(x), y(y), z(0.f) {}
float x, y, z;
};
const int MaxVerts = 1024; // per draw call
void Draw(GLenum mode, const float mvpMatrix[16], const BasicVertex* vertices, int count, float r, float g, float b, float a)
{
if (count > MaxVerts) {
count = MaxVerts; // maybe we could error out somehow
}
if (!m_initialised) {
Setup();
}
m_shader.EnableShader();
// update uniform memory
glUniformMatrix4fv(m_shader.uniformLocMap["mvp"], 1, GL_FALSE, mvpMatrix);
glUniform4f(m_shader.uniformLocMap["colour"], r, g, b, a);
// update vbo mem
m_vbo.Bind(true);
m_vbo.BufferSubData(0, count * sizeof(BasicVertex), vertices);
glBindVertexArray(m_vao);
glDrawArrays(mode, 0, count);
glBindVertexArray(0);
m_shader.DisableShader();
}
private:
void Setup()
{
const char* vertexShader = R"glsl(
#version 410 core
uniform mat4 mvp;
layout(location = 0) in vec3 inVertices;
void main(void)
{
gl_Position = mvp * vec4(inVertices,1.0);
}
)glsl";
const char* fragmentShader = R"glsl(
#version 410 core
uniform vec4 colour;
out vec4 fragColour;
void main(void)
{
fragColour = colour;
}
)glsl";
m_shader.LoadShaders(vertexShader, fragmentShader);
m_shader.GetUniformLocationMap("mvp");
m_shader.GetUniformLocationMap("colour");
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(BasicVertex) * (MaxVerts));
m_vbo.Bind(true);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(BasicVertex), 0);
glBindVertexArray(0);
m_vbo.Bind(false);
m_initialised = true;
}
GLSLShader m_shader;
VBO m_vbo;
GLuint m_vao = 0;
bool m_initialised = false;
} basicDraw;
static void GunToViewCoords(float *x, float *y) static void GunToViewCoords(float *x, float *y)
{ {
*x = (*x-150.0f)/(651.0f-150.0f); // Scale [150,651] -> [0.0,1.0] *x = (*x-150.0f)/(651.0f-150.0f); // Scale [150,651] -> [0.0,1.0]
*y = (*y-80.0f)/(465.0f-80.0f); // Scale [80,465] -> [0.0,1.0] *y = (*y-80.0f)/(465.0f-80.0f); // Scale [80,465] -> [0.0,1.0]
} }
static void DrawCrosshair(float x, float y, float r, float g, float b) static void DrawCrosshair(const float* matrix, float x, float y, float r, float g, float b)
{ {
float base = 0.01f, height = 0.02f; // geometric parameters of each triangle float base = 0.01f, height = 0.02f; // geometric parameters of each triangle
float dist = 0.004f; // distance of triangle tip from center float dist = 0.004f; // distance of triangle tip from center
float a = (float)xRes/(float)yRes; // aspect ratio (to square the crosshair) float a = (float)xRes/(float)yRes; // aspect ratio (to square the crosshair)
glColor3f(r, g, b); std::vector<BasicDraw::BasicVertex> verts;
glVertex2f(x, y+dist); // bottom triangle
glVertex2f(x+base/2.0f, y+(dist+height)*a); verts.emplace_back(x, y+dist); // bottom triangle
glVertex2f(x-base/2.0f, y+(dist+height)*a); verts.emplace_back(x+base/2.0f, y+(dist+height)*a);
glVertex2f(x, y-dist); // top triangle verts.emplace_back(x-base/2.0f, y+(dist+height)*a);
glVertex2f(x-base/2.0f, y-(dist+height)*a); verts.emplace_back(x, y-dist); // top triangle
glVertex2f(x+base/2.0f, y-(dist+height)*a); verts.emplace_back(x-base/2.0f, y-(dist+height)*a);
glVertex2f(x-dist, y); // left triangle verts.emplace_back(x+base/2.0f, y-(dist+height)*a);
glVertex2f(x-dist-height, y+(base/2.0f)*a); verts.emplace_back(x-dist, y); // left triangle
glVertex2f(x-dist-height, y-(base/2.0f)*a); verts.emplace_back(x-dist-height, y+(base/2.0f)*a);
glVertex2f(x+dist, y); // right triangle verts.emplace_back(x-dist-height, y-(base/2.0f)*a);
glVertex2f(x+dist+height, y-(base/2.0f)*a); verts.emplace_back(x+dist, y); // right triangle
glVertex2f(x+dist+height, y+(base/2.0f)*a); verts.emplace_back(x+dist+height, y-(base/2.0f)*a);
verts.emplace_back(x+dist+height, y+(base/2.0f)*a);
basicDraw.Draw(GL_TRIANGLES, matrix, verts.data(), (int)verts.size(), r, g, b, 1.0f);
} }
/* /*
@ -740,7 +878,6 @@ static void PrintGLError(GLenum error)
*/ */
static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned crosshairs) static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned crosshairs)
{ {
bool offscreenTrigger[2]; bool offscreenTrigger[2];
float x[2], y[2]; float x[2], y[2];
@ -762,6 +899,9 @@ static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned c
glDisable(GL_DEPTH_TEST); // no Z-buffering needed glDisable(GL_DEPTH_TEST); // no Z-buffering needed
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
New3D::Mat4 m;
m.Ortho(0.0, 1.0, 1.0, 0.0, -1.0f, 1.0f);
// Convert gun coordinates to viewspace coordinates // Convert gun coordinates to viewspace coordinates
if (currentInputs & Game::INPUT_ANALOG_GUN1) if (currentInputs & Game::INPUT_ANALOG_GUN1)
{ {
@ -790,12 +930,10 @@ static void UpdateCrosshairs(uint32_t currentInputs, CInputs *Inputs, unsigned c
offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0; offscreenTrigger[1] = (Inputs->trigger[1]->offscreenValue) > 0;
} }
// Draw visible crosshairs // Draw visible crosshairs
glBegin(GL_TRIANGLES);
if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1 if ((crosshairs & 1) && !offscreenTrigger[0]) // Player 1
DrawCrosshair(x[0], y[0], 1.0f, 0.0f, 0.0f); DrawCrosshair(m,x[0], y[0], 1.0f, 0.0f, 0.0f);
if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2 if ((crosshairs & 2) && !offscreenTrigger[1]) // Player 2
DrawCrosshair(x[1], y[1], 0.0f, 1.0f, 0.0f); DrawCrosshair(m,x[1], y[1], 0.0f, 1.0f, 0.0f);
glEnd();
//PrintGLError(glGetError()); //PrintGLError(glGetError());
} }
@ -1901,7 +2039,7 @@ int main(int argc, char **argv)
// Create a window // Create a window
xRes = 496; xRes = 496;
yRes = 384; yRes = 384;
if (OKAY != CreateGLScreen("Supermodel", false, &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false)) if (OKAY != CreateGLScreen(s_runtime_config["New3DEngine"].ValueAs<bool>(), s_runtime_config["QuadRendering"].ValueAs<bool>(),"Supermodel", false, &xOffset, &yOffset, &xRes, &yRes, &totalXRes, &totalYRes, false, false))
{ {
exitCode = 1; exitCode = 1;
goto Exit; goto Exit;

View file

@ -311,8 +311,6 @@ xcopy /D /Y "$(ProjectDir)..\Config\*" "$(TargetDir)Config"</Command>
<ClCompile Include="..\Src\Graphics\New3D\R3DFrameBuffers.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\R3DFrameBuffers.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DScrollFog.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\R3DScrollFog.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\Texture.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\TextureSheet.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\VBO.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\VBO.cpp" />
<ClCompile Include="..\Src\Graphics\New3D\Vec.cpp" /> <ClCompile Include="..\Src\Graphics\New3D\Vec.cpp" />
<ClCompile Include="..\Src\Graphics\Render2D.cpp" /> <ClCompile Include="..\Src\Graphics\Render2D.cpp" />
@ -487,8 +485,6 @@ xcopy /D /Y "$(ProjectDir)..\Config\*" "$(TargetDir)Config"</Command>
<ClInclude Include="..\Src\Graphics\New3D\R3DShader.h" /> <ClInclude Include="..\Src\Graphics\New3D\R3DShader.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h" /> <ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h" /> <ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h" />
<ClInclude Include="..\Src\Graphics\New3D\Texture.h" />
<ClInclude Include="..\Src\Graphics\New3D\TextureSheet.h" />
<ClInclude Include="..\Src\Graphics\New3D\VBO.h" /> <ClInclude Include="..\Src\Graphics\New3D\VBO.h" />
<ClInclude Include="..\Src\Graphics\New3D\Vec.h" /> <ClInclude Include="..\Src\Graphics\New3D\Vec.h" />
<ClInclude Include="..\Src\Graphics\Render2D.h" /> <ClInclude Include="..\Src\Graphics\Render2D.h" />

View file

@ -377,12 +377,6 @@
<ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp"> <ClCompile Include="..\Src\Graphics\New3D\R3DShader.cpp">
<Filter>Source Files\Graphics\New</Filter> <Filter>Source Files\Graphics\New</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Src\Graphics\New3D\Texture.cpp">
<Filter>Source Files\Graphics\New</Filter>
</ClCompile>
<ClCompile Include="..\Src\Graphics\New3D\TextureSheet.cpp">
<Filter>Source Files\Graphics\New</Filter>
</ClCompile>
<ClCompile Include="..\Src\Graphics\New3D\VBO.cpp"> <ClCompile Include="..\Src\Graphics\New3D\VBO.cpp">
<Filter>Source Files\Graphics\New</Filter> <Filter>Source Files\Graphics\New</Filter>
</ClCompile> </ClCompile>
@ -835,12 +829,6 @@
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h"> <ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h">
<Filter>Header Files\Graphics\New</Filter> <Filter>Header Files\Graphics\New</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Texture.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\TextureSheet.h">
<Filter>Header Files\Graphics\New</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\VBO.h"> <ClInclude Include="..\Src\Graphics\New3D\VBO.h">
<Filter>Header Files\Graphics\New</Filter> <Filter>Header Files\Graphics\New</Filter>
</ClInclude> </ClInclude>