mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 22:05:38 +00:00
Fixed shading (per vertex poly colours) on step 1.5 hardware have the viewport ambient value added to them. This fixes various shading on scud. To do this had to switch the maths to the vertex shader.
This commit is contained in:
parent
8f622714a7
commit
c12e4c3215
|
@ -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 };
|
||||
|
|
|
@ -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("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)
|
||||
|
@ -781,8 +784,7 @@ void CNew3D::RenderViewport(UINT32 addr)
|
|||
|
||||
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->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<Poly>& 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<Poly>& 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;
|
||||
|
|
|
@ -216,7 +216,6 @@ private:
|
|||
TextureSheet m_texSheet;
|
||||
NodeAttributes m_nodeAttribs;
|
||||
Mat4 m_modelMat; // current modelview matrix
|
||||
float m_vpAmbient; // cached value
|
||||
|
||||
std::vector<Node> m_nodes; // this represents the entire render frame
|
||||
std::vector<Poly> m_polyBufferRam; // dynamic polys
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 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,6 +330,7 @@ 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");
|
||||
|
@ -309,6 +338,8 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
|
|||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue