ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

util.c (12719B)


      1 /* See LICENSE for license details. */
      2 #define zero_struct(s) mem_clear(s, 0, sizeof(*s))
      3 function void *
      4 mem_clear(void *restrict p_, u8 c, iz size)
      5 {
      6 	u8 *p = p_;
      7 	while (size > 0) p[--size] = c;
      8 	return p;
      9 }
     10 
     11 function void
     12 mem_copy(void *restrict dest, void *restrict src, uz n)
     13 {
     14 	u8 *s = src, *d = dest;
     15 	for (; n; n--) *d++ = *s++;
     16 }
     17 
     18 function void
     19 mem_move(u8 *dest, u8 *src, iz n)
     20 {
     21 	if (dest < src) mem_copy(dest, src, n);
     22 	else            while (n) { n--; dest[n] = src[n]; }
     23 }
     24 
     25 function u8 *
     26 arena_commit(Arena *a, iz size)
     27 {
     28 	ASSERT(a->end - a->beg >= size);
     29 	u8 *result = a->beg;
     30 	a->beg += size;
     31 	return result;
     32 }
     33 
     34 function void
     35 arena_pop(Arena *a, iz length)
     36 {
     37 	a->beg -= length;
     38 }
     39 
     40 #define push_array(a, t, n) (t *)arena_alloc(a, sizeof(t), _Alignof(t), n)
     41 #define push_struct(a, t)   (t *)arena_alloc(a, sizeof(t), _Alignof(t), 1)
     42 function void *
     43 arena_alloc(Arena *a, iz len, iz align, iz count)
     44 {
     45 	/* NOTE: special case 0 arena */
     46 	if (a->beg == 0)
     47 		return 0;
     48 
     49 	iz padding   = -(uintptr_t)a->beg & (align - 1);
     50 	iz available = a->end - a->beg - padding;
     51 	if (available < 0 || count > available / len)
     52 		ASSERT(0 && "arena OOM\n");
     53 	void *p = a->beg + padding;
     54 	a->beg += padding + count * len;
     55 	/* TODO: Performance? */
     56 	return mem_clear(p, 0, count * len);
     57 }
     58 
     59 #define arena_capacity(a, t) arena_capacity_(a, sizeof(t), _Alignof(t))
     60 function iz
     61 arena_capacity_(Arena *a, iz size, iz alignment)
     62 {
     63 	iz padding   = -(uintptr_t)a->beg & (alignment - 1);
     64 	iz available = a->end - a->beg - padding;
     65 	iz result    = available / size;
     66 	return result;
     67 }
     68 
     69 enum { DA_INITIAL_CAP = 4 };
     70 #define da_reserve(a, s, n) \
     71   (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \
     72                           _Alignof(typeof(*(s)->data)), sizeof(*(s)->data))
     73 
     74 #define da_push(a, s) \
     75   ((s)->count == (s)->capacity  \
     76     ? da_reserve(a, s, 1),      \
     77       (s)->data + (s)->count++  \
     78     : (s)->data + (s)->count++)
     79 
     80 function void *
     81 da_reserve_(Arena *a, void *data, iz *capacity, iz needed, iz align, iz size)
     82 {
     83 	iz cap = *capacity;
     84 
     85 	/* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started
     86 	 * on the stack or someone allocated something in the middle of the arena during usage) */
     87 	if (!data || a->beg != (u8 *)data + cap * size) {
     88 		void *copy = arena_alloc(a, size, align, cap);
     89 		if (data) mem_copy(copy, data, cap * size);
     90 		data = copy;
     91 	}
     92 
     93 	if (!cap) cap = DA_INITIAL_CAP;
     94 	while (cap < needed) cap *= 2;
     95 	arena_alloc(a, size, align, cap - *capacity);
     96 	*capacity = cap;
     97 	return data;
     98 }
     99 
    100 function Arena
    101 sub_arena(Arena *a, iz len, iz align)
    102 {
    103 	Arena result = {0};
    104 
    105 	iz padding = -(uintptr_t)a->beg & (align - 1);
    106 	result.beg   = a->beg + padding;
    107 	result.end   = result.beg + len;
    108 	arena_commit(a, len + padding);
    109 
    110 	return result;
    111 }
    112 
    113 function TempArena
    114 begin_temp_arena(Arena *a)
    115 {
    116 	TempArena result = {.arena = a, .old_beg = a->beg};
    117 	return result;
    118 }
    119 
    120 function void
    121 end_temp_arena(TempArena ta)
    122 {
    123 	Arena *a = ta.arena;
    124 	if (a) {
    125 		assert(a->beg >= ta.old_beg);
    126 		a->beg = ta.old_beg;
    127 	}
    128 }
    129 
    130 function u32
    131 utf8_encode(u8 *out, u32 cp)
    132 {
    133 	u32 result = 1;
    134 	if (cp <= 0x7F) {
    135 		out[0] = cp & 0x7F;
    136 	} else if (cp <= 0x7FF) {
    137 		result = 2;
    138 		out[0] = ((cp >>  6) & 0x1F) | 0xC0;
    139 		out[1] = ((cp >>  0) & 0x3F) | 0x80;
    140 	} else if (cp <= 0xFFFF) {
    141 		result = 3;
    142 		out[0] = ((cp >> 12) & 0x0F) | 0xE0;
    143 		out[1] = ((cp >>  6) & 0x3F) | 0x80;
    144 		out[2] = ((cp >>  0) & 0x3F) | 0x80;
    145 	} else if (cp <= 0x10FFFF) {
    146 		result = 4;
    147 		out[0] = ((cp >> 18) & 0x07) | 0xF0;
    148 		out[1] = ((cp >> 12) & 0x3F) | 0x80;
    149 		out[2] = ((cp >>  6) & 0x3F) | 0x80;
    150 		out[3] = ((cp >>  0) & 0x3F) | 0x80;
    151 	} else {
    152 		out[0] = '?';
    153 	}
    154 	return result;
    155 }
    156 
    157 function UnicodeDecode
    158 utf16_decode(u16 *data, iz length)
    159 {
    160 	UnicodeDecode result = {.cp = U32_MAX};
    161 	if (length) {
    162 		result.consumed = 1;
    163 		result.cp = data[0];
    164 		if (length > 1 && BETWEEN(data[0], 0xD800, 0xDBFF)
    165 		               && BETWEEN(data[1], 0xDC00, 0xDFFF))
    166 		{
    167 			result.consumed = 2;
    168 			result.cp = ((data[0] - 0xD800) << 10) | ((data[1] - 0xDC00) + 0x10000);
    169 		}
    170 	}
    171 	return result;
    172 }
    173 
    174 function u32
    175 utf16_encode(u16 *out, u32 cp)
    176 {
    177 	u32 result = 1;
    178 	if (cp == U32_MAX) {
    179 		out[0] = '?';
    180 	} else if (cp < 0x10000) {
    181 		out[0] = cp;
    182 	} else {
    183 		u32 value = cp - 0x10000;
    184 		out[0] = 0xD800 + (value >> 10u);
    185 		out[1] = 0xDC00 + (value & 0x3FFu);
    186 		result = 2;
    187 	}
    188 	return result;
    189 }
    190 
    191 function Stream
    192 stream_alloc(Arena *a, iz cap)
    193 {
    194 	Stream result = {.cap = cap};
    195 	result.data = push_array(a, u8, cap);
    196 	return result;
    197 }
    198 
    199 function s8
    200 stream_to_s8(Stream *s)
    201 {
    202 	s8 result = s8("");
    203 	if (!s->errors) result = (s8){.len = s->widx, .data = s->data};
    204 	return result;
    205 }
    206 
    207 function void
    208 stream_reset(Stream *s, iz index)
    209 {
    210 	s->errors = s->cap <= index;
    211 	if (!s->errors)
    212 		s->widx = index;
    213 }
    214 
    215 function void
    216 stream_commit(Stream *s, iz count)
    217 {
    218 	s->errors |= !BETWEEN(s->widx + count, 0, s->cap);
    219 	if (!s->errors)
    220 		s->widx += count;
    221 }
    222 
    223 function void
    224 stream_append(Stream *s, void *data, iz count)
    225 {
    226 	s->errors |= (s->cap - s->widx) < count;
    227 	if (!s->errors) {
    228 		mem_copy(s->data + s->widx, data, count);
    229 		s->widx += count;
    230 	}
    231 }
    232 
    233 function void
    234 stream_append_byte(Stream *s, u8 b)
    235 {
    236 	stream_append(s, &b, 1);
    237 }
    238 
    239 function void
    240 stream_pad(Stream *s, u8 b, i32 n)
    241 {
    242 	while (n > 0) stream_append_byte(s, b), n--;
    243 }
    244 
    245 function void
    246 stream_append_s8(Stream *s, s8 str)
    247 {
    248 	stream_append(s, str.data, str.len);
    249 }
    250 
    251 #define stream_append_s8s(s, ...) stream_append_s8s_(s, arg_list(s8, ##__VA_ARGS__))
    252 function void
    253 stream_append_s8s_(Stream *s, s8 *strs, iz count)
    254 {
    255 	for (iz i = 0; i < count; i++)
    256 		stream_append(s, strs[i].data, strs[i].len);
    257 }
    258 
    259 function void
    260 stream_append_u64(Stream *s, u64 n)
    261 {
    262 	u8 tmp[64];
    263 	u8 *end = tmp + sizeof(tmp);
    264 	u8 *beg = end;
    265 	do { *--beg = '0' + (n % 10); } while (n /= 10);
    266 	stream_append(s, beg, end - beg);
    267 }
    268 
    269 function void
    270 stream_append_hex_u64(Stream *s, u64 n)
    271 {
    272 	if (!s->errors) {
    273 		u8  buf[16];
    274 		u8 *end = buf + sizeof(buf);
    275 		u8 *beg = end;
    276 		while (n) {
    277 			*--beg = "0123456789abcdef"[n & 0x0F];
    278 			n >>= 4;
    279 		}
    280 		while (end - beg < 2)
    281 			*--beg = '0';
    282 		stream_append(s, beg, end - beg);
    283 	}
    284 }
    285 
    286 function void
    287 stream_append_i64(Stream *s, i64 n)
    288 {
    289 	if (n < 0) {
    290 		stream_append_byte(s, '-');
    291 		n *= -1;
    292 	}
    293 	stream_append_u64(s, n);
    294 }
    295 
    296 function void
    297 stream_append_f64(Stream *s, f64 f, i64 prec)
    298 {
    299 	if (f < 0) {
    300 		stream_append_byte(s, '-');
    301 		f *= -1;
    302 	}
    303 
    304 	/* NOTE: round last digit */
    305 	f += 0.5f / prec;
    306 
    307 	if (f >= (f64)(-1UL >> 1)) {
    308 		stream_append_s8(s, s8("inf"));
    309 	} else {
    310 		u64 integral = f;
    311 		u64 fraction = (f - integral) * prec;
    312 		stream_append_u64(s, integral);
    313 		stream_append_byte(s, '.');
    314 		for (i64 i = prec / 10; i > 1; i /= 10) {
    315 			if (i > fraction)
    316 				stream_append_byte(s, '0');
    317 		}
    318 		stream_append_u64(s, fraction);
    319 	}
    320 }
    321 
    322 function void
    323 stream_append_f64_e(Stream *s, f64 f)
    324 {
    325 	/* TODO: there should be a better way of doing this */
    326 	#if 0
    327 	/* NOTE: we ignore subnormal numbers for now */
    328 	union { f64 f; u64 u; } u = {.f = f};
    329 	i32 exponent = ((u.u >> 52) & 0x7ff) - 1023;
    330 	f32 log_10_of_2 = 0.301f;
    331 	i32 scale       = (exponent * log_10_of_2);
    332 	/* NOTE: normalize f */
    333 	for (i32 i = ABS(scale); i > 0; i--)
    334 		f *= (scale > 0)? 0.1f : 10.0f;
    335 	#else
    336 	i32 scale = 0;
    337 	if (f != 0) {
    338 		while (f > 1) {
    339 			f *= 0.1f;
    340 			scale++;
    341 		}
    342 		while (f < 1) {
    343 			f *= 10.0f;
    344 			scale--;
    345 		}
    346 	}
    347 	#endif
    348 
    349 	i32 prec = 100;
    350 	stream_append_f64(s, f, prec);
    351 	stream_append_byte(s, 'e');
    352 	stream_append_byte(s, scale >= 0? '+' : '-');
    353 	for (i32 i = prec / 10; i > 1; i /= 10)
    354 		stream_append_byte(s, '0');
    355 	stream_append_u64(s, ABS(scale));
    356 }
    357 
    358 function void
    359 stream_append_v2(Stream *s, v2 v)
    360 {
    361 	stream_append_byte(s, '{');
    362 	stream_append_f64(s, v.x, 100);
    363 	stream_append_s8(s, s8(", "));
    364 	stream_append_f64(s, v.y, 100);
    365 	stream_append_byte(s, '}');
    366 }
    367 
    368 function Stream
    369 arena_stream(Arena a)
    370 {
    371 	Stream result = {0};
    372 	result.data   = a.beg;
    373 	result.cap    = a.end - a.beg;
    374 	return result;
    375 }
    376 
    377 function s8
    378 arena_stream_commit(Arena *a, Stream *s)
    379 {
    380 	ASSERT(s->data == a->beg);
    381 	s8 result = stream_to_s8(s);
    382 	arena_commit(a, result.len);
    383 	return result;
    384 }
    385 
    386 function s8
    387 arena_stream_commit_zero(Arena *a, Stream *s)
    388 {
    389 	b32 error = s->errors || s->widx == s->cap;
    390 	if (!error)
    391 		s->data[s->widx] = 0;
    392 	s8 result = stream_to_s8(s);
    393 	arena_commit(a, result.len + 1);
    394 	return result;
    395 }
    396 
    397 /* NOTE(rnp): FNV-1a hash */
    398 function u64
    399 s8_hash(s8 v)
    400 {
    401 	u64 h = 0x3243f6a8885a308d; /* digits of pi */
    402 	for (; v.len; v.len--) {
    403 		h ^= v.data[v.len - 1] & 0xFF;
    404 		h *= 1111111111111111111; /* random prime */
    405 	}
    406 	return h;
    407 }
    408 
    409 function s8
    410 c_str_to_s8(char *cstr)
    411 {
    412 	s8 result = {.data = (u8 *)cstr};
    413 	if (cstr) { while (*cstr) { result.len++; cstr++; } }
    414 	return result;
    415 }
    416 
    417 /* NOTE(rnp): returns < 0 if byte is not found */
    418 function iz
    419 s8_scan_backwards(s8 s, u8 byte)
    420 {
    421 	iz result = s.len;
    422 	while (result && s.data[result - 1] != byte) result--;
    423 	result--;
    424 	return result;
    425 }
    426 
    427 function s8
    428 s8_cut_head(s8 s, iz cut)
    429 {
    430 	s8 result = s;
    431 	if (cut > 0) {
    432 		result.data += cut;
    433 		result.len  -= cut;
    434 	}
    435 	return result;
    436 }
    437 
    438 function s8
    439 s8_alloc(Arena *a, iz len)
    440 {
    441 	s8 result = {.data = push_array(a, u8, len), .len = len};
    442 	return result;
    443 }
    444 
    445 function s8
    446 s16_to_s8(Arena *a, s16 in)
    447 {
    448 	s8 result = s8("");
    449 	if (in.len) {
    450 		iz commit = in.len * 4;
    451 		iz length = 0;
    452 		u8 *data = arena_commit(a, commit + 1);
    453 		u16 *beg = in.data;
    454 		u16 *end = in.data + in.len;
    455 		while (beg < end) {
    456 			UnicodeDecode decode = utf16_decode(beg, end - beg);
    457 			length += utf8_encode(data + length, decode.cp);
    458 			beg    += decode.consumed;
    459 		}
    460 		data[length] = 0;
    461 		result = (s8){.len = length, .data = data};
    462 		arena_pop(a, commit - length);
    463 	}
    464 	return result;
    465 }
    466 
    467 function s16
    468 s8_to_s16(Arena *a, s8 in)
    469 {
    470 	s16 result = {0};
    471 	if (in.len) {
    472 		iz required = 2 * in.len + 1;
    473 		u16 *data   = push_array(a, u16, required);
    474 		iz length   = 0;
    475 		/* TODO(rnp): utf8_decode */
    476 		for (iz i = 0; i < in.len; i++) {
    477 			u32 cp  = in.data[i];
    478 			length += utf16_encode(data + length, cp);
    479 		}
    480 		result = (s16){.len = length, .data = data};
    481 		arena_pop(a, required - length);
    482 	}
    483 	return result;
    484 }
    485 
    486 function s8
    487 push_s8(Arena *a, s8 str)
    488 {
    489 	s8 result = s8_alloc(a, str.len);
    490 	mem_copy(result.data, str.data, result.len);
    491 	return result;
    492 }
    493 
    494 function s8
    495 push_s8_zero(Arena *a, s8 str)
    496 {
    497 	s8 result   = s8_alloc(a, str.len + 1);
    498 	result.len -= 1;
    499 	mem_copy(result.data, str.data, result.len);
    500 	return result;
    501 }
    502 
    503 function u32
    504 round_down_power_of_2(u32 a)
    505 {
    506 	u32 result = 0x80000000UL >> clz_u32(a);
    507 	return result;
    508 }
    509 
    510 function u32
    511 round_up_power_of_2(u32 a)
    512 {
    513 	u32 result = 0x80000000UL >> (clz_u32(a - 1) - 1);
    514 	return result;
    515 }
    516 
    517 function iz
    518 round_up_to(iz value, iz multiple)
    519 {
    520 	iz result = value;
    521 	if (value % multiple != 0)
    522 		result += multiple - value % multiple;
    523 	return result;
    524 }
    525 
    526 function void
    527 split_rect_horizontal(Rect rect, f32 fraction, Rect *left, Rect *right)
    528 {
    529 	if (left) {
    530 		left->pos    = rect.pos;
    531 		left->size.h = rect.size.h;
    532 		left->size.w = rect.size.w * fraction;
    533 	}
    534 	if (right) {
    535 		right->pos    = rect.pos;
    536 		right->pos.x += rect.size.w * fraction;
    537 		right->size.h = rect.size.h;
    538 		right->size.w = rect.size.w * (1.0f - fraction);
    539 	}
    540 }
    541 
    542 function void
    543 split_rect_vertical(Rect rect, f32 fraction, Rect *top, Rect *bot)
    544 {
    545 	if (top) {
    546 		top->pos    = rect.pos;
    547 		top->size.w = rect.size.w;
    548 		top->size.h = rect.size.h * fraction;
    549 	}
    550 	if (bot) {
    551 		bot->pos    = rect.pos;
    552 		bot->pos.y += rect.size.h * fraction;
    553 		bot->size.w = rect.size.w;
    554 		bot->size.h = rect.size.h * (1.0f - fraction);
    555 	}
    556 }
    557 
    558 function void
    559 cut_rect_horizontal(Rect rect, f32 at, Rect *left, Rect *right)
    560 {
    561 	at = MIN(at, rect.size.w);
    562 	if (left) {
    563 		*left = rect;
    564 		left->size.w = at;
    565 	}
    566 	if (right) {
    567 		*right = rect;
    568 		right->pos.x  += at;
    569 		right->size.w -= at;
    570 	}
    571 }
    572 
    573 function void
    574 cut_rect_vertical(Rect rect, f32 at, Rect *top, Rect *bot)
    575 {
    576 	at = MIN(at, rect.size.h);
    577 	if (top) {
    578 		*top = rect;
    579 		top->size.h = at;
    580 	}
    581 	if (bot) {
    582 		*bot = rect;
    583 		bot->pos.y  += at;
    584 		bot->size.h -= at;
    585 	}
    586 }
    587 
    588 function f64
    589 parse_f64(s8 s)
    590 {
    591 	f64 integral = 0, fractional = 0, sign = 1;
    592 
    593 	if (s.len && *s.data == '-') {
    594 		sign = -1;
    595 		s.data++;
    596 		s.len--;
    597 	}
    598 
    599 	while (s.len && *s.data != '.') {
    600 		integral *= 10;
    601 		integral += *s.data - '0';
    602 		s.data++;
    603 		s.len--;
    604 	}
    605 
    606 	if (*s.data == '.') { s.data++; s.len--; }
    607 
    608 	while (s.len) {
    609 		ASSERT(s.data[s.len - 1] != '.');
    610 		fractional /= 10;
    611 		fractional += (f64)(s.data[--s.len] - '0') / 10.0;
    612 	}
    613 	f64 result = sign * (integral + fractional);
    614 	return result;
    615 }
    616 
    617 function FileWatchDirectory *
    618 lookup_file_watch_directory(FileWatchContext *ctx, u64 hash)
    619 {
    620 	FileWatchDirectory *result = 0;
    621 	for (u32 i = 0; i < ctx->count; i++) {
    622 		FileWatchDirectory *test = ctx->data + i;
    623 		if (test->hash == hash) {
    624 			result = test;
    625 			break;
    626 		}
    627 	}
    628 	return result;
    629 }