render: calculate texture coordinates based on scaling mode
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ie4e44a0cea68cbbee8122576c41aa4486a6a6964
This commit is contained in:
parent
9b42e70054
commit
e7f107a8fe
1 changed files with 169 additions and 6 deletions
175
src/render.c
175
src/render.c
|
|
@ -8,6 +8,146 @@
|
||||||
#include "../include/chroma.h"
|
#include "../include/chroma.h"
|
||||||
#include "../include/stb_image.h"
|
#include "../include/stb_image.h"
|
||||||
|
|
||||||
|
// Convert filter quality enum to OpenGL parameters
|
||||||
|
static void get_gl_filter_params(chroma_filter_quality_t quality,
|
||||||
|
GLint *min_filter, GLint *mag_filter) {
|
||||||
|
switch (quality) {
|
||||||
|
case CHROMA_FILTER_NEAREST:
|
||||||
|
*min_filter = GL_NEAREST;
|
||||||
|
*mag_filter = GL_NEAREST;
|
||||||
|
break;
|
||||||
|
case CHROMA_FILTER_LINEAR:
|
||||||
|
*min_filter = GL_LINEAR;
|
||||||
|
*mag_filter = GL_LINEAR;
|
||||||
|
break;
|
||||||
|
case CHROMA_FILTER_BILINEAR:
|
||||||
|
*min_filter = GL_LINEAR_MIPMAP_LINEAR;
|
||||||
|
*mag_filter = GL_LINEAR;
|
||||||
|
break;
|
||||||
|
case CHROMA_FILTER_TRILINEAR:
|
||||||
|
*min_filter = GL_LINEAR_MIPMAP_LINEAR;
|
||||||
|
*mag_filter = GL_LINEAR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*min_filter = GL_LINEAR;
|
||||||
|
*mag_filter = GL_LINEAR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate texture coordinates based on scaling mode
|
||||||
|
static void calculate_texture_coords(chroma_scale_mode_t scale_mode,
|
||||||
|
int image_width, int image_height,
|
||||||
|
int output_width, int output_height,
|
||||||
|
float tex_coords[8]) {
|
||||||
|
// Default texture coordinates (full texture)
|
||||||
|
float u1 = 0.0f, v1 = 0.0f; // top-left
|
||||||
|
float u2 = 1.0f, v2 = 1.0f; // bottom-right
|
||||||
|
|
||||||
|
switch (scale_mode) {
|
||||||
|
case CHROMA_SCALE_STRETCH:
|
||||||
|
// Use full texture, stretch to fit
|
||||||
|
u1 = 0.0f;
|
||||||
|
v1 = 0.0f;
|
||||||
|
u2 = 1.0f;
|
||||||
|
v2 = 1.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHROMA_SCALE_CENTER:
|
||||||
|
// Center image at original size
|
||||||
|
// Calculate how much of the texture to show
|
||||||
|
{
|
||||||
|
float image_aspect = (float)image_width / image_height;
|
||||||
|
float output_aspect = (float)output_width / output_height;
|
||||||
|
|
||||||
|
if (image_aspect > output_aspect) {
|
||||||
|
// Image is wider - fit width, show center portion vertically
|
||||||
|
float visible_height = (float)image_width / output_aspect;
|
||||||
|
float v_offset =
|
||||||
|
(image_height - visible_height) / (2.0f * image_height);
|
||||||
|
u1 = 0.0f;
|
||||||
|
v1 = v_offset;
|
||||||
|
u2 = 1.0f;
|
||||||
|
v2 = 1.0f - v_offset;
|
||||||
|
} else {
|
||||||
|
// Image is taller - fit height, show center portion horizontally
|
||||||
|
float visible_width = (float)image_height * output_aspect;
|
||||||
|
float u_offset = (image_width - visible_width) / (2.0f * image_width);
|
||||||
|
u1 = u_offset;
|
||||||
|
v1 = 0.0f;
|
||||||
|
u2 = 1.0f - u_offset;
|
||||||
|
v2 = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHROMA_SCALE_FIT:
|
||||||
|
// Fit image within output, maintaining aspect ratio
|
||||||
|
{
|
||||||
|
float image_aspect = (float)image_width / image_height;
|
||||||
|
float output_aspect = (float)output_width / output_height;
|
||||||
|
|
||||||
|
if (image_aspect > output_aspect) {
|
||||||
|
// Image is wider - fit width, add borders top/bottom
|
||||||
|
float scaled_height = (float)output_width / image_aspect;
|
||||||
|
float v_border =
|
||||||
|
(output_height - scaled_height) / (2.0f * output_height);
|
||||||
|
u1 = 0.0f;
|
||||||
|
v1 = v_border;
|
||||||
|
u2 = 1.0f;
|
||||||
|
v2 = 1.0f - v_border;
|
||||||
|
} else {
|
||||||
|
// Image is taller - fit height, add borders left/right
|
||||||
|
float scaled_width = (float)output_height * image_aspect;
|
||||||
|
float u_border = (output_width - scaled_width) / (2.0f * output_width);
|
||||||
|
u1 = u_border;
|
||||||
|
v1 = 0.0f;
|
||||||
|
u2 = 1.0f - u_border;
|
||||||
|
v2 = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHROMA_SCALE_FILL:
|
||||||
|
default:
|
||||||
|
// Fill entire output, crop if necessary
|
||||||
|
{
|
||||||
|
float image_aspect = (float)image_width / image_height;
|
||||||
|
float output_aspect = (float)output_width / output_height;
|
||||||
|
|
||||||
|
if (image_aspect > output_aspect) {
|
||||||
|
// Image is wider - crop left/right
|
||||||
|
float crop_width = image_height * output_aspect;
|
||||||
|
float u_crop = (image_width - crop_width) / (2.0f * image_width);
|
||||||
|
u1 = u_crop;
|
||||||
|
v1 = 0.0f;
|
||||||
|
u2 = 1.0f - u_crop;
|
||||||
|
v2 = 1.0f;
|
||||||
|
} else {
|
||||||
|
// Image is taller - crop top/bottom
|
||||||
|
float crop_height = image_width / output_aspect;
|
||||||
|
float v_crop = (image_height - crop_height) / (2.0f * image_height);
|
||||||
|
u1 = 0.0f;
|
||||||
|
v1 = v_crop;
|
||||||
|
u2 = 1.0f;
|
||||||
|
v2 = 1.0f - v_crop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set texture coordinates for quad (bottom-left, bottom-right, top-right,
|
||||||
|
// top-left)
|
||||||
|
tex_coords[0] = u1;
|
||||||
|
tex_coords[1] = v2; // bottom-left
|
||||||
|
tex_coords[2] = u2;
|
||||||
|
tex_coords[3] = v2; // bottom-right
|
||||||
|
tex_coords[4] = u2;
|
||||||
|
tex_coords[5] = v1; // top-right
|
||||||
|
tex_coords[6] = u1;
|
||||||
|
tex_coords[7] = v1; // top-left
|
||||||
|
}
|
||||||
|
|
||||||
// Vertex shader for simple texture rendering
|
// Vertex shader for simple texture rendering
|
||||||
static const char *vertex_shader_source =
|
static const char *vertex_shader_source =
|
||||||
"#version 120\n"
|
"#version 120\n"
|
||||||
|
|
@ -125,7 +265,7 @@ static int init_gl_resources(chroma_output_t *output) {
|
||||||
glGenBuffers(1, &output->ebo);
|
glGenBuffers(1, &output->ebo);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, output->vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, output->vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, output->ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, output->ebo);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
|
||||||
|
|
@ -140,7 +280,8 @@ static int init_gl_resources(chroma_output_t *output) {
|
||||||
|
|
||||||
// Create or update texture from image data
|
// Create or update texture from image data
|
||||||
static int update_texture_from_image(chroma_output_t *output,
|
static int update_texture_from_image(chroma_output_t *output,
|
||||||
chroma_image_t *image) {
|
chroma_image_t *image,
|
||||||
|
chroma_filter_quality_t filter_quality) {
|
||||||
if (!output || !image || !image->loaded) {
|
if (!output || !image || !image->loaded) {
|
||||||
return CHROMA_ERROR_INIT;
|
return CHROMA_ERROR_INIT;
|
||||||
}
|
}
|
||||||
|
|
@ -180,8 +321,12 @@ static int update_texture_from_image(chroma_output_t *output,
|
||||||
// Set texture parameters
|
// Set texture parameters
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
// Use configured filter quality
|
||||||
|
GLint min_filter, mag_filter;
|
||||||
|
get_gl_filter_params(filter_quality, &min_filter, &mag_filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
||||||
|
|
||||||
// Upload texture data (always RGBA now)
|
// Upload texture data (always RGBA now)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height, 0,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height, 0,
|
||||||
|
|
@ -503,7 +648,8 @@ int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output->texture_id == 0) {
|
if (output->texture_id == 0) {
|
||||||
if (update_texture_from_image(output, output->image) != CHROMA_OK) {
|
if (update_texture_from_image(output, output->image,
|
||||||
|
output->filter_quality) != CHROMA_OK) {
|
||||||
chroma_log("ERROR", "Failed to update texture for output %u", output->id);
|
chroma_log("ERROR", "Failed to update texture for output %u", output->id);
|
||||||
return CHROMA_ERROR_EGL;
|
return CHROMA_ERROR_EGL;
|
||||||
}
|
}
|
||||||
|
|
@ -524,8 +670,25 @@ int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output) {
|
||||||
glBindTexture(GL_TEXTURE_2D, output->texture_id);
|
glBindTexture(GL_TEXTURE_2D, output->texture_id);
|
||||||
glUniform1i(glGetUniformLocation(output->shader_program, "texture"), 0);
|
glUniform1i(glGetUniformLocation(output->shader_program, "texture"), 0);
|
||||||
|
|
||||||
// Use cached VBO/EBO
|
// Calculate texture coordinates based on scaling mode
|
||||||
|
float tex_coords[8];
|
||||||
|
calculate_texture_coords(output->scale_mode, output->image->width,
|
||||||
|
output->image->height, output->width, output->height,
|
||||||
|
tex_coords);
|
||||||
|
|
||||||
|
// Create dynamic vertex data with calculated texture coordinates
|
||||||
|
float dynamic_vertices[] = {
|
||||||
|
// Position Texcoord
|
||||||
|
-1.0f, -1.0f, tex_coords[0], tex_coords[1], // bottom-left
|
||||||
|
1.0f, -1.0f, tex_coords[2], tex_coords[3], // bottom-right
|
||||||
|
1.0f, 1.0f, tex_coords[4], tex_coords[5], // top-right
|
||||||
|
-1.0f, 1.0f, tex_coords[6], tex_coords[7] // top-left
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update VBO with dynamic texture coordinates
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, output->vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, output->vbo);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(dynamic_vertices),
|
||||||
|
dynamic_vertices);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, output->ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, output->ebo);
|
||||||
|
|
||||||
// Set vertex attributes
|
// Set vertex attributes
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue