Merge pull request #159 from gm-matthew/textureNP

Implementing texture NP values
This commit is contained in:
dukeeeey 2024-07-05 17:21:14 +01:00 committed by GitHub
commit ee5d6523c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 79 additions and 59 deletions

View file

@ -52,6 +52,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
UINT8 faceColour[4]; // per face colour
float textureNP;
int number = 4;
};
@ -59,6 +60,7 @@ struct FVertex : Vertex // full vertex including face attributes
{
float faceNormal[3];
UINT8 faceColour[4];
float textureNP;
FVertex& operator=(const Vertex& vertex)
{
@ -71,6 +73,7 @@ struct FVertex : Vertex // full vertex including 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]; }
textureNP = r3dPoly.textureNP;
*this = r3dPoly.v[index];
}
@ -82,6 +85,7 @@ struct FVertex : Vertex // full vertex including face attributes
// 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]; }
textureNP = r3dPoly.textureNP;
}
static void Average(const FVertex& p1, const FVertex& p2, FVertex& p3)
@ -142,7 +146,7 @@ struct Mesh
// microtexture
bool microTexture = false;
int microTextureID = 0;
float microTextureScale = 0;
float microTextureMinLOD = 0;
// attributes
bool textured = false;

View file

@ -55,6 +55,7 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) :
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inColour"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inFaceNormal"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inFixedShade"));
glEnableVertexAttribArray(m_r3dShader.GetVertexAttribPos("inTextureNP"));
// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 4, GL_FLOAT, GL_FALSE, sizeof(FVertex), 0);
@ -63,6 +64,7 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) :
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FVertex), (void*)offsetof(FVertex, faceColour));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFaceNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, faceNormal));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFixedShade"), 1, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, fixedShade));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inTextureNP"), 1, GL_FLOAT, GL_FALSE, sizeof(FVertex), (void*)offsetof(FVertex, textureNP));
glBindVertexArray(0);
m_vbo.Bind(false);
@ -102,10 +104,12 @@ void CNew3D::SetStepping(int stepping)
if (m_step > 0x10) {
m_offset = 0; // culling nodes are 10 words
m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format
m_textureNPFactor = (1.0f / 16384.0f); // texture NP values are in 10.14 format
}
else {
m_offset = 2; // 8 words
m_vertexFactor = (1.0f / 128.0f); // 17.7
m_textureNPFactor = (1.0f / 4096.0f); // 12.12
}
}
@ -1287,10 +1291,8 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
if (currentMesh->microTexture) {
static const float microTexScale[] = { 2.f, 4.f, 16.f, 256.f };
currentMesh->microTextureID = ph.MicroTextureID();
currentMesh->microTextureScale = microTexScale[ph.MicroTextureMinLOD()];
currentMesh->microTextureMinLOD = (float)ph.MicroTextureMinLOD();
}
}
}
@ -1396,6 +1398,8 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
p.v[i].normal[2] = p.faceNormal[2];
}
p.textureNP = ph.TextureNP() * m_textureNPFactor;
UINT32* vData = ph.StartOfData(); // vertex data starts here
// remaining vertices are new and defined here

View file

@ -244,6 +244,7 @@ private:
int m_step;
int m_offset; // offset to subtract for words 3 and higher of culling nodes
float m_vertexFactor; // fixed-point conversion factor for vertices
float m_textureNPFactor; // fixed-point conversion factor for texture NP values
// Memory (passed from outside)
const UINT32 *m_cullingRAMLo; // 4 MB

View file

@ -306,6 +306,11 @@ int PolyHeader::Y()
return y;
}
float PolyHeader::TextureNP()
{
return (float)(header[5] >> 8);
}
//
// header 6
//

View file

@ -55,7 +55,7 @@ xxxxxxxx xxxxxxxx xxxxxxxx -------- Color (RGB888 or two 12-bit indexes, sensor
-------- -------- -------- ---xxxxx Upper 5 bits of texture U coordinate
0x05 :
xxxxxxxx xxxxxxxx xxxxxxxx -------- Texture NP ?
xxxxxxxx xxxxxxxx xxxxxxxx -------- Texture NP
-------- -------- -------- x------- Low bit of texture U coordinate
-------- -------- -------- ---xxxxx Low 5 bits of texture V coordinate
@ -115,7 +115,7 @@ public:
bool TexVMirror();
bool MicroTexture();
int MicroTextureID();
int MicroTextureMinLOD(); // basically how many times it repeats compared to the base texture (i assume)
int MicroTextureMinLOD();
// header 3
int TexWidth();
@ -133,6 +133,7 @@ public:
// header 5
int X();
int Y();
float TextureNP();
//header 6
bool Layered();

View file

@ -36,7 +36,7 @@ void R3DShader::Start()
m_nodeAlpha = 1.0f;
m_shininess = 0;
m_specularValue = 0;
m_microTexScale = 0;
m_microTexMinLOD = 0;
m_microTexID = -1;
m_texturePage = -1;
@ -108,7 +108,7 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
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_locMicroTexMinLOD = glGetUniformLocation(m_shaderProgram, "microTextureMinLOD");
m_locMicroTexID = glGetUniformLocation(m_shaderProgram, "microTextureID");
m_locBaseTexInfo = glGetUniformLocation(m_shaderProgram, "baseTexInfo");
m_locBaseTexType = glGetUniformLocation(m_shaderProgram, "baseTexType");
@ -224,9 +224,9 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
m_texturePage = (m->page ^ m_transPage);
}
if (m_dirtyMesh || m->microTextureScale != m_microTexScale) {
glUniform1f(m_locMicroTexScale, m->microTextureScale);
m_microTexScale = m->microTextureScale;
if (m_dirtyMesh || m->microTextureMinLOD != m_microTexMinLOD) {
glUniform1f(m_locMicroTexMinLOD, m->microTextureMinLOD);
m_microTexMinLOD = m->microTextureMinLOD;
}
if (m_dirtyMesh || m->microTextureID != m_microTexID) {

View file

@ -46,7 +46,7 @@ private:
GLint m_locTexturePage;
GLint m_locTextureAlpha;
GLint m_locAlphaTest;
GLint m_locMicroTexScale;
GLint m_locMicroTexMinLOD;
GLint m_locMicroTexID;
GLint m_locBaseTexInfo;
GLint m_locBaseTexType;
@ -73,7 +73,7 @@ private:
bool m_layered;
bool m_noLosReturn;
float m_microTexScale;
float m_microTexMinLOD;
int m_microTexID;
int m_baseTexInfo[4];
int m_baseTexType;

View file

@ -119,13 +119,13 @@ ivec2 GetMicroTexturePos(int id)
return ivec2(xCoords[id],yCoords[id]);
}
float mip_map_level(in vec2 texture_coordinate) // in texel units
float mip_map_level(in vec3 coordinate)
{
vec2 dx_vtc = dFdx(texture_coordinate);
vec2 dy_vtc = dFdy(texture_coordinate);
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
float mml = 0.5 * log2(delta_max_sqr);
return max( 0.0, mml );
// Real3D uses vertex coordinates rather than texel coordinates to calculate mipmap levels
vec3 dx_vtc = dFdx(coordinate);
vec3 dy_vtc = dFdy(coordinate);
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
return log2(delta_max_sqr / (fsTextureNP * fsTextureNP)) * 0.5; // result not clamped
}
float LinearTexLocations(int wrapMode, float size, float u, out float u0, out float u1)
@ -207,59 +207,51 @@ vec4 texBiLinear(usampler2D texSampler, ivec2 wrapMode, vec2 texSize, ivec2 texP
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
}
vec4 textureR3D(usampler2D texSampler, ivec2 wrapMode, ivec2 texSize, ivec2 texPos, vec2 texCoord)
vec4 GetTextureValue()
{
float numLevels = floor(log2(min(float(texSize.x), float(texSize.y)))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension
float fLevel = min(mip_map_level(texCoord * vec2(texSize)), numLevels);
if(alphaTest) fLevel *= 0.5;
else fLevel *= 0.8;
float lod = mip_map_level(fsViewVertex);
float numLevels = floor(log2(min(float(baseTexInfo.z), float(baseTexInfo.w)))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension
float fLevel = clamp(lod, 0.0, numLevels);
int iLevel = int(fLevel);
ivec2 texPos0 = GetTexturePosition(iLevel,texPos);
ivec2 texSize0 = GetTextureSize(iLevel, texSize);
ivec2 tex1Pos = GetTexturePosition(iLevel, ivec2(baseTexInfo.xy));
ivec2 tex1Size = GetTextureSize(iLevel, ivec2(baseTexInfo.zw));
vec4 tex1Data = texBiLinear(textureBank[texturePage], textureWrapMode, vec2(tex1Size), tex1Pos, fsTexCoord, iLevel);
if (fLevel > 0)
// init second texel with blank data to avoid any potentially undefined behavior
vec4 tex2Data = vec4(0.0);
float blendFactor = 0.0;
// if LOD < 0, no need to blend with next mipmap level; slight performance boost
if (lod > 0.0)
{
ivec2 texPos1 = GetTexturePosition(iLevel+1,texPos);
ivec2 texSize1 = GetTextureSize(iLevel+1, texSize);
ivec2 tex2Pos = GetTexturePosition(iLevel+1, ivec2(baseTexInfo.xy));
ivec2 tex2Size = GetTextureSize(iLevel+1, ivec2(baseTexInfo.zw));
tex2Data = texBiLinear(textureBank[texturePage], textureWrapMode, vec2(tex2Size), tex2Pos, fsTexCoord, iLevel+1);
vec4 texLevel0 = texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord, iLevel);
vec4 texLevel1 = texBiLinear(texSampler, wrapMode, vec2(texSize1), texPos1, texCoord, iLevel+1);
return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels
blendFactor = fract(fLevel);
}
else
else if (microTexture && lod < -microTextureMinLOD)
{
// if fLevel is 0, no need to mix with next mipmap level; slight performance boost
return texBiLinear(texSampler, wrapMode, vec2(texSize0), texPos0, texCoord, iLevel);
}
}
vec4 scaleIndex = vec4(2.0, 4.0, 16.0, 256.0); // unsure if minLOD=4 has 256x scale? No games appear to use it
vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * scaleIndex[int(microTextureMinLOD)];
vec4 GetTextureValue()
{
vec4 tex1Data = textureR3D(textureBank[texturePage], textureWrapMode, ivec2(baseTexInfo.zw), ivec2(baseTexInfo.xy), fsTexCoord);
// microtextures are always 128x128 and only use LOD 0 mipmap
ivec2 tex2Pos = GetMicroTexturePos(microTextureID);
tex2Data = texBiLinear(textureBank[(texturePage+1)&1], ivec2(0), ivec2(128), tex2Pos, fsTexCoord * scale, 0);
blendFactor = -(lod + microTextureMinLOD) * 0.25;
blendFactor = clamp(blendFactor, 0.0, 0.5);
}
tex1Data = mix(tex1Data, tex2Data, blendFactor);
if(textureInverted) {
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
}
if (microTexture) {
vec2 scale = (vec2(baseTexInfo.zw) / 128.0) * microTextureScale;
ivec2 pos = GetMicroTexturePos(microTextureID);
vec4 tex2Data = textureR3D(textureBank[(texturePage+1)&1], ivec2(0), ivec2(128), pos, fsTexCoord * scale);
float lod = mip_map_level(fsTexCoord * scale * vec2(128.0));
float blendFactor = max(lod - 1.5, 0.0); // bias -1.5
blendFactor = min(blendFactor, 1.0); // clamp to max value 1
blendFactor = (blendFactor + 1.0) / 2.0; // 0.5 - 1 range
tex1Data = mix(tex2Data, tex1Data, blendFactor);
}
if (alphaTest) {
if (tex1Data.a < (32.0/255.0)) {
discard;

View file

@ -19,6 +19,7 @@ in vec2 inTexCoord;
in vec3 inFaceNormal; // used to emulate r3d culling
in float inFixedShade;
in vec4 inColour;
in float inTextureNP;
// outputs to geometry shader
@ -29,6 +30,7 @@ out VS_OUT
vec2 texCoord;
vec4 color;
float fixedShade;
float textureNP;
float discardPoly; // can't have varying bool (glsl spec)
} vs_out;
@ -62,6 +64,7 @@ void main(void)
vs_out.color = GetColour(inColour);
vs_out.texCoord = inTexCoord;
vs_out.fixedShade = inFixedShade;
vs_out.textureNP = inTextureNP * modelScale;
gl_Position = projMat * modelMat * inVertex;
}
)glsl";
@ -80,6 +83,7 @@ in VS_OUT
vec2 texCoord;
vec4 color;
float fixedShade;
float textureNP;
float discardPoly; // can't have varying bool (glsl spec)
} gs_in[4];
@ -95,6 +99,7 @@ out GS_OUT
flat vec2 texCoord[4];
flat vec4 color;
flat float fixedShade[4];
flat float textureNP;
} gs_out;
//a*b - c*d, computed in a stable fashion (Kahan)
@ -128,6 +133,7 @@ void main(void)
// flat attributes
gs_out.color = gs_in[0].color;
gs_out.textureNP = gs_in[0].textureNP;
// precompute crossproducts for all vertex combinations to be looked up in loop below for area computation
precise float cross[4][4];
@ -180,7 +186,7 @@ uniform usampler2D textureBank[2]; // entire texture sheet
// texturing
uniform bool textureEnabled;
uniform bool microTexture;
uniform float microTextureScale;
uniform float microTextureMinLOD;
uniform int microTextureID;
uniform ivec4 baseTexInfo; // x/y are x,y positions in the texture sheet. z/w are with and height
uniform int baseTexType;
@ -231,6 +237,7 @@ in GS_OUT
flat vec2 texCoord[4];
flat vec4 color;
flat float fixedShade[4];
flat float textureNP;
} fs_in;
//our calculated vertex attributes from the above
@ -239,6 +246,7 @@ vec3 fsViewNormal;
vec2 fsTexCoord;
float fsFixedShade;
vec4 fsColor;
float fsTextureNP;
//outputs
layout(location = 0) out vec4 out0; // opaque
@ -323,6 +331,7 @@ void QuadraticInterpolation()
fsTexCoord = vec2(0.0);
fsFixedShade = 0.0;
fsColor = fs_in.color;
fsTextureNP = fs_in.textureNP;
for (int i=0; i<4; i++) {
fsViewVertex += lambda[i] * fs_in.viewVertex[i];

View file

@ -19,6 +19,7 @@ in vec2 inTexCoord;
in vec4 inColour;
in vec3 inFaceNormal; // used to emulate r3d culling
in float inFixedShade;
in float inTextureNP;
// outputs to fragment shader
out vec3 fsViewVertex;
@ -27,6 +28,7 @@ out vec2 fsTexCoord;
out vec4 fsColor;
out float fsDiscard; // can't have varying bool (glsl spec)
out float fsFixedShade;
out float fsTextureNP;
vec4 GetColour(vec4 colour)
{
@ -58,6 +60,7 @@ void main(void)
fsColor = GetColour(inColour);
fsTexCoord = inTexCoord;
fsFixedShade = inFixedShade;
fsTextureNP = inTextureNP * modelScale;
gl_Position = projMat * modelMat * inVertex;
}
)glsl";
@ -71,7 +74,7 @@ uniform usampler2D textureBank[2]; // entire texture sheet
// texturing
uniform bool textureEnabled;
uniform bool microTexture;
uniform float microTextureScale;
uniform float microTextureMinLOD;
uniform int microTextureID;
uniform ivec4 baseTexInfo; // x/y are x,y positions in the texture sheet. z/w are with and height
uniform int baseTexType;
@ -115,6 +118,7 @@ in vec4 fsColor;
in vec2 fsTexCoord;
in float fsDiscard;
in float fsFixedShade;
in float fsTextureNP;
//outputs
layout(location = 0) out vec4 out0; // opaque