diff --git a/chroma.conf.sample b/chroma.conf.sample index d2b2c47..38b5fa3 100644 --- a/chroma.conf.sample +++ b/chroma.conf.sample @@ -43,14 +43,6 @@ scale_mode = fill # trilinear - Trilinear filtering (smoothest) filter_quality = linear -# Default anchor position (0-100 for both x and y) -# anchor_x: 0=left, 50=center, 100=right -# anchor_y: 0=top, 50=center, 100=bottom -# Can use named anchors: center, top, bottom, left, right, top-left, etc. -anchor = center -anchor_x = 50 -anchor_y = 50 - # Image downsampling settings for performance optimization # =================================================== # Enable automatic downsampling of large images to save memory and improve performance @@ -119,10 +111,4 @@ min_scale_factor = 0.25 # Don't scale below 25% of original size # output.eDP-1.scale = fill # output.eDP-1.anchor = bottom-right # output.eDP-1.filter = trilinear -# -# Custom anchor coordinates (anchor_x, anchor_y override anchor): -# output.ULTRAWIDE = ~/Pictures/ultrawide.jpg -# output.ULTRAWIDE.scale = fill -# output.ULTRAWIDE.anchor_x = 25 # 25% from left edge -# output.ULTRAWIDE.anchor_y = 10 # 10% from top edge diff --git a/include/chroma.h b/include/chroma.h index 7ff7ead..76afc43 100644 --- a/include/chroma.h +++ b/include/chroma.h @@ -104,8 +104,6 @@ typedef struct { chroma_scale_mode_t scale_mode; chroma_filter_quality_t filter_quality; chroma_anchor_t anchor; - float anchor_x; // custom X offset (0-100, 50=center) - float anchor_y; // custom Y offset (0-100, 50=center) bool config_loaded; // OpenGL resource cache @@ -125,8 +123,6 @@ typedef struct { chroma_scale_mode_t scale_mode; chroma_filter_quality_t filter_quality; chroma_anchor_t anchor; - float anchor_x; // custom X offset (0-100, 50=center, 0=left, 100=right) - float anchor_y; // custom Y offset (0-100, 50=center, 0=top, 100=bottom) } chroma_config_mapping_t; // Application configuration @@ -140,8 +136,6 @@ typedef struct { chroma_scale_mode_t default_scale_mode; chroma_filter_quality_t default_filter_quality; chroma_anchor_t default_anchor; - float default_anchor_x; // custom anchor X offset (0-100, 50=center) - float default_anchor_y; // custom anchor Y offset (0-100, 50=center) // Image downsampling settings bool enable_downsampling; // enable automatic downsampling @@ -254,7 +248,7 @@ const char *chroma_config_get_image_for_output(chroma_config_t *config, int chroma_config_get_mapping_for_output( chroma_config_t *config, const char *output_name, chroma_scale_mode_t *scale_mode, chroma_filter_quality_t *filter_quality, - chroma_anchor_t *anchor, float *anchor_x, float *anchor_y); + chroma_anchor_t *anchor); void chroma_config_print(const chroma_config_t *config); diff --git a/src/config.c b/src/config.c index 9bae27c..0a35467 100644 --- a/src/config.c +++ b/src/config.c @@ -184,8 +184,7 @@ static int add_output_mapping(chroma_config_t *config, const char *output_name, const char *image_path, chroma_scale_mode_t scale_mode, chroma_filter_quality_t filter_quality, - chroma_anchor_t anchor, float anchor_x, - float anchor_y) { + chroma_anchor_t anchor) { if (!config || !output_name || !image_path) { return CHROMA_ERROR_INIT; } @@ -219,17 +218,13 @@ static int add_output_mapping(chroma_config_t *config, const char *output_name, mapping->scale_mode = scale_mode; mapping->filter_quality = filter_quality; mapping->anchor = anchor; - mapping->anchor_x = anchor_x; - mapping->anchor_y = anchor_y; config->mapping_count++; chroma_log( - "DEBUG", - "Added mapping: %s -> %s (scale: %s, filter: %s, anchor: %s @ %.1f,%.1f)", + "DEBUG", "Added mapping: %s -> %s (scale: %s, filter: %s, anchor: %s)", output_name, image_path, scale_mode_to_string(scale_mode), - filter_quality_to_string(filter_quality), anchor_to_string(anchor), - anchor_x, anchor_y); + filter_quality_to_string(filter_quality), anchor_to_string(anchor)); chroma_log("TRACE", "Output mapping %d: '%s' -> '%s' (path length: %zu)", config->mapping_count, output_name, image_path, path_len); return CHROMA_OK; @@ -249,8 +244,6 @@ static void init_default_config(chroma_config_t *config) { config->default_scale_mode = CHROMA_SCALE_FILL; config->default_filter_quality = CHROMA_FILTER_LINEAR; config->default_anchor = CHROMA_ANCHOR_CENTER; - config->default_anchor_x = 50.0f; // center - config->default_anchor_y = 50.0f; // center // Set default downsampling settings config->enable_downsampling = true; // enable by default, performance etc. @@ -358,34 +351,6 @@ static int parse_config_line(chroma_config_t *config, char *line, config->default_anchor = parse_anchor(value); chroma_log("DEBUG", "Set default anchor: %s", anchor_to_string(config->default_anchor)); - } else if (strcasecmp(key, "anchor_x") == 0) { - char *endptr = NULL; - float ax = strtof(value, &endptr); - if (endptr == value || *endptr != '\0') { - chroma_log("WARN", "Invalid anchor_x: %s (not a number, using 50)", - value); - config->default_anchor_x = 50.0f; - } else if (ax < 0.0f || ax > 100.0f) { - chroma_log("WARN", "Invalid anchor_x: %s (range 0-100, using 50)", value); - config->default_anchor_x = 50.0f; - } else { - config->default_anchor_x = ax; - chroma_log("DEBUG", "Set default anchor_x: %.1f", ax); - } - } else if (strcasecmp(key, "anchor_y") == 0) { - char *endptr = NULL; - float ay = strtof(value, &endptr); - if (endptr == value || *endptr != '\0') { - chroma_log("WARN", "Invalid anchor_y: %s (not a number, using 50)", - value); - config->default_anchor_y = 50.0f; - } else if (ay < 0.0f || ay > 100.0f) { - chroma_log("WARN", "Invalid anchor_y: %s (range 0-100, using 50)", value); - config->default_anchor_y = 50.0f; - } else { - config->default_anchor_y = ay; - chroma_log("DEBUG", "Set default anchor_y: %.1f", ay); - } } else if (strcasecmp(key, "max_output_width") == 0) { int width = atoi(value); if (width > 0 && width <= 16384) { // Reasonable limits @@ -453,70 +418,8 @@ static int parse_config_line(chroma_config_t *config, char *line, filter_quality_to_string(mapping->filter_quality)); } else if (strcasecmp(property, "anchor") == 0) { mapping->anchor = parse_anchor(value); - // Set anchor_x/anchor_y based on named anchor - switch (mapping->anchor) { - case CHROMA_ANCHOR_TOP: - mapping->anchor_x = 50.0f; - mapping->anchor_y = 0.0f; - break; - case CHROMA_ANCHOR_BOTTOM: - mapping->anchor_x = 50.0f; - mapping->anchor_y = 100.0f; - break; - case CHROMA_ANCHOR_LEFT: - mapping->anchor_x = 0.0f; - mapping->anchor_y = 50.0f; - break; - case CHROMA_ANCHOR_RIGHT: - mapping->anchor_x = 100.0f; - mapping->anchor_y = 50.0f; - break; - case CHROMA_ANCHOR_TOP_LEFT: - mapping->anchor_x = 0.0f; - mapping->anchor_y = 0.0f; - break; - case CHROMA_ANCHOR_TOP_RIGHT: - mapping->anchor_x = 100.0f; - mapping->anchor_y = 0.0f; - break; - case CHROMA_ANCHOR_BOTTOM_LEFT: - mapping->anchor_x = 0.0f; - mapping->anchor_y = 100.0f; - break; - case CHROMA_ANCHOR_BOTTOM_RIGHT: - mapping->anchor_x = 100.0f; - mapping->anchor_y = 100.0f; - break; - default: - mapping->anchor_x = 50.0f; - mapping->anchor_y = 50.0f; - break; - } - chroma_log("DEBUG", "Set anchor for output %s: %s (x=%.1f, y=%.1f)", - output_name, anchor_to_string(mapping->anchor), - mapping->anchor_x, mapping->anchor_y); - } else if (strcasecmp(property, "anchor_x") == 0) { - float ax = atof(value); - if (ax >= 0.0f && ax <= 100.0f) { - mapping->anchor_x = ax; - chroma_log("DEBUG", "Set anchor_x for output %s: %.1f", output_name, - ax); - } else { - mapping->anchor_x = 50.0f; - chroma_log("WARN", "Invalid anchor_x: %s (range 0-100, using 50)", - value); - } - } else if (strcasecmp(property, "anchor_y") == 0) { - float ay = atof(value); - if (ay >= 0.0f && ay <= 100.0f) { - mapping->anchor_y = ay; - chroma_log("DEBUG", "Set anchor_y for output %s: %.1f", output_name, - ay); - } else { - mapping->anchor_y = 50.0f; - chroma_log("WARN", "Invalid anchor_y: %s (range 0-100, using 50)", - value); - } + chroma_log("DEBUG", "Set anchor for output %s: %s", output_name, + anchor_to_string(mapping->anchor)); } else { chroma_log("WARN", "Unknown output property: %s (line %d)", property, line_number); @@ -539,10 +442,10 @@ static int parse_config_line(chroma_config_t *config, char *line, return CHROMA_OK; } - if (add_output_mapping( - config, output_name, path_to_validate, config->default_scale_mode, - config->default_filter_quality, config->default_anchor, - config->default_anchor_x, config->default_anchor_y) != CHROMA_OK) { + if (add_output_mapping(config, output_name, path_to_validate, + config->default_scale_mode, + config->default_filter_quality, + config->default_anchor) != CHROMA_OK) { chroma_log("ERROR", "Failed to add output mapping: %s -> %s", output_name, path_to_validate); if (expanded_path) { @@ -686,13 +589,12 @@ const char *chroma_config_get_image_for_output(chroma_config_t *config, } // Get configuration mapping for output, including scale mode, filter -// quality, anchor, and custom anchor coordinates +// quality, and anchor int chroma_config_get_mapping_for_output( chroma_config_t *config, const char *output_name, chroma_scale_mode_t *scale_mode, chroma_filter_quality_t *filter_quality, - chroma_anchor_t *anchor, float *anchor_x, float *anchor_y) { - if (!config || !output_name || !scale_mode || !filter_quality || !anchor || - !anchor_x || !anchor_y) { + chroma_anchor_t *anchor) { + if (!config || !output_name || !scale_mode || !filter_quality || !anchor) { return CHROMA_ERROR_INIT; } @@ -702,14 +604,12 @@ int chroma_config_get_mapping_for_output( *scale_mode = config->mappings[i].scale_mode; *filter_quality = config->mappings[i].filter_quality; *anchor = config->mappings[i].anchor; - *anchor_x = config->mappings[i].anchor_x; - *anchor_y = config->mappings[i].anchor_y; chroma_log("DEBUG", "Found specific mapping for output %s: scale=%s, filter=%s, " - "anchor=%s @ %.1f,%.1f", + "anchor=%s", output_name, scale_mode_to_string(*scale_mode), filter_quality_to_string(*filter_quality), - anchor_to_string(*anchor), *anchor_x, *anchor_y); + anchor_to_string(*anchor)); return CHROMA_OK; } } @@ -718,14 +618,10 @@ int chroma_config_get_mapping_for_output( *scale_mode = config->default_scale_mode; *filter_quality = config->default_filter_quality; *anchor = config->default_anchor; - *anchor_x = config->default_anchor_x; - *anchor_y = config->default_anchor_y; - chroma_log("DEBUG", - "Using defaults for output %s: scale=%s, filter=%s, anchor=%s @ " - "%.1f,%.1f", - output_name, scale_mode_to_string(*scale_mode), - filter_quality_to_string(*filter_quality), - anchor_to_string(*anchor), *anchor_x, *anchor_y); + chroma_log( + "DEBUG", "Using defaults for output %s: scale=%s, filter=%s, anchor=%s", + output_name, scale_mode_to_string(*scale_mode), + filter_quality_to_string(*filter_quality), anchor_to_string(*anchor)); return CHROMA_OK; } diff --git a/src/core.c b/src/core.c index b7a5029..a8890c1 100644 --- a/src/core.c +++ b/src/core.c @@ -113,29 +113,20 @@ static int assign_wallpaper_to_output(chroma_state_t *state, chroma_scale_mode_t old_scale_mode = output->scale_mode; chroma_filter_quality_t old_filter_quality = output->filter_quality; chroma_anchor_t old_anchor = output->anchor; - float old_anchor_x = output->anchor_x; - float old_anchor_y = output->anchor_y; bool had_config = output->config_loaded; - // Load configuration for this output (scale mode, filter quality, anchor, - // anchor coords) + // Load configuration for this output (scale mode, filter quality, anchor) if (chroma_config_get_mapping_for_output( &state->config, output->name ? output->name : "unknown", - &output->scale_mode, &output->filter_quality, &output->anchor, - &output->anchor_x, &output->anchor_y) == CHROMA_OK) { + &output->scale_mode, &output->filter_quality, &output->anchor) == CHROMA_OK) { output->config_loaded = true; - chroma_log("DEBUG", - "Loaded config for output %u: scale=%d, filter=%d, anchor=%d @ " - "%.1f,%.1f", - output->id, output->scale_mode, output->filter_quality, - output->anchor, output->anchor_x, output->anchor_y); + chroma_log("DEBUG", "Loaded config for output %u: scale=%d, filter=%d, anchor=%d", + output->id, output->scale_mode, output->filter_quality, output->anchor); // Check if configuration changed and invalidate texture if needed - if (had_config && - (old_scale_mode != output->scale_mode || - old_filter_quality != output->filter_quality || - old_anchor != output->anchor || old_anchor_x != output->anchor_x || - old_anchor_y != output->anchor_y)) { + if (had_config && (old_scale_mode != output->scale_mode || + old_filter_quality != output->filter_quality || + old_anchor != output->anchor)) { chroma_output_invalidate_texture(output); output->vbo_dirty = true; // VBO needs update for new scale mode chroma_log("DEBUG", @@ -389,16 +380,14 @@ void chroma_log(const char *level, const char *format, ...) { gettimeofday(&tv, NULL); tm_info = localtime(&tv.tv_sec); - truncation_check = - snprintf(timestamp, sizeof(timestamp), - "%04d-%02d-%02d %02d:%02d:%02d.%03d", tm_info->tm_year + 1900, - tm_info->tm_mon + 1, tm_info->tm_mday, tm_info->tm_hour, - tm_info->tm_min, tm_info->tm_sec, (int)(tv.tv_usec / 1000)); + truncation_check = snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03d", + tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday, + tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, + (int)(tv.tv_usec / 1000)); - if (truncation_check > 32 || truncation_check < 0) { - // Something went seriously wrong with the snprintf, this is a fairly - // serious error as the timestamp may be incomplete or corrupted, so print a - // warning + if(truncation_check > 32 || truncation_check < 0) { + // Something went seriously wrong with the snprintf, this is a fairly serious error as + // the timestamp may be incomplete or corrupted, so print a warning printf("Following timestamp may be incomplete, truncated or corrupted!\n"); } printf("[%s] %s: ", timestamp, level); diff --git a/src/render.c b/src/render.c index 13444f3..281489f 100644 --- a/src/render.c +++ b/src/render.c @@ -43,7 +43,7 @@ static void get_gl_filter_params(chroma_filter_quality_t quality, // Calculate texture coordinates based on scaling mode and anchor position static void calculate_texture_coords(chroma_scale_mode_t scale_mode, - float anchor_x, float anchor_y, + chroma_anchor_t anchor, int image_width, int image_height, int output_width, int output_height, float tex_coords[8]) { @@ -143,13 +143,53 @@ static void calculate_texture_coords(chroma_scale_mode_t scale_mode, break; } - // Apply anchor-based offset using anchor_x and anchor_y (0-100, 50=center) - // anchor_x: 0=left edge, 50=center, 100=right edge - // anchor_y: 0=top edge, 50=center, 100=bottom edge - // u_shift: negative moves view left (shows more right side of image) - // v_shift: negative moves view up (shows more top of image) - float u_shift = (anchor_x - 50.0f) / 50.0f; // -1 to 1 - float v_shift = (50.0f - anchor_y) / 50.0f; // -1 to 1 (inverted for top-down) + // Apply anchor-based offset by shifting the visible crop region + // For fill: shift which part of image is shown + // For fit/center: shift where the image is positioned + // + // Positive shift reveals left/bottom portion + // Negative shift reveals right/top portion + float u_shift = 0.0f; + float v_shift = 0.0f; + + switch (anchor) { + case CHROMA_ANCHOR_CENTER: + u_shift = 0.0f; + v_shift = 0.0f; + break; + case CHROMA_ANCHOR_TOP: + u_shift = 0.0f; + v_shift = -0.5f; // shift up to show top of image + break; + case CHROMA_ANCHOR_BOTTOM: + u_shift = 0.0f; + v_shift = 0.5f; // shift down to show bottom of image + break; + case CHROMA_ANCHOR_LEFT: + u_shift = -0.5f; // shift left to show left of image + v_shift = 0.0f; + break; + case CHROMA_ANCHOR_RIGHT: + u_shift = 0.5f; // shift right to show right of image + v_shift = 0.0f; + break; + case CHROMA_ANCHOR_TOP_LEFT: + u_shift = -0.5f; + v_shift = -0.5f; + break; + case CHROMA_ANCHOR_TOP_RIGHT: + u_shift = 0.5f; + v_shift = -0.5f; + break; + case CHROMA_ANCHOR_BOTTOM_LEFT: + u_shift = -0.5f; + v_shift = 0.5f; + break; + case CHROMA_ANCHOR_BOTTOM_RIGHT: + u_shift = 0.5f; + v_shift = 0.5f; + break; + } // Calculate the shift amount based on crop/border space available float u_crop = 1.0f - (u2 - u1); @@ -715,13 +755,11 @@ int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output) { // Update VBO only if needed. E.g, image changed, scale mode changed, or first // render if (output->vbo_dirty) { - // Calculate texture coordinates based on scaling mode, anchor, and anchor - // coords + // Calculate texture coordinates based on scaling mode and anchor float tex_coords[8]; - calculate_texture_coords(output->scale_mode, output->anchor_x, - output->anchor_y, output->image->width, - output->image->height, output->width, - output->height, tex_coords); + calculate_texture_coords(output->scale_mode, output->anchor, + output->image->width, output->image->height, + output->width, output->height, tex_coords); // Create dynamic vertex data with calculated texture coordinates float dynamic_vertices[] = {