volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

util.c (10457B)


      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, uz size)
      5 {
      6 	u8 *p = p_;
      7 	while (size) 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 u8 *
     19 arena_commit(Arena *a, sz size)
     20 {
     21 	assert(a->end - a->beg >= size);
     22 	u8 *result = a->beg;
     23 	a->beg += size;
     24 	return result;
     25 }
     26 
     27 function void
     28 arena_pop(Arena *a, sz length)
     29 {
     30 	a->beg -= length;
     31 }
     32 
     33 #define push_array(a, t, n) (t *)arena_alloc(a, sizeof(t), alignof(t), n)
     34 #define push_struct(a, t)   (t *)arena_alloc(a, sizeof(t), alignof(t), 1)
     35 function void *
     36 arena_alloc(Arena *a, sz len, sz align, sz count)
     37 {
     38 	/* NOTE: special case 0 arena */
     39 	if (a->beg == 0)
     40 		return 0;
     41 
     42 	sz padding   = -(uintptr_t)a->beg & (align - 1);
     43 	sz available = a->end - a->beg - padding;
     44 	if (available < 0 || count > available / len)
     45 		assert(0 && "arena OOM\n");
     46 	void *p = a->beg + padding;
     47 	a->beg += padding + count * len;
     48 	/* TODO: Performance? */
     49 	return mem_clear(p, 0, count * len);
     50 }
     51 
     52 enum { DA_INITIAL_CAP = 4 };
     53 #define da_reserve(a, s, n) \
     54   (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \
     55                           _Alignof(typeof(*(s)->data)), sizeof(*(s)->data))
     56 
     57 #define da_push(a, s) \
     58   ((s)->count == (s)->capacity  \
     59     ? da_reserve(a, s, 1),      \
     60       (s)->data + (s)->count++  \
     61     : (s)->data + (s)->count++)
     62 
     63 function void *
     64 da_reserve_(Arena *a, void *data, sz *capacity, sz needed, sz align, sz size)
     65 {
     66 	sz cap = *capacity;
     67 
     68 	/* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started
     69 	 * on the stack or someone allocated something in the middle of the arena during usage) */
     70 	if (!data || a->beg != (u8 *)data + cap * size) {
     71 		void *copy = arena_alloc(a, size, align, cap);
     72 		if (data) mem_copy(copy, data, cap * size);
     73 		data = copy;
     74 	}
     75 
     76 	if (!cap) cap = DA_INITIAL_CAP;
     77 	while (cap < needed) cap *= 2;
     78 	arena_alloc(a, size, align, cap - *capacity);
     79 	*capacity = cap;
     80 	return data;
     81 }
     82 
     83 function sv2
     84 sv2_sub(sv2 a, sv2 b)
     85 {
     86 	sv2 result;
     87 	result.x = a.x - b.x;
     88 	result.y = a.y - b.y;
     89 	return result;
     90 }
     91 
     92 function v3
     93 v3_sub(v3 a, v3 b)
     94 {
     95 	v3 result;
     96 	result.x = a.x - b.x;
     97 	result.y = a.y - b.y;
     98 	result.z = a.z - b.z;
     99 	return result;
    100 }
    101 
    102 function f32
    103 v3_dot(v3 a, v3 b)
    104 {
    105 	f32 result = a.x * b.x + a.y * b.y + a.z * b.z;
    106 	return result;
    107 }
    108 
    109 function v3
    110 v3_normalize(v3 a)
    111 {
    112 	f32 scale   = sqrt_f32(1 / v3_dot(a, a));
    113 	v3  result  = a;
    114 	result.x   *= scale;
    115 	result.y   *= scale;
    116 	result.z   *= scale;
    117 	return result;
    118 }
    119 
    120 function v3
    121 cross(v3 a, v3 b)
    122 {
    123 	v3 result;
    124 	result.x = a.y * b.z - a.z * b.y;
    125 	result.y = a.z * b.x - a.x * b.z;
    126 	result.z = a.x * b.y - a.y * b.x;
    127 	return result;
    128 }
    129 
    130 function f32
    131 v4_dot(v4 a, v4 b)
    132 {
    133 	f32 result = 0;
    134 	result += a.x * b.x;
    135 	result += a.y * b.y;
    136 	result += a.z * b.z;
    137 	result += a.w * b.w;
    138 	return result;
    139 }
    140 
    141 function v4
    142 m4_row(m4 a, u32 row)
    143 {
    144 	v4 result;
    145 	result.E[0] = a.c[0].E[row];
    146 	result.E[1] = a.c[1].E[row];
    147 	result.E[2] = a.c[2].E[row];
    148 	result.E[3] = a.c[3].E[row];
    149 	return result;
    150 }
    151 
    152 function v4
    153 m4_column(m4 a, u32 column)
    154 {
    155 	v4 result = a.c[column];
    156 	return result;
    157 }
    158 
    159 function m4
    160 m4_mul(m4 a, m4 b)
    161 {
    162 	m4 result;
    163 	for (u32 i = 0; i < countof(result.E); i++) {
    164 		u32 base = i / 4;
    165 		u32 sub  = i % 4;
    166 		v4 v1 = m4_row(a, base);
    167 		v4 v2 = m4_column(b, sub);
    168 		result.E[i] = v4_dot(v1, v2);
    169 	}
    170 	return result;
    171 }
    172 
    173 function u32
    174 utf8_encode(u8 *out, u32 cp)
    175 {
    176 	u32 result = 1;
    177 	if (cp <= 0x7F) {
    178 		out[0] = cp & 0x7F;
    179 	} else if (cp <= 0x7FF) {
    180 		result = 2;
    181 		out[0] = ((cp >>  6) & 0x1F) | 0xC0;
    182 		out[1] = ((cp >>  0) & 0x3F) | 0x80;
    183 	} else if (cp <= 0xFFFF) {
    184 		result = 3;
    185 		out[0] = ((cp >> 12) & 0x0F) | 0xE0;
    186 		out[1] = ((cp >>  6) & 0x3F) | 0x80;
    187 		out[2] = ((cp >>  0) & 0x3F) | 0x80;
    188 	} else if (cp <= 0x10FFFF) {
    189 		result = 4;
    190 		out[0] = ((cp >> 18) & 0x07) | 0xF0;
    191 		out[1] = ((cp >> 12) & 0x3F) | 0x80;
    192 		out[2] = ((cp >>  6) & 0x3F) | 0x80;
    193 		out[3] = ((cp >>  0) & 0x3F) | 0x80;
    194 	} else {
    195 		out[0] = '?';
    196 	}
    197 	return result;
    198 }
    199 
    200 function UnicodeDecode
    201 utf16_decode(u16 *data, sz length)
    202 {
    203 	UnicodeDecode result = {.cp = U32_MAX};
    204 	if (length) {
    205 		result.consumed = 1;
    206 		result.cp = data[0];
    207 		if (length > 1 && BETWEEN(data[0], 0xD800, 0xDBFF)
    208 		               && BETWEEN(data[1], 0xDC00, 0xDFFF))
    209 		{
    210 			result.consumed = 2;
    211 			result.cp = ((data[0] - 0xD800) << 10) | ((data[1] - 0xDC00) + 0x10000);
    212 		}
    213 	}
    214 	return result;
    215 }
    216 
    217 function u32
    218 utf16_encode(u16 *out, u32 cp)
    219 {
    220 	u32 result = 1;
    221 	if (cp == U32_MAX) {
    222 		out[0] = '?';
    223 	} else if (cp < 0x10000) {
    224 		out[0] = cp;
    225 	} else {
    226 		u32 value = cp - 0x10000;
    227 		out[0] = 0xD800 + (value >> 10u);
    228 		out[1] = 0xDC00 + (value & 0x3FFu);
    229 		result = 2;
    230 	}
    231 	return result;
    232 }
    233 
    234 function Stream
    235 stream_alloc(Arena *a, sz cap)
    236 {
    237 	Stream result = {.cap = cap};
    238 	result.data = push_array(a, u8, cap);
    239 	return result;
    240 }
    241 
    242 function str8
    243 stream_to_str8(Stream *s)
    244 {
    245 	str8 result = str8("");
    246 	if (!s->errors) result = (str8){.len = s->widx, .data = s->data};
    247 	return result;
    248 }
    249 
    250 function void
    251 stream_reset(Stream *s, sz index)
    252 {
    253 	s->errors = s->cap <= index;
    254 	if (!s->errors)
    255 		s->widx = index;
    256 }
    257 
    258 function void
    259 stream_commit(Stream *s, sz count)
    260 {
    261 	s->errors |= !BETWEEN(s->widx + count, 0, s->cap);
    262 	if (!s->errors)
    263 		s->widx += count;
    264 }
    265 
    266 function void
    267 stream_append(Stream *s, void *data, sz count)
    268 {
    269 	s->errors |= (s->cap - s->widx) < count;
    270 	if (!s->errors) {
    271 		mem_copy(s->data + s->widx, data, count);
    272 		s->widx += count;
    273 	}
    274 }
    275 
    276 function void
    277 stream_append_byte(Stream *s, u8 b)
    278 {
    279 	stream_append(s, &b, 1);
    280 }
    281 
    282 function void
    283 stream_append_str8(Stream *s, str8 str)
    284 {
    285 	stream_append(s, str.data, str.len);
    286 }
    287 
    288 #define stream_append_str8s(s, ...) stream_append_str8s_(s, (str8 []){__VA_ARGS__}, \
    289                                                          sizeof((str8 []){__VA_ARGS__}) / sizeof(str8))
    290 function void
    291 stream_append_str8s_(Stream *s, str8 *strs, sz count)
    292 {
    293 	for (sz i = 0; i < count; i++)
    294 		stream_append(s, strs[i].data, strs[i].len);
    295 }
    296 
    297 function void
    298 stream_append_u64_width(Stream *s, u64 n, u64 min_width)
    299 {
    300 	u8 tmp[64];
    301 	u8 *end = tmp + sizeof(tmp);
    302 	u8 *beg = end;
    303 	min_width = MIN(sizeof(tmp), min_width);
    304 
    305 	do { *--beg = '0' + (n % 10); } while (n /= 10);
    306 	while (end - beg > 0 && end - beg < min_width)
    307 		*--beg = '0';
    308 
    309 	stream_append(s, beg, end - beg);
    310 }
    311 
    312 function void
    313 stream_append_u64(Stream *s, u64 n)
    314 {
    315 	stream_append_u64_width(s, n, 0);
    316 }
    317 
    318 function void
    319 stream_append_s64(Stream *s, s64 n)
    320 {
    321 	if (n < 0) {
    322 		stream_append_byte(s, '-');
    323 		n *= -1;
    324 	}
    325 	stream_append_u64(s, n);
    326 }
    327 
    328 function void
    329 stream_append_f64(Stream *s, f64 f, s64 prec)
    330 {
    331 	if (f < 0) {
    332 		stream_append_byte(s, '-');
    333 		f *= -1;
    334 	}
    335 
    336 	/* NOTE: round last digit */
    337 	f += 0.5f / prec;
    338 
    339 	if (f >= (f64)(-1UL >> 1)) {
    340 		stream_append_str8(s, str8("inf"));
    341 	} else {
    342 		u64 integral = f;
    343 		u64 fraction = (f - integral) * prec;
    344 		stream_append_u64(s, integral);
    345 		stream_append_byte(s, '.');
    346 		for (s64 i = prec / 10; i > 1; i /= 10) {
    347 			if (i > fraction)
    348 				stream_append_byte(s, '0');
    349 		}
    350 		stream_append_u64(s, fraction);
    351 	}
    352 }
    353 
    354 function Stream
    355 arena_stream(Arena a)
    356 {
    357 	Stream result = {0};
    358 	result.data   = a.beg;
    359 	result.cap    = a.end - a.beg;
    360 	return result;
    361 }
    362 
    363 function str8
    364 arena_stream_commit_zero(Arena *a, Stream *s)
    365 {
    366 	b32 error = s->errors || s->widx == s->cap;
    367 	if (!error)
    368 		s->data[s->widx] = 0;
    369 	str8 result = stream_to_str8(s);
    370 	arena_commit(a, result.len + 1);
    371 	return result;
    372 }
    373 
    374 
    375 /* NOTE(rnp): FNV-1a hash */
    376 function u64
    377 str8_hash(str8 v)
    378 {
    379 	u64 h = 0x3243f6a8885a308d; /* digits of pi */
    380 	for (; v.len; v.len--) {
    381 		h ^= v.data[v.len - 1] & 0xFF;
    382 		h *= 1111111111111111111; /* random prime */
    383 	}
    384 	return h;
    385 }
    386 
    387 function str8
    388 c_str_to_str8(char *cstr)
    389 {
    390 	str8 result = {.data = (u8 *)cstr};
    391 	if (cstr) while (*cstr) { cstr++; }
    392 	result.len = (u8 *)cstr - result.data;
    393 	return result;
    394 }
    395 
    396 /* NOTE(rnp): returns < 0 if byte is not found */
    397 function sz
    398 str8_scan_backwards(str8 s, u8 byte)
    399 {
    400 	sz result = s.len;
    401 	while (result && s.data[result - 1] != byte) result--;
    402 	result--;
    403 	return result;
    404 }
    405 
    406 function str8
    407 str8_cut_head(str8 s, sz cut)
    408 {
    409 	str8 result = s;
    410 	if (cut > 0) {
    411 		result.data += cut;
    412 		result.len  -= cut;
    413 	}
    414 	return result;
    415 }
    416 
    417 function str8
    418 str8_alloc(Arena *a, sz len)
    419 {
    420 	str8 result = {.data = push_array(a, u8, len), .len = len};
    421 	return result;
    422 }
    423 
    424 function str8
    425 str16_to_str8(Arena *a, str16 in)
    426 {
    427 	str8 result = str8("");
    428 	if (in.len) {
    429 		sz commit = in.len * 4;
    430 		sz length = 0;
    431 		u8 *data = arena_commit(a, commit + 1);
    432 		u16 *beg = in.data;
    433 		u16 *end = in.data + in.len;
    434 		while (beg < end) {
    435 			UnicodeDecode decode = utf16_decode(beg, end - beg);
    436 			length += utf8_encode(data + length, decode.cp);
    437 			beg    += decode.consumed;
    438 		}
    439 		data[length] = 0;
    440 		result = (str8){.len = length, .data = data};
    441 		arena_pop(a, commit - length);
    442 	}
    443 	return result;
    444 }
    445 
    446 function str16
    447 str8_to_str16(Arena *a, str8 in)
    448 {
    449 	str16 result = {0};
    450 	if (in.len) {
    451 		sz required = 2 * in.len + 1;
    452 		u16 *data   = push_array(a, u16, required);
    453 		sz length   = 0;
    454 		/* TODO(rnp): utf8_decode */
    455 		for (sz i = 0; i < in.len; i++) {
    456 			u32 cp  = in.data[i];
    457 			length += utf16_encode(data + length, cp);
    458 		}
    459 		result = (str16){.len = length, .data = data};
    460 		arena_pop(a, required - length);
    461 	}
    462 	return result;
    463 }
    464 
    465 function str8
    466 push_str8(Arena *a, str8 str)
    467 {
    468 	str8 result = str8_alloc(a, str.len);
    469 	mem_copy(result.data, str.data, result.len);
    470 	return result;
    471 }
    472 
    473 function str8
    474 push_str8_zero(Arena *a, str8 str)
    475 {
    476 	str8 result  = str8_alloc(a, str.len + 1);
    477 	result.len  -= 1;
    478 	mem_copy(result.data, str.data, result.len);
    479 	return result;
    480 }
    481 
    482 function f64
    483 parse_f64(str8 s)
    484 {
    485 	f64 integral = 0, fractional = 0, sign = 1;
    486 
    487 	if (s.len && *s.data == '-') {
    488 		sign = -1;
    489 		s.data++;
    490 		s.len--;
    491 	}
    492 
    493 	while (s.len && *s.data != '.') {
    494 		integral *= 10;
    495 		integral += *s.data - '0';
    496 		s.data++;
    497 		s.len--;
    498 	}
    499 
    500 	if (*s.data == '.') { s.data++; s.len--; }
    501 
    502 	while (s.len) {
    503 		assert(s.data[s.len - 1] != '.');
    504 		fractional /= 10;
    505 		fractional += (f64)(s.data[--s.len] - '0') / 10.0;
    506 	}
    507 	f64 result = sign * (integral + fractional);
    508 	return result;
    509 }
    510 
    511 function FileWatchDirectory *
    512 lookup_file_watch_directory(FileWatchContext *ctx, u64 hash)
    513 {
    514 	FileWatchDirectory *result = 0;
    515 	for (u32 i = 0; i < ctx->count; i++) {
    516 		FileWatchDirectory *test = ctx->data + i;
    517 		if (test->hash == hash) {
    518 			result = test;
    519 			break;
    520 		}
    521 	}
    522 	return result;
    523 }