notashelf /
e7f107a8fee992411f7e3841b1d59ceea83f9ed3
chroma
publicLightweight wallpaper daemon for Wayland
clone
ssh://git@git.notashelf.dev:33/notashelf/chroma.gitCommit e7f107a8fee9
tarballunverified1 files changed+169-6
@@ -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