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