Originally to do mipmapping, I just used the base texture and then let the h/w automatically generate the mipmap chain. I wasn't sure the real3d api even exposed to the programmer the ability to directly set the mipmap data. Anyway, as pointed out by HarryTuttle scud actually uses darker mipmaps for an effect on the water. This patch uses the uses the actual mipmap data from the real3d memory. Only tested scud, so hopefully I didn't cause any cataclysmic errors :)

This commit is contained in:
Ian Curtis 2017-03-24 13:38:20 +00:00
parent df3805e741
commit 17f878421b
2 changed files with 59 additions and 34 deletions

View file

@ -65,18 +65,12 @@ void Texture::SetWrapMode(bool mirrorU, bool mirrorV)
} }
} }
UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height) void Texture::UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height)
{ {
int xi, yi, i; int xi, yi, i;
GLubyte texel; GLubyte texel;
GLubyte c, a; GLubyte c, a;
if (!src || !scratch) {
return 0; // sanity checking
}
DeleteTexture(); // free any existing texture
i = 0; i = 0;
switch (format) switch (format)
@ -100,8 +94,8 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
for (xi = x; xi < (x + width); xi++) for (xi = x; xi < (x + width); xi++)
{ {
scratch[i++] = ((src[yi * 2048 + xi] >> 10) & 0x1F) * 255 / 0x1F; // R scratch[i++] = ((src[yi * 2048 + xi] >> 10) & 0x1F) * 255 / 0x1F; // R
scratch[i++] = ((src[yi * 2048 + xi] >> 5 ) & 0x1F) * 255 / 0x1F; // G scratch[i++] = ((src[yi * 2048 + xi] >> 5) & 0x1F) * 255 / 0x1F; // G
scratch[i++] = ((src[yi * 2048 + xi] >> 0 ) & 0x1F) * 255 / 0x1F; // B scratch[i++] = ((src[yi * 2048 + xi] >> 0) & 0x1F) * 255 / 0x1F; // B
scratch[i++] = ((src[yi * 2048 + xi] & 0x8000) ? 0 : 255); // T scratch[i++] = ((src[yi * 2048 + xi] & 0x8000) ? 0 : 255); // T
} }
} }
@ -182,7 +176,7 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
scratch[i++] = texel; scratch[i++] = texel;
scratch[i++] = texel; scratch[i++] = texel;
scratch[i++] = texel; scratch[i++] = texel;
scratch[i++] = (texel==255 ? 0 : 255); scratch[i++] = (texel == 255 ? 0 : 255);
} }
} }
break; break;
@ -280,38 +274,36 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
break; break;
} }
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
}
GLfloat maxAnistrophy; UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, 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 };
const int mipDivisor[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 };
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy); if (!src || !scratch) {
return 0; // sanity checking
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 DeleteTexture(); // free any existing texture
glGenTextures(1, &m_textureID); CreateTextureObject(format, mirrorU, mirrorV, x, y, width, height);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT); //todo this in shaders? int page = y / 1024;
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_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
// assuming successful we can copy details y -= (page * 1024); // remove page from tex y
for (int i = 0; i < 6; i++) {
m_x = x; int xPos = mipXBase[i] + (x / mipDivisor[i]);
m_y = y; int yPos = mipYBase[i] + (y / mipDivisor[i]);
m_width = width;
m_height = height;
m_format = format;
m_mirrorU = mirrorU;
m_mirrorV = mirrorV;
printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height); UploadTextureMip(i, src, scratch, format, xPos, yPos + (page * 1024), width, height);
width /= 2;
height /= 2;
}
return m_textureID; return m_textureID;
} }
@ -349,4 +341,35 @@ bool Texture::CheckMapPos(int ax1, int ax2, int ay1, int ay2)
return false; return false;
} }
void Texture::CreateTextureObject(int format, bool mirrorU, bool mirrorV, 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_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); // 0-5 (real3d only uses 6 possible mipmap levels)
m_x = x;
m_y = y;
m_width = width;
m_height = height;
m_format = format;
m_mirrorU = mirrorU;
m_mirrorV = mirrorV;
printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height);
}
} // New3D } // New3D

View file

@ -26,6 +26,8 @@ public:
private: private:
void CreateTextureObject(int format, bool mirrorU, bool mirrorV, 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(); void Reset();
int m_x; int m_x;