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/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
|
||||
static const char *vertex_shader_source =
|
||||
"#version 120\n"
|
||||
|
|
@ -125,7 +265,7 @@ static int init_gl_resources(chroma_output_t *output) {
|
|||
glGenBuffers(1, &output->ebo);
|
||||
|
||||
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);
|
||||
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
|
||||
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) {
|
||||
return CHROMA_ERROR_INIT;
|
||||
}
|
||||
|
|
@ -180,8 +321,12 @@ static int update_texture_from_image(chroma_output_t *output,
|
|||
// Set texture parameters
|
||||
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_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)
|
||||
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 (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);
|
||||
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);
|
||||
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);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(dynamic_vertices),
|
||||
dynamic_vertices);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, output->ebo);
|
||||
|
||||
// Set vertex attributes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue