tr1/output: improve bilinear filter UVs

This commit is contained in:
Marcin Kurczewski 2025-04-05 14:05:00 +02:00
parent d647539581
commit ebe743cb0e
No known key found for this signature in database
GPG key ID: CC65E6FD28CAE42A
8 changed files with 101 additions and 17 deletions

View file

@ -2,6 +2,7 @@
uniform int uTime;
uniform samplerBuffer uUVW; // texture u, v, layer
uniform samplerBuffer uAtlasSizes; // texture x, y, w, h
uniform vec2 uViewportSize;
uniform mat4 uMatProjection;
uniform mat4 uMatModelView;
@ -21,6 +22,7 @@ out vec3 gNormal;
flat out int gFlags;
flat out int gTexLayer;
out vec2 gTexUV;
flat out vec4 gAtlasSize;
out vec2 gTrapezoidRatios;
out float gShade;
out vec4 gColor;
@ -36,6 +38,7 @@ void main(void) {
}
vec3 uvw = texelFetch(uUVW, int(inUVWIdx)).xyz;
gAtlasSize = texelFetch(uAtlasSizes, int(inUVWIdx / 4));
gFlags = inFlags;
gTexLayer = int(uvw.z);
gTexUV = uvw.xy;
@ -67,14 +70,22 @@ in vec3 gNormal;
flat in int gFlags;
flat in int gTexLayer;
in vec2 gTexUV;
flat in vec4 gAtlasSize;
in float gShade;
in vec4 gColor;
in vec2 gTrapezoidRatios;
out vec4 outColor;
vec2 clampTexAtlas(vec2 uv, vec4 atlasSize)
{
float epsilon = 0.5 / 256.0;
return clamp(uv, atlasSize.xy + epsilon, atlasSize.zw - epsilon);
}
void main(void) {
vec4 texColor = gColor;
vec3 texCoords = vec3(gTexUV.x, gTexUV.y, gTexLayer);
texCoords.xy = clampTexAtlas(gTexUV.xy / gTrapezoidRatios.xy, gAtlasSize) * gTrapezoidRatios.xy;
if (uTrapezoidFilterEnabled) {
texCoords.xy /= gTrapezoidRatios.xy;
}

View file

@ -89,6 +89,5 @@ void Output_DisableScissor(void);
void Output_RememberState(void);
void Output_RestoreState(void);
float Output_AdjustUV(uint16_t uv);
int32_t Output_GetLightDivider(void);
XYZ_32 Output_GetLightVectorView(void);

View file

@ -16,17 +16,8 @@ static struct {
} m_CachedState;
static bool m_IsSkyboxEnabled = false;
static inline float M_GetUV(uint16_t uv);
static void M_DrawSphere(XYZ_32 pos, int32_t radius);
static inline float M_GetUV(const uint16_t uv)
{
return g_Config.rendering.pretty_pixels
&& g_Config.rendering.texture_filter == GFX_TF_NN
? uv / 65536.0f
: ((uv & 0xFF00) + 127) / 65536.0f;
}
static void M_DrawSphere(const XYZ_32 pos, const int32_t radius)
{
// More subdivisions means smoother spheres.
@ -92,11 +83,6 @@ static void M_DrawSphere(const XYZ_32 pos, const int32_t radius)
glPolygonMode(GL_FRONT_AND_BACK, m_CachedState.bound_polygon_mode[0]);
}
float Output_AdjustUV(const uint16_t uv)
{
return M_GetUV(uv);
}
void Output_SetSkyboxEnabled(const bool enabled)
{
m_IsSkyboxEnabled = enabled;

View file

@ -424,6 +424,8 @@ void Output_Meshes_RenderObjectMesh(
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetObjectUVWsTexture());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetAtlasSizesTexture());
GFX_GL_CheckError();
Output_Shader_UploadWibbleEffect(m_Shader, false);

View file

@ -314,6 +314,8 @@ void Output_Meshes_RenderRoomMesh(
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetObjectUVWsTexture());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetAtlasSizesTexture());
GFX_GL_CheckError();
if (Output_GetWibbleEffect()) {

View file

@ -11,6 +11,7 @@
typedef enum {
M_UNIFORM_TIME,
M_UNIFORM_TEX_ATLAS,
M_UNIFORM_TEX_ATLAS_SIZES,
M_UNIFORM_TEX_UVW,
M_UNIFORM_TEX_ENV_MAP,
M_UNIFORM_SMOOTHING_ENABLED,
@ -51,6 +52,7 @@ OUTPUT_SHADER *Output_Shader_Create(const char *const path)
const char *const uniform_names[] = {
[M_UNIFORM_TIME] = "uTime",
[M_UNIFORM_TEX_ATLAS] = "uTexAtlas",
[M_UNIFORM_TEX_ATLAS_SIZES] = "uAtlasSizes",
[M_UNIFORM_TEX_UVW] = "uUVW",
[M_UNIFORM_TEX_ENV_MAP] = "uTexEnvMap",
[M_UNIFORM_SMOOTHING_ENABLED] = "uSmoothingEnabled",
@ -77,6 +79,7 @@ OUTPUT_SHADER *Output_Shader_Create(const char *const path)
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ATLAS], 0);
glUniform1i(shader->uniforms[M_UNIFORM_TEX_UVW], 1);
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ENV_MAP], 2);
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ATLAS_SIZES], 3);
return shader;
}

View file

@ -8,6 +8,12 @@
#include <stdlib.h>
#pragma pack(push, 1)
typedef struct {
float x0, y0, x1, y1;
} M_ATLAS_SIZE;
#pragma pack(pop)
typedef struct {
int32_t index;
int32_t count;
@ -45,6 +51,11 @@ static struct {
GLuint tex_env_map;
M_TEXTURE_DATA objects;
M_TEXTURE_DATA sprites;
struct {
GLuint tex;
GLuint tbo;
M_ATLAS_SIZE *data;
} atlas_sizes;
} m_Priv = {};
static int M_CompareAnimationRange(const void *const a, const void *const b)
@ -170,13 +181,33 @@ static void M_FreeTextureData(M_TEXTURE_DATA *const data)
}
}
static void M_FillAtlasSize(const int32_t i)
{
M_ATLAS_SIZE *size = &m_Priv.atlas_sizes.data[i];
const OBJECT_TEXTURE *const texture = Output_GetObjectTexture(i);
size->x0 = texture->uv[0].u;
size->y0 = texture->uv[0].v;
size->x1 = texture->uv[0].u;
size->y1 = texture->uv[0].v;
for (int32_t j = 1; j < 3; j++) {
size->x0 = MIN(size->x0, texture->uv[j].u);
size->y0 = MIN(size->y0, texture->uv[j].v);
size->x1 = MAX(size->x1, texture->uv[j].u);
size->y1 = MAX(size->y1, texture->uv[j].v);
}
size->x0 /= 65535.0;
size->y0 /= 65535.0;
size->x1 /= 65535.0;
size->y1 /= 65535.0;
}
static void M_FillObjectUVW(const int32_t i)
{
const OBJECT_TEXTURE *const texture = Output_GetObjectTexture(i);
M_UVW *const corners = m_Priv.objects.uvw[i].corners;
for (int32_t j = 0; j < 4; j++) {
corners[j].u = Output_AdjustUV(texture->uv[j].u);
corners[j].v = Output_AdjustUV(texture->uv[j].v);
corners[j].u = texture->uv[j].u / 65535.0f;
corners[j].v = texture->uv[j].v / 65535.0f;
corners[j].w = texture->tex_page;
}
}
@ -245,6 +276,19 @@ static void M_UploadObjectAnimatedUVWs(const M_ANIMATION_RANGES *const source)
range->count * sizeof(M_UVW_PACK),
m_Priv.objects.uvw + range->index);
}
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tbo);
for (int32_t i = 0; i < source->range_count; i++) {
const M_ANIMATION_RANGE *const range = &source->ranges[i];
for (int32_t j = 0; j < range->count; j++) {
M_FillAtlasSize(range->index + j);
}
GFX_TRACK_DATA(
glBufferSubData, GL_TEXTURE_BUFFER,
range->index * sizeof(M_ATLAS_SIZE),
range->count * sizeof(M_ATLAS_SIZE),
m_Priv.atlas_sizes.data + range->index);
}
}
static void M_UploadSpriteAnimatedUVWs(const M_ANIMATION_RANGES *const source)
@ -304,6 +348,24 @@ static void M_PrepareEnvMap(void)
GFX_GL_CheckError();
}
static void M_PrepareAtlasSizes(void)
{
glGenBuffers(1, &m_Priv.atlas_sizes.tbo);
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tbo);
glGenTextures(1, &m_Priv.atlas_sizes.tex);
glBindTexture(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tex);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_Priv.atlas_sizes.tbo);
const int32_t count = Output_GetObjectTextureCount();
m_Priv.atlas_sizes.data =
Memory_Realloc(m_Priv.atlas_sizes.data, count * sizeof(M_ATLAS_SIZE));
for (int32_t i = 0; i < count; i++) {
M_FillAtlasSize(i);
}
GFX_TRACK_DATA(
glBufferData, GL_TEXTURE_BUFFER, count * sizeof(M_ATLAS_SIZE),
m_Priv.atlas_sizes.data, GL_DYNAMIC_DRAW);
}
static void M_UploadAtlas(void)
{
glGenTextures(1, &m_Priv.tex_atlas);
@ -335,6 +397,10 @@ static void M_UploadAtlas(void)
GL_RGBA, GL_UNSIGNED_BYTE, input_ptr);
}
GFX_GL_CheckError();
M_PrepareAtlasSizes();
GFX_GL_CheckError();
}
static void M_FreeLevelData(void)
@ -347,6 +413,15 @@ static void M_FreeLevelData(void)
glDeleteTextures(1, &m_Priv.tex_atlas);
m_Priv.tex_atlas = 0;
}
if (m_Priv.atlas_sizes.tex != 0) {
glDeleteTextures(1, &m_Priv.atlas_sizes.tex);
m_Priv.atlas_sizes.tex = 0;
}
if (m_Priv.atlas_sizes.tbo != 0) {
glDeleteBuffers(1, &m_Priv.atlas_sizes.tbo);
m_Priv.atlas_sizes.tbo = 0;
}
Memory_FreePointer(&m_Priv.atlas_sizes.data);
Memory_FreePointer(&m_AnimationRanges.objects.ranges);
Memory_FreePointer(&m_AnimationRanges.sprites.ranges);
}
@ -423,6 +498,11 @@ GLuint Output_Textures_GetAtlasTexture(void)
return m_Priv.tex_atlas;
}
GLuint Output_Textures_GetAtlasSizesTexture(void)
{
return m_Priv.atlas_sizes.tex;
}
GLuint Output_Textures_GetEnvMapTexture(void)
{
return m_Priv.tex_env_map;

View file

@ -11,4 +11,5 @@ void Output_Textures_ApplyRenderSettings(void);
GLuint Output_Textures_GetObjectUVWsTexture(void);
GLuint Output_Textures_GetSpriteUVWsTexture(void);
GLuint Output_Textures_GetAtlasTexture(void);
GLuint Output_Textures_GetAtlasSizesTexture(void);
GLuint Output_Textures_GetEnvMapTexture(void);