about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2007-05-27 00:47:07 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2007-05-27 00:47:07 +0000
commitbdcc0b09ddc630c166f0dfebcf376765fb1f9801 (patch)
tree90fd22f041b6e4519f3459fcad983930afc2a647 /src
parent4a128a9609cc5fc61077b3cd73ffa831551b7dc2 (diff)
downloadzcatch-bdcc0b09ddc630c166f0dfebcf376765fb1f9801.tar.gz
zcatch-bdcc0b09ddc630c166f0dfebcf376765fb1f9801.zip
major update. added png support. fixed abit with the network
Diffstat (limited to 'src')
-rw-r--r--src/engine/client/client.cpp15
-rw-r--r--src/engine/client/gfx.cpp91
-rw-r--r--src/engine/client/pnglite/pnglite.c612
-rw-r--r--src/engine/client/pnglite/pnglite.h212
-rw-r--r--src/engine/interface.h15
-rw-r--r--src/engine/packet.h186
-rw-r--r--src/engine/server/server.cpp15
-rw-r--r--src/engine/versions.h3
-rw-r--r--src/game/client/game_client.cpp12
-rw-r--r--src/game/client/mapres_image.cpp2
-rw-r--r--src/game/client/menu.cpp58
11 files changed, 1146 insertions, 75 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 4aceaf0f..dd52608c 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -6,6 +6,7 @@
 
 #include <string.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <math.h>
 #include <engine/interface.h>
 
@@ -331,7 +332,7 @@ public:
 		*/
 		
 		packet p(NETMSG_CLIENT_CONNECT);
-		p.write_str(TEEWARS_NETVERSION); // payload
+		p.write_str(TEEWARS_VERSION); // payload
 		p.write_str(name);
 		p.write_str("no clan");
 		p.write_str("password");
@@ -388,7 +389,7 @@ public:
 	
 	bool load_data()
 	{
-		debug_font = gfx_load_texture_tga("data/debug_font.tga");
+		debug_font = gfx_load_texture("data/debug_font.png");
 		return true;
 	}
 	
@@ -420,8 +421,8 @@ public:
 			
 			if (!inited)
 			{
-				tee_texture = gfx_load_texture_tga("data/gui_tee.tga");
-				connecting_texture = gfx_load_texture_tga("data/gui/connecting.tga");
+				tee_texture = gfx_load_texture("data/gui_tee.png");
+				connecting_texture = gfx_load_texture("data/gui/connecting.png");
 					
 				inited = true;
 			}
@@ -565,7 +566,11 @@ public:
 
 	void process_packet(packet *p)
 	{
-		if(p->msg() == NETMSG_SERVER_ACCEPT)
+		if(p->version() != TEEWARS_NETVERSION)
+		{
+			error("wrong version");
+		}
+		else if(p->msg() == NETMSG_SERVER_ACCEPT)
 		{
 			const char *map;
 			map = p->read_str();
diff --git a/src/engine/client/gfx.cpp b/src/engine/client/gfx.cpp
index a824feac..71b5de7d 100644
--- a/src/engine/client/gfx.cpp
+++ b/src/engine/client/gfx.cpp
@@ -4,6 +4,11 @@
 
 #include <engine/interface.h>
 
+#include "pnglite/pnglite.h"
+
+#include <string.h>
+
+
 using namespace baselib;
 
 static opengl::context context;
@@ -150,7 +155,7 @@ bool gfx_init(bool fullscreen)
 	textures[MAX_TEXTURES-1].next = -1;
 	
 	// create null texture, will get id=0
-	gfx_load_texture_raw(4,4,null_texture_data);
+	gfx_load_texture_raw(4,4,IMG_RGBA,null_texture_data);
 	
 	return true;
 }
@@ -175,7 +180,7 @@ void gfx_blend_additive()
 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 }
 
-int gfx_load_texture_raw(int w, int h, const void *data)
+int gfx_load_texture_raw(int w, int h, int format, const void *data)
 {
 	// grab texture
 	int tex = first_free_texture;
@@ -185,20 +190,51 @@ int gfx_load_texture_raw(int w, int h, const void *data)
 	// set data and return
 	// TODO: should be RGBA, not BGRA
 	dbg_msg("gfx", "%d = %dx%d", tex, w, h);
-	textures[tex].tex.data2d(w, h, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, data);
+	if(format == IMG_RGB)
+		textures[tex].tex.data2d(w, h, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, data);
+	else if(format == IMG_RGBA)
+		textures[tex].tex.data2d(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, data);
+	else if(format == IMG_BGR)
+		textures[tex].tex.data2d(w, h, GL_RGB, GL_BGR, GL_UNSIGNED_BYTE, data);
+	else if(format == IMG_BGRA)
+		textures[tex].tex.data2d(w, h, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, data);
 	return tex;
 }
 
 // simple uncompressed RGBA loaders
-int gfx_load_texture_tga(const char *filename)
+int gfx_load_texture(const char *filename)
 {
-	image_info img;
-	
-	if(gfx_load_tga(&img, filename))
+	int l = strlen(filename);
+	if(l < 3)
+		return 0;
+
+	if(	(filename[l-3] == 't' || filename[l-3] == 'T') &&
+		(filename[l-2] == 'g' || filename[l-2] == 'G') &&
+		(filename[l-1] == 'a' || filename[l-1] == 'A'))
+	{
+		image_info img;
+		if(gfx_load_tga(&img, filename))
+		{
+			int id = gfx_load_texture_raw(img.width, img.height, img.format, img.data);
+			mem_free(img.data);
+			return id;
+		}
+		return 0;
+	}
+
+	if(	(filename[l-3] == 'p' || filename[l-3] == 'P') &&
+		(filename[l-2] == 'n' || filename[l-2] == 'N') &&
+		(filename[l-1] == 'g' || filename[l-1] == 'G'))
 	{
-		int id = gfx_load_texture_raw(img.width, img.height, img.data);
-		mem_free(img.data);
-		return id;
+		image_info img;
+		if(gfx_load_png(&img, filename))
+		{
+			int id = gfx_load_texture_raw(img.width, img.height, img.format, img.data);
+			mem_free(img.data);
+			return id;
+		}
+		
+		return 0;
 	}
 	
 	return 0;
@@ -240,6 +276,7 @@ int gfx_load_tga(image_info *img, const char *filename)
 	// read data
 	int data_size = img->width*img->height*4;
 	img->data = mem_alloc(data_size, 1);
+	img->format = IMG_BGRA;
 
 	if (flipy)
 	{
@@ -255,6 +292,40 @@ int gfx_load_tga(image_info *img, const char *filename)
 	return 1;
 }
 
+
+
+int gfx_load_png(image_info *img, const char *filename)
+{
+	// open file for reading
+	png_init(0,0);
+
+	png_t png;
+	if(png_open_file(&png, filename) != PNG_NO_ERROR)
+	{
+		dbg_msg("game/png", "failed to open file. filename='%s'", filename);
+		return 0;
+	}
+	
+	if(png.depth != 8 || (png.color_type != PNG_TRUECOLOR && png.color_type != PNG_TRUECOLOR_ALPHA))
+	{
+		dbg_msg("game/png", "invalid format. filename='%s'", filename);
+		png_close_file(&png);
+	}
+		
+	unsigned char *buffer = (unsigned char *)mem_alloc(png.width * png.height * png.bpp, 1);
+	png_get_data(&png, buffer);
+	png_close_file(&png);
+	
+	img->width = png.width;
+	img->height = png.height;
+	if(png.color_type == PNG_TRUECOLOR)
+		img->format = IMG_RGB;
+	else if(png.color_type == PNG_TRUECOLOR_ALPHA)
+		img->format = IMG_RGBA;
+	img->data = buffer;
+	return 1;
+}
+
 void gfx_shutdown()
 {
 	if (g_pVertices)
diff --git a/src/engine/client/pnglite/pnglite.c b/src/engine/client/pnglite/pnglite.c
new file mode 100644
index 00000000..c0e96ec6
--- /dev/null
+++ b/src/engine/client/pnglite/pnglite.c
@@ -0,0 +1,612 @@
+/*  pnglite.c - pnglite library

+    For conditions of distribution and use, see copyright notice in pnglite.h

+*/

+

+#include <zlib.h>

+#include "pnglite.h"

+#include <stdio.h>

+#include <stdlib.h>

+#include <string.h>

+

+

+#define DO_CRC_CHECKS 1

+

+static png_alloc_t png_alloc;

+static png_free_t png_free;

+

+static size_t file_read(png_t* png, void* out, size_t size, size_t numel)

+{

+	size_t result;

+	if(png->read_fun)

+	{

+		result = png->read_fun(out, size, numel, png->user_pointer);

+	}

+	else

+	{

+		if(!out)

+		{

+			result = fseek(png->user_pointer, (long)(size*numel), SEEK_CUR);

+		}

+		else

+		{

+			result = fread(out, size, numel, png->user_pointer);

+		}

+	}

+

+	return result;

+}

+

+static unsigned file_read_ul(png_t* png)

+{

+	unsigned result;

+	unsigned char buf[4];

+

+	if(file_read(png, buf, 1, 4) != 4)

+		return PNG_FILE_ERROR;

+

+	result = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];

+

+	return result;

+}

+

+static unsigned get_ul(unsigned char* buf)

+{

+	unsigned result;

+	unsigned char foo[4];

+

+	memcpy(foo, buf, 4);

+

+	result = (foo[0]<<24) | (foo[1]<<16) | (foo[2]<<8) | foo[3];

+

+	return result;

+}

+

+int png_init(png_alloc_t pngalloc, png_free_t pngfree)

+{

+	if(pngalloc)

+		png_alloc = pngalloc;

+	else

+		png_alloc = &malloc;

+

+	if(pngfree)

+		png_free = pngfree;

+	else

+		png_free = &free;

+

+	return PNG_NO_ERROR;

+}

+

+static int png_get_bpp(png_t* png)

+{

+	int bpp;

+

+	switch(png->color_type)

+	{

+	case PNG_GREYSCALE:

+		bpp = 1; break;

+	case PNG_TRUECOLOR:

+		bpp = 3; break;

+	case PNG_INDEXED:

+		bpp = 1; break;

+	case PNG_GREYSCALE_ALPHA:

+		bpp = 2; break;

+	case PNG_TRUECOLOR_ALPHA:

+		bpp = 4; break;

+	default:

+		return PNG_FILE_ERROR;

+	}

+

+	bpp *= png->depth/8;

+

+	return bpp;

+}

+

+static int png_read_ihdr(png_t* png)

+{

+	unsigned length;

+#if DO_CRC_CHECKS

+	unsigned orig_crc;

+	unsigned calc_crc;

+#endif

+	unsigned char ihdr[13+4];		 // length should be 13, make room for type (IHDR)

+

+	length = file_read_ul(png);

+

+	if(length != 13)

+	{

+		printf("%d\n", length);

+		return PNG_CRC_ERROR;

+	}

+

+	if(file_read(png, ihdr, 1, 13+4) != 13+4)

+		return PNG_EOF_ERROR;

+#if DO_CRC_CHECKS

+	orig_crc = file_read_ul(png);

+

+	calc_crc = crc32(0L, Z_NULL, 0);

+	calc_crc = crc32(calc_crc, ihdr, 13+4);

+

+	if(orig_crc != calc_crc)

+		return PNG_CRC_ERROR;

+#else

+	file_read_ul(png);

+#endif

+

+	png->width = get_ul(ihdr+4);

+	png->height = get_ul(ihdr+8);

+	png->depth = ihdr[12];

+	png->color_type = ihdr[13];

+	png->compression_method = ihdr[14];

+	png->filter_method = ihdr[15];

+	png->interlace_method = ihdr[16];

+

+	if(png->color_type == PNG_INDEXED)

+		return PNG_NOT_SUPPORTED;

+

+	if(png->depth != 8 && png->depth != 16)

+		return PNG_NOT_SUPPORTED;

+

+	if(png->interlace_method)

+		return PNG_NOT_SUPPORTED;

+	

+	return PNG_NO_ERROR;

+}

+

+void png_print_info(png_t* png)

+{

+	printf("PNG INFO:\n");

+	printf("\twidth:\t\t%d\n", png->width);

+	printf("\theight:\t\t%d\n", png->height);

+	printf("\tdepth:\t\t%d\n", png->depth);

+	printf("\tcolor:\t\t");

+

+	switch(png->color_type)

+	{

+	case PNG_GREYSCALE:			printf("greyscale\n"); break;

+	case PNG_TRUECOLOR:			printf("truecolor\n"); break;

+	case PNG_INDEXED:			printf("palette\n"); break;

+	case PNG_GREYSCALE_ALPHA:	printf("greyscale with alpha\n"); break;

+	case PNG_TRUECOLOR_ALPHA:	printf("truecolor with alpha\n"); break;

+	default:					printf("unknown, this is not good\n"); break;

+	}

+

+	printf("\tcompression:\t%s\n",	png->compression_method?"unknown, this is not good":"inflate/deflate");

+	printf("\tfilter:\t\t%s\n",		png->filter_method?"unknown, this is not good":"adaptive");

+	printf("\tinterlace:\t%s\n",	png->interlace_method?"interlace":"no interlace");

+}

+

+

+int png_open(png_t* png, png_read_callback_t read_fun, void* user_pointer)

+{

+	char header[8];

+	int result;

+

+	png->read_fun = read_fun;

+	png->user_pointer = user_pointer;

+

+	if(!read_fun && !user_pointer)

+		return PNG_WRONG_ARGUMENTS;

+

+	if(file_read(png, header, 1, 8) != 8)

+		return PNG_EOF_ERROR;

+

+	if(memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) != 0)

+		return PNG_HEADER_ERROR;

+

+	result = png_read_ihdr(png);

+

+	png->bpp = png_get_bpp(png);

+

+	return result;

+}

+

+int png_open_file(png_t *png, const char* filename)

+{

+	FILE* fp = fopen(filename, "rb");

+

+	if(!fp)

+		return PNG_FILE_ERROR;

+

+	return png_open(png, 0, fp);

+}	

+

+int png_close_file(png_t* png)

+{

+	fclose(png->user_pointer);

+

+	return PNG_NO_ERROR;

+}

+

+static int png_init_inflate(png_t* png)

+{

+	z_stream *stream;

+	png->zs = png_alloc(sizeof(z_stream));

+

+	stream = png->zs;

+

+	if(!stream)

+		return PNG_MEMORY_ERROR;

+

+	memset(stream, 0, sizeof(z_stream));

+

+	if(inflateInit(stream) != Z_OK)

+		return PNG_ZLIB_ERROR;

+

+	stream->next_out = png->png_data;

+	stream->avail_out = png->png_datalen;

+

+	return PNG_NO_ERROR;

+}

+

+static int png_end_inflate(png_t* png)

+{

+	z_stream *stream = png->zs;

+

+	if(!stream)

+		return PNG_MEMORY_ERROR;

+

+	if(inflateEnd(stream) != Z_OK)

+	{

+		printf("ZLIB says: %s\n", stream->msg);

+		return PNG_ZLIB_ERROR;

+	}

+

+	png_free(png->zs);

+

+	return PNG_NO_ERROR;

+}

+

+static int png_inflate(png_t* png, unsigned char* data, int len)

+{

+	int result;

+	z_stream *stream = png->zs;

+

+	if(!stream)

+		return PNG_MEMORY_ERROR;

+

+	stream->next_in = data;

+	stream->avail_in = len;

+	

+	result = inflate(stream, Z_SYNC_FLUSH);

+

+	if(result != Z_STREAM_END && result != Z_OK)

+	{

+		printf("%s\n", stream->msg);

+		return PNG_ZLIB_ERROR;

+	}

+

+	if(stream->avail_in != 0)

+		return PNG_ZLIB_ERROR;

+

+	return PNG_NO_ERROR;

+}

+

+static int png_read_idat(png_t* png, unsigned char* output, unsigned out_len, unsigned firstlen) 

+{

+	unsigned type;

+	char *chunk;

+	int result;

+	unsigned length = firstlen;

+	unsigned old_len = length;

+

+#if DO_CRC_CHECKS

+	unsigned orig_crc;

+	unsigned calc_crc;

+#endif

+

+	chunk = png_alloc(firstlen); 

+

+	result = png_init_inflate(png);

+

+	if(result != PNG_NO_ERROR)

+	{

+		png_end_inflate(png);

+		png_free(chunk); 

+		return result;

+	}

+

+	do

+	{

+		if(file_read(png, chunk, 1, length) != length)

+		{

+			png_end_inflate(png);

+			png_free(chunk); 

+			return PNG_FILE_ERROR;

+		}

+

+#if DO_CRC_CHECKS

+		calc_crc = crc32(0L, Z_NULL, 0);

+		calc_crc = crc32(calc_crc, "IDAT", 4);

+		calc_crc = crc32(calc_crc, chunk, length);

+

+		orig_crc = file_read_ul(png);

+

+		if(orig_crc != calc_crc)

+		{

+			result = PNG_CRC_ERROR;

+			break;

+		}

+#else

+		file_read_ul(png);

+#endif

+

+		result = png_inflate(png, chunk, length);

+

+		if(result != PNG_NO_ERROR) break;

+		

+		length = file_read_ul(png);

+

+		if(length > old_len)

+		{

+			png_free(chunk); 

+			chunk = png_alloc(length); 

+			old_len = length;

+		}

+

+		if(file_read(png, &type, 1, 4) != 4)

+		{

+			result = PNG_FILE_ERROR;

+			break;

+		}

+

+	}while(type == *(int*)"IDAT");

+

+	if(type == *(int*)"IEND")

+		result = PNG_DONE;

+

+	png_free(chunk);

+	png_end_inflate(png);

+

+	return result;

+}

+

+static int png_process_chunk(png_t* png)

+{

+	int result = PNG_NO_ERROR, idat_len = 0;

+	unsigned type;

+	unsigned length;

+

+	length = file_read_ul(png);

+

+	if(file_read(png, &type, 1, 4) != 4)

+		return PNG_FILE_ERROR;

+

+	if(type == *(int*)"IDAT")	// if we found an idat, all other idats should be followed with no other chunks in between

+	{

+		png->png_datalen = png->width * png->height * png->bpp + png->height;

+		png->png_data = png_alloc(png->png_datalen);

+		

+		if(!png->png_data)

+			return PNG_MEMORY_ERROR;

+

+		return png_read_idat(png, png->png_data, png->png_datalen, length);

+	}

+	else if(type == *(int*)"IEND")

+	{

+		return PNG_DONE;

+	}

+	else

+	{

+		file_read(png, 0, 1, length + 4);		// unknown chunk

+	}

+

+	return result;

+}

+

+static void png_filter_sub(png_t* png, int stride, unsigned char* in, unsigned char* out, int len)

+{

+	int i;

+	unsigned char a = 0;

+

+	for(i = 0; i < len; i++)

+	{

+		if(i >= stride)

+			a = out[i - stride];

+		

+		out[i] = in[i] + a;

+	}

+}

+

+static void png_filter_up(png_t* png, int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len)

+{

+	int i;

+

+	if(prev_line) 

+    { 

+        for(i = 0; i < len; i++) 

+            out[i] = in[i] + prev_line[i]; 

+    } 

+    else 

+        memcpy(out, in, len);

+}

+

+static void png_filter_average(png_t* png, int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len)

+{

+	int i;

+	unsigned char a = 0;

+	unsigned char b = 0;

+	unsigned int sum = 0;

+

+	for(i = 0; i < len; i++)

+	{

+		if(prev_line)

+			b = prev_line[i];

+

+		if(i >= stride)

+			a = out[i - stride];

+

+		sum = a;

+		sum += b;

+

+		out[i] = in[i] + sum/2;

+	}

+}

+

+static unsigned char png_paeth(unsigned char a, unsigned char b, unsigned char c)

+{

+	int p = (int)a + b - c;

+	int pa = abs(p - a);

+	int pb = abs(p - b);

+	int pc = abs(p - c);

+

+	int pr;

+

+	if(pa <= pb && pa <= pc)

+		pr = a;

+	else if(pb <= pc)

+		pr = b;

+	else

+		pr = c;

+

+	return pr;

+}

+

+static void png_filter_paeth(png_t* png, int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len)

+{

+	int i;

+	unsigned char a;

+	unsigned char b;

+	unsigned char c;

+

+	for(i = 0; i < len; i++)

+	{

+		if(prev_line && i >= stride)

+		{

+			a = out[i - stride];

+			b = prev_line[i];

+			c = prev_line[i - stride];

+		}

+		else

+		{

+			if(prev_line)

+				b = prev_line[i];

+			else

+				b = 0;

+	

+			if(i >= stride)

+				a = out[i - stride];

+			else

+				a = 0;

+

+			c = 0;

+		}

+

+		out[i] = in[i] + png_paeth(a, b, c);

+	}

+}

+

+static int png_unfilter(png_t* png, unsigned char* data)

+{

+	unsigned i;

+	unsigned pos = 0;

+	unsigned outpos = 0;

+	unsigned char *filtered = png->png_data;

+

+	int stride = png->bpp;

+

+	while(pos < png->png_datalen)

+	{

+		unsigned char filter = filtered[pos];

+

+		pos++;

+

+		if(png->depth == 16)

+		{

+			for(i = 0; i < png->width * stride; i+=2)

+			{

+				*(short*)(filtered+pos+i) = (filtered[pos+i] << 8) | filtered[pos+i+1];

+			}

+		}

+

+		switch(filter)

+		{

+		case 0: // none

+			memcpy(data+outpos, filtered+pos, png->width * stride);

+			break;

+		case 1: // sub

+			png_filter_sub(png, stride, filtered+pos, data+outpos, png->width * stride);

+			break;

+		case 2: // up

+			if(outpos)

+				png_filter_up(png, stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride);

+			else

+				png_filter_up(png, stride, filtered+pos, data+outpos, 0, png->width*stride);

+			break;

+		case 3: // average

+			if(outpos)

+				png_filter_average(png, stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride);

+			else

+				png_filter_average(png, stride, filtered+pos, data+outpos, 0, png->width*stride);

+			break;

+		case 4: // paeth

+			if(outpos)

+				png_filter_paeth(png, stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride);

+			else

+				png_filter_paeth(png, stride, filtered+pos, data+outpos, 0, png->width*stride);

+			break;

+		default:

+			return PNG_UNKNOWN_FILTER;

+		}

+

+		outpos += png->width * stride;

+		pos += png->width * stride;

+	}

+

+	return PNG_NO_ERROR;

+}

+

+int png_get_data(png_t* png, unsigned char* data)

+{

+	int result = PNG_NO_ERROR;

+

+	while(result == PNG_NO_ERROR)

+	{

+		result = png_process_chunk(png);

+	}

+

+	if(result != PNG_DONE)

+	{

+		png_free(png->png_data); 

+		return result;

+	}

+

+	result = png_unfilter(png, data);

+

+	png_free(png->png_data); 

+

+	return result;

+}

+

+char* png_error_string(int error)

+{

+	switch(error)

+	{

+	case PNG_NO_ERROR:

+		return "No error";

+	case PNG_FILE_ERROR:

+		return "Unknown file error.";

+	case PNG_HEADER_ERROR:

+		return "No PNG header found. Are you sure this is a PNG?";

+	case PNG_IO_ERROR:

+		return "Failure while reading file.";

+	case PNG_EOF_ERROR:

+		return "Reached end of file.";

+	case PNG_CRC_ERROR:

+		return "CRC or chunk length error.";

+	case PNG_MEMORY_ERROR:

+		return "Could not allocate memory.";

+	case PNG_ZLIB_ERROR:

+		return "zlib reported an error.";

+	case PNG_UNKNOWN_FILTER:

+		return "Unknown filter method used in scanline.";

+	case PNG_DONE:

+		return "PNG done";

+	case PNG_NOT_SUPPORTED:

+		return "The PNG is unsupported by pnglite, too bad for you!";

+	case PNG_WRONG_ARGUMENTS:

+		return "Wrong combination of arguments passed to png_open. You must use either a read_function or supply a file pointer to use.";

+	default:

+		return "Unknown error.";

+	};

+}

+

diff --git a/src/engine/client/pnglite/pnglite.h b/src/engine/client/pnglite/pnglite.h
new file mode 100644
index 00000000..012a38d1
--- /dev/null
+++ b/src/engine/client/pnglite/pnglite.h
@@ -0,0 +1,212 @@
+/*  pnglite.h - Interface for pnglite library

+	Copyright (c) 2007 Daniel Karling

+

+	This software is provided 'as-is', without any express or implied

+	warranty. In no event will the authors be held liable for any damages

+	arising from the use of this software.

+

+	Permission is granted to anyone to use this software for any purpose,

+	including commercial applications, and to alter it and redistribute it

+	freely, subject to the following restrictions:

+

+	1. The origin of this software must not be misrepresented; you must not

+	   claim that you wrote the original software. If you use this software

+	   in a product, an acknowledgment in the product documentation would be

+	   appreciated but is not required.  

+

+	2. Altered source versions must be plainly marked as such, and must not be

+	   misrepresented as being the original software.

+

+	3. This notice may not be removed or altered from any source

+	   distribution.

+

+	Daniel Karling

+	daniel.karling@gmail.com

+ */

+

+

+#ifndef _PNGLITE_H_

+#define _PNGLITE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif

+

+/*

+	Enumerations for pnglite.

+	Negative numbers are error codes and 0 and up are okay responses.

+*/

+

+enum

+{

+	PNG_DONE				= 1,

+	PNG_NO_ERROR			= 0,

+	PNG_FILE_ERROR			= -1,

+	PNG_HEADER_ERROR		= -2,

+	PNG_IO_ERROR			= -3,

+	PNG_EOF_ERROR			= -4,

+	PNG_CRC_ERROR			= -5,

+	PNG_MEMORY_ERROR		= -6,

+	PNG_ZLIB_ERROR			= -7,

+	PNG_UNKNOWN_FILTER		= -8,

+	PNG_NOT_SUPPORTED		= -9,

+	PNG_WRONG_ARGUMENTS		= -10

+};

+

+/*

+	The five different kinds of color storage in PNG files.

+*/

+

+enum

+{

+	PNG_GREYSCALE			= 0,

+	PNG_TRUECOLOR			= 2,

+	PNG_INDEXED				= 3,

+	PNG_GREYSCALE_ALPHA		= 4,

+	PNG_TRUECOLOR_ALPHA		= 6

+};

+

+/*

+	Typedefs for callbacks.

+*/

+

+typedef unsigned (*png_read_callback_t)(void* output, unsigned size, unsigned numel, void* user_pointer);

+typedef void (*png_free_t)(void* p);

+typedef void * (*png_alloc_t)(unsigned s);

+

+typedef struct

+{

+	void*					zs;				// pointer to z_stream

+	png_read_callback_t		read_fun;

+	void*					user_pointer;

+

+	unsigned char*			png_data;

+	unsigned				png_datalen;

+

+	unsigned				width;

+	unsigned				height;

+	unsigned char			depth;

+	unsigned char			color_type;

+	unsigned char			compression_method;

+	unsigned char			filter_method;

+	unsigned char			interlace_method;

+	unsigned char			bpp;

+}png_t;

+

+/*

+	Function: png_init

+

+	This function initializes pnglite. The parameters can be used to set your own memory allocation routines following these formats:

+

+	> void* (*custom_alloc)(size_t s)

+	> void (*custom_free)(void* p)

+	Parameters:

+		pngalloc - Pointer to custom allocation routine. If 0 is passed, malloc from libc will be used.

+		pngfree - Pointer to custom free routine. If 0 is passed, free from libc will be used.

+

+	Returns:

+		Always returns PNG_NO_ERROR.

+*/

+

+int png_init(png_alloc_t pngalloc, png_free_t pngfree);

+

+/*

+	Function: png_open_file

+

+	This function is used to open a png file with the internal file IO system. This function should be used instead of

+	png_open if no custom read function is used.

+

+	Parameters:

+		png - Empty png_t struct.

+		filename - Filename of the file to be opened.

+

+	Returns:

+		PNG_NO_ERROR on success, otherwise an error code.

+*/

+

+int png_open_file(png_t *png, const char* filename);

+

+/*

+	Function: png_open

+

+	This function reads a png from the specified callback. The callback should be of the format:

+

+	> size_t (*png_read_callback_t)(void* output, size_t size, size_t numel, void* user_pointer).

+

+	The callback will be called each time pnglite needs more data. The callback should read as much data as requested, 

+	or return 0. This should always be possible if the PNG is sane.	If the output-buffer is a null-pointer the callback 

+	should only skip ahead the specified number of elements. If the callback is a null-pointer the user_pointer will be 

+	treated as a file pointer (use png_open_file instead).

+

+	Parameters:

+		png - png_t struct

+		read_fun - Callback function for reading.

+		user_pointer - User pointer to be passed to read_fun.

+

+	Returns:

+		PNG_NO_ERROR on success, otherwise an error code.

+*/

+

+int png_open(png_t* png, png_read_callback_t read_fun, void* user_pointer);

+

+/*

+	Function: png_print_info

+

+	This function prints some info about the opened png file to stdout.

+

+	Parameters:

+		png - png struct to get info from.

+*/

+

+void png_print_info(png_t* png);

+

+/*

+	Function: png_error_string

+

+	This function translates an error code to a human readable string.

+

+	Parameters:

+		error - Error code.

+

+	Returns:

+		Pointer to string.

+*/

+

+char* png_error_string(int error);

+

+/*

+	Function: png_get_data

+

+	This function decodes the opened png file and stores the result in data. data should be big enough to hold the decoded png. Required size will be:

+	

+	> width*height*(bytes per pixel)

+

+	Parameters:

+		data - Where to store result.

+

+	Returns:

+		PNG_NO_ERROR on success, otherwise an error code.

+*/

+

+int png_get_data(png_t* png, unsigned char* data);

+

+/*

+	Function: png_close_file

+

+	Closes an open png file pointer. Should only be used when the png has been opened with png_open_file.

+

+	Parameters:

+		png - png to close.

+	

+	Returns:

+		PNG_NO_ERROR

+*/

+

+int png_close_file(png_t* png);

+
+#ifdef __cplusplus
+}
+#endif
+
+

+#endif

diff --git a/src/engine/interface.h b/src/engine/interface.h
index 95ea0252..200e7322 100644
--- a/src/engine/interface.h
+++ b/src/engine/interface.h
@@ -15,6 +15,11 @@ enum
 	SERVER_CLIENT_TIMEOUT=5,
 	SNAP_CURRENT=0,
 	SNAP_PREV=1,
+	
+	IMG_RGB=0,
+	IMG_RGBA,
+	IMG_BGR,
+	IMG_BGRA,
 };
 
 struct snap_item
@@ -33,10 +38,12 @@ public:
 struct image_info
 {
 	int width, height;
+	int format;
 	void *data;
 };
 
 int gfx_load_tga(image_info *img, const char *filename);
+int gfx_load_png(image_info *img, const char *filename);
 
 
 /*
@@ -50,8 +57,8 @@ void gfx_swap(); // NOT EXPOSED
 
 // textures
 /*
-	Function: gfx_load_texture_tga
-		Loads a TGA from file.
+	Function: gfx_load_texture
+		Loads a texture from a file. TGA and PNG supported.
 	
 	Arguments:
 		filename - Null terminated string to the file to load.
@@ -62,7 +69,7 @@ void gfx_swap(); // NOT EXPOSED
 	See Also:
 		<gfx_unload_texture>
 */
-int gfx_load_texture_tga(const char *filename);
+int gfx_load_texture(const char *filename);
 
 /*
 	Function: gfx_load_texture_raw
@@ -83,7 +90,7 @@ int gfx_load_texture_tga(const char *filename);
 	See Also:
 		<gfx_unload_texture>
 */
-int gfx_load_texture_raw(int w, int h, const void *data);
+int gfx_load_texture_raw(int w, int h, int format, const void *data);
 
 /*
 	Function: gfx_texture_set
diff --git a/src/engine/packet.h b/src/engine/packet.h
index 6dc99043..fd93d744 100644
--- a/src/engine/packet.h
+++ b/src/engine/packet.h
@@ -1,9 +1,14 @@
 #include <baselib/stream/file.h>
 #include <baselib/network.h>
 
+#include "versions.h"
+
+#define MACRO_MAKEINT(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|d)
+
 // TODO: this is not KISS
 class packet
 {
+	friend class connection;
 protected:
 	enum
 	{
@@ -13,6 +18,11 @@ protected:
 	// packet data
 	struct header
 	{
+		unsigned id;
+		unsigned version;
+		unsigned size_and_flags;
+		unsigned crc;
+		
 		unsigned msg;
 		unsigned ack;
 		unsigned seq;
@@ -60,10 +70,20 @@ protected:
 	}
 	
 public:
+
+	enum
+	{
+		FLAG_VITAL=1,
+		FLAG_RESEND=2
+	};
+
 	packet(unsigned msg=0)
 	{
 		current = packet_data;
 		current += sizeof(header);
+
+		((header*)packet_data)->id = MACRO_MAKEINT('K','M','A',1);
+		((header*)packet_data)->version = TEEWARS_NETVERSION;
 		((header*)packet_data)->msg = msg;
 	}
 	
@@ -128,9 +148,11 @@ public:
 	// TODO: impelement this
 	bool is_good() const { return true; }
 
+	unsigned version() const { return ((header*)packet_data)->version; }
 	unsigned msg() const { return ((header*)packet_data)->msg; }
 	unsigned seq() const { return ((header*)packet_data)->seq; }
 	unsigned ack() const { return ((header*)packet_data)->ack; }
+	unsigned flags() const { return (((header*)packet_data)->size_and_flags) & 0xffff; }
 	
 	// access functions to get the size and data
 	int size() const { return (int)(current-(unsigned char*)packet_data); }
@@ -138,6 +160,89 @@ public:
 	void *data() { return packet_data; }
 };
 
+// TODO: remove all the allocations from this class
+class ring_buffer
+{
+	struct item
+	{
+		item *next;
+		item *prev;
+		int size;
+	};
+	
+	item *first;
+	item *last;
+	
+	unsigned buffer_size;
+public:
+	ring_buffer()
+	{
+		first = 0;
+		last = 0;
+		buffer_size = 0;
+	}
+	
+	~ring_buffer()
+	{
+		reset();
+	}
+	
+	void reset()
+	{
+		// clear all
+		while(peek_data())
+			next();		
+	}
+	
+	void *alloc(int size)
+	{
+		item *i = (item*)mem_alloc(sizeof(item)+size, 1);
+		i->size = size;
+		
+		i->prev = last;
+		i->next = 0;
+		if(last)
+			last->next = i;
+		else
+			first = i;
+		last = i;
+		
+		buffer_size += size;
+		return (void*)(i+1);
+	}
+	
+	unsigned peek_size()
+	{
+		if(!first)
+			return 0;
+		return first->size;
+	}
+
+	void *peek_data()
+	{
+		if(!first)
+			return 0;
+		return (void*)(first+1);
+	}
+	
+	void next()
+	{
+		if(first)
+		{
+			item *next = first->next;
+			buffer_size += first->size;
+			mem_free(first);
+			first = next;
+			if(first)
+				first->prev = 0;
+			else
+				last = 0;
+		}
+	}
+	
+	unsigned size() { return buffer_size; }
+};
+
 //
 class connection
 {
@@ -145,11 +250,52 @@ class connection
 	baselib::netaddr4 addr;
 	unsigned seq;
 	unsigned ack;
-	unsigned last_ack;
 	
 	unsigned counter_sent_bytes;
 	unsigned counter_recv_bytes;
 	
+	int needs_resend;
+	
+	/*
+	struct resend_packet
+	{
+		resend_packet *next;
+		unsigned seq;
+		unsigned msg;
+		unsigned size;
+		char data[1];
+	};
+	
+	resend_packet *first_resend;
+	resend_packet *last_resend;
+	*/
+	
+	ring_buffer resend_buffer;
+
+	void save_for_resend(packet *p)
+	{
+		/*
+		packet *n = (packet *)resend_buffer.alloc(p->size());
+		mem_copy(n->data(), p->data(), p->size());
+		n->current = (unsigned char*)n->data() + p->size();
+		*/
+	}
+	
+	void remove_resends(unsigned ack)
+	{
+		/*
+		while(1)
+		{
+			packet *p = (packet *)resend_buffer.peek_data();
+			if(!p)
+				break;
+			
+			if(p->seq() > ack)
+				break;
+			resend_buffer.next();
+		}*/
+	}
+	
 public:
 	void counter_reset()
 	{
@@ -165,24 +311,28 @@ public:
 
 	void init(baselib::socket_udp4 *socket, const baselib::netaddr4 *addr)
 	{
+		resend_buffer.reset();
+		
 		this->addr = *addr;
 		this->socket = socket;
-		last_ack = 0;
 		ack = 0;
 		seq = 0;
+		needs_resend = 0;
 		counter_reset();
 	}
 	
 	void send(packet *p)
 	{
-		if(p->msg()&(31<<1))
-		{
-			// vital packet
+		if(p->flags()&packet::FLAG_VITAL)
 			seq++;
-			// TODO: save packet, we might need to retransmit
-		}
 		
 		p->set_header(ack, seq);
+
+		if(p->flags()&packet::FLAG_VITAL)
+			save_for_resend(p);
+
+		// TODO: request resend if needed, use needs_resend variable
+		
 		socket->send(&address(), p->data(), p->size());
 		counter_sent_bytes += p->size();
 	}
@@ -191,7 +341,7 @@ public:
 	{
 		counter_recv_bytes += p->size();
 		
-		if(p->msg()&(31<<1))
+		if(p->flags()&packet::FLAG_VITAL)
 		{
 			if(p->seq() == ack+1)
 			{
@@ -202,8 +352,8 @@ public:
 			}
 			else if(p->seq() > ack)
 			{
-				// TODO: request resend
 				// packet loss
+				needs_resend = 1;
 				dbg_msg("network/connection", "packet loss! seq=%x ack=%x+1", p->seq(), ack);
 				return p;
 			}
@@ -214,9 +364,14 @@ public:
 			}
 		}
 		
-		if(last_ack != p->ack())
+		// remove resends
+		remove_resends(p->ack());
+		
+		// handle resends
+		if(p->flags()&packet::FLAG_RESEND)
 		{
-			// TODO: remove acked packets
+			// peer as requested a resend of all non acked packages.
+			
 		}
 		
 		return p;		
@@ -233,7 +388,6 @@ public:
 
 enum
 {
-	NETMSG_VITAL=0x80000000,
 	NETMSG_CONTEXT_CONNECT=0x00010000,
 	NETMSG_CONTEXT_GAME=0x00020000,
 	NETMSG_CONTEXT_GLOBAL=0x00040000,
@@ -253,7 +407,7 @@ enum
 		// str32 mapname
 
 	
-	NETMSG_CLIENT_DONE=NETMSG_VITAL|NETMSG_CONTEXT_CONNECT|3,
+	NETMSG_CLIENT_DONE=NETMSG_CONTEXT_CONNECT|3,
 		// nothing
 	
 	// game phase
@@ -266,10 +420,10 @@ enum
 	NETMSG_CLIENT_INPUT = NETMSG_CONTEXT_GAME|1, // client will spam these
 		// int input[MAX_INPUTS]
 	
-	NETMSG_SERVER_EVENT = NETMSG_CONTEXT_GAME|NETMSG_VITAL|2,
-	NETMSG_CLIENT_EVENT = NETMSG_CONTEXT_GAME|NETMSG_VITAL|2,
+	NETMSG_SERVER_EVENT = NETMSG_CONTEXT_GAME|2,
+	NETMSG_CLIENT_EVENT = NETMSG_CONTEXT_GAME|2,
 
-	NETMSG_CLIENT_CHECKALIVE = NETMSG_CONTEXT_GAME|NETMSG_VITAL|3, // check if client is alive
+	NETMSG_CLIENT_CHECKALIVE = NETMSG_CONTEXT_GAME|3, // check if client is alive
 	
 	NETMSG_CLIENT_ERROR=0x0fffffff,
 		// str128 reason
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index d9151a43..c272ec91 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -1,5 +1,16 @@
 #include <stdio.h>
#include <string.h>

#include <baselib/system.h>

#include <engine/interface.h>

//#include "socket.h"
#include <engine/packet.h>
#include <engine/snapshot.h>

#include <engine/lzw.h>
#include <engine/versions.h>

namespace baselib {}
using namespace baselib;

int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b)
{
	if(
		a->ip[0] != b->ip[0] ||
		a->ip[1] != b->ip[1] ||
		a->ip[2] != b->ip[2] ||
		a->ip[3] != b->ip[3] ||
		a->port != b->port
	)
		return 1;
	return 0;
}

// --- string handling (MOVE THESE!!) ---
void snap_encode_string(const char *src, int *dst, int length, int max_length)
{
        const unsigned char *p = (const unsigned char *)src;

        // handle whole int
        for(int i = 0; i < length/4; i++)
        {
                *dst = (p[0]<<24|p[1]<<16|p[2]<<8|p[3]);
                p += 4;
                dst++;
        }

        // take care of the left overs
        int left = length%4;
        if(left)
        {
                unsigned last = 0;
                switch(left)
                {
                        case 3: last |= p[2]<<8;
                        case 2: last |= p[1]<<16;
                        case 1: last |= p[0]<<24;
                }
                *dst = last;
        }
}


class snapshot_builder
{
public:
	static const int MAX_ITEMS = 512;
	//static const int MAX_DATA_SIZE=1*1024;

	char data[MAX_SNAPSHOT_SIZE];
	int data_size;

	int offsets[MAX_ITEMS];
	int num_items;

	int top_size;
	int top_items;

	int snapnum;

	snapshot_builder()
	{
		top_size = 0;
		top_items = 0;
		snapnum = 0;
	}
	
	void start()
	{
		data_size = 0;
		num_items = 0;
	}
	
	int finish(void *snapdata)
	{
		snapnum++;
		
		// collect some data
		/*
		int change = 0;
		if(data_size > top_size)
		{
			change++;
			top_size = data_size;
		}
		
		if(num_items > top_items)
		{
			change++;
			top_items = num_items;
		}
		
		if(change)
		{
			dbg_msg("snapshot", "new top, items=%d size=%d", top_items, top_size);
		}*/
		
		// flattern and make the snapshot
		snapshot *snap = (snapshot *)snapdata;
		snap->num_items = num_items;
		int offset_size = sizeof(int)*num_items;
		mem_copy(snap->offsets, offsets, offset_size);
		mem_copy(snap->data_start(), data, data_size);
		return sizeof(int) + offset_size + data_size;
	}
	
	void *new_item(int type, int id, int size)
	{
		snapshot::item *obj = (snapshot::item *)(data+data_size);
		obj->type_and_id = (type<<16)|id;
		offsets[num_items] = data_size;
		data_size += sizeof(int) + size;
		num_items++;
		dbg_assert(data_size < MAX_SNAPSHOT_SIZE, "too much data");
		dbg_assert(num_items < MAX_ITEMS, "too many items");
		
		return &obj->data;
	}
};

static snapshot_builder builder;

void *snap_new_item(int type, int id, int size)
{
	dbg_assert(type >= 0 && type <=0xffff, "incorrect type");
	dbg_assert(id >= 0 && id <=0xffff, "incorrect id");
	return builder.new_item(type, id, size);
}


//
class client
{
public:
	enum
	{
		STATE_EMPTY = 0,
		STATE_CONNECTING = 1,
		STATE_INGAME = 2,
	};

	// connection state info
	int state;

	// (ticks) if lastactivity > 5 seconds kick him
	int64 lastactivity;
	connection conn;
	
	char name[MAX_NAME_LENGTH];
	char clan[MAX_CLANNAME_LENGTH];
	/*
	client()
	{
		state = STATE_EMPTY;
		name[0] = 0;
		clan[0] = 0;
	}
	
	~client()
	{
		dbg_assert(state == STATE_EMPTY, "client destoyed while in use");
	}*/
	
	bool is_empty() const { return state == STATE_EMPTY; }
	bool is_ingame() const { return state == STATE_INGAME; }
	const netaddr4 &address() const { return conn.address(); }
};

static client clients[MAX_CLIENTS];
static int current_tick = 0;
static int send_heartbeats = 1;

int server_tick()
{
	return current_tick;
}

int server_tickspeed()
{
	return 50;
}

int server_init()
{
	for(int i = 0; i < MAX_CLIENTS; i++)
	{
		clients[i].state = client::STATE_EMPTY;
		clients[i].name[0] = 0;
		clients[i].clan[0] = 0;
		clients[i].lastactivity = 0;
	}
	
	current_tick = 0;
	
	return 0;
}

int server_getclientinfo(int client_id, client_info *info)
{
	dbg_assert(client_id >= 0 && client_id < MAX_CLIENTS, "client_id is not valid");
	dbg_assert(info != 0, "info can not be null");
	
	if(clients[client_id].is_ingame())
	{
		info->name = clients[client_id].name;
		info->latency = 0;
		return 1;
	}
	return 0;
}

//
class server
{
public:

	socket_udp4 game_socket;
 
-	const char *map_name;
	const char *server_name;
	int64 lasttick;
	int64 lastheartbeat;
	netaddr4 master_server;

	int biggest_snapshot;
	
	bool run(const char *servername, const char *mapname)
	{
		biggest_snapshot = 0;
		
		net_init(); // For Windows compatibility.
		map_name = mapname;
		server_name = servername;

		// load map
		if(!map_load(mapname))
		{
			dbg_msg("server", "failed to load map. mapname='%s'");
			return false;
		}
		
		// start server
		if(!game_socket.open(8303))
		{
			dbg_msg("network/server", "couldn't open socket");
			return false;
		}

		for(int i = 0; i < MAX_CLIENTS; i++)
			dbg_msg("network/server", "\t%d: %d", i, clients[i].state);

		if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &master_server) != 0)
		{
			// TODO: fix me
			//master_server = netaddr4(0, 0, 0, 0, 0);
		}
		
		mods_init();
		
		int64 time_per_tick = time_freq()/SERVER_TICK_SPEED;
		int64 time_per_heartbeat = time_freq() * 30;
		int64 starttime = time_get();
		//int64 lasttick = starttime;
		lasttick = starttime;
		lastheartbeat = 0;

		int64 reporttime = time_get();
		int64 reportinterval = time_freq()*3;
		
		int64 simulationtime = 0;
		int64 snaptime = 0;
		int64 networktime = 0;
		
		while(1)
		{
			int64 t = time_get();
			if(t-lasttick > time_per_tick)
			{
				{
					int64 start = time_get();
					tick();
					simulationtime += time_get()-start;
				}
				
				{
					int64 start = time_get();
					snap();
					snaptime += time_get()-start;
				}

				// Check for client timeouts
				for (int i = 0; i < MAX_CLIENTS; i++)
				{
					if (clients[i].state != client::STATE_EMPTY)
					{
						// check last activity time
						if (((lasttick - clients[i].lastactivity) / time_freq()) > SERVER_CLIENT_TIMEOUT)
							client_timeout(i);
					}
				}
				
				lasttick += time_per_tick;
			}

			if(send_heartbeats)
			{
				if (t > lastheartbeat+time_per_heartbeat)
				{
					if (master_server.port != 0)
					{
						int players = 0;
						
						for (int i = 0; i < MAX_CLIENTS; i++)
							if (!clients[i].is_empty())
								players++;
						
						// TODO: fix me
						netaddr4 me(127, 0, 0, 0, 8303);
						
						send_heartbeat(0, &me, players, MAX_CLIENTS, server_name, mapname);
					}

					lastheartbeat = t+time_per_heartbeat;
				}
			}
			
			{
				int64 start = time_get();
				pump_network();
				networktime += time_get()-start;
			}
			
			if(reporttime < time_get())
			{
				int64 totaltime = simulationtime+snaptime+networktime;
				dbg_msg("server/report", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%",
					simulationtime/(float)reportinterval*1000,
					snaptime/(float)reportinterval*1000,
					networktime/(float)reportinterval*1000,
					totaltime/(float)reportinterval*1000,
					(simulationtime+snaptime+networktime)/(float)reportinterval*100.0f);

				unsigned sent_total=0, recv_total=0;
				for (int i = 0; i < MAX_CLIENTS; i++)
					if (!clients[i].is_empty())
					{
						unsigned s,r;
						clients[i].conn.counter_get(&s,&r);
						clients[i].conn.counter_reset();
						sent_total += s;
						recv_total += r;
					}

				
				dbg_msg("server/report", "biggestsnap=%d send=%d recv=%d",
					biggest_snapshot, sent_total/3, recv_total/3);

				simulationtime = 0;
				snaptime = 0;
				networktime = 0;
				
				reporttime += reportinterval;
			}
			
			thread_sleep(1);
		}
		
		mods_shutdown();
		map_unload();
	}
	
	void tick()
	{
		current_tick++;
		mods_tick();
	}

	void snap()
	{
		mods_presnap();
	
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			if(clients[i].is_ingame())
			{
				char data[MAX_SNAPSHOT_SIZE];
				char compdata[MAX_SNAPSHOT_SIZE];
				builder.start();
				mods_snap(i);

				// finish snapshot
				int snapshot_size = builder.finish(data);
				
				// compress it
				int compsize = lzw_compress(data, snapshot_size, compdata);
				snapshot_size = compsize;

				if(snapshot_size > biggest_snapshot)
					biggest_snapshot = snapshot_size;
				
				const int max_size = MAX_SNAPSHOT_PACKSIZE;
				int numpackets = (snapshot_size+max_size-1)/max_size;
				for(int n = 0, left = snapshot_size; left; n++)
				{
					int chunk = left < max_size ? left : max_size;
					left -= chunk;
					
					packet p(NETMSG_SERVER_SNAP);
					p.write_int(numpackets);
					p.write_int(n);
					p.write_int(chunk);
					p.write_raw(&compdata[n*max_size], chunk);
					clients[i].conn.send(&p);
				}
			}
		}
		
		mods_postsnap();
	}	

	void send_accept(client *client, const char *map)
	{
		packet p(NETMSG_SERVER_ACCEPT);
		p.write_str(map);
		client->conn.send(&p);
	}
	
	void drop(int cid, const char *reason)
	{
		if(clients[cid].state == client::STATE_EMPTY)
			return;
		
		clients[cid].state = client::STATE_EMPTY;
		mods_client_drop(cid);
		dbg_msg("game", "player dropped. reason='%s' cid=%x name='%s'", reason, cid, clients[cid].name);
	}
	
	int find_client(const netaddr4 *addr)
	{
		// fetch client
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			if(!clients[i].is_empty() && clients[i].address() == *addr)
				return i;
		}		
		return -1;
	}
	
	void client_process_packet(int cid, packet *p)
	{
		clients[cid].lastactivity = lasttick;
		if(p->msg() == NETMSG_CLIENT_DONE)
		{
			dbg_msg("game", "player as entered the game. cid=%x", cid);
			clients[cid].state = client::STATE_INGAME;
			mods_client_enter(cid);
		}
		else if(p->msg() == NETMSG_CLIENT_INPUT)
		{
			int input[MAX_INPUT_SIZE];
			int size = p->read_int();
			for(int i = 0; i < size/4; i++)
				input[i] = p->read_int();
			if(p->is_good())
			{
				//dbg_msg("network/server", "applying input %d %d %d", input[0], input[1], input[2]);
				mods_client_input(cid, input);
			}
		}
		else if(p->msg() == NETMSG_CLIENT_ERROR)
		{
			const char *reason = p->read_str();
			if(p->is_good())
				dbg_msg("network/server", "client error. cid=%x reason='%s'", cid, reason);
			else
				dbg_msg("network/server", "client error. cid=%x", cid);
			drop(cid, "client error");
		}
		else
		{
			dbg_msg("network/server", "invalid message. cid=%x msg=%x", cid, p->msg());
			drop(cid, "invalid message");
		}
	}
	
	void process_packet(packet *p, netaddr4 *from)
	{
		if(p->msg() == NETMSG_CLIENT_CONNECT)
		{
			// we got no state for this client yet
			const char *version;
			const char *name;
			const char *clan;
			const char *password;
			const char *skin;
			
			version = p->read_str();
			name = p->read_str();
			clan = p->read_str();
			password = p->read_str();
			skin = p->read_str();
			
			if(p->is_good())
			{
				// check version
				if(strcmp(version, TEEWARS_NETVERSION) != 0)
				{
					dbg_msg("network/server", "wrong version connecting '%s'", version);
-					// TODO: send error
					return;
				}
				
				// look for empty slot, linear search
				int id = -1;
				for(int i = 0; i < MAX_CLIENTS; i++)
					if(clients[i].is_empty())
					{
						id = i;
						break;
					}
					
				if(id != -1)
				{
					// slot found
					// TODO: perform correct copy here
					mem_copy(clients[id].name, name, MAX_NAME_LENGTH);
					mem_copy(clients[id].clan, clan, MAX_CLANNAME_LENGTH);
					clients[id].state = client::STATE_CONNECTING;
					clients[id].conn.init(&game_socket, from);
					
					clients[id].lastactivity = lasttick;
					clients[id].name[MAX_NAME_LENGTH-1] = 0;
					clients[id].clan[MAX_CLANNAME_LENGTH-1] = 0;
					
					dbg_msg("network/server", "client connected. '%s' on slot %d", name, id);
					
					// TODO: return success
					send_accept(&clients[id], map_name);
				}
				else
				{
					// no slot found
					// TODO: send error
					dbg_msg("network/server", "client connected but server is full");

					for(int i = 0; i < MAX_CLIENTS; i++)
						dbg_msg("network/server", "\t%d: %d", i, clients[i].state);
				}
			}
		}
		else
		{
			int cid = find_client(from);
			if(cid >= 0)
			{
				if(clients[cid].conn.feed(p))
				{
					// packet is ok
					unsigned msg = p->msg();
					
					// client found, check state
					if(((msg>>16)&0xff)&clients[cid].state)
					{
						// state is ok
						client_process_packet(cid, p);
					}
					else
					{
						// invalid state, disconnect the client
						drop(cid, "invalid message at this state");
					}
				}
				else
				{
					drop(cid, "connection error");
				}
				
			}
			else
				dbg_msg("network/server", "packet from strange address.");
		}
	}

	void client_timeout(int clientId)
	{
		drop(clientId, "client timedout");
	}
	
	void pump_network()
	{
		while(1)
		{
			packet p;
			netaddr4 from;
			
			//int bytes = net_udp4_recv(
			int bytes = game_socket.recv(&from, p.data(), p.max_size());
			//int bytes = game_socket.recv(&from, p.data(), p.max_size());
			if(bytes <= 0)
				break;
			
			process_packet(&p, &from);
		}
		// TODO: check for client timeouts
	}

	char *write_int(char *buffer, int integer)
	{
		*buffer++ = integer >> 24;
		*buffer++ = integer >> 16;
		*buffer++ = integer >> 8;
		*buffer++ = integer;

		return buffer;
	}

	char *write_netaddr4(char *buffer, NETADDR4 *address)
	{
		*buffer++ = address->ip[0];
		*buffer++ = address->ip[1];
		*buffer++ = address->ip[2];
		*buffer++ = address->ip[3];
		
		return write_int(buffer, address->port);
	}

	void send_heartbeat(int version, netaddr4 *address, int players, int max_players, const char *name, const char *map_name)
	{
		char buffer[216] = {0};
		char *d = buffer;

		d = write_int(d, 'TWHB');
		d = write_int(d, version);
		d = write_netaddr4(d, address);
		d = write_int(d,players);
		d = write_int(d, max_players);
		
		int len = strlen(name);
		if (len > 128)
			len = 128;

		memcpy(d, name, len);
		d += 128;

		len = strlen(map_name);
		if (len > 64)
			len = 64;

		memcpy(d, map_name, len);
		d += 64;

+	const char *map_name;
	const char *server_name;
	int64 lasttick;
	int64 lastheartbeat;
	netaddr4 master_server;

	int biggest_snapshot;
	
	bool run(const char *servername, const char *mapname)
	{
		biggest_snapshot = 0;
		
		net_init(); // For Windows compatibility.
		map_name = mapname;
		server_name = servername;

		// load map
		if(!map_load(mapname))
		{
			dbg_msg("server", "failed to load map. mapname='%s'");
			return false;
		}
		
		// start server
		if(!game_socket.open(8303))
		{
			dbg_msg("network/server", "couldn't open socket");
			return false;
		}

		for(int i = 0; i < MAX_CLIENTS; i++)
			dbg_msg("network/server", "\t%d: %d", i, clients[i].state);

		if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &master_server) != 0)
		{
			// TODO: fix me
			//master_server = netaddr4(0, 0, 0, 0, 0);
		}
		
		mods_init();
		
		int64 time_per_tick = time_freq()/SERVER_TICK_SPEED;
		int64 time_per_heartbeat = time_freq() * 30;
		int64 starttime = time_get();
		//int64 lasttick = starttime;
		lasttick = starttime;
		lastheartbeat = 0;

		int64 reporttime = time_get();
		int64 reportinterval = time_freq()*3;
		
		int64 simulationtime = 0;
		int64 snaptime = 0;
		int64 networktime = 0;
		
		while(1)
		{
			int64 t = time_get();
			if(t-lasttick > time_per_tick)
			{
				{
					int64 start = time_get();
					tick();
					simulationtime += time_get()-start;
				}
				
				{
					int64 start = time_get();
					snap();
					snaptime += time_get()-start;
				}

				// Check for client timeouts
				for (int i = 0; i < MAX_CLIENTS; i++)
				{
					if (clients[i].state != client::STATE_EMPTY)
					{
						// check last activity time
						if (((lasttick - clients[i].lastactivity) / time_freq()) > SERVER_CLIENT_TIMEOUT)
							client_timeout(i);
					}
				}
				
				lasttick += time_per_tick;
			}

			if(send_heartbeats)
			{
				if (t > lastheartbeat+time_per_heartbeat)
				{
					if (master_server.port != 0)
					{
						int players = 0;
						
						for (int i = 0; i < MAX_CLIENTS; i++)
							if (!clients[i].is_empty())
								players++;
						
						// TODO: fix me
						netaddr4 me(127, 0, 0, 0, 8303);
						
						send_heartbeat(0, &me, players, MAX_CLIENTS, server_name, mapname);
					}

					lastheartbeat = t+time_per_heartbeat;
				}
			}
			
			{
				int64 start = time_get();
				pump_network();
				networktime += time_get()-start;
			}
			
			if(reporttime < time_get())
			{
				int64 totaltime = simulationtime+snaptime+networktime;
				dbg_msg("server/report", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%",
					simulationtime/(float)reportinterval*1000,
					snaptime/(float)reportinterval*1000,
					networktime/(float)reportinterval*1000,
					totaltime/(float)reportinterval*1000,
					(simulationtime+snaptime+networktime)/(float)reportinterval*100.0f);

				unsigned sent_total=0, recv_total=0;
				for (int i = 0; i < MAX_CLIENTS; i++)
					if (!clients[i].is_empty())
					{
						unsigned s,r;
						clients[i].conn.counter_get(&s,&r);
						clients[i].conn.counter_reset();
						sent_total += s;
						recv_total += r;
					}

				
				dbg_msg("server/report", "biggestsnap=%d send=%d recv=%d",
					biggest_snapshot, sent_total/3, recv_total/3);

				simulationtime = 0;
				snaptime = 0;
				networktime = 0;
				
				reporttime += reportinterval;
			}
			
			thread_sleep(1);
		}
		
		mods_shutdown();
		map_unload();
	}
	
	void tick()
	{
		current_tick++;
		mods_tick();
	}

	void snap()
	{
		mods_presnap();
	
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			if(clients[i].is_ingame())
			{
				char data[MAX_SNAPSHOT_SIZE];
				char compdata[MAX_SNAPSHOT_SIZE];
				builder.start();
				mods_snap(i);

				// finish snapshot
				int snapshot_size = builder.finish(data);
				
				// compress it
				int compsize = lzw_compress(data, snapshot_size, compdata);
				snapshot_size = compsize;

				if(snapshot_size > biggest_snapshot)
					biggest_snapshot = snapshot_size;
				
				const int max_size = MAX_SNAPSHOT_PACKSIZE;
				int numpackets = (snapshot_size+max_size-1)/max_size;
				for(int n = 0, left = snapshot_size; left; n++)
				{
					int chunk = left < max_size ? left : max_size;
					left -= chunk;
					
					packet p(NETMSG_SERVER_SNAP);
					p.write_int(numpackets);
					p.write_int(n);
					p.write_int(chunk);
					p.write_raw(&compdata[n*max_size], chunk);
					clients[i].conn.send(&p);
				}
			}
		}
		
		mods_postsnap();
	}	

	void send_accept(client *client, const char *map)
	{
		packet p(NETMSG_SERVER_ACCEPT);
		p.write_str(map);
		client->conn.send(&p);
	}
	
	void drop(int cid, const char *reason)
	{
		if(clients[cid].state == client::STATE_EMPTY)
			return;
		
		clients[cid].state = client::STATE_EMPTY;
		mods_client_drop(cid);
		dbg_msg("game", "player dropped. reason='%s' cid=%x name='%s'", reason, cid, clients[cid].name);
	}
	
	int find_client(const netaddr4 *addr)
	{
		// fetch client
		for(int i = 0; i < MAX_CLIENTS; i++)
		{
			if(!clients[i].is_empty() && clients[i].address() == *addr)
				return i;
		}		
		return -1;
	}
	
	void client_process_packet(int cid, packet *p)
	{
		clients[cid].lastactivity = lasttick;
		if(p->msg() == NETMSG_CLIENT_DONE)
		{
			dbg_msg("game", "player as entered the game. cid=%x", cid);
			clients[cid].state = client::STATE_INGAME;
			mods_client_enter(cid);
		}
		else if(p->msg() == NETMSG_CLIENT_INPUT)
		{
			int input[MAX_INPUT_SIZE];
			int size = p->read_int();
			for(int i = 0; i < size/4; i++)
				input[i] = p->read_int();
			if(p->is_good())
			{
				//dbg_msg("network/server", "applying input %d %d %d", input[0], input[1], input[2]);
				mods_client_input(cid, input);
			}
		}
		else if(p->msg() == NETMSG_CLIENT_ERROR)
		{
			const char *reason = p->read_str();
			if(p->is_good())
				dbg_msg("network/server", "client error. cid=%x reason='%s'", cid, reason);
			else
				dbg_msg("network/server", "client error. cid=%x", cid);
			drop(cid, "client error");
		}
		else
		{
			dbg_msg("network/server", "invalid message. cid=%x msg=%x", cid, p->msg());
			drop(cid, "invalid message");
		}
	}
	
	void process_packet(packet *p, netaddr4 *from)
	{
+		// do version check
+		if(p->version() != TEEWARS_NETVERSION)
+		{
+			// send an empty packet back.
+			// this will allow the client to check the version
+			packet p;
+			game_socket.send(from, p.data(), p.size());
+			return;
+		}
+		
		if(p->msg() == NETMSG_CLIENT_CONNECT)
		{
			// we got no state for this client yet
			const char *version;
			const char *name;
			const char *clan;
			const char *password;
			const char *skin;
			
			version = p->read_str();
			name = p->read_str();
			clan = p->read_str();
			password = p->read_str();
			skin = p->read_str();
			
			if(p->is_good())
			{
+				/*
				// check version
				if(strcmp(version, TEEWARS_NETVERSION) != 0)
				{
					dbg_msg("network/server", "wrong version connecting '%s'", version);
+					// TODO: send error
					return;
				}*/
				
				// look for empty slot, linear search
				int id = -1;
				for(int i = 0; i < MAX_CLIENTS; i++)
					if(clients[i].is_empty())
					{
						id = i;
						break;
					}
					
				if(id != -1)
				{
					// slot found
					// TODO: perform correct copy here
					mem_copy(clients[id].name, name, MAX_NAME_LENGTH);
					mem_copy(clients[id].clan, clan, MAX_CLANNAME_LENGTH);
					clients[id].state = client::STATE_CONNECTING;
					clients[id].conn.init(&game_socket, from);
					
					clients[id].lastactivity = lasttick;
					clients[id].name[MAX_NAME_LENGTH-1] = 0;
					clients[id].clan[MAX_CLANNAME_LENGTH-1] = 0;
					
					dbg_msg("network/server", "client connected. '%s' on slot %d", name, id);
					
					// TODO: return success
					send_accept(&clients[id], map_name);
				}
				else
				{
					// no slot found
					// TODO: send error
					dbg_msg("network/server", "client connected but server is full");

					for(int i = 0; i < MAX_CLIENTS; i++)
						dbg_msg("network/server", "\t%d: %d", i, clients[i].state);
				}
			}
		}
		else
		{
			int cid = find_client(from);
			if(cid >= 0)
			{
				if(clients[cid].conn.feed(p))
				{
					// packet is ok
					unsigned msg = p->msg();
					
					// client found, check state
					if(((msg>>16)&0xff)&clients[cid].state)
					{
						// state is ok
						client_process_packet(cid, p);
					}
					else
					{
						// invalid state, disconnect the client
						drop(cid, "invalid message at this state");
					}
				}
				else
				{
					drop(cid, "connection error");
				}
				
			}
			else
				dbg_msg("network/server", "packet from strange address.");
		}
	}

	void client_timeout(int clientId)
	{
		drop(clientId, "client timedout");
	}
	
	void pump_network()
	{
		while(1)
		{
			packet p;
			netaddr4 from;
			
			//int bytes = net_udp4_recv(
			int bytes = game_socket.recv(&from, p.data(), p.max_size());
			//int bytes = game_socket.recv(&from, p.data(), p.max_size());
			if(bytes <= 0)
				break;
			
			process_packet(&p, &from);
		}
		// TODO: check for client timeouts
	}

	char *write_int(char *buffer, int integer)
	{
		*buffer++ = integer >> 24;
		*buffer++ = integer >> 16;
		*buffer++ = integer >> 8;
		*buffer++ = integer;

		return buffer;
	}

	char *write_netaddr4(char *buffer, NETADDR4 *address)
	{
		*buffer++ = address->ip[0];
		*buffer++ = address->ip[1];
		*buffer++ = address->ip[2];
		*buffer++ = address->ip[3];
		
		return write_int(buffer, address->port);
	}

	void send_heartbeat(int version, netaddr4 *address, int players, int max_players, const char *name, const char *map_name)
	{
		char buffer[216] = {0};
		char *d = buffer;

		d = write_int(d, 'TWHB');
		d = write_int(d, version);
		d = write_netaddr4(d, address);
		d = write_int(d,players);
		d = write_int(d, max_players);
		
		int len = strlen(name);
		if (len > 128)
			len = 128;

		memcpy(d, name, len);
		d += 128;

		len = strlen(map_name);
		if (len > 64)
			len = 64;

		memcpy(d, map_name, len);
		d += 64;

 		game_socket.send(&master_server, buffer, sizeof(buffer));
	}
};

int main(int argc, char **argv)
{
	dbg_msg("server", "starting...");
	
	const char *mapname = "data/demo.map";
	const char *servername = 0;
	// parse arguments
	for(int i = 1; i < argc; i++)
	{
		if(argv[i][0] == '-' && argv[i][1] == 'm' && argv[i][2] == 0 && argc - i > 1)
		{
			// -m map
			i++;
			mapname = argv[i];
		}
		else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1)
		{
			// -n server name
			i++;
			servername = argv[i];
		}
		else if(argv[i][0] == '-' && argv[i][1] == 'p' && argv[i][2] == 0)
		{
			// -p (private server)
			send_heartbeats = 0;
		}
	}
	
	if(!mapname)
	{
		dbg_msg("server", "no map given (-m MAPNAME)");
		return 0;
	}

	if(!servername)
	{
		dbg_msg("server", "no server name given (-n \"server name\")");
		return 0;
	}
		
	server_init();
	server s;
	s.run(servername, mapname);
	return 0;
}
\ No newline at end of file
diff --git a/src/engine/versions.h b/src/engine/versions.h
index d70ee721..f5fceb48 100644
--- a/src/engine/versions.h
+++ b/src/engine/versions.h
@@ -1,2 +1,3 @@
-#define TEEWARS_NETVERSION "dev v2"
+#define TEEWARS_NETVERSION 0xffffffff
+//#define TEEWARS_NETVERSION_STRING "dev v2"
 #define TEEWARS_VERSION "0.2.1-dev"
diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp
index f510e00e..99a04b06 100644
--- a/src/game/client/game_client.cpp
+++ b/src/game/client/game_client.cpp
@@ -653,12 +653,12 @@ static particle_system temp_system;
 void modc_init()
 {
 	// load textures
-	texture_weapon = gfx_load_texture_tga("data/tileset_weapons.tga");
-	texture_game = gfx_load_texture_tga("data/game_main.tga");
-	texture_char_default = gfx_load_texture_tga("data/char_teefault.tga");
-	texture_sun = gfx_load_texture_tga("data/sun.tga");
-	texture_particles = gfx_load_texture_tga("data/tileset_particles.tga");
-	font_texture = gfx_load_texture_tga("data/debug_font.tga");
+	texture_weapon = gfx_load_texture("data/tileset_weapons.png");
+	texture_game = gfx_load_texture("data/game_main.png");
+	texture_char_default = gfx_load_texture("data/char_teefault.png");
+	texture_sun = gfx_load_texture("data/sun.png");
+	texture_particles = gfx_load_texture("data/tileset_particles.png");
+	font_texture = gfx_load_texture("data/debug_font.png");
 
 	
 	// load sounds
diff --git a/src/game/client/mapres_image.cpp b/src/game/client/mapres_image.cpp
index 1c81b309..e56a7c6a 100644
--- a/src/game/client/mapres_image.cpp
+++ b/src/game/client/mapres_image.cpp
@@ -24,7 +24,7 @@ int img_init()
 	{
 		mapres_image *img = (mapres_image *)map_get_item(start+i, 0, 0);
 		void *data = map_get_data(img->image_data);
-		map_textures[i] = gfx_load_texture_raw(img->width, img->height, data);
+		map_textures[i] = gfx_load_texture_raw(img->width, img->height, IMG_BGRA, data);
 	}
 	
 	return count;
diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp
index 88c87526..5d0cc473 100644
--- a/src/game/client/menu.cpp
+++ b/src/game/client/menu.cpp
@@ -216,7 +216,7 @@ int do_scroll_bar(void *id, float x, float y, float height, int steps, int last_
 				float pos = ui_mouse_y() - y - 8;
 				float perc = pos / (height - 16);
 
-				r = (steps + 1) * perc;
+				r = (int)((steps + 1) * perc);
 				if (r < 0)
 					r = 0;
 				else if (r > steps)
@@ -327,7 +327,6 @@ void refresh_list(server_list *list)
         {
             char data[256];
             int total_received = 0;
-            int pointer = 0;
             int received;
 
             int master_server_version = -1;
@@ -352,7 +351,6 @@ void refresh_list(server_list *list)
                     // TODO: handle master server version O.o
                         
                     const int server_info_size = 212;
-                    const int wanted_data_count = server_count * server_info_size;
 
                     list->active_count = 0;
     
@@ -489,42 +487,42 @@ void modmenu_init()
 	keys::enable_char_cache();
 	keys::enable_key_cache();
 
-    current_font->font_texture = gfx_load_texture_tga("data/big_font.tga");
-	background_texture = gfx_load_texture_tga("data/gui_bg.tga");
-    not_empty_item_texture = gfx_load_texture_tga("data/gui/game_list_item_not_empty.tga");
-    empty_item_texture = gfx_load_texture_tga("data/gui/game_list_item_empty.tga");
-    active_item_texture = gfx_load_texture_tga("data/gui/game_list_item_active.tga");
-	selected_item_texture = gfx_load_texture_tga("data/gui/game_list_item_selected.tga");
+    current_font->font_texture = gfx_load_texture("data/big_font.png");
+	background_texture = gfx_load_texture("data/gui_bg.png");
+    not_empty_item_texture = gfx_load_texture("data/gui/game_list_item_not_empty.png");
+    empty_item_texture = gfx_load_texture("data/gui/game_list_item_empty.png");
+    active_item_texture = gfx_load_texture("data/gui/game_list_item_active.png");
+	selected_item_texture = gfx_load_texture("data/gui/game_list_item_selected.png");
 
-	join_button_texture = gfx_load_texture_tga("data/gui/join_button.tga");
-	join_button_hot_texture = gfx_load_texture_tga("data/gui/join_button_hot.tga");
-	join_button_active_texture = gfx_load_texture_tga("data/gui/join_button_active.tga");
-	join_button_grey_texture = gfx_load_texture_tga("data/gui/join_button_greyed.tga");
+	join_button_texture = gfx_load_texture("data/gui/join_button.png");
+	join_button_hot_texture = gfx_load_texture("data/gui/join_button_hot.png");
+	join_button_active_texture = gfx_load_texture("data/gui/join_button_active.png");
+	join_button_grey_texture = gfx_load_texture("data/gui/join_button_greyed.png");
 
 
-//    button_not_hilighted_texture = gfx_load_texture_tga("data/gui/game_list_join_button.tga");
-//	button_hilighted_texture = gfx_load_texture_tga("data/gui/button_hilighted.tga");
-//	button_active_texture = gfx_load_texture_tga("data/gui/button_active.tga");
+//    button_not_hilighted_texture = gfx_load_texture("data/gui/game_list_join_button.png");
+//	button_hilighted_texture = gfx_load_texture("data/gui/button_hilighted.png");
+//	button_active_texture = gfx_load_texture("data/gui/button_active.png");
 
-    quit_button_texture = gfx_load_texture_tga("data/gui/quit_button.tga");
-	quit_button_hot_texture = gfx_load_texture_tga("data/gui/quit_button_hot.tga");
-	quit_button_active_texture = gfx_load_texture_tga("data/gui/quit_button_active.tga");
+    quit_button_texture = gfx_load_texture("data/gui/quit_button.png");
+	quit_button_hot_texture = gfx_load_texture("data/gui/quit_button_hot.png");
+	quit_button_active_texture = gfx_load_texture("data/gui/quit_button_active.png");
 
-    up_button_texture = gfx_load_texture_tga("data/gui/scroll_arrow_up.tga");
-	up_button_active_texture = gfx_load_texture_tga("data/gui/scroll_arrow_up_active.tga");
+    up_button_texture = gfx_load_texture("data/gui/scroll_arrow_up.png");
+	up_button_active_texture = gfx_load_texture("data/gui/scroll_arrow_up_active.png");
 
-    down_button_texture = gfx_load_texture_tga("data/gui/scroll_arrow_down.tga");
-	down_button_active_texture = gfx_load_texture_tga("data/gui/scroll_arrow_down_active.tga");
+    down_button_texture = gfx_load_texture("data/gui/scroll_arrow_down.png");
+	down_button_active_texture = gfx_load_texture("data/gui/scroll_arrow_down_active.png");
 
-    teewars_banner_texture = gfx_load_texture_tga("data/gui_logo.tga");
-    scroll_indicator_texture = gfx_load_texture_tga("data/gui/scroll_drag.tga");
-	connect_localhost_texture = gfx_load_texture_tga("data/gui/game_list_connect_localhost.tga");
+    teewars_banner_texture = gfx_load_texture("data/gui_logo.png");
+    scroll_indicator_texture = gfx_load_texture("data/gui/scroll_drag.png");
+	connect_localhost_texture = gfx_load_texture("data/gui/game_list_connect_localhost.png");
 
-	refresh_button_texture = gfx_load_texture_tga("data/gui/refresh_button.tga");
-	refresh_button_hot_texture = gfx_load_texture_tga("data/gui/refresh_button_hot.tga");
-	refresh_button_active_texture = gfx_load_texture_tga("data/gui/refresh_button_active.tga");
+	refresh_button_texture = gfx_load_texture("data/gui/refresh_button.png");
+	refresh_button_hot_texture = gfx_load_texture("data/gui/refresh_button_hot.png");
+	refresh_button_active_texture = gfx_load_texture("data/gui/refresh_button_active.png");
 
-	input_box_texture = gfx_load_texture_tga("data/gui/input_box.tga");
+	input_box_texture = gfx_load_texture("data/gui/input_box.png");
 
 	music_menu = snd_load_wav("data/audio/Music_Menu.wav");
 }