From 0a21755e831df9349e3630e0d1c3341bf386695f Mon Sep 17 00:00:00 2001 From: BlueStaggo Date: Mon, 31 Mar 2025 18:04:53 +0000 Subject: [PATCH] Manual mipmapping + Texture padding --- src/hardware/r_opengl/r_opengl.c | 139 +++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 02a32957a..2008beb00 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1486,6 +1486,114 @@ static void AllocTextureBuffer(GLMipmap_t *pTexInfo) } } +#define PADDING_CHECK(offset, alphaCheck) { from = to + (offset); if ((alphaCheck)) from = NULL; else goto foundFrom; } + +static void PadRGBABitmap(RGBA_t *tex, UINT16 w, UINT16 h) +{ + INT32 i; + boolean notLeft, notRight, notTop, notBottom; + RGBA_t *to = tex - 1, *from; + + for (i = 0; i < w * h; i++) + { + to++; + if (to->rgba != 0) + continue; + from = NULL; + + notLeft = i % w != 0; + notRight = i % w != w - 1; + notTop = i / w != 0; + notBottom = i / w != h - 1; + + if (notRight) PADDING_CHECK(1, from->s.alpha == 0) // Check +X + if (notBottom) PADDING_CHECK(w, from->s.alpha == 0) // Check +Y + if (notLeft) PADDING_CHECK(-1, from->s.alpha == 0) // Check -X + if (notTop) PADDING_CHECK(-w, from->s.alpha == 0) // Check -Y + if (notRight && notBottom) PADDING_CHECK(1 + w, from->s.alpha == 0) // Check +X+Y + if (notLeft && notBottom) PADDING_CHECK(-1 + w, from->s.alpha == 0) // Check -X+Y + if (notLeft && notTop) PADDING_CHECK(-1 - w, from->s.alpha == 0) // Check -X-Y + if (notRight && notTop) PADDING_CHECK(1 - w, from->s.alpha == 0) // Check +X-Y + +foundFrom: + if (from != NULL) + { + *to = *from; + to->s.alpha = 0; + } + } +} + +#undef PADDING_CHECK + +static void GenerateMipmaps(INT32 w, INT32 h, RGBA_t *tex, INT32 maxLOD) +{ + if (tex == NULL) + { + GL_MSG_Warning("GenerateMipmaps: attempted to generate mipmaps without texture data"); + return; + } + + RGBA_t samplePoint[4]; + boolean padTexture; + INT32 pointsSampled = 0; + INT32 m, j, i, p; + UINT16 sumR, sumG, sumB, sumA; + + for (m = 0; m < maxLOD; m++) + { + if (w <= 1 || h <= 1) + return; + + padTexture = false; + + for (j = 0; j < h / 2; j++) + { + for (i = 0; i < w / 2; i++) + { + samplePoint[0] = tex[w*j*2 + i*2]; + samplePoint[1] = tex[w*j*2 + i*2+1]; + samplePoint[2] = tex[w*(j*2+1) + i*2]; + samplePoint[3] = tex[w*(j*2+1) + i*2+1]; + + pointsSampled = sumR = sumG = sumB = sumA = 0; + + for (p = 0; p < 4; p++) + { + if (samplePoint[p].s.alpha == 0) + continue; + sumR += samplePoint[p].s.red; + sumG += samplePoint[p].s.green; + sumB += samplePoint[p].s.blue; + sumA += samplePoint[p].s.alpha; + pointsSampled++; + } + + if (pointsSampled > 0) + { + tex[(w/2)*j+i].s.red = sumR / pointsSampled; + tex[(w/2)*j+i].s.green = sumG / pointsSampled; + tex[(w/2)*j+i].s.blue = sumB / pointsSampled; + tex[(w/2)*j+i].s.alpha = sumA / pointsSampled; + } + else + { + tex[(w/2)*j+i].rgba = 0; + padTexture = true; + } + } + } + + w /= 2; + h /= 2; + + if (padTexture) + PadRGBABitmap(tex, w, h); + + pglTexSubImage2D(GL_TEXTURE_2D, m + 1, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex); + } +} + // -----------------+ // UpdateTexture : Updates texture data. // -----------------+ @@ -1494,6 +1602,7 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) // Upload a texture GLuint num = pTexInfo->downloaded; boolean update = true; + const boolean applyPadding = mag_filter == GL_LINEAR || min_filter == GL_LINEAR; INT32 w = pTexInfo->width, h = pTexInfo->height; INT32 i, j; @@ -1548,11 +1657,26 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) } } } + + if (applyPadding) + PadRGBABitmap(tex, w, h); } else if (pTexInfo->format == GL_TEXFMT_RGBA) { // Directly upload the texture data without any kind of conversion. ptex = pImgData; + + // However, it does need to be copied to a buffer for generating mipmaps and padding + if (MipMap || applyPadding) + { + AllocTextureBuffer(pTexInfo); + tex = textureBuffer; + memcpy(tex, ptex, w * h * 4); + ptex = tex; + + if (applyPadding) + PadRGBABitmap(tex, w, h); + } } else if (pTexInfo->format == GL_TEXFMT_ALPHA_INTENSITY_88) { @@ -1616,9 +1740,14 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); if (pTexInfo->flags & TF_TRANSPARENT) + { pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff + } else + { pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + GenerateMipmaps(w, h, tex, 4); + } //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR); } else @@ -1638,9 +1767,14 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); if (pTexInfo->flags & TF_TRANSPARENT) + { pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff + } else + { pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); + GenerateMipmaps(w, h, tex, 4); + } //pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR); } else @@ -1660,9 +1794,14 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) // Control the mipmap level of detail pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail if (pTexInfo->flags & TF_TRANSPARENT) + { pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff + } else + { pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5); + GenerateMipmaps(w, h, tex, 5); + } } else {