diff --git a/Src/Graphics/New3D/Model.h b/Src/Graphics/New3D/Model.h index b9f7d85..e01caad 100644 --- a/Src/Graphics/New3D/Model.h +++ b/Src/Graphics/New3D/Model.h @@ -26,7 +26,8 @@ struct Vertex float pos[3]; float normal[3]; float texcoords[2]; - float color[4]; //rgba + UINT8 color[4]; + UINT8 fixedShade[4]; }; struct Poly // our polys are always 3 triangles, unlike the real h/w @@ -40,7 +41,7 @@ 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 - float faceColour[4]; // per face colour + UINT8 faceColour[4]; // per face colour int number = 4; }; @@ -85,6 +86,7 @@ struct Mesh bool highPriority = false; // rendered over the top // lighting + bool fixedShading = false; bool lighting = false; bool specular = false; float shininess = 0; @@ -151,6 +153,8 @@ struct Viewport int number; // viewport number float spotFogColor[3]; // spotlight color on fog float scrollAtt; + + int hardwareStep; // not really a viewport param but will do here }; enum class Clip { INSIDE, OUTSIDE, INTERCEPT, NOT_SET }; diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index dc8c87a..b487b56 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -282,12 +282,14 @@ void CNew3D::RenderFrame(void) glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); + glEnableVertexAttribArray(4); // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); - glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inTexCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color)); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inTexCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color)); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFixedShade"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, fixedShade)); m_r3dShader.SetShader(true); @@ -321,6 +323,7 @@ void CNew3D::RenderFrame(void) glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); } void CNew3D::BeginFrame(void) @@ -779,10 +782,9 @@ void CNew3D::RenderViewport(UINT32 addr) vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity vp->lightingParams[5] = 0.0; // reserved - vp->sunClamp = 1; // TODO work out how this is passed, doesn't appear to be in the viewport .. or in the model data - vp->intensityClamp = (m_step == 0x10); // just step 1.0 ? - - m_vpAmbient = vp->lightingParams[4]; // cache this + vp->sunClamp = 1; // TODO work out how this is passed, doesn't appear to be in the viewport .. or in the model data + vp->intensityClamp = (m_step == 0x10); // just step 1.0 ? + vp->hardwareStep = m_step; // Spotlight int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index @@ -904,11 +906,11 @@ void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray p.p3 = r3dPoly.v[0]; } - //multiply face attributes with vertex attributes if required + // Copy face colour to vertices for (int i = 0; i < 4; i++) { - p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i]; - p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i]; - p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i]; + p.p1.color[i] = r3dPoly.faceColour[i]; + p.p2.color[i] = r3dPoly.faceColour[i]; + p.p3.color[i] = r3dPoly.faceColour[i]; } polyArray.emplace_back(p); @@ -931,11 +933,11 @@ void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray p.p3 = r3dPoly.v[2]; } - //multiply face attributes with vertex attributes if required + // Copy face colour to vertices for (int i = 0; i < 4; i++) { - p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i]; - p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i]; - p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i]; + p.p1.color[i] = r3dPoly.faceColour[i]; + p.p2.color[i] = r3dPoly.faceColour[i]; + p.p3.color[i] = r3dPoly.faceColour[i]; } polyArray.emplace_back(p); @@ -997,7 +999,8 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph) currentMesh->alphaTest = ph.AlphaTest(); currentMesh->textureAlpha = ph.TextureAlpha(); currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled() && !ph.FixedShading(); + currentMesh->lighting = ph.LightEnabled(); + currentMesh->fixedShading = ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading(); currentMesh->highPriority = ph.HighPriority(); if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) { @@ -1119,29 +1122,29 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data) // copy face attributes - if ((ph.header[1] & 2) == 0) { + if (!ph.PolyColor()) { int colorIdx = ph.ColorIndex(); - p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f; - p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f; - p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f; + p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF); + p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF); + p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF); } else { - p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f; - p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f; - p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f; + p.faceColour[0] = ((ph.header[4] >> 24)); + p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF); + p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF); if (ph.TranslatorMap()) { - p.faceColour[0] *= 15.9375f; // not using 16, as 16x16=256 not 255 and that would overflow (potentially) - p.faceColour[1] *= 15.9375f; - p.faceColour[2] *= 15.9375f; + p.faceColour[0] = (p.faceColour[0] * 255) / 16; // When the translator map is enabled, max colour seems + p.faceColour[1] = (p.faceColour[1] * 255) / 16; // to be 16. Scaling these up gives the correct colours. + p.faceColour[2] = (p.faceColour[2] * 255) / 16; // Not sure why didn't allow 32 colours with 4 bits? } } - p.faceColour[3] = ph.Transparency() / 255.f; + p.faceColour[3] = ph.Transparency(); if (ph.Discard1() && !ph.Discard2()) { - p.faceColour[3] *= 0.5f; + p.faceColour[3] /= 2; } // if we have flat shading, we can't re-use normals from shared vertices @@ -1176,42 +1179,32 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data) if (ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading()) { // fixed shading seems to be disabled if actual normals are set - //=========== - float shade; - float offset; // if lighting is disabled colour seems to be an offset - //=========== - - offset = !ph.LightEnabled() ? 1.f : 0.f; + //========== + UINT8 shade; + //========== if (m_step <= 0x15) { - - shade = ((ix & 0x7F) / 127.f); // this matches the sdk (values are from 0-127 only) and the intensity is clamped to to 0-1 - - if (m_vpAmbient > 0) { - shade = (shade + 1) / 2; // Viewport ambient seems to effect fixed shading. Technically vp ambient can change dynamically, but not an issue in practise. If it was we would need this logic in shader - } + shade = ((ix & 0x7F) * 255) / 127; // this matches the sdk (values are from 0-127 only) and the intensity is clamped to to 0-1 } else { if (ph.SpecularEnabled()) { - shade = (ix & 0xFF) / 255.f; // Star wars is the only game to use unsigned fixed shaded values. It's also the only game to set the specular flag on these polys + shade = ix & 0xFF; // Star wars is the only game to use unsigned fixed shaded values. It's also the only game to set the specular flag on these polys } else { - shade = (((ix + 128) & 0xFF) / 255.f); // Step 2+ uses signed or unsigned values for lighting 0-255. Todo finish this logic + shade = (ix + 128) & 0xFF; // Step 2+ uses signed or unsigned values for lighting 0-255. Todo finish this logic } } - shade += offset; - - p.v[j].color[0] = shade; // hardware doesn't really have per vertex colours, only per poly - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - p.v[j].color[3] = 1; + p.v[j].fixedShade[0] = shade; // hardware doesn't really have per vertex colours, only per poly + p.v[j].fixedShade[1] = shade; + p.v[j].fixedShade[2] = shade; + p.v[j].fixedShade[3] = 255; } else { - p.v[j].color[0] = 1; - p.v[j].color[1] = 1; - p.v[j].color[2] = 1; - p.v[j].color[3] = 1; + p.v[j].fixedShade[0] = 255; + p.v[j].fixedShade[1] = 255; + p.v[j].fixedShade[2] = 255; + p.v[j].fixedShade[3] = 255; } float texU, texV = 0; diff --git a/Src/Graphics/New3D/New3D.h b/Src/Graphics/New3D/New3D.h index 67e35d4..81983d0 100644 --- a/Src/Graphics/New3D/New3D.h +++ b/Src/Graphics/New3D/New3D.h @@ -216,7 +216,6 @@ private: TextureSheet m_texSheet; NodeAttributes m_nodeAttribs; Mat4 m_modelMat; // current modelview matrix - float m_vpAmbient; // cached value std::vector m_nodes; // this represents the entire render frame std::vector m_polyBufferRam; // dynamic polys diff --git a/Src/Graphics/New3D/PolyHeader.cpp b/Src/Graphics/New3D/PolyHeader.cpp index 6249059..a2dd088 100644 --- a/Src/Graphics/New3D/PolyHeader.cpp +++ b/Src/Graphics/New3D/PolyHeader.cpp @@ -344,7 +344,7 @@ UINT8 PolyHeader::Transparency() return 255; // without this check we get overflow. In the SDK, values are explicitly clamped to 0-32. } - return (UINT8)((((header[6] >> 18) & 0x3F) * 255) / 32.f); + return (((header[6] >> 18) & 0x3F) * 255) / 32; } bool PolyHeader::PolyAlpha() diff --git a/Src/Graphics/New3D/R3DShader.cpp b/Src/Graphics/New3D/R3DShader.cpp index fce4fbe..0137104 100644 --- a/Src/Graphics/New3D/R3DShader.cpp +++ b/Src/Graphics/New3D/R3DShader.cpp @@ -12,12 +12,17 @@ uniform float fogIntensity; uniform float fogDensity; uniform float fogStart; uniform float modelScale; +uniform int hardwareStep; +uniform vec3 lighting[2]; // also used in fragment shader +uniform bool lightEnabled; // also used in fragment shader +uniform bool fixedShading; // also used in fragment shader // attributes attribute vec3 inVertex; attribute vec3 inNormal; attribute vec2 inTexCoord; -attribute vec4 inColour; +attribute vec4 inColour; +attribute vec4 inFixedShade; // outputs to fragment shader varying float fsFogFactor; @@ -26,6 +31,27 @@ varying vec3 fsViewNormal; // per vertex normal vector varying vec2 fsTexCoord; varying vec4 fsColor; +vec4 GetVertexColour() +{ + vec4 polyColour = inColour; + + if(fixedShading) { + if(hardwareStep==0x15) { + if(!lightEnabled) { + polyColour += inFixedShade; // + vp ambient?? + } + else { + polyColour *= (inFixedShade + lighting[1].y); // fixed shade value + viewport ambient + } + } + else { + polyColour *= inFixedShade; //todo work out what ambient does. Probably a min clamp or 1-min clamp for signed values + } + } + + return polyColour; +} + void main(void) { fsViewVertex = vec3(gl_ModelViewMatrix * vec4(inVertex,1.0)); @@ -33,7 +59,7 @@ void main(void) float z = length(fsViewVertex); fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0); - fsColor = inColour; + fsColor = GetVertexColour(); fsTexCoord = inTexCoord; gl_Position = gl_ModelViewProjectionMatrix * vec4(inVertex,1.0); } @@ -70,6 +96,7 @@ uniform float specularValue; // specular coefficient uniform float shininess; // specular shininess uniform float fogAttenuation; uniform float fogAmbient; +uniform bool fixedShading; //interpolated inputs from vertex shader varying float fsFogFactor; @@ -132,7 +159,7 @@ void main() ellipse = 1.0 - ellipse; // invert ellipse = max(0.0, ellipse); // clamp - if (lightEnabled) { + if (lightEnabled && !fixedShading) { 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) @@ -242,6 +269,7 @@ void R3DShader::Start() m_specularEnabled = false; m_layered = false; m_textureInverted = false; + m_fixedShading = false; m_modelScale = 1.0f; m_shininess = 0; m_specularValue = 0; @@ -302,12 +330,15 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader) m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess"); m_locSpecularValue = glGetUniformLocation(m_shaderProgram, "specularValue"); m_locSpecularEnabled= glGetUniformLocation(m_shaderProgram, "specularEnabled"); + m_locFixedShading = glGetUniformLocation(m_shaderProgram, "fixedShading"); 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_locHardwareStep = glGetUniformLocation(m_shaderProgram, "hardwareStep"); return success; } @@ -400,6 +431,11 @@ void R3DShader::SetMeshUniforms(const Mesh* m) m_specularValue = m->specularValue; } + if (m_dirtyMesh || m->fixedShading != m_fixedShading) { + glUniform1i(m_locFixedShading, m->fixedShading); + m_fixedShading = m->fixedShading; + } + if (m_dirtyMesh || m->layered != m_layered) { m_layered = m->layered; if (m_layered) { @@ -445,6 +481,8 @@ void R3DShader::SetViewportUniforms(const Viewport *vp) glUniform2fv(m_locSpotRange, 1, vp->spotRange); glUniform3fv(m_locSpotColor, 1, vp->spotColor); glUniform3fv(m_locSpotFogColor, 1, vp->spotFogColor); + + glUniform1i (m_locHardwareStep, vp->hardwareStep); } void R3DShader::SetModelStates(const Model* model) diff --git a/Src/Graphics/New3D/R3DShader.h b/Src/Graphics/New3D/R3DShader.h index 0202b62..ee6006c 100644 --- a/Src/Graphics/New3D/R3DShader.h +++ b/Src/Graphics/New3D/R3DShader.h @@ -52,6 +52,7 @@ private: float m_shininess; float m_specularValue; bool m_specularEnabled; + bool m_fixedShading; bool m_layered; float m_microTexScale; @@ -83,6 +84,7 @@ private: GLint m_locShininess; GLint m_locSpecularValue; GLint m_locSpecularEnabled; + GLint m_locFixedShading; GLint m_locSpotEllipse; GLint m_locSpotRange; @@ -91,6 +93,9 @@ private: // model uniforms GLint m_locModelScale; + + // global uniforms + GLint m_locHardwareStep; }; } // New3D