sav

Sorting Algorithms Visualized
Index Commits Files Refs README LICENSE
commit 7491aa0aa7c06193a1d76d9e66dbf097958c923c
parent 30bbcbddd51b0668622d4ab6049fb5d4643b156f
Author: klewer-martin <martin.cachari@gmail.com>
Date:   Mon, 11 Apr 2022 19:29:35 -0300

Fixed SIGSEV, added responsize window resize, added restart function

the SIGSEV was caused by the computed values of window width & height,
the solution was to put default values in case SDL_GetWindowSize()
failed.

Also the 'R' key now behaves as restart function when the algorithms
ends

Diffstat:
MMakefile | 2+-
Mdrw.c | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mdrw.h | 12++++++++++--
Mmain.c | 28++++++++++++++++++++++------
Msav.c | 2++
Msdl_extra.c | 56++++++++++++++++++++++++++++++++++++--------------------
Msdl_extra.h | 4+++-
Mutil.h | 6+++++-
8 files changed, 137 insertions(+), 54 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,6 +1,6 @@
 CC := cc
 CLIBS := `sdl2-config --libs --cflags`
-CFLAGS := -lSDL2_ttf -lm -Werror -Wall -pedantic -ansi -std=c99 -g -pthread
+CFLAGS := -lSDL2_ttf -lm -Werror -pedantic -ansi -std=c99 -g -pthread
 SRCS := main.c sav.c util.c sort.c drw.c sdl_extra.c
 OBJS := $(SRCS:.c=.o)
 
diff --git a/drw.c b/drw.c
@@ -1,12 +1,12 @@
 #include "drw.h"
 
 void
-drw_element_color(SDL_Renderer *rend, int x, int y, int h, unsigned int col) {
+drw_element_color(Drw *drw, int x, int y, int h, unsigned int col) {
     SDL_Rect rect;
     unsigned char r, g, b, a;
 
-    rect.x = x + X_BORDER; /* bottom left + x */
-    rect.y = y - Y_BORDER; /* bottom */
+    rect.x = x + drw->x_border; /* bottom left + x */
+    rect.y = y - drw->y_border; /* bottom */
     rect.w = RECT_WIDTH; /* fixed width */
     rect.h = -h;
 
@@ -15,12 +15,12 @@ drw_element_color(SDL_Renderer *rend, int x, int y, int h, unsigned int col) {
     b = (char)(col >> 8) & 0xFF;
     a = (char)(col) & 0xFF;
 
-    SDL_RenderDrawRect(rend, &rect);
-    SDL_SetRenderDrawColor(rend, r, g, b, a);
-    SDL_RenderFillRect(rend, &rect);
+    SDL_RenderDrawRect(drw->rend, &rect);
+    SDL_SetRenderDrawColor(drw->rend, r, g, b, a);
+    SDL_RenderFillRect(drw->rend, &rect);
 
-    SDL_SetRenderDrawColor(rend, 0, 0, 0, 0);
-    SDL_RenderDrawLine(rend, x + X_BORDER, y - Y_BORDER, x + X_BORDER, y - Y_BORDER - h);
+    SDL_SetRenderDrawColor(drw->rend, 0, 0, 0, 0);
+    SDL_RenderDrawLine(drw->rend, x + drw->x_border, y - drw->y_border, x + drw->x_border, y - drw->y_border - h);
 }
 
 void
@@ -34,9 +34,9 @@ drw_array_graph(Drw *drw, SAV *sav) {
 
     size_t i;
     for(i = x = 0; i < sav->arr->len; i++, x += RECT_WIDTH) {
-        if(i == sav->sel) drw_element_color(drw->rend, x, h, sav->arr->v[i], SEL_COLOR);
-        else if(i == sav->cmp) drw_element_color(drw->rend, x, h, sav->arr->v[i], CMP_COLOR);
-        else drw_element_color(drw->rend, x, h, sav->arr->v[i], NORM_COLOR);
+        if(i == sav->sel) drw_element_color(drw, x, h, sav->arr->v[i], SEL_COLOR);
+        else if(i == sav->cmp) drw_element_color(drw, x, h, sav->arr->v[i], CMP_COLOR);
+        else drw_element_color(drw, x, h, sav->arr->v[i], NORM_COLOR);
     }
     drw_status_bar(drw, sav);
 }
@@ -52,33 +52,41 @@ drw_status_bar(Drw *drw, SAV *sav) {
     rect.h = -BAR_HEIGHT;
 
     SDL_RenderDrawRect(drw->rend, &rect);
+
+    /* TODO: Make a variable to store statusbar background color */
     SDL_SetRenderDrawColor(drw->rend, 0, 0, 0, 0); /* RGBA */
     SDL_RenderFillRect(drw->rend, &rect);
 
-    char status_text[drw-> w / drw->font_size];
+    if(sav->status == UPDATE) {
+        /* sprintf(drw->bar_text, "Press SPACE to start sorting the array or ESC/q to quit"); */
+        snprintf(drw->bar_text, drw->bar_text_len - 2,
+                "SORTING (%s sort)     L: %ld, C: %ld, S: %ld, I: %ld", 
+                algo_strings[sav->sel_algo], sav->arr->len, sav->cmps,
+                sav->swps, sav->its);
 
-    if((sav->status == RUN) || (sav->status == UPDATE)) {
-        /* sprintf(status_text, "Press SPACE to start sorting the array or ESC/q to quit"); */
-        sprintf(status_text, "SORTING (%s sort)     L: %ld, C: %ld, S: %ld, I: %ld", 
-                algo_strings[sav->sel_algo], sav->arr->len, sav->cmps, sav->swps, sav->its);
-        drw_text(drw, status_text, 0, drw->h - drw->font_size - 5);
+        drw_text(drw, drw->bar_text, 0, drw->h - drw->font_size - 5);
     } else if(sav->status == SORTED) {
-        sprintf(status_text, "SORTED (%s sort) done in %.2fs, L: %ld, C: %ld, S: %ld, I: %ld",
+        snprintf(drw->bar_text, drw->bar_text_len - 2,
+                "SORTED (%s sort) done in %.2fs, L: %ld, C: %ld, S: %ld, I: %ld",
                 algo_strings[sav->sel_algo],
                 (double)(sav->tf - sav->ti) / CLOCKS_PER_SEC,
                 sav->arr->len, sav->cmps, sav->swps, sav->its);
 
-        drw_text(drw, status_text, 0, drw->h - drw->font_size - 5);
+        drw_text(drw, drw->bar_text, 0, drw->h - drw->font_size - 5);
     }
+    memset(drw->bar_text, 0, sizeof(char) * drw->bar_text_len);
 }
 
 void drw_text(Drw *drw, char *text, int x, int y) {
     drw->text_surface = TTF_RenderText_Blended(drw->font, text, drw->text_color);
     drw->text_texture = SDL_CreateTextureFromSurface(drw->rend, drw->text_surface);
 
-    SDL_Rect text_rect = { 10 + x, drw->h - drw->font_size - 5, drw->text_surface->w, drw->text_surface->h };
+    drw->bar_text_rect.x = 10 + x;
+    drw->bar_text_rect.y = drw->h - drw->font_size - 5;
+    drw->bar_text_rect.w = drw->text_surface->w;
+    drw->bar_text_rect.h = drw->text_surface->h;
 
-    SDL_RenderCopy(drw->rend, drw->text_texture, NULL, &text_rect);
+    SDL_RenderCopy(drw->rend, drw->text_texture, NULL, &drw->bar_text_rect);
 }
 
 status_t DRW_New(SDL_Renderer *rend, SDL_Window *win, Drw **drw) {
@@ -87,12 +95,18 @@ status_t DRW_New(SDL_Renderer *rend, SDL_Window *win, Drw **drw) {
 
     TTF_Font *font = TTF_OpenFont(FONT_NAME, FONT_SIZE);
 
-    if(!font) fprintf(stderr, "TTF_OpenFont: %s\n", TTF_GetError());
+    if(!font) {
+        fprintf(stderr, "TTF_OpenFont: %s\n", TTF_GetError());
+        return ERROR_OPENING_FONT;
+    }
 
     (*drw)->rend = rend;
     (*drw)->win = win;
     (*drw)->font = font;
     (*drw)->font_size = FONT_SIZE;
+    (*drw)->bar_border = 2;
+    (*drw)->x_border = X_BORDER;
+    (*drw)->y_border = Y_BORDER;
 
     (*drw)->text_color.r = (char)(FONT_COLOR >> 16) & 0xFF;
     (*drw)->text_color.g = (char)(FONT_COLOR >> 8) & 0xFF;
@@ -100,10 +114,31 @@ status_t DRW_New(SDL_Renderer *rend, SDL_Window *win, Drw **drw) {
 
     SDL_GetWindowSize(win, &((*drw)->w), &((*drw)->h));
 
-    return 0;
+    (*drw)->bar_rect.x = (*drw)->bar_border; /* top left + x */
+    (*drw)->bar_rect.y = (*drw)->h - (*drw)->bar_border; /* top left + y, (y < 0) */
+    (*drw)->bar_rect.w = (*drw)->w - (2 * (*drw)->bar_border); /* fixed width */
+    (*drw)->bar_rect.h = -BAR_HEIGHT;
+
+    /* sometimes SDL_GetWindowSize() fails */
+    if((*drw)->w < WIN_MIN_W)
+        (*drw)->w = WIN_MIN_W;
+    else if((*drw)->h < WIN_MIN_H)
+        (*drw)->h = WIN_MIN_H;
+
+    (*drw)->bar_text_len = (*drw)->w / (*drw)->font_size;
+    (*drw)->bar_text = (char *)malloc(sizeof(char) * (*drw)->bar_text_len);
+    if((*drw)->bar_text == NULL) return ERROR_MEMORY_ALLOC;
+
+    (*drw)->text_surface = NULL;
+    (*drw)->text_texture = NULL;
+
+    return OK;
 }
 
 void DRW_Destroy(Drw *drw) {
+    if(drw == NULL) return;
+
     TTF_CloseFont(drw->font);
+    free(drw->bar_text);
     free(drw);
 }
diff --git a/drw.h b/drw.h
@@ -19,21 +19,29 @@
 
 #define BAR_HEIGHT    14
 
+#define WIN_MIN_W    800
+#define WIN_MIN_H    600
+
+#define WINDOW_TITLE "SAV - Sorting Algorithms Visualized"
+
 typedef struct {
     SDL_Renderer *rend;
     SDL_Window *win;
     SDL_Surface *text_surface;
     SDL_Texture *text_texture;
     SDL_Color text_color;
+    SDL_Rect bar_rect, bar_text_rect;
     TTF_Font *font;
-    int w, h, font_size;
+    int w, h, font_size, bar_text_len, bar_border;
+    size_t x_border, y_border;
+    char *bar_text;
 } Drw;
 
 status_t DRW_New(SDL_Renderer *rend, SDL_Window *win, Drw **drw);
 void DRW_Destroy(Drw *drw);
 
 void drw_element(SDL_Renderer *rend, int x, int y, int h);
-void drw_element_color(SDL_Renderer *rend, int x, int y, int h, unsigned int col);
+void drw_element_color(Drw *drw, int x, int y, int h, unsigned int col);
 void drw_array_graph(Drw *drw, SAV *sav);
 void drw_status_bar(Drw *drw, SAV *sav);
 void drw_text(Drw *drw, char *text, int x, int y);
diff --git a/main.c b/main.c
@@ -29,6 +29,13 @@ routine_wrapper(void *arg) {
     return NULL;
 }
 
+void
+shuffle(Arr *arr) {
+    srand((unsigned int)time(NULL));
+    for(size_t i = 0; i < arr->len; i++)
+        while(!(arr->v[i] = rand() % ARR_MAX));
+}
+
 int
 main (void) {
     SAV *sav;
@@ -37,16 +44,15 @@ main (void) {
     SDL_Window *win;
 
     pthread_t p1;
+    status_t st;
 
     setup(&win, &rend);
 
-    SAV_New(&sav);
-    DRW_New(rend, win, &drw);
+    if((st = SAV_New(&sav)) != OK) goto end;
+    if((st = DRW_New(rend, win, &drw)) != OK) goto end;
 
     /* assigns random values to array */
-    srand((unsigned int)time(NULL));
-    for(size_t i = 0; i < sav->arr->len; i++)
-        while(!(sav->arr->v[i] = rand() % ARR_MAX));
+    shuffle(sav->arr);
 
     /* start sorting thread */
     pthread_create(&p1, NULL, &routine_wrapper, (void *)sav);
@@ -56,18 +62,28 @@ main (void) {
 
     /* main loop */
     while(sav->status != STOP) {
-        check_events(&(sav->status)); 
+        check_events(drw, sav);
         if(sav->status == UPDATE) {
             drw_array_graph(drw, sav);
             sav->status = RUN;
             SDL_RenderPresent(rend);
         }
         if(sav->status == SORTED) {
+            /* p1 ended */
             drw_array_graph(drw, sav);
             SDL_RenderPresent(rend);
         }
+        if(sav->status == RESTART) {
+            /* this state can only be achived if p1 ended */
+            shuffle(sav->arr);
+            sav->status = RUN;
+
+            /* let's call p1 again */
+            pthread_create(&p1, NULL, &routine_wrapper, (void *)sav);
+        }
     }
 
+end:
     pthread_join(p1, NULL);
 
     SAV_Destroy(sav);
diff --git a/sav.c b/sav.c
@@ -29,6 +29,8 @@ status_t SAV_New(SAV **sav) {
 }
 
 void SAV_Destroy(SAV *sav) {
+    if(sav == NULL) return;
+
     free(sav->arr->v);
     free(sav->arr);
     free(sav);
diff --git a/sdl_extra.c b/sdl_extra.c
@@ -1,27 +1,42 @@
 #include "sdl_extra.h"
 
-#define WINDOW_TITLE "SAV - Sorting Algorithms Visualized"
-
 void
-check_events(status_t *status) {
+check_events(Drw *drw, SAV *sav) {
     SDL_Event event;
     while (SDL_PollEvent(&event)) {
         switch(event.type) {
-        case SDL_QUIT: *status = STOP; break;
-        /* case SDL_KEYDOWN: */
-        /*     switch(event.key.keysym.scancode) { */
-        /*     case SDL_SCANCODE_EQUALS: */ 
-        /*         if(speed > SPEED_MAX) speed -= SPEED_STEP; */
-        /*         break; */
-        /*     case SDL_SCANCODE_MINUS: */
-        /*         if(speed < SPEED_MIN) speed += SPEED_STEP; */
-        /*         break; */
-        /*     case SDL_SCANCODE_P: */
-        /*         if(status == PAUSE) *status = RUN; */
-        /*         else *status = PAUSE; */
-        /*         break; */
-        /*     default: break; */
-        /*    } */
+        case SDL_QUIT: sav->status = STOP; break;
+        case SDL_KEYDOWN:
+            switch(event.key.keysym.scancode) {
+            /* case SDL_SCANCODE_EQUALS: */ 
+            /*     if(speed > SPEED_MAX) speed -= SPEED_STEP; */
+            /*     break; */
+            /* case SDL_SCANCODE_MINUS: */
+            /*     if(speed < SPEED_MIN) speed += SPEED_STEP; */
+            /*     break; */
+            /* case SDL_SCANCODE_P: */
+            /*     if(status == PAUSE) *status = RUN; */
+            /*     else *status = PAUSE; */
+            /*     break; */
+            case SDL_SCANCODE_R:
+                if(sav->status == SORTED) sav->status = RESTART;
+                else break;
+            default: break;
+           }
+        case SDL_WINDOWEVENT:
+            switch(event.window.event) {
+            case SDL_WINDOWEVENT_RESIZED:
+                SDL_Log("Window resized to %dx%d", event.window.data1, event.window.data2);
+                drw->w = event.window.data1;
+                drw->h = event.window.data2;
+
+                /* set new window borders */
+                drw->x_border = (drw->w / 2) - ((sav->arr->len * RECT_WIDTH) / 2);
+                drw->y_border = (drw->h / 2) - (ARR_MAX / 2);
+
+                break;
+            default: break;
+           }
         default: break;
         }
     }
@@ -39,7 +54,7 @@ setup(SDL_Window **win, SDL_Renderer **rend) {
         SDL_WINDOWPOS_UNDEFINED,
         0,
         0,
-        SDL_WINDOW_OPENGL
+        SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY
     );
 
     *rend = SDL_CreateRenderer(*win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
@@ -49,6 +64,7 @@ setup(SDL_Window **win, SDL_Renderer **rend) {
         exit(2);
     }
 
+    /* TODO: return error codes */
     if (*win == NULL) end("SDL: window cannot be created");
     else if (*rend == NULL) end("SDL: renderer cannot be created");
 
@@ -61,7 +77,7 @@ setup(SDL_Window **win, SDL_Renderer **rend) {
     min_h = ((ARR_MAX) + (2 * Y_BORDER) + TOP_BORDER);
 
     SDL_SetWindowMinimumSize(*win, min_w, min_h);
-    SDL_SetWindowMaximumSize(*win, min_w, min_h);
+    /* SDL_SetWindowMaximumSize(*win, min_w, min_h); */
 }
 
 void
diff --git a/sdl_extra.h b/sdl_extra.h
@@ -15,8 +15,10 @@
 /* } Sav; */
 
 #include "util.h"
+#include "drw.h"
 
-void check_events(status_t *status);
+/* void check_events(status_t *status); */
+void check_events(Drw *drw, SAV *sav);
 void setup(SDL_Window **win, SDL_Renderer **rend);
 void cleanup(SDL_Window *win, SDL_Renderer *rend);
 
diff --git a/util.h b/util.h
@@ -4,7 +4,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#define ARR_LEN        150
+#define ARR_LEN        120
 #define ARR_MAX        500
 
 #define X_BORDER    40
@@ -14,11 +14,15 @@
 #define RECT_WIDTH    6    
 
 typedef enum {
+    OK = 0,
     RUN,
     PAUSE,
     UPDATE,
     ERROR_MEMORY_ALLOC,
+    ERROR_OPENING_FONT,
+    ERROR_DRW,
     SORTED,
+    RESTART,
     STOP
 } status_t;