util.c (10336B)
1 /* See LICENSE for copyright details */ 2 #ifndef _UTIL_C_ 3 #define _UTIL_C_ 4 #include <stddef.h> 5 #include <stdint.h> 6 7 typedef uint8_t u8; 8 typedef int32_t s32; 9 typedef uint32_t u32; 10 typedef uint32_t b32; 11 typedef int64_t s64; 12 typedef uint64_t u64; 13 typedef float f32; 14 typedef double f64; 15 typedef ptrdiff_t sz; 16 17 #define function static 18 #define global static 19 #define local_persist static 20 21 #include "lora_sb_0_inc.h" 22 #include "lora_sb_1_inc.h" 23 #include "config.h" 24 25 /* NOTE(rnp): symbols in release builds shaders are embedded in the binary */ 26 #ifndef _DEBUG 27 extern char _binary_slider_lerp_glsl_start[]; 28 #endif 29 30 #ifndef asm 31 #define asm __asm__ 32 #endif 33 34 #define FORCE_INLINE inline __attribute__((always_inline)) 35 36 #define fmod_f32(a, b) __builtin_fmodf((a), (b)) 37 38 #ifdef __ARM_ARCH_ISA_A64 39 #define debugbreak() asm volatile ("brk 0xf000") 40 41 function FORCE_INLINE u64 42 rdtsc(void) 43 { 44 register u64 cntvct asm("x0"); 45 asm volatile ("mrs x0, cntvct_el0" : "=x"(cntvct)); 46 return cntvct; 47 } 48 49 #elif __x86_64__ 50 #include <immintrin.h> 51 #define debugbreak() asm volatile ("int3; nop") 52 53 #define rdtsc() __rdtsc() 54 #endif 55 56 #ifdef _DEBUG 57 #define ASSERT(c) do { if (!(c)) debugbreak(); } while (0) 58 #define DEBUG_EXPORT 59 #else 60 #define ASSERT(c) 61 #define DEBUG_EXPORT function 62 #endif 63 64 typedef struct { sz len; u8 *data; } str8; 65 #define str8(s) (str8){.len = sizeof(s) - 1, .data = (u8 *)s} 66 67 typedef struct { 68 u8 *data; 69 u32 cap; 70 u32 widx; 71 s32 fd; 72 b32 errors; 73 } Stream; 74 75 typedef union { 76 struct { u32 w, h; }; 77 struct { u32 x, y; }; 78 u32 E[2]; 79 } uv2; 80 81 typedef union { 82 struct { f32 x, y; }; 83 struct { f32 w, h; }; 84 Vector2 rv; 85 f32 E[2]; 86 } v2; 87 88 typedef union { 89 struct { f32 x, y, z, w; }; 90 struct { f32 r, g, b, a; }; 91 Vector4 rv; 92 f32 E[4]; 93 } v4; 94 95 typedef union { 96 struct { v2 pos, size; }; 97 Rectangle rr; 98 } Rect; 99 100 typedef enum c{ 101 ColourKind_RGB, 102 ColourKind_HSV, 103 ColourKind_Last, 104 } ColourKind; 105 106 enum colour_picker_mode { 107 CPM_PICKER = 0, 108 CPM_SLIDERS = 1, 109 CPM_LAST 110 }; 111 112 typedef enum { 113 ColourPickerFlag_Ready = 1 << 0, 114 ColourPickerFlag_RefillTexture = 1 << 1, 115 ColourPickerFlag_PrintDebug = 1 << 30, 116 } ColourPickerFlags; 117 118 enum input_indices { 119 INPUT_HEX, 120 INPUT_R, 121 INPUT_G, 122 INPUT_B, 123 INPUT_A 124 }; 125 126 enum mouse_pressed { 127 MOUSE_NONE = 0 << 0, 128 MOUSE_LEFT = 1 << 0, 129 MOUSE_RIGHT = 1 << 1, 130 }; 131 132 enum cardinal_direction { NORTH, EAST, SOUTH, WEST }; 133 134 #define WINDOW_ASPECT_RATIO (4.3f/3.2f) 135 136 #define BUTTON_HOVER_SPEED 8.0f 137 138 #define SLIDER_BORDER_COLOUR (Color){.r = 0x00, .g = 0x00, .b = 0x00, .a = 0xCC} 139 #define SLIDER_BORDER_WIDTH 3.0f 140 #define SLIDER_ROUNDNESS 0.035f 141 #define SLIDER_SCALE_SPEED 8.0f 142 #define SLIDER_SCALE_TARGET 1.5f 143 #define SLIDER_TRI_SIZE (v2){.x = 6, .y = 8} 144 145 #define SELECTOR_BORDER_COLOUR SLIDER_BORDER_COLOUR 146 #define SELECTOR_BORDER_WIDTH SLIDER_BORDER_WIDTH 147 #define SELECTOR_ROUNDNESS 0.3f 148 149 #define RECT_BTN_BORDER_WIDTH (SLIDER_BORDER_WIDTH + 3.0f) 150 151 #define HOVER_SPEED 5.0f 152 153 typedef struct { 154 f32 hover_t; 155 } ButtonState; 156 157 #define COLOUR_STACK_ITEMS 8 158 typedef struct { 159 ButtonState buttons[COLOUR_STACK_ITEMS]; 160 v4 items[COLOUR_STACK_ITEMS]; 161 v4 last; 162 s32 widx; 163 f32 fade_param; 164 f32 y_off_t; 165 ButtonState tri_btn; 166 } ColourStackState; 167 168 typedef struct { 169 f32 scale_t[4]; 170 f32 colour_t[4]; 171 } SliderState; 172 173 typedef struct { 174 f32 hex_hover_t; 175 ButtonState mode; 176 } StatusBarState; 177 178 typedef struct { 179 ButtonState buttons[CPM_LAST]; 180 f32 mode_visible_t; 181 s32 next_mode; 182 } ModeChangeState; 183 184 typedef struct { 185 f32 scale_t[3]; 186 f32 base_hue; 187 f32 fractional_hue; 188 } PickerModeState; 189 190 typedef struct { 191 s32 idx; /* TODO(rnp): remove */ 192 s32 count; 193 s32 cursor; 194 f32 cursor_hover_p; /* TODO(rnp): remove */ 195 f32 cursor_t; 196 f32 cursor_t_target; /* TODO(rnp): remove */ 197 u8 buf[64]; 198 } TextInputState; 199 200 typedef struct { 201 str8 *labels; 202 u32 state; 203 u32 length; 204 } Cycler; 205 206 typedef struct Variable Variable; 207 typedef enum { 208 InteractionKind_None, 209 InteractionKind_Set, 210 InteractionKind_Text, 211 InteractionKind_Drag, 212 InteractionKind_Scroll, 213 } InteractionKind; 214 215 typedef struct { 216 Variable *active; 217 Variable *hot; 218 Variable *next_hot; 219 220 Rect rect; 221 Rect hot_rect; 222 223 InteractionKind kind; 224 } InteractionState; 225 226 typedef enum { 227 VariableFlag_Text = 1 << 0, 228 VariableFlag_UpdateStoredMode = 1 << 30, 229 } VariableFlags; 230 231 typedef enum { 232 VariableKind_F32, 233 VariableKind_U32, 234 VariableKind_F32Reference, 235 VariableKind_Button, 236 VariableKind_Cycler, 237 VariableKind_HexColourInput, 238 } VariableKind; 239 240 struct Variable { 241 union { 242 u32 U32; 243 f32 F32; 244 f32 *F32Reference; 245 void *generic; 246 Cycler cycler; 247 }; 248 VariableKind kind; 249 VariableFlags flags; 250 f32 parameter; 251 }; 252 253 typedef struct { 254 Variable colour_kind_cycler; 255 } SliderModeState; 256 257 typedef struct { 258 v4 colour, previous_colour; 259 ColourStackState colour_stack; 260 261 uv2 window_size; 262 v2 window_pos; 263 v2 mouse_pos; 264 v2 last_mouse; 265 266 Font font; 267 Color bg, fg; 268 269 TextInputState text_input_state; 270 InteractionState interaction; 271 272 ModeChangeState mcs; 273 PickerModeState pms; 274 SliderState ss; 275 StatusBarState sbs; 276 ButtonState buttons[2]; 277 278 SliderModeState slider_mode_state; 279 280 s32 held_idx; 281 282 f32 selection_hover_t[2]; 283 v4 hover_colour; 284 v4 cursor_colour; 285 286 Shader picker_shader; 287 RenderTexture slider_texture; 288 RenderTexture picker_texture; 289 290 s32 mode_id, colour_mode_id, colours_id; 291 s32 regions_id, radius_id, border_thick_id; 292 293 ColourPickerFlags flags; 294 ColourKind stored_colour_kind; 295 enum colour_picker_mode mode; 296 } ColourPickerCtx; 297 298 #define countof(a) (s64)(sizeof(a) / sizeof(*a)) 299 300 #define ABS(x) ((x) < 0 ? (-x) : (x)) 301 #define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b)) 302 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 303 #define MAX(a, b) ((a) < (b) ? (b) : (a)) 304 #define CLAMP(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)) 305 #define CLAMP01(a) CLAMP(a, 0, 1) 306 307 #define ISDIGIT(a) ((a) >= '0' && (a) <= '9') 308 #define ISHEX(a) (ISDIGIT(a) || ((a) >= 'a' && (a) <= 'f') || ((a) >= 'A' && (a) <= 'F')) 309 310 #define InvalidDefaultCase default: ASSERT(0); break 311 312 function v4 313 rgb_to_hsv(v4 rgb) 314 { 315 v4 hsv = {0}; 316 f32 M = MAX(rgb.r, MAX(rgb.g, rgb.b)); 317 f32 m = MIN(rgb.r, MIN(rgb.g, rgb.b)); 318 if (M - m > 0) { 319 f32 C = M - m; 320 if (M == rgb.r) { 321 hsv.x = fmod_f32((rgb.g - rgb.b) / C, 6) / 6.0; 322 } else if (M == rgb.g) { 323 hsv.x = ((rgb.b - rgb.r) / C + 2) / 6.0; 324 } else { 325 hsv.x = ((rgb.r - rgb.g) / C + 4) / 6.0; 326 } 327 hsv.y = M? C / M : 0; 328 hsv.z = M; 329 hsv.a = rgb.a; 330 } 331 return hsv; 332 } 333 334 function v4 335 hsv_to_rgb(v4 hsv) 336 { 337 v4 rgba; 338 f32 k = fmod_f32(5 + hsv.x * 6, 6); 339 rgba.r = hsv.z - hsv.z * hsv.y * MAX(0, MIN(1, MIN(k, 4 - k))); 340 k = fmod_f32(3 + hsv.x * 6, 6); 341 rgba.g = hsv.z - hsv.z * hsv.y * MAX(0, MIN(1, MIN(k, 4 - k))); 342 k = fmod_f32(1 + hsv.x * 6, 6); 343 rgba.b = hsv.z - hsv.z * hsv.y * MAX(0, MIN(1, MIN(k, 4 - k))); 344 rgba.a = hsv.a; 345 return rgba; 346 } 347 348 function v4 349 normalize_colour(u32 rgba) 350 { 351 v4 result; 352 result.r = ((rgba >> 24) & 0xFF) / 255.0f; 353 result.g = ((rgba >> 16) & 0xFF) / 255.0f; 354 result.b = ((rgba >> 8) & 0xFF) / 255.0f; 355 result.a = ((rgba >> 0) & 0xFF) / 255.0f; 356 return result; 357 } 358 359 function u32 360 pack_rl_colour(Color colour) 361 { 362 return colour.r << 24 | colour.g << 16 | colour.b << 8 | colour.a << 0; 363 } 364 365 function Color 366 rl_colour_from_normalized(v4 colour) 367 { 368 Color result; 369 result.r = colour.r * 255; 370 result.g = colour.g * 255; 371 result.b = colour.b * 255; 372 result.a = colour.a * 255; 373 return result; 374 } 375 376 function v2 377 add_v2(v2 a, v2 b) 378 { 379 v2 result; 380 result.x = a.x + b.x; 381 result.y = a.y + b.y; 382 return result; 383 } 384 385 function u32 386 parse_hex_u32(str8 s) 387 { 388 u32 res = 0; 389 390 /* NOTE: skip over '0x' or '0X' */ 391 if (s.len > 2 && s.data[0] == '0' && (s.data[1] == 'x' || s.data[1] == 'X')) { 392 s.data += 2; 393 s.len -= 2; 394 } 395 396 for (; s.len > 0; s.len--, s.data++) { 397 res <<= 4; 398 if (ISDIGIT(*s.data)) { 399 res |= *s.data - '0'; 400 } else if (ISHEX(*s.data)) { 401 /* NOTE: convert to lowercase first then convert to value */ 402 *s.data |= 0x20; 403 res |= *s.data - 0x57; 404 } else { 405 /* NOTE: do nothing (treat invalid value as 0) */ 406 } 407 } 408 return res; 409 } 410 411 function f64 412 parse_f64(str8 s) 413 { 414 f64 integral = 0, fractional = 0, sign = 1; 415 416 if (s.len && *s.data == '-') { 417 sign *= -1; 418 s.data++; 419 s.len--; 420 } 421 422 while (s.len && ISDIGIT(*s.data)) { 423 integral *= 10; 424 integral += *s.data - '0'; 425 s.data++; 426 s.len--; 427 } 428 429 if (s.len && *s.data == '.') { s.data++; s.len--; } 430 431 while (s.len) { 432 ASSERT(s.data[s.len - 1] != '.'); 433 fractional *= 0.1f; 434 fractional += (s.data[--s.len] - '0') * 0.1f; 435 } 436 437 f64 result = sign * (integral + fractional); 438 439 return result; 440 } 441 442 function str8 443 str8_from_c_str(char *s) 444 { 445 str8 result = {.data = (u8 *)s}; 446 if (s) { 447 while (*s) s++; 448 result.len = (u8 *)s - result.data; 449 } 450 return result; 451 } 452 453 function void 454 stream_append_byte(Stream *s, u8 b) 455 { 456 s->errors |= s->widx + 1 > s->cap; 457 if (!s->errors) 458 s->data[s->widx++] = b; 459 } 460 461 function void 462 stream_append_hex_u8(Stream *s, u32 n) 463 { 464 local_persist u8 hex[16] = {"0123456789abcdef"}; 465 s->errors |= (s->cap - s->widx) < 2; 466 if (!s->errors) { 467 s->data[s->widx + 1] = hex[(n >> 0) & 0x0f]; 468 s->data[s->widx + 0] = hex[(n >> 4) & 0x0f]; 469 s->widx += 2; 470 } 471 } 472 473 function void 474 stream_append_str8(Stream *s, str8 str) 475 { 476 s->errors |= (s->cap - s->widx) < str.len; 477 if (!s->errors) { 478 for (sz i = 0; i < str.len; i++) 479 s->data[s->widx++] = str.data[i]; 480 } 481 } 482 483 function void 484 stream_append_u64(Stream *s, u64 n) 485 { 486 u8 tmp[64]; 487 u8 *end = tmp + sizeof(tmp); 488 u8 *beg = end; 489 do { *--beg = '0' + (n % 10); } while (n /= 10); 490 stream_append_str8(s, (str8){.len = end - beg, .data = beg}); 491 } 492 493 function void 494 stream_append_f64(Stream *s, f64 f, s64 prec) 495 { 496 if (f < 0) { 497 stream_append_byte(s, '-'); 498 f *= -1; 499 } 500 501 /* NOTE: round last digit */ 502 f += 0.5f / prec; 503 504 if (f >= (f64)(-1UL >> 1)) { 505 stream_append_str8(s, str8("inf")); 506 } else { 507 u64 integral = f; 508 u64 fraction = (f - integral) * prec; 509 stream_append_u64(s, integral); 510 stream_append_byte(s, '.'); 511 for (u64 i = prec / 10; i > 1; i /= 10) { 512 if (i > fraction) 513 stream_append_byte(s, '0'); 514 } 515 stream_append_u64(s, fraction); 516 } 517 } 518 519 function void 520 stream_append_colour(Stream *s, Color c) 521 { 522 stream_append_hex_u8(s, c.r); 523 stream_append_hex_u8(s, c.g); 524 stream_append_hex_u8(s, c.b); 525 stream_append_hex_u8(s, c.a); 526 } 527 528 #endif /* _UTIL_C_ */