]> git.mcshandy.xyz Git - picker/commitdiff
Initial commit - beginnings of layout-based rendering, and RGB/HSL handling
authorrandy <randy@mcshandy.xyz>
Thu, 21 Sep 2023 02:21:24 +0000 (21:21 -0500)
committerrandy <randy@mcshandy.xyz>
Thu, 21 Sep 2023 02:21:24 +0000 (21:21 -0500)
Makefile [new file with mode: 0755]
project.vim [new file with mode: 0644]
source/Math_Utils.c [new file with mode: 0644]
source/Math_Utils.h [new file with mode: 0644]
source/main.c [new file with mode: 0644]
source/sdl/SDL_Utils.c [new file with mode: 0644]
source/sdl/SDL_Utils.h [new file with mode: 0644]
source/structs.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100755 (executable)
index 0000000..a947fbb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+LIBS := -lX11 -lm
+SOURCES := $(wildcard source/*.c)
+SDL_SOURCES := $(wildcard source/sdl/*.c)
+IMGUI_SOURCES = imgui/imgui.cpp imgui/imgui_impl_sdl.cpp imgui/imgui_impl_sdlrenderer.cpp imgui/imgui_tables.cpp imgui/imgui_widgets.cpp imgui/imgui_draw.cpp
+
+sdl: source/*.c source/*.h source/sdl/*.c source/sdl/*.h
+       gcc -DBUILD_SDL=1 $(SDL_SOURCES) $(SOURCES) $(LIBS) -lSDL2 -lSDL2_gfx -o bin/$@
+
+d_sdl: source/*.c source/*.h source/sdl/*.c source/sdl/*.h
+       gcc -g -DBUILD_SDL=1 $(SDL_SOURCES) $(SOURCES) $(LIBS) -lSDL2 -lSDL2_gfx -o bin/$@
diff --git a/project.vim b/project.vim
new file mode 100644 (file)
index 0000000..91cbb00
--- /dev/null
@@ -0,0 +1,28 @@
+let prj_base = expand('%:p:h')
+let build = prj_base . '/bin/sdl'
+let run_build  = "!" . build . " -nop"
+
+nmap \m :wa \| :make! sdl \| execute run_build<CR>
+nmap \d :wa \| :make! d_sdl
+
+" https://stackoverflow.com/questions/37552913/vim-how-to-keep-folds-on-save
+" Save folds between vim sessions
+augroup remember_folds
+       autocmd!
+       autocmd BufWinLeave * mkview
+       autocmd BufWinEnter * silent! loadview
+augroup END
+
+" start up a faux-IDE view
+command! Ide call s:ide()
+function! s:ide()
+       execute("sp")
+       execute("\<C-w\>J")
+       execute("resize 10")
+       execute("term")
+       execute("NERDTreeToggle")
+endfunction
+
+let $src=prj_base.'/source'
+let $sdl=$src.'/source/sdl'
+let $bin=prj_base.'/bin'
diff --git a/source/Math_Utils.c b/source/Math_Utils.c
new file mode 100644 (file)
index 0000000..847d8b9
--- /dev/null
@@ -0,0 +1,58 @@
+#include "Math_Utils.h"
+#include <math.h>
+
+FPoint rotate(float theta, FPoint* vec)
+{
+       return (FPoint){vec->x * cos(theta) - vec->y * sin(theta),
+                                                                       vec->x * sin(theta) + vec->y * cos(theta)};
+}
+
+// root of sum of squared components
+float magnitude(FPoint* vec)
+{
+       return sqrtf(pow(vec->x,2) + pow(vec->y, 2));
+}
+
+FPoint normalized(FPoint* vec)
+{
+       float mag = magnitude(vec);
+       return (FPoint){vec->x/mag, vec->y/mag};
+}
+
+float dot(const FPoint* left, const FPoint* right)
+{
+       return (left->x * right->x) + (left->y * right->y);
+}
+
+FPoint mult(FPoint* vec, float mag)
+{
+       return (FPoint){vec->x * mag, vec->y * mag};
+}
+
+void mult_left(FPoint* vec, float mag)
+{
+       vec->x *= mag; vec->y *= mag;
+}
+
+FPoint fp_add(FPoint* left, FPoint* right)
+{
+       return (FPoint){left->x + right->x, left->y + right->y};
+}
+
+void fp_add_left(FPoint* left, FPoint* right)
+{
+       left->x += right->x;
+       left->y += right->y;
+}
+
+FPoint fp_sub(FPoint* left, FPoint* right)
+{
+       return (FPoint){left->x - right->x, left->y - right->y};
+}
+
+void fp_sub_left(FPoint* left, FPoint* right)
+{
+       left->x -= right->x;
+       left->y -= right->y;
+}
+
diff --git a/source/Math_Utils.h b/source/Math_Utils.h
new file mode 100644 (file)
index 0000000..2391306
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __MATH_UTILS__
+#define __MATH_UTILS__
+#include "structs.h"
+#include <math.h>
+
+#define RAD_2_DEG(a) (float)a * (180.0f/M_PI)
+#define DEG_2_RAD(a) (float)a * (M_PI/180.0f)
+
+FPoint rotate(float theta, FPoint* vec);
+float magnitude(FPoint* vec);
+FPoint normalized(FPoint* vec);
+float dot(const FPoint* left, const FPoint* right);
+FPoint mult(FPoint* vec, float mag);
+void mult_left(FPoint* vec, float mag);
+FPoint fp_add(FPoint* left, FPoint* right);
+void fp_add_left(FPoint* left, FPoint* right);
+FPoint fp_sub(FPoint* left, FPoint* right);
+void fp_sub_left(FPoint* left, FPoint* right);
+
+#endif //__MATH_UTILS__
+
diff --git a/source/main.c b/source/main.c
new file mode 100644 (file)
index 0000000..6440aad
--- /dev/null
@@ -0,0 +1,104 @@
+#if BUILD_SDL
+#include "sdl/SDL_Utils.h"
+#endif // BUILD_SDL
+
+#include "structs.h"
+#include "Math_Utils.h"
+#include <sys/param.h>
+#include <time.h>
+#include <stdio.h>
+#include <signal.h>
+
+Game_Info gi;
+void killterm_handler(int signum);
+
+int init()
+{
+       signal(SIGINT, killterm_handler);
+       signal(SIGKILL, killterm_handler);
+       signal(SIGTERM, killterm_handler);
+
+       gi.window = (Rect){.x = 0.0f, .y = 0.0f, .w = 512.0f, .h = 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);
+
+       init_renderer(&gi);
+
+       gi.game_alive = 1;
+
+       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;
+       struct timespec ts_start;
+       struct timespec ts_end;
+       float time_step = 1000.0f/30;
+
+       if(init() != 0)
+       {
+               exit(__LINE__);
+       }
+
+       while(gi.game_alive)
+       {
+               clock_gettime(CLOCK_MONOTONIC_RAW, &ts_start);
+
+               check_inputs(&gi);
+               game_loop(&gi, time_step);
+               display(&gi);
+
+               clock_gettime(CLOCK_MONOTONIC_RAW, &ts_end);
+               uint64_t frameproc_ms = (ts_end.tv_nsec - ts_start.tv_nsec) / 1000000;
+               frameproc_ms = MIN(time_step, frameproc_ms);
+               delay(time_step - frameproc_ms);
+       }
+
+       killterm_handler(15);
+
+       return 0;
+}
+
+void killterm_handler(int signum)
+{
+       printf("handling sig %d, bye bye\n", signum);
+       shutdown_renderer();
+
+       exit(0);
+}
+
diff --git a/source/sdl/SDL_Utils.c b/source/sdl/SDL_Utils.c
new file mode 100644 (file)
index 0000000..9083746
--- /dev/null
@@ -0,0 +1,242 @@
+#include <SDL2/SDL2_gfxPrimitives.h>
+#include <sys/param.h>
+
+#include "SDL_Utils.h"
+#include "../Math_Utils.h"
+
+#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_group mgr;
+const int keypress_delta = 4;
+
+int32_t init_renderer(Game_Info* gi)
+{
+       mgr.pad = NULL;
+
+       // default game states
+       // start overriding these with configs
+
+       //load_config(argv[1], gs);
+
+       SDL_SetMainReady();
+       if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER))
+       {
+               fprintf(stderr, "SDL initialization failed\n");
+               exit(__LINE__);
+       }
+
+       mgr.win = SDL_CreateWindow("Color Picker", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gi->window.w, gi->window.h, 0);
+       if (mgr.win == NULL)
+       {
+               fprintf(stderr, "SDL initialization failed\n");
+               exit(__LINE__);
+       }
+
+       mgr.rend = SDL_CreateRenderer(mgr.win, -1, SDL_RENDERER_ACCELERATED);
+       if (mgr.rend == NULL)
+       {
+               fprintf(stderr, "SDL initialization failed\n");
+               exit(__LINE__);
+       }
+
+       SDL_SetRenderDrawBlendMode(mgr.rend, SDL_BLENDMODE_BLEND);
+}
+
+int32_t shutdown_renderer()
+{
+       SDL_DestroyRenderer(mgr.rend);
+       SDL_DestroyWindow(mgr.win);
+       SDL_Quit();
+}
+
+int32_t delay(int32_t delay_time)
+{
+       SDL_Delay(delay_time);
+
+       return 0;
+}
+
+int32_t render_rgb_square(Game_Info* gi)
+{
+       SDL_SetRenderDrawColor(mgr.rend, 0x00, 0x00, 0x00, 0xFF);
+       gi->rgb_square.real = fr_margin_adjust(gi->window, gi->rgb_square.rel);
+       SDL_RenderFillRectF(mgr.rend, &gi->rgb_square.real);
+
+       return 0;
+}
+
+// REALLY this should be "generate layout", and not a true rendering step
+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;
+}
+
+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);
+
+       // this would be really cool to turn into some stack-based type of thing
+       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->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);
+       return 0;
+}
+
+int32_t check_inputs(Game_Info* gi)
+{
+       while(SDL_PollEvent(&(mgr.event)))
+       {
+               // wasd movement and quitting
+               {
+                       if (mgr.event.type == SDL_KEYDOWN && mgr.event.key.keysym.sym == SDLK_q)
+                       {
+                               gi->game_alive = 0;
+                       }
+               }
+       }
+
+       // controller support later
+       if(mgr.pad)
+       {
+               // update_for_controller(mgr, gs);
+       }
+
+       return 0;
+}
+
+SDL_FRect fr_subtract(const SDL_FRect left, const SDL_FRect right)
+{
+       return
+       (SDL_FRect){
+               left.x - right.x,
+               left.y - right.y,
+               left.w - right.w,
+               left.h - right.h
+       };
+}
+
+SDL_FRect fr_add(const SDL_FRect left, const SDL_FRect right)
+{
+       return
+       (SDL_FRect){
+               left.x + right.x,
+               left.y + right.y,
+               left.w + right.w,
+               left.h + right.h
+       };
+}
+
+SDL_FRect fr_mult(const SDL_FRect left, const SDL_FRect right)
+{
+       return
+       (SDL_FRect){
+               left.x * right.x,
+               left.y * right.y,
+               left.w * right.w,
+               left.h * right.h
+       };
+}
+
+// Math out placement for a relative rect onto a concrete parent
+SDL_FRect fr_margin_adjust(const SDL_FRect parent, const Relative_Rect child)
+{
+       return
+       (SDL_FRect){
+               .x = parent.x + ( parent.w * (child.x ) ),
+               .y = parent.y + ( parent.h * (child.y ) ),
+
+               .w = parent.w * child.w,
+               .h = parent.h * child.h,
+       };
+}
+
+// https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+SDL_Color hsl_to_rgb (const HSL_Color hsl)
+{
+       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;
+       }
+
+       return (SDL_Color){
+               (rP + m) * 255,
+               (gP + m) * 255,
+               (bP + m) * 255};
+}
+
diff --git a/source/sdl/SDL_Utils.h b/source/sdl/SDL_Utils.h
new file mode 100644 (file)
index 0000000..ddd2520
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef SDL_Utils__
+#define SDL_Utils__
+#include "../structs.h"
+
+typedef struct sdl_group
+{
+  SDL_Window* win;
+  SDL_Renderer* rend;
+  SDL_Texture* text;
+  SDL_Event event;
+
+  SDL_GameController* pad;
+}
+sdl_group;
+
+int32_t init_renderer(Game_Info* gi);
+int32_t shutdown_renderer();
+int32_t delay(int32_t delay_time);
+int32_t display(Game_Info* gi);
+int32_t check_inputs(Game_Info* gi);
+
+SDL_FRect fr_add(const SDL_FRect left, const SDL_FRect right);
+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);
+#endif // SDL_Utils__
+
diff --git a/source/structs.h b/source/structs.h
new file mode 100644 (file)
index 0000000..894ed70
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef STRUCTS__
+#define STRUCTS__
+
+#if BUILD_SDL
+#include <SDL2/SDL.h>
+#define Point SDL_Point
+#define FPoint SDL_FPoint
+#define Rect SDL_FRect
+#define Relative_Rect SDL_FRect
+#define Color SDL_Color
+#endif // BUILD_SDL
+
+#include <stdint.h>
+
+// A placeable rect, with relative components to its parent,
+// and its finalized real placement rectangle
+typedef struct
+{
+       Relative_Rect rel;
+       Rect real;
+
+       // bool
+       // center in parent axis (even spacing on both sides?)
+       // unused so far
+       int x_center;
+       int y_center;
+       int x_offset;
+       int y_offset;
+} Layout_Rect;
+
+typedef struct
+{
+       // Internet says hue likes to go 0-360
+       // Saturation and luminence are 0-100
+       uint16_t h;
+       uint8_t s;
+       uint8_t l;
+       uint8_t a;
+
+} HSL_Color;
+
+typedef struct
+{
+       FPoint position;
+       uint32_t radius;
+
+} Circle;
+
+typedef struct
+{
+       // Tabbing these to visually indicate layout
+       Rect window;
+               Layout_Rect rgb_square; // big clicky draggy square
+               Layout_Rect hue_slider; // HSV slider bar
+               Layout_Rect info_container;
+                       Layout_Rect final_sample; // small square showing full selected color
+                       Layout_Rect info_boxes;
+                               Layout_Rect rgb_info;
+                                       Layout_Rect red;
+                                       Layout_Rect blue;
+                                       Layout_Rect green;
+                               Layout_Rect hsl_info;
+                                       Layout_Rect hue;
+                                       Layout_Rect saturation;
+                                       Layout_Rect luminence;
+
+       Color active_rgb;
+
+       // Hue value should correspond to value on HSV slider
+       HSL_Color active_hsv;
+
+       int game_alive;
+
+} Game_Info;
+
+#endif // STRUCTS__
+