mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 05:45:38 +00:00
Merge pull request #159 from gm-matthew/textureNP
Implementing texture NP values
This commit is contained in:
commit
ee5d6523c8
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -306,6 +306,11 @@ int PolyHeader::Y()
|
|||
return y;
|
||||
}
|
||||
|
||||
float PolyHeader::TextureNP()
|
||||
{
|
||||
return (float)(header[5] >> 8);
|
||||
}
|
||||
|
||||
//
|
||||
// header 6
|
||||
//
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
// 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));
|
||||
float mml = 0.5 * log2(delta_max_sqr);
|
||||
return max( 0.0, mml );
|
||||
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)];
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
vec4 GetTextureValue()
|
||||
{
|
||||
vec4 tex1Data = textureR3D(textureBank[texturePage], textureWrapMode, ivec2(baseTexInfo.zw), ivec2(baseTexInfo.xy), fsTexCoord);
|
||||
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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue