about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/base/system.c25
-rw-r--r--src/base/system.h2
-rw-r--r--src/engine/client/ec_client.c2
-rw-r--r--src/engine/client/ec_gfx.c101
-rw-r--r--src/engine/e_config_variables.h1
-rw-r--r--src/engine/e_huffman.c507
-rw-r--r--src/engine/e_huffman.h106
-rw-r--r--src/engine/e_if_gfx.h16
-rw-r--r--src/engine/e_network.c57
-rw-r--r--src/engine/server/es_server.c3
-rw-r--r--src/game/client/gc_render.cpp40
-rw-r--r--src/game/g_variables.hpp1
12 files changed, 420 insertions, 441 deletions
diff --git a/src/base/system.c b/src/base/system.c
index 1ac5f296..bb23a5e5 100644
--- a/src/base/system.c
+++ b/src/base/system.c
@@ -479,6 +479,7 @@ static void sockaddr_to_netaddr(const struct sockaddr *src, NETADDR *dst)
 {
 	/* TODO: IPv6 support */
 	unsigned int ip = htonl(((struct sockaddr_in*)src)->sin_addr.s_addr);
+	mem_zero(dst, sizeof(NETADDR));
 	dst->type = NETTYPE_IPV4;
 	dst->port = htons(((struct sockaddr_in*)src)->sin_port);
 	dst->ip[0] = (unsigned char)((ip>>24)&0xFF);
@@ -492,6 +493,21 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b)
 	return mem_comp(a, b, sizeof(NETADDR));
 }
 
+void net_addr_str(const NETADDR *addr, char *string, int max_length)
+{
+	if(addr->type == NETTYPE_IPV4)
+		str_format(string, max_length, "%d.%d.%d.%d:%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3], addr->port);
+	else if(addr->type == NETTYPE_IPV6)
+	{
+		str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
+			(addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7],
+			(addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15],
+			addr->port);
+	}
+	else
+		str_format(string, max_length, "unknown type %d", addr->type);
+}
+
 int net_host_lookup(const char *hostname, NETADDR *addr, int types)
 {
 	/* TODO: IPv6 support */
@@ -554,7 +570,16 @@ int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size
 	netaddr_to_sockaddr(addr, &sa);
 	d = sendto((int)sock, (const char*)data, size, 0, &sa, sizeof(sa));
 	if(d < 0)
+	{
+		char addrstr[256];
+		net_addr_str(addr, addrstr, sizeof(addrstr));
+		
 		dbg_msg("net", "sendto error %d %x", d, d);
+		dbg_msg("net", "\tsock = %d %x", sock, sock);
+		dbg_msg("net", "\tsize = %d %x", size, size);
+		dbg_msg("net", "\taddr = %s", addrstr);
+
+	}
 	network_stats.sent_bytes += size;
 	network_stats.sent_packets++;
 	return d;
diff --git a/src/base/system.h b/src/base/system.h
index 4449907c..abb20b42 100644
--- a/src/base/system.h
+++ b/src/base/system.h
@@ -478,7 +478,7 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b);
 		- The string will always be zero terminated
 
 */
-int net_addr_str(const NETADDR *addr, char *string, int max_length);
+void net_addr_str(const NETADDR *addr, char *string, int max_length);
 
 /* Group: Network UDP */
 
diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c
index 5f213ac6..268e82b0 100644
--- a/src/engine/client/ec_client.c
+++ b/src/engine/client/ec_client.c
@@ -297,7 +297,7 @@ int client_send_msg()
 		packet.flags = NETSENDFLAG_VITAL;
 	if(info->flags&MSGFLAG_FLUSH)
 		packet.flags = NETSENDFLAG_FLUSH;
-	
+
 	netclient_send(net, &packet);
 	return 0;
 }
diff --git a/src/engine/client/ec_gfx.c b/src/engine/client/ec_gfx.c
index 4f258d11..7b12e15d 100644
--- a/src/engine/client/ec_gfx.c
+++ b/src/engine/client/ec_gfx.c
@@ -168,7 +168,7 @@ int gfx_init()
 	/* open window */	
 	if(config.gfx_fullscreen)
 	{
-		int result = glfwOpenWindow(screen_width, screen_height, 8, 8, 8, 0, 24, 0, GLFW_FULLSCREEN);
+		int result = glfwOpenWindow(screen_width, screen_height, 8, 8, 8, config.gfx_alphabits, 24, 0, GLFW_FULLSCREEN);
 		if(result != GL_TRUE)
 		{
 			dbg_msg("game", "failed to create gl context");
@@ -177,7 +177,7 @@ int gfx_init()
 	}
 	else
 	{
-		int result = glfwOpenWindow(screen_width, screen_height, 0, 0, 0, 0, 24, 0, GLFW_WINDOW);
+		int result = glfwOpenWindow(screen_width, screen_height, 0, 0, 0, 8, 24, 0, GLFW_WINDOW);
 		if(result != GL_TRUE)
 		{
 			dbg_msg("game", "failed to create gl context");
@@ -600,52 +600,27 @@ void gfx_swap()
 	
 	if(do_screenshot)
 	{
-		/* fetch image data */
-		int y;
-		int w = screen_width;
-		int h = screen_height;
-		unsigned char *pixel_data = (unsigned char *)mem_alloc(w*(h+1)*3, 1);
-		unsigned char *temp_row = pixel_data+w*h*3;
-		glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixel_data);
-		
-		/* flip the pixel because opengl works from bottom left corner */
-		for(y = 0; y < h/2; y++)
-		{
-			mem_copy(temp_row, pixel_data+y*w*3, w*3);
-			mem_copy(pixel_data+y*w*3, pixel_data+(h-y-1)*w*3, w*3);
-			mem_copy(pixel_data+(h-y-1)*w*3, temp_row,w*3);
-		}
-		
 		/* find filename */
-		{
-			char wholepath[1024];
-			char filename[128];
-			static int index = 1;
-			png_t png;
+		char wholepath[1024];
+		char filename[128];
+		static int index = 1;
 
-			for(; index < 1000; index++)
-			{
-				IOHANDLE io;
-				sprintf(filename, "screenshots/screenshot%04d.png", index);
-				engine_savepath(filename, wholepath, sizeof(wholepath));
-				
-				io = io_open(wholepath, IOFLAG_READ);
-				if(io)
-					io_close(io);
-				else
-					break;
-			}
-		
-			/* save png */
-			dbg_msg("client", "saved screenshot to '%s'", wholepath);
-			png_open_file_write(&png, wholepath);
-			png_set_data(&png, w, h, 8, PNG_TRUECOLOR, (unsigned char *)pixel_data);
-			png_close_file(&png);
+		for(; index < 1000; index++)
+		{
+			IOHANDLE io;
+			sprintf(filename, "screenshots/screenshot%04d.png", index);
+			engine_savepath(filename, wholepath, sizeof(wholepath));
+			
+			io = io_open(wholepath, IOFLAG_READ);
+			if(io)
+				io_close(io);
+			else
+				break;
 		}
 
-		/* clean up */
-		mem_free(pixel_data);
-		do_screenshot = 0;
+		gfx_screenshot_direct(filename);
+	
+		do_screenshot = 0;	
 	}
 	
 	{
@@ -666,6 +641,42 @@ void gfx_swap()
 	}
 }
 
+void gfx_screenshot_direct(const char *filename)
+{
+	/* fetch image data */
+	int y;
+	int w = screen_width;
+	int h = screen_height;
+	unsigned char *pixel_data = (unsigned char *)mem_alloc(w*(h+1)*4, 1);
+	unsigned char *temp_row = pixel_data+w*h*4;
+	glReadPixels(0,0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data);
+	
+	/* flip the pixel because opengl works from bottom left corner */
+	for(y = 0; y < h/2; y++)
+	{
+		mem_copy(temp_row, pixel_data+y*w*4, w*4);
+		mem_copy(pixel_data+y*w*4, pixel_data+(h-y-1)*w*4, w*4);
+		mem_copy(pixel_data+(h-y-1)*w*4, temp_row,w*4);
+	}
+	
+	/* find filename */
+	{
+		char wholepath[1024];
+		png_t png;
+
+		engine_savepath(filename, wholepath, sizeof(wholepath));
+	
+		/* save png */
+		dbg_msg("client", "saved screenshot to '%s'", wholepath);
+		png_open_file_write(&png, wholepath);
+		png_set_data(&png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pixel_data);
+		png_close_file(&png);
+	}
+
+	/* clean up */
+	mem_free(pixel_data);
+}
+
 int gfx_screenwidth()
 {
 	return screen_width;
@@ -690,7 +701,7 @@ void gfx_texture_set(int slot)
 
 void gfx_clear(float r, float g, float b)
 {
-	glClearColor(r,g,b,1.0f);
+	glClearColor(r,g,b,0.0f);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 }
 
diff --git a/src/engine/e_config_variables.h b/src/engine/e_config_variables.h
index 3707f0e6..8396aa88 100644
--- a/src/engine/e_config_variables.h
+++ b/src/engine/e_config_variables.h
@@ -35,6 +35,7 @@ MACRO_CONFIG_INT(snd_nonactive_mute, 0, 0, 1)
 MACRO_CONFIG_INT(gfx_screen_width, 800, 0, 0)
 MACRO_CONFIG_INT(gfx_screen_height, 600, 0, 0)
 MACRO_CONFIG_INT(gfx_fullscreen, 1, 0, 1)
+MACRO_CONFIG_INT(gfx_alphabits, 0, 0, 0)
 MACRO_CONFIG_INT(gfx_color_depth, 24, 16, 24)
 MACRO_CONFIG_INT(gfx_clear, 0, 0, 1)
 MACRO_CONFIG_INT(gfx_vsync, 1, 0, 1)
diff --git a/src/engine/e_huffman.c b/src/engine/e_huffman.c
index dfb5c817..8adbb1f7 100644
--- a/src/engine/e_huffman.c
+++ b/src/engine/e_huffman.c
@@ -1,383 +1,262 @@
-#include <base/system.h>
-#include <stdlib.h>
-#include <string.h>
-#include <engine/e_huffman.h>
+#include <stdlib.h> /* qsort */
+#include <memory.h> /* memset */
+#include "e_huffman.h"
 
-void huffman_init(HUFFSTATE *huff)
+typedef struct HUFFMAN_CONSTRUCT_NODE
 {
-	mem_zero(huff, sizeof(HUFFSTATE));
-	huff->nodes[0].frequency = 1;
-	huff->nodes[0].symbol_size = -1;
-	huff->num_symbols++;
-	huff->num_nodes++;
-}
-
-void huffman_add_symbol(HUFFSTATE *huff, int frequency, int size, unsigned char *symbol)
-{
-	huff->nodes[huff->num_nodes].frequency = frequency;
-	huff->nodes[huff->num_nodes].symbol_size = size;
-	mem_copy(huff->nodes[huff->num_nodes].symbol, symbol, size);
-	huff->num_nodes++;
-	huff->num_symbols++;
-}
-
+	unsigned short node_id;
+ 	int frequency;
+} HUFFMAN_CONSTRUCT_NODE;
 
 static int sort_func(const void *a, const void *b)
 {
-	if((*(HUFFNODE **)a)->frequency > (*(HUFFNODE **)b)->frequency)
+	if((*(HUFFMAN_CONSTRUCT_NODE **)a)->frequency > (*(HUFFMAN_CONSTRUCT_NODE **)b)->frequency)
 		return -1;
-	if((*(HUFFNODE **)a)->frequency < (*(HUFFNODE **)b)->frequency)
+	if((*(HUFFMAN_CONSTRUCT_NODE **)a)->frequency < (*(HUFFMAN_CONSTRUCT_NODE **)b)->frequency)
 		return 1;
 	return 0;
 }
 
-void huffman_setbits_r(HUFFNODE *node, int bits, int depth)
+static void huffman_setbits_r(HUFFMAN_STATE *huff, HUFFMAN_NODE *node, int bits, int depth)
 {
-	if(node->one)
-		huffman_setbits_r(node->one, (bits<<1)|1, depth+1);
-	if(node->zero)
-		huffman_setbits_r(node->zero, (bits<<1), depth+1);
+	if(node->leafs[1] != 0xffff)
+		huffman_setbits_r(huff, &huff->nodes[node->leafs[1]], bits|(1<<depth), depth+1);
+	if(node->leafs[0] != 0xffff)
+		huffman_setbits_r(huff, &huff->nodes[node->leafs[0]], bits, depth+1);
 		
-	if(node->symbol_size)
+	if(node->num_bits)
 	{
 		node->bits = bits;
 		node->num_bits = depth;
 	}
 }
-	
-void huffman_checktree_r(HUFFNODE *node, int bits, int depth)
+
+static void huffman_construct_tree(HUFFMAN_STATE *huff, const unsigned *frequencies)
 {
-	if(node->one)
-		huffman_checktree_r(node->one, (bits<<1)|1, depth+1);
-	if(node->zero)
-		huffman_checktree_r(node->zero, (bits<<1), depth+1);
-		
-	if(node->symbol_size)
+	HUFFMAN_CONSTRUCT_NODE nodes_left_storage[HUFFMAN_MAX_NODES];
+	HUFFMAN_CONSTRUCT_NODE *nodes_left[HUFFMAN_MAX_NODES];
+	int num_nodes_left = HUFFMAN_MAX_SYMBOLS;
+	int i;
+
+	/* add the symbols */
+	for(i = 0; i < HUFFMAN_MAX_SYMBOLS; i++)
 	{
-		/*dbg_msg("", "%p %p %d %d %d", node->one, node->zero, node->symbol[0], node->bits, node->num_bits);*/
-		
-		if(node->bits != bits || node->num_bits != depth)
-		{
-			dbg_msg("", "crap!   %d %d=%d   %d!=%d", node->bits>>1, node->bits, bits, node->num_bits , depth);
-			/*dbg_msg("", "%p %p %d", node->one, node->zero, node->symbol[0]);*/
-		}
-	}
-}
+		huff->nodes[i].num_bits = -1;
+		huff->nodes[i].symbol = i;
+		huff->nodes[i].leafs[0] = -1;
+		huff->nodes[i].leafs[1] = -1;
 
-void huffman_construct_tree(HUFFSTATE *huff)
-{
-	HUFFNODE *nodes_left[MAX_NODES];
-	int num_nodes_left = huff->num_nodes;
-	int i, k;
+		if(i == HUFFMAN_EOF_SYMBOL)
+			nodes_left_storage[i].frequency = 1;
+		else
+			nodes_left_storage[i].frequency = frequencies[i];
+		nodes_left_storage[i].node_id = i;
+		nodes_left[i] = &nodes_left_storage[i];
+	}
 
-	for(i = 0; i < num_nodes_left; i++)
-		nodes_left[i] = &huff->nodes[i];
+	huff->num_nodes = HUFFMAN_MAX_SYMBOLS;
 	
 	/* construct the table */
 	while(num_nodes_left > 1)
 	{
-		qsort(nodes_left, num_nodes_left, sizeof(HUFFNODE *), sort_func);
+		qsort(nodes_left, num_nodes_left, sizeof(HUFFMAN_CONSTRUCT_NODE *), sort_func);
 		
-		huff->nodes[huff->num_nodes].symbol_size = 0;
-		huff->nodes[huff->num_nodes].frequency = nodes_left[num_nodes_left-1]->frequency + nodes_left[num_nodes_left-2]->frequency;
-		huff->nodes[huff->num_nodes].zero = nodes_left[num_nodes_left-1];
-		huff->nodes[huff->num_nodes].one = nodes_left[num_nodes_left-2];
-		nodes_left[num_nodes_left-1]->parent = &huff->nodes[huff->num_nodes];
-		nodes_left[num_nodes_left-2]->parent = &huff->nodes[huff->num_nodes];
-		nodes_left[num_nodes_left-2] = &huff->nodes[huff->num_nodes];
+		huff->nodes[huff->num_nodes].num_bits = 0;
+		huff->nodes[huff->num_nodes].leafs[0] = nodes_left[num_nodes_left-1]->node_id;
+		huff->nodes[huff->num_nodes].leafs[1] = nodes_left[num_nodes_left-2]->node_id;
+		nodes_left[num_nodes_left-2]->node_id = huff->num_nodes;
+		nodes_left[num_nodes_left-2]->frequency = nodes_left[num_nodes_left-1]->frequency + nodes_left[num_nodes_left-2]->frequency;
 		huff->num_nodes++;
 		num_nodes_left--;
 	}
 
-	dbg_msg("", "%d", huff->num_nodes);
-	for(i = 0; i < huff->num_nodes; i++)
-	{
-		if(huff->nodes[i].symbol_size && (huff->nodes[i].one || huff->nodes[i].zero))
-			dbg_msg("", "tree strangeness");
-			
-		if(!huff->nodes[i].parent)
-		{
-			dbg_msg("", "root %p %p", huff->nodes[i].one, huff->nodes[i].zero);
-			huff->start_node = &huff->nodes[i];
-		}
-	}
+	/* set start node */
+	huff->start_node = &huff->nodes[huff->num_nodes-1];
 	
-	huffman_setbits_r(huff->start_node, 0, 0);
-	
-	/*
-	for(i = 0; i < huff->num_symbols; i++)
-	{
-		unsigned bits = 0;
-		int num_bits = 0;
-		HUFFNODE *n = &huff->nodes[i];
-		HUFFNODE *p = n;
-		HUFFNODE *c = n->parent;
-		
-		while(c)
-		{
-			num_bits++;
-			if(c->one == p)
-				bits |= 1;
-			bits <<= 1;
-			p = c;
-			c = c->parent;
-		}
+	/* build symbol bits */
+	huffman_setbits_r(huff, huff->start_node, 0, 0);
+}
 
-		n->bits = bits;
-		n->num_bits = num_bits;
-	}*/
-	
-	huffman_checktree_r(huff->start_node, 0, 0);
+void huffman_init(HUFFMAN_STATE *huff, const unsigned *frequencies)
+{
+	int i;
 
-	for(i = 0; i < huff->num_symbols; i++)
+	/* make sure to cleanout every thing */
+	memset(huff, 0, sizeof(HUFFMAN_STATE));
+
+	/* construct the tree */
+	huffman_construct_tree(huff, frequencies);
+
+	/* build decode LUT */
+	for(i = 0; i < HUFFMAN_LUTSIZE; i++)
 	{
-		for(k = 0; k < huff->num_symbols; k++)
+		unsigned bits = i;
+		int k;
+		HUFFMAN_NODE *node = huff->start_node;
+		for(k = 0; k < HUFFMAN_LUTBITS; k++)
 		{
-			if(k == i)
-				continue;
-			if(huff->nodes[i].num_bits == huff->nodes[k].num_bits && huff->nodes[i].bits == huff->nodes[k].bits)
-				dbg_msg("", "tree error %d %d %d", i, k, huff->nodes[i].num_bits);
-		}
-	}
+			node = &huff->nodes[node->leafs[bits&1]];
+			bits >>= 1;
 
-}
+			if(!node)
+				break;
 
-typedef struct
-{
-	unsigned char *data;
-	unsigned char current_bits;
-	int num;
-} HUFFBITIO;
+			if(node->num_bits)
+			{
+				huff->decode_lut[i] = node;
+				break;
+			}
+		}
 
-int debug_count = 0;
+		if(k == HUFFMAN_LUTBITS)
+			huff->decode_lut[i] = node;
+	}
 
-static void bitio_init(HUFFBITIO *bitio, unsigned char *data)
-{
-	bitio->data = data;
-	bitio->num = 0;
-	bitio->current_bits = 0;
 }
 
-static void bitio_flush(HUFFBITIO *bitio)
+/*****************************************************************/
+int huffman_compress(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size)
 {
-	if(bitio->num == 8)
-		*bitio->data = bitio->current_bits << (8-bitio->num);
-	else
-		*bitio->data = bitio->current_bits;
-	bitio->data++;
-	bitio->num = 0;
-	bitio->current_bits = 0;
-}
+	/* this macro loads a symbol for a byte into bits and bitcount */
+#define HUFFMAN_MACRO_LOADSYMBOL(sym) \
+	bits |= huff->nodes[sym].bits << bitcount; \
+	bitcount += huff->nodes[sym].num_bits;
 
-static void bitio_write(HUFFBITIO *bitio, int bit)
-{
-	bitio->current_bits = (bitio->current_bits<<1)|bit;
-	bitio->num++;
-	if(bitio->num == 8)
-		bitio_flush(bitio);
-		
-	if(debug_count)
-	{
-		debug_count--;
-		dbg_msg("", "out %d", bit);
+	/* this macro writes the symbol stored in bits and bitcount to the dst pointer */
+#define HUFFMAN_MACRO_WRITE() \
+	while(bitcount >= 8) \
+	{ \
+		*dst++ = (unsigned char)(bits&0xff); \
+		if(dst == dst_end) \
+			return -1; \
+		bits >>= 8; \
+		bitcount -= 8; \
 	}
-}
 
-static int bitio_read(HUFFBITIO *bitio)
-{
-	int bit;
-	
-	if(!bitio->num)
-	{
-		bitio->current_bits = *bitio->data;
-		bitio->data++;
-		bitio->num = 8;
-	}
-	
-	bitio->num--;
-	bit = (bitio->current_bits>>bitio->num)&1;
+	/* setup buffer pointers */
+	const unsigned char *src = (const unsigned char *)input;
+	const unsigned char *src_end = src + input_size;
+	unsigned char *dst = (unsigned char *)output;
+	unsigned char *dst_end = dst + output_size;
 
-	if(debug_count)
-	{
-		debug_count--;
-		dbg_msg("", "in %d", bit);
-	}
-	return bit;
-}
+	/* symbol variables */
+	unsigned bits = 0;
+	unsigned bitcount = 0;
 
-int huffman_compress(HUFFSTATE *huff, const void *input, int input_size, void *output, int output_size)
-{
-	const unsigned char *src = (const unsigned char *)input;
-	int ret = 0;
-	int quit = 0;
-	HUFFBITIO io;
-	
-	bitio_init(&io, (unsigned char *)output);
-	
-	while(!quit)
+	/* make sure that we have data that we want to compress */
+	if(input_size)
 	{
-		int i;
-		int best_match = -1;
-		int best_match_size = 0;
-		
-		if(input_size)
-		{
-			for(i = 0; i < huff->num_symbols; i++)
-			{
-				if(huff->nodes[i].symbol_size <= input_size && huff->nodes[i].symbol_size > best_match_size)
-				{
-					if(memcmp(src, huff->nodes[i].symbol, huff->nodes[i].symbol_size) == 0)
-					{
-						best_match = i;
-						best_match_size = huff->nodes[i].symbol_size;
-					}
-				}
-			}
-		}
-		else
-		{
-			best_match = 0;
-			best_match_size = 0;
-			quit = 1;
-		}
-		
-		
-		if(best_match == -1)
+		/* {A} load the first symbol */
+		int symbol = *src++;
+
+		while(src != src_end)
 		{
-			dbg_msg("huffman", "couldn't find symbol! %d left", input_size);
-			return -1;
+			/* {B} load the symbol */
+			HUFFMAN_MACRO_LOADSYMBOL(symbol)
+
+			/* {C} fetch next symbol, this is done here because it will reduce dependency in the code */
+			symbol = *src++;
+
+			/* {B} write the symbol loaded at */
+			HUFFMAN_MACRO_WRITE()
 		}
-		
-		i = huff->nodes[best_match].num_bits;
-		for(i = huff->nodes[best_match].num_bits-1; i >= 0; i--)
-			bitio_write(&io, (huff->nodes[best_match].bits>>i)&1);
 
-		if(debug_count)		
-			dbg_msg("", "--");
-		
-		ret += huff->nodes[best_match].num_bits;
-		input_size -= best_match_size;
-		src += best_match_size;
+		/* write the last symbol loaded from {C} or {A} in the case of only 1 byte input buffer */
+		HUFFMAN_MACRO_LOADSYMBOL(symbol)
+		HUFFMAN_MACRO_WRITE()
 	}
-	
-	bitio_flush(&io);
-	return ret;
+
+	/* write EOF symbol */
+	HUFFMAN_MACRO_LOADSYMBOL(HUFFMAN_EOF_SYMBOL)
+	HUFFMAN_MACRO_WRITE()
+
+	/* write out the last bits */
+	*dst++ = bits;
+
+	/* return the size of the output */
+	return (int)(dst - (const unsigned char *)output);
+
+	/* remove macros */
+#undef HUFFMAN_MACRO_LOADSYMBOL
+#undef HUFFMAN_MACRO_WRITE
 }
 
-int huffman_decompress(HUFFSTATE *huff, const void *input, int input_size, void *output, int output_size)
+/*****************************************************************/
+int huffman_decompress(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size)
 {
+	/* setup buffer pointers */
 	unsigned char *dst = (unsigned char *)output;
-	HUFFBITIO io;
-	int size = 0;
-	
-	bitio_init(&io, (unsigned char *)input);
-	
-	while(size < 1401)
+	unsigned char *src = (unsigned char *)input;
+	unsigned char *dst_end = dst + output_size;
+	unsigned char *src_end = src + input_size;
+
+	unsigned bits = 0;
+	unsigned bitcount = 0;
+
+	HUFFMAN_NODE *eof = &huff->nodes[HUFFMAN_EOF_SYMBOL];
+	HUFFMAN_NODE *node = 0;
+
+	while(1)
 	{
-		HUFFNODE *node = huff->start_node;
-		int i;
-		
-		while(node)
+		/* {A} try to load a node now, this will reduce dependency at location {D} */
+		node = 0;
+		if(bitcount >= HUFFMAN_LUTBITS)
+			node = huff->decode_lut[bits&HUFFMAN_LUTMASK];
+
+		/* {B} fill with new bits */
+		while(bitcount < 24 && src != src_end)
 		{
-			if(node->symbol_size)
-				break;
-				
-			if(bitio_read(&io))
-				node = node->one;
-			else
-				node = node->zero;
+			bits |= (*src++) << bitcount;
+			bitcount += 8;
 		}
 
-		if(debug_count)		
-			dbg_msg("", "-- %d %d", node->bits, node->num_bits);
-		
-		/* check for eof */
-		if(node == &huff->nodes[0])
-			break;
-		
-		for(i = 0; i < node->symbol_size; i++)
+		/* {C} load symbol now if we didn't that earlier at location {A} */
+		if(!node)
+			node = huff->decode_lut[bits&HUFFMAN_LUTMASK];
+
+		/* {D} check if we hit a symbol already */
+		if(node->num_bits)
 		{
-			*dst++ = node->symbol[i];
-			size++;
+			/* remove the bits for that symbol */
+			bits >>= node->num_bits;
+			bitcount -= node->num_bits;
 		}
-	}
-	
-	return size;
-}
-
-unsigned char test_data[1024*64];
-int test_data_size;
+		else
+		{
+			/* remove the bits that the lut checked up for us */
+			bits >>= HUFFMAN_LUTBITS;
+			bitcount -= HUFFMAN_LUTBITS;
 
-unsigned char compressed_data[1024*64];
-int compressed_data_size;
+			/* walk the tree bit by bit */
+			while(1)
+			{
+				/* traverse tree */
+				node = &huff->nodes[node->leafs[bits&1]];
 
-unsigned char output_data[1024*64];
-int output_data_size;
+				/* remove bit */
+				bitcount--;
+				bits >>= 1;
 
-HUFFSTATE state;
+				/* check if we hit a symbol */
+				if(node->num_bits)
+					break;
 
-int huffman_test()
-{
-	huffman_init(&state);
-	
-	dbg_msg("", "test test");
-	
-	/* bitio testing */
-	{
-		char bits[] = {1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1,1,1,1,1,1,1,0};
-		unsigned char buf[64];
-		int i;
-		HUFFBITIO io;
-		
-		bitio_init(&io, buf);
-		for(i = 0; i < sizeof(bits); i++)
-			bitio_write(&io, bits[i]);
-			
-		bitio_flush(&io);
-		bitio_init(&io, buf);
-		for(i = 0; i < sizeof(bits); i++)
-		{
-			if(bitio_read(&io) != bits[i])
-				dbg_msg("", "bitio failed at %d", i);
-		}
-	}
-	
-	/* read test data */
-	{
-		IOHANDLE io = io_open("license.txt", IOFLAG_READ);
-		test_data_size = io_read(io, test_data, sizeof(test_data));
-		io_close(io);
-	}
-	
-	/* add symbols */
-	{
-		int counts[256] = {0};
-		int i;
-		for(i = 0; i < test_data_size; i++)
-			counts[test_data[i]]++;
-		
-		for(i = 0; i < 256; i++)
-		{
-			unsigned char symbol = (unsigned char )i;
-			if(counts[i])
-				huffman_add_symbol(&state, counts[i], 1, &symbol);
+				/* no more bits, decoding error */
+				if(bitcount == 0)
+					return -1;
+			}
 		}
+
+		/* check for eof */
+		if(node == eof)
+			break;
+
+		/* output character */
+		if(dst == dst_end)
+			return -1;
+		*dst++ = node->symbol;
 	}
-	
-	huffman_construct_tree(&state);
-	/*debug_count = 20;*/
-	compressed_data_size = huffman_compress(&state, test_data, test_data_size, compressed_data, sizeof(compressed_data));
-	/*debug_count = 20;*/
-	output_data_size = huffman_decompress(&state, compressed_data, compressed_data_size, output_data, sizeof(output_data));
-	
-	dbg_msg("huffman", "%d -> %d -> %d", test_data_size, compressed_data_size/8, output_data_size);
-	
-	/* write test data */
-	{
-		IOHANDLE io = io_open("out.txt", IOFLAG_WRITE);
-		io_write(io, output_data, output_data_size);
-		io_close(io);
-	}	
-	
-	return 0;
+
+	/* return the size of the decompressed buffer */
+	return (int)(dst - (const unsigned char *)output);
 }
diff --git a/src/engine/e_huffman.h b/src/engine/e_huffman.h
index 84c71e60..c4e20223 100644
--- a/src/engine/e_huffman.h
+++ b/src/engine/e_huffman.h
@@ -1,43 +1,91 @@
+#ifndef __HUFFMAN_HEADER__
+#define __HUFFMAN_HEADER__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 enum
 {
-	MAX_SYMBOL_SIZE=8,
-	MAX_NODES=1024*8
-};
+	HUFFMAN_EOF_SYMBOL = 256,
 
-typedef struct
-{
-	int i;
-} HUFFSYMBOL;
+	HUFFMAN_MAX_SYMBOLS=HUFFMAN_EOF_SYMBOL+1,
+	HUFFMAN_MAX_NODES=HUFFMAN_MAX_SYMBOLS*2-1,
+	
+	HUFFMAN_LUTBITS = 10,
+	HUFFMAN_LUTSIZE = (1<<HUFFMAN_LUTBITS),
+	HUFFMAN_LUTMASK = (HUFFMAN_LUTSIZE-1)
+};
 
-typedef struct HUFFNODE_t
+typedef struct HUFFMAN_NODE
 {
-	int frequency;
-	
-	int symbol_size;
-	unsigned char symbol[MAX_SYMBOL_SIZE];
-	
-	int num_bits;
+	/* symbol */
 	unsigned bits;
+	unsigned num_bits;
+
+	/* don't use pointers for this. shorts are smaller so we can fit more data into the cache */
+	unsigned short leafs[2];
 
-	struct HUFFNODE_t *parent;
-	struct HUFFNODE_t *zero;
-	struct HUFFNODE_t *one;
-} HUFFNODE;
+	/* what the symbol represents */
+	unsigned char symbol;
+} HUFFMAN_NODE;
 
-typedef struct
+typedef struct HUFFMAN_STATE
 {
-	HUFFNODE nodes[MAX_NODES];
-	HUFFNODE *start_node;
-	int num_symbols;
+	HUFFMAN_NODE nodes[HUFFMAN_MAX_NODES];
+	HUFFMAN_NODE *decode_lut[HUFFMAN_LUTSIZE];
+	HUFFMAN_NODE *start_node;
 	int num_nodes;
-} HUFFSTATE;
+} HUFFMAN_STATE;
+
+/*
+	Function: huffman_init
+		Inits the compressor/decompressor.
+
+	Parameters:
+		huff - Pointer to the state to init
+		frequencies - A pointer to an array of 256 entries of the frequencies of the bytes
+
+	Remarks:
+		- Does no allocation what so ever.
+		- You don't have to call any cleanup functions when you are done with it
+*/
+void huffman_init(HUFFMAN_STATE *huff, const unsigned *frequencies);
+
+/*
+	Function: huffman_compress
+		Compresses a buffer and outputs a compressed buffer.
+
+	Parameters:
+		huff - Pointer to the huffman state
+		input - Buffer to compress
+		input_size - Size of the buffer to compress
+		output - Buffer to put the compressed data into
+		output_size - Size of the output buffer
+
+	Returns:
+		Returns the size of the compressed data. Negative value on failure.
+*/
+int huffman_compress(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size);
+
+/*
+	Function: huffman_decompress
+		Decompresses a buffer
+
+	Parameters:
+		huff - Pointer to the huffman state
+		input - Buffer to decompress
+		input_size - Size of the buffer to decompress
+		output - Buffer to put the uncompressed data into
+		output_size - Size of the output buffer
 
+	Returns:
+		Returns the size of the uncompressed data. Negative value on failure.
+*/
+int huffman_decompress(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size);
 
-void huffman_add_symbol(HUFFSTATE *huff, int frequency, int size, unsigned char *symbol);
-void huffman_init(HUFFSTATE *huff);
-void huffman_construct_tree(HUFFSTATE *huff);
-int huffman_compress(HUFFSTATE *huff, const void *input, int input_size, void *output, int output_size);
-int huffman_decompress(HUFFSTATE *huff, const void *input, int input_size, void *output, int output_size);
+#ifdef __cplusplus
+}
+#endif
 
-int huffman_test();
+#endif /* __HUFFMAN_HEADER__ */
diff --git a/src/engine/e_if_gfx.h b/src/engine/e_if_gfx.h
index b758ed30..acbd4afc 100644
--- a/src/engine/e_if_gfx.h
+++ b/src/engine/e_if_gfx.h
@@ -557,7 +557,7 @@ int gfx_memory_usage();
 		TODO		
 	
 	Arguments:
-		arg1 - desc
+		filename - desc
 	
 	Returns:
 
@@ -567,6 +567,20 @@ int gfx_memory_usage();
 void gfx_screenshot();
 
 /*
+	Function: gfx_screenshot_direct
+		TODO		
+	
+	Arguments:
+		filename - desc
+	
+	Returns:
+
+	See Also:
+		<other_func>
+*/
+void gfx_screenshot_direct(const char *filename);
+
+/*
 	Function: gfx_clip_enable
 		TODO
 	
diff --git a/src/engine/e_network.c b/src/engine/e_network.c
index 1e320293..d3560d84 100644
--- a/src/engine/e_network.c
+++ b/src/engine/e_network.c
@@ -154,12 +154,8 @@ typedef struct
 	unsigned state;
 	
 	int token;
-	
 	int remote_closed;
 	
-	int connected;
-	int disconnected;
-	
 	RINGBUFFER buffer;
 	
 	int64 last_update_time;
@@ -213,27 +209,10 @@ struct NETCLIENT_t
 };
 
 static IOHANDLE datalog = 0;
-static HUFFSTATE huffmanstate;
+static HUFFMAN_STATE huffmanstate;
 
 #define COMPRESSION 1
 
-typedef struct pcap_hdr_s {
-        unsigned magic_number;   /* magic number */
-        short version_major;  /* major version number */
-        short version_minor;  /* minor version number */
-        int  thiszone;       /* GMT to local correction */
-        unsigned sigfigs;        /* accuracy of timestamps */
-        unsigned snaplen;        /* max length of captured packets, in octets */
-        unsigned network;        /* data link type */
-} pcap_hdr_t;
-
-typedef struct pcaprec_hdr_s {
-        unsigned ts_sec;         /* timestamp seconds */
-        unsigned ts_usec;        /* timestamp microseconds */
-        unsigned incl_len;       /* number of octets of packet saved in file */
-        unsigned orig_len;       /* actual length of packet */
-} pcaprec_hdr_t;
-
 /* packs the data tight and sends it */
 static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet)
 {
@@ -249,7 +228,7 @@ static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *pac
 	
 	if(COMPRESSION)
 	{
-		int compressed_size = (huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4)+7)/8;
+		int compressed_size = huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4);
 		net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size);
 	}
 	else
@@ -276,9 +255,7 @@ static int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *pa
 	packet->data_size = size - NET_PACKETHEADERSIZE;
 	
 	if(COMPRESSION)
-	{
 		huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data));
-	}
 	else
 		mem_copy(packet->chunk_data, &buffer[3], packet->data_size);
 	
@@ -326,12 +303,7 @@ static void conn_reset(NETCONNECTION *conn)
 	conn->ack = 0;
 	conn->remote_closed = 0;
 	
-	if(conn->state == NET_CONNSTATE_ONLINE ||
-		conn->state == NET_CONNSTATE_ERROR)
-	{
-		conn->disconnected++;
-	}
-		
+	conn->state = NET_CONNSTATE_OFFLINE;
 	conn->state = NET_CONNSTATE_OFFLINE;
 	conn->last_send_time = 0;
 	conn->last_recv_time = 0;
@@ -340,6 +312,8 @@ static void conn_reset(NETCONNECTION *conn)
 	mem_zero(&conn->peeraddr, sizeof(conn->peeraddr));
 	
 	rb_clear(&conn->buffer);
+	
+	mem_zero(&conn->construct, sizeof(conn->construct));
 }
 
 
@@ -358,8 +332,6 @@ static void conn_init(NETCONNECTION *conn, NETSOCKET socket)
 	conn_reset(conn);
 	conn_reset_stats(conn);
 	conn->socket = socket;
-	conn->connected = 0;
-	conn->disconnected = 0;
 	rb_init(&conn->buffer);
 	mem_zero(conn->error_string, sizeof(conn->error_string));
 }
@@ -489,6 +461,9 @@ static int conn_connect(NETCONNECTION *conn, NETADDR *addr)
 
 static void conn_disconnect(NETCONNECTION *conn, const char *reason)
 {
+	if(conn->state == NET_CONNSTATE_OFFLINE)
+		return;
+
 	if(conn->remote_closed == 0)
 	{
 		if(reason)
@@ -518,8 +493,6 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *a
 	{
 		int ctrlmsg = packet->chunk_data[0];
 		
-		dbg_msg("connection", "\tgot control message %d", ctrlmsg);
-
 		if(ctrlmsg == NET_CTRLMSG_CLOSE)
 		{
 			conn->state = NET_CONNSTATE_ERROR;
@@ -554,7 +527,6 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *a
 					/* send response and init connection */
 					conn_reset(conn);
 					conn->state = NET_CONNSTATE_ONLINE;
-					conn->connected++;
 					conn->peeraddr = *addr;
 					conn->last_send_time = now;
 					conn->last_recv_time = now;
@@ -571,7 +543,6 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *a
 				{
 					conn_send_control(conn, NET_CTRLMSG_ACCEPT, 0, 0);
 					conn->state = NET_CONNSTATE_ONLINE;
-					conn->connected++;
 					if(config.debug)
 						dbg_msg("connection", "got connect+accept, sending accept. connection online");
 				}
@@ -1088,7 +1059,7 @@ void netcommon_openlog(const char *filename)
 }
 
 
-static const int freq_table[256+1] = {
+static const unsigned freq_table[256+1] = {
 1<<30,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186,
 283,131,146,166,543,164,167,136,179,859,363,113,157,154,204,108,137,180,202,176,
 872,404,168,134,151,111,113,109,120,126,129,100,41,20,16,22,18,18,17,19,
@@ -1105,13 +1076,5 @@ static const int freq_table[256+1] = {
 
 void netcommon_init()
 {
-	int i;
-	huffman_init(&huffmanstate);
-	for(i = 0; i < 256; i++)
-	{
-		unsigned char sym = (unsigned char)i;
-		huffman_add_symbol(&huffmanstate, freq_table[i], 1, &sym);
-	}
-	
-	huffman_construct_tree(&huffmanstate);
+	huffman_init(&huffmanstate, freq_table);
 }
diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c
index 7ed8712b..6e015dbe 100644
--- a/src/engine/server/es_server.c
+++ b/src/engine/server/es_server.c
@@ -331,7 +331,7 @@ int server_send_msg(int client_id)
 		packet.flags |= NETSENDFLAG_VITAL;
 	if(info->flags&MSGFLAG_FLUSH)
 		packet.flags |= NETSENDFLAG_FLUSH;
-			
+	
 	if(client_id == -1)
 	{
 		/* broadcast */
@@ -594,6 +594,7 @@ static void server_process_client_packet(NETCHUNK *packet)
 	int cid = packet->client_id;
 	int sys;
 	int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
+	
 	if(sys)
 	{
 		/* system message */
diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp
index 5a2af697..28e16686 100644
--- a/src/game/client/gc_render.cpp
+++ b/src/game/client/gc_render.cpp
@@ -16,6 +16,25 @@
 static float sprite_w_scale;
 static float sprite_h_scale;
 
+static void layershot_begin()
+{
+	if(!config.cl_layershot)
+		return;
+
+	gfx_clear(0,0,0);
+}
+
+static void layershot_end()
+{
+	if(!config.cl_layershot)
+		return;
+	
+	char buf[256];
+	str_format(buf, sizeof(buf), "screenshots/layers_%04d.png", config.cl_layershot);
+	gfx_screenshot_direct(buf);
+	config.cl_layershot++;
+}
+
 void select_sprite(SPRITE *spr, int flags, int sx, int sy)
 {
 	int x = spr->x+sx;
@@ -299,7 +318,7 @@ static void envelope_eval(float time_offset, int env, float *channels)
 void render_layers(float center_x, float center_y, int pass)
 {
 	bool passed_gamelayer = false;
-
+	
 	for(int g = 0; g < layers_num_groups(); g++)
 	{
 		MAPITEM_GROUP *group = layers_get_group(g);
@@ -353,6 +372,8 @@ void render_layers(float center_x, float center_y, int pass)
 			
 			if(render && !is_game_layer)
 			{
+				layershot_begin();
+				
 				if(layer->type == LAYERTYPE_TILES)
 				{
 					MAPITEM_LAYER_TILEMAP *tmap = (MAPITEM_LAYER_TILEMAP *)layer;
@@ -381,8 +402,9 @@ void render_layers(float center_x, float center_y, int pass)
 					render_quads(quads, qlayer->num_quads, envelope_eval, LAYERRENDERFLAG_OPAQUE);
 					gfx_blend_normal();
 					render_quads(quads, qlayer->num_quads, envelope_eval, LAYERRENDERFLAG_TRANSPARENT);
-						
 				}
+				
+				layershot_end();	
 			}
 		}
 		
@@ -502,25 +524,39 @@ void render_world(float center_x, float center_y, float zoom)
 	gfx_clip_disable();
 	
 	// render trails
+	layershot_begin();
 	particle_render(PARTGROUP_PROJECTILE_TRAIL);
+	layershot_end();
 
 	// render items
+	layershot_begin();
 	render_items();
+	layershot_end();
 
 	// render players above all
+	layershot_begin();
 	render_players();
+	layershot_end();
 
 	// render particles
+	layershot_begin();
 	particle_render(PARTGROUP_EXPLOSIONS);
 	particle_render(PARTGROUP_GENERAL);
+	layershot_end();
 	
 	if(config.dbg_flow)
 		flow_dbg_render();
 
 	// render foreground layers
+	layershot_begin();
 	render_layers(center_x, center_y, 1);
+	layershot_end();
 	gfx_clip_disable();
 
 	// render damage indications
+	layershot_begin();
 	render_damage_indicators();
+	layershot_end();
+	
+	config.cl_layershot = 0;
 }
diff --git a/src/game/g_variables.hpp b/src/game/g_variables.hpp
index fb69584e..c0852bc4 100644
--- a/src/game/g_variables.hpp
+++ b/src/game/g_variables.hpp
@@ -16,6 +16,7 @@ MACRO_CONFIG_INT(cl_mouse_deadzone, 300, 0, 0)
 MACRO_CONFIG_INT(cl_mouse_followfactor, 60, 0, 200)
 MACRO_CONFIG_INT(cl_mouse_max_distance, 800, 0, 0)
 
+MACRO_CONFIG_INT(cl_layershot, 0, 0, 1)
 
 MACRO_CONFIG_INT(ed_showkeys, 0, 0, 1)