mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-24 22:55:40 +00:00
Quad rendering engine. Set QuadRendering = 1 in the ini file to use, or -quad-rendering at the end of the command line to use.
This commit is contained in:
parent
e4f5f0bcaf
commit
b5f9ad9651
|
@ -22,12 +22,43 @@ struct ClipPoly
|
||||||
int count = 0;
|
int count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Vertex // half vertex
|
struct Vertex // half vertex
|
||||||
{
|
{
|
||||||
float pos[4];
|
float pos[4];
|
||||||
float normal[3];
|
float normal[3];
|
||||||
float texcoords[2];
|
float texcoords[2];
|
||||||
float fixedShade;
|
float fixedShade;
|
||||||
|
|
||||||
|
static bool Equal(const Vertex& p1, const Vertex& p2)
|
||||||
|
{
|
||||||
|
if (p1.pos[0] == p2.pos[0] &&
|
||||||
|
p1.pos[1] == p2.pos[1] &&
|
||||||
|
p1.pos[2] == p2.pos[2])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Average(const Vertex& p1, const Vertex& p2, Vertex& p3)
|
||||||
|
{
|
||||||
|
p3.pos[3] = 1.0f; //always 1
|
||||||
|
p3.fixedShade = (p1.fixedShade + p2.fixedShade) / 2.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) { p3.pos[i] = (p1.pos[i] + p2.pos[i]) / 2.0f; }
|
||||||
|
for (int i = 0; i < 3; i++) { p3.normal[i] = (p1.normal[i] + p2.normal[i]) / 2.0f; }
|
||||||
|
for (int i = 0; i < 2; i++) { p3.texcoords[i] = (p1.texcoords[i] + p2.texcoords[i]) / 2.0f; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct R3DPoly
|
||||||
|
{
|
||||||
|
Vertex v[4]; // just easier to have them as an array
|
||||||
|
float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
|
||||||
|
UINT8 faceColour[4]; // per face colour
|
||||||
|
int number = 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FVertex : Vertex // full vertex including face attributes
|
struct FVertex : Vertex // full vertex including face attributes
|
||||||
|
@ -40,50 +71,31 @@ struct FVertex : Vertex // full vertex including face attributes
|
||||||
memcpy(this, &vertex, sizeof(Vertex));
|
memcpy(this, &vertex, sizeof(Vertex));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct R3DPoly
|
FVertex() {}
|
||||||
{
|
FVertex(const R3DPoly& r3dPoly, int index)
|
||||||
Vertex v[4]; // just easier to have them as an array
|
{
|
||||||
float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
|
for (int i = 0; i < 4; i++) { faceColour[i] = r3dPoly.faceColour[i]; }
|
||||||
UINT8 faceColour[4]; // per face colour
|
for (int i = 0; i < 3; i++) { faceNormal[i] = r3dPoly.faceNormal[i]; }
|
||||||
int number = 4;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Poly // our polys are always 3 triangles, unlike the real h/w
|
*this = r3dPoly.v[index];
|
||||||
{
|
|
||||||
Poly() {}; // default
|
|
||||||
|
|
||||||
Poly(bool firstTriangle, const R3DPoly& r3dPoly) {
|
|
||||||
|
|
||||||
if (firstTriangle) {
|
|
||||||
p1 = r3dPoly.v[0];
|
|
||||||
p2 = r3dPoly.v[1];
|
|
||||||
p3 = r3dPoly.v[2];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
p1 = r3dPoly.v[0];
|
|
||||||
p2 = r3dPoly.v[2];
|
|
||||||
p3 = r3dPoly.v[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy face attributes
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
p1.faceColour[i] = r3dPoly.faceColour[i];
|
|
||||||
p2.faceColour[i] = r3dPoly.faceColour[i];
|
|
||||||
p3.faceColour[i] = r3dPoly.faceColour[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
p1.faceNormal[i] = r3dPoly.faceNormal[i];
|
|
||||||
p2.faceNormal[i] = r3dPoly.faceNormal[i];
|
|
||||||
p3.faceNormal[i] = r3dPoly.faceNormal[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FVertex p1;
|
FVertex(const R3DPoly& r3dPoly, int index1, int index2) // average of 2 points
|
||||||
FVertex p2;
|
{
|
||||||
FVertex p3;
|
Vertex::Average(r3dPoly.v[index1], r3dPoly.v[index2], *this);
|
||||||
|
|
||||||
|
// copy face attributes
|
||||||
|
for (int i = 0; i < 4; i++) { faceColour[i] = r3dPoly.faceColour[i]; }
|
||||||
|
for (int i = 0; i < 3; i++) { faceNormal[i] = r3dPoly.faceNormal[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Average(const FVertex& p1, const FVertex& p2, FVertex& p3)
|
||||||
|
{
|
||||||
|
Vertex::Average(p1, p2, p3);
|
||||||
|
for (int i = 0; i < 4; i++) { p3.faceColour[i] = p1.faceColour[i]; }
|
||||||
|
for (int i = 0; i < 3; i++) { p3.faceNormal[i] = p1.faceNormal[i]; }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Layer { colour, trans1, trans2, all, none };
|
enum class Layer { colour, trans1, trans2, all, none };
|
||||||
|
@ -150,12 +162,12 @@ struct Mesh
|
||||||
|
|
||||||
// opengl resources
|
// opengl resources
|
||||||
int vboOffset = 0; // this will be calculated later
|
int vboOffset = 0; // this will be calculated later
|
||||||
int triangleCount = 0;
|
int vertexCount = 0; // /3 for triangles /4 for quads
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SortingMesh : public Mesh // This struct temporarily holds the model data, before it gets copied to the main buffer
|
struct SortingMesh : public Mesh // This struct temporarily holds the model data, before it gets copied to the main buffer
|
||||||
{
|
{
|
||||||
std::vector<Poly> polys;
|
std::vector<FVertex> verts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Model
|
struct Model
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "R3DFloat.h"
|
#include "R3DFloat.h"
|
||||||
|
|
||||||
#define MAX_RAM_POLYS 100000
|
#define MAX_RAM_VERTS 300000
|
||||||
#define MAX_ROM_POLYS 500000
|
#define MAX_ROM_VERTS 1500000
|
||||||
|
|
||||||
#define BYTE_TO_FLOAT(B) ((2.0f * (B) + 1.0f) * (1.0F/255.0f))
|
#define BYTE_TO_FLOAT(B) ((2.0f * (B) + 1.0f) * (1.0F/255.0f))
|
||||||
|
|
||||||
|
@ -26,6 +26,13 @@ CNew3D::CNew3D(const Util::Config::Node &config, std::string gameName)
|
||||||
m_textureRAM = nullptr;
|
m_textureRAM = nullptr;
|
||||||
m_sunClamp = true;
|
m_sunClamp = true;
|
||||||
m_shadeIsSigned = true;
|
m_shadeIsSigned = true;
|
||||||
|
m_numPolyVerts = 3;
|
||||||
|
m_primType = GL_TRIANGLES;
|
||||||
|
|
||||||
|
if (config["QuadRendering"].ValueAs<bool>()) {
|
||||||
|
m_numPolyVerts = 4;
|
||||||
|
m_primType = GL_LINES_ADJACENCY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CNew3D::~CNew3D()
|
CNew3D::~CNew3D()
|
||||||
|
@ -59,7 +66,7 @@ void CNew3D::SetStepping(int stepping)
|
||||||
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(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
|
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)
|
||||||
|
@ -159,11 +166,7 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
|
||||||
std::shared_ptr<Texture> tex1;
|
std::shared_ptr<Texture> tex1;
|
||||||
|
|
||||||
CalcViewport(&n.viewport, std::abs(m_nfPairs[priority].zNear*0.95f), std::abs(m_nfPairs[priority].zFar*1.05f)); // make planes 5% bigger
|
CalcViewport(&n.viewport, std::abs(m_nfPairs[priority].zNear*0.95f), 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);
|
|
||||||
glMatrixMode (GL_PROJECTION);
|
|
||||||
glLoadMatrixf (n.viewport.projectionMatrix);
|
|
||||||
glMatrixMode (GL_MODELVIEW);
|
|
||||||
|
|
||||||
m_r3dShader.SetViewportUniforms(&n.viewport);
|
m_r3dShader.SetViewportUniforms(&n.viewport);
|
||||||
|
|
||||||
|
@ -221,7 +224,7 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_r3dShader.SetMeshUniforms(&mesh);
|
m_r3dShader.SetMeshUniforms(&mesh);
|
||||||
glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3); // times 3 to convert triangles to vertices
|
glDrawArrays(m_primType, mesh.vboOffset, mesh.vertexCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,25 +311,25 @@ void CNew3D::RenderFrame(void)
|
||||||
DrawScrollFog(); // fog layer if applicable must be drawn here
|
DrawScrollFog(); // fog layer if applicable must be drawn here
|
||||||
|
|
||||||
m_vbo.Bind(true);
|
m_vbo.Bind(true);
|
||||||
m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go
|
m_vbo.BufferSubData(MAX_ROM_VERTS*sizeof(FVertex), m_polyBufferRam.size()*sizeof(FVertex), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go
|
||||||
|
|
||||||
if (m_polyBufferRom.size()) {
|
if (m_polyBufferRom.size()) {
|
||||||
|
|
||||||
// sync rom memory with vbo
|
// sync rom memory with vbo
|
||||||
int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly);
|
int romBytes = (int)m_polyBufferRom.size() * sizeof(FVertex);
|
||||||
int vboBytes = m_vbo.GetSize();
|
int vboBytes = m_vbo.GetSize();
|
||||||
int size = romBytes - vboBytes;
|
int size = romBytes - vboBytes;
|
||||||
|
|
||||||
if (size) {
|
if (size) {
|
||||||
//check we haven't blown up the memory buffers
|
//check we haven't blown up the memory buffers
|
||||||
//we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway
|
//we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway
|
||||||
if (m_polyBufferRom.size() >= MAX_ROM_POLYS) {
|
if (m_polyBufferRom.size() >= MAX_ROM_VERTS) {
|
||||||
m_polyBufferRom.clear();
|
m_polyBufferRom.clear();
|
||||||
m_romMap.clear();
|
m_romMap.clear();
|
||||||
m_vbo.Reset();
|
m_vbo.Reset();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
|
m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(FVertex)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,7 +426,7 @@ bool CNew3D::DrawModel(UINT32 modelAddr)
|
||||||
modelAddress = TranslateModelAddress(modelAddr);
|
modelAddress = TranslateModelAddress(modelAddr);
|
||||||
|
|
||||||
// create a new model to push onto the vector
|
// create a new model to push onto the vector
|
||||||
m_nodes.back().models.emplace_back(Model());
|
m_nodes.back().models.emplace_back();
|
||||||
|
|
||||||
// get the last model in the array
|
// get the last model in the array
|
||||||
m = &m_nodes.back().models.back();
|
m = &m_nodes.back().models.back();
|
||||||
|
@ -811,7 +814,6 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
vp->angle_top = (1.0f / cw) * -(0.0f - io);
|
vp->angle_top = (1.0f / cw) * -(0.0f - io);
|
||||||
|
|
||||||
// calculate the frustum shape, near/far pair are dummy values
|
// calculate the frustum shape, near/far pair are dummy values
|
||||||
|
|
||||||
CalcViewport(vp, 1, 1000);
|
CalcViewport(vp, 1, 1000);
|
||||||
|
|
||||||
// calculate frustum planes
|
// calculate frustum planes
|
||||||
|
@ -924,12 +926,46 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
|
void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertexArray)
|
||||||
{
|
{
|
||||||
polyArray.emplace_back(Poly(true,r3dPoly)); // create object directly in array without temporary copy
|
if (m_numPolyVerts==4) {
|
||||||
|
if (r3dPoly.number == 4) {
|
||||||
|
vertexArray.emplace_back(r3dPoly, 0); // construct directly inside container without copy
|
||||||
|
vertexArray.emplace_back(r3dPoly, 1);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 2);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 3);
|
||||||
|
|
||||||
if (r3dPoly.number == 4) {
|
// check for identical points (ie forced triangle) and replace with average point
|
||||||
polyArray.emplace_back(Poly(false, r3dPoly)); // copy second triangle
|
// if we don't do this our quad code falls apart
|
||||||
|
FVertex* v = (&vertexArray.back()) - 3;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
||||||
|
int next1 = (i + 1) % 4;
|
||||||
|
int next2 = (i + 2) % 4;
|
||||||
|
|
||||||
|
if (FVertex::Equal(v[i], v[next1])) {
|
||||||
|
FVertex::Average(v[i], v[next1], v[next2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vertexArray.emplace_back(r3dPoly, 0);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 1);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 2);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 0, 2); // last point is an average of 0 and 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vertexArray.emplace_back(r3dPoly, 0);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 1);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 2);
|
||||||
|
|
||||||
|
if (r3dPoly.number == 4) {
|
||||||
|
vertexArray.emplace_back(r3dPoly, 0);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 2);
|
||||||
|
vertexArray.emplace_back(r3dPoly, 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1062,7 +1098,7 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
currentMesh = &sMap[hash];
|
currentMesh = &sMap[hash];
|
||||||
|
|
||||||
//make space for our vertices
|
//make space for our vertices
|
||||||
currentMesh->polys.reserve(numTriangles);
|
currentMesh->verts.reserve(numTriangles * 3);
|
||||||
|
|
||||||
//set mesh values
|
//set mesh values
|
||||||
SetMeshValues(currentMesh, ph);
|
SetMeshValues(currentMesh, ph);
|
||||||
|
@ -1222,12 +1258,12 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
V3::inverse(tempP.v[i].normal);
|
V3::inverse(tempP.v[i].normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyVertexData(tempP, currentMesh->polys);
|
CopyVertexData(tempP, currentMesh->verts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy this polygon into the model buffer
|
// Copy this polygon into the model buffer
|
||||||
if (!ph.Discard()) {
|
if (!ph.Discard()) {
|
||||||
CopyVertexData(p, currentMesh->polys);
|
CopyVertexData(p, currentMesh->verts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy current vertices into previous vertex array
|
// Copy current vertices into previous vertex array
|
||||||
|
@ -1249,19 +1285,19 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
if (m->dynamic) {
|
if (m->dynamic) {
|
||||||
|
|
||||||
// calculate VBO values for current mesh
|
// calculate VBO values for current mesh
|
||||||
it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS;
|
it.second.vboOffset = (int)m_polyBufferRam.size() + MAX_ROM_VERTS;
|
||||||
it.second.triangleCount = it.second.polys.size();
|
it.second.vertexCount = (int)it.second.verts.size();
|
||||||
|
|
||||||
// copy poly data to main buffer
|
// copy poly data to main buffer
|
||||||
m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
|
m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.verts.begin(), it.second.verts.end());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// calculate VBO values for current mesh
|
// calculate VBO values for current mesh
|
||||||
it.second.vboOffset = m_polyBufferRom.size();
|
it.second.vboOffset = (int)m_polyBufferRom.size();
|
||||||
it.second.triangleCount = it.second.polys.size();
|
it.second.vertexCount = (int)it.second.verts.size();
|
||||||
|
|
||||||
// copy poly data to main buffer
|
// copy poly data to main buffer
|
||||||
m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
|
m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.verts.begin(), it.second.verts.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
//copy the temp mesh into the model structure
|
//copy the temp mesh into the model structure
|
||||||
|
@ -1270,21 +1306,6 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float CNew3D::Determinant3x3(const float m[16]) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
| A B C |
|
|
||||||
M = | D E F |
|
|
||||||
| G H I |
|
|
||||||
|
|
||||||
then the determinant is calculated as follows:
|
|
||||||
|
|
||||||
det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
|
|
||||||
*/
|
|
||||||
|
|
||||||
return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CNew3D::IsDynamicModel(UINT32 *data)
|
bool CNew3D::IsDynamicModel(UINT32 *data)
|
||||||
{
|
{
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
|
@ -1551,18 +1572,18 @@ void CNew3D::ClipPolygon(ClipPoly& clipPoly, Plane planes[4])
|
||||||
|
|
||||||
void CNew3D::ClipModel(const Model *m)
|
void CNew3D::ClipModel(const Model *m)
|
||||||
{
|
{
|
||||||
//================
|
//===============================
|
||||||
ClipPoly clipPoly;
|
ClipPoly clipPoly;
|
||||||
std::vector<Poly> *polys;
|
std::vector<FVertex>* vertices;
|
||||||
int offset;
|
int offset;
|
||||||
//================
|
//===============================
|
||||||
|
|
||||||
if (m->dynamic) {
|
if (m->dynamic) {
|
||||||
polys = &m_polyBufferRam;
|
vertices = &m_polyBufferRam;
|
||||||
offset = MAX_ROM_POLYS;
|
offset = MAX_ROM_VERTS;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
polys = &m_polyBufferRom;
|
vertices = &m_polyBufferRom;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1570,17 +1591,13 @@ void CNew3D::ClipModel(const Model *m)
|
||||||
|
|
||||||
int start = mesh.vboOffset - offset;
|
int start = mesh.vboOffset - offset;
|
||||||
|
|
||||||
for (int i = 0; i < mesh.triangleCount; i++) {
|
for (int i = 0; i < mesh.vertexCount; i += m_numPolyVerts) { // inc to next poly
|
||||||
|
|
||||||
//==================================
|
for (int j = 0; j < m_numPolyVerts; j++) {
|
||||||
Poly& poly = (*polys)[start + i];
|
MultVec(m->modelMat, (*vertices)[start + i + j].pos, clipPoly.list[j].pos); // copy all 3 of 4 our transformed vertices into our clip poly struct
|
||||||
//==================================
|
}
|
||||||
|
|
||||||
MultVec(m->modelMat, poly.p1.pos, clipPoly.list[0].pos);
|
clipPoly.count = m_numPolyVerts;
|
||||||
MultVec(m->modelMat, poly.p2.pos, clipPoly.list[1].pos);
|
|
||||||
MultVec(m->modelMat, poly.p3.pos, clipPoly.list[2].pos);
|
|
||||||
|
|
||||||
clipPoly.count = 3;
|
|
||||||
|
|
||||||
ClipPolygon(clipPoly, m_planes);
|
ClipPolygon(clipPoly, m_planes);
|
||||||
|
|
||||||
|
|
|
@ -198,11 +198,10 @@ private:
|
||||||
// building the scene
|
// building the scene
|
||||||
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<Poly>& polyArray);
|
void CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertexArray);
|
||||||
void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
|
void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
|
||||||
|
|
||||||
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
|
||||||
float Determinant3x3(const float m[16]);
|
|
||||||
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
|
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
|
||||||
bool IsVROMModel(UINT32 modelAddr);
|
bool IsVROMModel(UINT32 modelAddr);
|
||||||
void DrawScrollFog();
|
void DrawScrollFog();
|
||||||
|
@ -218,6 +217,8 @@ private:
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
std::string m_gameName;
|
std::string m_gameName;
|
||||||
|
int m_numPolyVerts;
|
||||||
|
GLenum m_primType;
|
||||||
|
|
||||||
// GPU configuration
|
// GPU configuration
|
||||||
bool m_sunClamp;
|
bool m_sunClamp;
|
||||||
|
@ -253,9 +254,9 @@ private:
|
||||||
Vertex m_prev[4]; // these are class variables because sega bass fishing starts meshes with shared vertices from the previous one
|
Vertex m_prev[4]; // these are class variables because sega bass fishing starts meshes with shared vertices from the previous one
|
||||||
UINT16 m_prevTexCoords[4][2]; // basically relying on undefined behavour
|
UINT16 m_prevTexCoords[4][2]; // basically relying on undefined behavour
|
||||||
|
|
||||||
std::vector<Node> m_nodes; // this represents the entire render frame
|
std::vector<Node> m_nodes; // this represents the entire render frame
|
||||||
std::vector<Poly> m_polyBufferRam; // dynamic polys
|
std::vector<FVertex> m_polyBufferRam; // dynamic polys
|
||||||
std::vector<Poly> 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
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -1,307 +1,18 @@
|
||||||
#include "R3DShader.h"
|
#include "R3DShader.h"
|
||||||
#include "Graphics/Shader.h"
|
#include "R3DShaderQuads.h"
|
||||||
|
#include "R3DShaderTriangles.h"
|
||||||
|
|
||||||
|
// having 2 sets of shaders to maintain is really less than ideal
|
||||||
|
// but hopefully not too many breaking changes at this point
|
||||||
|
|
||||||
namespace New3D {
|
namespace New3D {
|
||||||
|
|
||||||
static const char *vertexShaderR3D = R"glsl(
|
|
||||||
|
|
||||||
#version 120
|
|
||||||
|
|
||||||
// uniforms
|
|
||||||
uniform float modelScale;
|
|
||||||
|
|
||||||
// attributes
|
|
||||||
attribute vec4 inVertex;
|
|
||||||
attribute vec3 inNormal;
|
|
||||||
attribute vec2 inTexCoord;
|
|
||||||
attribute vec4 inColour;
|
|
||||||
attribute vec3 inFaceNormal; // used to emulate r3d culling
|
|
||||||
attribute float inFixedShade;
|
|
||||||
|
|
||||||
// outputs to fragment shader
|
|
||||||
varying vec3 fsViewVertex;
|
|
||||||
varying vec3 fsViewNormal; // per vertex normal vector
|
|
||||||
varying vec2 fsTexCoord;
|
|
||||||
varying vec4 fsColor;
|
|
||||||
varying float fsDiscard; // can't have varying bool (glsl spec)
|
|
||||||
varying float fsFixedShade;
|
|
||||||
|
|
||||||
float CalcBackFace(in vec3 viewVertex)
|
|
||||||
{
|
|
||||||
vec3 vt = viewVertex - vec3(0.0);
|
|
||||||
vec3 vn = (mat3(gl_ModelViewMatrix) * inFaceNormal);
|
|
||||||
|
|
||||||
// dot product of face normal with view direction
|
|
||||||
return dot(vt, vn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
fsViewVertex = vec3(gl_ModelViewMatrix * inVertex);
|
|
||||||
fsViewNormal = (mat3(gl_ModelViewMatrix) * inNormal) / modelScale;
|
|
||||||
fsDiscard = CalcBackFace(fsViewVertex);
|
|
||||||
fsColor = inColour;
|
|
||||||
fsTexCoord = inTexCoord;
|
|
||||||
fsFixedShade = inFixedShade;
|
|
||||||
gl_Position = gl_ModelViewProjectionMatrix * inVertex;
|
|
||||||
}
|
|
||||||
)glsl";
|
|
||||||
|
|
||||||
static const char *fragmentShaderR3D = R"glsl(
|
|
||||||
|
|
||||||
#version 120
|
|
||||||
|
|
||||||
uniform sampler2D tex1; // base tex
|
|
||||||
uniform sampler2D tex2; // micro tex (optional)
|
|
||||||
|
|
||||||
// texturing
|
|
||||||
uniform bool textureEnabled;
|
|
||||||
uniform bool microTexture;
|
|
||||||
uniform float microTextureScale;
|
|
||||||
uniform vec2 baseTexSize;
|
|
||||||
uniform bool textureInverted;
|
|
||||||
uniform bool textureAlpha;
|
|
||||||
uniform bool alphaTest;
|
|
||||||
uniform bool discardAlpha;
|
|
||||||
|
|
||||||
// general
|
|
||||||
uniform vec3 fogColour;
|
|
||||||
uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)
|
|
||||||
uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit
|
|
||||||
uniform vec3 spotColor; // spotlight RGB color
|
|
||||||
uniform vec3 spotFogColor; // spotlight RGB color on fog
|
|
||||||
uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)
|
|
||||||
uniform bool lightEnabled; // lighting enabled (1.0) or luminous (0.0), drawn at full intensity
|
|
||||||
uniform bool sunClamp; // not used by daytona and la machine guns
|
|
||||||
uniform bool intensityClamp; // some games such as daytona and
|
|
||||||
uniform bool specularEnabled; // specular enabled
|
|
||||||
uniform float specularValue; // specular coefficient
|
|
||||||
uniform float shininess; // specular shininess
|
|
||||||
uniform float fogIntensity;
|
|
||||||
uniform float fogDensity;
|
|
||||||
uniform float fogStart;
|
|
||||||
uniform float fogAttenuation;
|
|
||||||
uniform float fogAmbient;
|
|
||||||
uniform bool fixedShading;
|
|
||||||
uniform int hardwareStep;
|
|
||||||
|
|
||||||
//interpolated inputs from vertex shader
|
|
||||||
varying vec3 fsViewVertex;
|
|
||||||
varying vec3 fsViewNormal; // per vertex normal vector
|
|
||||||
varying vec4 fsColor;
|
|
||||||
varying vec2 fsTexCoord;
|
|
||||||
varying float fsDiscard;
|
|
||||||
varying float fsFixedShade;
|
|
||||||
|
|
||||||
vec4 GetTextureValue()
|
|
||||||
{
|
|
||||||
vec4 tex1Data = texture2D( tex1, fsTexCoord.st);
|
|
||||||
|
|
||||||
if(textureInverted) {
|
|
||||||
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (microTexture) {
|
|
||||||
vec2 scale = (baseTexSize / 128.0) * microTextureScale;
|
|
||||||
vec4 tex2Data = texture2D( tex2, fsTexCoord.st * scale);
|
|
||||||
tex1Data = (tex1Data+tex2Data)/2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alphaTest) {
|
|
||||||
if (tex1Data.a < (8.0/16.0)) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(textureAlpha) {
|
|
||||||
if(discardAlpha) { // opaque 1st pass
|
|
||||||
if (tex1Data.a < 1.0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // transparent 2nd pass
|
|
||||||
if ((tex1Data.a * fsColor.a) >= 1.0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textureAlpha == false) {
|
|
||||||
tex1Data.a = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tex1Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Step15Luminous(inout vec4 colour)
|
|
||||||
{
|
|
||||||
// luminous polys seem to behave very differently on step 1.5 hardware
|
|
||||||
// when fixed shading is enabled the colour is modulated by the vp ambient + fixed shade value
|
|
||||||
// when disabled it appears to be multiplied by 1.5, presumably to allow a higher range
|
|
||||||
if(hardwareStep==0x15) {
|
|
||||||
if(!lightEnabled && textureEnabled) {
|
|
||||||
if(fixedShading) {
|
|
||||||
colour.rgb *= 1.0 + fsFixedShade + lighting[1].y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
colour.rgb *= vec3(1.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float CalcFog()
|
|
||||||
{
|
|
||||||
float z = -fsViewVertex.z;
|
|
||||||
float fog = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);
|
|
||||||
|
|
||||||
return fog;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 tex1Data;
|
|
||||||
vec4 colData;
|
|
||||||
vec4 finalData;
|
|
||||||
vec4 fogData;
|
|
||||||
|
|
||||||
if(fsDiscard>=0) {
|
|
||||||
discard; //emulate back face culling here
|
|
||||||
}
|
|
||||||
|
|
||||||
fogData = vec4(fogColour.rgb * fogAmbient, CalcFog());
|
|
||||||
tex1Data = vec4(1.0, 1.0, 1.0, 1.0);
|
|
||||||
|
|
||||||
if(textureEnabled) {
|
|
||||||
tex1Data = GetTextureValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
colData = fsColor;
|
|
||||||
Step15Luminous(colData); // no-op for step 2.0+
|
|
||||||
finalData = tex1Data * colData;
|
|
||||||
|
|
||||||
if (finalData.a < (1.0/16.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ellipse;
|
|
||||||
ellipse = length((gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw);
|
|
||||||
ellipse = pow(ellipse, 2.0); // decay rate = square of distance from center
|
|
||||||
ellipse = 1.0 - ellipse; // invert
|
|
||||||
ellipse = max(0.0, ellipse); // clamp
|
|
||||||
|
|
||||||
// Compute spotlight and apply lighting
|
|
||||||
float enable, absExtent, d, inv_r, range;
|
|
||||||
|
|
||||||
// start of spotlight
|
|
||||||
enable = step(spotRange.x, -fsViewVertex.z);
|
|
||||||
|
|
||||||
if (spotRange.y == 0.0) {
|
|
||||||
range = 0.0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
absExtent = abs(spotRange.y);
|
|
||||||
|
|
||||||
d = spotRange.x + absExtent + fsViewVertex.z;
|
|
||||||
d = min(d, 0.0);
|
|
||||||
|
|
||||||
// slope of decay function
|
|
||||||
inv_r = 1.0 / (1.0 + absExtent);
|
|
||||||
|
|
||||||
// inverse-linear falloff
|
|
||||||
// Reference: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
|
|
||||||
// y = 1 / (d/r + 1)^2
|
|
||||||
range = 1.0 / pow(d * inv_r - 1.0, 2.0);
|
|
||||||
range *= enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
float lobeEffect = range * ellipse;
|
|
||||||
float lobeFogEffect = enable * ellipse;
|
|
||||||
|
|
||||||
if (lightEnabled) {
|
|
||||||
vec3 lightIntensity;
|
|
||||||
vec3 sunVector; // sun lighting vector (as reflecting away from vertex)
|
|
||||||
float sunFactor; // sun light projection along vertex normal (0.0 to 1.0)
|
|
||||||
|
|
||||||
// Sun angle
|
|
||||||
sunVector = lighting[0];
|
|
||||||
|
|
||||||
// Compute diffuse factor for sunlight
|
|
||||||
if(fixedShading) {
|
|
||||||
sunFactor = fsFixedShade;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sunFactor = dot(sunVector, fsViewNormal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp ceil, fix for upscaled models without "modelScale" defined
|
|
||||||
sunFactor = clamp(sunFactor,-1.0,1.0);
|
|
||||||
|
|
||||||
// Optional clamping, value is allowed to be negative
|
|
||||||
if(sunClamp) {
|
|
||||||
sunFactor = max(sunFactor,0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Total light intensity: sum of all components
|
|
||||||
lightIntensity = vec3(sunFactor*lighting[1].x + lighting[1].y); // diffuse + ambient
|
|
||||||
|
|
||||||
lightIntensity.rgb += spotColor*lobeEffect;
|
|
||||||
|
|
||||||
// Upper clamp is optional, step 1.5+ games will drive brightness beyond 100%
|
|
||||||
if(intensityClamp) {
|
|
||||||
lightIntensity = min(lightIntensity,1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
finalData.rgb *= lightIntensity;
|
|
||||||
|
|
||||||
// for now assume fixed shading doesn't work with specular
|
|
||||||
if (specularEnabled) {
|
|
||||||
|
|
||||||
float exponent, NdotL, specularFactor;
|
|
||||||
vec4 biasIndex, expIndex, multIndex;
|
|
||||||
|
|
||||||
// Always clamp floor to zero, we don't want deep black areas
|
|
||||||
NdotL = max(0.0,sunFactor);
|
|
||||||
|
|
||||||
expIndex = vec4(8.0, 16.0, 32.0, 64.0);
|
|
||||||
multIndex = vec4(2.0, 2.0, 3.0, 4.0);
|
|
||||||
biasIndex = vec4(0.95, 0.95, 1.05, 1.0);
|
|
||||||
exponent = expIndex[int(shininess)] / biasIndex[int(shininess)];
|
|
||||||
|
|
||||||
specularFactor = pow(NdotL, exponent);
|
|
||||||
specularFactor *= multIndex[int(shininess)];
|
|
||||||
specularFactor *= biasIndex[int(shininess)];
|
|
||||||
|
|
||||||
specularFactor *= specularValue;
|
|
||||||
specularFactor *= lighting[1].x;
|
|
||||||
|
|
||||||
if (colData.a < 1.0) {
|
|
||||||
/// Specular hi-light affects translucent polygons alpha channel ///
|
|
||||||
finalData.a = max(finalData.a, specularFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
finalData.rgb += vec3(specularFactor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final clamp: we need it for proper shading in dimmed light and dark ambients
|
|
||||||
finalData.rgb = min(finalData.rgb, vec3(1.0));
|
|
||||||
|
|
||||||
// Spotlight on fog
|
|
||||||
vec3 lSpotFogColor = spotFogColor * fogAttenuation * fogColour.rgb * lobeFogEffect;
|
|
||||||
|
|
||||||
// Fog & spotlight applied
|
|
||||||
finalData.rgb = mix(finalData.rgb, fogData.rgb + lSpotFogColor, fogData.a);
|
|
||||||
|
|
||||||
gl_FragColor = finalData;
|
|
||||||
}
|
|
||||||
)glsl";
|
|
||||||
|
|
||||||
R3DShader::R3DShader(const Util::Config::Node &config)
|
R3DShader::R3DShader(const Util::Config::Node &config)
|
||||||
: m_config(config)
|
: m_config(config)
|
||||||
{
|
{
|
||||||
m_shaderProgram = 0;
|
m_shaderProgram = 0;
|
||||||
m_vertexShader = 0;
|
m_vertexShader = 0;
|
||||||
|
m_geoShader = 0;
|
||||||
m_fragmentShader = 0;
|
m_fragmentShader = 0;
|
||||||
|
|
||||||
Start(); // reset attributes
|
Start(); // reset attributes
|
||||||
|
@ -323,71 +34,93 @@ void R3DShader::Start()
|
||||||
m_specularValue = 0;
|
m_specularValue = 0;
|
||||||
m_microTexScale = 0;
|
m_microTexScale = 0;
|
||||||
|
|
||||||
m_baseTexSize[0] = 0;
|
m_baseTexSize[0] = 0;
|
||||||
m_baseTexSize[1] = 0;
|
m_baseTexSize[1] = 0;
|
||||||
|
|
||||||
m_dirtyMesh = true; // dirty means all the above are dirty, ie first run
|
m_dirtyMesh = true; // dirty means all the above are dirty, ie first run
|
||||||
m_dirtyModel = true;
|
m_dirtyModel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
|
bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
|
||||||
{
|
{
|
||||||
const char* vShader;
|
bool quads = m_config["QuadRendering"].ValueAs<bool>();
|
||||||
const char* fShader;
|
|
||||||
bool success;
|
|
||||||
|
|
||||||
if (vertexShader) {
|
const char* vShader = vertexShaderR3D;
|
||||||
vShader = vertexShader;
|
const char* gShader = "";
|
||||||
}
|
const char* fShader = fragmentShaderR3D;
|
||||||
else {
|
|
||||||
vShader = vertexShaderR3D;
|
if (quads) {
|
||||||
|
vShader = vertexShaderR3DQuads;
|
||||||
|
gShader = geometryShaderR3DQuads;
|
||||||
|
fShader = fragmentShaderR3DQuads;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fragmentShader) {
|
m_shaderProgram = glCreateProgram();
|
||||||
fShader = fragmentShader;
|
m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
}
|
m_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
else {
|
|
||||||
fShader = fragmentShaderR3D;
|
glShaderSource(m_vertexShader, 1, (const GLchar **)&vShader, NULL);
|
||||||
|
glShaderSource(m_fragmentShader, 1, (const GLchar **)&fShader, NULL);
|
||||||
|
|
||||||
|
glCompileShader(m_vertexShader);
|
||||||
|
glCompileShader(m_fragmentShader);
|
||||||
|
|
||||||
|
if (quads) {
|
||||||
|
m_geoShader = glCreateShader(GL_GEOMETRY_SHADER);
|
||||||
|
glShaderSource(m_geoShader, 1, (const GLchar **)&gShader, NULL);
|
||||||
|
glCompileShader(m_geoShader);
|
||||||
|
glAttachShader(m_shaderProgram, m_geoShader);
|
||||||
|
PrintShaderResult(m_geoShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, m_config["VertexShader"].ValueAs<std::string>(), m_config["FragmentShader"].ValueAs<std::string>(), vShader, fShader);
|
PrintShaderResult(m_vertexShader);
|
||||||
|
PrintShaderResult(m_fragmentShader);
|
||||||
|
|
||||||
m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1");
|
glAttachShader(m_shaderProgram, m_vertexShader);
|
||||||
m_locTexture2 = glGetUniformLocation(m_shaderProgram, "tex2");
|
glAttachShader(m_shaderProgram, m_fragmentShader);
|
||||||
m_locTexture1Enabled= glGetUniformLocation(m_shaderProgram, "textureEnabled");
|
glLinkProgram(m_shaderProgram);
|
||||||
m_locTexture2Enabled= glGetUniformLocation(m_shaderProgram, "microTexture");
|
|
||||||
m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha");
|
|
||||||
m_locAlphaTest = glGetUniformLocation(m_shaderProgram, "alphaTest");
|
|
||||||
m_locMicroTexScale = glGetUniformLocation(m_shaderProgram, "microTextureScale");
|
|
||||||
m_locBaseTexSize = glGetUniformLocation(m_shaderProgram, "baseTexSize");
|
|
||||||
m_locTextureInverted= glGetUniformLocation(m_shaderProgram, "textureInverted");
|
|
||||||
|
|
||||||
m_locFogIntensity = glGetUniformLocation(m_shaderProgram, "fogIntensity");
|
PrintProgramResult(m_shaderProgram);
|
||||||
m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity");
|
|
||||||
m_locFogStart = glGetUniformLocation(m_shaderProgram, "fogStart");
|
|
||||||
m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour");
|
|
||||||
m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation");
|
|
||||||
m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient");
|
|
||||||
|
|
||||||
m_locLighting = glGetUniformLocation(m_shaderProgram, "lighting");
|
m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1");
|
||||||
m_locLightEnabled = glGetUniformLocation(m_shaderProgram, "lightEnabled");
|
m_locTexture2 = glGetUniformLocation(m_shaderProgram, "tex2");
|
||||||
m_locSunClamp = glGetUniformLocation(m_shaderProgram, "sunClamp");
|
m_locTexture1Enabled = glGetUniformLocation(m_shaderProgram, "textureEnabled");
|
||||||
m_locIntensityClamp = glGetUniformLocation(m_shaderProgram, "intensityClamp");
|
m_locTexture2Enabled = glGetUniformLocation(m_shaderProgram, "microTexture");
|
||||||
m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess");
|
m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha");
|
||||||
m_locSpecularValue = glGetUniformLocation(m_shaderProgram, "specularValue");
|
m_locAlphaTest = glGetUniformLocation(m_shaderProgram, "alphaTest");
|
||||||
m_locSpecularEnabled= glGetUniformLocation(m_shaderProgram, "specularEnabled");
|
m_locMicroTexScale = glGetUniformLocation(m_shaderProgram, "microTextureScale");
|
||||||
m_locFixedShading = glGetUniformLocation(m_shaderProgram, "fixedShading");
|
m_locBaseTexSize = glGetUniformLocation(m_shaderProgram, "baseTexSize");
|
||||||
|
m_locTextureInverted = glGetUniformLocation(m_shaderProgram, "textureInverted");
|
||||||
|
|
||||||
m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse");
|
m_locFogIntensity = glGetUniformLocation(m_shaderProgram, "fogIntensity");
|
||||||
m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange");
|
m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity");
|
||||||
m_locSpotColor = glGetUniformLocation(m_shaderProgram, "spotColor");
|
m_locFogStart = glGetUniformLocation(m_shaderProgram, "fogStart");
|
||||||
m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor");
|
m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour");
|
||||||
m_locModelScale = glGetUniformLocation(m_shaderProgram, "modelScale");
|
m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation");
|
||||||
|
m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient");
|
||||||
|
|
||||||
m_locHardwareStep = glGetUniformLocation(m_shaderProgram, "hardwareStep");
|
m_locLighting = glGetUniformLocation(m_shaderProgram, "lighting");
|
||||||
m_locDiscardAlpha = glGetUniformLocation(m_shaderProgram, "discardAlpha");
|
m_locLightEnabled = glGetUniformLocation(m_shaderProgram, "lightEnabled");
|
||||||
|
m_locSunClamp = glGetUniformLocation(m_shaderProgram, "sunClamp");
|
||||||
|
m_locIntensityClamp = glGetUniformLocation(m_shaderProgram, "intensityClamp");
|
||||||
|
m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess");
|
||||||
|
m_locSpecularValue = glGetUniformLocation(m_shaderProgram, "specularValue");
|
||||||
|
m_locSpecularEnabled = glGetUniformLocation(m_shaderProgram, "specularEnabled");
|
||||||
|
m_locFixedShading = glGetUniformLocation(m_shaderProgram, "fixedShading");
|
||||||
|
|
||||||
return success;
|
m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse");
|
||||||
|
m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange");
|
||||||
|
m_locSpotColor = glGetUniformLocation(m_shaderProgram, "spotColor");
|
||||||
|
m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor");
|
||||||
|
m_locModelScale = glGetUniformLocation(m_shaderProgram, "modelScale");
|
||||||
|
|
||||||
|
m_locProjMat = glGetUniformLocation(m_shaderProgram, "projMat");
|
||||||
|
m_locModelMat = glGetUniformLocation(m_shaderProgram, "modelMat");
|
||||||
|
|
||||||
|
m_locHardwareStep = glGetUniformLocation(m_shaderProgram, "hardwareStep");
|
||||||
|
m_locDiscardAlpha = glGetUniformLocation(m_shaderProgram, "discardAlpha");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint R3DShader::GetVertexAttribPos(const char* attrib)
|
GLint R3DShader::GetVertexAttribPos(const char* attrib)
|
||||||
|
@ -500,21 +233,23 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
|
||||||
void R3DShader::SetViewportUniforms(const Viewport *vp)
|
void R3DShader::SetViewportUniforms(const Viewport *vp)
|
||||||
{
|
{
|
||||||
//didn't bother caching these, they don't get frequently called anyway
|
//didn't bother caching these, they don't get frequently called anyway
|
||||||
glUniform1f (m_locFogDensity, vp->fogParams[3]);
|
glUniform1f(m_locFogDensity, vp->fogParams[3]);
|
||||||
glUniform1f (m_locFogStart, vp->fogParams[4]);
|
glUniform1f(m_locFogStart, vp->fogParams[4]);
|
||||||
glUniform3fv(m_locFogColour, 1, vp->fogParams);
|
glUniform3fv(m_locFogColour, 1, vp->fogParams);
|
||||||
glUniform1f (m_locFogAttenuation, vp->fogParams[5]);
|
glUniform1f(m_locFogAttenuation, vp->fogParams[5]);
|
||||||
glUniform1f (m_locFogAmbient, vp->fogParams[6]);
|
glUniform1f(m_locFogAmbient, vp->fogParams[6]);
|
||||||
|
|
||||||
glUniform3fv(m_locLighting, 2, vp->lightingParams);
|
glUniform3fv(m_locLighting, 2, vp->lightingParams);
|
||||||
glUniform1i (m_locSunClamp, vp->sunClamp);
|
glUniform1i(m_locSunClamp, vp->sunClamp);
|
||||||
glUniform1i (m_locIntensityClamp, vp->intensityClamp);
|
glUniform1i(m_locIntensityClamp, vp->intensityClamp);
|
||||||
glUniform4fv(m_locSpotEllipse, 1, vp->spotEllipse);
|
glUniform4fv(m_locSpotEllipse, 1, vp->spotEllipse);
|
||||||
glUniform2fv(m_locSpotRange, 1, vp->spotRange);
|
glUniform2fv(m_locSpotRange, 1, vp->spotRange);
|
||||||
glUniform3fv(m_locSpotColor, 1, vp->spotColor);
|
glUniform3fv(m_locSpotColor, 1, vp->spotColor);
|
||||||
glUniform3fv(m_locSpotFogColor, 1, vp->spotFogColor);
|
glUniform3fv(m_locSpotFogColor, 1, vp->spotFogColor);
|
||||||
|
|
||||||
glUniform1i (m_locHardwareStep, vp->hardwareStep);
|
glUniformMatrix4fv(m_locProjMat, 1, GL_FALSE, vp->projectionMatrix);
|
||||||
|
|
||||||
|
glUniform1i(m_locHardwareStep, vp->hardwareStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void R3DShader::SetModelStates(const Model* model)
|
void R3DShader::SetModelStates(const Model* model)
|
||||||
|
@ -524,6 +259,8 @@ void R3DShader::SetModelStates(const Model* model)
|
||||||
m_modelScale = model->scale;
|
m_modelScale = model->scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glUniformMatrix4fv(m_locModelMat, 1, GL_FALSE, model->modelMat);
|
||||||
|
|
||||||
m_dirtyModel = false;
|
m_dirtyModel = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,4 +269,44 @@ void R3DShader::DiscardAlpha(bool discard)
|
||||||
glUniform1i(m_locDiscardAlpha, discard);
|
glUniform1i(m_locDiscardAlpha, discard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void R3DShader::PrintShaderResult(GLuint shader)
|
||||||
|
{
|
||||||
|
//===========
|
||||||
|
GLint result;
|
||||||
|
GLint length;
|
||||||
|
//===========
|
||||||
|
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
|
||||||
|
|
||||||
|
if (result == GL_FALSE) {
|
||||||
|
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
std::vector<char> msg(length);
|
||||||
|
glGetShaderInfoLog(shader, length, NULL, msg.data());
|
||||||
|
printf("%s\n", msg.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void R3DShader::PrintProgramResult(GLuint program)
|
||||||
|
{
|
||||||
|
//===========
|
||||||
|
GLint result;
|
||||||
|
//===========
|
||||||
|
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &result);
|
||||||
|
|
||||||
|
if (result == GL_FALSE) {
|
||||||
|
|
||||||
|
GLint maxLength = 0;
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
|
||||||
|
|
||||||
|
//The maxLength includes the NULL character
|
||||||
|
std::vector<GLchar> infoLog(maxLength);
|
||||||
|
glGetProgramInfoLog(program, maxLength, &maxLength, infoLog.data());
|
||||||
|
printf("%s\n", infoLog.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
} // New3D
|
} // New3D
|
||||||
|
|
|
@ -23,12 +23,16 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void PrintShaderResult(GLuint shader);
|
||||||
|
void PrintProgramResult(GLuint program);
|
||||||
|
|
||||||
// run-time config
|
// run-time config
|
||||||
const Util::Config::Node &m_config;
|
const Util::Config::Node &m_config;
|
||||||
|
|
||||||
// shader IDs
|
// shader IDs
|
||||||
GLuint m_shaderProgram;
|
GLuint m_shaderProgram;
|
||||||
GLuint m_vertexShader;
|
GLuint m_vertexShader;
|
||||||
|
GLuint m_geoShader;
|
||||||
GLuint m_fragmentShader;
|
GLuint m_fragmentShader;
|
||||||
|
|
||||||
// mesh uniform locations
|
// mesh uniform locations
|
||||||
|
@ -73,6 +77,7 @@ private:
|
||||||
GLint m_locFogColour;
|
GLint m_locFogColour;
|
||||||
GLint m_locFogAttenuation;
|
GLint m_locFogAttenuation;
|
||||||
GLint m_locFogAmbient;
|
GLint m_locFogAmbient;
|
||||||
|
GLint m_locProjMat;
|
||||||
|
|
||||||
// lighting / other
|
// lighting / other
|
||||||
GLint m_locLighting;
|
GLint m_locLighting;
|
||||||
|
@ -91,12 +96,14 @@ private:
|
||||||
|
|
||||||
// model uniforms
|
// model uniforms
|
||||||
GLint m_locModelScale;
|
GLint m_locModelScale;
|
||||||
|
GLint m_locModelMat;
|
||||||
|
|
||||||
// global uniforms
|
// global uniforms
|
||||||
GLint m_locHardwareStep;
|
GLint m_locHardwareStep;
|
||||||
GLint m_locDiscardAlpha;
|
GLint m_locDiscardAlpha;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // New3D
|
} // New3D
|
||||||
|
|
||||||
#endif
|
#endif
|
527
Src/Graphics/New3D/R3DShaderQuads.h
Normal file
527
Src/Graphics/New3D/R3DShaderQuads.h
Normal file
|
@ -0,0 +1,527 @@
|
||||||
|
#ifndef _R3DSHADERQUADS_H_
|
||||||
|
#define _R3DSHADERQUADS_H_
|
||||||
|
|
||||||
|
static const char *vertexShaderR3DQuads = R"glsl(
|
||||||
|
|
||||||
|
#version 410 core
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
uniform float modelScale;
|
||||||
|
uniform mat4 modelMat;
|
||||||
|
uniform mat4 projMat;
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
in vec4 inVertex;
|
||||||
|
in vec3 inNormal;
|
||||||
|
in vec2 inTexCoord;
|
||||||
|
in vec3 inFaceNormal; // used to emulate r3d culling
|
||||||
|
in float inFixedShade;
|
||||||
|
in vec4 inColour;
|
||||||
|
|
||||||
|
// outputs to geometry shader
|
||||||
|
|
||||||
|
out VS_OUT
|
||||||
|
{
|
||||||
|
vec3 viewVertex;
|
||||||
|
vec3 viewNormal; // per vertex normal vector
|
||||||
|
vec2 texCoord;
|
||||||
|
float fixedShade;
|
||||||
|
vec4 color;
|
||||||
|
float discardPoly; // can't have varying bool (glsl spec)
|
||||||
|
} vs_out;
|
||||||
|
|
||||||
|
float CalcBackFace(in vec3 viewVertex)
|
||||||
|
{
|
||||||
|
vec3 vt = viewVertex - vec3(0.0);
|
||||||
|
vec3 vn = (mat3(modelMat) * inFaceNormal);
|
||||||
|
|
||||||
|
// dot product of face normal with view direction
|
||||||
|
return dot(vt, vn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
vs_out.viewVertex = vec3(modelMat * inVertex);
|
||||||
|
vs_out.viewNormal = (mat3(modelMat) * inNormal) / modelScale;
|
||||||
|
vs_out.discardPoly = CalcBackFace(vs_out.viewVertex);
|
||||||
|
vs_out.color = inColour;
|
||||||
|
vs_out.texCoord = inTexCoord;
|
||||||
|
vs_out.fixedShade = inFixedShade;
|
||||||
|
gl_Position = projMat * modelMat * inVertex;
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
static const char *geometryShaderR3DQuads = R"glsl(
|
||||||
|
|
||||||
|
#version 410 core
|
||||||
|
|
||||||
|
layout (lines_adjacency) in;
|
||||||
|
layout (triangle_strip, max_vertices = 4) out;
|
||||||
|
|
||||||
|
in VS_OUT
|
||||||
|
{
|
||||||
|
vec3 viewVertex;
|
||||||
|
vec3 viewNormal; // per vertex normal vector
|
||||||
|
vec2 texCoord;
|
||||||
|
float fixedShade;
|
||||||
|
vec4 color;
|
||||||
|
float discardPoly; // can't have varying bool (glsl spec)
|
||||||
|
} gs_in[4];
|
||||||
|
|
||||||
|
out GS_OUT
|
||||||
|
{
|
||||||
|
noperspective vec2 v[4];
|
||||||
|
noperspective float area[4];
|
||||||
|
flat float oneOverW[4];
|
||||||
|
|
||||||
|
//our regular attributes
|
||||||
|
flat vec3 viewVertex[4];
|
||||||
|
flat vec3 viewNormal[4]; // per vertex normal vector
|
||||||
|
flat vec2 texCoord[4];
|
||||||
|
flat float fixedShade[4];
|
||||||
|
flat vec4 color;
|
||||||
|
} gs_out;
|
||||||
|
|
||||||
|
float area(vec2 a, vec2 b)
|
||||||
|
{
|
||||||
|
return a.x*b.y - a.y*b.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
if(gs_in[0].discardPoly>=0) {
|
||||||
|
return; //emulate back face culling here (all vertices in poly have same value)
|
||||||
|
}
|
||||||
|
|
||||||
|
int i, j, j_next;
|
||||||
|
vec2 v[4];
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
float oneOverW = 1.0 / gl_in[i].gl_Position.w;
|
||||||
|
gs_out.oneOverW[i] = oneOverW;
|
||||||
|
v[i] = gl_in[i].gl_Position.xy * oneOverW;
|
||||||
|
|
||||||
|
// our regular vertex attribs
|
||||||
|
gs_out.viewVertex[i] = gs_in[i].viewVertex * oneOverW;
|
||||||
|
gs_out.viewNormal[i] = gs_in[i].viewNormal * oneOverW;
|
||||||
|
gs_out.texCoord[i] = gs_in[i].texCoord * oneOverW;
|
||||||
|
gs_out.fixedShade[i] = gs_in[i].fixedShade * oneOverW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flat attributes
|
||||||
|
gs_out.color = gs_in[0].color;
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
// Mapping of polygon vertex order to triangle strip vertex order.
|
||||||
|
//
|
||||||
|
// Quad (lines adjacency) Triangle strip
|
||||||
|
// vertex order: vertex order:
|
||||||
|
//
|
||||||
|
// 1----2 1----3
|
||||||
|
// | | ===> | \ |
|
||||||
|
// | | | \ |
|
||||||
|
// 0----3 0----2
|
||||||
|
//
|
||||||
|
int reorder[4] = int[]( 1, 0, 2, 3 );
|
||||||
|
int ii = reorder[i];
|
||||||
|
|
||||||
|
for (j=0; j<4; j++) {
|
||||||
|
gs_out.v[j] = v[j] - v[ii];
|
||||||
|
}
|
||||||
|
for (j=0; j<4; j++) {
|
||||||
|
j_next = (j+1) % 4;
|
||||||
|
gs_out.area[j] = area(gs_out.v[j], gs_out.v[j_next]);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_Position = gl_in[ii].gl_Position;
|
||||||
|
|
||||||
|
EmitVertex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
static const char *fragmentShaderR3DQuads = R"glsl(
|
||||||
|
|
||||||
|
#version 410 core
|
||||||
|
|
||||||
|
uniform sampler2D tex1; // base tex
|
||||||
|
uniform sampler2D tex2; // micro tex (optional)
|
||||||
|
|
||||||
|
// texturing
|
||||||
|
uniform bool textureEnabled;
|
||||||
|
uniform bool microTexture;
|
||||||
|
uniform float microTextureScale;
|
||||||
|
uniform vec2 baseTexSize;
|
||||||
|
uniform bool textureInverted;
|
||||||
|
uniform bool textureAlpha;
|
||||||
|
uniform bool alphaTest;
|
||||||
|
uniform bool discardAlpha;
|
||||||
|
|
||||||
|
// general
|
||||||
|
uniform vec3 fogColour;
|
||||||
|
uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)
|
||||||
|
uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit
|
||||||
|
uniform vec3 spotColor; // spotlight RGB color
|
||||||
|
uniform vec3 spotFogColor; // spotlight RGB color on fog
|
||||||
|
uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)
|
||||||
|
uniform bool lightEnabled; // lighting enabled (1.0) or luminous (0.0), drawn at full intensity
|
||||||
|
uniform bool sunClamp; // not used by daytona and la machine guns
|
||||||
|
uniform bool intensityClamp; // some games such as daytona and
|
||||||
|
uniform bool specularEnabled; // specular enabled
|
||||||
|
uniform float specularValue; // specular coefficient
|
||||||
|
uniform float shininess; // specular shininess
|
||||||
|
uniform float fogIntensity;
|
||||||
|
uniform float fogDensity;
|
||||||
|
uniform float fogStart;
|
||||||
|
uniform float fogAttenuation;
|
||||||
|
uniform float fogAmbient;
|
||||||
|
uniform bool fixedShading;
|
||||||
|
uniform int hardwareStep;
|
||||||
|
|
||||||
|
// test
|
||||||
|
uniform mat4 projMat;
|
||||||
|
|
||||||
|
//interpolated inputs from geometry shader
|
||||||
|
|
||||||
|
in GS_OUT
|
||||||
|
{
|
||||||
|
noperspective vec2 v[4];
|
||||||
|
noperspective float area[4];
|
||||||
|
flat float oneOverW[4];
|
||||||
|
|
||||||
|
//our regular attributes
|
||||||
|
flat vec3 viewVertex[4];
|
||||||
|
flat vec3 viewNormal[4]; // per vertex normal vector
|
||||||
|
flat vec2 texCoord[4];
|
||||||
|
flat float fixedShade[4];
|
||||||
|
flat vec4 color;
|
||||||
|
} fs_in;
|
||||||
|
|
||||||
|
//our calculated vertex attributes from the above
|
||||||
|
vec3 fsViewVertex;
|
||||||
|
vec3 fsViewNormal;
|
||||||
|
vec2 fsTexCoord;
|
||||||
|
float fsFixedShade;
|
||||||
|
vec4 fsColor;
|
||||||
|
|
||||||
|
//outputs
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
|
void QuadraticInterpolation()
|
||||||
|
{
|
||||||
|
uint i, i_next, i_prev;
|
||||||
|
|
||||||
|
vec2 s[4];
|
||||||
|
float A[4];
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
s[i] = fs_in.v[i];
|
||||||
|
A[i] = fs_in.area[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
float D[4];
|
||||||
|
float r[4];
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
i_next = (i+1)%4;
|
||||||
|
D[i] = dot(s[i], s[i_next]);
|
||||||
|
r[i] = length(s[i]);
|
||||||
|
if (fs_in.oneOverW[i] < 0) { // is w[i] negative?
|
||||||
|
r[i] = -r[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float t[4];
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
i_next = (i+1)%4;
|
||||||
|
if(A[i]==0.0) t[i] = 0; // check for zero area + div by zero
|
||||||
|
else t[i] = (r[i]*r[i_next] - D[i]) / A[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
float uSum = 0;
|
||||||
|
float u[4];
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
i_prev = (i-1)%4;
|
||||||
|
u[i] = (t[i_prev] + t[i]) / r[i];
|
||||||
|
uSum += u[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
float lambda[4];
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
lambda[i] = u[i] / uSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Discard fragments when all the weights are neither all negative nor all positive. */
|
||||||
|
|
||||||
|
int lambdaSignCount = 0;
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
if (fs_in.oneOverW[i] < 0) {
|
||||||
|
if (lambda[i] > 0) {
|
||||||
|
lambdaSignCount--;
|
||||||
|
} else {
|
||||||
|
lambdaSignCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (lambda[i] < 0) {
|
||||||
|
lambdaSignCount--;
|
||||||
|
} else {
|
||||||
|
lambdaSignCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (abs(lambdaSignCount) != 4) {
|
||||||
|
discard; // need to revisit this
|
||||||
|
}
|
||||||
|
|
||||||
|
float interp_oneOverW = 0;
|
||||||
|
|
||||||
|
fsViewVertex = vec3(0.0);
|
||||||
|
fsViewNormal = vec3(0.0);
|
||||||
|
fsTexCoord = vec2(0.0);
|
||||||
|
fsFixedShade = 0.0;
|
||||||
|
fsColor = fs_in.color;
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
fsViewVertex += lambda[i] * fs_in.viewVertex[i];
|
||||||
|
fsViewNormal += lambda[i] * fs_in.viewNormal[i];
|
||||||
|
fsTexCoord += lambda[i] * fs_in.texCoord[i];
|
||||||
|
fsFixedShade += lambda[i] * fs_in.fixedShade[i];
|
||||||
|
interp_oneOverW += lambda[i] * fs_in.oneOverW[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
fsViewVertex /= interp_oneOverW;
|
||||||
|
fsViewNormal /= interp_oneOverW;
|
||||||
|
fsTexCoord /= interp_oneOverW;
|
||||||
|
fsFixedShade /= interp_oneOverW;
|
||||||
|
|
||||||
|
vec4 vertex;
|
||||||
|
float depth;
|
||||||
|
|
||||||
|
// dirty hack for co-planar polys that really need 100% identical values to depth test correctly
|
||||||
|
// the reason we waste cycles and calcute depth value here is because we have run out of vertex attribs
|
||||||
|
if(fs_in.oneOverW[0]==fs_in.oneOverW[1] &&
|
||||||
|
fs_in.oneOverW[1]==fs_in.oneOverW[2] &&
|
||||||
|
fs_in.oneOverW[2]==fs_in.oneOverW[3]) {
|
||||||
|
|
||||||
|
fsViewVertex.z = fs_in.viewVertex[0].z / fs_in.oneOverW[0];
|
||||||
|
vertex = projMat * vec4(fsViewVertex,1.0);
|
||||||
|
depth = ((vertex.z / vertex.w) + 1.0) / 2.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vertex = projMat * vec4(fsViewVertex,1.0);
|
||||||
|
depth = ((vertex.z * interp_oneOverW) + 1.0) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragDepth = depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 GetTextureValue()
|
||||||
|
{
|
||||||
|
vec4 tex1Data = texture2D( tex1, fsTexCoord.st);
|
||||||
|
|
||||||
|
if(textureInverted) {
|
||||||
|
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (microTexture) {
|
||||||
|
vec2 scale = (baseTexSize / 128.0) * microTextureScale;
|
||||||
|
vec4 tex2Data = texture2D( tex2, fsTexCoord.st * scale);
|
||||||
|
tex1Data = (tex1Data+tex2Data)/2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alphaTest) {
|
||||||
|
if (tex1Data.a < (8.0/16.0)) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(textureAlpha) {
|
||||||
|
if(discardAlpha) { // opaque 1st pass
|
||||||
|
if (tex1Data.a < 1.0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // transparent 2nd pass
|
||||||
|
if ((tex1Data.a * fsColor.a) >= 1.0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureAlpha == false) {
|
||||||
|
tex1Data.a = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tex1Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Step15Luminous(inout vec4 colour)
|
||||||
|
{
|
||||||
|
// luminous polys seem to behave very differently on step 1.5 hardware
|
||||||
|
// when fixed shading is enabled the colour is modulated by the vp ambient + fixed shade value
|
||||||
|
// when disabled it appears to be multiplied by 1.5, presumably to allow a higher range
|
||||||
|
if(hardwareStep==0x15) {
|
||||||
|
if(!lightEnabled && textureEnabled) {
|
||||||
|
if(fixedShading) {
|
||||||
|
colour.rgb *= 1.0 + fsFixedShade + lighting[1].y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
colour.rgb *= vec3(1.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float CalcFog()
|
||||||
|
{
|
||||||
|
float z = -fsViewVertex.z;
|
||||||
|
float fog = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);
|
||||||
|
|
||||||
|
return fog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 tex1Data;
|
||||||
|
vec4 colData;
|
||||||
|
vec4 finalData;
|
||||||
|
vec4 fogData;
|
||||||
|
|
||||||
|
QuadraticInterpolation(); // calculate our vertex attributes
|
||||||
|
|
||||||
|
fogData = vec4(fogColour.rgb * fogAmbient, CalcFog());
|
||||||
|
tex1Data = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
if(textureEnabled) {
|
||||||
|
tex1Data = GetTextureValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
colData = fsColor;
|
||||||
|
Step15Luminous(colData); // no-op for step 2.0+
|
||||||
|
finalData = tex1Data * colData;
|
||||||
|
|
||||||
|
if (finalData.a < (1.0/16.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ellipse;
|
||||||
|
ellipse = length((gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw);
|
||||||
|
ellipse = pow(ellipse, 2.0); // decay rate = square of distance from center
|
||||||
|
ellipse = 1.0 - ellipse; // invert
|
||||||
|
ellipse = max(0.0, ellipse); // clamp
|
||||||
|
|
||||||
|
// Compute spotlight and apply lighting
|
||||||
|
float enable, absExtent, d, inv_r, range;
|
||||||
|
|
||||||
|
// start of spotlight
|
||||||
|
enable = step(spotRange.x, -fsViewVertex.z);
|
||||||
|
|
||||||
|
if (spotRange.y == 0.0) {
|
||||||
|
range = 0.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
absExtent = abs(spotRange.y);
|
||||||
|
|
||||||
|
d = spotRange.x + absExtent + fsViewVertex.z;
|
||||||
|
d = min(d, 0.0);
|
||||||
|
|
||||||
|
// slope of decay function
|
||||||
|
inv_r = 1.0 / (1.0 + absExtent);
|
||||||
|
|
||||||
|
// inverse-linear falloff
|
||||||
|
// Reference: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
|
||||||
|
// y = 1 / (d/r + 1)^2
|
||||||
|
range = 1.0 / pow(d * inv_r - 1.0, 2.0);
|
||||||
|
range *= enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lobeEffect = range * ellipse;
|
||||||
|
float lobeFogEffect = enable * ellipse;
|
||||||
|
|
||||||
|
if (lightEnabled) {
|
||||||
|
vec3 lightIntensity;
|
||||||
|
vec3 sunVector; // sun lighting vector (as reflecting away from vertex)
|
||||||
|
float sunFactor; // sun light projection along vertex normal (0.0 to 1.0)
|
||||||
|
|
||||||
|
// Sun angle
|
||||||
|
sunVector = lighting[0];
|
||||||
|
|
||||||
|
// Compute diffuse factor for sunlight
|
||||||
|
if(fixedShading) {
|
||||||
|
sunFactor = fsFixedShade;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sunFactor = dot(sunVector, fsViewNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp ceil, fix for upscaled models without "modelScale" defined
|
||||||
|
sunFactor = clamp(sunFactor,-1.0,1.0);
|
||||||
|
|
||||||
|
// Optional clamping, value is allowed to be negative
|
||||||
|
if(sunClamp) {
|
||||||
|
sunFactor = max(sunFactor,0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total light intensity: sum of all components
|
||||||
|
lightIntensity = vec3(sunFactor*lighting[1].x + lighting[1].y); // diffuse + ambient
|
||||||
|
|
||||||
|
lightIntensity.rgb += spotColor*lobeEffect;
|
||||||
|
|
||||||
|
// Upper clamp is optional, step 1.5+ games will drive brightness beyond 100%
|
||||||
|
if(intensityClamp) {
|
||||||
|
lightIntensity = min(lightIntensity,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalData.rgb *= lightIntensity;
|
||||||
|
|
||||||
|
// for now assume fixed shading doesn't work with specular
|
||||||
|
if (specularEnabled) {
|
||||||
|
|
||||||
|
float exponent, NdotL, specularFactor;
|
||||||
|
vec4 biasIndex, expIndex, multIndex;
|
||||||
|
|
||||||
|
// Always clamp floor to zero, we don't want deep black areas
|
||||||
|
NdotL = max(0.0,sunFactor);
|
||||||
|
|
||||||
|
expIndex = vec4(8.0, 16.0, 32.0, 64.0);
|
||||||
|
multIndex = vec4(2.0, 2.0, 3.0, 4.0);
|
||||||
|
biasIndex = vec4(0.95, 0.95, 1.05, 1.0);
|
||||||
|
exponent = expIndex[int(shininess)] / biasIndex[int(shininess)];
|
||||||
|
|
||||||
|
specularFactor = pow(NdotL, exponent);
|
||||||
|
specularFactor *= multIndex[int(shininess)];
|
||||||
|
specularFactor *= biasIndex[int(shininess)];
|
||||||
|
|
||||||
|
specularFactor *= specularValue;
|
||||||
|
specularFactor *= lighting[1].x;
|
||||||
|
|
||||||
|
if (colData.a < 1.0) {
|
||||||
|
/// Specular hi-light affects translucent polygons alpha channel ///
|
||||||
|
finalData.a = max(finalData.a, specularFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalData.rgb += vec3(specularFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final clamp: we need it for proper shading in dimmed light and dark ambients
|
||||||
|
finalData.rgb = min(finalData.rgb, vec3(1.0));
|
||||||
|
|
||||||
|
// Spotlight on fog
|
||||||
|
vec3 lSpotFogColor = spotFogColor * fogAttenuation * fogColour.rgb * lobeFogEffect;
|
||||||
|
|
||||||
|
// Fog & spotlight applied
|
||||||
|
finalData.rgb = mix(finalData.rgb, fogData.rgb + lSpotFogColor, fogData.a);
|
||||||
|
|
||||||
|
// Write output
|
||||||
|
outColor = finalData;
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
#endif
|
300
Src/Graphics/New3D/R3DShaderTriangles.h
Normal file
300
Src/Graphics/New3D/R3DShaderTriangles.h
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
#ifndef _R3DSHADERTRIANGLES_H_
|
||||||
|
#define _R3DSHADERTRIANGLES_H_
|
||||||
|
|
||||||
|
static const char *vertexShaderR3D = R"glsl(
|
||||||
|
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
uniform float modelScale;
|
||||||
|
uniform mat4 modelMat;
|
||||||
|
uniform mat4 projMat;
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
attribute vec4 inVertex;
|
||||||
|
attribute vec3 inNormal;
|
||||||
|
attribute vec2 inTexCoord;
|
||||||
|
attribute vec4 inColour;
|
||||||
|
attribute vec3 inFaceNormal; // used to emulate r3d culling
|
||||||
|
attribute float inFixedShade;
|
||||||
|
|
||||||
|
// outputs to fragment shader
|
||||||
|
varying vec3 fsViewVertex;
|
||||||
|
varying vec3 fsViewNormal; // per vertex normal vector
|
||||||
|
varying vec2 fsTexCoord;
|
||||||
|
varying vec4 fsColor;
|
||||||
|
varying float fsDiscard; // can't have varying bool (glsl spec)
|
||||||
|
varying float fsFixedShade;
|
||||||
|
|
||||||
|
float CalcBackFace(in vec3 viewVertex)
|
||||||
|
{
|
||||||
|
vec3 vt = viewVertex - vec3(0.0);
|
||||||
|
vec3 vn = (mat3(modelMat) * inFaceNormal);
|
||||||
|
|
||||||
|
// dot product of face normal with view direction
|
||||||
|
return dot(vt, vn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
fsViewVertex = vec3(modelMat * inVertex);
|
||||||
|
fsViewNormal = (mat3(modelMat) * inNormal) / modelScale;
|
||||||
|
fsDiscard = CalcBackFace(fsViewVertex);
|
||||||
|
fsColor = inColour;
|
||||||
|
fsTexCoord = inTexCoord;
|
||||||
|
fsFixedShade = inFixedShade;
|
||||||
|
gl_Position = projMat * modelMat * inVertex;
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
static const char *fragmentShaderR3D = R"glsl(
|
||||||
|
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
uniform sampler2D tex1; // base tex
|
||||||
|
uniform sampler2D tex2; // micro tex (optional)
|
||||||
|
|
||||||
|
// texturing
|
||||||
|
uniform bool textureEnabled;
|
||||||
|
uniform bool microTexture;
|
||||||
|
uniform float microTextureScale;
|
||||||
|
uniform vec2 baseTexSize;
|
||||||
|
uniform bool textureInverted;
|
||||||
|
uniform bool textureAlpha;
|
||||||
|
uniform bool alphaTest;
|
||||||
|
uniform bool discardAlpha;
|
||||||
|
|
||||||
|
// general
|
||||||
|
uniform vec3 fogColour;
|
||||||
|
uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)
|
||||||
|
uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit
|
||||||
|
uniform vec3 spotColor; // spotlight RGB color
|
||||||
|
uniform vec3 spotFogColor; // spotlight RGB color on fog
|
||||||
|
uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)
|
||||||
|
uniform bool lightEnabled; // lighting enabled (1.0) or luminous (0.0), drawn at full intensity
|
||||||
|
uniform bool sunClamp; // not used by daytona and la machine guns
|
||||||
|
uniform bool intensityClamp; // some games such as daytona and
|
||||||
|
uniform bool specularEnabled; // specular enabled
|
||||||
|
uniform float specularValue; // specular coefficient
|
||||||
|
uniform float shininess; // specular shininess
|
||||||
|
uniform float fogIntensity;
|
||||||
|
uniform float fogDensity;
|
||||||
|
uniform float fogStart;
|
||||||
|
uniform float fogAttenuation;
|
||||||
|
uniform float fogAmbient;
|
||||||
|
uniform bool fixedShading;
|
||||||
|
uniform int hardwareStep;
|
||||||
|
|
||||||
|
//interpolated inputs from vertex shader
|
||||||
|
varying vec3 fsViewVertex;
|
||||||
|
varying vec3 fsViewNormal; // per vertex normal vector
|
||||||
|
varying vec4 fsColor;
|
||||||
|
varying vec2 fsTexCoord;
|
||||||
|
varying float fsDiscard;
|
||||||
|
varying float fsFixedShade;
|
||||||
|
|
||||||
|
vec4 GetTextureValue()
|
||||||
|
{
|
||||||
|
vec4 tex1Data = texture2D( tex1, fsTexCoord.st);
|
||||||
|
|
||||||
|
if(textureInverted) {
|
||||||
|
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (microTexture) {
|
||||||
|
vec2 scale = (baseTexSize / 128.0) * microTextureScale;
|
||||||
|
vec4 tex2Data = texture2D( tex2, fsTexCoord.st * scale);
|
||||||
|
tex1Data = (tex1Data+tex2Data)/2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alphaTest) {
|
||||||
|
if (tex1Data.a < (8.0/16.0)) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(textureAlpha) {
|
||||||
|
if(discardAlpha) { // opaque 1st pass
|
||||||
|
if (tex1Data.a < 1.0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // transparent 2nd pass
|
||||||
|
if ((tex1Data.a * fsColor.a) >= 1.0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureAlpha == false) {
|
||||||
|
tex1Data.a = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tex1Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Step15Luminous(inout vec4 colour)
|
||||||
|
{
|
||||||
|
// luminous polys seem to behave very differently on step 1.5 hardware
|
||||||
|
// when fixed shading is enabled the colour is modulated by the vp ambient + fixed shade value
|
||||||
|
// when disabled it appears to be multiplied by 1.5, presumably to allow a higher range
|
||||||
|
if(hardwareStep==0x15) {
|
||||||
|
if(!lightEnabled && textureEnabled) {
|
||||||
|
if(fixedShading) {
|
||||||
|
colour.rgb *= 1.0 + fsFixedShade + lighting[1].y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
colour.rgb *= vec3(1.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float CalcFog()
|
||||||
|
{
|
||||||
|
float z = -fsViewVertex.z;
|
||||||
|
float fog = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);
|
||||||
|
|
||||||
|
return fog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 tex1Data;
|
||||||
|
vec4 colData;
|
||||||
|
vec4 finalData;
|
||||||
|
vec4 fogData;
|
||||||
|
|
||||||
|
if(fsDiscard>=0) {
|
||||||
|
discard; //emulate back face culling here
|
||||||
|
}
|
||||||
|
|
||||||
|
fogData = vec4(fogColour.rgb * fogAmbient, CalcFog());
|
||||||
|
tex1Data = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
if(textureEnabled) {
|
||||||
|
tex1Data = GetTextureValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
colData = fsColor;
|
||||||
|
Step15Luminous(colData); // no-op for step 2.0+
|
||||||
|
finalData = tex1Data * colData;
|
||||||
|
|
||||||
|
if (finalData.a < (1.0/16.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ellipse;
|
||||||
|
ellipse = length((gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw);
|
||||||
|
ellipse = pow(ellipse, 2.0); // decay rate = square of distance from center
|
||||||
|
ellipse = 1.0 - ellipse; // invert
|
||||||
|
ellipse = max(0.0, ellipse); // clamp
|
||||||
|
|
||||||
|
// Compute spotlight and apply lighting
|
||||||
|
float enable, absExtent, d, inv_r, range;
|
||||||
|
|
||||||
|
// start of spotlight
|
||||||
|
enable = step(spotRange.x, -fsViewVertex.z);
|
||||||
|
|
||||||
|
if (spotRange.y == 0.0) {
|
||||||
|
range = 0.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
absExtent = abs(spotRange.y);
|
||||||
|
|
||||||
|
d = spotRange.x + absExtent + fsViewVertex.z;
|
||||||
|
d = min(d, 0.0);
|
||||||
|
|
||||||
|
// slope of decay function
|
||||||
|
inv_r = 1.0 / (1.0 + absExtent);
|
||||||
|
|
||||||
|
// inverse-linear falloff
|
||||||
|
// Reference: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
|
||||||
|
// y = 1 / (d/r + 1)^2
|
||||||
|
range = 1.0 / pow(d * inv_r - 1.0, 2.0);
|
||||||
|
range *= enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lobeEffect = range * ellipse;
|
||||||
|
float lobeFogEffect = enable * ellipse;
|
||||||
|
|
||||||
|
if (lightEnabled) {
|
||||||
|
vec3 lightIntensity;
|
||||||
|
vec3 sunVector; // sun lighting vector (as reflecting away from vertex)
|
||||||
|
float sunFactor; // sun light projection along vertex normal (0.0 to 1.0)
|
||||||
|
|
||||||
|
// Sun angle
|
||||||
|
sunVector = lighting[0];
|
||||||
|
|
||||||
|
// Compute diffuse factor for sunlight
|
||||||
|
if(fixedShading) {
|
||||||
|
sunFactor = fsFixedShade;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sunFactor = dot(sunVector, fsViewNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp ceil, fix for upscaled models without "modelScale" defined
|
||||||
|
sunFactor = clamp(sunFactor,-1.0,1.0);
|
||||||
|
|
||||||
|
// Optional clamping, value is allowed to be negative
|
||||||
|
if(sunClamp) {
|
||||||
|
sunFactor = max(sunFactor,0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total light intensity: sum of all components
|
||||||
|
lightIntensity = vec3(sunFactor*lighting[1].x + lighting[1].y); // diffuse + ambient
|
||||||
|
|
||||||
|
lightIntensity.rgb += spotColor*lobeEffect;
|
||||||
|
|
||||||
|
// Upper clamp is optional, step 1.5+ games will drive brightness beyond 100%
|
||||||
|
if(intensityClamp) {
|
||||||
|
lightIntensity = min(lightIntensity,1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalData.rgb *= lightIntensity;
|
||||||
|
|
||||||
|
// for now assume fixed shading doesn't work with specular
|
||||||
|
if (specularEnabled) {
|
||||||
|
|
||||||
|
float exponent, NdotL, specularFactor;
|
||||||
|
vec4 biasIndex, expIndex, multIndex;
|
||||||
|
|
||||||
|
// Always clamp floor to zero, we don't want deep black areas
|
||||||
|
NdotL = max(0.0,sunFactor);
|
||||||
|
|
||||||
|
expIndex = vec4(8.0, 16.0, 32.0, 64.0);
|
||||||
|
multIndex = vec4(2.0, 2.0, 3.0, 4.0);
|
||||||
|
biasIndex = vec4(0.95, 0.95, 1.05, 1.0);
|
||||||
|
exponent = expIndex[int(shininess)] / biasIndex[int(shininess)];
|
||||||
|
|
||||||
|
specularFactor = pow(NdotL, exponent);
|
||||||
|
specularFactor *= multIndex[int(shininess)];
|
||||||
|
specularFactor *= biasIndex[int(shininess)];
|
||||||
|
|
||||||
|
specularFactor *= specularValue;
|
||||||
|
specularFactor *= lighting[1].x;
|
||||||
|
|
||||||
|
if (colData.a < 1.0) {
|
||||||
|
/// Specular hi-light affects translucent polygons alpha channel ///
|
||||||
|
finalData.a = max(finalData.a, specularFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalData.rgb += vec3(specularFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final clamp: we need it for proper shading in dimmed light and dark ambients
|
||||||
|
finalData.rgb = min(finalData.rgb, vec3(1.0));
|
||||||
|
|
||||||
|
// Spotlight on fog
|
||||||
|
vec3 lSpotFogColor = spotFogColor * fogAttenuation * fogColour.rgb * lobeFogEffect;
|
||||||
|
|
||||||
|
// Fog & spotlight applied
|
||||||
|
finalData.rgb = mix(finalData.rgb, fogData.rgb + lSpotFogColor, fogData.a);
|
||||||
|
|
||||||
|
gl_FragColor = finalData;
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
#endif
|
|
@ -304,6 +304,7 @@ static void PrintGLInfo(bool createScreen, bool infoLog, bool printExtensions)
|
||||||
else printf(" %s\n", strLocal);
|
else printf(" %s\n", strLocal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(strLocal);
|
||||||
}
|
}
|
||||||
if (infoLog) InfoLog("");
|
if (infoLog) InfoLog("");
|
||||||
else printf("\n");
|
else printf("\n");
|
||||||
|
@ -1333,6 +1334,7 @@ static Util::Config::Node DefaultConfig()
|
||||||
#endif
|
#endif
|
||||||
// Platform-specific/UI
|
// Platform-specific/UI
|
||||||
config.Set("New3DEngine", true);
|
config.Set("New3DEngine", true);
|
||||||
|
config.Set("QuadRendering", false);
|
||||||
config.Set("XResolution", "496");
|
config.Set("XResolution", "496");
|
||||||
config.Set("YResolution", "384");
|
config.Set("YResolution", "384");
|
||||||
config.Set("FullScreen", false);
|
config.Set("FullScreen", false);
|
||||||
|
@ -1507,6 +1509,7 @@ static ParsedCommandLine ParseCommandLine(int argc, char **argv)
|
||||||
{ "-show-fps", { "ShowFrameRate", true } },
|
{ "-show-fps", { "ShowFrameRate", true } },
|
||||||
{ "-no-fps", { "ShowFrameRate", false } },
|
{ "-no-fps", { "ShowFrameRate", false } },
|
||||||
{ "-new3d", { "New3DEngine", true } },
|
{ "-new3d", { "New3DEngine", true } },
|
||||||
|
{ "-quad-rendering", { "QuadRendering", true } },
|
||||||
{ "-legacy3d", { "New3DEngine", false } },
|
{ "-legacy3d", { "New3DEngine", false } },
|
||||||
{ "-no-flip-stereo", { "FlipStereo", false } },
|
{ "-no-flip-stereo", { "FlipStereo", false } },
|
||||||
{ "-flip-stereo", { "FlipStereo", true } },
|
{ "-flip-stereo", { "FlipStereo", true } },
|
||||||
|
|
|
@ -13,6 +13,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZLib", "ZLib\ZLib.vcxproj",
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Musashi68K", "Musashi68K\Musashi68K.vcxproj", "{1248CF7C-B122-461C-9624-196AEFAE5046}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Musashi68K", "Musashi68K\Musashi68K.vcxproj", "{1248CF7C-B122-461C-9624-196AEFAE5046}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E195ADFF-E02F-4AE3-88E8-D90A4EC278A0}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
Performance1.psess = Performance1.psess
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
@ -65,4 +70,7 @@ Global
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(Performance) = preSolution
|
||||||
|
HasPerformanceSessions = true
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -550,6 +550,8 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi
|
||||||
<ClInclude Include="..\Src\Graphics\New3D\R3DFrameBuffers.h" />
|
<ClInclude Include="..\Src\Graphics\New3D\R3DFrameBuffers.h" />
|
||||||
<ClInclude Include="..\Src\Graphics\New3D\R3DScrollFog.h" />
|
<ClInclude Include="..\Src\Graphics\New3D\R3DScrollFog.h" />
|
||||||
<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\R3DShaderTriangles.h" />
|
||||||
<ClInclude Include="..\Src\Graphics\New3D\Texture.h" />
|
<ClInclude Include="..\Src\Graphics\New3D\Texture.h" />
|
||||||
<ClInclude Include="..\Src\Graphics\New3D\TextureSheet.h" />
|
<ClInclude Include="..\Src\Graphics\New3D\TextureSheet.h" />
|
||||||
<ClInclude Include="..\Src\Graphics\New3D\VBO.h" />
|
<ClInclude Include="..\Src\Graphics\New3D\VBO.h" />
|
||||||
|
|
|
@ -874,6 +874,12 @@
|
||||||
<ClInclude Include="..\Src\Graphics\New3D\GLSLShader.h">
|
<ClInclude Include="..\Src\Graphics\New3D\GLSLShader.h">
|
||||||
<Filter>Source Files\Graphics\New</Filter>
|
<Filter>Source Files\Graphics\New</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderQuads.h">
|
||||||
|
<Filter>Source Files\Graphics\New</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Src\Graphics\New3D\R3DShaderTriangles.h">
|
||||||
|
<Filter>Source Files\Graphics\New</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="..\Src\Debugger\ReadMe.txt">
|
<CustomBuild Include="..\Src\Debugger\ReadMe.txt">
|
||||||
|
|
Loading…
Reference in a new issue