util.c (8312B)
1 /* See LICENSE for copyright details */ 2 #ifndef _UTIL_C_ 3 #define _UTIL_C_ 4 #include <emmintrin.h> 5 #include <immintrin.h> 6 7 #include <stddef.h> 8 #include <stdint.h> 9 10 #include "shader_inc.h" 11 #include "lora_sb_0_inc.h" 12 #include "lora_sb_1_inc.h" 13 #include "config.h" 14 15 #ifndef asm 16 #define asm __asm__ 17 #endif 18 19 #ifdef _DEBUG 20 #define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while (0); 21 #define DEBUG_EXPORT 22 #else 23 #define ASSERT(c) 24 #define DEBUG_EXPORT static 25 #endif 26 27 typedef uint8_t u8; 28 typedef int32_t i32; 29 typedef uint32_t u32; 30 typedef uint32_t b32; 31 typedef int64_t i64; 32 typedef float f32; 33 typedef double f64; 34 typedef ptrdiff_t size; 35 36 typedef struct { size len; char *data; } s8; 37 #define s8(s) (s8){.len = sizeof(s) - 1, .data = s} 38 39 typedef union { 40 struct { u32 w, h; }; 41 struct { u32 x, y; }; 42 u32 E[2]; 43 } uv2; 44 45 typedef union { 46 struct { f32 x, y; }; 47 struct { f32 w, h; }; 48 Vector2 rv; 49 f32 E[2]; 50 } v2; 51 52 typedef union { 53 struct { f32 x, y, z, w; }; 54 struct { f32 r, g, b, a; }; 55 Vector4 rv; 56 f32 E[4]; 57 } v4; 58 59 typedef union { 60 struct { v2 pos, size; }; 61 Rectangle rr; 62 } Rect; 63 64 enum colour_mode { 65 CM_RGB = 0, 66 CM_HSV = 1, 67 CM_LAST 68 }; 69 70 enum colour_picker_mode { 71 CPM_PICKER = 0, 72 CPM_SLIDERS = 1, 73 CPM_LAST 74 }; 75 76 enum colour_picker_flags { 77 CPF_REFILL_TEXTURE = 1 << 0, 78 CPF_PRINT_DEBUG = 1 << 30, 79 }; 80 81 enum input_indices { 82 INPUT_HEX, 83 INPUT_R, 84 INPUT_G, 85 INPUT_B, 86 INPUT_A 87 }; 88 89 enum mouse_pressed { 90 MOUSE_NONE = 0 << 0, 91 MOUSE_LEFT = 1 << 0, 92 MOUSE_RIGHT = 1 << 1, 93 }; 94 95 enum cardinal_direction { NORTH, EAST, SOUTH, WEST }; 96 97 #define WINDOW_ASPECT_RATIO (4.3f/3.2f) 98 99 #define BUTTON_HOVER_SPEED 8.0f 100 101 #define SLIDER_BORDER_COLOUR (Color){.r = 0x00, .g = 0x00, .b = 0x00, .a = 0xCC} 102 #define SLIDER_BORDER_WIDTH 3.0f 103 #define SLIDER_ROUNDNESS 0.035f 104 #define SLIDER_SCALE_SPEED 8.0f 105 #define SLIDER_SCALE_TARGET 1.5f 106 #define SLIDER_TRI_SIZE (v2){.x = 6, .y = 8} 107 108 #define SELECTOR_BORDER_COLOUR SLIDER_BORDER_COLOUR 109 #define SELECTOR_BORDER_WIDTH SLIDER_BORDER_WIDTH 110 #define SELECTOR_ROUNDNESS 0.3f 111 112 #define RECT_BTN_BORDER_WIDTH (SLIDER_BORDER_WIDTH + 3.0f) 113 114 #define TEXT_HOVER_SPEED 5.0f 115 116 typedef struct { 117 f32 hover_t; 118 } ButtonState; 119 120 #define COLOUR_STACK_ITEMS 8 121 typedef struct { 122 ButtonState buttons[COLOUR_STACK_ITEMS]; 123 v4 items[COLOUR_STACK_ITEMS]; 124 v4 last; 125 i32 widx; 126 f32 fade_param; 127 f32 y_off_t; 128 ButtonState tri_btn; 129 } ColourStackState; 130 131 typedef struct { 132 f32 scale_t[4]; 133 f32 colour_t[4]; 134 } SliderState; 135 136 typedef struct { 137 f32 hex_hover_t; 138 ButtonState mode; 139 } StatusBarState; 140 141 typedef struct { 142 ButtonState buttons[CPM_LAST]; 143 f32 mode_visible_t; 144 i32 next_mode; 145 } ModeChangeState; 146 147 typedef struct { 148 f32 scale_t[3]; 149 f32 base_hue; 150 f32 fractional_hue; 151 } PickerModeState; 152 153 typedef struct { 154 i32 idx; 155 i32 cursor; 156 f32 cursor_hover_p; 157 f32 cursor_t; 158 f32 cursor_t_target; 159 i32 buf_len; 160 char buf[64]; 161 } InputState; 162 163 #ifdef _DEBUG 164 enum clock_counts { 165 CC_WHOLE_RUN, 166 CC_DO_PICKER, 167 CC_DO_SLIDER, 168 CC_UPPER, 169 CC_LOWER, 170 CC_TEMP, 171 CC_LAST 172 }; 173 174 static struct { 175 i64 cpu_cycles[CC_LAST]; 176 i64 total_cycles[CC_LAST]; 177 i64 hit_count[CC_LAST]; 178 } g_debug_clock_counts; 179 180 #define BEGIN_CYCLE_COUNT(cc_name) \ 181 g_debug_clock_counts.cpu_cycles[cc_name] = __rdtsc(); \ 182 g_debug_clock_counts.hit_count[cc_name]++ 183 184 #define END_CYCLE_COUNT(cc_name) \ 185 g_debug_clock_counts.cpu_cycles[cc_name] = __rdtsc() - g_debug_clock_counts.cpu_cycles[cc_name]; \ 186 g_debug_clock_counts.total_cycles[cc_name] += g_debug_clock_counts.cpu_cycles[cc_name] 187 188 #else 189 #define BEGIN_CYCLE_COUNT(a) 190 #define END_CYCLE_COUNT(a) 191 #endif 192 193 typedef struct { 194 v4 colour, previous_colour; 195 ColourStackState colour_stack; 196 197 uv2 window_size; 198 v2 window_pos; 199 v2 mouse_pos; 200 201 f32 dt; 202 203 Font font; 204 Color bg, fg; 205 206 InputState is; 207 ModeChangeState mcs; 208 PickerModeState pms; 209 SliderState ss; 210 StatusBarState sbs; 211 ButtonState buttons[2]; 212 213 i32 held_idx; 214 215 f32 selection_hover_t[2]; 216 v4 hover_colour; 217 v4 cursor_colour; 218 219 Shader picker_shader; 220 RenderTexture slider_texture; 221 RenderTexture picker_texture; 222 223 i32 mode_id, colour_mode_id, colours_id; 224 i32 regions_id, radius_id, border_thick_id; 225 226 u32 flags; 227 enum colour_mode colour_mode; 228 enum colour_picker_mode mode; 229 } ColourPickerCtx; 230 231 #define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) 232 #define ABS(x) ((x) < 0 ? (-x) : (x)) 233 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 234 #define CLAMP(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)) 235 #define CLAMP01(a) CLAMP(a, 0, 1) 236 237 #define ISDIGIT(a) ((a) >= '0' && (a) <= '9') 238 #define ISHEX(a) (ISDIGIT(a) || ((a) >= 'a' && (a) <= 'f') || ((a) >= 'A' && (a) <= 'F')) 239 240 static Color 241 colour_from_normalized(v4 colour) 242 { 243 __m128 colour_v = _mm_loadu_ps(colour.E); 244 __m128 scale = _mm_set1_ps(255.0f); 245 __m128i result = _mm_cvtps_epi32(_mm_mul_ps(colour_v, scale)); 246 _Alignas(16) u32 outu[4]; 247 _mm_store_si128((__m128i *)outu, result); 248 return (Color){.r = outu[0] & 0xFF, .g = outu[1] & 0xFF, .b = outu[2] & 0xFF, .a = outu[3] & 0xFF }; 249 } 250 251 static v4 252 rgb_to_hsv(v4 rgb) 253 { 254 __m128 rgba = _mm_loadu_ps(rgb.E); 255 __m128 gbra = _mm_shuffle_ps(rgba, rgba, _MM_SHUFFLE(3, 0, 2, 1)); 256 __m128 brga = _mm_shuffle_ps(gbra, gbra, _MM_SHUFFLE(3, 0, 2, 1)); 257 258 __m128 Max = _mm_max_ps(rgba, _mm_max_ps(gbra, brga)); 259 __m128 Min = _mm_min_ps(rgba, _mm_min_ps(gbra, brga)); 260 __m128 C = _mm_sub_ps(Max, Min); 261 262 __m128 zero = _mm_set1_ps(0); 263 __m128 six = _mm_set1_ps(6); 264 265 _Alignas(16) f32 aval[4] = {0, 2, 4, 0}; 266 _Alignas(16) f32 scale[4] = {1.0/6.0f, 0, 0, 0}; 267 /* NOTE if C == 0 then take H as 0/1 (which are equivalent in HSV) */ 268 __m128 t = _mm_div_ps(_mm_sub_ps(gbra, brga), C); 269 t = _mm_and_ps(t, _mm_cmpneq_ps(zero, C)); 270 t = _mm_add_ps(t, _mm_load_ps(aval)); 271 /* TODO: does (G - B) / C ever exceed 6.0? */ 272 /* NOTE: Compute fmodf on element [0] */ 273 t = _mm_sub_ps(t, _mm_mul_ps(_mm_floor_ps(_mm_mul_ps(t, _mm_load_ps(scale))), six)); 274 275 __m128 H = _mm_div_ps(_mm_and_ps(t, _mm_cmpeq_ps(rgba, Max)), six); 276 __m128 S = _mm_div_ps(C, Max); 277 278 /* NOTE: Make sure H & S are 0 instead of NaN when V == 0 */ 279 H = _mm_and_ps(H, _mm_cmpneq_ps(zero, Max)); 280 S = _mm_and_ps(S, _mm_cmpneq_ps(zero, Max)); 281 282 __m128 H0 = _mm_shuffle_ps(H, H, _MM_SHUFFLE(3, 0, 0, 0)); 283 __m128 H1 = _mm_shuffle_ps(H, H, _MM_SHUFFLE(3, 1, 1, 1)); 284 __m128 H2 = _mm_shuffle_ps(H, H, _MM_SHUFFLE(3, 2, 2, 2)); 285 H = _mm_or_ps(H0, _mm_or_ps(H1, H2)); 286 287 /* NOTE: keep only element [0] from H vector; Max contains V & A */ 288 __m128 hva = _mm_blend_ps(Max, H, 0x01); 289 __m128 hsva = _mm_blend_ps(hva, S, 0x02); 290 hsva = _mm_min_ps(hsva, _mm_set1_ps(1)); 291 292 v4 res; 293 _mm_storeu_ps(res.E, hsva); 294 return res; 295 } 296 297 static v4 298 hsv_to_rgb(v4 hsv) 299 { 300 /* f(k(n)) = V - V*S*max(0, min(k, min(4 - k, 1))) 301 * k(n) = fmod((n + H * 6), 6) 302 * (R, G, B) = (f(n = 5), f(n = 3), f(n = 1)) 303 */ 304 _Alignas(16) f32 nval[4] = {5.0f, 3.0f, 1.0f, 0.0f}; 305 __m128 n = _mm_load_ps(nval); 306 __m128 H = _mm_set1_ps(hsv.x); 307 __m128 S = _mm_set1_ps(hsv.y); 308 __m128 V = _mm_set1_ps(hsv.z); 309 __m128 six = _mm_set1_ps(6); 310 311 __m128 t = _mm_add_ps(n, _mm_mul_ps(six, H)); 312 __m128 rem = _mm_floor_ps(_mm_div_ps(t, six)); 313 __m128 k = _mm_sub_ps(t, _mm_mul_ps(rem, six)); 314 315 t = _mm_min_ps(_mm_sub_ps(_mm_set1_ps(4), k), _mm_set1_ps(1)); 316 t = _mm_max_ps(_mm_set1_ps(0), _mm_min_ps(k, t)); 317 t = _mm_mul_ps(t, _mm_mul_ps(S, V)); 318 319 v4 rgba; 320 _mm_storeu_ps(rgba.E, _mm_sub_ps(V, t)); 321 rgba.a = hsv.a; 322 323 return rgba; 324 } 325 326 static v4 327 normalize_colour(u32 rgba) 328 { 329 return (v4){ 330 .r = ((rgba >> 24) & 0xFF) / 255.0f, 331 .g = ((rgba >> 16) & 0xFF) / 255.0f, 332 .b = ((rgba >> 8) & 0xFF) / 255.0f, 333 .a = ((rgba >> 0) & 0xFF) / 255.0f, 334 }; 335 } 336 337 static u32 338 pack_rl_colour(Color colour) 339 { 340 return colour.r << 24 | colour.g << 16 | colour.b << 8 | colour.a << 0; 341 } 342 343 static u32 344 parse_hex_u32(char *s) 345 { 346 u32 res = 0; 347 348 /* NOTE: skip over '0x' or '0X' */ 349 if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) 350 s += 2; 351 352 for (; *s; s++) { 353 res <<= 4; 354 if (ISDIGIT(*s)) { 355 res |= *s - '0'; 356 } else if (ISHEX(*s)) { 357 /* NOTE: convert to lowercase first then convert to value */ 358 *s |= 0x20; 359 res |= *s - 0x57; 360 } else { 361 /* NOTE: do nothing (treat invalid value as 0) */ 362 } 363 } 364 return res; 365 } 366 367 static f32 368 parse_f32(char *s) 369 { 370 return atof(s); 371 } 372 373 #endif /* _UTIL_C_ */