antizona

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

render.c (85385B)


      1 #include <arpa/inet.h>
      2 #include <netinet/in.h>
      3 #include <sys/ipc.h>
      4 #include <sys/mman.h>
      5 #include <sys/socket.h>
      6 #include <sys/shm.h>
      7 #include <sys/stat.h>
      8 
      9 #include <X11/Xlib.h>
     10 #include <X11/Xutil.h>
     11 #include <X11/keysym.h>
     12 #include <X11/extensions/XShm.h>
     13 
     14 #include <ctype.h>
     15 #include <err.h>
     16 #include <fcntl.h>
     17 #include <locale.h>
     18 #include <math.h>
     19 #include <pthread.h>
     20 #include <stdio.h>
     21 #include <stdint.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <strings.h>
     25 #include <time.h>
     26 #include <unistd.h>
     27 
     28 #include "skins.h"
     29 #include "net.h"
     30 
     31 #define WIDTH			640
     32 #define HEIGHT			480
     33 #define MAX_CACHE		8192
     34 #define NAME_SZ			24
     35 #define MAX_DIST		250.0f
     36 #define GRID_SZ			64
     37 #define MAP_MIN			-3000.0f
     38 #define MAP_MAX			 3000.0f
     39 #define MAX_RENDER_TRIS		262144
     40 #define TAR_INDEX_SIZE		32768
     41 #define CHAT_LINES		6
     42 
     43 #define GRAVITY			9.81f
     44 #define TERMINAL_VEL		50.0f
     45 #define JUMP_FORCE		6.2f
     46 #define STEP_SNAP_DOWN		0.40f
     47 
     48 #define MIN(a, b) ((a) < (b) ? (a) : (b))
     49 #define MAX(a, b) ((a) > (b) ? (a) : (b))
     50 
     51 struct vec3 { float x, y, z; };
     52 struct mat4 { float m[4][4]; };
     53 
     54 struct col_triangle {
     55 	float		v0[3];
     56 	float		v1[3];
     57 	float		v2[3];
     58 	float		norm[3];
     59 	uint8_t		surface;
     60 };
     61 
     62 struct col_cell {
     63 	const struct col_triangle	*tris;
     64 	uint32_t			 count;
     65 };
     66 
     67 struct chat_entry {
     68 	char	text[160];
     69 	float	timer;
     70 };
     71 
     72 struct timecyc_entry {
     73 	uint8_t	amb[3], dir[3], sky_top[3], sky_bot[3], water[4];
     74 	float	far_clp, fog_st;
     75 };
     76 
     77 struct sys_gfx {
     78 	Display			*dpy;
     79 	Window			 win;
     80 	GC			 gc;
     81 	XImage			*img;
     82 	XShmSegmentInfo		 shm;
     83 	uint32_t		*pixels;
     84 	float			*zbuffer;
     85 	Atom			 wm_delete;
     86 	struct mat4		 proj;
     87 	char			 keys[512];
     88 	float			 game_time_sec, game_time_hours;
     89 	struct timecyc_entry	 weathers[32][8], cur_weather;
     90 	int			 num_weathers, game_weather;
     91 	float			 far_clip_override;
     92 	int			 in_chat, chat_len;
     93 	char			 chat_buf[128];
     94 	int			 menu_open;
     95 	int			 show_debug;
     96 	float			 fps;
     97 	uint32_t		 pkts_in, pkts_out;
     98 	uint32_t		 pkts_in_sec, pkts_out_sec;
     99 	float			 stats_timer;
    100 	KeyCode			 key_w, key_a, key_s, key_d, key_t,
    101 	    key_esc, key_space, key_up, key_down, key_left, key_right;
    102 	XIC			 ic;
    103 	XFontSet		 font_set;
    104 };
    105 
    106 struct vertex { float x, y, z, w, u, v, r, g, b, a, f; };
    107 struct clip_vertex { float x, y, z, w, u, v, r, g, b, a, f; };
    108 
    109 struct texture {
    110 	uint32_t	*pixels;
    111 	int		 w, h, has_alpha;
    112 	uint32_t	*mips[4];
    113 	int		 mip_w[4];
    114 	int		 mip_h[4];
    115 };
    116 
    117 struct render_triangle {
    118 	struct vertex		v0, v1, v2;
    119 	const struct texture	*tex;
    120 	int			is_water, mip;
    121 };
    122 
    123 struct ply_vertex {
    124 	float x, y, z;
    125 	float s, t;
    126 	uint8_t r, g, b, a;
    127 };
    128 
    129 struct mesh {
    130 	struct ply_vertex	*ply_verts;
    131 	uint16_t		*indices, *mat_ids;
    132 	uint32_t		 num_verts, num_tris, num_materials;
    133 	char			(*raw_tex_names)[32];
    134 	struct texture		**textures;
    135 	float			 spr_x, spr_y, spr_z, spr_r, total_area;
    136 };
    137 
    138 struct net_snap {
    139 	float	x, y, z;
    140 	float	yaw;
    141 	double	time;
    142 };
    143 
    144 struct net_player {
    145 	uint8_t		id;
    146 	uint16_t	skin;
    147 	float		cur_x, cur_y, cur_z;
    148 	float		cur_yaw;
    149 	struct net_snap	snaps[4];
    150 	int		snap_count;
    151 	int		active;
    152 };
    153 
    154 struct transform_array {
    155 	float			*pos_x, *pos_y, *pos_z;
    156 	float			*rot_qx, *rot_qy, *rot_qz, *rot_qw;
    157 	struct mat4		*world_matrices;
    158 	float			*sphere_cx, *sphere_cy, *sphere_cz, *sphere_r;
    159 	int16_t			*time_on, *time_off;
    160 	int			 count;
    161 };
    162 
    163 struct grid_cell { int *ids, count, cap; };
    164 
    165 struct asset_cache {
    166 	struct mesh	 meshes[MAX_CACHE];
    167 	struct texture	 textures[MAX_CACHE];
    168 	char		 mesh_names[MAX_CACHE][NAME_SZ], tex_names[MAX_CACHE][32];
    169 	int		 mesh_count, tex_count, mesh_hash[MAX_CACHE * 2], tex_hash[MAX_CACHE * 2];
    170 };
    171 
    172 struct draw_item { int id; float dist_sq; };
    173 struct water_face {
    174 	float	x[4], y[4], z[4];
    175 	float	u[4], v[4], h[4]; 
    176 	int num;
    177 };
    178 
    179 static pthread_barrier_t	barrier_start;
    180 static pthread_barrier_t	barrier_end;
    181 
    182 struct tar_header {
    183 	char name[100];
    184 	char mode[8];
    185 	char uid[8];
    186 	char gid[8];
    187 	char size[12];
    188 	char mtime[12];
    189 	char chksum[8];
    190 	char typeflag;
    191 	char linkname[100];
    192 	char magic[6];
    193 	char version[2];
    194 	char uname[32];
    195 	char gname[32];
    196 	char devmajor[8];
    197 	char devminor[8];
    198 	char prefix[155];
    199 	char pad[12];
    200 } __attribute__((packed));
    201 
    202 struct tga_header {
    203 	uint8_t  id_length;
    204 	uint8_t  color_map_type;
    205 	uint8_t  image_type;
    206 	uint16_t color_map_first;
    207 	uint16_t color_map_length;
    208 	uint8_t  color_map_entry_size;
    209 	uint16_t x_origin;
    210 	uint16_t y_origin;
    211 	uint16_t width;
    212 	uint16_t height;
    213 	uint8_t  pixel_depth;
    214 	uint8_t  image_descriptor;
    215 } __attribute__((packed));
    216 
    217 struct tar_index_entry {
    218 	char			name[128];
    219 	const uint8_t		*data;
    220 	size_t			size;
    221 };
    222 
    223 static struct col_cell		 g_col_grid[GRID_SZ][GRID_SZ];
    224 static struct sys_gfx		*g_sys;
    225 static struct transform_array	 g_transforms;
    226 static struct mesh		**scene_meshes = NULL;
    227 static int			 scene_inst_count = 0, scene_inst_capacity = 0;
    228 static struct grid_cell		 scene_grid[GRID_SZ][GRID_SZ];
    229 static struct draw_item		*draw_list = NULL;
    230 static int			 draw_cap = 0, draw_count = 0;
    231 static struct render_triangle	 render_list[MAX_RENDER_TRIS];
    232 static int			 render_count = 0;
    233 static struct water_face	*water_faces = NULL;
    234 static uint32_t			 water_count = 0;
    235 static struct texture		*water_tex = NULL, *sand_tex = NULL;
    236 static pthread_t		*workers = NULL;
    237 static int			 num_threads = 1, threads_running = 1;
    238 static struct clip_vertex	*v_scratch = NULL;
    239 static size_t			 v_scratch_cap = 0;
    240 
    241 static uint8_t			*g_tar_mapped = NULL;
    242 static size_t			 g_tar_size = 0;
    243 static struct tar_index_entry	 tar_idx[TAR_INDEX_SIZE];
    244 static struct asset_cache	*g_cache = NULL;
    245 static int			 active_skin_id = 7;
    246 
    247 static int			net_fd = -1;
    248 static struct sockaddr_in	srv_addr;
    249 static int			my_player_id = -1;
    250 static int			net_connected = 0;
    251 static struct net_player	net_players[MAX_PLAYERS];
    252 
    253 static struct chat_entry	chat_log[CHAT_LINES];
    254 static int			chat_log_count = 0;
    255 static char			local_nick[24];
    256 
    257 static size_t
    258 get_tar_size(const char *octal)
    259 {
    260 	size_t size = 0;
    261 	int i;
    262 
    263 	for (i = 0; i < 11; i++) {
    264 		if (octal[i] < '0' || octal[i] > '7') {
    265 			break;
    266 		}
    267 		size = size * 8 + (octal[i] - '0');
    268 	}
    269 	return (size);
    270 }
    271 
    272 static uint32_t
    273 tar_hash(const char *str)
    274 {
    275 	uint32_t hash = 5381;
    276 	int c;
    277 
    278 	while ((c = (unsigned char)*str++)) {
    279 		hash = ((hash << 5) + hash) + tolower(c);
    280 	}
    281 	return (hash);
    282 }
    283 
    284 static void
    285 tar_build_index(void)
    286 {
    287 	size_t offset = 0;
    288 	struct tar_header *h;
    289 	size_t file_sz;
    290 	uint32_t slot;
    291 
    292 	memset(tar_idx, 0, sizeof(tar_idx));
    293 
    294 	while (offset < g_tar_size) {
    295 		h = (struct tar_header *)(g_tar_mapped + offset);
    296 		if (h->name[0] == '\0') {
    297 			break;
    298 		}
    299 		file_sz = get_tar_size(h->size);
    300 		const uint8_t *file_data = g_tar_mapped + offset + 512;
    301 
    302 		slot = tar_hash(h->name) % TAR_INDEX_SIZE;
    303 		while (tar_idx[slot].data != NULL) {
    304 			if (strcasecmp(tar_idx[slot].name, h->name) == 0) {
    305 				goto next_file;
    306 			}
    307 			slot = (slot + 1) % TAR_INDEX_SIZE;
    308 		}
    309 
    310 		strncpy(tar_idx[slot].name, h->name, sizeof(tar_idx[slot].name) - 1);
    311 		tar_idx[slot].data = file_data;
    312 		tar_idx[slot].size = file_sz;
    313 
    314 	next_file:
    315 		offset += 512 + ((file_sz + 511) & ~511);
    316 	}
    317 }
    318 
    319 static const uint8_t *
    320 tar_lookup(const char *filename, size_t *out_size)
    321 {
    322 	uint32_t slot;
    323 
    324 	slot = tar_hash(filename) % TAR_INDEX_SIZE;
    325 	while (tar_idx[slot].data != NULL) {
    326 		if (strcasecmp(tar_idx[slot].name, filename) == 0) {
    327 			*out_size = tar_idx[slot].size;
    328 			return (tar_idx[slot].data);
    329 		}
    330 		slot = (slot + 1) % TAR_INDEX_SIZE;
    331 	}
    332 	return (NULL);
    333 }
    334 
    335 static inline float
    336 edge_func(float ax, float ay, float bx, float by, float cx, float cy)
    337 {
    338 	return ((cx - ax) * (by - ay) - (cy - ay) * (bx - ax));
    339 }
    340 
    341 static void
    342 closest_point_triangle(const float p[3], const float a[3], const float b[3], const float c[3], float out[3])
    343 {
    344 	float ab[3], ac[3], ap[3], bp[3], cp[3];
    345 	float d1, d2, d3, d4, d5, d6;
    346 	float vc, vb, va, denom, v, w, u;
    347 
    348 	ab[0] = b[0] - a[0];
    349 	ab[1] = b[1] - a[1];
    350 	ab[2] = b[2] - a[2];
    351 
    352 	ac[0] = c[0] - a[0];
    353 	ac[1] = c[1] - a[1];
    354 	ac[2] = c[2] - a[2];
    355 
    356 	ap[0] = p[0] - a[0];
    357 	ap[1] = p[1] - a[1];
    358 	ap[2] = p[2] - a[2];
    359 
    360 	d1 = ab[0] * ap[0] + ab[1] * ap[1] + ab[2] * ap[2];
    361 	d2 = ac[0] * ap[0] + ac[1] * ap[1] + ac[2] * ap[2];
    362 	if (d1 <= 0.0f && d2 <= 0.0f) {
    363 		out[0] = a[0];
    364 		out[1] = a[1];
    365 		out[2] = a[2];
    366 		return;
    367 	}
    368 
    369 	bp[0] = p[0] - b[0];
    370 	bp[1] = p[1] - b[1];
    371 	bp[2] = p[2] - b[2];
    372 
    373 	d3 = ab[0] * bp[0] + ab[1] * bp[1] + ab[2] * bp[2];
    374 	d4 = ac[0] * bp[0] + ac[1] * bp[1] + ac[2] * bp[2];
    375 	if (d3 >= 0.0f && d4 <= d3) {
    376 		out[0] = b[0];
    377 		out[1] = b[1];
    378 		out[2] = b[2];
    379 		return;
    380 	}
    381 
    382 	vc = d1 * d4 - d3 * d2;
    383 	if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
    384 		v = d1 / (d1 - d3);
    385 		out[0] = a[0] + v * ab[0];
    386 		out[1] = a[1] + v * ab[1];
    387 		out[2] = a[2] + v * ab[2];
    388 		return;
    389 	}
    390 
    391 	cp[0] = p[0] - c[0];
    392 	cp[1] = p[1] - c[1];
    393 	cp[2] = p[2] - c[2];
    394 
    395 	d5 = ab[0] * cp[0] + ab[1] * cp[1] + ab[2] * cp[2];
    396 	d6 = ac[0] * cp[0] + ac[1] * cp[1] + ac[2] * cp[2];
    397 	if (d6 >= 0.0f && d5 <= d6) {
    398 		out[0] = c[0];
    399 		out[1] = c[1];
    400 		out[2] = c[2];
    401 		return;
    402 	}
    403 
    404 	vb = d5 * d2 - d1 * d6;
    405 	if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
    406 		w = d2 / (d2 - d6);
    407 		out[0] = a[0] + w * ac[0];
    408 		out[1] = a[1] + w * ac[1];
    409 		out[2] = a[2] + w * ac[2];
    410 		return;
    411 	}
    412 
    413 	va = d3 * d6 - d5 * d4;
    414 	if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
    415 		w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
    416 		out[0] = b[0] + w * (c[0] - b[0]);
    417 		out[1] = b[1] + w * (c[1] - b[1]);
    418 		out[2] = b[2] + w * (c[2] - b[2]);
    419 		return;
    420 	}
    421 
    422 	denom = 1.0f / (va + vb + vc);
    423 	v = vb * denom;
    424 	w = vc * denom;
    425 	u = 1.0f - v - w;
    426 	out[0] = u * a[0] + v * b[0] + w * c[0];
    427 	out[1] = u * a[1] + v * b[1] + w * c[1];
    428 	out[2] = u * a[2] + v * b[2] + w * c[2];
    429 }
    430 
    431 static void
    432 draw_triangle_band(const struct render_triangle *tri, int min_y_band, int max_y_band)
    433 {
    434 	struct vertex v0, v1, v2, sv0, sv1, sv2, tmp;
    435 	const struct texture *tex;
    436 	const uint32_t *pixels;
    437 	float area, inv_area, dy12, dy20, dx12, dx20, dy01;
    438 	float p_x_start, p_y_start, w0_start, w1_start;
    439 	float dw0_dx, dw0_dy, dw1_dx, dw1_dy;
    440 	float u0_w, u1_w, u2_w, v0_w, v1_w, v2_w, f0_w, f1_w, f2_w;
    441 	float d_inv_w_dx, d_u_w_dx, d_v_w_dx, d_f_w_dx, d_r_dx, d_g_dx, d_b_dx;
    442 	float d_r_dx_255, d_g_dx_255, d_b_dx_255;
    443 	float inv_slope_long, inv_slope_short1, inv_slope_short2;
    444 	float row_y, x_long, x_short, x_min, x_max;
    445 	float dx, dy, row_w0, row_w1, row_w2;
    446 	float inv_w, u_w, v_w, f_w, r, g_val, b, wf, f, inv_f, min_inv_w;
    447 	uint32_t sky_r, sky_g, sky_b, color, bg, tex_r, tex_g, tex_b;
    448 	uint8_t tex_a, wa_tc, wr, wg, wb, wa;
    449 	int min_x, max_x, min_y, max_y, row_min_x, row_max_x;
    450 	int tw, th, tw_mask, th_mask, py, px, idx, ir, ig, ib, tx, ty, m;
    451 
    452 	v0 = tri->v0;
    453 	v1 = tri->v1;
    454 	v2 = tri->v2;
    455 
    456 	min_y = (int)floorf(MIN(v0.y, MIN(v1.y, v2.y)));
    457 	max_y = (int)ceilf(MAX(v0.y, MAX(v1.y, v2.y)));
    458 	if (max_y < min_y_band || min_y > max_y_band) {
    459 		return;
    460 	}
    461 
    462 	min_x = (int)floorf(MIN(v0.x, MIN(v1.x, v2.x)));
    463 	max_x = (int)ceilf(MAX(v0.x, MAX(v1.x, v2.x)));
    464 	if (min_x >= WIDTH || max_x < 0) {
    465 		return;
    466 	}
    467 
    468 	min_inv_w = MIN(v0.w, MIN(v1.w, v2.w));
    469 	if (min_inv_w < 0.0001f) {
    470 		min_inv_w = 0.0001f;
    471 	}
    472 
    473 	area = edge_func(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
    474 	if (fabsf(area) < 1e-5f) {
    475 		return;
    476 	}
    477 	inv_area = 1.0f / area;
    478 
    479 	dy12 = v2.y - v1.y;
    480 	dy20 = v0.y - v2.y;
    481 	dx12 = v2.x - v1.x;
    482 	dx20 = v0.x - v2.x;
    483 	dy01 = v1.y - v0.y;
    484 
    485 	if (min_x < 0) min_x = 0;
    486 	if (max_x >= WIDTH) max_x = WIDTH - 1;
    487 	if (min_y < min_y_band) min_y = min_y_band;
    488 	if (max_y > max_y_band) max_y = max_y_band;
    489 	if (min_y > max_y || min_x > max_x) {
    490 		return;
    491 	}
    492 
    493 	p_x_start = min_x + 0.5f;
    494 	p_y_start = min_y + 0.5f;
    495 	w0_start = ((p_x_start - v1.x) * dy12 - (p_y_start - v1.y) * dx12) * inv_area;
    496 	w1_start = ((p_x_start - v2.x) * dy20 - (p_y_start - v2.y) * dx20) * inv_area;
    497 
    498 	dw0_dx = dy12 * inv_area;
    499 	dw0_dy = -dx12 * inv_area;
    500 	dw1_dx = dy20 * inv_area;
    501 	dw1_dy = -dx20 * inv_area;
    502 
    503 	u0_w = v0.u * v0.w; u1_w = v1.u * v1.w; u2_w = v2.u * v2.w;
    504 	v0_w = v0.v * v0.w; v1_w = v1.v * v1.w; v2_w = v2.v * v2.w;
    505 	f0_w = v0.f * v0.w; f1_w = v1.f * v1.w; f2_w = v2.f * v2.w;
    506 
    507 	d_inv_w_dx = (dy12 * v0.w + dy20 * v1.w + dy01 * v2.w) * inv_area;
    508 	d_u_w_dx   = (dy12 * u0_w + dy20 * u1_w + dy01 * u2_w) * inv_area;
    509 	d_v_w_dx   = (dy12 * v0_w + dy20 * v1_w + dy01 * v2_w) * inv_area;
    510 	d_f_w_dx   = (dy12 * f0_w + dy20 * f1_w + dy01 * f2_w) * inv_area;
    511 	d_r_dx     = (dy12 * v0.r + dy20 * v1.r + dy01 * v2.r) * inv_area;
    512 	d_g_dx     = (dy12 * v0.g + dy20 * v1.g + dy01 * v2.g) * inv_area;
    513 	d_b_dx     = (dy12 * v0.b + dy20 * v1.b + dy01 * v2.b) * inv_area;
    514 
    515 	d_r_dx_255 = d_r_dx * 255.0f;
    516 	d_g_dx_255 = d_g_dx * 255.0f;
    517 	d_b_dx_255 = d_b_dx * 255.0f;
    518 
    519 	sky_r = g_sys->cur_weather.sky_bot[0];
    520 	sky_g = g_sys->cur_weather.sky_bot[1];
    521 	sky_b = g_sys->cur_weather.sky_bot[2];
    522 
    523 	sv0 = v0; sv1 = v1; sv2 = v2;
    524 	if (sv0.y > sv1.y) { tmp = sv0; sv0 = sv1; sv1 = tmp; }
    525 	if (sv0.y > sv2.y) { tmp = sv0; sv0 = sv2; sv2 = tmp; }
    526 	if (sv1.y > sv2.y) { tmp = sv1; sv1 = sv2; sv2 = tmp; }
    527 
    528 	inv_slope_long = (sv2.y != sv0.y) ? (sv2.x - sv0.x) / (sv2.y - sv0.y) : 0.0f;
    529 	inv_slope_short1 = (sv1.y != sv0.y) ? (sv1.x - sv0.x) / (sv1.y - sv0.y) : 0.0f;
    530 	inv_slope_short2 = (sv2.y != sv1.y) ? (sv2.x - sv1.x) / (sv2.y - sv1.y) : 0.0f;
    531 
    532 	if (tri->tex && (uintptr_t)tri->tex != (uintptr_t)-1 && !tri->is_water) {
    533 		tex = tri->tex;
    534 		m = tri->mip;
    535 		if (m < 0) m = 0;
    536 		if (m > 3) m = 3;
    537 		pixels = tex->mips[m];
    538 		tw = tex->mip_w[m];
    539 		th = tex->mip_h[m];
    540 		tw_mask = tw - 1;
    541 		th_mask = th - 1;
    542 
    543 		for (py = min_y; py <= max_y; py++) {
    544 			row_y = (float)py + 0.5f;
    545 			x_long = sv0.x + (row_y - sv0.y) * inv_slope_long;
    546 			x_short = (row_y < sv1.y) ?
    547 			    sv0.x + (row_y - sv0.y) * inv_slope_short1 :
    548 			    sv1.x + (row_y - sv1.y) * inv_slope_short2;
    549 
    550 			x_min = (x_long < x_short) ? x_long : x_short;
    551 			x_max = (x_long < x_short) ? x_short : x_long;
    552 
    553 			row_min_x = (int)floorf(x_min);
    554 			row_max_x = (int)ceilf(x_max);
    555 
    556 			if (row_min_x < min_x) row_min_x = min_x;
    557 			if (row_max_x > max_x) row_max_x = max_x;
    558 			if (row_min_x > row_max_x) continue;
    559 
    560 			dx = (row_min_x + 0.5f) - p_x_start;
    561 			dy = row_y - p_y_start;
    562 			row_w0 = w0_start + dw0_dx * dx + dw0_dy * dy;
    563 			row_w1 = w1_start + dw1_dx * dx + dw1_dy * dy;
    564 			row_w2 = 1.0f - row_w0 - row_w1;
    565 
    566 			inv_w = row_w0 * v0.w + row_w1 * v1.w + row_w2 * v2.w;
    567 			u_w = row_w0 * u0_w + row_w1 * u1_w + row_w2 * u2_w;
    568 			v_w = row_w0 * v0_w + row_w1 * v1_w + row_w2 * v2_w;
    569 			f_w = row_w0 * f0_w + row_w1 * f1_w + row_w2 * f2_w;
    570 			r = (row_w0 * v0.r + row_w1 * v1.r + row_w2 * v2.r) * 255.0f;
    571 			g_val = (row_w0 * v0.g + row_w1 * v1.g + row_w2 * v2.g) * 255.0f;
    572 			b = (row_w0 * v0.b + row_w1 * v1.b + row_w2 * v2.b) * 255.0f;
    573 
    574 			for (px = row_min_x; px <= row_max_x; px++) {
    575 				if (row_w0 >= -1e-4f && row_w1 >= -1e-4f && row_w2 >= -1e-4f) {
    576 					idx = py * WIDTH + px;
    577 					if (inv_w >= g_sys->zbuffer[idx] - 1e-6f && inv_w >= min_inv_w * 0.99f) {
    578 						wf = 1.0f / inv_w;
    579 						tx = (int)(u_w * wf * tw) & tw_mask;
    580 						ty = (int)(v_w * wf * th) & th_mask;
    581 						color = pixels[ty * tw + tx];
    582 						tex_a = (color >> 24) & 0xFF;
    583 						if (tex_a > 127) {
    584 							ir = (int)r; if (ir > 255) ir = 255; else if (ir < 0) ir = 0;
    585 							ig = (int)g_val; if (ig > 255) ig = 255; else if (ig < 0) ig = 0;
    586 							ib = (int)b; if (ib > 255) ib = 255; else if (ib < 0) ib = 0;
    587 
    588 							tex_r = ((color >> 16) & 0xFF) * ir >> 8;
    589 							tex_g = ((color >> 8) & 0xFF) * ig >> 8;
    590 							tex_b = (color & 0xFF) * ib >> 8;
    591 
    592 							f = f_w * wf;
    593 							if (f > 0.001f) {
    594 								if (f > 1.0f) f = 1.0f;
    595 								inv_f = 1.0f - f;
    596 								tex_r = (uint32_t)(tex_r * inv_f + sky_r * f);
    597 								tex_g = (uint32_t)(tex_g * inv_f + sky_g * f);
    598 								tex_b = (uint32_t)(tex_b * inv_f + sky_b * f);
    599 							}
    600 
    601 							g_sys->pixels[idx] = (tex_a << 24) |
    602 							    (tex_r << 16) | (tex_g << 8) | tex_b;
    603 							g_sys->zbuffer[idx] = inv_w;
    604 						}
    605 					}
    606 				}
    607 				row_w0 += dw0_dx; row_w1 += dw1_dx; row_w2 -= (dw0_dx + dw1_dx);
    608 				inv_w += d_inv_w_dx; u_w += d_u_w_dx; v_w += d_v_w_dx; f_w += d_f_w_dx;
    609 				r += d_r_dx_255; g_val += d_g_dx_255; b += d_b_dx_255;
    610 			}
    611 		}
    612 	} else if (tri->is_water && tri->tex && (uintptr_t)tri->tex != (uintptr_t)-1) {
    613 		tex = tri->tex;
    614 		pixels = tex->pixels;
    615 		tw = tex->w;
    616 		th = tex->h;
    617 		tw_mask = tw - 1;
    618 		th_mask = th - 1;
    619 		wa_tc = g_sys->cur_weather.water[3];
    620 		wr = g_sys->cur_weather.water[0];
    621 		wg = g_sys->cur_weather.water[1];
    622 		wb = g_sys->cur_weather.water[2];
    623 
    624 		for (py = min_y; py <= max_y; py++) {
    625 			row_y = (float)py + 0.5f;
    626 			x_long = sv0.x + (row_y - sv0.y) * inv_slope_long;
    627 			x_short = (row_y < sv1.y) ?
    628 			    sv0.x + (row_y - sv0.y) * inv_slope_short1 :
    629 			    sv1.x + (row_y - sv1.y) * inv_slope_short2;
    630 
    631 			x_min = (x_long < x_short) ? x_long : x_short;
    632 			x_max = (x_long < x_short) ? x_short : x_long;
    633 
    634 			row_min_x = (int)floorf(x_min);
    635 			row_max_x = (int)ceilf(x_max);
    636 
    637 			if (row_min_x < min_x) row_min_x = min_x;
    638 			if (row_max_x > max_x) row_max_x = max_x;
    639 			if (row_min_x > row_max_x) continue;
    640 
    641 			dx = (row_min_x + 0.5f) - p_x_start;
    642 			dy = row_y - p_y_start;
    643 			row_w0 = w0_start + dw0_dx * dx + dw0_dy * dy;
    644 			row_w1 = w1_start + dw1_dx * dx + dw1_dy * dy;
    645 			row_w2 = 1.0f - row_w0 - row_w1;
    646 
    647 			inv_w = row_w0 * v0.w + row_w1 * v1.w + row_w2 * v2.w;
    648 			u_w = row_w0 * u0_w + row_w1 * u1_w + row_w2 * u2_w;
    649 			v_w = row_w0 * v0_w + row_w1 * v1_w + row_w2 * v2_w;
    650 			f_w = row_w0 * f0_w + row_w1 * f1_w + row_w2 * f2_w;
    651 			r = (row_w0 * v0.r + row_w1 * v1.r + row_w2 * v2.r) * 255.0f;
    652 			g_val = (row_w0 * v0.g + row_w1 * v1.g + row_w2 * v2.g) * 255.0f;
    653 			b = (row_w0 * v0.b + row_w1 * v1.b + row_w2 * v2.b) * 255.0f;
    654 
    655 			for (px = row_min_x; px <= row_max_x; px++) {
    656 				if (row_w0 >= -1e-4f && row_w1 >= -1e-4f && row_w2 >= -1e-4f) {
    657 					idx = py * WIDTH + px;
    658 					if (inv_w >= g_sys->zbuffer[idx] - 1e-6f && inv_w >= min_inv_w * 0.99f) {
    659 						ir = (int)r; if (ir > 255) ir = 255; else if (ir < 0) ir = 0;
    660 						ig = (int)g_val; if (ig > 255) ig = 255; else if (ig < 0) ig = 0;
    661 						ib = (int)b; if (ib > 255) ib = 255; else if (ib < 0) ib = 0;
    662 						wf = 1.0f / inv_w;
    663 
    664 						tx = (int)(u_w * wf * tw) & tw_mask;
    665 						ty = (int)(v_w * wf * th) & th_mask;
    666 						color = pixels[ty * tw + tx];
    667 
    668 						wa = (wa_tc * ((color >> 24) & 0xFF)) >> 8;
    669 						tex_r = ((((color >> 16) & 0xFF) * ir >> 8) * wr) >> 8;
    670 						tex_g = ((((color >> 8) & 0xFF) * ig >> 8) * wg) >> 8;
    671 						tex_b = ((color & 0xFF) * ib >> 8) * wb >> 8;
    672 
    673 						f = f_w * wf;
    674 						if (f > 0.001f) {
    675 							if (f > 1.0f) f = 1.0f;
    676 							inv_f = 1.0f - f;
    677 							tex_r = (uint32_t)(tex_r * inv_f + sky_r * f);
    678 							tex_g = (uint32_t)(tex_g * inv_f + sky_g * f);
    679 							tex_b = (uint32_t)(tex_b * inv_f + sky_b * f);
    680 						}
    681 
    682 						bg = g_sys->pixels[idx];
    683 						g_sys->pixels[idx] = (0xFF << 24) |
    684 						    (((tex_r * wa + ((bg >> 16) & 0xFF) * (255 - wa)) >> 8) << 16) |
    685 						    (((tex_g * wa + ((bg >> 8) & 0xFF) * (255 - wa)) >> 8) << 8) |
    686 						    ((tex_b * wa + (bg & 0xFF) * (255 - wa)) >> 8);
    687 					}
    688 				}
    689 				row_w0 += dw0_dx; row_w1 += dw1_dx; row_w2 -= (dw0_dx + dw1_dx);
    690 				inv_w += d_inv_w_dx; u_w += d_u_w_dx; v_w += d_v_w_dx; f_w += d_f_w_dx;
    691 				r += d_r_dx_255; g_val += d_g_dx_255; b += d_b_dx_255;
    692 			}
    693 		}
    694 	}
    695 }
    696 
    697 static void *
    698 render_worker(void *arg)
    699 {
    700 	int id, start_y, end_y, i;
    701 
    702 	id = (int)(intptr_t)arg;
    703 	start_y = id * HEIGHT / num_threads;
    704 	end_y = (id == num_threads - 1) ? HEIGHT - 1 : (id + 1) * HEIGHT / num_threads - 1;
    705 
    706 	while (1) {
    707 		pthread_barrier_wait(&barrier_start);
    708 		if (!threads_running) {
    709 			break;
    710 		}
    711 		for (i = 0; i < render_count; i++) {
    712 			draw_triangle_band(&render_list[i], start_y, end_y);
    713 		}
    714 		pthread_barrier_wait(&barrier_end);
    715 	}
    716 	return (NULL);
    717 }
    718 
    719 static void
    720 chat_add_message(const char *name, const char *msg)
    721 {
    722 	int i;
    723 
    724 	if (chat_log_count < CHAT_LINES) {
    725 		snprintf(chat_log[chat_log_count].text,
    726 		    sizeof(chat_log[chat_log_count].text), "[%s]: %s", name, msg);
    727 		chat_log[chat_log_count].timer = 8.0f;
    728 		chat_log_count++;
    729 	} else {
    730 		for (i = 0; i < CHAT_LINES - 1; i++) {
    731 			chat_log[i] = chat_log[i + 1];
    732 		}
    733 		snprintf(chat_log[CHAT_LINES - 1].text,
    734 		    sizeof(chat_log[CHAT_LINES - 1].text), "[%s]: %s", name, msg);
    735 		chat_log[CHAT_LINES - 1].timer = 8.0f;
    736 	}
    737 }
    738 
    739 static void
    740 net_init(const char *ip, int port, const char *nick)
    741 {
    742 	struct pkt_join pj;
    743 
    744 	strncpy(local_nick, nick, sizeof(local_nick) - 1);
    745 	local_nick[sizeof(local_nick) - 1] = '\0';
    746 
    747 	net_fd = socket(AF_INET, SOCK_DGRAM, 0);
    748 	if (net_fd < 0) {
    749 		return;
    750 	}
    751 	fcntl(net_fd, F_SETFL, O_NONBLOCK);
    752 
    753 	memset(&srv_addr, 0, sizeof(srv_addr));
    754 	srv_addr.sin_family = AF_INET;
    755 	srv_addr.sin_port = htons(port);
    756 	inet_pton(AF_INET, ip, &srv_addr.sin_addr);
    757 
    758 	memset(&pj, 0, sizeof(pj));
    759 	pj.hdr.magic = NET_MAGIC;
    760 	pj.hdr.type = PKT_JOIN;
    761 	pj.hdr.player_id = 0;
    762 	strncpy(pj.name, local_nick, sizeof(pj.name) - 1);
    763 	pj.skin = (uint16_t)active_skin_id;
    764 
    765 	sendto(net_fd, &pj, sizeof(pj), 0,
    766 	    (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    767 }
    768 
    769 static void
    770 net_send_sync(float px, float py, float pz, float pyaw)
    771 {
    772 	struct pkt_sync ps;
    773 
    774 	if (net_fd < 0 || !net_connected) {
    775 		return;
    776 	}
    777 	memset(&ps, 0, sizeof(ps));
    778 	ps.hdr.magic = NET_MAGIC;
    779 	ps.hdr.type = PKT_SYNC;
    780 	ps.hdr.player_id = (uint8_t)my_player_id;
    781 	ps.x = px;
    782 	ps.y = py;
    783 	ps.z = pz;
    784 	ps.yaw = pyaw;
    785 	ps.skin = (uint16_t)active_skin_id;
    786 
    787 	sendto(net_fd, &ps, sizeof(ps), 0,
    788 	    (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    789 	if (g_sys) {
    790 		g_sys->pkts_out++;
    791 	}
    792 }
    793 
    794 static void
    795 net_send_chat(const char *msg)
    796 {
    797 	struct pkt_chat pc;
    798 
    799 	if (net_fd < 0 || !net_connected) {
    800 		return;
    801 	}
    802 	memset(&pc, 0, sizeof(pc));
    803 	pc.hdr.magic = NET_MAGIC;
    804 	pc.hdr.type = PKT_CHAT;
    805 	pc.hdr.player_id = (uint8_t)my_player_id;
    806 	strncpy(pc.name, local_nick, sizeof(pc.name) - 1);
    807 	strncpy(pc.msg, msg, sizeof(pc.msg) - 1);
    808 
    809 	sendto(net_fd, &pc, sizeof(pc), 0,
    810 	    (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    811 	if (g_sys) {
    812 		g_sys->pkts_out++;
    813 	}
    814 }
    815 
    816 static void
    817 net_player_add_snap(struct net_player *np, float x, float y, float z, float yaw, double now)
    818 {
    819 	int i;
    820 
    821 	if (np->snap_count < 4) {
    822 		np->snaps[np->snap_count].x = x;
    823 		np->snaps[np->snap_count].y = y;
    824 		np->snaps[np->snap_count].z = z;
    825 		np->snaps[np->snap_count].yaw = yaw;
    826 		np->snaps[np->snap_count].time = now;
    827 		np->snap_count++;
    828 	} else {
    829 		for (i = 0; i < 3; i++) {
    830 			np->snaps[i] = np->snaps[i + 1];
    831 		}
    832 		np->snaps[3].x = x;
    833 		np->snaps[3].y = y;
    834 		np->snaps[3].z = z;
    835 		np->snaps[3].yaw = yaw;
    836 		np->snaps[3].time = now;
    837 	}
    838 }
    839 
    840 static void
    841 net_poll(struct sys_gfx *g, double now)
    842 {
    843 	uint8_t buf[2048];
    844 	ssize_t n;
    845 	const struct pkt_header *hdr;
    846 	const struct pkt_join_ack *ack;
    847 	const struct pkt_world_state *ws;
    848 	const struct pkt_chat *pc;
    849 	int i, id, seen[MAX_PLAYERS];
    850 
    851 	if (net_fd < 0) {
    852 		return;
    853 	}
    854 
    855 	while ((n = recvfrom(net_fd, buf, sizeof(buf), 0, NULL, NULL)) > 0) {
    856 		g->pkts_in++;
    857 		if (n < (ssize_t)sizeof(struct pkt_header)) {
    858 			continue;
    859 		}
    860 		hdr = (const struct pkt_header *)buf;
    861 		if (hdr->magic != NET_MAGIC) {
    862 			continue;
    863 		}
    864 
    865 		if (hdr->type == PKT_JOIN_ACK) {
    866 			if (n >= (ssize_t)sizeof(struct pkt_join_ack)) {
    867 				ack = (const struct pkt_join_ack *)buf;
    868 				my_player_id = ack->your_id;
    869 				net_connected = 1;
    870 				g->game_weather = ack->game_weather;
    871 				g->game_time_hours = ack->game_time;
    872 			}
    873 		} else if (hdr->type == PKT_WORLD_STATE) {
    874 			if (n >= (ssize_t)(sizeof(struct pkt_header) + 1)) {
    875 				ws = (const struct pkt_world_state *)buf;
    876 				memset(seen, 0, sizeof(seen));
    877 				for (i = 0; i < ws->player_count && i < MAX_PLAYERS; i++) {
    878 					id = ws->players[i].id;
    879 					if (id >= MAX_PLAYERS) {
    880 						continue;
    881 					}
    882 					seen[id] = 1;
    883 					if (!net_players[id].active) {
    884 						net_players[id].id = id;
    885 						net_players[id].skin = ws->players[i].skin;
    886 						net_players[id].cur_x = ws->players[i].x;
    887 						net_players[id].cur_y = ws->players[i].y;
    888 						net_players[id].cur_z = ws->players[i].z;
    889 						net_players[id].cur_yaw = ws->players[i].yaw;
    890 						net_players[id].snap_count = 0;
    891 						net_players[id].active = 1;
    892 					}
    893 					net_players[id].skin = ws->players[i].skin;
    894 					net_player_add_snap(&net_players[id],
    895 					    ws->players[i].x, ws->players[i].y, ws->players[i].z,
    896 					    ws->players[i].yaw, now);
    897 				}
    898 				for (i = 0; i < MAX_PLAYERS; i++) {
    899 					if (!seen[i]) {
    900 						net_players[i].active = 0;
    901 						net_players[i].snap_count = 0;
    902 					}
    903 				}
    904 			}
    905 		} else if (hdr->type == PKT_CHAT) {
    906 			if (n >= (ssize_t)sizeof(struct pkt_chat)) {
    907 				pc = (const struct pkt_chat *)buf;
    908 				chat_add_message(pc->name, pc->msg);
    909 			}
    910 		}
    911 	}
    912 }
    913 
    914 static void
    915 net_send_leave(void)
    916 {
    917 	struct pkt_header ph;
    918 
    919 	if (net_fd < 0 || !net_connected) {
    920 		return;
    921 	}
    922 	ph.magic = NET_MAGIC;
    923 	ph.type = PKT_LEAVE;
    924 	ph.player_id = (uint8_t)my_player_id;
    925 
    926 	sendto(net_fd, &ph, sizeof(ph), 0,
    927 	    (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    928 	close(net_fd);
    929 	net_fd = -1;
    930 }
    931 
    932 static void
    933 net_interpolate(double now)
    934 {
    935 	double render_time, dt_snap, t;
    936 	float dyaw;
    937 	int i, k;
    938 	struct net_player *np;
    939 	struct net_snap *s0, *s1;
    940 
    941 	render_time = now - 0.066;
    942 
    943 	for (i = 0; i < MAX_PLAYERS; i++) {
    944 		np = &net_players[i];
    945 		if (!np->active || i == my_player_id || np->snap_count < 2) {
    946 			continue;
    947 		}
    948 
    949 		s0 = NULL;
    950 		s1 = NULL;
    951 
    952 		for (k = 0; k < np->snap_count - 1; k++) {
    953 			if (render_time >= np->snaps[k].time &&
    954 			    render_time <= np->snaps[k + 1].time) {
    955 				s0 = &np->snaps[k];
    956 				s1 = &np->snaps[k + 1];
    957 				break;
    958 			}
    959 		}
    960 
    961 		if (s0 && s1) {
    962 			dt_snap = s1->time - s0->time;
    963 			t = (dt_snap > 1e-5) ? (render_time - s0->time) / dt_snap : 0.0;
    964 			if (t < 0.0) t = 0.0;
    965 			if (t > 1.0) t = 1.0;
    966 
    967 			np->cur_x = s0->x + (s1->x - s0->x) * t;
    968 			np->cur_y = s0->y + (s1->y - s0->y) * t;
    969 			np->cur_z = s0->z + (s1->z - s0->z) * t;
    970 
    971 			dyaw = s1->yaw - s0->yaw;
    972 			while (dyaw > 3.14159265f) dyaw -= 6.2831853f;
    973 			while (dyaw < -3.14159265f) dyaw += 6.2831853f;
    974 			np->cur_yaw = s0->yaw + dyaw * t;
    975 		} else if (render_time > np->snaps[np->snap_count - 1].time) {
    976 			s0 = &np->snaps[np->snap_count - 2];
    977 			s1 = &np->snaps[np->snap_count - 1];
    978 			dt_snap = s1->time - s0->time;
    979 			t = (dt_snap > 1e-5) ? (render_time - s1->time) / dt_snap : 0.0;
    980 			if (t > 2.0) {
    981 				t = 2.0;
    982 			}
    983 
    984 			np->cur_x = s1->x + (s1->x - s0->x) * t;
    985 			np->cur_y = s1->y + (s1->y - s0->y) * t;
    986 			np->cur_z = s1->z + (s1->z - s0->z) * t;
    987 			np->cur_yaw = s1->yaw;
    988 		}
    989 	}
    990 }
    991 
    992 static void
    993 gfx_init(struct sys_gfx *g)
    994 {
    995 	XIM im;
    996 	int scr;
    997 	XColor black;
    998 	Pixmap bm_no;
    999 	Cursor no_ptr;
   1000 	char no_data[] = { 0,0,0,0,0,0,0,0 };
   1001 	int i;
   1002 	char **missing_charsets;
   1003 	int missing_count;
   1004 	char *def_string;
   1005 
   1006 	memset(g, 0, sizeof(*g));
   1007 	
   1008 	setlocale(LC_ALL, "");
   1009 	setlocale(LC_NUMERIC, "C");
   1010 	XSetLocaleModifiers("");
   1011 
   1012 	g->dpy = XOpenDisplay(NULL);
   1013 	if (g->dpy == NULL) {
   1014 		errx(1, "xopendisplay failed");
   1015 	}
   1016 	if (!XShmQueryExtension(g->dpy)) {
   1017 		errx(1, "xshm extension not supported");
   1018 	}
   1019 	scr = DefaultScreen(g->dpy);
   1020 	g->win = XCreateSimpleWindow(g->dpy, DefaultRootWindow(g->dpy), 0, 0,
   1021 	    WIDTH, HEIGHT, 0, 0, 0);
   1022 	XSelectInput(g->dpy, g->win, KeyPressMask | KeyReleaseMask |
   1023 	    StructureNotifyMask | FocusChangeMask | PointerMotionMask);
   1024 	
   1025 	im = XOpenIM(g->dpy, NULL, NULL, NULL);
   1026 	g->ic = NULL;
   1027 	if (im) {
   1028 		g->ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, g->win, NULL);
   1029 	}
   1030 
   1031 	g->gc = XCreateGC(g->dpy, g->win, 0, NULL);
   1032 	g->img = XShmCreateImage(g->dpy, DefaultVisual(g->dpy, scr),
   1033 	    DefaultDepth(g->dpy, scr), ZPixmap, NULL, &g->shm, WIDTH, HEIGHT);
   1034 	g->shm.shmid = shmget(IPC_PRIVATE, g->img->bytes_per_line * g->img->height,
   1035 	    IPC_CREAT | 0777);
   1036 	g->shm.shmaddr = shmat(g->shm.shmid, 0, 0);
   1037 	g->img->data = g->shm.shmaddr;
   1038 	g->pixels = (uint32_t *)g->img->data;
   1039 	g->shm.readOnly = False;
   1040 	XShmAttach(g->dpy, &g->shm);
   1041 	shmctl(g->shm.shmid, IPC_RMID, 0);
   1042 	g->zbuffer = malloc(WIDTH * HEIGHT * sizeof(float));
   1043 	g->wm_delete = XInternAtom(g->dpy, "WM_DELETE_WINDOW", False);
   1044 	XSetWMProtocols(g->dpy, g->win, &g->wm_delete, 1);
   1045 	
   1046 	memset(&black, 0, sizeof(black));
   1047 	bm_no = XCreateBitmapFromData(g->dpy, g->win, no_data, 8, 8);
   1048 	no_ptr = XCreatePixmapCursor(g->dpy, bm_no, bm_no, &black, &black, 0, 0);
   1049 	XDefineCursor(g->dpy, g->win, no_ptr);
   1050 	XFreeCursor(g->dpy, no_ptr);
   1051 	XFreePixmap(g->dpy, bm_no);
   1052 
   1053 	g->font_set = XCreateFontSet(g->dpy, "-*-*-medium-r-normal-*-14-*-*-*-*-*-iso10646-1",
   1054 	    &missing_charsets, &missing_count, &def_string);
   1055 	if (!g->font_set) {
   1056 		g->font_set = XCreateFontSet(g->dpy, "fixed",
   1057 		    &missing_charsets, &missing_count, &def_string);
   1058 	}
   1059 	if (missing_count > 0) {
   1060 		XFreeStringList(missing_charsets);
   1061 	}
   1062 
   1063 	g->key_w     = XKeysymToKeycode(g->dpy, XK_w);
   1064 	g->key_a     = XKeysymToKeycode(g->dpy, XK_a);
   1065 	g->key_s     = XKeysymToKeycode(g->dpy, XK_s);
   1066 	g->key_d     = XKeysymToKeycode(g->dpy, XK_d);
   1067 	g->key_t     = XKeysymToKeycode(g->dpy, XK_t);
   1068 	g->key_esc   = XKeysymToKeycode(g->dpy, XK_Escape);
   1069 	g->key_up    = XKeysymToKeycode(g->dpy, XK_Up);
   1070 	g->key_down  = XKeysymToKeycode(g->dpy, XK_Down);
   1071 	g->key_left  = XKeysymToKeycode(g->dpy, XK_Left);
   1072 	g->key_right = XKeysymToKeycode(g->dpy, XK_Right);
   1073 
   1074 	num_threads = sysconf(_SC_NPROCESSORS_ONLN);
   1075 	if (num_threads < 1) {
   1076 		num_threads = 4;
   1077 	}
   1078 	pthread_barrier_init(&barrier_start, NULL, num_threads + 1);
   1079 	pthread_barrier_init(&barrier_end, NULL, num_threads + 1);
   1080 	workers = malloc(num_threads * sizeof(pthread_t));
   1081 	for (i = 0; i < num_threads; i++) {
   1082 		pthread_create(&workers[i], NULL, render_worker, (void *)(intptr_t)i);
   1083 	}
   1084 
   1085 	v_scratch_cap = 16384;
   1086 	v_scratch = malloc(v_scratch_cap * sizeof(struct clip_vertex));
   1087 }
   1088 
   1089 static void
   1090 gfx_cleanup(struct sys_gfx *g)
   1091 {
   1092 	int i;
   1093 
   1094 	threads_running = 0;
   1095 	pthread_barrier_wait(&barrier_start);
   1096 	for (i = 0; i < num_threads; i++) {
   1097 		pthread_join(workers[i], NULL);
   1098 	}
   1099 	pthread_barrier_destroy(&barrier_start);
   1100 	pthread_barrier_destroy(&barrier_end);
   1101 	free(workers);
   1102 	free(v_scratch);
   1103 	XUngrabPointer(g->dpy, CurrentTime);
   1104 	XShmDetach(g->dpy, &g->shm);
   1105 	XDestroyImage(g->img);
   1106 	shmdt(g->shm.shmaddr);
   1107 	free(g->zbuffer);
   1108 	if (g->font_set) {
   1109 		XFreeFontSet(g->dpy, g->font_set);
   1110 	}
   1111 	XFreeGC(g->dpy, g->gc);
   1112 	XDestroyWindow(g->dpy, g->win);
   1113 	XCloseDisplay(g->dpy);
   1114 }
   1115 
   1116 static void
   1117 gfx_present(struct sys_gfx *g, float px, float py, float pz)
   1118 {
   1119 	char txt[256];
   1120 	int i, y_offset, active_count;
   1121 
   1122 	if (g->menu_open) {
   1123 		for (i = 0; i < WIDTH * HEIGHT; i++) {
   1124 			g->pixels[i] = (g->pixels[i] >> 1) & 0x7F7F7F;
   1125 		}
   1126 	}
   1127 
   1128 	XShmPutImage(g->dpy, g->win, g->gc, g->img, 0, 0, 0, 0, WIDTH, HEIGHT, False);
   1129 
   1130 	XSetForeground(g->dpy, g->gc, 0xFFFFFF);
   1131 	XSetBackground(g->dpy, g->gc, 0x000000);
   1132 
   1133 	for (i = 0; i < chat_log_count; i++) {
   1134 		if (chat_log[i].timer > 0.0f || g->in_chat) {
   1135 			y_offset = HEIGHT - 45 - (chat_log_count - 1 - i) * 16;
   1136 			if (g->font_set) {
   1137 				Xutf8DrawImageString(g->dpy, g->win, g->font_set, g->gc,
   1138 				    10, y_offset, chat_log[i].text, strlen(chat_log[i].text));
   1139 			} else {
   1140 				XDrawImageString(g->dpy, g->win, g->gc,
   1141 				    10, y_offset, chat_log[i].text, strlen(chat_log[i].text));
   1142 			}
   1143 		}
   1144 	}
   1145 
   1146 	if (g->show_debug) {
   1147 		active_count = 0;
   1148 		for (i = 0; i < MAX_PLAYERS; i++) {
   1149 			if (net_players[i].active) {
   1150 				active_count++;
   1151 			}
   1152 		}
   1153 
   1154 		XSetForeground(g->dpy, g->gc, 0x00FF00);
   1155 		XSetBackground(g->dpy, g->gc, 0x000000);
   1156 
   1157 		snprintf(txt, sizeof(txt), "FPS: %.1f | PLAYERS: %d/%d | ID: %d",
   1158 		    g->fps, active_count, MAX_PLAYERS, my_player_id);
   1159 		if (g->font_set) {
   1160 			Xutf8DrawImageString(g->dpy, g->win, g->font_set, g->gc, 10, 20, txt, strlen(txt));
   1161 		} else {
   1162 			XDrawImageString(g->dpy, g->win, g->gc, 10, 20, txt, strlen(txt));
   1163 		}
   1164 
   1165 		snprintf(txt, sizeof(txt), "POS: X=%.2f Y=%.2f Z=%.2f", px, py, pz);
   1166 		if (g->font_set) {
   1167 			Xutf8DrawImageString(g->dpy, g->win, g->font_set, g->gc, 10, 36, txt, strlen(txt));
   1168 		} else {
   1169 			XDrawImageString(g->dpy, g->win, g->gc, 10, 36, txt, strlen(txt));
   1170 		}
   1171 
   1172 		snprintf(txt, sizeof(txt), "NET: IN=%u pkts/s | OUT=%u pkts/s",
   1173 		    g->pkts_in_sec, g->pkts_out_sec);
   1174 		if (g->font_set) {
   1175 			Xutf8DrawImageString(g->dpy, g->win, g->font_set, g->gc, 10, 52, txt, strlen(txt));
   1176 		} else {
   1177 			XDrawImageString(g->dpy, g->win, g->gc, 10, 52, txt, strlen(txt));
   1178 		}
   1179 	}
   1180 
   1181 	if (g->menu_open) {
   1182 		snprintf(txt, sizeof(txt), "[ PAUSED - PRESS ESC TO RESUME ]");
   1183 		XSetForeground(g->dpy, g->gc, 0xFFFFFF);
   1184 		XSetBackground(g->dpy, g->gc, 0x000000);
   1185 		if (g->font_set) {
   1186 			Xutf8DrawImageString(g->dpy, g->win, g->font_set, g->gc,
   1187 			    WIDTH / 2 - 110, HEIGHT / 2, txt, strlen(txt));
   1188 		} else {
   1189 			XDrawImageString(g->dpy, g->win, g->gc,
   1190 			    WIDTH / 2 - 110, HEIGHT / 2, txt, strlen(txt));
   1191 		}
   1192 	} else if (g->in_chat) {
   1193 		snprintf(txt, sizeof(txt), "> %s_", g->chat_buf);
   1194 		XSetForeground(g->dpy, g->gc, 0x00FF00);
   1195 		XSetBackground(g->dpy, g->gc, 0x000000);
   1196 		if (g->font_set) {
   1197 			Xutf8DrawImageString(g->dpy, g->win, g->font_set, g->gc,
   1198 			    10, HEIGHT - 20, txt, strlen(txt));
   1199 		} else {
   1200 			XDrawImageString(g->dpy, g->win, g->gc,
   1201 			    10, HEIGHT - 20, txt, strlen(txt));
   1202 		}
   1203 	}
   1204 	XSync(g->dpy, False);
   1205 }
   1206 
   1207 static int
   1208 ray_tri_intersect_y(const struct col_triangle *t, float x, float z, float *out_y)
   1209 {
   1210 	float x0, z0, x1, z1, x2, z2;
   1211 	float det, inv_det, w0, w1, w2;
   1212 
   1213 	x0 = t->v0[0];
   1214 	z0 = t->v0[2];
   1215 	x1 = t->v1[0];
   1216 	z1 = t->v1[2];
   1217 	x2 = t->v2[0];
   1218 	z2 = t->v2[2];
   1219 
   1220 	det = (z1 - z2) * (x0 - x2) + (x2 - x1) * (z0 - z2);
   1221 	if (fabsf(det) < 1e-6f) {
   1222 		return (0);
   1223 	}
   1224 	inv_det = 1.0f / det;
   1225 
   1226 	w0 = ((z1 - z2) * (x - x2) + (x2 - x1) * (z - z2)) * inv_det;
   1227 	w1 = ((z2 - z0) * (x - x2) + (x0 - x2) * (z - z2)) * inv_det;
   1228 	w2 = 1.0f - w0 - w1;
   1229 
   1230 	if (w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f) {
   1231 		*out_y = w0 * t->v0[1] + w1 * t->v1[1] + w2 * t->v2[1];
   1232 		return (1);
   1233 	}
   1234 	return (0);
   1235 }
   1236 
   1237 static float
   1238 get_ground_height(float px, float pz, float cur_y)
   1239 {
   1240 	const struct col_cell *c;
   1241 	const struct col_triangle *t;
   1242 	float best_below, hit_y, min_x, max_x, min_z, max_z, sx, sz;
   1243 	uint32_t i;
   1244 	int gx, gz, k;
   1245 	static const float offsets[5][2] = {
   1246 		{ 0.0f,    0.0f },
   1247 		{ 0.18f,   0.0f },
   1248 		{-0.18f,   0.0f },
   1249 		{ 0.0f,    0.18f },
   1250 		{ 0.0f,   -0.18f }
   1251 	};
   1252 
   1253 	gx = (int)((px - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1254 	gz = (int)((pz - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1255 	if (gx < 0 || gx >= GRID_SZ || gz < 0 || gz >= GRID_SZ) {
   1256 		return (-1000.0f);
   1257 	}
   1258 
   1259 	best_below = -1000.0f;
   1260 	c = &g_col_grid[gx][gz];
   1261 
   1262 	for (i = 0; i < c->count; i++) {
   1263 		t = &c->tris[i];
   1264 		if (t->norm[1] < 0.45f) {
   1265 			continue;
   1266 		}
   1267 
   1268 		min_x = fminf(t->v0[0], fminf(t->v1[0], t->v2[0]));
   1269 		max_x = fmaxf(t->v0[0], fmaxf(t->v1[0], t->v2[0]));
   1270 		if (px + 0.20f < min_x || px - 0.20f > max_x) {
   1271 			continue;
   1272 		}
   1273 
   1274 		min_z = fminf(t->v0[2], fminf(t->v1[2], t->v2[2]));
   1275 		max_z = fmaxf(t->v0[2], fmaxf(t->v1[2], t->v2[2]));
   1276 		if (pz + 0.20f < min_z || pz - 0.20f > max_z) {
   1277 			continue;
   1278 		}
   1279 
   1280 		for (k = 0; k < 5; k++) {
   1281 			sx = px + offsets[k][0];
   1282 			sz = pz + offsets[k][1];
   1283 			if (ray_tri_intersect_y(t, sx, sz, &hit_y)) {
   1284 				if (hit_y <= cur_y + 0.60f && hit_y > best_below) {
   1285 					best_below = hit_y;
   1286 				}
   1287 			}
   1288 		}
   1289 	}
   1290 	return (best_below);
   1291 }
   1292 
   1293 static float
   1294 get_ceiling_height(float px, float pz, float cur_y)
   1295 {
   1296 	const struct col_cell *c;
   1297 	const struct col_triangle *t;
   1298 	float best_above, hit_y, min_x, max_x, min_z, max_z;
   1299 	uint32_t i;
   1300 	int gx, gz;
   1301 
   1302 	gx = (int)((px - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1303 	gz = (int)((pz - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1304 	if (gx < 0 || gx >= GRID_SZ || gz < 0 || gz >= GRID_SZ) {
   1305 		return (1000.0f);
   1306 	}
   1307 
   1308 	best_above = 1000.0f;
   1309 	c = &g_col_grid[gx][gz];
   1310 
   1311 	for (i = 0; i < c->count; i++) {
   1312 		t = &c->tris[i];
   1313 		if (t->norm[1] > -0.2f && t->norm[1] < 0.2f) {
   1314 			continue;
   1315 		}
   1316 
   1317 		min_x = fminf(t->v0[0], fminf(t->v1[0], t->v2[0]));
   1318 		max_x = fmaxf(t->v0[0], fmaxf(t->v1[0], t->v2[0]));
   1319 		if (px < min_x || px > max_x) {
   1320 			continue;
   1321 		}
   1322 
   1323 		min_z = fminf(t->v0[2], fminf(t->v1[2], t->v2[2]));
   1324 		max_z = fmaxf(t->v0[2], fmaxf(t->v1[2], t->v2[2]));
   1325 		if (pz < min_z || pz > max_z) {
   1326 			continue;
   1327 		}
   1328 
   1329 		if (ray_tri_intersect_y(t, px, pz, &hit_y)) {
   1330 			if (hit_y >= cur_y + 1.0f && hit_y < best_above) {
   1331 				best_above = hit_y;
   1332 			}
   1333 		}
   1334 	}
   1335 	return (best_above);
   1336 }
   1337 
   1338 static void
   1339 move_and_slide(float *px, float py, float *pz, float vx, float vz, float dt)
   1340 {
   1341 	const struct col_cell *c;
   1342 	const struct col_triangle *t;
   1343 	float sphere[3][3];
   1344 	float closest[3], diff[3];
   1345 	float rad, dist_sq, dist, h_len, dot, step_x, step_z, push;
   1346 	float min_x, max_x, min_y, max_y, min_z, max_z;
   1347 	float prev_x, prev_z, accum_nx, accum_nz, n_len;
   1348 	int sub, iter, s, i, gx, gz, gx0, gx1, gz0, gz1, contacts;
   1349 
   1350 	rad = 0.35f;
   1351 	step_x = (vx * dt) * 0.25f;
   1352 	step_z = (vz * dt) * 0.25f;
   1353 
   1354 	for (sub = 0; sub < 4; sub++) {
   1355 		prev_x = *px;
   1356 		prev_z = *pz;
   1357 
   1358 		*px += step_x;
   1359 		*pz += step_z;
   1360 
   1361 		accum_nx = 0.0f;
   1362 		accum_nz = 0.0f;
   1363 		contacts = 0;
   1364 
   1365 		gx0 = (int)((*px - rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1366 		gx1 = (int)((*px + rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1367 		gz0 = (int)((*pz - rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1368 		gz1 = (int)((*pz + rad - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   1369 
   1370 		if (gx0 < 0) gx0 = 0;
   1371 		if (gx1 >= GRID_SZ) gx1 = GRID_SZ - 1;
   1372 		if (gz0 < 0) gz0 = 0;
   1373 		if (gz1 >= GRID_SZ) gz1 = GRID_SZ - 1;
   1374 
   1375 		for (iter = 0; iter < 2; iter++) {
   1376 			sphere[0][0] = *px;
   1377 			sphere[0][1] = py + 0.35f;
   1378 			sphere[0][2] = *pz;
   1379 
   1380 			sphere[1][0] = *px;
   1381 			sphere[1][1] = py + 0.95f;
   1382 			sphere[1][2] = *pz;
   1383 
   1384 			sphere[2][0] = *px;
   1385 			sphere[2][1] = py + 1.55f;
   1386 			sphere[2][2] = *pz;
   1387 
   1388 			for (gz = gz0; gz <= gz1; gz++) {
   1389 				for (gx = gx0; gx <= gx1; gx++) {
   1390 					c = &g_col_grid[gx][gz];
   1391 
   1392 					for (i = 0; i < (int)c->count; i++) {
   1393 						t = &c->tris[i];
   1394 						if (t->norm[1] > 0.6f) {
   1395 							continue;
   1396 						}
   1397 
   1398 						min_y = fminf(t->v0[1], fminf(t->v1[1], t->v2[1]));
   1399 						max_y = fmaxf(t->v0[1], fmaxf(t->v1[1], t->v2[1]));
   1400 						if (py + 1.9f < min_y || py > max_y) {
   1401 							continue;
   1402 						}
   1403 
   1404 						min_x = fminf(t->v0[0], fminf(t->v1[0], t->v2[0]));
   1405 						max_x = fmaxf(t->v0[0], fmaxf(t->v1[0], t->v2[0]));
   1406 						if (*px + rad < min_x || *px - rad > max_x) {
   1407 							continue;
   1408 						}
   1409 
   1410 						min_z = fminf(t->v0[2], fminf(t->v1[2], t->v2[2]));
   1411 						max_z = fmaxf(t->v0[2], fmaxf(t->v1[2], t->v2[2]));
   1412 						if (*pz + rad < min_z || *pz - rad > max_z) {
   1413 							continue;
   1414 						}
   1415 
   1416 						for (s = 0; s < 3; s++) {
   1417 							closest_point_triangle(sphere[s],
   1418 							    t->v0, t->v1, t->v2, closest);
   1419 
   1420 							diff[0] = sphere[s][0] - closest[0];
   1421 							diff[1] = sphere[s][1] - closest[1];
   1422 							diff[2] = sphere[s][2] - closest[2];
   1423 
   1424 							dist_sq = diff[0] * diff[0] +
   1425 							    diff[1] * diff[1] +
   1426 							    diff[2] * diff[2];
   1427 
   1428 							if (dist_sq < rad * rad) {
   1429 								dist = sqrtf(dist_sq);
   1430 								h_len = sqrtf(diff[0] * diff[0] + diff[2] * diff[2]);
   1431 
   1432 								if (h_len > 1e-4f) {
   1433 									diff[0] /= h_len;
   1434 									diff[2] /= h_len;
   1435 								} else {
   1436 									diff[0] = prev_x - closest[0];
   1437 									diff[2] = prev_z - closest[2];
   1438 									h_len = sqrtf(diff[0] * diff[0] + diff[2] * diff[2]);
   1439 									if (h_len > 1e-4f) {
   1440 										diff[0] /= h_len;
   1441 										diff[2] /= h_len;
   1442 									} else {
   1443 										diff[0] = 1.0f;
   1444 										diff[2] = 0.0f;
   1445 									}
   1446 								}
   1447 
   1448 								push = rad - dist;
   1449 								*px += diff[0] * push;
   1450 								*pz += diff[2] * push;
   1451 
   1452 								accum_nx += diff[0];
   1453 								accum_nz += diff[2];
   1454 								contacts++;
   1455 
   1456 								sphere[0][0] = *px;
   1457 								sphere[0][2] = *pz;
   1458 								sphere[1][0] = *px;
   1459 								sphere[1][2] = *pz;
   1460 								sphere[2][0] = *px;
   1461 								sphere[2][2] = *pz;
   1462 							}
   1463 						}
   1464 					}
   1465 				}
   1466 			}
   1467 		}
   1468 
   1469 		if (contacts > 0) {
   1470 			n_len = sqrtf(accum_nx * accum_nx + accum_nz * accum_nz);
   1471 			if (n_len > 1e-4f) {
   1472 				accum_nx /= n_len;
   1473 				accum_nz /= n_len;
   1474 				dot = vx * accum_nx + vz * accum_nz;
   1475 				if (dot < 0.0f) {
   1476 					vx -= dot * accum_nx;
   1477 					vz -= dot * accum_nz;
   1478 				}
   1479 			}
   1480 		}
   1481 	}
   1482 }
   1483 
   1484 static unsigned int
   1485 hash_str(const char *str)
   1486 {
   1487 	unsigned int hash = 5381;
   1488 	int c;
   1489 
   1490 	while ((c = (unsigned char)*str++)) {
   1491 		hash = ((hash << 5) + hash) + c;
   1492 	}
   1493 	return (hash);
   1494 }
   1495 
   1496 static void
   1497 mesh_load_ply(struct mesh *m, const uint8_t *data, size_t sz)
   1498 {
   1499 	const char *header_end;
   1500 	const char *p;
   1501 	const uint8_t *bin;
   1502 	int temp_materials, idx, k;
   1503 	char *dst;
   1504 	const char *src;
   1505 	uint16_t *mat;
   1506 	int32_t *idx_ptr;
   1507 	uint32_t i;
   1508 
   1509 	(void)sz;
   1510 	header_end = strstr((const char *)data, "end_header\n");
   1511 	if (!header_end) {
   1512 		return;
   1513 	}
   1514 	header_end += 11;
   1515 
   1516 	memset(m, 0, sizeof(*m));
   1517 
   1518 	p = (const char *)data;
   1519 	temp_materials = 0;
   1520 	while (p < header_end) {
   1521 		if (strncmp(p, "comment spr_cx", 14) == 0) m->spr_x = strtof(p + 14, NULL);
   1522 		else if (strncmp(p, "comment spr_cy", 14) == 0) m->spr_y = strtof(p + 14, NULL);
   1523 		else if (strncmp(p, "comment spr_cz", 14) == 0) m->spr_z = strtof(p + 14, NULL);
   1524 		else if (strncmp(p, "comment spr_r", 13) == 0) m->spr_r = strtof(p + 13, NULL);
   1525 		else if (strncmp(p, "element vertex", 14) == 0) m->num_verts = strtoul(p + 14, NULL, 10);
   1526 		else if (strncmp(p, "element face", 12) == 0) m->num_tris = strtoul(p + 12, NULL, 10);
   1527 		else if (strncmp(p, "comment texture", 15) == 0) temp_materials++;
   1528 		p = strchr(p, '\n');
   1529 		if (!p) break;
   1530 		p++;
   1531 	}
   1532 
   1533 	m->num_materials = temp_materials;
   1534 	if (m->num_materials > 0) {
   1535 		m->raw_tex_names = malloc(m->num_materials * 32);
   1536 		p = (const char *)data;
   1537 		idx = 0;
   1538 		while (p < header_end) {
   1539 			if (strncmp(p, "comment texture", 15) == 0) {
   1540 				src = p + 16;
   1541 				dst = m->raw_tex_names[idx];
   1542 				k = 0;
   1543 				while (src[k] != '\n' && src[k] != '\r' && k < 31) {
   1544 					dst[k] = src[k];
   1545 					k++;
   1546 				}
   1547 				dst[k] = '\0';
   1548 				idx++;
   1549 			}
   1550 			p = strchr(p, '\n');
   1551 			if (!p) break;
   1552 			p++;
   1553 		}
   1554 	}
   1555 
   1556 	m->ply_verts = malloc(m->num_verts * sizeof(struct ply_vertex));
   1557 	m->indices = malloc(m->num_tris * 3 * sizeof(uint16_t));
   1558 	m->mat_ids = malloc(m->num_tris * sizeof(uint16_t));
   1559 
   1560 	bin = (const uint8_t *)header_end;
   1561 
   1562 	memcpy(m->ply_verts, bin, m->num_verts * sizeof(struct ply_vertex));
   1563 	bin += m->num_verts * sizeof(struct ply_vertex);
   1564 
   1565 	for (i = 0; i < m->num_tris; i++) {
   1566 		bin += 1;
   1567 		idx_ptr = (int32_t *)bin;
   1568 		m->indices[i*3+0] = idx_ptr[0];
   1569 		m->indices[i*3+1] = idx_ptr[1];
   1570 		m->indices[i*3+2] = idx_ptr[2];
   1571 		bin += 12;
   1572 
   1573 		mat = (uint16_t *)bin;
   1574 		m->mat_ids[i] = *mat;
   1575 		bin += 2;
   1576 	}
   1577 
   1578 	m->total_area = 0.0f;
   1579 	for (i = 0; i < m->num_tris; i++) {
   1580 		uint16_t i0 = m->indices[i*3], i1 = m->indices[i*3+1], i2 = m->indices[i*3+2];
   1581 		float ux = m->ply_verts[i1].x - m->ply_verts[i0].x;
   1582 		float uy = m->ply_verts[i1].y - m->ply_verts[i0].y;
   1583 		float uz = m->ply_verts[i1].z - m->ply_verts[i0].z;
   1584 		float vx = m->ply_verts[i2].x - m->ply_verts[i0].x;
   1585 		float vy = m->ply_verts[i2].y - m->ply_verts[i0].y;
   1586 		float vz = m->ply_verts[i2].z - m->ply_verts[i0].z;
   1587 		float cx = uy * vz - uz * vy, cy = uz * vx - ux * vz, cz = ux * vy - uy * vx;
   1588 		m->total_area += 0.5f * sqrtf(cx*cx + cy*cy + cz*cz);
   1589 	}
   1590 }
   1591 
   1592 static void
   1593 tex_load_tga(struct texture *t, const uint8_t *data, size_t sz)
   1594 {
   1595 	struct tga_header *hdr;
   1596 	const uint8_t *src_pixels;
   1597 	uint32_t *dst, *curr_offset, *src;
   1598 	int w, h, mw, mh, total_pixels, i, level;
   1599 	int prev_w, prev_h, next_w, next_h, x, y;
   1600 	uint32_t c00, c10, c01, c11, r, g, b, a;
   1601 
   1602 	memset(t, 0, sizeof(*t));
   1603 	if (data == NULL || sz < sizeof(struct tga_header)) {
   1604 		w = 2;
   1605 		h = 2;
   1606 		t->w = w;
   1607 		t->h = h;
   1608 		t->has_alpha = 0;
   1609 		t->pixels = malloc((4 + 1 + 1 + 1) * sizeof(uint32_t));
   1610 		if (t->pixels == NULL) {
   1611 			return;
   1612 		}
   1613 		t->pixels[0] = 0xffa0a0a0;
   1614 		t->pixels[1] = 0xff808080;
   1615 		t->pixels[2] = 0xff808080;
   1616 		t->pixels[3] = 0xffa0a0a0;
   1617 
   1618 		t->mips[0] = t->pixels;
   1619 		t->mip_w[0] = 2;
   1620 		t->mip_h[0] = 2;
   1621 
   1622 		for (i = 1; i < 4; i++) {
   1623 			t->mips[i] = t->pixels + 4;
   1624 			t->mip_w[i] = 1;
   1625 			t->mip_h[i] = 1;
   1626 		}
   1627 		t->mips[1][0] = 0xff909090;
   1628 		return;
   1629 	}
   1630 
   1631 	hdr = (struct tga_header *)data;
   1632 	w = hdr->width;
   1633 	h = hdr->height;
   1634 	t->w = w;
   1635 	t->h = h;
   1636 
   1637 	mw = w;
   1638 	mh = h;
   1639 	total_pixels = 0;
   1640 	for (i = 0; i < 4; i++) {
   1641 		total_pixels += mw * mh;
   1642 		mw = mw > 1 ? mw / 2 : 1;
   1643 		mh = mh > 1 ? mh / 2 : 1;
   1644 	}
   1645 
   1646 	t->pixels = malloc(total_pixels * sizeof(uint32_t));
   1647 	if (t->pixels == NULL) {
   1648 		return;
   1649 	}
   1650 	src_pixels = data + sizeof(struct tga_header) + hdr->id_length;
   1651 
   1652 	if (hdr->pixel_depth == 32) {
   1653 		memcpy(t->pixels, src_pixels, w * h * 4);
   1654 		t->has_alpha = 0;
   1655 		for (i = 0; i < w * h; i++) {
   1656 			a = (t->pixels[i] >> 24) & 0xFF;
   1657 			if (a < 250) {
   1658 				t->has_alpha = 1;
   1659 				break;
   1660 			}
   1661 		}
   1662 	} else if (hdr->pixel_depth == 24) {
   1663 		t->has_alpha = 0;
   1664 		dst = t->pixels;
   1665 		for (i = 0; i < w * h; i++) {
   1666 			dst[i] = (255U << 24) | (src_pixels[i*3+2] << 16) |
   1667 			    (src_pixels[i*3+1] << 8) | src_pixels[i*3+0];
   1668 		}
   1669 	}
   1670 
   1671 	t->mips[0] = t->pixels;
   1672 	t->mip_w[0] = w;
   1673 	t->mip_h[0] = h;
   1674 
   1675 	curr_offset = t->pixels + (w * h);
   1676 	for (level = 1; level < 4; level++) {
   1677 		prev_w = t->mips[level-1] ? t->mip_w[level-1] : 1;
   1678 		prev_h = t->mips[level-1] ? t->mip_h[level-1] : 1;
   1679 		next_w = prev_w > 1 ? prev_w / 2 : 1;
   1680 		next_h = prev_h > 1 ? prev_h / 2 : 1;
   1681 
   1682 		t->mips[level] = curr_offset;
   1683 		t->mip_w[level] = next_w;
   1684 		t->mip_h[level] = next_h;
   1685 
   1686 		src = t->mips[level-1];
   1687 		dst = t->mips[level];
   1688 
   1689 		if (prev_w > 1 && prev_h > 1) {
   1690 			for (y = 0; y < next_h; y++) {
   1691 				for (x = 0; x < next_w; x++) {
   1692 					c00 = src[(y*2)*prev_w + (x*2)];
   1693 					c10 = src[(y*2)*prev_w + (x*2+1)];
   1694 					c01 = src[(y*2+1)*prev_w + (x*2)];
   1695 					c11 = src[(y*2+1)*prev_w + (x*2+1)];
   1696 
   1697 					r = (((c00 >> 16) & 0xFF) + ((c10 >> 16) & 0xFF) +
   1698 					    ((c01 >> 16) & 0xFF) + ((c11 >> 16) & 0xFF)) / 4;
   1699 					g = (((c00 >> 8) & 0xFF) + ((c10 >> 8) & 0xFF) +
   1700 					    ((c01 >> 8) & 0xFF) + ((c11 >> 8) & 0xFF)) / 4;
   1701 					b = ((c00 & 0xFF) + (c10 & 0xFF) +
   1702 					    (c01 & 0xFF) + (c11 & 0xFF)) / 4;
   1703 					a = (((c00 >> 24) & 0xFF) + ((c10 >> 24) & 0xFF) +
   1704 					    ((c01 >> 24) & 0xFF) + ((c11 >> 24) & 0xFF)) / 4;
   1705 
   1706 					dst[y * next_w + x] = (a << 24) | (r << 16) |
   1707 					    (g << 8) | b;
   1708 				}
   1709 			}
   1710 		} else {
   1711 			for (i = 0; i < next_w * next_h; i++) {
   1712 				dst[i] = src[0];
   1713 			}
   1714 		}
   1715 		curr_offset += next_w * next_h;
   1716 	}
   1717 }
   1718 
   1719 static struct texture *
   1720 cache_get_tex(struct asset_cache *c, const char *name)
   1721 {
   1722 	unsigned int h;
   1723 	int idx;
   1724 	char tar_path[1024];
   1725 	size_t sz = 0;
   1726 	const uint8_t *data;
   1727 
   1728 	if (!name || name[0] == '\0') {
   1729 		name = "missing";
   1730 	}
   1731 	h = hash_str(name) % (MAX_CACHE * 2);
   1732 	while (c->tex_hash[h] != 0) {
   1733 		idx = c->tex_hash[h] - 1;
   1734 		if (strcasecmp(c->tex_names[idx], name) == 0) {
   1735 			return (&c->textures[idx]);
   1736 		}
   1737 		h = (h + 1) % (MAX_CACHE * 2);
   1738 	}
   1739 	if (c->tex_count >= MAX_CACHE) {
   1740 		return (NULL);
   1741 	}
   1742 	idx = c->tex_count++;
   1743 	snprintf(c->tex_names[idx], 32, "%s", name);
   1744 	c->tex_hash[h] = idx + 1;
   1745 
   1746 	snprintf(tar_path, sizeof(tar_path), "assets/textures/%s.tga", name);
   1747 
   1748 	data = tar_lookup(tar_path, &sz);
   1749 	tex_load_tga(&c->textures[idx], data, sz);
   1750 	return (&c->textures[idx]);
   1751 }
   1752 
   1753 static struct mesh *
   1754 cache_get_mesh(struct asset_cache *c, const char *name)
   1755 {
   1756 	unsigned int h;
   1757 	int idx;
   1758 	char tar_path[1024];
   1759 	size_t sz = 0;
   1760 	const uint8_t *data;
   1761 	uint32_t i;
   1762 
   1763 	h = hash_str(name) % (MAX_CACHE * 2);
   1764 	while (c->mesh_hash[h] != 0) {
   1765 		idx = c->mesh_hash[h] - 1;
   1766 		if (strcasecmp(c->mesh_names[idx], name) == 0) {
   1767 			return (&c->meshes[idx]);
   1768 		}
   1769 		h = (h + 1) % (MAX_CACHE * 2);
   1770 	}
   1771 	if (c->mesh_count >= MAX_CACHE) {
   1772 		return (NULL);
   1773 	}
   1774 	idx = c->mesh_count++;
   1775 	snprintf(c->mesh_names[idx], NAME_SZ, "%s", name);
   1776 	c->mesh_hash[h] = idx + 1;
   1777 
   1778 	snprintf(tar_path, sizeof(tar_path), "assets/models/%s.ply", name);
   1779 
   1780 	data = tar_lookup(tar_path, &sz);
   1781 	if (data) {
   1782 		mesh_load_ply(&c->meshes[idx], data, sz);
   1783 		if (c->meshes[idx].num_materials > 0) {
   1784 			c->meshes[idx].textures = malloc(c->meshes[idx].num_materials * sizeof(struct texture *));
   1785 			for (i = 0; i < c->meshes[idx].num_materials; i++) {
   1786 				c->meshes[idx].textures[i] = cache_get_tex(c, c->meshes[idx].raw_tex_names[i]);
   1787 			}
   1788 		}
   1789 	}
   1790 	return (&c->meshes[idx]);
   1791 }
   1792 
   1793 static void
   1794 mat_identity(struct mat4 *m)
   1795 {
   1796 	memset(m, 0, sizeof(*m));
   1797 	m->m[0][0] = m->m[1][1] = m->m[2][2] = m->m[3][3] = 1.0f;
   1798 }
   1799 
   1800 static inline void
   1801 mat_mul(struct mat4 *dst, const struct mat4 *a, const struct mat4 *b)
   1802 {
   1803 	struct mat4 r;
   1804 	int i;
   1805 
   1806 	for (i = 0; i < 4; i++) {
   1807 		r.m[i][0] = a->m[i][0]*b->m[0][0] + a->m[i][1]*b->m[1][0] + a->m[i][2]*b->m[2][0] + a->m[i][3]*b->m[3][0];
   1808 		r.m[i][1] = a->m[i][0]*b->m[0][1] + a->m[i][1]*b->m[1][1] + a->m[i][2]*b->m[2][1] + a->m[i][3]*b->m[3][1];
   1809 		r.m[i][2] = a->m[i][0]*b->m[0][2] + a->m[i][1]*b->m[1][2] + a->m[i][2]*b->m[2][2] + a->m[i][3]*b->m[3][2];
   1810 		r.m[i][3] = a->m[i][0]*b->m[0][3] + a->m[i][1]*b->m[1][3] + a->m[i][2]*b->m[2][3] + a->m[i][3]*b->m[3][3];
   1811 	}
   1812 	*dst = r;
   1813 }
   1814 
   1815 static void
   1816 mat_translate(struct mat4 *m, float x, float y, float z)
   1817 {
   1818 	mat_identity(m);
   1819 	m->m[0][3] = x;
   1820 	m->m[1][3] = y;
   1821 	m->m[2][3] = z;
   1822 }
   1823 
   1824 static void
   1825 mat_from_quat(struct mat4 *m, float qx, float qy, float qz, float qw)
   1826 {
   1827 	float len;
   1828 
   1829 	qw = -qw;
   1830 	len = sqrtf(qx * qx + qy * qy + qz * qz + qw * qw);
   1831 	if (len > 0.0f) {
   1832 		qx /= len; qy /= len; qz /= len; qw /= len;
   1833 	}
   1834 	mat_identity(m);
   1835 	m->m[0][0] = 1.0f - 2.0f * (qy * qy + qz * qz);
   1836 	m->m[0][1] = 2.0f * (qx * qy - qz * qw);
   1837 	m->m[0][2] = 2.0f * (qx * qz + qy * qw);
   1838 	m->m[1][0] = 2.0f * (qx * qy + qz * qw);
   1839 	m->m[1][1] = 1.0f - 2.0f * (qx * qx + qz * qz);
   1840 	m->m[1][2] = 2.0f * (qy * qz - qx * qw);
   1841 	m->m[2][0] = 2.0f * (qx * qz - qy * qw);
   1842 	m->m[2][1] = 2.0f * (qy * qz + qx * qw);
   1843 	m->m[2][2] = 1.0f - 2.0f * (qx * qx + qy * qy);
   1844 }
   1845 
   1846 static void
   1847 mat_projection(struct mat4 *m, float fov, float aspect, float near, float far)
   1848 {
   1849 	float f;
   1850 
   1851 	f = 1.0f / tanf(fov * 0.5f * 3.14159265f / 180.0f);
   1852 	memset(m, 0, sizeof(*m));
   1853 	m->m[0][0] = f / aspect;
   1854 	m->m[1][1] = f;
   1855 	m->m[2][2] = (far + near) / (far - near);
   1856 	m->m[2][3] = -(2.0f * far * near) / (far - near);
   1857 	m->m[3][2] = 1.0f;
   1858 }
   1859 
   1860 static void
   1861 mat_view(struct mat4 *m, float cx, float cy, float cz, float cyaw, float cpitch)
   1862 {
   1863 	struct mat4 trans, rot_y, rot_x, rot;
   1864 
   1865 	mat_translate(&trans, -cx, -cy, -cz);
   1866 	mat_identity(&rot_y);
   1867 	rot_y.m[0][0] = cosf(-cyaw);
   1868 	rot_y.m[0][2] = sinf(-cyaw);
   1869 	rot_y.m[2][0] = -sinf(-cyaw);
   1870 	rot_y.m[2][2] = cosf(-cyaw);
   1871 	mat_identity(&rot_x);
   1872 	rot_x.m[1][1] = cosf(cpitch);
   1873 	rot_x.m[1][2] = -sinf(cpitch);
   1874 	rot_x.m[2][1] = sinf(cpitch);
   1875 	rot_x.m[2][2] = cosf(cpitch);
   1876 	mat_mul(&rot, &rot_x, &rot_y);
   1877 	mat_mul(m, &rot, &trans);
   1878 }
   1879 
   1880 static inline void
   1881 mat_transform(struct vec3 *dst, float *w_out, const struct mat4 *m, const struct vec3 *v)
   1882 {
   1883 	dst->x = m->m[0][0] * v->x + m->m[0][1] * v->y + m->m[0][2] * v->z + m->m[0][3];
   1884 	dst->y = m->m[1][0] * v->x + m->m[1][1] * v->y + m->m[1][2] * v->z + m->m[1][3];
   1885 	dst->z = m->m[2][0] * v->x + m->m[2][1] * v->y + m->m[2][2] * v->z + m->m[2][3];
   1886 	*w_out = m->m[3][0] * v->x + m->m[3][1] * v->y + m->m[3][2] * v->z + m->m[3][3];
   1887 }
   1888 
   1889 static void
   1890 flush_render_list(void)
   1891 {
   1892 	if (render_count == 0) {
   1893 		return;
   1894 	}
   1895 	pthread_barrier_wait(&barrier_start);
   1896 	pthread_barrier_wait(&barrier_end);
   1897 	render_count = 0;
   1898 }
   1899 
   1900 static void
   1901 project_and_push(const struct clip_vertex *c0, const struct clip_vertex *c1, const struct clip_vertex *c2, const struct texture *tex, int is_water, int mip)
   1902 {
   1903 	struct vertex v0, v1, v2;
   1904 	float area;
   1905 	int double_sided;
   1906 	struct vertex tmp;
   1907 
   1908 	v0.w = 1.0f / c0->w; v0.x = (c0->x * v0.w + 1.0f) * WIDTH * 0.5f; v0.y = (1.0f - c0->y * v0.w) * HEIGHT * 0.5f;
   1909 	v0.z = c0->w; v0.u = c0->u; v0.v = c0->v; v0.r = c0->r; v0.g = c0->g; v0.b = c0->b; v0.a = c0->a; v0.f = c0->f;
   1910 	v1.w = 1.0f / c1->w; v1.x = (c1->x * v1.w + 1.0f) * WIDTH * 0.5f; v1.y = (1.0f - c1->y * v1.w) * HEIGHT * 0.5f;
   1911 	v1.z = c1->w; v1.u = c1->u; v1.v = c1->v; v1.r = c1->r; v1.g = c1->g; v1.b = c1->b; v1.a = c1->a; v1.f = c1->f;
   1912 	v2.w = 1.0f / c2->w; v2.x = (c2->x * v2.w + 1.0f) * WIDTH * 0.5f; v2.y = (1.0f - c2->y * v2.w) * HEIGHT * 0.5f;
   1913 	v2.z = c2->w; v2.u = c2->u; v2.v = c2->v; v2.r = c2->r; v2.g = c2->g; v2.b = c2->b; v2.a = c2->a; v2.f = c2->f;
   1914 
   1915 	area = edge_func(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
   1916 	double_sided = (tex && tex->has_alpha) || is_water;
   1917 	if (area >= 0.0f) {
   1918 		if (double_sided) {
   1919 			tmp = v1;
   1920 			v1 = v2;
   1921 			v2 = tmp;
   1922 		} else {
   1923 			return;
   1924 		}
   1925 	}
   1926 
   1927 	if (render_count >= MAX_RENDER_TRIS) {
   1928 		flush_render_list();
   1929 	}
   1930 	render_list[render_count].v0 = v0;
   1931 	render_list[render_count].v1 = v1;
   1932 	render_list[render_count].v2 = v2;
   1933 	render_list[render_count].tex = tex;
   1934 	render_list[render_count].is_water = is_water;
   1935 	render_list[render_count].mip = mip;
   1936 	render_count++;
   1937 }
   1938 
   1939 static struct clip_vertex
   1940 clip_intersect(const struct clip_vertex *a, const struct clip_vertex *b, float w_clip)
   1941 {
   1942 	struct clip_vertex out;
   1943 	float t;
   1944 
   1945 	t = (w_clip - a->w) / (b->w - a->w);
   1946 	out.x = a->x + t * (b->x - a->x);
   1947 	out.y = a->y + t * (b->y - a->y);
   1948 	out.z = a->z + t * (b->z - a->z);
   1949 	out.w = w_clip;
   1950 	out.u = a->u + t * (b->u - a->u);
   1951 	out.v = a->v + t * (b->v - a->v);
   1952 	out.r = a->r + t * (b->r - a->r);
   1953 	out.g = a->g + t * (b->g - a->g);
   1954 	out.b = a->b + t * (b->b - a->b);
   1955 	out.a = a->a + t * (b->a - a->a);
   1956 	out.f = a->f + t * (b->f - a->f);
   1957 	return (out);
   1958 }
   1959 
   1960 static void
   1961 clip_and_push_triangle(const struct clip_vertex *c0, const struct clip_vertex *c1, const struct clip_vertex *c2, const struct texture *tex, int is_water, int mip)
   1962 {
   1963 	struct clip_vertex p[4];
   1964 	const struct clip_vertex *v[3];
   1965 	const struct clip_vertex *c, *n;
   1966 	int len = 0;
   1967 	int i;
   1968 
   1969 	v[0] = c0;
   1970 	v[1] = c1;
   1971 	v[2] = c2;
   1972 
   1973 	for (i = 0; i < 3; i++) {
   1974 		c = v[i];
   1975 		n = v[(i + 1) % 3];
   1976 		if (c->w >= 0.1f) {
   1977 			p[len++] = *c;
   1978 		}
   1979 		if ((c->w >= 0.1f) != (n->w >= 0.1f)) {
   1980 			p[len++] = clip_intersect(c, n, 0.1f);
   1981 		}
   1982 	}
   1983 	if (len == 3) {
   1984 		project_and_push(&p[0], &p[1], &p[2], tex, is_water, mip);
   1985 	} else if (len == 4) {
   1986 		project_and_push(&p[0], &p[1], &p[2], tex, is_water, mip);
   1987 		project_and_push(&p[0], &p[2], &p[3], tex, is_water, mip);
   1988 	}
   1989 }
   1990 
   1991 static void
   1992 draw_mesh(const struct mesh *m, const struct mat4 *mvp, int is_seabed)
   1993 {
   1994 	struct clip_vertex *cv;
   1995 	float ar, ag, ab, far_clp, fog_st, min_dist;
   1996 	int mip;
   1997 	float scale;
   1998 	uint32_t i;
   1999 	struct vec3 in, out;
   2000 	float w, fog, d;
   2001 
   2002 	if (m->ply_verts == NULL || m->num_verts == 0) {
   2003 		return;
   2004 	}
   2005 	if (m->num_verts > v_scratch_cap) {
   2006 		v_scratch_cap = m->num_verts * 2;
   2007 		v_scratch = realloc(v_scratch, v_scratch_cap * sizeof(struct clip_vertex));
   2008 	}
   2009 	cv = v_scratch;
   2010 	ar = g_sys->cur_weather.amb[0] / 255.0f * 1.2f;
   2011 	ag = g_sys->cur_weather.amb[1] / 255.0f * 1.2f;
   2012 	ab = g_sys->cur_weather.amb[2] / 255.0f * 1.2f;
   2013 	far_clp = g_sys->cur_weather.far_clp;
   2014 	fog_st = g_sys->cur_weather.fog_st;
   2015 	if (far_clp <= fog_st) {
   2016 		far_clp = fog_st + 1.0f;
   2017 	}
   2018 	min_dist = 1e9f;
   2019 
   2020 	for (i = 0; i < m->num_verts; i++) {
   2021 		in.x = m->ply_verts[i].x;
   2022 		in.y = m->ply_verts[i].y;
   2023 		in.z = m->ply_verts[i].z;
   2024 		mat_transform(&out, &w, mvp, &in);
   2025 		cv[i].x = out.x;
   2026 		cv[i].y = out.y;
   2027 		cv[i].z = out.z;
   2028 		cv[i].w = w;
   2029 		cv[i].u = m->ply_verts[i].s;
   2030 		cv[i].v = m->ply_verts[i].t;
   2031 		fog = (out.z - fog_st) / (far_clp - fog_st);
   2032 		if (fog < 0.0f) {
   2033 			fog = 0.0f;
   2034 		} else if (fog > 1.0f) {
   2035 			fog = 1.0f;
   2036 		}
   2037 		cv[i].f = fog;
   2038 		
   2039 		if (is_seabed) {
   2040 			cv[i].r = 0.25f * ar;
   2041 			cv[i].g = 0.28f * ag;
   2042 			cv[i].b = 0.30f * ab;
   2043 		} else {
   2044 			cv[i].r = (m->ply_verts[i].r / 255.0f) * ar;
   2045 			cv[i].g = (m->ply_verts[i].g / 255.0f) * ag;
   2046 			cv[i].b = (m->ply_verts[i].b / 255.0f) * ab;
   2047 		}
   2048 		cv[i].a = 1.0f;
   2049 
   2050 		d = sqrtf(out.x*out.x + out.y*out.y + out.z*out.z);
   2051 		if (d < min_dist) {
   2052 			min_dist = d;
   2053 		}
   2054 	}
   2055 	mip = 0;
   2056 	scale = sqrtf(m->total_area) * 0.05f;
   2057 	if (scale < 0.2f) {
   2058 		scale = 0.2f;
   2059 	}
   2060 	if (scale > 5.0f) {
   2061 		scale = 5.0f;
   2062 	}
   2063 	if (min_dist > 150.0f * scale) {
   2064 		mip = 3;
   2065 	} else if (min_dist > 80.0f * scale) {
   2066 		mip = 2;
   2067 	} else if (min_dist > 30.0f * scale) {
   2068 		mip = 1;
   2069 	}
   2070 
   2071 	for (i = 0; i < m->num_tris; i++) {
   2072 		uint16_t i0 = m->indices[i*3], i1 = m->indices[i*3+1], i2 = m->indices[i*3+2];
   2073 		struct texture *tex;
   2074 
   2075 		if (cv[i0].w < 0.1f && cv[i1].w < 0.1f && cv[i2].w < 0.1f) {
   2076 			continue;
   2077 		}
   2078 		if (cv[i0].w > far_clp && cv[i1].w > far_clp && cv[i2].w > far_clp) {
   2079 			continue;
   2080 		}
   2081 		tex = (m->num_materials > 0 && m->textures) ? m->textures[m->mat_ids[i] < m->num_materials ? m->mat_ids[i] : 0] : NULL;
   2082 		clip_and_push_triangle(&cv[i0], &cv[i1], &cv[i2], tex, 0, mip);
   2083 	}
   2084 }
   2085 
   2086 static int
   2087 is_occluded(struct sys_gfx *g, float cx, float cy, float cz, float r)
   2088 {
   2089 	(void)g; (void)cx; (void)cy; (void)cz; (void)r;
   2090 	return (0);
   2091 }
   2092 
   2093 static int
   2094 cmp_draw_item(const void *a, const void *b)
   2095 {
   2096 	float da = ((const struct draw_item *)a)->dist_sq;
   2097 	float db = ((const struct draw_item *)b)->dist_sq;
   2098 
   2099 	if (da < db)
   2100 		return (-1);
   2101 	if (da > db)
   2102 		return (1);
   2103 	return (0);
   2104 }
   2105 
   2106 static const char *
   2107 ped_lookup_model(int id)
   2108 {
   2109 	if (id < 0 || id >= 313) {
   2110 		return (NULL);
   2111 	}
   2112 	return (skin_names[id][0] != '\0' ? skin_names[id] : NULL);
   2113 }
   2114 
   2115 static void
   2116 draw_scene(struct sys_gfx *g, const struct mat4 *proj, const struct mat4 *view,
   2117     float cam_x, float cam_y, float cam_z,
   2118     float player_x, float player_y, float player_z, float player_yaw)
   2119 {
   2120 	float val, pitch, fov_y, fov_x, far_clp, dx, dy, dz, dist_sq, w, r;
   2121 	float obj_max_dist;
   2122 	int y_horiz, min_gx, max_gx, min_gz, max_gz, id, x, y, gx, gz, i;
   2123 	uint8_t sr, sg, sb, hr, hg, hb;
   2124 	uint32_t c;
   2125 	struct mesh *m;
   2126 	struct vec3 mc, cv;
   2127 	struct mat4 mvp;
   2128 
   2129 	val = view->m[1][2];
   2130 	if (val > 1.0f) {
   2131 		val = 1.0f;
   2132 	} else if (val < -1.0f) {
   2133 		val = -1.0f;
   2134 	}
   2135 	pitch = asin(val);
   2136 	y_horiz = HEIGHT / 2 + (int)(pitch * 400.0f);
   2137 	sr = g->cur_weather.sky_top[0];
   2138 	sg = g->cur_weather.sky_top[1];
   2139 	sb = g->cur_weather.sky_top[2];
   2140 	hr = g->cur_weather.sky_bot[0];
   2141 	hg = g->cur_weather.sky_bot[1];
   2142 	hb = g->cur_weather.sky_bot[2];
   2143 
   2144 	for (y = 0; y < HEIGHT; y++) {
   2145 		c = (hr << 16) | (hg << 8) | hb;
   2146 		if (y < y_horiz) {
   2147 			float f = (float)y / (float)(y_horiz > 0 ? y_horiz : 1);
   2148 			c = ((sr + (uint8_t)(f * (hr - sr))) << 16) |
   2149 			    ((sg + (uint8_t)(f * (hg - sg))) << 8) |
   2150 			    (sb + (uint8_t)(f * (hb - sb)));
   2151 		}
   2152 		for (x = 0; x < WIDTH; x++) {
   2153 			g->pixels[y * WIDTH + x] = c;
   2154 		}
   2155 	}
   2156 
   2157 	far_clp = g->cur_weather.far_clp;
   2158 	fov_y = tanf(60.0f * 0.5f * 3.14159f / 180.0f);
   2159 	fov_x = fov_y * ((float)WIDTH / HEIGHT);
   2160 
   2161 	min_gx = (int)((cam_x - far_clp - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2162 	max_gx = (int)((cam_x + far_clp - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2163 	min_gz = (int)((cam_z - far_clp - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2164 	max_gz = (int)((cam_z + far_clp - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2165 
   2166 	if (min_gx < 0) min_gx = 0;
   2167 	if (max_gx >= GRID_SZ) max_gx = GRID_SZ - 1;
   2168 	if (min_gz < 0) min_gz = 0;
   2169 	if (max_gz >= GRID_SZ) max_gz = GRID_SZ - 1;
   2170 
   2171 	draw_count = 0;
   2172 	for (gz = min_gz; gz <= max_gz; gz++) {
   2173 		for (gx = min_gx; gx <= max_gx; gx++) {
   2174 			for (i = 0; i < scene_grid[gx][gz].count; i++) {
   2175 				id = scene_grid[gx][gz].ids[i];
   2176 
   2177 				int16_t t_on = g_transforms.time_on[id];
   2178 				int16_t t_off = g_transforms.time_off[id];
   2179 				if (t_on != t_off) {
   2180 					float cur_h = g->game_time_hours;
   2181 					int visible = 0;
   2182 					if (t_on > t_off) {
   2183 						if (cur_h >= t_on || cur_h < t_off) {
   2184 							visible = 1;
   2185 						}
   2186 					} else {
   2187 						if (cur_h >= t_on && cur_h < t_off) {
   2188 							visible = 1;
   2189 						}
   2190 					}
   2191 					if (!visible) {
   2192 						continue;
   2193 					}
   2194 				}
   2195 
   2196 				dx = g_transforms.sphere_cx[id] - cam_x;
   2197 				dy = g_transforms.sphere_cy[id] - cam_y;
   2198 				dz = g_transforms.sphere_cz[id] - cam_z;
   2199 				dist_sq = dx * dx + dy * dy + dz * dz;
   2200 
   2201 				obj_max_dist = g_transforms.sphere_r[id] * 35.0f;
   2202 				if (obj_max_dist < 40.0f) {
   2203 					obj_max_dist = 40.0f;
   2204 				}
   2205 				if (obj_max_dist > far_clp) {
   2206 					obj_max_dist = far_clp;
   2207 				}
   2208 
   2209 				if (dist_sq > (obj_max_dist + g_transforms.sphere_r[id]) *
   2210 				    (obj_max_dist + g_transforms.sphere_r[id])) {
   2211 					continue;
   2212 				}
   2213 
   2214 				if (draw_count >= draw_cap) {
   2215 					draw_cap = draw_cap == 0 ? 1024 : draw_cap * 2;
   2216 					draw_list = realloc(draw_list, draw_cap * sizeof(struct draw_item));
   2217 				}
   2218 				draw_list[draw_count].id = id;
   2219 				draw_list[draw_count].dist_sq = dist_sq;
   2220 				draw_count++;
   2221 			}
   2222 		}
   2223 	}
   2224 	qsort(draw_list, draw_count, sizeof(struct draw_item), cmp_draw_item);
   2225 
   2226 	for (i = 0; i < draw_count; i++) {
   2227 		id = draw_list[i].id;
   2228 		m = scene_meshes[id];
   2229 		if (!m || !m->ply_verts) {
   2230 			continue;
   2231 		}
   2232 		mc.x = g_transforms.sphere_cx[id];
   2233 		mc.y = g_transforms.sphere_cy[id];
   2234 		mc.z = g_transforms.sphere_cz[id];
   2235 		r = g_transforms.sphere_r[id] * 1.05f;
   2236 
   2237 		dx = mc.x - cam_x;
   2238 		dy = mc.y - cam_y;
   2239 		dz = mc.z - cam_z;
   2240 		dist_sq = dx * dx + dy * dy + dz * dz;
   2241 
   2242 		if (dist_sq > r * r) {
   2243 			mat_transform(&cv, &w, view, &mc);
   2244 
   2245 			if (cv.z + r < 0.1f || cv.z - r > far_clp) {
   2246 				continue;
   2247 			}
   2248 			if (cv.z > 0.0f) {
   2249 				if (fabsf(cv.x) - r > cv.z * fov_x ||
   2250 				    fabsf(cv.y) - r > cv.z * fov_y) {
   2251 					continue;
   2252 				}
   2253 			}
   2254 		} else {
   2255 			mat_transform(&cv, &w, view, &mc);
   2256 		}
   2257 
   2258 		if (is_occluded(g, cv.x, cv.y, cv.z, r)) {
   2259 			continue;
   2260 		}
   2261 		mat_mul(&mvp, view, &g_transforms.world_matrices[id]);
   2262 		mat_mul(&mvp, proj, &mvp);
   2263 		draw_mesh(m, &mvp, 0);
   2264 	}
   2265 
   2266 	if (active_skin_id >= 0) {
   2267 		const char *skin_model_name;
   2268 
   2269 		skin_model_name = ped_lookup_model(active_skin_id);
   2270 		if (skin_model_name) {
   2271 			struct mesh *skin_mesh;
   2272 
   2273 			skin_mesh = cache_get_mesh(g_cache, skin_model_name);
   2274 			if (skin_mesh && skin_mesh->ply_verts) {
   2275 				struct mat4 rot_y, trans, world;
   2276 
   2277 				mat_identity(&rot_y);
   2278 				rot_y.m[0][0] = cosf(player_yaw);
   2279 				rot_y.m[0][2] = sinf(player_yaw);
   2280 				rot_y.m[2][0] = -sinf(player_yaw);
   2281 				rot_y.m[2][2] = cosf(player_yaw);
   2282 
   2283 				mat_translate(&trans, player_x, player_y + 1.0f, player_z);
   2284 				mat_mul(&world, &trans, &rot_y);
   2285 
   2286 				mat_mul(&mvp, view, &world);
   2287 				mat_mul(&mvp, proj, &mvp);
   2288 				draw_mesh(skin_mesh, &mvp, 0);
   2289 			}
   2290 		}
   2291 	}
   2292 
   2293 	for (i = 0; i < MAX_PLAYERS; i++) {
   2294 		const char *rem_skin_name;
   2295 
   2296 		if (!net_players[i].active || i == my_player_id) {
   2297 			continue;
   2298 		}
   2299 
   2300 		rem_skin_name = ped_lookup_model(net_players[i].skin);
   2301 		if (rem_skin_name) {
   2302 			struct mesh *rem_mesh;
   2303 
   2304 			rem_mesh = cache_get_mesh(g_cache, rem_skin_name);
   2305 			if (rem_mesh && rem_mesh->ply_verts) {
   2306 				struct mat4 rot_y, trans, world;
   2307 
   2308 				mat_identity(&rot_y);
   2309 				rot_y.m[0][0] = cosf(net_players[i].cur_yaw);
   2310 				rot_y.m[0][2] = sinf(net_players[i].cur_yaw);
   2311 				rot_y.m[2][0] = -sinf(net_players[i].cur_yaw);
   2312 				rot_y.m[2][2] = cosf(net_players[i].cur_yaw);
   2313 
   2314 				mat_translate(&trans, net_players[i].cur_x,
   2315 				    net_players[i].cur_y + 1.0f, net_players[i].cur_z);
   2316 				mat_mul(&world, &trans, &rot_y);
   2317 
   2318 				mat_mul(&mvp, view, &world);
   2319 				mat_mul(&mvp, proj, &mvp);
   2320 				draw_mesh(rem_mesh, &mvp, 0);
   2321 			}
   2322 		}
   2323 	}
   2324 
   2325 	flush_render_list();
   2326 }
   2327 
   2328 static void
   2329 update_weather(struct sys_gfx *g)
   2330 {
   2331 	float t, snaps[8] = {0.0f, 5.0f, 6.0f, 7.0f, 12.0f, 19.0f, 20.0f, 22.0f};
   2332 	int i0, i1, i;
   2333 	float f;
   2334 	struct timecyc_entry *w0, *w1;
   2335 
   2336 	if (g->num_weathers == 0) {
   2337 		return;
   2338 	}
   2339 	if (g->game_weather >= g->num_weathers) {
   2340 		g->game_weather = 0;
   2341 	}
   2342 	t = g->game_time_hours;
   2343 	i0 = 7;
   2344 	i1 = 0;
   2345 	f = 0.0f;
   2346 	if (t >= snaps[7] || t < snaps[0]) {
   2347 		float wt = t;
   2348 		if (wt < snaps[0]) {
   2349 			wt += 24.0f;
   2350 		}
   2351 		f = (wt - snaps[7]) / (24.0f - snaps[7] + snaps[0]);
   2352 	} else {
   2353 		for (i = 0; i < 7; i++) {
   2354 			if (t >= snaps[i] && t < snaps[i + 1]) {
   2355 				i0 = i;
   2356 				i1 = i + 1;
   2357 				f = (t - snaps[i]) / (snaps[i + 1] - snaps[i]);
   2358 				break;
   2359 			}
   2360 		}
   2361 	}
   2362 	w0 = &g->weathers[g->game_weather][i0];
   2363 	w1 = &g->weathers[g->game_weather][i1];
   2364 	#define LERP(c) g->cur_weather.c = w0->c + f * (w1->c - w0->c)
   2365 	LERP(amb[0]); LERP(amb[1]); LERP(amb[2]);
   2366 	LERP(sky_top[0]); LERP(sky_top[1]); LERP(sky_top[2]);
   2367 	LERP(sky_bot[0]); LERP(sky_bot[1]); LERP(sky_bot[2]);
   2368 	LERP(water[0]); LERP(water[1]); LERP(water[2]); LERP(water[3]);
   2369 	LERP(far_clp); LERP(fog_st);
   2370 	#undef LERP
   2371 
   2372 	if (g->far_clip_override > 10.0f) {
   2373 		g->cur_weather.far_clp = g->far_clip_override;
   2374 	} else if (g->cur_weather.far_clp > 220.0f) {
   2375 		g->cur_weather.far_clp = 220.0f;
   2376 	}
   2377 }
   2378 
   2379 static void
   2380 draw_water(const struct mat4 *proj, const struct mat4 *view)
   2381 {
   2382 	struct clip_vertex cv[4];
   2383 	struct mat4 mvp;
   2384 	struct vec3 in, out;
   2385 	float t, far_clp, fog_st, ar, ag, ab, w, fog, u_tex, v_tex;
   2386 	float wave_height, wave_factor, dy, flow_u, flow_v;
   2387 	uint32_t i;
   2388 	int j;
   2389 
   2390 	mat_mul(&mvp, proj, view);
   2391 	t = g_sys->game_time_sec;
   2392 	far_clp = g_sys->cur_weather.far_clp;
   2393 	fog_st = g_sys->cur_weather.fog_st;
   2394 	if (far_clp <= fog_st) {
   2395 		far_clp = fog_st + 1.0f;
   2396 	}
   2397 	ar = g_sys->cur_weather.amb[0] / 255.0f * 1.2f;
   2398 	ag = g_sys->cur_weather.amb[1] / 255.0f * 1.2f;
   2399 	ab = g_sys->cur_weather.amb[2] / 255.0f * 1.2f;
   2400 
   2401 	for (i = 0; i < water_count; i++) {
   2402 		for (j = 0; j < water_faces[i].num; j++) {
   2403 			in.x = water_faces[i].x[j];
   2404 			
   2405 			wave_height = water_faces[i].h[j];
   2406 			wave_factor = sinf(t * 1.5f + water_faces[i].x[j] * 0.05f + water_faces[i].y[j] * 0.05f);
   2407 			dy = wave_factor * wave_height;
   2408 
   2409 			in.y = water_faces[i].z[j] + dy;
   2410 			in.z = water_faces[i].y[j];
   2411 			
   2412 			mat_transform(&out, &w, &mvp, &in);
   2413 			fog = (out.z - fog_st) / (far_clp - fog_st);
   2414 			if (fog < 0.0f) {
   2415 				fog = 0.0f;
   2416 			} else if (fog > 1.0f) {
   2417 				fog = 1.0f;
   2418 			}
   2419 			
   2420 			flow_u = water_faces[i].u[j];
   2421 			flow_v = water_faces[i].v[j];
   2422 
   2423 			u_tex = (water_faces[i].x[j] - water_faces[i].x[0]) * 0.01f + t * (flow_u - 0.015f) + dy * 0.05f;
   2424 			v_tex = (water_faces[i].y[j] - water_faces[i].y[0]) * 0.01f + t * (flow_v - 0.015f) + dy * 0.05f;
   2425 			
   2426 			cv[j].x = out.x;
   2427 			cv[j].y = out.y;
   2428 			cv[j].z = out.z;
   2429 			cv[j].w = w;
   2430 			cv[j].u = u_tex;
   2431 			cv[j].v = v_tex;
   2432 			cv[j].r = ar;
   2433 			cv[j].g = ag;
   2434 			cv[j].b = ab;
   2435 			cv[j].a = 1.0f;
   2436 			cv[j].f = fog;
   2437 		}
   2438 		if (water_faces[i].num == 4) {
   2439 			if (!(cv[0].w < 0.1f && cv[2].w < 0.1f && cv[1].w < 0.1f) && !(cv[0].w > far_clp && cv[2].w > far_clp && cv[1].w > far_clp)) {
   2440 				clip_and_push_triangle(&cv[0], &cv[2], &cv[1], water_tex, 1, 0);
   2441 			}
   2442 			if (!(cv[2].w < 0.1f && cv[3].w < 0.1f && cv[1].w < 0.1f) && !(cv[2].w > far_clp && cv[3].w > far_clp && cv[1].w > far_clp)) {
   2443 				clip_and_push_triangle(&cv[2], &cv[3], &cv[1], water_tex, 1, 0);
   2444 			}
   2445 		} else if (water_faces[i].num == 3) {
   2446 			if (!(cv[0].w < 0.1f && cv[2].w < 0.1f && cv[1].w < 0.1f) && !(cv[0].w > far_clp && cv[2].w > far_clp && cv[1].w > far_clp)) {
   2447 				clip_and_push_triangle(&cv[0], &cv[2], &cv[1], water_tex, 1, 0);
   2448 			}
   2449 		}
   2450 	}
   2451 	flush_render_list();
   2452 }
   2453 
   2454 static void
   2455 draw_ocean_sector(const struct mat4 *mvp, float x0, float x1, float z0, float z1, float height, float t, const struct texture *tex, int is_water)
   2456 {
   2457 	struct clip_vertex cv[4];
   2458 	struct vec3 in, out;
   2459 	float far_clp, fog_st, ar, ag, ab, w, fog, u_tex, v_tex;
   2460 	float prelight_r, prelight_g, prelight_b;
   2461 	float step = 500.0f;
   2462 	float tx, tz, next_tx, next_tz;
   2463 	float xs[4], zs[4];
   2464 	int i;
   2465 
   2466 	far_clp = g_sys->cur_weather.far_clp;
   2467 	fog_st = g_sys->cur_weather.fog_st;
   2468 	if (far_clp <= fog_st) {
   2469 		far_clp = fog_st + 1.0f;
   2470 	}
   2471 	ar = g_sys->cur_weather.amb[0] / 255.0f * 1.2f;
   2472 	ag = g_sys->cur_weather.amb[1] / 255.0f * 1.2f;
   2473 	ab = g_sys->cur_weather.amb[2] / 255.0f * 1.2f;
   2474 
   2475 	prelight_r = is_water ? 1.0f : 0.35f;
   2476 	prelight_g = is_water ? 1.0f : 0.38f;
   2477 	prelight_b = is_water ? 1.0f : 0.40f;
   2478 
   2479 	for (tx = floorf(x0 / step) * step; tx < x1; tx += step) {
   2480 		next_tx = tx + step;
   2481 		if (next_tx > x1) {
   2482 			next_tx = x1;
   2483 		}
   2484 		for (tz = floorf(z0 / step) * step; tz < z1; tz += step) {
   2485 			next_tz = tz + step;
   2486 			if (next_tz > z1) {
   2487 				next_tz = z1;
   2488 			}
   2489 
   2490 			xs[0] = tx;      xs[1] = next_tx; xs[2] = next_tx; xs[3] = tx;
   2491 			zs[0] = tz;      zs[1] = tz;      zs[2] = next_tz; zs[3] = next_tz;
   2492 
   2493 			for (i = 0; i < 4; i++) {
   2494 				in.x = xs[i];
   2495 				in.y = height;
   2496 				in.z = zs[i];
   2497 				mat_transform(&out, &w, mvp, &in);
   2498 				fog = (out.z - fog_st) / (far_clp - fog_st);
   2499 				if (fog < 0.0f) {
   2500 					fog = 0.0f;
   2501 				} else if (fog > 1.0f) {
   2502 					fog = 1.0f;
   2503 				}
   2504 				u_tex = xs[i] * 0.01f;
   2505 				v_tex = zs[i] * 0.01f;
   2506 				if (is_water) {
   2507 					u_tex -= t * 0.02f;
   2508 					v_tex -= t * 0.02f;
   2509 				}
   2510 				cv[i] = (struct clip_vertex){
   2511 					out.x, out.y, out.z, w, u_tex, v_tex,
   2512 					ar * prelight_r, ag * prelight_g, ab * prelight_b,
   2513 					1.0f, fog
   2514 				};
   2515 			}
   2516 			if (!(cv[0].w < 0.1f && cv[2].w < 0.1f && cv[1].w < 0.1f) && !(cv[0].w > far_clp && cv[2].w > far_clp && cv[1].w > far_clp)) {
   2517 				clip_and_push_triangle(&cv[0], &cv[2], &cv[1], tex, is_water, 0);
   2518 			}
   2519 			if (!(cv[0].w < 0.1f && cv[3].w < 0.1f && cv[2].w < 0.1f) && !(cv[0].w > far_clp && cv[3].w > far_clp && cv[2].w > far_clp)) {
   2520 				clip_and_push_triangle(&cv[0], &cv[3], &cv[2], tex, is_water, 0);
   2521 			}
   2522 		}
   2523 	}
   2524 }
   2525 
   2526 static void
   2527 draw_infinite_ocean(const struct mat4 *proj, const struct mat4 *view, float cam_x, float cam_z, float t)
   2528 {
   2529 	struct mat4 mvp;
   2530 	float far_clp, b;
   2531 	float n_x0, n_x1, n_z0, n_z1;
   2532 	float s_x0, s_x1, s_z0, s_z1;
   2533 	float w_x0, w_x1, w_z0, w_z1;
   2534 	float e_x0, e_x1, e_z0, e_z1;
   2535 
   2536 	mat_mul(&mvp, proj, view);
   2537 	far_clp = g_sys->cur_weather.far_clp;
   2538 	b = 2970.0f;
   2539 
   2540 	n_x0 = cam_x - far_clp * 1.5f;
   2541 	n_x1 = cam_x + far_clp * 1.5f;
   2542 	n_z0 = fmaxf(b, cam_z - far_clp * 1.5f);
   2543 	n_z1 = cam_z + far_clp * 1.5f;
   2544 	if (n_z1 > n_z0) {
   2545 		draw_ocean_sector(&mvp, n_x0, n_x1, n_z0, n_z1, -65.0f, t, sand_tex, 0);
   2546 		draw_ocean_sector(&mvp, n_x0, n_x1, n_z0, n_z1, 0.0f, t, water_tex, 1);
   2547 	}
   2548 
   2549 	s_x0 = cam_x - far_clp * 1.5f;
   2550 	s_x1 = cam_x + far_clp * 1.5f;
   2551 	s_z0 = cam_z - far_clp * 1.5f;
   2552 	s_z1 = fminf(-b, cam_z + far_clp * 1.5f);
   2553 	if (s_z1 > s_z0) {
   2554 		draw_ocean_sector(&mvp, s_x0, s_x1, s_z0, s_z1, -65.0f, t, sand_tex, 0);
   2555 		draw_ocean_sector(&mvp, s_x0, s_x1, s_z0, s_z1, 0.0f, t, water_tex, 1);
   2556 	}
   2557 
   2558 	w_x0 = cam_x - far_clp * 1.5f;
   2559 	w_x1 = fminf(-b, cam_x + far_clp * 1.5f);
   2560 	w_z0 = fmaxf(-b, cam_z - far_clp * 1.5f);
   2561 	w_z1 = fminf(b, cam_z + far_clp * 1.5f);
   2562 	if (w_x1 > w_x0 && w_z1 > w_z0) {
   2563 		draw_ocean_sector(&mvp, w_x0, w_x1, w_z0, w_z1, -65.0f, t, sand_tex, 0);
   2564 		draw_ocean_sector(&mvp, w_x0, w_x1, w_z0, w_z1, 0.0f, t, water_tex, 1);
   2565 	}
   2566 
   2567 	e_x0 = fmaxf(b, cam_x - far_clp * 1.5f);
   2568 	e_x1 = cam_x + far_clp * 1.5f;
   2569 	e_z0 = fmaxf(-b, cam_z - far_clp * 1.5f);
   2570 	e_z1 = fminf(b, cam_z + far_clp * 1.5f);
   2571 	if (e_x1 > e_x0 && e_z1 > e_z0) {
   2572 		draw_ocean_sector(&mvp, e_x0, e_x1, e_z0, e_z1, -65.0f, t, sand_tex, 0);
   2573 		draw_ocean_sector(&mvp, e_x0, e_x1, e_z0, e_z1, 0.0f, t, water_tex, 1);
   2574 	}
   2575 	flush_render_list();
   2576 }
   2577 
   2578 static void
   2579 scene_load(struct asset_cache *cache, const uint8_t *data, size_t sz)
   2580 {
   2581 	char *buf, *line, *next_line, *p;
   2582 	int in_inst, id, interior, idx, gx, gz;
   2583 	char name[NAME_SZ];
   2584 	float px, py, pz, qx, qy, qz, qw, w;
   2585 	struct mesh *m;
   2586 	struct mat4 rot, trans, sa2gl;
   2587 	struct vec3 wc;
   2588 	struct grid_cell *c;
   2589 	int lod, time_on, time_off;
   2590 
   2591 	buf = malloc(sz + 1);
   2592 	if (buf == NULL) {
   2593 		return;
   2594 	}
   2595 	memcpy(buf, data, sz);
   2596 	buf[sz] = '\0';
   2597 
   2598 	line = buf;
   2599 	in_inst = 0;
   2600 	while (line && *line) {
   2601 		next_line = strchr(line, '\n');
   2602 		if (next_line) {
   2603 			*next_line = '\0';
   2604 			next_line++;
   2605 		}
   2606 		p = line;
   2607 		while (*p == ' ' || *p == '\t') {
   2608 			p++;
   2609 		}
   2610 		if (*p == '\0' || *p == '#') {
   2611 			line = next_line;
   2612 			continue;
   2613 		}
   2614 		if (strncasecmp(p, "inst", 4) == 0 || strncasecmp(p, "tobj", 4) == 0) {
   2615 			in_inst = 1;
   2616 			line = next_line;
   2617 			continue;
   2618 		}
   2619 		if (strncasecmp(p, "end", 3) == 0) {
   2620 			in_inst = 0;
   2621 			line = next_line;
   2622 			continue;
   2623 		}
   2624 		if (in_inst) {
   2625 			lod = -1;
   2626 			time_on = 0;
   2627 			time_off = 0;
   2628 			
   2629 			if (sscanf(p, "%d, %23[^,], %d, %f, %f, %f, %f, %f, %f, %f, %d, %d, %d", 
   2630 			    &id, name, &interior, &px, &py, &pz, &qx, &qy, &qz, &qw, &lod, &time_on, &time_off) >= 10) {
   2631 				char *end_ptr = name + strlen(name) - 1;
   2632 				while (end_ptr > name && (*end_ptr == ' ' || *end_ptr == '\t')) {
   2633 					*end_ptr = '\0';
   2634 					end_ptr--;
   2635 				}
   2636 				for (p = name; *p; p++) {
   2637 					*p = tolower((unsigned char)*p);
   2638 				}
   2639 
   2640 				if (scene_inst_count >= scene_inst_capacity) {
   2641 					scene_inst_capacity = scene_inst_capacity == 0 ? 512 : scene_inst_capacity * 2;
   2642 					scene_meshes = realloc(scene_meshes, scene_inst_capacity * sizeof(struct mesh *));
   2643 					g_transforms.pos_x = realloc(g_transforms.pos_x, scene_inst_capacity * sizeof(float));
   2644 					g_transforms.pos_y = realloc(g_transforms.pos_y, scene_inst_capacity * sizeof(float));
   2645 					g_transforms.pos_z = realloc(g_transforms.pos_z, scene_inst_capacity * sizeof(float));
   2646 					g_transforms.rot_qx = realloc(g_transforms.rot_qx, scene_inst_capacity * sizeof(float));
   2647 					g_transforms.rot_qy = realloc(g_transforms.rot_qy, scene_inst_capacity * sizeof(float));
   2648 					g_transforms.rot_qz = realloc(g_transforms.rot_qz, scene_inst_capacity * sizeof(float));
   2649 					g_transforms.rot_qw = realloc(g_transforms.rot_qw, scene_inst_capacity * sizeof(float));
   2650 					g_transforms.world_matrices = realloc(g_transforms.world_matrices, scene_inst_capacity * sizeof(struct mat4));
   2651 					g_transforms.sphere_cx = realloc(g_transforms.sphere_cx, scene_inst_capacity * sizeof(float));
   2652 					g_transforms.sphere_cy = realloc(g_transforms.sphere_cy, scene_inst_capacity * sizeof(float));
   2653 					g_transforms.sphere_cz = realloc(g_transforms.sphere_cz, scene_inst_capacity * sizeof(float));
   2654 					g_transforms.sphere_r = realloc(g_transforms.sphere_r, scene_inst_capacity * sizeof(float));
   2655 					g_transforms.time_on = realloc(g_transforms.time_on, scene_inst_capacity * sizeof(int16_t));
   2656 					g_transforms.time_off = realloc(g_transforms.time_off, scene_inst_capacity * sizeof(int16_t));
   2657 				}
   2658 
   2659 				m = cache_get_mesh(cache, name);
   2660 				if (m) {
   2661 					idx = scene_inst_count++;
   2662 					scene_meshes[idx] = m;
   2663 					g_transforms.pos_x[idx] = px;
   2664 					g_transforms.pos_y[idx] = py;
   2665 					g_transforms.pos_z[idx] = pz;
   2666 					g_transforms.rot_qx[idx] = qx;
   2667 					g_transforms.rot_qy[idx] = qy;
   2668 					g_transforms.rot_qz[idx] = qz;
   2669 					g_transforms.rot_qw[idx] = qw;
   2670 					
   2671 					g_transforms.time_on[idx] = (time_on >= 0) ? time_on : 0;
   2672 					g_transforms.time_off[idx] = (time_off >= 0) ? time_off : 0;
   2673 
   2674 					mat_from_quat(&rot, qx, qy, qz, qw);
   2675 					mat_translate(&trans, px, py, pz);
   2676 					mat_mul(&g_transforms.world_matrices[idx], &trans, &rot);
   2677 
   2678 					memset(&sa2gl, 0, sizeof(sa2gl));
   2679 					sa2gl.m[0][0] = sa2gl.m[1][2] = sa2gl.m[2][1] = sa2gl.m[3][3] = 1.0f;
   2680 					mat_mul(&g_transforms.world_matrices[idx], &sa2gl, &g_transforms.world_matrices[idx]);
   2681 
   2682 					mat_transform(&wc, &w, &g_transforms.world_matrices[idx], &(struct vec3){m->spr_x, m->spr_y, m->spr_z});
   2683 					g_transforms.sphere_cx[idx] = wc.x;
   2684 					g_transforms.sphere_cy[idx] = wc.y;
   2685 					g_transforms.sphere_cz[idx] = wc.z;
   2686 					g_transforms.sphere_r[idx] = m->spr_r;
   2687 
   2688 					gx = (int)((wc.x - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2689 					gz = (int)((wc.z - MAP_MIN) / ((MAP_MAX - MAP_MIN) / GRID_SZ));
   2690 					if (gx < 0) gx = 0; if (gx >= GRID_SZ) gx = GRID_SZ - 1;
   2691 					if (gz < 0) gz = 0; if (gz >= GRID_SZ) gz = GRID_SZ - 1;
   2692 
   2693 					c = &scene_grid[gx][gz];
   2694 					if (c->count >= c->cap) {
   2695 						c->cap = c->cap == 0 ? 16 : c->cap * 2;
   2696 						c->ids = realloc(c->ids, c->cap * sizeof(int));
   2697 					}
   2698 					c->ids[c->count++] = idx;
   2699 				}
   2700 			}
   2701 		}
   2702 		line = next_line;
   2703 	}
   2704 	free(buf);
   2705 }
   2706 
   2707 int
   2708 main(int argc, char *argv[])
   2709 {
   2710 	struct sys_gfx g;
   2711 	struct mat4 view;
   2712 	struct timespec ts, t_start, t_end;
   2713 	XEvent sa_event;
   2714 	KeySym sym;
   2715 	float player_x = 2490.0f, player_y = 13.5f, player_z = -1660.0f;
   2716 	float player_vy = 0.0f;
   2717 	float player_yaw = 0.0f;
   2718 	float cam_x, cam_y, cam_z;
   2719 	float cam_yaw = -1.57f, cam_pitch = 0.2f, cam_dist = 3.5f;
   2720 	float move_forward, move_strafe, move_x, move_z, move_len;
   2721 	float speed, ground_y, dt, net_timer = 0.0f;
   2722 	int running, tar_fd, m_dx, m_dy, gz, gx, last_mx, last_my, i;
   2723 	int is_grounded = 0;
   2724 	struct stat st;
   2725 	size_t ipl_sz = 0, water_sz = 0, tc_sz = 0, col_sz = 0;
   2726 	const uint8_t *ipl_data, *water_data, *tc_data, *col_data;
   2727 	char srv_ip[64] = "127.0.0.1";
   2728 	int srv_port = NET_PORT;
   2729 	char nick[24] = "player";
   2730 	char *colon;
   2731 	KeyCode code;
   2732 
   2733 	if (argc < 3) {
   2734 		fprintf(stderr, "usage: %s <ip:port> <nick>\n", argv[0]);
   2735 		return (1);
   2736 	}
   2737 
   2738 	strncpy(srv_ip, argv[1], sizeof(srv_ip) - 1);
   2739 	srv_ip[sizeof(srv_ip) - 1] = '\0';
   2740 	colon = strchr(srv_ip, ':');
   2741 	if (colon) {
   2742 		*colon = '\0';
   2743 		srv_port = atoi(colon + 1);
   2744 	}
   2745 
   2746 	strncpy(nick, argv[2], sizeof(nick) - 1);
   2747 	nick[sizeof(nick) - 1] = '\0';
   2748 
   2749 	g_sys = &g;
   2750 	gfx_init(&g);
   2751 	g_cache = calloc(1, sizeof(struct asset_cache));
   2752 	g.game_time_sec = 0.0f;
   2753 	g.game_time_hours = 12.0f;
   2754 	ts.tv_sec = 0;
   2755 	ts.tv_nsec = 16666666;
   2756 
   2757 	tar_fd = open("assets.tar", O_RDONLY);
   2758 	if (tar_fd < 0) {
   2759 		err(1, "failed to open assets.tar");
   2760 	}
   2761 	fstat(tar_fd, &st);
   2762 	g_tar_size = st.st_size;
   2763 	g_tar_mapped = mmap(NULL, g_tar_size, PROT_READ, MAP_PRIVATE, tar_fd, 0);
   2764 	if (g_tar_mapped == MAP_FAILED) {
   2765 		err(1, "failed to mmap assets.tar");
   2766 	}
   2767 
   2768 	tar_build_index();
   2769 
   2770 	ipl_data = tar_lookup("assets/map.ipl", &ipl_sz);
   2771 	if (ipl_data) {
   2772 		scene_load(g_cache, ipl_data, ipl_sz);
   2773 	}
   2774 
   2775 	water_data = tar_lookup("assets/water.bin", &water_sz);
   2776 	if (water_data && water_sz > 0) {
   2777 		memcpy(&water_count, water_data, 4);
   2778 		water_faces = malloc(water_count * sizeof(struct water_face));
   2779 		memcpy(water_faces, water_data + 4, water_count * sizeof(struct water_face));
   2780 	}
   2781 
   2782 	tc_data = tar_lookup("assets/timecyc.bin", &tc_sz);
   2783 	if (tc_data && tc_sz > 0) {
   2784 		memcpy(&g.num_weathers, tc_data, 4);
   2785 		if (g.num_weathers > 32) {
   2786 			g.num_weathers = 32;
   2787 		}
   2788 		memcpy(g.weathers, tc_data + 4, g.num_weathers * 8 * sizeof(struct timecyc_entry));
   2789 	}
   2790 
   2791 	col_data = tar_lookup("assets/collision.bin", &col_sz);
   2792 	if (col_data && col_sz > 0) {
   2793 		const uint8_t *ptr = col_data;
   2794 		for (gz = 0; gz < GRID_SZ; gz++) {
   2795 			for (gx = 0; gx < GRID_SZ; gx++) {
   2796 				uint32_t cnt;
   2797 				memcpy(&cnt, ptr, sizeof(uint32_t));
   2798 				ptr += sizeof(uint32_t);
   2799 				g_col_grid[gx][gz].count = cnt;
   2800 				if (cnt > 0) {
   2801 					g_col_grid[gx][gz].tris = (const struct col_triangle *)ptr;
   2802 					ptr += cnt * sizeof(struct col_triangle);
   2803 				} else {
   2804 					g_col_grid[gx][gz].tris = NULL;
   2805 				}
   2806 			}
   2807 		}
   2808 	}
   2809 
   2810 	water_tex = cache_get_tex(g_cache, "waterclear256");
   2811 	sand_tex = cache_get_tex(g_cache, "sand256");
   2812 
   2813 	net_init(srv_ip, srv_port, nick);
   2814 
   2815 	XMapWindow(g.dpy, g.win);
   2816 	clock_gettime(CLOCK_MONOTONIC, &t_start);
   2817 	XWarpPointer(g.dpy, None, g.win, 0, 0, 0, 0, WIDTH / 2, HEIGHT / 2);
   2818 	XGrabPointer(g.dpy, g.win, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
   2819 	    GrabModeAsync, GrabModeAsync, g.win, None, CurrentTime);
   2820 	XSync(g.dpy, False);
   2821 
   2822 	running = 1;
   2823 	while (running) {
   2824 		last_mx = WIDTH / 2;
   2825 		last_my = HEIGHT / 2;
   2826 		m_dx = 0;
   2827 		m_dy = 0;
   2828 
   2829 		while (XPending(g.dpy)) {
   2830 			XNextEvent(g.dpy, &sa_event);
   2831 			if (XFilterEvent(&sa_event, None)) {
   2832 				continue;
   2833 			}
   2834 			if (sa_event.type == ClientMessage &&
   2835 			    (Atom)sa_event.xclient.data.l[0] == g.wm_delete) {
   2836 				running = 0;
   2837 			}
   2838 			if (sa_event.type == FocusIn && !g.in_chat && !g.menu_open) {
   2839 				XGrabPointer(g.dpy, g.win, True,
   2840 				    PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
   2841 				    GrabModeAsync, GrabModeAsync, g.win, None, CurrentTime);
   2842 			}
   2843 			if (sa_event.type == FocusOut) {
   2844 				memset(g.keys, 0, sizeof(g.keys));
   2845 			}
   2846 			if (sa_event.type == MotionNotify && !g.menu_open) {
   2847 				last_mx = sa_event.xmotion.x;
   2848 				last_my = sa_event.xmotion.y;
   2849 			}
   2850 			if (sa_event.type == KeyPress) {
   2851 				code = sa_event.xkey.keycode;
   2852 				sym = XLookupKeysym(&sa_event.xkey, 0);
   2853 
   2854 				if (code == g.key_esc || sym == XK_Escape) {
   2855 					if (g.in_chat) {
   2856 						g.in_chat = 0;
   2857 						XGrabPointer(g.dpy, g.win, True,
   2858 						    PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
   2859 						    GrabModeAsync, GrabModeAsync, g.win, None, CurrentTime);
   2860 					} else {
   2861 						g.menu_open = !g.menu_open;
   2862 						if (g.menu_open) {
   2863 							XUngrabPointer(g.dpy, CurrentTime);
   2864 							memset(g.keys, 0, sizeof(g.keys));
   2865 						} else {
   2866 							XWarpPointer(g.dpy, None, g.win, 0, 0, 0, 0,
   2867 							    WIDTH / 2, HEIGHT / 2);
   2868 							XGrabPointer(g.dpy, g.win, True,
   2869 							    PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
   2870 							    GrabModeAsync, GrabModeAsync, g.win, None, CurrentTime);
   2871 						}
   2872 					}
   2873 				} else if (sym == XK_F5) {
   2874 					g.show_debug = !g.show_debug;
   2875 				}
   2876 
   2877 				if (g.in_chat) {
   2878 					char str[32];
   2879 					Status status;
   2880 					int n = 0;
   2881 
   2882 					if (g_sys->ic) {
   2883 						n = Xutf8LookupString(g_sys->ic, &sa_event.xkey, str,
   2884 						    sizeof(str), &sym, &status);
   2885 					} else {
   2886 						n = XLookupString(&sa_event.xkey, str, sizeof(str), &sym, NULL);
   2887 					}
   2888 
   2889 					if (sym == XK_Return) {
   2890 						if (strcmp(g.chat_buf, "/q") == 0 ||
   2891 						    strcmp(g.chat_buf, "/quit") == 0) {
   2892 							running = 0;
   2893 						} else if (strncmp(g.chat_buf, "/st ", 4) == 0) {
   2894 							g.game_time_hours = atof(g.chat_buf + 4);
   2895 						} else if (strncmp(g.chat_buf, "/sw ", 4) == 0) {
   2896 							g.game_weather = atoi(g.chat_buf + 4);
   2897 						} else if (strncmp(g.chat_buf, "/sd ", 4) == 0) {
   2898 							g.far_clip_override = atof(g.chat_buf + 4);
   2899 						} else if (strncmp(g.chat_buf, "/skin ", 6) == 0) {
   2900 							int new_id = atoi(g.chat_buf + 6);
   2901 							if (ped_lookup_model(new_id) != NULL) {
   2902 								active_skin_id = new_id;
   2903 							}
   2904 						} else if (g.chat_buf[0] != '/' && g.chat_len > 0) {
   2905 							net_send_chat(g.chat_buf);
   2906 						}
   2907 						g.in_chat = 0;
   2908 						XGrabPointer(g.dpy, g.win, True,
   2909 						    PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
   2910 						    GrabModeAsync, GrabModeAsync, g.win, None, CurrentTime);
   2911 					} else if (sym == XK_BackSpace) {
   2912 						if (g.chat_len > 0) {
   2913 							while (g.chat_len > 0) {
   2914 								g.chat_len--;
   2915 								if ((g.chat_buf[g.chat_len] & 0xC0) != 0x80) {
   2916 									break;
   2917 								}
   2918 							}
   2919 							g.chat_buf[g.chat_len] = '\0';
   2920 						}
   2921 					} else if (n > 0 && (unsigned char)str[0] >= 32 &&
   2922 					    str[0] != 127 && g.chat_len + n < 127) {
   2923 						memcpy(&g.chat_buf[g.chat_len], str, n);
   2924 						g.chat_len += n;
   2925 						g.chat_buf[g.chat_len] = '\0';
   2926 					}
   2927 				} else if (!g.menu_open) {
   2928 					if (code == g.key_w || sym == XK_w || sym == XK_W) g.keys['w'] = 1;
   2929 					else if (code == g.key_a || sym == XK_a || sym == XK_A) g.keys['a'] = 1;
   2930 					else if (code == g.key_s || sym == XK_s || sym == XK_S) g.keys['s'] = 1;
   2931 					else if (code == g.key_d || sym == XK_d || sym == XK_D) g.keys['d'] = 1;
   2932 					else if (code == g.key_space || sym == XK_space) g.keys[' '] = 1;
   2933 					else if (code == g.key_t || sym == XK_t || sym == XK_T) {
   2934 						g.in_chat = 1;
   2935 						g.chat_len = 0;
   2936 						g.chat_buf[0] = '\0';
   2937 						XUngrabPointer(g.dpy, CurrentTime);
   2938 					}
   2939 				}
   2940 			}
   2941 			if (sa_event.type == KeyRelease && !g.menu_open) {
   2942 				code = sa_event.xkey.keycode;
   2943 				sym = XLookupKeysym(&sa_event.xkey, 0);
   2944 
   2945 				if (code == g.key_w || sym == XK_w || sym == XK_W) g.keys['w'] = 0;
   2946 				else if (code == g.key_a || sym == XK_a || sym == XK_A) g.keys['a'] = 0;
   2947 				else if (code == g.key_s || sym == XK_s || sym == XK_S) g.keys['s'] = 0;
   2948 				else if (code == g.key_d || sym == XK_d || sym == XK_D) g.keys['d'] = 0;
   2949 				else if (code == g.key_space || sym == XK_space) g.keys[' '] = 0;
   2950 			}
   2951 		}
   2952 
   2953 		clock_gettime(CLOCK_MONOTONIC, &t_end);
   2954 		dt = (t_end.tv_sec - t_start.tv_sec) + (t_end.tv_nsec - t_start.tv_nsec) * 1e-9f;
   2955 		t_start = t_end;
   2956 		if (dt > 0.1f) dt = 0.1f;
   2957 		if (dt < 0.001f) dt = 0.001f;
   2958 
   2959 		double cur_time = t_end.tv_sec + t_end.tv_nsec * 1e-9;
   2960 
   2961 		g.game_time_sec += dt;
   2962 		g.game_time_hours += dt * (24.0f / 1440.0f);
   2963 		if (g.game_time_hours >= 24.0f) {
   2964 			g.game_time_hours -= 24.0f;
   2965 		}
   2966 
   2967 		for (i = 0; i < chat_log_count; i++) {
   2968 			if (chat_log[i].timer > 0.0f) {
   2969 				chat_log[i].timer -= dt;
   2970 			}
   2971 		}
   2972 
   2973 		net_poll(&g, cur_time);
   2974 		net_interpolate(cur_time);
   2975 
   2976 		net_timer += dt;
   2977 		if (net_timer >= 0.033f) {
   2978 			net_send_sync(player_x, player_y, player_z, player_yaw);
   2979 			net_timer = 0.0f;
   2980 		}
   2981 
   2982 		g.stats_timer += dt;
   2983 		if (g.stats_timer >= 1.0f) {
   2984 			g.pkts_in_sec = g.pkts_in;
   2985 			g.pkts_out_sec = g.pkts_out;
   2986 			g.pkts_in = 0;
   2987 			g.pkts_out = 0;
   2988 			g.stats_timer = 0.0f;
   2989 		}
   2990 		g.fps = g.fps * 0.90f + (1.0f / dt) * 0.10f;
   2991 
   2992 		move_forward = 0.0f;
   2993 		move_strafe = 0.0f;
   2994 
   2995 		if (!g.in_chat && !g.menu_open) {
   2996 			m_dx = last_mx - WIDTH / 2;
   2997 			m_dy = last_my - HEIGHT / 2;
   2998 			if (m_dx != 0 || m_dy != 0) {
   2999 				XWarpPointer(g.dpy, None, g.win, 0, 0, 0, 0, WIDTH / 2, HEIGHT / 2);
   3000 				XFlush(g.dpy);
   3001 			}
   3002 
   3003 			cam_yaw += m_dx * 0.003f;
   3004 			cam_pitch -= m_dy * 0.003f;
   3005 			if (cam_pitch > 1.2f) {
   3006 				cam_pitch = 1.2f;
   3007 			}
   3008 			if (cam_pitch < -1.2f) {
   3009 				cam_pitch = -1.2f;
   3010 			}
   3011 
   3012 			if (g.keys['w']) move_forward += 1.0f;
   3013 			if (g.keys['s']) move_forward -= 1.0f;
   3014 			if (g.keys['d']) move_strafe += 1.0f;
   3015 			if (g.keys['a']) move_strafe -= 1.0f;
   3016 		}
   3017 
   3018 		move_x = sinf(cam_yaw) * move_forward + cosf(cam_yaw) * move_strafe;
   3019 		move_z = cosf(cam_yaw) * move_forward - sinf(cam_yaw) * move_strafe;
   3020 		move_len = sqrtf(move_x * move_x + move_z * move_z);
   3021 
   3022 		if (move_len > 0.001f) {
   3023 			move_x /= move_len;
   3024 			move_z /= move_len;
   3025 			player_yaw = atan2f(move_x, move_z);
   3026 			speed = 6.0f;
   3027 			move_and_slide(&player_x, player_y, &player_z,
   3028 			    move_x * speed, move_z * speed, dt);
   3029 		}
   3030 
   3031 		ground_y = get_ground_height(player_x, player_z, player_y);
   3032 
   3033 		if (ground_y > -900.0f && player_y <= ground_y + 0.1f && player_vy <= 0.0f) {
   3034 			player_y = ground_y;
   3035 			player_vy = 0.0f;
   3036 			is_grounded = 1;
   3037 		} else {
   3038 			is_grounded = 0;
   3039 		}
   3040 
   3041 		if (g.keys[' '] && is_grounded && !g.in_chat && !g.menu_open) {
   3042 			player_vy = JUMP_FORCE;
   3043 			player_y += 0.05f;
   3044 			is_grounded = 0;
   3045 		}
   3046 
   3047 		if (!is_grounded) {
   3048 			player_vy -= GRAVITY * dt;
   3049 			if (player_vy < -TERMINAL_VEL) {
   3050 				player_vy = -TERMINAL_VEL;
   3051 			}
   3052 
   3053 			if (player_vy > 0.0f) {
   3054 				float ceil_y = get_ceiling_height(player_x, player_z, player_y);
   3055 				if (ceil_y < 900.0f && (player_y + 1.85f + player_vy * dt) >= ceil_y) {
   3056 					player_y = ceil_y - 1.85f;
   3057 					player_vy = 0.0f;
   3058 				} else {
   3059 					player_y += player_vy * dt;
   3060 				}
   3061 			} else {
   3062 				player_y += player_vy * dt;
   3063 			}
   3064 
   3065 			if (player_vy <= 0.0f && ground_y > -900.0f && player_y <= ground_y) {
   3066 				player_y = ground_y;
   3067 				player_vy = 0.0f;
   3068 				is_grounded = 1;
   3069 			}
   3070 		}
   3071 
   3072 		cam_x = player_x - sinf(cam_yaw) * cosf(cam_pitch) * cam_dist;
   3073 		cam_y = player_y + 1.2f - sinf(cam_pitch) * cam_dist;
   3074 		cam_z = player_z - cosf(cam_yaw) * cosf(cam_pitch) * cam_dist;
   3075 
   3076 		update_weather(&g);
   3077 		mat_projection(&g.proj, 60.0f, (float)WIDTH / HEIGHT, 0.1f, g.cur_weather.far_clp);
   3078 		memset(g.zbuffer, 0, WIDTH * HEIGHT * sizeof(float));
   3079 
   3080 		mat_view(&view, cam_x, cam_y, cam_z, cam_yaw, cam_pitch);
   3081 		draw_scene(&g, &g.proj, &view, cam_x, cam_y, cam_z,
   3082 		    player_x, player_y, player_z, player_yaw);
   3083 		draw_water(&g.proj, &view);
   3084 		draw_infinite_ocean(&g.proj, &view, cam_x, cam_z, g.game_time_sec);
   3085 		gfx_present(&g, player_x, player_y, player_z);
   3086 	}
   3087 
   3088 	net_send_leave();
   3089 	munmap(g_tar_mapped, g_tar_size);
   3090 	close(tar_fd);
   3091 	gfx_cleanup(&g);
   3092 	return (0);
   3093 }