mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
added cl_layershot. fixed some bugs in the network
This commit is contained in:
parent
d1282138cd
commit
16912026db
|
@ -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_header" in sys.argv: gen_server_content_header = True
|
||||||
if "server_content_source" in sys.argv: gen_server_content_source = 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:
|
if gen_client_content_header or gen_server_content_header:
|
||||||
# emit the type declarations
|
# emit the type declarations
|
||||||
contentlines = file("datasrc/content.py").readlines()
|
contentlines = file("datasrc/content.py").readlines()
|
||||||
|
@ -210,3 +219,5 @@ if gen_network_source:
|
||||||
for l in lines:
|
for l in lines:
|
||||||
print l
|
print l
|
||||||
|
|
||||||
|
if gen_client_content_header or gen_server_content_header:
|
||||||
|
print "#endif"
|
||||||
|
|
|
@ -302,7 +302,10 @@ function build(settings)
|
||||||
masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
|
masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
|
||||||
game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, network_source)
|
game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, network_source)
|
||||||
game_client = Compile(settings, Collect("src/game/client/*.cpp"), client_content_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"))
|
game_editor = Compile(settings, Collect("src/game/editor/*.cpp"))
|
||||||
|
|
||||||
-- build tools (TODO: fix this so we don't get double _d_d stuff)
|
-- build tools (TODO: fix this so we don't get double _d_d stuff)
|
||||||
|
|
|
@ -479,6 +479,7 @@ static void sockaddr_to_netaddr(const struct sockaddr *src, NETADDR *dst)
|
||||||
{
|
{
|
||||||
/* TODO: IPv6 support */
|
/* TODO: IPv6 support */
|
||||||
unsigned int ip = htonl(((struct sockaddr_in*)src)->sin_addr.s_addr);
|
unsigned int ip = htonl(((struct sockaddr_in*)src)->sin_addr.s_addr);
|
||||||
|
mem_zero(dst, sizeof(NETADDR));
|
||||||
dst->type = NETTYPE_IPV4;
|
dst->type = NETTYPE_IPV4;
|
||||||
dst->port = htons(((struct sockaddr_in*)src)->sin_port);
|
dst->port = htons(((struct sockaddr_in*)src)->sin_port);
|
||||||
dst->ip[0] = (unsigned char)((ip>>24)&0xFF);
|
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));
|
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)
|
int net_host_lookup(const char *hostname, NETADDR *addr, int types)
|
||||||
{
|
{
|
||||||
/* TODO: IPv6 support */
|
/* 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);
|
netaddr_to_sockaddr(addr, &sa);
|
||||||
d = sendto((int)sock, (const char*)data, size, 0, &sa, sizeof(sa));
|
d = sendto((int)sock, (const char*)data, size, 0, &sa, sizeof(sa));
|
||||||
if(d < 0)
|
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", "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_bytes += size;
|
||||||
network_stats.sent_packets++;
|
network_stats.sent_packets++;
|
||||||
return d;
|
return d;
|
||||||
|
|
|
@ -478,7 +478,7 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b);
|
||||||
- The string will always be zero terminated
|
- 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 */
|
/* Group: Network UDP */
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ int gfx_init()
|
||||||
/* open window */
|
/* open window */
|
||||||
if(config.gfx_fullscreen)
|
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)
|
if(result != GL_TRUE)
|
||||||
{
|
{
|
||||||
dbg_msg("game", "failed to create gl context");
|
dbg_msg("game", "failed to create gl context");
|
||||||
|
@ -177,7 +177,7 @@ int gfx_init()
|
||||||
}
|
}
|
||||||
else
|
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)
|
if(result != GL_TRUE)
|
||||||
{
|
{
|
||||||
dbg_msg("game", "failed to create gl context");
|
dbg_msg("game", "failed to create gl context");
|
||||||
|
@ -600,28 +600,10 @@ void gfx_swap()
|
||||||
|
|
||||||
if(do_screenshot)
|
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 */
|
/* find filename */
|
||||||
{
|
|
||||||
char wholepath[1024];
|
char wholepath[1024];
|
||||||
char filename[128];
|
char filename[128];
|
||||||
static int index = 1;
|
static int index = 1;
|
||||||
png_t png;
|
|
||||||
|
|
||||||
for(; index < 1000; index++)
|
for(; index < 1000; index++)
|
||||||
{
|
{
|
||||||
|
@ -636,15 +618,8 @@ void gfx_swap()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save png */
|
gfx_screenshot_direct(filename);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
mem_free(pixel_data);
|
|
||||||
do_screenshot = 0;
|
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()
|
int gfx_screenwidth()
|
||||||
{
|
{
|
||||||
return screen_width;
|
return screen_width;
|
||||||
|
@ -690,7 +701,7 @@ void gfx_texture_set(int slot)
|
||||||
|
|
||||||
void gfx_clear(float r, float g, float b)
|
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);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_width, 800, 0, 0)
|
||||||
MACRO_CONFIG_INT(gfx_screen_height, 600, 0, 0)
|
MACRO_CONFIG_INT(gfx_screen_height, 600, 0, 0)
|
||||||
MACRO_CONFIG_INT(gfx_fullscreen, 1, 0, 1)
|
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_color_depth, 24, 16, 24)
|
||||||
MACRO_CONFIG_INT(gfx_clear, 0, 0, 1)
|
MACRO_CONFIG_INT(gfx_clear, 0, 0, 1)
|
||||||
MACRO_CONFIG_INT(gfx_vsync, 1, 0, 1)
|
MACRO_CONFIG_INT(gfx_vsync, 1, 0, 1)
|
||||||
|
|
|
@ -1,383 +1,262 @@
|
||||||
#include <base/system.h>
|
#include <stdlib.h> /* qsort */
|
||||||
#include <stdlib.h>
|
#include <memory.h> /* memset */
|
||||||
#include <string.h>
|
#include "e_huffman.h"
|
||||||
#include <engine/e_huffman.h>
|
|
||||||
|
|
||||||
void huffman_init(HUFFSTATE *huff)
|
typedef struct HUFFMAN_CONSTRUCT_NODE
|
||||||
{
|
{
|
||||||
mem_zero(huff, sizeof(HUFFSTATE));
|
unsigned short node_id;
|
||||||
huff->nodes[0].frequency = 1;
|
int frequency;
|
||||||
huff->nodes[0].symbol_size = -1;
|
} HUFFMAN_CONSTRUCT_NODE;
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int sort_func(const void *a, const void *b)
|
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;
|
return -1;
|
||||||
if((*(HUFFNODE **)a)->frequency < (*(HUFFNODE **)b)->frequency)
|
if((*(HUFFMAN_CONSTRUCT_NODE **)a)->frequency < (*(HUFFMAN_CONSTRUCT_NODE **)b)->frequency)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
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)
|
if(node->leafs[1] != 0xffff)
|
||||||
huffman_setbits_r(node->one, (bits<<1)|1, depth+1);
|
huffman_setbits_r(huff, &huff->nodes[node->leafs[1]], bits|(1<<depth), depth+1);
|
||||||
if(node->zero)
|
if(node->leafs[0] != 0xffff)
|
||||||
huffman_setbits_r(node->zero, (bits<<1), depth+1);
|
huffman_setbits_r(huff, &huff->nodes[node->leafs[0]], bits, depth+1);
|
||||||
|
|
||||||
if(node->symbol_size)
|
if(node->num_bits)
|
||||||
{
|
{
|
||||||
node->bits = bits;
|
node->bits = bits;
|
||||||
node->num_bits = depth;
|
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_CONSTRUCT_NODE nodes_left_storage[HUFFMAN_MAX_NODES];
|
||||||
huffman_checktree_r(node->one, (bits<<1)|1, depth+1);
|
HUFFMAN_CONSTRUCT_NODE *nodes_left[HUFFMAN_MAX_NODES];
|
||||||
if(node->zero)
|
int num_nodes_left = HUFFMAN_MAX_SYMBOLS;
|
||||||
huffman_checktree_r(node->zero, (bits<<1), depth+1);
|
int i;
|
||||||
|
|
||||||
if(node->symbol_size)
|
/* 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);*/
|
huff->nodes[i].num_bits = -1;
|
||||||
|
huff->nodes[i].symbol = i;
|
||||||
|
huff->nodes[i].leafs[0] = -1;
|
||||||
|
huff->nodes[i].leafs[1] = -1;
|
||||||
|
|
||||||
if(node->bits != bits || node->num_bits != depth)
|
if(i == HUFFMAN_EOF_SYMBOL)
|
||||||
{
|
nodes_left_storage[i].frequency = 1;
|
||||||
dbg_msg("", "crap! %d %d=%d %d!=%d", node->bits>>1, node->bits, bits, node->num_bits , depth);
|
else
|
||||||
/*dbg_msg("", "%p %p %d", node->one, node->zero, node->symbol[0]);*/
|
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)
|
huff->num_nodes = HUFFMAN_MAX_SYMBOLS;
|
||||||
{
|
|
||||||
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];
|
|
||||||
|
|
||||||
/* construct the table */
|
/* construct the table */
|
||||||
while(num_nodes_left > 1)
|
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].num_bits = 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].leafs[0] = nodes_left[num_nodes_left-1]->node_id;
|
||||||
huff->nodes[huff->num_nodes].zero = nodes_left[num_nodes_left-1];
|
huff->nodes[huff->num_nodes].leafs[1] = nodes_left[num_nodes_left-2]->node_id;
|
||||||
huff->nodes[huff->num_nodes].one = nodes_left[num_nodes_left-2];
|
nodes_left[num_nodes_left-2]->node_id = huff->num_nodes;
|
||||||
nodes_left[num_nodes_left-1]->parent = &huff->nodes[huff->num_nodes];
|
nodes_left[num_nodes_left-2]->frequency = nodes_left[num_nodes_left-1]->frequency + nodes_left[num_nodes_left-2]->frequency;
|
||||||
nodes_left[num_nodes_left-2]->parent = &huff->nodes[huff->num_nodes];
|
|
||||||
nodes_left[num_nodes_left-2] = &huff->nodes[huff->num_nodes];
|
|
||||||
huff->num_nodes++;
|
huff->num_nodes++;
|
||||||
num_nodes_left--;
|
num_nodes_left--;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg_msg("", "%d", huff->num_nodes);
|
/* set start node */
|
||||||
for(i = 0; i < huff->num_nodes; i++)
|
huff->start_node = &huff->nodes[huff->num_nodes-1];
|
||||||
{
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
n->bits = bits;
|
|
||||||
n->num_bits = num_bits;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
huffman_checktree_r(huff->start_node, 0, 0);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* build symbol bits */
|
||||||
|
huffman_setbits_r(huff, huff->start_node, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
void huffman_init(HUFFMAN_STATE *huff, const unsigned *frequencies)
|
||||||
{
|
{
|
||||||
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 i;
|
||||||
int best_match = -1;
|
|
||||||
int best_match_size = 0;
|
|
||||||
|
|
||||||
|
/* 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++)
|
||||||
|
{
|
||||||
|
unsigned bits = i;
|
||||||
|
int k;
|
||||||
|
HUFFMAN_NODE *node = huff->start_node;
|
||||||
|
for(k = 0; k < HUFFMAN_LUTBITS; k++)
|
||||||
|
{
|
||||||
|
node = &huff->nodes[node->leafs[bits&1]];
|
||||||
|
bits >>= 1;
|
||||||
|
|
||||||
|
if(!node)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(node->num_bits)
|
||||||
|
{
|
||||||
|
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)
|
if(input_size)
|
||||||
{
|
{
|
||||||
for(i = 0; i < huff->num_symbols; i++)
|
/* {A} load the first symbol */
|
||||||
|
int symbol = *src++;
|
||||||
|
|
||||||
|
while(src != src_end)
|
||||||
{
|
{
|
||||||
if(huff->nodes[i].symbol_size <= input_size && huff->nodes[i].symbol_size > best_match_size)
|
/* {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)
|
||||||
{
|
{
|
||||||
if(memcmp(src, huff->nodes[i].symbol, huff->nodes[i].symbol_size) == 0)
|
/* {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)
|
||||||
{
|
{
|
||||||
best_match = i;
|
bits |= (*src++) << bitcount;
|
||||||
best_match_size = huff->nodes[i].symbol_size;
|
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
|
else
|
||||||
{
|
{
|
||||||
best_match = 0;
|
/* remove the bits that the lut checked up for us */
|
||||||
best_match_size = 0;
|
bits >>= HUFFMAN_LUTBITS;
|
||||||
quit = 1;
|
bitcount -= HUFFMAN_LUTBITS;
|
||||||
}
|
|
||||||
|
|
||||||
|
/* walk the tree bit by bit */
|
||||||
if(best_match == -1)
|
while(1)
|
||||||
{
|
{
|
||||||
dbg_msg("huffman", "couldn't find symbol! %d left", input_size);
|
/* traverse tree */
|
||||||
|
node = &huff->nodes[node->leafs[bits&1]];
|
||||||
|
|
||||||
|
/* 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;
|
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(debug_count)
|
|
||||||
dbg_msg("", "-- %d %d", node->bits, node->num_bits);
|
|
||||||
|
|
||||||
/* check for eof */
|
/* check for eof */
|
||||||
if(node == &huff->nodes[0])
|
if(node == eof)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for(i = 0; i < node->symbol_size; i++)
|
/* output character */
|
||||||
{
|
if(dst == dst_end)
|
||||||
*dst++ = node->symbol[i];
|
return -1;
|
||||||
size++;
|
*dst++ = node->symbol;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
/* return the size of the decompressed buffer */
|
||||||
}
|
return (int)(dst - (const unsigned char *)output);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,91 @@
|
||||||
|
#ifndef __HUFFMAN_HEADER__
|
||||||
|
#define __HUFFMAN_HEADER__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MAX_SYMBOL_SIZE=8,
|
HUFFMAN_EOF_SYMBOL = 256,
|
||||||
MAX_NODES=1024*8
|
|
||||||
|
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
|
typedef struct HUFFMAN_NODE
|
||||||
{
|
{
|
||||||
int i;
|
/* symbol */
|
||||||
} HUFFSYMBOL;
|
|
||||||
|
|
||||||
typedef struct HUFFNODE_t
|
|
||||||
{
|
|
||||||
int frequency;
|
|
||||||
|
|
||||||
int symbol_size;
|
|
||||||
unsigned char symbol[MAX_SYMBOL_SIZE];
|
|
||||||
|
|
||||||
int num_bits;
|
|
||||||
unsigned bits;
|
unsigned bits;
|
||||||
|
unsigned num_bits;
|
||||||
|
|
||||||
struct HUFFNODE_t *parent;
|
/* don't use pointers for this. shorts are smaller so we can fit more data into the cache */
|
||||||
struct HUFFNODE_t *zero;
|
unsigned short leafs[2];
|
||||||
struct HUFFNODE_t *one;
|
|
||||||
} HUFFNODE;
|
|
||||||
|
|
||||||
typedef struct
|
/* what the symbol represents */
|
||||||
|
unsigned char symbol;
|
||||||
|
} HUFFMAN_NODE;
|
||||||
|
|
||||||
|
typedef struct HUFFMAN_STATE
|
||||||
{
|
{
|
||||||
HUFFNODE nodes[MAX_NODES];
|
HUFFMAN_NODE nodes[HUFFMAN_MAX_NODES];
|
||||||
HUFFNODE *start_node;
|
HUFFMAN_NODE *decode_lut[HUFFMAN_LUTSIZE];
|
||||||
int num_symbols;
|
HUFFMAN_NODE *start_node;
|
||||||
int num_nodes;
|
int num_nodes;
|
||||||
} HUFFSTATE;
|
} HUFFMAN_STATE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: huffman_init
|
||||||
|
Inits the compressor/decompressor.
|
||||||
|
|
||||||
void huffman_add_symbol(HUFFSTATE *huff, int frequency, int size, unsigned char *symbol);
|
Parameters:
|
||||||
void huffman_init(HUFFSTATE *huff);
|
huff - Pointer to the state to init
|
||||||
void huffman_construct_tree(HUFFSTATE *huff);
|
frequencies - A pointer to an array of 256 entries of the frequencies of the bytes
|
||||||
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);
|
|
||||||
|
|
||||||
int huffman_test();
|
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);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HUFFMAN_HEADER__ */
|
||||||
|
|
|
@ -557,7 +557,7 @@ int gfx_memory_usage();
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
arg1 - desc
|
filename - desc
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
|
@ -566,6 +566,20 @@ int gfx_memory_usage();
|
||||||
*/
|
*/
|
||||||
void gfx_screenshot();
|
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
|
Function: gfx_clip_enable
|
||||||
TODO
|
TODO
|
||||||
|
|
|
@ -154,12 +154,8 @@ typedef struct
|
||||||
unsigned state;
|
unsigned state;
|
||||||
|
|
||||||
int token;
|
int token;
|
||||||
|
|
||||||
int remote_closed;
|
int remote_closed;
|
||||||
|
|
||||||
int connected;
|
|
||||||
int disconnected;
|
|
||||||
|
|
||||||
RINGBUFFER buffer;
|
RINGBUFFER buffer;
|
||||||
|
|
||||||
int64 last_update_time;
|
int64 last_update_time;
|
||||||
|
@ -213,27 +209,10 @@ struct NETCLIENT_t
|
||||||
};
|
};
|
||||||
|
|
||||||
static IOHANDLE datalog = 0;
|
static IOHANDLE datalog = 0;
|
||||||
static HUFFSTATE huffmanstate;
|
static HUFFMAN_STATE huffmanstate;
|
||||||
|
|
||||||
#define COMPRESSION 1
|
#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 */
|
/* packs the data tight and sends it */
|
||||||
static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet)
|
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)
|
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);
|
net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -276,9 +255,7 @@ static int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *pa
|
||||||
packet->data_size = size - NET_PACKETHEADERSIZE;
|
packet->data_size = size - NET_PACKETHEADERSIZE;
|
||||||
|
|
||||||
if(COMPRESSION)
|
if(COMPRESSION)
|
||||||
{
|
|
||||||
huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data));
|
huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data));
|
||||||
}
|
|
||||||
else
|
else
|
||||||
mem_copy(packet->chunk_data, &buffer[3], packet->data_size);
|
mem_copy(packet->chunk_data, &buffer[3], packet->data_size);
|
||||||
|
|
||||||
|
@ -326,12 +303,7 @@ static void conn_reset(NETCONNECTION *conn)
|
||||||
conn->ack = 0;
|
conn->ack = 0;
|
||||||
conn->remote_closed = 0;
|
conn->remote_closed = 0;
|
||||||
|
|
||||||
if(conn->state == NET_CONNSTATE_ONLINE ||
|
conn->state = NET_CONNSTATE_OFFLINE;
|
||||||
conn->state == NET_CONNSTATE_ERROR)
|
|
||||||
{
|
|
||||||
conn->disconnected++;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->state = NET_CONNSTATE_OFFLINE;
|
conn->state = NET_CONNSTATE_OFFLINE;
|
||||||
conn->last_send_time = 0;
|
conn->last_send_time = 0;
|
||||||
conn->last_recv_time = 0;
|
conn->last_recv_time = 0;
|
||||||
|
@ -340,6 +312,8 @@ static void conn_reset(NETCONNECTION *conn)
|
||||||
mem_zero(&conn->peeraddr, sizeof(conn->peeraddr));
|
mem_zero(&conn->peeraddr, sizeof(conn->peeraddr));
|
||||||
|
|
||||||
rb_clear(&conn->buffer);
|
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(conn);
|
||||||
conn_reset_stats(conn);
|
conn_reset_stats(conn);
|
||||||
conn->socket = socket;
|
conn->socket = socket;
|
||||||
conn->connected = 0;
|
|
||||||
conn->disconnected = 0;
|
|
||||||
rb_init(&conn->buffer);
|
rb_init(&conn->buffer);
|
||||||
mem_zero(conn->error_string, sizeof(conn->error_string));
|
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)
|
static void conn_disconnect(NETCONNECTION *conn, const char *reason)
|
||||||
{
|
{
|
||||||
|
if(conn->state == NET_CONNSTATE_OFFLINE)
|
||||||
|
return;
|
||||||
|
|
||||||
if(conn->remote_closed == 0)
|
if(conn->remote_closed == 0)
|
||||||
{
|
{
|
||||||
if(reason)
|
if(reason)
|
||||||
|
@ -518,8 +493,6 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *a
|
||||||
{
|
{
|
||||||
int ctrlmsg = packet->chunk_data[0];
|
int ctrlmsg = packet->chunk_data[0];
|
||||||
|
|
||||||
dbg_msg("connection", "\tgot control message %d", ctrlmsg);
|
|
||||||
|
|
||||||
if(ctrlmsg == NET_CTRLMSG_CLOSE)
|
if(ctrlmsg == NET_CTRLMSG_CLOSE)
|
||||||
{
|
{
|
||||||
conn->state = NET_CONNSTATE_ERROR;
|
conn->state = NET_CONNSTATE_ERROR;
|
||||||
|
@ -554,7 +527,6 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *a
|
||||||
/* send response and init connection */
|
/* send response and init connection */
|
||||||
conn_reset(conn);
|
conn_reset(conn);
|
||||||
conn->state = NET_CONNSTATE_ONLINE;
|
conn->state = NET_CONNSTATE_ONLINE;
|
||||||
conn->connected++;
|
|
||||||
conn->peeraddr = *addr;
|
conn->peeraddr = *addr;
|
||||||
conn->last_send_time = now;
|
conn->last_send_time = now;
|
||||||
conn->last_recv_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_send_control(conn, NET_CTRLMSG_ACCEPT, 0, 0);
|
||||||
conn->state = NET_CONNSTATE_ONLINE;
|
conn->state = NET_CONNSTATE_ONLINE;
|
||||||
conn->connected++;
|
|
||||||
if(config.debug)
|
if(config.debug)
|
||||||
dbg_msg("connection", "got connect+accept, sending accept. connection online");
|
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,
|
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,
|
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,
|
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()
|
void netcommon_init()
|
||||||
{
|
{
|
||||||
int i;
|
huffman_init(&huffmanstate, freq_table);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,6 +594,7 @@ static void server_process_client_packet(NETCHUNK *packet)
|
||||||
int cid = packet->client_id;
|
int cid = packet->client_id;
|
||||||
int sys;
|
int sys;
|
||||||
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
|
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
|
||||||
|
|
||||||
if(sys)
|
if(sys)
|
||||||
{
|
{
|
||||||
/* system message */
|
/* system message */
|
||||||
|
|
|
@ -16,6 +16,25 @@
|
||||||
static float sprite_w_scale;
|
static float sprite_w_scale;
|
||||||
static float sprite_h_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)
|
void select_sprite(SPRITE *spr, int flags, int sx, int sy)
|
||||||
{
|
{
|
||||||
int x = spr->x+sx;
|
int x = spr->x+sx;
|
||||||
|
@ -353,6 +372,8 @@ void render_layers(float center_x, float center_y, int pass)
|
||||||
|
|
||||||
if(render && !is_game_layer)
|
if(render && !is_game_layer)
|
||||||
{
|
{
|
||||||
|
layershot_begin();
|
||||||
|
|
||||||
if(layer->type == LAYERTYPE_TILES)
|
if(layer->type == LAYERTYPE_TILES)
|
||||||
{
|
{
|
||||||
MAPITEM_LAYER_TILEMAP *tmap = (MAPITEM_LAYER_TILEMAP *)layer;
|
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);
|
render_quads(quads, qlayer->num_quads, envelope_eval, LAYERRENDERFLAG_OPAQUE);
|
||||||
gfx_blend_normal();
|
gfx_blend_normal();
|
||||||
render_quads(quads, qlayer->num_quads, envelope_eval, LAYERRENDERFLAG_TRANSPARENT);
|
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();
|
gfx_clip_disable();
|
||||||
|
|
||||||
// render trails
|
// render trails
|
||||||
|
layershot_begin();
|
||||||
particle_render(PARTGROUP_PROJECTILE_TRAIL);
|
particle_render(PARTGROUP_PROJECTILE_TRAIL);
|
||||||
|
layershot_end();
|
||||||
|
|
||||||
// render items
|
// render items
|
||||||
|
layershot_begin();
|
||||||
render_items();
|
render_items();
|
||||||
|
layershot_end();
|
||||||
|
|
||||||
// render players above all
|
// render players above all
|
||||||
|
layershot_begin();
|
||||||
render_players();
|
render_players();
|
||||||
|
layershot_end();
|
||||||
|
|
||||||
// render particles
|
// render particles
|
||||||
|
layershot_begin();
|
||||||
particle_render(PARTGROUP_EXPLOSIONS);
|
particle_render(PARTGROUP_EXPLOSIONS);
|
||||||
particle_render(PARTGROUP_GENERAL);
|
particle_render(PARTGROUP_GENERAL);
|
||||||
|
layershot_end();
|
||||||
|
|
||||||
if(config.dbg_flow)
|
if(config.dbg_flow)
|
||||||
flow_dbg_render();
|
flow_dbg_render();
|
||||||
|
|
||||||
// render foreground layers
|
// render foreground layers
|
||||||
|
layershot_begin();
|
||||||
render_layers(center_x, center_y, 1);
|
render_layers(center_x, center_y, 1);
|
||||||
|
layershot_end();
|
||||||
gfx_clip_disable();
|
gfx_clip_disable();
|
||||||
|
|
||||||
// render damage indications
|
// render damage indications
|
||||||
|
layershot_begin();
|
||||||
render_damage_indicators();
|
render_damage_indicators();
|
||||||
|
layershot_end();
|
||||||
|
|
||||||
|
config.cl_layershot = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_followfactor, 60, 0, 200)
|
||||||
MACRO_CONFIG_INT(cl_mouse_max_distance, 800, 0, 0)
|
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)
|
MACRO_CONFIG_INT(ed_showkeys, 0, 0, 1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue