From 061f3696f5f48138be8cd26c305e49aeea23da7f Mon Sep 17 00:00:00 2001 From: Lilian1024 Date: Sat, 7 Dec 2024 13:50:52 +0100 Subject: [PATCH] feat added remove_mini_clusters --- src/menus/main_menu.c | 3 +- src/menus/selection_menu.c | 143 +++++++++++++++++----- src/menus/selection_menu.h | 17 ++- src/utils/EZ_UI/EZ_manager.c | 2 + src/utils/EZ_UI/EZ_utils.h | 2 +- src/utils/EZ_UI/elements/EZ_list.c | 10 +- src/utils/EZ_UI/elements/EZ_list.h | 8 +- src/utils/EZ_UI/elements/EZ_select_zone.c | 45 +++++++ src/utils/EZ_UI/elements/EZ_select_zone.h | 22 ++++ src/utils/EZ_UI/elements/EZ_text_input.c | 7 ++ src/utils/Image/ImageUtils.c | 126 +++++++++++++++++++ src/utils/Image/ImageUtils.h | 2 + src/utils/Spliting/Spliting.c | 11 +- 13 files changed, 354 insertions(+), 44 deletions(-) create mode 100644 src/utils/EZ_UI/elements/EZ_select_zone.c create mode 100644 src/utils/EZ_UI/elements/EZ_select_zone.h diff --git a/src/menus/main_menu.c b/src/menus/main_menu.c index 7c9d8f2..f5ec41a 100644 --- a/src/menus/main_menu.c +++ b/src/menus/main_menu.c @@ -74,10 +74,8 @@ void button_action_switch(EZ_button* tmp) { (void)tmp; loaded_image= rotate_pixels(loaded_image, rotation); - on_selection_menu_load(); EZ_select_menu(1); selection_menu_enter(); - } void load_image(EZ_text_input* tmp) @@ -90,6 +88,7 @@ void load_image(EZ_text_input* tmp) SDL_Surface * Surface= IMG_Load(tmp->inputed_text); loaded_image= Surface; image_to_black_white(Surface); + //remove_mini_clusters(Surface); EZ_edit_image((EZ_image*)main_menu_objects[0], Surface, main_renderer, 1); main_menu.drawable_elements[9]->visible=1; main_menu.drawable_elements[1]->visible=1; diff --git a/src/menus/selection_menu.c b/src/menus/selection_menu.c index 615f683..70b1459 100644 --- a/src/menus/selection_menu.c +++ b/src/menus/selection_menu.c @@ -2,27 +2,33 @@ #include "selection_menu.h" #include "global.h" #include "result_menu.h" -#include "../utils/Spliting/Spliting.h" #include "../utils/Application/ApplicationUtils.h" #include "../utils/EZ_UI/EZ_manager.h" #include "../utils/Rendering/RenderingUtils.h" #include "../utils/EZ_UI/elements/EZ_image.h" #include "../utils/EZ_UI/elements/EZ_button.h" #include "../utils/EZ_UI/elements/EZ_text.h" +#include "../utils/EZ_UI/elements/EZ_list.h" +#include "../utils/EZ_UI/elements/EZ_select_zone.h" #include "../utils/Application/ApplicationUtils.h" #include "../utils/Image/ImageUtils.h" #include "../utils/AI/neural_utils.h" #include +#include #include #include #include #include #include "EZ_drag_select.h" -EZ_DRAWABLE* selection_menu_drawables[14]; -EZ_INTERACTIBLE* selection_menu_interactibles[6]; +EZ_DRAWABLE* selection_menu_drawables[15]; +EZ_INTERACTIBLE* selection_menu_interactibles[7]; -void* selection_menu_objects[14]; +size_t selection_menu_objects_len = 15; +void* selection_menu_objects[15]; + +int auto_split_grid; +int auto_split_words; size_t grid_index; pixel_cluster** cluster_splitting; @@ -32,43 +38,25 @@ size_t* array_length; int grid_x, grid_y; char** grid; -size_t words_nb; +size_t words_nb = 0; size_t* word_len; char** words; +EZ_select_zone** words_select_zones; + EZ_MENU selection_menu; void unload_selection_menu(void) { - for (size_t i = 0; i < 2; i++) + for (size_t i = 0; i < selection_menu_objects_len; i++) { free(selection_menu_objects[i]); } -} -void on_selection_menu_load() -{ - cluster_splitting= get_main_linkages(loaded_image, &linkage_length, &array_length); - grid_index = get_grid_cluster(linkage_length,array_length); - SDL_Rect GridRect = get_grid_rect(cluster_splitting[grid_index], array_length[grid_index]); - SDL_Rect image_rect = anchore_to_rect(main_window,selection_menu.drawable_elements[0]->dst_anchore); - double xp = (double)GridRect.x / (double)loaded_image->w; - double yp = (double)GridRect.y / (double)loaded_image->h; - double fxp = (double)GridRect.w / (double)loaded_image->w; - double fyp = (double)GridRect.h / (double)loaded_image->h; - - int x = (double)xp * (double)image_rect.w; - int y = (double)yp * (double)image_rect.h; - int fx = (double)fxp * (double)image_rect.w; - int fy = (double)fyp * (double)image_rect.h; - - selection_menu.drawable_elements[10]->dst_anchore = rect_to_anchore((SDL_Rect){ - image_rect.x + x, - image_rect.y + y, - fx - x, - fy - y - }); - selection_menu.drawable_elements[10]->visible = 1; + for (size_t i = 0; i < words_nb; i++) + { + free(words_select_zones[i]); + } } void selection_menu_process_events(SDL_Window* window, SDL_Renderer* renderer, SDL_Event* event, EZ_MENU* current_menu) //exectuted each frame with all avaliable events @@ -85,12 +73,21 @@ void selection_menu_process_events(SDL_Window* window, SDL_Renderer* renderer, S void home_button_action1(EZ_button* tmp) { (void)tmp; + + for (size_t i = 0; i < words_nb; i++) //free words select zones + { + free(words_select_zones[i]); + } + + EZ_list_clear((EZ_list*)selection_menu_objects[14]); + EZ_select_menu(0); } void grid_selection_end(EZ_drag_select* tmp) { (void)tmp; + auto_split_grid = 0; EZ_drag_select* Drag=((EZ_drag_select*)selection_menu_objects[10]); Drag->interactible_select.enable=0; ((EZ_image*)selection_menu_objects[11])->drawable_image.dst_anchore= Drag->drawable_drag.dst_anchore; @@ -100,6 +97,7 @@ void grid_selection_end(EZ_drag_select* tmp) void word_selection_end(EZ_drag_select* tmp) { (void)tmp; + auto_split_words = 0; EZ_drag_select* Drag=((EZ_drag_select*)selection_menu_objects[12]); Drag->interactible_select.enable=0; ((EZ_image*)selection_menu_objects[13])->drawable_image.dst_anchore= Drag->drawable_drag.dst_anchore; @@ -234,10 +232,39 @@ void button_action_switch_result(EZ_button* tmp) } } + for (size_t i = 0; i < words_nb; i++) //free words select zones + { + free(words_select_zones[i]); + } + + EZ_list_clear((EZ_list*)selection_menu_objects[14]); + EZ_select_menu(2); result_menu_enter(); } +SDL_Rect from_surface_to_image_rect(anchore_point image, SDL_Surface* surface, SDL_Rect surface_rect) +{ + SDL_Rect image_rect = anchore_to_rect(main_window, image); + + double xp = (double)surface_rect.x / (double)surface->w; + double yp = (double)surface_rect.y / (double)surface->h; + double wp = (double)surface_rect.w / (double)surface->w; + double hp = (double)surface_rect.h / (double)surface->h; + + int x = round((double)xp * (double)image_rect.w); + int y = round((double)yp * (double)image_rect.h); + int w = round((double)wp * (double)image_rect.w); + int h = round((double)hp * (double)image_rect.h); + + return (SDL_Rect) { + image_rect.x + x, + image_rect.y + y, + w, + h + }; +} + void selection_menu_enter(void) { EZ_drag_select* drag_grid=((EZ_drag_select*)selection_menu_objects[10]); @@ -251,14 +278,50 @@ void selection_menu_enter(void) drag_word->drag_anchore = img->drawable_image.dst_anchore; drag_word->interactible_select.anchore = img->drawable_image.dst_anchore; + + auto_split_grid = 1; + auto_split_words = 1; + + cluster_splitting= get_main_linkages(loaded_image, &linkage_length, &array_length); + grid_index = get_grid_cluster(linkage_length,array_length); + + words_nb = linkage_length - 1; + + SDL_Rect GridRect = get_grid_rect(cluster_splitting[grid_index], array_length[grid_index]); + + selection_menu.drawable_elements[10]->dst_anchore = rect_to_anchore(from_surface_to_image_rect(selection_menu.drawable_elements[0]->dst_anchore, loaded_image, GridRect)); + selection_menu.drawable_elements[10]->visible = 1; + + words_select_zones = calloc(words_nb, sizeof(EZ_image*)); + + for (size_t w = 0; w < linkage_length; w++) + { + if (w == grid_index) + continue; + + size_t wi = w > grid_index ? w-1 : w; + + SDL_Rect WordRect = get_grid_rect(cluster_splitting[w], array_length[w]); + + //words_select_zones[wi] = EZ_create_image_file(combine_path(application_directory, "resources/SelectImageBlue.png"), main_renderer, rect_to_anchore(from_surface_to_image_rect(selection_menu.drawable_elements[0]->dst_anchore, loaded_image, WordRect)), 0); + words_select_zones[wi] = EZ_create_select_zone(rect_to_anchore(from_surface_to_image_rect(selection_menu.drawable_elements[0]->dst_anchore, loaded_image, WordRect)), (SDL_Color){255, 255, 0, 255}); + words_select_zones[wi]->drawable_select_zone.visible = 1; + + EZ_list_element* element = malloc(sizeof(EZ_list_element)); + + element->drawable_element = &words_select_zones[wi]->drawable_select_zone; + element->interactible_element = NULL; + + EZ_list_add_element((EZ_list*)selection_menu_objects[14], element); + } } void load_selection_menu(SDL_Renderer* renderer) { selection_menu.drawable_elements = selection_menu_drawables; - selection_menu.drawable_elements_len = 14; + selection_menu.drawable_elements_len = 15; selection_menu.interactible_elements = selection_menu_interactibles; - selection_menu.interactible_elements_len = 6; + selection_menu.interactible_elements_len = 7; SDL_Color back_col = {255, 255, 255, 255}; selection_menu.background_color = back_col; selection_menu.process_event = &selection_menu_process_events; @@ -505,5 +568,21 @@ void load_selection_menu(SDL_Renderer* renderer) selection_menu.drawable_elements[9] = &home_text->drawable_text; selection_menu_objects[9] = (void*)home_text; + anchore_point Word_List_Anchore= { + 0.05, + 0.25, + 0.55, + 0.7, + 0, + 0, + 0, + 0, + 0.0 + }; + EZ_list* word_list = EZ_create_list(Word_List_Anchore); + + selection_menu.drawable_elements[14] = &word_list->drawable_list; + selection_menu.interactible_elements[6] = &word_list->interactible_list; + selection_menu_objects[14] = (void*)word_list; } diff --git a/src/menus/selection_menu.h b/src/menus/selection_menu.h index 2847f00..f7f49c2 100644 --- a/src/menus/selection_menu.h +++ b/src/menus/selection_menu.h @@ -1,4 +1,5 @@ #include "../utils/EZ_UI/EZ_utils.h" +#include "../utils/Spliting/Spliting.h" #ifndef SELECTION_MENU_H #define SELECTION_MENU_H @@ -9,5 +10,19 @@ void load_selection_menu(SDL_Renderer* renderer); void selection_menu_enter(void); -void on_selection_menu_load(); +extern int auto_split_grid; +extern int auto_split_words; + +extern size_t grid_index; +extern pixel_cluster** cluster_splitting; +extern size_t linkage_length; +extern size_t* array_length; + +extern int grid_x, grid_y; +extern char** grid; + +extern size_t words_nb; +extern size_t* word_len; +extern char** words; + #endif diff --git a/src/utils/EZ_UI/EZ_manager.c b/src/utils/EZ_UI/EZ_manager.c index 4fd60d0..07be57d 100644 --- a/src/utils/EZ_UI/EZ_manager.c +++ b/src/utils/EZ_UI/EZ_manager.c @@ -1,5 +1,6 @@ #include #include +#include #include "EZ_utils.h" #include "EZ_manager.h" #include "../Rendering/RenderingUtils.h" @@ -101,6 +102,7 @@ void EZ_draw_menu(SDL_Window* window, SDL_Renderer* renderer) { if (!curr->drawable_elements[i]->visible) continue; + SDL_Rect dst_rect = anchore_to_rect(window, curr->drawable_elements[i]->dst_anchore); SDL_Color color = curr->drawable_elements[i]->color; SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); diff --git a/src/utils/EZ_UI/EZ_utils.h b/src/utils/EZ_UI/EZ_utils.h index e00f837..d9d555b 100644 --- a/src/utils/EZ_UI/EZ_utils.h +++ b/src/utils/EZ_UI/EZ_utils.h @@ -13,7 +13,7 @@ typedef struct SDL_Color color; char visible; void* data; - void (*on_draw)(SDL_Window* window, SDL_Renderer* renderer, void*); + void (*on_draw)(SDL_Window* window, SDL_Renderer* renderer, void* data); }EZ_DRAWABLE; typedef struct interactible diff --git a/src/utils/EZ_UI/elements/EZ_list.c b/src/utils/EZ_UI/elements/EZ_list.c index 249a6cb..80f5374 100644 --- a/src/utils/EZ_UI/elements/EZ_list.c +++ b/src/utils/EZ_UI/elements/EZ_list.c @@ -8,11 +8,14 @@ void EZ_list_draw(SDL_Window* window, SDL_Renderer* renderer, void* data) { if (p->drawable_element == NULL || !p->drawable_element->visible) continue; + SDL_Rect dst_rect = anchore_to_rect(window, p->drawable_element->dst_anchore); SDL_Color color = p->drawable_element->color; SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); if (p->drawable_element->texture != NULL) SDL_RenderCopy(renderer, p->drawable_element->texture, &p->drawable_element->src_rect, &dst_rect); + if (p->drawable_element->on_draw != NULL) + p->drawable_element->on_draw(window, renderer, p->drawable_element->data); } } @@ -81,7 +84,7 @@ void EZ_list_add_element(EZ_list* list, EZ_list_element* element) { EZ_list_element* p; - for (p = list->element_list; p; p = p->next) + for (p = list->element_list; p->next; p = p->next) {} p->next = element; @@ -103,3 +106,8 @@ void EZ_list_remove_element(EZ_list* list, EZ_list_element* element) prev = p; } } + +void EZ_list_clear(EZ_list* list) +{ + list->element_list->next = NULL; +} diff --git a/src/utils/EZ_UI/elements/EZ_list.h b/src/utils/EZ_UI/elements/EZ_list.h index c465000..efbb68c 100644 --- a/src/utils/EZ_UI/elements/EZ_list.h +++ b/src/utils/EZ_UI/elements/EZ_list.h @@ -21,6 +21,12 @@ typedef struct EZ_list_element* element_list; }EZ_list; -EZ_list* EZ_create_image(SDL_Surface* surface, SDL_Renderer* renderer, anchore_point dst_anchore, int auto_aspect); +EZ_list* EZ_create_list(anchore_point dst_anchore); + +void EZ_list_add_element(EZ_list* list, EZ_list_element* element); + +void EZ_list_remove_element(EZ_list* list, EZ_list_element* element); + +void EZ_list_clear(EZ_list* list); #endif diff --git a/src/utils/EZ_UI/elements/EZ_select_zone.c b/src/utils/EZ_UI/elements/EZ_select_zone.c new file mode 100644 index 0000000..1030ce1 --- /dev/null +++ b/src/utils/EZ_UI/elements/EZ_select_zone.c @@ -0,0 +1,45 @@ +#include +#include "EZ_select_zone.h" + +void on_select_zone_draw(SDL_Window* window, SDL_Renderer* renderer, void* data) +{ + EZ_select_zone* zone = (EZ_select_zone*)data; + + SDL_Rect rect = anchore_to_rect(window, zone->drawable_select_zone.dst_anchore); + + SDL_RenderDrawRect(renderer, &rect); +} + +EZ_select_zone* EZ_create_select_zone(anchore_point dst_anchore, SDL_Color color) +/** + * Not done yet! + */ +{ + EZ_select_zone* zone = (EZ_select_zone*)malloc(sizeof(EZ_select_zone)); + + EZ_DRAWABLE drw = { + dst_anchore, + (SDL_Rect){0,0,0,0}, + NULL, + color, + 1, + (void*)zone, + &on_select_zone_draw + }; + + zone->drawable_select_zone = drw; + zone->select_zone_anchore = dst_anchore; + zone->color = color; + + return zone; +} + +/*void EZ_move_select_zone(EZ_select_zone* select_zone, anchore_point dst_anchore) +{ + +}*/ + +/*void EZ_change_color_select_zone(EZ_select_zone* select_zone, SDL_Color color) +{ + +}*/ diff --git a/src/utils/EZ_UI/elements/EZ_select_zone.h b/src/utils/EZ_UI/elements/EZ_select_zone.h new file mode 100644 index 0000000..a5e3ac7 --- /dev/null +++ b/src/utils/EZ_UI/elements/EZ_select_zone.h @@ -0,0 +1,22 @@ +#include +#include +#include "../EZ_utils.h" +#include "../../Rendering/RenderingUtils.h" + +#ifndef EZ_SELECT_ZONE_H +#define EZ_SELECT_ZONE_H + +typedef struct +{ + EZ_DRAWABLE drawable_select_zone; + anchore_point select_zone_anchore; + SDL_Color color; +}EZ_select_zone; + +EZ_select_zone* EZ_create_select_zone(anchore_point dst_anchore, SDL_Color color); + +//void EZ_move_select_zone(EZ_select_zone* select_zone, anchore_point dst_anchore); + +//void EZ_change_color_select_zone(EZ_select_zone* select_zone, SDL_Color color); + +#endif diff --git a/src/utils/EZ_UI/elements/EZ_text_input.c b/src/utils/EZ_UI/elements/EZ_text_input.c index 7d955fe..4135299 100644 --- a/src/utils/EZ_UI/elements/EZ_text_input.c +++ b/src/utils/EZ_UI/elements/EZ_text_input.c @@ -67,6 +67,13 @@ void EZ_process_text_input(SDL_Window* window, SDL_Renderer* renderer, SDL_Event if (input->type != Decimal) return; } + else if (c == '-') + { + if (i > 0 || strlen(input->inputed_text) > 0) + return; + if (input->type != Decimal) + return; + } else { return; diff --git a/src/utils/Image/ImageUtils.c b/src/utils/Image/ImageUtils.c index 98fc47f..3813833 100644 --- a/src/utils/Image/ImageUtils.c +++ b/src/utils/Image/ImageUtils.c @@ -1,7 +1,9 @@ +#define MIN_CLUSTER_SIZE 3 #include #include #include #include "ImageUtils.h" +#include "../Spliting/Spliting.h" void render_image_file(const char* file, SDL_Renderer* renderer, const SDL_Rect* srcrect, const SDL_Rect* dstrect) @@ -478,3 +480,127 @@ SDL_Surface* resize_image(SDL_Surface* source, int new_width, int new_height) { return resized_surface; } + +int get_bin_pixel_image(SDL_Surface* surface, int x, int y) +{ + Uint8 r,g,b; + SDL_GetRGB(get_pixel_val(get_pixel_pt(surface, x, y), surface->format), surface->format, &r, &g, &b); + + int bright = (r + g + b) / 3; + + return bright < 127; +} + +void count_mini_clusters_aux(SDL_Surface* surface, int* nb_pixels, int currx, int curry, int visited[surface->w][surface->h]) +{ + visited[currx][curry] = 1; + + (*nb_pixels)++; + + for (int i = 0; i < 9; i++) + { + if (i == 4) + continue; + + int dx = (i%3) - 1; + int dy = (i/3) - 1; + + if (dx < 0 && currx <= 0) + continue; + if (dx > 0 && currx >= surface->w - 1) + continue; + if (dy < 0 && curry <= 0) + continue; + if (dy > 0 && curry >= surface->h - 1) + continue; + + if (visited[currx + dx][curry + dy]) + continue; + + if (get_bin_pixel_image(surface, currx + dx, curry + dy)) + { + count_mini_clusters_aux(surface, nb_pixels, currx + dx, curry + dy, visited); + } + } +} + +void remove_clusters_aux(SDL_Surface* surface, int currx, int curry, int visited[surface->w][surface->h]) +{ + visited[currx][curry] = 1; + + int r = 255; + int g = 255; + int b = 255; + + set_pixel_val(get_pixel_pt(surface, currx, curry), surface->format, SDL_MapRGB(surface->format, r, g, b)); + + for (int i = 0; i < 9; i++) + { + if (i == 4) + continue; + + int dx = (i%3) - 1; + int dy = (i/3) - 1; + + if (dx < 0 && currx <= 0) + continue; + if (dx > 0 && currx >= surface->w - 1) + continue; + if (dy < 0 && curry <= 0) + continue; + if (dy > 0 && curry >= surface->h - 1) + continue; + + if (visited[currx + dx][curry + dy]) + continue; + + if (get_bin_pixel_image(surface, currx + dx, curry + dy)) + { + remove_clusters_aux(surface, currx + dx, curry + dy, visited); + } + } +} + +void remove_mini_clusters(SDL_Surface* surface) +{ + int visited[surface->w][surface->h]; + + for (int y = 0; y < surface->h; y++) + { + for (int x = 0; x < surface->w; x++) + { + visited[x][y] = 0; + } + } + + int removed_pixels[surface->w][surface->h]; + + for (int y = 0; y < surface->h; y++) + { + for (int x = 0; x < surface->w; x++) + { + removed_pixels[x][y] = 0; + } + } + + for (int y = 0; y < surface->h; y++) + { + for (int x = 0; x < surface->w; x++) + { + if (visited[x][y]) + continue; + + if (!get_bin_pixel_image(surface, x, y)) + continue; + + int nb_pixels = 0; + + count_mini_clusters_aux(surface, &nb_pixels, x, y, visited); + + if (nb_pixels < MIN_CLUSTER_SIZE) + { + remove_clusters_aux(surface, x, y, removed_pixels); + } + } + } +} diff --git a/src/utils/Image/ImageUtils.h b/src/utils/Image/ImageUtils.h index 6067c6c..09d7933 100644 --- a/src/utils/Image/ImageUtils.h +++ b/src/utils/Image/ImageUtils.h @@ -43,4 +43,6 @@ double* image_to_bool_array(const char* file, size_t* image_len); SDL_Surface* resize_image(SDL_Surface* source, int new_width, int new_height); +void remove_mini_clusters(SDL_Surface* surface); + #endif diff --git a/src/utils/Spliting/Spliting.c b/src/utils/Spliting/Spliting.c index efbd215..8258d8e 100644 --- a/src/utils/Spliting/Spliting.c +++ b/src/utils/Spliting/Spliting.c @@ -1,3 +1,4 @@ +#define SPLITTING_LINKAGE_MARGIN 0.25 #define _GNU_SOURCE #include #include @@ -814,8 +815,6 @@ void get_cluster_linkage_aux(pixel_cluster* clusters, size_t start, size_t clust pixel_cluster* get_cluster_linkage(pixel_cluster* clusters, size_t start, size_t cluster_nb, size_t* linkage_nb, int visited[cluster_nb]) { - double margin = 0.2; - int center_x, center_y; get_cluster_center(clusters[start], ¢er_x, ¢er_y); @@ -850,7 +849,7 @@ pixel_cluster* get_cluster_linkage(pixel_cluster* clusters, size_t start, size_t visited_copy[i] = visited[i]; } - get_cluster_linkage_count_aux(clusters, start, cluster_nb, linkage_nb, min_distance, margin, visited_copy); + get_cluster_linkage_count_aux(clusters, start, cluster_nb, linkage_nb, min_distance, SPLITTING_LINKAGE_MARGIN, visited_copy); pixel_cluster* linkage = calloc(*linkage_nb, sizeof(pixel_cluster)); @@ -858,7 +857,7 @@ pixel_cluster* get_cluster_linkage(pixel_cluster* clusters, size_t start, size_t size_t linkage_count = 1; - get_cluster_linkage_aux(clusters, start, cluster_nb, &linkage_count, linkage, min_distance, margin, visited); + get_cluster_linkage_aux(clusters, start, cluster_nb, &linkage_count, linkage, min_distance, SPLITTING_LINKAGE_MARGIN, visited); return linkage; } @@ -1049,7 +1048,7 @@ SDL_Rect get_grid_rect(pixel_cluster* linkages, size_t nb_linkages) return (SDL_Rect){ x, y, - max_x, - max_y + max_x - x, + max_y - y }; }