brewery
notashelf /
e7f107a8fee992411f7e3841b1d59ceea83f9ed3

chroma

public

Lightweight wallpaper daemon for Wayland

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/chroma.git

Commit e7f107a8fee9

tarball

NotAShelf <raf@notashelf.dev> · 2025-11-01 22:19 UTC

unverified1 files changed+169-6
render: calculate texture coordinates based on scaling mode

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ie4e44a0cea68cbbee8122576c41aa4486a6a6964
diff --git a/src/render.c b/src/render.cindex b73e1ab..be9f98a 100644--- a/src/render.c+++ b/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