--- /dev/null
+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/$@
--- /dev/null
+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'
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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__
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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};
+}
+
--- /dev/null
+#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__
+
--- /dev/null
+#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__
+