From: randy Date: Thu, 21 Sep 2023 17:35:17 +0000 (-0500) Subject: Proper HSV->RGB conversion, HSL slider, preview window, and some controls X-Git-Url: http://git.mcshandy.xyz/gitweb.cgi?a=commitdiff_plain;h=0dc72da907ff5d81850885731b116dca739a5fa4;p=picker Proper HSV->RGB conversion, HSL slider, preview window, and some controls --- diff --git a/source/main.c b/source/main.c index 6440aad..c9df6ae 100644 --- a/source/main.c +++ b/source/main.c @@ -18,33 +18,25 @@ int init() signal(SIGKILL, killterm_handler); signal(SIGTERM, killterm_handler); - gi.window = (Rect){.x = 0.0f, .y = 0.0f, .w = 512.0f, .h = 512.0f}; + gi.window = (Rect){.x = 0.0f, .y = 0.0f, .w = 2*512.0f, .h = 2*512.0f}; + // satisfying rel.[xy]*2 == .[wh] centers axis in parent container gi.rgb_square.rel = (Rect){.x = 0.05, .y = 0.05, .w = 0.5, .h = 0.5}; gi.hue_slider.rel = (Rect){.x = 0.65, .y = 0.05, .w = .08, .h = 0.5}; gi.final_sample.rel = (Rect){.x = 0.05, .y = .65, .w = 0.20, .h = 0.20}; - gi.info_container.rel = (Rect){.x = 0.05, .y = .65, .w = .9, .h = .30}; gi.info_boxes.rel = (Rect){.x = .25, .y = 0.00, .w = 0.75, .h = 1.00}; - gi.rgb_info.rel = (Rect){.x = 0.00, .y = 0.00, .w = 1.00, .h = 0.50}; gi.red.rel = (Rect){.x = 0.00, .y = 0.00, .w = 0.30, .h = 1.00}; gi.green.rel = (Rect){.x = 0.35, .y = 0.00, .w = 0.30, .h = 1.00}; gi.blue.rel = (Rect){.x = 0.70, .y = 0.00, .w = 0.30, .h = 1.00}; - gi.hsl_info.rel = (Rect){.x = 0.00, .y = 0.50, .w = 1.00, .h = 0.50}; gi.hue.rel = (Rect){.x = 0.00, .y = 0.00, .w = 0.30, .h = 1.00}; gi.saturation.rel = (Rect){.x = 0.35, .y = 0.00, .w = 0.30, .h = 1.00}; gi.luminence.rel = (Rect){.x = 0.70, .y = 0.00, .w = 0.30, .h = 1.00}; - // lime (120 100 50) - > (0 255 0) - gi.active_hsv = (HSL_Color){.h = 120, .s = 100, .l = 50}; - - // silver (0 0 75) - > (0 255 0) - gi.active_hsv = (HSL_Color){.h = 0, .s = 0, .l = 75}; - - Color rgb = hsl_to_rgb(gi.active_hsv); - printf("%d %d %d\n", rgb.r, rgb.g, rgb.b); + gi.active_hsl = (HSL_Color){.h = 0, .s = 100, .l = 50}; + gi.active_rgb = hsl_to_rgb(gi.active_hsl); init_renderer(&gi); @@ -53,16 +45,6 @@ int init() return 0; }; -int handle_collisions(Game_Info* gi) -{ -} - -int game_loop(Game_Info* gi, float time_step) -{ - - return 0; -} - int main(void) { int quit = 0; @@ -80,7 +62,6 @@ int main(void) clock_gettime(CLOCK_MONOTONIC_RAW, &ts_start); check_inputs(&gi); - game_loop(&gi, time_step); display(&gi); clock_gettime(CLOCK_MONOTONIC_RAW, &ts_end); diff --git a/source/sdl/SDL_Utils.c b/source/sdl/SDL_Utils.c index 9083746..11335fd 100644 --- a/source/sdl/SDL_Utils.c +++ b/source/sdl/SDL_Utils.c @@ -7,6 +7,13 @@ #define unroll_sdl_color(color) color.r, color.g, color.b, color.a #define lineColorFPoints(r, a, b, c) lineColor(r, a.x - camera_offset.x, a.y - camera_offset.y, b.x - camera_offset.x, b.y - camera_offset.y, c) +SDL_Color red = {255, 0, 0, 255}; +SDL_Color green = {0, 255, 0, 255}; +SDL_Color blue = {0, 0, 255, 255}; +SDL_Color black = {0, 0, 0, 255}; +SDL_Color white = {255, 255, 255, 255}; +SDL_Color magenta = {255, 0, 255, 255}; + sdl_group mgr; const int keypress_delta = 4; @@ -66,15 +73,42 @@ int32_t render_rgb_square(Game_Info* gi) return 0; } +int32_t render_solid_color(Game_Info* gi, SDL_FRect* container, SDL_Color color) +{ + SDL_SetRenderDrawColor(mgr.rend, unroll_sdl_color(color)); + SDL_RenderFillRectF(mgr.rend, container); + + return 0; +} + +int32_t render_vertical_hue_spectrum(Game_Info* gi, SDL_FRect* container) +{ + + int hue_slice_scale = container->h; + float hue_slice_height = hue_slice_scale/360.0f; + + int bar_y = gi->active_hsl.h/360.0f*container->h + container->y; + SDL_SetRenderDrawColor(mgr.rend, unroll_sdl_color(black)); + SDL_RenderDrawLine(mgr.rend, container->x-16, bar_y, container->w+container->x+16, bar_y); + + for (int n = 0; n < (int)container->h; n++) + { + HSL_Color slice_hsl = {((float)n/(float)container->h) * 360, 100, 50}; + SDL_Color slice_color = hsl_to_rgb (slice_hsl); + + SDL_SetRenderDrawColor(mgr.rend, unroll_sdl_color(slice_color)); + SDL_RenderDrawLine(mgr.rend, container->x, container->y + n, container->w+container->x, container->y+n); + } + + return 0; +} + // REALLY this should be "generate layout", and not a true rendering step +// For now just do the math and color the full space of the child int32_t render_container(Game_Info* gi, SDL_FRect* parent, Layout_Rect* child, SDL_Color color) { SDL_SetRenderDrawColor(mgr.rend, unroll_sdl_color(color)); child->real = fr_margin_adjust(*parent, child->rel); - - // replace this with corresponding item's callback - // hmm maybe that can be wedged into the layout_rect? - // nahhhh SDL_RenderFillRectF(mgr.rend, &child->real); return 0; @@ -82,35 +116,32 @@ int32_t render_container(Game_Info* gi, SDL_FRect* parent, Layout_Rect* child, S int32_t display(Game_Info* gi) { - SDL_Color red = {255, 0, 0, 255}; - SDL_Color green = {0, 255, 0, 255}; - SDL_Color blue = {0, 0, 255, 255}; - SDL_Color black = {0, 0, 0, 255}; - SDL_Color white = {255, 255, 255, 255}; - SDL_Color magenta = {255, 0, 255, 255}; - - // This is kinda the important stuff - SDL_RenderPresent(mgr.rend); SDL_SetRenderDrawColor(mgr.rend, 0xCB, 0xCB, 0xCB, 0xCB); SDL_RenderClear(mgr.rend); + gi->active_rgb = hsl_to_rgb(gi->active_hsl); + // this would be really cool to turn into some stack-based type of thing + // Also, if resizing is disabled, this can be moved to a static initialization section render_container(gi, &gi->window, &gi->rgb_square, green); render_container(gi, &gi->window, &gi->hue_slider, green); render_container(gi, &gi->window, &gi->info_container, blue); - render_container(gi, &gi->window, &gi->final_sample, green); - - render_container(gi, &gi->info_container.real, &gi->info_boxes, green); - render_container(gi, &gi->info_boxes.real, &gi->rgb_info, black); - render_container(gi, &gi->info_boxes.real, &gi->hsl_info, white); + render_container(gi, &gi->window, &gi->final_sample, green); + render_container(gi, &gi->info_container.real, &gi->info_boxes, green); + render_container(gi, &gi->info_boxes.real, &gi->rgb_info, black); + render_container(gi, &gi->rgb_info.real, &gi->red, red); + render_container(gi, &gi->rgb_info.real, &gi->green, green); + render_container(gi, &gi->rgb_info.real, &gi->blue, blue); + render_container(gi, &gi->info_boxes.real, &gi->hsl_info, white); + render_container(gi, &gi->hsl_info.real, &gi->hue, green); + render_container(gi, &gi->hsl_info.real, &gi->saturation, blue); + render_container(gi, &gi->hsl_info.real, &gi->luminence, red); + + render_solid_color(gi, &gi->final_sample.real, gi->active_rgb); + render_vertical_hue_spectrum(gi, &gi->hue_slider.real); - render_container(gi, &gi->rgb_info.real, &gi->red, red); - render_container(gi, &gi->rgb_info.real, &gi->green, green); - render_container(gi, &gi->rgb_info.real, &gi->blue, blue); - - render_container(gi, &gi->hsl_info.real, &gi->hue, green); - render_container(gi, &gi->hsl_info.real, &gi->saturation, blue); - render_container(gi, &gi->hsl_info.real, &gi->luminence, red); + // This is kinda the important stuff + SDL_RenderPresent(mgr.rend); return 0; } @@ -118,11 +149,23 @@ int32_t check_inputs(Game_Info* gi) { while(SDL_PollEvent(&(mgr.event))) { - // wasd movement and quitting + if (mgr.event.type == SDL_KEYDOWN) { - if (mgr.event.type == SDL_KEYDOWN && mgr.event.key.keysym.sym == SDLK_q) + switch(mgr.event.key.keysym.sym) { - gi->game_alive = 0; + case SDLK_q: + gi->game_alive = 0; + break; + case SDLK_j: + gi->active_hsl.h += 1; + if(gi->active_hsl.h > 360) + gi->active_hsl.h -= 360; + break; + case SDLK_k: + gi->active_hsl.h -= 1; + if(gi->active_hsl.h < 0) + gi->active_hsl.h += 360; + break; } } } @@ -182,61 +225,23 @@ SDL_FRect fr_margin_adjust(const SDL_FRect parent, const Relative_Rect child) }; } -// https://www.rapidtables.com/convert/color/hsl-to-rgb.html -SDL_Color hsl_to_rgb (const HSL_Color hsl) +float hsl_to_rgb_alt_internal(const HSL_Color hsl, int n) { - float C, X, m; - float rP, gP, bP; - - float h = fmod(hsl.h, 360.0); - float s = hsl.s/100.0f; - float l = hsl.l/100.0f; - - C = (1 - abs((2*(l)) - 1)) * s; - X = C * (1 - abs(fmod(h/60, 2.0f) -1)); - m = l - (C/2.0); - - - if (h >= 0 && h <= 60) - { - rP = C; - gP = X; - bP = 0; - } - else if (h >= 60 && h <= 120) - { - rP = X; - gP = C; - bP = 0; - } - else if (h >= 120 && h <= 180) - { - rP = 0; - gP = C; - bP = X; - } - else if (h >= 180 && h <= 240) - { - rP = 0; - gP = X; - bP = C; - } - else if (h >= 240 && h <= 300) - { - rP = X; - gP = 0; - bP = C; - } - else if (h >= 300 && h <= 360) - { - rP = C; - gP = 0; - bP = X; - } + float H = (float)hsl.h; + float L = (float)hsl.l/100.0f; + float S = (float)hsl.s/100.0f; + float a = S * MIN(L, 1-L); + float k = fmod((n + (H/30.0)), 12.0); + return L - a * MAX(-1, MIN(k-3, MIN(9-k, 1))); +} +// https://www.wikiwand.com/en/HSL_and_HSV#To_RGB +SDL_Color hsl_to_rgb (const HSL_Color hsl) +{ return (SDL_Color){ - (rP + m) * 255, - (gP + m) * 255, - (bP + m) * 255}; + .r = (uint8_t)(hsl_to_rgb_alt_internal(hsl, 0) * 255), + .g = (uint8_t)(hsl_to_rgb_alt_internal(hsl, 8) * 255), + .b = (uint8_t)(hsl_to_rgb_alt_internal(hsl, 4) * 255), + .a = 0xFF}; // Opaque } diff --git a/source/sdl/SDL_Utils.h b/source/sdl/SDL_Utils.h index ddd2520..7631c08 100644 --- a/source/sdl/SDL_Utils.h +++ b/source/sdl/SDL_Utils.h @@ -24,5 +24,6 @@ SDL_FRect fr_subtract(const SDL_FRect left, const SDL_FRect right); SDL_FRect fr_mult(const SDL_FRect left, const SDL_FRect right); SDL_FRect fr_margin_adjust(const SDL_FRect parent, const Relative_Rect child); SDL_Color hsl_to_rgb (const HSL_Color hsl); +SDL_Color wikipedia_hsl_to_rgb (const HSL_Color hsl); #endif // SDL_Utils__ diff --git a/source/structs.h b/source/structs.h index 894ed70..367ccc2 100644 --- a/source/structs.h +++ b/source/structs.h @@ -32,7 +32,7 @@ typedef struct { // Internet says hue likes to go 0-360 // Saturation and luminence are 0-100 - uint16_t h; + int16_t h; uint8_t s; uint8_t l; uint8_t a; @@ -67,7 +67,7 @@ typedef struct Color active_rgb; // Hue value should correspond to value on HSV slider - HSL_Color active_hsv; + HSL_Color active_hsl; int game_alive;