mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-02-16 17:35:39 +00:00
Correctly emulate the real3d pro-1000 texture modes in our shader.
This commit is contained in:
parent
a5ad1c4099
commit
3eeec35e7c
|
@ -129,10 +129,12 @@ struct Mesh
|
|||
return true;
|
||||
}
|
||||
|
||||
enum TexWrapMode : int { repeat = 0, repeatClamp, mirror, mirrorClamp };
|
||||
|
||||
// texture
|
||||
int format, x, y, width, height = 0;
|
||||
bool mirrorU = false;
|
||||
bool mirrorV = false;
|
||||
TexWrapMode wrapModeU;
|
||||
TexWrapMode wrapModeV;
|
||||
bool inverted = false;
|
||||
|
||||
// microtexture
|
||||
|
@ -145,7 +147,6 @@ struct Mesh
|
|||
bool polyAlpha = false; // specified in the rgba colour
|
||||
bool textureAlpha = false; // use alpha in texture
|
||||
bool alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function)
|
||||
bool clockWise = true; // we need to check if the matrix will change the winding
|
||||
bool layered = false; // stencil poly
|
||||
bool highPriority = false; // rendered over the top
|
||||
bool transLSelect = false; // actually the transparency layer, false = layer 0, true = layer 1
|
||||
|
|
|
@ -198,13 +198,12 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
|
|||
CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y);
|
||||
|
||||
if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) {
|
||||
tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
|
||||
// texture already bound
|
||||
}
|
||||
else {
|
||||
tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height);
|
||||
tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, x, y, mesh.width, mesh.height);
|
||||
if (tex1) {
|
||||
tex1->BindTexture();
|
||||
tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +212,7 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
|
|||
int mX, mY;
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY);
|
||||
auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128);
|
||||
auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, mX, mY, 128, 128);
|
||||
if (tex2) {
|
||||
tex2->BindTexture();
|
||||
}
|
||||
|
@ -371,6 +370,7 @@ void CNew3D::RenderFrame(void)
|
|||
}
|
||||
|
||||
m_r3dFrameBuffers.DisableFBO(); // draw to back buffer normally
|
||||
|
||||
}
|
||||
|
||||
void CNew3D::BeginFrame(void)
|
||||
|
@ -974,53 +974,6 @@ void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertex
|
|||
}
|
||||
}
|
||||
|
||||
// non smooth texturing on the pro-1000 seems to sample like gl_nearest
|
||||
// ie not outside of the texture coordinates, but with bilinear filtering
|
||||
// this is about as close as we can emulate in hardware
|
||||
// if we don't do this with gl_repeat enabled, it will wrap around and sample the
|
||||
// other side of the texture which produces ugly seems
|
||||
void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2])
|
||||
{
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
float min = std::numeric_limits<float>::max();
|
||||
float max = -std::numeric_limits<float>::max();
|
||||
|
||||
if (!offset[i]) continue;
|
||||
|
||||
for (int j = 0; j < r3dPoly.number; j++) {
|
||||
min = std::min(r3dPoly.v[j].texcoords[i], min);
|
||||
max = std::max(r3dPoly.v[j].texcoords[i], max);
|
||||
}
|
||||
|
||||
float fTemp;
|
||||
float iTemp;
|
||||
bool fractMin;
|
||||
bool fractMax;
|
||||
|
||||
fTemp = std::modf(min, &iTemp);
|
||||
fractMin = fTemp > 0;
|
||||
|
||||
fTemp = std::modf(max, &iTemp);
|
||||
fractMax = fTemp > 0;
|
||||
|
||||
for (int j = 0; j < r3dPoly.number && min != max; j++) {
|
||||
|
||||
if (!fractMin) {
|
||||
if (r3dPoly.v[j].texcoords[i] == min) {
|
||||
r3dPoly.v[j].texcoords[i] += offset[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!fractMax) {
|
||||
if (r3dPoly.v[j].texcoords[i] == max) {
|
||||
r3dPoly.v[j].texcoords[i] -= offset[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
|
||||
{
|
||||
//copy attributes
|
||||
|
@ -1050,11 +1003,32 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
|
|||
currentMesh->y = ph.Y();
|
||||
currentMesh->width = ph.TexWidth();
|
||||
currentMesh->height = ph.TexHeight();
|
||||
currentMesh->mirrorU = ph.TexUMirror();
|
||||
currentMesh->mirrorV = ph.TexVMirror();
|
||||
currentMesh->microTexture = ph.MicroTexture();
|
||||
currentMesh->inverted = ph.TranslatorMapOffset() == 2;
|
||||
|
||||
{
|
||||
bool smoothU = ph.TexSmoothU();
|
||||
bool smoothV = ph.TexSmoothU();
|
||||
|
||||
if (ph.TexUMirror()) {
|
||||
if (smoothU) currentMesh->wrapModeU = Mesh::TexWrapMode::mirror;
|
||||
else currentMesh->wrapModeU = Mesh::TexWrapMode::mirrorClamp;
|
||||
}
|
||||
else {
|
||||
if (smoothU) currentMesh->wrapModeU = Mesh::TexWrapMode::repeat;
|
||||
else currentMesh->wrapModeU = Mesh::TexWrapMode::repeatClamp;
|
||||
}
|
||||
|
||||
if (ph.TexVMirror()) {
|
||||
if (smoothV) currentMesh->wrapModeV = Mesh::TexWrapMode::mirror;
|
||||
else currentMesh->wrapModeV = Mesh::TexWrapMode::mirrorClamp;
|
||||
}
|
||||
else {
|
||||
if (smoothV) currentMesh->wrapModeV = Mesh::TexWrapMode::repeat;
|
||||
else currentMesh->wrapModeV = Mesh::TexWrapMode::repeatClamp;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMesh->microTexture) {
|
||||
|
||||
float microTexScale[] = { 2, 4, 16, 256 };
|
||||
|
@ -1235,22 +1209,6 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
|||
vData += 4;
|
||||
}
|
||||
|
||||
// check if we need to modify the texture coordinates
|
||||
if (ph.TexEnabled()) {
|
||||
|
||||
float offset[2] = { 0 };
|
||||
|
||||
if (!ph.TexSmoothU() && !ph.TexUMirror()) {
|
||||
offset[0] = 0.5f / ph.TexWidth(); // half texel
|
||||
}
|
||||
|
||||
if (!ph.TexSmoothV() && !ph.TexVMirror()) {
|
||||
offset[1] = 0.5f / ph.TexHeight(); // half texel
|
||||
}
|
||||
|
||||
OffsetTexCoords(p, offset);
|
||||
}
|
||||
|
||||
// check if we need to double up vertices for two sided lighting
|
||||
if (ph.DoubleSided() && !ph.Discard()) {
|
||||
|
||||
|
|
|
@ -199,7 +199,6 @@ private:
|
|||
void SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph);
|
||||
void CacheModel(Model *m, const UINT32 *data);
|
||||
void CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertexArray);
|
||||
void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
|
||||
|
||||
bool RenderScene(int priority, bool renderOverlay, Layer layer); // returns if has overlay plane
|
||||
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
|
||||
|
|
|
@ -37,6 +37,9 @@ void R3DShader::Start()
|
|||
m_baseTexSize[0] = 0;
|
||||
m_baseTexSize[1] = 0;
|
||||
|
||||
m_texWrapMode[0] = 0;
|
||||
m_texWrapMode[1] = 0;
|
||||
|
||||
m_dirtyMesh = true; // dirty means all the above are dirty, ie first run
|
||||
m_dirtyModel = true;
|
||||
}
|
||||
|
@ -91,6 +94,7 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
|
|||
m_locMicroTexScale = glGetUniformLocation(m_shaderProgram, "microTextureScale");
|
||||
m_locBaseTexSize = glGetUniformLocation(m_shaderProgram, "baseTexSize");
|
||||
m_locTextureInverted = glGetUniformLocation(m_shaderProgram, "textureInverted");
|
||||
m_locTexWrapMode = glGetUniformLocation(m_shaderProgram, "textureWrapMode");
|
||||
|
||||
m_locFogIntensity = glGetUniformLocation(m_shaderProgram, "fogIntensity");
|
||||
m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity");
|
||||
|
@ -166,7 +170,7 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
|
|||
m_microTexScale = m->microTextureScale;
|
||||
}
|
||||
|
||||
if (m_dirtyMesh || m->microTexture && (m_baseTexSize[0] != m->width || m_baseTexSize[1] != m->height)) {
|
||||
if (m_dirtyMesh || (m_baseTexSize[0] != m->width || m_baseTexSize[1] != m->height)) {
|
||||
m_baseTexSize[0] = (float)m->width;
|
||||
m_baseTexSize[1] = (float)m->height;
|
||||
glUniform2fv(m_locBaseTexSize, 1, m_baseTexSize);
|
||||
|
@ -217,6 +221,12 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
|
|||
m_fixedShading = m->fixedShading;
|
||||
}
|
||||
|
||||
if (m_dirtyMesh || m->wrapModeU != m_texWrapMode[0] || m->wrapModeV != m_texWrapMode[1]) {
|
||||
m_texWrapMode[0] = m->wrapModeU;
|
||||
m_texWrapMode[1] = m->wrapModeV;
|
||||
glUniform2iv(m_locTexWrapMode, 1, m_texWrapMode);
|
||||
}
|
||||
|
||||
if (m_dirtyMesh || m->layered != m_layered) {
|
||||
m_layered = m->layered;
|
||||
if (m_layered) {
|
||||
|
|
|
@ -45,6 +45,7 @@ private:
|
|||
GLint m_locMicroTexScale;
|
||||
GLint m_locBaseTexSize;
|
||||
GLint m_locTextureInverted;
|
||||
GLint m_locTexWrapMode;
|
||||
|
||||
// cached mesh values
|
||||
bool m_textured1;
|
||||
|
@ -61,6 +62,7 @@ private:
|
|||
bool m_layered;
|
||||
float m_microTexScale;
|
||||
float m_baseTexSize[2];
|
||||
int m_texWrapMode[2];
|
||||
bool m_textureInverted;
|
||||
|
||||
// cached model values
|
||||
|
|
|
@ -157,6 +157,7 @@ uniform bool textureInverted;
|
|||
uniform bool textureAlpha;
|
||||
uniform bool alphaTest;
|
||||
uniform bool discardAlpha;
|
||||
uniform ivec2 textureWrapMode;
|
||||
|
||||
// general
|
||||
uniform vec3 fogColour;
|
||||
|
@ -321,9 +322,116 @@ void QuadraticInterpolation()
|
|||
gl_FragDepth = depth;
|
||||
}
|
||||
|
||||
float mip_map_level(in vec2 texture_coordinate) // in texel units
|
||||
{
|
||||
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, mml );
|
||||
}
|
||||
|
||||
float LinearTexLocations(int wrapMode, float size, float u, out float u0, out float u1)
|
||||
{
|
||||
float texelSize = 1.0 / size;
|
||||
float halfTexelSize = 0.5 / size;
|
||||
|
||||
if(wrapMode==0) { // repeat
|
||||
u = (u * size) - 0.5;
|
||||
u0 = (floor(u) + 0.5) / size; // + 0.5 offset added to push us into the centre of a pixel, without we'll get rounding errors
|
||||
u0 = fract(u0);
|
||||
u1 = u0 + texelSize;
|
||||
u1 = fract(u1);
|
||||
|
||||
return fract(u); // return weight
|
||||
}
|
||||
else if(wrapMode==1) { // repeat + clamp
|
||||
u = fract(u); // must force into 0-1 to start
|
||||
u = (u * size) - 0.5;
|
||||
u0 = (floor(u) + 0.5) / size; // + 0.5 offset added to push us into the centre of a pixel, without we'll get rounding errors
|
||||
u1 = u0 + texelSize;
|
||||
|
||||
if(u0 < 0.0) u0 = 0.0;
|
||||
if(u1 >= 1.0) u1 = 1.0 - halfTexelSize;
|
||||
|
||||
return fract(u); // return weight
|
||||
}
|
||||
else { // mirror + mirror clamp - both are the same since the edge pixels are repeated anyway
|
||||
|
||||
float odd = floor(mod(u, 2.0)); // odd values are mirrored
|
||||
|
||||
if(odd > 0.0) {
|
||||
u = 1.0 - fract(u);
|
||||
}
|
||||
else {
|
||||
u = fract(u);
|
||||
}
|
||||
|
||||
u = (u * size) - 0.5;
|
||||
u0 = (floor(u) + 0.5) / size; // + 0.5 offset added to push us into the centre of a pixel, without we'll get rounding errors
|
||||
u1 = u0 + texelSize;
|
||||
|
||||
if(u0 < 0.0) u0 = 0.0;
|
||||
if(u1 >= 1.0) u1 = 1.0 - halfTexelSize;
|
||||
|
||||
return fract(u); // return weight
|
||||
}
|
||||
}
|
||||
|
||||
vec4 texBiLinear(sampler2D texSampler, float level, ivec2 wrapMode, vec2 texSize, vec2 texCoord)
|
||||
{
|
||||
float tx[2], ty[2];
|
||||
float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]);
|
||||
float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]);
|
||||
|
||||
vec4 p0q0 = textureLod(texSampler, vec2(tx[0],ty[0]), level);
|
||||
vec4 p1q0 = textureLod(texSampler, vec2(tx[1],ty[0]), level);
|
||||
vec4 p0q1 = textureLod(texSampler, vec2(tx[0],ty[1]), level);
|
||||
vec4 p1q1 = textureLod(texSampler, vec2(tx[1],ty[1]), level);
|
||||
|
||||
if(alphaTest) {
|
||||
if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; }
|
||||
if(p0q0.a > p0q1.a) { p0q1.rgb = p0q0.rgb; }
|
||||
|
||||
if(p1q0.a > p0q0.a) { p0q0.rgb = p1q0.rgb; }
|
||||
if(p1q0.a > p1q1.a) { p1q1.rgb = p1q0.rgb; }
|
||||
|
||||
if(p0q1.a > p0q0.a) { p0q0.rgb = p0q1.rgb; }
|
||||
if(p0q1.a > p1q1.a) { p1q1.rgb = p0q1.rgb; }
|
||||
|
||||
if(p1q1.a > p0q1.a) { p0q1.rgb = p1q1.rgb; }
|
||||
if(p1q1.a > p1q0.a) { p1q0.rgb = p1q1.rgb; }
|
||||
}
|
||||
|
||||
// Interpolation in X direction.
|
||||
vec4 pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction.
|
||||
vec4 pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction.
|
||||
|
||||
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
|
||||
}
|
||||
|
||||
vec4 textureR3D(sampler2D texSampler, ivec2 wrapMode, vec2 texSize, vec2 texCoord)
|
||||
{
|
||||
float numLevels = floor(log2(min(texSize.x, texSize.y))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension
|
||||
float fLevel = min(mip_map_level(texCoord * texSize), numLevels);
|
||||
|
||||
if(alphaTest) fLevel *= 0.5;
|
||||
else fLevel *= 0.8;
|
||||
|
||||
float iLevel = floor(fLevel); // value as an 'int'
|
||||
|
||||
vec2 texSize0 = texSize / pow(2, iLevel);
|
||||
vec2 texSize1 = texSize / pow(2, iLevel+1.0);
|
||||
|
||||
vec4 texLevel0 = texBiLinear(texSampler, iLevel, wrapMode, texSize0, texCoord);
|
||||
vec4 texLevel1 = texBiLinear(texSampler, iLevel+1.0, wrapMode, texSize1, texCoord);
|
||||
|
||||
return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels
|
||||
}
|
||||
|
||||
vec4 GetTextureValue()
|
||||
{
|
||||
vec4 tex1Data = texture2D( tex1, fsTexCoord.st);
|
||||
vec4 tex1Data = textureR3D(tex1, textureWrapMode, baseTexSize, fsTexCoord);
|
||||
|
||||
if(textureInverted) {
|
||||
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
|
||||
|
@ -331,12 +439,12 @@ vec4 GetTextureValue()
|
|||
|
||||
if (microTexture) {
|
||||
vec2 scale = (baseTexSize / 128.0) * microTextureScale;
|
||||
vec4 tex2Data = texture2D( tex2, fsTexCoord.st * scale);
|
||||
vec4 tex2Data = textureR3D( tex2, ivec2(0), vec2(128.0), fsTexCoord.st * scale);
|
||||
tex1Data = (tex1Data+tex2Data)/2.0;
|
||||
}
|
||||
|
||||
if (alphaTest) {
|
||||
if (tex1Data.a < (8.0/16.0)) {
|
||||
if (tex1Data.a < (32.0/255.0)) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ uniform bool textureInverted;
|
|||
uniform bool textureAlpha;
|
||||
uniform bool alphaTest;
|
||||
uniform bool discardAlpha;
|
||||
uniform ivec2 textureWrapMode;
|
||||
|
||||
// general
|
||||
uniform vec3 fogColour;
|
||||
|
@ -93,9 +94,116 @@ varying vec2 fsTexCoord;
|
|||
varying float fsDiscard;
|
||||
varying float fsFixedShade;
|
||||
|
||||
float mip_map_level(in vec2 texture_coordinate) // in texel units
|
||||
{
|
||||
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, mml );
|
||||
}
|
||||
|
||||
float LinearTexLocations(int wrapMode, float size, float u, out float u0, out float u1)
|
||||
{
|
||||
float texelSize = 1.0 / size;
|
||||
float halfTexelSize = 0.5 / size;
|
||||
|
||||
if(wrapMode==0) { // repeat
|
||||
u = (u * size) - 0.5;
|
||||
u0 = (floor(u) + 0.5) / size; // + 0.5 offset added to push us into the centre of a pixel, without we'll get rounding errors
|
||||
u0 = fract(u0);
|
||||
u1 = u0 + texelSize;
|
||||
u1 = fract(u1);
|
||||
|
||||
return fract(u); // return weight
|
||||
}
|
||||
else if(wrapMode==1) { // repeat + clamp
|
||||
u = fract(u); // must force into 0-1 to start
|
||||
u = (u * size) - 0.5;
|
||||
u0 = (floor(u) + 0.5) / size; // + 0.5 offset added to push us into the centre of a pixel, without we'll get rounding errors
|
||||
u1 = u0 + texelSize;
|
||||
|
||||
if(u0 < 0.0) u0 = 0.0;
|
||||
if(u1 >= 1.0) u1 = 1.0 - halfTexelSize;
|
||||
|
||||
return fract(u); // return weight
|
||||
}
|
||||
else { // mirror + mirror clamp - both are the same since the edge pixels are repeated anyway
|
||||
|
||||
float odd = floor(mod(u, 2.0)); // odd values are mirrored
|
||||
|
||||
if(odd > 0.0) {
|
||||
u = 1.0 - fract(u);
|
||||
}
|
||||
else {
|
||||
u = fract(u);
|
||||
}
|
||||
|
||||
u = (u * size) - 0.5;
|
||||
u0 = (floor(u) + 0.5) / size; // + 0.5 offset added to push us into the centre of a pixel, without we'll get rounding errors
|
||||
u1 = u0 + texelSize;
|
||||
|
||||
if(u0 < 0.0) u0 = 0.0;
|
||||
if(u1 >= 1.0) u1 = 1.0 - halfTexelSize;
|
||||
|
||||
return fract(u); // return weight
|
||||
}
|
||||
}
|
||||
|
||||
vec4 texBiLinear(sampler2D texSampler, float level, ivec2 wrapMode, vec2 texSize, vec2 texCoord)
|
||||
{
|
||||
float tx[2], ty[2];
|
||||
float a = LinearTexLocations(wrapMode.s, texSize.x, texCoord.x, tx[0], tx[1]);
|
||||
float b = LinearTexLocations(wrapMode.t, texSize.y, texCoord.y, ty[0], ty[1]);
|
||||
|
||||
vec4 p0q0 = texture2DLod(texSampler, vec2(tx[0],ty[0]), level);
|
||||
vec4 p1q0 = texture2DLod(texSampler, vec2(tx[1],ty[0]), level);
|
||||
vec4 p0q1 = texture2DLod(texSampler, vec2(tx[0],ty[1]), level);
|
||||
vec4 p1q1 = texture2DLod(texSampler, vec2(tx[1],ty[1]), level);
|
||||
|
||||
if(alphaTest) {
|
||||
if(p0q0.a > p1q0.a) { p1q0.rgb = p0q0.rgb; }
|
||||
if(p0q0.a > p0q1.a) { p0q1.rgb = p0q0.rgb; }
|
||||
|
||||
if(p1q0.a > p0q0.a) { p0q0.rgb = p1q0.rgb; }
|
||||
if(p1q0.a > p1q1.a) { p1q1.rgb = p1q0.rgb; }
|
||||
|
||||
if(p0q1.a > p0q0.a) { p0q0.rgb = p0q1.rgb; }
|
||||
if(p0q1.a > p1q1.a) { p1q1.rgb = p0q1.rgb; }
|
||||
|
||||
if(p1q1.a > p0q1.a) { p0q1.rgb = p1q1.rgb; }
|
||||
if(p1q1.a > p1q0.a) { p1q0.rgb = p1q1.rgb; }
|
||||
}
|
||||
|
||||
// Interpolation in X direction.
|
||||
vec4 pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction.
|
||||
vec4 pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction.
|
||||
|
||||
return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction.
|
||||
}
|
||||
|
||||
vec4 textureR3D(sampler2D texSampler, ivec2 wrapMode, vec2 texSize, vec2 texCoord)
|
||||
{
|
||||
float numLevels = floor(log2(min(texSize.x, texSize.y))); // r3d only generates down to 1:1 for square textures, otherwise its the min dimension
|
||||
float fLevel = min(mip_map_level(texCoord * texSize), numLevels);
|
||||
|
||||
if(alphaTest) fLevel *= 0.5;
|
||||
else fLevel *= 0.8;
|
||||
|
||||
float iLevel = floor(fLevel); // value as an 'int'
|
||||
|
||||
vec2 texSize0 = texSize / pow(2, iLevel);
|
||||
vec2 texSize1 = texSize / pow(2, iLevel+1.0);
|
||||
|
||||
vec4 texLevel0 = texBiLinear(texSampler, iLevel, wrapMode, texSize0, texCoord);
|
||||
vec4 texLevel1 = texBiLinear(texSampler, iLevel+1.0, wrapMode, texSize1, texCoord);
|
||||
|
||||
return mix(texLevel0, texLevel1, fract(fLevel)); // linear blend between our mipmap levels
|
||||
}
|
||||
|
||||
vec4 GetTextureValue()
|
||||
{
|
||||
vec4 tex1Data = texture2D( tex1, fsTexCoord.st);
|
||||
vec4 tex1Data = textureR3D(tex1, textureWrapMode, baseTexSize, fsTexCoord);
|
||||
|
||||
if(textureInverted) {
|
||||
tex1Data.rgb = vec3(1.0) - vec3(tex1Data.rgb);
|
||||
|
@ -103,12 +211,12 @@ vec4 GetTextureValue()
|
|||
|
||||
if (microTexture) {
|
||||
vec2 scale = (baseTexSize / 128.0) * microTextureScale;
|
||||
vec4 tex2Data = texture2D( tex2, fsTexCoord.st * scale);
|
||||
vec4 tex2Data = textureR3D( tex2, ivec2(0), vec2(128.0), fsTexCoord.st * scale);
|
||||
tex1Data = (tex1Data+tex2Data)/2.0;
|
||||
}
|
||||
|
||||
if (alphaTest) {
|
||||
if (tex1Data.a < (8.0/16.0)) {
|
||||
if (tex1Data.a < (32.0/255.0)) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ void Texture::Reset()
|
|||
m_height = 0;
|
||||
m_format = 0;
|
||||
m_textureID = 0;
|
||||
m_mirrorU = false;
|
||||
m_mirrorV = false;
|
||||
}
|
||||
|
||||
void Texture::BindTexture()
|
||||
|
@ -52,19 +50,6 @@ void Texture::GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, floa
|
|||
vOut = (vIn*uvScale) / height;
|
||||
}
|
||||
|
||||
void Texture::SetWrapMode(bool mirrorU, bool mirrorV)
|
||||
{
|
||||
if (mirrorU != m_mirrorU) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT);
|
||||
m_mirrorU = mirrorU;
|
||||
}
|
||||
|
||||
if (mirrorV != m_mirrorV) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT);
|
||||
m_mirrorV = mirrorV;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height)
|
||||
{
|
||||
int xi, yi, i;
|
||||
|
@ -290,7 +275,7 @@ void Texture::UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int
|
|||
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, subWidth, subHeight, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
|
||||
}
|
||||
|
||||
UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
|
||||
UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height)
|
||||
{
|
||||
const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
|
||||
const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
|
||||
|
@ -301,7 +286,7 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
|
|||
}
|
||||
|
||||
DeleteTexture(); // free any existing texture
|
||||
CreateTextureObject(format, mirrorU, mirrorV, x, y, width, height);
|
||||
CreateTextureObject(format, x, y, width, height);
|
||||
|
||||
int page = y / 1024;
|
||||
|
||||
|
@ -354,23 +339,15 @@ bool Texture::CheckMapPos(int ax1, int ax2, int ay1, int ay2)
|
|||
return false;
|
||||
}
|
||||
|
||||
void Texture::CreateTextureObject(int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
|
||||
void Texture::CreateTextureObject(int format, int x, int y, int width, int height)
|
||||
{
|
||||
GLfloat maxAnistrophy;
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy);
|
||||
|
||||
if (maxAnistrophy > 8) {
|
||||
maxAnistrophy = 8.0f; //anymore than 8 can get expensive for little gain
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // rgba is always 4 byte aligned
|
||||
glGenTextures(1, &m_textureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_textureID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnistrophy);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
|
||||
int minD = std::min(width, height);
|
||||
int count = 0;
|
||||
|
@ -388,8 +365,6 @@ void Texture::CreateTextureObject(int format, bool mirrorU, bool mirrorV, int x,
|
|||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_mirrorU = mirrorU;
|
||||
m_mirrorV = mirrorV;
|
||||
}
|
||||
|
||||
} // New3D
|
||||
|
|
|
@ -13,12 +13,11 @@ public:
|
|||
Texture();
|
||||
~Texture();
|
||||
|
||||
UINT32 UploadTexture (const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height);
|
||||
UINT32 UploadTexture (const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height);
|
||||
void DeleteTexture ();
|
||||
void BindTexture ();
|
||||
void GetCoordinates (UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
|
||||
void GetDetails (int& x, int&y, int& width, int& height, int& format);
|
||||
void SetWrapMode (bool mirrorU, bool mirrorV);
|
||||
bool Compare (int x, int y, int width, int height, int format);
|
||||
bool CheckMapPos (int ax1, int ax2, int ay1, int ay2); //check to see if textures overlap
|
||||
|
||||
|
@ -26,7 +25,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void CreateTextureObject(int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height);
|
||||
void CreateTextureObject(int format, int x, int y, int width, int height);
|
||||
void UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height);
|
||||
void Reset();
|
||||
|
||||
|
@ -35,8 +34,6 @@ private:
|
|||
int m_width;
|
||||
int m_height;
|
||||
int m_format;
|
||||
bool m_mirrorU;
|
||||
bool m_mirrorV;
|
||||
GLuint m_textureID;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ int TextureSheet::ToIndex(int x, int y)
|
|||
return (y * 2048) + x;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> TextureSheet::BindTexture(const UINT16* src, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
|
||||
std::shared_ptr<Texture> TextureSheet::BindTexture(const UINT16* src, int format, int x, int y, int width, int height)
|
||||
{
|
||||
//========
|
||||
int index;
|
||||
|
@ -35,7 +35,7 @@ std::shared_ptr<Texture> TextureSheet::BindTexture(const UINT16* src, int format
|
|||
|
||||
std::shared_ptr<Texture> t(new Texture());
|
||||
m_texMap.insert(std::pair<int, std::shared_ptr<Texture>>(index, t));
|
||||
t->UploadTexture(src, m_temp.data(), format, mirrorU, mirrorV, x, y, width, height);
|
||||
t->UploadTexture(src, m_temp.data(), format, x, y, width, height);
|
||||
return t;
|
||||
}
|
||||
else {
|
||||
|
@ -57,7 +57,7 @@ std::shared_ptr<Texture> TextureSheet::BindTexture(const UINT16* src, int format
|
|||
|
||||
std::shared_ptr<Texture> t(new Texture());
|
||||
m_texMap.insert(std::pair<int, std::shared_ptr<Texture>>(index, t));
|
||||
t->UploadTexture(src, m_temp.data(), format, mirrorU, mirrorV, x, y, width, height);
|
||||
t->UploadTexture(src, m_temp.data(), format, x, y, width, height);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class TextureSheet
|
|||
public:
|
||||
TextureSheet();
|
||||
|
||||
std::shared_ptr<Texture> BindTexture (const UINT16* src, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height);
|
||||
std::shared_ptr<Texture> BindTexture (const UINT16* src, int format, int x, int y, int width, int height);
|
||||
void Invalidate (int x, int y, int width, int height); // release parts of the memory
|
||||
void Release (); // release all texture objects and memory
|
||||
int GetTexFormat (int originalFormat, bool contour);
|
||||
|
|
Loading…
Reference in a new issue