diff --git a/datasrc/compile.py b/datasrc/compile.py
index 30734a21e..d3970ed68 100644
--- a/datasrc/compile.py
+++ b/datasrc/compile.py
@@ -36,6 +36,15 @@ if "client_content_source" in sys.argv: gen_client_content_source = True
if "server_content_header" in sys.argv: gen_server_content_header = True
if "server_content_source" in sys.argv: gen_server_content_source = True
+if gen_client_content_header:
+ print "#ifndef CLIENT_CONTENT_HEADER"
+ print "#define CLIENT_CONTENT_HEADER"
+
+if gen_server_content_header:
+ print "#ifndef SERVER_CONTENT_HEADER"
+ print "#define SERVER_CONTENT_HEADER"
+
+
if gen_client_content_header or gen_server_content_header:
# emit the type declarations
contentlines = file("datasrc/content.py").readlines()
@@ -210,3 +219,5 @@ if gen_network_source:
for l in lines:
print l
+if gen_client_content_header or gen_server_content_header:
+ print "#endif"
diff --git a/default.bam b/default.bam
index 2d10baf29..02c04077e 100644
--- a/default.bam
+++ b/default.bam
@@ -302,7 +302,10 @@ function build(settings)
masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, network_source)
game_client = Compile(settings, Collect("src/game/client/*.cpp"), client_content_source)
- game_server = Compile(settings, Collect("src/game/server/*.cpp"), server_content_source)
+ game_server = Compile(settings, Collect(
+ "src/game/server/*.cpp",
+ "src/game/server/entities/*.cpp",
+ "src/game/server/gamemodes/*.cpp"), server_content_source)
game_editor = Compile(settings, Collect("src/game/editor/*.cpp"))
-- build tools (TODO: fix this so we don't get double _d_d stuff)
diff --git a/src/base/system.c b/src/base/system.c
index 1ac5f2967..bb23a5e5c 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 4449907c9..abb20b422 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 5f213ac64..268e82b0b 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 4f258d11a..7b12e15d1 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 3707f0e6e..8396aa884 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 dfb5c8178..8adbb1f78 100644
--- a/src/engine/e_huffman.c
+++ b/src/engine/e_huffman.c
@@ -1,383 +1,262 @@
-#include
-#include
-#include
-#include
+#include /* qsort */
+#include /* 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<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;
+
+ 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];
}
-}
-void huffman_construct_tree(HUFFSTATE *huff)
-{
- HUFFNODE *nodes_left[MAX_NODES];
- int num_nodes_left = huff->num_nodes;
- int i, k;
-
- 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++)
+ /* set start node */
+ huff->start_node = &huff->nodes[huff->num_nodes-1];
+
+ /* build symbol bits */
+ huffman_setbits_r(huff, huff->start_node, 0, 0);
+}
+
+void huffman_init(HUFFMAN_STATE *huff, const unsigned *frequencies)
+{
+ int 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++)
{
- if(huff->nodes[i].symbol_size && (huff->nodes[i].one || huff->nodes[i].zero))
- dbg_msg("", "tree strangeness");
-
- if(!huff->nodes[i].parent)
+ unsigned bits = i;
+ int k;
+ HUFFMAN_NODE *node = huff->start_node;
+ for(k = 0; k < HUFFMAN_LUTBITS; k++)
{
- dbg_msg("", "root %p %p", huff->nodes[i].one, huff->nodes[i].zero);
- huff->start_node = &huff->nodes[i];
- }
- }
-
- 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;
- }
+ node = &huff->nodes[node->leafs[bits&1]];
+ bits >>= 1;
- n->bits = bits;
- n->num_bits = num_bits;
- }*/
-
- huffman_checktree_r(huff->start_node, 0, 0);
+ if(!node)
+ break;
- for(i = 0; i < huff->num_symbols; i++)
- {
- for(k = 0; k < huff->num_symbols; 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);
- }
- }
-
-}
-
-typedef struct
-{
- unsigned char *data;
- unsigned char current_bits;
- int num;
-} HUFFBITIO;
-
-int debug_count = 0;
-
-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)
-{
- 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;
-}
-
-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);
- }
-}
-
-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;
-
- if(debug_count)
- {
- debug_count--;
- dbg_msg("", "in %d", bit);
- }
- return bit;
-}
-
-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)
- {
- int i;
- int best_match = -1;
- int best_match_size = 0;
-
- if(input_size)
- {
- for(i = 0; i < huff->num_symbols; i++)
+ if(node->num_bits)
{
- 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;
- }
- }
+ huff->decode_lut[i] = node;
+ break;
}
}
+
+ if(k == HUFFMAN_LUTBITS)
+ huff->decode_lut[i] = node;
+ }
+
+}
+
+/*****************************************************************/
+int huffman_compress(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size)
+{
+ /* 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;
+
+ /* 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; \
+ }
+
+ /* 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;
+
+ /* symbol variables */
+ unsigned bits = 0;
+ unsigned bitcount = 0;
+
+ /* make sure that we have data that we want to compress */
+ if(input_size)
+ {
+ /* {A} load the first symbol */
+ int symbol = *src++;
+
+ while(src != src_end)
+ {
+ /* {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()
+ }
+
+ /* 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()
+ }
+
+ /* 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(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size)
+{
+ /* setup buffer pointers */
+ unsigned char *dst = (unsigned char *)output;
+ 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)
+ {
+ /* {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)
+ {
+ bits |= (*src++) << bitcount;
+ bitcount += 8;
+ }
+
+ /* {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)
+ {
+ /* remove the bits for that symbol */
+ bits >>= node->num_bits;
+ bitcount -= node->num_bits;
+ }
else
{
- best_match = 0;
- best_match_size = 0;
- quit = 1;
- }
-
-
- if(best_match == -1)
- {
- dbg_msg("huffman", "couldn't find symbol! %d left", input_size);
- return -1;
- }
-
- 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);
+ /* remove the bits that the lut checked up for us */
+ bits >>= HUFFMAN_LUTBITS;
+ bitcount -= HUFFMAN_LUTBITS;
- if(debug_count)
- dbg_msg("", "--");
-
- ret += huff->nodes[best_match].num_bits;
- input_size -= best_match_size;
- src += best_match_size;
- }
-
- bitio_flush(&io);
- return ret;
-}
+ /* walk the tree bit by bit */
+ while(1)
+ {
+ /* traverse tree */
+ node = &huff->nodes[node->leafs[bits&1]];
-int huffman_decompress(HUFFSTATE *huff, const void *input, int input_size, void *output, int output_size)
-{
- unsigned char *dst = (unsigned char *)output;
- HUFFBITIO io;
- int size = 0;
-
- bitio_init(&io, (unsigned char *)input);
-
- while(size < 1401)
- {
- HUFFNODE *node = huff->start_node;
- int i;
-
- while(node)
- {
- if(node->symbol_size)
- break;
-
- if(bitio_read(&io))
- node = node->one;
- else
- node = node->zero;
+ /* remove bit */
+ bitcount--;
+ bits >>= 1;
+
+ /* check if we hit a symbol */
+ if(node->num_bits)
+ break;
+
+ /* no more bits, decoding error */
+ if(bitcount == 0)
+ return -1;
+ }
}
- if(debug_count)
- dbg_msg("", "-- %d %d", node->bits, node->num_bits);
-
/* check for eof */
- if(node == &huff->nodes[0])
+ if(node == eof)
break;
-
- for(i = 0; i < node->symbol_size; i++)
- {
- *dst++ = node->symbol[i];
- size++;
- }
+
+ /* output character */
+ if(dst == dst_end)
+ return -1;
+ *dst++ = node->symbol;
}
-
- return size;
-}
-
-unsigned char test_data[1024*64];
-int test_data_size;
-
-unsigned char compressed_data[1024*64];
-int compressed_data_size;
-
-unsigned char output_data[1024*64];
-int output_data_size;
-
-HUFFSTATE state;
-
-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);
- }
- }
-
- 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 84c71e609..c4e202234 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,
+
+ HUFFMAN_MAX_SYMBOLS=HUFFMAN_EOF_SYMBOL+1,
+ HUFFMAN_MAX_NODES=HUFFMAN_MAX_SYMBOLS*2-1,
+
+ HUFFMAN_LUTBITS = 10,
+ HUFFMAN_LUTSIZE = (1<
+*/
+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 1e320293d..d3560d849 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 7ed8712b3..6e015dbed 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 5a2af6970..28e16686f 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 fb69584ee..c0852bc42 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)