antizona

antizona - Minimalist 3D software-rendered multiplayer engine for GTA: San Andreas in pure C99
Log | Files | Refs | README

build.c (60794B)


      1 #include <sys/mman.h>
      2 #include <sys/stat.h>
      3 #include <sys/types.h>
      4 
      5 #include <ctype.h>
      6 #include <dirent.h>
      7 #include <err.h>
      8 #include <fcntl.h>
      9 #include <math.h>
     10 #include <pthread.h>
     11 #include <stdio.h>
     12 #include <stdint.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <unistd.h>
     16 
     17 #include "skins.h"
     18 
     19 #define COL_HASH_SZ	65536
     20 #define GRID_SZ		64
     21 #define MAP_MAX		3000.0f
     22 #define MAP_MIN		-3000.0f
     23 #define MAX_COL_MODELS	32768
     24 #define MAX_FILES	32768
     25 #define NAME_SZ		24
     26 #define PATH_CACHE_SZ	16384
     27 #define PATH_DB_SZ	65536
     28 
     29 
     30 struct col_cell {
     31 	struct col_triangle	*tris;
     32 	uint32_t		count;
     33 	uint32_t		capacity;
     34 };
     35 
     36 struct col_header {
     37 	char		magic[4];
     38 	uint32_t	size;
     39 	char		model_name[22];
     40 	uint16_t	model_id;
     41 	float		radius;
     42 	float		center[3];
     43 	float		min[3];
     44 	float		max[3];
     45 	uint16_t	num_spheres;
     46 	uint16_t	num_boxes;
     47 	uint16_t	num_faces;
     48 	uint8_t		num_lines;
     49 	uint8_t		pad;
     50 	uint32_t	flags;
     51 	uint32_t	spheres_offset;
     52 	uint32_t	boxes_offset;
     53 	uint32_t	lines_offset;
     54 	uint32_t	vertices_offset;
     55 	uint32_t	faces_offset;
     56 	uint32_t	shadow_offset;
     57 } __attribute__((packed));
     58 
     59 struct col_model {
     60 	char			name[NAME_SZ];
     61 	struct col_triangle	*tris;
     62 	uint32_t		num_tris;
     63 };
     64 
     65 struct col_triangle {
     66 	float		v0[3];
     67 	float		v1[3];
     68 	float		v2[3];
     69 	float		norm[3];
     70 	uint8_t		surface;
     71 };
     72 
     73 struct file_list {
     74 	char	names[MAX_FILES][NAME_SZ];
     75 	int	count;
     76 };
     77 
     78 struct img_header {
     79 	char		magic[4];
     80 	uint32_t	entries;
     81 };
     82 
     83 struct img_entry {
     84 	uint32_t	offset;
     85 	uint16_t	size;
     86 	uint16_t	size2;
     87 	char		name[24];
     88 };
     89 
     90 struct ide_entry {
     91 	int	id;
     92 	char	model[NAME_SZ];
     93 	char	txd[NAME_SZ];
     94 	int	time_on;
     95 	int	time_off;
     96 };
     97 
     98 struct mstream {
     99 	const uint8_t *data;
    100 	size_t		 size;
    101 	size_t		 pos;
    102 };
    103 
    104 struct path_entry {
    105 	char	key[512];
    106 	char	resolved[1024];
    107 };
    108 
    109 struct raw_col_box {
    110 	float		min[3];
    111 	float		max[3];
    112 	uint8_t		surface;
    113 	uint8_t		piece;
    114 	uint8_t		lighting;
    115 	uint8_t		pad;
    116 } __attribute__((packed));
    117 
    118 struct raw_col_face {
    119 	uint16_t	a;
    120 	uint16_t	b;
    121 	uint16_t	c;
    122 	uint8_t		surface;
    123 	uint8_t		piece;
    124 } __attribute__((packed));
    125 
    126 struct raw_col_vertex {
    127 	int16_t		x;
    128 	int16_t		y;
    129 	int16_t		z;
    130 } __attribute__((packed));
    131 
    132 struct rw_header {
    133 	uint32_t	type;
    134 	uint32_t	size;
    135 	uint32_t	version;
    136 } __attribute__((packed));
    137 
    138 struct special_actor {
    139 	int id;
    140 	const char *model;
    141 	const char *txd;
    142 };
    143 
    144 struct mat4 { float m[4][4]; };
    145 struct rw_triangle { uint16_t v1, v2, m, v3; };
    146 struct atomic_entry { uint32_t f, g; };
    147 struct tex_name { char name[32]; };
    148 
    149 struct water_face {
    150 	float	x[4], y[4], z[4];
    151 	float	u[4], v[4], h[4];
    152 	int	num;
    153 };
    154 
    155 struct timecyc_entry {
    156 	uint8_t	amb[3];
    157 	uint8_t	dir[3];
    158 	uint8_t	sky_top[3];
    159 	uint8_t	sky_bot[3];
    160 	uint8_t	water[4];
    161 	float	far_clp;
    162 	float	fog_st;
    163 };
    164 
    165 struct arena {
    166 	uint8_t	*mem;
    167 	size_t	 pos;
    168 	size_t	 size;
    169 };
    170 
    171 struct thread_arg {
    172 	const uint8_t		*img_data;
    173 	struct img_entry	*entries;
    174 	uint32_t		 start;
    175 	uint32_t		 end;
    176 	struct file_list	*fl;
    177 	struct arena		 arena;
    178 };
    179 
    180 struct tga_header {
    181 	uint8_t  id_length;
    182 	uint8_t  color_map_type;
    183 	uint8_t  image_type;
    184 	uint16_t color_map_first;
    185 	uint16_t color_map_length;
    186 	uint8_t  color_map_entry_size;
    187 	uint16_t x_origin;
    188 	uint16_t y_origin;
    189 	uint16_t width;
    190 	uint16_t height;
    191 	uint8_t  pixel_depth;
    192 	uint8_t  image_descriptor;
    193 } __attribute__((packed));
    194 
    195 struct tar_header {
    196 	char name[100];
    197 	char mode[8];
    198 	char uid[8];
    199 	char gid[8];
    200 	char size[12];
    201 	char mtime[12];
    202 	char chksum[8];
    203 	char typeflag;
    204 	char linkname[100];
    205 	char magic[6];
    206 	char version[2];
    207 	char uname[32];
    208 	char gname[32];
    209 	char devmajor[8];
    210 	char devminor[8];
    211 	char prefix[155];
    212 	char pad[12];
    213 } __attribute__((packed));
    214 
    215 static struct ide_entry		ide_db[65536];
    216 static int			ide_count = 0;
    217 
    218 static struct col_cell		world_col_grid[GRID_SZ][GRID_SZ];
    219 static struct col_model		col_db[MAX_COL_MODELS];
    220 static int			col_db_count = 0;
    221 static int			col_hash[COL_HASH_SZ];
    222 
    223 static char			existing_models[32768][NAME_SZ];
    224 static int			existing_models_count = 0;
    225 static char			existing_textures[32768][NAME_SZ];
    226 static int			existing_textures_count = 0;
    227 
    228 static struct water_face	water_db[8192];
    229 static int			water_face_count = 0;
    230 
    231 static const struct special_actor special_actors[] = {
    232 	{ 1, "truth", "truth" },
    233 	{ 2, "maccer", "maccer" },
    234 	{ 3, "andre", "andre" },
    235 	{ 4, "bbthin", "bbthin" },
    236 	{ 5, "bb", "bb" },
    237 	{ 6, "emmet", "emmet" },
    238 	{ 8, "janitor", "janitor" },
    239 	{ 290, "rose", "rose" },
    240 	{ 291, "paul", "paul" },
    241 	{ 292, "cesar", "cesar" },
    242 	{ 293, "ogloc", "ogloc" },
    243 	{ 294, "wuzimu", "wuzimu" },
    244 	{ 295, "toreno", "toreno" },
    245 	{ 296, "jizzy", "jizzy" },
    246 	{ 297, "maddogg", "maddogg" },
    247 	{ 298, "cat", "cat" },
    248 	{ 299, "claude", "claude" },
    249 	{ 300, "ryder2", "ryder" },
    250 	{ 301, "ryder3", "ryder" },
    251 	{ 302, "emmet", "emmet" },
    252 	{ 303, "andre", "andre" },
    253 	{ 304, "kendl", "kendl" },
    254 	{ 305, "jethro", "jethro" },
    255 	{ 306, "zero", "zero" },
    256 	{ 307, "tbone", "tbone" },
    257 	{ 308, "maccer", "maccer" },
    258 	{ 309, "forelli", "forelli" },
    259 	{ 310, "sweet", "sweet" },
    260 	{ 311, "smoke", "smoke" },
    261 	{ 312, "ryder", "ryder" }
    262 };
    263 
    264 static void
    265 to_lower_str(char *str)
    266 {
    267 	while (*str) {
    268 		*str = tolower((unsigned char)*str);
    269 		str++;
    270 	}
    271 }
    272 
    273 static void
    274 scan_existing_assets(void)
    275 {
    276 	DIR *dir;
    277 	struct dirent *de;
    278 	char *ext;
    279 	size_t len;
    280 
    281 	dir = opendir("assets/models");
    282 	if (dir) {
    283 		while ((de = readdir(dir))) {
    284 			ext = strrchr(de->d_name, '.');
    285 			if (ext && strcasecmp(ext, ".ply") == 0 &&
    286 			    existing_models_count < 32768) {
    287 				len = ext - de->d_name;
    288 				if (len >= NAME_SZ) {
    289 					len = NAME_SZ - 1;
    290 				}
    291 				memcpy(existing_models[existing_models_count],
    292 				    de->d_name, len);
    293 				existing_models[existing_models_count][len] = '\0';
    294 				to_lower_str(existing_models[existing_models_count]);
    295 				existing_models_count++;
    296 			}
    297 		}
    298 		closedir(dir);
    299 	}
    300 
    301 	dir = opendir("assets/textures");
    302 	if (dir) {
    303 		while ((de = readdir(dir))) {
    304 			ext = strrchr(de->d_name, '.');
    305 			if (ext && strcasecmp(ext, ".tga") == 0 &&
    306 			    existing_textures_count < 32768) {
    307 				len = ext - de->d_name;
    308 				if (len >= NAME_SZ) {
    309 					len = NAME_SZ - 1;
    310 				}
    311 				memcpy(existing_textures[existing_textures_count],
    312 				    de->d_name, len);
    313 				existing_textures[existing_textures_count][len] = '\0';
    314 				to_lower_str(existing_textures[existing_textures_count]);
    315 				existing_textures_count++;
    316 			}
    317 		}
    318 		closedir(dir);
    319 	}
    320 }
    321 	
    322 static int
    323 asset_cached(const char *name, int is_model)
    324 {
    325 	char base[NAME_SZ];
    326 	size_t len;
    327 	int i;
    328 
    329 	len = strlen(name);
    330 	if (len < 5) {
    331 		return (0);
    332 	}
    333 
    334 	strncpy(base, name, len - 4);
    335 	base[len - 4] = '\0';
    336 	to_lower_str(base);
    337 
    338 	if (is_model) {
    339 		for (i = 0; i < existing_models_count; i++) {
    340 			if (strcmp(existing_models[i], base) == 0) {
    341 				return (1);
    342 			}
    343 		}
    344 	} else {
    345 
    346 	for (i = 0; i < existing_textures_count; i++) {
    347 			if (strcmp(existing_textures[i], base) == 0) {
    348 				return (1);
    349 			}
    350 		}
    351 	}
    352 	return (0);
    353 }
    354 
    355 static int
    356 asset_exists(const char *name)
    357 {
    358 	if (strstr(name, ".dff") || strstr(name, ".DFF")) {
    359 		return (asset_cached(name, 1));
    360 	}
    361 	if (strstr(name, ".txd") || strstr(name, ".TXD")) {
    362 		return (asset_cached(name, 0));
    363 	}
    364 	return (0);
    365 }
    366 
    367 static void *
    368 arena_alloc(struct arena *a, size_t sz)
    369 {
    370 	size_t align;
    371 	void *ptr;
    372 
    373 	align = (sz + 7) & ~7;
    374 	if (a->pos + align > a->size) {
    375 		errx(1, "OOM arena");
    376 	}
    377 	ptr = a->mem + a->pos;
    378 	a->pos += align;
    379 	return (ptr);
    380 }
    381 #define A_ALLOC(a, type, count) (type *)arena_alloc((a), sizeof(type) * (count))
    382 
    383 static size_t
    384 mread(void *dst, size_t sz, size_t n, struct mstream *s)
    385 {
    386 	size_t bytes;
    387 
    388 	bytes = sz * n;
    389 	if (s->pos + bytes <= s->size) {
    390 		memcpy(dst, s->data + s->pos, bytes);
    391 		s->pos += bytes;
    392 		return (n);
    393 	}
    394 	return (0);
    395 }
    396 
    397 static void
    398 mat_identity(struct mat4 *m)
    399 {
    400 	memset(m, 0, sizeof(*m));
    401 	m->m[0][0] = 1.0f;
    402 	m->m[1][1] = 1.0f;
    403 	m->m[2][2] = 1.0f;
    404 	m->m[3][3] = 1.0f;
    405 }
    406 
    407 static inline void
    408 mat_mul(struct mat4 *dst, const struct mat4 *a, const struct mat4 *b)
    409 {
    410 	struct mat4 r;
    411 	int i;
    412 
    413 	for (i = 0; i < 4; i++) {
    414 		r.m[i][0] = a->m[i][0]*b->m[0][0] + a->m[i][1]*b->m[1][0] +
    415 		    a->m[i][2]*b->m[2][0] + a->m[i][3]*b->m[3][0];
    416 		r.m[i][1] = a->m[i][0]*b->m[0][1] + a->m[i][1]*b->m[1][1] +
    417 		    a->m[i][2]*b->m[2][1] + a->m[i][3]*b->m[3][1];
    418 		r.m[i][2] = a->m[i][0]*b->m[0][2] + a->m[i][1]*b->m[1][2] +
    419 		    a->m[i][2]*b->m[2][2] + a->m[i][3]*b->m[3][2];
    420 		r.m[i][3] = a->m[i][0]*b->m[0][3] + a->m[i][1]*b->m[1][3] +
    421 		    a->m[i][2]*b->m[2][3] + a->m[i][3]*b->m[3][3];
    422 	}
    423 	*dst = r;
    424 }
    425 
    426 static int
    427 resolve_simple(const char *root, const char *rel, char *out, size_t out_sz)
    428 {
    429 	DIR *dir;
    430 	struct dirent *de;
    431 	char path[1024];
    432 	char tmp[1024];
    433 	char *seg, *saveptr;
    434 	int found;
    435 
    436 	if (snprintf(path, sizeof(path), "%s", root) >= (int)sizeof(path)) {
    437 		return (0);
    438 	}
    439 	strncpy(tmp, rel, sizeof(tmp) - 1);
    440 	tmp[sizeof(tmp) - 1] = '\0';
    441 
    442 	seg = strtok_r(tmp, "/", &saveptr);
    443 	while (seg) {
    444 		dir = opendir(path);
    445 		if (!dir) {
    446 			return (0);
    447 		}
    448 		found = 0;
    449 		while ((de = readdir(dir))) {
    450 			if (strcasecmp(de->d_name, seg) == 0) {
    451 				if (snprintf(path + strlen(path),
    452 				    sizeof(path) - strlen(path), "/%s",
    453 				    de->d_name) >= (int)(sizeof(path) - strlen(path))) {
    454 					closedir(dir);
    455 					return (0);
    456 				}
    457 				found = 1;
    458 				break;
    459 			}
    460 		}
    461 		closedir(dir);
    462 		if (!found) {
    463 			return (0);
    464 		}
    465 		seg = strtok_r(NULL, "/", &saveptr);
    466 	}
    467 
    468 	strncpy(out, path, out_sz - 1);
    469 	out[out_sz - 1] = '\0';
    470 	return (1);
    471 }
    472 
    473 static FILE *
    474 fopen_simple(const char *root, const char *rel)
    475 {
    476 	char resolved[1024];
    477 
    478 	if (resolve_simple(root, rel, resolved, sizeof(resolved))) {
    479 		return (fopen(resolved, "rb"));
    480 	}
    481 	return (NULL);
    482 }
    483 
    484 static void
    485 trim_spaces(char *str)
    486 {
    487 	char *start = str;
    488 	size_t len;
    489 	char *end;
    490 
    491 	while (*start == ' ' || *start == '\t') {
    492 		start++;
    493 	}
    494 	if (start != str) {
    495 		memmove(str, start, strlen(start) + 1);
    496 	}
    497 
    498 	len = strlen(str);
    499 	if (len == 0) {
    500 		return;
    501 	}
    502 
    503 	end = str + len - 1;
    504 	while (end >= str && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n')) {
    505 		*end = '\0';
    506 		end--;
    507 	}
    508 }
    509 
    510 static int
    511 list_has(struct file_list *l, const char *name)
    512 {
    513 	int i;
    514 
    515 	for (i = 0; i < l->count; i++) {
    516 		if (strcasecmp(l->names[i], name) == 0) {
    517 			return (1);
    518 		}
    519 	}
    520 	return (0);
    521 }
    522 
    523 static void
    524 list_add(struct file_list *l, const char *name)
    525 {
    526 	size_t len, i;
    527 
    528 	if (l->count >= MAX_FILES || list_has(l, name)) {
    529 		return;
    530 	}
    531 	len = strlen(name);
    532 	if (len >= NAME_SZ) {
    533 		len = NAME_SZ - 1;
    534 	}
    535 	for (i = 0; i < len; i++) {
    536 		l->names[l->count][i] = tolower((unsigned char)name[i]);
    537 	}
    538 	l->names[l->count][len] = '\0';
    539 	l->count++;
    540 }
    541 
    542 static void
    543 clean_ide_line(char *p)
    544 {
    545 	char *comment;
    546 	char *end;
    547 	size_t len;
    548 
    549 	comment = strchr(p, '#');
    550 	if (comment) {
    551 		*comment = '\0';
    552 	}
    553 
    554 	len = strlen(p);
    555 	if (len == 0) {
    556 		return;
    557 	}
    558 
    559 	end = p + len - 1;
    560 	while (end >= p && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n')) {
    561 		*end = '\0';
    562 		end--;
    563 	}
    564 }
    565 
    566 static void
    567 preparse_ide(const char *root, const char *rel, struct file_list *fl)
    568 {
    569 	FILE *f;
    570 	char line[512];
    571 	char *p;
    572 	int in_tobj = 0;
    573 	int in_peds = 0;
    574 
    575 	f = fopen_simple(root, rel);
    576 	if (!f) {
    577 		return;
    578 	}
    579 
    580 	while (fgets(line, sizeof(line), f)) {
    581 		p = line;
    582 		line[strcspn(line, "\r\n")] = '\0';
    583 		while (*p == ' ' || *p == '\t') {
    584 			p++;
    585 		}
    586 		if (*p == '\0' || *p == '#') {
    587 			continue;
    588 		}
    589 
    590 		if (strncasecmp(p, "objs", 4) == 0) {
    591 			in_tobj = 0;
    592 			in_peds = 0;
    593 			continue;
    594 		}
    595 		if (strncasecmp(p, "cars", 4) == 0) {
    596 			in_tobj = 0;
    597 			in_peds = 0;
    598 			continue;
    599 		}
    600 		if (strncasecmp(p, "peds", 4) == 0) {
    601 			in_tobj = 0;
    602 			in_peds = 1;
    603 			continue;
    604 		}
    605 		if (strncasecmp(p, "tobj", 4) == 0) {
    606 			in_tobj = 1;
    607 			in_peds = 0;
    608 			continue;
    609 		}
    610 		if (strncasecmp(p, "end", 3) == 0) {
    611 			in_tobj = 0;
    612 			in_peds = 0;
    613 			continue;
    614 		}
    615 
    616 		if (isdigit((unsigned char)p[0]) && ide_count < 65536) {
    617 			char model[NAME_SZ], txd[NAME_SZ];
    618 			char *c1, *c2, *c3;
    619 			char *last_comma, *prev_comma;
    620 			size_t len;
    621 			int time_on = 0, time_off = 0;
    622 
    623 			c1 = strchr(p, ',');
    624 			if (!c1) continue;
    625 			c2 = strchr(c1 + 1, ',');
    626 			if (!c2) continue;
    627 			c3 = strchr(c2 + 1, ',');
    628 			if (!c3) continue;
    629 
    630 			len = c2 - (c1 + 1);
    631 			if (len >= NAME_SZ) {
    632 				len = NAME_SZ - 1;
    633 			}
    634 			memcpy(model, c1 + 1, len);
    635 			model[len] = '\0';
    636 			trim_spaces(model);
    637 			to_lower_str(model);
    638 
    639 			len = c3 - (c2 + 1);
    640 			if (len >= NAME_SZ) {
    641 				len = NAME_SZ - 1;
    642 			}
    643 			memcpy(txd, c2 + 1, len);
    644 			txd[len] = '\0';
    645 			trim_spaces(txd);
    646 			to_lower_str(txd);
    647 
    648 			if (in_tobj) {
    649 				char temp_line[512];
    650 				strncpy(temp_line, p, sizeof(temp_line) - 1);
    651 				temp_line[sizeof(temp_line) - 1] = '\0';
    652 				clean_ide_line(temp_line);
    653 
    654 				last_comma = strrchr(temp_line, ',');
    655 				if (last_comma) {
    656 					time_off = atoi(last_comma + 1);
    657 					*last_comma = '\0';
    658 					prev_comma = strrchr(temp_line, ',');
    659 					if (prev_comma) {
    660 						time_on = atoi(prev_comma + 1);
    661 					}
    662 					*last_comma = ',';
    663 				}
    664 			}
    665 
    666 			if (in_peds && fl) {
    667 				char d_name[32], t_name[32];
    668 				snprintf(d_name, sizeof(d_name), "%s.dff", model);
    669 				snprintf(t_name, sizeof(t_name), "%s.txd", txd);
    670 				list_add(fl, d_name);
    671 				list_add(fl, t_name);
    672 			}
    673 
    674 			ide_db[ide_count].id = atoi(p);
    675 			strncpy(ide_db[ide_count].model, model, NAME_SZ);
    676 			strncpy(ide_db[ide_count].txd, txd, NAME_SZ);
    677 			ide_db[ide_count].time_on = time_on;
    678 			ide_db[ide_count].time_off = time_off;
    679 			ide_count++;
    680 		}
    681 	}
    682 	fclose(f);
    683 }
    684 
    685 
    686 static const struct ide_entry *
    687 ide_lookup(int id)
    688 {
    689 	int i;
    690 
    691 	for (i = 0; i < ide_count; i++) {
    692 		if (ide_db[i].id == id) {
    693 			return (&ide_db[i]);
    694 		}
    695 	}
    696 	return (NULL);
    697 }
    698 
    699 static int
    700 is_lod_name(const char *name)
    701 {
    702 	return (strstr(name, "lod") != NULL);
    703 }
    704 
    705 static void
    706 parse_text_ipl(const char *buf, size_t size, FILE *out, struct file_list *fl)
    707 {
    708 	const char *p, *end, *next;
    709 	char line[512];
    710 	char *s, *comma;
    711 	size_t len;
    712 	int in_inst;
    713 
    714 	p = buf;
    715 	end = buf + size;
    716 	in_inst = 0;
    717 
    718 	while (p < end) {
    719 		next = memchr(p, '\n', end - p);
    720 		len = next ? (size_t)(next - p) : (size_t)(end - p);
    721 		if (len >= sizeof(line)) {
    722 			len = sizeof(line) - 1;
    723 		}
    724 		memcpy(line, p, len);
    725 		line[len] = '\0';
    726 		p = next ? next + 1 : end;
    727 
    728 		s = line;
    729 		while (*s == ' ' || *s == '\t' || *s == '\r') {
    730 			s++;
    731 		}
    732 		if (*s == '\0' || *s == '#') {
    733 			continue;
    734 		}
    735 
    736 		if (strncasecmp(s, "inst", 4) == 0 || strncasecmp(s, "tobj", 4) == 0) {
    737 			in_inst = 1;
    738 			fprintf(out, "\ninst\n");
    739 			continue;
    740 		}
    741 		if (strncasecmp(s, "end", 3) == 0) {
    742 			in_inst = 0;
    743 			fprintf(out, "end\n");
    744 			continue;
    745 		}
    746 
    747 		if (in_inst) {
    748 			int id;
    749 			const struct ide_entry *ide;
    750 
    751 			id = atoi(s);
    752 			ide = ide_lookup(id);
    753 			if (ide && (!is_lod_name(ide->model) || ide->time_on != ide->time_off)) {
    754 				char d_name[32], t_name[32];
    755 
    756 				snprintf(d_name, sizeof(d_name), "%s.dff", ide->model);
    757 				snprintf(t_name, sizeof(t_name), "%s.txd", ide->txd);
    758 				list_add(fl, d_name);
    759 				list_add(fl, t_name);
    760 
    761 				comma = strchr(s, ',');
    762 				if (comma) {
    763 					int dummy_id;
    764 					char dummy_model[64];
    765 					int interior;
    766 					float px, py, pz, rx, ry, rz, rw;
    767 
    768 					if (sscanf(s, "%d, %63[^,], %d, %f, "
    769 					    "%f, %f, %f, %f, %f, %f",
    770 					    &dummy_id, dummy_model, &interior,
    771 					    &px, &py, &pz, &rx, &ry, &rz, &rw) == 10) {
    772 						fprintf(out, "%d, %s, %d, %f, "
    773 						    "%f, %f, %f, %f, %f, %f, "
    774 						    "-1, %d, %d\n",
    775 						    id, ide->model, interior,
    776 						    px, py, pz, rx, ry, rz, rw,
    777 						    ide->time_on, ide->time_off);
    778 					}
    779 				}
    780 			}
    781 		}
    782 	}
    783 }
    784 
    785 static void
    786 parse_binary_ipl(const uint8_t *buf, size_t size, FILE *out, struct file_list *fl)
    787 {
    788 	uint32_t num, off, i;
    789 
    790 	memcpy(&num, buf + 4, 4);
    791 	memcpy(&off, buf + 28, 4);
    792 	if (off + num * 40 > size) {
    793 		return;
    794 	}
    795 
    796 	fprintf(out, "\ninst\n");
    797 	for (i = 0; i < num; i++) {
    798 		struct {
    799 			float px, py, pz, rx, ry, rz, rw;
    800 			int32_t id, interior, lod;
    801 		} inst;
    802 		const struct ide_entry *ide;
    803 
    804 		memcpy(&inst, buf + off + i * 40, 40);
    805 
    806 		ide = ide_lookup(inst.id);
    807 		if (ide && (!is_lod_name(ide->model) || ide->time_on != ide->time_off)) {
    808 			char d_name[32], t_name[32];
    809 
    810 			snprintf(d_name, sizeof(d_name), "%s.dff", ide->model);
    811 			snprintf(t_name, sizeof(t_name), "%s.txd", ide->txd);
    812 			list_add(fl, d_name);
    813 			list_add(fl, t_name);
    814 
    815 			fprintf(out, "%d, %s, %d, %f, %f, %f, %f, %f, %f, %f, "
    816 			    "-1, %d, %d\n",
    817 			    inst.id, ide->model, inst.interior,
    818 			    inst.px, inst.py, inst.pz, inst.rx, inst.ry,
    819 			    inst.rz, inst.rw, ide->time_on, ide->time_off);
    820 		}
    821 	}
    822 	fprintf(out, "end\n");
    823 }
    824 
    825 static void
    826 blur_pixels(uint32_t *pixels, int w, int h)
    827 {
    828 	uint32_t *temp;
    829 	int x, y, kx, ky, px, py, count;
    830 	uint32_t r_sum, g_sum, b_sum, a_sum, c;
    831 
    832 	temp = malloc(w * h * 4);
    833 	if (!temp) {
    834 		return;
    835 	}
    836 	memcpy(temp, pixels, w * h * 4);
    837 
    838 	for (y = 0; y < h; y++) {
    839 		for (x = 0; x < w; x++) {
    840 			r_sum = 0;
    841 			g_sum = 0;
    842 			b_sum = 0;
    843 			a_sum = 0;
    844 			count = 0;
    845 			for (ky = -1; ky <= 1; ky++) {
    846 				for (kx = -1; kx <= 1; kx++) {
    847 					px = x + kx;
    848 					py = y + ky;
    849 					if (px >= 0 && px < w && py >= 0 &&
    850 					    py < h) {
    851 						c = temp[py * w + px];
    852 						b_sum += (c & 0xFF);
    853 						g_sum += ((c >> 8) & 0xFF);
    854 						r_sum += ((c >> 16) & 0xFF);
    855 						a_sum += ((c >> 24) & 0xFF);
    856 						count++;
    857 					}
    858 				}
    859 			}
    860 			pixels[y * w + x] = (b_sum/count) |
    861 			    ((g_sum/count) << 8) | ((r_sum/count) << 16) |
    862 			    ((a_sum/count) << 24);
    863 		}
    864 	}
    865 	free(temp);
    866 }
    867 
    868 static int
    869 nearest_pow2(int x)
    870 {
    871 	int p = 1;
    872 
    873 	while (p * 2 <= x) {
    874 		p *= 2;
    875 	}
    876 	if (x - p < p * 2 - x) {
    877 		return (p);
    878 	}
    879 	return (p * 2);
    880 }
    881 
    882 static void
    883 convert_txd(const uint8_t *data, size_t size, const char *name, struct arena *a)
    884 {
    885 	struct mstream ms = { data, size, 0 };
    886 	struct rw_header h, sh;
    887 	struct {
    888 		uint32_t plt, flt; char n[32], m[32]; uint32_t fmt; char fcc[4];
    889 		uint16_t w, h; uint8_t d, lvl, typ, cmp;
    890 	} __attribute__((packed)) rh;
    891 	uint32_t mip_size, p_size, *pixels, code, cols[4], pal[256];
    892 	uint8_t *cmp, r0, g0, b0, r1, g1, b1, a_val, *src, *indices;
    893 	uint16_t c0, c1, *src16;
    894 	size_t chunk_end;
    895 	int bx, by, is_dxt3, x, y, i, j, k, pal_has_alpha;
    896 	char t_name[32], out_name[256];
    897 	FILE *out;
    898 	struct tga_header out_hdr;
    899 	uint32_t *final_pixels;
    900 	int new_w, new_h, sy, sx;
    901 
    902 	while (mread(&h, sizeof(h), 1, &ms) == 1) {
    903 		chunk_end = ms.pos + h.size;
    904 		if (h.type == 0x16) {
    905 			continue;
    906 		}
    907 
    908 		if (h.type == 0x15) {
    909 			if (mread(&sh, sizeof(sh), 1, &ms) != 1) {
    910 				break;
    911 			}
    912 			if (mread(&rh, sizeof(rh), 1, &ms) != 1) {
    913 				break;
    914 			}
    915 
    916 			if (rh.plt != 9 && rh.plt != 8) {
    917 				ms.pos = chunk_end;
    918 				continue;
    919 			}
    920 
    921 			if (rh.d == 8) {
    922 				if (mread(pal, 4, 256, &ms) != 256) {
    923 					break;
    924 				}
    925 				pal_has_alpha = 0;
    926 				for (k = 0; k < 256; k++) {
    927 					if ((pal[k] >> 24) != 0) {
    928 						pal_has_alpha = 1;
    929 						break;
    930 					}
    931 				}
    932 				if (!pal_has_alpha) {
    933 					for (k = 0; k < 256; k++) {
    934 						pal[k] |= (255U << 24);
    935 					}
    936 				}
    937 			} else if (rh.d == 4) {
    938 				if (mread(pal, 4, 16, &ms) != 16) {
    939 					break;
    940 				}
    941 				for (k = 0; k < 16; k++) {
    942 					pal[k] |= (255U << 24);
    943 				}
    944 			}
    945 
    946 			if (mread(&mip_size, 4, 1, &ms) != 1) {
    947 				break;
    948 			}
    949 
    950 			p_size = rh.w * rh.h;
    951 			pixels = A_ALLOC(a, uint32_t, p_size);
    952 			memset(pixels, 0, p_size * 4);
    953 
    954 			if (memcmp(rh.fcc, "DXT1", 4) == 0 ||
    955 			    memcmp(rh.fcc, "DXT3", 4) == 0) {
    956 				cmp = A_ALLOC(a, uint8_t, mip_size);
    957 				mread(cmp, 1, mip_size, &ms);
    958 				bx = rh.w / 4;
    959 				by = rh.h / 4;
    960 				is_dxt3 = memcmp(rh.fcc, "DXT3", 4) == 0;
    961 
    962 				for (y = 0; y < by; y++) {
    963 					for (x = 0; x < bx; x++) {
    964 						const uint8_t *blk = cmp +
    965 						    (y * bx + x) * (is_dxt3 ? 16 : 8);
    966 						const uint8_t *cblk = is_dxt3 ?
    967 						    blk + 8 : blk;
    968 
    969 						c0 = cblk[0] | (cblk[1] << 8);
    970 						c1 = cblk[2] | (cblk[3] << 8);
    971 						code = cblk[4] | (cblk[5] << 8) |
    972 						    (cblk[6] << 16) | (cblk[7] << 24);
    973 
    974 						r0 = ((c0 >> 11) & 0x1F) << 3;
    975 						g0 = ((c0 >> 5) & 0x3F) << 2;
    976 						b0 = (c0 & 0x1F) << 3;
    977 						r1 = ((c1 >> 11) & 0x1F) << 3;
    978 						g1 = ((c1 >> 5) & 0x3F) << 2;
    979 						b1 = (c1 & 0x1F) << 3;
    980 
    981 						cols[0] = b0 | (g0 << 8) |
    982 						    (r0 << 16) | (0xFFU << 24);
    983 						cols[1] = b1 | (g1 << 8) |
    984 						    (r1 << 16) | (0xFFU << 24);
    985 						if (c0 > c1 || is_dxt3) {
    986 							cols[2] = ((2*b0+b1)/3) |
    987 							    (((2*g0+g1)/3)<<8) |
    988 							    (((2*r0+r1)/3)<<16) |
    989 							    (0xFFU<<24);
    990 							cols[3] = ((b0+2*b1)/3) |
    991 							    (((g0+2*g1)/3)<<8) |
    992 							    (((r0+2*r1)/3)<<16) |
    993 							    (0xFFU<<24);
    994 						} else {
    995 							cols[2] = ((b0+b1)/2) |
    996 							    (((g0+g1)/2)<<8) |
    997 							    (((r0+r1)/2)<<16) |
    998 							    (0xFFU<<24);
    999 							cols[3] = 0;
   1000 						}
   1001 
   1002 						for (i = 0; i < 4; i++) {
   1003 							for (j = 0; j < 4; j++) {
   1004 								int px_idx = x * 4 + j;
   1005 								int py_idx = y * 4 + i;
   1006 								if (px_idx < rh.w &&
   1007 								    py_idx < rh.h) {
   1008 									uint32_t c = cols[(code >> (2 * (i * 4 + j))) & 3];
   1009 									if (is_dxt3) {
   1010 										a_val = (blk[i * 2 + (j / 2)] >> (4 * (j % 2))) & 0x0F;
   1011 										a_val = (a_val << 4) | a_val;
   1012 										c = (c & 0x00FFFFFF) | ((uint32_t)a_val << 24);
   1013 									}
   1014 									pixels[py_idx * rh.w + px_idx] = c;
   1015 								}
   1016 							}
   1017 						}
   1018 					}
   1019 				}
   1020 			} else if (rh.d == 8) {
   1021 				indices = malloc(mip_size);
   1022 				if (indices) {
   1023 					mread(indices, 1, mip_size, &ms);
   1024 					for (i = 0; (uint32_t)i < p_size; i++) {
   1025 						uint32_t c = pal[indices[i]];
   1026 						pixels[i] = (c & 0xFF00FF00) |
   1027 						    ((c & 0x00FF0000) >> 16) |
   1028 						    ((c & 0x000000FF) << 16);
   1029 					}
   1030 					free(indices);
   1031 				}
   1032 			} else if (rh.d == 32) {
   1033 				mread(pixels, 1, mip_size, &ms);
   1034 				if (rh.fmt == 22) {
   1035 					for (i = 0; (uint32_t)i < p_size; i++) {
   1036 						pixels[i] |= (255U << 24);
   1037 					}
   1038 				}
   1039 			} else if (rh.d == 16) {
   1040 				src16 = malloc(mip_size);
   1041 				if (src16) {
   1042 					mread(src16, 1, mip_size, &ms);
   1043 					for (i = 0; (uint32_t)i < p_size; i++) {
   1044 						uint16_t val = src16[i];
   1045 						uint8_t r = 0, g = 0, b = 0, a_v = 255;
   1046 						if (rh.fmt == 26) {
   1047 							a_v = ((val >> 12) & 0x0F) * 17;
   1048 							r = ((val >> 8) & 0x0F) * 17;
   1049 							g = ((val >> 4) & 0x0F) * 17;
   1050 							b = (val & 0x0F) * 17;
   1051 						} else if (rh.fmt == 25) {
   1052 							a_v = ((val >> 15) & 0x01) ? 255 : 0;
   1053 							r = ((val >> 10) & 0x1F) << 3;
   1054 							g = ((val >> 5) & 0x1F) << 3;
   1055 							b = (val & 0x1F) << 3;
   1056 							r |= (r >> 5); g |= (g >> 5); b |= (b >> 5);
   1057 						} else if (rh.fmt == 23) {
   1058 							r = ((val >> 11) & 0x1F) << 3;
   1059 							g = ((val >> 5) & 0x3F) << 2;
   1060 							b = (val & 0x1F) << 3;
   1061 							r |= (r >> 5); g |= (g >> 6); b |= (b >> 5);
   1062 							a_v = 255;
   1063 						}
   1064 						pixels[i] = (a_v << 24) | (r << 16) | (g << 8) | b;
   1065 					}
   1066 					free(src16);
   1067 				}
   1068 			} else if (rh.d == 24) {
   1069 				src = malloc(mip_size);
   1070 				if (src) {
   1071 					mread(src, 1, mip_size, &ms);
   1072 					for (i = 0; (uint32_t)i < p_size; i++) {
   1073 						pixels[i] = (255U << 24) |
   1074 						    (src[i*3+2] << 16) |
   1075 						    (src[i*3+1] << 8) | src[i*3+0];
   1076 					}
   1077 					free(src);
   1078 				}
   1079 			}
   1080 
   1081 			for (k = 0; k < 31 && rh.n[k]; k++) {
   1082 				t_name[k] = tolower((unsigned char)rh.n[k]);
   1083 			}
   1084 			t_name[k] = '\0';
   1085 			if (t_name[0] == '\0') {
   1086 				strncpy(t_name, name, 31);
   1087 				t_name[31] = '\0';
   1088 			}
   1089 			to_lower_str(t_name);
   1090 
   1091 			if (strstr(t_name, "waterclear256")) {
   1092 				blur_pixels(pixels, rh.w, rh.h);
   1093 				blur_pixels(pixels, rh.w, rh.h);
   1094 			}
   1095 
   1096 			new_w = nearest_pow2(rh.w);
   1097 			new_h = nearest_pow2(rh.h);
   1098 			final_pixels = pixels;
   1099 
   1100 			if (new_w != rh.w || new_h != rh.h) {
   1101 				final_pixels = malloc(new_w * new_h * 4);
   1102 				if (final_pixels) {
   1103 					for (y = 0; y < new_h; y++) {
   1104 						sy = (y * rh.h) / new_h;
   1105 						if (sy >= rh.h) {
   1106 							sy = rh.h - 1;
   1107 						}
   1108 						for (x = 0; x < new_w; x++) {
   1109 							sx = (x * rh.w) / new_w;
   1110 							if (sx >= rh.w) {
   1111 								sx = rh.w - 1;
   1112 							}
   1113 							final_pixels[y * new_w + x] = pixels[sy * rh.w + sx];
   1114 						}
   1115 					}
   1116 				} else {
   1117 					final_pixels = pixels;
   1118 					new_w = rh.w;
   1119 					new_h = rh.h;
   1120 				}
   1121 			}
   1122 
   1123 			snprintf(out_name, sizeof(out_name), "assets/textures/%s.tga", t_name);
   1124 			out = fopen(out_name, "wb");
   1125 			if (out) {
   1126 				memset(&out_hdr, 0, sizeof(out_hdr));
   1127 				out_hdr.image_type = 2;
   1128 				out_hdr.width = new_w;
   1129 				out_hdr.height = new_h;
   1130 				out_hdr.pixel_depth = 32;
   1131 				out_hdr.image_descriptor = 8;
   1132 
   1133 				fwrite(&out_hdr, sizeof(out_hdr), 1, out);
   1134 				fwrite(final_pixels, 4, new_w * new_h, out);
   1135 				fclose(out);
   1136 			}
   1137 
   1138 			if (final_pixels != pixels) {
   1139 				free(final_pixels);
   1140 			}
   1141 		}
   1142 		ms.pos = chunk_end;
   1143 	}
   1144 }
   1145 
   1146 static void
   1147 process_particle_txd(const char *root, struct arena *a)
   1148 {
   1149 	FILE *f;
   1150 	size_t sz;
   1151 	uint8_t *buf;
   1152 
   1153 	f = fopen_simple(root, "models/particle.txd");
   1154 	if (!f) {
   1155 		return;
   1156 	}
   1157 	fseek(f, 0, SEEK_END);
   1158 	sz = ftell(f);
   1159 	fseek(f, 0, SEEK_SET);
   1160 	buf = malloc(sz);
   1161 	if (fread(buf, 1, sz, f) == sz) {
   1162 		a->pos = 0;
   1163 		convert_txd(buf, sz, "particle", a);
   1164 	}
   1165 	free(buf);
   1166 	fclose(f);
   1167 }
   1168 
   1169 struct frame { struct mat4 abs; int32_t parent; };
   1170 struct geom { float *v, *u; uint8_t *c; uint16_t *i, *m; uint32_t nv, ni, nm; struct tex_name *t; };
   1171 
   1172 static int
   1173 is_container(uint32_t type)
   1174 {
   1175 	switch (type) {
   1176 	case 0x03: case 0x06: case 0x07: case 0x08: case 0x0E: case 0x0F:
   1177 	case 0x10: case 0x14: case 0x1A: case 0x1B:
   1178 		return (1);
   1179 	}
   1180 	return (0);
   1181 }
   1182 
   1183 static int
   1184 is_skin(const char *name)
   1185 {
   1186 	int i;
   1187 
   1188 	for (i = 0; i < 313; i++) {
   1189 		if (skin_names[i] && skin_names[i][0] != '\0' &&
   1190 		    strcasecmp(skin_names[i], name) == 0) {
   1191 			return (1);
   1192 		}
   1193 	}
   1194 	for (i = 0; i < (int)(sizeof(special_actors) / sizeof(special_actors[0])); i++) {
   1195 		if (strcasecmp(special_actors[i].model, name) == 0) {
   1196 			return (1);
   1197 		}
   1198 	}
   1199 	return (0);
   1200 }
   1201 
   1202 static void
   1203 convert_dff(const uint8_t *data, size_t size, const char *name, struct arena *a)
   1204 {
   1205 	struct mstream ms = { data, size, 0 };
   1206 	struct rw_header h;
   1207 	struct frame *frames = NULL;
   1208 	struct geom *geoms = NULL;
   1209 	struct atomic_entry *atomics;
   1210 	uint32_t n_frames = 0, n_geoms = 0, n_atomics = 0;
   1211 	uint32_t last_cont = 0;
   1212 	int32_t cur_g = -1, cur_m = -1, wait_tex = 0;
   1213 	size_t end;
   1214 	int is_ped;
   1215 
   1216 	is_ped = is_skin(name);
   1217 
   1218 	atomics = A_ALLOC(a, struct atomic_entry, 256);
   1219 
   1220 	while (mread(&h, sizeof(h), 1, &ms) == 1) {
   1221 		end = ms.pos + h.size;
   1222 
   1223 		if (is_container(h.type)) {
   1224 			last_cont = h.type;
   1225 			if (h.type == 0x0F) cur_g++;
   1226 			if (h.type == 0x08) cur_m = -1;
   1227 			if (h.type == 0x07) cur_m++;
   1228 			if (h.type == 0x06) wait_tex = 1;
   1229 			continue;
   1230 		}
   1231 
   1232 		if (h.type == 0x01) {
   1233 			if (last_cont == 0x0E) {
   1234 				mread(&n_frames, 4, 1, &ms);
   1235 				frames = A_ALLOC(a, struct frame, n_frames);
   1236 				for (uint32_t i = 0; i < n_frames; i++) {
   1237 					float rot[9], pos[3]; int32_t parent, flags;
   1238 					mread(rot, 4, 9, &ms); mread(pos, 4, 3, &ms);
   1239 					mread(&parent, 4, 1, &ms); mread(&flags, 4, 1, &ms);
   1240 
   1241 					struct mat4 l; memset(&l, 0, sizeof(l));
   1242 					l.m[0][0] = rot[0]; l.m[0][1] = rot[3]; l.m[0][2] = rot[6];
   1243 					l.m[1][0] = rot[1]; l.m[1][1] = rot[4]; l.m[1][2] = rot[7];
   1244 					l.m[2][0] = rot[2]; l.m[2][1] = rot[5]; l.m[2][2] = rot[8];
   1245 					l.m[0][3] = pos[0]; l.m[1][3] = pos[1]; l.m[2][3] = pos[2]; l.m[3][3] = 1.0f;
   1246 
   1247 					if (parent >= 0 && parent < (int32_t)i) {
   1248 						mat_mul(&frames[i].abs, &frames[parent].abs, &l);
   1249 					} else {
   1250 						float sx = sqrtf(l.m[0][0]*l.m[0][0] + l.m[1][0]*l.m[1][0] + l.m[2][0]*l.m[2][0]);
   1251 						float sy = sqrtf(l.m[0][1]*l.m[0][1] + l.m[1][1]*l.m[1][1] + l.m[2][1]*l.m[2][1]);
   1252 						float sz = sqrtf(l.m[0][2]*l.m[0][2] + l.m[1][2]*l.m[1][2] + l.m[2][2]*l.m[2][2]);
   1253 						mat_identity(&frames[i].abs);
   1254 						frames[i].abs.m[0][0] = sx;
   1255 						frames[i].abs.m[1][1] = sy;
   1256 						frames[i].abs.m[2][2] = sz;
   1257 					}
   1258 				}
   1259 			} else if (last_cont == 0x1A) {
   1260 				mread(&n_geoms, 4, 1, &ms);
   1261 				if (n_geoms) {
   1262 					geoms = A_ALLOC(a, struct geom, n_geoms);
   1263 				}
   1264 				cur_g = -1;
   1265 			} else if (last_cont == 0x0F && cur_g >= 0) {
   1266 				struct geom *g = &geoms[cur_g];
   1267 				uint32_t fmt, morphs;
   1268 				mread(&fmt, 4, 1, &ms); mread(&g->ni, 4, 1, &ms);
   1269 				mread(&g->nv, 4, 1, &ms); mread(&morphs, 4, 1, &ms);
   1270 
   1271 				if (g->nv > 0 && g->ni > 0) {
   1272 					uint16_t flg = fmt & 0xFFFF, tex_c = (fmt & 0x00FF0000) >> 16;
   1273 					if (tex_c == 0 && (flg & 0x0004)) {
   1274 						tex_c = 1;
   1275 					}
   1276 
   1277 					g->c = NULL;
   1278 					if (flg & 0x0008) {
   1279 						g->c = A_ALLOC(a, uint8_t, g->nv * 4);
   1280 						mread(g->c, 1, g->nv * 4, &ms);
   1281 					}
   1282 
   1283 					g->u = A_ALLOC(a, float, g->nv * 2);
   1284 					if (tex_c > 0) {
   1285 						mread(g->u, sizeof(float) * 2, g->nv, &ms);
   1286 						if (tex_c > 1) {
   1287 							ms.pos += (tex_c - 1) * sizeof(float) * 2 * g->nv;
   1288 						}
   1289 					}
   1290 
   1291 					struct rw_triangle *tris = A_ALLOC(a, struct rw_triangle, g->ni);
   1292 					mread(tris, sizeof(*tris), g->ni, &ms);
   1293 					ms.pos += sizeof(float) * 4;
   1294 
   1295 					int32_t has_v, has_n;
   1296 					mread(&has_v, 4, 1, &ms); mread(&has_n, 4, 1, &ms);
   1297 					if (has_v) {
   1298 						g->v = A_ALLOC(a, float, g->nv * 3);
   1299 						mread(g->v, sizeof(float) * 3, g->nv, &ms);
   1300 					}
   1301 
   1302 					g->i = A_ALLOC(a, uint16_t, g->ni * 3);
   1303 					g->m = A_ALLOC(a, uint16_t, g->ni);
   1304 					for (uint32_t j = 0; j < g->ni; j++) {
   1305 						g->i[j*3+0] = tris[j].v1;
   1306 						g->i[j*3+1] = tris[j].v2;
   1307 						g->i[j*3+2] = tris[j].v3;
   1308 						g->m[j] = tris[j].m;
   1309 					}
   1310 				}
   1311 			} else if (last_cont == 0x08 && cur_g >= 0) {
   1312 				mread(&geoms[cur_g].nm, 4, 1, &ms);
   1313 				if (geoms[cur_g].nm > 0) {
   1314 					geoms[cur_g].t = A_ALLOC(a, struct tex_name, geoms[cur_g].nm);
   1315 				}
   1316 			} else if (last_cont == 0x14) {
   1317 				uint32_t f_idx, g_idx, flg, unused;
   1318 				mread(&f_idx, 4, 1, &ms); mread(&g_idx, 4, 1, &ms);
   1319 				mread(&flg, 4, 1, &ms); mread(&unused, 4, 1, &ms);
   1320 				if (n_atomics < 256) {
   1321 					atomics[n_atomics].f = f_idx;
   1322 					atomics[n_atomics].g = g_idx;
   1323 					n_atomics++;
   1324 				}
   1325 			}
   1326 			last_cont = 0;
   1327 		} else if (h.type == 0x02 && wait_tex && cur_g >= 0) {
   1328 			struct geom *g = &geoms[cur_g];
   1329 			if (cur_m >= 0 && (uint32_t)cur_m < g->nm) {
   1330 				size_t len = h.size < 31 ? h.size : 31;
   1331 				mread(g->t[cur_m].name, 1, len, &ms);
   1332 				for (size_t k = 0; k < len; k++) {
   1333 					g->t[cur_m].name[k] = tolower((unsigned char)g->t[cur_m].name[k]);
   1334 				}
   1335 			}
   1336 			wait_tex = 0;
   1337 		}
   1338 
   1339 		ms.pos = end;
   1340 	}
   1341 
   1342 	uint32_t t_nv = 0, t_ni = 0, t_nm = 0;
   1343 	int has_any_colors = 0;
   1344 	for (uint32_t i = 0; i < n_atomics; i++) {
   1345 		if (atomics[i].g < n_geoms) {
   1346 			t_nv += geoms[atomics[i].g].nv;
   1347 			t_ni += geoms[atomics[i].g].ni;
   1348 			t_nm += geoms[atomics[i].g].nm;
   1349 			if (geoms[atomics[i].g].c) {
   1350 				has_any_colors = 1;
   1351 			}
   1352 		}
   1353 	}
   1354 
   1355 	if (t_nv > 0 && t_ni > 0) {
   1356 		float *f_v = A_ALLOC(a, float, t_nv * 3);
   1357 		float *f_u = A_ALLOC(a, float, t_nv * 2);
   1358 		uint8_t *f_c = A_ALLOC(a, uint8_t, t_nv * 4);
   1359 		uint16_t *f_i = A_ALLOC(a, uint16_t, t_ni * 3);
   1360 		uint16_t *f_m = A_ALLOC(a, uint16_t, t_ni);
   1361 		struct tex_name *f_t = t_nm > 0 ? A_ALLOC(a, struct tex_name, t_nm) : NULL;
   1362 
   1363 		uint32_t vo = 0, to = 0, mo = 0;
   1364 		for (uint32_t i = 0; i < n_atomics; i++) {
   1365 			if (atomics[i].g >= n_geoms || atomics[i].f >= n_frames) {
   1366 				continue;
   1367 			}
   1368 			struct geom *g = &geoms[atomics[i].g];
   1369 			struct frame *fr = &frames[atomics[i].f];
   1370 
   1371 			for (uint32_t j = 0; j < g->nv; j++) {
   1372 				float x = g->v[j*3+0], y = g->v[j*3+1], z = g->v[j*3+2];
   1373 				f_v[(vo+j)*3+0] = fr->abs.m[0][0]*x + fr->abs.m[0][1]*y + fr->abs.m[0][2]*z + fr->abs.m[0][3];
   1374 				f_v[(vo+j)*3+1] = fr->abs.m[1][0]*x + fr->abs.m[1][1]*y + fr->abs.m[1][2]*z + fr->abs.m[1][3];
   1375 				f_v[(vo+j)*3+2] = fr->abs.m[2][0]*x + fr->abs.m[2][1]*y + fr->abs.m[2][2]*z + fr->abs.m[2][3];
   1376 				f_u[(vo+j)*2+0] = g->u[j*2+0];
   1377 				f_u[(vo+j)*2+1] = g->u[j*2+1];
   1378 				if (g->c) {
   1379 					f_c[(vo+j)*4+0] = g->c[j*4+0];
   1380 					f_c[(vo+j)*4+1] = g->c[j*4+1];
   1381 					f_c[(vo+j)*4+2] = g->c[j*4+2];
   1382 					f_c[(vo+j)*4+3] = g->c[j*4+3];
   1383 				} else {
   1384 					f_c[(vo+j)*4+0] = 255;
   1385 					f_c[(vo+j)*4+1] = 255;
   1386 					f_c[(vo+j)*4+2] = 255;
   1387 					f_c[(vo+j)*4+3] = 255;
   1388 				}
   1389 			}
   1390 			for (uint32_t j = 0; j < g->ni; j++) {
   1391 				f_i[(to+j)*3+0] = g->i[j*3+0] + vo;
   1392 				f_i[(to+j)*3+1] = g->i[j*3+1] + vo;
   1393 				f_i[(to+j)*3+2] = g->i[j*3+2] + vo;
   1394 				f_m[to+j] = g->m[j] + mo;
   1395 			}
   1396 			for (uint32_t j = 0; j < g->nm; j++) {
   1397 				memcpy(f_t[mo+j].name, g->t[j].name, 32);
   1398 			}
   1399 			vo += g->nv;
   1400 			to += g->ni;
   1401 			mo += g->nm;
   1402 		}
   1403 
   1404 		float b_cx = 0, b_cy = 0, b_cz = 0, b_r = 0;
   1405 		float minx = f_v[0], maxx = f_v[0], miny = f_v[1], maxy = f_v[1], minz = f_v[2], maxz = f_v[2];
   1406 		for (uint32_t i = 1; i < t_nv; i++) {
   1407 			if (f_v[i*3+0] < minx) minx = f_v[i*3+0];
   1408 			if (f_v[i*3+0] > maxx) maxx = f_v[i*3+0];
   1409 			if (f_v[i*3+1] < miny) miny = f_v[i*3+1];
   1410 			if (f_v[i*3+1] > maxy) maxy = f_v[i*3+1];
   1411 			if (f_v[i*3+2] < minz) minz = f_v[i*3+2];
   1412 			if (f_v[i*3+2] > maxz) maxz = f_v[i*3+2];
   1413 		}
   1414 		b_cx = (minx+maxx)*0.5f;
   1415 		b_cy = (miny+maxy)*0.5f;
   1416 		b_cz = (minz+maxz)*0.5f;
   1417 		for (uint32_t i = 0; i < t_nv; i++) {
   1418 			float dx = f_v[i*3+0] - b_cx, dy = f_v[i*3+1] - b_cy, dz = f_v[i*3+2] - b_cz;
   1419 			float d2 = dx*dx + dy*dy + dz*dz;
   1420 			if (d2 > b_r) {
   1421 				b_r = d2;
   1422 			}
   1423 		}
   1424 		b_r = sqrtf(b_r);
   1425 
   1426 		char out_name[256];
   1427 		snprintf(out_name, sizeof(out_name), "assets/models/%s.ply", name);
   1428 		FILE *out = fopen(out_name, "wb");
   1429 		if (out) {
   1430 			fprintf(out, "ply\n");
   1431 			fprintf(out, "format binary_little_endian 1.0\n");
   1432 			fprintf(out, "comment spr_cx %f\n", b_cx);
   1433 			fprintf(out, "comment spr_cy %f\n", b_cy);
   1434 			fprintf(out, "comment spr_cz %f\n", b_cz);
   1435 			fprintf(out, "comment spr_r %f\n", b_r);
   1436 			fprintf(out, "comment flags %u\n", has_any_colors ? 1 : 0);
   1437 			for (uint32_t i = 0; i < t_nm; i++) {
   1438 				fprintf(out, "comment texture %s\n", f_t[i].name);
   1439 			}
   1440 			fprintf(out, "element vertex %u\n", t_nv);
   1441 			fprintf(out, "property float x\n");
   1442 			fprintf(out, "property float y\n");
   1443 			fprintf(out, "property float z\n");
   1444 			fprintf(out, "property float s\n");
   1445 			fprintf(out, "property float t\n");
   1446 			fprintf(out, "property uchar red\n");
   1447 			fprintf(out, "property uchar green\n");
   1448 			fprintf(out, "property uchar blue\n");
   1449 			fprintf(out, "property uchar alpha\n");
   1450 			fprintf(out, "element face %u\n", t_ni);
   1451 			fprintf(out, "property list uchar int vertex_indices\n");
   1452 			fprintf(out, "property ushort material_index\n");
   1453 			fprintf(out, "end_header\n");
   1454 
   1455 			for (uint32_t i = 0; i < t_nv; i++) {
   1456 				float vx = f_v[i*3+0], vy = f_v[i*3+1], vz = f_v[i*3+2];
   1457 				float tu = f_u[i*2+0], tv = f_u[i*2+1];
   1458 				uint8_t cr = f_c[i*4+0], cg = f_c[i*4+1], cb = f_c[i*4+2], ca = f_c[i*4+3];
   1459 
   1460 				if (is_ped) {
   1461 					vx = -vx;
   1462 				}
   1463 
   1464 				fwrite(&vx, 4, 1, out);
   1465 				fwrite(&vy, 4, 1, out);
   1466 				fwrite(&vz, 4, 1, out);
   1467 				fwrite(&tu, 4, 1, out);
   1468 				fwrite(&tv, 4, 1, out);
   1469 				fwrite(&cr, 1, 1, out);
   1470 				fwrite(&cg, 1, 1, out);
   1471 				fwrite(&cb, 1, 1, out);
   1472 				fwrite(&ca, 1, 1, out);
   1473 			}
   1474 
   1475 			for (uint32_t i = 0; i < t_ni; i++) {
   1476 				uint8_t count = 3;
   1477 				int32_t idx[3] = { f_i[i*3+0], f_i[i*3+1], f_i[i*3+2] };
   1478 				uint16_t mat = f_m[i];
   1479 				fwrite(&count, 1, 1, out);
   1480 				fwrite(idx, 4, 3, out);
   1481 				fwrite(&mat, 2, 1, out);
   1482 			}
   1483 			fclose(out);
   1484 		}
   1485 	}
   1486 }
   1487 
   1488 static void
   1489 process_local_ipl(const char *root, const char *rel, FILE *out, struct file_list *fl)
   1490 {
   1491 	FILE *f;
   1492 	size_t sz;
   1493 	char *buf;
   1494 
   1495 	f = fopen_simple(root, rel);
   1496 	if (!f) {
   1497 		return;
   1498 	}
   1499 	fseek(f, 0, SEEK_END);
   1500 	sz = ftell(f);
   1501 	fseek(f, 0, SEEK_SET);
   1502 	buf = malloc(sz);
   1503 	if (fread(buf, 1, sz, f) == sz) {
   1504 		parse_text_ipl(buf, sz, out, fl);
   1505 	}
   1506 	free(buf);
   1507 	fclose(f);
   1508 }
   1509 
   1510 static void
   1511 process_gta_dat_ide(const char *root, const char *dat_path, struct file_list *fl)
   1512 {
   1513 	FILE *f;
   1514 	char line[512];
   1515 	char *p;
   1516 
   1517 	f = fopen_simple(root, dat_path);
   1518 	if (!f) {
   1519 		return;
   1520 	}
   1521 
   1522 	while (fgets(line, sizeof(line), f)) {
   1523 		p = line;
   1524 		line[strcspn(line, "\r\n")] = '\0';
   1525 		while (*p == ' ' || *p == '\t') {
   1526 			p++;
   1527 		}
   1528 		if (*p == '\0' || *p == '#') {
   1529 			continue;
   1530 		}
   1531 
   1532 		if (strncasecmp(p, "IDE ", 4) == 0) {
   1533 			char rel[512];
   1534 			char *src = p + 4;
   1535 			while (*src == ' ' || *src == '\t') {
   1536 				src++;
   1537 			}
   1538 			for (size_t i = 0; i < sizeof(rel) - 1 && src[i]; i++) {
   1539 				if (src[i] == '\\') {
   1540 					rel[i] = '/';
   1541 				} else {
   1542 					rel[i] = src[i];
   1543 				}
   1544 				rel[i+1] = '\0';
   1545 			}
   1546 			trim_spaces(rel);
   1547 			preparse_ide(root, rel, fl);
   1548 		}
   1549 	}
   1550 	fclose(f);
   1551 }
   1552 
   1553 static void
   1554 process_gta_dat_ipl(const char *root, const char *dat_path, FILE *map_out, struct file_list *fl)
   1555 {
   1556 	FILE *f;
   1557 	char line[512];
   1558 	char *p;
   1559 
   1560 	f = fopen_simple(root, dat_path);
   1561 	if (!f) {
   1562 		return;
   1563 	}
   1564 
   1565 	while (fgets(line, sizeof(line), f)) {
   1566 		p = line;
   1567 		line[strcspn(line, "\r\n")] = '\0';
   1568 		while (*p == ' ' || *p == '\t') {
   1569 			p++;
   1570 		}
   1571 		if (*p == '\0' || *p == '#') {
   1572 			continue;
   1573 		}
   1574 
   1575 		if (strncasecmp(p, "IPL ", 4) == 0) {
   1576 			char rel[512];
   1577 			char *src = p + 4;
   1578 			while (*src == ' ' || *src == '\t') {
   1579 				src++;
   1580 			}
   1581 			for (size_t i = 0; i < sizeof(rel) - 1 && src[i]; i++) {
   1582 				if (src[i] == '\\') {
   1583 					rel[i] = '/';
   1584 				} else {
   1585 					rel[i] = src[i];
   1586 				}
   1587 				rel[i+1] = '\0';
   1588 			}
   1589 			trim_spaces(rel);
   1590 			process_local_ipl(root, rel, map_out, fl);
   1591 		}
   1592 	}
   1593 	fclose(f);
   1594 }
   1595 
   1596 static void
   1597 process_water(const char *root)
   1598 {
   1599 	FILE *f, *out;
   1600 	char line[512], *p, *tok, *save;
   1601 	char *tokens[32];
   1602 	int t_count, i, j, k, collapsed;
   1603 	uint32_t count;
   1604 	float limit = 2980.0f;
   1605 	float ax_min, ax_max, ay_min, ay_max, az;
   1606 	float bx_min, bx_max, by_min, by_max;
   1607 	struct water_face *a, *b, *face;
   1608 
   1609 	f = fopen_simple(root, "data/water.dat");
   1610 	if (f == NULL) {
   1611 		return;
   1612 	}
   1613 
   1614 	out = fopen("assets/water.bin", "wb");
   1615 	if (out == NULL) {
   1616 		fclose(f);
   1617 		return;
   1618 	}
   1619 
   1620 	count = 0;
   1621 	water_face_count = 0;
   1622 
   1623 	while (fgets(line, sizeof(line), f)) {
   1624 		p = line;
   1625 		while (*p == ' ' || *p == '\t') {
   1626 			p++;
   1627 		}
   1628 		if (*p == '\0' || *p == '#' || *p == '*' || *p == '\r' ||
   1629 		    *p == '\n' || strncasecmp(p, "processed", 9) == 0) {
   1630 			continue;
   1631 		}
   1632 
   1633 		t_count = 0;
   1634 		tok = strtok_r(p, " \t\r\n", &save);
   1635 		while (tok && t_count < 32) {
   1636 			tokens[t_count++] = tok;
   1637 			tok = strtok_r(NULL, " \t\r\n", &save);
   1638 		}
   1639 
   1640 		if ((t_count == 29 || t_count == 22) && water_face_count < 8192) {
   1641 			face = &water_db[water_face_count];
   1642 			k = atoi(tokens[t_count - 1]);
   1643 			if (k == 1 || k == 3) {
   1644 				face->num = t_count == 29 ? 4 : 3;
   1645 				for (j = 0; j < face->num; j++) {
   1646 					face->x[j] = strtof(tokens[j * 7 + 0], NULL);
   1647 					face->y[j] = strtof(tokens[j * 7 + 1], NULL);
   1648 					
   1649 					face->z[j] = strtof(tokens[j * 7 + 2], NULL);
   1650 					face->z[j] = roundf(face->z[j] * 10.0f) / 10.0f;
   1651 					
   1652 					face->u[j] = strtof(tokens[j * 7 + 3], NULL);
   1653 					face->v[j] = strtof(tokens[j * 7 + 4], NULL);
   1654 					face->h[j] = strtof(tokens[j * 7 + 6], NULL);
   1655 
   1656 					if (face->x[j] > limit) {
   1657 						face->x[j] = limit;
   1658 					}
   1659 					if (face->x[j] < -limit) {
   1660 						face->x[j] = -limit;
   1661 					}
   1662 					if (face->y[j] > limit) {
   1663 						face->y[j] = limit;
   1664 					}
   1665 					if (face->y[j] < -limit) {
   1666 						face->y[j] = -limit;
   1667 					}
   1668 				}
   1669 				water_face_count++;
   1670 			}
   1671 		}
   1672 	}
   1673 
   1674 	for (i = 0; i < water_face_count; i++) {
   1675 		a = &water_db[i];
   1676 		if (a->num == 0) {
   1677 			continue;
   1678 		}
   1679 
   1680 		ax_min = a->x[0];
   1681 		ax_max = a->x[0];
   1682 		ay_min = a->y[0];
   1683 		ay_max = a->y[0];
   1684 		az = a->z[0];
   1685 		for (k = 1; k < a->num; k++) {
   1686 			if (a->x[k] < ax_min) {
   1687 				ax_min = a->x[k];
   1688 			}
   1689 			if (a->x[k] > ax_max) {
   1690 				ax_max = a->x[k];
   1691 			}
   1692 			if (a->y[k] < ay_min) {
   1693 				ay_min = a->y[k];
   1694 			}
   1695 			if (a->y[k] > ay_max) {
   1696 				ay_max = a->y[k];
   1697 			}
   1698 		}
   1699 
   1700 		for (j = 0; j < water_face_count; j++) {
   1701 			if (i == j) {
   1702 				continue;
   1703 			}
   1704 			b = &water_db[j];
   1705 			if (b->num == 0) {
   1706 				continue;
   1707 			}
   1708 
   1709 			if (fabsf(b->z[0] - az) > 0.01f) {
   1710 				continue;
   1711 			}
   1712 
   1713 			bx_min = b->x[0];
   1714 			bx_max = b->x[0];
   1715 			by_min = b->y[0];
   1716 			by_max = b->y[0];
   1717 			for (k = 1; k < b->num; k++) {
   1718 				if (b->x[k] < bx_min) {
   1719 					bx_min = b->x[k];
   1720 				}
   1721 				if (b->x[k] > bx_max) {
   1722 					bx_max = b->x[k];
   1723 				}
   1724 				if (b->y[k] < by_min) {
   1725 					by_min = b->y[k];
   1726 				}
   1727 				if (b->y[k] > by_max) {
   1728 					by_max = b->y[k];
   1729 				}
   1730 			}
   1731 
   1732 			if (bx_max > ax_min && bx_min < ax_max && by_max > ay_min && by_min < ay_max) {
   1733 				if (bx_min < ax_max && bx_max > ax_max && bx_min > ax_min) {
   1734 					for (k = 0; k < b->num; k++) {
   1735 						if (fabsf(b->x[k] - bx_min) < 0.1f) {
   1736 							b->x[k] = ax_max;
   1737 						}
   1738 					}
   1739 				} else if (bx_max > ax_min && bx_min < ax_min && bx_max < ax_max) {
   1740 					for (k = 0; k < b->num; k++) {
   1741 						if (fabsf(b->x[k] - bx_max) < 0.1f) {
   1742 							b->x[k] = ax_min;
   1743 						}
   1744 					}
   1745 				} else if (by_min < ay_max && by_max > ay_max && by_min > ay_min) {
   1746 					for (k = 0; k < b->num; k++) {
   1747 						if (fabsf(b->y[k] - by_min) < 0.1f) {
   1748 							b->y[k] = ay_max;
   1749 						}
   1750 					}
   1751 				} else if (by_max > ay_min && by_min < ay_min && by_max < ay_max) {
   1752 					for (k = 0; k < b->num; k++) {
   1753 						if (fabsf(b->y[k] - by_max) < 0.1f) {
   1754 							b->y[k] = ay_min;
   1755 						}
   1756 					}
   1757 				}
   1758 			}
   1759 		}
   1760 	}
   1761 
   1762 	fwrite(&count, sizeof(count), 1, out);
   1763 	for (i = 0; i < water_face_count; i++) {
   1764 		face = &water_db[i];
   1765 		collapsed = 0;
   1766 
   1767 		if (face->num == 4) {
   1768 			if (fabsf(face->x[0] - face->x[2]) < 0.1f && fabsf(face->y[0] - face->y[2]) < 0.1f) {
   1769 				collapsed = 1;
   1770 			}
   1771 		} else if (face->num == 3) {
   1772 			if (fabsf(face->x[0] - face->x[1]) < 0.1f && fabsf(face->y[0] - face->y[1]) < 0.1f) {
   1773 				collapsed = 1;
   1774 			}
   1775 		}
   1776 
   1777 		if (collapsed == 0) {
   1778 			fwrite(face, sizeof(struct water_face), 1, out);
   1779 			count++;
   1780 		}
   1781 	}
   1782 
   1783 	fseek(out, 0, SEEK_SET);
   1784 	fwrite(&count, sizeof(count), 1, out);
   1785 	fclose(out);
   1786 	fclose(f);
   1787 }
   1788 
   1789 static void
   1790 mat_translate(struct mat4 *m, float x, float y, float z)
   1791 {
   1792 	mat_identity(m);
   1793 	m->m[0][3] = x;
   1794 	m->m[1][3] = y;
   1795 	m->m[2][3] = z;
   1796 }
   1797 
   1798 static void
   1799 mat_from_quat(struct mat4 *m, float qx, float qy, float qz, float qw)
   1800 {
   1801 	float len;
   1802 
   1803 	qw = -qw;
   1804 	len = sqrtf(qx * qx + qy * qy + qz * qz + qw * qw);
   1805 	if (len > 0.0f) {
   1806 		qx /= len;
   1807 		qy /= len;
   1808 		qz /= len;
   1809 		qw /= len;
   1810 	}
   1811 	mat_identity(m);
   1812 	m->m[0][0] = 1.0f - 2.0f * (qy * qy + qz * qz);
   1813 	m->m[0][1] = 2.0f * (qx * qy - qz * qw);
   1814 	m->m[0][2] = 2.0f * (qx * qz + qy * qw);
   1815 	m->m[1][0] = 2.0f * (qx * qy + qz * qw);
   1816 	m->m[1][1] = 1.0f - 2.0f * (qx * qx + qz * qz);
   1817 	m->m[1][2] = 2.0f * (qy * qz - qx * qw);
   1818 	m->m[2][0] = 2.0f * (qx * qz - qy * qw);
   1819 	m->m[2][1] = 2.0f * (qy * qz + qx * qw);
   1820 	m->m[2][2] = 1.0f - 2.0f * (qx * qx + qy * qy);
   1821 }
   1822 
   1823 static inline void
   1824 mat_transform(float dst[3], float *w_out, const struct mat4 *m, const float v[3])
   1825 {
   1826 	dst[0] = m->m[0][0] * v[0] + m->m[0][1] * v[1] + m->m[0][2] * v[2] + m->m[0][3];
   1827 	dst[1] = m->m[1][0] * v[0] + m->m[1][1] * v[1] + m->m[1][2] * v[2] + m->m[1][3];
   1828 	dst[2] = m->m[2][0] * v[0] + m->m[2][1] * v[1] + m->m[2][2] * v[2] + m->m[2][3];
   1829 	*w_out = m->m[3][0] * v[0] + m->m[3][1] * v[1] + m->m[3][2] * v[2] + m->m[3][3];
   1830 }
   1831 
   1832 static uint32_t
   1833 str_hash(const char *s)
   1834 {
   1835 	uint32_t h;
   1836 
   1837 	h = 5381;
   1838 	while (*s) {
   1839 		h = ((h << 5) + h) + (unsigned char)*s;
   1840 		s++;
   1841 	}
   1842 	return (h);
   1843 }
   1844 
   1845 static void
   1846 col_db_insert(struct col_model *cm)
   1847 {
   1848 	uint32_t slot;
   1849 
   1850 	slot = str_hash(cm->name) % COL_HASH_SZ;
   1851 	while (col_hash[slot] != 0) {
   1852 		slot = (slot + 1) % COL_HASH_SZ;
   1853 	}
   1854 	col_hash[slot] = col_db_count;
   1855 }
   1856 
   1857 static void
   1858 parse_col_data(const uint8_t *data, size_t size)
   1859 {
   1860 	const struct col_header *h;
   1861 	const uint8_t *base;
   1862 	const struct raw_col_vertex *verts;
   1863 	const struct raw_col_face *faces;
   1864 	const struct raw_col_box *boxes;
   1865 	struct col_model *cm;
   1866 	struct col_triangle *t;
   1867 	size_t pos;
   1868 	uint32_t total_tris, i, b;
   1869 	int k;
   1870 	float x0, y0, z0, x1, y1, z1;
   1871 	uint8_t surf;
   1872 	float p[8][3];
   1873 	static const int box_idx[12][3] = {
   1874 		{0, 1, 2}, {0, 2, 3}, {4, 6, 5}, {4, 7, 6},
   1875 		{0, 4, 5}, {0, 5, 1}, {3, 2, 6}, {3, 6, 7},
   1876 		{0, 3, 7}, {0, 7, 4}, {1, 5, 6}, {1, 6, 2}
   1877 	};
   1878 
   1879 	pos = 0;
   1880 	while (pos + sizeof(struct col_header) <= size) {
   1881 		h = (const struct col_header *)(data + pos);
   1882 		if (memcmp(h->magic, "COL2", 4) != 0 &&
   1883 		    memcmp(h->magic, "COL3", 4) != 0 &&
   1884 		    memcmp(h->magic, "COLL", 4) != 0) {
   1885 			break;
   1886 		}
   1887 		if (col_db_count >= MAX_COL_MODELS) {
   1888 			break;
   1889 		}
   1890 
   1891 		cm = &col_db[col_db_count];
   1892 		strncpy(cm->name, h->model_name, sizeof(cm->name) - 1);
   1893 		cm->name[sizeof(cm->name) - 1] = '\0';
   1894 		trim_spaces(cm->name);
   1895 		to_lower_str(cm->name);
   1896 
   1897 		total_tris = h->num_faces + (h->num_boxes * 12);
   1898 		if (total_tris > 0) {
   1899 			cm->tris = malloc(total_tris * sizeof(struct col_triangle));
   1900 			if (!cm->tris) {
   1901 				break;
   1902 			}
   1903 			cm->num_tris = 0;
   1904 			base = data + pos + 4;
   1905 
   1906 			if (h->num_faces > 0 && h->vertices_offset && h->faces_offset) {
   1907 				verts = (const struct raw_col_vertex *)(base + h->vertices_offset);
   1908 				faces = (const struct raw_col_face *)(base + h->faces_offset);
   1909 				for (i = 0; i < h->num_faces; i++) {
   1910 					t = &cm->tris[cm->num_tris++];
   1911 					t->v0[0] = verts[faces[i].a].x / 128.0f;
   1912 					t->v0[1] = verts[faces[i].a].y / 128.0f;
   1913 					t->v0[2] = verts[faces[i].a].z / 128.0f;
   1914 
   1915 					t->v1[0] = verts[faces[i].b].x / 128.0f;
   1916 					t->v1[1] = verts[faces[i].b].y / 128.0f;
   1917 					t->v1[2] = verts[faces[i].b].z / 128.0f;
   1918 
   1919 					t->v2[0] = verts[faces[i].c].x / 128.0f;
   1920 					t->v2[1] = verts[faces[i].c].y / 128.0f;
   1921 					t->v2[2] = verts[faces[i].c].z / 128.0f;
   1922 
   1923 					t->surface = faces[i].surface;
   1924 				}
   1925 			}
   1926 
   1927 			if (h->num_boxes > 0 && h->boxes_offset) {
   1928 				boxes = (const struct raw_col_box *)(base + h->boxes_offset);
   1929 				for (b = 0; b < h->num_boxes; b++) {
   1930 					x0 = boxes[b].min[0];
   1931 					y0 = boxes[b].min[1];
   1932 					z0 = boxes[b].min[2];
   1933 					x1 = boxes[b].max[0];
   1934 					y1 = boxes[b].max[1];
   1935 					z1 = boxes[b].max[2];
   1936 					surf = boxes[b].surface;
   1937 
   1938 					p[0][0] = x0; p[0][1] = y0; p[0][2] = z0;
   1939 					p[1][0] = x1; p[1][1] = y0; p[1][2] = z0;
   1940 					p[2][0] = x1; p[2][1] = y1; p[2][2] = z0;
   1941 					p[3][0] = x0; p[3][1] = y1; p[3][2] = z0;
   1942 					p[4][0] = x0; p[4][1] = y0; p[4][2] = z1;
   1943 					p[5][0] = x1; p[5][1] = y0; p[5][2] = z1;
   1944 					p[6][0] = x1; p[6][1] = y1; p[6][2] = z1;
   1945 					p[7][0] = x0; p[7][1] = y1; p[7][2] = z1;
   1946 
   1947 					for (k = 0; k < 12; k++) {
   1948 						t = &cm->tris[cm->num_tris++];
   1949 						memcpy(t->v0, p[box_idx[k][0]], sizeof(float) * 3);
   1950 						memcpy(t->v1, p[box_idx[k][1]], sizeof(float) * 3);
   1951 						memcpy(t->v2, p[box_idx[k][2]], sizeof(float) * 3);
   1952 						t->surface = surf;
   1953 					}
   1954 				}
   1955 			}
   1956 			col_db_count++;
   1957 			col_db_insert(cm);
   1958 		}
   1959 		pos += 8 + h->size;
   1960 	}
   1961 }
   1962 
   1963 static void
   1964 process_gta_dat_col(const char *root, const char *dat_path)
   1965 {
   1966 	FILE *f;
   1967 	FILE *cf;
   1968 	char line[512];
   1969 	char rel[512];
   1970 	char *p;
   1971 	char *src;
   1972 	uint8_t *buf;
   1973 	size_t sz, i;
   1974 
   1975 	f = fopen_simple(root, dat_path);
   1976 	if (!f) {
   1977 		return;
   1978 	}
   1979 
   1980 	while (fgets(line, sizeof(line), f)) {
   1981 		p = line;
   1982 		while (*p == ' ' || *p == '\t') {
   1983 			p++;
   1984 		}
   1985 		if (strncasecmp(p, "COLFILE ", 8) == 0) {
   1986 			src = p + 8;
   1987 			while (*src == ' ' || *src == '\t') {
   1988 				src++;
   1989 			}
   1990 			while (*src >= '0' && *src <= '9') {
   1991 				src++;
   1992 			}
   1993 			while (*src == ' ' || *src == '\t') {
   1994 				src++;
   1995 			}
   1996 			for (i = 0; i < sizeof(rel) - 1 && src[i]; i++) {
   1997 				if (src[i] == '\\') {
   1998 					rel[i] = '/';
   1999 				} else {
   2000 					rel[i] = src[i];
   2001 				}
   2002 				rel[i + 1] = '\0';
   2003 			}
   2004 			trim_spaces(rel);
   2005 
   2006 			cf = fopen_simple(root, rel);
   2007 			if (cf) {
   2008 				fseek(cf, 0, SEEK_END);
   2009 				sz = ftell(cf);
   2010 				fseek(cf, 0, SEEK_SET);
   2011 				buf = malloc(sz);
   2012 				if (buf && fread(buf, 1, sz, cf) == sz) {
   2013 					parse_col_data(buf, sz);
   2014 				}
   2015 				free(buf);
   2016 				fclose(cf);
   2017 			}
   2018 		}
   2019 	}
   2020 	fclose(f);
   2021 }
   2022 
   2023 static struct col_model *
   2024 col_lookup(const char *name)
   2025 {
   2026 	uint32_t slot;
   2027 	int idx;
   2028 
   2029 	slot = str_hash(name) % COL_HASH_SZ;
   2030 	while (col_hash[slot] != 0) {
   2031 		idx = col_hash[slot] - 1;
   2032 		if (strcmp(col_db[idx].name, name) == 0) {
   2033 			return (&col_db[idx]);
   2034 		}
   2035 		slot = (slot + 1) % COL_HASH_SZ;
   2036 	}
   2037 	return (NULL);
   2038 }
   2039 
   2040 static void
   2041 instantiate_collision(const char *model_name, const struct mat4 *world_mat)
   2042 {
   2043 	struct col_model *cm;
   2044 	struct col_triangle wt;
   2045 	struct col_cell *c;
   2046 	float w, min_x, max_x, min_z, max_z, e1[3], e2[3], len;
   2047 	uint32_t i;
   2048 	int gx0, gx1, gz0, gz1, gx, gz;
   2049 
   2050 	cm = col_lookup(model_name);
   2051 	if (!cm || cm->num_tris == 0) {
   2052 		return;
   2053 	}
   2054 
   2055 	for (i = 0; i < cm->num_tris; i++) {
   2056 		mat_transform(wt.v0, &w, world_mat, cm->tris[i].v0);
   2057 		mat_transform(wt.v1, &w, world_mat, cm->tris[i].v1);
   2058 		mat_transform(wt.v2, &w, world_mat, cm->tris[i].v2);
   2059 		wt.surface = cm->tris[i].surface;
   2060 
   2061 		e1[0] = wt.v1[0] - wt.v0[0];
   2062 		e1[1] = wt.v1[1] - wt.v0[1];
   2063 		e1[2] = wt.v1[2] - wt.v0[2];
   2064 
   2065 		e2[0] = wt.v2[0] - wt.v0[0];
   2066 		e2[1] = wt.v2[1] - wt.v0[1];
   2067 		e2[2] = wt.v2[2] - wt.v0[2];
   2068 
   2069 		wt.norm[0] = e1[1] * e2[2] - e1[2] * e2[1];
   2070 		wt.norm[1] = e1[2] * e2[0] - e1[0] * e2[2];
   2071 		wt.norm[2] = e1[0] * e2[1] - e1[1] * e2[0];
   2072 
   2073 		len = sqrtf(wt.norm[0] * wt.norm[0] +
   2074 		    wt.norm[1] * wt.norm[1] +
   2075 		    wt.norm[2] * wt.norm[2]);
   2076 		if (len > 1e-6f) {
   2077 			wt.norm[0] /= len;
   2078 			wt.norm[1] /= len;
   2079 			wt.norm[2] /= len;
   2080 		} else {
   2081 			wt.norm[0] = 0.0f;
   2082 			wt.norm[1] = 1.0f;
   2083 			wt.norm[2] = 0.0f;
   2084 		}
   2085 
   2086 		min_x = fminf(wt.v0[0], fminf(wt.v1[0], wt.v2[0]));
   2087 		max_x = fmaxf(wt.v0[0], fmaxf(wt.v1[0], wt.v2[0]));
   2088 		min_z = fminf(wt.v0[2], fminf(wt.v1[2], wt.v2[2]));
   2089 		max_z = fmaxf(wt.v0[2], fmaxf(wt.v1[2], wt.v2[2]));
   2090 
   2091 		gx0 = (int)((min_x - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2092 		gx1 = (int)((max_x - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2093 		gz0 = (int)((min_z - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2094 		gz1 = (int)((max_z - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2095 
   2096 		if (gx0 < 0) gx0 = 0;
   2097 		if (gx1 >= GRID_SZ) gx1 = GRID_SZ - 1;
   2098 		if (gz0 < 0) gz0 = 0;
   2099 		if (gz1 >= GRID_SZ) gz1 = GRID_SZ - 1;
   2100 
   2101 		for (gz = gz0; gz <= gz1; gz++) {
   2102 			for (gx = gx0; gx <= gx1; gx++) {
   2103 				c = &world_col_grid[gx][gz];
   2104 				if (c->count >= c->capacity) {
   2105 					c->capacity = c->capacity == 0 ? 64 : c->capacity * 2;
   2106 					c->tris = realloc(c->tris, c->capacity * sizeof(struct col_triangle));
   2107 				}
   2108 				c->tris[c->count++] = wt;
   2109 			}
   2110 		}
   2111 	}
   2112 }
   2113 
   2114 static void
   2115 bake_world_collision(void)
   2116 {
   2117 	FILE *f;
   2118 	char line[512];
   2119 	char name[NAME_SZ];
   2120 	char *p;
   2121 	struct mat4 rot, trans, sa2gl, world;
   2122 	int in_inst, id, interior, lod, time_on, time_off;
   2123 	float px, py, pz, qx, qy, qz, qw;
   2124 
   2125 	f = fopen("assets/map.ipl", "r");
   2126 	if (!f) {
   2127 		return;
   2128 	}
   2129 
   2130 	in_inst = 0;
   2131 	while (fgets(line, sizeof(line), f)) {
   2132 		p = line;
   2133 		while (*p == ' ' || *p == '\t') {
   2134 			p++;
   2135 		}
   2136 		if (*p == '\0' || *p == '#') {
   2137 			continue;
   2138 		}
   2139 		if (strncasecmp(p, "inst", 4) == 0 || strncasecmp(p, "tobj", 4) == 0) {
   2140 			in_inst = 1;
   2141 			continue;
   2142 		}
   2143 		if (strncasecmp(p, "end", 3) == 0) {
   2144 			in_inst = 0;
   2145 			continue;
   2146 		}
   2147 		if (in_inst) {
   2148 			lod = -1;
   2149 			time_on = 0;
   2150 			time_off = 0;
   2151 			if (sscanf(p, "%d, %23[^,], %d, %f, %f, %f, %f, %f, %f, %f, %d, %d, %d",
   2152 			    &id, name, &interior, &px, &py, &pz, &qx, &qy, &qz, &qw,
   2153 			    &lod, &time_on, &time_off) >= 10) {
   2154 				trim_spaces(name);
   2155 				to_lower_str(name);
   2156 
   2157 				mat_from_quat(&rot, qx, qy, qz, qw);
   2158 				mat_translate(&trans, px, py, pz);
   2159 				mat_mul(&world, &trans, &rot);
   2160 
   2161 				memset(&sa2gl, 0, sizeof(sa2gl));
   2162 				sa2gl.m[0][0] = 1.0f;
   2163 				sa2gl.m[1][2] = 1.0f;
   2164 				sa2gl.m[2][1] = 1.0f;
   2165 				sa2gl.m[3][3] = 1.0f;
   2166 				mat_mul(&world, &sa2gl, &world);
   2167 
   2168 				instantiate_collision(name, &world);
   2169 			}
   2170 		}
   2171 	}
   2172 	fclose(f);
   2173 }
   2174 
   2175 static void
   2176 save_collision_bin(void)
   2177 {
   2178 	FILE *out;
   2179 	uint32_t cnt;
   2180 	int gx, gz;
   2181 
   2182 	out = fopen("assets/collision.bin", "wb");
   2183 	if (!out) {
   2184 		return;
   2185 	}
   2186 
   2187 	for (gz = 0; gz < GRID_SZ; gz++) {
   2188 		for (gx = 0; gx < GRID_SZ; gx++) {
   2189 			cnt = world_col_grid[gx][gz].count;
   2190 			fwrite(&cnt, sizeof(uint32_t), 1, out);
   2191 			if (cnt > 0) {
   2192 				fwrite(world_col_grid[gx][gz].tris,
   2193 				    sizeof(struct col_triangle), cnt, out);
   2194 			}
   2195 		}
   2196 	}
   2197 	fclose(out);
   2198 }
   2199 
   2200 static void
   2201 process_timecyc(const char *root)
   2202 {
   2203 	FILE *f;
   2204 	FILE *out;
   2205 	char line[512];
   2206 	struct timecyc_entry snaps[32 * 8];
   2207 	int w_idx, s_idx, total_weathers;
   2208 	char *p;
   2209 
   2210 	f = fopen_simple(root, "data/timecycp.dat");
   2211 	if (!f) {
   2212 		f = fopen_simple(root, "data/timecyc.dat");
   2213 	}
   2214 	if (!f) {
   2215 		return;
   2216 	}
   2217 
   2218 	out = fopen("assets/timecyc.bin", "wb");
   2219 	if (!out) {
   2220 		fclose(f);
   2221 		return;
   2222 	}
   2223 
   2224 	memset(snaps, 0, sizeof(snaps));
   2225 	w_idx = 0;
   2226 	s_idx = 0;
   2227 	total_weathers = 0;
   2228 
   2229 	while (fgets(line, sizeof(line), f)) {
   2230 		p = line;
   2231 		while (*p == ' ' || *p == '\t') {
   2232 			p++;
   2233 		}
   2234 		if (*p == '\0' || *p == '\n' || *p == '\r' ||
   2235 		    strncmp(p, "//", 2) == 0) {
   2236 			continue;
   2237 		}
   2238 
   2239 		char *tok, *save;
   2240 		char *tokens[64];
   2241 		int t = 0;
   2242 
   2243 		tok = strtok_r(p, " \t\r\n", &save);
   2244 		while (tok && t < 64) {
   2245 			tokens[t++] = tok;
   2246 			tok = strtok_r(NULL, " \t\r\n", &save);
   2247 		}
   2248 
   2249 		if (t >= 40) {
   2250 			struct timecyc_entry *e = &snaps[w_idx * 8 + s_idx];
   2251 			e->amb[0] = atoi(tokens[3]);
   2252 			e->amb[1] = atoi(tokens[4]);
   2253 			e->amb[2] = atoi(tokens[5]);
   2254 			e->dir[0] = atoi(tokens[6]);
   2255 			e->dir[1] = atoi(tokens[7]);
   2256 			e->dir[2] = atoi(tokens[8]);
   2257 			e->sky_top[0] = atoi(tokens[9]);
   2258 			e->sky_top[1] = atoi(tokens[10]);
   2259 			e->sky_top[2] = atoi(tokens[11]);
   2260 			e->sky_bot[0] = atoi(tokens[12]);
   2261 			e->sky_bot[1] = atoi(tokens[13]);
   2262 			e->sky_bot[2] = atoi(tokens[14]);
   2263 			e->far_clp = strtof(tokens[27], NULL);
   2264 			e->fog_st = strtof(tokens[28], NULL);
   2265 			e->water[0] = atoi(tokens[36]);
   2266 			e->water[1] = atoi(tokens[37]);
   2267 			e->water[2] = atoi(tokens[38]);
   2268 			e->water[3] = (t >= 40) ? atoi(tokens[39]) : 255;
   2269 
   2270 			s_idx++;
   2271 			if (s_idx == 8) {
   2272 				s_idx = 0;
   2273 				w_idx++;
   2274 				if (w_idx > total_weathers) {
   2275 					total_weathers = w_idx;
   2276 				}
   2277 				if (w_idx >= 32) {
   2278 					break;
   2279 				}
   2280 			}
   2281 		}
   2282 	}
   2283 	fwrite(&total_weathers, sizeof(int), 1, out);
   2284 	fwrite(snaps, sizeof(struct timecyc_entry), total_weathers * 8, out);
   2285 	fclose(out);
   2286 	fclose(f);
   2287 }
   2288 
   2289 static void *
   2290 build_worker(void *arg)
   2291 {
   2292 	struct thread_arg *ta;
   2293 	uint32_t i;
   2294 
   2295 	ta = arg;
   2296 	ta->arena.size = 128 * 1024 * 1024;
   2297 	ta->arena.mem = malloc(ta->arena.size);
   2298 
   2299 	for (i = ta->start; i < ta->end; i++) {
   2300 		char n[NAME_SZ + 1];
   2301 		size_t j;
   2302 		for (j = 0; j < sizeof(ta->entries[i].name) && ta->entries[i].name[j]; j++) {
   2303 			n[j] = tolower((unsigned char)ta->entries[i].name[j]);
   2304 		}
   2305 		n[j] = '\0';
   2306 
   2307 		if (list_has(ta->fl, n)) {
   2308 			uint32_t size = ta->entries[i].size * 2048;
   2309 			const uint8_t *buf = ta->img_data + ta->entries[i].offset * 2048;
   2310 			char *ext = strrchr(n, '.');
   2311 			if (ext) {
   2312 				*ext = '\0';
   2313 			}
   2314 
   2315 			ta->arena.pos = 0;
   2316 
   2317 			if (strstr(ta->entries[i].name, ".dff") || strstr(ta->entries[i].name, ".DFF")) {
   2318 				convert_dff(buf, size, n, &ta->arena);
   2319 			} else if (strstr(ta->entries[i].name, ".txd") || strstr(ta->entries[i].name, ".TXD")) {
   2320 				convert_txd(buf, size, n, &ta->arena);
   2321 			}
   2322 		}
   2323 	}
   2324 	free(ta->arena.mem);
   2325 	return (NULL);
   2326 }
   2327 
   2328 static void
   2329 tar_add_file(FILE *tar, const char *path, const char *tar_name)
   2330 {
   2331 	FILE *src;
   2332 	size_t sz, n, padding;
   2333 	struct tar_header th;
   2334 	unsigned int sum;
   2335 	uint8_t *p;
   2336 	char buf[4096];
   2337 
   2338 	src = fopen(path, "rb");
   2339 	if (!src) {
   2340 		return;
   2341 	}
   2342 
   2343 	fseek(src, 0, SEEK_END);
   2344 	sz = ftell(src);
   2345 	fseek(src, 0, SEEK_SET);
   2346 
   2347 	memset(&th, 0, sizeof(th));
   2348 	strncpy(th.name, tar_name, sizeof(th.name) - 1);
   2349 	snprintf(th.mode, sizeof(th.mode), "%07o", 0644);
   2350 	snprintf(th.size, sizeof(th.size), "%011lo", (unsigned long)sz);
   2351 	snprintf(th.magic, sizeof(th.magic), "ustar");
   2352 
   2353 	/* Simple checksum calculation. */
   2354 	memset(th.chksum, ' ', 8);
   2355 	sum = 0;
   2356 	p = (uint8_t *)&th;
   2357 	for (size_t i = 0; i < sizeof(th); i++) {
   2358 		sum += p[i];
   2359 	}
   2360 	snprintf(th.chksum, sizeof(th.chksum), "%06o", sum);
   2361 
   2362 	fwrite(&th, sizeof(th), 1, tar);
   2363 
   2364 	while ((n = fread(buf, 1, sizeof(buf), src)) > 0) {
   2365 		fwrite(buf, 1, n, tar);
   2366 	}
   2367 	fclose(src);
   2368 
   2369 	padding = (512 - (sz % 512)) % 512;
   2370 	if (padding > 0) {
   2371 		char pad[512] = {0};
   2372 		fwrite(pad, 1, padding, tar);
   2373 	}
   2374 }
   2375 
   2376 static void
   2377 pack_directory(FILE *tar, const char *dir_path, const char *prefix)
   2378 {
   2379 	DIR *dir;
   2380 	struct dirent *de;
   2381 	char path[1024];
   2382 	char tar_name[1024];
   2383 	struct stat st;
   2384 
   2385 	dir = opendir(dir_path);
   2386 	if (!dir) {
   2387 		return;
   2388 	}
   2389 	while ((de = readdir(dir))) {
   2390 		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) {
   2391 			continue;
   2392 		}
   2393 		snprintf(path, sizeof(path), "%s/%s", dir_path, de->d_name);
   2394 		snprintf(tar_name, sizeof(tar_name), "%s%s", prefix, de->d_name);
   2395 
   2396 		if (stat(path, &st) == 0) {
   2397 			if (S_ISDIR(st.st_mode)) {
   2398 				char new_prefix[1024];
   2399 				snprintf(new_prefix, sizeof(new_prefix), "%s/", tar_name);
   2400 				pack_directory(tar, path, new_prefix);
   2401 			} else {
   2402 				tar_add_file(tar, path, tar_name);
   2403 			}
   2404 		}
   2405 	}
   2406 	closedir(dir);
   2407 }
   2408 
   2409 static void
   2410 process_img_file(const char *root, const char *rel_path, struct file_list *fl, int num_threads, pthread_t *threads, struct thread_arg *args)
   2411 {
   2412 	char img_path[1024];
   2413 	int img_fd;
   2414 	struct stat st;
   2415 	uint8_t *img_data;
   2416 	struct img_header *hdr;
   2417 	struct img_entry *entries;
   2418 	uint32_t chunk;
   2419 	int i;
   2420 
   2421 	if (!resolve_simple(root, rel_path, img_path, sizeof(img_path))) {
   2422 		warnx("failed to resolve %s", rel_path);
   2423 		return;
   2424 	}
   2425 
   2426 	img_fd = open(img_path, O_RDONLY);
   2427 	if (img_fd < 0) {
   2428 		warn("failed to open %s", rel_path);
   2429 		return;
   2430 	}
   2431 
   2432 	if (fstat(img_fd, &st) < 0) {
   2433 		close(img_fd);
   2434 		return;
   2435 	}
   2436 
   2437 	img_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, img_fd, 0);
   2438 	if (img_data == MAP_FAILED) {
   2439 		close(img_fd);
   2440 		return;
   2441 	}
   2442 
   2443 	hdr = (struct img_header *)img_data;
   2444 	if (memcmp(hdr->magic, "VER2", 4) != 0) {
   2445 		munmap(img_data, st.st_size);
   2446 		close(img_fd);
   2447 		return;
   2448 	}
   2449 	entries = (struct img_entry *)(img_data + sizeof(struct img_header));
   2450 
   2451 	printf("build: processing %s (%u entries)...\n", rel_path, hdr->entries);
   2452 
   2453 	chunk = hdr->entries / num_threads;
   2454 	for (i = 0; i < num_threads; i++) {
   2455 		args[i].img_data = img_data;
   2456 		args[i].entries = entries;
   2457 		args[i].start = i * chunk;
   2458 		args[i].end = (i == num_threads - 1) ? hdr->entries : (i + 1) * chunk;
   2459 		args[i].fl = fl;
   2460 		pthread_create(&threads[i], NULL, build_worker, &args[i]);
   2461 	}
   2462 
   2463 	for (i = 0; i < num_threads; i++) {
   2464 		pthread_join(threads[i], NULL);
   2465 	}
   2466 
   2467 	munmap(img_data, st.st_size);
   2468 	close(img_fd);
   2469 }
   2470 
   2471 int
   2472 main(int argc, char *argv[])
   2473 {
   2474 	struct file_list fl;
   2475 	struct arena shared_arena;
   2476 	FILE *map_out;
   2477 	char img_path[1024];
   2478 	int img_fd;
   2479 	struct stat st;
   2480 	uint8_t *img_data;
   2481 	struct img_header *hdr;
   2482 	struct img_entry *entries;
   2483 	struct file_list missing_fl;
   2484 	int num_threads;
   2485 	pthread_t *threads;
   2486 	struct thread_arg *args;
   2487 	FILE *tar;
   2488 
   2489 	if (argc < 2) {
   2490 		return (1);
   2491 	}
   2492 
   2493 	mkdir("assets", 0777);
   2494 	mkdir("assets/models", 0777);
   2495 	mkdir("assets/textures", 0777);
   2496 
   2497 	scan_existing_assets();
   2498 	memset(&fl, 0, sizeof(fl));
   2499 
   2500 	map_out = fopen("assets/map.ipl", "w");
   2501 	if (!map_out) {
   2502 		err(1, "failed to create map.ipl");
   2503 	}
   2504 
   2505 	process_gta_dat_ide(argv[1], "data/default.dat", &fl);
   2506 	process_gta_dat_ide(argv[1], "data/gta.dat", &fl);
   2507 
   2508 	for (int i = 0; i < (int)(sizeof(special_actors) / sizeof(special_actors[0])); i++) {
   2509 		char d_name[64], t_name[64];
   2510 		snprintf(d_name, sizeof(d_name), "%s.dff", special_actors[i].model);
   2511 		snprintf(t_name, sizeof(t_name), "%s.txd", special_actors[i].txd);
   2512 		list_add(&fl, d_name);
   2513 		list_add(&fl, t_name);
   2514 	}
   2515 
   2516 	for (int i = 0; i < 313; i++) {
   2517 		if (skin_names[i][0] != '\0') {
   2518 			char d_name[64], t_name[64];
   2519 			snprintf(d_name, sizeof(d_name), "%s.dff", skin_names[i]);
   2520 			snprintf(t_name, sizeof(t_name), "%s.txd", skin_names[i]);
   2521 			list_add(&fl, d_name);
   2522 			list_add(&fl, t_name);
   2523 		}
   2524 	}
   2525 
   2526 	process_gta_dat_ipl(argv[1], "data/default.dat", map_out, &fl);
   2527 	process_gta_dat_ipl(argv[1], "data/gta.dat", map_out, &fl);
   2528 
   2529 	if (!resolve_simple(argv[1], "models/gta3.img", img_path, sizeof(img_path))) {
   2530 		errx(1, "failed to resolve gta3.img");
   2531 	}
   2532 
   2533 	img_fd = open(img_path, O_RDONLY);
   2534 	if (img_fd < 0) {
   2535 		err(1, "failed to open gta3.img");
   2536 	}
   2537 
   2538 	fstat(img_fd, &st);
   2539 	img_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, img_fd, 0);
   2540 	if (img_data == MAP_FAILED) {
   2541 		err(1, "mmap failed");
   2542 	}
   2543 
   2544 	hdr = (struct img_header *)img_data;
   2545 	if (memcmp(hdr->magic, "VER2", 4) != 0) {
   2546 		errx(1, "invalid img");
   2547 	}
   2548 	entries = (struct img_entry *)(img_data + sizeof(struct img_header));
   2549 
   2550 	for (uint32_t i = 0; i < hdr->entries; i++) {
   2551 		char name_lower[NAME_SZ + 1];
   2552 		size_t j;
   2553 		for (j = 0; j < sizeof(entries[i].name) && entries[i].name[j]; j++) {
   2554 			name_lower[j] = tolower((unsigned char)entries[i].name[j]);
   2555 		}
   2556 		name_lower[j] = '\0';
   2557 
   2558 		if (strstr(name_lower, ".ipl") != NULL) {
   2559 			uint32_t size = entries[i].size * 2048;
   2560 			const uint8_t *buf = img_data + entries[i].offset * 2048;
   2561 			if (size >= 4 && memcmp(buf, "bnry", 4) == 0) {
   2562 				parse_binary_ipl(buf, size, map_out, &fl);
   2563 			} else {
   2564 				parse_text_ipl((char *)buf, size, map_out, &fl);
   2565 			}
   2566 		}
   2567 
   2568 		if (strstr(name_lower, ".col") != NULL) {
   2569 			uint32_t size = entries[i].size * 2048;
   2570 			const uint8_t *buf = img_data + entries[i].offset * 2048;
   2571 			parse_col_data(buf, size);
   2572 		}
   2573 	}
   2574 	fclose(map_out);
   2575 
   2576 	memset(&missing_fl, 0, sizeof(missing_fl));
   2577 	for (int i = 0; i < fl.count; i++) {
   2578 		if (!asset_exists(fl.names[i])) {
   2579 			list_add(&missing_fl, fl.names[i]);
   2580 		}
   2581 	}
   2582 	printf("Total map files: %d, missing/rebuilding: %d\n", fl.count, missing_fl.count);
   2583 	fl = missing_fl;
   2584 
   2585 	munmap(img_data, st.st_size);
   2586 	close(img_fd);
   2587 
   2588 	shared_arena.size = 128 * 1024 * 1024;
   2589 	shared_arena.mem = malloc(shared_arena.size);
   2590 	process_particle_txd(argv[1], &shared_arena);
   2591 	free(shared_arena.mem);
   2592 
   2593 	process_water(argv[1]);
   2594 	process_timecyc(argv[1]);
   2595 
   2596 	num_threads = sysconf(_SC_NPROCESSORS_ONLN);
   2597 	if (num_threads < 1) {
   2598 		num_threads = 4;
   2599 	}
   2600 
   2601 	threads = malloc(num_threads * sizeof(pthread_t));
   2602 	args = malloc(num_threads * sizeof(struct thread_arg));
   2603 
   2604 	process_img_file(argv[1], "models/gta3.img", &fl, num_threads, threads, args);
   2605 
   2606 	process_img_file(argv[1], "models/gta_int.img", &fl, num_threads, threads, args);
   2607 
   2608 	process_img_file(argv[1], "models/cutscene.img", &fl, num_threads, threads, args);
   2609 	process_gta_dat_col(argv[1], "data/default.dat");
   2610 	process_gta_dat_col(argv[1], "data/gta.dat");
   2611 	printf("Loaded %d collision models into memory\n", col_db_count);
   2612 	bake_world_collision();
   2613 	save_collision_bin();
   2614 
   2615 	free(threads);
   2616 	free(args);
   2617 
   2618 	printf("Packing assets.tar...\n");
   2619 	tar = fopen("assets.tar", "wb");
   2620 	if (tar) {
   2621 		pack_directory(tar, "assets", "assets/");
   2622 		char empty[1024] = {0};
   2623 		fwrite(empty, 1, sizeof(empty), tar);
   2624 		fclose(tar);
   2625 		system("rm -rf assets");
   2626 	}
   2627 
   2628 	return (0);
   2629 }