about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bam.lua (renamed from default.bam)24
-rw-r--r--other/sdl/sdl.lua (renamed from other/sdl/sdl.bam)0
-rw-r--r--src/base/system.h3
-rw-r--r--src/base/tl/array.hpp6
-rw-r--r--src/engine/client/ec_client.cpp (renamed from src/engine/client/ec_client.c)396
-rw-r--r--src/engine/client/ec_gfx.c1020
-rw-r--r--src/engine/client/ec_gfx.cpp992
-rw-r--r--src/engine/client/ec_gfx_text.cpp (renamed from src/engine/client/ec_gfx_text.c)29
-rw-r--r--src/engine/client/ec_inp.cpp (renamed from src/engine/client/ec_inp.c)12
-rw-r--r--src/engine/client/ec_snd.cpp (renamed from src/engine/client/ec_snd.c)22
-rw-r--r--src/engine/client/ec_srvbrowse.cpp (renamed from src/engine/client/ec_srvbrowse.c)69
-rw-r--r--src/engine/e_client_interface.h8
-rw-r--r--src/engine/e_common_interface.h8
-rw-r--r--src/engine/e_compression.cpp (renamed from src/engine/e_compression.c)62
-rw-r--r--src/engine/e_compression.h4
-rw-r--r--src/engine/e_config.cpp (renamed from src/engine/e_config.c)0
-rw-r--r--src/engine/e_config.h8
-rw-r--r--src/engine/e_console.cpp (renamed from src/engine/e_console.c)14
-rw-r--r--src/engine/e_console.h14
-rw-r--r--src/engine/e_datafile.cpp (renamed from src/engine/e_datafile.c)0
-rw-r--r--src/engine/e_demorec.cpp (renamed from src/engine/e_demorec.c)33
-rw-r--r--src/engine/e_demorec.h8
-rw-r--r--src/engine/e_engine.cpp (renamed from src/engine/e_engine.c)6
-rw-r--r--src/engine/e_huffman.cpp (renamed from src/engine/e_huffman.c)0
-rw-r--r--src/engine/e_huffman.h8
-rw-r--r--src/engine/e_if_other.h3
-rw-r--r--src/engine/e_jobs.cpp (renamed from src/engine/e_jobs.c)0
-rw-r--r--src/engine/e_keynames.cpp (renamed from src/engine/e_keynames.c)0
-rw-r--r--src/engine/e_linereader.cpp (renamed from src/engine/e_linereader.c)0
-rw-r--r--src/engine/e_map.cpp (renamed from src/engine/e_map.c)0
-rw-r--r--src/engine/e_memheap.cpp (renamed from src/engine/e_memheap.c)10
-rw-r--r--src/engine/e_memheap.h2
-rw-r--r--src/engine/e_msg.cpp (renamed from src/engine/e_msg.c)30
-rw-r--r--src/engine/e_network.c351
-rw-r--r--src/engine/e_network.cpp347
-rw-r--r--src/engine/e_network.h395
-rw-r--r--src/engine/e_network_client.c154
-rw-r--r--src/engine/e_network_client.cpp139
-rw-r--r--src/engine/e_network_conn.c366
-rw-r--r--src/engine/e_network_conn.cpp349
-rw-r--r--src/engine/e_network_internal.h156
-rw-r--r--src/engine/e_network_server.c484
-rw-r--r--src/engine/e_network_server.cpp408
-rw-r--r--src/engine/e_packer.c213
-rw-r--r--src/engine/e_packer.cpp155
-rw-r--r--src/engine/e_packer.h58
-rw-r--r--src/engine/e_ringbuffer.c362
-rw-r--r--src/engine/e_ringbuffer.cpp194
-rw-r--r--src/engine/e_ringbuffer.h67
-rw-r--r--src/engine/e_server_interface.h8
-rw-r--r--src/engine/e_snapshot.c604
-rw-r--r--src/engine/e_snapshot.cpp571
-rw-r--r--src/engine/e_snapshot.h160
-rw-r--r--src/engine/server/es_register.cpp (renamed from src/engine/server/es_register.c)83
-rw-r--r--src/engine/server/es_server.c1380
-rw-r--r--src/engine/server/es_server.cpp1969
-rw-r--r--src/game/client/clienthooks.cpp31
-rw-r--r--src/game/client/component.hpp8
-rw-r--r--src/game/client/components/broadcast.cpp5
-rw-r--r--src/game/client/components/chat.cpp3
-rw-r--r--src/game/client/components/console.cpp97
-rw-r--r--src/game/client/components/console.hpp8
-rw-r--r--src/game/client/components/damageind.cpp15
-rw-r--r--src/game/client/components/debughud.cpp17
-rw-r--r--src/game/client/components/emoticon.cpp37
-rw-r--r--src/game/client/components/flow.cpp9
-rw-r--r--src/game/client/components/hud.cpp109
-rw-r--r--src/game/client/components/hud.hpp2
-rw-r--r--src/game/client/components/items.cpp87
-rw-r--r--src/game/client/components/killmessages.cpp47
-rw-r--r--src/game/client/components/mapimages.cpp7
-rw-r--r--src/game/client/components/maplayers.cpp56
-rw-r--r--src/game/client/components/maplayers.hpp3
-rw-r--r--src/game/client/components/menus.cpp724
-rw-r--r--src/game/client/components/menus.hpp104
-rw-r--r--src/game/client/components/menus_browser.cpp338
-rw-r--r--src/game/client/components/menus_demo.cpp221
-rw-r--r--src/game/client/components/menus_ingame.cpp194
-rw-r--r--src/game/client/components/menus_settings.cpp460
-rw-r--r--src/game/client/components/motd.cpp17
-rw-r--r--src/game/client/components/particles.cpp20
-rw-r--r--src/game/client/components/players.cpp101
-rw-r--r--src/game/client/components/scoreboard.cpp67
-rw-r--r--src/game/client/components/skins.cpp12
-rw-r--r--src/game/client/components/voting.cpp24
-rw-r--r--src/game/client/components/voting.hpp8
-rw-r--r--src/game/client/gameclient.cpp41
-rw-r--r--src/game/client/gameclient.hpp20
-rw-r--r--src/game/client/render.cpp93
-rw-r--r--src/game/client/render.hpp51
-rw-r--r--src/game/client/render_map.cpp47
-rw-r--r--src/game/client/ui.cpp225
-rw-r--r--src/game/client/ui.hpp117
-rw-r--r--src/game/editor/ed_editor.cpp1708
-rw-r--r--src/game/editor/ed_editor.hpp155
-rw-r--r--src/game/editor/ed_io.cpp23
-rw-r--r--src/game/editor/ed_layer_game.cpp2
-rw-r--r--src/game/editor/ed_layer_quads.cpp45
-rw-r--r--src/game/editor/ed_layer_tiles.cpp60
-rw-r--r--src/game/editor/ed_popups.cpp235
-rw-r--r--src/game/localization.cpp2
-rw-r--r--src/game/server/hooks.cpp10
102 files changed, 9087 insertions, 8342 deletions
diff --git a/default.bam b/bam.lua
index 8f735dff..c83fdab0 100644
--- a/default.bam
+++ b/bam.lua
@@ -1,12 +1,12 @@
-CheckVersion("0.2")
+CheckVersion("0.3")
 
-Import("other/sdl/sdl.bam")
+Import("other/sdl/sdl.lua")
 
 --- Setup Config --------
 config = NewConfig()
-config:Add(OptFindCompiler())
+config:Add(OptCCompiler("compiler"))
 config:Add(OptTestCompileC("stackprotector", "int main(){return 0;}", "-fstack-protector -fstack-protector-all"))
-config:Add(OptFindLibrary("zlib", "zlib.h", false))
+config:Add(OptLibrary("zlib", "zlib.h", false))
 config:Add(SDL.OptFind("sdl", true))
 config:Finalize("config.bam")
 
@@ -19,7 +19,7 @@ function Script(name)
 end
 
 function CHash(output, ...)
-	local inputs = FlatternTable({...})
+	local inputs = FlattenTable({...})
 	
 	output = Path(output)
 	
@@ -184,9 +184,9 @@ function build(settings)
 	-- apply sdl settings
 	config.sdl:Apply(client_settings)
 	
-	engine = Compile(engine_settings, Collect("src/engine/*.c", "src/base/*.c"))
-	client = Compile(client_settings, Collect("src/engine/client/*.c"))
-	server = Compile(server_settings, Collect("src/engine/server/*.c"))
+	engine = Compile(engine_settings, Collect("src/engine/*.cpp", "src/base/*.c"))
+	client = Compile(client_settings, Collect("src/engine/client/*.cpp"))
+	server = Compile(server_settings, Collect("src/engine/server/*.cpp"))
 	
 	versionserver = Compile(settings, Collect("src/versionsrv/*.cpp"))
 	masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
@@ -239,15 +239,7 @@ function build(settings)
 	m = PseudoTarget("masterserver".."_"..settings.config_name, masterserver_exe)
 	t = PseudoTarget("tools".."_"..settings.config_name, tools)
 
-	Target(c)
-	Target(s)
-	Target(v)
-	Target(m)
-	Target(t)
-	
 	all = PseudoTarget(settings.config_name, c, s, v, m, t)
-
-	Target(all)
 	return all
 end
 
diff --git a/other/sdl/sdl.bam b/other/sdl/sdl.lua
index be94209d..be94209d 100644
--- a/other/sdl/sdl.bam
+++ b/other/sdl/sdl.lua
diff --git a/src/base/system.h b/src/base/system.h
index cdbfe294..3c9974d8 100644
--- a/src/base/system.h
+++ b/src/base/system.h
@@ -46,8 +46,7 @@ void dbg_break();
 
 /*
 	Function: dbg_msg
-	
-	Prints a debug message.
+		Prints a debug message.
 	
 	Parameters:
 		sys - A string that describes what system the message belongs to
diff --git a/src/base/tl/array.hpp b/src/base/tl/array.hpp
index 7fa4ab1b..7b8698d4 100644
--- a/src/base/tl/array.hpp
+++ b/src/base/tl/array.hpp
@@ -165,7 +165,7 @@ public:
 	int add(const T& item)
 	{
 		incsize();
-		set_size(size()+1);
+		num_elements = size()+1;
 		list[num_elements-1] = item;
 		return num_elements-1;
 	}
@@ -189,7 +189,7 @@ public:
 			
 		int index = (int)(&r.front()-list);
 		incsize();
-		set_size(size()+1);
+		num_elements = size()+1;
 		
 		for(int i = num_elements-1; i > index; i--)
 			list[i] = list[i-1];
@@ -283,7 +283,7 @@ public:
 	*/
 	int memusage()
 	{
-		return sizeof(array) + sizeof(T)*size;
+		return sizeof(*this) + sizeof(T)*list_size;
 	}
 
 	/*
diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.cpp
index 0c707ccf..7ba0a2bb 100644
--- a/src/engine/client/ec_client.c
+++ b/src/engine/client/ec_client.cpp
@@ -28,6 +28,28 @@
 #include <mastersrv/mastersrv.h>
 #include <versionsrv/versionsrv.h>
 
+#include "editor.h"
+#include "graphics.h"
+#include "client.h"
+
+static IEditor *m_pEditor = 0;
+static IEngineGraphics *m_pGraphics = 0;
+IEngineGraphics *Graphics() { return m_pGraphics; }
+
+static IGameClient *m_pGameClient = 0;
+
+
+class CClient : public IEngine
+{
+public:
+	virtual class IGraphics *Graphics()
+	{
+		return m_pGraphics;
+	}
+};
+
+static CClient m_Client;
+
 const int prediction_margin = 1000/50/2; /* magic network prediction value */
 
 /*
@@ -43,7 +65,7 @@ const int prediction_margin = 1000/50/2; /* magic network prediction value */
 */
 
 /* network client, must be accessible from other parts like the server browser */
-NETCLIENT *net;
+CNetClient m_NetClient;
 
 /* TODO: ugly, fix me */
 extern void client_serverbrowse_set(NETADDR *addr, int request, int token, SERVER_INFO *info);
@@ -171,22 +193,22 @@ static void graph_render(GRAPH *g, float x, float y, float w, float h, const cha
 	char buf[32];
 	int i;
 
-	gfx_blend_normal();
+	//m_pGraphics->BlendNormal();
 
 	
-	gfx_texture_set(-1);
+	Graphics()->TextureSet(-1);
 	
-	gfx_quads_begin();
-	gfx_setcolor(0, 0, 0, 0.75f);
-	gfx_quads_drawTL(x, y, w, h);
-	gfx_quads_end();
+	m_pGraphics->QuadsBegin();
+	Graphics()->SetColor(0, 0, 0, 0.75f);
+	Graphics()->QuadsDrawTL(x, y, w, h);
+	m_pGraphics->QuadsEnd();
 		
-	gfx_lines_begin();
-	gfx_setcolor(0.95f, 0.95f, 0.95f, 1.00f);
-	gfx_lines_draw(x, y+h/2, x+w, y+h/2);
-	gfx_setcolor(0.5f, 0.5f, 0.5f, 0.75f);
-	gfx_lines_draw(x, y+(h*3)/4, x+w, y+(h*3)/4);
-	gfx_lines_draw(x, y+h/4, x+w, y+h/4);
+	Graphics()->LinesBegin();
+	Graphics()->SetColor(0.95f, 0.95f, 0.95f, 1.00f);
+	Graphics()->LinesDraw(x, y+h/2, x+w, y+h/2);
+	Graphics()->SetColor(0.5f, 0.5f, 0.5f, 0.75f);
+	Graphics()->LinesDraw(x, y+(h*3)/4, x+w, y+(h*3)/4);
+	Graphics()->LinesDraw(x, y+h/4, x+w, y+h/4);
 	for(i = 1; i < GRAPH_MAX; i++)
 	{
 		float a0 = (i-1)/(float)GRAPH_MAX;
@@ -197,22 +219,22 @@ static void graph_render(GRAPH *g, float x, float y, float w, float h, const cha
 		float v0 = (g->values[i0]-g->min) / (g->max-g->min);
 		float v1 = (g->values[i1]-g->min) / (g->max-g->min);
 		
-		gfx_setcolorvertex(0, g->colors[i0][0], g->colors[i0][1], g->colors[i0][2], 0.75f);
-		gfx_setcolorvertex(1, g->colors[i1][0], g->colors[i1][1], g->colors[i1][2], 0.75f);
-		gfx_lines_draw(x+a0*w, y+h-v0*h, x+a1*w, y+h-v1*h);
+		Graphics()->SetColorVertex(0, g->colors[i0][0], g->colors[i0][1], g->colors[i0][2], 0.75f);
+		Graphics()->SetColorVertex(1, g->colors[i1][0], g->colors[i1][1], g->colors[i1][2], 0.75f);
+		Graphics()->LinesDraw(x+a0*w, y+h-v0*h, x+a1*w, y+h-v1*h);
 
 	}
-	gfx_lines_end();
+	Graphics()->LinesEnd();
 	
 
-	gfx_texture_set(debug_font);	
-	gfx_quads_text(x+2, y+h-16, 16, 1,1,1,1, description);
+	Graphics()->TextureSet(debug_font);	
+	Graphics()->QuadsText(x+2, y+h-16, 16, 1,1,1,1, description);
 
 	str_format(buf, sizeof(buf), "%.2f", g->max);
-	gfx_quads_text(x+w-8*strlen(buf)-8, y+2, 16, 1,1,1,1, buf);
+	Graphics()->QuadsText(x+w-8*strlen(buf)-8, y+2, 16, 1,1,1,1, buf);
 	
 	str_format(buf, sizeof(buf), "%.2f", g->min);
-	gfx_quads_text(x+w-8*strlen(buf)-8, y+h-16, 16, 1,1,1,1, buf);
+	Graphics()->QuadsText(x+w-8*strlen(buf)-8, y+h-16, 16, 1,1,1,1, buf);
 	
 }
 
@@ -336,40 +358,40 @@ enum
 };
 
 /* the game snapshots are modifiable by the game */
-SNAPSTORAGE snapshot_storage;
-static SNAPSTORAGE_HOLDER *snapshots[NUM_SNAPSHOT_TYPES] = {0, 0};
+CSnapshotStorage snapshot_storage;
+static CSnapshotStorage::CHolder *snapshots[NUM_SNAPSHOT_TYPES] = {0, 0};
 
 static int recived_snapshots = 0;
-static char snapshot_incomming_data[MAX_SNAPSHOT_SIZE];
+static char snapshot_incomming_data[CSnapshot::MAX_SIZE];
 
-static SNAPSTORAGE_HOLDER demorec_snapshotholders[NUM_SNAPSHOT_TYPES];
-static char *demorec_snapshotdata[NUM_SNAPSHOT_TYPES][2][MAX_SNAPSHOT_SIZE];
+static CSnapshotStorage::CHolder demorec_snapshotholders[NUM_SNAPSHOT_TYPES];
+static char *demorec_snapshotdata[NUM_SNAPSHOT_TYPES][2][CSnapshot::MAX_SIZE];
 
 /* --- */
 
 void *snap_get_item(int snapid, int index, SNAP_ITEM *item)
 {
-	SNAPSHOT_ITEM *i;
+	CSnapshotItem *i;
 	dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid");
-	i = snapshot_get_item(snapshots[snapid]->alt_snap, index);
-	item->datasize = snapshot_get_item_datasize(snapshots[snapid]->alt_snap, index);
-	item->type = snapitem_type(i);
-	item->id = snapitem_id(i);
-	return (void *)snapitem_data(i);
+	i = snapshots[snapid]->m_pAltSnap->GetItem(index);
+	item->datasize = snapshots[snapid]->m_pAltSnap->GetItemSize(index);
+	item->type = i->Type();
+	item->id = i->ID();
+	return (void *)i->Data();
 }
 
 void snap_invalidate_item(int snapid, int index)
 {
-	SNAPSHOT_ITEM *i;
+	CSnapshotItem *i;
 	dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid");
-	i = snapshot_get_item(snapshots[snapid]->alt_snap, index);
+	i = snapshots[snapid]->m_pAltSnap->GetItem(index);
 	if(i)
 	{
-		if((char *)i < (char *)snapshots[snapid]->alt_snap || (char *)i > (char *)snapshots[snapid]->alt_snap + snapshots[snapid]->snap_size)
+		if((char *)i < (char *)snapshots[snapid]->m_pAltSnap || (char *)i > (char *)snapshots[snapid]->m_pAltSnap + snapshots[snapid]->m_SnapSize)
 			dbg_msg("ASDFASDFASdf", "ASDFASDFASDF");
-		if((char *)i >= (char *)snapshots[snapid]->snap && (char *)i < (char *)snapshots[snapid]->snap + snapshots[snapid]->snap_size)
+		if((char *)i >= (char *)snapshots[snapid]->m_pSnap && (char *)i < (char *)snapshots[snapid]->m_pSnap + snapshots[snapid]->m_SnapSize)
 			dbg_msg("ASDFASDFASdf", "ASDFASDFASDF");
-		i->type_and_id = -1;
+		i->m_TypeAndID = -1;
 	}
 }
 
@@ -381,11 +403,11 @@ void *snap_find_item(int snapid, int type, int id)
 	if(!snapshots[snapid])
 		return 0x0;
 	
-	for(i = 0; i < snapshots[snapid]->snap->num_items; i++)
+	for(i = 0; i < snapshots[snapid]->m_pSnap->m_NumItems; i++)
 	{
-		SNAPSHOT_ITEM *itm = snapshot_get_item(snapshots[snapid]->alt_snap, i);
-		if(snapitem_type(itm) == type && snapitem_id(itm) == id)
-			return (void *)snapitem_data(itm);
+		CSnapshotItem *itm = snapshots[snapid]->m_pAltSnap->GetItem(i);
+		if(itm->Type() == type && itm->ID() == id)
+			return (void *)itm->Data();
 	}
 	return 0x0;
 }
@@ -395,7 +417,7 @@ int snap_num_items(int snapid)
 	dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid");
 	if(!snapshots[snapid])
 		return 0;
-	return snapshots[snapid]->snap->num_items;
+	return snapshots[snapid]->m_pSnap->m_NumItems;
 }
 
 /* ------ time functions ------ */
@@ -412,35 +434,34 @@ float client_localtime() { return (time_get()-local_start_time)/(float)(time_fre
 /* ----- send functions ----- */
 int client_send_msg()
 {
-	const MSG_INFO *info = msg_get_info();
-	NETCHUNK packet;
+	const MSG_INFO *pInfo = msg_get_info();
+	CNetChunk Packet;
 	
-	if(!info)
+	if(!pInfo)
 		return -1;
 
 	if(client_state() == CLIENTSTATE_OFFLINE)
 		return 0;
 	
-		
-	mem_zero(&packet, sizeof(NETCHUNK));
+	mem_zero(&Packet, sizeof(CNetChunk));
 	
-	packet.client_id = 0;
-	packet.data = info->data;
-	packet.data_size = info->size;
+	Packet.m_ClientID = 0;
+	Packet.m_pData = pInfo->data;
+	Packet.m_DataSize = pInfo->size;
 
-	if(info->flags&MSGFLAG_VITAL)
-		packet.flags |= NETSENDFLAG_VITAL;
-	if(info->flags&MSGFLAG_FLUSH)
-		packet.flags |= NETSENDFLAG_FLUSH;
+	if(pInfo->flags&MSGFLAG_VITAL)
+		Packet.m_Flags |= NETSENDFLAG_VITAL;
+	if(pInfo->flags&MSGFLAG_FLUSH)
+		Packet.m_Flags |= NETSENDFLAG_FLUSH;
 		
-	if(info->flags&MSGFLAG_RECORD)
+	if(pInfo->flags&MSGFLAG_RECORD)
 	{
 		if(demorec_isrecording())
-			demorec_record_message(packet.data, packet.data_size);
+			demorec_record_message(Packet.m_pData, Packet.m_DataSize);
 	}
 
-	if(!(info->flags&MSGFLAG_NOSEND))
-		netclient_send(net, &packet);
+	if(!(pInfo->flags&MSGFLAG_NOSEND))
+		m_NetClient.Send(&Packet);
 	return 0;
 }
 
@@ -494,7 +515,7 @@ void client_rcon(const char *cmd)
 
 int client_connection_problems()
 {
-	return netclient_gotproblems(net);
+	return m_NetClient.GotProblems();
 }
 
 void client_direct_input(int *input, int size)
@@ -594,7 +615,7 @@ static void client_on_enter_game()
 	/* reset snapshots */
 	snapshots[SNAP_CURRENT] = 0;
 	snapshots[SNAP_PREV] = 0;
-	snapstorage_purge_all(&snapshot_storage);
+	snapshot_storage.PurgeAll();
 	recived_snapshots = 0;
 	snapshot_parts = 0;
 	current_predtick = 0;
@@ -645,7 +666,7 @@ void client_connect(const char *server_address_str)
 	
 	rcon_authed = 0;
 	server_address.port = port;
-	netclient_connect(net, &server_address);
+	m_NetClient.Connect(&server_address);
 	client_set_state(CLIENTSTATE_CONNECTING);
 	
 	graph_init(&inputtime_margin_graph, -150.0f, 150.0f);
@@ -659,7 +680,7 @@ void client_disconnect_with_reason(const char *reason)
 	
 	/* */
 	rcon_authed = 0;
-	netclient_disconnect(net, reason);
+	m_NetClient.Disconnect(reason);
 	client_set_state(CLIENTSTATE_OFFLINE);
 	map_unload();
 	
@@ -701,7 +722,7 @@ void client_serverinfo_request()
 
 static int client_load_data()
 {
-	debug_font = gfx_load_texture("debug_font.png", IMG_AUTO, TEXLOAD_NORESAMPLE);
+	debug_font = Graphics()->LoadTexture("debug_font.png", IMG_AUTO, TEXLOAD_NORESAMPLE);
 	return 1;
 }
 
@@ -721,9 +742,9 @@ static void client_debug_render()
 	if(!config.debug)
 		return;
 	
-	gfx_blend_normal();
-	gfx_texture_set(debug_font);
-	gfx_mapscreen(0,0,gfx_screenwidth(),gfx_screenheight());
+	//m_pGraphics->BlendNormal();
+	Graphics()->TextureSet(debug_font);
+	Graphics()->MapScreen(0,0,Graphics()->ScreenWidth(),Graphics()->ScreenHeight());
 	
 	if(time_get()-last_snap > time_freq())
 	{
@@ -739,13 +760,13 @@ static void client_debug_render()
 		total = 42
 	*/
 	frametime_avg = frametime_avg*0.9f + frametime*0.1f;
-	str_format(buffer, sizeof(buffer), "ticks: %8d %8d mem %dk %d  gfxmem: %dk  fps: %3d",
+	str_format(buffer, sizeof(buffer), "ticks: %8d %8d mem %dk %d  gfxmem: N/A  fps: %3d",
 		current_tick, current_predtick,
 		mem_stats()->allocated/1024,
 		mem_stats()->total_allocations,
-		gfx_memory_usage()/1024,
+		/*gfx_memory_usage()/1024, */ // TODO: Refactor: Reenable this
 		(int)(1.0f/frametime_avg));
-	gfx_quads_text(2, 2, 16, 1,1,1,1, buffer);
+	Graphics()->QuadsText(2, 2, 16, 1,1,1,1, buffer);
 
 	
 	{
@@ -761,7 +782,7 @@ static void client_debug_render()
 		str_format(buffer, sizeof(buffer), "send: %3d %5d+%4d=%5d (%3d kbps) avg: %5d\nrecv: %3d %5d+%4d=%5d (%3d kbps) avg: %5d",
 			send_packets, send_bytes, send_packets*42, send_total, (send_total*8)/1024, send_bytes/send_packets,
 			recv_packets, recv_bytes, recv_packets*42, recv_total, (recv_total*8)/1024, recv_bytes/recv_packets);
-		gfx_quads_text(2, 14, 16, 1,1,1,1, buffer);
+		Graphics()->QuadsText(2, 14, 16, 1,1,1,1, buffer);
 	}
 	
 	/* render rates */
@@ -774,7 +795,7 @@ static void client_debug_render()
 			{
 				str_format(buffer, sizeof(buffer), "%4d %20s: %8d %8d %8d", i, modc_getitemname(i), snapshot_data_rate[i]/8, snapshot_data_updates[i],
 					(snapshot_data_rate[i]/snapshot_data_updates[i])/8);
-				gfx_quads_text(2, 100+y*12, 16, 1,1,1,1, buffer);
+				Graphics()->QuadsText(2, 100+y*12, 16, 1,1,1,1, buffer);
 				y++;
 			}
 		}
@@ -783,16 +804,16 @@ static void client_debug_render()
 	str_format(buffer, sizeof(buffer), "pred: %d ms  %3.2f", 
 		(int)((st_get(&predicted_time, now)-st_get(&game_time, now))*1000/(float)time_freq()),
 		predicted_time.adjustspeed[1]);
-	gfx_quads_text(2, 70, 16, 1,1,1,1, buffer);
+	Graphics()->QuadsText(2, 70, 16, 1,1,1,1, buffer);
 	
 	/* render graphs */
 	if(config.dbg_graphs)
 	{
-		//gfx_mapscreen(0,0,400.0f,300.0f);
-		float w = gfx_screenwidth()/4.0f;
-		float h = gfx_screenheight()/6.0f;
-		float sp = gfx_screenwidth()/100.0f;
-		float x = gfx_screenwidth()-w-sp;
+		//Graphics()->MapScreen(0,0,400.0f,300.0f);
+		float w = Graphics()->ScreenWidth()/4.0f;
+		float h = Graphics()->ScreenHeight()/6.0f;
+		float sp = Graphics()->ScreenWidth()/100.0f;
+		float x = Graphics()->ScreenWidth()-w-sp;
 
 		graph_scale_max(&fps_graph);
 		graph_scale_min(&fps_graph);
@@ -809,13 +830,13 @@ void client_quit()
 
 const char *client_error_string()
 {
-	return netclient_error_string(net);
+	return m_NetClient.ErrorString();
 }
 
 static void client_render()
 {
 	if(config.gfx_clear)	
-		gfx_clear(1,1,0);
+		Graphics()->Clear(1,1,0);
 
 	modc_render();
 	client_debug_render();
@@ -888,15 +909,15 @@ static int player_score_comp(const void *a, const void *b)
 	return -1;
 }
 
-static void client_process_packet(NETCHUNK *packet)
+static void client_process_packet(CNetChunk *pPacket)
 {
-	if(packet->client_id == -1)
+	if(pPacket->m_ClientID == -1)
 	{
 		/* connectionlesss */
-		if(packet->data_size == (int)(sizeof(VERSIONSRV_VERSION) + sizeof(VERSION_DATA)) &&
-			memcmp(packet->data, VERSIONSRV_VERSION, sizeof(VERSIONSRV_VERSION)) == 0)
+		if(pPacket->m_DataSize == (int)(sizeof(VERSIONSRV_VERSION) + sizeof(VERSION_DATA)) &&
+			memcmp(pPacket->m_pData, VERSIONSRV_VERSION, sizeof(VERSIONSRV_VERSION)) == 0)
 		{
-			unsigned char *versiondata = (unsigned char*) packet->data + sizeof(VERSIONSRV_VERSION);
+			unsigned char *versiondata = (unsigned char*)pPacket->m_pData + sizeof(VERSIONSRV_VERSION);
 			int version_match = !memcmp(versiondata, VERSION_DATA, sizeof(VERSION_DATA));
 			
 			dbg_msg("client/version", "version does %s (%d.%d.%d)",
@@ -910,12 +931,12 @@ static void client_process_packet(NETCHUNK *packet)
 			}
 		}
 		
-		if(packet->data_size >= (int)sizeof(SERVERBROWSE_LIST) &&
-			memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
+		if(pPacket->m_DataSize >= (int)sizeof(SERVERBROWSE_LIST) &&
+			memcmp(pPacket->m_pData, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
 		{
-			int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
+			int size = pPacket->m_DataSize-sizeof(SERVERBROWSE_LIST);
 			int num = size/sizeof(MASTERSRV_ADDR);
-			MASTERSRV_ADDR *addrs = (MASTERSRV_ADDR *)((char*)packet->data+sizeof(SERVERBROWSE_LIST));
+			MASTERSRV_ADDR *addrs = (MASTERSRV_ADDR *)((char*)pPacket->m_pData+sizeof(SERVERBROWSE_LIST));
 			int i;
 
 			for(i = 0; i < num; i++)
@@ -937,47 +958,47 @@ static void client_process_packet(NETCHUNK *packet)
 
 		{
 			int packet_type = 0;
-			if(packet->data_size >= (int)sizeof(SERVERBROWSE_INFO) && memcmp(packet->data, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
+			if(pPacket->m_DataSize >= (int)sizeof(SERVERBROWSE_INFO) && memcmp(pPacket->m_pData, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
 				packet_type = 2;
 
-			if(packet->data_size >= (int)sizeof(SERVERBROWSE_OLD_INFO) && memcmp(packet->data, SERVERBROWSE_OLD_INFO, sizeof(SERVERBROWSE_OLD_INFO)) == 0)
+			if(pPacket->m_DataSize >= (int)sizeof(SERVERBROWSE_OLD_INFO) && memcmp(pPacket->m_pData, SERVERBROWSE_OLD_INFO, sizeof(SERVERBROWSE_OLD_INFO)) == 0)
 				packet_type = 1;
 			
 			if(packet_type)
 			{
 				/* we got ze info */
-				UNPACKER up;
+				CUnpacker up;
 				SERVER_INFO info = {0};
 				int i;
 				int token = -1;
 				
-				unpacker_reset(&up, (unsigned char*)packet->data+sizeof(SERVERBROWSE_INFO), packet->data_size-sizeof(SERVERBROWSE_INFO));
+				up.Reset((unsigned char*)pPacket->m_pData+sizeof(SERVERBROWSE_INFO), pPacket->m_DataSize-sizeof(SERVERBROWSE_INFO));
 				if(packet_type >= 2)
-					token = atol(unpacker_get_string(&up));
-				str_copy(info.version, unpacker_get_string(&up), sizeof(info.version));
-				str_copy(info.name, unpacker_get_string(&up), sizeof(info.name));
-				str_copy(info.map, unpacker_get_string(&up), sizeof(info.map));
-				str_copy(info.gametype, unpacker_get_string(&up), sizeof(info.gametype));
-				info.flags = atol(unpacker_get_string(&up));
-				info.progression = atol(unpacker_get_string(&up));
-				info.num_players = atol(unpacker_get_string(&up));
-				info.max_players = atol(unpacker_get_string(&up));
+					token = atol(up.GetString());
+				str_copy(info.version, up.GetString(), sizeof(info.version));
+				str_copy(info.name, up.GetString(), sizeof(info.name));
+				str_copy(info.map, up.GetString(), sizeof(info.map));
+				str_copy(info.gametype, up.GetString(), sizeof(info.gametype));
+				info.flags = atol(up.GetString());
+				info.progression = atol(up.GetString());
+				info.num_players = atol(up.GetString());
+				info.max_players = atol(up.GetString());
 				str_format(info.address, sizeof(info.address), "%d.%d.%d.%d:%d",
-					packet->address.ip[0], packet->address.ip[1], packet->address.ip[2],
-					packet->address.ip[3], packet->address.port);
+					pPacket->m_Address.ip[0], pPacket->m_Address.ip[1], pPacket->m_Address.ip[2],
+					pPacket->m_Address.ip[3], pPacket->m_Address.port);
 				
 				for(i = 0; i < info.num_players; i++)
 				{
-					str_copy(info.players[i].name, unpacker_get_string(&up), sizeof(info.players[i].name));
-					info.players[i].score = atol(unpacker_get_string(&up));
+					str_copy(info.players[i].name, up.GetString(), sizeof(info.players[i].name));
+					info.players[i].score = atol(up.GetString());
 				}
 				
-				if(!up.error)
+				if(!up.Error())
 				{
 					/* sort players */
 					qsort(info.players, info.num_players, sizeof(*info.players), player_score_comp);
 					
-					if(net_addr_comp(&server_address, &packet->address) == 0)
+					if(net_addr_comp(&server_address, &pPacket->m_Address) == 0)
 					{
 						mem_copy(&current_server_info, &info, sizeof(current_server_info));
 						current_server_info.netaddr = server_address;
@@ -986,9 +1007,9 @@ static void client_process_packet(NETCHUNK *packet)
 					else
 					{
 						if(packet_type == 2)
-							client_serverbrowse_set(&packet->address, BROWSESET_TOKEN, token, &info);
+							client_serverbrowse_set(&pPacket->m_Address, BROWSESET_TOKEN, token, &info);
 						else
-							client_serverbrowse_set(&packet->address, BROWSESET_OLD_INTERNET, -1, &info);
+							client_serverbrowse_set(&pPacket->m_Address, BROWSESET_OLD_INTERNET, -1, &info);
 					}
 				}
 			}
@@ -997,7 +1018,7 @@ static void client_process_packet(NETCHUNK *packet)
 	else
 	{
 		int sys;
-		int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
+		int msg = msg_unpack_start(pPacket->m_pData, pPacket->m_DataSize, &sys);
 		
 		if(sys)
 		{
@@ -1193,15 +1214,15 @@ static void client_process_packet(NETCHUNK *packet)
 					mem_copy((char*)snapshot_incomming_data + part*MAX_SNAPSHOT_PACKSIZE, data, part_size);
 					snapshot_parts |= 1<<part;
 				
-					if(snapshot_parts == (1<<num_parts)-1)
+					if(snapshot_parts == (unsigned)((1<<num_parts)-1))
 					{
-						static SNAPSHOT emptysnap;
-						SNAPSHOT *deltashot = &emptysnap;
+						static CSnapshot emptysnap;
+						CSnapshot *deltashot = &emptysnap;
 						int purgetick;
 						void *deltadata;
 						int deltasize;
-						unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
-						unsigned char tmpbuffer3[MAX_SNAPSHOT_SIZE];
+						unsigned char tmpbuffer2[CSnapshot::MAX_SIZE];
+						unsigned char tmpbuffer3[CSnapshot::MAX_SIZE];
 						int snapsize;
 						
 						complete_size = (num_parts-1) * MAX_SNAPSHOT_PACKSIZE + part_size;
@@ -1210,13 +1231,13 @@ static void client_process_packet(NETCHUNK *packet)
 						snapshot_parts = 0;
 						
 						/* find snapshot that we should use as delta */
-						emptysnap.data_size = 0;
-						emptysnap.num_items = 0;
+						emptysnap.m_DataSize = 0;
+						emptysnap.m_NumItems = 0;
 						
 						/* find delta */
 						if(delta_tick >= 0)
 						{
-							int deltashot_size = snapstorage_get(&snapshot_storage, delta_tick, 0, &deltashot, 0);
+							int deltashot_size = snapshot_storage.Get(delta_tick, 0, &deltashot, 0);
 							
 							if(deltashot_size < 0)
 							{
@@ -1233,7 +1254,7 @@ static void client_process_packet(NETCHUNK *packet)
 						}
 
 						/* decompress snapshot */
-						deltadata = snapshot_empty_delta();
+						deltadata = CSnapshot::EmptyDelta();
 						deltasize = sizeof(int)*3;
 
 						if(complete_size)
@@ -1249,19 +1270,19 @@ static void client_process_packet(NETCHUNK *packet)
 						
 						/* unpack delta */
 						purgetick = delta_tick;
-						snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize);
+						snapsize = CSnapshot::UnpackDelta(deltashot, (CSnapshot*)tmpbuffer3, deltadata, deltasize);
 						if(snapsize < 0)
 						{
 							dbg_msg("client", "delta unpack failed!");
 							return;
 						}
 						
-						if(msg != NETMSG_SNAPEMPTY && snapshot_crc((SNAPSHOT*)tmpbuffer3) != crc)
+						if(msg != NETMSG_SNAPEMPTY && ((CSnapshot*)tmpbuffer3)->Crc() != crc)
 						{
 							if(config.debug)
 							{
 								dbg_msg("client", "snapshot crc error #%d - tick=%d wantedcrc=%d gotcrc=%d compressed_size=%d delta_tick=%d",
-									snapcrcerrors, game_tick, crc, snapshot_crc((SNAPSHOT*)tmpbuffer3), complete_size, delta_tick);
+									snapcrcerrors, game_tick, crc, ((CSnapshot*)tmpbuffer3)->Crc(), complete_size, delta_tick);
 							}
 								
 							snapcrcerrors++;
@@ -1282,14 +1303,14 @@ static void client_process_packet(NETCHUNK *packet)
 
 						/* purge old snapshots */
 						purgetick = delta_tick;
-						if(snapshots[SNAP_PREV] && snapshots[SNAP_PREV]->tick < purgetick)
-							purgetick = snapshots[SNAP_PREV]->tick;
-						if(snapshots[SNAP_CURRENT] && snapshots[SNAP_CURRENT]->tick < purgetick)
-							purgetick = snapshots[SNAP_PREV]->tick;
-						snapstorage_purge_until(&snapshot_storage, purgetick);
+						if(snapshots[SNAP_PREV] && snapshots[SNAP_PREV]->m_Tick < purgetick)
+							purgetick = snapshots[SNAP_PREV]->m_Tick;
+						if(snapshots[SNAP_CURRENT] && snapshots[SNAP_CURRENT]->m_Tick < purgetick)
+							purgetick = snapshots[SNAP_PREV]->m_Tick;
+						snapshot_storage.PurgeUntil(purgetick);
 						
 						/* add new */
-						snapstorage_add(&snapshot_storage, game_tick, time_get(), snapsize, (SNAPSHOT*)tmpbuffer3, 1);
+						snapshot_storage.Add(game_tick, time_get(), snapsize, (CSnapshot*)tmpbuffer3, 1);
 
 						/* add snapshot to demo */
 						if(demorec_isrecording())
@@ -1320,8 +1341,8 @@ static void client_process_packet(NETCHUNK *packet)
 							st_init(&predicted_time, game_tick*time_freq()/50);
 							predicted_time.adjustspeed[1] = 1000.0f;
 							st_init(&game_time, (game_tick-1)*time_freq()/50);
-							snapshots[SNAP_PREV] = snapshot_storage.first;
-							snapshots[SNAP_CURRENT] = snapshot_storage.last;
+							snapshots[SNAP_PREV] = snapshot_storage.m_pFirst;
+							snapshots[SNAP_CURRENT] = snapshot_storage.m_pLast;
 							local_start_time = time_get();
 							client_set_state(CLIENTSTATE_ONLINE);
 						}
@@ -1345,8 +1366,8 @@ static void client_process_packet(NETCHUNK *packet)
 		{
 			/* game message */
 			if(demorec_isrecording())
-				demorec_record_message(packet->data, packet->data_size);
-				/* demorec_record_write("MESG", packet->data_size, ); */
+				demorec_record_message(pPacket->m_pData, pPacket->m_DataSize);
+				/* demorec_record_write("MESG", pPacket->data_size, ); */
 
 			modc_message(msg);
 		}
@@ -1358,22 +1379,21 @@ int client_mapdownload_totalsize() { return mapdownload_totalsize; }
 
 static void client_pump_network()
 {
-	NETCHUNK packet;
 
-	netclient_update(net);
+	m_NetClient.Update();
 
 	if(client_state() != CLIENTSTATE_DEMOPLAYBACK)
 	{
 		/* check for errors */
-		if(client_state() != CLIENTSTATE_OFFLINE && netclient_state(net) == NETSTATE_OFFLINE)
+		if(client_state() != CLIENTSTATE_OFFLINE && m_NetClient.State() == NETSTATE_OFFLINE)
 		{
 			client_set_state(CLIENTSTATE_OFFLINE);
 			client_disconnect();
-			dbg_msg("client", "offline error='%s'", netclient_error_string(net));
+			dbg_msg("client", "offline error='%s'", m_NetClient.ErrorString());
 		}
 
 		/* */
-		if(client_state() == CLIENTSTATE_CONNECTING && netclient_state(net) == NETSTATE_ONLINE)
+		if(client_state() == CLIENTSTATE_CONNECTING && m_NetClient.State() == NETSTATE_ONLINE)
 		{
 			/* we switched to online */
 			dbg_msg("client", "connected, sending info");
@@ -1383,15 +1403,16 @@ static void client_pump_network()
 	}
 	
 	/* process packets */
-	while(netclient_recv(net, &packet))
-		client_process_packet(&packet);
+	CNetChunk Packet;
+	while(m_NetClient.Recv(&Packet))
+		client_process_packet(&Packet);
 }
 
-static void client_democallback_snapshot(void *data, int size)
+static void client_democallback_snapshot(void *pData, int Size)
 {
 	/* update ticks, they could have changed */
 	const DEMOREC_PLAYBACKINFO *info = demorec_playback_info();			
-	SNAPSTORAGE_HOLDER *temp;
+	CSnapshotStorage::CHolder *temp;
 	current_tick = info->current_tick;
 	prev_tick = info->previous_tick;
 	
@@ -1400,8 +1421,8 @@ static void client_democallback_snapshot(void *data, int size)
 	snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
 	snapshots[SNAP_CURRENT] = temp;
 	
-	mem_copy(snapshots[SNAP_CURRENT]->snap, data, size);
-	mem_copy(snapshots[SNAP_CURRENT]->alt_snap, data, size);
+	mem_copy(snapshots[SNAP_CURRENT]->m_pSnap, pData, Size);
+	mem_copy(snapshots[SNAP_CURRENT]->m_pAltSnap, pData, Size);
 	
 	modc_newsnapshot();
 	/*modc_predict();*/
@@ -1476,20 +1497,20 @@ static void client_update()
 
 		while(1)
 		{
-			SNAPSTORAGE_HOLDER *cur = snapshots[SNAP_CURRENT];
-			int64 tickstart = (cur->tick)*time_freq()/50;
+			CSnapshotStorage::CHolder *cur = snapshots[SNAP_CURRENT];
+			int64 tickstart = (cur->m_Tick)*time_freq()/50;
 
 			if(tickstart < now)
 			{
-				SNAPSTORAGE_HOLDER *next = snapshots[SNAP_CURRENT]->next;
+				CSnapshotStorage::CHolder *next = snapshots[SNAP_CURRENT]->m_pNext;
 				if(next)
 				{
 					snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
 					snapshots[SNAP_CURRENT] = next;
 					
 					/* set ticks */
-					current_tick = snapshots[SNAP_CURRENT]->tick;
-					prev_tick = snapshots[SNAP_PREV]->tick;
+					current_tick = snapshots[SNAP_CURRENT]->m_Tick;
+					prev_tick = snapshots[SNAP_PREV]->m_Tick;
 					
 					if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
 					{
@@ -1506,8 +1527,8 @@ static void client_update()
 
 		if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
 		{
-			int64 curtick_start = (snapshots[SNAP_CURRENT]->tick)*time_freq()/50;
-			int64 prevtick_start = (snapshots[SNAP_PREV]->tick)*time_freq()/50;
+			int64 curtick_start = (snapshots[SNAP_CURRENT]->m_Tick)*time_freq()/50;
+			int64 prevtick_start = (snapshots[SNAP_PREV]->m_Tick)*time_freq()/50;
 			/*tg_add(&predicted_time_graph, pred_now, 0); */
 			int prev_pred_tick = (int)(pred_now*50/time_freq());
 			int new_pred_tick = prev_pred_tick+1;
@@ -1520,10 +1541,10 @@ static void client_update()
 			prevtick_start = prev_pred_tick*time_freq()/50;
 			predintratick = (pred_now - prevtick_start) / (float)(curtick_start-prevtick_start);
 			
-			if(new_pred_tick < snapshots[SNAP_PREV]->tick-SERVER_TICK_SPEED || new_pred_tick > snapshots[SNAP_PREV]->tick+SERVER_TICK_SPEED)
+			if(new_pred_tick < snapshots[SNAP_PREV]->m_Tick-SERVER_TICK_SPEED || new_pred_tick > snapshots[SNAP_PREV]->m_Tick+SERVER_TICK_SPEED)
 			{
 				dbg_msg("client", "prediction time reset!");
-				st_init(&predicted_time, snapshots[SNAP_CURRENT]->tick*time_freq()/50);
+				st_init(&predicted_time, snapshots[SNAP_CURRENT]->m_Tick*time_freq()/50);
 			}
 			
 			if(new_pred_tick > current_predtick)
@@ -1606,27 +1627,24 @@ static void client_versionupdate()
 	{
 		if(jobs_status(&version_serveraddr.job) == JOBSTATUS_DONE)
 		{
-			NETCHUNK packet;
+			CNetChunk Packet;
 			
-			mem_zero(&packet, sizeof(NETCHUNK));
+			mem_zero(&Packet, sizeof(Packet));
 			
 			version_serveraddr.addr.port = VERSIONSRV_PORT;
 			
-			packet.client_id = -1;
-			packet.address = version_serveraddr.addr;
-			packet.data = VERSIONSRV_GETVERSION;
-			packet.data_size = sizeof(VERSIONSRV_GETVERSION);
-			packet.flags = NETSENDFLAG_CONNLESS;
+			Packet.m_ClientID = -1;
+			Packet.m_Address = version_serveraddr.addr;
+			Packet.m_pData = VERSIONSRV_GETVERSION;
+			Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION);
+			Packet.m_Flags = NETSENDFLAG_CONNLESS;
 			
-			netclient_send(net, &packet);
+			m_NetClient.Send(&Packet);
 			state++;
 		}
 	}
 }
 
-extern int editor_update_and_render();
-extern void editor_init();
-
 static void client_run()
 {
 	NETADDR bindaddr;
@@ -1640,14 +1658,16 @@ static void client_run()
 	snapshot_parts = 0;
 	
 	/* init graphics and sound */
-	if(gfx_init() != 0)
+	m_pGraphics = CreateEngineGraphics();
+	if(m_pGraphics->Init() != 0)
 		return;
 
 	/* start refreshing addresses while we load */
 	mastersrv_refresh_addresses();
 	
 	/* init the editor */
-	editor_init();
+	m_pEditor = CreateEditor();
+	m_pEditor->Init(m_pGraphics);
 
 	/* sound is allowed to fail */
 	snd_init();
@@ -1657,12 +1677,13 @@ static void client_run()
 		return;
 
 	/* init the mod */
+	m_pGameClient = CreateGameClient(&m_Client);
 	modc_init();
 	dbg_msg("client", "version %s", modc_net_version());
 	
 	/* open socket */
 	mem_zero(&bindaddr, sizeof(bindaddr));
-	net = netclient_open(bindaddr, 0);
+	m_NetClient.Open(bindaddr, 0);
 	
 	/* connect to the server if wanted */
 	/*
@@ -1714,7 +1735,7 @@ static void client_run()
 		}
 		
 		/* release focus */
-		if(!gfx_window_active())
+		if(!Graphics()->WindowActive())
 		{
 			if(window_must_refocus == 0)
 				inp_mouse_mode_absolute();
@@ -1727,7 +1748,7 @@ static void client_run()
 		}
 
 		/* refocus */
-		if(window_must_refocus && gfx_window_active())
+		if(window_must_refocus && Graphics()->WindowActive())
 		{
 			if(window_must_refocus < 3)
 			{
@@ -1767,8 +1788,8 @@ static void client_run()
 		if(config.cl_editor)
 		{
 			client_update();
-			editor_update_and_render();
-			gfx_swap();
+			m_pEditor->UpdateAndRender();
+			m_pGraphics->Swap();
 		}
 		else
 		{
@@ -1784,7 +1805,7 @@ static void client_run()
 				if((frames%10) == 0)
 				{
 					client_render();
-					gfx_swap();
+					m_pGraphics->Swap();
 				}
 			}
 			else
@@ -1799,7 +1820,7 @@ static void client_run()
 				{
 					static PERFORMACE_INFO scope = {"gfx_swap", 0};
 					perf_start(&scope);
-					gfx_swap();
+					m_pGraphics->Swap();
 					perf_end();
 				}
 			}
@@ -1815,7 +1836,7 @@ static void client_run()
 		/* be nice */
 		if(config.dbg_stress)
 			thread_sleep(5);
-		else if(config.cl_cpu_throttle || !gfx_window_active())
+		else if(config.cl_cpu_throttle || !Graphics()->WindowActive())
 			thread_sleep(1);
 			
 		if(config.dbg_hitch)
@@ -1832,7 +1853,7 @@ static void client_run()
 					frames/(float)(reportinterval/time_freq()),
 					1.0f/frametime_high,
 					1.0f/frametime_low,
-					netclient_state(net));
+					m_NetClient.State());
 			}
 			frametime_low = 1;
 			frametime_high = 0;
@@ -1857,10 +1878,15 @@ static void client_run()
 	modc_shutdown();
 	client_disconnect();
 
-	gfx_shutdown();
+	m_pGraphics->Shutdown();
 	snd_shutdown();
 }
 
+void gfx_swap()
+{
+	m_pGraphics->Swap();
+}
+
 static void con_connect(void *result, void *user_data)
 {
 	str_copy(cmd_connect, console_arg_string(result, 0), sizeof(cmd_connect));
@@ -1886,7 +1912,7 @@ static void con_ping(void *result, void *user_data)
 
 static void con_screenshot(void *result, void *user_data)
 {
-	gfx_screenshot();
+	Graphics()->TakeScreenshot();
 }
 
 static void con_rcon(void *result, void *user_data)
@@ -1911,7 +1937,7 @@ const char *client_demoplayer_play(const char *filename)
 	int crc;
 	const char *error;
 	client_disconnect();
-	netclient_error_string_reset(net);
+	m_NetClient.ResetErrorString();
 	
 	/* try to start playback */
 	demorec_playback_registercallbacks(client_democallback_snapshot, client_democallback_message);
@@ -1939,15 +1965,15 @@ const char *client_demoplayer_play(const char *filename)
 	snapshots[SNAP_CURRENT] = &demorec_snapshotholders[SNAP_CURRENT];
 	snapshots[SNAP_PREV] = &demorec_snapshotholders[SNAP_PREV];
 	
-	snapshots[SNAP_CURRENT]->snap = (SNAPSHOT *)demorec_snapshotdata[SNAP_CURRENT][0];
-	snapshots[SNAP_CURRENT]->alt_snap = (SNAPSHOT *)demorec_snapshotdata[SNAP_CURRENT][1];
-	snapshots[SNAP_CURRENT]->snap_size = 0;
-	snapshots[SNAP_CURRENT]->tick = -1;
+	snapshots[SNAP_CURRENT]->m_pSnap = (CSnapshot *)demorec_snapshotdata[SNAP_CURRENT][0];
+	snapshots[SNAP_CURRENT]->m_pAltSnap = (CSnapshot *)demorec_snapshotdata[SNAP_CURRENT][1];
+	snapshots[SNAP_CURRENT]->m_SnapSize = 0;
+	snapshots[SNAP_CURRENT]->m_Tick = -1;
 	
-	snapshots[SNAP_PREV]->snap = (SNAPSHOT *)demorec_snapshotdata[SNAP_PREV][0];
-	snapshots[SNAP_PREV]->alt_snap = (SNAPSHOT *)demorec_snapshotdata[SNAP_PREV][1];
-	snapshots[SNAP_PREV]->snap_size = 0;
-	snapshots[SNAP_PREV]->tick = -1;
+	snapshots[SNAP_PREV]->m_pSnap = (CSnapshot *)demorec_snapshotdata[SNAP_PREV][0];
+	snapshots[SNAP_PREV]->m_pAltSnap = (CSnapshot *)demorec_snapshotdata[SNAP_PREV][1];
+	snapshots[SNAP_PREV]->m_SnapSize = 0;
+	snapshots[SNAP_PREV]->m_Tick = -1;
 
 	/* enter demo playback state */
 	client_set_state(CLIENTSTATE_DEMOPLAYBACK);
diff --git a/src/engine/client/ec_gfx.c b/src/engine/client/ec_gfx.c
deleted file mode 100644
index 1ea9f407..00000000
--- a/src/engine/client/ec_gfx.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-
-#include <base/detect.h>
-
-#include "SDL.h"
-
-#ifdef CONF_FAMILY_WINDOWS
-	#define WIN32_LEAN_AND_MEAN
-	#include <windows.h>
-#endif
-
-#ifdef CONF_PLATFORM_MACOSX
-	#include <OpenGL/gl.h>
-	#include <OpenGL/glu.h>
-#else
-	#include <GL/gl.h>
-	#include <GL/glu.h>
-#endif
-
-#include <base/system.h>
-#include <engine/external/pnglite/pnglite.h>
-
-#include <engine/e_client_interface.h>
-#include <engine/e_engine.h>
-#include <engine/e_config.h>
-#include <engine/e_keys.h>
-
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-
-/* compressed textures */
-#define GL_COMPRESSED_RGB_ARB 0x84ED
-#define GL_COMPRESSED_RGBA_ARB 0x84EE
-#define GL_COMPRESSED_ALPHA_ARB 0x84E9
-
-#define TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
-
-enum
-{
-	DRAWING_QUADS=1,
-	DRAWING_LINES=2
-};
-
-/* */
-typedef struct { float x, y, z; } VEC3;
-typedef struct { float u, v; } TEXCOORD;
-typedef struct { float r, g, b, a; } COLOR;
-
-typedef struct
-{
-	VEC3 pos;
-	TEXCOORD tex;
-	COLOR color;
-} VERTEX;
-
-const int vertex_buffer_size = 32*1024;
-static VERTEX *vertices = 0;
-static int num_vertices = 0;
-
-static int no_gfx = 0;
-
-static COLOR color[4];
-static TEXCOORD texture[4];
-
-static int do_screenshot = 0;
-static int render_enable = 1;
-
-static int screen_width = -1;
-static int screen_height = -1;
-static float rotation = 0;
-static int drawing = 0;
-
-static float screen_x0 = 0;
-static float screen_y0 = 0;
-static float screen_x1 = 0;
-static float screen_y1 = 0;
-
-static int invalid_texture = 0;
-
-typedef struct
-{
-	GLuint tex;
-	int memsize;
-	int flags;
-	int next;
-} TEXTURE;
-
-enum
-{
-	MAX_TEXTURES = 1024*4
-};
-
-static TEXTURE textures[MAX_TEXTURES];
-static int first_free_texture;
-static int memory_usage = 0;
-
-static SDL_Surface *screen_surface;
-
-static const unsigned char null_texture_data[] = {
-	0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, 
-	0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, 
-	0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, 
-	0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, 
-};
-
-static void flush()
-{
-	if(num_vertices == 0)
-		return;
-		
-	if(no_gfx)
-	{
-		num_vertices = 0;
-		return;
-	}
-	
-		
-	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-	glVertexPointer(3, GL_FLOAT,
-			sizeof(VERTEX),
-			(char*)vertices);
-	glTexCoordPointer(2, GL_FLOAT,
-			sizeof(VERTEX),
-			(char*)vertices + sizeof(float)*3);
-	glColorPointer(4, GL_FLOAT,
-			sizeof(VERTEX),
-			(char*)vertices + sizeof(float)*5);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-	
-	if(render_enable)
-	{
-		if(drawing == DRAWING_QUADS)
-			glDrawArrays(GL_QUADS, 0, num_vertices);
-		else if(drawing == DRAWING_LINES)
-			glDrawArrays(GL_LINES, 0, num_vertices);
-	}
-	
-	/* Reset pointer */
-	num_vertices = 0;
-}
-
-static void add_vertices(int count)
-{
-	num_vertices += count;
-	if((num_vertices + count) >= vertex_buffer_size)
-		flush();
-}
-
-static int try_init()
-{
-	const SDL_VideoInfo *info;
-	int flags = SDL_OPENGL;
-	
-	screen_width = config.gfx_screen_width;
-	screen_height = config.gfx_screen_height;
-
-	info = SDL_GetVideoInfo();
-
-	/* set flags */
-	flags  = SDL_OPENGL;
-	flags |= SDL_GL_DOUBLEBUFFER;
-	flags |= SDL_HWPALETTE;
-	if(config.dbg_resizable)
-		flags |= SDL_RESIZABLE;
-
-	if(info->hw_available)
-		flags |= SDL_HWSURFACE;
-	else
-		flags |= SDL_SWSURFACE;
-
-	if(info->blit_hw)
-		flags |= SDL_HWACCEL;
-
-	if(config.gfx_fullscreen)
-		flags |= SDL_FULLSCREEN;
-
-	/* set gl attributes */
-	if(config.gfx_fsaa_samples)
-	{
-		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
-		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config.gfx_fsaa_samples);
-	}
-	else
-	{
-		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
-		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
-	}
-
-	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-	SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, config.gfx_vsync);
-
-	/* set caption */
-	SDL_WM_SetCaption("Teeworlds", "Teeworlds");
-	
-	/* create window */
-	screen_surface = SDL_SetVideoMode(screen_width, screen_height, 0, flags);
-	if(screen_surface == NULL)
-	{
-		dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError());
-		return -1;
-	}
-	
-	return 0;
-}
-
-void gfx_font_init();
-
-static int gfx_init_window()
-{
-	if(try_init() == 0)
-		return 0;
-	
-	/* try disabling fsaa */
-	while(config.gfx_fsaa_samples)
-	{
-		config.gfx_fsaa_samples--;
-		
-		if(config.gfx_fsaa_samples)
-			dbg_msg("gfx", "lowering FSAA to %d and trying again", config.gfx_fsaa_samples);
-		else
-			dbg_msg("gfx", "disabling FSAA and trying again");
-
-		if(try_init() == 0)
-			return 0;
-	}
-
-	/* try lowering the resolution */
-	if(config.gfx_screen_width != 640 || config.gfx_screen_height != 480)
-	{
-		dbg_msg("gfx", "setting resolution to 640x480 and trying again");
-		config.gfx_screen_width = 640;
-		config.gfx_screen_height = 480;
-
-		if(try_init() == 0)
-			return 0;
-	}
-
-	dbg_msg("gfx", "out of ideas. failed to init graphics");
-					
-	return -1;		
-}
-
-int gfx_init()
-{
-	int i;
-
-	if(config.dbg_stress)
-		no_gfx = 1;
-
-	{
-		int systems = 0;
-		
-		if(!no_gfx)
-			systems |= SDL_INIT_VIDEO;
-			
-		if(config.snd_enable)
-			systems |= SDL_INIT_AUDIO;
-
-		if(config.cl_eventthread)
-			systems |= SDL_INIT_EVENTTHREAD;
-		
-		if(SDL_Init(systems) < 0)
-		{
-			dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError());
-			return -1;
-		}
-	}
-	
-    atexit(SDL_Quit);
-
-	if(!no_gfx)
-	{
-		#ifdef CONF_FAMILY_WINDOWS
-			if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED"))
-				putenv("SDL_VIDEO_WINDOW_POS=8,27");
-		#endif
-		
-		if(gfx_init_window() != 0)
-			return -1;
-	}
-	
-	/* Init vertices */
-	if (vertices)
-		mem_free(vertices);
-	vertices = (VERTEX*)mem_alloc(sizeof(VERTEX) * vertex_buffer_size, 1);
-	num_vertices = 0;
-
-
-	/*
-	dbg_msg("gfx", "OpenGL version %d.%d.%d", context.version_major(),
-											  context.version_minor(),
-											  context.version_rev());*/
-
-	
-	/* Set all z to -5.0f */
-	for (i = 0; i < vertex_buffer_size; i++)
-		vertices[i].pos.z = -5.0f;
-
-	/* init textures */
-	first_free_texture = 0;
-	for(i = 0; i < MAX_TEXTURES; i++)
-		textures[i].next = i+1;
-	textures[MAX_TEXTURES-1].next = -1;
-	
-	if(!no_gfx)
-	{
-		SDL_ShowCursor(0);
-		gfx_mapscreen(0,0,config.gfx_screen_width, config.gfx_screen_height);
-
-		/* set some default settings */	
-		glEnable(GL_BLEND);
-		glDisable(GL_CULL_FACE);
-		glDisable(GL_DEPTH_TEST);
-		glMatrixMode(GL_MODELVIEW);
-		glLoadIdentity();
-		
-		glAlphaFunc(GL_GREATER, 0);
-		glEnable(GL_ALPHA_TEST);
-		glDepthMask(0);
-
-		
-		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	}
-
-	/* init input */
-	inp_init();
-	
-	/* create null texture, will get id=0 */
-	invalid_texture = gfx_load_texture_raw(4,4,IMG_RGBA,null_texture_data,IMG_RGBA,TEXLOAD_NORESAMPLE);
-	dbg_msg("", "invalid texture id: %d %d", invalid_texture, textures[invalid_texture].tex);
-
-
-	/* font init */
-	gfx_font_init();
-	/* perform some tests */
-	/* pixeltest_dotesting(); */
-	
-	/*if(config.dbg_stress)
-		gfx_minimize();*/
-
-	return 0;
-}
-
-float gfx_screenaspect()
-{
-    return gfx_screenwidth()/(float)gfx_screenheight();
-}
-
-int gfx_window_active()
-{
-	return SDL_GetAppState()&SDL_APPINPUTFOCUS;
-}
-
-int gfx_window_open()
-{
-	return SDL_GetAppState()&SDL_APPACTIVE;
-}
-
-VIDEO_MODE fakemodes[] = {
-	{320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8},
-	{720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8},
-	{1024,600,8,8,8}, {1024,768,8,8,8}, {1152,864,8,8,8},
-	{1280,768,8,8,8}, {1280,800,8,8,8}, {1280,960,8,8,8},
-	{1280,1024,8,8,8}, {1368,768,8,8,8}, {1400,1050,8,8,8},
-	{1440,900,8,8,8}, {1440,1050,8,8,8}, {1600,1000,8,8,8},
-	{1600,1200,8,8,8}, {1680,1050,8,8,8}, {1792,1344,8,8,8},
-	{1800,1440,8,8,8}, {1856,1392,8,8,8}, {1920,1080,8,8,8},
-	{1920,1200,8,8,8}, {1920,1440,8,8,8}, {1920,2400,8,8,8},
-	{2048,1536,8,8,8},
-		
-	{320,240,5,6,5}, {400,300,5,6,5}, {640,480,5,6,5},
-	{720,400,5,6,5}, {768,576,5,6,5}, {800,600,5,6,5},
-	{1024,600,5,6,5}, {1024,768,5,6,5}, {1152,864,5,6,5},
-	{1280,768,5,6,5}, {1280,800,5,6,5}, {1280,960,5,6,5},
-	{1280,1024,5,6,5}, {1368,768,5,6,5}, {1400,1050,5,6,5},
-	{1440,900,5,6,5}, {1440,1050,5,6,5}, {1600,1000,5,6,5},
-	{1600,1200,5,6,5}, {1680,1050,5,6,5}, {1792,1344,5,6,5},
-	{1800,1440,5,6,5}, {1856,1392,5,6,5}, {1920,1080,5,6,5},
-	{1920,1200,5,6,5}, {1920,1440,5,6,5}, {1920,2400,5,6,5},
-	{2048,1536,5,6,5}
-};
-
-int gfx_get_video_modes(VIDEO_MODE *list, int maxcount)
-{
-	int num_modes = sizeof(fakemodes)/sizeof(VIDEO_MODE);
-	SDL_Rect **modes;
-
-	if(config.gfx_display_all_modes)
-	{
-		int count = sizeof(fakemodes)/sizeof(VIDEO_MODE);
-		mem_copy(list, fakemodes, sizeof(fakemodes));
-		if(maxcount < count)
-			count = maxcount;
-		return count;
-	}
-	
-	/* TODO: fix this code on osx or windows */
-		
-	modes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN);
-	if(modes == NULL)
-	{
-		/* no modes */
-		num_modes = 0;
-	}
-	else if(modes == (SDL_Rect**)-1)
-	{
-		/* all modes */
-	}
-	else
-	{
-		int i;
-		num_modes = 0;
-		for(i = 0; modes[i]; ++i)
-		{
-			if(num_modes == maxcount)
-				break;
-			list[num_modes].width = modes[i]->w;
-			list[num_modes].height = modes[i]->h;
-			list[num_modes].red = 8;
-			list[num_modes].green = 8;
-			list[num_modes].blue = 8;
-			num_modes++;
-		}
-	}
-	
-	return num_modes;
-}
-
-int gfx_unload_texture(int index)
-{
-	if(index == invalid_texture)
-		return 0;
-		
-	if(index < 0)
-		return 0;
-		
-	glDeleteTextures(1, &textures[index].tex);
-	textures[index].next = first_free_texture;
-	memory_usage -= textures[index].memsize;
-	first_free_texture = index;
-	return 0;
-}
-
-void gfx_blend_none()
-{
-	if(no_gfx) return;
-	glDisable(GL_BLEND);
-}
-
-void gfx_blend_normal()
-{
-	if(no_gfx) return;
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-}
-
-void gfx_blend_additive()
-{
-	if(no_gfx) return;
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-}
-
-int gfx_memory_usage() { return memory_usage; }
-
-static unsigned char sample(int w, int h, const unsigned char *data, int u, int v, int offset)
-{
-	return (data[(v*w+u)*4+offset]+
-	data[(v*w+u+1)*4+offset]+
-	data[((v+1)*w+u)*4+offset]+
-	data[((v+1)*w+u+1)*4+offset])/4;
-}
-
-int gfx_load_texture_raw(int w, int h, int format, const void *data, int store_format, int flags)
-{
-	int mipmap = 1;
-	unsigned char *texdata = (unsigned char *)data;
-	unsigned char *tmpdata = 0;
-	int oglformat = 0;
-	int store_oglformat = 0;
-	int tex = 0;
-	
-	/* don't waste memory on texture if we are stress testing */
-	if(config.dbg_stress || no_gfx)
-		return 	invalid_texture;
-	
-	/* grab texture */
-	tex = first_free_texture;
-	first_free_texture = textures[tex].next;
-	textures[tex].next = -1;
-	
-	/* resample if needed */
-	if(!(flags&TEXLOAD_NORESAMPLE) && config.gfx_texture_quality==0)
-	{
-		if(w > 16 && h > 16 && format == IMG_RGBA)
-		{
-			unsigned char *tmpdata;
-			int c = 0;
-			int x, y;
-
-			tmpdata = (unsigned char *)mem_alloc(w*h*4, 1);
-
-			w/=2;
-			h/=2;
-
-			for(y = 0; y < h; y++)
-				for(x = 0; x < w; x++, c++)
-				{
-					tmpdata[c*4] = sample(w*2, h*2, texdata, x*2,y*2, 0);
-					tmpdata[c*4+1] = sample(w*2, h*2, texdata, x*2,y*2, 1);
-					tmpdata[c*4+2] = sample(w*2, h*2, texdata, x*2,y*2, 2);
-					tmpdata[c*4+3] = sample(w*2, h*2, texdata, x*2,y*2, 3);
-				}
-			texdata = tmpdata;
-		}
-	}
-	
-	oglformat = GL_RGBA;
-	if(format == IMG_RGB)
-		oglformat = GL_RGB;
-	else if(format == IMG_ALPHA)
-		oglformat = GL_ALPHA;
-	
-	/* upload texture */
-	if(config.gfx_texture_compression)
-	{
-		store_oglformat = GL_COMPRESSED_RGBA_ARB;
-		if(store_format == IMG_RGB)
-			store_oglformat = GL_COMPRESSED_RGB_ARB;
-		else if(store_format == IMG_ALPHA)
-			store_oglformat = GL_COMPRESSED_ALPHA_ARB;
-	}
-	else
-	{
-		store_oglformat = GL_RGBA;
-		if(store_format == IMG_RGB)
-			store_oglformat = GL_RGB;
-		else if(store_format == IMG_ALPHA)
-			store_oglformat = GL_ALPHA;
-	}
-		
-	glGenTextures(1, &textures[tex].tex);
-	glBindTexture(GL_TEXTURE_2D, textures[tex].tex);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-	gluBuild2DMipmaps(GL_TEXTURE_2D, store_oglformat, w, h, oglformat, GL_UNSIGNED_BYTE, texdata);
-	
-	/* calculate memory usage */
-	{
-		int pixel_size = 4;
-		if(store_format == IMG_RGB)
-			pixel_size = 3;
-		else if(store_format == IMG_ALPHA)
-			pixel_size = 1;
-
-		textures[tex].memsize = w*h*pixel_size;
-		if(mipmap)
-		{
-			while(w > 2 && h > 2)
-			{
-				w>>=1;
-				h>>=1;
-				textures[tex].memsize += w*h*pixel_size;
-			}
-		}
-	}
-	
-	memory_usage += textures[tex].memsize;
-	mem_free(tmpdata);
-	return tex;
-}
-
-/* simple uncompressed RGBA loaders */
-int gfx_load_texture(const char *filename, int store_format, int flags)
-{
-	int l = strlen(filename);
-	int id;
-	IMAGE_INFO img;
-	
-	if(l < 3)
-		return -1;
-	if(gfx_load_png(&img, filename))
-	{
-		if (store_format == IMG_AUTO)
-			store_format = img.format;
-
-		id = gfx_load_texture_raw(img.width, img.height, img.format, img.data, store_format, flags);
-		mem_free(img.data);
-		return id;
-	}
-	
-	return invalid_texture;
-}
-
-int gfx_load_png(IMAGE_INFO *img, const char *filename)
-{
-	char completefilename[512];
-	unsigned char *buffer;
-	png_t png;
-	
-	/* open file for reading */
-	png_init(0,0);
-
-	engine_getpath(completefilename, sizeof(completefilename), filename, IOFLAG_READ);
-	
-	if(png_open_file(&png, completefilename) != PNG_NO_ERROR)
-	{
-		dbg_msg("game/png", "failed to open file. filename='%s'", completefilename);
-		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'", completefilename);
-		png_close_file(&png);
-        return 0;
-	}
-		
-	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 (vertices)
-		mem_free(vertices);
-
-	/* TODO: SDL, is this correct? */
-	SDL_Quit();
-}
-
-void gfx_screenshot()
-{
-	do_screenshot = 1;
-}
-
-
-extern int text_render_codepaths_usage[5];
-
-void gfx_swap()
-{
-	/*dbg_msg("", "%d %d %d %d %d",
-		text_render_codepaths_usage[0],
-		text_render_codepaths_usage[1],
-		text_render_codepaths_usage[2],
-		text_render_codepaths_usage[3],
-		text_render_codepaths_usage[4]);
-
-	text_render_codepaths_usage[0] = 0;
-	text_render_codepaths_usage[1] = 0;
-	text_render_codepaths_usage[2] = 0;
-	text_render_codepaths_usage[3] = 0;
-	text_render_codepaths_usage[4] = 0;*/
-
-	if(do_screenshot)
-	{
-		/* find filename */
-		char filename[128];
-		static int index = 1;
-
-		for(; index < 1000; index++)
-		{
-			IOHANDLE io;
-			str_format(filename, sizeof(filename), "screenshots/screenshot%04d.png", index);
-			io = engine_openfile(filename, IOFLAG_READ);
-			if(io)
-				io_close(io);
-			else
-				break;
-		}
-
-		gfx_screenshot_direct(filename);
-	
-		do_screenshot = 0;	
-	}
-	
-	{
-		static PERFORMACE_INFO pscope = {"glfwSwapBuffers", 0};
-		perf_start(&pscope);
-		SDL_GL_SwapBuffers();
-		perf_end();
-	}
-	
-	if(render_enable && config.gfx_finish)
-		glFinish();
-}
-
-void gfx_screenshot_direct(const char *filename)
-{
-	/* fetch image data */
-	int y;
-	int w = screen_width;
-	int h = screen_height;
-	unsigned char *pixel_data = (unsigned char *)mem_alloc(w*(h+1)*4, 1);
-	unsigned char *temp_row = pixel_data+w*h*4;
-	glReadPixels(0,0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data);
-	
-	/* flip the pixel because opengl works from bottom left corner */
-	for(y = 0; y < h/2; y++)
-	{
-		mem_copy(temp_row, pixel_data+y*w*4, w*4);
-		mem_copy(pixel_data+y*w*4, pixel_data+(h-y-1)*w*4, w*4);
-		mem_copy(pixel_data+(h-y-1)*w*4, temp_row,w*4);
-	}
-	
-	/* find filename */
-	{
-		char wholepath[1024];
-		png_t png;
-
-		engine_savepath(filename, wholepath, sizeof(wholepath));
-	
-		/* save png */
-		dbg_msg("client", "saved screenshot to '%s'", wholepath);
-		png_open_file_write(&png, wholepath);
-		png_set_data(&png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pixel_data);
-		png_close_file(&png);
-	}
-
-	/* clean up */
-	mem_free(pixel_data);
-}
-
-int gfx_screenwidth()
-{
-	return screen_width;
-}
-
-int gfx_screenheight()
-{
-	return screen_height;
-}
-
-void gfx_texture_set(int slot)
-{
-	dbg_assert(drawing == 0, "called gfx_texture_set within begin");
-	if(no_gfx) return;
-	if(slot == -1)
-	{
-		glDisable(GL_TEXTURE_2D);
-	}
-	else
-	{
-		glEnable(GL_TEXTURE_2D);
-		glBindTexture(GL_TEXTURE_2D, textures[slot].tex);
-	}
-}
-
-void gfx_clear(float r, float g, float b)
-{
-	if(no_gfx) return;
-	glClearColor(r,g,b,0.0f);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-}
-
-void gfx_mapscreen(float tl_x, float tl_y, float br_x, float br_y)
-{
-	screen_x0 = tl_x;
-	screen_y0 = tl_y;
-	screen_x1 = br_x;
-	screen_y1 = br_y;
-	if(no_gfx) return;
-	glMatrixMode(GL_PROJECTION);
-	glLoadIdentity();
-	glOrtho(tl_x, br_x, br_y, tl_y, 1.0f, 10.f);
-}
-
-void gfx_getscreen(float *tl_x, float *tl_y, float *br_x, float *br_y)
-{
-	*tl_x = screen_x0;
-	*tl_y = screen_y0;
-	*br_x = screen_x1;
-	*br_y = screen_y1;
-}
-
-void gfx_quads_begin()
-{
-	dbg_assert(drawing == 0, "called quads_begin twice");
-	drawing = DRAWING_QUADS;
-	
-	gfx_quads_setsubset(0,0,1,1);
-	gfx_quads_setrotation(0);
-	gfx_setcolor(1,1,1,1);
-}
-
-void gfx_quads_end()
-{
-	dbg_assert(drawing == DRAWING_QUADS, "called quads_end without begin");
-	flush();
-	drawing = 0;
-}
-
-
-void gfx_quads_setrotation(float angle)
-{
-	dbg_assert(drawing == DRAWING_QUADS, "called gfx_quads_setrotation without begin");
-	rotation = angle;
-}
-
-void gfx_setcolorvertex(int i, float r, float g, float b, float a)
-{
-	dbg_assert(drawing != 0, "called gfx_quads_setcolorvertex without begin");
-	color[i].r = r;
-	color[i].g = g;
-	color[i].b = b;
-	color[i].a = a;
-}
-
-void gfx_setcolor(float r, float g, float b, float a)
-{
-	dbg_assert(drawing != 0, "called gfx_quads_setcolor without begin");
-	gfx_setcolorvertex(0, r, g, b, a);
-	gfx_setcolorvertex(1, r, g, b, a);
-	gfx_setcolorvertex(2, r, g, b, a);
-	gfx_setcolorvertex(3, r, g, b, a);
-}
-
-void gfx_quads_setsubset(float tl_u, float tl_v, float br_u, float br_v)
-{
-	dbg_assert(drawing == DRAWING_QUADS, "called gfx_quads_setsubset without begin");
-
-	texture[0].u = tl_u;	texture[1].u = br_u;
-	texture[0].v = tl_v;	texture[1].v = tl_v;
-
-	texture[3].u = tl_u;	texture[2].u = br_u;
-	texture[3].v = br_v;	texture[2].v = br_v;
-}
-
-void gfx_quads_setsubset_free(
-	float x0, float y0, float x1, float y1,
-	float x2, float y2, float x3, float y3)
-{
-	texture[0].u = x0; texture[0].v = y0;
-	texture[1].u = x1; texture[1].v = y1;
-	texture[2].u = x2; texture[2].v = y2;
-	texture[3].u = x3; texture[3].v = y3;
-}
-
-
-static void rotate(VEC3 *center, VEC3 *point)
-{
-	float x = point->x - center->x;
-	float y = point->y - center->y;
-	point->x = x * cosf(rotation) - y * sinf(rotation) + center->x;
-	point->y = x * sinf(rotation) + y * cosf(rotation) + center->y;
-}
-
-void gfx_quads_draw(float x, float y, float w, float h)
-{
-	gfx_quads_drawTL(x-w/2, y-h/2,w,h);
-}
-
-void gfx_quads_drawTL(float x, float y, float width, float height)
-{
-	VEC3 center;
-
-	dbg_assert(drawing == DRAWING_QUADS, "called quads_draw without begin");
-
-	center.x = x + width/2;
-	center.y = y + height/2;
-	center.z = 0;
-	
-	vertices[num_vertices].pos.x = x;
-	vertices[num_vertices].pos.y = y;
-	vertices[num_vertices].tex = texture[0];
-	vertices[num_vertices].color = color[0];
-	rotate(&center, &vertices[num_vertices].pos);
-
-	vertices[num_vertices + 1].pos.x = x+width;
-	vertices[num_vertices + 1].pos.y = y;
-	vertices[num_vertices + 1].tex = texture[1];
-	vertices[num_vertices + 1].color = color[1];
-	rotate(&center, &vertices[num_vertices + 1].pos);
-
-	vertices[num_vertices + 2].pos.x = x + width;
-	vertices[num_vertices + 2].pos.y = y+height;
-	vertices[num_vertices + 2].tex = texture[2];
-	vertices[num_vertices + 2].color = color[2];
-	rotate(&center, &vertices[num_vertices + 2].pos);
-
-	vertices[num_vertices + 3].pos.x = x;
-	vertices[num_vertices + 3].pos.y = y+height;
-	vertices[num_vertices + 3].tex = texture[3];
-	vertices[num_vertices + 3].color = color[3];
-	rotate(&center, &vertices[num_vertices + 3].pos);
-	
-	add_vertices(4);
-}
-
-void gfx_quads_draw_freeform(
-	float x0, float y0, float x1, float y1,
-	float x2, float y2, float x3, float y3)
-{
-	dbg_assert(drawing == DRAWING_QUADS, "called quads_draw_freeform without begin");
-	
-	vertices[num_vertices].pos.x = x0;
-	vertices[num_vertices].pos.y = y0;
-	vertices[num_vertices].tex = texture[0];
-	vertices[num_vertices].color = color[0];
-
-	vertices[num_vertices + 1].pos.x = x1;
-	vertices[num_vertices + 1].pos.y = y1;
-	vertices[num_vertices + 1].tex = texture[1];
-	vertices[num_vertices + 1].color = color[1];
-
-	vertices[num_vertices + 2].pos.x = x3;
-	vertices[num_vertices + 2].pos.y = y3;
-	vertices[num_vertices + 2].tex = texture[3];
-	vertices[num_vertices + 2].color = color[3];
-
-	vertices[num_vertices + 3].pos.x = x2;
-	vertices[num_vertices + 3].pos.y = y2;
-	vertices[num_vertices + 3].tex = texture[2];
-	vertices[num_vertices + 3].color = color[2];
-	
-	add_vertices(4);
-}
-
-void gfx_quads_text(float x, float y, float size, float r, float g, float b, float a, const char *text)
-{
-	float startx = x;
-
-	gfx_quads_begin();
-	gfx_setcolor(r,g,b,a);
-
-	while(*text)
-	{
-		char c = *text;
-		text++;
-		
-		if(c == '\n')
-		{
-			x = startx;
-			y += size;
-		}
-		else
-		{
-			gfx_quads_setsubset(
-				(c%16)/16.0f,
-				(c/16)/16.0f,
-				(c%16)/16.0f+1.0f/16.0f,
-				(c/16)/16.0f+1.0f/16.0f);
-			
-			gfx_quads_drawTL(x,y,size,size);
-			x += size/2;
-		}
-	}
-	
-	gfx_quads_end();
-}
-
-void gfx_lines_begin()
-{
-	dbg_assert(drawing == 0, "called begin twice");
-	drawing = DRAWING_LINES;
-	gfx_setcolor(1,1,1,1);
-}
-
-void gfx_lines_end()
-{
-	dbg_assert(drawing == DRAWING_LINES, "called end without begin");
-	flush();
-	drawing = 0;
-}
-
-void gfx_lines_draw(float x0, float y0, float x1, float y1)
-{
-	dbg_assert(drawing == DRAWING_LINES, "called draw without begin");
-	
-	vertices[num_vertices].pos.x = x0;
-	vertices[num_vertices].pos.y = y0;
-	vertices[num_vertices].tex = texture[0];
-	vertices[num_vertices].color = color[0];
-
-	vertices[num_vertices + 1].pos.x = x1;
-	vertices[num_vertices + 1].pos.y = y1;
-	vertices[num_vertices + 1].tex = texture[1];
-	vertices[num_vertices + 1].color = color[1];
-	
-	add_vertices(2);
-}
-
-void gfx_clip_enable(int x, int y, int w, int h)
-{
-	if(no_gfx) return;
-	glScissor(x, gfx_screenheight()-(y+h), w, h);
-	glEnable(GL_SCISSOR_TEST);
-}
-
-void gfx_clip_disable()
-{
-	if(no_gfx) return;
-	glDisable(GL_SCISSOR_TEST);
-}
-
-void gfx_minimize()
-{
-	SDL_WM_IconifyWindow();
-}
-
-void gfx_maximize()
-{
-	/* TODO: SDL */
-}
diff --git a/src/engine/client/ec_gfx.cpp b/src/engine/client/ec_gfx.cpp
new file mode 100644
index 00000000..5632581a
--- /dev/null
+++ b/src/engine/client/ec_gfx.cpp
@@ -0,0 +1,992 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+
+#include <base/detect.h>
+
+#include "SDL.h"
+
+#ifdef CONF_FAMILY_WINDOWS
+	#define WIN32_LEAN_AND_MEAN
+	#include <windows.h>
+#endif
+
+#ifdef CONF_PLATFORM_MACOSX
+	#include <OpenGL/gl.h>
+	#include <OpenGL/glu.h>
+#else
+	#include <GL/gl.h>
+	#include <GL/glu.h>
+#endif
+
+#include <base/system.h>
+#include <engine/external/pnglite/pnglite.h>
+
+#include <engine/e_client_interface.h>
+#include <engine/e_engine.h>
+#include <engine/e_config.h>
+#include <engine/e_keys.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+/* compressed textures */
+#define GL_COMPRESSED_RGB_ARB 0x84ED
+#define GL_COMPRESSED_RGBA_ARB 0x84EE
+#define GL_COMPRESSED_ALPHA_ARB 0x84E9
+
+#define TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+
+
+void gfx_font_init();
+
+VIDEO_MODE fakemodes[] = {
+	{320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8},
+	{720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8},
+	{1024,600,8,8,8}, {1024,768,8,8,8}, {1152,864,8,8,8},
+	{1280,768,8,8,8}, {1280,800,8,8,8}, {1280,960,8,8,8},
+	{1280,1024,8,8,8}, {1368,768,8,8,8}, {1400,1050,8,8,8},
+	{1440,900,8,8,8}, {1440,1050,8,8,8}, {1600,1000,8,8,8},
+	{1600,1200,8,8,8}, {1680,1050,8,8,8}, {1792,1344,8,8,8},
+	{1800,1440,8,8,8}, {1856,1392,8,8,8}, {1920,1080,8,8,8},
+	{1920,1200,8,8,8}, {1920,1440,8,8,8}, {1920,2400,8,8,8},
+	{2048,1536,8,8,8},
+		
+	{320,240,5,6,5}, {400,300,5,6,5}, {640,480,5,6,5},
+	{720,400,5,6,5}, {768,576,5,6,5}, {800,600,5,6,5},
+	{1024,600,5,6,5}, {1024,768,5,6,5}, {1152,864,5,6,5},
+	{1280,768,5,6,5}, {1280,800,5,6,5}, {1280,960,5,6,5},
+	{1280,1024,5,6,5}, {1368,768,5,6,5}, {1400,1050,5,6,5},
+	{1440,900,5,6,5}, {1440,1050,5,6,5}, {1600,1000,5,6,5},
+	{1600,1200,5,6,5}, {1680,1050,5,6,5}, {1792,1344,5,6,5},
+	{1800,1440,5,6,5}, {1856,1392,5,6,5}, {1920,1080,5,6,5},
+	{1920,1200,5,6,5}, {1920,1440,5,6,5}, {1920,2400,5,6,5},
+	{2048,1536,5,6,5}
+};
+
+int gfx_get_video_modes(VIDEO_MODE *list, int maxcount)
+{
+	int num_modes = sizeof(fakemodes)/sizeof(VIDEO_MODE);
+	SDL_Rect **modes;
+
+	if(config.gfx_display_all_modes)
+	{
+		int count = sizeof(fakemodes)/sizeof(VIDEO_MODE);
+		mem_copy(list, fakemodes, sizeof(fakemodes));
+		if(maxcount < count)
+			count = maxcount;
+		return count;
+	}
+	
+	/* TODO: fix this code on osx or windows */
+		
+	modes = SDL_ListModes(NULL, SDL_OPENGL|SDL_GL_DOUBLEBUFFER|SDL_FULLSCREEN);
+	if(modes == NULL)
+	{
+		/* no modes */
+		num_modes = 0;
+	}
+	else if(modes == (SDL_Rect**)-1)
+	{
+		/* all modes */
+	}
+	else
+	{
+		int i;
+		num_modes = 0;
+		for(i = 0; modes[i]; ++i)
+		{
+			if(num_modes == maxcount)
+				break;
+			list[num_modes].width = modes[i]->w;
+			list[num_modes].height = modes[i]->h;
+			list[num_modes].red = 8;
+			list[num_modes].green = 8;
+			list[num_modes].blue = 8;
+			num_modes++;
+		}
+	}
+	
+	return num_modes;
+}
+
+
+#include "graphics.h"
+
+class CGraphics_OpenGL : public IEngineGraphics
+{
+protected:
+	/* */
+	typedef struct { float x, y, z; } CPoint;
+	typedef struct { float u, v; } CTexCoord;
+	typedef struct { float r, g, b, a; } CColor;
+
+	typedef struct
+	{
+		CPoint m_Pos;
+		CTexCoord m_Tex;
+		CColor m_Color;
+	} CVertex;
+	
+	enum
+	{
+		MAX_VERTICES = 32*1024,
+		MAX_TEXTURES = 1024*4,
+		
+		DRAWING_QUADS=1,
+		DRAWING_LINES=2		
+	};
+
+	CVertex m_aVertices[MAX_VERTICES];
+	int m_NumVertices;
+
+	CColor m_aColor[4];
+	CTexCoord m_aTexture[4];
+
+	bool m_RenderEnable;
+
+	float m_Rotation;
+	int m_Drawing;
+	bool m_DoScreenshot;
+
+	float m_ScreenX0;
+	float m_ScreenY0;
+	float m_ScreenX1;
+	float m_ScreenY1;
+
+	int m_InvalidTexture;
+
+	struct CTexture
+	{
+		GLuint tex;
+		int memsize;
+		int flags;
+		int next;
+	};
+
+	enum
+	{
+		
+	};
+
+	CTexture m_aTextures[MAX_TEXTURES];
+	int m_FirstFreeTexture;
+	int m_TextureMemoryUsage;
+
+
+	void Flush()
+	{
+		if(m_NumVertices == 0)
+			return;
+			
+		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+		glVertexPointer(3, GL_FLOAT,
+				sizeof(CVertex),
+				(char*)m_aVertices);
+		glTexCoordPointer(2, GL_FLOAT,
+				sizeof(CVertex),
+				(char*)m_aVertices + sizeof(float)*3);
+		glColorPointer(4, GL_FLOAT,
+				sizeof(CVertex),
+				(char*)m_aVertices + sizeof(float)*5);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glEnableClientState(GL_COLOR_ARRAY);
+		
+		if(m_RenderEnable)
+		{
+			if(m_Drawing == DRAWING_QUADS)
+				glDrawArrays(GL_QUADS, 0, m_NumVertices);
+			else if(m_Drawing == DRAWING_LINES)
+				glDrawArrays(GL_LINES, 0, m_NumVertices);
+		}
+		
+		/* Reset pointer */
+		m_NumVertices = 0;
+	}
+
+	void AddVertices(int count)
+	{
+		m_NumVertices += count;
+		if((m_NumVertices + count) >= MAX_VERTICES)
+			Flush();
+	}
+	
+	void Rotate(CPoint *pCenter, CPoint *pPoint)
+	{
+		float x = pPoint->x - pCenter->x;
+		float y = pPoint->y - pCenter->y;
+		pPoint->x = x * cosf(m_Rotation) - y * sinf(m_Rotation) + pCenter->x;
+		pPoint->y = x * sinf(m_Rotation) + y * cosf(m_Rotation) + pCenter->y;
+	}
+	
+	
+
+
+	static unsigned char sample(int w, int h, const unsigned char *data, int u, int v, int offset)
+	{
+		return (data[(v*w+u)*4+offset]+
+		data[(v*w+u+1)*4+offset]+
+		data[((v+1)*w+u)*4+offset]+
+		data[((v+1)*w+u+1)*4+offset])/4;
+	}	
+public:
+	CGraphics_OpenGL()
+	{
+		m_NumVertices = 0;
+		
+		m_ScreenX0 = 0;
+		m_ScreenY0 = 0;
+		m_ScreenX1 = 0;
+		m_ScreenY1 = 0;
+		
+		m_ScreenWidth = -1;
+		m_ScreenHeight = -1;
+		
+		m_Rotation = 0;
+		m_Drawing = 0;
+		m_InvalidTexture = 0;
+		
+		m_TextureMemoryUsage = 0;
+		
+		m_RenderEnable = true;
+		m_DoScreenshot = false;
+	}
+	
+
+	virtual void ClipEnable(int x, int y, int w, int h)
+	{
+		//if(no_gfx) return;
+		glScissor(x, ScreenHeight()-(y+h), w, h);
+		glEnable(GL_SCISSOR_TEST);
+	}
+
+	virtual void ClipDisable()
+	{
+		//if(no_gfx) return;
+		glDisable(GL_SCISSOR_TEST);
+	}
+		
+
+	virtual void BlendNone()
+	{
+		glDisable(GL_BLEND);
+	}
+
+	virtual void BlendNormal()
+	{
+		glEnable(GL_BLEND);
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	}
+
+	virtual void BlendAdditive()
+	{
+		glEnable(GL_BLEND);
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+	}
+
+	//int gfx_memory_usage() { return m_MemoryUsage; }	
+		
+	virtual void MapScreen(float tl_x, float tl_y, float br_x, float br_y)
+	{
+		m_ScreenX0 = tl_x;
+		m_ScreenY0 = tl_y;
+		m_ScreenX1 = br_x;
+		m_ScreenY1 = br_y;
+		glMatrixMode(GL_PROJECTION);
+		glLoadIdentity();
+		glOrtho(tl_x, br_x, br_y, tl_y, 1.0f, 10.f);
+	}
+
+	virtual void GetScreen(float *tl_x, float *tl_y, float *br_x, float *br_y)
+	{
+		*tl_x = m_ScreenX0;
+		*tl_y = m_ScreenY0;
+		*br_x = m_ScreenX1;
+		*br_y = m_ScreenY1;
+	}
+
+	virtual void LinesBegin()
+	{
+		dbg_assert(m_Drawing == 0, "called begin twice");
+		m_Drawing = DRAWING_LINES;
+		SetColor(1,1,1,1);
+	}
+
+	virtual void LinesEnd()
+	{
+		dbg_assert(m_Drawing == DRAWING_LINES, "called end without begin");
+		Flush();
+		m_Drawing = 0;
+	}
+
+	virtual void LinesDraw(float x0, float y0, float x1, float y1)
+	{
+		dbg_assert(m_Drawing == DRAWING_LINES, "called draw without begin");
+		
+		m_aVertices[m_NumVertices].m_Pos.x = x0;
+		m_aVertices[m_NumVertices].m_Pos.y = y0;
+		m_aVertices[m_NumVertices].m_Tex = m_aTexture[0];
+		m_aVertices[m_NumVertices].m_Color = m_aColor[0];
+
+		m_aVertices[m_NumVertices + 1].m_Pos.x = x1;
+		m_aVertices[m_NumVertices + 1].m_Pos.y = y1;
+		m_aVertices[m_NumVertices + 1].m_Tex = m_aTexture[1];
+		m_aVertices[m_NumVertices + 1].m_Color = m_aColor[1];
+		
+		AddVertices(2);
+	}
+	
+
+	
+	virtual int UnloadTexture(int Index)
+	{
+		if(Index == m_InvalidTexture)
+			return 0;
+			
+		if(Index < 0)
+			return 0;
+			
+		glDeleteTextures(1, &m_aTextures[Index].tex);
+		m_aTextures[Index].next = m_FirstFreeTexture;
+		m_TextureMemoryUsage -= m_aTextures[Index].memsize;
+		m_FirstFreeTexture = Index;
+		return 0;
+	}
+
+
+	virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags)
+	{
+		int mipmap = 1;
+		unsigned char *texdata = (unsigned char *)pData;
+		unsigned char *tmpdata = 0;
+		int oglformat = 0;
+		int store_oglformat = 0;
+		int tex = 0;
+		
+		/* don't waste memory on texture if we are stress testing */
+		if(config.dbg_stress)
+			return 	m_InvalidTexture;
+		
+		/* grab texture */
+		tex = m_FirstFreeTexture;
+		m_FirstFreeTexture = m_aTextures[tex].next;
+		m_aTextures[tex].next = -1;
+		
+		/* resample if needed */
+		if(!(Flags&TEXLOAD_NORESAMPLE) && config.gfx_texture_quality==0)
+		{
+			if(Width > 16 && Height > 16 && Format == IMG_RGBA)
+			{
+				unsigned char *tmpdata;
+				int c = 0;
+				int x, y;
+
+				tmpdata = (unsigned char *)mem_alloc(Width*Height*4, 1);
+
+				Width/=2;
+				Height/=2;
+
+				for(y = 0; y < Height; y++)
+					for(x = 0; x < Width; x++, c++)
+					{
+						tmpdata[c*4] = sample(Width*2, Height*2, texdata, x*2,y*2, 0);
+						tmpdata[c*4+1] = sample(Width*2, Height*2, texdata, x*2,y*2, 1);
+						tmpdata[c*4+2] = sample(Width*2, Height*2, texdata, x*2,y*2, 2);
+						tmpdata[c*4+3] = sample(Width*2, Height*2, texdata, x*2,y*2, 3);
+					}
+				texdata = tmpdata;
+			}
+		}
+		
+		oglformat = GL_RGBA;
+		if(Format == IMG_RGB)
+			oglformat = GL_RGB;
+		else if(Format == IMG_ALPHA)
+			oglformat = GL_ALPHA;
+		
+		/* upload texture */
+		if(config.gfx_texture_compression)
+		{
+			store_oglformat = GL_COMPRESSED_RGBA_ARB;
+			if(StoreFormat == IMG_RGB)
+				store_oglformat = GL_COMPRESSED_RGB_ARB;
+			else if(StoreFormat == IMG_ALPHA)
+				store_oglformat = GL_COMPRESSED_ALPHA_ARB;
+		}
+		else
+		{
+			store_oglformat = GL_RGBA;
+			if(StoreFormat == IMG_RGB)
+				store_oglformat = GL_RGB;
+			else if(StoreFormat == IMG_ALPHA)
+				store_oglformat = GL_ALPHA;
+		}
+			
+		glGenTextures(1, &m_aTextures[tex].tex);
+		glBindTexture(GL_TEXTURE_2D, m_aTextures[tex].tex);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+		gluBuild2DMipmaps(GL_TEXTURE_2D, store_oglformat, Width, Height, oglformat, GL_UNSIGNED_BYTE, texdata);
+		
+		/* calculate memory usage */
+		{
+			int pixel_size = 4;
+			if(StoreFormat == IMG_RGB)
+				pixel_size = 3;
+			else if(StoreFormat == IMG_ALPHA)
+				pixel_size = 1;
+
+			m_aTextures[tex].memsize = Width*Height*pixel_size;
+			if(mipmap)
+			{
+				while(Width > 2 && Height > 2)
+				{
+					Width>>=1;
+					Height>>=1;
+					m_aTextures[tex].memsize += Width*Height*pixel_size;
+				}
+			}
+		}
+		
+		m_TextureMemoryUsage += m_aTextures[tex].memsize;
+		mem_free(tmpdata);
+		return tex;
+	}
+
+	/* simple uncompressed RGBA loaders */
+	virtual int LoadTexture(const char *pFilename, int StoreFormat, int Flags)
+	{
+		int l = strlen(pFilename);
+		int id;
+		IMAGE_INFO img;
+		
+		if(l < 3)
+			return -1;
+		if(LoadPNG(&img, pFilename))
+		{
+			if (StoreFormat == IMG_AUTO)
+				StoreFormat = img.format;
+
+			id = LoadTextureRaw(img.width, img.height, img.format, img.data, StoreFormat, Flags);
+			mem_free(img.data);
+			return id;
+		}
+		
+		return m_InvalidTexture;
+	}
+
+	virtual int LoadPNG(IMAGE_INFO *pImg, const char *pFilename)
+	{
+		char aCompleteFilename[512];
+		unsigned char *pBuffer;
+		png_t png;
+		
+		/* open file for reading */
+		png_init(0,0);
+
+		engine_getpath(aCompleteFilename, sizeof(aCompleteFilename), pFilename, IOFLAG_READ);
+		
+		if(png_open_file(&png, aCompleteFilename) != PNG_NO_ERROR)
+		{
+			dbg_msg("game/png", "failed to open file. filename='%s'", aCompleteFilename);
+			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'", aCompleteFilename);
+			png_close_file(&png);
+			return 0;
+		}
+			
+		pBuffer = (unsigned char *)mem_alloc(png.width * png.height * png.bpp, 1);
+		png_get_data(&png, pBuffer);
+		png_close_file(&png);
+		
+		pImg->width = png.width;
+		pImg->height = png.height;
+		if(png.color_type == PNG_TRUECOLOR)
+			pImg->format = IMG_RGB;
+		else if(png.color_type == PNG_TRUECOLOR_ALPHA)
+			pImg->format = IMG_RGBA;
+		pImg->data = pBuffer;
+		return 1;
+	}
+
+	void ScreenshotDirect(const char *filename)
+	{
+		/* fetch image data */
+		int y;
+		int w = m_ScreenWidth;
+		int h = m_ScreenHeight;
+		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);
+	}
+
+	virtual void TextureSet(int TextureID)
+	{
+		dbg_assert(m_Drawing == 0, "called Graphics()->TextureSet within begin");
+		if(TextureID == -1)
+		{
+			glDisable(GL_TEXTURE_2D);
+		}
+		else
+		{
+			glEnable(GL_TEXTURE_2D);
+			glBindTexture(GL_TEXTURE_2D, m_aTextures[TextureID].tex);
+		}
+	}
+
+	virtual void Clear(float r, float g, float b)
+	{
+		glClearColor(r,g,b,0.0f);
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	}
+
+	virtual void QuadsBegin()
+	{
+		dbg_assert(m_Drawing == 0, "called quads_begin twice");
+		m_Drawing = DRAWING_QUADS;
+		
+		QuadsSetSubset(0,0,1,1);
+		QuadsSetRotation(0);
+		SetColor(1,1,1,1);
+	}
+
+	virtual void QuadsEnd()
+	{
+		dbg_assert(m_Drawing == DRAWING_QUADS, "called quads_end without begin");
+		Flush();
+		m_Drawing = 0;
+	}
+
+	virtual void QuadsSetRotation(float Angle)
+	{
+		dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetRotation without begin");
+		m_Rotation = Angle;
+	}
+
+	virtual void SetColorVertex(int i, float r, float g, float b, float a)
+	{
+		dbg_assert(m_Drawing != 0, "called gfx_quads_setcolorvertex without begin");
+		m_aColor[i].r = r;
+		m_aColor[i].g = g;
+		m_aColor[i].b = b;
+		m_aColor[i].a = a;
+	}
+
+	virtual void SetColor(float r, float g, float b, float a)
+	{
+		dbg_assert(m_Drawing != 0, "called gfx_quads_setcolor without begin");
+		SetColorVertex(0, r, g, b, a);
+		SetColorVertex(1, r, g, b, a);
+		SetColorVertex(2, r, g, b, a);
+		SetColorVertex(3, r, g, b, a);
+	}
+
+	virtual void QuadsSetSubset(float tl_u, float tl_v, float br_u, float br_v)
+	{
+		dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin");
+
+		m_aTexture[0].u = tl_u;	m_aTexture[1].u = br_u;
+		m_aTexture[0].v = tl_v;	m_aTexture[1].v = tl_v;
+
+		m_aTexture[3].u = tl_u;	m_aTexture[2].u = br_u;
+		m_aTexture[3].v = br_v;	m_aTexture[2].v = br_v;
+	}
+
+	virtual void QuadsSetSubsetFree(
+		float x0, float y0, float x1, float y1,
+		float x2, float y2, float x3, float y3)
+	{
+		m_aTexture[0].u = x0; m_aTexture[0].v = y0;
+		m_aTexture[1].u = x1; m_aTexture[1].v = y1;
+		m_aTexture[2].u = x2; m_aTexture[2].v = y2;
+		m_aTexture[3].u = x3; m_aTexture[3].v = y3;
+	}
+
+	virtual void QuadsDraw(float x, float y, float w, float h)
+	{
+		QuadsDrawTL(x-w/2, y-h/2,w,h);
+	}
+
+	virtual void QuadsDrawTL(float x, float y, float w, float h)
+	{
+		CPoint Center;
+
+		dbg_assert(m_Drawing == DRAWING_QUADS, "called quads_draw without begin");
+
+		Center.x = x + w/2;
+		Center.y = y + h/2;
+		Center.z = 0;
+		
+		m_aVertices[m_NumVertices].m_Pos.x = x;
+		m_aVertices[m_NumVertices].m_Pos.y = y;
+		m_aVertices[m_NumVertices].m_Tex = m_aTexture[0];
+		m_aVertices[m_NumVertices].m_Color = m_aColor[0];
+		Rotate(&Center, &m_aVertices[m_NumVertices].m_Pos);
+
+		m_aVertices[m_NumVertices + 1].m_Pos.x = x+w;
+		m_aVertices[m_NumVertices + 1].m_Pos.y = y;
+		m_aVertices[m_NumVertices + 1].m_Tex = m_aTexture[1];
+		m_aVertices[m_NumVertices + 1].m_Color = m_aColor[1];
+		Rotate(&Center, &m_aVertices[m_NumVertices + 1].m_Pos);
+
+		m_aVertices[m_NumVertices + 2].m_Pos.x = x + w;
+		m_aVertices[m_NumVertices + 2].m_Pos.y = y+h;
+		m_aVertices[m_NumVertices + 2].m_Tex = m_aTexture[2];
+		m_aVertices[m_NumVertices + 2].m_Color = m_aColor[2];
+		Rotate(&Center, &m_aVertices[m_NumVertices + 2].m_Pos);
+
+		m_aVertices[m_NumVertices + 3].m_Pos.x = x;
+		m_aVertices[m_NumVertices + 3].m_Pos.y = y+h;
+		m_aVertices[m_NumVertices + 3].m_Tex = m_aTexture[3];
+		m_aVertices[m_NumVertices + 3].m_Color = m_aColor[3];
+		Rotate(&Center, &m_aVertices[m_NumVertices + 3].m_Pos);
+		
+		AddVertices(4);
+	}
+
+	void QuadsDrawFreeform(
+		float x0, float y0, float x1, float y1,
+		float x2, float y2, float x3, float y3)
+	{
+		dbg_assert(m_Drawing == DRAWING_QUADS, "called quads_draw_freeform without begin");
+		
+		m_aVertices[m_NumVertices].m_Pos.x = x0;
+		m_aVertices[m_NumVertices].m_Pos.y = y0;
+		m_aVertices[m_NumVertices].m_Tex = m_aTexture[0];
+		m_aVertices[m_NumVertices].m_Color = m_aColor[0];
+
+		m_aVertices[m_NumVertices + 1].m_Pos.x = x1;
+		m_aVertices[m_NumVertices + 1].m_Pos.y = y1;
+		m_aVertices[m_NumVertices + 1].m_Tex = m_aTexture[1];
+		m_aVertices[m_NumVertices + 1].m_Color = m_aColor[1];
+
+		m_aVertices[m_NumVertices + 2].m_Pos.x = x3;
+		m_aVertices[m_NumVertices + 2].m_Pos.y = y3;
+		m_aVertices[m_NumVertices + 2].m_Tex = m_aTexture[3];
+		m_aVertices[m_NumVertices + 2].m_Color = m_aColor[3];
+
+		m_aVertices[m_NumVertices + 3].m_Pos.x = x2;
+		m_aVertices[m_NumVertices + 3].m_Pos.y = y2;
+		m_aVertices[m_NumVertices + 3].m_Tex = m_aTexture[2];
+		m_aVertices[m_NumVertices + 3].m_Color = m_aColor[2];
+		
+		AddVertices(4);
+	}
+
+	virtual void QuadsText(float x, float y, float Size, float r, float g, float b, float a, const char *pText)
+	{
+		float startx = x;
+
+		QuadsBegin();
+		SetColor(r,g,b,a);
+
+		while(*pText)
+		{
+			char c = *pText;
+			pText++;
+			
+			if(c == '\n')
+			{
+				x = startx;
+				y += Size;
+			}
+			else
+			{
+				QuadsSetSubset(
+					(c%16)/16.0f,
+					(c/16)/16.0f,
+					(c%16)/16.0f+1.0f/16.0f,
+					(c/16)/16.0f+1.0f/16.0f);
+				
+				QuadsDrawTL(x,y,Size,Size);
+				x += Size/2;
+			}
+		}
+		
+		QuadsEnd();
+	}
+	
+	virtual bool Init()
+	{
+		/* Set all z to -5.0f */
+		for(int i = 0; i < MAX_VERTICES; i++)
+			m_aVertices[i].m_Pos.z = -5.0f;
+
+		/* init textures */
+		m_FirstFreeTexture = 0;
+		for(int i = 0; i < MAX_TEXTURES; i++)
+			m_aTextures[i].next = i+1;
+		m_aTextures[MAX_TEXTURES-1].next = -1;
+
+		/* set some default settings */	
+		glEnable(GL_BLEND);
+		glDisable(GL_CULL_FACE);
+		glDisable(GL_DEPTH_TEST);
+		glMatrixMode(GL_MODELVIEW);
+		glLoadIdentity();
+		
+		glAlphaFunc(GL_GREATER, 0);
+		glEnable(GL_ALPHA_TEST);
+		glDepthMask(0);
+
+		/* create null texture, will get id=0 */
+		static const unsigned char aNullTextureData[] = {
+			0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, 
+			0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff, 
+			0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, 
+			0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff, 
+		};
+		
+		m_InvalidTexture = LoadTextureRaw(4,4,IMG_RGBA,aNullTextureData,IMG_RGBA,TEXLOAD_NORESAMPLE);
+		dbg_msg("", "invalid texture id: %d %d", m_InvalidTexture, m_aTextures[m_InvalidTexture].tex);
+		
+		return true;
+	}
+};
+
+class CGraphics_SDL : public CGraphics_OpenGL
+{
+	SDL_Surface *m_pScreenSurface;	
+	
+	int TryInit()
+	{
+		const SDL_VideoInfo *pInfo;
+		int Flags = SDL_OPENGL;
+		
+		m_ScreenWidth = config.gfx_screen_width;
+		m_ScreenHeight = config.gfx_screen_height;
+
+		pInfo = SDL_GetVideoInfo();
+
+		/* set flags */
+		Flags  = SDL_OPENGL;
+		Flags |= SDL_GL_DOUBLEBUFFER;
+		Flags |= SDL_HWPALETTE;
+		if(config.dbg_resizable)
+			Flags |= SDL_RESIZABLE;
+
+		if(pInfo->hw_available)
+			Flags |= SDL_HWSURFACE;
+		else
+			Flags |= SDL_SWSURFACE;
+
+		if(pInfo->blit_hw)
+			Flags |= SDL_HWACCEL;
+
+		if(config.gfx_fullscreen)
+			Flags |= SDL_FULLSCREEN;
+
+		/* set gl attributes */
+		if(config.gfx_fsaa_samples)
+		{
+			SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
+			SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config.gfx_fsaa_samples);
+		}
+		else
+		{
+			SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+			SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
+		}
+
+		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+		SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, config.gfx_vsync);
+
+		/* set caption */
+		SDL_WM_SetCaption("Teeworlds", "Teeworlds");
+		
+		/* create window */
+		m_pScreenSurface = SDL_SetVideoMode(m_ScreenWidth, m_ScreenHeight, 0, Flags);
+		if(m_pScreenSurface == NULL)
+		{
+			dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError());
+			return -1;
+		}
+		
+		return 0;
+	}
+
+
+	int InitWindow()
+	{
+		if(TryInit() == 0)
+			return 0;
+		
+		/* try disabling fsaa */
+		while(config.gfx_fsaa_samples)
+		{
+			config.gfx_fsaa_samples--;
+			
+			if(config.gfx_fsaa_samples)
+				dbg_msg("gfx", "lowering FSAA to %d and trying again", config.gfx_fsaa_samples);
+			else
+				dbg_msg("gfx", "disabling FSAA and trying again");
+
+			if(TryInit() == 0)
+				return 0;
+		}
+
+		/* try lowering the resolution */
+		if(config.gfx_screen_width != 640 || config.gfx_screen_height != 480)
+		{
+			dbg_msg("gfx", "setting resolution to 640x480 and trying again");
+			config.gfx_screen_width = 640;
+			config.gfx_screen_height = 480;
+
+			if(TryInit() == 0)
+				return 0;
+		}
+
+		dbg_msg("gfx", "out of ideas. failed to init graphics");
+						
+		return -1;		
+	}
+
+	
+public:
+	CGraphics_SDL()
+	{
+		m_pScreenSurface = 0;
+	}
+
+	virtual bool Init()
+	{
+		{
+			int Systems = SDL_INIT_VIDEO;
+			
+			if(config.snd_enable)
+				Systems |= SDL_INIT_AUDIO;
+
+			if(config.cl_eventthread)
+				Systems |= SDL_INIT_EVENTTHREAD;
+			
+			if(SDL_Init(Systems) < 0)
+			{
+				dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError());
+				return -1;
+			}
+		}
+		
+		atexit(SDL_Quit);
+
+		#ifdef CONF_FAMILY_WINDOWS
+			if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED"))
+				putenv("SDL_VIDEO_WINDOW_POS=8,27");
+		#endif
+		
+		if(InitWindow() != 0)
+			return -1;
+
+		SDL_ShowCursor(0);
+			
+		CGraphics_OpenGL::Init();
+		
+		MapScreen(0,0,config.gfx_screen_width, config.gfx_screen_height);
+
+		/* init input */
+		inp_init();
+
+		/* font init */
+		gfx_font_init();
+
+		return 0;
+	}
+	
+	virtual void Shutdown()
+	{
+		/* TODO: SDL, is this correct? */
+		SDL_Quit();
+	}
+
+	virtual void Minimize()
+	{
+		SDL_WM_IconifyWindow();
+	}
+
+	virtual void Maximize()
+	{
+		/* TODO: SDL */
+	}
+
+	virtual int WindowActive()
+	{
+		return SDL_GetAppState()&SDL_APPINPUTFOCUS;
+	}
+
+	virtual int WindowOpen()
+	{
+		return SDL_GetAppState()&SDL_APPACTIVE;
+
+	}
+	
+	virtual void TakeScreenshot()
+	{
+		m_DoScreenshot = true;
+	}
+	
+	virtual void Swap()
+	{
+		if(m_DoScreenshot)
+		{
+			/* find filename */
+			char filename[128];
+			static int index = 1;
+
+			for(; index < 1000; index++)
+			{
+				IOHANDLE io;
+				str_format(filename, sizeof(filename), "screenshots/screenshot%04d.png", index);
+				io = engine_openfile(filename, IOFLAG_READ);
+				if(io)
+					io_close(io);
+				else
+					break;
+			}
+
+			ScreenshotDirect(filename);
+			m_DoScreenshot = false;
+		}
+		
+		{
+			static PERFORMACE_INFO pscope = {"glfwSwapBuffers", 0};
+			perf_start(&pscope);
+			SDL_GL_SwapBuffers();
+			perf_end();
+		}
+		
+		if(config.gfx_finish)
+			glFinish();		
+	}
+};
+
+extern IEngineGraphics *CreateEngineGraphics() { return new CGraphics_SDL(); }
diff --git a/src/engine/client/ec_gfx_text.c b/src/engine/client/ec_gfx_text.cpp
index de40e391..d17d1bed 100644
--- a/src/engine/client/ec_gfx_text.c
+++ b/src/engine/client/ec_gfx_text.cpp
@@ -1,7 +1,9 @@
 #include <base/system.h>
 #include <string.h>
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 
+extern IEngineGraphics *Graphics();
 
 #ifdef CONF_PLATFORM_MACOSX
 	#include <OpenGL/gl.h>
@@ -138,8 +140,7 @@ typedef struct FONT
 
 static int font_get_index(int pixelsize)
 {
-	int i;
-	for(i = 0; i < NUM_FONT_SIZES; i++)
+	for(unsigned i = 0; i < NUM_FONT_SIZES; i++)
 	{
 		if(font_sizes[i] >= pixelsize)
 			return i;
@@ -150,8 +151,7 @@ static int font_get_index(int pixelsize)
 
 FONT *gfx_font_load(const char *filename)
 {
-	int i;
-	FONT *font = mem_alloc(sizeof(FONT), 1);
+	FONT *font = (FONT *)mem_alloc(sizeof(FONT), 1);
 	
 	mem_zero(font, sizeof(*font));
 	str_copy(font->filename, filename, sizeof(font->filename));
@@ -162,7 +162,7 @@ FONT *gfx_font_load(const char *filename)
 		return NULL;
 	}
 
-	for(i = 0; i < NUM_FONT_SIZES; i++)
+	for(unsigned i = 0; i < NUM_FONT_SIZES; i++)
 		font->sizes[i].font_size = -1;
 		
 	return font;
@@ -484,6 +484,7 @@ static float font_kerning(FONT *font, int left, int right)
 	return (kerning.x>>6);
 }
 
+
 void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
 {
 	FONT *font = cursor->font;
@@ -503,10 +504,10 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
 	float size = cursor->font_size;
 
 	/* to correct coords, convert to screen coords, round, and convert back */
-	gfx_getscreen(&screen_x0, &screen_y0, &screen_x1, &screen_y1);
+	Graphics()->GetScreen(&screen_x0, &screen_y0, &screen_x1, &screen_y1);
 	
-	fake_to_screen_x = (gfx_screenwidth()/(screen_x1-screen_x0));
-	fake_to_screen_y = (gfx_screenheight()/(screen_y1-screen_y0));
+	fake_to_screen_x = (Graphics()->ScreenWidth()/(screen_x1-screen_x0));
+	fake_to_screen_y = (Graphics()->ScreenHeight()/(screen_y1-screen_y0));
 	actual_x = cursor->x * fake_to_screen_x;
 	actual_y = cursor->y * fake_to_screen_y;
 
@@ -554,11 +555,11 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
 			else
 				glBindTexture(GL_TEXTURE_2D, sizedata->textures[0]);
 
-			gfx_quads_begin();
+			Graphics()->QuadsBegin();
 			if (i == 0)
-				gfx_setcolor(0.0f, 0.0f, 0.0f, 0.3f*text_a);
+				Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.3f*text_a);
 			else
-				gfx_setcolor(text_r, text_g, text_b, text_a);
+				Graphics()->SetColor(text_r, text_g, text_b, text_a);
 		}
 
 		while(current < end)
@@ -629,8 +630,8 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
 				{
 					if(cursor->flags&TEXTFLAG_RENDER)
 					{
-						gfx_quads_setsubset(chr->uvs[0], chr->uvs[1], chr->uvs[2], chr->uvs[3]);
-						gfx_quads_drawTL(draw_x+chr->offset_x*size, draw_y+chr->offset_y*size, chr->width*size, chr->height*size);
+						Graphics()->QuadsSetSubset(chr->uvs[0], chr->uvs[1], chr->uvs[2], chr->uvs[3]);
+						Graphics()->QuadsDrawTL(draw_x+chr->offset_x*size, draw_y+chr->offset_y*size, chr->width*size, chr->height*size);
 					}
 
 					advance = chr->advance_x + font_kerning(font, character, nextcharacter)/size;
@@ -658,7 +659,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
 		}
 
 		if(cursor->flags&TEXTFLAG_RENDER)
-			gfx_quads_end();
+			Graphics()->QuadsEnd();
 	}
 
 	cursor->x = draw_x;
diff --git a/src/engine/client/ec_inp.c b/src/engine/client/ec_inp.cpp
index 495614d6..cf956471 100644
--- a/src/engine/client/ec_inp.c
+++ b/src/engine/client/ec_inp.cpp
@@ -5,6 +5,7 @@
 #include <base/system.h>
 #include <engine/e_client_interface.h>
 #include <engine/e_config.h>
+#include <engine/client/graphics.h>
 
 static struct
 {
@@ -20,6 +21,9 @@ static int input_grabbed = 0;
 static unsigned int last_release = 0;
 static unsigned int release_delta = -1;
 
+// TODO: Refactor: Remove this
+extern IEngineGraphics *Graphics();
+
 void inp_mouse_relative(int *x, int *y)
 {
 	int nx = 0, ny = 0;
@@ -32,8 +36,8 @@ void inp_mouse_relative(int *x, int *y)
 		if(input_grabbed)
 		{
 			SDL_GetMouseState(&nx,&ny);
-			SDL_WarpMouse(gfx_screenwidth()/2,gfx_screenheight()/2);
-			nx -= gfx_screenwidth()/2; ny -= gfx_screenheight()/2;
+			SDL_WarpMouse(Graphics()->ScreenWidth()/2,Graphics()->ScreenHeight()/2);
+			nx -= Graphics()->ScreenWidth()/2; ny -= Graphics()->ScreenHeight()/2;
 		}
 	}
 
@@ -138,10 +142,10 @@ void inp_update()
 {
 	int i;
 	
-	if(input_grabbed && !gfx_window_active())
+	if(input_grabbed && !Graphics()->WindowActive())
 		inp_mouse_mode_absolute();
 
-	/*if(!input_grabbed && gfx_window_active())
+	/*if(!input_grabbed && Graphics()->WindowActive())
 		inp_mouse_mode_relative();*/
 	
 	/* clear and begin count on the other one */
diff --git a/src/engine/client/ec_snd.c b/src/engine/client/ec_snd.cpp
index ac41ec59..3baea982 100644
--- a/src/engine/client/ec_snd.c
+++ b/src/engine/client/ec_snd.cpp
@@ -1,12 +1,15 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <base/system.h>
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <engine/e_config.h>
 #include <engine/e_engine.h>
 
 #include "SDL.h"
 
-#include <engine/external/wavpack/wavpack.h>
+extern "C" { // wavpack
+	#include <engine/external/wavpack/wavpack.h>
+}
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
@@ -140,7 +143,6 @@ static int iabs(int i)
 static void mix(short *final_out, unsigned frames)
 {
 	int mix_buffer[MAX_FRAMES*2] = {0};
-	int i, s;
 	int master_vol;
 
 	/* aquire lock while we are mixing */
@@ -148,7 +150,7 @@ static void mix(short *final_out, unsigned frames)
 	
 	master_vol = sound_volume;
 	
-	for(i = 0; i < NUM_VOICES; i++)
+	for(unsigned i = 0; i < NUM_VOICES; i++)
 	{
 		if(voices[i].snd)
 		{
@@ -160,7 +162,7 @@ static void mix(short *final_out, unsigned frames)
 			short *in_l = &v->snd->data[v->tick*step];
 			short *in_r = &v->snd->data[v->tick*step+1];
 			
-			int end = v->snd->num_frames-v->tick;
+			unsigned end = v->snd->num_frames-v->tick;
 
 			int rvol = v->channel->vol;
 			int lvol = v->channel->vol;
@@ -202,7 +204,7 @@ static void mix(short *final_out, unsigned frames)
 			}
 
 			/* process all frames */
-			for(s = 0; s < end; s++)
+			for(unsigned s = 0; s < end; s++)
 			{
 				*out++ += (*in_l)*lvol;
 				*out++ += (*in_r)*rvol;
@@ -225,7 +227,7 @@ static void mix(short *final_out, unsigned frames)
 	{
 		/* clamp accumulated values */
 		/* TODO: this seams slow */
-		for(i = 0; i < frames; i++)
+		for(unsigned i = 0; i < frames; i++)
 		{
 			int j = i<<1;
 			int vl = ((mix_buffer[j]*master_vol)/101)>>8;
@@ -281,12 +283,16 @@ int snd_init()
 	return 0;
 }
 
+// TODO: Refactor: Remove this
+extern IEngineGraphics *Graphics();
+
+
 int snd_update()
 {
 	/* update volume */
 	int wanted_volume = config.snd_volume;
 	
-	if(!gfx_window_active() && config.snd_nonactive_mute)
+	if(!Graphics()->WindowActive() && config.snd_nonactive_mute)
 		wanted_volume = 0;
 	
 	if(wanted_volume != sound_volume)
@@ -332,7 +338,7 @@ static void rate_convert(int sid)
 
 	/* allocate new data */
 	num_frames = (int)((snd->num_frames/(float)snd->rate)*mixing_rate);
-	new_data = mem_alloc(num_frames*snd->channels*sizeof(short), 1);
+	new_data = (short *)mem_alloc(num_frames*snd->channels*sizeof(short), 1);
 	
 	for(i = 0; i < num_frames; i++)
 	{
diff --git a/src/engine/client/ec_srvbrowse.c b/src/engine/client/ec_srvbrowse.cpp
index 4a85e778..1b04937a 100644
--- a/src/engine/client/ec_srvbrowse.c
+++ b/src/engine/client/ec_srvbrowse.cpp
@@ -11,7 +11,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-extern NETCLIENT *net;
+extern CNetClient m_NetClient;
 
 
 /* ------ server browse ---- */
@@ -150,7 +150,7 @@ static void client_serverbrowse_filter()
 		if(sorted_serverlist)
 			mem_free(sorted_serverlist);
 		num_sorted_servers_capacity = num_servers;
-		sorted_serverlist = mem_alloc(num_sorted_servers_capacity*sizeof(int), 1);
+		sorted_serverlist = (int *)mem_alloc(num_sorted_servers_capacity*sizeof(int), 1);
 	}
 	
 	/* filter the servers */
@@ -401,7 +401,7 @@ SERVERENTRY *client_serverbrowse_add(NETADDR *addr)
 	{
 		SERVERENTRY **newlist;
 		num_server_capacity += 100;
-		newlist = mem_alloc(num_server_capacity*sizeof(SERVERENTRY*), 1);
+		newlist = (SERVERENTRY **)mem_alloc(num_server_capacity*sizeof(SERVERENTRY*), 1);
 		mem_copy(newlist, serverlist, num_servers*sizeof(SERVERENTRY*));
 		mem_free(serverlist);
 		serverlist = newlist;
@@ -506,28 +506,28 @@ void client_serverbrowse_refresh(int type)
 
 	if(type == BROWSETYPE_LAN)
 	{
-		unsigned char buffer[sizeof(SERVERBROWSE_GETINFO)+1];
-		NETCHUNK packet;
+		unsigned char Buffer[sizeof(SERVERBROWSE_GETINFO)+1];
+		CNetChunk Packet;
 		int i;
 		
-		mem_copy(buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO));
-		buffer[sizeof(SERVERBROWSE_GETINFO)] = current_token;
+		mem_copy(Buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO));
+		Buffer[sizeof(SERVERBROWSE_GETINFO)] = current_token;
 			
-		packet.client_id = -1;
-		mem_zero(&packet, sizeof(packet));
-		packet.address.ip[0] = 255;
-		packet.address.ip[1] = 255;
-		packet.address.ip[2] = 255;
-		packet.address.ip[3] = 255;
-		packet.flags = NETSENDFLAG_CONNLESS;
-		packet.data_size = sizeof(buffer);
-		packet.data = buffer;
+		Packet.m_ClientID = -1;
+		mem_zero(&Packet, sizeof(Packet));
+		Packet.m_Address.ip[0] = 255;
+		Packet.m_Address.ip[1] = 255;
+		Packet.m_Address.ip[2] = 255;
+		Packet.m_Address.ip[3] = 255;
+		Packet.m_Flags = NETSENDFLAG_CONNLESS;
+		Packet.m_DataSize = sizeof(Buffer);
+		Packet.m_pData = Buffer;
 		broadcast_time = time_get();
 
 		for(i = 8303; i <= 8310; i++)
 		{
-			packet.address.port = i;
-			netclient_send(net, &packet);
+			Packet.m_Address.port = i;
+			m_NetClient.Send(&Packet);
 		}
 
 		if(config.debug)
@@ -537,8 +537,7 @@ void client_serverbrowse_refresh(int type)
 		need_refresh = 1;
 	else if(type == BROWSETYPE_FAVORITES)
 	{
-		int i;
-		for(i = 0; i < num_favorite_servers; i++)
+		for(int i = 0; i < num_favorite_servers; i++)
 			client_serverbrowse_set(&favorite_servers[i], BROWSESET_FAV_ADD, -1, 0);
 	}
 }
@@ -546,7 +545,7 @@ void client_serverbrowse_refresh(int type)
 static void client_serverbrowse_request_impl(NETADDR *addr, SERVERENTRY *entry)
 {
 	/*unsigned char buffer[sizeof(SERVERBROWSE_GETINFO)+1];*/
-	NETCHUNK p;
+	CNetChunk Packet;
 
 	if(config.debug)
 	{
@@ -558,17 +557,17 @@ static void client_serverbrowse_request_impl(NETADDR *addr, SERVERENTRY *entry)
 	/*mem_copy(buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO));
 	buffer[sizeof(SERVERBROWSE_GETINFO)] = current_token;*/
 	
-	p.client_id = -1;
-	p.address = *addr;
-	p.flags = NETSENDFLAG_CONNLESS;
+	Packet.m_ClientID = -1;
+	Packet.m_Address = *addr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
 	/*p.data_size = sizeof(buffer);
 	p.data = buffer;
 	netclient_send(net, &p);*/
 
 	/* send old requtest style aswell */	
-	p.data_size = sizeof(SERVERBROWSE_OLD_GETINFO);
-	p.data = SERVERBROWSE_OLD_GETINFO;
-	netclient_send(net, &p);
+	Packet.m_DataSize = sizeof(SERVERBROWSE_OLD_GETINFO);
+	Packet.m_pData = SERVERBROWSE_OLD_GETINFO;
+	m_NetClient.Send(&Packet);
 	
 	if(entry)
 		entry->request_time = time_get();
@@ -591,16 +590,16 @@ void client_serverbrowse_update()
 	if(need_refresh && !mastersrv_refreshing())
 	{
 		NETADDR addr;
-		NETCHUNK p;
+		CNetChunk Packet;
 		int i;
 		
 		need_refresh = 0;
 		
-		mem_zero(&p, sizeof(p));
-		p.client_id = -1;
-		p.flags = NETSENDFLAG_CONNLESS;
-		p.data_size = sizeof(SERVERBROWSE_GETLIST);
-		p.data = SERVERBROWSE_GETLIST;
+		mem_zero(&Packet, sizeof(Packet));
+		Packet.m_ClientID = -1;
+		Packet.m_Flags = NETSENDFLAG_CONNLESS;
+		Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST);
+		Packet.m_pData = SERVERBROWSE_GETLIST;
 		
 		for(i = 0; i < MAX_MASTERSERVERS; i++)
 		{
@@ -608,8 +607,8 @@ void client_serverbrowse_update()
 			if(!addr.ip[0] && !addr.ip[1] && !addr.ip[2] && !addr.ip[3])
 				continue;
 			
-			p.address = addr;
-			netclient_send(net, &p);
+			Packet.m_Address = addr;
+			m_NetClient.Send(&Packet);
 		}
 
 		if(config.debug)
diff --git a/src/engine/e_client_interface.h b/src/engine/e_client_interface.h
index 7ec5c93d..079eabca 100644
--- a/src/engine/e_client_interface.h
+++ b/src/engine/e_client_interface.h
@@ -2,10 +2,6 @@
 #ifndef ENGINE_CLIENT_INTERFACE_H
 #define ENGINE_CLIENT_INTERFACE_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "e_if_other.h"
 #include "e_if_client.h"
 #include "e_if_snd.h"
@@ -17,8 +13,4 @@ extern "C" {
 #include "e_console.h"
 #include "e_config.h"
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/engine/e_common_interface.h b/src/engine/e_common_interface.h
index 498bb6b4..9c95b48b 100644
--- a/src/engine/e_common_interface.h
+++ b/src/engine/e_common_interface.h
@@ -2,15 +2,7 @@
 #ifndef ENGINE_COMMON_INTERFACE_H
 #define ENGINE_COMMON_INTERFACE_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "e_if_other.h"
 #include "e_if_msg.h"
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/engine/e_compression.c b/src/engine/e_compression.cpp
index 6a534feb..f4d6e0c0 100644
--- a/src/engine/e_compression.c
+++ b/src/engine/e_compression.cpp
@@ -84,65 +84,3 @@ long intpack_compress(const void *src_, int size, void *dst_)
 	return (long)(dst-(unsigned char *)dst_);
 }
 
-
-/* */
-long zerobit_compress(const void *src_, int size, void *dst_)
-{
-	unsigned char *src = (unsigned char *)src_;
-	unsigned char *dst = (unsigned char *)dst_;
-	
-	while(size)
-	{
-		unsigned char bit = 0x80;
-		unsigned char mask = 0;
-		int dst_move = 1;
-		int chunk = size < 8 ? size : 8;
-		int b;
-		size -= chunk;
-		
-		for(b = 0; b < chunk; b++, bit>>=1)
-		{
-			if(*src)
-			{
-				dst[dst_move] = *src;
-				mask |= bit;
-				dst_move++;
-			}
-			
-			src++;
-		}
-		
-		*dst = mask;
-		dst += dst_move;
-	}
-	
-	return (long)(dst-(unsigned char *)dst_);
-}
-
-long zerobit_decompress(const void *src_, int size, void *dst_)
-{
-	unsigned char *src = (unsigned char *)src_;
-	unsigned char *dst = (unsigned char *)dst_;
-	unsigned char *end = src + size;
-	
-	while(src < end)
-	{
-		unsigned char bit = 0x80;
-		unsigned char mask = *src++;
-		int b;
-		
-		for(b = 0; b < 8; b++, bit>>=1)
-		{
-			if(mask&bit)
-				*dst++ = *src++;
-			else
-				*dst++ = 0;
-		}
-
-		if(src > end)
-			return -1;
-	}
-	
-	return (long)(dst-(unsigned char *)dst_);
-}
-
diff --git a/src/engine/e_compression.h b/src/engine/e_compression.h
index 39ffd596..be5bf78f 100644
--- a/src/engine/e_compression.h
+++ b/src/engine/e_compression.h
@@ -5,7 +5,3 @@ unsigned char *vint_pack(unsigned char *dst, int i);
 const unsigned char *vint_unpack(const unsigned char *src, int *inout);
 long intpack_compress(const void *src, int size, void *dst);
 long intpack_decompress(const void *src, int size, void *dst);
-
-/* zerobit packing */
-long zerobit_compress(const void *src, int size, void *dst);
-long zerobit_decompress(const void *src, int size, void *dst);
diff --git a/src/engine/e_config.c b/src/engine/e_config.cpp
index 67a4c81a..67a4c81a 100644
--- a/src/engine/e_config.c
+++ b/src/engine/e_config.cpp
diff --git a/src/engine/e_config.h b/src/engine/e_config.h
index 965e08f0..6ca7a8ee 100644
--- a/src/engine/e_config.h
+++ b/src/engine/e_config.h
@@ -2,10 +2,6 @@
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
-#ifdef __cplusplus
-extern "C"{
-#endif
-
 typedef struct
 { 
     #define MACRO_CONFIG_INT(name,def,min,max,save,desc) int name;
@@ -45,8 +41,4 @@ typedef void (*CONFIG_STR_SETTER)(CONFIGURATION *c, const char *str);
 #undef MACRO_CONFIG_INT
 #undef MACRO_CONFIG_STR
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/engine/e_console.c b/src/engine/e_console.cpp
index 5c0f37f3..c641289d 100644
--- a/src/engine/e_console.c
+++ b/src/engine/e_console.cpp
@@ -151,7 +151,7 @@ static int console_parse_args(PARSE_RESULT *result, const char *format)
 	return error;
 }
 
-const char *console_arg_string(void *res, int index)
+const char *console_arg_string(void *res, unsigned index)
 {
 	PARSE_RESULT *result = (PARSE_RESULT *)res;
 	if (index < 0 || index >= result->num_args)
@@ -159,7 +159,7 @@ const char *console_arg_string(void *res, int index)
 	return result->args[index];
 }
 
-int console_arg_int(void *res, int index)
+int console_arg_int(void *res, unsigned index)
 {
 	PARSE_RESULT *result = (PARSE_RESULT *)res;
 	if (index < 0 || index >= result->num_args)
@@ -167,7 +167,7 @@ int console_arg_int(void *res, int index)
 	return atoi(result->args[index]);
 }
 
-float console_arg_float(void *res, int index)
+float console_arg_float(void *res, unsigned index)
 {
 	PARSE_RESULT *result = (PARSE_RESULT *)res;
 	if (index < 0 || index >= result->num_args)
@@ -354,7 +354,7 @@ struct EXECFILE
 void console_execute_file(const char *filename)
 {
 	static struct EXECFILE *first = 0;
-	struct EXECFILE this;
+	struct EXECFILE this_file;
 	struct EXECFILE *cur;
 	struct EXECFILE *prev;
 
@@ -365,9 +365,9 @@ void console_execute_file(const char *filename)
 	
 	/* push this one to the stack */
 	prev = first;
-	this.filename = filename;
-	this.next = first;
-	first = &this;
+	this_file.filename = filename;
+	this_file.next = first;
+	first = &this_file;
 	
 	/* execute file */
 	console_execute_file_real(filename);
diff --git a/src/engine/e_console.h b/src/engine/e_console.h
index b37931b2..a45bac10 100644
--- a/src/engine/e_console.h
+++ b/src/engine/e_console.h
@@ -1,10 +1,6 @@
 #ifndef _CONSOLE_H
 #define _CONSOLE_H
 
-#ifdef __cplusplus
-extern "C"{
-#endif
-
 typedef void (*CONSOLE_CALLBACK)(void *result, void *user_data);
 typedef void (*CONSOLE_CHAIN_CALLBACK)(void *result, void *user_data, CONSOLE_CALLBACK cb, void *cbuser);
 
@@ -42,15 +38,11 @@ void console_register_print_callback(void (*callback)(const char *, void *user_d
 int console_result_int(void *result, int index, int *i);
 int console_result_float(void *result, int index, float *f);*/
 
-const char *console_arg_string(void *result, int index);
-int console_arg_int(void *result, int index);
-float console_arg_float(void *result, int index);
+const char *console_arg_string(void *result, unsigned index);
+int console_arg_int(void *result, unsigned index);
+float console_arg_float(void *result, unsigned index);
 int console_arg_num(void *result);
 
 #define MACRO_REGISTER_COMMAND(name, params, flags, func, ptr, help) { static COMMAND cmd = { name, params, flags, func, ptr, help, 0x0}; console_register(&cmd); }
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/engine/e_datafile.c b/src/engine/e_datafile.cpp
index 0317f9d0..0317f9d0 100644
--- a/src/engine/e_datafile.c
+++ b/src/engine/e_datafile.cpp
diff --git a/src/engine/e_demorec.c b/src/engine/e_demorec.cpp
index e66173e4..1bab1b8d 100644
--- a/src/engine/e_demorec.c
+++ b/src/engine/e_demorec.cpp
@@ -1,4 +1,3 @@
-
 #include <base/system.h>
 #include "e_demorec.h"
 #include "e_memheap.h"
@@ -14,7 +13,7 @@ static const unsigned char header_marker[8] = {'T', 'W', 'D', 'E', 'M', 'O', 0,
 /* Record */
 static int record_lasttickmarker = -1;
 static int record_lastkeyframe;
-static unsigned char record_lastsnapshotdata[MAX_SNAPSHOT_SIZE];
+static unsigned char record_lastsnapshotdata[CSnapshot::MAX_SIZE];
 
 int demorec_isrecording() { return record_file != 0; }
 
@@ -121,7 +120,7 @@ static void demorec_record_write(int type, const void *data, int size)
 	while(size&3)
 		buffer2[size++] = 0;
 	size = intpack_compress(buffer2, size, buffer); /* buffer2 -> buffer */
-	size = netcommon_compress(buffer, size, buffer2, sizeof(buffer2)); /* buffer -> buffer2 */
+	size = CNetBase::Compress(buffer, size, buffer2, sizeof(buffer2)); /* buffer -> buffer2 */
 	
 	
 	chunk[0] = ((type&0x3)<<5);
@@ -166,13 +165,13 @@ void demorec_record_snapshot(int tick, const void *data, int size)
 	else
 	{
 		/* create delta, prepend tick */
-		char delta_data[MAX_SNAPSHOT_SIZE+sizeof(int)];
+		char delta_data[CSnapshot::MAX_SIZE+sizeof(int)];
 		int delta_size;
 
 		/* write tickmarker */
 		demorec_record_write_tickmarker(tick, 0);
 		
-		delta_size = snapshot_create_delta((SNAPSHOT*)record_lastsnapshotdata, (SNAPSHOT*)data, &delta_data);
+		delta_size = CSnapshot::CreateDelta((CSnapshot*)record_lastsnapshotdata, (CSnapshot*)data, &delta_data);
 		if(delta_size)
 		{
 			/* record delta */
@@ -217,7 +216,7 @@ static DEMOREC_PLAYCALLBACK play_callback_message = 0;
 static KEYFRAME *keyframes = 0;
 
 static DEMOREC_PLAYBACKINFO playbackinfo;
-static unsigned char playback_lastsnapshotdata[MAX_SNAPSHOT_SIZE];
+static unsigned char playback_lastsnapshotdata[CSnapshot::MAX_SIZE];
 static int playback_lastsnapshotdata_size = -1;
 
 
@@ -316,7 +315,7 @@ static void scan_file()
 				KEYFRAME_SEARCH *key;
 				
 				/* save the position */
-				key = memheap_allocate(heap, sizeof(KEYFRAME_SEARCH));
+				key = (KEYFRAME_SEARCH *)memheap_allocate(heap, sizeof(KEYFRAME_SEARCH));
 				key->frame.filepos = current_pos;
 				key->frame.tick = chunk_tick;
 				key->next = 0;
@@ -349,10 +348,10 @@ static void scan_file()
 
 static void do_tick()
 {
-	static char compresseddata[MAX_SNAPSHOT_SIZE];
-	static char decompressed[MAX_SNAPSHOT_SIZE];
-	static char data[MAX_SNAPSHOT_SIZE];
-	int chunk_size, chunk_type, chunk_tick;
+	static char compresseddata[CSnapshot::MAX_SIZE];
+	static char decompressed[CSnapshot::MAX_SIZE];
+	static char data[CSnapshot::MAX_SIZE];
+	int chunk_type, chunk_tick, chunk_size;
 	int data_size;
 	int got_snapshot = 0;
 
@@ -374,7 +373,7 @@ static void do_tick()
 		/* read the chunk */
 		if(chunk_size)
 		{
-			if(io_read(play_file, compresseddata, chunk_size) != chunk_size)
+			if(io_read(play_file, compresseddata, chunk_size) != (unsigned)chunk_size)
 			{
 				/* stop on error or eof */
 				dbg_msg("demorec", "error reading chunk");
@@ -382,7 +381,7 @@ static void do_tick()
 				break;
 			}
 			
-			data_size = netcommon_decompress(compresseddata, chunk_size, decompressed, sizeof(decompressed));
+			data_size = CNetBase::Decompress(compresseddata, chunk_size, decompressed, sizeof(decompressed));
 			if(data_size < 0)
 			{
 				/* stop on error or eof */
@@ -404,11 +403,11 @@ static void do_tick()
 		if(chunk_type == CHUNKTYPE_DELTA)
 		{
 			/* process delta snapshot */
-			static char newsnap[MAX_SNAPSHOT_SIZE];
+			static char newsnap[CSnapshot::MAX_SIZE];
 			
 			got_snapshot = 1;
 			
-			data_size = snapshot_unpack_delta((SNAPSHOT*)playback_lastsnapshotdata, (SNAPSHOT*)newsnap, data, data_size);
+			data_size = CSnapshot::UnpackDelta((CSnapshot*)playback_lastsnapshotdata, (CSnapshot*)newsnap, data, data_size);
 			
 			if(data_size >= 0)
 			{
@@ -625,7 +624,7 @@ int demorec_playback_update()
 	return 0;
 }
 
-int demorec_playback_stop(const char *filename)
+int demorec_playback_stop()
 {
 	if(!play_file)
 		return -1;
@@ -637,3 +636,5 @@ int demorec_playback_stop(const char *filename)
 	keyframes = 0;
 	return 0;
 }
+
+
diff --git a/src/engine/e_demorec.h b/src/engine/e_demorec.h
index 482debb4..9716b463 100644
--- a/src/engine/e_demorec.h
+++ b/src/engine/e_demorec.h
@@ -2,10 +2,6 @@
 #ifndef _DEMOREC_H
 #define _DEMOREC_H
 
-#ifdef __cplusplus
-extern "C"{
-#endif
-
 typedef struct DEMOREC_HEADER
 {
 	char marker[8];
@@ -70,8 +66,4 @@ const DEMOREC_PLAYBACKINFO *demorec_playback_info();
 int demorec_isplaying();
 int demorec_playback_stop();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/engine/e_engine.c b/src/engine/e_engine.cpp
index 7afbb2ce..4475478a 100644
--- a/src/engine/e_engine.c
+++ b/src/engine/e_engine.cpp
@@ -25,7 +25,7 @@ static void con_dbg_dumpmem(void *result, void *user_data)
 
 static void con_dbg_lognetwork(void *result, void *user_data)
 {
-	netcommon_openlog("network_sent.dat", "network_recv.dat");
+	CNetBase::OpenLog("network_sent.dat", "network_recv.dat");
 }
 
 
@@ -55,7 +55,7 @@ void engine_init(const char *appname)
 
 	/* init the network */
 	net_init();
-	netcommon_init();
+	CNetBase::Init();
 	
 	/* create storage location */
 	{
@@ -246,7 +246,7 @@ static IOHANDLE config_file = 0;
 
 int engine_config_write_start()
 {
-	config_save("settings.cfg");
+	config_save();
 	config_file = engine_openfile("settings.cfg", IOFLAG_WRITE);
 	if(config_file == 0)
 		return -1;
diff --git a/src/engine/e_huffman.c b/src/engine/e_huffman.cpp
index 43914010..43914010 100644
--- a/src/engine/e_huffman.c
+++ b/src/engine/e_huffman.cpp
diff --git a/src/engine/e_huffman.h b/src/engine/e_huffman.h
index c4e20223..635c74a1 100644
--- a/src/engine/e_huffman.h
+++ b/src/engine/e_huffman.h
@@ -1,10 +1,6 @@
 #ifndef __HUFFMAN_HEADER__
 #define __HUFFMAN_HEADER__
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 enum
 {
 	HUFFMAN_EOF_SYMBOL = 256,
@@ -84,8 +80,4 @@ int huffman_compress(HUFFMAN_STATE *huff, const void *input, int input_size, voi
 */
 int huffman_decompress(HUFFMAN_STATE *huff, const void *input, int input_size, void *output, int output_size);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __HUFFMAN_HEADER__ */
diff --git a/src/engine/e_if_other.h b/src/engine/e_if_other.h
index 5c839750..3fbbd81e 100644
--- a/src/engine/e_if_other.h
+++ b/src/engine/e_if_other.h
@@ -69,11 +69,12 @@ void perf_init();
 void perf_next();
 void perf_start(PERFORMACE_INFO *info);
 void perf_end();
-void perf_dump();
+void perf_dump(PERFORMACE_INFO *top);
 
 int gfx_init();
 void gfx_shutdown();
 void gfx_swap();
+
 int gfx_window_active();
 int gfx_window_open();
 
diff --git a/src/engine/e_jobs.c b/src/engine/e_jobs.cpp
index e87b395a..e87b395a 100644
--- a/src/engine/e_jobs.c
+++ b/src/engine/e_jobs.cpp
diff --git a/src/engine/e_keynames.c b/src/engine/e_keynames.cpp
index c81744b9..c81744b9 100644
--- a/src/engine/e_keynames.c
+++ b/src/engine/e_keynames.cpp
diff --git a/src/engine/e_linereader.c b/src/engine/e_linereader.cpp
index 57ba9a85..57ba9a85 100644
--- a/src/engine/e_linereader.c
+++ b/src/engine/e_linereader.cpp
diff --git a/src/engine/e_map.c b/src/engine/e_map.cpp
index a2048310..a2048310 100644
--- a/src/engine/e_map.c
+++ b/src/engine/e_map.cpp
diff --git a/src/engine/e_memheap.c b/src/engine/e_memheap.cpp
index 7589e2c1..fe157e86 100644
--- a/src/engine/e_memheap.c
+++ b/src/engine/e_memheap.cpp
@@ -1,18 +1,18 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 #include <base/system.h>
 
-typedef struct CHUNK_t
+struct CHUNK
 {
 	char *memory;
 	char *current;
 	char *end;
-	struct CHUNK_t *next;
-} CHUNK;
+	CHUNK *next;
+};
 
-typedef struct 
+struct HEAP
 {
 	CHUNK *current;
-} HEAP;
+};
 
 /* how large each chunk should be */
 static const int chunksize = 1024*64;
diff --git a/src/engine/e_memheap.h b/src/engine/e_memheap.h
index af3c0b29..b4391ec7 100644
--- a/src/engine/e_memheap.h
+++ b/src/engine/e_memheap.h
@@ -1,6 +1,6 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 
-typedef struct HEAP_t HEAP;
+struct HEAP;
 HEAP *memheap_create();
 void memheap_destroy(HEAP *heap);
 void *memheap_allocate(HEAP *heap, unsigned int size);
diff --git a/src/engine/e_msg.c b/src/engine/e_msg.cpp
index f9efc2bf..999a0ff0 100644
--- a/src/engine/e_msg.c
+++ b/src/engine/e_msg.cpp
@@ -3,17 +3,17 @@
 #include "e_packer.h"
 
 /* message packing */
-static PACKER msg_packer;
+static CPacker msg_packer;
 static MSG_INFO pack_info;
 static int packer_failed = 0;
 
-void msg_pack_int(int i) { packer_add_int(&msg_packer, i); }
-void msg_pack_string(const char *p, int limit) { packer_add_string(&msg_packer, p, limit); }
-void msg_pack_raw(const void *data, int size) { packer_add_raw(&msg_packer, (const unsigned char *)data, size); }
+void msg_pack_int(int i) { msg_packer.AddInt(i); }
+void msg_pack_string(const char *p, int limit) { msg_packer.AddString(p, limit); }
+void msg_pack_raw(const void *data, int size) { msg_packer.AddRaw((const unsigned char *)data, size); }
 
 void msg_pack_start_system(int msg, int flags)
 {
-	packer_reset(&msg_packer);
+	msg_packer.Reset();
 	pack_info.msg = (msg<<1)|1;
 	pack_info.flags = flags;
 	packer_failed = 0;
@@ -23,7 +23,7 @@ void msg_pack_start_system(int msg, int flags)
 
 void msg_pack_start(int msg, int flags)
 {
-	packer_reset(&msg_packer);
+	msg_packer.Reset();
 	pack_info.msg = msg<<1;
 	pack_info.flags = flags;
 	packer_failed = 0;
@@ -33,7 +33,7 @@ void msg_pack_start(int msg, int flags)
 
 void msg_pack_end()
 {
-	if(msg_packer.error)
+	if(msg_packer.Error())
 	{
 		packer_failed = 1;
 		pack_info.size = 0;
@@ -41,8 +41,8 @@ void msg_pack_end()
 	}
 	else
 	{
-		pack_info.size = packer_size(&msg_packer);
-		pack_info.data = packer_data(&msg_packer);
+		pack_info.size = msg_packer.Size();
+		pack_info.data = msg_packer.Data();
 	}
 }
 
@@ -54,17 +54,17 @@ const MSG_INFO *msg_get_info()
 }
 
 /* message unpacking */
-static UNPACKER msg_unpacker;
+static CUnpacker msg_unpacker;
 int msg_unpack_start(const void *data, int data_size, int *system)
 {
 	int msg;
-	unpacker_reset(&msg_unpacker, (const unsigned char *)data, data_size);
+	msg_unpacker.Reset((const unsigned char *)data, data_size);
 	msg = msg_unpack_int();
 	*system = msg&1;
 	return msg>>1;
 }
 
-int msg_unpack_int() { return unpacker_get_int(&msg_unpacker); }
-const char *msg_unpack_string() { return unpacker_get_string(&msg_unpacker); }
-const unsigned char *msg_unpack_raw(int size)  { return unpacker_get_raw(&msg_unpacker, size); }
-int msg_unpack_error() { return msg_unpacker.error; }
+int msg_unpack_int() { return msg_unpacker.GetInt(); }
+const char *msg_unpack_string() { return msg_unpacker.GetString(); }
+const unsigned char *msg_unpack_raw(int size)  { return msg_unpacker.GetRaw(size); }
+int msg_unpack_error() { return msg_unpacker.Error(); }
diff --git a/src/engine/e_network.c b/src/engine/e_network.c
deleted file mode 100644
index 3c32de1d..00000000
--- a/src/engine/e_network.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-#include <base/system.h>
-
-#include <string.h> /* strlen */
-
-#include "e_config.h"
-#include "e_engine.h"
-#include "e_network.h"
-#include "e_network_internal.h"
-#include "e_huffman.h"
-
-void recvinfo_clear(NETRECVINFO *info)
-{
-	info->valid = 0;
-}
-
-void recvinfo_start(NETRECVINFO *info, NETADDR *addr, NETCONNECTION *conn, int cid)
-{
-	info->addr = *addr;
-	info->conn = conn;
-	info->client_id = cid;
-	info->current_chunk = 0;
-	info->valid = 1;
-}
-
-
-int seq_in_backroom(int seq, int ack)
-{
-	int bottom = (ack-NET_MAX_SEQUENCE/2);
-	if(bottom < 0)
-	{
-		if(seq <= ack)
-			return 1;
-		if(seq >= (bottom + NET_MAX_SEQUENCE))
-			return 1;
-	}
-	else
-	{
-		if(seq <= ack && seq >= bottom)
-			return 1;
-	}
-	
-	return 0;
-}
-
-/* TODO: rename this function */
-int recvinfo_fetch_chunk(NETRECVINFO *info, NETCHUNK *chunk)
-{
-	NETCHUNKHEADER header;
-	unsigned char *end = info->data.chunk_data + info->data.data_size;
-	int i;
-	
-	while(1)
-	{
-		unsigned char *data = info->data.chunk_data;
-		
-		/* check for old data to unpack */
-		if(!info->valid || info->current_chunk >= info->data.num_chunks)
-		{
-			recvinfo_clear(info);
-			return 0;
-		}
-		
-		/* TODO: add checking here so we don't read too far */
-		for(i = 0; i < info->current_chunk; i++)
-		{
-			data = unpack_chunk_header(data, &header);
-			data += header.size;
-		}
-		
-		/* unpack the header */	
-		data = unpack_chunk_header(data, &header);
-		info->current_chunk++;
-		
-		if(data+header.size > end)
-		{
-			recvinfo_clear(info);
-			return 0;
-		}
-		
-		/* handle sequence stuff */
-		if(info->conn && (header.flags&NET_CHUNKFLAG_VITAL))
-		{
-			if(header.sequence == (info->conn->ack+1)%NET_MAX_SEQUENCE)
-			{
-				/* in sequence */
-				info->conn->ack = (info->conn->ack+1)%NET_MAX_SEQUENCE;
-			}
-			else
-			{
-				/* old packet that we already got */
-				if(seq_in_backroom(header.sequence, info->conn->ack))
-					continue;
-
-				/* out of sequence, request resend */
-				if(config.debug)
-					dbg_msg("conn", "asking for resend %d %d", header.sequence, (info->conn->ack+1)%NET_MAX_SEQUENCE);
-				conn_want_resend(info->conn);
-				continue; /* take the next chunk in the packet */
-			}
-		}
-		
-		/* fill in the info */
-		chunk->client_id = info->client_id;
-		chunk->address = info->addr;
-		chunk->flags = 0;
-		chunk->data_size = header.size;
-		chunk->data = data;
-		return 1;
-	}
-}
-
-
-static IOHANDLE datalog_sent = 0;
-static IOHANDLE datalog_recv = 0;
-static HUFFMAN_STATE huffmanstate;
-
-#define COMPRESSION 1
-
-/* packs the data tight and sends it */
-void send_packet_connless(NETSOCKET socket, NETADDR *addr, const void *data, int data_size)
-{
-	unsigned char buffer[NET_MAX_PACKETSIZE];
-	buffer[0] = 0xff;
-	buffer[1] = 0xff;
-	buffer[2] = 0xff;
-	buffer[3] = 0xff;
-	buffer[4] = 0xff;
-	buffer[5] = 0xff;
-	mem_copy(&buffer[6], data, data_size);
-	net_udp_send(socket, addr, buffer, 6+data_size);
-}
-
-int netcommon_compress(const void *data, int data_size, void *output, int output_size)
-{
-	return huffman_compress(&huffmanstate, data, data_size, output, output_size);
-}
-
-int netcommon_decompress(const void *data, int data_size, void *output, int output_size)
-{
-	return huffman_decompress(&huffmanstate, data, data_size, output, output_size);
-}
-
-void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet)
-{
-	unsigned char buffer[NET_MAX_PACKETSIZE];
-	int compressed_size = -1;
-	int final_size = -1;
-
-	/* log the data */
-	if(datalog_sent)
-	{
-		int type = 1;
-		io_write(datalog_sent, &type, sizeof(type));
-		io_write(datalog_sent, &packet->data_size, sizeof(packet->data_size));
-		io_write(datalog_sent, &packet->chunk_data, packet->data_size);
-		io_flush(datalog_sent);
-	}
-	
-	/* compress if its enabled */
-	if(COMPRESSION)
-		compressed_size = huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4);
-
-	/* check if the compression was enabled, successful and good enough	*/
-	if(compressed_size > 0 && compressed_size < packet->data_size)
-	{
-		final_size = compressed_size;
-		packet->flags |= NET_PACKETFLAG_COMPRESSION;
-	}
-	else
-	{
-		/* use uncompressed data */
-		final_size = packet->data_size;
-		mem_copy(&buffer[3], packet->chunk_data, packet->data_size);
-		packet->flags &= ~NET_PACKETFLAG_COMPRESSION;
-	}
-
-	/* set header and send the packet if all things are good */
-	if(final_size >= 0)
-	{
-		final_size += NET_PACKETHEADERSIZE;
-		buffer[0] = ((packet->flags<<4)&0xf0)|((packet->ack>>8)&0xf);
-		buffer[1] = packet->ack&0xff;
-		buffer[2] = packet->num_chunks;
-		net_udp_send(socket, addr, buffer, final_size);
-
-		/* log raw socket data */
-		if(datalog_sent)
-		{
-			int type = 0;
-			io_write(datalog_sent, &type, sizeof(type));
-			io_write(datalog_sent, &final_size, sizeof(final_size));
-			io_write(datalog_sent, buffer, final_size);
-			io_flush(datalog_sent);
-		}
-	}
-}
-
-/* TODO: rename this function */
-int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *packet)
-{
-	/* check the size */
-	if(size < NET_PACKETHEADERSIZE || size > NET_MAX_PACKETSIZE)
-	{
-		dbg_msg("", "packet too small, %d", size);
-		return -1;
-	}
-
-	/* log the data */
-	if(datalog_recv)
-	{
-		int type = 0;
-		io_write(datalog_recv, &type, sizeof(type));
-		io_write(datalog_recv, &size, sizeof(size));
-		io_write(datalog_recv, buffer, size);
-		io_flush(datalog_recv);
-	}
-	
-	/* read the packet */
-	packet->flags = buffer[0]>>4;
-	packet->ack = ((buffer[0]&0xf)<<8) | buffer[1];
-	packet->num_chunks = buffer[2];
-	packet->data_size = size - NET_PACKETHEADERSIZE;
-
-	if(packet->flags&NET_PACKETFLAG_CONNLESS)
-	{
-		if(size < 6)
-		{
-			dbg_msg("", "connection less packet too small, %d", size);
-			return -1;
-		}
-			
-		packet->flags = NET_PACKETFLAG_CONNLESS;
-		packet->ack = 0;
-		packet->num_chunks = 0;
-		packet->data_size = size - 6;
-		mem_copy(packet->chunk_data, &buffer[6], packet->data_size);
-	}
-	else
-	{
-		if(packet->flags&NET_PACKETFLAG_COMPRESSION)
-			packet->data_size = huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data));
-		else
-			mem_copy(packet->chunk_data, &buffer[3], packet->data_size);
-	}
-
-	/* check for errors */	
-	if(packet->data_size < 0)
-	{
-		if(config.debug)
-			dbg_msg("network", "error during packet decoding");
-		return -1;
-	}
-
-	/* log the data */
-	if(datalog_recv)
-	{
-		int type = 1;
-		io_write(datalog_recv, &type, sizeof(type));
-		io_write(datalog_recv, &packet->data_size, sizeof(packet->data_size));
-		io_write(datalog_recv, packet->chunk_data, packet->data_size);
-		io_flush(datalog_recv);
-	}
-		
-	/* return success */
-	return 0;
-}
-
-
-/* TODO: change the arguments of this function */
-unsigned char *pack_chunk_header(unsigned char *data, int flags, int size, int sequence)
-{
-	data[0] = ((flags&3)<<6)|((size>>4)&0x3f);
-	data[1] = (size&0xf);
-	if(flags&NET_CHUNKFLAG_VITAL)
-	{
-		data[1] |= (sequence>>2)&0xf0;
-		data[2] = sequence&0xff;
-		return data + 3;
-	}
-	return data + 2;
-}
-
-unsigned char *unpack_chunk_header(unsigned char *data, NETCHUNKHEADER *header)
-{
-	header->flags = (data[0]>>6)&3;
-	header->size = ((data[0]&0x3f)<<4) | (data[1]&0xf);
-	header->sequence = -1;
-	if(header->flags&NET_CHUNKFLAG_VITAL)
-	{
-		header->sequence = ((data[1]&0xf0)<<2) | data[2];
-		return data + 3;
-	}
-	return data + 2;
-}
-
-
-void send_controlmsg(NETSOCKET socket, NETADDR *addr, int ack, int controlmsg, const void *extra, int extra_size)
-{
-	NETPACKETCONSTRUCT construct;
-	construct.flags = NET_PACKETFLAG_CONTROL;
-	construct.ack = ack;
-	construct.num_chunks = 0;
-	construct.data_size = 1+extra_size;
-	construct.chunk_data[0] = controlmsg;
-	mem_copy(&construct.chunk_data[1], extra, extra_size);
-	
-	/* send the control message */
-	send_packet(socket, addr, &construct);
-}
-
-void netcommon_openlog(const char *sentlog, const char *recvlog)
-{
-	if(sentlog)
-	{
-		datalog_sent = engine_openfile(sentlog, IOFLAG_WRITE);
-		if(datalog_sent)
-			dbg_msg("network", "logging sent packages to '%s'", sentlog);
-		else
-			dbg_msg("network", "failed to open for logging '%s'", sentlog);
-	}
-	
-	if(recvlog)
-	{
-		datalog_recv = engine_openfile(recvlog, IOFLAG_WRITE);
-		if(recvlog)
-			dbg_msg("network", "logging recv packages to '%s'", recvlog);
-		else
-			dbg_msg("network", "failed to open for logging '%s'", recvlog);
-	}
-}
-
-static const unsigned freq_table[256+1] = {
-	1<<30,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186,
-	283,131,146,166,543,164,167,136,179,859,363,113,157,154,204,108,137,180,202,176,
-	872,404,168,134,151,111,113,109,120,126,129,100,41,20,16,22,18,18,17,19,
-	16,37,13,21,362,166,99,78,95,88,81,70,83,284,91,187,77,68,52,68,
-	59,66,61,638,71,157,50,46,69,43,11,24,13,19,10,12,12,20,14,9,
-	20,20,10,10,15,15,12,12,7,19,15,14,13,18,35,19,17,14,8,5,
-	15,17,9,15,14,18,8,10,2173,134,157,68,188,60,170,60,194,62,175,71,
-	148,67,167,78,211,67,156,69,1674,90,174,53,147,89,181,51,174,63,163,80,
-	167,94,128,122,223,153,218,77,200,110,190,73,174,69,145,66,277,143,141,60,
-	136,53,180,57,142,57,158,61,166,112,152,92,26,22,21,28,20,26,30,21,
-	32,27,20,17,23,21,30,22,22,21,27,25,17,27,23,18,39,26,15,21,
-	12,18,18,27,20,18,15,19,11,17,33,12,18,15,19,18,16,26,17,18,
-	9,10,25,22,22,17,20,16,6,16,15,20,14,18,24,335,1517};
-
-void netcommon_init()
-{
-	huffman_init(&huffmanstate, freq_table);
-}
diff --git a/src/engine/e_network.cpp b/src/engine/e_network.cpp
new file mode 100644
index 00000000..ac753e50
--- /dev/null
+++ b/src/engine/e_network.cpp
@@ -0,0 +1,347 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <base/system.h>
+
+#include <string.h> /* strlen */
+
+#include "e_config.h"
+#include "e_engine.h"
+#include "e_network.h"
+#include "e_huffman.h"
+
+void CNetRecvUnpacker::Clear()
+{
+	m_Valid = false;
+}
+
+void CNetRecvUnpacker::Start(const NETADDR *pAddr, CNetConnection *pConnection, int ClientID)
+{
+	m_Addr = *pAddr;
+	m_pConnection = pConnection;
+	m_ClientID = ClientID;
+	m_CurrentChunk = 0;
+	m_Valid = true;
+}
+
+/* TODO: rename this function */
+int CNetRecvUnpacker::FetchChunk(CNetChunk *pChunk)
+{
+	CNetChunkHeader Header;
+	unsigned char *pEnd = m_Data.m_aChunkData + m_Data.m_DataSize;
+	
+	while(1)
+	{
+		unsigned char *pData = m_Data.m_aChunkData;
+		
+		/* check for old data to unpack */
+		if(!m_Valid || m_CurrentChunk >= m_Data.m_NumChunks)
+		{
+			Clear();
+			return 0;
+		}
+		
+		/* TODO: add checking here so we don't read too far */
+		for(int i = 0; i < m_CurrentChunk; i++)
+		{
+			pData = Header.Unpack(pData);
+			pData += Header.m_Size;
+		}
+		
+		/* unpack the header */
+		pData = Header.Unpack(pData);
+		m_CurrentChunk++;
+		
+		if(pData+Header.m_Size > pEnd)
+		{
+			Clear();
+			return 0;
+		}
+		
+		/* handle sequence stuff */
+		if(m_pConnection && (Header.m_Flags&NET_CHUNKFLAG_VITAL))
+		{
+			if(Header.m_Sequence == (m_pConnection->m_Ack+1)%NET_MAX_SEQUENCE)
+			{
+				/* in sequence */
+				m_pConnection->m_Ack = (m_pConnection->m_Ack+1)%NET_MAX_SEQUENCE;
+			}
+			else
+			{
+				/* old packet that we already got */
+				if(CNetBase::IsSeqInBackroom(Header.m_Sequence, m_pConnection->m_Ack))
+					continue;
+
+				/* out of sequence, request resend */
+				if(config.debug)
+					dbg_msg("conn", "asking for resend %d %d", Header.m_Sequence, (m_pConnection->m_Ack+1)%NET_MAX_SEQUENCE);
+				m_pConnection->SignalResend();
+				continue; /* take the next chunk in the packet */
+			}
+		}
+		
+		/* fill in the info */
+		pChunk->m_ClientID = m_ClientID;
+		pChunk->m_Address = m_Addr;
+		pChunk->m_Flags = 0;
+		pChunk->m_DataSize = Header.m_Size;
+		pChunk->m_pData = pData;
+		return 1;
+	}
+}
+
+/* packs the data tight and sends it */
+void CNetBase::SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize)
+{
+	unsigned char aBuffer[NET_MAX_PACKETSIZE];
+	aBuffer[0] = 0xff;
+	aBuffer[1] = 0xff;
+	aBuffer[2] = 0xff;
+	aBuffer[3] = 0xff;
+	aBuffer[4] = 0xff;
+	aBuffer[5] = 0xff;
+	mem_copy(&aBuffer[6], pData, DataSize);
+	net_udp_send(Socket, pAddr, aBuffer, 6+DataSize);
+}
+
+void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket)
+{
+	unsigned char aBuffer[NET_MAX_PACKETSIZE];
+	int CompressedSize = -1;
+	int FinalSize = -1;
+
+	/* log the data */
+	if(ms_DataLogSent)
+	{
+		int type = 1;
+		io_write(ms_DataLogSent, &type, sizeof(type));
+		io_write(ms_DataLogSent, &pPacket->m_DataSize, sizeof(pPacket->m_DataSize));
+		io_write(ms_DataLogSent, &pPacket->m_aChunkData, pPacket->m_DataSize);
+		io_flush(ms_DataLogSent);
+	}
+	
+	/* compress */
+	CompressedSize = huffman_compress(&ms_HuffmanState, pPacket->m_aChunkData, pPacket->m_DataSize, &aBuffer[3], NET_MAX_PACKETSIZE-4);
+
+	/* check if the compression was enabled, successful and good enough	*/
+	if(CompressedSize > 0 && CompressedSize < pPacket->m_DataSize)
+	{
+		FinalSize = CompressedSize;
+		pPacket->m_Flags |= NET_PACKETFLAG_COMPRESSION;
+	}
+	else
+	{
+		/* use uncompressed data */
+		FinalSize = pPacket->m_DataSize;
+		mem_copy(&aBuffer[3], pPacket->m_aChunkData, pPacket->m_DataSize);
+		pPacket->m_Flags &= ~NET_PACKETFLAG_COMPRESSION;
+	}
+
+	/* set header and send the packet if all things are good */
+	if(FinalSize >= 0)
+	{
+		FinalSize += NET_PACKETHEADERSIZE;
+		aBuffer[0] = ((pPacket->m_Flags<<4)&0xf0)|((pPacket->m_Ack>>8)&0xf);
+		aBuffer[1] = pPacket->m_Ack&0xff;
+		aBuffer[2] = pPacket->m_NumChunks;
+		net_udp_send(Socket, pAddr, aBuffer, FinalSize);
+
+		/* log raw socket data */
+		if(ms_DataLogSent)
+		{
+			int type = 0;
+			io_write(ms_DataLogSent, &type, sizeof(type));
+			io_write(ms_DataLogSent, &FinalSize, sizeof(FinalSize));
+			io_write(ms_DataLogSent, aBuffer, FinalSize);
+			io_flush(ms_DataLogSent);
+		}
+	}
+}
+
+/* TODO: rename this function */
+int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket)
+{
+	/* check the size */
+	if(Size < NET_PACKETHEADERSIZE || Size > NET_MAX_PACKETSIZE)
+	{
+		dbg_msg("", "packet too small, %d", Size);
+		return -1;
+	}
+
+	/* log the data */
+	if(ms_DataLogRecv)
+	{
+		int type = 0;
+		io_write(ms_DataLogRecv, &type, sizeof(type));
+		io_write(ms_DataLogRecv, &Size, sizeof(Size));
+		io_write(ms_DataLogRecv, pBuffer, Size);
+		io_flush(ms_DataLogRecv);
+	}
+	
+	/* read the packet */
+	pPacket->m_Flags = pBuffer[0]>>4;
+	pPacket->m_Ack = ((pBuffer[0]&0xf)<<8) | pBuffer[1];
+	pPacket->m_NumChunks = pBuffer[2];
+	pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE;
+
+	if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS)
+	{
+		if(Size < 6)
+		{
+			dbg_msg("", "connection less packet too small, %d", Size);
+			return -1;
+		}
+			
+		pPacket->m_Flags = NET_PACKETFLAG_CONNLESS;
+		pPacket->m_Ack = 0;
+		pPacket->m_NumChunks = 0;
+		pPacket->m_DataSize = Size - 6;
+		mem_copy(pPacket->m_aChunkData, &pBuffer[6], pPacket->m_DataSize);
+	}
+	else
+	{
+		if(pPacket->m_Flags&NET_PACKETFLAG_COMPRESSION)
+			pPacket->m_DataSize = huffman_decompress(&ms_HuffmanState, &pBuffer[3], pPacket->m_DataSize, pPacket->m_aChunkData, sizeof(pPacket->m_aChunkData));
+		else
+			mem_copy(pPacket->m_aChunkData, &pBuffer[3], pPacket->m_DataSize);
+	}
+
+	/* check for errors */	
+	if(pPacket->m_DataSize < 0)
+	{
+		if(config.debug)
+			dbg_msg("network", "error during packet decoding");
+		return -1;
+	}
+
+	/* log the data */
+	if(ms_DataLogRecv)
+	{
+		int type = 1;
+		io_write(ms_DataLogRecv, &type, sizeof(type));
+		io_write(ms_DataLogRecv, &pPacket->m_DataSize, sizeof(pPacket->m_DataSize));
+		io_write(ms_DataLogRecv, pPacket->m_aChunkData, pPacket->m_DataSize);
+		io_flush(ms_DataLogRecv);
+	}
+		
+	/* return success */
+	return 0;
+}
+
+
+void CNetBase::SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize)
+{
+	CNetPacketConstruct Construct;
+	Construct.m_Flags = NET_PACKETFLAG_CONTROL;
+	Construct.m_Ack = Ack;
+	Construct.m_NumChunks = 0;
+	Construct.m_DataSize = 1+ExtraSize;
+	Construct.m_aChunkData[0] = ControlMsg;
+	mem_copy(&Construct.m_aChunkData[1], pExtra, ExtraSize);
+	
+	/* send the control message */
+	CNetBase::SendPacket(Socket, pAddr, &Construct);
+}
+
+
+
+unsigned char *CNetChunkHeader::Pack(unsigned char *pData)
+{
+	pData[0] = ((m_Flags&3)<<6)|((m_Size>>4)&0x3f);
+	pData[1] = (m_Size&0xf);
+	if(m_Flags&NET_CHUNKFLAG_VITAL)
+	{
+		pData[1] |= (m_Sequence>>2)&0xf0;
+		pData[2] = m_Sequence&0xff;
+		return pData + 3;
+	}
+	return pData + 2;
+}
+
+unsigned char *CNetChunkHeader::Unpack(unsigned char *pData)
+{
+	m_Flags = (pData[0]>>6)&3;
+	m_Size = ((pData[0]&0x3f)<<4) | (pData[1]&0xf);
+	m_Sequence = -1;
+	if(m_Flags&NET_CHUNKFLAG_VITAL)
+	{
+		m_Sequence = ((pData[1]&0xf0)<<2) | pData[2];
+		return pData + 3;
+	}
+	return pData + 2;
+}
+
+
+int CNetBase::IsSeqInBackroom(int Seq, int Ack)
+{
+	int Bottom = (Ack-NET_MAX_SEQUENCE/2);
+	if(Bottom < 0)
+	{
+		if(Seq <= Ack)
+			return 1;
+		if(Seq >= (Bottom + NET_MAX_SEQUENCE))
+			return 1;
+	}
+	else
+	{
+		if(Seq <= Ack && Seq >= Bottom)
+			return 1;
+	}
+	
+	return 0;
+}
+
+IOHANDLE CNetBase::ms_DataLogSent = 0;
+IOHANDLE CNetBase::ms_DataLogRecv = 0;
+HUFFMAN_STATE CNetBase::ms_HuffmanState;
+
+
+void CNetBase::OpenLog(const char *pSentLog, const char *pRecvLog)
+{
+	if(pSentLog)
+	{
+		ms_DataLogSent = engine_openfile(pSentLog, IOFLAG_WRITE);
+		if(ms_DataLogSent)
+			dbg_msg("network", "logging sent packages to '%s'", pSentLog);
+		else
+			dbg_msg("network", "failed to open for logging '%s'", pSentLog);
+	}
+	
+	if(pRecvLog)
+	{
+		ms_DataLogRecv = engine_openfile(pRecvLog, IOFLAG_WRITE);
+		if(ms_DataLogRecv)
+			dbg_msg("network", "logging recv packages to '%s'", pRecvLog);
+		else
+			dbg_msg("network", "failed to open for logging '%s'", pRecvLog);
+	}
+}
+
+int CNetBase::Compress(const void *pData, int DataSize, void *pOutput, int OutputSize)
+{
+	return huffman_compress(&ms_HuffmanState, pData, DataSize, pOutput, OutputSize);
+}
+
+int CNetBase::Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize)
+{
+	return huffman_decompress(&ms_HuffmanState, pData, DataSize, pOutput, OutputSize);
+}
+
+
+static const unsigned gs_aFreqTable[256+1] = {
+	1<<30,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186,
+	283,131,146,166,543,164,167,136,179,859,363,113,157,154,204,108,137,180,202,176,
+	872,404,168,134,151,111,113,109,120,126,129,100,41,20,16,22,18,18,17,19,
+	16,37,13,21,362,166,99,78,95,88,81,70,83,284,91,187,77,68,52,68,
+	59,66,61,638,71,157,50,46,69,43,11,24,13,19,10,12,12,20,14,9,
+	20,20,10,10,15,15,12,12,7,19,15,14,13,18,35,19,17,14,8,5,
+	15,17,9,15,14,18,8,10,2173,134,157,68,188,60,170,60,194,62,175,71,
+	148,67,167,78,211,67,156,69,1674,90,174,53,147,89,181,51,174,63,163,80,
+	167,94,128,122,223,153,218,77,200,110,190,73,174,69,145,66,277,143,141,60,
+	136,53,180,57,142,57,158,61,166,112,152,92,26,22,21,28,20,26,30,21,
+	32,27,20,17,23,21,30,22,22,21,27,25,17,27,23,18,39,26,15,21,
+	12,18,18,27,20,18,15,19,11,17,33,12,18,15,19,18,16,26,17,18,
+	9,10,25,22,22,17,20,16,6,16,15,20,14,18,24,335,1517};
+
+void CNetBase::Init()
+{
+	huffman_init(&ms_HuffmanState, gs_aFreqTable);
+}
diff --git a/src/engine/e_network.h b/src/engine/e_network.h
index 04453cf9..19eca8da 100644
--- a/src/engine/e_network.h
+++ b/src/engine/e_network.h
@@ -2,38 +2,26 @@
 #define ENGINE_NETWORK_H
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 
+#include "e_ringbuffer.h"
+#include "e_huffman.h"
 
-typedef struct
-{
-	/* -1 means that it's a stateless packet */
-	/* 0 on the client means the server */
-	int client_id;
-	NETADDR address; /* only used when client_id == -1 */
-	int flags;
-	int data_size;
-	const void *data;
-} NETCHUNK;
-
-
-typedef struct
-{
-	NETADDR addr;
-	int expires;
-} NETBANINFO;
+/*
 
-/*typedef struct
-{
-	int send_bytes;
-	int recv_bytes;
-	int send_packets;
-	int recv_packets;
-	
-	int resend_packets;
-	int resend_bytes;
-} NETSTATS;*/
+CURRENT:
+	packet header: 3 bytes
+		unsigned char flags_ack; // 4bit flags, 4bit ack
+		unsigned char ack; // 8 bit ack
+		unsigned char num_chunks; // 8 bit chunks
+		
+		(unsigned char padding[3])	// 24 bit extra incase it's a connection less packet
+									// this is to make sure that it's compatible with the
+									// old protocol
 
-typedef struct NETSERVER NETSERVER;
-typedef struct NETCLIENT NETCLIENT;
+	chunk header: 2-3 bytes
+		unsigned char flags_size; // 2bit flags, 6 bit size
+		unsigned char size_seq; // 4bit size, 4bit seq
+		(unsigned char seq;) // 8bit seq, if vital flag is set
+*/
 
 enum
 {
@@ -50,97 +38,310 @@ enum
 	NETBANTYPE_DROP=2
 };
 
+
+enum
+{
+	NET_VERSION = 2,
+
+	NET_MAX_CHUNKSIZE = 1024,
+	NET_MAX_PAYLOAD = NET_MAX_CHUNKSIZE+16,
+	NET_MAX_PACKETSIZE = NET_MAX_PAYLOAD+16,
+	NET_MAX_CHUNKHEADERSIZE = 5,
+	NET_PACKETHEADERSIZE = 3,
+	NET_MAX_CLIENTS = 16,
+	NET_MAX_SEQUENCE = 1<<10,
+	NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1,
+
+	NET_CONNSTATE_OFFLINE=0,
+	NET_CONNSTATE_CONNECT=1,
+	NET_CONNSTATE_PENDING=2,
+	NET_CONNSTATE_ONLINE=3,
+	NET_CONNSTATE_ERROR=4,
+
+	NET_PACKETFLAG_CONTROL=1,
+	NET_PACKETFLAG_CONNLESS=2,
+	NET_PACKETFLAG_RESEND=4,
+	NET_PACKETFLAG_COMPRESSION=8,
+
+	NET_CHUNKFLAG_VITAL=1,
+	NET_CHUNKFLAG_RESEND=2,
+	
+	NET_CTRLMSG_KEEPALIVE=0,
+	NET_CTRLMSG_CONNECT=1,
+	NET_CTRLMSG_CONNECTACCEPT=2,
+	NET_CTRLMSG_ACCEPT=3,
+	NET_CTRLMSG_CLOSE=4,
+	
+	NET_SERVER_MAXBANS=1024,
+	
+	NET_CONN_BUFFERSIZE=1024*16,
+	
+	NET_ENUM_TERMINATOR
+};
+
+
 typedef int (*NETFUNC_DELCLIENT)(int cid, void *user);
 typedef int (*NETFUNC_NEWCLIENT)(int cid, void *user);
 
-/* both */
-void netcommon_openlog(const char *sentlog, const char *recvlog);
-void netcommon_init();
-int netcommon_compress(const void *data, int data_size, void *output, int output_size);
-int netcommon_decompress(const void *data, int data_size, void *output, int output_size);
+struct CNetChunk
+{
+	/* -1 means that it's a stateless packet */
+	/* 0 on the client means the server */
+	int m_ClientID;
+	NETADDR m_Address; /* only used when client_id == -1 */
+	int m_Flags;
+	int m_DataSize;
+	const void *m_pData;
+};
 
-/* server side */
-NETSERVER *netserver_open(NETADDR bindaddr, int max_clients, int flags);
-int netserver_set_callbacks(NETSERVER *s, NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user);
-int netserver_recv(NETSERVER *s, NETCHUNK *chunk);
-int netserver_send(NETSERVER *s, NETCHUNK *chunk);
-int netserver_close(NETSERVER *s);
-int netserver_update(NETSERVER *s);
-NETSOCKET netserver_socket(NETSERVER *s);
-int netserver_drop(NETSERVER *s, int client_id, const char *reason);
-int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr);
-int netserver_max_clients(NETSERVER *s);
-
-int netserver_ban_add(NETSERVER *s, NETADDR addr, int seconds);
-int netserver_ban_remove(NETSERVER *s, NETADDR addr);
-int netserver_ban_num(NETSERVER *s); /* caution, slow */
-int netserver_ban_get(NETSERVER *s, int index, NETBANINFO *info); /* caution, slow */
-
-/*void netserver_stats(NETSERVER *s, NETSTATS *stats);*/
+class CNetChunkHeader
+{
+public:
+	int m_Flags;
+	int m_Size;
+	int m_Sequence;
+	
+	unsigned char *Pack(unsigned char *pData);
+	unsigned char *Unpack(unsigned char *pData);
+};
 
-/* client side */
-NETCLIENT *netclient_open(NETADDR bindaddr, int flags);
-int netclient_disconnect(NETCLIENT *c, const char *reason);
-int netclient_connect(NETCLIENT *c, NETADDR *addr);
-int netclient_recv(NETCLIENT *c, NETCHUNK *chunk);
-int netclient_send(NETCLIENT *c, NETCHUNK *chunk);
-int netclient_close(NETCLIENT *c);
-int netclient_update(NETCLIENT *c);
-int netclient_state(NETCLIENT *c);
-int netclient_flush(NETCLIENT *c);
-int netclient_gotproblems(NETCLIENT *c);
-/*void netclient_stats(NETCLIENT *c, NETSTATS *stats);*/
-int netclient_error_string_reset(NETCLIENT *c);
-const char *netclient_error_string(NETCLIENT *c);
-
-#ifdef __cplusplus
-class net_server
+class CNetChunkResend
+{
+public:
+	int m_Flags;
+	int m_DataSize;
+	unsigned char *m_pData;
+
+	int m_Sequence;
+	int64 m_LastSendTime;
+	int64 m_FirstSendTime;
+};
+
+class CNetPacketConstruct
 {
-	NETSERVER *ptr;
 public:
-	net_server() : ptr(0) {}
-	~net_server() { close(); }
+	int m_Flags;
+	int m_Ack;
+	int m_NumChunks;
+	int m_DataSize;
+	unsigned char m_aChunkData[NET_MAX_PAYLOAD];
+};
+
+
+class CNetConnection
+{
+	// TODO: is this needed because this needs to be aware of
+	// the ack sequencing number and is also responible for updating
+	// that. this should be fixed.
+	friend class CNetRecvUnpacker;
+private:
+	unsigned short m_Sequence;
+	unsigned short m_Ack;
+	unsigned m_State;
+	
+	int m_Token;
+	int m_RemoteClosed;
+	
+	TStaticRingBuffer<CNetChunkResend, NET_CONN_BUFFERSIZE> m_Buffer;
+	
+	int64 m_LastUpdateTime;
+	int64 m_LastRecvTime;
+	int64 m_LastSendTime;
+	
+	char m_ErrorString[256];
 	
-	int open(NETADDR bindaddr, int max, int flags) { ptr = netserver_open(bindaddr, max, flags); return ptr != 0; }
-	int close() { int r = netserver_close(ptr); ptr = 0; return r; }
+	CNetPacketConstruct m_Construct;
 	
-	int set_callbacks(NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user)
-	{ return netserver_set_callbacks(ptr, new_client, del_client, user); }
+	NETADDR m_PeerAddr;
+	NETSOCKET m_Socket;
+	NETSTATS m_Stats;
 	
-	int recv(NETCHUNK *chunk) { return netserver_recv(ptr, chunk); }
-	int send(NETCHUNK *chunk) { return netserver_send(ptr, chunk); }
-	int update() { return netserver_update(ptr); }
+	//
+	void Reset();
+	void ResetStats();
+	void SetError(const char *pString);
+	void AckChunks(int Ack);
 	
-	int drop(int client_id, const char *reason) { return netserver_drop(ptr, client_id, reason); } 
+	void QueueChunkEx(int Flags, int DataSize, const void *pData, int Sequence);
+	void SendControl(int ControlMsg, const void *pExtra, int ExtraSize);
+	void ResendChunk(CNetChunkResend *pResend);
+	void Resend();
 
-	int max_clients() { return netserver_max_clients(ptr); }
-	/*void stats(NETSTATS *stats) { netserver_stats(ptr, stats); }*/
+public:
+	void Init(NETSOCKET Socket);
+	int Connect(NETADDR *pAddr);
+	void Disconnect(const char *pReason);
+
+	int Update();
+	int Flush();	
+
+	int Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr);
+	void QueueChunk(int Flags, int DataSize, const void *pData);
+
+	const char *ErrorString();
+	void SignalResend();
+	int State() const { return m_State; }
+	NETADDR PeerAddress() const { return m_PeerAddr; }
+	
+	void ResetErrorString() { m_ErrorString[0] = 0; }
+	const char *ErrorString() const { return m_ErrorString; }
+	
+	// Needed for GotProblems in NetClient
+	int64 LastRecvTime() const { return m_LastRecvTime; }
+	
+	int AckSequence() const { return m_Ack; }
+};
+
+struct CNetRecvUnpacker
+{
+public:
+	bool m_Valid;
+	
+	NETADDR m_Addr;
+	CNetConnection *m_pConnection;
+	int m_CurrentChunk;
+	int m_ClientID;
+	CNetPacketConstruct m_Data;
+	unsigned char m_aBuffer[NET_MAX_PACKETSIZE];
+
+	CNetRecvUnpacker() { Clear(); }
+	void Clear();
+	void Start(const NETADDR *pAddr, CNetConnection *pConnection, int ClientID);
+	int FetchChunk(CNetChunk *pChunk);	
+};
+
+/* server side */
+class CNetServer
+{
+public:
+	struct CBanInfo
+	{
+		NETADDR m_Addr;
+		int m_Expires;
+	};
+	
+private:
+	class CSlot
+	{
+	public:
+		CNetConnection m_Connection;
+	};
+	
+	class CBan
+	{
+	public:
+		CBanInfo m_Info;
+		
+		/* hash list */
+		CBan *m_pHashNext;
+		CBan *m_pHashPrev;
+		
+		/* used or free list */
+		CBan *m_pNext;
+		CBan *m_pPrev;
+	};
+	
+	
+	NETSOCKET m_Socket;
+	CSlot m_aSlots[NET_MAX_CLIENTS];
+	int m_MaxClients;
+
+	CBan *m_aBans[256];
+	CBan m_BanPool[NET_SERVER_MAXBANS];
+	CBan *m_BanPool_FirstFree;
+	CBan *m_BanPool_FirstUsed;
+
+	NETFUNC_NEWCLIENT m_pfnNewClient;
+	NETFUNC_DELCLIENT m_pfnDelClient;
+	void *m_UserPtr;
+	
+	CNetRecvUnpacker m_RecvUnpacker;
+	
+	void BanRemoveByObject(CBan *ban);
+	
+public:
+	int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
+
+	//
+	bool Open(NETADDR bindaddr, int MaxClients, int Flags);
+	int Close();
+	
+	//
+	int Recv(CNetChunk *pChunk);
+	int Send(CNetChunk *pChunk);
+	int Update();
+	
+	//
+	int Drop(int ClientID, const char *Reason);
+
+	// banning
+	int BanAdd(NETADDR Addr, int Seconds);
+	int BanRemove(NETADDR Addr);
+	int BanNum(); /* caution, slow */
+	int BanGet(int Index, CBanInfo *pInfo); /* caution, slow */
+
+	// status requests
+	NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
+	NETSOCKET Socket() const { return m_Socket; }
+	int MaxClients() const { return m_MaxClients; }
 };
 
 
-class net_client
+
+/* client side */
+class CNetClient
 {
-	NETCLIENT *ptr;
+	NETADDR m_ServerAddr;
+	CNetConnection m_Connection;
+	CNetRecvUnpacker m_RecvUnpacker;
+	NETSOCKET m_Socket;
 public:
-	net_client() : ptr(0) {}
-	~net_client() { close(); }
+	// openness
+	bool Open(NETADDR BindAddr, int Flags);
+	int Close();
 	
-	int open(NETADDR bindaddr, int flags) { ptr = netclient_open(bindaddr, flags); return ptr != 0; }
-	int close() { int r = netclient_close(ptr); ptr = 0; return r; }
+	// connection state
+	int Disconnect(const char *Reason);
+	int Connect(NETADDR *Addr);
 	
-	int connect(NETADDR *addr) { return netclient_connect(ptr, addr); }
-	int disconnect(const char *reason) { return netclient_disconnect(ptr, reason); }
+	// communication
+	int Recv(CNetChunk *Chunk);
+	int Send(CNetChunk *Chunk);
 	
-	int recv(NETCHUNK *chunk) { return netclient_recv(ptr, chunk); }
-	int send(NETCHUNK *chunk) { return netclient_send(ptr, chunk); }
-	int update() { return netclient_update(ptr); }
+	// pumping
+	int Update();
+	int Flush();
+
+	int ResetErrorString();
 	
-	const char *error_string() { return netclient_error_string(ptr); }
+	// error and state
+	int State();
+	int GotProblems();
+	const char *ErrorString();
+};
+
+
+
+// TODO: both, fix these. This feels like a junk class for stuff that doesn't fit anywere
+class CNetBase
+{
+	static IOHANDLE ms_DataLogSent;
+	static IOHANDLE ms_DataLogRecv;
+	static HUFFMAN_STATE ms_HuffmanState;
+public:
+	static void OpenLog(const char *pSentlog, const char *pRecvlog);
+	static void Init();
+	static int Compress(const void *pData, int DataSize, void *pOutput, int OutputSize);
+	static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize);
 	
-	int state() { return netclient_state(ptr); }
-	/*void stats(NETSTATS *stats) { netclient_stats(ptr, stats); }*/
+	static void SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize);
+	static void SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize);
+	static void SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket);
+	static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket);
+
+	/* The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not */
+	static int IsSeqInBackroom(int Seq, int Ack);	
 };
-#endif
 
 
 #endif
diff --git a/src/engine/e_network_client.c b/src/engine/e_network_client.c
deleted file mode 100644
index 75f7c538..00000000
--- a/src/engine/e_network_client.c
+++ /dev/null
@@ -1,154 +0,0 @@
-#include <base/system.h>
-#include "e_network.h"
-#include "e_network_internal.h"
-
-struct NETCLIENT
-{
-	NETADDR server_addr;
-	NETSOCKET socket;
-	
-	NETRECVINFO recv;
-	NETCONNECTION conn;
-};
-
-NETCLIENT *netclient_open(NETADDR bindaddr, int flags)
-{
-	NETCLIENT *client = (NETCLIENT *)mem_alloc(sizeof(NETCLIENT), 1);
-	mem_zero(client, sizeof(NETCLIENT));
-	client->socket = net_udp_create(bindaddr);
-	conn_init(&client->conn, client->socket);
-	return client;
-}
-
-int netclient_close(NETCLIENT *c)
-{
-	/* TODO: implement me */
-	return 0;
-}
-
-
-int netclient_disconnect(NETCLIENT *c, const char *reason)
-{
-	dbg_msg("netclient", "disconnected. reason=\"%s\"", reason);
-	conn_disconnect(&c->conn, reason);
-	return 0;
-}
-
-int netclient_update(NETCLIENT *c)
-{
-	conn_update(&c->conn);
-	if(c->conn.state == NET_CONNSTATE_ERROR)
-		netclient_disconnect(c, conn_error(&c->conn));
-	return 0;
-}
-
-int netclient_connect(NETCLIENT *c, NETADDR *addr)
-{
-	conn_connect(&c->conn, addr);
-	return 0;
-}
-
-int netclient_error_string_reset(NETCLIENT *c)
-{
-	mem_zero(c->conn.error_string, sizeof(c->conn.error_string));
-	return 0;
-}
-
-int netclient_recv(NETCLIENT *c, NETCHUNK *chunk)
-{
-	while(1)
-	{
-		NETADDR addr;
-		int bytes;
-			
-		/* check for a chunk */
-		if(recvinfo_fetch_chunk(&c->recv, chunk))
-			return 1;
-		
-		/* TODO: empty the recvinfo */
-		bytes = net_udp_recv(c->socket, &addr, c->recv.buffer, NET_MAX_PACKETSIZE);
-
-		/* no more packets for now */
-		if(bytes <= 0)
-			break;
-
-		if(unpack_packet(c->recv.buffer, bytes, &c->recv.data) == 0)
-		{
-			if(c->recv.data.flags&NET_PACKETFLAG_CONNLESS)
-			{
-				chunk->flags = NETSENDFLAG_CONNLESS;
-				chunk->client_id = -1;
-				chunk->address = addr;
-				chunk->data_size = c->recv.data.data_size;
-				chunk->data = c->recv.data.chunk_data;
-				return 1;
-			}
-			else
-			{
-				if(conn_feed(&c->conn, &c->recv.data, &addr))
-					recvinfo_start(&c->recv, &addr, &c->conn, 0);
-			}
-		}
-	}
-	return 0;
-}
-
-int netclient_send(NETCLIENT *c, NETCHUNK *chunk)
-{
-	if(chunk->data_size >= NET_MAX_PAYLOAD)
-	{
-		dbg_msg("netclient", "chunk payload too big. %d. dropping chunk", chunk->data_size);
-		return -1;
-	}
-	
-	if(chunk->flags&NETSENDFLAG_CONNLESS)
-	{
-		/* send connectionless packet */
-		send_packet_connless(c->socket, &chunk->address, chunk->data, chunk->data_size);
-	}
-	else
-	{
-		int f = 0;
-		dbg_assert(chunk->client_id == 0, "errornous client id");
-		
-		if(chunk->flags&NETSENDFLAG_VITAL)
-			f = NET_CHUNKFLAG_VITAL;
-		
-		conn_queue_chunk(&c->conn, f, chunk->data_size, chunk->data);
-
-		if(chunk->flags&NETSENDFLAG_FLUSH)
-			conn_flush(&c->conn);
-	}
-	return 0;
-}
-
-int netclient_state(NETCLIENT *c)
-{
-	if(c->conn.state == NET_CONNSTATE_ONLINE)
-		return NETSTATE_ONLINE;
-	if(c->conn.state == NET_CONNSTATE_OFFLINE)
-		return NETSTATE_OFFLINE;
-	return NETSTATE_CONNECTING;
-}
-
-int netclient_flush(NETCLIENT *c)
-{
-	return conn_flush(&c->conn);
-}
-
-int netclient_gotproblems(NETCLIENT *c)
-{
-	if(time_get() - c->conn.last_recv_time > time_freq())
-		return 1;
-	return 0;
-}
-
-void netclient_stats(NETCLIENT *c, NETSTATS *stats)
-{
-	*stats = c->conn.stats;
-}
-
-const char *netclient_error_string(NETCLIENT *c)
-{
-	return conn_error(&c->conn);
-}
diff --git a/src/engine/e_network_client.cpp b/src/engine/e_network_client.cpp
new file mode 100644
index 00000000..ce243b32
--- /dev/null
+++ b/src/engine/e_network_client.cpp
@@ -0,0 +1,139 @@
+#include <base/system.h>
+#include "e_network.h"
+
+bool CNetClient::Open(NETADDR BindAddr, int Flags)
+{
+	// clean it
+	mem_zero(this, sizeof(*this));
+
+	// open socket
+	m_Socket = net_udp_create(BindAddr);
+	m_Connection.Init(m_Socket);
+	return true;
+}
+
+int CNetClient::Close()
+{
+	/* TODO: implement me */
+	return 0;
+}
+
+
+int CNetClient::Disconnect(const char *pReason)
+{
+	dbg_msg("netclient", "disconnected. reason=\"%s\"", pReason);
+	m_Connection.Disconnect(pReason);
+	return 0;
+}
+
+int CNetClient::Update()
+{
+	m_Connection.Update();
+	if(m_Connection.State() == NET_CONNSTATE_ERROR)
+		Disconnect(m_Connection.ErrorString());
+	return 0;
+}
+
+int CNetClient::Connect(NETADDR *pAddr)
+{
+	m_Connection.Connect(pAddr);
+	return 0;
+}
+
+int CNetClient::ResetErrorString()
+{
+	m_Connection.ResetErrorString();
+	return 0;
+}
+
+int CNetClient::Recv(CNetChunk *pChunk)
+{
+	while(1)
+	{
+		/* check for a chunk */
+		if(m_RecvUnpacker.FetchChunk(pChunk))
+			return 1;
+		
+		/* TODO: empty the recvinfo */
+		NETADDR Addr;
+		int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE);
+
+		/* no more packets for now */
+		if(Bytes <= 0)
+			break;
+
+		if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0)
+		{
+			if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS)
+			{
+				pChunk->m_Flags = NETSENDFLAG_CONNLESS;
+				pChunk->m_ClientID = -1;
+				pChunk->m_Address = Addr;
+				pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize;
+				pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData;
+				return 1;
+			}
+			else
+			{
+				if(m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr))
+					m_RecvUnpacker.Start(&Addr, &m_Connection, 0);
+			}
+		}
+	}
+	return 0;
+}
+
+int CNetClient::Send(CNetChunk *pChunk)
+{
+	if(pChunk->m_DataSize >= NET_MAX_PAYLOAD)
+	{
+		dbg_msg("netclient", "chunk payload too big. %d. dropping chunk", pChunk->m_DataSize);
+		return -1;
+	}
+	
+	if(pChunk->m_Flags&NETSENDFLAG_CONNLESS)
+	{
+		/* send connectionless packet */
+		CNetBase::SendPacketConnless(m_Socket, &pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize);
+	}
+	else
+	{
+		int Flags = 0;
+		dbg_assert(pChunk->m_ClientID == 0, "errornous client id");
+		
+		if(pChunk->m_Flags&NETSENDFLAG_VITAL)
+			Flags = NET_CHUNKFLAG_VITAL;
+		
+		m_Connection.QueueChunk(Flags, pChunk->m_DataSize, pChunk->m_pData);
+
+		if(pChunk->m_Flags&NETSENDFLAG_FLUSH)
+			m_Connection.Flush();
+	}
+	return 0;
+}
+
+int CNetClient::State()
+{
+	if(m_Connection.State() == NET_CONNSTATE_ONLINE)
+		return NETSTATE_ONLINE;
+	if(m_Connection.State() == NET_CONNSTATE_OFFLINE)
+		return NETSTATE_OFFLINE;
+	return NETSTATE_CONNECTING;
+}
+
+int CNetClient::Flush()
+{
+	return m_Connection.Flush();
+}
+
+int CNetClient::GotProblems()
+{
+	if(time_get() - m_Connection.LastRecvTime() > time_freq())
+		return 1;
+	return 0;
+}
+
+const char *CNetClient::ErrorString()
+{
+	return m_Connection.ErrorString();
+}
diff --git a/src/engine/e_network_conn.c b/src/engine/e_network_conn.c
deleted file mode 100644
index 583dbe65..00000000
--- a/src/engine/e_network_conn.c
+++ /dev/null
@@ -1,366 +0,0 @@
-#include <base/system.h>
-#include <string.h>
-#include "e_config.h"
-#include "e_network_internal.h"
-
-static void conn_reset_stats(NETCONNECTION *conn)
-{
-	mem_zero(&conn->stats, sizeof(conn->stats));
-}
-
-static void conn_reset(NETCONNECTION *conn)
-{
-	conn->seq = 0;
-	conn->ack = 0;
-	conn->remote_closed = 0;
-	
-	conn->state = NET_CONNSTATE_OFFLINE;
-	conn->last_send_time = 0;
-	conn->last_recv_time = 0;
-	conn->last_update_time = 0;
-	conn->token = -1;
-	mem_zero(&conn->peeraddr, sizeof(conn->peeraddr));
-	
-	conn->buffer = ringbuf_init(conn->buffer_memory, sizeof(conn->buffer_memory), 0);
-	
-	mem_zero(&conn->construct, sizeof(conn->construct));
-}
-
-
-const char *conn_error(NETCONNECTION *conn)
-{
-	return conn->error_string;
-}
-
-static void conn_set_error(NETCONNECTION *conn, const char *str)
-{
-	str_copy(conn->error_string, str, sizeof(conn->error_string));
-}
-
-void conn_init(NETCONNECTION *conn, NETSOCKET socket)
-{
-	conn_reset(conn);
-	conn_reset_stats(conn);
-	conn->socket = socket;
-	mem_zero(conn->error_string, sizeof(conn->error_string));
-}
-
-
-static void conn_ack(NETCONNECTION *conn, int ack)
-{
-	
-	while(1)
-	{
-		NETCHUNKDATA *resend = (NETCHUNKDATA *)ringbuf_first(conn->buffer);
-		if(!resend)
-			break;
-		
-		if(seq_in_backroom(resend->sequence, ack))
-			ringbuf_popfirst(conn->buffer);
-		else
-			break;
-	}
-}
-
-void conn_want_resend(NETCONNECTION *conn)
-{
-	conn->construct.flags |= NET_PACKETFLAG_RESEND;
-}
-
-int conn_flush(NETCONNECTION *conn)
-{
-	int num_chunks = conn->construct.num_chunks;
-	if(!num_chunks && !conn->construct.flags)
-		return 0;
-
-	/* send of the packets */	
-	conn->construct.ack = conn->ack;
-	send_packet(conn->socket, &conn->peeraddr, &conn->construct);
-	
-	/* update send times */
-	conn->last_send_time = time_get();
-	
-	/* clear construct so we can start building a new package */
-	mem_zero(&conn->construct, sizeof(conn->construct));
-	return num_chunks;
-}
-
-static void conn_queue_chunk_ex(NETCONNECTION *conn, int flags, int data_size, const void *data, int sequence)
-{
-	unsigned char *chunk_data;
-	
-	/* check if we have space for it, if not, flush the connection */
-	if(conn->construct.data_size + data_size + NET_MAX_CHUNKHEADERSIZE > sizeof(conn->construct.chunk_data))
-		conn_flush(conn);
-
-	/* pack all the data */
-	chunk_data = &conn->construct.chunk_data[conn->construct.data_size];
-	chunk_data = pack_chunk_header(chunk_data, flags, data_size, sequence);
-	mem_copy(chunk_data, data, data_size);
-	chunk_data += data_size;
-
-	/* */
-	conn->construct.num_chunks++;
-	conn->construct.data_size = (int)(chunk_data-conn->construct.chunk_data);
-	
-	/* set packet flags aswell */
-	
-	if(flags&NET_CHUNKFLAG_VITAL && !(flags&NET_CHUNKFLAG_RESEND))
-	{
-		/* save packet if we need to resend */
-		NETCHUNKDATA *resend = (NETCHUNKDATA *)ringbuf_allocate(conn->buffer, sizeof(NETCHUNKDATA)+data_size);
-		if(resend)
-		{
-			resend->sequence = sequence;
-			resend->flags = flags;
-			resend->data_size = data_size;
-			resend->data = (unsigned char *)(resend+1);
-			resend->first_send_time = time_get();
-			resend->last_send_time = resend->first_send_time;
-			mem_copy(resend->data, data, data_size);
-		}
-		else
-		{
-			/* out of buffer */
-			conn_disconnect(conn, "too weak connection (out of buffer)");
-		}
-	}
-}
-
-void conn_queue_chunk(NETCONNECTION *conn, int flags, int data_size, const void *data)
-{
-	if(flags&NET_CHUNKFLAG_VITAL)
-		conn->seq = (conn->seq+1)%NET_MAX_SEQUENCE;
-	conn_queue_chunk_ex(conn, flags, data_size, data, conn->seq);
-}
-
-
-static void conn_send_control(NETCONNECTION *conn, int controlmsg, const void *extra, int extra_size)
-{
-	/* send the control message */
-	conn->last_send_time = time_get();
-	send_controlmsg(conn->socket, &conn->peeraddr, conn->ack, controlmsg, extra, extra_size);
-}
-
-static void conn_resend_chunk(NETCONNECTION *conn, NETCHUNKDATA *resend)
-{
-	conn_queue_chunk_ex(conn, resend->flags|NET_CHUNKFLAG_RESEND, resend->data_size, resend->data, resend->sequence);
-	resend->last_send_time = time_get();
-}
-
-static void conn_resend(NETCONNECTION *conn)
-{
-	int resend_count = 0;
-	int first = 0, last = 0;
-	void *item = ringbuf_first(conn->buffer);
-	
-	while(item)
-	{
-		NETCHUNKDATA *resend = item;
-		
-		if(resend_count == 0)
-			first = resend->sequence;
-		last = resend->sequence;
-			
-		conn_resend_chunk(conn, resend);
-		item = ringbuf_next(conn->buffer, item);
-		resend_count++;
-	}
-	
-	if(config.debug)
-		dbg_msg("conn", "resent %d packets (%d to %d)", resend_count, first, last);
-}
-
-int conn_connect(NETCONNECTION *conn, NETADDR *addr)
-{
-	if(conn->state != NET_CONNSTATE_OFFLINE)
-		return -1;
-	
-	/* init connection */
-	conn_reset(conn);
-	conn->peeraddr = *addr;
-	mem_zero(conn->error_string, sizeof(conn->error_string));
-	conn->state = NET_CONNSTATE_CONNECT;
-	conn_send_control(conn, NET_CTRLMSG_CONNECT, 0, 0);
-	return 0;
-}
-
-void conn_disconnect(NETCONNECTION *conn, const char *reason)
-{
-	if(conn->state == NET_CONNSTATE_OFFLINE)
-		return;
-
-	if(conn->remote_closed == 0)
-	{
-		if(reason)
-			conn_send_control(conn, NET_CTRLMSG_CLOSE, reason, strlen(reason)+1);
-		else
-			conn_send_control(conn, NET_CTRLMSG_CLOSE, 0, 0);
-
-		conn->error_string[0] = 0;
-		if(reason)
-			str_copy(conn->error_string, reason, sizeof(conn->error_string));
-	}
-	
-	conn_reset(conn);
-}
-
-int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *addr)
-{
-	int64 now = time_get();
-	conn->last_recv_time = now;
-	
-	/* check if resend is requested */
-	if(packet->flags&NET_PACKETFLAG_RESEND)
-		conn_resend(conn);
-
-	/* */									
-	if(packet->flags&NET_PACKETFLAG_CONTROL)
-	{
-		int ctrlmsg = packet->chunk_data[0];
-		
-		if(ctrlmsg == NET_CTRLMSG_CLOSE)
-		{
-			conn->state = NET_CONNSTATE_ERROR;
-			conn->remote_closed = 1;
-			
-			if(packet->data_size)
-			{
-				/* make sure to sanitize the error string form the other party*/
-				char str[128];
-				if(packet->data_size < 128)
-					str_copy(str, (char *)packet->chunk_data, packet->data_size);
-				else
-					str_copy(str, (char *)packet->chunk_data, 128);
-				str_sanitize_strong(str);
-				
-				/* set the error string */
-				conn_set_error(conn, str);
-			}
-			else
-				conn_set_error(conn, "no reason given");
-				
-			if(config.debug)
-				dbg_msg("conn", "closed reason='%s'", conn_error(conn));
-			return 0;			
-		}
-		else
-		{
-			if(conn->state == NET_CONNSTATE_OFFLINE)
-			{
-				if(ctrlmsg == NET_CTRLMSG_CONNECT)
-				{
-					/* send response and init connection */
-					conn_reset(conn);
-					conn->state = NET_CONNSTATE_PENDING;
-					conn->peeraddr = *addr;
-					conn->last_send_time = now;
-					conn->last_recv_time = now;
-					conn->last_update_time = now;
-					conn_send_control(conn, NET_CTRLMSG_CONNECTACCEPT, 0, 0);
-					if(config.debug)
-						dbg_msg("connection", "got connection, sending connect+accept");			
-				}
-			}
-			else if(conn->state == NET_CONNSTATE_CONNECT)
-			{
-				/* connection made */
-				if(ctrlmsg == NET_CTRLMSG_CONNECTACCEPT)
-				{
-					conn_send_control(conn, NET_CTRLMSG_ACCEPT, 0, 0);
-					conn->state = NET_CONNSTATE_ONLINE;
-					if(config.debug)
-						dbg_msg("connection", "got connect+accept, sending accept. connection online");
-				}
-			}
-			else if(conn->state == NET_CONNSTATE_ONLINE)
-			{
-				/* connection made */
-				/*
-				if(ctrlmsg == NET_CTRLMSG_CONNECTACCEPT)
-				{
-					
-				}*/
-			}
-		}
-	}
-	else
-	{
-		if(conn->state == NET_CONNSTATE_PENDING)
-		{
-			conn->state = NET_CONNSTATE_ONLINE;
-			if(config.debug)
-				dbg_msg("connection", "connecting online");
-		}
-	}
-	
-	if(conn->state == NET_CONNSTATE_ONLINE)
-	{
-		
-		conn_ack(conn, packet->ack);
-	}
-	
-	return 1;
-}
-
-int conn_update(NETCONNECTION *conn)
-{
-	int64 now = time_get();
-
-	if(conn->state == NET_CONNSTATE_OFFLINE || conn->state == NET_CONNSTATE_ERROR)
-		return 0;
-	
-	/* check for timeout */
-	if(conn->state != NET_CONNSTATE_OFFLINE &&
-		conn->state != NET_CONNSTATE_CONNECT &&
-		(now-conn->last_recv_time) > time_freq()*10)
-	{
-		conn->state = NET_CONNSTATE_ERROR;
-		conn_set_error(conn, "timeout");
-	}
-
-	/* fix resends */
-	if(ringbuf_first(conn->buffer))
-	{
-		NETCHUNKDATA *resend = (NETCHUNKDATA *)ringbuf_first(conn->buffer);
-
-		/* check if we have some really old stuff laying around and abort if not acked */
-		if(now-resend->first_send_time > time_freq()*10)
-		{
-			conn->state = NET_CONNSTATE_ERROR;
-			conn_set_error(conn, "too weak connection (not acked for 10 seconds)");
-		}
-		else
-		{
-			/* resend packet if we havn't got it acked in 1 second */
-			if(now-resend->last_send_time > time_freq())
-				conn_resend_chunk(conn, resend);
-		}
-	}
-	
-	/* send keep alives if nothing has happend for 250ms */
-	if(conn->state == NET_CONNSTATE_ONLINE)
-	{
-		if(time_get()-conn->last_send_time > time_freq()/2) /* flush connection after 500ms if needed */
-		{
-			int num_flushed_chunks = conn_flush(conn);
-			if(num_flushed_chunks && config.debug)
-				dbg_msg("connection", "flushed connection due to timeout. %d chunks.", num_flushed_chunks);
-		}
-			
-		if(time_get()-conn->last_send_time > time_freq())
-			conn_send_control(conn, NET_CTRLMSG_KEEPALIVE, 0, 0);
-	}
-	else if(conn->state == NET_CONNSTATE_CONNECT)
-	{
-		if(time_get()-conn->last_send_time > time_freq()/2) /* send a new connect every 500ms */
-			conn_send_control(conn, NET_CTRLMSG_CONNECT, 0, 0);
-	}
-	else if(conn->state == NET_CONNSTATE_PENDING)
-	{
-		if(time_get()-conn->last_send_time > time_freq()/2) /* send a new connect/accept every 500ms */
-			conn_send_control(conn, NET_CTRLMSG_CONNECTACCEPT, 0, 0);
-	}
-	
-	return 0;
-}
diff --git a/src/engine/e_network_conn.cpp b/src/engine/e_network_conn.cpp
new file mode 100644
index 00000000..a54c9ce3
--- /dev/null
+++ b/src/engine/e_network_conn.cpp
@@ -0,0 +1,349 @@
+#include <base/system.h>
+#include <string.h>
+#include "e_config.h"
+#include "e_network.h"
+
+void CNetConnection::ResetStats()
+{
+	mem_zero(&m_Stats, sizeof(m_Stats));
+}
+
+void CNetConnection::Reset()
+{
+	m_Sequence = 0;
+	m_Ack = 0;
+	m_RemoteClosed = 0;
+	
+	m_State = NET_CONNSTATE_OFFLINE;
+	m_LastSendTime = 0;
+	m_LastRecvTime = 0;
+	m_LastUpdateTime = 0;
+	m_Token = -1;
+	mem_zero(&m_PeerAddr, sizeof(m_PeerAddr));
+	
+	m_Buffer.Init();
+	
+	mem_zero(&m_Construct, sizeof(m_Construct));
+}
+
+const char *CNetConnection::ErrorString()
+{
+	return m_ErrorString;
+}
+
+void CNetConnection::SetError(const char *pString)
+{
+	str_copy(m_ErrorString, pString, sizeof(m_ErrorString));
+}
+
+void CNetConnection::Init(NETSOCKET Socket)
+{
+	Reset();
+	ResetStats();
+	
+	m_Socket = Socket;
+	mem_zero(m_ErrorString, sizeof(m_ErrorString));
+}
+
+void CNetConnection::AckChunks(int Ack)
+{
+	while(1)
+	{
+		CNetChunkResend *pResend = m_Buffer.First();
+		if(!pResend)
+			break;
+		
+		if(CNetBase::IsSeqInBackroom(pResend->m_Sequence, Ack))
+			m_Buffer.PopFirst();
+		else
+			break;
+	}
+}
+
+void CNetConnection::SignalResend()
+{
+	m_Construct.m_Flags |= NET_PACKETFLAG_RESEND;
+}
+
+int CNetConnection::Flush()
+{
+	int NumChunks = m_Construct.m_NumChunks;
+	if(!NumChunks && !m_Construct.m_Flags)
+		return 0;
+
+	/* send of the packets */	
+	m_Construct.m_Ack = m_Ack;
+	CNetBase::SendPacket(m_Socket, &m_PeerAddr, &m_Construct);
+	
+	/* update send times */
+	m_LastSendTime = time_get();
+	
+	/* clear construct so we can start building a new package */
+	mem_zero(&m_Construct, sizeof(m_Construct));
+	return NumChunks;
+}
+
+void CNetConnection::QueueChunkEx(int Flags, int DataSize, const void *pData, int Sequence)
+{
+	unsigned char *pChunkData;
+	
+	/* check if we have space for it, if not, flush the connection */
+	if(m_Construct.m_DataSize + DataSize + NET_MAX_CHUNKHEADERSIZE > (int)sizeof(m_Construct.m_aChunkData))
+		Flush();
+
+	/* pack all the data */
+	CNetChunkHeader Header;
+	Header.m_Flags = Flags;
+	Header.m_Size = DataSize;
+	Header.m_Sequence = Sequence;
+	pChunkData = &m_Construct.m_aChunkData[m_Construct.m_DataSize];
+	pChunkData = Header.Pack(pChunkData);
+	mem_copy(pChunkData, pData, DataSize);
+	pChunkData += DataSize;
+
+	/* */
+	m_Construct.m_NumChunks++;
+	m_Construct.m_DataSize = (int)(pChunkData-m_Construct.m_aChunkData);
+	
+	/* set packet flags aswell */
+	
+	if(Flags&NET_CHUNKFLAG_VITAL && !(Flags&NET_CHUNKFLAG_RESEND))
+	{
+		/* save packet if we need to resend */
+		CNetChunkResend *pResend = m_Buffer.Allocate(sizeof(CNetChunkResend)+DataSize);
+		if(pResend)
+		{
+			pResend->m_Sequence = Sequence;
+			pResend->m_Flags = Flags;
+			pResend->m_DataSize = DataSize;
+			pResend->m_pData = (unsigned char *)(pResend+1);
+			pResend->m_FirstSendTime = time_get();
+			pResend->m_LastSendTime = pResend->m_FirstSendTime;
+			mem_copy(pResend->m_pData, pData, DataSize);
+		}
+		else
+		{
+			/* out of buffer */
+			Disconnect("too weak connection (out of buffer)");
+		}
+	}
+}
+
+void CNetConnection::QueueChunk(int Flags, int DataSize, const void *pData)
+{
+	if(Flags&NET_CHUNKFLAG_VITAL)
+		m_Sequence = (m_Sequence+1)%NET_MAX_SEQUENCE;
+	QueueChunkEx(Flags, DataSize, pData, m_Sequence);
+}
+
+void CNetConnection::SendControl(int ControlMsg, const void *pExtra, int ExtraSize)
+{
+	/* send the control message */
+	m_LastSendTime = time_get();
+	CNetBase::SendControlMsg(m_Socket, &m_PeerAddr, m_Ack, ControlMsg, pExtra, ExtraSize);
+}
+
+void CNetConnection::ResendChunk(CNetChunkResend *pResend)
+{
+	QueueChunkEx(pResend->m_Flags|NET_CHUNKFLAG_RESEND, pResend->m_DataSize, pResend->m_pData, pResend->m_Sequence);
+	pResend->m_LastSendTime = time_get();
+}
+
+void CNetConnection::Resend()
+{
+	for(CNetChunkResend *pResend = m_Buffer.First(); pResend; m_Buffer.Next(pResend))
+		ResendChunk(pResend);
+}
+
+int CNetConnection::Connect(NETADDR *pAddr)
+{
+	if(State() != NET_CONNSTATE_OFFLINE)
+		return -1;
+	
+	/* init connection */
+	Reset();
+	m_PeerAddr = *pAddr;
+	mem_zero(m_ErrorString, sizeof(m_ErrorString));
+	m_State = NET_CONNSTATE_CONNECT;
+	SendControl(NET_CTRLMSG_CONNECT, 0, 0);
+	return 0;
+}
+
+void CNetConnection::Disconnect(const char *pReason)
+{
+	if(State() == NET_CONNSTATE_OFFLINE)
+		return;
+
+	if(m_RemoteClosed == 0)
+	{
+		if(pReason)
+			SendControl(NET_CTRLMSG_CLOSE, pReason, strlen(pReason)+1);
+		else
+			SendControl(NET_CTRLMSG_CLOSE, 0, 0);
+
+		m_ErrorString[0] = 0;
+		if(pReason)
+			str_copy(m_ErrorString, pReason, sizeof(m_ErrorString));
+	}
+	
+	Reset();
+}
+
+int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr)
+{
+	int64 now = time_get();
+	m_LastRecvTime = now;
+	
+	/* check if resend is requested */
+	if(pPacket->m_Flags&NET_PACKETFLAG_RESEND)
+		Resend();
+
+	/* */									
+	if(pPacket->m_Flags&NET_PACKETFLAG_CONTROL)
+	{
+		int CtrlMsg = pPacket->m_aChunkData[0];
+		
+		if(CtrlMsg == NET_CTRLMSG_CLOSE)
+		{
+			m_State = NET_CONNSTATE_ERROR;
+			m_RemoteClosed = 1;
+			
+			if(pPacket->m_DataSize)
+			{
+				/* make sure to sanitize the error string form the other party*/
+				char Str[128];
+				if(pPacket->m_DataSize < 128)
+					str_copy(Str, (char *)pPacket->m_aChunkData, pPacket->m_DataSize);
+				else
+					str_copy(Str, (char *)pPacket->m_aChunkData, sizeof(Str));
+				str_sanitize_strong(Str);
+				
+				/* set the error string */
+				SetError(Str);
+			}
+			else
+				SetError("no reason given");
+				
+			if(config.debug)
+				dbg_msg("conn", "closed reason='%s'", ErrorString());
+			return 0;			
+		}
+		else
+		{
+			if(State() == NET_CONNSTATE_OFFLINE)
+			{
+				if(CtrlMsg == NET_CTRLMSG_CONNECT)
+				{
+					/* send response and init connection */
+					Reset();
+					m_State = NET_CONNSTATE_PENDING;
+					m_PeerAddr = *pAddr;
+					m_LastSendTime = now;
+					m_LastRecvTime = now;
+					m_LastUpdateTime = now;
+					SendControl(NET_CTRLMSG_CONNECTACCEPT, 0, 0);
+					if(config.debug)
+						dbg_msg("connection", "got connection, sending connect+accept");			
+				}
+			}
+			else if(State() == NET_CONNSTATE_CONNECT)
+			{
+				/* connection made */
+				if(CtrlMsg == NET_CTRLMSG_CONNECTACCEPT)
+				{
+					SendControl(NET_CTRLMSG_ACCEPT, 0, 0);
+					m_State = NET_CONNSTATE_ONLINE;
+					if(config.debug)
+						dbg_msg("connection", "got connect+accept, sending accept. connection online");
+				}
+			}
+			else if(State() == NET_CONNSTATE_ONLINE)
+			{
+				/* connection made */
+				/*
+				if(ctrlmsg == NET_CTRLMSG_CONNECTACCEPT)
+				{
+					
+				}*/
+			}
+		}
+	}
+	else
+	{
+		if(State() == NET_CONNSTATE_PENDING)
+		{
+			m_State = NET_CONNSTATE_ONLINE;
+			if(config.debug)
+				dbg_msg("connection", "connecting online");
+		}
+	}
+	
+	if(State() == NET_CONNSTATE_ONLINE)
+	{
+		AckChunks(pPacket->m_Ack);
+	}
+	
+	return 1;
+}
+
+int CNetConnection::Update()
+{
+	int64 now = time_get();
+
+	if(State() == NET_CONNSTATE_OFFLINE || State() == NET_CONNSTATE_ERROR)
+		return 0;
+	
+	/* check for timeout */
+	if(State() != NET_CONNSTATE_OFFLINE &&
+		State() != NET_CONNSTATE_CONNECT &&
+		(now-m_LastRecvTime) > time_freq()*10)
+	{
+		m_State = NET_CONNSTATE_ERROR;
+		SetError("timeout");
+	}
+
+	/* fix resends */
+	if(m_Buffer.First())
+	{
+		CNetChunkResend *pResend = m_Buffer.First();
+
+		/* check if we have some really old stuff laying around and abort if not acked */
+		if(now-pResend->m_FirstSendTime > time_freq()*10)
+		{
+			m_State = NET_CONNSTATE_ERROR;
+			SetError("too weak connection (not acked for 10 seconds)");
+		}
+		else
+		{
+			/* resend packet if we havn't got it acked in 1 second */
+			if(now-pResend->m_LastSendTime > time_freq())
+				ResendChunk(pResend);
+		}
+	}
+	
+	/* send keep alives if nothing has happend for 250ms */
+	if(State() == NET_CONNSTATE_ONLINE)
+	{
+		if(time_get()-m_LastSendTime > time_freq()/2) /* flush connection after 500ms if needed */
+		{
+			int NumFlushedChunks = Flush();
+			if(NumFlushedChunks && config.debug)
+				dbg_msg("connection", "flushed connection due to timeout. %d chunks.", NumFlushedChunks);
+		}
+			
+		if(time_get()-m_LastSendTime > time_freq())
+			SendControl(NET_CTRLMSG_KEEPALIVE, 0, 0);
+	}
+	else if(State() == NET_CONNSTATE_CONNECT)
+	{
+		if(time_get()-m_LastSendTime > time_freq()/2) /* send a new connect every 500ms */
+			SendControl(NET_CTRLMSG_CONNECT, 0, 0);
+	}
+	else if(State() == NET_CONNSTATE_PENDING)
+	{
+		if(time_get()-m_LastSendTime > time_freq()/2) /* send a new connect/accept every 500ms */
+			SendControl(NET_CTRLMSG_CONNECTACCEPT, 0, 0);
+	}
+	
+	return 0;
+}
diff --git a/src/engine/e_network_internal.h b/src/engine/e_network_internal.h
deleted file mode 100644
index f1a25b31..00000000
--- a/src/engine/e_network_internal.h
+++ /dev/null
@@ -1,156 +0,0 @@
-#include <base/system.h>
-#include "e_network.h"
-#include "e_ringbuffer.h"
-
-/*
-
-CURRENT:
-	packet header: 3 bytes
-		unsigned char flags_ack; // 4bit flags, 4bit ack
-		unsigned char ack; // 8 bit ack
-		unsigned char num_chunks; // 8 bit chunks
-		
-		(unsigned char padding[3])	// 24 bit extra incase it's a connection less packet
-									// this is to make sure that it's compatible with the
-									// old protocol
-
-	chunk header: 2-3 bytes
-		unsigned char flags_size; // 2bit flags, 6 bit size
-		unsigned char size_seq; // 4bit size, 4bit seq
-		(unsigned char seq;) // 8bit seq, if vital flag is set
-
-
-*/
-
-enum
-{
-	NET_VERSION = 2,
-
-	NET_MAX_CHUNKSIZE = 1024,
-	NET_MAX_PAYLOAD = NET_MAX_CHUNKSIZE+16,
-	NET_MAX_PACKETSIZE = NET_MAX_PAYLOAD+16,
-	NET_MAX_CHUNKHEADERSIZE = 5,
-	NET_PACKETHEADERSIZE = 3,
-	NET_MAX_CLIENTS = 16,
-	NET_MAX_SEQUENCE = 1<<10,
-	NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1,
-
-	NET_CONNSTATE_OFFLINE=0,
-	NET_CONNSTATE_CONNECT=1,
-	NET_CONNSTATE_PENDING=2,
-	NET_CONNSTATE_ONLINE=3,
-	NET_CONNSTATE_ERROR=4,
-
-	NET_PACKETFLAG_CONTROL=1,
-	NET_PACKETFLAG_CONNLESS=2,
-	NET_PACKETFLAG_RESEND=4,
-	NET_PACKETFLAG_COMPRESSION=8,
-
-	NET_CHUNKFLAG_VITAL=1,
-	NET_CHUNKFLAG_RESEND=2,
-	
-	NET_CTRLMSG_KEEPALIVE=0,
-	NET_CTRLMSG_CONNECT=1,
-	NET_CTRLMSG_CONNECTACCEPT=2,
-	NET_CTRLMSG_ACCEPT=3,
-	NET_CTRLMSG_CLOSE=4,
-	
-	NET_SERVER_MAXBANS=1024,
-	
-	NET_CONN_BUFFERSIZE=1024*16,
-	
-	NET_ENUM_TERMINATOR
-};
-
-
-typedef struct NETPACKETCONSTRUCT
-{
-	int flags;
-	int ack;
-	int num_chunks;
-	int data_size;
-	unsigned char chunk_data[NET_MAX_PAYLOAD];
-} NETPACKETCONSTRUCT;
-
-typedef struct NETCHUNKHEADER
-{
-	int flags;
-	int size;
-	int sequence;
-} NETCHUNKHEADER;
-
-typedef struct
-{
-	int flags;
-	int data_size;
-	unsigned char *data;
-
-	int sequence;
-	int64 last_send_time;
-	int64 first_send_time;
-} NETCHUNKDATA;
-
-typedef struct
-{
-	unsigned short seq;
-	unsigned short ack;
-	unsigned state;
-	
-	int token;
-	int remote_closed;
-	
-	RINGBUFFER *buffer;
-	
-	int64 last_update_time;
-	int64 last_recv_time;
-	int64 last_send_time;
-	
-	char error_string[256];
-	
-	NETPACKETCONSTRUCT construct;
-	
-	NETADDR peeraddr;
-	NETSOCKET socket;
-	NETSTATS stats;
-
-	char buffer_memory[NET_CONN_BUFFERSIZE];
-} NETCONNECTION;
-
-typedef struct NETRECVINFO
-{
-	NETADDR addr;
-	NETCONNECTION *conn;
-	int current_chunk;
-	int client_id;
-	int valid;
-	NETPACKETCONSTRUCT data;
-	unsigned char buffer[NET_MAX_PACKETSIZE];
-} NETRECVINFO;
-
-/* */
-
-/* connection functions */
-void conn_init(NETCONNECTION *conn, NETSOCKET socket);
-int conn_connect(NETCONNECTION *conn, NETADDR *addr);
-void conn_disconnect(NETCONNECTION *conn, const char *reason);
-int conn_update(NETCONNECTION *conn);
-int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *addr);
-void conn_queue_chunk(NETCONNECTION *conn, int flags, int data_size, const void *data);
-const char *conn_error(NETCONNECTION *conn);
-void conn_want_resend(NETCONNECTION *conn);
-int conn_flush(NETCONNECTION *conn);
-
-/* recvinfo functions */
-void recvinfo_clear(NETRECVINFO *info);
-void recvinfo_start(NETRECVINFO *info, NETADDR *addr, NETCONNECTION *conn, int cid);
-int recvinfo_fetch_chunk(NETRECVINFO *info, NETCHUNK *chunk);
-
-/* misc helper functions */
-/* The backroom is ack-NET_MAX_SEQUENCE/2. Used for knowing if we acked a packet or not */
-int seq_in_backroom(int seq, int ack);
-void send_controlmsg(NETSOCKET socket, NETADDR *addr, int ack, int controlmsg, const void *extra, int extra_size);
-void send_packet_connless(NETSOCKET socket, NETADDR *addr, const void *data, int data_size);
-void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet);
-int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *packet);
-unsigned char *pack_chunk_header(unsigned char *data, int flags, int size, int sequence);
-unsigned char *unpack_chunk_header(unsigned char *data, NETCHUNKHEADER *header);
diff --git a/src/engine/e_network_server.c b/src/engine/e_network_server.c
deleted file mode 100644
index 8ec65504..00000000
--- a/src/engine/e_network_server.c
+++ /dev/null
@@ -1,484 +0,0 @@
-#include <base/system.h>
-#include "e_network.h"
-#include "e_network_internal.h"
-
-typedef struct
-{
-	NETCONNECTION conn;
-} NETSLOT;
-
-typedef struct NETBAN
-{
-	NETBANINFO info;
-	
-	/* hash list */
-	struct NETBAN *hashnext;
-	struct NETBAN *hashprev;
-	
-	/* used or free list */
-	struct NETBAN *next;
-	struct NETBAN *prev;
-} NETBAN;
-
-#define MACRO_LIST_LINK_FIRST(object, first, prev, next) \
-	{ if(first) first->prev = object; \
-	object->prev = (void*)0; \
-	object->next = first; \
-	first = object; }
-	
-#define MACRO_LIST_LINK_AFTER(object, after, prev, next) \
-	{ object->prev = after; \
-	object->next = after->next; \
-	after->next = object; \
-	if(object->next) \
-		object->next->prev = object; \
-	}
-
-#define MACRO_LIST_UNLINK(object, first, prev, next) \
-	{ if(object->next) object->next->prev = object->prev; \
-	if(object->prev) object->prev->next = object->next; \
-	else first = object->next; \
-	object->next = 0; object->prev = 0; }
-	
-#define MACRO_LIST_FIND(start, next, expression) \
-	{ while(start && !(expression)) start = start->next; }
-
-struct NETSERVER
-{
-	NETSOCKET socket;
-	NETSLOT slots[NET_MAX_CLIENTS];
-	int max_clients;
-
-	NETBAN *bans[256];
-	NETBAN banpool[NET_SERVER_MAXBANS];
-	NETBAN *banpool_firstfree;
-	NETBAN *banpool_firstused;
-
-	NETFUNC_NEWCLIENT new_client;
-	NETFUNC_NEWCLIENT del_client;
-	void *user_ptr;
-	
-	NETRECVINFO recv;
-};
-
-NETSERVER *netserver_open(NETADDR bindaddr, int max_clients, int flags)
-{
-	int i;
-	NETSERVER *server;
-	NETSOCKET socket = net_udp_create(bindaddr);
-	if(socket == NETSOCKET_INVALID)
-		return 0;
-	
-	server = (NETSERVER *)mem_alloc(sizeof(NETSERVER), 1);
-	mem_zero(server, sizeof(NETSERVER));
-	server->socket = socket;
-	server->max_clients = max_clients;
-	if(server->max_clients > NET_MAX_CLIENTS)
-		server->max_clients = NET_MAX_CLIENTS;
-	if(server->max_clients < 1)
-		server->max_clients = 1;
-	
-	for(i = 0; i < NET_MAX_CLIENTS; i++)
-		conn_init(&server->slots[i].conn, server->socket);
-	
-	/* setup all pointers for bans */
-	for(i = 1; i < NET_SERVER_MAXBANS-1; i++)
-	{
-		server->banpool[i].next = &server->banpool[i+1];
-		server->banpool[i].prev = &server->banpool[i-1];
-	}
-	
-	server->banpool[0].next = &server->banpool[1];
-	server->banpool[NET_SERVER_MAXBANS-1].prev = &server->banpool[NET_SERVER_MAXBANS-2];
-	server->banpool_firstfree = &server->banpool[0];
-
-	return server;
-}
-
-int netserver_set_callbacks(NETSERVER *s, NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user)
-{
-	s->new_client = new_client;
-	s->del_client = del_client;
-	s->user_ptr = user;
-	return 0;
-}
-
-int netserver_max_clients(NETSERVER *s)
-{
-	return s->max_clients;
-}
-
-int netserver_close(NETSERVER *s)
-{
-	/* TODO: implement me */
-	return 0;
-}
-
-int netserver_drop(NETSERVER *s, int client_id, const char *reason)
-{
-	/* TODO: insert lots of checks here */
-	NETADDR addr;
-	netserver_client_addr(s, client_id, &addr);
-	
-	dbg_msg("net_server", "client dropped. cid=%d ip=%d.%d.%d.%d reason=\"%s\"",
-		client_id,
-		addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3],
-		reason
-		);
-	conn_disconnect(&s->slots[client_id].conn, reason);
-
-	if(s->del_client)
-		s->del_client(client_id, s->user_ptr);
-		
-	return 0;
-}
-
-int netserver_ban_get(NETSERVER *s, int index, NETBANINFO *info)
-{
-	NETBAN *ban;
-	for(ban = s->banpool_firstused; ban && index; ban = ban->next, index--)
-		{}
-		
-	if(!ban)
-		return 0;
-	*info = ban->info;
-	return 1;
-}
-
-int netserver_ban_num(NETSERVER *s)
-{
-	int count = 0;
-	NETBAN *ban;
-	for(ban = s->banpool_firstused; ban; ban = ban->next)
-		count++;
-	return count;
-}
-
-static void netserver_ban_remove_by_object(NETSERVER *s, NETBAN *ban)
-{
-	int iphash = (ban->info.addr.ip[0]+ban->info.addr.ip[1]+ban->info.addr.ip[2]+ban->info.addr.ip[3])&0xff;
-	dbg_msg("netserver", "removing ban on %d.%d.%d.%d",
-		ban->info.addr.ip[0], ban->info.addr.ip[1], ban->info.addr.ip[2], ban->info.addr.ip[3]);
-	MACRO_LIST_UNLINK(ban, s->banpool_firstused, prev, next);
-	MACRO_LIST_UNLINK(ban, s->bans[iphash], hashprev, hashnext);
-	MACRO_LIST_LINK_FIRST(ban, s->banpool_firstfree, prev, next);
-}
-
-int netserver_ban_remove(NETSERVER *s, NETADDR addr)
-{
-	int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
-	NETBAN *ban = s->bans[iphash];
-	
-	MACRO_LIST_FIND(ban, hashnext, net_addr_comp(&ban->info.addr, &addr) == 0);
-	
-	if(ban)
-	{
-		netserver_ban_remove_by_object(s, ban);
-		return 0;
-	}
-	
-	return -1;
-}
-
-int netserver_ban_add(NETSERVER *s, NETADDR addr, int seconds)
-{
-	int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
-	unsigned stamp = 0xffffffff;
-	NETBAN *ban;
-	
-	/* remove the port */
-	addr.port = 0;
-	
-	if(seconds)
-		stamp = time_timestamp() + seconds;
-		
-	/* search to see if it already exists */
-	ban = s->bans[iphash];
-	MACRO_LIST_FIND(ban, hashnext, net_addr_comp(&ban->info.addr, &addr) == 0);
-	if(ban)
-	{
-		/* adjust the ban */
-		ban->info.expires = stamp;
-		return 0;
-	}
-	
-	if(!s->banpool_firstfree)
-		return -1;
-
-	/* fetch and clear the new ban */
-	ban = s->banpool_firstfree;
-	MACRO_LIST_UNLINK(ban, s->banpool_firstfree, prev, next);
-	
-	/* setup the ban info */
-	ban->info.expires = stamp;
-	ban->info.addr = addr;
-	
-	/* add it to the ban hash */
-	MACRO_LIST_LINK_FIRST(ban, s->bans[iphash], hashprev, hashnext);
-	
-	/* insert it into the used list */
-	{
-		if(s->banpool_firstused)
-		{
-			NETBAN *insert_after = s->banpool_firstused;
-			MACRO_LIST_FIND(insert_after, next, stamp < insert_after->info.expires);
-			
-			if(insert_after)
-				insert_after = insert_after->prev;
-			else
-			{
-				/* add to last */
-				insert_after = s->banpool_firstused;
-				while(insert_after->next)
-					insert_after = insert_after->next;
-			}
-			
-			if(insert_after)
-			{
-				MACRO_LIST_LINK_AFTER(ban, insert_after, prev, next);
-			}
-			else
-			{
-				MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next);
-			}
-		}
-		else
-		{
-			MACRO_LIST_LINK_FIRST(ban, s->banpool_firstused, prev, next);
-		}
-	}
-
-	/* drop banned clients */	
-	{
-		char buf[128];
-		int i;
-		NETADDR banaddr;
-		
-		if(seconds)
-			str_format(buf, sizeof(buf), "you have been banned for %d minutes", seconds/60);
-		else
-			str_format(buf, sizeof(buf), "you have been banned for life");
-		
-		for(i = 0; i < s->max_clients; i++)
-		{
-			banaddr = s->slots[i].conn.peeraddr;
-			banaddr.port = 0;
-			
-			if(net_addr_comp(&addr, &banaddr) == 0)
-				netserver_drop(s, i, buf);
-		}
-	}
-	return 0;
-}
-
-int netserver_update(NETSERVER *s)
-{
-	unsigned now = time_timestamp();
-	
-	int i;
-	for(i = 0; i < s->max_clients; i++)
-	{
-		conn_update(&s->slots[i].conn);
-		if(s->slots[i].conn.state == NET_CONNSTATE_ERROR)
-			netserver_drop(s, i, conn_error(&s->slots[i].conn));
-	}
-	
-	/* remove expired bans */
-	while(s->banpool_firstused && s->banpool_firstused->info.expires < now)
-	{
-		NETBAN *ban = s->banpool_firstused;
-		netserver_ban_remove_by_object(s, ban);
-	}
-	
-	(void)now;
-	
-	return 0;
-}
-
-/*
-	TODO: chopp up this function into smaller working parts
-*/
-int netserver_recv(NETSERVER *s, NETCHUNK *chunk)
-{
-	unsigned now = time_timestamp();
-	
-	while(1)
-	{
-		NETADDR addr;
-		int i, bytes, found;
-			
-		/* check for a chunk */
-		if(recvinfo_fetch_chunk(&s->recv, chunk))
-			return 1;
-		
-		/* TODO: empty the recvinfo */
-		bytes = net_udp_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE);
-
-		/* no more packets for now */
-		if(bytes <= 0)
-			break;
-		
-		if(unpack_packet(s->recv.buffer, bytes, &s->recv.data) == 0)
-		{
-			NETBAN *ban = 0;
-			NETADDR banaddr = addr;
-			int iphash = (addr.ip[0]+addr.ip[1]+addr.ip[2]+addr.ip[3])&0xff;
-			found = 0;
-			banaddr.port = 0;
-			
-			/* search a ban */
-			for(ban = s->bans[iphash]; ban; ban = ban->hashnext)
-			{
-				if(net_addr_comp(&ban->info.addr, &banaddr) == 0)
-					break;
-			}
-			
-			/* check if we just should drop the packet */
-			if(ban)
-			{
-				// banned, reply with a message
-				char banstr[128];
-				if(ban->info.expires)
-				{
-					int mins = ((ban->info.expires - now)+59)/60;
-					if(mins == 1)
-						str_format(banstr, sizeof(banstr), "banned for %d minute", mins);
-					else
-						str_format(banstr, sizeof(banstr), "banned for %d minutes", mins);
-				}
-				else
-					str_format(banstr, sizeof(banstr), "banned for life");
-				send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, banstr, str_length(banstr)+1);
-				continue;
-			}
-			
-			if(s->recv.data.flags&NET_PACKETFLAG_CONNLESS)
-			{
-				chunk->flags = NETSENDFLAG_CONNLESS;
-				chunk->client_id = -1;
-				chunk->address = addr;
-				chunk->data_size = s->recv.data.data_size;
-				chunk->data = s->recv.data.chunk_data;
-				return 1;
-			}
-			else
-			{			
-				/* TODO: check size here */
-				if(s->recv.data.flags&NET_PACKETFLAG_CONTROL && s->recv.data.chunk_data[0] == NET_CTRLMSG_CONNECT)
-				{
-					found = 0;
-				
-					/* check if we already got this client */
-					for(i = 0; i < s->max_clients; i++)
-					{
-						if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE &&
-							net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
-						{
-							found = 1; /* silent ignore.. we got this client already */
-							break;
-						}
-					}
-					
-					/* client that wants to connect */
-					if(!found)
-					{
-						for(i = 0; i < s->max_clients; i++)
-						{
-							if(s->slots[i].conn.state == NET_CONNSTATE_OFFLINE)
-							{
-								found = 1;
-								conn_feed(&s->slots[i].conn, &s->recv.data, &addr);
-								if(s->new_client)
-									s->new_client(i, s->user_ptr);
-								break;
-							}
-						}
-						
-						if(!found)
-						{
-							const char fullmsg[] = "server is full";
-							send_controlmsg(s->socket, &addr, 0, NET_CTRLMSG_CLOSE, fullmsg, sizeof(fullmsg));
-						}
-					}
-				}
-				else
-				{
-					/* normal packet, find matching slot */
-					for(i = 0; i < s->max_clients; i++)
-					{
-						if(net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0)
-						{
-							if(conn_feed(&s->slots[i].conn, &s->recv.data, &addr))
-							{
-								if(s->recv.data.data_size)
-									recvinfo_start(&s->recv, &addr, &s->slots[i].conn, i);
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-int netserver_send(NETSERVER *s, NETCHUNK *chunk)
-{
-	if(chunk->data_size >= NET_MAX_PAYLOAD)
-	{
-		dbg_msg("netserver", "packet payload too big. %d. dropping packet", chunk->data_size);
-		return -1;
-	}
-	
-	if(chunk->flags&NETSENDFLAG_CONNLESS)
-	{
-		/* send connectionless packet */
-		send_packet_connless(s->socket, &chunk->address, chunk->data, chunk->data_size);
-	}
-	else
-	{
-		int f = 0;
-		dbg_assert(chunk->client_id >= 0, "errornous client id");
-		dbg_assert(chunk->client_id < s->max_clients, "errornous client id");
-		
-		if(chunk->flags&NETSENDFLAG_VITAL)
-			f = NET_CHUNKFLAG_VITAL;
-		
-		conn_queue_chunk(&s->slots[chunk->client_id].conn, f, chunk->data_size, chunk->data);
-
-		if(chunk->flags&NETSENDFLAG_FLUSH)
-			conn_flush(&s->slots[chunk->client_id].conn);
-	}
-	return 0;
-}
-
-void netserver_stats(NETSERVER *s, NETSTATS *stats)
-{
-	int num_stats = sizeof(NETSTATS)/sizeof(int);
-	int *istats = (int *)stats;
-	int c, i;
-
-	mem_zero(stats, sizeof(NETSTATS));
-	
-	for(c = 0; c < s->max_clients; c++)
-	{
-		if(s->slots[c].conn.state != NET_CONNSTATE_OFFLINE)
-		{
-			int *sstats = (int *)(&(s->slots[c].conn.stats));
-			for(i = 0; i < num_stats; i++)
-				istats[i] += sstats[i];
-		}
-	}
-}
-
-NETSOCKET netserver_socket(NETSERVER *s)
-{
-	return s->socket;
-}
-
-
-int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr)
-{
-	*addr = s->slots[client_id].conn.peeraddr;
-	return 1;
-}
diff --git a/src/engine/e_network_server.cpp b/src/engine/e_network_server.cpp
new file mode 100644
index 00000000..995290ef
--- /dev/null
+++ b/src/engine/e_network_server.cpp
@@ -0,0 +1,408 @@
+#include <base/system.h>
+#include "e_network.h"
+
+#define MACRO_LIST_LINK_FIRST(object, first, prev, next) \
+	{ if(first) first->prev = object; \
+	object->prev = (struct CBan *)0; \
+	object->next = first; \
+	first = object; }
+	
+#define MACRO_LIST_LINK_AFTER(object, after, prev, next) \
+	{ object->prev = after; \
+	object->next = after->next; \
+	after->next = object; \
+	if(object->next) \
+		object->next->prev = object; \
+	}
+
+#define MACRO_LIST_UNLINK(object, first, prev, next) \
+	{ if(object->next) object->next->prev = object->prev; \
+	if(object->prev) object->prev->next = object->next; \
+	else first = object->next; \
+	object->next = 0; object->prev = 0; }
+	
+#define MACRO_LIST_FIND(start, next, expression) \
+	{ while(start && !(expression)) start = start->next; }
+
+bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int Flags)
+{
+	// zero out the whole structure
+	mem_zero(this, sizeof(*this));
+	
+	// open socket
+	m_Socket = net_udp_create(BindAddr);
+	if(m_Socket == NETSOCKET_INVALID)
+		return false;
+	
+	// clamp clients
+	m_MaxClients = MaxClients;
+	if(m_MaxClients > NET_MAX_CLIENTS)
+		m_MaxClients = NET_MAX_CLIENTS;
+	if(m_MaxClients < 1)
+		m_MaxClients = 1;
+	
+	for(int i = 0; i < NET_MAX_CLIENTS; i++)
+		m_aSlots[i].m_Connection.Init(m_Socket);
+	
+	/* setup all pointers for bans */
+	for(int i = 1; i < NET_SERVER_MAXBANS-1; i++)
+	{
+		m_BanPool[i].m_pNext = &m_BanPool[i+1];
+		m_BanPool[i].m_pPrev = &m_BanPool[i-1];
+	}
+	
+	m_BanPool[0].m_pNext = &m_BanPool[1];
+	m_BanPool[NET_SERVER_MAXBANS-1].m_pPrev = &m_BanPool[NET_SERVER_MAXBANS-2];
+	m_BanPool_FirstFree = &m_BanPool[0];
+
+	return true;
+}
+
+int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
+{
+	m_pfnNewClient = pfnNewClient;
+	m_pfnDelClient = pfnDelClient;
+	m_UserPtr = pUser;
+	return 0;
+}
+
+int CNetServer::Close()
+{
+	/* TODO: implement me */
+	return 0;
+}
+
+int CNetServer::Drop(int ClientID, const char *pReason)
+{
+	/* TODO: insert lots of checks here */
+	NETADDR Addr = ClientAddr(ClientID);
+
+	dbg_msg("net_server", "client dropped. cid=%d ip=%d.%d.%d.%d reason=\"%s\"",
+		ClientID,
+		Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3],
+		pReason
+		);
+		
+	m_aSlots[ClientID].m_Connection.Disconnect(pReason);
+
+	if(m_pfnDelClient)
+		m_pfnDelClient(ClientID, m_UserPtr);
+		
+	return 0;
+}
+
+int CNetServer::BanGet(int Index, CBanInfo *pInfo)
+{
+	CBan *pBan;
+	for(pBan = m_BanPool_FirstUsed; pBan && Index; pBan = pBan->m_pNext, Index--)
+		{}
+		
+	if(!pBan)
+		return 0;
+	*pInfo = pBan->m_Info;
+	return 1;
+}
+
+int CNetServer::BanNum()
+{
+	int Count = 0;
+	CBan *pBan;
+	for(pBan = m_BanPool_FirstUsed; pBan; pBan = pBan->m_pNext)
+		Count++;
+	return Count;
+}
+
+void CNetServer::BanRemoveByObject(CBan *pBan)
+{
+	int iphash = (pBan->m_Info.m_Addr.ip[0]+pBan->m_Info.m_Addr.ip[1]+pBan->m_Info.m_Addr.ip[2]+pBan->m_Info.m_Addr.ip[3])&0xff;
+	dbg_msg("netserver", "removing ban on %d.%d.%d.%d",
+		pBan->m_Info.m_Addr.ip[0], pBan->m_Info.m_Addr.ip[1], pBan->m_Info.m_Addr.ip[2], pBan->m_Info.m_Addr.ip[3]);
+	MACRO_LIST_UNLINK(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
+	MACRO_LIST_UNLINK(pBan, m_aBans[iphash], m_pHashPrev, m_pHashNext);
+	MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
+}
+
+int CNetServer::BanRemove(NETADDR Addr)
+{
+	int iphash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff;
+	CBan *pBan = m_aBans[iphash];
+	
+	MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
+	
+	if(pBan)
+	{
+		BanRemoveByObject(pBan);
+		return 0;
+	}
+	
+	return -1;
+}
+
+int CNetServer::BanAdd(NETADDR Addr, int Seconds)
+{
+	int iphash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff;
+	int Stamp = -1;
+	CBan *pBan;
+	
+	/* remove the port */
+	Addr.port = 0;
+	
+	if(Seconds)
+		Stamp = time_timestamp() + Seconds;
+		
+	/* search to see if it already exists */
+	pBan = m_aBans[iphash];
+	MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
+	if(pBan)
+	{
+		/* adjust the ban */
+		pBan->m_Info.m_Expires = Stamp;
+		return 0;
+	}
+	
+	if(!m_BanPool_FirstFree)
+		return -1;
+
+	/* fetch and clear the new ban */
+	pBan = m_BanPool_FirstFree;
+	MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
+	
+	/* setup the ban info */
+	pBan->m_Info.m_Expires = Stamp;
+	pBan->m_Info.m_Addr = Addr;
+	
+	/* add it to the ban hash */
+	MACRO_LIST_LINK_FIRST(pBan, m_aBans[iphash], m_pHashPrev, m_pHashNext);
+	
+	/* insert it into the used list */
+	{
+		if(m_BanPool_FirstUsed)
+		{
+			CBan *pInsertAfter = m_BanPool_FirstUsed;
+			MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires);
+			
+			if(pInsertAfter)
+				pInsertAfter = pInsertAfter->m_pPrev;
+			else
+			{
+				/* add to last */
+				pInsertAfter = m_BanPool_FirstUsed;
+				while(pInsertAfter->m_pNext)
+					pInsertAfter = pInsertAfter->m_pNext;
+			}
+			
+			if(pInsertAfter)
+			{
+				MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext);
+			}
+			else
+			{
+				MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
+			}
+		}
+		else
+		{
+			MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
+		}
+	}
+
+	/* drop banned clients */	
+	{
+		char Buf[128];
+		NETADDR BanAddr;
+		
+		if(Seconds)
+			str_format(Buf, sizeof(Buf), "you have been banned for %d minutes", Seconds/60);
+		else
+			str_format(Buf, sizeof(Buf), "you have been banned for life");
+		
+		for(int i = 0; i < MaxClients(); i++)
+		{
+			BanAddr = m_aSlots[i].m_Connection.PeerAddress();
+			BanAddr.port = 0;
+			
+			if(net_addr_comp(&Addr, &BanAddr) == 0)
+				Drop(i, Buf);
+		}
+	}
+	return 0;
+}
+
+int CNetServer::Update()
+{
+	int Now = time_timestamp();
+	for(int i = 0; i < MaxClients(); i++)
+	{
+		m_aSlots[i].m_Connection.Update();
+		if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR)
+			Drop(i, m_aSlots[i].m_Connection.ErrorString());
+	}
+	
+	/* remove expired bans */
+	while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires < Now)
+	{
+		CBan *pBan = m_BanPool_FirstUsed;
+		BanRemoveByObject(pBan);
+	}
+	
+	return 0;
+}
+
+/*
+	TODO: chopp up this function into smaller working parts
+*/
+int CNetServer::Recv(CNetChunk *pChunk)
+{
+	unsigned now = time_timestamp();
+	
+	while(1)
+	{
+		NETADDR Addr;
+			
+		/* check for a chunk */
+		if(m_RecvUnpacker.FetchChunk(pChunk))
+			return 1;
+		
+		/* TODO: empty the recvinfo */
+		int Bytes = net_udp_recv(m_Socket, &Addr, m_RecvUnpacker.m_aBuffer, NET_MAX_PACKETSIZE);
+
+		/* no more packets for now */
+		if(Bytes <= 0)
+			break;
+		
+		if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0)
+		{
+			CBan *pBan = 0;
+			NETADDR BanAddr = Addr;
+			int iphash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3])&0xff;
+			int Found = 0;
+			BanAddr.port = 0;
+			
+			/* search a ban */
+			for(pBan = m_aBans[iphash]; pBan; pBan = pBan->m_pHashNext)
+			{
+				if(net_addr_comp(&pBan->m_Info.m_Addr, &BanAddr) == 0)
+					break;
+			}
+			
+			/* check if we just should drop the packet */
+			if(pBan)
+			{
+				// banned, reply with a message
+				char BanStr[128];
+				if(pBan->m_Info.m_Expires)
+				{
+					int Mins = ((pBan->m_Info.m_Expires - now)+59)/60;
+					if(Mins == 1)
+						str_format(BanStr, sizeof(BanStr), "banned for %d minute", Mins);
+					else
+						str_format(BanStr, sizeof(BanStr), "banned for %d minutes", Mins);
+				}
+				else
+					str_format(BanStr, sizeof(BanStr), "banned for life");
+				CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1);
+				continue;
+			}
+			
+			if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS)
+			{
+				pChunk->m_Flags = NETSENDFLAG_CONNLESS;
+				pChunk->m_ClientID = -1;
+				pChunk->m_Address = Addr;
+				pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize;
+				pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData;
+				return 1;
+			}
+			else
+			{			
+				/* TODO: check size here */
+				if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT)
+				{
+					Found = 0;
+				
+					/* check if we already got this client */
+					for(int i = 0; i < MaxClients(); i++)
+					{
+						NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
+						if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE &&
+							net_addr_comp(&PeerAddr, &Addr) == 0)
+						{
+							Found = 1; /* silent ignore.. we got this client already */
+							break;
+						}
+					}
+					
+					/* client that wants to connect */
+					if(!Found)
+					{
+						for(int i = 0; i < MaxClients(); i++)
+						{
+							if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
+							{
+								Found = 1;
+								m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
+								if(m_pfnNewClient)
+									m_pfnNewClient(i, m_UserPtr);
+								break;
+							}
+						}
+						
+						if(!Found)
+						{
+							const char FullMsg[] = "server is full";
+							CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, FullMsg, sizeof(FullMsg));
+						}
+					}
+				}
+				else
+				{
+					/* normal packet, find matching slot */
+					for(int i = 0; i < MaxClients(); i++)
+					{
+						NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
+						if(net_addr_comp(&PeerAddr, &Addr) == 0)
+						{
+							if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr))
+							{
+								if(m_RecvUnpacker.m_Data.m_DataSize)
+									m_RecvUnpacker.Start(&Addr, &m_aSlots[i].m_Connection, i);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+int CNetServer::Send(CNetChunk *pChunk)
+{
+	if(pChunk->m_DataSize >= NET_MAX_PAYLOAD)
+	{
+		dbg_msg("netserver", "packet payload too big. %d. dropping packet", pChunk->m_DataSize);
+		return -1;
+	}
+	
+	if(pChunk->m_Flags&NETSENDFLAG_CONNLESS)
+	{
+		/* send connectionless packet */
+		CNetBase::SendPacketConnless(m_Socket, &pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize);
+	}
+	else
+	{
+		int Flags = 0;
+		dbg_assert(pChunk->m_ClientID >= 0, "errornous client id");
+		dbg_assert(pChunk->m_ClientID < MaxClients(), "errornous client id");
+		
+		if(pChunk->m_Flags&NETSENDFLAG_VITAL)
+			Flags = NET_CHUNKFLAG_VITAL;
+		
+		m_aSlots[pChunk->m_ClientID].m_Connection.QueueChunk(Flags, pChunk->m_DataSize, pChunk->m_pData);
+
+		if(pChunk->m_Flags&NETSENDFLAG_FLUSH)
+			m_aSlots[pChunk->m_ClientID].m_Connection.Flush();
+	}
+	return 0;
+}
+
diff --git a/src/engine/e_packer.c b/src/engine/e_packer.c
deleted file mode 100644
index aee08aed..00000000
--- a/src/engine/e_packer.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-#include <stdlib.h> /* rand() */
-#include <base/system.h>
-
-#include "e_packer.h"
-#include "e_compression.h"
-#include "e_engine.h"
-#include "e_config.h"
-
-/* useful for debugging */
-#if 0
-	#define packing_error(p) p->error = 1; dbg_break()
-#else
-	#define packing_error(p) p->error = 1
-#endif
-
-static int stress_get_int()
-{
-	static const int nasty[] = {-1, 0, 1, 66000, -66000, (-1<<31), 0x7fffffff};
-	if(rand()&1)
-		return rand();
-	return nasty[rand()%6];
-}
-
-static const char *stress_get_string(int *size)
-{
-	static char noise[1024];
-	int i;
-	int s;
-	s = (rand()%1024)-1;
-	for(i = 0; i < s; i++)
-		noise[i] = (rand()%254)+1;
-	noise[s] = 0;
-	if(size)
-		*size = s;
-	return noise;
-}
-
-
-static int stress_prob(float probability)
-{
-	if(!config.dbg_stress_network)
-		return 0;
-	if(rand()/(float)RAND_MAX < probability)
-		return 1;
-	return 0;
-}
-
-
-void packer_reset(PACKER *p)
-{
-	p->error = 0;
-	p->current = p->buffer;
-	p->end = p->current + PACKER_BUFFER_SIZE;
-}
-
-void packer_add_int(PACKER *p, int i)
-{
-	if(p->error)
-		return;
-		
-	if(stress_prob(0.025f))
-		i = stress_get_int();
-	
-	/* make sure that we have space enough */
-	if(p->end - p->current < 6)
-	{
-		dbg_break();
-		p->error = 1;
-	}
-	else
-		p->current = vint_pack(p->current, i);
-}
-
-void packer_add_string(PACKER *p, const char *str, int limit)
-{
-	if(p->error)
-		return;
-		
-	if(stress_prob(0.1f))
-	{
-		str = stress_get_string(0);
-		limit = 0;
-	}
-	
-	/* */
-	if(limit > 0)
-	{
-		while(*str && limit != 0)
-		{
-			*p->current++ = *str++;
-			limit--;
-			
-			if(p->current >= p->end)
-			{
-				packing_error(p);
-				break;
-			}
-		}
-		*p->current++ = 0;
-	}
-	else
-	{
-		while(*str)
-		{
-			*p->current++ = *str++;
-
-			if(p->current >= p->end)
-			{
-				packing_error(p);
-				break;
-			}
-		}
-		*p->current++ = 0;
-	}
-}
-
-void packer_add_raw(PACKER *p, const unsigned char *data, int size)
-{
-	if(p->error)
-		return;
-		
-	if(p->current+size >= p->end)
-	{
-		packing_error(p);
-		return;
-	}
-	
-	while(size)
-	{
-		*p->current++ = *data++;
-		size--;
-	}
-}
-
-int packer_size(PACKER *p)
-{
-	return (const unsigned char *)p->current-(const unsigned char *)p->buffer;
-}
-
-const unsigned char *packer_data(PACKER *p)
-{
-	return (const unsigned char *)p->buffer;
-}
-
-void unpacker_reset(UNPACKER *p, const unsigned char *data, int size)
-{
-	p->error = 0;
-	p->start = data;
-	p->end = p->start + size;
-	p->current = p->start;
-}
-
-int unpacker_get_int(UNPACKER *p)
-{
-	int i;
-	if(p->error)
-		return 0;
-	if(p->current >= p->end)
-	{
-		packing_error(p);
-		return 0;
-	}
-	
-	p->current = vint_unpack(p->current, &i);
-	if(p->current > p->end)
-	{
-		packing_error(p);
-		return 0;
-	}
-	return i;
-}
-
-const char *unpacker_get_string(UNPACKER *p)
-{
-	char *ptr;
-	if(p->error || p->current >= p->end)
-		return "";
-		
-	ptr = (char *)p->current;
-	while(*p->current) /* skip the string */
-	{
-		p->current++;
-		if(p->current == p->end)
-		{
-			packing_error(p);
-			return "";
-		}
-	}
-	p->current++;
-	
-	/* sanitize all strings */
-	str_sanitize(ptr);
-	return ptr;
-}
-
-const unsigned char *unpacker_get_raw(UNPACKER *p, int size)
-{
-	const unsigned char *ptr = p->current;
-	if(p->error)
-		return 0;
-	
-	/* check for nasty sizes */
-	if(size < 0 || p->current+size > p->end)
-	{
-		packing_error(p);
-		return 0;
-	}
-
-	/* "unpack" the data */	
-	p->current += size;
-	return ptr;
-}
diff --git a/src/engine/e_packer.cpp b/src/engine/e_packer.cpp
new file mode 100644
index 00000000..0d8aeab3
--- /dev/null
+++ b/src/engine/e_packer.cpp
@@ -0,0 +1,155 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <stdlib.h> /* rand() */
+#include <base/system.h>
+
+#include "e_packer.h"
+#include "e_compression.h"
+#include "e_engine.h"
+#include "e_config.h"
+
+void CPacker::Reset()
+{
+	m_Error = 0;
+	m_pCurrent = m_aBuffer;
+	m_pEnd = m_pCurrent + PACKER_BUFFER_SIZE;
+}
+
+void CPacker::AddInt(int i)
+{
+	if(m_Error)
+		return;
+		
+	/* make sure that we have space enough */
+	if(m_pEnd - m_pCurrent < 6)
+	{
+		dbg_break();
+		m_Error = 1;
+	}
+	else
+		m_pCurrent = vint_pack(m_pCurrent, i);
+}
+
+void CPacker::AddString(const char *pStr, int Limit)
+{
+	if(m_Error)
+		return;
+	
+	/* */
+	if(Limit > 0)
+	{
+		while(*pStr && Limit != 0)
+		{
+			*m_pCurrent++ = *pStr++;
+			Limit--;
+			
+			if(m_pCurrent >= m_pEnd)
+			{
+				m_Error = 1;
+				break;
+			}
+		}
+		*m_pCurrent++ = 0;
+	}
+	else
+	{
+		while(*pStr)
+		{
+			*m_pCurrent++ = *pStr++;
+
+			if(m_pCurrent >= m_pEnd)
+			{
+				m_Error = 1;
+				break;
+			}
+		}
+		*m_pCurrent++ = 0;
+	}
+}
+
+void CPacker::AddRaw(const unsigned char *pData, int Size)
+{
+	if(m_Error)
+		return;
+		
+	if(m_pCurrent+Size >= m_pEnd)
+	{
+		m_Error = 1;
+		return;
+	}
+	
+	while(Size)
+	{
+		*m_pCurrent++ = *pData++;
+		Size--;
+	}
+}
+
+
+void CUnpacker::Reset(const unsigned char *pData, int Size)
+{
+	m_Error = 0;
+	m_pStart = pData;
+	m_pEnd = m_pStart + Size;
+	m_pCurrent = m_pStart;
+}
+
+int CUnpacker::GetInt()
+{
+	if(m_Error)
+		return 0;
+		
+	if(m_pCurrent >= m_pEnd)
+	{
+		m_Error = 1;
+		return 0;
+	}
+	
+	int i;
+	m_pCurrent = vint_unpack(m_pCurrent, &i);
+	if(m_pCurrent > m_pEnd)
+	{
+		m_Error = 1;
+		return 0;
+	}
+	return i;
+}
+
+const char *CUnpacker::GetString()
+{
+	if(m_Error || m_pCurrent >= m_pEnd)
+		return "";
+		
+	char *pPtr = (char *)m_pCurrent;
+	while(*m_pCurrent) /* skip the string */
+	{
+		m_pCurrent++;
+		if(m_pCurrent == m_pEnd)
+		{
+			m_Error = 1;;
+			return "";
+		}
+	}
+	m_pCurrent++;
+	
+	/* sanitize all strings */
+	str_sanitize(pPtr);
+	return pPtr;
+}
+
+const unsigned char *CUnpacker::GetRaw(int Size)
+{
+	const unsigned char *pPtr = m_pCurrent;
+	if(m_Error)
+		return 0;
+	
+	/* check for nasty sizes */
+	if(Size < 0 || m_pCurrent+Size > m_pEnd)
+	{
+		m_Error = 1;
+		return 0;
+	}
+
+	/* "unpack" the data */	
+	m_pCurrent += Size;
+	return pPtr;
+}
diff --git a/src/engine/e_packer.h b/src/engine/e_packer.h
index 71b99ff7..5dc80e7a 100644
--- a/src/engine/e_packer.h
+++ b/src/engine/e_packer.h
@@ -1,35 +1,37 @@
 /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
 
-enum
+class CPacker
 {
-	PACKER_BUFFER_SIZE=1024*2
-};
+	enum
+	{
+		PACKER_BUFFER_SIZE=1024*2
+	};
 
-typedef struct
-{
+	unsigned char m_aBuffer[PACKER_BUFFER_SIZE];
+	unsigned char *m_pCurrent;
+	unsigned char *m_pEnd;
+	int m_Error;
+public:
+	void Reset();
+	void AddInt(int i);
+	void AddString(const char *pStr, int Limit);
+	void AddRaw(const unsigned char *pData, int Size);
 	
-	unsigned char buffer[PACKER_BUFFER_SIZE];
-	unsigned char *current;
-	unsigned char *end;
-	int error;
-} PACKER;
+	int Size() const { return (int)(m_pCurrent-m_aBuffer); }
+	const unsigned char *Data() const { return m_aBuffer; }
+	bool Error() const { return m_Error; }
+};
 
-typedef struct
+class CUnpacker
 {
-	const unsigned char *current;
-	const unsigned char *start;
-	const unsigned char *end;
-	int error;
-} UNPACKER;
-
-void packer_reset(PACKER *p);
-void packer_add_int(PACKER *p, int i);
-void packer_add_string(PACKER *p, const char *str, int limit);
-void packer_add_raw(PACKER *p, const unsigned char *data, int size);
-int packer_size(PACKER *p);
-const unsigned char *packer_data(PACKER *p);
-
-void unpacker_reset(UNPACKER *p, const unsigned char *data, int size);
-int unpacker_get_int(UNPACKER *p);
-const char *unpacker_get_string(UNPACKER *p);
-const unsigned char *unpacker_get_raw(UNPACKER *p, int size);
+	const unsigned char *m_pStart;
+	const unsigned char *m_pCurrent;
+	const unsigned char *m_pEnd;
+	int m_Error;
+public:
+	void Reset(const unsigned char *pData, int Size);
+	int GetInt();
+	const char *GetString();
+	const unsigned char *GetRaw(int Size);
+	bool Error() const { return m_Error; }
+};
diff --git a/src/engine/e_ringbuffer.c b/src/engine/e_ringbuffer.c
deleted file mode 100644
index 39dfa3e9..00000000
--- a/src/engine/e_ringbuffer.c
+++ /dev/null
@@ -1,362 +0,0 @@
-#include <base/system.h>
-
-#include "e_ringbuffer.h"
-
-typedef struct RBITEM
-{
-    struct RBITEM *prev;
-    struct RBITEM *next;
-    int free;
-    int size;
-} RBITEM;
-
-/*
-
-*/
-struct RINGBUFFER
-{
-	RBITEM *produce;
-	RBITEM *consume;
-	
-	RBITEM *first;
-	RBITEM *last;
-	void *memory;
-	int size;
-	int flags;
-};
-
-RINGBUFFER *ringbuf_init(void *memory, int size, int flags)
-{
-	RINGBUFFER *rb = (RINGBUFFER *)memory;
-	mem_zero(memory, size);
-	
-	rb->memory = rb+1;
-	rb->size = (size-sizeof(RINGBUFFER))/sizeof(RBITEM)*sizeof(RBITEM);
-	rb->first = (RBITEM *)rb->memory;
-	rb->first->free = 1;
-	rb->first->size = rb->size;
-	rb->last = rb->first;
-	rb->produce = rb->first;
-	rb->consume = rb->first;
-	
-	rb->flags = flags;
-	
-	return rb;
-}
-
-static RBITEM *ringbuf_nextblock(RINGBUFFER *rb, RBITEM *item)
-{
-	if(item->next)
-		return item->next;
-	return rb->first;
-}
-
-static RBITEM *ringbuf_prevblock(RINGBUFFER *rb, RBITEM *item)
-{
-	if(item->prev)
-		return item->prev;
-	return rb->last;
-}
-
-static RBITEM *ringbuf_mergeback(RINGBUFFER *rb, RBITEM *item)
-{
-	/* make sure that this block and previous block is free */
-	if(!item->free || !item->prev || !item->prev->free)
-		return item;
-
-	/* merge the blocks */
-	item->prev->size += item->size;
-	item->prev->next = item->next;
-	
-	/* fixup pointers */
-	if(item->next)
-		item->next->prev = item->prev;
-	else
-		rb->last = item->prev;
-		
-	if(item == rb->produce)
-		rb->produce = item->prev;
-	
-	if(item == rb->consume)
-		rb->consume = item->prev;
-	
-	/* return the current block */
-	return item->prev;
-}
-
-int ringbuf_popfirst(RINGBUFFER *rb)
-{
-	if(rb->consume->free)
-		return 0;
-	
-	/* set the free flag */
-	rb->consume->free = 1;
-	
-	/* previous block is also free, merge them */
-	rb->consume = ringbuf_mergeback(rb, rb->consume);
-	
-	/* advance the consume pointer */
-	rb->consume = ringbuf_nextblock(rb, rb->consume);
-	while(rb->consume->free && rb->consume != rb->produce)
-	{
-		rb->consume = ringbuf_mergeback(rb, rb->consume);
-		rb->consume = ringbuf_nextblock(rb, rb->consume);
-	}
-		
-	/* in the case that we have catched up with the produce pointer */
-	/* we might stand on a free block so merge em */
-	ringbuf_mergeback(rb, rb->consume);
-	return 1;
-}
-
-void *ringbuf_allocate(RINGBUFFER *rb, int size)
-{
-	int wanted_size = (size+sizeof(RBITEM)+sizeof(RBITEM)-1)/sizeof(RBITEM)*sizeof(RBITEM);
-	RBITEM *block = 0;
-
-	/* check if we even can fit this block */
-	if(wanted_size > rb->size)
-		return 0;
-
-	while(1)	
-	{
-		/* check for space */
-		if(rb->produce->free)
-		{
-			if(rb->produce->size >= wanted_size)
-				block = rb->produce;
-			else
-			{
-				/* wrap around to try to find a block */
-				if(rb->first->free && rb->first->size >= wanted_size)
-					block = rb->first;
-			}
-		}
-		
-		if(block)
-			break;
-		else
-		{
-			/* we have no block, check our policy and see what todo */
-			if(rb->flags&RINGBUF_FLAG_RECYCLE)
-			{
-				if(!ringbuf_popfirst(rb))
-					return 0;
-			}
-			else
-				return 0;
-		}
-	}
-	
-	/* okey, we have our block */
-	
-	/* split the block if needed */
-	if(block->size > wanted_size)
-	{
-		RBITEM *new_item = (RBITEM *)((char *)block + wanted_size);
-		new_item->prev = block;
-		new_item->next = block->next;
-		if(new_item->next)
-			new_item->next->prev = new_item;
-		block->next = new_item;
-		
-		new_item->free = 1;
-		new_item->size = block->size - wanted_size;
-		block->size = wanted_size;
-		
-		if(!new_item->next)
-			rb->last = new_item;
-	}
-	
-	
-	/* set next block */
-	rb->produce = ringbuf_nextblock(rb, block);
-	
-	/* set as used and return the item pointer */
-	block->free = 0;
-	return block+1;
-}
-
-void *ringbuf_prev(RINGBUFFER *rb, void *current)
-{
-	RBITEM *item = ((RBITEM *)current) - 1;
-	
-	while(1)
-	{
-		item = ringbuf_prevblock(rb, item);
-		if(item == rb->produce)
-			return 0;
-		if(!item->free)
-			return item+1;
-	}
-}
-
-void *ringbuf_next(RINGBUFFER *rb, void *current)
-{
-	RBITEM *item = ((RBITEM *)current) - 1;
-	
-	while(1)
-	{
-		item = ringbuf_nextblock(rb, item);
-		if(item == rb->produce)
-			return 0;
-		if(!item->free)
-			return item+1;
-	}
-}
-
-void *ringbuf_first(RINGBUFFER *rb)
-{
-	if(rb->consume->free)
-		return 0;
-	return rb->consume+1;
-}
-
-void *ringbuf_last(RINGBUFFER *rb)
-{
-	if(!rb->produce->free)
-		return rb->produce+1;
-	return ringbuf_prev(rb, rb->produce+1);
-}
-
-
-/* debugging and testing stuff */
-
-static void ringbuf_debugdump(RINGBUFFER *rb, const char *msg)
-{
-	RBITEM *cur = rb->first;
-	
-	dbg_msg("ringbuf", "-- dumping --");
-	
-	while(cur)
-	{
-		char flags[4] = "   ";
-		if(cur->free)
-			flags[0] = 'F';
-		if(cur == rb->consume)
-			flags[1] = '>';
-		if(cur == rb->produce)
-			flags[2] = '<';
-		dbg_msg("ringbuf", "%s %d", flags, cur->size);
-		cur = cur->next;
-	}
-	
-	dbg_msg("ringbuf", "--  --");
-	
-	if(msg)
-		dbg_assert(0, msg);
-}
-
-
-
-static void ringbuf_validate(RINGBUFFER *rb)
-{
-	RBITEM *prev = 0;
-	RBITEM *cur = rb->first;
-	int freechunks = 0;
-	int got_consume = 0;
-	int got_produce = 0;
-	
-	while(cur)
-	{
-		
-		if(cur->free)
-			freechunks++;
-		
-		if(freechunks > 2) ringbuf_debugdump(rb, "too many free chunks");
-		if(prev && prev->free && cur->free) ringbuf_debugdump(rb, "two free chunks next to each other");
-		if(cur == rb->consume) got_consume = 1;
-		if(cur == rb->produce) got_produce = 1;
-
-		dbg_assert(cur->prev == prev, "prev pointers doesn't match");
-		dbg_assert(!prev || prev->next == cur, "next pointers doesn't match");
-		dbg_assert(cur->next || cur == rb->last, "last isn't last");
-
-		prev = cur;
-		cur = cur->next;
-	}
-
-	if(!got_consume) ringbuf_debugdump(rb, "consume pointer isn't pointing at a valid block");
-	if(!got_produce) ringbuf_debugdump(rb, "produce pointer isn't pointing at a valid block");
-}
-
-int ringbuf_test()
-{
-	char buffer[256];
-	RINGBUFFER *rb;
-	int i, s, k, m;
-	int count;
-	int testcount = 0;
-	
-	void *item;
-	int before;
-	
-	
-	for(k = 100; k < sizeof(buffer); k++)
-	{
-		if((k%10) == 0)
-			dbg_msg("ringbuf", "testing at %d", k);
-		rb = ringbuf_init(buffer, k, 0);
-		count = 0;
-		
-		for(s = 1; s < sizeof(buffer); s++)
-		{
-			for(i = 0; i < k*8; i++, testcount++)
-			{
-				for(m = 0, item = ringbuf_first(rb); item; item = ringbuf_next(rb, item), m++);
-				before = m;
-				
-				if(ringbuf_allocate(rb, s))
-				{
-					count++;
-					for(m = 0, item = ringbuf_first(rb); item; item = ringbuf_next(rb, item), m++);
-					if(before+1 != m) ringbuf_debugdump(rb, "alloc error");
-					if(count != m) ringbuf_debugdump(rb, "count error");
-				}
-				else
-				{
-					if(ringbuf_popfirst(rb))
-					{
-						count--;
-						
-						for(m = 0, item = ringbuf_first(rb); item; item = ringbuf_next(rb, item), m++);
-						if(before-1 != m) dbg_msg("", "popping error %d %d", before, m);
-						if(count != m) ringbuf_debugdump(rb, "count error");
-					}
-				}
-				
-				/* remove an item every 10 */
-				if((i%10) == 0)
-				{
-					for(m = 0, item = ringbuf_first(rb); item; item = ringbuf_next(rb, item), m++);
-					before = m;
-					
-					if(ringbuf_popfirst(rb))
-					{
-						count--;
-						for(m = 0, item = ringbuf_first(rb); item; item = ringbuf_next(rb, item), m++);
-						if(before-1 != m) dbg_msg("", "popping error %d %d", before, m);
-						dbg_assert(count == m, "count error");
-					}
-				}
-				
-				/* count items */
-				for(m = 0, item = ringbuf_first(rb); item; item = ringbuf_next(rb, item), m++);
-				if(m != count) ringbuf_debugdump(rb, "wrong number of items during forward count");
-
-				for(m = 0, item = ringbuf_last(rb); item; item = ringbuf_prev(rb, item), m++);
-				if(m != count) ringbuf_debugdump(rb, "wrong number of items during backward count");
-					
-				ringbuf_validate(rb);
-			}
-
-			/* empty the ring buffer */			
-			while(ringbuf_first(rb))
-				ringbuf_popfirst(rb);
-			ringbuf_validate(rb);
-			count = 0;
-		}
-	}
-	
-	return 0;
-}
diff --git a/src/engine/e_ringbuffer.cpp b/src/engine/e_ringbuffer.cpp
new file mode 100644
index 00000000..eb8a8af4
--- /dev/null
+++ b/src/engine/e_ringbuffer.cpp
@@ -0,0 +1,194 @@
+#include <base/system.h>
+
+#include "e_ringbuffer.h"
+	
+CRingBufferBase::CItem *CRingBufferBase::NextBlock(CItem *pItem)
+{
+	if(pItem->m_pNext)
+		return pItem->m_pNext;
+	return m_pFirst;
+}
+
+CRingBufferBase::CItem *CRingBufferBase::PrevBlock(CItem *pItem)
+{
+	if(pItem->m_pPrev)
+		return pItem->m_pPrev;
+	return m_pLast;
+}
+
+CRingBufferBase::CItem *CRingBufferBase::MergeBack(CItem *pItem)
+{
+	/* make sure that this block and previous block is free */
+	if(!pItem->m_Free || !pItem->m_pPrev || !pItem->m_pPrev->m_Free)
+		return pItem;
+
+	/* merge the blocks */
+	pItem->m_pPrev->m_Size += pItem->m_Size;
+	pItem->m_pPrev->m_pNext = pItem->m_pNext;
+	
+	/* fixup pointers */
+	if(pItem->m_pNext)
+		pItem->m_pNext->m_pPrev = pItem->m_pPrev;
+	else
+		m_pLast = pItem->m_pPrev;
+		
+	if(pItem == m_pProduce)
+		m_pProduce = pItem->m_pPrev;
+	
+	if(pItem == m_pConsume)
+		m_pConsume = pItem->m_pPrev;
+	
+	/* return the current block */
+	return pItem->m_pPrev;
+}
+
+void CRingBufferBase::Init(void *pMemory, int Size, int Flags)
+{
+	mem_zero(pMemory, Size);
+	m_Size = (Size)/sizeof(CItem)*sizeof(CItem);
+	m_pFirst = (CItem *)pMemory;
+	m_pFirst->m_Free = 1;
+	m_pFirst->m_Size = m_Size;
+	m_pLast = m_pFirst;
+	m_pProduce = m_pFirst;
+	m_pConsume = m_pFirst;
+	m_Flags = Flags;		
+	
+}
+
+void *CRingBufferBase::Allocate(int Size)
+{
+	int WantedSize = (Size+sizeof(CItem)+sizeof(CItem)-1)/sizeof(CItem)*sizeof(CItem);
+	CItem *pBlock = 0;
+
+	/* check if we even can fit this block */
+	if(WantedSize > m_Size)
+		return 0;
+
+	while(1)	
+	{
+		/* check for space */
+		if(m_pProduce->m_Free)
+		{
+			if(m_pProduce->m_Size >= WantedSize)
+				pBlock = m_pProduce;
+			else
+			{
+				/* wrap around to try to find a block */
+				if(m_pFirst->m_Free && m_pFirst->m_Size >= WantedSize)
+					pBlock = m_pFirst;
+			}
+		}
+		
+		if(pBlock)
+			break;
+		else
+		{
+			/* we have no block, check our policy and see what todo */
+			if(m_Flags&FLAG_RECYCLE)
+			{
+				if(!PopFirst())
+					return 0;
+			}
+			else
+				return 0;
+		}
+	}
+	
+	/* okey, we have our block */
+	
+	/* split the block if needed */
+	if(pBlock->m_Size > WantedSize)
+	{
+		CItem *pNewItem = (CItem *)((char *)pBlock + WantedSize);
+		pNewItem->m_pPrev = pBlock;
+		pNewItem->m_pNext = pBlock->m_pNext;
+		if(pNewItem->m_pNext)
+			pNewItem->m_pNext->m_pPrev = pNewItem;
+		pBlock->m_pNext = pNewItem;
+		
+		pNewItem->m_Free = 1;
+		pNewItem->m_Size = pBlock->m_Size - WantedSize;
+		pBlock->m_Size = WantedSize;
+		
+		if(!pNewItem->m_pNext)
+			m_pLast = pNewItem;
+	}
+	
+	
+	/* set next block */
+	m_pProduce = NextBlock(pBlock);
+	
+	/* set as used and return the item pointer */
+	pBlock->m_Free = 0;
+	return (void *)(pBlock+1);
+}
+
+int CRingBufferBase::PopFirst()
+{
+	if(m_pConsume->m_Free)
+		return 0;
+	
+	/* set the free flag */
+	m_pConsume->m_Free = 1;
+	
+	/* previous block is also free, merge them */
+	m_pConsume = MergeBack(m_pConsume);
+	
+	/* advance the consume pointer */
+	m_pConsume = NextBlock(m_pConsume);
+	while(m_pConsume->m_Free && m_pConsume != m_pProduce)
+	{
+		m_pConsume = MergeBack(m_pConsume);
+		m_pConsume = NextBlock(m_pConsume);
+	}
+		
+	/* in the case that we have catched up with the produce pointer */
+	/* we might stand on a free block so merge em */
+	MergeBack(m_pConsume);
+	return 1;
+}
+
+
+void *CRingBufferBase::Prev(void *pCurrent)
+{
+	CItem *pItem = ((CItem *)pCurrent) - 1;
+	
+	while(1)
+	{
+		pItem = PrevBlock(pItem);
+		if(pItem == m_pProduce)
+			return 0;
+		if(!pItem->m_Free)
+			return pItem+1;
+	}
+}
+
+void *CRingBufferBase::Next(void *pCurrent)
+{
+	CItem *pItem = ((CItem *)pCurrent) - 1;
+	
+	while(1)
+	{
+		pItem = NextBlock(pItem);
+		if(pItem == m_pProduce)
+			return 0;
+		if(!pItem->m_Free)
+			return pItem+1;
+	}
+}
+
+void *CRingBufferBase::First()
+{
+	if(m_pConsume->m_Free)
+		return 0;
+	return (void *)(m_pConsume+1);
+}
+
+void *CRingBufferBase::Last()
+{
+	if(!m_pProduce->m_Free)
+		return m_pProduce+1;
+	return Prev(m_pProduce+1);
+}
+
diff --git a/src/engine/e_ringbuffer.h b/src/engine/e_ringbuffer.h
index 6113c19b..b9f7219c 100644
--- a/src/engine/e_ringbuffer.h
+++ b/src/engine/e_ringbuffer.h
@@ -3,21 +3,64 @@
 
 typedef struct RINGBUFFER RINGBUFFER;
 
-enum
+class CRingBufferBase
 {
-	/* Will start to destroy items to try to fit the next one */
-	RINGBUF_FLAG_RECYCLE=1
+	class CItem
+	{
+	public:
+		CItem *m_pPrev;
+		CItem *m_pNext;
+		int m_Free;
+		int m_Size;
+	};
+	
+	CItem *m_pProduce;
+	CItem *m_pConsume;
+	
+	CItem *m_pFirst;
+	CItem *m_pLast;
+	
+	void *m_pMemory;
+	int m_Size;
+	int m_Flags;
+	
+	CItem *NextBlock(CItem *pItem);
+	CItem *PrevBlock(CItem *pItem);
+	CItem *MergeBack(CItem *pItem);
+protected:
+	void *Allocate(int Size);
+	
+	void *Prev(void *pCurrent);
+	void *Next(void *pCurrent);
+	void *First();
+	void *Last();
+	
+	void Init(void *pMemory, int Size, int Flags);
+	int PopFirst();
+public:
+	enum
+	{
+		/* Will start to destroy items to try to fit the next one */
+		FLAG_RECYCLE=1
+	};
 };
- 
-RINGBUFFER *ringbuf_init(void *memory, int size, int flags);
-void ringbuf_clear(RINGBUFFER *rb);
-void *ringbuf_allocate(RINGBUFFER *rb, int size);
 
-void *ringbuf_prev(RINGBUFFER *rb, void *current);
-void *ringbuf_next(RINGBUFFER *rb, void *current);
-void *ringbuf_first(RINGBUFFER *rb);
-void *ringbuf_last(RINGBUFFER *rb);
+template<typename T, int TSIZE, int TFLAGS=0>
+class TStaticRingBuffer : public CRingBufferBase
+{
+	unsigned char m_aBuffer[TSIZE];
+public:
+	TStaticRingBuffer() { Init(); }
+	
+	void Init() { CRingBufferBase::Init(m_aBuffer, TSIZE, TFLAGS); }
+	
+	T *Allocate(int Size) { return (T*)CRingBufferBase::Allocate(Size); }
+	int PopFirst() { return CRingBufferBase::PopFirst(); }
 
-int ringbuf_popfirst(RINGBUFFER *rb);
+	T *Prev(T *pCurrent) { return (T*)CRingBufferBase::Prev(pCurrent); }
+	T *Next(T *pCurrent) { return (T*)CRingBufferBase::Next(pCurrent); }
+	T *First() { return (T*)CRingBufferBase::First(); }
+	T *Last() { return (T*)CRingBufferBase::Last(); }
+};
 
 #endif
diff --git a/src/engine/e_server_interface.h b/src/engine/e_server_interface.h
index 5b1e6327..c325b9a1 100644
--- a/src/engine/e_server_interface.h
+++ b/src/engine/e_server_interface.h
@@ -2,10 +2,6 @@
 #ifndef ENGINE_SERVER_INTERFACE_H
 #define ENGINE_SERVER_INTERFACE_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "e_if_other.h"
 #include "e_if_server.h"
 #include "e_if_msg.h"
@@ -13,8 +9,4 @@ extern "C" {
 
 #include "e_console.h" /* TODO: clean this up*/
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/engine/e_snapshot.c b/src/engine/e_snapshot.c
deleted file mode 100644
index cce8a06e..00000000
--- a/src/engine/e_snapshot.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-#include <stdlib.h>
-#include "e_snapshot.h"
-#include "e_engine.h"
-#include "e_compression.h"
-#include "e_common_interface.h"
-
-
-/* TODO: strange arbitrary number */
-static short item_sizes[64] = {0};
-
-void snap_set_staticsize(int itemtype, int size)
-{
-	item_sizes[itemtype] = size;
-}
-
-int *snapitem_data(SNAPSHOT_ITEM *item) { return (int *)(item+1); }
-int snapitem_type(SNAPSHOT_ITEM *item) { return item->type_and_id>>16; }
-int snapitem_id(SNAPSHOT_ITEM *item) { return item->type_and_id&0xffff; }
-int snapitem_key(SNAPSHOT_ITEM *item) { return item->type_and_id; }
-
-int *snapshot_offsets(SNAPSHOT *snap) { return (int *)(snap+1); }
-char *snapshot_datastart(SNAPSHOT *snap) { return (char*)(snapshot_offsets(snap)+snap->num_items); }
-
-SNAPSHOT_ITEM *snapshot_get_item(SNAPSHOT *snap, int index)
-{ return (SNAPSHOT_ITEM *)(snapshot_datastart(snap) + snapshot_offsets(snap)[index]); }
-
-int snapshot_get_item_datasize(SNAPSHOT *snap, int index)
-{
-    if(index == snap->num_items-1)
-        return (snap->data_size - snapshot_offsets(snap)[index]) - sizeof(SNAPSHOT_ITEM);
-    return (snapshot_offsets(snap)[index+1] - snapshot_offsets(snap)[index]) - sizeof(SNAPSHOT_ITEM);
-}
-
-int snapshot_get_item_index(SNAPSHOT *snap, int key)
-{
-    /* TODO: OPT: this should not be a linear search. very bad */
-    int i;
-    for(i = 0; i < snap->num_items; i++)
-    {
-        if(snapitem_key(snapshot_get_item(snap, i)) == key)
-            return i;
-    }
-    return -1;
-}
-typedef struct 
-{
-	int num;
-	int keys[64];
-	int index[64];
-} ITEMLIST;
-static ITEMLIST sorted[256];
-
-static int snapshot_generate_hash(SNAPSHOT *snap)
-{
-	int i, key, hashid;
-
-    for(i = 0; i < 256; i++)
-    	sorted[i].num = 0;
-    	
-    for(i = 0; i < snap->num_items; i++)
-    {
-    	key = snapitem_key(snapshot_get_item(snap, i));
-    	hashid = ((key>>8)&0xf0) | (key&0xf);
-    	if(sorted[hashid].num != 64)
-    	{
-			sorted[hashid].index[sorted[hashid].num] = i;
-			sorted[hashid].keys[sorted[hashid].num] = key;
-			sorted[hashid].num++;
-		}
-	}
-    return 0;
-}
-
-int snapshot_get_item_index_hashed(SNAPSHOT *snap, int key)
-{
-   	int hashid = ((key>>8)&0xf0) | (key&0xf);
-   	int i;
-   	for(i = 0; i < sorted[hashid].num; i++)
-   	{
-   		if(sorted[hashid].keys[i] == key)
-   			return sorted[hashid].index[i];
-	}
-	
-	return -1;
-}
-
-typedef struct
-{
-	int num_deleted_items;
-	int num_update_items;
-	int num_temp_items; /* needed? */
-	int data[1];
-	
-	/*
-	char *data_start() { return (char *)&offsets[num_deleted_items+num_update_items+num_temp_items]; }
-	
-	int deleted_item(int index) { return offsets[index]; }
-	item *update_item(int index) { return (item *)(data_start() + offsets[num_deleted_items+index]); }
-	item *temp_item(int index) { return (item *)(data_start() + offsets[num_deleted_items+num_update_items+index]); }
-	*/
-} SNAPSHOT_DELTA;
-
-
-static const int MAX_ITEMS = 512;
-static SNAPSHOT_DELTA empty = {0,0,0,{0}};
-
-void *snapshot_empty_delta()
-{
-	return &empty;
-}
-
-int snapshot_crc(SNAPSHOT *snap)
-{
-	int crc = 0;
-	int i, b;
-	SNAPSHOT_ITEM *item;
-	int size;
-	
-	for(i = 0; i < snap->num_items; i++)
-	{
-		item = snapshot_get_item(snap, i);
-		size = snapshot_get_item_datasize(snap, i);
-		
-		for(b = 0; b < size/4; b++)
-			crc += snapitem_data(item)[b];
-	}
-	return crc;
-}
-
-void snapshot_debug_dump(SNAPSHOT *snap)
-{
-	int size, i, b;
-	SNAPSHOT_ITEM *item;
-	
-	dbg_msg("snapshot", "data_size=%d num_items=%d", snap->data_size, snap->num_items);
-	for(i = 0; i < snap->num_items; i++)
-	{
-		item = snapshot_get_item(snap, i);
-		size = snapshot_get_item_datasize(snap, i);
-		dbg_msg("snapshot", "\ttype=%d id=%d", snapitem_type(item), snapitem_id(item));
-		for(b = 0; b < size/4; b++)
-			dbg_msg("snapshot", "\t\t%3d %12d\t%08x", b, snapitem_data(item)[b], snapitem_data(item)[b]);
-	}
-}
-
-static int diff_item(int *past, int *current, int *out, int size)
-{
-	int needed = 0;
-	while(size)
-	{
-		*out = *current-*past;
-		needed |= *out;
-		out++;
-		past++;
-		current++;
-		size--;
-	}
-	
-	return needed;
-}
-
-int snapshot_data_rate[0xffff] = {0};
-int snapshot_data_updates[0xffff] = {0};
-static int snapshot_current = 0;
-
-static void undiff_item(int *past, int *diff, int *out, int size)
-{
-	while(size)
-	{
-		*out = *past+*diff;
-		
-		if(*diff == 0)
-			snapshot_data_rate[snapshot_current] += 1;
-		else
-		{
-			unsigned char buf[16];
-			unsigned char *end = vint_pack(buf,  *diff);
-			snapshot_data_rate[snapshot_current] += (int)(end - (unsigned char*)buf) * 8;
-		}
-		
-		out++;
-		past++;
-		diff++;
-		size--;
-	}
-}
-
-
-/* TODO: OPT: this should be made much faster */
-int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *dstdata)
-{
-	static PERFORMACE_INFO hash_scope = {"hash", 0};
-	SNAPSHOT_DELTA *delta = (SNAPSHOT_DELTA *)dstdata;
-	int *data = (int *)delta->data;
-	int i, itemsize, pastindex;
-	SNAPSHOT_ITEM *fromitem;
-	SNAPSHOT_ITEM *curitem;
-	SNAPSHOT_ITEM *pastitem;
-	int count = 0;
-	int size_count = 0;
-	
-	delta->num_deleted_items = 0;
-	delta->num_update_items = 0;
-	delta->num_temp_items = 0;
-	
-	perf_start(&hash_scope);
-	snapshot_generate_hash(to);
-	perf_end();
-
-	/* pack deleted stuff */
-	{
-		static PERFORMACE_INFO scope = {"delete", 0};
-		perf_start(&scope);
-		
-		for(i = 0; i < from->num_items; i++)
-		{
-			fromitem = snapshot_get_item(from, i);
-			if(snapshot_get_item_index_hashed(to, (snapitem_key(fromitem))) == -1)
-			{
-				/* deleted */
-				delta->num_deleted_items++;
-				*data = snapitem_key(fromitem);
-				data++;
-			}
-		}
-		
-		perf_end();
-	}
-	
-	perf_start(&hash_scope);
-	snapshot_generate_hash(from);
-	perf_end();
-	
-	/* pack updated stuff */
-	{
-		static PERFORMACE_INFO scope = {"update", 0};
-		int pastindecies[1024];
-		perf_start(&scope);
-
-		/* fetch previous indices */
-		/* we do this as a separate pass because it helps the cache */
-		{
-			static PERFORMACE_INFO scope = {"find", 0};
-			perf_start(&scope);
-			for(i = 0; i < to->num_items; i++)
-			{
-				curitem = snapshot_get_item(to, i);  /* O(1) .. O(n) */
-				pastindecies[i] = snapshot_get_item_index_hashed(from, snapitem_key(curitem)); /* O(n) .. O(n^n)*/
-			}
-			perf_end();
-		}		
-			
-		for(i = 0; i < to->num_items; i++)
-		{
-			/* do delta */
-			itemsize = snapshot_get_item_datasize(to, i); /* O(1) .. O(n) */
-			curitem = snapshot_get_item(to, i);  /* O(1) .. O(n) */
-			pastindex = pastindecies[i];
-			
-			if(pastindex != -1)
-			{
-				static PERFORMACE_INFO scope = {"diff", 0};
-				int *item_data_dst = data+3;
-				perf_start(&scope);
-		
-				pastitem = snapshot_get_item(from, pastindex);
-				
-				if(item_sizes[snapitem_type(curitem)])
-					item_data_dst = data+2;
-				
-				if(diff_item((int*)snapitem_data(pastitem), (int*)snapitem_data(curitem), item_data_dst, itemsize/4))
-				{
-					
-					*data++ = snapitem_type(curitem);
-					*data++ = snapitem_id(curitem);
-					if(!item_sizes[snapitem_type(curitem)])
-						*data++ = itemsize/4;
-					data += itemsize/4;
-					delta->num_update_items++;
-				}
-				perf_end();
-			}
-			else
-			{
-				static PERFORMACE_INFO scope = {"copy", 0};
-				perf_start(&scope);
-				
-				*data++ = snapitem_type(curitem);
-				*data++ = snapitem_id(curitem);
-				if(!item_sizes[snapitem_type(curitem)])
-					*data++ = itemsize/4;
-				
-				mem_copy(data, snapitem_data(curitem), itemsize);
-				size_count += itemsize;
-				data += itemsize/4;
-				delta->num_update_items++;
-				count++;
-				
-				perf_end();
-			}
-		}
-		
-		perf_end();
-	}
-	
-	if(0)
-	{
-		dbg_msg("snapshot", "%d %d %d",
-			delta->num_deleted_items,
-			delta->num_update_items,
-			delta->num_temp_items);
-	}
-
-	/*
-	// TODO: pack temp stuff
-	
-	// finish
-	//mem_copy(delta->offsets, deleted, delta->num_deleted_items*sizeof(int));
-	//mem_copy(&(delta->offsets[delta->num_deleted_items]), update, delta->num_update_items*sizeof(int));
-	//mem_copy(&(delta->offsets[delta->num_deleted_items+delta->num_update_items]), temp, delta->num_temp_items*sizeof(int));
-	//mem_copy(delta->data_start(), data, data_size);
-	//delta->data_size = data_size;
-	* */
-	
-	if(!delta->num_deleted_items && !delta->num_update_items && !delta->num_temp_items)
-		return 0;
-	
-	return (int)((char*)data-(char*)dstdata);
-}
-
-static int range_check(void *end, void *ptr, int size)
-{
-	if((const char *)ptr + size > (const char *)end)
-		return -1;
-	return 0;
-}
-
-int snapshot_unpack_delta(SNAPSHOT *from, SNAPSHOT *to, void *srcdata, int data_size)
-{
-	SNAPBUILD builder;
-	SNAPSHOT_DELTA *delta = (SNAPSHOT_DELTA *)srcdata;
-	int *data = (int *)delta->data;
-	int *end = (int *)(((char *)srcdata + data_size));
-	
-	SNAPSHOT_ITEM *fromitem;
-	int i, d, keep, itemsize;
-	int *deleted;
-	int id, type, key;
-	int fromindex;
-	int *newdata;
-			
-	snapbuild_init(&builder);
-	
-	/* unpack deleted stuff */
-	deleted = data;
-	data += delta->num_deleted_items;
-	if(data > end)
-		return -1;
-
-	/* copy all non deleted stuff */
-	for(i = 0; i < from->num_items; i++)
-	{
-		/* dbg_assert(0, "fail!"); */
-		fromitem = snapshot_get_item(from, i);
-		itemsize = snapshot_get_item_datasize(from, i);
-		keep = 1;
-		for(d = 0; d < delta->num_deleted_items; d++)
-		{
-			if(deleted[d] == snapitem_key(fromitem))
-			{
-				keep = 0;
-				break;
-			}
-		}
-		
-		if(keep)
-		{
-			/* keep it */
-			mem_copy(
-				snapbuild_new_item(&builder, snapitem_type(fromitem), snapitem_id(fromitem), itemsize),
-				snapitem_data(fromitem), itemsize);
-		}
-	}
-		
-	/* unpack updated stuff */
-	for(i = 0; i < delta->num_update_items; i++)
-	{
-		if(data+2 > end)
-			return -1;
-		
-		type = *data++;
-		id = *data++;
-		if(item_sizes[type])
-			itemsize = item_sizes[type];
-		else
-		{
-			if(data+1 > end)
-				return -2;
-			itemsize = (*data++) * 4;
-		}
-		snapshot_current = type;
-		
-		if(range_check(end, data, itemsize) || itemsize < 0) return -3;
-		
-		key = (type<<16)|id;
-		
-		/* create the item if needed */
-		newdata = snapbuild_get_item_data(&builder, key);
-		if(!newdata)
-			newdata = (int *)snapbuild_new_item(&builder, key>>16, key&0xffff, itemsize);
-
-		/*if(range_check(end, newdata, itemsize)) return -4;*/
-			
-		fromindex = snapshot_get_item_index(from, key);
-		if(fromindex != -1)
-		{
-			/* we got an update so we need to apply the diff */
-			undiff_item((int *)snapitem_data(snapshot_get_item(from, fromindex)), data, newdata, itemsize/4);
-			snapshot_data_updates[snapshot_current]++;
-		}
-		else /* no previous, just copy the data */
-		{
-			mem_copy(newdata, data, itemsize);
-			snapshot_data_rate[snapshot_current] += itemsize*8;
-			snapshot_data_updates[snapshot_current]++;
-		}
-			
-		data += itemsize/4;
-	}
-	
-	/* finish up */
-	return snapbuild_finish(&builder, to);
-}
-
-/* SNAPSTORAGE */
-
-void snapstorage_init(SNAPSTORAGE *ss)
-{
-	ss->first = 0;
-}
-
-void snapstorage_purge_all(SNAPSTORAGE *ss)
-{
-	SNAPSTORAGE_HOLDER *h = ss->first;
-	SNAPSTORAGE_HOLDER *next;
-
-	while(h)
-	{
-		next = h->next;
-		mem_free(h);
-		h = next;
-	}
-
-	/* no more snapshots in storage */
-	ss->first = 0;
-	ss->last = 0;
-}
-
-void snapstorage_purge_until(SNAPSTORAGE *ss, int tick)
-{
-	SNAPSTORAGE_HOLDER *next;
-	SNAPSTORAGE_HOLDER *h = ss->first;
-	
-	while(h)
-	{
-		next = h->next;
-		if(h->tick >=  tick)
-			return; /* no more to remove */
-		mem_free(h);
-		
-		/* did we come to the end of the list? */
-        if (!next)
-            break;
-
-		ss->first = next;
-		next->prev = 0x0;
-		
-		h = next;
-	}
-	
-	/* no more snapshots in storage */
-	ss->first = 0;
-	ss->last = 0;
-}
-
-void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, void *data, int create_alt)
-{
-	/* allocate memory for holder + snapshot_data */
-	SNAPSTORAGE_HOLDER *h;
-	int total_size = sizeof(SNAPSTORAGE_HOLDER)+data_size;
-	
-	if(create_alt)
-		total_size += data_size;
-	
-	h = (SNAPSTORAGE_HOLDER *)mem_alloc(total_size, 1);
-	
-	/* set data */
-	h->tick = tick;
-	h->tagtime = tagtime;
-	h->snap_size = data_size;
-	h->snap = (SNAPSHOT*)(h+1);
-	mem_copy(h->snap, data, data_size);
-
-	if(create_alt) /* create alternative if wanted */
-	{
-		h->alt_snap = (SNAPSHOT*)(((char *)h->snap) + data_size);
-		mem_copy(h->alt_snap, data, data_size);
-	}
-	else
-		h->alt_snap = 0;
-		
-	
-	/* link */
-	h->next = 0;
-	h->prev = ss->last;
-	if(ss->last)
-		ss->last->next = h;
-	else
-		ss->first = h;
-	ss->last = h;
-}
-
-int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data, SNAPSHOT **alt_data)
-{
-	SNAPSTORAGE_HOLDER *h = ss->first;
-	
-	while(h)
-	{
-		if(h->tick == tick)
-		{
-			if(tagtime)
-				*tagtime = h->tagtime;
-			if(data)
-				*data = h->snap;
-			if(alt_data)
-				*alt_data = h->alt_snap;
-			return h->snap_size;
-		}
-		
-		h = h->next;
-	}
-	
-	return -1;
-}
-
-/* SNAPBUILD */
-
-void snapbuild_init(SNAPBUILD *sb)
-{
-	sb->data_size = 0;
-	sb->num_items = 0;
-}
-
-SNAPSHOT_ITEM *snapbuild_get_item(SNAPBUILD *sb, int index) 
-{
-	return (SNAPSHOT_ITEM *)&(sb->data[sb->offsets[index]]);
-}
-
-int *snapbuild_get_item_data(SNAPBUILD *sb, int key)
-{
-	int i;
-	for(i = 0; i < sb->num_items; i++)
-	{
-		if(snapitem_key(snapbuild_get_item(sb, i)) == key)
-			return (int *)snapitem_data(snapbuild_get_item(sb, i));
-	}
-	return 0;
-}
-
-int snapbuild_finish(SNAPBUILD *sb, void *snapdata)
-{
-	/* flattern and make the snapshot */
-	SNAPSHOT *snap = (SNAPSHOT *)snapdata;
-	int offset_size = sizeof(int)*sb->num_items;
-	snap->data_size = sb->data_size;
-	snap->num_items = sb->num_items;
-	mem_copy(snapshot_offsets(snap), sb->offsets, offset_size);
-	mem_copy(snapshot_datastart(snap), sb->data, sb->data_size);
-	return sizeof(SNAPSHOT) + offset_size + sb->data_size;
-}
-
-void *snapbuild_new_item(SNAPBUILD *sb, int type, int id, int size)
-{
-	SNAPSHOT_ITEM *obj = (SNAPSHOT_ITEM *)(sb->data+sb->data_size);
-
-	/*if(stress_prob(0.01f))
-	{
-		size += ((rand()%5) - 2)*4;
-		if(size < 0)
-			size = 0;
-	}*/
-
-	mem_zero(obj, sizeof(SNAPSHOT_ITEM) + size);
-	obj->type_and_id = (type<<16)|id;
-	sb->offsets[sb->num_items] = sb->data_size;
-	sb->data_size += sizeof(SNAPSHOT_ITEM) + size;
-	sb->num_items++;
-	
-	dbg_assert(sb->data_size < MAX_SNAPSHOT_SIZE, "too much data");
-	dbg_assert(sb->num_items < SNAPBUILD_MAX_ITEMS, "too many items");
-
-	return snapitem_data(obj);
-}
diff --git a/src/engine/e_snapshot.cpp b/src/engine/e_snapshot.cpp
new file mode 100644
index 00000000..65487665
--- /dev/null
+++ b/src/engine/e_snapshot.cpp
@@ -0,0 +1,571 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <stdlib.h>
+#include "e_snapshot.h"
+#include "e_engine.h"
+#include "e_compression.h"
+#include "e_common_interface.h"
+
+
+/* TODO: strange arbitrary number */
+static short item_sizes[64] = {0};
+
+void snap_set_staticsize(int itemtype, int size)
+{
+	item_sizes[itemtype] = size;
+}
+
+CSnapshotItem *CSnapshot::GetItem(int Index)
+{
+	return (CSnapshotItem *)(DataStart() + Offsets()[Index]);
+}
+
+int CSnapshot::GetItemSize(int Index)
+{
+    if(Index == m_NumItems-1)
+        return (m_DataSize - Offsets()[Index]) - sizeof(CSnapshotItem);
+    return (Offsets()[Index+1] - Offsets()[Index]) - sizeof(CSnapshotItem);
+}
+
+int CSnapshot::GetItemIndex(int Key)
+{
+    /* TODO: OPT: this should not be a linear search. very bad */
+    for(int i = 0; i < m_NumItems; i++)
+    {
+        if(GetItem(i)->Key() == Key)
+            return i;
+    }
+    return -1;
+}
+
+// TODO: clean up this
+typedef struct 
+{
+	int num;
+	int keys[64];
+	int index[64];
+} ITEMLIST;
+
+static ITEMLIST sorted[256];
+
+int CSnapshot::GenerateHash()
+{
+    for(int i = 0; i < 256; i++)
+    	sorted[i].num = 0;
+    	
+    for(int i = 0; i < m_NumItems; i++)
+    {
+    	int Key = GetItem(i)->Key();
+    	int HashID = ((Key>>8)&0xf0) | (Key&0xf);
+    	if(sorted[HashID].num != 64)
+    	{
+			sorted[HashID].index[sorted[HashID].num] = i;
+			sorted[HashID].keys[sorted[HashID].num] = Key;
+			sorted[HashID].num++;
+		}
+	}
+    return 0;
+}
+
+int CSnapshot::GetItemIndexHashed(int Key)
+{
+   	int HashID = ((Key>>8)&0xf0) | (Key&0xf);
+   	for(int i = 0; i < sorted[HashID].num; i++)
+   	{
+   		if(sorted[HashID].keys[i] == Key)
+   			return sorted[HashID].index[i];
+	}
+	
+	return -1;
+}
+
+
+
+static const int MAX_ITEMS = 512;
+static CSnapshotDelta empty = {0,0,0,{0}};
+
+CSnapshotDelta *CSnapshot::EmptyDelta()
+{
+	return &empty;
+}
+
+int CSnapshot::Crc()
+{
+	int crc = 0;
+	
+	for(int i = 0; i < m_NumItems; i++)
+	{
+		CSnapshotItem *pItem = GetItem(i);
+		int Size = GetItemSize(i);
+		
+		for(int b = 0; b < Size/4; b++)
+			crc += pItem->Data()[b];
+	}
+	return crc;
+}
+
+void CSnapshot::DebugDump()
+{
+	dbg_msg("snapshot", "data_size=%d num_items=%d", m_DataSize, m_NumItems);
+	for(int i = 0; i < m_NumItems; i++)
+	{
+		CSnapshotItem *pItem = GetItem(i);
+		int Size = GetItemSize(i);
+		dbg_msg("snapshot", "\ttype=%d id=%d", pItem->Type(), pItem->ID());
+		for(int b = 0; b < Size/4; b++)
+			dbg_msg("snapshot", "\t\t%3d %12d\t%08x", b, pItem->Data()[b], pItem->Data()[b]);
+	}
+}
+
+
+// TODO: remove these
+int snapshot_data_rate[0xffff] = {0};
+int snapshot_data_updates[0xffff] = {0};
+static int snapshot_current = 0;
+
+static int diff_item(int *past, int *current, int *out, int size)
+{
+	int needed = 0;
+	while(size)
+	{
+		*out = *current-*past;
+		needed |= *out;
+		out++;
+		past++;
+		current++;
+		size--;
+	}
+	
+	return needed;
+}
+
+static void undiff_item(int *past, int *diff, int *out, int size)
+{
+	while(size)
+	{
+		*out = *past+*diff;
+		
+		if(*diff == 0)
+			snapshot_data_rate[snapshot_current] += 1;
+		else
+		{
+			unsigned char buf[16];
+			unsigned char *end = vint_pack(buf,  *diff);
+			snapshot_data_rate[snapshot_current] += (int)(end - (unsigned char*)buf) * 8;
+		}
+		
+		out++;
+		past++;
+		diff++;
+		size--;
+	}
+}
+
+
+/* TODO: OPT: this should be made much faster */
+int CSnapshot::CreateDelta(CSnapshot *from, CSnapshot *to, void *dstdata)
+{
+	static PERFORMACE_INFO hash_scope = {"hash", 0};
+	CSnapshotDelta *delta = (CSnapshotDelta *)dstdata;
+	int *data = (int *)delta->m_pData;
+	int i, itemsize, pastindex;
+	CSnapshotItem *pFromItem;
+	CSnapshotItem *pCurItem;
+	CSnapshotItem *pPastItem;
+	int count = 0;
+	int size_count = 0;
+	
+	delta->m_NumDeletedItems = 0;
+	delta->m_NumUpdateItems = 0;
+	delta->m_NumTempItems = 0;
+	
+	perf_start(&hash_scope);
+	to->GenerateHash();
+	perf_end();
+
+	/* pack deleted stuff */
+	{
+		static PERFORMACE_INFO scope = {"delete", 0};
+		perf_start(&scope);
+		
+		for(i = 0; i < from->m_NumItems; i++)
+		{
+			pFromItem = from->GetItem(i);
+			if(to->GetItemIndexHashed(pFromItem->Key()) == -1)
+			{
+				/* deleted */
+				delta->m_NumDeletedItems++;
+				*data = pFromItem->Key();
+				data++;
+			}
+		}
+		
+		perf_end();
+	}
+	
+	perf_start(&hash_scope);
+	from->GenerateHash();
+	perf_end();
+	
+	/* pack updated stuff */
+	{
+		static PERFORMACE_INFO scope = {"update", 0};
+		int pastindecies[1024];
+		perf_start(&scope);
+
+		/* fetch previous indices */
+		/* we do this as a separate pass because it helps the cache */
+		{
+			static PERFORMACE_INFO scope = {"find", 0};
+			perf_start(&scope);
+			for(i = 0; i < to->m_NumItems; i++)
+			{
+				pCurItem = to->GetItem(i);  /* O(1) .. O(n) */
+				pastindecies[i] = from->GetItemIndexHashed(pCurItem->Key()); /* O(n) .. O(n^n)*/
+			}
+			perf_end();
+		}		
+			
+		for(i = 0; i < to->m_NumItems; i++)
+		{
+			/* do delta */
+			itemsize = to->GetItemSize(i); /* O(1) .. O(n) */
+			pCurItem = to->GetItem(i);  /* O(1) .. O(n) */
+			pastindex = pastindecies[i];
+			
+			if(pastindex != -1)
+			{
+				static PERFORMACE_INFO scope = {"diff", 0};
+				int *item_data_dst = data+3;
+				perf_start(&scope);
+		
+				pPastItem = from->GetItem(pastindex);
+				
+				if(item_sizes[pCurItem->Type()])
+					item_data_dst = data+2;
+				
+				if(diff_item((int*)pPastItem->Data(), (int*)pCurItem->Data(), item_data_dst, itemsize/4))
+				{
+					
+					*data++ = pCurItem->Type();
+					*data++ = pCurItem->ID();
+					if(!item_sizes[pCurItem->Type()])
+						*data++ = itemsize/4;
+					data += itemsize/4;
+					delta->m_NumUpdateItems++;
+				}
+				perf_end();
+			}
+			else
+			{
+				static PERFORMACE_INFO scope = {"copy", 0};
+				perf_start(&scope);
+				
+				*data++ = pCurItem->Type();
+				*data++ = pCurItem->ID();
+				if(!item_sizes[pCurItem->Type()])
+					*data++ = itemsize/4;
+				
+				mem_copy(data, pCurItem->Data(), itemsize);
+				size_count += itemsize;
+				data += itemsize/4;
+				delta->m_NumUpdateItems++;
+				count++;
+				
+				perf_end();
+			}
+		}
+		
+		perf_end();
+	}
+	
+	if(0)
+	{
+		dbg_msg("snapshot", "%d %d %d",
+			delta->m_NumDeletedItems,
+			delta->m_NumUpdateItems,
+			delta->m_NumTempItems);
+	}
+
+	/*
+	// TODO: pack temp stuff
+	
+	// finish
+	//mem_copy(delta->offsets, deleted, delta->num_deleted_items*sizeof(int));
+	//mem_copy(&(delta->offsets[delta->num_deleted_items]), update, delta->num_update_items*sizeof(int));
+	//mem_copy(&(delta->offsets[delta->num_deleted_items+delta->num_update_items]), temp, delta->num_temp_items*sizeof(int));
+	//mem_copy(delta->data_start(), data, data_size);
+	//delta->data_size = data_size;
+	* */
+	
+	if(!delta->m_NumDeletedItems && !delta->m_NumUpdateItems && !delta->m_NumTempItems)
+		return 0;
+	
+	return (int)((char*)data-(char*)dstdata);
+}
+
+static int range_check(void *end, void *ptr, int size)
+{
+	if((const char *)ptr + size > (const char *)end)
+		return -1;
+	return 0;
+}
+
+int CSnapshot::UnpackDelta(CSnapshot *from, CSnapshot *to, void *srcdata, int data_size)
+{
+	CSnapshotBuilder builder;
+	CSnapshotDelta *delta = (CSnapshotDelta *)srcdata;
+	int *data = (int *)delta->m_pData;
+	int *end = (int *)(((char *)srcdata + data_size));
+	
+	CSnapshotItem *fromitem;
+	int i, d, keep, itemsize;
+	int *deleted;
+	int id, type, key;
+	int fromindex;
+	int *newdata;
+			
+	builder.Init();
+	
+	/* unpack deleted stuff */
+	deleted = data;
+	data += delta->m_NumDeletedItems;
+	if(data > end)
+		return -1;
+
+	/* copy all non deleted stuff */
+	for(i = 0; i < from->m_NumItems; i++)
+	{
+		/* dbg_assert(0, "fail!"); */
+		fromitem = from->GetItem(i);
+		itemsize = from->GetItemSize(i); 
+		keep = 1;
+		for(d = 0; d < delta->m_NumDeletedItems; d++)
+		{
+			if(deleted[d] == fromitem->Key())
+			{
+				keep = 0;
+				break;
+			}
+		}
+		
+		if(keep)
+		{
+			/* keep it */
+			mem_copy(
+				builder.NewItem(fromitem->Type(), fromitem->ID(), itemsize),
+				fromitem->Data(), itemsize);
+		}
+	}
+		
+	/* unpack updated stuff */
+	for(i = 0; i < delta->m_NumUpdateItems; i++)
+	{
+		if(data+2 > end)
+			return -1;
+		
+		type = *data++;
+		id = *data++;
+		if(item_sizes[type])
+			itemsize = item_sizes[type];
+		else
+		{
+			if(data+1 > end)
+				return -2;
+			itemsize = (*data++) * 4;
+		}
+		snapshot_current = type;
+		
+		if(range_check(end, data, itemsize) || itemsize < 0) return -3;
+		
+		key = (type<<16)|id;
+		
+		/* create the item if needed */
+		newdata = builder.GetItemData(key);
+		if(!newdata)
+			newdata = (int *)builder.NewItem(key>>16, key&0xffff, itemsize);
+
+		/*if(range_check(end, newdata, itemsize)) return -4;*/
+			
+		fromindex = from->GetItemIndex(key);
+		if(fromindex != -1)
+		{
+			/* we got an update so we need to apply the diff */
+			undiff_item((int *)from->GetItem(fromindex)->Data(), data, newdata, itemsize/4);
+			snapshot_data_updates[snapshot_current]++;
+		}
+		else /* no previous, just copy the data */
+		{
+			mem_copy(newdata, data, itemsize);
+			snapshot_data_rate[snapshot_current] += itemsize*8;
+			snapshot_data_updates[snapshot_current]++;
+		}
+			
+		data += itemsize/4;
+	}
+	
+	/* finish up */
+	return builder.Finish(to);
+}
+
+/* CSnapshotStorage */
+
+void CSnapshotStorage::Init()
+{
+	m_pFirst = 0;
+	m_pLast = 0;
+}
+
+void CSnapshotStorage::PurgeAll()
+{
+	CHolder *pHolder = m_pFirst;
+	CHolder *pNext;
+
+	while(pHolder)
+	{
+		pNext = pHolder->m_pNext;
+		mem_free(pHolder);
+		pHolder = pNext;
+	}
+
+	/* no more snapshots in storage */
+	m_pFirst = 0;
+	m_pLast = 0;
+}
+
+void CSnapshotStorage::PurgeUntil(int Tick)
+{
+	CHolder *pHolder = m_pFirst;
+	CHolder *pNext;
+	
+	while(pHolder)
+	{
+		pNext = pHolder->m_pNext;
+		if(pHolder->m_Tick >= Tick)
+			return; /* no more to remove */
+		mem_free(pHolder);
+		
+		/* did we come to the end of the list? */
+        if (!pNext)
+            break;
+
+		m_pFirst = pNext;
+		pNext->m_pPrev = 0x0;
+		
+		pHolder = pNext;
+	}
+	
+	/* no more snapshots in storage */
+	m_pFirst = 0;
+	m_pLast = 0;
+}
+
+void CSnapshotStorage::Add(int Tick, int64 Tagtime, int DataSize, void *pData, int CreateAlt)
+{
+	/* allocate memory for holder + snapshot_data */
+	int TotalSize = sizeof(CHolder)+DataSize;
+	
+	if(CreateAlt)
+		TotalSize += DataSize;
+	
+	CHolder *pHolder = (CHolder *)mem_alloc(TotalSize, 1);
+	
+	/* set data */
+	pHolder->m_Tick = Tick;
+	pHolder->m_Tagtime = Tagtime;
+	pHolder->m_SnapSize = DataSize;
+	pHolder->m_pSnap = (CSnapshot*)(pHolder+1);
+	mem_copy(pHolder->m_pSnap, pData, DataSize);
+
+	if(CreateAlt) /* create alternative if wanted */
+	{
+		pHolder->m_pAltSnap = (CSnapshot*)(((char *)pHolder->m_pSnap) + DataSize);
+		mem_copy(pHolder->m_pAltSnap, pData, DataSize);
+	}
+	else
+		pHolder->m_pAltSnap = 0;
+		
+	
+	/* link */
+	pHolder->m_pNext = 0;
+	pHolder->m_pPrev = m_pLast;
+	if(m_pLast)
+		m_pLast->m_pNext = pHolder;
+	else
+		m_pFirst = pHolder;
+	m_pLast = pHolder;
+}
+
+int CSnapshotStorage::Get(int Tick, int64 *pTagtime, CSnapshot **ppData, CSnapshot **ppAltData)
+{
+	CHolder *pHolder = m_pFirst;
+	
+	while(pHolder)
+	{
+		if(pHolder->m_Tick == Tick)
+		{
+			if(pTagtime)
+				*pTagtime = pHolder->m_Tagtime;
+			if(ppData)
+				*ppData = pHolder->m_pSnap;
+			if(ppAltData)
+				*ppData = pHolder->m_pAltSnap;
+			return pHolder->m_SnapSize;
+		}
+		
+		pHolder = pHolder->m_pNext;
+	}
+	
+	return -1;
+}
+
+/* CSnapshotBuilder */
+
+void CSnapshotBuilder::Init()
+{
+	m_DataSize = 0;
+	m_NumItems = 0;
+}
+
+CSnapshotItem *CSnapshotBuilder::GetItem(int Index) 
+{
+	return (CSnapshotItem *)&(m_aData[m_aOffsets[Index]]);
+}
+
+int *CSnapshotBuilder::GetItemData(int key)
+{
+	int i;
+	for(i = 0; i < m_NumItems; i++)
+	{
+		if(GetItem(i)->Key() == key)
+			return (int *)GetItem(i)->Data();
+	}
+	return 0;
+}
+
+int CSnapshotBuilder::Finish(void *snapdata)
+{
+	/* flattern and make the snapshot */
+	CSnapshot *pSnap = (CSnapshot *)snapdata;
+	int OffsetSize = sizeof(int)*m_NumItems;
+	pSnap->m_DataSize = m_DataSize;
+	pSnap->m_NumItems = m_NumItems;
+	mem_copy(pSnap->Offsets(), m_aOffsets, OffsetSize);
+	mem_copy(pSnap->DataStart(), m_aData, m_DataSize);
+	return sizeof(CSnapshot) + OffsetSize + m_DataSize;
+}
+
+void *CSnapshotBuilder::NewItem(int Type, int ID, int Size)
+{
+	CSnapshotItem *pObj = (CSnapshotItem *)(m_aData + m_DataSize);
+
+	mem_zero(pObj, sizeof(CSnapshotItem) + Size);
+	pObj->m_TypeAndID = (Type<<16)|ID;
+	m_aOffsets[m_NumItems] = m_DataSize;
+	m_DataSize += sizeof(CSnapshotItem) + Size;
+	m_NumItems++;
+	
+	dbg_assert(m_DataSize < CSnapshot::MAX_SIZE, "too much data");
+	dbg_assert(m_NumItems < MAX_ITEMS, "too many items");
+
+	return pObj->Data();
+}
diff --git a/src/engine/e_snapshot.h b/src/engine/e_snapshot.h
index f57c95c0..60dc254c 100644
--- a/src/engine/e_snapshot.h
+++ b/src/engine/e_snapshot.h
@@ -4,89 +4,115 @@
 
 #include <base/system.h>
 
-/* SNAPSHOT */
+/* CSnapshot */
 
-enum
+
+
+class CSnapshotItem
 {
-	MAX_SNAPSHOT_SIZE=64*1024
+public:
+	int m_TypeAndID;
+	
+	int *Data() { return (int *)(this+1); }
+	int Type() { return m_TypeAndID>>16; }
+	int ID() { return m_TypeAndID&0xffff; }
+	int Key() { return m_TypeAndID; }
 };
 
-typedef struct
+class CSnapshotDelta
 {
-	int type_and_id;
-} SNAPSHOT_ITEM;
+public:
+	int m_NumDeletedItems;
+	int m_NumUpdateItems;
+	int m_NumTempItems; /* needed? */
+	int m_pData[1];
+};
 
-typedef struct 
+// TODO: hide a lot of these members
+class CSnapshot
 {
-	int data_size;
-	int num_items;
-} SNAPSHOT;
-
-int *snapitem_data(SNAPSHOT_ITEM *item);
-int snapitem_type(SNAPSHOT_ITEM *item);
-int snapitem_id(SNAPSHOT_ITEM *item);
-int snapitem_key(SNAPSHOT_ITEM *item);
-
-int *snapshot_offsets(SNAPSHOT *snap);
-char *snapshot_datastart(SNAPSHOT *snap);
-
-SNAPSHOT_ITEM *snapshot_get_item(SNAPSHOT *snap, int index);
-int snapshot_get_item_datasize(SNAPSHOT *snap, int index);
-int snapshot_get_item_index(SNAPSHOT *snap, int key);
+public:
+	enum
+	{
+		MAX_SIZE=64*1024
+	};
+
+	int m_DataSize;
+	int m_NumItems;
+	
+	int *Offsets() const { return (int *)(this+1); }
+	char *DataStart() const { return (char*)(Offsets()+m_NumItems); }
+	CSnapshotItem *GetItem(int Index);
+	int GetItemSize(int Index);
+	int GetItemIndex(int Key);
+
+	int Crc();
+	void DebugDump();
+
+	// TODO: move these
+	int GetItemIndexHashed(int Key);
+	int GenerateHash();
+	
+	//
+	static CSnapshotDelta *EmptyDelta();
+	static int CreateDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pData);
+	static int UnpackDelta(CSnapshot *pFrom, CSnapshot *pTo, void *pData, int DataSize);
+};
 
-void *snapshot_empty_delta();
-int snapshot_crc(SNAPSHOT *snap);
-void snapshot_debug_dump(SNAPSHOT *snap);
-int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *data);
-int snapshot_unpack_delta(SNAPSHOT *from, SNAPSHOT *to, void *data, int data_size);
+/* CSnapshotStorage */
 
-/* SNAPSTORAGE */
 
-typedef struct SNAPSTORAGE_HOLDER_t
+class CSnapshotStorage
 {
-	struct SNAPSTORAGE_HOLDER_t *prev;
-	struct SNAPSTORAGE_HOLDER_t *next;
-	
-	int64 tagtime;
-	int tick;
-	
-	int snap_size;
-	SNAPSHOT *snap;
-	SNAPSHOT *alt_snap;
-} SNAPSTORAGE_HOLDER;
- 
-typedef struct SNAPSTORAGE_t
+public:
+	class CHolder
+	{
+	public:
+		CHolder *m_pPrev;
+		CHolder *m_pNext;
+		
+		int64 m_Tagtime;
+		int m_Tick;
+		
+		int m_SnapSize;
+		CSnapshot *m_pSnap;
+		CSnapshot *m_pAltSnap;
+	};
+	 
+
+	CHolder *m_pFirst;
+	CHolder *m_pLast;
+
+	void Init();
+	void PurgeAll();
+	void PurgeUntil(int Tick);
+	void Add(int Tick, int64 Tagtime, int DataSize, void *pData, int CreateAlt);
+	int Get(int Tick, int64 *Tagtime, CSnapshot **pData, CSnapshot **ppAltData);
+};
+
+class CSnapshotBuilder
 {
-	SNAPSTORAGE_HOLDER *first;
-	SNAPSTORAGE_HOLDER *last;
-} SNAPSTORAGE;
+	enum
+	{
+		MAX_ITEMS = 1024*2
+	};
 
-void snapstorage_init(SNAPSTORAGE *ss);
-void snapstorage_purge_all(SNAPSTORAGE *ss);
-void snapstorage_purge_until(SNAPSTORAGE *ss, int tick);
-void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, void *data, int create_alt);
-int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data, SNAPSHOT **alt_data);
+	char m_aData[CSnapshot::MAX_SIZE];
+	int m_DataSize;
 
-/* SNAPBUILD */
+	int m_aOffsets[MAX_ITEMS];
+	int m_NumItems;
 
-enum
-{
-	SNAPBUILD_MAX_ITEMS = 1024*2
+public:
+	void Init();
+	
+	void *NewItem(int Type, int ID, int Size);
+	
+	CSnapshotItem *GetItem(int Index);
+	int *GetItemData(int Key);
+	
+	int Finish(void *Snapdata);
 };
 
-typedef struct SNAPBUILD
-{
-	char data[MAX_SNAPSHOT_SIZE];
-	int data_size;
-
-	int offsets[SNAPBUILD_MAX_ITEMS];
-	int num_items;
-} SNAPBUILD;
-
-void snapbuild_init(SNAPBUILD *sb);
-SNAPSHOT_ITEM *snapbuild_get_item(SNAPBUILD *sb, int index);
-int *snapbuild_get_item_data(SNAPBUILD *sb, int key);
-int snapbuild_finish(SNAPBUILD *sb, void *snapdata);
-void *snapbuild_new_item(SNAPBUILD *sb, int type, int id, int size);
 
 #endif /* ENGINE_SNAPSHOT_H */
diff --git a/src/engine/server/es_register.c b/src/engine/server/es_register.cpp
index b3ac70a6..0eb5dba5 100644
--- a/src/engine/server/es_register.c
+++ b/src/engine/server/es_register.cpp
@@ -6,7 +6,7 @@
 
 #include <mastersrv/mastersrv.h>
 
-extern NETSERVER *net;
+extern CNetServer *m_pNetServer;
 
 enum
 {
@@ -29,48 +29,48 @@ static void register_new_state(int state)
 	register_state_start = time_get();
 }
 
-static void register_send_fwcheckresponse(NETADDR *addr)
+static void register_send_fwcheckresponse(NETADDR *pAddr)
 {
-	NETCHUNK packet;
-	packet.client_id = -1;
-	packet.address = *addr;
-	packet.flags = NETSENDFLAG_CONNLESS;
-	packet.data_size = sizeof(SERVERBROWSE_FWRESPONSE);
-	packet.data = SERVERBROWSE_FWRESPONSE;
-	netserver_send(net, &packet);
+	CNetChunk Packet;
+	Packet.m_ClientID = -1;
+	Packet.m_Address = *pAddr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
+	Packet.m_DataSize = sizeof(SERVERBROWSE_FWRESPONSE);
+	Packet.m_pData = SERVERBROWSE_FWRESPONSE;
+	m_pNetServer->Send(&Packet);
 }
 	
 static void register_send_heartbeat(NETADDR addr)
 {
 	static unsigned char data[sizeof(SERVERBROWSE_HEARTBEAT) + 2];
 	unsigned short port = config.sv_port;
-	NETCHUNK packet;
+	CNetChunk Packet;
 	
 	mem_copy(data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT));
 	
-	packet.client_id = -1;
-	packet.address = addr;
-	packet.flags = NETSENDFLAG_CONNLESS;
-	packet.data_size = sizeof(SERVERBROWSE_HEARTBEAT) + 2;
-	packet.data = &data;
+	Packet.m_ClientID = -1;
+	Packet.m_Address = addr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
+	Packet.m_DataSize = sizeof(SERVERBROWSE_HEARTBEAT) + 2;
+	Packet.m_pData = &data;
 
 	/* supply the set port that the master can use if it has problems */	
 	if(config.sv_external_port)
 		port = config.sv_external_port;
 	data[sizeof(SERVERBROWSE_HEARTBEAT)] = port >> 8;
 	data[sizeof(SERVERBROWSE_HEARTBEAT)+1] = port&0xff;
-	netserver_send(net, &packet);
+	m_pNetServer->Send(&Packet);
 }
 
-static void register_send_count_request(NETADDR addr)
+static void register_send_count_request(NETADDR Addr)
 {
-	NETCHUNK packet;
-	packet.client_id = -1;
-	packet.address = addr;
-	packet.flags = NETSENDFLAG_CONNLESS;
-	packet.data_size = sizeof(SERVERBROWSE_GETCOUNT);
-	packet.data = SERVERBROWSE_GETCOUNT;
-	netserver_send(net, &packet);
+	CNetChunk Packet;
+	Packet.m_ClientID = -1;
+	Packet.m_Address = Addr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
+	Packet.m_DataSize = sizeof(SERVERBROWSE_GETCOUNT);
+	Packet.m_pData = SERVERBROWSE_GETCOUNT;
+	m_pNetServer->Send(&Packet);
 }
 
 typedef struct
@@ -221,50 +221,49 @@ void register_update()
 	}
 }
 
-static void register_got_count(NETCHUNK *p)
+static void register_got_count(CNetChunk *pChunk)
 {
-	unsigned char *data = (unsigned char *)p->data;
-	int count = (data[sizeof(SERVERBROWSE_COUNT)]<<8) | data[sizeof(SERVERBROWSE_COUNT)+1];
-	int i;
+	unsigned char *pData = (unsigned char *)pChunk->m_pData;
+	int Count = (pData[sizeof(SERVERBROWSE_COUNT)]<<8) | pData[sizeof(SERVERBROWSE_COUNT)+1];
 
-	for(i = 0; i < MAX_MASTERSERVERS; i++)
+	for(int i = 0; i < MAX_MASTERSERVERS; i++)
 	{
-		if(net_addr_comp(&masterserver_info[i].addr, &p->address) == 0)
+		if(net_addr_comp(&masterserver_info[i].addr, &pChunk->m_Address) == 0)
 		{
-			masterserver_info[i].count = count;
+			masterserver_info[i].count = Count;
 			break;
 		}
 	}
 }
 
-int register_process_packet(NETCHUNK *packet)
+int register_process_packet(CNetChunk *pPacket)
 {
-	if(packet->data_size == sizeof(SERVERBROWSE_FWCHECK) &&
-		memcmp(packet->data, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0)
+	if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWCHECK) &&
+		memcmp(pPacket->m_pData, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0)
 	{
-		register_send_fwcheckresponse(&packet->address);
+		register_send_fwcheckresponse(&pPacket->m_Address);
 		return 1;
 	}
-	else if(packet->data_size == sizeof(SERVERBROWSE_FWOK) &&
-		memcmp(packet->data, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0)
+	else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWOK) &&
+		memcmp(pPacket->m_pData, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0)
 	{
 		if(register_first)
 			dbg_msg("register", "no firewall/nat problems detected");
 		register_new_state(REGISTERSTATE_REGISTERED);
 		return 1;
 	}
-	else if(packet->data_size == sizeof(SERVERBROWSE_FWERROR) &&
-		memcmp(packet->data, SERVERBROWSE_FWERROR, sizeof(SERVERBROWSE_FWERROR)) == 0)
+	else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWERROR) &&
+		memcmp(pPacket->m_pData, SERVERBROWSE_FWERROR, sizeof(SERVERBROWSE_FWERROR)) == 0)
 	{
 		dbg_msg("register", "ERROR: the master server reports that clients can not connect to this server.");
 		dbg_msg("register", "ERROR: configure your firewall/nat to let through udp on port %d.", config.sv_port);
 		register_new_state(REGISTERSTATE_ERROR);
 		return 1;
 	}
-	else if(packet->data_size == sizeof(SERVERBROWSE_COUNT)+2 &&
-		memcmp(packet->data, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)) == 0)
+	else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_COUNT)+2 &&
+		memcmp(pPacket->m_pData, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)) == 0)
 	{
-		register_got_count(packet);
+		register_got_count(pPacket);
 		return 1;
 	}
 
diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c
deleted file mode 100644
index 8763351d..00000000
--- a/src/engine/server/es_server.c
+++ /dev/null
@@ -1,1380 +0,0 @@
-/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <base/system.h>
-
-#include <engine/e_config.h>
-#include <engine/e_engine.h>
-#include <engine/e_server_interface.h>
-
-#include <engine/e_protocol.h>
-#include <engine/e_snapshot.h>
-
-#include <engine/e_compression.h>
-
-#include <engine/e_network.h>
-#include <engine/e_config.h>
-#include <engine/e_packer.h>
-#include <engine/e_datafile.h>
-#include <engine/e_demorec.h>
-
-#include <mastersrv/mastersrv.h>
-
-#if defined(CONF_FAMILY_WINDOWS) 
-	#define _WIN32_WINNT 0x0500 
-	#include <windows.h> 
-#endif 
-
-static SNAPBUILD builder;
-
-static int64 game_start_time;
-static int current_tick = 0;
-static int run_server = 1;
-
-static char browseinfo_gametype[16] = {0};
-static int browseinfo_progression = -1;
-
-static int64 lastheartbeat;
-/*static NETADDR4 master_server;*/
-
-static char current_map[64];
-static int current_map_crc;
-static unsigned char *current_map_data = 0;
-static int current_map_size = 0;
-
-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 snapbuild_new_item(&builder, type, id, size);
-}
-
-typedef struct
-{
-	short next;
-	short state; /* 0 = free, 1 = alloced, 2 = timed */
-	int timeout;
-} SNAP_ID;
-
-static const int MAX_IDS = 16*1024; /* should be lowered */
-static SNAP_ID snap_ids[16*1024];
-static int snap_first_free_id;
-static int snap_first_timed_id;
-static int snap_last_timed_id;
-static int snap_id_usage;
-static int snap_id_inusage;
-static int snap_id_inited = 0;
-
-enum
-{
-	SRVCLIENT_STATE_EMPTY = 0,
-	SRVCLIENT_STATE_AUTH,
-	SRVCLIENT_STATE_CONNECTING,
-	SRVCLIENT_STATE_READY,
-	SRVCLIENT_STATE_INGAME,
-	
-	SRVCLIENT_SNAPRATE_INIT=0,
-	SRVCLIENT_SNAPRATE_FULL,
-	SRVCLIENT_SNAPRATE_RECOVER
-};
-
-typedef struct 
-{
-	int data[MAX_INPUT_SIZE];
-	int game_tick; /* the tick that was chosen for the input */
-} CLIENT_INPUT;
-	
-/* */
-typedef struct
-{
-	/* connection state info */
-	int state;
-	int latency;
-	int snap_rate;
-	
-	int last_acked_snapshot;
-	int last_input_tick;
-	SNAPSTORAGE snapshots;
-	
-	CLIENT_INPUT latestinput;
-	CLIENT_INPUT inputs[200]; /* TODO: handle input better */
-	int current_input;
-	
-	char name[MAX_NAME_LENGTH];
-	char clan[MAX_CLANNAME_LENGTH];
-	int score;
-	int authed;
-} CLIENT;
-
-static CLIENT clients[MAX_CLIENTS];
-NETSERVER *net;
-
-static void snap_init_id()
-{
-	int i;
-	if(snap_id_inited)
-		return;
-	
-	for(i = 0; i < MAX_IDS; i++)
-	{
-		snap_ids[i].next = i+1;
-		snap_ids[i].state = 0;
-	}
-		
-	snap_ids[MAX_IDS-1].next = -1;
-	snap_first_free_id = 0;
-	snap_first_timed_id = -1;
-	snap_last_timed_id = -1;
-	snap_id_usage = 0;
-	snap_id_inusage = 0;
-	
-	snap_id_inited = 1;
-}
-
-static void snap_remove_first_timeout()
-{
-	int next_timed = snap_ids[snap_first_timed_id].next;
-	
-	/* add it to the free list */
-	snap_ids[snap_first_timed_id].next = snap_first_free_id;
-	snap_ids[snap_first_timed_id].state = 0;
-	snap_first_free_id = snap_first_timed_id;
-	
-	/* remove it from the timed list */
-	snap_first_timed_id = next_timed;
-	if(snap_first_timed_id == -1)
-		snap_last_timed_id = -1;
-		
-	snap_id_usage--;
-}
-
-int snap_new_id()
-{
-	int id;
-	int64 now = time_get();
-	if(!snap_id_inited)
-		snap_init_id();
-	
-	/* process timed ids */
-	while(snap_first_timed_id != -1 && snap_ids[snap_first_timed_id].timeout < now)
-		snap_remove_first_timeout();
-	
-	id = snap_first_free_id;
-	dbg_assert(id != -1, "id error");
-	snap_first_free_id = snap_ids[snap_first_free_id].next;
-	snap_ids[id].state = 1;
-	snap_id_usage++;
-	snap_id_inusage++;
-	return id;
-}
-
-void snap_timeout_ids()
-{
-	/* process timed ids */
-	while(snap_first_timed_id != -1)
-		snap_remove_first_timeout();
-}
-
-void snap_free_id(int id)
-{
-	dbg_assert(snap_ids[id].state == 1, "id is not alloced");
-
-	snap_id_inusage--;
-	snap_ids[id].state = 2;
-	snap_ids[id].timeout = time_get()+time_freq()*5;
-	snap_ids[id].next = -1;
-	
-	if(snap_last_timed_id != -1)
-	{
-		snap_ids[snap_last_timed_id].next = id;
-		snap_last_timed_id = id;
-	}
-	else
-	{
-		snap_first_timed_id = id;
-		snap_last_timed_id = id;
-	}
-}
-
-int *server_latestinput(int client_id, int *size)
-{
-	if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
-		return 0;
-	return clients[client_id].latestinput.data;
-}
-
-const char *server_clientname(int client_id)
-{
-	if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
-		return "(invalid client)";
-	return clients[client_id].name;
-}
-
-static const char *str_ltrim(const char *str)
-{
-	while(*str && *str <= 32)
-		str++;
-	return str;
-}
-
-static void str_rtrim(char *str)
-{
-	int i = str_length(str);
-	while(i >= 0)
-	{
-		if(str[i] > 32)
-			break;
-		str[i] = 0;
-		i--;
-	}
-}
-
-static int server_try_setclientname(int client_id, const char *name)
-{
-	int i;
-	char trimmed_name[64];
-
-	/* trim the name */
-	str_copy(trimmed_name, str_ltrim(name), sizeof(trimmed_name));
-	str_rtrim(trimmed_name);
-	dbg_msg("", "'%s' -> '%s'", name, trimmed_name);
-	name = trimmed_name;
-	
-	
-	/* check for empty names */
-	if(!name[0])
-		return -1;
-	
-	/* make sure that two clients doesn't have the same name */
-	for(i = 0; i < MAX_CLIENTS; i++)
-		if(i != client_id && clients[i].state >= SRVCLIENT_STATE_READY)
-		{
-			if(strcmp(name, clients[i].name) == 0)
-				return -1;
-		}
-
-	/* set the client name */
-	str_copy(clients[client_id].name, name, MAX_NAME_LENGTH);
-	return 0;
-}
-
-void server_setclientname(int client_id, const char *name)
-{
-	char nametry[MAX_NAME_LENGTH];
-	int i;
-	if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
-		return;
-		
-	if(!name)
-		return;
-		
-	str_copy(nametry, name, MAX_NAME_LENGTH);
-	if(server_try_setclientname(client_id, nametry))
-	{
-		/* auto rename */
-		for(i = 1;; i++)
-		{
-			str_format(nametry, MAX_NAME_LENGTH, "(%d)%s", i, name);
-			if(server_try_setclientname(client_id, nametry) == 0)
-				break;
-		}
-	}
-}
-
-void server_setclientscore(int client_id, int score)
-{
-	if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
-		return;
-	clients[client_id].score = score;
-}
-
-void server_setbrowseinfo(const char *game_type, int progression)
-{
-	str_copy(browseinfo_gametype, game_type, sizeof(browseinfo_gametype));
-	browseinfo_progression = progression;
-	if(browseinfo_progression > 100)
-		browseinfo_progression = 100;
-	if(browseinfo_progression < -1)
-		browseinfo_progression = -1;
-}
-
-void server_kick(int client_id, const char *reason)
-{
-	if(client_id < 0 || client_id > MAX_CLIENTS)
-		return;
-		
-	if(clients[client_id].state != SRVCLIENT_STATE_EMPTY)
-		netserver_drop(net, client_id, reason);
-}
-
-int server_tick()
-{
-	return current_tick;
-}
-
-int64 server_tick_start_time(int tick)
-{
-	return game_start_time + (time_freq()*tick)/SERVER_TICK_SPEED;
-}
-
-int server_tickspeed()
-{
-	return SERVER_TICK_SPEED;
-}
-
-int server_init()
-{
-	int i;
-	for(i = 0; i < MAX_CLIENTS; i++)
-	{
-		clients[i].state = SRVCLIENT_STATE_EMPTY;
-		clients[i].name[0] = 0;
-		clients[i].clan[0] = 0;
-		snapstorage_init(&clients[i].snapshots);
-	}
-
-	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].state == SRVCLIENT_STATE_INGAME)
-	{
-		info->name = clients[client_id].name;
-		info->latency = clients[client_id].latency;
-		return 1;
-	}
-	return 0;
-}
-
-int server_send_msg(int client_id)
-{
-	const MSG_INFO *info = msg_get_info();
-	NETCHUNK packet;
-	if(!info)
-		return -1;
-		
-	mem_zero(&packet, sizeof(NETCHUNK));
-	
-	packet.client_id = client_id;
-	packet.data = info->data;
-	packet.data_size = info->size;
-
-	if(info->flags&MSGFLAG_VITAL)
-		packet.flags |= NETSENDFLAG_VITAL;
-	if(info->flags&MSGFLAG_FLUSH)
-		packet.flags |= NETSENDFLAG_FLUSH;
-	
-	/* write message to demo recorder */
-	if(!(info->flags&MSGFLAG_NORECORD))
-		demorec_record_message(info->data, info->size);
-
-	if(!(info->flags&MSGFLAG_NOSEND))
-	{
-		if(client_id == -1)
-		{
-			/* broadcast */
-			int i;
-			for(i = 0; i < MAX_CLIENTS; i++)
-				if(clients[i].state == SRVCLIENT_STATE_INGAME)
-				{
-					packet.client_id = i;
-					netserver_send(net, &packet);
-				}
-		}
-		else
-			netserver_send(net, &packet);
-	}
-	return 0;
-}
-
-static void server_do_snap()
-{
-	int i;
-	
-	{
-		static PERFORMACE_INFO scope = {"presnap", 0};
-		perf_start(&scope);
-		mods_presnap();
-		perf_end();
-	}
-	
-	/* create snapshot for demo recording */
-	if(demorec_isrecording())
-	{
-		char data[MAX_SNAPSHOT_SIZE];
-		int snapshot_size;
-
-		/* build snap and possibly add some messages */
-		snapbuild_init(&builder);
-		mods_snap(-1);
-		snapshot_size = snapbuild_finish(&builder, data);
-		
-		/* write snapshot */
-		demorec_record_snapshot(server_tick(), data, snapshot_size);
-	}
-
-	/* create snapshots for all clients */
-	for(i = 0; i < MAX_CLIENTS; i++)
-	{
-		/* client must be ingame to recive snapshots */
-		if(clients[i].state != SRVCLIENT_STATE_INGAME)
-			continue;
-			
-		/* this client is trying to recover, don't spam snapshots */
-		if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_RECOVER && (server_tick()%50) != 0)
-			continue;
-			
-		/* this client is trying to recover, don't spam snapshots */
-		if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_INIT && (server_tick()%10) != 0)
-			continue;
-			
-		{
-			char data[MAX_SNAPSHOT_SIZE];
-			char deltadata[MAX_SNAPSHOT_SIZE];
-			char compdata[MAX_SNAPSHOT_SIZE];
-			int snapshot_size;
-			int crc;
-			static SNAPSHOT emptysnap;
-			SNAPSHOT *deltashot = &emptysnap;
-			int deltashot_size;
-			int delta_tick = -1;
-			int deltasize;
-			static PERFORMACE_INFO scope = {"build", 0};
-			perf_start(&scope);
-
-			snapbuild_init(&builder);
-
-			{
-				static PERFORMACE_INFO scope = {"modsnap", 0};
-				perf_start(&scope);
-				mods_snap(i);
-				perf_end();
-			}
-
-			/* finish snapshot */
-			snapshot_size = snapbuild_finish(&builder, data);
-			crc = snapshot_crc((SNAPSHOT*)data);
-
-			/* remove old snapshos */
-			/* keep 3 seconds worth of snapshots */
-			snapstorage_purge_until(&clients[i].snapshots, current_tick-SERVER_TICK_SPEED*3);
-			
-			/* save it the snapshot */
-			snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data, 0);
-			
-			/* find snapshot that we can preform delta against */
-			emptysnap.data_size = 0;
-			emptysnap.num_items = 0;
-			
-			{
-				deltashot_size = snapstorage_get(&clients[i].snapshots, clients[i].last_acked_snapshot, 0, &deltashot, 0);
-				if(deltashot_size >= 0)
-					delta_tick = clients[i].last_acked_snapshot;
-				else
-				{
-					/* no acked package found, force client to recover rate */
-					if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_FULL)
-						clients[i].snap_rate = SRVCLIENT_SNAPRATE_RECOVER;
-				}
-			}
-			
-			/* create delta */
-			{
-				static PERFORMACE_INFO scope = {"delta", 0};
-				perf_start(&scope);
-				deltasize = snapshot_create_delta(deltashot, (SNAPSHOT*)data, deltadata);
-				perf_end();
-			}
-
-			
-			if(deltasize)
-			{
-				/* compress it */
-				int snapshot_size;
-				const int max_size = MAX_SNAPSHOT_PACKSIZE;
-				int numpackets;
-				int n, left;
-
-				{				
-					static PERFORMACE_INFO scope = {"compress", 0};
-					/*char buffer[512];*/
-					perf_start(&scope);
-					snapshot_size = intpack_compress(deltadata, deltasize, compdata);
-					
-					/*str_hex(buffer, sizeof(buffer), compdata, snapshot_size);
-					dbg_msg("", "deltasize=%d -> %d : %s", deltasize, snapshot_size, buffer);*/
-					
-					perf_end();
-				}
-
-				numpackets = (snapshot_size+max_size-1)/max_size;
-				
-				for(n = 0, left = snapshot_size; left; n++)
-				{
-					int chunk = left < max_size ? left : max_size;
-					left -= chunk;
-
-					if(numpackets == 1)
-						msg_pack_start_system(NETMSG_SNAPSINGLE, MSGFLAG_FLUSH);
-					else
-						msg_pack_start_system(NETMSG_SNAP, MSGFLAG_FLUSH);
-						
-					msg_pack_int(current_tick);
-					msg_pack_int(current_tick-delta_tick); /* compressed with */
-					
-					if(numpackets != 1)
-					{
-						msg_pack_int(numpackets);
-						msg_pack_int(n);
-					}
-					
-					msg_pack_int(crc);
-					msg_pack_int(chunk);
-					msg_pack_raw(&compdata[n*max_size], chunk);
-					msg_pack_end();
-					server_send_msg(i);
-				}
-			}
-			else
-			{
-				msg_pack_start_system(NETMSG_SNAPEMPTY, MSGFLAG_FLUSH);
-				msg_pack_int(current_tick);
-				msg_pack_int(current_tick-delta_tick); /* compressed with */
-				msg_pack_end();
-				server_send_msg(i);
-			}
-			
-			perf_end();
-		}
-	}
-
-	mods_postsnap();
-}
-
-
-static void reset_client(int cid)
-{
-	/* reset input */
-	int i;
-	for(i = 0; i < 200; i++)
-		clients[cid].inputs[i].game_tick = -1;
-	clients[cid].current_input = 0;
-	mem_zero(&clients[cid].latestinput, sizeof(clients[cid].latestinput));
-
-	snapstorage_purge_all(&clients[cid].snapshots);
-	clients[cid].last_acked_snapshot = -1;
-	clients[cid].last_input_tick = -1;
-	clients[cid].snap_rate = SRVCLIENT_SNAPRATE_INIT;
-	clients[cid].score = 0;
-
-}
-
-static int new_client_callback(int cid, void *user)
-{
-	clients[cid].state = SRVCLIENT_STATE_AUTH;
-	clients[cid].name[0] = 0;
-	clients[cid].clan[0] = 0;
-	clients[cid].authed = 0;
-	reset_client(cid);
-	return 0;
-}
-
-static int del_client_callback(int cid, void *user)
-{
-	/* notify the mod about the drop */
-	if(clients[cid].state >= SRVCLIENT_STATE_READY)
-		mods_client_drop(cid);
-	
-	clients[cid].state = SRVCLIENT_STATE_EMPTY;
-	clients[cid].name[0] = 0;
-	clients[cid].clan[0] = 0;
-	clients[cid].authed = 0;
-	snapstorage_purge_all(&clients[cid].snapshots);
-	return 0;
-}
-
-static void server_send_map(int cid)
-{
-	msg_pack_start_system(NETMSG_MAP_CHANGE, MSGFLAG_VITAL|MSGFLAG_FLUSH);
-	msg_pack_string(config.sv_map, 0);
-	msg_pack_int(current_map_crc);
-	msg_pack_end();
-	server_send_msg(cid);
-}
-
-static void server_send_rcon_line(int cid, const char *line)
-{
-	msg_pack_start_system(NETMSG_RCON_LINE, MSGFLAG_VITAL);
-	msg_pack_string(line, 512);
-	msg_pack_end();
-	server_send_msg(cid);
-}
-
-static void server_send_rcon_line_authed(const char *line, void *user_data)
-{
-	static volatile int reentry_guard = 0;
-	int i;
-	
-	if(reentry_guard) return;
-	reentry_guard++;
-	
-	for(i = 0; i < MAX_CLIENTS; i++)
-	{
-		if(clients[i].state != SRVCLIENT_STATE_EMPTY && clients[i].authed)
-			server_send_rcon_line(i, line);
-	}
-	
-	reentry_guard--;
-}
-
-static void server_process_client_packet(NETCHUNK *packet)
-{
-	int cid = packet->client_id;
-	NETADDR addr;
-	
-	int sys;
-	int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
-	
-	if(clients[cid].state == SRVCLIENT_STATE_AUTH)
-	{
-		if(sys && msg == NETMSG_INFO)
-		{
-			char version[64];
-			const char *password;
-			str_copy(version, msg_unpack_string(), 64);
-			if(strcmp(version, mods_net_version()) != 0)
-			{
-				/* OH FUCK! wrong version, drop him */
-				char reason[256];
-				str_format(reason, sizeof(reason), "wrong version. server is running '%s' and client '%s'.", mods_net_version(), version);
-				netserver_drop(net, cid, reason);
-				return;
-			}
-			
-			str_copy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
-			str_copy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
-			password = msg_unpack_string();
-			
-			if(config.password[0] != 0 && strcmp(config.password, password) != 0)
-			{
-				/* wrong password */
-				netserver_drop(net, cid, "wrong password");
-				return;
-			}
-			
-			clients[cid].state = SRVCLIENT_STATE_CONNECTING;
-			server_send_map(cid);
-		}
-	}
-	else
-	{
-		if(sys)
-		{
-			/* system message */
-			if(msg == NETMSG_REQUEST_MAP_DATA)
-			{
-				int chunk = msg_unpack_int();
-				int chunk_size = 1024-128;
-				int offset = chunk * chunk_size;
-				int last = 0;
-				
-				/* drop faulty map data requests */
-				if(chunk < 0 || offset > current_map_size)
-					return;
-				
-				if(offset+chunk_size >= current_map_size)
-				{
-					chunk_size = current_map_size-offset;
-					if(chunk_size < 0)
-						chunk_size = 0;
-					last = 1;
-				}
-				
-				msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH);
-				msg_pack_int(last);
-				msg_pack_int(current_map_size);
-				msg_pack_int(chunk_size);
-				msg_pack_raw(&current_map_data[offset], chunk_size);
-				msg_pack_end();
-				server_send_msg(cid);
-				
-				if(config.debug)
-					dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size);
-			}
-			else if(msg == NETMSG_READY)
-			{
-				if(clients[cid].state == SRVCLIENT_STATE_CONNECTING)
-				{
-					netserver_client_addr(net, cid, &addr);
-					
-					dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d",
-						cid,
-						addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
-						);
-					clients[cid].state = SRVCLIENT_STATE_READY;
-					mods_connected(cid);
-				}
-			}
-			else if(msg == NETMSG_ENTERGAME)
-			{
-				if(clients[cid].state == SRVCLIENT_STATE_READY)
-				{
-					netserver_client_addr(net, cid, &addr);
-					
-					dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d",
-						cid,
-						addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
-						);
-					clients[cid].state = SRVCLIENT_STATE_INGAME;
-					mods_client_enter(cid);
-				}
-			}
-			else if(msg == NETMSG_INPUT)
-			{
-				int tick, size, i;
-				CLIENT_INPUT *input;
-				int64 tagtime;
-				
-				clients[cid].last_acked_snapshot = msg_unpack_int();
-				tick = msg_unpack_int();
-				size = msg_unpack_int();
-				
-				/* check for errors */
-				if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
-					return;
-
-				if(clients[cid].last_acked_snapshot > 0)
-					clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL;
-					
-				if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0)
-					clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq());
-
-				/* add message to report the input timing */
-				/* skip packets that are old */
-				if(tick > clients[cid].last_input_tick)
-				{
-					int time_left = ((server_tick_start_time(tick)-time_get())*1000) / time_freq();
-					msg_pack_start_system(NETMSG_INPUTTIMING, 0);
-					msg_pack_int(tick);
-					msg_pack_int(time_left);
-					msg_pack_end();
-					server_send_msg(cid);
-				}
-
-				clients[cid].last_input_tick = tick;
-
-				input = &clients[cid].inputs[clients[cid].current_input];
-				
-				if(tick <= server_tick())
-					tick = server_tick()+1;
-
-				input->game_tick = tick;
-				
-				for(i = 0; i < size/4; i++)
-					input->data[i] = msg_unpack_int();
-				
-				mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int));
-				
-				clients[cid].current_input++;
-				clients[cid].current_input %= 200;
-			
-				/* call the mod with the fresh input data */
-				if(clients[cid].state == SRVCLIENT_STATE_INGAME)
-					mods_client_direct_input(cid, clients[cid].latestinput.data);
-			}
-			else if(msg == NETMSG_RCON_CMD)
-			{
-				const char *cmd = msg_unpack_string();
-				
-				if(msg_unpack_error() == 0 && clients[cid].authed)
-				{
-					dbg_msg("server", "cid=%d rcon='%s'", cid, cmd);
-					console_execute_line(cmd);
-				}
-			}
-			else if(msg == NETMSG_RCON_AUTH)
-			{
-				const char *pw;
-				msg_unpack_string(); /* login name, not used */
-				pw = msg_unpack_string();
-				
-				if(msg_unpack_error() == 0)
-				{
-					if(config.sv_rcon_password[0] == 0)
-					{
-						server_send_rcon_line(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console.");
-					}
-					else if(strcmp(pw, config.sv_rcon_password) == 0)
-					{
-						msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL);
-						msg_pack_int(1);
-						msg_pack_end();
-						server_send_msg(cid);
-						
-						clients[cid].authed = 1;
-						server_send_rcon_line(cid, "Authentication successful. Remote console access granted.");
-						dbg_msg("server", "cid=%d authed", cid);
-					}
-					else
-					{
-						server_send_rcon_line(cid, "Wrong password.");
-					}
-				}
-			}
-			else if(msg == NETMSG_PING)
-			{
-				msg_pack_start_system(NETMSG_PING_REPLY, 0);
-				msg_pack_end();
-				server_send_msg(cid);
-			}
-			else
-			{
-				char hex[] = "0123456789ABCDEF";
-				char buf[512];
-				int b;
-
-				for(b = 0; b < packet->data_size && b < 32; b++)
-				{
-					buf[b*3] = hex[((const unsigned char *)packet->data)[b]>>4];
-					buf[b*3+1] = hex[((const unsigned char *)packet->data)[b]&0xf];
-					buf[b*3+2] = ' ';
-					buf[b*3+3] = 0;
-				}
-
-				dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size);
-				dbg_msg("server", "%s", buf);
-				
-			}
-		}
-		else
-		{
-			/* game message */
-			if(clients[cid].state >= SRVCLIENT_STATE_READY)
-				mods_message(msg, cid);
-		}
-	}
-}
-
-
-int server_ban_add(NETADDR addr, int seconds)
-{
-	return netserver_ban_add(net, addr, seconds);	
-}
-
-int server_ban_remove(NETADDR addr)
-{
-	return netserver_ban_remove(net, addr);
-}
-
-static void server_send_serverinfo(NETADDR *addr, int token)
-{
-	NETCHUNK packet;
-	PACKER p;
-	char buf[128];
-
-	/* count the players */	
-	int player_count = 0;
-	int i;
-	for(i = 0; i < MAX_CLIENTS; i++)
-	{
-		if(clients[i].state != SRVCLIENT_STATE_EMPTY)
-			player_count++;
-	}
-	
-	packer_reset(&p);
-
-	if(token >= 0)
-	{
-		/* new token based format */
-		packer_add_raw(&p, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO));
-		str_format(buf, sizeof(buf), "%d", token);
-		packer_add_string(&p, buf, 6);
-	}
-	else
-	{
-		/* old format */
-		packer_add_raw(&p, SERVERBROWSE_OLD_INFO, sizeof(SERVERBROWSE_OLD_INFO));
-	}
-	
-	packer_add_string(&p, mods_version(), 32);
-	packer_add_string(&p, config.sv_name, 64);
-	packer_add_string(&p, config.sv_map, 32);
-
-	/* gametype */
-	packer_add_string(&p, browseinfo_gametype, 16);
-
-	/* flags */
-	i = 0;
-	if(config.password[0])   /* password set */
-		i |= SRVFLAG_PASSWORD;
-	str_format(buf, sizeof(buf), "%d", i);
-	packer_add_string(&p, buf, 2);
-
-	/* progression */
-	str_format(buf, sizeof(buf), "%d", browseinfo_progression);
-	packer_add_string(&p, buf, 4);
-	
-	str_format(buf, sizeof(buf), "%d", player_count); packer_add_string(&p, buf, 3);  /* num players */
-	str_format(buf, sizeof(buf), "%d", netserver_max_clients(net)); packer_add_string(&p, buf, 3); /* max players */
-
-	for(i = 0; i < MAX_CLIENTS; i++)
-	{
-		if(clients[i].state != SRVCLIENT_STATE_EMPTY)
-		{
-			packer_add_string(&p, clients[i].name, 48);  /* player name */
-			str_format(buf, sizeof(buf), "%d", clients[i].score); packer_add_string(&p, buf, 6);  /* player score */
-		}
-	}
-	
-	
-	packet.client_id = -1;
-	packet.address = *addr;
-	packet.flags = NETSENDFLAG_CONNLESS;
-	packet.data_size = packer_size(&p);
-	packet.data = packer_data(&p);
-	netserver_send(net, &packet);
-}
-
-extern int register_process_packet(NETCHUNK *packet);
-extern int register_update();
-
-static void server_pump_network()
-{
-	NETCHUNK packet;
-
-	netserver_update(net);
-	
-	/* process packets */
-	while(netserver_recv(net, &packet))
-	{
-		if(packet.client_id == -1)
-		{
-			/* stateless */
-			if(!register_process_packet(&packet))
-			{
-				if(packet.data_size == sizeof(SERVERBROWSE_GETINFO)+1 &&
-					memcmp(packet.data, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
-				{
-					server_send_serverinfo(&packet.address, ((unsigned char *)packet.data)[sizeof(SERVERBROWSE_GETINFO)]);
-				}
-				
-				
-				if(packet.data_size == sizeof(SERVERBROWSE_OLD_GETINFO) &&
-					memcmp(packet.data, SERVERBROWSE_OLD_GETINFO, sizeof(SERVERBROWSE_OLD_GETINFO)) == 0)
-				{
-					server_send_serverinfo(&packet.address, -1);
-				}
-			}
-		}
-		else
-			server_process_client_packet(&packet);
-	}
-}
-
-static int server_load_map(const char *mapname)
-{
-	DATAFILE *df;
-	char buf[512];
-	str_format(buf, sizeof(buf), "maps/%s.map", mapname);
-	df = datafile_load(buf);
-	if(!df)
-		return 0;
-	
-	/* stop recording when we change map */
-	demorec_record_stop();
-	
-	/* reinit snapshot ids */
-	snap_timeout_ids();
-	
-	/* get the crc of the map */
-	current_map_crc = datafile_crc(buf);
-	dbg_msg("server", "%s crc is %08x", buf, current_map_crc);
-		
-	str_copy(current_map, mapname, sizeof(current_map));
-	map_set(df);
-	
-	/* load compelate map into memory for download */
-	{
-		IOHANDLE file = engine_openfile(buf, IOFLAG_READ);
-		current_map_size = (int)io_length(file);
-		if(current_map_data)
-			mem_free(current_map_data);
-		current_map_data = (unsigned char *)mem_alloc(current_map_size, 1);
-		io_read(file, current_map_data, current_map_size);
-		io_close(file);
-	}
-	return 1;
-}
-
-static int server_run()
-{
-	NETADDR bindaddr;
-
-	snap_init_id();
-	net_init();
-	
-	/* */
-	console_register_print_callback(server_send_rcon_line_authed, 0);
-
-	/* load map */
-	if(!server_load_map(config.sv_map))
-	{
-		dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
-		return -1;
-	}
-	
-	/* start server */
-	/* TODO: IPv6 support */
-	if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, &bindaddr, NETTYPE_IPV4) == 0)
-	{
-		/* sweet! */
-		bindaddr.port = config.sv_port;
-	}
-	else
-	{
-		mem_zero(&bindaddr, sizeof(bindaddr));
-		bindaddr.port = config.sv_port;
-	}
-	
-	net = netserver_open(bindaddr, config.sv_max_clients, 0);
-	if(!net)
-	{
-		dbg_msg("server", "couldn't open socket. port might already be in use");
-		return -1;
-	}
-	
-	netserver_set_callbacks(net, new_client_callback, del_client_callback, 0);
-	
-	dbg_msg("server", "server name is '%s'", config.sv_name);
-	
-	mods_init();
-	dbg_msg("server", "version %s", mods_net_version());
-
-	/* start game */
-	{
-		int64 reporttime = time_get();
-		int reportinterval = 3;
-	
-		lastheartbeat = 0;
-		game_start_time = time_get();
-	
-		if(config.debug)
-			dbg_msg("server", "baseline memory usage %dk", mem_stats()->allocated/1024);
-
-		while(run_server)
-		{
-			static PERFORMACE_INFO rootscope = {"root", 0};
-			int64 t = time_get();
-			int new_ticks = 0;
-			
-			perf_start(&rootscope);
-			
-			/* load new map TODO: don't poll this */
-			if(strcmp(config.sv_map, current_map) != 0 || config.sv_map_reload)
-			{
-				config.sv_map_reload = 0;
-				
-				/* load map */
-				if(server_load_map(config.sv_map))
-				{
-					int c;
-					
-					/* new map loaded */
-					mods_shutdown();
-					
-					for(c = 0; c < MAX_CLIENTS; c++)
-					{
-						if(clients[c].state == SRVCLIENT_STATE_EMPTY)
-							continue;
-						
-						server_send_map(c);
-						reset_client(c);
-						clients[c].state = SRVCLIENT_STATE_CONNECTING;
-					}
-					
-					game_start_time = time_get();
-					current_tick = 0;
-					mods_init();
-				}
-				else
-				{
-					dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
-					config_set_sv_map(&config, current_map);
-				}
-			}
-			
-			while(t > server_tick_start_time(current_tick+1))
-			{
-				current_tick++;
-				new_ticks++;
-				
-				/* apply new input */
-				{
-					static PERFORMACE_INFO scope = {"input", 0};
-					int c, i;
-					
-					perf_start(&scope);
-					
-					for(c = 0; c < MAX_CLIENTS; c++)
-					{
-						if(clients[c].state == SRVCLIENT_STATE_EMPTY)
-							continue;
-						for(i = 0; i < 200; i++)
-						{
-							if(clients[c].inputs[i].game_tick == server_tick())
-							{
-								if(clients[c].state == SRVCLIENT_STATE_INGAME)
-									mods_client_predicted_input(c, clients[c].inputs[i].data);
-								break;
-							}
-						}
-					}
-					
-					perf_end();
-				}
-				
-				/* progress game */
-				{
-					static PERFORMACE_INFO scope = {"tick", 0};
-					perf_start(&scope);
-					mods_tick();
-					perf_end();
-				}
-			}
-			
-			/* snap game */
-			if(new_ticks)
-			{
-				if(config.sv_high_bandwidth || (current_tick%2) == 0)
-				{
-					static PERFORMACE_INFO scope = {"snap", 0};
-					perf_start(&scope);
-					server_do_snap();
-					perf_end();
-				}
-			}
-			
-			/* master server stuff */
-			register_update();
-	
-
-			{
-				static PERFORMACE_INFO scope = {"net", 0};
-				perf_start(&scope);
-				server_pump_network();
-				perf_end();
-			}
-
-			perf_end();
-	
-			if(reporttime < time_get())
-			{
-				if(config.debug)
-				{
-					/*
-					static NETSTATS prev_stats;
-					NETSTATS stats;
-					netserver_stats(net, &stats);
-					
-					perf_next();
-					
-					if(config.dbg_pref)
-						perf_dump(&rootscope);
-
-					dbg_msg("server", "send=%8d recv=%8d",
-						(stats.send_bytes - prev_stats.send_bytes)/reportinterval,
-						(stats.recv_bytes - prev_stats.recv_bytes)/reportinterval);
-						
-					prev_stats = stats;
-					*/
-				}
-	
-				reporttime += time_freq()*reportinterval;
-			}
-			
-			/* wait for incomming data */
-			net_socket_read_wait(netserver_socket(net), 5);
-		}
-	}
-
-	mods_shutdown();
-	map_unload();
-
-	if(current_map_data)
-		mem_free(current_map_data);
-	return 0;
-}
-
-static void con_kick(void *result, void *user_data)
-{
-	server_kick(console_arg_int(result, 0), "kicked by console");
-}
-
-static int str_allnum(const char *str)
-{
-	while(*str)
-	{
-		if(!(*str >= '0' && *str <= '9'))
-			return 0;
-		str++;
-	}
-	return 1;
-}
-
-static void con_ban(void *result, void *user_data)
-{
-	NETADDR addr;
-	char addrstr[128];
-	const char *str = console_arg_string(result, 0);
-	int minutes = 30;
-	
-	if(console_arg_num(result) > 1)
-		minutes = console_arg_int(result, 1);
-	
-	if(net_addr_from_str(&addr, str) == 0)
-		server_ban_add(addr, minutes*60);
-	else if(str_allnum(str))
-	{
-		NETADDR addr;
-		int cid = atoi(str);
-
-		if(cid < 0 || cid > MAX_CLIENTS || clients[cid].state == SRVCLIENT_STATE_EMPTY)
-		{
-			dbg_msg("server", "invalid client id");
-			return;
-		}
-
-		netserver_client_addr(net, cid, &addr);
-		server_ban_add(addr, minutes*60);
-	}
-	
-	addr.port = 0;
-	net_addr_str(&addr, addrstr, sizeof(addrstr));
-	
-	if(minutes)
-		dbg_msg("server", "banned %s for %d minutes", addrstr, minutes);
-	else
-		dbg_msg("server", "banned %s for life", addrstr);
-}
-
-static void con_unban(void *result, void *user_data)
-{
-	NETADDR addr;
-	const char *str = console_arg_string(result, 0);
-	
-	if(net_addr_from_str(&addr, str) == 0)
-		server_ban_remove(addr);
-	else
-		dbg_msg("server", "invalid network address");
-}
-
-static void con_bans(void *result, void *user_data)
-{
-	int i;
-	unsigned now = time_timestamp();
-	NETBANINFO info;
-	NETADDR addr;
-	int num = netserver_ban_num(net);
-	for(i = 0; i < num; i++)
-	{
-		unsigned t;
-		netserver_ban_get(net, i, &info);
-		addr = info.addr;
-		
-		if(info.expires == 0xffffffff)
-		{
-			dbg_msg("server", "#%d %d.%d.%d.%d for life", i, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]);
-		}
-		else
-		{
-			t = info.expires - now;
-			dbg_msg("server", "#%d %d.%d.%d.%d for %d minutes and %d seconds", i, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], t/60, t%60);
-		}
-	}
-	dbg_msg("server", "%d ban(s)", num);
-}
-
-static void con_status(void *result, void *user_data)
-{
-	int i;
-	NETADDR addr;
-	for(i = 0; i < MAX_CLIENTS; i++)
-	{
-		if(clients[i].state == SRVCLIENT_STATE_INGAME)
-		{
-			netserver_client_addr(net, i, &addr);
-			dbg_msg("server", "id=%d addr=%d.%d.%d.%d:%d name='%s' score=%d",
-				i, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], addr.port,
-				clients[i].name, clients[i].score);
-		}
-	}
-}
-
-static void con_shutdown(void *result, void *user_data)
-{
-	run_server = 0;
-}
-
-static void con_record(void *result, void *user_data)
-{
-	char filename[512];
-	str_format(filename, sizeof(filename), "demos/%s.demo", console_arg_string(result, 0));
-	demorec_record_start(filename, mods_net_version(), current_map, current_map_crc, "server");
-}
-
-static void con_stoprecord(void *result, void *user_data)
-{
-	demorec_record_stop();
-}
-
-static void server_register_commands()
-{
-	MACRO_REGISTER_COMMAND("kick", "i", CFGFLAG_SERVER, con_kick, 0, "");
-	MACRO_REGISTER_COMMAND("ban", "s?i", CFGFLAG_SERVER, con_ban, 0, "");
-	MACRO_REGISTER_COMMAND("unban", "s", CFGFLAG_SERVER, con_unban, 0, "");
-	MACRO_REGISTER_COMMAND("bans", "", CFGFLAG_SERVER, con_bans, 0, "");
-	MACRO_REGISTER_COMMAND("status", "", CFGFLAG_SERVER, con_status, 0, "");
-	MACRO_REGISTER_COMMAND("shutdown", "", CFGFLAG_SERVER, con_shutdown, 0, "");
-
-	MACRO_REGISTER_COMMAND("record", "s", CFGFLAG_SERVER, con_record, 0, "");
-	MACRO_REGISTER_COMMAND("stoprecord", "", CFGFLAG_SERVER, con_stoprecord, 0, "");
-}
-
-int main(int argc, char **argv)
-{
-#if defined(CONF_FAMILY_WINDOWS)
-	int i;
-	for(i = 1; i < argc; i++)
-	{
-		if(strcmp("-s", argv[i]) == 0 || strcmp("--silent", argv[i]) == 0)
-		{
-			ShowWindow(GetConsoleWindow(), SW_HIDE);
-			break;
-		}
-	}
-#endif
-
-	/* init the engine */
-	dbg_msg("server", "starting...");
-	engine_init("Teeworlds");
-	
-	/* register all console commands */
-	server_register_commands();
-	mods_console_init();
-	
-	/* parse the command line arguments */
-	engine_parse_arguments(argc, argv);
-	
-	/* run the server */
-	server_run();
-	return 0;
-}
-
diff --git a/src/engine/server/es_server.cpp b/src/engine/server/es_server.cpp
new file mode 100644
index 00000000..cc0e6e0f
--- /dev/null
+++ b/src/engine/server/es_server.cpp
@@ -0,0 +1,1969 @@
+/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <base/system.h>
+
+#include <engine/e_config.h>
+#include <engine/e_engine.h>
+#include <engine/e_server_interface.h>
+
+#include <engine/e_protocol.h>
+#include <engine/e_snapshot.h>
+
+#include <engine/e_compression.h>
+
+#include <engine/e_network.h>
+#include <engine/e_config.h>
+#include <engine/e_packer.h>
+#include <engine/e_datafile.h>
+#include <engine/e_demorec.h>
+
+#include <mastersrv/mastersrv.h>
+
+#if defined(CONF_FAMILY_WINDOWS) 
+	#define _WIN32_WINNT 0x0500 
+	#include <windows.h> 
+#endif
+
+
+extern int register_process_packet(CNetChunk *pPacket);
+extern int register_update();
+
+static const char *str_ltrim(const char *str)
+{
+	while(*str && *str <= 32)
+		str++;
+	return str;
+}
+
+static void str_rtrim(char *str)
+{
+	int i = str_length(str);
+	while(i >= 0)
+	{
+		if(str[i] > 32)
+			break;
+		str[i] = 0;
+		i--;
+	}
+}
+
+
+class CSnapIDPool
+{
+	enum
+	{
+		MAX_IDS = 16*1024,
+	};
+
+	class CID
+	{
+	public:
+		short m_Next;
+		short m_State; /* 0 = free, 1 = alloced, 2 = timed */
+		int m_Timeout;
+	};
+
+	CID m_aIDs[MAX_IDS];
+		
+	int m_FirstFree;
+	int m_FirstTimed;
+	int m_LastTimed;
+	int m_Usage;
+	int m_InUsage;
+
+public:	
+
+	CSnapIDPool()
+	{
+		Reset();
+	}
+	
+	void Reset()
+	{
+		for(int i = 0; i < MAX_IDS; i++)
+		{
+			m_aIDs[i].m_Next = i+1;
+			m_aIDs[i].m_State = 0;
+		}
+			
+		m_aIDs[MAX_IDS-1].m_Next = -1;
+		m_FirstFree = 0;
+		m_FirstTimed = -1;
+		m_LastTimed = -1;
+		m_Usage = 0;
+		m_InUsage = 0;
+	}
+	
+
+	void RemoveFirstTimeout()
+	{
+		int NextTimed = m_aIDs[m_FirstTimed].m_Next;
+		
+		/* add it to the free list */
+		m_aIDs[m_FirstTimed].m_Next = m_FirstFree;
+		m_aIDs[m_FirstTimed].m_State = 0;
+		m_FirstFree = m_FirstTimed;
+		
+		/* remove it from the timed list */
+		m_FirstTimed = NextTimed;
+		if(m_FirstTimed == -1)
+			m_LastTimed = -1;
+			
+		m_Usage--;
+	}
+
+	int NewID()
+	{
+		int64 now = time_get();
+		
+		/* process timed ids */
+		while(m_FirstTimed != -1 && m_aIDs[m_FirstTimed].m_Timeout < now)
+			RemoveFirstTimeout();
+		
+		int id = m_FirstFree;
+		dbg_assert(id != -1, "id error");
+		m_FirstFree = m_aIDs[m_FirstFree].m_Next;
+		m_aIDs[id].m_State = 1;
+		m_Usage++;
+		m_InUsage++;
+		return id;
+	}
+
+	void TimeoutIDs()
+	{
+		/* process timed ids */
+		while(m_FirstTimed != -1)
+			RemoveFirstTimeout();
+	}
+
+	void FreeID(int id)
+	{
+		dbg_assert(m_aIDs[id].m_State == 1, "id is not alloced");
+
+		m_InUsage--;
+		m_aIDs[id].m_State = 2;
+		m_aIDs[id].m_Timeout = time_get()+time_freq()*5;
+		m_aIDs[id].m_Next = -1;
+		
+		if(m_LastTimed != -1)
+		{
+			m_aIDs[m_LastTimed].m_Next = id;
+			m_LastTimed = id;
+		}
+		else
+		{
+			m_FirstTimed = id;
+			m_LastTimed = id;
+		}
+	}
+};
+
+#if 0
+class IGameServer
+{
+public:
+	/*
+		Function: mods_console_init
+			TODO
+	*/
+	virtual void ConsoleInit();
+
+	/*
+		Function: Init
+			Called when the server is started.
+		
+		Remarks:
+			It's called after the map is loaded so all map items are available.
+	*/
+	void Init() = 0;
+
+	/*
+		Function: Shutdown
+			Called when the server quits.
+		
+		Remarks:
+			Should be used to clean up all resources used.
+	*/
+	void Shutdown() = 0;
+
+	/*
+		Function: ClientEnter
+			Called when a client has joined the game.
+			
+		Arguments:
+			cid - Client ID. Is 0 - MAX_CLIENTS.
+		
+		Remarks:
+			It's called when the client is finished loading and should enter gameplay.
+	*/
+	void ClientEnter(int cid) = 0;
+
+	/*
+		Function: ClientDrop
+			Called when a client drops from the server.
+
+		Arguments:
+			cid - Client ID. Is 0 - MAX_CLIENTS
+	*/
+	void ClientDrop(int cid) = 0;
+
+	/*
+		Function: ClientDirectInput
+			Called when the server recives new input from a client.
+
+		Arguments:
+			cid - Client ID. Is 0 - MAX_CLIENTS.
+			input - Pointer to the input data.
+			size - Size of the data. (NOT IMPLEMENTED YET)
+	*/
+	void ClientDirectInput(int cid, void *input) = 0;
+
+	/*
+		Function: ClientPredictedInput
+			Called when the server applys the predicted input on the client.
+
+		Arguments:
+			cid - Client ID. Is 0 - MAX_CLIENTS.
+			input - Pointer to the input data.
+			size - Size of the data. (NOT IMPLEMENTED YET)
+	*/
+	void ClientPredictedInput(int cid, void *input) = 0;
+
+
+	/*
+		Function: Tick
+			Called with a regular interval to progress the gameplay.
+			
+		Remarks:
+			The SERVER_TICK_SPEED tells the number of ticks per second.
+	*/
+	void Tick() = 0;
+
+	/*
+		Function: Presnap
+			Called before the server starts to construct snapshots for the clients.
+	*/
+	void Presnap() = 0;
+
+	/*
+		Function: Snap
+			Called to create the snapshot for a client.
+		
+		Arguments:
+			cid - Client ID. Is 0 - MAX_CLIENTS.
+		
+		Remarks:
+			The game should make a series of calls to <snap_new_item> to construct
+			the snapshot for the client.
+	*/
+	void Snap(int cid) = 0;
+
+	/*
+		Function: PostSnap
+			Called after the server is done sending the snapshots.
+	*/
+	void PostSnap() = 0;
+
+	/*
+		Function: ClientConnected
+			TODO
+		
+		Arguments:
+			arg1 - desc
+		
+		Returns:
+
+		See Also:
+			<other_func>
+	*/
+	void ClientConnected(int client_id) = 0;
+
+
+	/*
+		Function: NetVersion
+			TODO
+		
+		Arguments:
+			arg1 - desc
+		
+		Returns:
+
+		See Also:
+			<other_func>
+	*/
+	const char *NetVersion() = 0;
+
+	/*
+		Function: Version
+			TODO
+		
+		Arguments:
+			arg1 - desc
+		
+		Returns:
+
+		See Also:
+			<other_func>
+	*/
+	const char *Version() = 0;
+
+	/*
+		Function: Message
+			TODO
+		
+		Arguments:
+			arg1 - desc
+		
+		Returns:
+
+		See Also:
+			<other_func>
+	*/
+	void Message(int msg, int client_id) = 0;
+};
+
+#endif
+/*
+class IServer
+{
+public:
+	BanAdd
+	BanRemove
+	TickSpeed
+	Tick
+	Kick
+	SetBrowseInfo
+	SetClientScore
+	SetClientName
+	GetClientInfo
+	LatestInput
+	ClientName
+	
+	SendMessage()
+	
+	Map
+	
+	virtual int NewSnapID() = 0;
+	virtual int FreeSnapID(int i) = 0;
+};*/
+
+class CServer
+{
+public:
+	/* */
+	class CClient
+	{
+	public:
+	
+		enum
+		{
+			STATE_EMPTY = 0,
+			STATE_AUTH,
+			STATE_CONNECTING,
+			STATE_READY,
+			STATE_INGAME,
+			
+			SNAPRATE_INIT=0,
+			SNAPRATE_FULL,
+			SNAPRATE_RECOVER
+		};
+	
+		class CInput
+		{
+		public:
+			int m_aData[MAX_INPUT_SIZE];
+			int m_GameTick; /* the tick that was chosen for the input */
+		};
+	
+		/* connection state info */
+		int m_State;
+		int m_Latency;
+		int m_SnapRate;
+		
+		int m_LastAckedSnapshot;
+		int m_LastInputTick;
+		CSnapshotStorage m_Snapshots;
+		
+		CInput m_LatestInput;
+		CInput m_aInputs[200]; /* TODO: handle input better */
+		int m_CurrentInput;
+		
+		char m_aName[MAX_NAME_LENGTH];
+		char m_aClan[MAX_CLANNAME_LENGTH];
+		int m_Score;
+		int m_Authed;
+		
+		void Reset()
+		{
+			/* reset input */
+			for(int i = 0; i < 200; i++)
+				m_aInputs[i].m_GameTick = -1;
+			m_CurrentInput = 0;
+			mem_zero(&m_LatestInput, sizeof(m_LatestInput));
+
+			m_Snapshots.PurgeAll();
+			m_LastAckedSnapshot = -1;
+			m_LastInputTick = -1;
+			m_SnapRate = CClient::SNAPRATE_INIT;
+			m_Score = 0;
+		}
+	};
+	
+	CClient m_aClients[MAX_CLIENTS];
+
+	CSnapshotBuilder m_SnapshotBuilder;
+	CSnapIDPool m_IDPool;
+	CNetServer m_NetServer;
+
+	int64 m_GameStartTime;
+	int m_CurrentTick;
+	int m_RunServer;
+
+	char m_aBrowseinfoGametype[16];
+	int m_BrowseinfoProgression;
+
+	int64 m_Lastheartbeat;
+	/*static NETADDR4 master_server;*/
+
+	char m_aCurrentMap[64];
+	int m_CurrentMapCrc;
+	unsigned char *m_pCurrentMapData;
+	int m_CurrentMapSize;	
+	
+	CServer()
+	{
+		m_CurrentTick = 0;
+		m_RunServer = 1;
+
+		mem_zero(m_aBrowseinfoGametype, sizeof(m_aBrowseinfoGametype));
+		m_BrowseinfoProgression = -1;
+
+		m_pCurrentMapData = 0;
+		m_CurrentMapSize = 0;	
+	}
+	
+
+	int TrySetClientName(int ClientID, const char *pName)
+	{
+		int i;
+		char aTrimmedName[64];
+
+		/* trim the name */
+		str_copy(aTrimmedName, str_ltrim(pName), sizeof(aTrimmedName));
+		str_rtrim(aTrimmedName);
+		dbg_msg("", "'%s' -> '%s'", pName, aTrimmedName);
+		pName = aTrimmedName;
+		
+		
+		/* check for empty names */
+		if(!pName[0])
+			return -1;
+		
+		/* make sure that two clients doesn't have the same name */
+		for(i = 0; i < MAX_CLIENTS; i++)
+			if(i != ClientID && m_aClients[i].m_State >= CClient::STATE_READY)
+			{
+				if(strcmp(pName, m_aClients[i].m_aName) == 0)
+					return -1;
+			}
+
+		/* set the client name */
+		str_copy(m_aClients[ClientID].m_aName, pName, MAX_NAME_LENGTH);
+		return 0;
+	}
+
+
+
+	void SetClientName(int ClientID, const char *pName)
+	{
+		if(ClientID < 0 || ClientID > MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY)
+			return;
+			
+		if(!pName)
+			return;
+			
+		char aNameTry[MAX_NAME_LENGTH];
+		str_copy(aNameTry, pName, MAX_NAME_LENGTH);
+		if(TrySetClientName(ClientID, aNameTry))
+		{
+			/* auto rename */
+			for(int i = 1;; i++)
+			{
+				str_format(aNameTry, MAX_NAME_LENGTH, "(%d)%s", i, pName);
+				if(TrySetClientName(ClientID, aNameTry) == 0)
+					break;
+			}
+		}
+	}
+
+	void SetClientScore(int ClientID, int Score)
+	{
+		if(ClientID < 0 || ClientID > MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY)
+			return;
+		m_aClients[ClientID].m_Score = Score;
+	}
+
+	void SetBrowseInfo(const char *pGameType, int Progression)
+	{
+		str_copy(m_aBrowseinfoGametype, pGameType, sizeof(m_aBrowseinfoGametype));
+		m_BrowseinfoProgression = Progression;
+		if(m_BrowseinfoProgression > 100)
+			m_BrowseinfoProgression = 100;
+		if(m_BrowseinfoProgression < -1)
+			m_BrowseinfoProgression = -1;
+	}
+
+	void Kick(int ClientID, const char *pReason)
+	{
+		if(ClientID < 0 || ClientID > MAX_CLIENTS)
+			return;
+			
+		if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY)
+			m_NetServer.Drop(ClientID, pReason);
+	}
+
+	int Tick()
+	{
+		return m_CurrentTick;
+	}
+
+	int64 TickStartTime(int Tick)
+	{
+		return m_GameStartTime + (time_freq()*Tick)/SERVER_TICK_SPEED;
+	}
+
+	int TickSpeed()
+	{
+		return SERVER_TICK_SPEED;
+	}
+
+	int Init()
+	{
+		int i;
+		for(i = 0; i < MAX_CLIENTS; i++)
+		{
+			m_aClients[i].m_State = CClient::STATE_EMPTY;
+			m_aClients[i].m_aName[0] = 0;
+			m_aClients[i].m_aClan[0] = 0;
+			m_aClients[i].m_Snapshots.Init();
+		}
+
+		m_CurrentTick = 0;
+
+		return 0;
+	}
+
+	int GetClientInfo(int ClientID, CLIENT_INFO *pInfo)
+	{
+		dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
+		dbg_assert(pInfo != 0, "info can not be null");
+
+		if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
+		{
+			pInfo->name = m_aClients[ClientID].m_aName;
+			pInfo->latency = m_aClients[ClientID].m_Latency;
+			return 1;
+		}
+		return 0;
+	}
+
+	int SendMsg(int ClientID)
+	{
+		const MSG_INFO *pInfo = msg_get_info();
+		CNetChunk Packet;
+		if(!pInfo)
+			return -1;
+			
+		mem_zero(&Packet, sizeof(CNetChunk));
+		
+		Packet.m_ClientID = ClientID;
+		Packet.m_pData = pInfo->data;
+		Packet.m_DataSize = pInfo->size;
+
+		if(pInfo->flags&MSGFLAG_VITAL)
+			Packet.m_Flags |= NETSENDFLAG_VITAL;
+		if(pInfo->flags&MSGFLAG_FLUSH)
+			Packet.m_Flags |= NETSENDFLAG_FLUSH;
+		
+		/* write message to demo recorder */
+		if(!(pInfo->flags&MSGFLAG_NORECORD))
+			demorec_record_message(pInfo->data, pInfo->size);
+
+		if(!(pInfo->flags&MSGFLAG_NOSEND))
+		{
+			if(ClientID == -1)
+			{
+				/* broadcast */
+				int i;
+				for(i = 0; i < MAX_CLIENTS; i++)
+					if(m_aClients[i].m_State == CClient::STATE_INGAME)
+					{
+						Packet.m_ClientID = i;
+						m_NetServer.Send(&Packet);
+					}
+			}
+			else
+				m_NetServer.Send(&Packet);
+		}
+		return 0;
+	}
+
+	void DoSnapshot()
+	{
+		int i;
+		
+		{
+			static PERFORMACE_INFO scope = {"presnap", 0};
+			perf_start(&scope);
+			mods_presnap();
+			perf_end();
+		}
+		
+		/* create snapshot for demo recording */
+		if(demorec_isrecording())
+		{
+			char data[CSnapshot::MAX_SIZE];
+			int snapshot_size;
+
+			/* build snap and possibly add some messages */
+			m_SnapshotBuilder.Init();
+			mods_snap(-1);
+			snapshot_size = m_SnapshotBuilder.Finish(data);
+			
+			/* write snapshot */
+			demorec_record_snapshot(Tick(), data, snapshot_size);
+		}
+
+		/* create snapshots for all clients */
+		for(i = 0; i < MAX_CLIENTS; i++)
+		{
+			/* client must be ingame to recive snapshots */
+			if(m_aClients[i].m_State != CClient::STATE_INGAME)
+				continue;
+				
+			/* this client is trying to recover, don't spam snapshots */
+			if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_RECOVER && (Tick()%50) != 0)
+				continue;
+				
+			/* this client is trying to recover, don't spam snapshots */
+			if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_INIT && (Tick()%10) != 0)
+				continue;
+				
+			{
+				char data[CSnapshot::MAX_SIZE];
+				char deltadata[CSnapshot::MAX_SIZE];
+				char compdata[CSnapshot::MAX_SIZE];
+				int snapshot_size;
+				int crc;
+				static CSnapshot emptysnap;
+				CSnapshot *deltashot = &emptysnap;
+				int deltashot_size;
+				int delta_tick = -1;
+				int deltasize;
+				static PERFORMACE_INFO scope = {"build", 0};
+				perf_start(&scope);
+
+				m_SnapshotBuilder.Init();
+
+				{
+					static PERFORMACE_INFO scope = {"modsnap", 0};
+					perf_start(&scope);
+					mods_snap(i);
+					perf_end();
+				}
+
+				/* finish snapshot */
+				snapshot_size = m_SnapshotBuilder.Finish(data);
+				crc = ((CSnapshot*)data)->Crc();
+
+				/* remove old snapshos */
+				/* keep 3 seconds worth of snapshots */
+				m_aClients[i].m_Snapshots.PurgeUntil(m_CurrentTick-SERVER_TICK_SPEED*3);
+				
+				/* save it the snapshot */
+				m_aClients[i].m_Snapshots.Add(m_CurrentTick, time_get(), snapshot_size, data, 0);
+				
+				/* find snapshot that we can preform delta against */
+				emptysnap.m_DataSize = 0;
+				emptysnap.m_NumItems = 0;
+				
+				{
+					deltashot_size = m_aClients[i].m_Snapshots.Get(m_aClients[i].m_LastAckedSnapshot, 0, &deltashot, 0);
+					if(deltashot_size >= 0)
+						delta_tick = m_aClients[i].m_LastAckedSnapshot;
+					else
+					{
+						/* no acked package found, force client to recover rate */
+						if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_FULL)
+							m_aClients[i].m_SnapRate = CClient::SNAPRATE_RECOVER;
+					}
+				}
+				
+				/* create delta */
+				{
+					static PERFORMACE_INFO scope = {"delta", 0};
+					perf_start(&scope);
+					deltasize = CSnapshot::CreateDelta(deltashot, (CSnapshot*)data, deltadata);
+					perf_end();
+				}
+
+				
+				if(deltasize)
+				{
+					/* compress it */
+					int snapshot_size;
+					const int max_size = MAX_SNAPSHOT_PACKSIZE;
+					int numpackets;
+					int n, left;
+
+					{				
+						static PERFORMACE_INFO scope = {"compress", 0};
+						/*char buffer[512];*/
+						perf_start(&scope);
+						snapshot_size = intpack_compress(deltadata, deltasize, compdata);
+						
+						/*str_hex(buffer, sizeof(buffer), compdata, snapshot_size);
+						dbg_msg("", "deltasize=%d -> %d : %s", deltasize, snapshot_size, buffer);*/
+						
+						perf_end();
+					}
+
+					numpackets = (snapshot_size+max_size-1)/max_size;
+					
+					for(n = 0, left = snapshot_size; left; n++)
+					{
+						int chunk = left < max_size ? left : max_size;
+						left -= chunk;
+
+						if(numpackets == 1)
+							msg_pack_start_system(NETMSG_SNAPSINGLE, MSGFLAG_FLUSH);
+						else
+							msg_pack_start_system(NETMSG_SNAP, MSGFLAG_FLUSH);
+							
+						msg_pack_int(m_CurrentTick);
+						msg_pack_int(m_CurrentTick-delta_tick); /* compressed with */
+						
+						if(numpackets != 1)
+						{
+							msg_pack_int(numpackets);
+							msg_pack_int(n);
+						}
+						
+						msg_pack_int(crc);
+						msg_pack_int(chunk);
+						msg_pack_raw(&compdata[n*max_size], chunk);
+						msg_pack_end();
+						SendMsg(i);
+					}
+				}
+				else
+				{
+					msg_pack_start_system(NETMSG_SNAPEMPTY, MSGFLAG_FLUSH);
+					msg_pack_int(m_CurrentTick);
+					msg_pack_int(m_CurrentTick-delta_tick); /* compressed with */
+					msg_pack_end();
+					SendMsg(i);
+				}
+				
+				perf_end();
+			}
+		}
+
+		mods_postsnap();
+	}
+
+
+	static int NewClientCallback(int cid, void *pUser)
+	{
+		CServer *pThis = (CServer *)pUser;
+		pThis->m_aClients[cid].m_State = CClient::STATE_AUTH;
+		pThis->m_aClients[cid].m_aName[0] = 0;
+		pThis->m_aClients[cid].m_aClan[0] = 0;
+		pThis->m_aClients[cid].m_Authed = 0;
+		pThis->m_aClients[cid].Reset();
+		return 0;
+	}
+
+	static int DelClientCallback(int cid, void *pUser)
+	{
+		CServer *pThis = (CServer *)pUser;
+		
+		/* notify the mod about the drop */
+		if(pThis->m_aClients[cid].m_State >= CClient::STATE_READY)
+			mods_client_drop(cid);
+		
+		pThis->m_aClients[cid].m_State = CClient::STATE_EMPTY;
+		pThis->m_aClients[cid].m_aName[0] = 0;
+		pThis->m_aClients[cid].m_aClan[0] = 0;
+		pThis->m_aClients[cid].m_Authed = 0;
+		pThis->m_aClients[cid].m_Snapshots.PurgeAll();
+		return 0;
+	}
+
+	void SendMap(int cid)
+	{
+		msg_pack_start_system(NETMSG_MAP_CHANGE, MSGFLAG_VITAL|MSGFLAG_FLUSH);
+		msg_pack_string(config.sv_map, 0);
+		msg_pack_int(m_CurrentMapCrc);
+		msg_pack_end();
+		server_send_msg(cid);
+	}
+
+	void SendRconLine(int cid, const char *pLine)
+	{
+		msg_pack_start_system(NETMSG_RCON_LINE, MSGFLAG_VITAL);
+		msg_pack_string(pLine, 512);
+		msg_pack_end();
+		server_send_msg(cid);
+	}
+
+	static void SendRconLineAuthed(const char *pLine, void *pUser)
+	{
+		CServer *pThis = (CServer *)pUser;
+		static volatile int reentry_guard = 0;
+		int i;
+		
+		if(reentry_guard) return;
+		reentry_guard++;
+		
+		for(i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed)
+				pThis->SendRconLine(i, pLine);
+		}
+		
+		reentry_guard--;
+	}
+	
+	void ProcessClientPacket(CNetChunk *pPacket)
+	{
+		int cid = pPacket->m_ClientID;
+		NETADDR addr;
+		
+		int sys;
+		int msg = msg_unpack_start(pPacket->m_pData, pPacket->m_DataSize, &sys);
+		
+		if(m_aClients[cid].m_State == CClient::STATE_AUTH)
+		{
+			if(sys && msg == NETMSG_INFO)
+			{
+				char version[64];
+				const char *password;
+				str_copy(version, msg_unpack_string(), 64);
+				if(strcmp(version, mods_net_version()) != 0)
+				{
+					/* OH FUCK! wrong version, drop him */
+					char reason[256];
+					str_format(reason, sizeof(reason), "wrong version. server is running '%s' and client '%s'.", mods_net_version(), version);
+					m_NetServer.Drop(cid, reason);
+					return;
+				}
+				
+				str_copy(m_aClients[cid].m_aName, msg_unpack_string(), MAX_NAME_LENGTH);
+				str_copy(m_aClients[cid].m_aClan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
+				password = msg_unpack_string();
+				
+				if(config.password[0] != 0 && strcmp(config.password, password) != 0)
+				{
+					/* wrong password */
+					m_NetServer.Drop(cid, "wrong password");
+					return;
+				}
+				
+				m_aClients[cid].m_State = CClient::STATE_CONNECTING;
+				SendMap(cid);
+			}
+		}
+		else
+		{
+			if(sys)
+			{
+				/* system message */
+				if(msg == NETMSG_REQUEST_MAP_DATA)
+				{
+					int chunk = msg_unpack_int();
+					int chunk_size = 1024-128;
+					int offset = chunk * chunk_size;
+					int last = 0;
+					
+					/* drop faulty map data requests */
+					if(chunk < 0 || offset > m_CurrentMapSize)
+						return;
+					
+					if(offset+chunk_size >= m_CurrentMapSize)
+					{
+						chunk_size = m_CurrentMapSize-offset;
+						if(chunk_size < 0)
+							chunk_size = 0;
+						last = 1;
+					}
+					
+					msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH);
+					msg_pack_int(last);
+					msg_pack_int(m_CurrentMapSize);
+					msg_pack_int(chunk_size);
+					msg_pack_raw(&m_pCurrentMapData[offset], chunk_size);
+					msg_pack_end();
+					server_send_msg(cid);
+					
+					if(config.debug)
+						dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size);
+				}
+				else if(msg == NETMSG_READY)
+				{
+					if(m_aClients[cid].m_State == CClient::STATE_CONNECTING)
+					{
+						addr = m_NetServer.ClientAddr(cid);
+						
+						dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d",
+							cid,
+							addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
+							);
+						m_aClients[cid].m_State = CClient::STATE_READY;
+						mods_connected(cid);
+					}
+				}
+				else if(msg == NETMSG_ENTERGAME)
+				{
+					if(m_aClients[cid].m_State == CClient::STATE_READY)
+					{
+						addr = m_NetServer.ClientAddr(cid);
+						
+						dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d",
+							cid,
+							addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3]
+							);
+						m_aClients[cid].m_State = CClient::STATE_INGAME;
+						mods_client_enter(cid);
+					}
+				}
+				else if(msg == NETMSG_INPUT)
+				{
+					int tick, size, i;
+					CClient::CInput *pInput;
+					int64 tagtime;
+					
+					m_aClients[cid].m_LastAckedSnapshot = msg_unpack_int();
+					tick = msg_unpack_int();
+					size = msg_unpack_int();
+					
+					/* check for errors */
+					if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
+						return;
+
+					if(m_aClients[cid].m_LastAckedSnapshot > 0)
+						m_aClients[cid].m_SnapRate = CClient::SNAPRATE_FULL;
+						
+					if(m_aClients[cid].m_Snapshots.Get(m_aClients[cid].m_LastAckedSnapshot, &tagtime, 0, 0) >= 0)
+						m_aClients[cid].m_Latency = (int)(((time_get()-tagtime)*1000)/time_freq());
+
+					/* add message to report the input timing */
+					/* skip packets that are old */
+					if(tick > m_aClients[cid].m_LastInputTick)
+					{
+						int time_left = ((TickStartTime(tick)-time_get())*1000) / time_freq();
+						msg_pack_start_system(NETMSG_INPUTTIMING, 0);
+						msg_pack_int(tick);
+						msg_pack_int(time_left);
+						msg_pack_end();
+						server_send_msg(cid);
+					}
+
+					m_aClients[cid].m_LastInputTick = tick;
+
+					pInput = &m_aClients[cid].m_aInputs[m_aClients[cid].m_CurrentInput];
+					
+					if(tick <= server_tick())
+						tick = server_tick()+1;
+
+					pInput->m_GameTick = tick;
+					
+					for(i = 0; i < size/4; i++)
+						pInput->m_aData[i] = msg_unpack_int();
+					
+					mem_copy(m_aClients[cid].m_LatestInput.m_aData, pInput->m_aData, MAX_INPUT_SIZE*sizeof(int));
+					
+					m_aClients[cid].m_CurrentInput++;
+					m_aClients[cid].m_CurrentInput %= 200;
+				
+					/* call the mod with the fresh input data */
+					if(m_aClients[cid].m_State == CClient::STATE_INGAME)
+						mods_client_direct_input(cid, m_aClients[cid].m_LatestInput.m_aData);
+				}
+				else if(msg == NETMSG_RCON_CMD)
+				{
+					const char *cmd = msg_unpack_string();
+					
+					if(msg_unpack_error() == 0 && m_aClients[cid].m_Authed)
+					{
+						dbg_msg("server", "cid=%d rcon='%s'", cid, cmd);
+						console_execute_line(cmd);
+					}
+				}
+				else if(msg == NETMSG_RCON_AUTH)
+				{
+					const char *pw;
+					msg_unpack_string(); /* login name, not used */
+					pw = msg_unpack_string();
+					
+					if(msg_unpack_error() == 0)
+					{
+						if(config.sv_rcon_password[0] == 0)
+						{
+							SendRconLine(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console.");
+						}
+						else if(strcmp(pw, config.sv_rcon_password) == 0)
+						{
+							msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL);
+							msg_pack_int(1);
+							msg_pack_end();
+							server_send_msg(cid);
+							
+							m_aClients[cid].m_Authed = 1;
+							SendRconLine(cid, "Authentication successful. Remote console access granted.");
+							dbg_msg("server", "cid=%d authed", cid);
+						}
+						else
+						{
+							SendRconLine(cid, "Wrong password.");
+						}
+					}
+				}
+				else if(msg == NETMSG_PING)
+				{
+					msg_pack_start_system(NETMSG_PING_REPLY, 0);
+					msg_pack_end();
+					server_send_msg(cid);
+				}
+				else
+				{
+					char hex[] = "0123456789ABCDEF";
+					char buf[512];
+					int b;
+
+					for(b = 0; b < pPacket->m_DataSize && b < 32; b++)
+					{
+						buf[b*3] = hex[((const unsigned char *)pPacket->m_pData)[b]>>4];
+						buf[b*3+1] = hex[((const unsigned char *)pPacket->m_pData)[b]&0xf];
+						buf[b*3+2] = ' ';
+						buf[b*3+3] = 0;
+					}
+
+					dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, pPacket->m_DataSize);
+					dbg_msg("server", "%s", buf);
+					
+				}
+			}
+			else
+			{
+				/* game message */
+				if(m_aClients[cid].m_State >= CClient::STATE_READY)
+					mods_message(msg, cid);
+			}
+		}
+	}
+		
+	void SendServerInfo(NETADDR *addr, int token)
+	{
+		CNetChunk Packet;
+		CPacker p;
+		char buf[128];
+
+		/* count the players */	
+		int player_count = 0;
+		int i;
+		for(i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(m_aClients[i].m_State != CClient::STATE_EMPTY)
+				player_count++;
+		}
+		
+		p.Reset();
+
+		if(token >= 0)
+		{
+			/* new token based format */
+			p.AddRaw(SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO));
+			str_format(buf, sizeof(buf), "%d", token);
+			p.AddString(buf, 6);
+		}
+		else
+		{
+			/* old format */
+			p.AddRaw(SERVERBROWSE_OLD_INFO, sizeof(SERVERBROWSE_OLD_INFO));
+		}
+		
+		p.AddString(mods_version(), 32);
+		p.AddString(config.sv_name, 64);
+		p.AddString(config.sv_map, 32);
+
+		/* gametype */
+		p.AddString(m_aBrowseinfoGametype, 16);
+
+		/* flags */
+		i = 0;
+		if(config.password[0])   /* password set */
+			i |= SRVFLAG_PASSWORD;
+		str_format(buf, sizeof(buf), "%d", i);
+		p.AddString(buf, 2);
+
+		/* progression */
+		str_format(buf, sizeof(buf), "%d", m_BrowseinfoProgression);
+		p.AddString(buf, 4);
+		
+		str_format(buf, sizeof(buf), "%d", player_count); p.AddString(buf, 3);  /* num players */
+		str_format(buf, sizeof(buf), "%d", m_NetServer.MaxClients()); p.AddString(buf, 3); /* max players */
+
+		for(i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(m_aClients[i].m_State != CClient::STATE_EMPTY)
+			{
+				p.AddString(m_aClients[i].m_aName, 48);  /* player name */
+				str_format(buf, sizeof(buf), "%d", m_aClients[i].m_Score); p.AddString(buf, 6);  /* player score */
+			}
+		}
+		
+		
+		Packet.m_ClientID = -1;
+		Packet.m_Address = *addr;
+		Packet.m_Flags = NETSENDFLAG_CONNLESS;
+		Packet.m_DataSize = p.Size();
+		Packet.m_pData = p.Data();
+		m_NetServer.Send(&Packet);
+	}
+
+	int BanAdd(NETADDR Addr, int Seconds)
+	{
+		return m_NetServer.BanAdd(Addr, Seconds);	
+	}
+
+	int BanRemove(NETADDR Addr)
+	{
+		return m_NetServer.BanRemove(Addr);
+	}
+		
+
+	void PumpNetwork()
+	{
+		CNetChunk Packet;
+
+		m_NetServer.Update();
+		
+		/* process packets */
+		while(m_NetServer.Recv(&Packet))
+		{
+			if(Packet.m_ClientID == -1)
+			{
+				/* stateless */
+				if(!register_process_packet(&Packet))
+				{
+					if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETINFO)+1 &&
+						memcmp(Packet.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
+					{
+						SendServerInfo(&Packet.m_Address, ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO)]);
+					}
+					
+					
+					if(Packet.m_DataSize == sizeof(SERVERBROWSE_OLD_GETINFO) &&
+						memcmp(Packet.m_pData, SERVERBROWSE_OLD_GETINFO, sizeof(SERVERBROWSE_OLD_GETINFO)) == 0)
+					{
+						SendServerInfo(&Packet.m_Address, -1);
+					}
+				}
+			}
+			else
+				ProcessClientPacket(&Packet);
+		}
+	}
+
+	int LoadMap(const char *pMapName)
+	{
+		DATAFILE *df;
+		char buf[512];
+		str_format(buf, sizeof(buf), "maps/%s.map", pMapName);
+		df = datafile_load(buf);
+		if(!df)
+			return 0;
+		
+		/* stop recording when we change map */
+		demorec_record_stop();
+		
+		/* reinit snapshot ids */
+		m_IDPool.TimeoutIDs();
+		
+		/* get the crc of the map */
+		m_CurrentMapCrc = datafile_crc(buf);
+		dbg_msg("server", "%s crc is %08x", buf, m_CurrentMapCrc);
+			
+		str_copy(m_aCurrentMap, pMapName, sizeof(m_aCurrentMap));
+		map_set(df);
+		
+		/* load compelate map into memory for download */
+		{
+			IOHANDLE file = engine_openfile(buf, IOFLAG_READ);
+			m_CurrentMapSize = (int)io_length(file);
+			if(m_pCurrentMapData)
+				mem_free(m_pCurrentMapData);
+			m_pCurrentMapData = (unsigned char *)mem_alloc(m_CurrentMapSize, 1);
+			io_read(file, m_pCurrentMapData, m_CurrentMapSize);
+			io_close(file);
+		}
+		return 1;
+	}
+
+	int Run()
+	{
+		NETADDR bindaddr;
+
+		//snap_init_id();
+		net_init();
+		
+		/* */
+		console_register_print_callback(SendRconLineAuthed, this);
+
+		/* load map */
+		if(!LoadMap(config.sv_map))
+		{
+			dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
+			return -1;
+		}
+		
+		/* start server */
+		/* TODO: IPv6 support */
+		if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, &bindaddr, NETTYPE_IPV4) == 0)
+		{
+			/* sweet! */
+			bindaddr.port = config.sv_port;
+		}
+		else
+		{
+			mem_zero(&bindaddr, sizeof(bindaddr));
+			bindaddr.port = config.sv_port;
+		}
+		
+		
+		if(!m_NetServer.Open(bindaddr, config.sv_max_clients, 0))
+		{
+			dbg_msg("server", "couldn't open socket. port might already be in use");
+			return -1;
+		}
+
+		m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this);
+		
+		dbg_msg("server", "server name is '%s'", config.sv_name);
+		
+		mods_init();
+		dbg_msg("server", "version %s", mods_net_version());
+
+		/* start game */
+		{
+			int64 reporttime = time_get();
+			int reportinterval = 3;
+		
+			m_Lastheartbeat = 0;
+			m_GameStartTime = time_get();
+		
+			if(config.debug)
+				dbg_msg("server", "baseline memory usage %dk", mem_stats()->allocated/1024);
+
+			while(m_RunServer)
+			{
+				static PERFORMACE_INFO rootscope = {"root", 0};
+				int64 t = time_get();
+				int new_ticks = 0;
+				
+				perf_start(&rootscope);
+				
+				/* load new map TODO: don't poll this */
+				if(strcmp(config.sv_map, m_aCurrentMap) != 0 || config.sv_map_reload)
+				{
+					config.sv_map_reload = 0;
+					
+					/* load map */
+					if(LoadMap(config.sv_map))
+					{
+						int c;
+						
+						/* new map loaded */
+						mods_shutdown();
+						
+						for(c = 0; c < MAX_CLIENTS; c++)
+						{
+							if(m_aClients[c].m_State == CClient::STATE_EMPTY)
+								continue;
+							
+							SendMap(c);
+							m_aClients[c].Reset();
+							m_aClients[c].m_State = CClient::STATE_CONNECTING;
+						}
+						
+						m_GameStartTime = time_get();
+						m_CurrentTick = 0;
+						mods_init();
+					}
+					else
+					{
+						dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
+						config_set_sv_map(&config, m_aCurrentMap);
+					}
+				}
+				
+				while(t > TickStartTime(m_CurrentTick+1))
+				{
+					m_CurrentTick++;
+					new_ticks++;
+					
+					/* apply new input */
+					{
+						static PERFORMACE_INFO scope = {"input", 0};
+						int c, i;
+						
+						perf_start(&scope);
+						
+						for(c = 0; c < MAX_CLIENTS; c++)
+						{
+							if(m_aClients[c].m_State == CClient::STATE_EMPTY)
+								continue;
+							for(i = 0; i < 200; i++)
+							{
+								if(m_aClients[c].m_aInputs[i].m_GameTick == server_tick())
+								{
+									if(m_aClients[c].m_State == CClient::STATE_INGAME)
+										mods_client_predicted_input(c, m_aClients[c].m_aInputs[i].m_aData);
+									break;
+								}
+							}
+						}
+						
+						perf_end();
+					}
+					
+					/* progress game */
+					{
+						static PERFORMACE_INFO scope = {"tick", 0};
+						perf_start(&scope);
+						mods_tick();
+						perf_end();
+					}
+				}
+				
+				/* snap game */
+				if(new_ticks)
+				{
+					if(config.sv_high_bandwidth || (m_CurrentTick%2) == 0)
+					{
+						static PERFORMACE_INFO scope = {"snap", 0};
+						perf_start(&scope);
+						DoSnapshot();
+						perf_end();
+					}
+				}
+				
+				/* master server stuff */
+				register_update();
+		
+
+				{
+					static PERFORMACE_INFO scope = {"net", 0};
+					perf_start(&scope);
+					PumpNetwork();
+					perf_end();
+				}
+
+				perf_end();
+		
+				if(reporttime < time_get())
+				{
+					if(config.debug)
+					{
+						/*
+						static NETSTATS prev_stats;
+						NETSTATS stats;
+						netserver_stats(net, &stats);
+						
+						perf_next();
+						
+						if(config.dbg_pref)
+							perf_dump(&rootscope);
+
+						dbg_msg("server", "send=%8d recv=%8d",
+							(stats.send_bytes - prev_stats.send_bytes)/reportinterval,
+							(stats.recv_bytes - prev_stats.recv_bytes)/reportinterval);
+							
+						prev_stats = stats;
+						*/
+					}
+		
+					reporttime += time_freq()*reportinterval;
+				}
+				
+				/* wait for incomming data */
+				net_socket_read_wait(m_NetServer.Socket(), 5);
+			}
+		}
+
+		mods_shutdown();
+		map_unload();
+
+		if(m_pCurrentMapData)
+			mem_free(m_pCurrentMapData);
+		return 0;
+	}
+
+	static void ConKick(void *pResult, void *pUser)
+	{
+		((CServer *)pUser)->Kick(console_arg_int(pResult, 0), "kicked by console");
+	}
+
+	static int str_allnum(const char *str)
+	{
+		while(*str)
+		{
+			if(!(*str >= '0' && *str <= '9'))
+				return 0;
+			str++;
+		}
+		return 1;
+	}
+
+	static void ConBan(void *pResult, void *pUser)
+	{
+		NETADDR addr;
+		char addrstr[128];
+		const char *str = console_arg_string(pResult, 0);
+		int minutes = 30;
+		
+		if(console_arg_num(pResult) > 1)
+			minutes = console_arg_int(pResult, 1);
+		
+		if(net_addr_from_str(&addr, str) == 0)
+			((CServer *)pUser)->BanAdd(addr, minutes*60);
+		else if(str_allnum(str))
+		{
+			NETADDR addr;
+			int cid = atoi(str);
+
+			if(cid < 0 || cid > MAX_CLIENTS || ((CServer *)pUser)->m_aClients[cid].m_State == CClient::STATE_EMPTY)
+			{
+				dbg_msg("server", "invalid client id");
+				return;
+			}
+
+			addr = ((CServer *)pUser)->m_NetServer.ClientAddr(cid);
+			((CServer *)pUser)->BanAdd(addr, minutes*60);
+		}
+		
+		addr.port = 0;
+		net_addr_str(&addr, addrstr, sizeof(addrstr));
+		
+		if(minutes)
+			dbg_msg("server", "banned %s for %d minutes", addrstr, minutes);
+		else
+			dbg_msg("server", "banned %s for life", addrstr);
+	}
+
+	static void ConUnban(void *result, void *pUser)
+	{
+		NETADDR addr;
+		const char *str = console_arg_string(result, 0);
+		
+		if(net_addr_from_str(&addr, str) == 0)
+			((CServer *)pUser)->BanRemove(addr);
+		else
+			dbg_msg("server", "invalid network address");
+	}
+
+	static void ConBans(void *pResult, void *pUser)
+	{
+		unsigned now = time_timestamp();
+		
+		int num = ((CServer *)pUser)->m_NetServer.BanNum();
+		for(int i = 0; i < num; i++)
+		{
+			CNetServer::CBanInfo Info;
+			((CServer *)pUser)->m_NetServer.BanGet(i, &Info);
+			NETADDR Addr = Info.m_Addr;
+			
+			if(Info.m_Expires == -1)
+			{
+				dbg_msg("server", "#%d %d.%d.%d.%d for life", i, Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3]);
+			}
+			else
+			{
+				unsigned t = Info.m_Expires - now;
+				dbg_msg("server", "#%d %d.%d.%d.%d for %d minutes and %d seconds", i, Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3], t/60, t%60);
+			}
+		}
+		dbg_msg("server", "%d ban(s)", num);
+	}
+
+	static void ConStatus(void *pResult, void *pUser)
+	{
+		int i;
+		NETADDR addr;
+		for(i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(((CServer *)pUser)->m_aClients[i].m_State == CClient::STATE_INGAME)
+			{
+				addr = ((CServer *)pUser)->m_NetServer.ClientAddr(i);
+				dbg_msg("server", "id=%d addr=%d.%d.%d.%d:%d name='%s' score=%d",
+					i, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], addr.port,
+					((CServer *)pUser)->m_aClients[i].m_aName, ((CServer *)pUser)->m_aClients[i].m_Score);
+			}
+		}
+	}
+
+	static void ConShutdown(void *pResult, void *pUser)
+	{
+		((CServer *)pUser)->m_RunServer = 0;
+	}
+
+	static void ConRecord(void *pResult, void *pUser)
+	{
+		char filename[512];
+		str_format(filename, sizeof(filename), "demos/%s.demo", console_arg_string(pResult, 0));
+		demorec_record_start(filename, mods_net_version(), ((CServer *)pUser)->m_aCurrentMap, ((CServer *)pUser)->m_CurrentMapCrc, "server");
+	}
+
+	static void ConStopRecord(void *pResult, void *pUser)
+	{
+		demorec_record_stop();
+	}
+	
+
+	void RegisterCommands()
+	{
+		MACRO_REGISTER_COMMAND("kick", "i", CFGFLAG_SERVER, ConKick, this, "");
+		MACRO_REGISTER_COMMAND("ban", "s?i", CFGFLAG_SERVER, ConBan, this, "");
+		MACRO_REGISTER_COMMAND("unban", "s", CFGFLAG_SERVER, ConUnban, this, "");
+		MACRO_REGISTER_COMMAND("bans", "", CFGFLAG_SERVER, ConBans, this, "");
+		MACRO_REGISTER_COMMAND("status", "", CFGFLAG_SERVER, ConStatus, this, "");
+		MACRO_REGISTER_COMMAND("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "");
+
+		MACRO_REGISTER_COMMAND("record", "s", CFGFLAG_SERVER, ConRecord, this, "");
+		MACRO_REGISTER_COMMAND("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "");
+	}	
+	
+};
+
+
+// UGLY UGLY HACK for now
+CServer g_Server;
+CNetServer *m_pNetServer;
+
+int server_tick() { return g_Server.Tick(); }
+int server_tickspeed() { return g_Server.TickSpeed(); }
+int snap_new_id() { return g_Server.m_IDPool.NewID(); }
+void snap_free_id(int id) { return g_Server.m_IDPool.FreeID(id); }
+int server_send_msg(int client_id) { return g_Server.SendMsg(client_id); }
+void server_setbrowseinfo(const char *game_type, int progression) { g_Server.SetBrowseInfo(game_type, progression); }
+void server_setclientname(int client_id, const char *name) { g_Server.SetClientName(client_id, name); }
+void server_setclientscore(int client_id, int score) { g_Server.SetClientScore(client_id, score); }
+
+int server_getclientinfo(int client_id, CLIENT_INFO *info) { return g_Server.GetClientInfo(client_id, info); }
+
+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 g_Server.m_SnapshotBuilder.NewItem(type, id, size);
+}
+
+int *server_latestinput(int client_id, int *size)
+{
+	if(client_id < 0 || client_id > MAX_CLIENTS || g_Server.m_aClients[client_id].m_State < CServer::CClient::STATE_READY)
+		return 0;
+	return g_Server.m_aClients[client_id].m_LatestInput.m_aData;
+}
+
+const char *server_clientname(int client_id)
+{
+	if(client_id < 0 || client_id > MAX_CLIENTS || g_Server.m_aClients[client_id].m_State < CServer::CClient::STATE_READY)
+		return "(invalid client)";
+	return g_Server.m_aClients[client_id].m_aName;
+}
+
+#if 0
+
+
+static void reset_client(int cid)
+{
+	/* reset input */
+	int i;
+	for(i = 0; i < 200; i++)
+		m_aClients[cid].m_aInputs[i].m_GameTick = -1;
+	m_aClients[cid].m_CurrentInput = 0;
+	mem_zero(&m_aClients[cid].m_Latestinput, sizeof(m_aClients[cid].m_Latestinput));
+
+	m_aClients[cid].m_Snapshots.PurgeAll();
+	m_aClients[cid].m_LastAckedSnapshot = -1;
+	m_aClients[cid].m_LastInputTick = -1;
+	m_aClients[cid].m_SnapRate = CClient::SNAPRATE_INIT;
+	m_aClients[cid].m_Score = 0;
+
+}
+
+
+static int new_client_callback(int cid, void *user)
+{
+	m_aClients[cid].state = CClient::STATE_AUTH;
+	m_aClients[cid].name[0] = 0;
+	m_aClients[cid].clan[0] = 0;
+	m_aClients[cid].authed = 0;
+	reset_client(cid);
+	return 0;
+}
+
+static int del_client_callback(int cid, void *user)
+{
+	/* notify the mod about the drop */
+	if(m_aClients[cid].state >= CClient::STATE_READY)
+		mods_client_drop(cid);
+	
+	m_aClients[cid].state = CClient::STATE_EMPTY;
+	m_aClients[cid].name[0] = 0;
+	m_aClients[cid].clan[0] = 0;
+	m_aClients[cid].authed = 0;
+	m_aClients[cid].snapshots.PurgeAll();
+	return 0;
+}
+static void server_send_map(int cid)
+{
+	msg_pack_start_system(NETMSG_MAP_CHANGE, MSGFLAG_VITAL|MSGFLAG_FLUSH);
+	msg_pack_string(config.sv_map, 0);
+	msg_pack_int(current_map_crc);
+	msg_pack_end();
+	server_send_msg(cid);
+}
+
+static void server_send_rcon_line(int cid, const char *line)
+{
+	msg_pack_start_system(NETMSG_RCON_LINE, MSGFLAG_VITAL);
+	msg_pack_string(line, 512);
+	msg_pack_end();
+	server_send_msg(cid);
+}
+
+static void server_send_rcon_line_authed(const char *line, void *user_data)
+{
+	static volatile int reentry_guard = 0;
+	int i;
+	
+	if(reentry_guard) return;
+	reentry_guard++;
+	
+	for(i = 0; i < MAX_CLIENTS; i++)
+	{
+		if(m_aClients[i].state != CClient::STATE_EMPTY && m_aClients[i].authed)
+			server_send_rcon_line(i, line);
+	}
+	
+	reentry_guard--;
+}
+
+static void server_pump_network()
+{
+	CNetChunk Packet;
+
+	m_NetServer.Update();
+	
+	/* process packets */
+	while(m_NetServer.Recv(&Packet))
+	{
+		if(Packet.m_ClientID == -1)
+		{
+			/* stateless */
+			if(!register_process_packet(&Packet))
+			{
+				if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETINFO)+1 &&
+					memcmp(Packet.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
+				{
+					server_send_serverinfo(&Packet.m_Address, ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO)]);
+				}
+				
+				
+				if(Packet.m_DataSize == sizeof(SERVERBROWSE_OLD_GETINFO) &&
+					memcmp(Packet.m_pData, SERVERBROWSE_OLD_GETINFO, sizeof(SERVERBROWSE_OLD_GETINFO)) == 0)
+				{
+					server_send_serverinfo(&Packet.m_Address, -1);
+				}
+			}
+		}
+		else
+			server_process_client_packet(&Packet);
+	}
+}
+
+static int server_load_map(const char *mapname)
+{
+	DATAFILE *df;
+	char buf[512];
+	str_format(buf, sizeof(buf), "maps/%s.map", mapname);
+	df = datafile_load(buf);
+	if(!df)
+		return 0;
+	
+	/* stop recording when we change map */
+	demorec_record_stop();
+	
+	/* reinit snapshot ids */
+	snap_timeout_ids();
+	
+	/* get the crc of the map */
+	current_map_crc = datafile_crc(buf);
+	dbg_msg("server", "%s crc is %08x", buf, current_map_crc);
+		
+	str_copy(current_map, mapname, sizeof(current_map));
+	map_set(df);
+	
+	/* load compelate map into memory for download */
+	{
+		IOHANDLE file = engine_openfile(buf, IOFLAG_READ);
+		current_map_size = (int)io_length(file);
+		if(current_map_data)
+			mem_free(current_map_data);
+		current_map_data = (unsigned char *)mem_alloc(current_map_size, 1);
+		io_read(file, current_map_data, current_map_size);
+		io_close(file);
+	}
+	return 1;
+}
+
+static int server_run()
+{
+	NETADDR bindaddr;
+
+	snap_init_id();
+	net_init();
+	
+	/* */
+	console_register_print_callback(server_send_rcon_line_authed, 0);
+
+	/* load map */
+	if(!server_load_map(config.sv_map))
+	{
+		dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
+		return -1;
+	}
+	
+	/* start server */
+	/* TODO: IPv6 support */
+	if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, &bindaddr, NETTYPE_IPV4) == 0)
+	{
+		/* sweet! */
+		bindaddr.port = config.sv_port;
+	}
+	else
+	{
+		mem_zero(&bindaddr, sizeof(bindaddr));
+		bindaddr.port = config.sv_port;
+	}
+	
+	
+	if(!m_NetServer.Open(bindaddr, config.sv_max_clients, 0))
+	{
+		dbg_msg("server", "couldn't open socket. port might already be in use");
+		return -1;
+	}
+
+	m_NetServer.SetCallbacks(new_client_callback, del_client_callback, this);
+	
+	dbg_msg("server", "server name is '%s'", config.sv_name);
+	
+	mods_init();
+	dbg_msg("server", "version %s", mods_net_version());
+
+	/* start game */
+	{
+		int64 reporttime = time_get();
+		int reportinterval = 3;
+	
+		lastheartbeat = 0;
+		game_start_time = time_get();
+	
+		if(config.debug)
+			dbg_msg("server", "baseline memory usage %dk", mem_stats()->allocated/1024);
+
+		while(run_server)
+		{
+			static PERFORMACE_INFO rootscope = {"root", 0};
+			int64 t = time_get();
+			int new_ticks = 0;
+			
+			perf_start(&rootscope);
+			
+			/* load new map TODO: don't poll this */
+			if(strcmp(config.sv_map, current_map) != 0 || config.sv_map_reload)
+			{
+				config.sv_map_reload = 0;
+				
+				/* load map */
+				if(server_load_map(config.sv_map))
+				{
+					int c;
+					
+					/* new map loaded */
+					mods_shutdown();
+					
+					for(c = 0; c < MAX_CLIENTS; c++)
+					{
+						if(m_aClients[c].state == CClient::STATE_EMPTY)
+							continue;
+						
+						server_send_map(c);
+						reset_client(c);
+						m_aClients[c].state = CClient::STATE_CONNECTING;
+					}
+					
+					game_start_time = time_get();
+					current_tick = 0;
+					mods_init();
+				}
+				else
+				{
+					dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map);
+					config_set_sv_map(&config, current_map);
+				}
+			}
+			
+			while(t > server_tick_start_time(current_tick+1))
+			{
+				current_tick++;
+				new_ticks++;
+				
+				/* apply new input */
+				{
+					static PERFORMACE_INFO scope = {"input", 0};
+					int c, i;
+					
+					perf_start(&scope);
+					
+					for(c = 0; c < MAX_CLIENTS; c++)
+					{
+						if(m_aClients[c].state == CClient::STATE_EMPTY)
+							continue;
+						for(i = 0; i < 200; i++)
+						{
+							if(m_aClients[c].inputs[i].game_tick == server_tick())
+							{
+								if(m_aClients[c].state == CClient::STATE_INGAME)
+									mods_client_predicted_input(c, m_aClients[c].inputs[i].data);
+								break;
+							}
+						}
+					}
+					
+					perf_end();
+				}
+				
+				/* progress game */
+				{
+					static PERFORMACE_INFO scope = {"tick", 0};
+					perf_start(&scope);
+					mods_tick();
+					perf_end();
+				}
+			}
+			
+			/* snap game */
+			if(new_ticks)
+			{
+				if(config.sv_high_bandwidth || (current_tick%2) == 0)
+				{
+					static PERFORMACE_INFO scope = {"snap", 0};
+					perf_start(&scope);
+					server_do_snap();
+					perf_end();
+				}
+			}
+			
+			/* master server stuff */
+			register_update();
+	
+
+			{
+				static PERFORMACE_INFO scope = {"net", 0};
+				perf_start(&scope);
+				server_pump_network();
+				perf_end();
+			}
+
+			perf_end();
+	
+			if(reporttime < time_get())
+			{
+				if(config.debug)
+				{
+					/*
+					static NETSTATS prev_stats;
+					NETSTATS stats;
+					netserver_stats(net, &stats);
+					
+					perf_next();
+					
+					if(config.dbg_pref)
+						perf_dump(&rootscope);
+
+					dbg_msg("server", "send=%8d recv=%8d",
+						(stats.send_bytes - prev_stats.send_bytes)/reportinterval,
+						(stats.recv_bytes - prev_stats.recv_bytes)/reportinterval);
+						
+					prev_stats = stats;
+					*/
+				}
+	
+				reporttime += time_freq()*reportinterval;
+			}
+			
+			/* wait for incomming data */
+			net_socket_read_wait(m_NetServer.Socket(), 5);
+		}
+	}
+
+	mods_shutdown();
+	map_unload();
+
+	if(current_map_data)
+		mem_free(current_map_data);
+	return 0;
+}
+
+
+#endif
+
+int main(int argc, char **argv)
+{
+	
+	m_pNetServer = &g_Server.m_NetServer;
+#if defined(CONF_FAMILY_WINDOWS)
+	int i;
+	for(i = 1; i < argc; i++)
+	{
+		if(strcmp("-s", argv[i]) == 0 || strcmp("--silent", argv[i]) == 0)
+		{
+			ShowWindow(GetConsoleWindow(), SW_HIDE);
+			break;
+		}
+	}
+#endif
+
+	/* init the engine */
+	dbg_msg("server", "starting...");
+	engine_init("Teeworlds");
+	
+	/* register all console commands */
+	
+	g_Server.RegisterCommands();
+	mods_console_init();
+	
+	/* parse the command line arguments */
+	engine_parse_arguments(argc, argv);
+	
+	/* run the server */
+	g_Server.Run();
+	return 0;
+}
+
diff --git a/src/game/client/clienthooks.cpp b/src/game/client/clienthooks.cpp
index 88a7722a..76fa8dcd 100644
--- a/src/game/client/clienthooks.cpp
+++ b/src/game/client/clienthooks.cpp
@@ -7,22 +7,21 @@
 
 
 
-
 // clean hooks
-extern "C" void modc_entergame() {}
-extern "C" void modc_shutdown() {}
-extern "C" void modc_console_init() { gameclient.on_console_init(); }
-extern "C" void modc_save_config() { gameclient.on_save(); }
-extern "C" void modc_init() { gameclient.on_init(); }
-extern "C" void modc_connected() { gameclient.on_connected(); }
-extern "C" void modc_predict() { gameclient.on_predict(); }
-extern "C" void modc_newsnapshot() { gameclient.on_snapshot(); }
-extern "C" int modc_snap_input(int *data) { return gameclient.on_snapinput(data); }
-extern "C" void modc_statechange(int state, int old) { gameclient.on_statechange(state, old); }
-extern "C" void modc_render() { gameclient.on_render(); }
-extern "C" void modc_message(int msgtype) { gameclient.on_message(msgtype); }
-extern "C" void modc_rcon_line(const char *line) { gameclient.console->print_line(1, line); }
+void modc_entergame() {}
+void modc_shutdown() {}
+void modc_console_init() { gameclient.on_console_init(); }
+void modc_save_config() { gameclient.on_save(); }
+void modc_init() { gameclient.on_init(); }
+void modc_connected() { gameclient.on_connected(); }
+void modc_predict() { gameclient.on_predict(); }
+void modc_newsnapshot() { gameclient.on_snapshot(); }
+int modc_snap_input(int *data) { return gameclient.on_snapinput(data); }
+void modc_statechange(int state, int old) { gameclient.on_statechange(state, old); }
+void modc_render() { gameclient.on_render(); }
+void modc_message(int msgtype) { gameclient.on_message(msgtype); }
+void modc_rcon_line(const char *line) { gameclient.console->print_line(1, line); }
 
-extern "C" const char *modc_net_version() { return GAME_NETVERSION; }
-extern "C" const char *modc_getitemname(int type) { return netobj_get_name(type); }
+const char *modc_net_version() { return GAME_NETVERSION; }
+const char *modc_getitemname(int type) { return netobj_get_name(type); }
 
diff --git a/src/game/client/component.hpp b/src/game/client/component.hpp
index 3d5edb86..6534e56b 100644
--- a/src/game/client/component.hpp
+++ b/src/game/client/component.hpp
@@ -2,13 +2,21 @@
 #define GAME_CLIENT_GAMESYSTEM_H
 
 #include <engine/e_client_interface.h>
+#include "gameclient.hpp"
 
 class GAMECLIENT;
 
 class COMPONENT
 {
 protected:
+	friend class GAMECLIENT;
+
 	GAMECLIENT *client;
+	
+	// perhaps propagte pointers for these as well
+	class IGraphics *Graphics() const { return client->Graphics(); }
+	class CUI *UI() const { return client->UI(); }
+	class CRenderTools *RenderTools() const { return client->RenderTools(); }
 public:
 	virtual ~COMPONENT() {}
 	
diff --git a/src/game/client/components/broadcast.cpp b/src/game/client/components/broadcast.cpp
index 960b004c..b86ed658 100644
--- a/src/game/client/components/broadcast.cpp
+++ b/src/game/client/components/broadcast.cpp
@@ -1,5 +1,6 @@
 #include <engine/e_client_interface.h>
 #include <engine/e_config.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -14,12 +15,12 @@ void BROADCAST::on_reset()
 
 void BROADCAST::on_render()
 {
-	gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300);
+	Graphics()->MapScreen(0, 0, 300*Graphics()->ScreenAspect(), 300);
 		
 	if(time_get() < broadcast_time)
 	{
 		float w = gfx_text_width(0, 14, broadcast_text, -1);
-		gfx_text(0, 150*gfx_screenaspect()-w/2, 35, 14, broadcast_text, -1);
+		gfx_text(0, 150*Graphics()->ScreenAspect()-w/2, 35, 14, broadcast_text, -1);
 	}
 }
 
diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp
index 37015337..fdf1d21b 100644
--- a/src/game/client/components/chat.cpp
+++ b/src/game/client/components/chat.cpp
@@ -1,6 +1,7 @@
 #include <string.h> // strcmp
 
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -133,7 +134,7 @@ void CHAT::add_line(int client_id, int team, const char *line)
 
 void CHAT::on_render()
 {
-	gfx_mapscreen(0,0,300*gfx_screenaspect(),300);
+	Graphics()->MapScreen(0,0,300*Graphics()->ScreenAspect(),300);
 	float x = 10.0f;
 	float y = 300.0f-20.0f;
 	if(mode != MODE_NONE)
diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp
index 7b806b36..382cb134 100644
--- a/src/game/client/components/console.cpp
+++ b/src/game/client/components/console.cpp
@@ -6,10 +6,9 @@
 #include <base/system.h>
 
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 
-extern "C" {
-	#include <engine/e_ringbuffer.h>
-}
+#include <engine/e_ringbuffer.h>
 
 #include <cstring>
 #include <cstdio>
@@ -34,8 +33,8 @@ enum
 CONSOLE::INSTANCE::INSTANCE(int t)
 {
 	// init ringbuffers
-	history = ringbuf_init(history_data, sizeof(history_data), RINGBUF_FLAG_RECYCLE);
-	backlog = ringbuf_init(backlog_data, sizeof(backlog_data), RINGBUF_FLAG_RECYCLE);
+	//history = ringbuf_init(history_data, sizeof(history_data), RINGBUF_FLAG_RECYCLE);
+	//backlog = ringbuf_init(backlog_data, sizeof(backlog_data), RINGBUF_FLAG_RECYCLE);
 	
 	history_entry = 0x0;
 	
@@ -83,7 +82,7 @@ void CONSOLE::INSTANCE::on_input(INPUT_EVENT e)
 		{
 			if(input.get_string()[0])
 			{
-				char *entry = (char *)ringbuf_allocate(history, input.get_length()+1);
+				char *entry = history.Allocate(input.get_length()+1);
 				mem_copy(entry, input.get_string(), input.get_length()+1);
 				
 				execute_line(input.get_string());
@@ -97,13 +96,13 @@ void CONSOLE::INSTANCE::on_input(INPUT_EVENT e)
 		{
 			if (history_entry)
 			{
-				char *test = (char *)ringbuf_prev(history, history_entry);
+				char *test = history.Prev(history_entry);
 
 				if (test)
 					history_entry = test;
 			}
 			else
-				history_entry = (char *)ringbuf_last(history);
+				history_entry = history.Last();
 
 			if (history_entry)
 			{
@@ -116,7 +115,7 @@ void CONSOLE::INSTANCE::on_input(INPUT_EVENT e)
 		else if (e.key == KEY_DOWN)
 		{
 			if (history_entry)
-				history_entry = (char *)ringbuf_next(history, history_entry);
+				history_entry = history.Next(history_entry);
 
 			if (history_entry)
 			{
@@ -173,7 +172,7 @@ void CONSOLE::INSTANCE::print_line(const char *line)
 	if (len > 255)
 		len = 255;
 
-	char *entry = (char *)ringbuf_allocate(backlog, len+1);
+	char *entry = backlog.Allocate(len+1);
 	mem_copy(entry, line, len+1);
 }
 
@@ -212,6 +211,7 @@ static float console_scale_func(float t)
 
 struct RENDERINFO
 {
+	CONSOLE *self;
 	TEXT_CURSOR cursor;
 	const char *current_cmd;
 	int wanted_completion;
@@ -225,11 +225,11 @@ void CONSOLE::possible_commands_render_callback(const char *str, void *user)
 	if(info->enum_count == info->wanted_completion)
 	{
 		float tw = gfx_text_width(info->cursor.font, info->cursor.font_size, str, -1);
-		gfx_texture_set(-1);
-		gfx_quads_begin();
-			gfx_setcolor(229.0f/255.0f,185.0f/255.0f,4.0f/255.0f,0.85f);
-			draw_round_rect(info->cursor.x-3, info->cursor.y, tw+5, info->cursor.font_size+4, info->cursor.font_size/3);
-		gfx_quads_end();
+		info->self->Graphics()->TextureSet(-1);
+		info->self->Graphics()->QuadsBegin();
+			info->self->Graphics()->SetColor(229.0f/255.0f,185.0f/255.0f,4.0f/255.0f,0.85f);
+			info->self->RenderTools()->draw_round_rect(info->cursor.x-3, info->cursor.y, tw+5, info->cursor.font_size+4, info->cursor.font_size/3);
+		info->self->Graphics()->QuadsEnd();
 		
 		gfx_text_color(0.05f, 0.05f, 0.05f,1);
 		gfx_text_ex(&info->cursor, str, -1);
@@ -260,7 +260,7 @@ void CONSOLE::possible_commands_render_callback(const char *str, void *user)
 
 void CONSOLE::on_render()
 {
-    RECT screen = *ui_screen();
+    CUIRect screen = *UI()->Screen();
 	float console_max_height = screen.h*3/5.0f;
 	float console_height;
 
@@ -296,45 +296,45 @@ void CONSOLE::on_render()
 
 	console_height = console_height_scale*console_max_height;
 
-	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+	Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 
 	// do console shadow
-	gfx_texture_set(-1);
-    gfx_quads_begin();
-    gfx_setcolorvertex(0, 0,0,0, 0.5f);
-    gfx_setcolorvertex(1, 0,0,0, 0.5f);
-    gfx_setcolorvertex(2, 0,0,0, 0.0f);
-    gfx_setcolorvertex(3, 0,0,0, 0.0f);
-    gfx_quads_drawTL(0,console_height,screen.w,10.0f);
-    gfx_quads_end();
+	Graphics()->TextureSet(-1);
+    Graphics()->QuadsBegin();
+    Graphics()->SetColorVertex(0, 0,0,0, 0.5f);
+    Graphics()->SetColorVertex(1, 0,0,0, 0.5f);
+    Graphics()->SetColorVertex(2, 0,0,0, 0.0f);
+    Graphics()->SetColorVertex(3, 0,0,0, 0.0f);
+    Graphics()->QuadsDrawTL(0,console_height,screen.w,10.0f);
+    Graphics()->QuadsEnd();
 
 	// do background
-	gfx_texture_set(data->images[IMAGE_CONSOLE_BG].id);
-    gfx_quads_begin();
-    gfx_setcolor(0.2f, 0.2f, 0.2f,0.9f);
+	Graphics()->TextureSet(data->images[IMAGE_CONSOLE_BG].id);
+    Graphics()->QuadsBegin();
+    Graphics()->SetColor(0.2f, 0.2f, 0.2f,0.9f);
     if(console_type != 0)
-	    gfx_setcolor(0.4f, 0.2f, 0.2f,0.9f);
-    gfx_quads_setsubset(0,-console_height*0.075f,screen.w*0.075f*0.5f,0);
-    gfx_quads_drawTL(0,0,screen.w,console_height);
-    gfx_quads_end();
+	    Graphics()->SetColor(0.4f, 0.2f, 0.2f,0.9f);
+    Graphics()->QuadsSetSubset(0,-console_height*0.075f,screen.w*0.075f*0.5f,0);
+    Graphics()->QuadsDrawTL(0,0,screen.w,console_height);
+    Graphics()->QuadsEnd();
 
 	// do small bar shadow
-	gfx_texture_set(-1);
-    gfx_quads_begin();
-    gfx_setcolorvertex(0, 0,0,0, 0.0f);
-    gfx_setcolorvertex(1, 0,0,0, 0.0f);
-    gfx_setcolorvertex(2, 0,0,0, 0.25f);
-    gfx_setcolorvertex(3, 0,0,0, 0.25f);
-    gfx_quads_drawTL(0,console_height-20,screen.w,10);
-    gfx_quads_end();
+	Graphics()->TextureSet(-1);
+    Graphics()->QuadsBegin();
+    Graphics()->SetColorVertex(0, 0,0,0, 0.0f);
+    Graphics()->SetColorVertex(1, 0,0,0, 0.0f);
+    Graphics()->SetColorVertex(2, 0,0,0, 0.25f);
+    Graphics()->SetColorVertex(3, 0,0,0, 0.25f);
+    Graphics()->QuadsDrawTL(0,console_height-20,screen.w,10);
+    Graphics()->QuadsEnd();
 
 	// do the lower bar
-	gfx_texture_set(data->images[IMAGE_CONSOLE_BAR].id);
-    gfx_quads_begin();
-    gfx_setcolor(1.0f, 1.0f, 1.0f, 0.9f);
-    gfx_quads_setsubset(0,0.1f,screen.w*0.015f,1-0.1f);
-    gfx_quads_drawTL(0,console_height-10.0f,screen.w,10.0f);
-    gfx_quads_end();
+	Graphics()->TextureSet(data->images[IMAGE_CONSOLE_BAR].id);
+    Graphics()->QuadsBegin();
+    Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.9f);
+    Graphics()->QuadsSetSubset(0,0.1f,screen.w*0.015f,1-0.1f);
+    Graphics()->QuadsDrawTL(0,console_height-10.0f,screen.w,10.0f);
+    Graphics()->QuadsEnd();
     
     console_height -= 22.0f;
     
@@ -351,6 +351,7 @@ void CONSOLE::on_render()
 		gfx_text_set_cursor(&cursor, x, y, font_size, TEXTFLAG_RENDER);
 
 		RENDERINFO info;
+		info.self = this;
 		info.wanted_completion = console->completion_chosen;
 		info.enum_count = 0;
 		info.current_cmd = console->completion_buffer;
@@ -407,13 +408,13 @@ void CONSOLE::on_render()
 
 		// render log
 		y -= row_height;
-		char *entry = (char *)ringbuf_last(console->backlog);
+		char *entry = console->backlog.Last();
 		while (y > 0.0f && entry)
 		{
 			gfx_text(0, x, y, font_size, entry, -1);
 			y -= row_height;
 
-			entry = (char *)ringbuf_prev(console->backlog, entry);
+			entry = console->backlog.Prev(entry);
 		}
 	}	
 }
diff --git a/src/game/client/components/console.hpp b/src/game/client/components/console.hpp
index 0a4adbda..78da98b8 100644
--- a/src/game/client/components/console.hpp
+++ b/src/game/client/components/console.hpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/e_ringbuffer.h>
 #include <game/client/component.hpp>
 #include <game/client/lineinput.hpp>
 
@@ -7,12 +8,9 @@ class CONSOLE : public COMPONENT
 	class INSTANCE
 	{
 	public:
-		char history_data[65536];
-		struct RINGBUFFER *history;
+		TStaticRingBuffer<char, 64*1024, CRingBufferBase::FLAG_RECYCLE> backlog;
+		TStaticRingBuffer<char, 64*1024, CRingBufferBase::FLAG_RECYCLE> history;
 		char *history_entry;
-		
-		char backlog_data[65536];
-		struct RINGBUFFER *backlog;
 
 		LINEINPUT input;
 		
diff --git a/src/game/client/components/damageind.cpp b/src/game/client/components/damageind.cpp
index f585e4d3..7f1991dc 100644
--- a/src/game/client/components/damageind.cpp
+++ b/src/game/client/components/damageind.cpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -44,8 +45,8 @@ void DAMAGEIND::create(vec2 pos, vec2 dir)
 
 void DAMAGEIND::on_render()
 {
-	gfx_texture_set(data->images[IMAGE_GAME].id);
-	gfx_quads_begin();
+	Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+	Graphics()->QuadsBegin();
 	for(int i = 0; i < num_items;)
 	{
 		vec2 pos = mix(items[i].pos+items[i].dir*75.0f, items[i].pos, clamp((items[i].life-0.60f)/0.15f, 0.0f, 1.0f));
@@ -55,12 +56,12 @@ void DAMAGEIND::on_render()
 			destroy_i(&items[i]);
 		else
 		{
-			gfx_setcolor(1.0f,1.0f,1.0f, items[i].life/0.1f);
-			gfx_quads_setrotation(items[i].startangle + items[i].life * 2.0f);
-			select_sprite(SPRITE_STAR1);
-			draw_sprite(pos.x, pos.y, 48.0f);
+			Graphics()->SetColor(1.0f,1.0f,1.0f, items[i].life/0.1f);
+			Graphics()->QuadsSetRotation(items[i].startangle + items[i].life * 2.0f);
+			RenderTools()->select_sprite(SPRITE_STAR1);
+			RenderTools()->draw_sprite(pos.x, pos.y, 48.0f);
 			i++;
 		}
 	}
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 }
diff --git a/src/game/client/components/debughud.cpp b/src/game/client/components/debughud.cpp
index ada006ea..c7cc559b 100644
--- a/src/game/client/components/debughud.cpp
+++ b/src/game/client/components/debughud.cpp
@@ -5,6 +5,7 @@ extern "C" {
 }
 
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -23,7 +24,7 @@ void DEBUGHUD::render_netcorrections()
 	if(!config.debug || !gameclient.snap.local_character || !gameclient.snap.local_prev_character)
 		return;
 
-	gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300);
+	Graphics()->MapScreen(0, 0, 300*Graphics()->ScreenAspect(), 300);
 	
 	/*float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y),
 		vec2(netobjects.local_character->x, netobjects.local_character->y));*/
@@ -50,7 +51,7 @@ void DEBUGHUD::render_tuning()
 		
 	TUNING_PARAMS standard_tuning;
 		
-	gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300);
+	Graphics()->MapScreen(0, 0, 300*Graphics()->ScreenAspect(), 300);
 	
 	float y = 50.0f;
 	int count = 0;
@@ -87,9 +88,9 @@ void DEBUGHUD::render_tuning()
 	
 	y = y+count*6;
 	
-	gfx_texture_set(-1);
-	gfx_blend_normal();
-	gfx_lines_begin();
+	Graphics()->TextureSet(-1);
+	Graphics()->BlendNormal();
+	Graphics()->LinesBegin();
 	float height = 50.0f;
 	float pv = 1;
 	for(int i = 0; i < 100; i++)
@@ -97,11 +98,11 @@ void DEBUGHUD::render_tuning()
 		float speed = i/100.0f * 3000;
 		float ramp = velocity_ramp(speed, gameclient.tuning.velramp_start, gameclient.tuning.velramp_range, gameclient.tuning.velramp_curvature);
 		float rampedspeed = (speed * ramp)/1000.0f;
-		gfx_lines_draw((i-1)*2, y+height-pv*height, i*2, y+height-rampedspeed*height);
-		//gfx_lines_draw((i-1)*2, 200, i*2, 200);
+		Graphics()->LinesDraw((i-1)*2, y+height-pv*height, i*2, y+height-rampedspeed*height);
+		//Graphics()->LinesDraw((i-1)*2, 200, i*2, 200);
 		pv = rampedspeed;
 	}
-	gfx_lines_end();
+	Graphics()->LinesEnd();
 	gfx_text_color(1,1,1,1);
 }
 
diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp
index 934b2fcf..8001a306 100644
--- a/src/game/client/components/emoticon.cpp
+++ b/src/game/client/components/emoticon.cpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -70,7 +71,7 @@ void EMOTICON::draw_circle(float x, float y, float r, int segments)
 		float sa2 = sinf(a2);
 		float sa3 = sinf(a3);
 
-		gfx_quads_draw_freeform(
+		client->Graphics()->QuadsDrawFreeform(
 			x, y,
 			x+ca1*r, y+sa1*r,
 			x+ca3*r, y+sa3*r,
@@ -107,20 +108,20 @@ void EMOTICON::on_render()
 	if (length(selector_mouse) > 100)
 		selected_emote = (int)(selected_angle / (2*pi) * 12.0f);
 
-    RECT screen = *ui_screen();
+    CUIRect screen = *UI()->Screen();
 
-	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+	Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 
-	gfx_blend_normal();
+	Graphics()->BlendNormal();
 
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.3f);
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.3f);
 	draw_circle(screen.w/2, screen.h/2, 160, 64);
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 
-	gfx_texture_set(data->images[IMAGE_EMOTICONS].id);
-	gfx_quads_begin();
+	Graphics()->TextureSet(data->images[IMAGE_EMOTICONS].id);
+	Graphics()->QuadsBegin();
 
 	for (int i = 0; i < 12; i++)
 	{
@@ -134,17 +135,17 @@ void EMOTICON::on_render()
 
 		float nudge_x = 120 * cos(angle);
 		float nudge_y = 120 * sin(angle);
-		select_sprite(SPRITE_OOP + i);
-		gfx_quads_draw(screen.w/2 + nudge_x, screen.h/2 + nudge_y, size, size);
+		RenderTools()->select_sprite(SPRITE_OOP + i);
+		Graphics()->QuadsDraw(screen.w/2 + nudge_x, screen.h/2 + nudge_y, size, size);
 	}
 
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 
-    gfx_texture_set(data->images[IMAGE_CURSOR].id);
-    gfx_quads_begin();
-    gfx_setcolor(1,1,1,1);
-    gfx_quads_drawTL(selector_mouse.x+screen.w/2,selector_mouse.y+screen.h/2,24,24);
-    gfx_quads_end();
+    Graphics()->TextureSet(data->images[IMAGE_CURSOR].id);
+    Graphics()->QuadsBegin();
+    Graphics()->SetColor(1,1,1,1);
+    Graphics()->QuadsDrawTL(selector_mouse.x+screen.w/2,selector_mouse.y+screen.h/2,24,24);
+    Graphics()->QuadsEnd();
 }
 
 void EMOTICON::emote(int emoticon)
diff --git a/src/game/client/components/flow.cpp b/src/game/client/components/flow.cpp
index b2f983e6..9ecd4b5c 100644
--- a/src/game/client/components/flow.cpp
+++ b/src/game/client/components/flow.cpp
@@ -1,3 +1,4 @@
+#include <engine/client/graphics.h>
 #include <game/mapitems.hpp>
 #include <game/layers.hpp>
 #include "flow.hpp"
@@ -15,17 +16,17 @@ void FLOW::dbg_render()
 	if(!cells)
 		return;
 
-	gfx_texture_set(-1);
-	gfx_lines_begin();
+	Graphics()->TextureSet(-1);
+	Graphics()->LinesBegin();
 	for(int y = 0; y < height; y++)
 		for(int x = 0; x < width; x++)
 		{
 			vec2 pos(x*spacing, y*spacing);
 			vec2 vel = cells[y*width+x].vel * 0.01f;
-			gfx_lines_draw(pos.x, pos.y, pos.x+vel.x, pos.y+vel.y);
+			Graphics()->LinesDraw(pos.x, pos.y, pos.x+vel.x, pos.y+vel.y);
 		}
 		
-	gfx_lines_end();
+	Graphics()->LinesEnd();
 }
 
 void FLOW::init()
diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp
index b1926ab4..837322fb 100644
--- a/src/game/client/components/hud.cpp
+++ b/src/game/client/components/hud.cpp
@@ -1,6 +1,7 @@
 #include <memory.h> // memcmp
 
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -35,11 +36,11 @@ void HUD::render_goals()
 	
 	int gameflags = gameclient.snap.gameobj->flags;
 	
-	float whole = 300*gfx_screenaspect();
+	float whole = 300*Graphics()->ScreenAspect();
 	float half = whole/2.0f;
 
 
-	gfx_mapscreen(0,0,300*gfx_screenaspect(),300);
+	Graphics()->MapScreen(0,0,300*Graphics()->ScreenAspect(),300);
 	if(!gameclient.snap.gameobj->sudden_death)
 	{
 		char buf[32];
@@ -71,15 +72,15 @@ void HUD::render_goals()
 	{
 		for(int t = 0; t < 2; t++)
 		{
-			gfx_blend_normal();
-			gfx_texture_set(-1);
-			gfx_quads_begin();
+			Graphics()->BlendNormal();
+			Graphics()->TextureSet(-1);
+			Graphics()->QuadsBegin();
 			if(t == 0)
-				gfx_setcolor(1,0,0,0.25f);
+				Graphics()->SetColor(1,0,0,0.25f);
 			else
-				gfx_setcolor(0,0,1,0.25f);
-			draw_round_rect(whole-40, 300-40-15+t*20, 50, 18, 5.0f);
-			gfx_quads_end();
+				Graphics()->SetColor(0,0,1,0.25f);
+			RenderTools()->draw_round_rect(whole-40, 300-40-15+t*20, 50, 18, 5.0f);
+			Graphics()->QuadsEnd();
 
 			char buf[32];
 			str_format(buf, sizeof(buf), "%d", t?gameclient.snap.gameobj->teamscore_blue:gameclient.snap.gameobj->teamscore_red);
@@ -92,16 +93,16 @@ void HUD::render_goals()
 				{
 					if(gameclient.snap.flags[t]->carried_by == -2 || (gameclient.snap.flags[t]->carried_by == -1 && ((client_tick()/10)&1)))
 					{
-						gfx_blend_normal();
-						gfx_texture_set(data->images[IMAGE_GAME].id);
-						gfx_quads_begin();
+						Graphics()->BlendNormal();
+						Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+						Graphics()->QuadsBegin();
 
-						if(t == 0) select_sprite(SPRITE_FLAG_RED);
-						else select_sprite(SPRITE_FLAG_BLUE);
+						if(t == 0) RenderTools()->select_sprite(SPRITE_FLAG_RED);
+						else RenderTools()->select_sprite(SPRITE_FLAG_BLUE);
 						
 						float size = 16;					
-						gfx_quads_drawTL(whole-40+5, 300-40-15+t*20+1, size/2, size);
-						gfx_quads_end();
+						Graphics()->QuadsDrawTL(whole-40+5, 300-40-15+t*20+1, size/2, size);
+						Graphics()->QuadsEnd();
 					}
 					else if(gameclient.snap.flags[t]->carried_by >= 0)
 					{
@@ -112,7 +113,7 @@ void HUD::render_goals()
 						TEE_RENDER_INFO info = gameclient.clients[id].render_info;
 						info.size = 18.0f;
 						
-						render_tee(ANIMSTATE::get_idle(), &info, EMOTE_NORMAL, vec2(1,0),
+						RenderTools()->RenderTee(ANIMSTATE::get_idle(), &info, EMOTE_NORMAL, vec2(1,0),
 							vec2(whole-40+10, 300-40-15+9+t*20+1));
 					}
 				}
@@ -127,7 +128,7 @@ void HUD::render_goals()
 	{
 		char buf[256];
 		float w = gfx_text_width(0, 24, "Warmup", -1);
-		gfx_text(0, 150*gfx_screenaspect()+-w/2, 50, 24, "Warmup", -1);
+		gfx_text(0, 150*Graphics()->ScreenAspect()+-w/2, 50, 24, "Warmup", -1);
 
 		int seconds = gameclient.snap.gameobj->warmup/SERVER_TICK_SPEED;
 		if(seconds < 5)
@@ -135,16 +136,16 @@ void HUD::render_goals()
 		else
 			str_format(buf, sizeof(buf), "%d", seconds);
 		w = gfx_text_width(0, 24, buf, -1);
-		gfx_text(0, 150*gfx_screenaspect()+-w/2, 75, 24, buf, -1);
+		gfx_text(0, 150*Graphics()->ScreenAspect()+-w/2, 75, 24, buf, -1);
 	}	
 }
 
-static void mapscreen_to_group(float center_x, float center_y, MAPITEM_GROUP *group)
+void HUD::mapscreen_to_group(float center_x, float center_y, MAPITEM_GROUP *group)
 {
 	float points[4];
-	mapscreen_to_world(center_x, center_y, group->parallax_x/100.0f, group->parallax_y/100.0f,
-		group->offset_x, group->offset_y, gfx_screenaspect(), 1.0f, points);
-	gfx_mapscreen(points[0], points[1], points[2], points[3]);
+	RenderTools()->mapscreen_to_world(center_x, center_y, group->parallax_x/100.0f, group->parallax_y/100.0f,
+		group->offset_x, group->offset_y, Graphics()->ScreenAspect(), 1.0f, points);
+	Graphics()->MapScreen(points[0], points[1], points[2], points[3]);
 }
 
 void HUD::render_fps()
@@ -163,7 +164,7 @@ void HUD::render_connectionwarning()
 	{
 		const char *text = "Connection Problems...";
 		float w = gfx_text_width(0, 24, text, -1);
-		gfx_text(0, 150*gfx_screenaspect()-w/2, 50, 24, text, -1);
+		gfx_text(0, 150*Graphics()->ScreenAspect()-w/2, 50, 24, text, -1);
 	}
 }
 
@@ -192,11 +193,11 @@ void HUD::render_voting()
 	if(!gameclient.voting->is_voting())
 		return;
 	
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.40f);
-	draw_round_rect(-10, 60-2, 100+10+4+5, 28, 5.0f);
-	gfx_quads_end();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.40f);
+	RenderTools()->draw_round_rect(-10, 60-2, 100+10+4+5, 28, 5.0f);
+	Graphics()->QuadsEnd();
 
 	gfx_text_color(1,1,1,1);
 
@@ -208,17 +209,17 @@ void HUD::render_voting()
 	gfx_text(0x0, 5+100-tw, 60, 6, buf, -1);
 	
 
-	RECT base = {5, 70, 100, 4};
+	CUIRect base = {5, 70, 100, 4};
 	gameclient.voting->render_bars(base, false);
 	
 	const char *yes_key = gameclient.binds->get_key("vote yes");
 	const char *no_key = gameclient.binds->get_key("vote no");
 	str_format(buf, sizeof(buf), "%s - Vote Yes", yes_key);
 	base.y += base.h+1;
-	ui_do_label(&base, buf, 6.0f, -1);
+	UI()->DoLabel(&base, buf, 6.0f, -1);
 
 	str_format(buf, sizeof(buf), "Vote No - %s", no_key);
-	ui_do_label(&base, buf, 6.0f, 1);
+	UI()->DoLabel(&base, buf, 6.0f, 1);
 }
 
 void HUD::render_cursor()
@@ -227,14 +228,14 @@ void HUD::render_cursor()
 		return;
 		
 	mapscreen_to_group(gameclient.camera->center.x, gameclient.camera->center.y, layers_game_group());
-	gfx_texture_set(data->images[IMAGE_GAME].id);
-	gfx_quads_begin();
+	Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+	Graphics()->QuadsBegin();
 
 	// render cursor
-	select_sprite(data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].sprite_cursor);
+	RenderTools()->select_sprite(data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].sprite_cursor);
 	float cursorsize = 64;
-	draw_sprite(gameclient.controls->target_pos.x, gameclient.controls->target_pos.y, cursorsize);
-	gfx_quads_end();
+	RenderTools()->draw_sprite(gameclient.controls->target_pos.x, gameclient.controls->target_pos.y, cursorsize);
+	Graphics()->QuadsEnd();
 }
 
 void HUD::render_healthandammo()
@@ -247,40 +248,40 @@ void HUD::render_healthandammo()
 	// render ammo count
 	// render gui stuff
 
-	gfx_texture_set(data->images[IMAGE_GAME].id);
-	gfx_mapscreen(0,0,width,300);
+	Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+	Graphics()->MapScreen(0,0,width,300);
 	
-	gfx_quads_begin();
+	Graphics()->QuadsBegin();
 	
 	// if weaponstage is active, put a "glow" around the stage ammo
-	select_sprite(data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].sprite_proj);
+	RenderTools()->select_sprite(data->weapons.id[gameclient.snap.local_character->weapon%NUM_WEAPONS].sprite_proj);
 	for (int i = 0; i < min(gameclient.snap.local_character->ammocount, 10); i++)
-		gfx_quads_drawTL(x+i*12,y+24,10,10);
+		Graphics()->QuadsDrawTL(x+i*12,y+24,10,10);
 
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 
-	gfx_quads_begin();
+	Graphics()->QuadsBegin();
 	int h = 0;
 
 	// render health
-	select_sprite(SPRITE_HEALTH_FULL);
+	RenderTools()->select_sprite(SPRITE_HEALTH_FULL);
 	for(; h < gameclient.snap.local_character->health; h++)
-		gfx_quads_drawTL(x+h*12,y,10,10);
+		Graphics()->QuadsDrawTL(x+h*12,y,10,10);
 
-	select_sprite(SPRITE_HEALTH_EMPTY);
+	RenderTools()->select_sprite(SPRITE_HEALTH_EMPTY);
 	for(; h < 10; h++)
-		gfx_quads_drawTL(x+h*12,y,10,10);
+		Graphics()->QuadsDrawTL(x+h*12,y,10,10);
 
 	// render armor meter
 	h = 0;
-	select_sprite(SPRITE_ARMOR_FULL);
+	RenderTools()->select_sprite(SPRITE_ARMOR_FULL);
 	for(; h < gameclient.snap.local_character->armor; h++)
-		gfx_quads_drawTL(x+h*12,y+12,10,10);
+		Graphics()->QuadsDrawTL(x+h*12,y+12,10,10);
 
-	select_sprite(SPRITE_ARMOR_EMPTY);
+	RenderTools()->select_sprite(SPRITE_ARMOR_EMPTY);
 	for(; h < 10; h++)
-		gfx_quads_drawTL(x+h*12,y+12,10,10);
-	gfx_quads_end();
+		Graphics()->QuadsDrawTL(x+h*12,y+12,10,10);
+	Graphics()->QuadsEnd();
 }
 
 void HUD::on_render()
@@ -288,7 +289,7 @@ void HUD::on_render()
 	if(!gameclient.snap.gameobj)
 		return;
 		
-	width = 300*gfx_screenaspect();
+	width = 300*Graphics()->ScreenAspect();
 
 	bool spectate = false;
 	if(gameclient.snap.local_info && gameclient.snap.local_info->team == -1)
diff --git a/src/game/client/components/hud.hpp b/src/game/client/components/hud.hpp
index 41fa0ff2..92ff0122 100644
--- a/src/game/client/components/hud.hpp
+++ b/src/game/client/components/hud.hpp
@@ -13,6 +13,8 @@ class HUD : public COMPONENT
 	void render_healthandammo();
 	void render_goals();
 	
+	
+	void mapscreen_to_group(float center_x, float center_y, struct MAPITEM_GROUP *group);
 public:
 	HUD();
 	
diff --git a/src/game/client/components/items.cpp b/src/game/client/components/items.cpp
index 1d579619..3c9e1b79 100644
--- a/src/game/client/components/items.cpp
+++ b/src/game/client/components/items.cpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -44,10 +45,10 @@ void ITEMS::render_projectile(const NETOBJ_PROJECTILE *current, int itemid)
 	vec2 prevpos = calc_pos(startpos, startvel, curvature, speed, ct-0.001f);
 
 
-	gfx_texture_set(data->images[IMAGE_GAME].id);
-	gfx_quads_begin();
+	Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+	Graphics()->QuadsBegin();
 	
-	select_sprite(data->weapons.id[clamp(current->type, 0, NUM_WEAPONS-1)].sprite_proj);
+	RenderTools()->select_sprite(data->weapons.id[clamp(current->type, 0, NUM_WEAPONS-1)].sprite_proj);
 	vec2 vel = pos-prevpos;
 	//vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
 	
@@ -57,7 +58,7 @@ void ITEMS::render_projectile(const NETOBJ_PROJECTILE *current, int itemid)
 	{
 		gameclient.effects->smoketrail(pos, vel*-1);
 		gameclient.flow->add(pos, vel*1000*client_frametime(), 10.0f);
-		gfx_quads_setrotation(client_localtime()*pi*2*2 + itemid);
+		Graphics()->QuadsSetRotation(client_localtime()*pi*2*2 + itemid);
 	}
 	else
 	{
@@ -65,28 +66,28 @@ void ITEMS::render_projectile(const NETOBJ_PROJECTILE *current, int itemid)
 		gameclient.flow->add(pos, vel*1000*client_frametime(), 10.0f);
 
 		if(length(vel) > 0.00001f)
-			gfx_quads_setrotation(get_angle(vel));
+			Graphics()->QuadsSetRotation(get_angle(vel));
 		else
-			gfx_quads_setrotation(0);
+			Graphics()->QuadsSetRotation(0);
 
 	}
 
-	gfx_quads_draw(pos.x, pos.y, 32, 32);
-	gfx_quads_setrotation(0);
-	gfx_quads_end();
+	Graphics()->QuadsDraw(pos.x, pos.y, 32, 32);
+	Graphics()->QuadsSetRotation(0);
+	Graphics()->QuadsEnd();
 }
 
 void ITEMS::render_pickup(const NETOBJ_PICKUP *prev, const NETOBJ_PICKUP *current)
 {
-	gfx_texture_set(data->images[IMAGE_GAME].id);
-	gfx_quads_begin();
+	Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+	Graphics()->QuadsBegin();
 	vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
 	float angle = 0.0f;
 	float size = 64.0f;
 	if (current->type == POWERUP_WEAPON)
 	{
 		angle = 0; //-pi/6;//-0.25f * pi * 2.0f;
-		select_sprite(data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].sprite_body);
+		RenderTools()->select_sprite(data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].sprite_body);
 		size = data->weapons.id[clamp(current->subtype, 0, NUM_WEAPONS-1)].visual_size;
 	}
 	else
@@ -97,7 +98,7 @@ void ITEMS::render_pickup(const NETOBJ_PICKUP *prev, const NETOBJ_PICKUP *curren
 			SPRITE_PICKUP_WEAPON,
 			SPRITE_PICKUP_NINJA
 			};
-		select_sprite(c[current->type]);
+		RenderTools()->select_sprite(c[current->type]);
 
 		if(c[current->type] == SPRITE_PICKUP_NINJA)
 		{
@@ -107,13 +108,13 @@ void ITEMS::render_pickup(const NETOBJ_PICKUP *prev, const NETOBJ_PICKUP *curren
 		}
 	}
 
-	gfx_quads_setrotation(angle);
+	Graphics()->QuadsSetRotation(angle);
 
 	float offset = pos.y/32.0f + pos.x/32.0f;
 	pos.x += cosf(client_localtime()*2.0f+offset)*2.5f;
 	pos.y += sinf(client_localtime()*2.0f+offset)*2.5f;
-	draw_sprite(pos.x, pos.y, size);
-	gfx_quads_end();
+	RenderTools()->draw_sprite(pos.x, pos.y, size);
+	Graphics()->QuadsEnd();
 }
 
 void ITEMS::render_flag(const NETOBJ_FLAG *prev, const NETOBJ_FLAG *current)
@@ -121,16 +122,16 @@ void ITEMS::render_flag(const NETOBJ_FLAG *prev, const NETOBJ_FLAG *current)
 	float angle = 0.0f;
 	float size = 42.0f;
 
-	gfx_blend_normal();
-	gfx_texture_set(data->images[IMAGE_GAME].id);
-	gfx_quads_begin();
+	Graphics()->BlendNormal();
+	Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+	Graphics()->QuadsBegin();
 
 	if(current->team == 0) // red team
-		select_sprite(SPRITE_FLAG_RED);
+		RenderTools()->select_sprite(SPRITE_FLAG_RED);
 	else
-		select_sprite(SPRITE_FLAG_BLUE);
+		RenderTools()->select_sprite(SPRITE_FLAG_BLUE);
 
-	gfx_quads_setrotation(angle);
+	Graphics()->QuadsSetRotation(angle);
 
 	vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
 	
@@ -142,8 +143,8 @@ void ITEMS::render_flag(const NETOBJ_FLAG *prev, const NETOBJ_FLAG *current)
 	if(gameclient.snap.local_info && current->carried_by == gameclient.snap.local_info->cid)
 		pos = gameclient.local_character_pos;
 
-	gfx_quads_draw(pos.x, pos.y-size*0.75f, size, size*2);
-	gfx_quads_end();
+	Graphics()->QuadsDraw(pos.x, pos.y-size*0.75f, size, size*2);
+	Graphics()->QuadsEnd();
 }
 
 
@@ -161,19 +162,19 @@ void ITEMS::render_laser(const struct NETOBJ_LASER *current)
 	
 	vec2 out, border;
 	
-	gfx_blend_normal();
-	gfx_texture_set(-1);
-	gfx_quads_begin();
+	Graphics()->BlendNormal();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
 	
 	//vec4 inner_color(0.15f,0.35f,0.75f,1.0f);
 	//vec4 outer_color(0.65f,0.85f,1.0f,1.0f);
 
 	// do outline
 	vec4 outer_color(0.075f,0.075f,0.25f,1.0f);
-	gfx_setcolor(outer_color.r,outer_color.g,outer_color.b,1.0f);
+	Graphics()->SetColor(outer_color.r,outer_color.g,outer_color.b,1.0f);
 	out = vec2(dir.y, -dir.x) * (7.0f*ia);
 
-	gfx_quads_draw_freeform(
+	Graphics()->QuadsDrawFreeform(
 			from.x-out.x, from.y-out.y,
 			from.x+out.x, from.y+out.y,
 			pos.x-out.x, pos.y-out.y,
@@ -183,34 +184,34 @@ void ITEMS::render_laser(const struct NETOBJ_LASER *current)
 	// do inner	
 	vec4 inner_color(0.5f,0.5f,1.0f,1.0f);
 	out = vec2(dir.y, -dir.x) * (5.0f*ia);
-	gfx_setcolor(inner_color.r, inner_color.g, inner_color.b, 1.0f); // center
+	Graphics()->SetColor(inner_color.r, inner_color.g, inner_color.b, 1.0f); // center
 	
-	gfx_quads_draw_freeform(
+	Graphics()->QuadsDrawFreeform(
 			from.x-out.x, from.y-out.y,
 			from.x+out.x, from.y+out.y,
 			pos.x-out.x, pos.y-out.y,
 			pos.x+out.x, pos.y+out.y
 		);
 		
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 	
 	// render head
 	{
-		gfx_blend_normal();
-		gfx_texture_set(data->images[IMAGE_PARTICLES].id);
-		gfx_quads_begin();
+		Graphics()->BlendNormal();
+		Graphics()->TextureSet(data->images[IMAGE_PARTICLES].id);
+		Graphics()->QuadsBegin();
 
 		int sprites[] = {SPRITE_PART_SPLAT01, SPRITE_PART_SPLAT02, SPRITE_PART_SPLAT03};
-		select_sprite(sprites[client_tick()%3]);
-		gfx_quads_setrotation(client_tick());
-		gfx_setcolor(outer_color.r,outer_color.g,outer_color.b,1.0f);
-		gfx_quads_draw(pos.x, pos.y, 24,24);
-		gfx_setcolor(inner_color.r, inner_color.g, inner_color.b, 1.0f);
-		gfx_quads_draw(pos.x, pos.y, 20,20);
-		gfx_quads_end();
+		RenderTools()->select_sprite(sprites[client_tick()%3]);
+		Graphics()->QuadsSetRotation(client_tick());
+		Graphics()->SetColor(outer_color.r,outer_color.g,outer_color.b,1.0f);
+		Graphics()->QuadsDraw(pos.x, pos.y, 24,24);
+		Graphics()->SetColor(inner_color.r, inner_color.g, inner_color.b, 1.0f);
+		Graphics()->QuadsDraw(pos.x, pos.y, 20,20);
+		Graphics()->QuadsEnd();
 	}
 	
-	gfx_blend_normal();	
+	Graphics()->BlendNormal();	
 }
 
 void ITEMS::on_render()
diff --git a/src/game/client/components/killmessages.cpp b/src/game/client/components/killmessages.cpp
index 410f2c3d..e6232b7d 100644
--- a/src/game/client/components/killmessages.cpp
+++ b/src/game/client/components/killmessages.cpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -35,10 +36,10 @@ void KILLMESSAGES::on_message(int msgtype, void *rawmsg)
 
 void KILLMESSAGES::on_render()
 {
-	float width = 400*3.0f*gfx_screenaspect();
+	float width = 400*3.0f*Graphics()->ScreenAspect();
 	float height = 400*3.0f;
 
-	gfx_mapscreen(0, 0, width*1.5f, height*1.5f);
+	Graphics()->MapScreen(0, 0, width*1.5f, height*1.5f);
 	float startx = width*1.5f-10.0f;
 	float y = 20.0f;
 
@@ -66,31 +67,31 @@ void KILLMESSAGES::on_render()
 		{
 			if(killmsgs[r].mode_special&1)
 			{
-				gfx_blend_normal();
-				gfx_texture_set(data->images[IMAGE_GAME].id);
-				gfx_quads_begin();
+				Graphics()->BlendNormal();
+				Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+				Graphics()->QuadsBegin();
 
-				if(gameclient.clients[killmsgs[r].victim].team == 0) select_sprite(SPRITE_FLAG_BLUE);
-				else select_sprite(SPRITE_FLAG_RED);
+				if(gameclient.clients[killmsgs[r].victim].team == 0) RenderTools()->select_sprite(SPRITE_FLAG_BLUE);
+				else RenderTools()->select_sprite(SPRITE_FLAG_RED);
 				
 				float size = 56.0f;
-				gfx_quads_drawTL(x, y-16, size/2, size);
-				gfx_quads_end();					
+				Graphics()->QuadsDrawTL(x, y-16, size/2, size);
+				Graphics()->QuadsEnd();					
 			}
 		}
 		
-		render_tee(ANIMSTATE::get_idle(), &gameclient.clients[killmsgs[r].victim].render_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28));
+		RenderTools()->RenderTee(ANIMSTATE::get_idle(), &gameclient.clients[killmsgs[r].victim].render_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28));
 		x -= 32.0f;
 		
 		// render weapon
 		x -= 44.0f;
 		if (killmsgs[r].weapon >= 0)
 		{
-			gfx_texture_set(data->images[IMAGE_GAME].id);
-			gfx_quads_begin();
-			select_sprite(data->weapons.id[killmsgs[r].weapon].sprite_body);
-			draw_sprite(x, y+28, 96);
-			gfx_quads_end();
+			Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+			Graphics()->QuadsBegin();
+			RenderTools()->select_sprite(data->weapons.id[killmsgs[r].weapon].sprite_body);
+			RenderTools()->draw_sprite(x, y+28, 96);
+			Graphics()->QuadsEnd();
 		}
 		x -= 52.0f;
 
@@ -100,22 +101,22 @@ void KILLMESSAGES::on_render()
 			{
 				if(killmsgs[r].mode_special&2)
 				{
-					gfx_blend_normal();
-					gfx_texture_set(data->images[IMAGE_GAME].id);
-					gfx_quads_begin();
+					Graphics()->BlendNormal();
+					Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+					Graphics()->QuadsBegin();
 
-					if(gameclient.clients[killmsgs[r].killer].team == 0) select_sprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X);
-					else select_sprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
+					if(gameclient.clients[killmsgs[r].killer].team == 0) RenderTools()->select_sprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X);
+					else RenderTools()->select_sprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
 					
 					float size = 56.0f;
-					gfx_quads_drawTL(x-56, y-16, size/2, size);
-					gfx_quads_end();				
+					Graphics()->QuadsDrawTL(x-56, y-16, size/2, size);
+					Graphics()->QuadsEnd();				
 				}
 			}				
 			
 			// render killer tee
 			x -= 24.0f;
-			render_tee(ANIMSTATE::get_idle(), &gameclient.clients[killmsgs[r].killer].render_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28));
+			RenderTools()->RenderTee(ANIMSTATE::get_idle(), &gameclient.clients[killmsgs[r].killer].render_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28));
 			x -= 32.0f;
 
 			// render killer name
diff --git a/src/game/client/components/mapimages.cpp b/src/game/client/components/mapimages.cpp
index 7f839da0..51194853 100644
--- a/src/game/client/components/mapimages.cpp
+++ b/src/game/client/components/mapimages.cpp
@@ -1,3 +1,4 @@
+#include <engine/client/graphics.h>
 #include <game/client/component.hpp>
 #include <game/mapitems.hpp>
 
@@ -13,7 +14,7 @@ void MAPIMAGES::on_mapload()
 	// unload all textures
 	for(int i = 0; i < count; i++)
 	{
-		gfx_unload_texture(textures[i]);
+		Graphics()->UnloadTexture(textures[i]);
 		textures[i] = -1;
 	}
 	count = 0;
@@ -32,12 +33,12 @@ void MAPIMAGES::on_mapload()
 			char buf[256];
 			char *name = (char *)map_get_data(img->image_name);
 			str_format(buf, sizeof(buf), "mapres/%s.png", name);
-			textures[i] = gfx_load_texture(buf, IMG_AUTO, 0);
+			textures[i] = Graphics()->LoadTexture(buf, IMG_AUTO, 0);
 		}
 		else
 		{
 			void *data = map_get_data(img->image_data);
-			textures[i] = gfx_load_texture_raw(img->width, img->height, IMG_RGBA, data, IMG_RGBA, 0);
+			textures[i] = Graphics()->LoadTextureRaw(img->width, img->height, IMG_RGBA, data, IMG_RGBA, 0);
 			map_unload_data(img->image_data);
 		}
 	}
diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp
index 847350e6..75f91521 100644
--- a/src/game/client/components/maplayers.cpp
+++ b/src/game/client/components/maplayers.cpp
@@ -1,3 +1,5 @@
+#include <engine/client/graphics.h>
+
 #include <game/layers.hpp>
 #include <game/client/gameclient.hpp>
 #include <game/client/component.hpp>
@@ -6,6 +8,7 @@
 #include <game/client/components/camera.hpp>
 #include <game/client/components/mapimages.hpp>
 
+
 #include "maplayers.hpp"
 
 MAPLAYERS::MAPLAYERS(int t)
@@ -14,16 +17,17 @@ MAPLAYERS::MAPLAYERS(int t)
 }
 
 
-static void mapscreen_to_group(float center_x, float center_y, MAPITEM_GROUP *group)
+void MAPLAYERS::mapscreen_to_group(float center_x, float center_y, MAPITEM_GROUP *group)
 {
 	float points[4];
-	mapscreen_to_world(center_x, center_y, group->parallax_x/100.0f, group->parallax_y/100.0f,
-		group->offset_x, group->offset_y, gfx_screenaspect(), 1.0f, points);
-	gfx_mapscreen(points[0], points[1], points[2], points[3]);
+	RenderTools()->mapscreen_to_world(center_x, center_y, group->parallax_x/100.0f, group->parallax_y/100.0f,
+		group->offset_x, group->offset_y, Graphics()->ScreenAspect(), 1.0f, points);
+	Graphics()->MapScreen(points[0], points[1], points[2], points[3]);
 }
 
-static void envelope_eval(float time_offset, int env, float *channels)
+void MAPLAYERS::envelope_eval(float time_offset, int env, float *channels, void *user)
 {
+	MAPLAYERS *pThis = (MAPLAYERS *)user;
 	channels[0] = 0;
 	channels[1] = 0;
 	channels[2] = 0;
@@ -45,7 +49,7 @@ static void envelope_eval(float time_offset, int env, float *channels)
 		return;
 	
 	MAPITEM_ENVELOPE *item = (MAPITEM_ENVELOPE *)map_get_item(start+env, 0, 0);
-	render_eval_envelope(points+item->start_point, item->num_points, 4, client_localtime()+time_offset, channels);
+	pThis->RenderTools()->render_eval_envelope(points+item->start_point, item->num_points, 4, client_localtime()+time_offset, channels);
 }
 
 void MAPLAYERS::on_render()
@@ -53,8 +57,8 @@ void MAPLAYERS::on_render()
 	if(client_state() != CLIENTSTATE_ONLINE && client_state() != CLIENTSTATE_DEMOPLAYBACK)
 		return;
 	
-	RECT screen;
-	gfx_getscreen(&screen.x, &screen.y, &screen.w, &screen.h);
+	CUIRect screen;
+	Graphics()->GetScreen(&screen.x, &screen.y, &screen.w, &screen.h);
 	
 	vec2 center = gameclient.camera->center;
 	//float center_x = gameclient.camera->center.x;
@@ -71,14 +75,14 @@ void MAPLAYERS::on_render()
 			// set clipping
 			float points[4];
 			mapscreen_to_group(center.x, center.y, layers_game_group());
-			gfx_getscreen(&points[0], &points[1], &points[2], &points[3]);
+			Graphics()->GetScreen(&points[0], &points[1], &points[2], &points[3]);
 			float x0 = (group->clip_x - points[0]) / (points[2]-points[0]);
 			float y0 = (group->clip_y - points[1]) / (points[3]-points[1]);
 			float x1 = ((group->clip_x+group->clip_w) - points[0]) / (points[2]-points[0]);
 			float y1 = ((group->clip_y+group->clip_h) - points[1]) / (points[3]-points[1]);
 			
-			gfx_clip_enable((int)(x0*gfx_screenwidth()), (int)(y0*gfx_screenheight()),
-				(int)((x1-x0)*gfx_screenwidth()), (int)((y1-y0)*gfx_screenheight()));
+			Graphics()->ClipEnable((int)(x0*Graphics()->ScreenWidth()), (int)(y0*Graphics()->ScreenHeight()),
+				(int)((x1-x0)*Graphics()->ScreenWidth()), (int)((y1-y0)*Graphics()->ScreenHeight()));
 		}		
 		
 		mapscreen_to_group(center.x, center.y, group);
@@ -121,43 +125,43 @@ void MAPLAYERS::on_render()
 				{
 					MAPITEM_LAYER_TILEMAP *tmap = (MAPITEM_LAYER_TILEMAP *)layer;
 					if(tmap->image == -1)
-						gfx_texture_set(-1);
+						Graphics()->TextureSet(-1);
 					else
-						gfx_texture_set(gameclient.mapimages->get(tmap->image));
+						Graphics()->TextureSet(gameclient.mapimages->get(tmap->image));
 						
 					TILE *tiles = (TILE *)map_get_data(tmap->data);
-					gfx_blend_none();
-					render_tilemap(tiles, tmap->width, tmap->height, 32.0f, vec4(1,1,1,1), TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE);
-					gfx_blend_normal();
-					render_tilemap(tiles, tmap->width, tmap->height, 32.0f, vec4(1,1,1,1), TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT);
+					Graphics()->BlendNone();
+					RenderTools()->render_tilemap(tiles, tmap->width, tmap->height, 32.0f, vec4(1,1,1,1), TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE);
+					Graphics()->BlendNormal();
+					RenderTools()->render_tilemap(tiles, tmap->width, tmap->height, 32.0f, vec4(1,1,1,1), TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT);
 				}
 				else if(layer->type == LAYERTYPE_QUADS)
 				{
 					MAPITEM_LAYER_QUADS *qlayer = (MAPITEM_LAYER_QUADS *)layer;
 					if(qlayer->image == -1)
-						gfx_texture_set(-1);
+						Graphics()->TextureSet(-1);
 					else
-						gfx_texture_set(gameclient.mapimages->get(qlayer->image));
+						Graphics()->TextureSet(gameclient.mapimages->get(qlayer->image));
 
 					QUAD *quads = (QUAD *)map_get_data_swapped(qlayer->data);
 					
-					gfx_blend_none();
-					render_quads(quads, qlayer->num_quads, envelope_eval, LAYERRENDERFLAG_OPAQUE);
-					gfx_blend_normal();
-					render_quads(quads, qlayer->num_quads, envelope_eval, LAYERRENDERFLAG_TRANSPARENT);
+					Graphics()->BlendNone();
+					RenderTools()->render_quads(quads, qlayer->num_quads, LAYERRENDERFLAG_OPAQUE, envelope_eval, this);
+					Graphics()->BlendNormal();
+					RenderTools()->render_quads(quads, qlayer->num_quads, LAYERRENDERFLAG_TRANSPARENT, envelope_eval, this);
 				}
 				
 				//layershot_end();	
 			}
 		}
 		if(!config.gfx_noclip)
-			gfx_clip_disable();
+			Graphics()->ClipDisable();
 	}
 	
 	if(!config.gfx_noclip)
-		gfx_clip_disable();
+		Graphics()->ClipDisable();
 	
 	// reset the screen like it was before
-	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+	Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 }
 
diff --git a/src/game/client/components/maplayers.hpp b/src/game/client/components/maplayers.hpp
index c2919f08..c8b154b2 100644
--- a/src/game/client/components/maplayers.hpp
+++ b/src/game/client/components/maplayers.hpp
@@ -3,6 +3,9 @@
 class MAPLAYERS : public COMPONENT
 {	
 	int type;
+
+	void mapscreen_to_group(float center_x, float center_y, MAPITEM_GROUP *group);
+	static void envelope_eval(float time_offset, int env, float *channels, void *user);
 public:
 	enum
 	{
diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp
index 168c514d..5f1bbf42 100644
--- a/src/game/client/components/menus.cpp
+++ b/src/game/client/components/menus.cpp
@@ -12,6 +12,7 @@
 #include "skins.hpp"
 
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 
 #include <game/version.hpp>
 #include <game/generated/g_protocol.hpp>
@@ -94,356 +95,366 @@ MENUS::MENUS()
 	last_input = time_get();
 }
 
-vec4 MENUS::button_color_mul(const void *id)
+vec4 MENUS::button_color_mul(const void *pID)
 {
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == pID)
 		return vec4(1,1,1,0.5f);
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == pID)
 		return vec4(1,1,1,1.5f);
 	return vec4(1,1,1,1);
 }
 
-void MENUS::ui_draw_browse_icon(int what, const RECT *r)
+int MENUS::DoButton_BrowseIcon(int What, const CUIRect *pRect)
 {
-	gfx_texture_set(data->images[IMAGE_BROWSEICONS].id);
-	gfx_quads_begin();
-	select_sprite(what);
-	gfx_quads_drawTL(r->x,r->y,r->w,r->h);
-	gfx_quads_end();
+	Graphics()->TextureSet(data->images[IMAGE_BROWSEICONS].id);
+	
+	Graphics()->QuadsBegin();
+	RenderTools()->select_sprite(What);
+	Graphics()->QuadsDrawTL(pRect->x, pRect->y, pRect->w, pRect->h);
+	Graphics()->QuadsEnd();
+	
+	return 0;
 }
 
 
-void MENUS::ui_draw_menu_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
-	ui_draw_rect(r, vec4(1,1,1,0.5f)*button_color_mul(id), CORNER_ALL, 5.0f);
-	ui_do_label(r, text, r->h*fontmod_height, 0);
+	RenderTools()->DrawUIRect(pRect, vec4(1,1,1,0.5f)*button_color_mul(pID), CUI::CORNER_ALL, 5.0f);
+	UI()->DoLabel(pRect, pText, pRect->h*fontmod_height, 0);
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
-void MENUS::ui_draw_keyselect_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_KeySelect(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
-	ui_draw_rect(r, vec4(1,1,1,0.5f)*button_color_mul(id), CORNER_ALL, 5.0f);
-	ui_do_label(r, text, r->h*fontmod_height, 0);
+	RenderTools()->DrawUIRect(pRect, vec4(1,1,1,0.5f)*button_color_mul(pID), CUI::CORNER_ALL, 5.0f);
+	UI()->DoLabel(pRect, pText, pRect->h*fontmod_height, 0);
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
-void MENUS::ui_draw_menu_tab_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_MenuTab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Corners)
 {
-	int corners = CORNER_T;
-	vec4 colormod(1,1,1,1);
-	if(extra)
-		corners = *(int *)extra;
+	vec4 ColorMod(1,1,1,1);
 	
-	if(checked)
-		ui_draw_rect(r, color_tabbar_active, corners, 10.0f);
+	if(Checked)
+		RenderTools()->DrawUIRect(pRect, color_tabbar_active, Corners, 10.0f);
 	else
-		ui_draw_rect(r, color_tabbar_inactive, corners, 10.0f);
-	ui_do_label(r, text, r->h*fontmod_height, 0);
+		RenderTools()->DrawUIRect(pRect, color_tabbar_inactive, Corners, 10.0f);
+	UI()->DoLabel(pRect, pText, pRect->h*fontmod_height, 0);
+	
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
 
-void MENUS::ui_draw_settings_tab_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_SettingsTab(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
-	if(checked)
-		ui_draw_rect(r, color_tabbar_active, CORNER_R, 10.0f);
+	if(Checked)
+		RenderTools()->DrawUIRect(pRect, color_tabbar_active, CUI::CORNER_R, 10.0f);
 	else
-		ui_draw_rect(r, color_tabbar_inactive, CORNER_R, 10.0f);
-	ui_do_label(r, text, r->h*fontmod_height, 0);
+		RenderTools()->DrawUIRect(pRect, color_tabbar_inactive, CUI::CORNER_R, 10.0f);
+	UI()->DoLabel(pRect, pText, pRect->h*fontmod_height, 0);
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
-void MENUS::ui_draw_grid_header(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_GridHeader(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
+//void MENUS::ui_draw_grid_header(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
 {
-	if(checked)
-		ui_draw_rect(r, vec4(1,1,1,0.5f), CORNER_T, 5.0f);
-	RECT t;
-	ui_vsplit_l(r, 5.0f, 0, &t);
-	ui_do_label(&t, text, r->h*fontmod_height, -1);
+	if(Checked)
+		RenderTools()->DrawUIRect(pRect, vec4(1,1,1,0.5f), CUI::CORNER_T, 5.0f);
+	CUIRect t;
+	pRect->VSplitLeft(5.0f, 0, &t);
+	UI()->DoLabel(&t, pText, pRect->h*fontmod_height, -1);
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
-void MENUS::ui_draw_list_row(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_ListRow(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
-	if(checked)
+	if(Checked)
 	{
-		RECT sr = *r;
-		ui_margin(&sr, 1.5f, &sr);
-		ui_draw_rect(&sr, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f);
+		CUIRect sr = *pRect;
+		sr.Margin(1.5f, &sr);
+		RenderTools()->DrawUIRect(&sr, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f);
 	}
-	ui_do_label(r, text, r->h*fontmod_height, -1);
+	UI()->DoLabel(pRect, pText, pRect->h*fontmod_height, -1);
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
-void MENUS::ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r)
+int MENUS::DoButton_CheckBox_Common(const void *pID, const char *pText, const char *pBoxText, const CUIRect *pRect)
+//void MENUS::ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const CUIRect *r, const void *extra)
 {
-	RECT c = *r;
-	RECT t = *r;
+	CUIRect c = *pRect;
+	CUIRect t = *pRect;
 	c.w = c.h;
 	t.x += c.w;
 	t.w -= c.w;
-	ui_vsplit_l(&t, 5.0f, 0, &t);
+	t.VSplitLeft(5.0f, 0, &t);
 	
-	ui_margin(&c, 2.0f, &c);
-	ui_draw_rect(&c, vec4(1,1,1,0.25f)*button_color_mul(id), CORNER_ALL, 3.0f);
+	c.Margin(2.0f, &c);
+	RenderTools()->DrawUIRect(&c, vec4(1,1,1,0.25f)*button_color_mul(pID), CUI::CORNER_ALL, 3.0f);
 	c.y += 2;
-	ui_do_label(&c, boxtext, r->h*fontmod_height*0.6f, 0);
-	ui_do_label(&t, text, r->h*fontmod_height*0.8f, -1);
+	UI()->DoLabel(&c, pBoxText, pRect->h*fontmod_height*0.6f, 0);
+	UI()->DoLabel(&t, pText, pRect->h*fontmod_height*0.8f, -1);
+	return UI()->DoButtonLogic(pID, pText, 0, pRect);
 }
 
-void MENUS::ui_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_CheckBox(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
-	ui_draw_checkbox_common(id, text, checked?"X":"", r);
+	return DoButton_CheckBox_Common(pID, pText, Checked?"X":"", pRect);
 }
 
 
-void MENUS::ui_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_CheckBox_Number(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
 	char buf[16];
-	str_format(buf, sizeof(buf), "%d", checked);
-	ui_draw_checkbox_common(id, text, buf, r);
+	str_format(buf, sizeof(buf), "%d", Checked);
+	return DoButton_CheckBox_Common(pID, pText, buf, pRect);
 }
 
-int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden)
+int MENUS::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden)
 {
-    int inside = ui_mouse_inside(rect);
-	int r = 0;
-	static int at_index = 0;
+    int Inside = UI()->MouseInside(pRect);
+	int ReturnValue = 0;
+	static int AtIndex = 0;
 
-	if(ui_last_active_item() == id)
+	if(UI()->LastActiveItem() == pID)
 	{
-		int len = strlen(str);
+		int Len = strlen(pStr);
 			
-		if (inside && ui_mouse_button(0))
+		if(Inside && UI()->MouseButton(0))
 		{
-			int mx_rel = (int)(ui_mouse_x() - rect->x);
+			int mx_rel = (int)(UI()->MouseX() - pRect->x);
 
-			for (int i = 1; i <= len; i++)
+			for (int i = 1; i <= Len; i++)
 			{
-				if (gfx_text_width(0, font_size, str, i) + 10 > mx_rel)
+				if (gfx_text_width(0, FontSize, pStr, i) + 10 > mx_rel)
 				{
-					at_index = i - 1;
+					AtIndex = i - 1;
 					break;
 				}
 
-				if (i == len)
-					at_index = len;
+				if (i == Len)
+					AtIndex = Len;
 			}
 		}
 
 		for(int i = 0; i < num_inputevents; i++)
 		{
-			len = strlen(str);
-			LINEINPUT::manipulate(inputevents[i], str, str_size, &len, &at_index);
+			Len = strlen(pStr);
+			LINEINPUT::manipulate(inputevents[i], pStr, StrSize, &Len, &AtIndex);
 		}
 	}
 
-	bool just_got_active = false;
+	bool JustGotActive = false;
 	
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == pID)
 	{
-		if(!ui_mouse_button(0))
-			ui_set_active_item(0);
+		if(!UI()->MouseButton(0))
+			UI()->SetActiveItem(0);
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == pID)
 	{
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			if (ui_last_active_item() != id)
-				just_got_active = true;
-			ui_set_active_item(id);
+			if (UI()->LastActiveItem() != pID)
+				JustGotActive = true;
+			UI()->SetActiveItem(pID);
 		}
 	}
 	
-	if(inside)
-		ui_set_hot_item(id);
+	if(Inside)
+		UI()->SetHotItem(pID);
 
-	RECT textbox = *rect;
-	ui_draw_rect(&textbox, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f);
-	ui_vmargin(&textbox, 5.0f, &textbox);
+	CUIRect Textbox = *pRect;
+	RenderTools()->DrawUIRect(&Textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f);
+	Textbox.VMargin(5.0f, &Textbox);
 	
-	const char *display_str = str;
-	char stars[128];
+	const char *pDisplayStr = pStr;
+	char aStars[128];
 	
-	if(hidden)
+	if(Hidden)
 	{
-		unsigned s = strlen(str);
-		if(s >= sizeof(stars))
-			s = sizeof(stars)-1;
-		memset(stars, '*', s);
-		stars[s] = 0;
-		display_str = stars;
+		unsigned s = strlen(pStr);
+		if(s >= sizeof(aStars))
+			s = sizeof(aStars)-1;
+		memset(aStars, '*', s);
+		aStars[s] = 0;
+		pDisplayStr = aStars;
 	}
 
-	ui_do_label(&textbox, display_str, font_size, -1);
+	UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1);
 	
-	if (ui_last_active_item() == id && !just_got_active)
+	if (UI()->LastActiveItem() == pID && !JustGotActive)
 	{
-		float w = gfx_text_width(0, font_size, display_str, at_index);
-		textbox.x += w*ui_scale();
-		ui_do_label(&textbox, "_", font_size, -1);
+		float w = gfx_text_width(0, FontSize, pDisplayStr, AtIndex);
+		Textbox.x += w*UI()->Scale();
+		UI()->DoLabel(&Textbox, "_", FontSize, -1);
 	}
 
-	return r;
+	return ReturnValue;
 }
 
-float MENUS::ui_do_scrollbar_v(const void *id, const RECT *rect, float current)
+float MENUS::DoScrollbarV(const void *pID, const CUIRect *pRect, float Current)
 {
-	RECT handle;
-	static float offset_y;
-	ui_hsplit_t(rect, 33, &handle, 0);
+	CUIRect Handle;
+	static float OffsetY;
+	pRect->HSplitTop(33, &Handle, 0);
 
-	handle.y += (rect->h-handle.h)*current;
+	Handle.y += (pRect->h-Handle.h)*Current;
 
 	/* logic */
-    float ret = current;
-    int inside = ui_mouse_inside(&handle);
+    float ReturnValue = Current;
+    int Inside = UI()->MouseInside(&Handle);
 
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == pID)
 	{
-		if(!ui_mouse_button(0))
-			ui_set_active_item(0);
+		if(!UI()->MouseButton(0))
+			UI()->SetActiveItem(0);
 		
-		float min = rect->y;
-		float max = rect->h-handle.h;
-		float cur = ui_mouse_y()-offset_y;
-		ret = (cur-min)/max;
-		if(ret < 0.0f) ret = 0.0f;
-		if(ret > 1.0f) ret = 1.0f;
+		float min = pRect->y;
+		float max = pRect->h-Handle.h;
+		float cur = UI()->MouseY()-OffsetY;
+		ReturnValue = (cur-min)/max;
+		if(ReturnValue < 0.0f) ReturnValue = 0.0f;
+		if(ReturnValue > 1.0f) ReturnValue = 1.0f;
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == pID)
 	{
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			ui_set_active_item(id);
-			offset_y = ui_mouse_y()-handle.y;
+			UI()->SetActiveItem(pID);
+			OffsetY = UI()->MouseY()-Handle.y;
 		}
 	}
 	
-	if(inside)
-		ui_set_hot_item(id);
+	if(Inside)
+		UI()->SetHotItem(pID);
 
 	// render
-	RECT rail;
-	ui_vmargin(rect, 5.0f, &rail);
-	ui_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f);
-
-	RECT slider = handle;
-	slider.w = rail.x-slider.x;
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_L, 2.5f);
-	slider.x = rail.x+rail.w;
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_R, 2.5f);
-
-	slider = handle;
-	ui_margin(&slider, 5.0f, &slider);
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f)*button_color_mul(id), CORNER_ALL, 2.5f);
+	CUIRect Rail;
+	pRect->VMargin(5.0f, &Rail);
+	RenderTools()->DrawUIRect(&Rail, vec4(1,1,1,0.25f), 0, 0.0f);
+
+	CUIRect Slider = Handle;
+	Slider.w = Rail.x-Slider.x;
+	RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_L, 2.5f);
+	Slider.x = Rail.x+Rail.w;
+	RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_R, 2.5f);
+
+	Slider = Handle;
+	Slider.Margin(5.0f, &Slider);
+	RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f)*button_color_mul(pID), CUI::CORNER_ALL, 2.5f);
 	
-    return ret;
+    return ReturnValue;
 }
 
 
 
-float MENUS::ui_do_scrollbar_h(const void *id, const RECT *rect, float current)
+float MENUS::DoScrollbarH(const void *pID, const CUIRect *pRect, float Current)
 {
-	RECT handle;
-	static float offset_x;
-	ui_vsplit_l(rect, 33, &handle, 0);
+	CUIRect Handle;
+	static float OffsetX;
+	pRect->VSplitLeft(33, &Handle, 0);
 
-	handle.x += (rect->w-handle.w)*current;
+	Handle.x += (pRect->w-Handle.w)*Current;
 
 	/* logic */
-    float ret = current;
-    int inside = ui_mouse_inside(&handle);
+    float ReturnValue = Current;
+    int Inside = UI()->MouseInside(&Handle);
 
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == pID)
 	{
-		if(!ui_mouse_button(0))
-			ui_set_active_item(0);
+		if(!UI()->MouseButton(0))
+			UI()->SetActiveItem(0);
 		
-		float min = rect->x;
-		float max = rect->w-handle.w;
-		float cur = ui_mouse_x()-offset_x;
-		ret = (cur-min)/max;
-		if(ret < 0.0f) ret = 0.0f;
-		if(ret > 1.0f) ret = 1.0f;
+		float min = pRect->x;
+		float max = pRect->w-Handle.w;
+		float cur = UI()->MouseX()-OffsetX;
+		ReturnValue = (cur-min)/max;
+		if(ReturnValue < 0.0f) ReturnValue = 0.0f;
+		if(ReturnValue > 1.0f) ReturnValue = 1.0f;
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == pID)
 	{
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			ui_set_active_item(id);
-			offset_x = ui_mouse_x()-handle.x;
+			UI()->SetActiveItem(pID);
+			OffsetX = UI()->MouseX()-Handle.x;
 		}
 	}
 	
-	if(inside)
-		ui_set_hot_item(id);
+	if(Inside)
+		UI()->SetHotItem(pID);
 
 	// render
-	RECT rail;
-	ui_hmargin(rect, 5.0f, &rail);
-	ui_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f);
-
-	RECT slider = handle;
-	slider.h = rail.y-slider.y;
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_T, 2.5f);
-	slider.y = rail.y+rail.h;
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_B, 2.5f);
-
-	slider = handle;
-	ui_margin(&slider, 5.0f, &slider);
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f)*button_color_mul(id), CORNER_ALL, 2.5f);
+	CUIRect Rail;
+	pRect->HMargin(5.0f, &Rail);
+	RenderTools()->DrawUIRect(&Rail, vec4(1,1,1,0.25f), 0, 0.0f);
+
+	CUIRect Slider = Handle;
+	Slider.h = Rail.y-Slider.y;
+	RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_T, 2.5f);
+	Slider.y = Rail.y+Rail.h;
+	RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f), CUI::CORNER_B, 2.5f);
+
+	Slider = Handle;
+	Slider.Margin(5.0f, &Slider);
+	RenderTools()->DrawUIRect(&Slider, vec4(1,1,1,0.25f)*button_color_mul(pID), CUI::CORNER_ALL, 2.5f);
 	
-    return ret;
+    return ReturnValue;
 }
 
-int MENUS::ui_do_key_reader(void *id, const RECT *rect, int key)
+int MENUS::DoKeyReader(void *pID, const CUIRect *pRect, int Key)
 {
 	// process
-	static void *grabbed_id = 0;
-	static bool mouse_released = true;
-	int inside = ui_mouse_inside(rect);
-	int new_key = key;
+	static void *pGrabbedID = 0;
+	static bool MouseReleased = true;
+	int Inside = UI()->MouseInside(pRect);
+	int NewKey = Key;
 	
-	if(!ui_mouse_button(0) && grabbed_id == id)
-		mouse_released = true;
+	if(!UI()->MouseButton(0) && pGrabbedID == pID)
+		MouseReleased = true;
 
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == pID)
 	{
 		if(binder.got_key)
 		{
-			new_key = binder.key.key;
+			NewKey = binder.key.key;
 			binder.got_key = false;
-			ui_set_active_item(0);
-			mouse_released = false;
-			grabbed_id = id;
+			UI()->SetActiveItem(0);
+			MouseReleased = false;
+			pGrabbedID = pID;
 		}
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == pID)
 	{
-		if(ui_mouse_button(0) && mouse_released)
+		if(UI()->MouseButton(0) && MouseReleased)
 		{
 			binder.take_key = true;
 			binder.got_key = false;
-			ui_set_active_item(id);
+			UI()->SetActiveItem(pID);
 		}
 	}
 	
-	if(inside)
-		ui_set_hot_item(id);
+	if(Inside)
+		UI()->SetHotItem(pID);
 
 	// draw
-	if (ui_active_item() == id)
-		ui_draw_keyselect_button(id, "???", 0, rect, 0);
+	if (UI()->ActiveItem() == pID)
+		DoButton_KeySelect(pID, "???", 0, pRect);
 	else
 	{
-		if(key == 0)
-			ui_draw_keyselect_button(id, "", 0, rect, 0);
+		if(Key == 0)
+			DoButton_KeySelect(pID, "", 0, pRect);
 		else
-			ui_draw_keyselect_button(id, inp_key_name(key), 0, rect, 0);
+			DoButton_KeySelect(pID, inp_key_name(Key), 0, pRect);
 	}
-	return new_key;
+	return NewKey;
 }
 
 
-int MENUS::render_menubar(RECT r)
+int MENUS::render_menubar(CUIRect r)
 {
-	RECT box = r;
-	RECT button;
+	CUIRect box = r;
+	CUIRect button;
 	
 	int active_page = config.ui_page;
 	int new_page = -1;
@@ -456,46 +467,43 @@ int MENUS::render_menubar(RECT r)
 		/* offline menus */
 		if(0) // this is not done yet
 		{
-			ui_vsplit_l(&box, 90.0f, &button, &box);
+			box.VSplitLeft(90.0f, &button, &box);
 			static int news_button=0;
-			if (ui_do_button(&news_button, localize("News"), active_page==PAGE_NEWS, &button, ui_draw_menu_tab_button, 0))
+			if (DoButton_MenuTab(&news_button, localize("News"), active_page==PAGE_NEWS, &button, 0))
 				new_page = PAGE_NEWS;
-			ui_vsplit_l(&box, 30.0f, 0, &box); 
+			box.VSplitLeft(30.0f, 0, &box); 
 		}
 
-		ui_vsplit_l(&box, 100.0f, &button, &box);
+		box.VSplitLeft(100.0f, &button, &box);
 		static int internet_button=0;
-		int corners = CORNER_TL;
-		if (ui_do_button(&internet_button, localize("Internet"), active_page==PAGE_INTERNET, &button, ui_draw_menu_tab_button, &corners))
+		if(DoButton_MenuTab(&internet_button, localize("Internet"), active_page==PAGE_INTERNET, &button, CUI::CORNER_TL))
 		{
 			client_serverbrowse_refresh(BROWSETYPE_INTERNET);
 			new_page = PAGE_INTERNET;
 		}
 
-		//ui_vsplit_l(&box, 4.0f, 0, &box);
-		ui_vsplit_l(&box, 80.0f, &button, &box);
+		//box.VSplitLeft(4.0f, 0, &box);
+		box.VSplitLeft(80.0f, &button, &box);
 		static int lan_button=0;
-		corners = 0;
-		if (ui_do_button(&lan_button, localize("LAN"), active_page==PAGE_LAN, &button, ui_draw_menu_tab_button, &corners))
+		if(DoButton_MenuTab(&lan_button, localize("LAN"), active_page==PAGE_LAN, &button, 0))
 		{
 			client_serverbrowse_refresh(BROWSETYPE_LAN);
 			new_page = PAGE_LAN;
 		}
 
-		//ui_vsplit_l(&box, 4.0f, 0, &box);
-		ui_vsplit_l(&box, 110.0f, &button, &box);
+		//box.VSplitLeft(4.0f, 0, &box);
+		box.VSplitLeft(110.0f, &button, &box);
 		static int favorites_button=0;
-		corners = CORNER_TR;
-		if (ui_do_button(&favorites_button, localize("Favorites"), active_page==PAGE_FAVORITES, &button, ui_draw_menu_tab_button, &corners))
+		if(DoButton_MenuTab(&favorites_button, localize("Favorites"), active_page==PAGE_FAVORITES, &button, CUI::CORNER_TR))
 		{
 			client_serverbrowse_refresh(BROWSETYPE_FAVORITES);
 			new_page  = PAGE_FAVORITES;
 		}
 		
-		ui_vsplit_l(&box, 4.0f*5, 0, &box);
-		ui_vsplit_l(&box, 100.0f, &button, &box);
+		box.VSplitLeft(4.0f*5, 0, &box);
+		box.VSplitLeft(100.0f, &button, &box);
 		static int demos_button=0;
-		if (ui_do_button(&demos_button, localize("Demos"), active_page==PAGE_DEMOS, &button, ui_draw_menu_tab_button, 0))
+		if(DoButton_MenuTab(&demos_button, localize("Demos"), active_page==PAGE_DEMOS, &button, 0))
 		{
 			demolist_populate();
 			new_page  = PAGE_DEMOS;
@@ -504,44 +512,44 @@ int MENUS::render_menubar(RECT r)
 	else
 	{
 		/* online menus */
-		ui_vsplit_l(&box, 90.0f, &button, &box);
+		box.VSplitLeft(90.0f, &button, &box);
 		static int game_button=0;
-		if (ui_do_button(&game_button, localize("Game"), active_page==PAGE_GAME, &button, ui_draw_menu_tab_button, 0))
+		if(DoButton_MenuTab(&game_button, localize("Game"), active_page==PAGE_GAME, &button, 0))
 			new_page = PAGE_GAME;
 
-		ui_vsplit_l(&box, 4.0f, 0, &box);
-		ui_vsplit_l(&box, 140.0f, &button, &box);
+		box.VSplitLeft(4.0f, 0, &box);
+		box.VSplitLeft(140.0f, &button, &box);
 		static int server_info_button=0;
-		if (ui_do_button(&server_info_button, localize("Server info"), active_page==PAGE_SERVER_INFO, &button, ui_draw_menu_tab_button, 0))
+		if(DoButton_MenuTab(&server_info_button, localize("Server info"), active_page==PAGE_SERVER_INFO, &button, 0))
 			new_page = PAGE_SERVER_INFO;
 
-		ui_vsplit_l(&box, 4.0f, 0, &box);
-		ui_vsplit_l(&box, 140.0f, &button, &box);
+		box.VSplitLeft(4.0f, 0, &box);
+		box.VSplitLeft(140.0f, &button, &box);
 		static int callvote_button=0;
-		if (ui_do_button(&callvote_button, localize("Call vote"), active_page==PAGE_CALLVOTE, &button, ui_draw_menu_tab_button, 0))
+		if(DoButton_MenuTab(&callvote_button, localize("Call vote"), active_page==PAGE_CALLVOTE, &button, 0))
 			new_page = PAGE_CALLVOTE;
 			
-		ui_vsplit_l(&box, 30.0f, 0, &box);
+		box.VSplitLeft(30.0f, 0, &box);
 	}
 		
 	/*
-	ui_vsplit_r(&box, 110.0f, &box, &button);
+	box.VSplitRight(110.0f, &box, &button);
 	static int system_button=0;
-	if (ui_do_button(&system_button, "System", config.ui_page==PAGE_SYSTEM, &button, ui_draw_menu_tab_button, 0))
+	if (UI()->DoButton(&system_button, "System", config.ui_page==PAGE_SYSTEM, &button))
 		config.ui_page = PAGE_SYSTEM;
 		
-	ui_vsplit_r(&box, 30.0f, &box, 0);
+	box.VSplitRight(30.0f, &box, 0);
 	*/
 	
-	ui_vsplit_r(&box, 90.0f, &box, &button);
+	box.VSplitRight(90.0f, &box, &button);
 	static int quit_button=0;
-	if (ui_do_button(&quit_button, localize("Quit"), 0, &button, ui_draw_menu_tab_button, 0))
+	if(DoButton_MenuTab(&quit_button, localize("Quit"), 0, &button, 0))
 		popup = POPUP_QUIT;
 
-	ui_vsplit_r(&box, 10.0f, &box, &button);
-	ui_vsplit_r(&box, 130.0f, &box, &button);
+	box.VSplitRight(10.0f, &box, &button);
+	box.VSplitRight(130.0f, &box, &button);
 	static int settings_button=0;
-	if (ui_do_button(&settings_button, localize("Settings"), active_page==PAGE_SETTINGS, &button, ui_draw_menu_tab_button, 0))
+	if(DoButton_MenuTab(&settings_button, localize("Settings"), active_page==PAGE_SETTINGS, &button, 0))
 		new_page = PAGE_SETTINGS;
 	
 	if(new_page != -1)
@@ -570,8 +578,8 @@ void MENUS::render_loading(float percent)
 	vec3 rgb = hsl_to_rgb(vec3(config.ui_color_hue/255.0f, config.ui_color_sat/255.0f, config.ui_color_lht/255.0f));
 	gui_color = vec4(rgb.r, rgb.g, rgb.b, config.ui_color_alpha/255.0f);
 	
-    RECT screen = *ui_screen();
-	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+    CUIRect screen = *UI()->Screen();
+	Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 	
 	render_background();
 
@@ -582,37 +590,37 @@ void MENUS::render_loading(float percent)
 	float x = screen.w/2-w/2;
 	float y = screen.h/2-h/2;
 
-	gfx_blend_normal();
+	Graphics()->BlendNormal();
 
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.50f);
-	draw_round_rect(x, y, w, h, 40.0f);
-	gfx_quads_end();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.50f);
+	RenderTools()->draw_round_rect(x, y, w, h, 40.0f);
+	Graphics()->QuadsEnd();
 
 
 	const char *caption = localize("Loading");
 
 	tw = gfx_text_width(0, 48.0f, caption, -1);
-	RECT r;
+	CUIRect r;
 	r.x = x;
 	r.y = y+20;
 	r.w = w;
 	r.h = h;
-	ui_do_label(&r, caption, 48.0f, 0, -1);
+	UI()->DoLabel(&r, caption, 48.0f, 0, -1);
 
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(1,1,1,0.75f);
-	draw_round_rect(x+40, y+h-75, (w-80)*percent, 25, 5.0f);
-	gfx_quads_end();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(1,1,1,0.75f);
+	RenderTools()->draw_round_rect(x+40, y+h-75, (w-80)*percent, 25, 5.0f);
+	Graphics()->QuadsEnd();
 
 	gfx_swap();
 }
 
-void MENUS::render_news(RECT main_view)
+void MENUS::render_news(CUIRect main_view)
 {
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_ALL, 10.0f);
 }
 
 void MENUS::on_init()
@@ -677,8 +685,8 @@ void MENUS::popup_message(const char *topic, const char *body, const char *butto
 
 int MENUS::render()
 {
-    RECT screen = *ui_screen();
-	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+    CUIRect screen = *UI()->Screen();
+	Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 
 	static bool first = true;
 	if(first)
@@ -702,17 +710,17 @@ int MENUS::render()
 		color_tabbar_active = color_tabbar_active_outgame;
 	}
 	
-	RECT tab_bar;
-	RECT main_view;
+	CUIRect tab_bar;
+	CUIRect main_view;
 
 	// some margin around the screen
-	ui_margin(&screen, 10.0f, &screen);
+	screen.Margin(10.0f, &screen);
 	
 	if(popup == POPUP_NONE)
 	{
 		// do tab bar
-		ui_hsplit_t(&screen, 24.0f, &tab_bar, &main_view);
-		ui_vmargin(&tab_bar, 20.0f, &tab_bar);
+		screen.HSplitTop(24.0f, &tab_bar, &main_view);
+		tab_bar.VMargin(20.0f, &tab_bar);
 		render_menubar(tab_bar);
 		
 		// news is not implemented yet
@@ -750,8 +758,8 @@ int MENUS::render()
 	else
 	{
 		// make sure that other windows doesn't do anything funnay!
-		//ui_set_hot_item(0);
-		//ui_set_active_item(0);
+		//UI()->SetHotItem(0);
+		//UI()->SetActiveItem(0);
 		char buf[128];
 		const char *title = "";
 		const char *extra_text = "";
@@ -809,109 +817,109 @@ int MENUS::render()
 			extra_align = -1;
 		}
 		
-		RECT box, part;
+		CUIRect box, part;
 		box = screen;
-		ui_vmargin(&box, 150.0f, &box);
-		ui_hmargin(&box, 150.0f, &box);
+		box.VMargin(150.0f, &box);
+		box.HMargin(150.0f, &box);
 		
 		// render the box
-		ui_draw_rect(&box, vec4(0,0,0,0.5f), CORNER_ALL, 15.0f);
+		RenderTools()->DrawUIRect(&box, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 15.0f);
 		 
-		ui_hsplit_t(&box, 20.f, &part, &box);
-		ui_hsplit_t(&box, 24.f, &part, &box);
-		ui_do_label(&part, title, 24.f, 0);
-		ui_hsplit_t(&box, 20.f, &part, &box);
-		ui_hsplit_t(&box, 24.f, &part, &box);
-		ui_vmargin(&part, 20.f, &part);
+		box.HSplitTop(20.f, &part, &box);
+		box.HSplitTop(24.f, &part, &box);
+		UI()->DoLabel(&part, title, 24.f, 0);
+		box.HSplitTop(20.f, &part, &box);
+		box.HSplitTop(24.f, &part, &box);
+		part.VMargin(20.f, &part);
 		
 		if(extra_align == -1)
-			ui_do_label(&part, extra_text, 20.f, -1, (int)part.w);
+			UI()->DoLabel(&part, extra_text, 20.f, -1, (int)part.w);
 		else
-			ui_do_label(&part, extra_text, 20.f, 0, -1);
+			UI()->DoLabel(&part, extra_text, 20.f, 0, -1);
 
 		if(popup == POPUP_QUIT)
 		{
-			RECT yes, no;
-			ui_hsplit_b(&box, 20.f, &box, &part);
-			ui_hsplit_b(&box, 24.f, &box, &part);
-			ui_vmargin(&part, 80.0f, &part);
+			CUIRect yes, no;
+			box.HSplitBottom(20.f, &box, &part);
+			box.HSplitBottom(24.f, &box, &part);
+			part.VMargin(80.0f, &part);
 			
-			ui_vsplit_mid(&part, &no, &yes);
+			part.VSplitMid(&no, &yes);
 			
-			ui_vmargin(&yes, 20.0f, &yes);
-			ui_vmargin(&no, 20.0f, &no);
+			yes.VMargin(20.0f, &yes);
+			no.VMargin(20.0f, &no);
 
 			static int button_abort = 0;
-			if(ui_do_button(&button_abort, localize("No"), 0, &no, ui_draw_menu_button, 0) || escape_pressed)
+			if(DoButton_Menu(&button_abort, localize("No"), 0, &no) || escape_pressed)
 				popup = POPUP_NONE;
 
 			static int button_tryagain = 0;
-			if(ui_do_button(&button_tryagain, localize("Yes"), 0, &yes, ui_draw_menu_button, 0) || enter_pressed)
+			if(DoButton_Menu(&button_tryagain, localize("Yes"), 0, &yes) || enter_pressed)
 				client_quit();
 		}
 		else if(popup == POPUP_PASSWORD)
 		{
-			RECT label, textbox, tryagain, abort;
+			CUIRect label, textbox, tryagain, abort;
 			
-			ui_hsplit_b(&box, 20.f, &box, &part);
-			ui_hsplit_b(&box, 24.f, &box, &part);
-			ui_vmargin(&part, 80.0f, &part);
+			box.HSplitBottom(20.f, &box, &part);
+			box.HSplitBottom(24.f, &box, &part);
+			part.VMargin(80.0f, &part);
 			
-			ui_vsplit_mid(&part, &abort, &tryagain);
+			part.VSplitMid(&abort, &tryagain);
 			
-			ui_vmargin(&tryagain, 20.0f, &tryagain);
-			ui_vmargin(&abort, 20.0f, &abort);
+			tryagain.VMargin(20.0f, &tryagain);
+			abort.VMargin(20.0f, &abort);
 			
 			static int button_abort = 0;
-			if(ui_do_button(&button_abort, localize("Abort"), 0, &abort, ui_draw_menu_button, 0) || escape_pressed)
+			if(DoButton_Menu(&button_abort, localize("Abort"), 0, &abort) || escape_pressed)
 				popup = POPUP_NONE;
 
 			static int button_tryagain = 0;
-			if(ui_do_button(&button_tryagain, localize("Try again"), 0, &tryagain, ui_draw_menu_button, 0) || enter_pressed)
+			if(DoButton_Menu(&button_tryagain, localize("Try again"), 0, &tryagain) || enter_pressed)
 			{
 				client_connect(config.ui_server_address);
 			}
 			
-			ui_hsplit_b(&box, 60.f, &box, &part);
-			ui_hsplit_b(&box, 24.f, &box, &part);
+			box.HSplitBottom(60.f, &box, &part);
+			box.HSplitBottom(24.f, &box, &part);
 			
-			ui_vsplit_l(&part, 60.0f, 0, &label);
-			ui_vsplit_l(&label, 100.0f, 0, &textbox);
-			ui_vsplit_l(&textbox, 20.0f, 0, &textbox);
-			ui_vsplit_r(&textbox, 60.0f, &textbox, 0);
-			ui_do_label(&label, localize("Password"), 20, -1);
-			ui_do_edit_box(&config.password, &textbox, config.password, sizeof(config.password), 14.0f, true);
+			part.VSplitLeft(60.0f, 0, &label);
+			label.VSplitLeft(100.0f, 0, &textbox);
+			textbox.VSplitLeft(20.0f, 0, &textbox);
+			textbox.VSplitRight(60.0f, &textbox, 0);
+			UI()->DoLabel(&label, localize("Password"), 20, -1);
+			DoEditBox(&config.password, &textbox, config.password, sizeof(config.password), 14.0f, true);
 		}
 		else if(popup == POPUP_FIRST_LAUNCH)
 		{
-			RECT label, textbox;
+			CUIRect label, textbox;
 			
-			ui_hsplit_b(&box, 20.f, &box, &part);
-			ui_hsplit_b(&box, 24.f, &box, &part);
-			ui_vmargin(&part, 80.0f, &part);
+			box.HSplitBottom(20.f, &box, &part);
+			box.HSplitBottom(24.f, &box, &part);
+			part.VMargin(80.0f, &part);
 			
 			static int enter_button = 0;
-			if(ui_do_button(&enter_button, localize("Enter"), 0, &part, ui_draw_menu_button, 0) || enter_pressed)
+			if(DoButton_Menu(&enter_button, localize("Enter"), 0, &part) || enter_pressed)
 				popup = POPUP_NONE;
 			
-			ui_hsplit_b(&box, 40.f, &box, &part);
-			ui_hsplit_b(&box, 24.f, &box, &part);
+			box.HSplitBottom(40.f, &box, &part);
+			box.HSplitBottom(24.f, &box, &part);
 			
-			ui_vsplit_l(&part, 60.0f, 0, &label);
-			ui_vsplit_l(&label, 100.0f, 0, &textbox);
-			ui_vsplit_l(&textbox, 20.0f, 0, &textbox);
-			ui_vsplit_r(&textbox, 60.0f, &textbox, 0);
-			ui_do_label(&label, localize("Nickname"), 20, -1);
-			ui_do_edit_box(&config.player_name, &textbox, config.player_name, sizeof(config.player_name), 14.0f);
+			part.VSplitLeft(60.0f, 0, &label);
+			label.VSplitLeft(100.0f, 0, &textbox);
+			textbox.VSplitLeft(20.0f, 0, &textbox);
+			textbox.VSplitRight(60.0f, &textbox, 0);
+			UI()->DoLabel(&label, localize("Nickname"), 20, -1);
+			DoEditBox(&config.player_name, &textbox, config.player_name, sizeof(config.player_name), 14.0f);
 		}
 		else
 		{
-			ui_hsplit_b(&box, 20.f, &box, &part);
-			ui_hsplit_b(&box, 24.f, &box, &part);
-			ui_vmargin(&part, 120.0f, &part);
+			box.HSplitBottom(20.f, &box, &part);
+			box.HSplitBottom(24.f, &box, &part);
+			part.VMargin(120.0f, &part);
 
 			static int button = 0;
-			if(ui_do_button(&button, button_text, 0, &part, ui_draw_menu_button, 0) || escape_pressed || enter_pressed)
+			if(DoButton_Menu(&button, button_text, 0, &part) || escape_pressed || enter_pressed)
 			{
 				if(popup == POPUP_CONNECTING)
 					client_disconnect();
@@ -949,8 +957,8 @@ bool MENUS::on_mousemove(float x, float y)
 	mouse_pos.y += y;
 	if(mouse_pos.x < 0) mouse_pos.x = 0;
 	if(mouse_pos.y < 0) mouse_pos.y = 0;
-	if(mouse_pos.x > gfx_screenwidth()) mouse_pos.x = gfx_screenwidth();
-	if(mouse_pos.y > gfx_screenheight()) mouse_pos.y = gfx_screenheight();
+	if(mouse_pos.x > Graphics()->ScreenWidth()) mouse_pos.x = Graphics()->ScreenWidth();
+	if(mouse_pos.y > Graphics()->ScreenHeight()) mouse_pos.y = Graphics()->ScreenHeight();
 	
 	return true;
 }
@@ -993,8 +1001,8 @@ void MENUS::on_statechange(int new_state, int old_state)
 			if(strstr(client_error_string(), "password"))
 			{
 				popup = POPUP_PASSWORD;
-				ui_set_hot_item(&config.password);
-				ui_set_active_item(&config.password);
+				UI()->SetHotItem(&config.password);
+				UI()->SetActiveItem(&config.password);
 			}
 			else
 				popup = POPUP_DISCONNECTED;
@@ -1028,10 +1036,10 @@ void MENUS::on_render()
 	gfx_text_set_cursor(&cursor, 10, 30, 15, TEXTFLAG_RENDER);
 	gfx_text_ex(&cursor, "ようこそ - ガイド", -1);
 	
-	//gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_quads_drawTL(60, 60, 5000, 5000);
-	gfx_quads_end();
+	//Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->QuadsDrawTL(60, 60, 5000, 5000);
+	Graphics()->QuadsEnd();
 	return;*/
 	
 	if(client_state() != CLIENTSTATE_ONLINE && client_state() != CLIENTSTATE_DEMOPLAYBACK)
@@ -1039,8 +1047,8 @@ void MENUS::on_render()
 
 	if(client_state() == CLIENTSTATE_DEMOPLAYBACK)
 	{
-		RECT screen = *ui_screen();
-		gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+		CUIRect screen = *UI()->Screen();
+		Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 		render_demoplayer(screen);
 	}
 	
@@ -1081,36 +1089,36 @@ void MENUS::on_render()
 		gui_color.a);
     
 	// update the ui
-	RECT *screen = ui_screen();
-	float mx = (mouse_pos.x/(float)gfx_screenwidth())*screen->w;
-	float my = (mouse_pos.y/(float)gfx_screenheight())*screen->h;
+	CUIRect *screen = UI()->Screen();
+	float mx = (mouse_pos.x/(float)Graphics()->ScreenWidth())*screen->w;
+	float my = (mouse_pos.y/(float)Graphics()->ScreenHeight())*screen->h;
 		
 	int buttons = 0;
 	if(inp_key_pressed(KEY_MOUSE_1)) buttons |= 1;
 	if(inp_key_pressed(KEY_MOUSE_2)) buttons |= 2;
 	if(inp_key_pressed(KEY_MOUSE_3)) buttons |= 4;
 		
-	ui_update(mx,my,mx*3.0f,my*3.0f,buttons);
+	UI()->Update(mx,my,mx*3.0f,my*3.0f,buttons);
     
 	// render
 	if(client_state() != CLIENTSTATE_DEMOPLAYBACK)
 		render();
 
 	// render cursor
-	gfx_texture_set(data->images[IMAGE_CURSOR].id);
-	gfx_quads_begin();
-	gfx_setcolor(1,1,1,1);
-	gfx_quads_drawTL(mx,my,24,24);
-	gfx_quads_end();
+	Graphics()->TextureSet(data->images[IMAGE_CURSOR].id);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(1,1,1,1);
+	Graphics()->QuadsDrawTL(mx,my,24,24);
+	Graphics()->QuadsEnd();
 
 	// render debug information
 	if(config.debug)
 	{
-		RECT screen = *ui_screen();
-		gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
+		CUIRect screen = *UI()->Screen();
+		Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);
 
 		char buf[512];
-		str_format(buf, sizeof(buf), "%p %p %p", ui_hot_item(), ui_active_item(), ui_last_active_item());
+		str_format(buf, sizeof(buf), "%p %p %p", UI()->HotItem(), UI()->ActiveItem(), UI()->LastActiveItem());
 		TEXT_CURSOR cursor;
 		gfx_text_set_cursor(&cursor, 10, 10, 10, TEXTFLAG_RENDER);
 		gfx_text_ex(&cursor, buf, -1);
@@ -1125,53 +1133,53 @@ static int texture_blob = -1;
 
 void MENUS::render_background()
 {
-	//gfx_clear(1,1,1);
+	//Graphics()->Clear(1,1,1);
 	//render_sunrays(0,0);
 	if(texture_blob == -1)
-		texture_blob = gfx_load_texture("blob.png", IMG_AUTO, 0);
+		texture_blob = Graphics()->LoadTexture("blob.png", IMG_AUTO, 0);
 
 
-	float sw = 300*gfx_screenaspect();
+	float sw = 300*Graphics()->ScreenAspect();
 	float sh = 300;
-	gfx_mapscreen(0, 0, sw, sh);
+	Graphics()->MapScreen(0, 0, sw, sh);
 
-	RECT s = *ui_screen();
+	CUIRect s = *UI()->Screen();
 
 	// render background color
-	gfx_texture_set(-1);
-	gfx_quads_begin();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
 		//vec4 bottom(gui_color.r*0.3f, gui_color.g*0.3f, gui_color.b*0.3f, 1.0f);
 		//vec4 bottom(0, 0, 0, 1.0f);
 		vec4 bottom(gui_color.r, gui_color.g, gui_color.b, 1.0f);
 		vec4 top(gui_color.r, gui_color.g, gui_color.b, 1.0f);
-		gfx_setcolorvertex(0, top.r, top.g, top.b, top.a);
-		gfx_setcolorvertex(1, top.r, top.g, top.b, top.a);
-		gfx_setcolorvertex(2, bottom.r, bottom.g, bottom.b, bottom.a);
-		gfx_setcolorvertex(3, bottom.r, bottom.g, bottom.b, bottom.a);
-		gfx_quads_drawTL(0, 0, sw, sh);
-	gfx_quads_end();
+		Graphics()->SetColorVertex(0, top.r, top.g, top.b, top.a);
+		Graphics()->SetColorVertex(1, top.r, top.g, top.b, top.a);
+		Graphics()->SetColorVertex(2, bottom.r, bottom.g, bottom.b, bottom.a);
+		Graphics()->SetColorVertex(3, bottom.r, bottom.g, bottom.b, bottom.a);
+		Graphics()->QuadsDrawTL(0, 0, sw, sh);
+	Graphics()->QuadsEnd();
 	
 	// render the tiles
-	gfx_texture_set(-1);
-	gfx_quads_begin();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
 		float size = 15.0f;
 		float offset_time = fmod(client_localtime()*0.15f, 2.0f);
 		for(int y = -2; y < (int)(sw/size); y++)
 			for(int x = -2; x < (int)(sh/size); x++)
 			{
-				gfx_setcolor(0,0,0,0.045f);
-				gfx_quads_drawTL((x-offset_time)*size*2+(y&1)*size, (y+offset_time)*size, size, size);
+				Graphics()->SetColor(0,0,0,0.045f);
+				Graphics()->QuadsDrawTL((x-offset_time)*size*2+(y&1)*size, (y+offset_time)*size, size, size);
 			}
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 
 	// render border fade
-	gfx_texture_set(texture_blob);
-	gfx_quads_begin();
-		gfx_setcolor(0,0,0,0.5f);
-		gfx_quads_drawTL(-100, -100, sw+200, sh+200);
-	gfx_quads_end();
+	Graphics()->TextureSet(texture_blob);
+	Graphics()->QuadsBegin();
+		Graphics()->SetColor(0,0,0,0.5f);
+		Graphics()->QuadsDrawTL(-100, -100, sw+200, sh+200);
+	Graphics()->QuadsEnd();
 
 	// restore screen	
-    {RECT screen = *ui_screen();
-	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);}	
+    {CUIRect screen = *UI()->Screen();
+	Graphics()->MapScreen(screen.x, screen.y, screen.w, screen.h);}	
 }
diff --git a/src/game/client/components/menus.hpp b/src/game/client/components/menus.hpp
index 15369dbc..02759403 100644
--- a/src/game/client/components/menus.hpp
+++ b/src/game/client/components/menus.hpp
@@ -26,39 +26,58 @@ class MENUS : public COMPONENT
 	static vec4 color_tabbar_inactive;
 	static vec4 color_tabbar_active;
 	
-	static vec4 button_color_mul(const void *id);
+	vec4 button_color_mul(const void *pID);
 
 
-	static void ui_draw_demoplayer_button(const void *id, const char *text, int checked, const RECT *r, const void *extra);
+	int DoButton_DemoPlayer(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
+	int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
+	int DoButton_MenuTab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Corners);
+	int DoButton_SettingsTab(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
 
-	static void ui_draw_browse_icon(int what, const RECT *r);
-	static void ui_draw_menu_button(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_keyselect_button(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_menu_tab_button(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_settings_tab_button(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_grid_header(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_list_row(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r);
-	static void ui_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static void ui_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-	static int ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden=false);
+	int DoButton_CheckBox_Common(const void *pID, const char *pText, const char *pBoxText, const CUIRect *pRect);
+	int DoButton_CheckBox(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
+	int DoButton_CheckBox_Number(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
 
-	static float ui_do_scrollbar_v(const void *id, const RECT *rect, float current);
-	static float ui_do_scrollbar_h(const void *id, const RECT *rect, float current);
+	/*static void ui_draw_menu_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	static void ui_draw_keyselect_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	static void ui_draw_menu_tab_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	static void ui_draw_settings_tab_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	*/
 
-	static int ui_do_key_reader(void *id, const RECT *rect, int key);
-	static void ui_do_getbuttons(int start, int stop, RECT view);
+	int DoButton_BrowseIcon(int Checked, const CUIRect *pRect);
+	int DoButton_GridHeader(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
+	int DoButton_ListRow(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
+
+	//static void ui_draw_browse_icon(int what, const CUIRect *r);
+	//static void ui_draw_grid_header(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	
+	/*static void ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const CUIRect *r, const void *extra);
+	static void ui_draw_checkbox(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	static void ui_draw_checkbox_number(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	*/
+	int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden=false);
+	//static int ui_do_edit_box(void *id, const CUIRect *rect, char *str, unsigned str_size, float font_size, bool hidden=false);
+
+	float DoScrollbarV(const void *pID, const CUIRect *pRect, float Current);
+	float DoScrollbarH(const void *pID, const CUIRect *pRect, float Current);
+	int DoButton_KeySelect(const void *pID, const char *pText, int Checked, const CUIRect *pRect);
+	int DoKeyReader(void *pID, const CUIRect *pRect, int Key);
+
+	//static int ui_do_key_reader(void *id, const CUIRect *rect, int key);
+	void ui_do_getbuttons(int start, int stop, CUIRect view);
 
 	struct LISTBOXITEM
 	{
 		int visible;
 		int selected;
-		RECT rect;
+		CUIRect rect;
+		CUIRect hitrect;
 	};
 	
-	static void ui_do_listbox_start(void *id, const RECT *rect, float row_height, const char *title, int num_items, int selected_index);
-	static LISTBOXITEM ui_do_listbox_nextitem(void *id);
-	static int ui_do_listbox_end();
+	void ui_do_listbox_start(void *id, const CUIRect *rect, float row_height, const char *title, int num_items, int selected_index);
+	LISTBOXITEM ui_do_listbox_nextitem(void *id);
+	static LISTBOXITEM ui_do_listbox_nextrow();
+	int ui_do_listbox_end();
 	
 	//static void demolist_listdir_callback(const char *name, int is_dir, void *user);
 	//static void demolist_list_callback(const RECT *rect, int index, void *user);
@@ -143,39 +162,42 @@ class MENUS : public COMPONENT
 
 	// found in menus.cpp
 	int render();
-	void render_background();
+	//void render_background();
 	//void render_loading(float percent);
-	int render_menubar(RECT r);
-	void render_news(RECT main_view);
+	int render_menubar(CUIRect r);
+	void render_news(CUIRect main_view);
 	
 	// found in menus_demo.cpp
-	void render_demoplayer(RECT main_view);
-	void render_demolist(RECT main_view);
+	void render_demoplayer(CUIRect main_view);
+	void render_demolist(CUIRect main_view);
 	
 	// found in menus_ingame.cpp
-	void render_game(RECT main_view);
-	void render_serverinfo(RECT main_view);
-	void render_servercontrol(RECT main_view);
-	void render_servercontrol_kick(RECT main_view);
-	void render_servercontrol_server(RECT main_view);
+	void render_game(CUIRect main_view);
+	void render_serverinfo(CUIRect main_view);
+	void render_servercontrol(CUIRect main_view);
+	void render_servercontrol_kick(CUIRect main_view);
+	void render_servercontrol_server(CUIRect main_view);
 	
 	// found in menus_browser.cpp
 	int selected_index;
-	void render_serverbrowser_serverlist(RECT view);
-	void render_serverbrowser_serverdetail(RECT view);
-	void render_serverbrowser_filters(RECT view);
-	void render_serverbrowser(RECT main_view);
+	void render_serverbrowser_serverlist(CUIRect view);
+	void render_serverbrowser_serverdetail(CUIRect view);
+	void render_serverbrowser_filters(CUIRect view);
+	void render_serverbrowser(CUIRect main_view);
 	
 	// found in menus_settings.cpp
-	void render_settings_general(RECT main_view);
-	void render_settings_player(RECT main_view);
-	void render_settings_controls(RECT main_view);
-	void render_settings_graphics(RECT main_view);
-	void render_settings_sound(RECT main_view);
-	void render_settings(RECT main_view);
+	void render_settings_general(CUIRect main_view);
+	void render_settings_player(CUIRect main_view);
+	void render_settings_controls(CUIRect main_view);
+	void render_settings_graphics(CUIRect main_view);
+	void render_settings_sound(CUIRect main_view);
+	void render_settings(CUIRect main_view);
 	
 	void set_active(bool active);
 public:
+	void render_background();
+
+
 	static MENUS_KEYBINDER binder;
 	
 	MENUS();
diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp
index a7f21084..dcf68f8d 100644
--- a/src/game/client/components/menus_browser.cpp
+++ b/src/game/client/components/menus_browser.cpp
@@ -12,17 +12,17 @@
 #include <game/localization.hpp>
 #include <game/version.hpp>
 
-void MENUS::render_serverbrowser_serverlist(RECT view)
+void MENUS::render_serverbrowser_serverlist(CUIRect view)
 {
-	RECT headers;
-	RECT status;
+	CUIRect headers;
+	CUIRect status;
 	
-	ui_hsplit_t(&view, listheader_height, &headers, &view);
-	ui_hsplit_b(&view, 28.0f, &view, &status);
+	view.HSplitTop(listheader_height, &headers, &view);
+	view.HSplitBottom(28.0f, &view, &status);
 	
 	// split of the scrollbar
-	ui_draw_rect(&headers, vec4(1,1,1,0.25f), CORNER_T, 5.0f);
-	ui_vsplit_r(&headers, 20.0f, &headers, 0);
+	RenderTools()->DrawUIRect(&headers, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f);
+	headers.VSplitRight(20.0f, &headers, 0);
 	
 	struct column
 	{
@@ -32,8 +32,8 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 		int direction;
 		float width;
 		int flags;
-		RECT rect;
-		RECT spacer;
+		CUIRect rect;
+		CUIRect spacer;
 	};
 	
 	enum
@@ -72,12 +72,12 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 	{
 		if(cols[i].direction == -1)
 		{
-			ui_vsplit_l(&headers, cols[i].width, &cols[i].rect, &headers);
+			headers.VSplitLeft(cols[i].width, &cols[i].rect, &headers);
 			
 			if(i+1 < num_cols)
 			{
 				//cols[i].flags |= SPACER;
-				ui_vsplit_l(&headers, 2, &cols[i].spacer, &headers);
+				headers.VSplitLeft(2, &cols[i].spacer, &headers);
 			}
 		}
 	}
@@ -86,8 +86,8 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 	{
 		if(cols[i].direction == 1)
 		{
-			ui_vsplit_r(&headers, cols[i].width, &headers, &cols[i].rect);
-			ui_vsplit_r(&headers, 2, &headers, &cols[i].spacer);
+			headers.VSplitRight(cols[i].width, &headers, &cols[i].rect);
+			headers.VSplitRight(2, &headers, &cols[i].spacer);
 		}
 	}
 	
@@ -100,7 +100,7 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 	// do headers
 	for(int i = 0; i < num_cols; i++)
 	{
-		if(ui_do_button(cols[i].caption, cols[i].caption, config.b_sort == cols[i].sort, &cols[i].rect, ui_draw_grid_header, 0))
+		if(DoButton_GridHeader(cols[i].caption, cols[i].caption, config.b_sort == cols[i].sort, &cols[i].rect))
 		{
 			if(cols[i].sort != -1)
 			{
@@ -113,33 +113,33 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 		}
 	}
 	
-	ui_draw_rect(&view, vec4(0,0,0,0.15f), 0, 0);
+	RenderTools()->DrawUIRect(&view, vec4(0,0,0,0.15f), 0, 0);
 	
-	RECT scroll;
-	ui_vsplit_r(&view, 15, &view, &scroll);
+	CUIRect scroll;
+	view.VSplitRight(15, &view, &scroll);
 	
 	int num_servers = client_serverbrowse_sorted_num();
 	
 	// display important messages in the middle of the screen so no
 	// users misses it
 	{
-		RECT msgbox = view;
+		CUIRect msgbox = view;
 		msgbox.y += view.h/3;
 		
 		if(active_page == PAGE_INTERNET && client_serverbrowse_refreshingmasters())
-			ui_do_label(&msgbox, localize("Refreshing master servers"), 16.0f, 0);
+			UI()->DoLabel(&msgbox, localize("Refreshing master servers"), 16.0f, 0);
 		else if(!client_serverbrowse_num())
-			ui_do_label(&msgbox, localize("No servers found"), 16.0f, 0);
+			UI()->DoLabel(&msgbox, localize("No servers found"), 16.0f, 0);
 		else if(client_serverbrowse_num() && !num_servers)
-			ui_do_label(&msgbox, localize("No servers match your filter criteria"), 16.0f, 0);
+			UI()->DoLabel(&msgbox, localize("No servers match your filter criteria"), 16.0f, 0);
 	}
 
 	int num = (int)(view.h/cols[0].rect.h);
 	static int scrollbar = 0;
 	static float scrollvalue = 0;
 	//static int selected_index = -1;
-	ui_hmargin(&scroll, 5.0f, &scroll);
-	scrollvalue = ui_do_scrollbar_v(&scrollbar, &scroll, scrollvalue);
+	scroll.HMargin(5.0f, &scroll);
+	scrollvalue = DoScrollbarV(&scrollbar, &scroll, scrollvalue);
 	
 	int scrollnum = num_servers-num+10;
 	if(scrollnum > 0)
@@ -156,13 +156,13 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 		scrollnum = 0;
 
 	// set clipping
-	ui_clip_enable(&view);
+	UI()->ClipEnable(&view);
 	
 	int start = (int)(scrollnum*scrollvalue);
 	if(start < 0)
 		start = 0;
 	
-	RECT original_view = view;
+	CUIRect original_view = view;
 	view.y -= scrollvalue*scrollnum*cols[0].rect.h;
 	
 	int new_selected = -1;
@@ -180,20 +180,20 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 	{
 		int item_index = i;
 		SERVER_INFO *item = client_serverbrowse_sorted_get(item_index);
-		RECT row;
-        RECT select_hit_box;
+		CUIRect row;
+        CUIRect select_hit_box;
 		
 		int selected = strcmp(item->address, config.ui_server_address) == 0; //selected_index==item_index;
 		
-		ui_hsplit_t(&view, 17.0f, &row, &view);
+		view.HSplitTop(17.0f, &row, &view);
 		select_hit_box = row;
 		
 		if(selected)
 		{
 			selected_index = i;
-			RECT r = row;
-			ui_margin(&r, 1.5f, &r);
-			ui_draw_rect(&r, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f);
+			CUIRect r = row;
+			r.Margin(1.5f, &r);
+			RenderTools()->DrawUIRect(&r, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f);
 		}
 
 
@@ -206,7 +206,7 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 				select_hit_box.y = original_view.y;
 			}
 			
-			if(ui_do_button(item, "", selected, &select_hit_box, 0, 0))
+			if(UI()->DoButtonLogic(item, "", selected, &select_hit_box))
 			{
 				new_selected = item_index;
 			}
@@ -218,7 +218,7 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 
 		for(int c = 0; c < num_cols; c++)
 		{
-			RECT button;
+			CUIRect button;
 			char temp[64];
 			button.x = cols[c].rect.x;
 			button.y = row.y;
@@ -228,12 +228,12 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 			//int s = 0;
 			int id = cols[c].id;
 
-			//s = ui_do_button(item, "L", l, &button, ui_draw_browse_icon, 0);
+			//s = UI()->DoButton(item, "L", l, &button, ui_draw_browse_icon, 0);
 			
 			if(id == COL_FLAG_LOCK)
 			{
 				if(item->flags & SRVFLAG_PASSWORD)
-					ui_draw_browse_icon(SPRITE_BROWSE_LOCK, &button);
+					DoButton_BrowseIcon(SPRITE_BROWSE_LOCK, &button);
 			}
 			else if(id == COL_FLAG_PURE)
 			{
@@ -244,13 +244,13 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 				else
 				{
 					// unpure
-					ui_draw_browse_icon(SPRITE_BROWSE_UNPURE, &button);
+					DoButton_BrowseIcon(SPRITE_BROWSE_UNPURE, &button);
 				}
 			}
 			else if(id == COL_FLAG_FAV)
 			{
 				if(item->favorite)
-					ui_draw_browse_icon(SPRITE_BROWSE_HEART, &button);
+					DoButton_BrowseIcon(SPRITE_BROWSE_HEART, &button);
 			}
 			else if(id == COL_NAME)
 			{
@@ -277,36 +277,36 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 					gfx_text_ex(&cursor, item->name, -1);
 			}
 			else if(id == COL_MAP)
-				ui_do_label(&button, item->map, 12.0f, -1);
+				UI()->DoLabel(&button, item->map, 12.0f, -1);
 			else if(id == COL_PLAYERS)
 			{
 				str_format(temp, sizeof(temp), "%i/%i", item->num_players, item->max_players);
 				if(config.b_filter_string[0] && (item->quicksearch_hit&BROWSEQUICK_PLAYERNAME))
 					gfx_text_color(0.4f,0.4f,1.0f,1);
-				ui_do_label(&button, temp, 12.0f, 1);
+				UI()->DoLabel(&button, temp, 12.0f, 1);
 				gfx_text_color(1,1,1,1);
 			}
 			else if(id == COL_PING)
 			{
 				str_format(temp, sizeof(temp), "%i", item->latency);
-				ui_do_label(&button, temp, 12.0f, 1);
+				UI()->DoLabel(&button, temp, 12.0f, 1);
 			}
 			else if(id == COL_VERSION)
 			{
 				const char *version = item->version;
 				if(strcmp(version, "0.3 e2d7973c6647a13c") == 0) // TODO: remove me later on
 					version = "0.3.0";
-				ui_do_label(&button, version, 12.0f, 1);
+				UI()->DoLabel(&button, version, 12.0f, 1);
 			}			
 			else if(id == COL_GAMETYPE)
 			{
-				ui_do_label(&button, item->gametype, 12.0f, 0);
+				UI()->DoLabel(&button, item->gametype, 12.0f, 0);
 			}
 
 		}
 	}
 
-	ui_clip_disable();
+	UI()->ClipDisable();
 	
 	if(new_selected != -1)
 	{
@@ -317,84 +317,84 @@ void MENUS::render_serverbrowser_serverlist(RECT view)
 			client_connect(config.ui_server_address);
 	}
 
-	ui_draw_rect(&status, vec4(1,1,1,0.25f), CORNER_B, 5.0f);
-	ui_margin(&status, 5.0f, &status);
+	RenderTools()->DrawUIRect(&status, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f);
+	status.Margin(5.0f, &status);
 	
 	// render quick search
-	RECT quicksearch;
-	ui_vsplit_l(&status, 250.0f, &quicksearch, &status);
+	CUIRect quicksearch;
+	status.VSplitLeft(250.0f, &quicksearch, &status);
 	const char *label = localize("Quick search");
-	ui_do_label(&quicksearch, label, 14.0f, -1);
-	ui_vsplit_l(&quicksearch, gfx_text_width(0, 14.0f, label, -1), 0, &quicksearch);
-	ui_vsplit_l(&quicksearch, 5, 0, &quicksearch);
-	ui_do_edit_box(&config.b_filter_string, &quicksearch, config.b_filter_string, sizeof(config.b_filter_string), 14.0f);
+	UI()->DoLabel(&quicksearch, label, 14.0f, -1);
+	quicksearch.VSplitLeft(gfx_text_width(0, 14.0f, label, -1), 0, &quicksearch);
+	quicksearch.VSplitLeft(5, 0, &quicksearch);
+	DoEditBox(&config.b_filter_string, &quicksearch, config.b_filter_string, sizeof(config.b_filter_string), 14.0f);
 	
 	// render status
 	char buf[128];
 	str_format(buf, sizeof(buf), localize("%d of %d servers, %d players"), client_serverbrowse_sorted_num(), client_serverbrowse_num(), num_players);
-	ui_vsplit_r(&status, gfx_text_width(0, 14.0f, buf, -1), 0, &status);
-	ui_do_label(&status, buf, 14.0f, -1);
+	status.VSplitRight(gfx_text_width(0, 14.0f, buf, -1), 0, &status);
+	UI()->DoLabel(&status, buf, 14.0f, -1);
 }
 
-void MENUS::render_serverbrowser_filters(RECT view)
+void MENUS::render_serverbrowser_filters(CUIRect view)
 {
 	// filters
-	RECT button;
+	CUIRect button;
 
-	ui_hsplit_t(&view, 5.0f, 0, &view);
-	ui_vsplit_l(&view, 5.0f, 0, &view);
-	ui_vsplit_r(&view, 5.0f, &view, 0);
-	ui_hsplit_b(&view, 5.0f, &view, 0);
+	view.HSplitTop(5.0f, 0, &view);
+	view.VSplitLeft(5.0f, 0, &view);
+	view.VSplitRight(5.0f, &view, 0);
+	view.HSplitBottom(5.0f, &view, 0);
 
 	// render filters
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	if (ui_do_button(&config.b_filter_empty, localize("Has people playing"), config.b_filter_empty, &button, ui_draw_checkbox, 0))
+	view.HSplitTop(20.0f, &button, &view);
+	if (DoButton_CheckBox(&config.b_filter_empty, localize("Has people playing"), config.b_filter_empty, &button))
 		config.b_filter_empty ^= 1;
 
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	if (ui_do_button(&config.b_filter_full, localize("Server not full"), config.b_filter_full, &button, ui_draw_checkbox, 0))
+	view.HSplitTop(20.0f, &button, &view);
+	if (DoButton_CheckBox(&config.b_filter_full, localize("Server not full"), config.b_filter_full, &button))
 		config.b_filter_full ^= 1;
 
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	if (ui_do_button(&config.b_filter_pw, localize("No password"), config.b_filter_pw, &button, ui_draw_checkbox, 0))
+	view.HSplitTop(20.0f, &button, &view);
+	if (DoButton_CheckBox(&config.b_filter_pw, localize("No password"), config.b_filter_pw, &button))
 		config.b_filter_pw ^= 1;
 
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	if (ui_do_button((char *)&config.b_filter_compatversion, localize("Compatible version"), config.b_filter_compatversion, &button, ui_draw_checkbox, 0))
+	view.HSplitTop(20.0f, &button, &view);
+	if (DoButton_CheckBox((char *)&config.b_filter_compatversion, localize("Compatible version"), config.b_filter_compatversion, &button))
 		config.b_filter_compatversion ^= 1;
 	
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	if (ui_do_button((char *)&config.b_filter_pure, localize("Standard gametype"), config.b_filter_pure, &button, ui_draw_checkbox, 0))
+	view.HSplitTop(20.0f, &button, &view);
+	if (DoButton_CheckBox((char *)&config.b_filter_pure, localize("Standard gametype"), config.b_filter_pure, &button))
 		config.b_filter_pure ^= 1;
 
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	/*ui_vsplit_l(&button, 20.0f, 0, &button);*/
-	if (ui_do_button((char *)&config.b_filter_pure_map, localize("Standard map"), config.b_filter_pure_map, &button, ui_draw_checkbox, 0))
+	view.HSplitTop(20.0f, &button, &view);
+	/*button.VSplitLeft(20.0f, 0, &button);*/
+	if (DoButton_CheckBox((char *)&config.b_filter_pure_map, localize("Standard map"), config.b_filter_pure_map, &button))
 		config.b_filter_pure_map ^= 1;
 		
-	ui_hsplit_t(&view, 20.0f, &button, &view);
-	ui_do_label(&button, localize("Game types"), 14.0f, -1);
-	ui_vsplit_l(&button, 95.0f, 0, &button);
-	ui_margin(&button, 1.0f, &button);
-	ui_do_edit_box(&config.b_filter_gametype, &button, config.b_filter_gametype, sizeof(config.b_filter_gametype), 14.0f);
+	view.HSplitTop(20.0f, &button, &view);
+	UI()->DoLabel(&button, localize("Game types"), 14.0f, -1);
+	button.VSplitLeft(95.0f, 0, &button);
+	button.Margin(1.0f, &button);
+	DoEditBox(&config.b_filter_gametype, &button, config.b_filter_gametype, sizeof(config.b_filter_gametype), 14.0f);
 
 	{
-		ui_hsplit_t(&view, 20.0f, &button, &view);
-		RECT editbox;
-		ui_vsplit_l(&button, 40.0f, &editbox, &button);
-		ui_vsplit_l(&button, 5.0f, &button, &button);
+		view.HSplitTop(20.0f, &button, &view);
+		CUIRect editbox;
+		button.VSplitLeft(40.0f, &editbox, &button);
+		button.VSplitLeft(5.0f, &button, &button);
 		
 		char buf[8];
 		str_format(buf, sizeof(buf), "%d", config.b_filter_ping);
-		ui_do_edit_box(&config.b_filter_ping, &editbox, buf, sizeof(buf), 14.0f);
+		DoEditBox(&config.b_filter_ping, &editbox, buf, sizeof(buf), 14.0f);
 		config.b_filter_ping = atoi(buf);
 		
-		ui_do_label(&button, localize("Maximum ping"), 14.0f, -1);
+		UI()->DoLabel(&button, localize("Maximum ping"), 14.0f, -1);
 	}
 	
-	ui_hsplit_b(&view, button_height, &view, &button);
+	view.HSplitBottom(button_height, &view, &button);
 	static int clear_button = 0;
-	if(ui_do_button(&clear_button, localize("Reset filter"), 0, &button, ui_draw_menu_button, 0))
+	if(DoButton_Menu(&clear_button, localize("Reset filter"), 0, &button))
 	{
 		config.b_filter_full = 0;
 		config.b_filter_empty = 0;
@@ -407,48 +407,48 @@ void MENUS::render_serverbrowser_filters(RECT view)
 	}
 }
 
-void MENUS::render_serverbrowser_serverdetail(RECT view)
+void MENUS::render_serverbrowser_serverdetail(CUIRect view)
 {
-	RECT server_details = view;
-	RECT server_scoreboard, server_header;
+	CUIRect server_details = view;
+	CUIRect server_scoreboard, server_header;
 	
 	SERVER_INFO *selected_server = client_serverbrowse_sorted_get(selected_index);
 	
-	//ui_vsplit_l(&server_details, 10.0f, 0x0, &server_details);
+	//server_details.VSplitLeft(10.0f, 0x0, &server_details);
 
 	// split off a piece to use for scoreboard
-	ui_hsplit_t(&server_details, 140.0f, &server_details, &server_scoreboard);
-	ui_hsplit_b(&server_details, 10.0f, &server_details, 0x0);
+	server_details.HSplitTop(140.0f, &server_details, &server_scoreboard);
+	server_details.HSplitBottom(10.0f, &server_details, 0x0);
 
 	// server details
 	const float font_size = 12.0f;
-	ui_hsplit_t(&server_details, 20.0f, &server_header, &server_details);
-	ui_draw_rect(&server_header, vec4(1,1,1,0.25f), CORNER_T, 4.0f);
-	ui_draw_rect(&server_details, vec4(0,0,0,0.15f), CORNER_B, 4.0f);
-	ui_vsplit_l(&server_header, 8.0f, 0x0, &server_header);
-	ui_do_label(&server_header, localize("Server details"), font_size+2.0f, -1);
+	server_details.HSplitTop(20.0f, &server_header, &server_details);
+	RenderTools()->DrawUIRect(&server_header, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f);
+	RenderTools()->DrawUIRect(&server_details, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f);
+	server_header.VSplitLeft(8.0f, 0x0, &server_header);
+	UI()->DoLabel(&server_header, localize("Server details"), font_size+2.0f, -1);
 
-	ui_vsplit_l(&server_details, 5.0f, 0x0, &server_details);
+	server_details.VSplitLeft(5.0f, 0x0, &server_details);
 
-	ui_margin(&server_details, 3.0f, &server_details);
+	server_details.Margin(3.0f, &server_details);
 
 	if (selected_server)
 	{
-		RECT row;
+		CUIRect row;
 		static LOC_CONSTSTRING labels[] = {
 			localize("Version"),
 			localize("Game type"),
 			localize("Ping")};
 
-		RECT left_column;
-		RECT right_column;
+		CUIRect left_column;
+		CUIRect right_column;
 
 		// 
 		{
-			RECT button;
-			ui_hsplit_b(&server_details, 20.0f, &server_details, &button);
+			CUIRect button;
+			server_details.HSplitBottom(20.0f, &server_details, &button);
 			static int add_fav_button = 0;
-			if (ui_do_button(&add_fav_button, localize("Favorite"), selected_server->favorite, &button, ui_draw_checkbox, 0))
+			if(DoButton_CheckBox(&add_fav_button, localize("Favorite"), selected_server->favorite, &button))
 			{
 				if(selected_server->favorite)
 					client_serverbrowse_removefavorite(selected_server->netaddr);
@@ -456,55 +456,55 @@ void MENUS::render_serverbrowser_serverdetail(RECT view)
 					client_serverbrowse_addfavorite(selected_server->netaddr);
 			}
 		}
-		//ui_do_label(&row, temp, font_size, -1);		
+		//UI()->DoLabel(&row, temp, font_size, -1);		
 
-		ui_vsplit_l(&server_details, 5.0f, 0x0, &server_details);
-		ui_vsplit_l(&server_details, 80.0f, &left_column, &right_column);
+		server_details.VSplitLeft(5.0f, 0x0, &server_details);
+		server_details.VSplitLeft(80.0f, &left_column, &right_column);
 
 		for (unsigned int i = 0; i < sizeof(labels) / sizeof(labels[0]); i++)
 		{
-			ui_hsplit_t(&left_column, 15.0f, &row, &left_column);
-			ui_do_label(&row, labels[i], font_size, -1);
+			left_column.HSplitTop(15.0f, &row, &left_column);
+			UI()->DoLabel(&row, labels[i], font_size, -1);
 		}
 
-		ui_hsplit_t(&right_column, 15.0f, &row, &right_column);
-		ui_do_label(&row, selected_server->version, font_size, -1);
+		right_column.HSplitTop(15.0f, &row, &right_column);
+		UI()->DoLabel(&row, selected_server->version, font_size, -1);
 
-		ui_hsplit_t(&right_column, 15.0f, &row, &right_column);
-		ui_do_label(&row, selected_server->gametype, font_size, -1);
+		right_column.HSplitTop(15.0f, &row, &right_column);
+		UI()->DoLabel(&row, selected_server->gametype, font_size, -1);
 
 		char temp[16];
 		str_format(temp, sizeof(temp), "%d", selected_server->latency);
-		ui_hsplit_t(&right_column, 15.0f, &row, &right_column);
-		ui_do_label(&row, temp, font_size, -1);
+		right_column.HSplitTop(15.0f, &row, &right_column);
+		UI()->DoLabel(&row, temp, font_size, -1);
 
 	}
 	
 	// server scoreboard
 	
-	ui_hsplit_b(&server_scoreboard, 10.0f, &server_scoreboard, 0x0);
-	ui_hsplit_t(&server_scoreboard, 20.0f, &server_header, &server_scoreboard);
-	ui_draw_rect(&server_header, vec4(1,1,1,0.25f), CORNER_T, 4.0f);
-	ui_draw_rect(&server_scoreboard, vec4(0,0,0,0.15f), CORNER_B, 4.0f);
-	ui_vsplit_l(&server_header, 8.0f, 0x0, &server_header);
-	ui_do_label(&server_header, localize("Scoreboard"), font_size+2.0f, -1);
+	server_scoreboard.HSplitBottom(10.0f, &server_scoreboard, 0x0);
+	server_scoreboard.HSplitTop(20.0f, &server_header, &server_scoreboard);
+	RenderTools()->DrawUIRect(&server_header, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f);
+	RenderTools()->DrawUIRect(&server_scoreboard, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f);
+	server_header.VSplitLeft(8.0f, 0x0, &server_header);
+	UI()->DoLabel(&server_header, localize("Scoreboard"), font_size+2.0f, -1);
 
-	ui_vsplit_l(&server_scoreboard, 5.0f, 0x0, &server_scoreboard);
+	server_scoreboard.VSplitLeft(5.0f, 0x0, &server_scoreboard);
 
-	ui_margin(&server_scoreboard, 3.0f, &server_scoreboard);
+	server_scoreboard.Margin(3.0f, &server_scoreboard);
 
 	if (selected_server)
 	{
 		for (int i = 0; i < selected_server->num_players; i++)
 		{
-			RECT row;
+			CUIRect row;
 			char temp[16];
-			ui_hsplit_t(&server_scoreboard, 16.0f, &row, &server_scoreboard);
+			server_scoreboard.HSplitTop(16.0f, &row, &server_scoreboard);
 
 			str_format(temp, sizeof(temp), "%d", selected_server->players[i].score);
-			ui_do_label(&row, temp, font_size, -1);
+			UI()->DoLabel(&row, temp, font_size, -1);
 
-			ui_vsplit_l(&row, 25.0f, 0x0, &row);
+			row.VSplitLeft(25.0f, 0x0, &row);
 		
 			TEXT_CURSOR cursor;
 			gfx_text_set_cursor(&cursor, row.x, row.y, 12.0f, TEXTFLAG_RENDER);
@@ -532,12 +532,12 @@ void MENUS::render_serverbrowser_serverdetail(RECT view)
 	}
 }
 
-void MENUS::render_serverbrowser(RECT main_view)
+void MENUS::render_serverbrowser(CUIRect main_view)
 {
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_ALL, 10.0f);
 	
-	RECT view;
-	ui_margin(&main_view, 10.0f, &view);
+	CUIRect view;
+	main_view.Margin(10.0f, &view);
 	
 	/*
 		+-----------------+ +------+
@@ -551,44 +551,44 @@ void MENUS::render_serverbrowser(RECT main_view)
 	*/
 	
 	
-	//RECT filters;
-	RECT status_toolbar;
-	RECT toolbox;
-	RECT button_box;
+	//CUIRect filters;
+	CUIRect status_toolbar;
+	CUIRect toolbox;
+	CUIRect button_box;
 
 	// split off a piece for filters, details and scoreboard
-	ui_vsplit_r(&view, 200.0f, &view, &toolbox);
-	ui_hsplit_b(&toolbox, 80.0f, &toolbox, &button_box);
-	ui_hsplit_b(&view, button_height+5.0f, &view, &status_toolbar);
+	view.VSplitRight(200.0f, &view, &toolbox);
+	toolbox.HSplitBottom(80.0f, &toolbox, &button_box);
+	view.HSplitBottom(button_height+5.0f, &view, &status_toolbar);
 
 	render_serverbrowser_serverlist(view);
 	
 	static int toolbox_page = 0;
 	
-	ui_vsplit_l(&toolbox, 5.0f, 0, &toolbox);
+	toolbox.VSplitLeft(5.0f, 0, &toolbox);
 
 	// do tabbar
 	{
-		RECT tab_bar;
-		RECT tabbutton0, tabbutton1;
-		ui_hsplit_t(&toolbox, 22.0f, &tab_bar, &toolbox);
+		CUIRect tab_bar;
+		CUIRect tabbutton0, tabbutton1;
+		toolbox.HSplitTop(22.0f, &tab_bar, &toolbox);
 	
-		ui_vsplit_mid(&tab_bar, &tabbutton0, &tabbutton1);
-		ui_vsplit_r(&tabbutton0, 5.0f, &tabbutton0, 0);
-		ui_vsplit_l(&tabbutton1, 5.0f, 0, &tabbutton1);
+		tab_bar.VSplitMid(&tabbutton0, &tabbutton1);
+		tabbutton0.VSplitRight(5.0f, &tabbutton0, 0);
+		tabbutton1.VSplitLeft(5.0f, 0, &tabbutton1);
 		
 		static int filters_tab = 0;
-		if (ui_do_button(&filters_tab, localize("Filter"), toolbox_page==0, &tabbutton0, ui_draw_menu_tab_button, 0))
+		if (DoButton_MenuTab(&filters_tab, localize("Filter"), toolbox_page==0, &tabbutton0, 0))
 			toolbox_page = 0;
 			
 		static int info_tab = 0;
-		if (ui_do_button(&info_tab, localize("Info"), toolbox_page==1, &tabbutton1, ui_draw_menu_tab_button, 0))
+		if (DoButton_MenuTab(&info_tab, localize("Info"), toolbox_page==1, &tabbutton1, 0))
 			toolbox_page = 1;
 	}
 
-	ui_draw_rect(&toolbox, vec4(0,0,0,0.15f), 0, 0);
+	RenderTools()->DrawUIRect(&toolbox, vec4(0,0,0,0.15f), 0, 0);
 	
-	ui_hsplit_t(&toolbox, 5.0f, 0, &toolbox);
+	toolbox.HSplitTop(5.0f, 0, &toolbox);
 	
 	if(toolbox_page == 0)
 		render_serverbrowser_filters(toolbox);
@@ -596,14 +596,14 @@ void MENUS::render_serverbrowser(RECT main_view)
 		render_serverbrowser_serverdetail(toolbox);
 
 	{
-		ui_hsplit_t(&status_toolbar, 5.0f, 0, &status_toolbar);
+		status_toolbar.HSplitTop(5.0f, 0, &status_toolbar);
 		
-		RECT button;
-		//ui_vsplit_r(&buttons, 20.0f, &buttons, &button);
-		ui_vsplit_r(&status_toolbar, 110.0f, &status_toolbar, &button);
-		ui_vmargin(&button, 2.0f, &button);
+		CUIRect button;
+		//buttons.VSplitRight(20.0f, &buttons, &button);
+		status_toolbar.VSplitRight(110.0f, &status_toolbar, &button);
+		button.VMargin(2.0f, &button);
 		static int refresh_button = 0;
-		if(ui_do_button(&refresh_button, localize("Refresh"), 0, &button, ui_draw_menu_button, 0))
+		if(DoButton_Menu(&refresh_button, localize("Refresh"), 0, &button))
 		{
 			if(config.ui_page == PAGE_INTERNET)
 				client_serverbrowse_refresh(BROWSETYPE_INTERNET);
@@ -618,31 +618,31 @@ void MENUS::render_serverbrowser(RECT main_view)
 			str_format(buf, sizeof(buf), localize("Teeworlds %s is out! Download it at www.teeworlds.com!"), client_latestversion());
 		else
 			str_format(buf, sizeof(buf), localize("Current version: %s"), GAME_VERSION);
-		ui_do_label(&status_toolbar, buf, 14.0f, -1);
+		UI()->DoLabel(&status_toolbar, buf, 14.0f, -1);
 	}
 	
 	// do the button box
 	{
 		
-		ui_vsplit_l(&button_box, 5.0f, 0, &button_box);
-		ui_vsplit_r(&button_box, 5.0f, &button_box, 0);
+		button_box.VSplitLeft(5.0f, 0, &button_box);
+		button_box.VSplitRight(5.0f, &button_box, 0);
 		
-		RECT button;
-		ui_hsplit_b(&button_box, button_height, &button_box, &button);
-		ui_vsplit_r(&button, 120.0f, 0, &button);
-		ui_vmargin(&button, 2.0f, &button);
-		//ui_vmargin(&button, 2.0f, &button);
+		CUIRect button;
+		button_box.HSplitBottom(button_height, &button_box, &button);
+		button.VSplitRight(120.0f, 0, &button);
+		button.VMargin(2.0f, &button);
+		//button.VMargin(2.0f, &button);
 		static int join_button = 0;
-		if(ui_do_button(&join_button, localize("Connect"), 0, &button, ui_draw_menu_button, 0) || enter_pressed)
+		if(DoButton_Menu(&join_button, localize("Connect"), 0, &button) || enter_pressed)
 		{
 			client_connect(config.ui_server_address);
 			enter_pressed = false;
 		}
 					
-		ui_hsplit_b(&button_box, 5.0f, &button_box, &button);
-		ui_hsplit_b(&button_box, 20.0f, &button_box, &button);
-		ui_do_edit_box(&config.ui_server_address, &button, config.ui_server_address, sizeof(config.ui_server_address), 14.0f);
-		ui_hsplit_b(&button_box, 20.0f, &button_box, &button);
-		ui_do_label(&button, localize("Host address"), 14.0f, -1);
+		button_box.HSplitBottom(5.0f, &button_box, &button);
+		button_box.HSplitBottom(20.0f, &button_box, &button);
+		DoEditBox(&config.ui_server_address, &button, config.ui_server_address, sizeof(config.ui_server_address), 14.0f);
+		button_box.HSplitBottom(20.0f, &button_box, &button);
+		UI()->DoLabel(&button, localize("Host address"), 14.0f, -1);
 	}
 }
diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp
index 594ee3df..07019d46 100644
--- a/src/game/client/components/menus_demo.cpp
+++ b/src/game/client/components/menus_demo.cpp
@@ -17,13 +17,14 @@
 
 #include "menus.hpp"
 
-void MENUS::ui_draw_demoplayer_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int MENUS::DoButton_DemoPlayer(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
-	ui_draw_rect(r, vec4(1,1,1, checked ? 0.10f : 0.5f)*button_color_mul(id), CORNER_ALL, 5.0f);
-	ui_do_label(r, text, 14.0f, 0);
+	RenderTools()->DrawUIRect(pRect, vec4(1,1,1, Checked ? 0.10f : 0.5f)*button_color_mul(pID), CUI::CORNER_ALL, 5.0f);
+	UI()->DoLabel(pRect, pText, 14.0f, 0);
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
 }
 
-void MENUS::render_demoplayer(RECT main_view)
+void MENUS::render_demoplayer(CUIRect main_view)
 {
 	const DEMOPLAYBACK_INFO *info = client_demoplayer_getinfo();
 	
@@ -37,20 +38,20 @@ void MENUS::render_demoplayer(RECT main_view)
 	else
 		total_height = seekbar_height+margins*2;
 	
-	ui_hsplit_b(&main_view, total_height, 0, &main_view);
-	ui_vsplit_l(&main_view, 250.0f, 0, &main_view);
-	ui_vsplit_r(&main_view, 250.0f, &main_view, 0);
+	main_view.HSplitBottom(total_height, 0, &main_view);
+	main_view.VSplitLeft(250.0f, 0, &main_view);
+	main_view.VSplitRight(250.0f, &main_view, 0);
 	
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_T, 10.0f);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_T, 10.0f);
 		
-	ui_margin(&main_view, 5.0f, &main_view);
+	main_view.Margin(5.0f, &main_view);
 	
-	RECT seekbar, buttonbar;
+	CUIRect seekbar, buttonbar;
 	
 	if(menu_active)
 	{
-		ui_hsplit_t(&main_view, seekbar_height, &seekbar, &buttonbar);
-		ui_hsplit_t(&buttonbar, margins, 0, &buttonbar);
+		main_view.HSplitTop(seekbar_height, &seekbar, &buttonbar);
+		buttonbar.HSplitTop(margins, 0, &buttonbar);
 	}
 	else
 		seekbar = main_view;
@@ -61,33 +62,33 @@ void MENUS::render_demoplayer(RECT main_view)
 		void *id = &seekbar_id;
 		char buffer[128];
 		
-		ui_draw_rect(&seekbar, vec4(0,0,0,0.5f), CORNER_ALL, 5.0f);
+		RenderTools()->DrawUIRect(&seekbar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f);
 		
 		int current_tick = info->current_tick - info->first_tick;
 		int total_ticks = info->last_tick - info->first_tick;
 		
 		float amount = current_tick/(float)total_ticks;
 		
-		RECT filledbar = seekbar;
+		CUIRect filledbar = seekbar;
 		filledbar.w = 10.0f + (filledbar.w-10.0f)*amount;
 		
-		ui_draw_rect(&filledbar, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f);
+		RenderTools()->DrawUIRect(&filledbar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f);
 		
 		str_format(buffer, sizeof(buffer), "%d:%02d / %d:%02d",
 			current_tick/SERVER_TICK_SPEED/60, (current_tick/SERVER_TICK_SPEED)%60,
 			total_ticks/SERVER_TICK_SPEED/60, (total_ticks/SERVER_TICK_SPEED)%60);
-		ui_do_label(&seekbar, buffer, seekbar.h*0.70f, 0);
+		UI()->DoLabel(&seekbar, buffer, seekbar.h*0.70f, 0);
 
 		// do the logic
-	    int inside = ui_mouse_inside(&seekbar);
+	    int inside = UI()->MouseInside(&seekbar);
 			
-		if(ui_active_item() == id)
+		if(UI()->ActiveItem() == id)
 		{
-			if(!ui_mouse_button(0))
-				ui_set_active_item(0);
+			if(!UI()->MouseButton(0))
+				UI()->SetActiveItem(0);
 			else
 			{
-				float amount = (ui_mouse_x()-seekbar.x)/(float)seekbar.w;
+				float amount = (UI()->MouseX()-seekbar.x)/(float)seekbar.w;
 				if(amount > 0 && amount < 1.0f)
 				{
 					gameclient.on_reset();
@@ -97,43 +98,43 @@ void MENUS::render_demoplayer(RECT main_view)
 				}
 			}
 		}
-		else if(ui_hot_item() == id)
+		else if(UI()->HotItem() == id)
 		{
-			if(ui_mouse_button(0))
-				ui_set_active_item(id);
+			if(UI()->MouseButton(0))
+				UI()->SetActiveItem(id);
 		}		
 		
 		if(inside)
-			ui_set_hot_item(id);
+			UI()->SetHotItem(id);
 	}	
 	
 
 	if(menu_active)
 	{
 		// do buttons
-		RECT button;
+		CUIRect button;
 
 		// pause button
-		ui_vsplit_l(&buttonbar, buttonbar_height, &button, &buttonbar);
+		buttonbar.VSplitLeft(buttonbar_height, &button, &buttonbar);
 		static int pause_button = 0;
-		if(ui_do_button(&pause_button, "| |", info->paused, &button, ui_draw_demoplayer_button, 0))
+		if(DoButton_DemoPlayer(&pause_button, "| |", info->paused, &button))
 			client_demoplayer_setpause(!info->paused);
 		
 		// play button
-		ui_vsplit_l(&buttonbar, margins, 0, &buttonbar);
-		ui_vsplit_l(&buttonbar, buttonbar_height, &button, &buttonbar);
+		buttonbar.VSplitLeft(margins, 0, &buttonbar);
+		buttonbar.VSplitLeft(buttonbar_height, &button, &buttonbar);
 		static int play_button = 0;
-		if(ui_do_button(&play_button, ">", !info->paused, &button, ui_draw_demoplayer_button, 0))
+		if(DoButton_DemoPlayer(&play_button, ">", !info->paused, &button))
 		{
 			client_demoplayer_setpause(0);
 			client_demoplayer_setspeed(1.0f);
 		}
 
 		// slowdown
-		ui_vsplit_l(&buttonbar, margins, 0, &buttonbar);
-		ui_vsplit_l(&buttonbar, buttonbar_height, &button, &buttonbar);
+		buttonbar.VSplitLeft(margins, 0, &buttonbar);
+		buttonbar.VSplitLeft(buttonbar_height, &button, &buttonbar);
 		static int slowdown_button = 0;
-		if(ui_do_button(&slowdown_button, "<<", 0, &button, ui_draw_demoplayer_button, 0))
+		if(DoButton_DemoPlayer(&slowdown_button, "<<", 0, &button))
 		{
 			if(info->speed > 4.0f) client_demoplayer_setspeed(4.0f);
 			else if(info->speed > 2.0f) client_demoplayer_setspeed(2.0f);
@@ -143,10 +144,10 @@ void MENUS::render_demoplayer(RECT main_view)
 		}
 		
 		// fastforward
-		ui_vsplit_l(&buttonbar, margins, 0, &buttonbar);
-		ui_vsplit_l(&buttonbar, buttonbar_height, &button, &buttonbar);
+		buttonbar.VSplitLeft(margins, 0, &buttonbar);
+		buttonbar.VSplitLeft(buttonbar_height, &button, &buttonbar);
 		static int fastforward_button = 0;
-		if(ui_do_button(&fastforward_button, ">>", 0, &button, ui_draw_demoplayer_button, 0))
+		if(DoButton_DemoPlayer(&fastforward_button, ">>", 0, &button))
 		{
 			if(info->speed < 0.5f) client_demoplayer_setspeed(0.5f);
 			else if(info->speed < 1.0f) client_demoplayer_setspeed(1.0f);
@@ -156,24 +157,24 @@ void MENUS::render_demoplayer(RECT main_view)
 		}
 
 		// speed meter
-		ui_vsplit_l(&buttonbar, margins*3, 0, &buttonbar);
+		buttonbar.VSplitLeft(margins*3, 0, &buttonbar);
 		char buffer[64];
 		if(info->speed >= 1.0f)
 			str_format(buffer, sizeof(buffer), "x%.0f", info->speed);
 		else
 			str_format(buffer, sizeof(buffer), "x%.1f", info->speed);
-		ui_do_label(&buttonbar, buffer, button.h*0.7f, -1);
+		UI()->DoLabel(&buttonbar, buffer, button.h*0.7f, -1);
 
 		// close button
-		ui_vsplit_r(&buttonbar, buttonbar_height*3, &buttonbar, &button);
+		buttonbar.VSplitRight(buttonbar_height*3, &buttonbar, &button);
 		static int exit_button = 0;
-		if(ui_do_button(&exit_button, localize("Close"), 0, &button, ui_draw_demoplayer_button, 0))
+		if(DoButton_DemoPlayer(&exit_button, localize("Close"), 0, &button))
 			client_disconnect();
 	}
 }
 
-static RECT listbox_originalview;
-static RECT listbox_view;
+static CUIRect listbox_originalview;
+static CUIRect listbox_view;
 static float listbox_rowheight;
 static int listbox_itemindex;
 static int listbox_selected_index;
@@ -181,27 +182,27 @@ static int listbox_new_selected;
 static int listbox_doneevents;
 static int listbox_numitems;
 
-void MENUS::ui_do_listbox_start(void *id, const RECT *rect, float row_height, const char *title, int num_items, int selected_index)
+void MENUS::ui_do_listbox_start(void *id, const CUIRect *rect, float row_height, const char *title, int num_items, int selected_index)
 {
-	RECT scroll, row;
-	RECT view = *rect;
-	RECT header, footer;
+	CUIRect scroll, row;
+	CUIRect view = *rect;
+	CUIRect header, footer;
 	
 	// draw header
-	ui_hsplit_t(&view, listheader_height, &header, &view);
-	ui_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); 
-	ui_do_label(&header, title, header.h*fontmod_height, 0);
+	view.HSplitTop(listheader_height, &header, &view);
+	RenderTools()->DrawUIRect(&header, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f); 
+	UI()->DoLabel(&header, title, header.h*fontmod_height, 0);
 
 	// draw footers
-	ui_hsplit_b(&view, listheader_height, &view, &footer);
-	ui_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); 
-	ui_vsplit_l(&footer, 10.0f, 0, &footer);
+	view.HSplitBottom(listheader_height, &view, &footer);
+	RenderTools()->DrawUIRect(&footer, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f); 
+	footer.VSplitLeft(10.0f, 0, &footer);
 
 	// background
-	ui_draw_rect(&view, vec4(0,0,0,0.15f), 0, 0);
+	RenderTools()->DrawUIRect(&view, vec4(0,0,0,0.15f), 0, 0);
 
 	// prepare the scroll
-	ui_vsplit_r(&view, 15, &view, &scroll);
+	view.VSplitRight(15, &view, &scroll);
 
 	// setup the variables	
 	listbox_originalview = view;
@@ -215,7 +216,7 @@ void MENUS::ui_do_listbox_start(void *id, const RECT *rect, float row_height, co
 
 
 	// do the scrollbar
-	ui_hsplit_t(&view, listbox_rowheight, &row, 0);
+	view.HSplitTop(listbox_rowheight, &row, 0);
 	
 	int num_viewable = (int)(listbox_originalview.h/row.h) + 1;
 	int num = num_items-num_viewable+1;
@@ -223,8 +224,8 @@ void MENUS::ui_do_listbox_start(void *id, const RECT *rect, float row_height, co
 		num = 0;
 		
 	static float scrollvalue = 0;
-	ui_hmargin(&scroll, 5.0f, &scroll);
-	scrollvalue = ui_do_scrollbar_v(id, &scroll, scrollvalue);
+	scroll.HMargin(5.0f, &scroll);
+	scrollvalue = DoScrollbarV(id, &scroll, scrollvalue);
 
 	int start = (int)(num*scrollvalue);
 	if(start < 0)
@@ -232,19 +233,62 @@ void MENUS::ui_do_listbox_start(void *id, const RECT *rect, float row_height, co
 	
 	// the list
 	listbox_view = listbox_originalview;
-	ui_vmargin(&listbox_view, 5.0f, &listbox_view);
-	ui_clip_enable(&listbox_view);
+	listbox_view.VMargin(5.0f, &listbox_view);
+	UI()->ClipEnable(&listbox_view);
 	listbox_view.y -= scrollvalue*num*row.h;	
 }
 
-MENUS::LISTBOXITEM MENUS::ui_do_listbox_nextitem(void *id)
+MENUS::LISTBOXITEM MENUS::ui_do_listbox_nextrow()
 {
-	RECT row;
 	LISTBOXITEM item = {0};
-	ui_hsplit_t(&listbox_view, listbox_rowheight /*-2.0f*/, &row, &listbox_view);
-	//ui_hsplit_t(&listbox_view, 2.0f, 0, &listbox_view);
+	listbox_view.HSplitTop(listbox_rowheight /*-2.0f*/, &item.rect, &listbox_view);
+	item.visible = 1;
+	//item.rect = row;
+	
+	item.hitrect = item.rect;
+	
+	//CUIRect select_hit_box = item.rect;
+
+	if(listbox_selected_index == listbox_itemindex)
+		item.selected = 1;
+	
+	// make sure that only those in view can be selected
+	if(item.rect.y+item.rect.h > listbox_originalview.y)
+	{
+		
+		if(item.hitrect.y < item.hitrect.y) // clip the selection
+		{
+			item.hitrect.h -= listbox_originalview.y-item.hitrect.y;
+			item.hitrect.y = listbox_originalview.y;
+		}
+		
+	}
+	else
+		item.visible = 0;
 
-	RECT select_hit_box = row;
+	// check if we need to do more
+	if(item.rect.y > listbox_originalview.y+listbox_originalview.h)
+		item.visible = 0;
+		
+	listbox_itemindex++;
+	return item;
+}
+
+MENUS::LISTBOXITEM MENUS::ui_do_listbox_nextitem(void *id)
+{
+	int this_itemindex = listbox_itemindex;
+	
+	LISTBOXITEM item = ui_do_listbox_nextrow();
+
+	if(UI()->DoButtonLogic(id, "", listbox_selected_index == listbox_itemindex, &item.hitrect))
+		listbox_new_selected = listbox_itemindex;
+	
+	//CUIRect row;
+	//LISTBOXITEM item = {0};
+	//listbox_view.HSplitTop(listbox_rowheight /*-2.0f*/, &row, &listbox_view);
+	//listbox_view.HSplitTop(2.0f, 0, &listbox_view);
+	/*
+	CUIRect select_hit_box = row;
 
 	item.visible = 1;
 	if(listbox_selected_index == listbox_itemindex)
@@ -260,19 +304,17 @@ MENUS::LISTBOXITEM MENUS::ui_do_listbox_nextitem(void *id)
 			select_hit_box.y = listbox_originalview.y;
 		}
 		
-		if(ui_do_button(id, "", listbox_selected_index==listbox_itemindex, &select_hit_box, 0, 0))
+		if(UI()->DoButton(id, "", listbox_selected_index==listbox_itemindex, &select_hit_box, 0, 0))
 			listbox_new_selected = listbox_itemindex;
 	}
 	else
 		item.visible = 0;
 	
 	item.rect = row;
+	*/
 	
-	// check if we need to do more
-	if(row.y > listbox_originalview.y+listbox_originalview.h)
-		item.visible = 0;
 
-	if(listbox_selected_index==listbox_itemindex)
+	if(listbox_selected_index == this_itemindex)
 	{
 		if(!listbox_doneevents)
 		{
@@ -294,21 +336,18 @@ MENUS::LISTBOXITEM MENUS::ui_do_listbox_nextitem(void *id)
 		}
 		
 		//selected_index = i;
-		RECT r = row;
-		ui_margin(&r, 1.5f, &r);
-		ui_draw_rect(&r, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f);
+		CUIRect r = item.rect;
+		r.Margin(1.5f, &r);
+		RenderTools()->DrawUIRect(&r, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f);
 	}	
 
-	listbox_itemindex++;
-
-	ui_vmargin(&item.rect, 5.0f, &item.rect);
-
+	//listbox_itemindex++;
 	return item;
 }
 
 int MENUS::ui_do_listbox_end()
 {
-	ui_clip_disable();
+	UI()->ClipDisable();
 	return listbox_new_selected;
 }
 
@@ -346,7 +385,7 @@ void MENUS::demolist_populate()
 }
 
 
-void MENUS::render_demolist(RECT main_view)
+void MENUS::render_demolist(CUIRect main_view)
 {
 	static int inited = 0;
 	if(!inited)
@@ -354,12 +393,12 @@ void MENUS::render_demolist(RECT main_view)
 	inited = 1;
 	
 	// render background
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f);
-	ui_margin(&main_view, 10.0f, &main_view);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_ALL, 10.0f);
+	main_view.Margin(10.0f, &main_view);
 	
-	RECT buttonbar;
-	ui_hsplit_b(&main_view, button_height+5.0f, &main_view, &buttonbar);
-	ui_hsplit_t(&buttonbar, 5.0f, 0, &buttonbar);
+	CUIRect buttonbar;
+	main_view.HSplitBottom(button_height+5.0f, &main_view, &buttonbar);
+	buttonbar.HSplitTop(5.0f, 0, &buttonbar);
 	
 	static int selected_item = -1;
 	static int demolist_id = 0;
@@ -370,23 +409,23 @@ void MENUS::render_demolist(RECT main_view)
 	{
 		LISTBOXITEM item = ui_do_listbox_nextitem((void*)(&r.front()));
 		if(item.visible)
-			ui_do_label(&item.rect, r.front().name, item.rect.h*fontmod_height, -1);
+			UI()->DoLabel(&item.rect, r.front().name, item.rect.h*fontmod_height, -1);
 	}
 	selected_item = ui_do_listbox_end();
 	
-	RECT refresh_rect, play_rect;
-	ui_vsplit_r(&buttonbar, 250.0f, &buttonbar, &refresh_rect);
-	ui_vsplit_r(&refresh_rect, 130.0f, &refresh_rect, &play_rect);
-	ui_vsplit_r(&play_rect, 120.0f, 0x0, &play_rect);
+	CUIRect refresh_rect, play_rect;
+	buttonbar.VSplitRight(250.0f, &buttonbar, &refresh_rect);
+	refresh_rect.VSplitRight(130.0f, &refresh_rect, &play_rect);
+	play_rect.VSplitRight(120.0f, 0x0, &play_rect);
 	
 	static int refresh_button = 0;
-	if(ui_do_button(&refresh_button, localize("Refresh"), 0, &refresh_rect, ui_draw_menu_button, 0))
+	if(DoButton_Menu(&refresh_button, localize("Refresh"), 0, &refresh_rect))
 	{
 		demolist_populate();
 	}	
 	
 	static int play_button = 0;
-	if(ui_do_button(&play_button, localize("Play"), 0, &play_rect, ui_draw_menu_button, 0))
+	if(DoButton_Menu(&play_button, localize("Play"), 0, &play_rect))
 	{
 		if(selected_item >= 0 && selected_item < demos.size())
 		{
diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp
index 83673631..d31a15bd 100644
--- a/src/game/client/components/menus_ingame.cpp
+++ b/src/game/client/components/menus_ingame.cpp
@@ -17,30 +17,30 @@
 #include "motd.hpp"
 #include "voting.hpp"
 
-void MENUS::render_game(RECT main_view)
+void MENUS::render_game(CUIRect main_view)
 {
-	RECT button;
-	//RECT votearea;
-	ui_hsplit_t(&main_view, 45.0f, &main_view, 0);
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f);
-
-	ui_hsplit_t(&main_view, 10.0f, 0, &main_view);
-	ui_hsplit_t(&main_view, 25.0f, &main_view, 0);
-	ui_vmargin(&main_view, 10.0f, &main_view);
+	CUIRect button;
+	//CUIRect votearea;
+	main_view.HSplitTop(45.0f, &main_view, 0);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_ALL, 10.0f);
+
+	main_view.HSplitTop(10.0f, 0, &main_view);
+	main_view.HSplitTop(25.0f, &main_view, 0);
+	main_view.VMargin(10.0f, &main_view);
 	
-	ui_vsplit_r(&main_view, 120.0f, &main_view, &button);
+	main_view.VSplitRight(120.0f, &main_view, &button);
 	static int disconnect_button = 0;
-	if(ui_do_button(&disconnect_button, localize("Disconnect"), 0, &button, ui_draw_menu_button, 0))
+	if(DoButton_Menu(&disconnect_button, localize("Disconnect"), 0, &button))
 		client_disconnect();
 
 	if(gameclient.snap.local_info && gameclient.snap.gameobj)
 	{
 		if(gameclient.snap.local_info->team != -1)
 		{
-			ui_vsplit_l(&main_view, 10.0f, &button, &main_view);
-			ui_vsplit_l(&main_view, 120.0f, &button, &main_view);
+			main_view.VSplitLeft(10.0f, &button, &main_view);
+			main_view.VSplitLeft(120.0f, &button, &main_view);
 			static int spectate_button = 0;
-			if(ui_do_button(&spectate_button, localize("Spectate"), 0, &button, ui_draw_menu_button, 0))
+			if(DoButton_Menu(&spectate_button, localize("Spectate"), 0, &button))
 			{
 				gameclient.send_switch_team(-1);
 				set_active(false);
@@ -51,10 +51,10 @@ void MENUS::render_game(RECT main_view)
 		{
 			if(gameclient.snap.local_info->team != 0)
 			{
-				ui_vsplit_l(&main_view, 10.0f, &button, &main_view);
-				ui_vsplit_l(&main_view, 120.0f, &button, &main_view);
+				main_view.VSplitLeft(10.0f, &button, &main_view);
+				main_view.VSplitLeft(120.0f, &button, &main_view);
 				static int spectate_button = 0;
-				if(ui_do_button(&spectate_button, localize("Join red"), 0, &button, ui_draw_menu_button, 0))
+				if(DoButton_Menu(&spectate_button, localize("Join red"), 0, &button))
 				{
 					gameclient.send_switch_team(0);
 					set_active(false);
@@ -63,10 +63,10 @@ void MENUS::render_game(RECT main_view)
 
 			if(gameclient.snap.local_info->team != 1)
 			{
-				ui_vsplit_l(&main_view, 10.0f, &button, &main_view);
-				ui_vsplit_l(&main_view, 120.0f, &button, &main_view);
+				main_view.VSplitLeft(10.0f, &button, &main_view);
+				main_view.VSplitLeft(120.0f, &button, &main_view);
 				static int spectate_button = 0;
-				if(ui_do_button(&spectate_button, localize("Join blue"), 0, &button, ui_draw_menu_button, 0))
+				if(DoButton_Menu(&spectate_button, localize("Join blue"), 0, &button))
 				{
 					gameclient.send_switch_team(1);
 					set_active(false);
@@ -77,10 +77,10 @@ void MENUS::render_game(RECT main_view)
 		{
 			if(gameclient.snap.local_info->team != 0)
 			{
-				ui_vsplit_l(&main_view, 10.0f, &button, &main_view);
-				ui_vsplit_l(&main_view, 120.0f, &button, &main_view);
+				main_view.VSplitLeft(10.0f, &button, &main_view);
+				main_view.VSplitLeft(120.0f, &button, &main_view);
 				static int spectate_button = 0;
-				if(ui_do_button(&spectate_button, localize("Join game"), 0, &button, ui_draw_menu_button, 0))
+				if(DoButton_Menu(&spectate_button, localize("Join game"), 0, &button))
 				{
 					gameclient.send_switch_team(0);
 					set_active(false);
@@ -90,58 +90,58 @@ void MENUS::render_game(RECT main_view)
 	}
 	
 	/*
-	RECT bars;
-	ui_hsplit_t(&votearea, 10.0f, 0, &votearea);
-	ui_hsplit_t(&votearea, 25.0f + 10.0f*3 + 25.0f, &votearea, &bars);
+	CUIRect bars;
+	votearea.HSplitTop(10.0f, 0, &votearea);
+	votearea.HSplitTop(25.0f + 10.0f*3 + 25.0f, &votearea, &bars);
 
-	ui_draw_rect(&votearea, color_tabbar_active, CORNER_ALL, 10.0f);
+	RenderTools()->DrawUIRect(&votearea, color_tabbar_active, CUI::CORNER_ALL, 10.0f);
 
-	ui_vmargin(&votearea, 20.0f, &votearea);
-	ui_hmargin(&votearea, 10.0f, &votearea);
+	votearea.VMargin(20.0f, &votearea);
+	votearea.HMargin(10.0f, &votearea);
 
-	ui_hsplit_b(&votearea, 35.0f, &votearea, &bars);
+	votearea.HSplitBottom(35.0f, &votearea, &bars);
 
 	if(gameclient.voting->is_voting())
 	{
 		// do yes button
-		ui_vsplit_l(&votearea, 50.0f, &button, &votearea);
+		votearea.VSplitLeft(50.0f, &button, &votearea);
 		static int yes_button = 0;
-		if(ui_do_button(&yes_button, "Yes", 0, &button, ui_draw_menu_button, 0))
+		if(UI()->DoButton(&yes_button, "Yes", 0, &button, ui_draw_menu_button, 0))
 			gameclient.voting->vote(1);
 
 		// do no button
-		ui_vsplit_l(&votearea, 5.0f, 0, &votearea);
-		ui_vsplit_l(&votearea, 50.0f, &button, &votearea);
+		votearea.VSplitLeft(5.0f, 0, &votearea);
+		votearea.VSplitLeft(50.0f, &button, &votearea);
 		static int no_button = 0;
-		if(ui_do_button(&no_button, "No", 0, &button, ui_draw_menu_button, 0))
+		if(UI()->DoButton(&no_button, "No", 0, &button, ui_draw_menu_button, 0))
 			gameclient.voting->vote(-1);
 		
 		// do time left
-		ui_vsplit_r(&votearea, 50.0f, &votearea, &button);
+		votearea.VSplitRight(50.0f, &votearea, &button);
 		char buf[256];
 		str_format(buf, sizeof(buf), "%d", gameclient.voting->seconds_left());
-		ui_do_label(&button, buf, 24.0f, 0);
+		UI()->DoLabel(&button, buf, 24.0f, 0);
 
 		// do description and command
-		ui_vsplit_l(&votearea, 5.0f, 0, &votearea);
-		ui_do_label(&votearea, gameclient.voting->vote_description(), 14.0f, -1);
-		ui_hsplit_t(&votearea, 16.0f, 0, &votearea);
-		ui_do_label(&votearea, gameclient.voting->vote_command(), 10.0f, -1);
+		votearea.VSplitLeft(5.0f, 0, &votearea);
+		UI()->DoLabel(&votearea, gameclient.voting->vote_description(), 14.0f, -1);
+		votearea.HSplitTop(16.0f, 0, &votearea);
+		UI()->DoLabel(&votearea, gameclient.voting->vote_command(), 10.0f, -1);
 
 		// do bars
-		ui_hsplit_t(&bars, 10.0f, 0, &bars);
-		ui_hmargin(&bars, 5.0f, &bars);
+		bars.HSplitTop(10.0f, 0, &bars);
+		bars.HMargin(5.0f, &bars);
 		
 		gameclient.voting->render_bars(bars, true);
 
 	}		
 	else
 	{
-		ui_do_label(&votearea, "No vote in progress", 18.0f, -1);
+		UI()->DoLabel(&votearea, "No vote in progress", 18.0f, -1);
 	}*/
 }
 
-void MENUS::render_serverinfo(RECT main_view)
+void MENUS::render_serverinfo(CUIRect main_view)
 {
 	// fetch server info
 	SERVER_INFO current_server_info;
@@ -164,9 +164,9 @@ void MENUS::render_serverinfo(RECT main_view)
 	}
 
 	// render background
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_ALL, 10.0f);
 	
-	RECT view, serverinfo, gameinfo, motd;
+	CUIRect view, serverinfo, gameinfo, motd;
 	
 	float x = 0.0f;
 	float y = 0.0f;
@@ -174,14 +174,14 @@ void MENUS::render_serverinfo(RECT main_view)
 	char buf[1024];
 	
 	// set view to use for all sub-modules
-	ui_margin(&main_view, 10.0f, &view);
+	main_view.Margin(10.0f, &view);
 	
 	/* serverinfo */
-	ui_hsplit_t(&view, view.h/2-5.0f, &serverinfo, &motd);
-	ui_vsplit_l(&serverinfo, view.w/2-5.0f, &serverinfo, &gameinfo);
-	ui_draw_rect(&serverinfo, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
+	view.HSplitTop(view.h/2-5.0f, &serverinfo, &motd);
+	serverinfo.VSplitLeft(view.w/2-5.0f, &serverinfo, &gameinfo);
+	RenderTools()->DrawUIRect(&serverinfo, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
 	
-	ui_margin(&serverinfo, 5.0f, &serverinfo);
+	serverinfo.Margin(5.0f, &serverinfo);
 	
 	x = 5.0f;
 	y = 0.0f;
@@ -208,11 +208,11 @@ void MENUS::render_serverinfo(RECT main_view)
 	gfx_text(0, serverinfo.x+x, serverinfo.y+y, 20, buf, 250);
 	
 	{
-		RECT button;
+		CUIRect button;
 		int is_favorite = client_serverbrowse_isfavorite(current_server_info.netaddr);
-		ui_hsplit_b(&serverinfo, 20.0f, &serverinfo, &button);
+		serverinfo.HSplitBottom(20.0f, &serverinfo, &button);
 		static int add_fav_button = 0;
-		if (ui_do_button(&add_fav_button, localize("Favorite"), is_favorite, &button, ui_draw_checkbox, 0))
+		if(DoButton_CheckBox(&add_fav_button, localize("Favorite"), is_favorite, &button))
 		{
 			if(is_favorite)
 				client_serverbrowse_removefavorite(current_server_info.netaddr);
@@ -222,10 +222,10 @@ void MENUS::render_serverinfo(RECT main_view)
 	}
 	
 	/* gameinfo */
-	ui_vsplit_l(&gameinfo, 10.0f, 0x0, &gameinfo);
-	ui_draw_rect(&gameinfo, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
+	gameinfo.VSplitLeft(10.0f, 0x0, &gameinfo);
+	RenderTools()->DrawUIRect(&gameinfo, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
 	
-	ui_margin(&gameinfo, 5.0f, &gameinfo);
+	gameinfo.Margin(5.0f, &gameinfo);
 	
 	x = 5.0f;
 	y = 0.0f;
@@ -253,9 +253,9 @@ void MENUS::render_serverinfo(RECT main_view)
 	gfx_text(0, gameinfo.x+x, gameinfo.y+y, 20, buf, 250);
 	
 	/* motd */
-	ui_hsplit_t(&motd, 10.0f, 0, &motd);
-	ui_draw_rect(&motd, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
-	ui_margin(&motd, 5.0f, &motd);
+	motd.HSplitTop(10.0f, 0, &motd);
+	RenderTools()->DrawUIRect(&motd, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
+	motd.Margin(5.0f, &motd);
 	y = 0.0f;
 	x = 5.0f;
 	gfx_text(0, motd.x+x, motd.y+y, 32, localize("MOTD"), -1);
@@ -268,14 +268,14 @@ static const char *format_command(const char *cmd)
 	return cmd;
 }
 
-void MENUS::render_servercontrol_server(RECT main_view)
+void MENUS::render_servercontrol_server(CUIRect main_view)
 {
 	int num_options = 0;
 	for(VOTING::VOTEOPTION *option = gameclient.voting->first; option; option = option->next)
 		num_options++;
 
 	static int votelist = 0;
-	RECT list = main_view;
+	CUIRect list = main_view;
 	ui_do_listbox_start(&votelist, &list, 24.0f, localize("Settings"), num_options, callvote_selectedoption);
 	
 	for(VOTING::VOTEOPTION *option = gameclient.voting->first; option; option = option->next)
@@ -283,62 +283,62 @@ void MENUS::render_servercontrol_server(RECT main_view)
 		LISTBOXITEM item = ui_do_listbox_nextitem(option);
 		
 		if(item.visible)
-			ui_do_label(&item.rect, format_command(option->command), 16.0f, -1);
+			UI()->DoLabel(&item.rect, format_command(option->command), 16.0f, -1);
 	}
 	
 	callvote_selectedoption = ui_do_listbox_end();
 }
 
-void MENUS::render_servercontrol_kick(RECT main_view)
+void MENUS::render_servercontrol_kick(CUIRect main_view)
 {
 	// draw header
-	RECT header, footer;
-	ui_hsplit_t(&main_view, 20, &header, &main_view);
-	ui_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); 
-	ui_do_label(&header, localize("Players"), 18.0f, 0);
+	CUIRect header, footer;
+	main_view.HSplitTop(20, &header, &main_view);
+	RenderTools()->DrawUIRect(&header, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f); 
+	UI()->DoLabel(&header, localize("Players"), 18.0f, 0);
 
 	// draw footers	
-	ui_hsplit_b(&main_view, 20, &main_view, &footer);
-	ui_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); 
-	ui_vsplit_l(&footer, 10.0f, 0, &footer);
+	main_view.HSplitBottom(20, &main_view, &footer);
+	RenderTools()->DrawUIRect(&footer, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f); 
+	footer.VSplitLeft(10.0f, 0, &footer);
 
 	// players
-	ui_draw_rect(&main_view, vec4(0,0,0,0.15f), 0, 0);
-	RECT list = main_view;
+	RenderTools()->DrawUIRect(&main_view, vec4(0,0,0,0.15f), 0, 0);
+	CUIRect list = main_view;
 	for(int i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(!gameclient.snap.player_infos[i])
 			continue;
 
-		RECT button;
-		ui_hsplit_t(&list, button_height, &button, &list);
+		CUIRect button;
+		list.HSplitTop(button_height, &button, &list);
 		
-		if(ui_do_button((char *)&gameclient.snap+i, "", callvote_selectedplayer == i, &button, ui_draw_list_row, 0))
+		if(DoButton_ListRow((char *)&gameclient.snap+i, "", callvote_selectedplayer == i, &button))
 			callvote_selectedplayer = i;
 
 		TEE_RENDER_INFO info = gameclient.clients[i].render_info;
 		info.size = button.h;
-		render_tee(ANIMSTATE::get_idle(), &info, EMOTE_NORMAL, vec2(1,0), vec2(button.x+button.h/2, button.y+button.h/2));
+		RenderTools()->RenderTee(ANIMSTATE::get_idle(), &info, EMOTE_NORMAL, vec2(1,0), vec2(button.x+button.h/2, button.y+button.h/2));
 
 		button.x += button.h;
-		ui_do_label(&button, gameclient.clients[i].name, 18.0f, -1);
+		UI()->DoLabel(&button, gameclient.clients[i].name, 18.0f, -1);
 	}
 }
 
-void MENUS::render_servercontrol(RECT main_view)
+void MENUS::render_servercontrol(CUIRect main_view)
 {
 	static int control_page = 0;
 	
 	// render background
-	RECT temp, tabbar;
-	ui_vsplit_r(&main_view, 120.0f, &main_view, &tabbar);
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_B|CORNER_TL, 10.0f);
-	ui_hsplit_t(&tabbar, 50.0f, &temp, &tabbar);
-	ui_draw_rect(&temp, color_tabbar_active, CORNER_R, 10.0f);
+	CUIRect temp, tabbar;
+	main_view.VSplitRight(120.0f, &main_view, &tabbar);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_B|CUI::CORNER_TL, 10.0f);
+	tabbar.HSplitTop(50.0f, &temp, &tabbar);
+	RenderTools()->DrawUIRect(&temp, color_tabbar_active, CUI::CORNER_R, 10.0f);
 	
-	ui_hsplit_t(&main_view, 10.0f, 0, &main_view);
+	main_view.HSplitTop(10.0f, 0, &main_view);
 	
-	RECT button;
+	CUIRect button;
 	
 	const char *tabs[] = {
 		localize("Settings"),
@@ -347,9 +347,9 @@ void MENUS::render_servercontrol(RECT main_view)
 	
 	for(int i = 0; i < num_tabs; i++)
 	{
-		ui_hsplit_t(&tabbar, 10, &button, &tabbar);
-		ui_hsplit_t(&tabbar, 26, &button, &tabbar);
-		if(ui_do_button(tabs[i], tabs[i], control_page == i, &button, ui_draw_settings_tab_button, 0))
+		tabbar.HSplitTop(10, &button, &tabbar);
+		tabbar.HSplitTop(26, &button, &tabbar);
+		if(DoButton_SettingsTab(tabs[i], tabs[i], control_page == i, &button))
 		{
 			control_page = i;
 			callvote_selectedplayer = -1;
@@ -357,10 +357,10 @@ void MENUS::render_servercontrol(RECT main_view)
 		}
 	}
 		
-	ui_margin(&main_view, 10.0f, &main_view);
-	RECT bottom;
-	ui_hsplit_b(&main_view, button_height + 5*2, &main_view, &bottom);
-	ui_hmargin(&bottom, 5.0f, &bottom);
+	main_view.Margin(10.0f, &main_view);
+	CUIRect bottom;
+	main_view.HSplitBottom(button_height + 5*2, &main_view, &bottom);
+	bottom.HMargin(5.0f, &bottom);
 	
 	// render page		
 	if(control_page == 0)
@@ -370,11 +370,11 @@ void MENUS::render_servercontrol(RECT main_view)
 		
 
 	{
-		RECT button;
-		ui_vsplit_r(&bottom, 120.0f, &bottom, &button);
+		CUIRect button;
+		bottom.VSplitRight(120.0f, &bottom, &button);
 		
 		static int callvote_button = 0;
-		if(ui_do_button(&callvote_button, localize("Call vote"), 0, &button, ui_draw_menu_button, 0))
+		if(DoButton_Menu(&callvote_button, localize("Call vote"), 0, &button))
 		{
 			if(control_page == 0)
 			{
diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp
index 86325ab9..05b4d047 100644
--- a/src/game/client/components/menus_settings.cpp
+++ b/src/game/client/components/menus_settings.cpp
@@ -5,6 +5,7 @@
 #include <stdlib.h> // atoi
 
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
@@ -43,33 +44,31 @@ bool MENUS_KEYBINDER::on_input(INPUT_EVENT e)
 	return false;
 }
 
-void MENUS::render_settings_player(RECT main_view)
+void MENUS::render_settings_player(CUIRect main_view)
 {
-	RECT button;
-	RECT skinselection;
-	ui_vsplit_l(&main_view, 300.0f, &main_view, &skinselection);
-
-
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
+	CUIRect button;
+	CUIRect othersection;
+	main_view.VSplitLeft(300.0f, &main_view, &othersection);
+	main_view.HSplitTop(20.0f, &button, &main_view);
 
 	// render settings
 	{	
 		char buf[128];
 		
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
+		main_view.HSplitTop(20.0f, &button, &main_view);
 		str_format(buf, sizeof(buf), "%s:", localize("Name"));
-		ui_do_label(&button, buf, 14.0, -1);
-		ui_vsplit_l(&button, 80.0f, 0, &button);
-		ui_vsplit_l(&button, 180.0f, &button, 0);
-		if(ui_do_edit_box(config.player_name, &button, config.player_name, sizeof(config.player_name), 14.0f))
+		UI()->DoLabel(&button, buf, 14.0, -1);
+		button.VSplitLeft(80.0f, 0, &button);
+		button.VSplitLeft(180.0f, &button, 0);
+		if(DoEditBox(config.player_name, &button, config.player_name, sizeof(config.player_name), 14.0f))
 			need_sendinfo = true;
 
 		// extra spacing
-		ui_hsplit_t(&main_view, 10.0f, 0, &main_view);
+		main_view.HSplitTop(10.0f, 0, &main_view);
 
 		static int dynamic_camera_button = 0;
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-		if(ui_do_button(&dynamic_camera_button, localize("Dynamic Camera"), config.cl_mouse_deadzone != 0, &button, ui_draw_checkbox, 0))
+		main_view.HSplitTop(20.0f, &button, &main_view);
+		if(DoButton_CheckBox(&dynamic_camera_button, localize("Dynamic Camera"), config.cl_mouse_deadzone != 0, &button))
 		{
 			
 			if(config.cl_mouse_deadzone)
@@ -86,26 +85,26 @@ void MENUS::render_settings_player(RECT main_view)
 			}
 		}
 
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-		if (ui_do_button(&config.cl_autoswitch_weapons, localize("Switch weapon on pickup"), config.cl_autoswitch_weapons, &button, ui_draw_checkbox, 0))
+		main_view.HSplitTop(20.0f, &button, &main_view);
+		if(DoButton_CheckBox(&config.cl_autoswitch_weapons, localize("Switch weapon on pickup"), config.cl_autoswitch_weapons, &button))
 			config.cl_autoswitch_weapons ^= 1;
 			
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-		if (ui_do_button(&config.cl_nameplates, localize("Show name plates"), config.cl_nameplates, &button, ui_draw_checkbox, 0))
+		main_view.HSplitTop(20.0f, &button, &main_view);
+		if(DoButton_CheckBox(&config.cl_nameplates, localize("Show name plates"), config.cl_nameplates, &button))
 			config.cl_nameplates ^= 1;
 
 		//if(config.cl_nameplates)
 		{
-			ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-			ui_vsplit_l(&button, 15.0f, 0, &button);
-			if (ui_do_button(&config.cl_nameplates_always, localize("Always show name plates"), config.cl_nameplates_always, &button, ui_draw_checkbox, 0))
+			main_view.HSplitTop(20.0f, &button, &main_view);
+			button.VSplitLeft(15.0f, 0, &button);
+			if(DoButton_CheckBox(&config.cl_nameplates_always, localize("Always show name plates"), config.cl_nameplates_always, &button))
 				config.cl_nameplates_always ^= 1;
 		}
 			
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
+		main_view.HSplitTop(20.0f, &button, &main_view);
 		
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-		if (ui_do_button(&config.player_color_body, localize("Custom colors"), config.player_use_custom_color, &button, ui_draw_checkbox, 0))
+		main_view.HSplitTop(20.0f, &button, &main_view);
+		if(DoButton_CheckBox(&config.player_color_body, localize("Custom colors"), config.player_use_custom_color, &button))
 		{
 			config.player_use_custom_color = config.player_use_custom_color?0:1;
 			need_sendinfo = true;
@@ -129,27 +128,27 @@ void MENUS::render_settings_player(RECT main_view)
 				
 			for(int i = 0; i < 2; i++)
 			{
-				RECT text;
-				ui_hsplit_t(&main_view, 20.0f, &text, &main_view);
-				ui_vsplit_l(&text, 15.0f, 0, &text);
-				ui_do_label(&text, parts[i], 14.0f, -1);
+				CUIRect text;
+				main_view.HSplitTop(20.0f, &text, &main_view);
+				text.VSplitLeft(15.0f, 0, &text);
+				UI()->DoLabel(&text, parts[i], 14.0f, -1);
 				
 				int prevcolor = *colors[i];
 				int color = 0;
 				for(int s = 0; s < 3; s++)
 				{
-					RECT text;
-					ui_hsplit_t(&main_view, 19.0f, &button, &main_view);
-					ui_vsplit_l(&button, 30.0f, 0, &button);
-					ui_vsplit_l(&button, 70.0f, &text, &button);
-					ui_vsplit_r(&button, 5.0f, &button, 0);
-					ui_hsplit_t(&button, 4.0f, 0, &button);
+					CUIRect text;
+					main_view.HSplitTop(19.0f, &button, &main_view);
+					button.VSplitLeft(30.0f, 0, &button);
+					button.VSplitLeft(70.0f, &text, &button);
+					button.VSplitRight(5.0f, &button, 0);
+					button.HSplitTop(4.0f, 0, &button);
 					
 					float k = ((prevcolor>>((2-s)*8))&0xff)  / 255.0f;
-					k = ui_do_scrollbar_h(&color_slider[i][s], &button, k);
+					k = DoScrollbarH(&color_slider[i][s], &button, k);
 					color <<= 8;
 					color += clamp((int)(k*255), 0, 255);
-					ui_do_label(&text, labels[s], 15.0f, -1);
+					UI()->DoLabel(&text, labels[s], 15.0f, -1);
 					 
 				}
 		
@@ -157,35 +156,103 @@ void MENUS::render_settings_player(RECT main_view)
 					need_sendinfo = true;
 					
 				*colors[i] = color;
-				ui_hsplit_t(&main_view, 5.0f, 0, &main_view);
+				main_view.HSplitTop(5.0f, 0, &main_view);
 			}
 		}
+		
+		// render skinselector
+		static int skinselector_id = 0;		
+		ui_do_listbox_start(&skinselector_id, &main_view, 50, localize("Skins"), (gameclient.skins->num()+3)/4, 0);
+
+		for(int skin_id = 0; skin_id < gameclient.skins->num(); )
+		{
+			LISTBOXITEM item = ui_do_listbox_nextrow();
+			CUIRect boxes[4];
+			CUIRect first_half, second_half;
+			item.rect.VSplitMid(&first_half, &second_half);
+			first_half.VSplitMid(&boxes[0], &boxes[1]);
+			second_half.VSplitMid(&boxes[2], &boxes[3]);
+			
+			for(int i = 0; i < 4 && skin_id < gameclient.skins->num(); i++, skin_id++)
+			{
+				//CUIRect r = item.
+				const SKINS::SKIN *s = gameclient.skins->get(skin_id);
+
+				TEE_RENDER_INFO info;
+				info.texture = s->org_texture;
+				info.color_body = vec4(1,1,1,1);
+				info.color_feet = vec4(1,1,1,1);
+				if(config.player_use_custom_color)
+				{
+					info.color_body = gameclient.skins->get_color(config.player_color_body);
+					info.color_feet = gameclient.skins->get_color(config.player_color_feet);
+					info.texture = s->color_texture;
+				}
+					
+				info.size = UI()->Scale()*50.0f;
+				
+				CUIRect icon = boxes[i]; //item.rect;
+				//button.VSplitLeft(50.0f, &icon, &text);
+				
+				/*if(UI()->DoButton(s, "", selected, &button, ui_draw_list_row, 0))
+				{
+					config_set_player_skin(&config, s->name);
+					need_sendinfo = true;
+				}*/
+
+				//text.HSplitTop(12.0f, 0, &text); // some margin from the top
+				//UI()->DoLabel(&text, buf, 18.0f, 0);
+				
+				icon.HSplitTop(5.0f, 0, &icon); // some margin from the top
+				RenderTools()->RenderTee(ANIMSTATE::get_idle(), &info, 0, vec2(1, 0), vec2(icon.x+icon.w/2, icon.y+icon.h/2));
+				
+				if(config.debug)
+				{
+					Graphics()->TextureSet(-1);
+					Graphics()->QuadsBegin();
+					Graphics()->SetColor(s->blood_color.r, s->blood_color.g, s->blood_color.b, 1.0f);
+					Graphics()->QuadsDrawTL(icon.x, icon.y, 12, 12);
+					Graphics()->QuadsEnd();
+				}
+			}
+		}
+		
+		int new_selection = ui_do_listbox_end();
+		(void)new_selection;
+		//main_view
+	}
+	
+	// render skinselector
+	/*
+	{
+		
+		//othersection
 	}
 		
 	// draw header
-	RECT header, footer;
-	ui_hsplit_t(&skinselection, 20, &header, &skinselection);
-	ui_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); 
-	ui_do_label(&header, localize("Skins"), 18.0f, 0);
+	CUIRect header, footer;
+	skinselection.HSplitTop(20, &header, &skinselection);
+	RenderTools()->DrawUIRect(&header, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f); 
+	UI()->DoLabel(&header, localize("Skins"), 18.0f, 0);
 
 	// draw footers	
-	ui_hsplit_b(&skinselection, 20, &skinselection, &footer);
-	ui_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); 
-	ui_vsplit_l(&footer, 10.0f, 0, &footer);
+	skinselection.HSplitBottom(20, &skinselection, &footer);
+	RenderTools()->DrawUIRect(&footer, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f); 
+	footer.VSplitLeft(10.0f, 0, &footer);
 
 	// modes
-	ui_draw_rect(&skinselection, vec4(0,0,0,0.15f), 0, 0);
+	RenderTools()->DrawUIRect(&skinselection, vec4(0,0,0,0.15f), 0, 0);
 
-	RECT scroll;
-	ui_vsplit_r(&skinselection, 15, &skinselection, &scroll);
+	CUIRect scroll;
+	skinselection.VSplitRight(15, &skinselection, &scroll);
 
-	RECT list = skinselection;
-	ui_hsplit_t(&list, 50, &button, &list);
+	CUIRect list = skinselection;
+	list.HSplitTop(50, &button, &list);
 	
 	int num = (int)(skinselection.h/button.h);
 	static float scrollvalue = 0;
 	static int scrollbar = 0;
-	ui_hmargin(&scroll, 5.0f, &scroll);
+	scroll.HMargin(5.0f, &scroll);
 	scrollvalue = ui_do_scrollbar_v(&scrollbar, &scroll, scrollvalue);
 
 	int start = (int)((gameclient.skins->num()-num)*scrollvalue);
@@ -220,35 +287,35 @@ void MENUS::render_settings_player(RECT main_view)
 			info.texture = s->color_texture;
 		}
 			
-		info.size = ui_scale()*50.0f;
+		info.size = UI()->Scale()*50.0f;
 		
-		RECT icon;
-		RECT text;
-		ui_vsplit_l(&button, 50.0f, &icon, &text);
+		CUIRect icon;
+		CUIRect text;
+		button.VSplitLeft(50.0f, &icon, &text);
 		
-		if(ui_do_button(s, "", selected, &button, ui_draw_list_row, 0))
+		if(UI()->DoButton(s, "", selected, &button, ui_draw_list_row, 0))
 		{
 			config_set_player_skin(&config, s->name);
 			need_sendinfo = true;
 		}
 
-		ui_hsplit_t(&text, 12.0f, 0, &text); // some margin from the top
-		ui_do_label(&text, buf, 18.0f, 0);
+		text.HSplitTop(12.0f, 0, &text); // some margin from the top
+		UI()->DoLabel(&text, buf, 18.0f, 0);
 		
-		ui_hsplit_t(&icon, 5.0f, 0, &icon); // some margin from the top
-		render_tee(ANIMSTATE::get_idle(), &info, 0, vec2(1, 0), vec2(icon.x+icon.w/2, icon.y+icon.h/2));
+		icon.HSplitTop(5.0f, 0, &icon); // some margin from the top
+		RenderTools()->RenderTee(ANIMSTATE::get_idle(), &info, 0, vec2(1, 0), vec2(icon.x+icon.w/2, icon.y+icon.h/2));
 		
 		if(config.debug)
 		{
-			gfx_texture_set(-1);
-			gfx_quads_begin();
-			gfx_setcolor(s->blood_color.r, s->blood_color.g, s->blood_color.b, 1.0f);
-			gfx_quads_drawTL(icon.x, icon.y, 12, 12);
-			gfx_quads_end();
+			Graphics()->TextureSet(-1);
+			Graphics()->QuadsBegin();
+			Graphics()->SetColor(s->blood_color.r, s->blood_color.g, s->blood_color.b, 1.0f);
+			Graphics()->QuadsDrawTL(icon.x, icon.y, 12, 12);
+			Graphics()->QuadsEnd();
 		}
 		
-		ui_hsplit_t(&list, 50, &button, &list);
-	}
+		list.HSplitTop(50, &button, &list);
+	}*/
 }
 
 typedef void (*assign_func_callback)(CONFIGURATION *config, int value);
@@ -288,31 +355,31 @@ static KEYINFO keys[] =
 
 const int key_count = sizeof(keys) / sizeof(KEYINFO);
 
-void MENUS::ui_do_getbuttons(int start, int stop, RECT view)
+void MENUS::ui_do_getbuttons(int start, int stop, CUIRect view)
 {
 	for (int i = start; i < stop; i++)
 	{
 		KEYINFO &key = keys[i];
-		RECT button, label;
-		ui_hsplit_t(&view, 20.0f, &button, &view);
-		ui_vsplit_l(&button, 130.0f, &label, &button);
+		CUIRect button, label;
+		view.HSplitTop(20.0f, &button, &view);
+		button.VSplitLeft(130.0f, &label, &button);
 	
 		char buf[64];
 		str_format(buf, sizeof(buf), "%s:", (const char *)key.name);
 		
-		ui_do_label(&label, key.name, 14.0f, -1);
+		UI()->DoLabel(&label, key.name, 14.0f, -1);
 		int oldid = key.keyid;
-		int newid = ui_do_key_reader((void *)&keys[i].name, &button, oldid);
+		int newid = DoKeyReader((void *)&keys[i].name, &button, oldid);
 		if(newid != oldid)
 		{
 			gameclient.binds->bind(oldid, "");
 			gameclient.binds->bind(newid, keys[i].command);
 		}
-		ui_hsplit_t(&view, 5.0f, 0, &view);
+		view.HSplitTop(5.0f, 0, &view);
 	}
 }
 
-void MENUS::render_settings_controls(RECT main_view)
+void MENUS::render_settings_controls(CUIRect main_view)
 {
 	// this is kinda slow, but whatever
 	for(int i = 0; i < key_count; i++)
@@ -332,28 +399,28 @@ void MENUS::render_settings_controls(RECT main_view)
 			}
 	}
 
-	RECT movement_settings, weapon_settings, voting_settings, chat_settings, misc_settings, reset_button;
-	ui_vsplit_l(&main_view, main_view.w/2-5.0f, &movement_settings, &voting_settings);
+	CUIRect movement_settings, weapon_settings, voting_settings, chat_settings, misc_settings, reset_button;
+	main_view.VSplitLeft(main_view.w/2-5.0f, &movement_settings, &voting_settings);
 	
 	/* movement settings */
 	{
-		ui_hsplit_t(&movement_settings, main_view.h/2-5.0f, &movement_settings, &weapon_settings);
-		ui_draw_rect(&movement_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
-		ui_margin(&movement_settings, 10.0f, &movement_settings);
+		movement_settings.HSplitTop(main_view.h/2-5.0f, &movement_settings, &weapon_settings);
+		RenderTools()->DrawUIRect(&movement_settings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
+		movement_settings.Margin(10.0f, &movement_settings);
 		
 		gfx_text(0, movement_settings.x, movement_settings.y, 14, localize("Movement"), -1);
 		
-		ui_hsplit_t(&movement_settings, 14.0f+5.0f+10.0f, 0, &movement_settings);
+		movement_settings.HSplitTop(14.0f+5.0f+10.0f, 0, &movement_settings);
 		
 		{
-			RECT button, label;
-			ui_hsplit_t(&movement_settings, 20.0f, &button, &movement_settings);
-			ui_vsplit_l(&button, 130.0f, &label, &button);
-			ui_do_label(&label, localize("Mouse sens."), 14.0f, -1);
-			ui_hmargin(&button, 2.0f, &button);
-			config.inp_mousesens = (int)(ui_do_scrollbar_h(&config.inp_mousesens, &button, (config.inp_mousesens-5)/500.0f)*500.0f)+5;
+			CUIRect button, label;
+			movement_settings.HSplitTop(20.0f, &button, &movement_settings);
+			button.VSplitLeft(130.0f, &label, &button);
+			UI()->DoLabel(&label, localize("Mouse sens."), 14.0f, -1);
+			button.HMargin(2.0f, &button);
+			config.inp_mousesens = (int)(DoScrollbarV(&config.inp_mousesens, &button, (config.inp_mousesens-5)/500.0f)*500.0f)+5;
 			//*key.key = ui_do_key_reader(key.key, &button, *key.key);
-			ui_hsplit_t(&movement_settings, 20.0f, 0, &movement_settings);
+			movement_settings.HSplitTop(20.0f, 0, &movement_settings);
 		}
 		
 		ui_do_getbuttons(0, 5, movement_settings);
@@ -362,65 +429,65 @@ void MENUS::render_settings_controls(RECT main_view)
 	
 	/* weapon settings */
 	{
-		ui_hsplit_t(&weapon_settings, 10.0f, 0, &weapon_settings);
-		ui_draw_rect(&weapon_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
-		ui_margin(&weapon_settings, 10.0f, &weapon_settings);
+		weapon_settings.HSplitTop(10.0f, 0, &weapon_settings);
+		RenderTools()->DrawUIRect(&weapon_settings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
+		weapon_settings.Margin(10.0f, &weapon_settings);
 
 		gfx_text(0, weapon_settings.x, weapon_settings.y, 14, localize("Weapon"), -1);
 		
-		ui_hsplit_t(&weapon_settings, 14.0f+5.0f+10.0f, 0, &weapon_settings);
+		weapon_settings.HSplitTop(14.0f+5.0f+10.0f, 0, &weapon_settings);
 		ui_do_getbuttons(5, 12, weapon_settings);
 	}
 	
 	/* voting settings */
 	{
-		ui_vsplit_l(&voting_settings, 10.0f, 0, &voting_settings);
-		ui_hsplit_t(&voting_settings, main_view.h/4-5.0f, &voting_settings, &chat_settings);
-		ui_draw_rect(&voting_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
-		ui_margin(&voting_settings, 10.0f, &voting_settings);
+		voting_settings.VSplitLeft(10.0f, 0, &voting_settings);
+		voting_settings.HSplitTop(main_view.h/4-5.0f, &voting_settings, &chat_settings);
+		RenderTools()->DrawUIRect(&voting_settings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
+		voting_settings.Margin(10.0f, &voting_settings);
 	
 		gfx_text(0, voting_settings.x, voting_settings.y, 14, localize("Voting"), -1);
 		
-		ui_hsplit_t(&voting_settings, 14.0f+5.0f+10.0f, 0, &voting_settings);
+		voting_settings.HSplitTop(14.0f+5.0f+10.0f, 0, &voting_settings);
 		ui_do_getbuttons(12, 14, voting_settings);
 	}
 	
 	/* chat settings */
 	{
-		ui_hsplit_t(&chat_settings, 10.0f, 0, &chat_settings);
-		ui_hsplit_t(&chat_settings, main_view.h/4-10.0f, &chat_settings, &misc_settings);
-		ui_draw_rect(&chat_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
-		ui_margin(&chat_settings, 10.0f, &chat_settings);
+		chat_settings.HSplitTop(10.0f, 0, &chat_settings);
+		chat_settings.HSplitTop(main_view.h/4-10.0f, &chat_settings, &misc_settings);
+		RenderTools()->DrawUIRect(&chat_settings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
+		chat_settings.Margin(10.0f, &chat_settings);
 	
 		gfx_text(0, chat_settings.x, chat_settings.y, 14, localize("Chat"), -1);
 		
-		ui_hsplit_t(&chat_settings, 14.0f+5.0f+10.0f, 0, &chat_settings);
+		chat_settings.HSplitTop(14.0f+5.0f+10.0f, 0, &chat_settings);
 		ui_do_getbuttons(14, 16, chat_settings);
 	}
 	
 	/* misc settings */
 	{
-		ui_hsplit_t(&misc_settings, 10.0f, 0, &misc_settings);
-		ui_hsplit_t(&misc_settings, main_view.h/2-5.0f-45.0f, &misc_settings, &reset_button);
-		ui_draw_rect(&misc_settings, vec4(1,1,1,0.25f), CORNER_ALL, 10.0f);
-		ui_margin(&misc_settings, 10.0f, &misc_settings);
+		misc_settings.HSplitTop(10.0f, 0, &misc_settings);
+		misc_settings.HSplitTop(main_view.h/2-5.0f-45.0f, &misc_settings, &reset_button);
+		RenderTools()->DrawUIRect(&misc_settings, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
+		misc_settings.Margin(10.0f, &misc_settings);
 	
 		gfx_text(0, misc_settings.x, misc_settings.y, 14, localize("Miscellaneous"), -1);
 		
-		ui_hsplit_t(&misc_settings, 14.0f+5.0f+10.0f, 0, &misc_settings);
+		misc_settings.HSplitTop(14.0f+5.0f+10.0f, 0, &misc_settings);
 		ui_do_getbuttons(16, 21, misc_settings);
 	}
 	
 	// defaults
-	ui_hsplit_t(&reset_button, 10.0f, 0, &reset_button);
+	reset_button.HSplitTop(10.0f, 0, &reset_button);
 	static int default_button = 0;
-	if (ui_do_button((void*)&default_button, localize("Reset to defaults"), 0, &reset_button, ui_draw_menu_button, 0))
+	if(DoButton_Menu((void*)&default_button, localize("Reset to defaults"), 0, &reset_button))
 		gameclient.binds->set_defaults();
 }
 
-void MENUS::render_settings_graphics(RECT main_view)
+void MENUS::render_settings_graphics(CUIRect main_view)
 {
-	RECT button;
+	CUIRect button;
 	char buf[128];
 	
 	static const int MAX_RESOLUTIONS = 256;
@@ -430,44 +497,44 @@ void MENUS::render_settings_graphics(RECT main_view)
 	if(num_modes == -1)
 		num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS);
 	
-	RECT modelist;
-	ui_vsplit_l(&main_view, 300.0f, &main_view, &modelist);
+	CUIRect modelist;
+	main_view.VSplitLeft(300.0f, &main_view, &modelist);
 	
 	// draw allmodes switch
-	RECT header, footer;
-	ui_hsplit_t(&modelist, 20, &button, &modelist);
-	if (ui_do_button(&config.gfx_display_all_modes, localize("Show only supported"), config.gfx_display_all_modes^1, &button, ui_draw_checkbox, 0))
+	CUIRect header, footer;
+	modelist.HSplitTop(20, &button, &modelist);
+	if(DoButton_CheckBox(&config.gfx_display_all_modes, localize("Show only supported"), config.gfx_display_all_modes^1, &button))
 	{
 		config.gfx_display_all_modes ^= 1;
 		num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS);
 	}
 	
 	// draw header
-	ui_hsplit_t(&modelist, 20, &header, &modelist);
-	ui_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); 
-	ui_do_label(&header, localize("Display Modes"), 14.0f, 0);
+	modelist.HSplitTop(20, &header, &modelist);
+	RenderTools()->DrawUIRect(&header, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f); 
+	UI()->DoLabel(&header, localize("Display Modes"), 14.0f, 0);
 
 	// draw footers	
-	ui_hsplit_b(&modelist, 20, &modelist, &footer);
+	modelist.HSplitBottom(20, &modelist, &footer);
 	str_format(buf, sizeof(buf), "%s: %dx%d %d bit", localize("Current"), config.gfx_screen_width, config.gfx_screen_height, config.gfx_color_depth);
-	ui_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); 
-	ui_vsplit_l(&footer, 10.0f, 0, &footer);
-	ui_do_label(&footer, buf, 14.0f, -1);
+	RenderTools()->DrawUIRect(&footer, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f); 
+	footer.VSplitLeft(10.0f, 0, &footer);
+	UI()->DoLabel(&footer, buf, 14.0f, -1);
 
 	// modes
-	ui_draw_rect(&modelist, vec4(0,0,0,0.15f), 0, 0);
+	RenderTools()->DrawUIRect(&modelist, vec4(0,0,0,0.15f), 0, 0);
 
-	RECT scroll;
-	ui_vsplit_r(&modelist, 15, &modelist, &scroll);
+	CUIRect scroll;
+	modelist.VSplitRight(15, &modelist, &scroll);
 
-	RECT list = modelist;
-	ui_hsplit_t(&list, 20, &button, &list);
+	CUIRect list = modelist;
+	list.HSplitTop(20, &button, &list);
 	
 	int num = (int)(modelist.h/button.h);
 	static float scrollvalue = 0;
 	static int scrollbar = 0;
-	ui_hmargin(&scroll, 5.0f, &scroll);
-	scrollvalue = ui_do_scrollbar_v(&scrollbar, &scroll, scrollvalue);
+	scroll.HMargin(5.0f, &scroll);
+	scrollvalue = DoScrollbarV(&scrollbar, &scroll, scrollvalue);
 
 	int start = (int)((num_modes-num)*scrollvalue);
 	if(start < 0)
@@ -490,7 +557,7 @@ void MENUS::render_settings_graphics(RECT main_view)
 		}
 		
 		str_format(buf, sizeof(buf), "  %dx%d %d bit", modes[i].width, modes[i].height, depth);
-		if(ui_do_button(&modes[i], buf, selected, &button, ui_draw_list_row, 0))
+		if(DoButton_ListRow(&modes[i], buf, selected, &button))
 		{
 			config.gfx_color_depth = depth;
 			config.gfx_screen_width = modes[i].width;
@@ -499,58 +566,58 @@ void MENUS::render_settings_graphics(RECT main_view)
 				need_restart = true;
 		}
 		
-		ui_hsplit_t(&list, 20, &button, &list);
+		list.HSplitTop(20, &button, &list);
 	}
 	
 	
 	// switches
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.gfx_fullscreen, localize("Fullscreen"), config.gfx_fullscreen, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.gfx_fullscreen, localize("Fullscreen"), config.gfx_fullscreen, &button))
 	{
 		config.gfx_fullscreen ^= 1;
 		need_restart = true;
 	}
 
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.gfx_vsync, localize("V-Sync"), config.gfx_vsync, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.gfx_vsync, localize("V-Sync"), config.gfx_vsync, &button))
 	{
 		config.gfx_vsync ^= 1;
 		need_restart = true;
 	}
 
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.gfx_fsaa_samples, localize("FSAA samples"), config.gfx_fsaa_samples, &button, ui_draw_checkbox_number, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox_Number(&config.gfx_fsaa_samples, localize("FSAA samples"), config.gfx_fsaa_samples, &button))
 	{
 		config.gfx_fsaa_samples = (config.gfx_fsaa_samples+1)%17;
 		need_restart = true;
 	}
 		
-	ui_hsplit_t(&main_view, 40.0f, &button, &main_view);
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.gfx_texture_quality, localize("Quality Textures"), config.gfx_texture_quality, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(40.0f, &button, &main_view);
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.gfx_texture_quality, localize("Quality Textures"), config.gfx_texture_quality, &button))
 	{
 		config.gfx_texture_quality ^= 1;
 		need_restart = true;
 	}
 
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.gfx_texture_compression, localize("Texture Compression"), config.gfx_texture_compression, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.gfx_texture_compression, localize("Texture Compression"), config.gfx_texture_compression, &button))
 	{
 		config.gfx_texture_compression ^= 1;
 		need_restart = true;
 	}
 
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.gfx_high_detail, localize("High Detail"), config.gfx_high_detail, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.gfx_high_detail, localize("High Detail"), config.gfx_high_detail, &button))
 		config.gfx_high_detail ^= 1;
 
 	//
 	
-	RECT text;
-	ui_hsplit_t(&main_view, 20.0f, 0, &main_view);
-	ui_hsplit_t(&main_view, 20.0f, &text, &main_view);
-	//ui_vsplit_l(&text, 15.0f, 0, &text);
-	ui_do_label(&text, localize("UI Color"), 14.0f, -1);
+	CUIRect text;
+	main_view.HSplitTop(20.0f, 0, &main_view);
+	main_view.HSplitTop(20.0f, &text, &main_view);
+	//text.VSplitLeft(15.0f, 0, &text);
+	UI()->DoLabel(&text, localize("UI Color"), 14.0f, -1);
 	
 	const char *labels[] = {
 		localize("Hue"),
@@ -560,27 +627,27 @@ void MENUS::render_settings_graphics(RECT main_view)
 	int *color_slider[4] = {&config.ui_color_hue, &config.ui_color_sat, &config.ui_color_lht, &config.ui_color_alpha};
 	for(int s = 0; s < 4; s++)
 	{
-		RECT text;
-		ui_hsplit_t(&main_view, 19.0f, &button, &main_view);
-		ui_vmargin(&button, 15.0f, &button);
-		ui_vsplit_l(&button, 50.0f, &text, &button);
-		ui_vsplit_r(&button, 5.0f, &button, 0);
-		ui_hsplit_t(&button, 4.0f, 0, &button);
+		CUIRect text;
+		main_view.HSplitTop(19.0f, &button, &main_view);
+		button.VMargin(15.0f, &button);
+		button.VSplitLeft(50.0f, &text, &button);
+		button.VSplitRight(5.0f, &button, 0);
+		button.HSplitTop(4.0f, 0, &button);
 		
 		float k = (*color_slider[s]) / 255.0f;
-		k = ui_do_scrollbar_h(color_slider[s], &button, k);
+		k = DoScrollbarH(color_slider[s], &button, k);
 		*color_slider[s] = (int)(k*255.0f);
-		ui_do_label(&text, labels[s], 15.0f, -1);
+		UI()->DoLabel(&text, labels[s], 15.0f, -1);
 	}		
 }
 
-void MENUS::render_settings_sound(RECT main_view)
+void MENUS::render_settings_sound(CUIRect main_view)
 {
-	RECT button;
-	ui_vsplit_l(&main_view, 300.0f, &main_view, 0);
+	CUIRect button;
+	main_view.VSplitLeft(300.0f, &main_view, 0);
 	
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.snd_enable, localize("Use sounds"), config.snd_enable, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.snd_enable, localize("Use sounds"), config.snd_enable, &button))
 	{
 		config.snd_enable ^= 1;
 		need_restart = true;
@@ -589,19 +656,19 @@ void MENUS::render_settings_sound(RECT main_view)
 	if(!config.snd_enable)
 		return;
 	
-	ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-	if (ui_do_button(&config.snd_nonactive_mute, localize("Mute when not active"), config.snd_nonactive_mute, &button, ui_draw_checkbox, 0))
+	main_view.HSplitTop(20.0f, &button, &main_view);
+	if(DoButton_CheckBox(&config.snd_nonactive_mute, localize("Mute when not active"), config.snd_nonactive_mute, &button))
 		config.snd_nonactive_mute ^= 1;
 		
 	// sample rate box
 	{
 		char buf[64];
 		str_format(buf, sizeof(buf), "%d", config.snd_rate);
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-		ui_do_label(&button, localize("Sample rate"), 14.0f, -1);
-		ui_vsplit_l(&button, 110.0f, 0, &button);
-		ui_vsplit_l(&button, 180.0f, &button, 0);
-		ui_do_edit_box(&config.snd_rate, &button, buf, sizeof(buf), 14.0f);
+		main_view.HSplitTop(20.0f, &button, &main_view);
+		UI()->DoLabel(&button, localize("Sample rate"), 14.0f, -1);
+		button.VSplitLeft(110.0f, 0, &button);
+		button.VSplitLeft(180.0f, &button, 0);
+		DoEditBox(&config.snd_rate, &button, buf, sizeof(buf), 14.0f);
 		int before = config.snd_rate;
 		config.snd_rate = atoi(buf);
 		
@@ -614,14 +681,14 @@ void MENUS::render_settings_sound(RECT main_view)
 	
 	// volume slider
 	{
-		RECT button, label;
-		ui_hsplit_t(&main_view, 5.0f, &button, &main_view);
-		ui_hsplit_t(&main_view, 20.0f, &button, &main_view);
-		ui_vsplit_l(&button, 110.0f, &label, &button);
-		ui_hmargin(&button, 2.0f, &button);
-		ui_do_label(&label, localize("Sound volume"), 14.0f, -1);
-		config.snd_volume = (int)(ui_do_scrollbar_h(&config.snd_volume, &button, config.snd_volume/100.0f)*100.0f);
-		ui_hsplit_t(&main_view, 20.0f, 0, &main_view);
+		CUIRect button, label;
+		main_view.HSplitTop(5.0f, &button, &main_view);
+		main_view.HSplitTop(20.0f, &button, &main_view);
+		button.VSplitLeft(110.0f, &label, &button);
+		button.HMargin(2.0f, &button);
+		UI()->DoLabel(&label, localize("Sound volume"), 14.0f, -1);
+		config.snd_volume = (int)(DoScrollbarH(&config.snd_volume, &button, config.snd_volume/100.0f)*100.0f);
+		main_view.HSplitTop(20.0f, 0, &main_view);
 	}
 }
 
@@ -660,7 +727,7 @@ void gather_languages(const char *name, int is_dir, void *user)
 	languages.add(LANGUAGE(nicename, filename));
 }
 
-void MENUS::render_settings_general(RECT main_view)
+void MENUS::render_settings_general(CUIRect main_view)
 {
 	static int lanuagelist = 0;
 	static int selected_language = 0;
@@ -680,7 +747,7 @@ void MENUS::render_settings_general(RECT main_view)
 	
 	int old_selected = selected_language;
 	
-	RECT list = main_view;
+	CUIRect list = main_view;
 	ui_do_listbox_start(&lanuagelist, &list, 24.0f, localize("Language"), languages.size(), selected_language);
 	
 	for(sorted_array<LANGUAGE>::range r = languages.all(); !r.empty(); r.pop_front())
@@ -688,7 +755,7 @@ void MENUS::render_settings_general(RECT main_view)
 		LISTBOXITEM item = ui_do_listbox_nextitem(&r.front());
 		
 		if(item.visible)
-			ui_do_label(&item.rect, r.front().name, 16.0f, -1);
+			UI()->DoLabel(&item.rect, r.front().name, 16.0f, -1);
 	}
 	
 	selected_language = ui_do_listbox_end();
@@ -700,20 +767,20 @@ void MENUS::render_settings_general(RECT main_view)
 	}
 }
 
-void MENUS::render_settings(RECT main_view)
+void MENUS::render_settings(CUIRect main_view)
 {
 	static int settings_page = 0;
 	
 	// render background
-	RECT temp, tabbar;
-	ui_vsplit_r(&main_view, 120.0f, &main_view, &tabbar);
-	ui_draw_rect(&main_view, color_tabbar_active, CORNER_B|CORNER_TL, 10.0f);
-	ui_hsplit_t(&tabbar, 50.0f, &temp, &tabbar);
-	ui_draw_rect(&temp, color_tabbar_active, CORNER_R, 10.0f);
+	CUIRect temp, tabbar;
+	main_view.VSplitRight(120.0f, &main_view, &tabbar);
+	RenderTools()->DrawUIRect(&main_view, color_tabbar_active, CUI::CORNER_B|CUI::CORNER_TL, 10.0f);
+	tabbar.HSplitTop(50.0f, &temp, &tabbar);
+	RenderTools()->DrawUIRect(&temp, color_tabbar_active, CUI::CORNER_R, 10.0f);
 	
-	ui_hsplit_t(&main_view, 10.0f, 0, &main_view);
+	main_view.HSplitTop(10.0f, 0, &main_view);
 	
-	RECT button;
+	CUIRect button;
 	
 	const char *tabs[] = {
 		localize("General"),
@@ -721,17 +788,18 @@ void MENUS::render_settings(RECT main_view)
 		localize("Controls"),
 		localize("Graphics"),
 		localize("Sound")};
+		
 	int num_tabs = (int)(sizeof(tabs)/sizeof(*tabs));
 
 	for(int i = 0; i < num_tabs; i++)
 	{
-		ui_hsplit_t(&tabbar, 10, &button, &tabbar);
-		ui_hsplit_t(&tabbar, 26, &button, &tabbar);
-		if(ui_do_button(tabs[i], tabs[i], settings_page == i, &button, ui_draw_settings_tab_button, 0))
+		tabbar.HSplitTop(10, &button, &tabbar);
+		tabbar.HSplitTop(26, &button, &tabbar);
+		if(DoButton_SettingsTab(tabs[i], tabs[i], settings_page == i, &button))
 			settings_page = i;
 	}
 	
-	ui_margin(&main_view, 10.0f, &main_view);
+	main_view.Margin(10.0f, &main_view);
 	
 	if(settings_page == 0)
 		render_settings_general(main_view);
@@ -746,8 +814,8 @@ void MENUS::render_settings(RECT main_view)
 
 	if(need_restart)
 	{
-		RECT restart_warning;
-		ui_hsplit_b(&main_view, 40, &main_view, &restart_warning);
-		ui_do_label(&restart_warning, localize("You must restart the game for all settings to take effect."), 15.0f, -1, 220);
+		CUIRect restart_warning;
+		main_view.HSplitBottom(40, &main_view, &restart_warning);
+		UI()->DoLabel(&restart_warning, localize("You must restart the game for all settings to take effect."), 15.0f, -1, 220);
 	}
 }
diff --git a/src/game/client/components/motd.cpp b/src/game/client/components/motd.cpp
index 0d1eacba..ba85f7f8 100644
--- a/src/game/client/components/motd.cpp
+++ b/src/game/client/components/motd.cpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <engine/e_config.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
@@ -28,22 +29,22 @@ void MOTD::on_render()
 	if(!is_active())
 		return;
 		
-	float width = 400*3.0f*gfx_screenaspect();
+	float width = 400*3.0f*Graphics()->ScreenAspect();
 	float height = 400*3.0f;
 
-	gfx_mapscreen(0, 0, width, height);
+	Graphics()->MapScreen(0, 0, width, height);
 	
 	float h = 800.0f;
 	float w = 650.0f;
 	float x = width/2 - w/2;
 	float y = 150.0f;
 
-	gfx_blend_normal();
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.5f);
-	draw_round_rect(x, y, w, h, 40.0f);
-	gfx_quads_end();
+	Graphics()->BlendNormal();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.5f);
+	RenderTools()->draw_round_rect(x, y, w, h, 40.0f);
+	Graphics()->QuadsEnd();
 
 	gfx_text(0, x+40.0f, y+40.0f, 32.0f, server_motd, (int)(w-80.0f));
 }
diff --git a/src/game/client/components/particles.cpp b/src/game/client/components/particles.cpp
index ef6dbbe9..61fcf738 100644
--- a/src/game/client/components/particles.cpp
+++ b/src/game/client/components/particles.cpp
@@ -1,4 +1,6 @@
 #include <base/math.hpp>
+#include <engine/client/graphics.h>
+
 #include <game/generated/gc_data.hpp>
 #include <game/client/render.hpp>
 #include <game/gamecore.hpp>
@@ -124,31 +126,31 @@ void PARTICLES::on_render()
 
 void PARTICLES::render_group(int group)
 {
-	gfx_blend_normal();
+	Graphics()->BlendNormal();
 	//gfx_blend_additive();
-	gfx_texture_set(data->images[IMAGE_PARTICLES].id);
-	gfx_quads_begin();
+	Graphics()->TextureSet(data->images[IMAGE_PARTICLES].id);
+	Graphics()->QuadsBegin();
 
 	int i = first_part[group];
 	while(i != -1)
 	{
-		select_sprite(particles[i].spr);
+		RenderTools()->select_sprite(particles[i].spr);
 		float a = particles[i].life / particles[i].life_span;
 		vec2 p = particles[i].pos;
 		float size = mix(particles[i].start_size, particles[i].end_size, a);
 
-		gfx_quads_setrotation(particles[i].rot);
+		Graphics()->QuadsSetRotation(particles[i].rot);
 
-		gfx_setcolor(
+		Graphics()->SetColor(
 			particles[i].color.r,
 			particles[i].color.g,
 			particles[i].color.b,
 			particles[i].color.a); // pow(a, 0.75f) * 
 
-		gfx_quads_draw(p.x, p.y, size, size);
+		Graphics()->QuadsDraw(p.x, p.y, size, size);
 		
 		i = particles[i].next_part;
 	}
-	gfx_quads_end();
-	gfx_blend_normal();
+	Graphics()->QuadsEnd();
+	Graphics()->BlendNormal();
 }
diff --git a/src/game/client/components/players.cpp b/src/game/client/components/players.cpp
index 6d6bcc37..e1fee3e8 100644
--- a/src/game/client/components/players.cpp
+++ b/src/game/client/components/players.cpp
@@ -1,4 +1,5 @@
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 
@@ -40,23 +41,23 @@ void PLAYERS::render_hand(TEE_RENDER_INFO *info, vec2 center_pos, vec2 dir, floa
 	hand_pos += dirx * post_rot_offset.x;
 	hand_pos += diry * post_rot_offset.y;
 
-	//gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id);
-	gfx_texture_set(info->texture);
-	gfx_quads_begin();
-	gfx_setcolor(info->color_body.r, info->color_body.g, info->color_body.b, info->color_body.a);
+	//Graphics()->TextureSet(data->images[IMAGE_CHAR_DEFAULT].id);
+	Graphics()->TextureSet(info->texture);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(info->color_body.r, info->color_body.g, info->color_body.b, info->color_body.a);
 
 	// two passes
 	for (int i = 0; i < 2; i++)
 	{
 		bool outline = i == 0;
 
-		select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, 0);
-		gfx_quads_setrotation(angle);
-		gfx_quads_draw(hand_pos.x, hand_pos.y, 2*basesize, 2*basesize);
+		RenderTools()->select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, 0);
+		Graphics()->QuadsSetRotation(angle);
+		Graphics()->QuadsDraw(hand_pos.x, hand_pos.y, 2*basesize, 2*basesize);
 	}
 
-	gfx_quads_setrotation(0);
-	gfx_quads_end();
+	Graphics()->QuadsSetRotation(0);
+	Graphics()->QuadsEnd();
 }
 
 inline float normalize_angular(float f)
@@ -237,9 +238,9 @@ void PLAYERS::render_player(
 	// draw hook
 	if (prev.hook_state>0 && player.hook_state>0)
 	{
-		gfx_texture_set(data->images[IMAGE_GAME].id);
-		gfx_quads_begin();
-		//gfx_quads_begin();
+		Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+		Graphics()->QuadsBegin();
+		//Graphics()->QuadsBegin();
 
 		vec2 pos = position;
 		vec2 hook_pos;
@@ -260,36 +261,36 @@ void PLAYERS::render_player(
 		float d = distance(pos, hook_pos);
 		vec2 dir = normalize(pos-hook_pos);
 
-		gfx_quads_setrotation(get_angle(dir)+pi);
+		Graphics()->QuadsSetRotation(get_angle(dir)+pi);
 
 		// render head
-		select_sprite(SPRITE_HOOK_HEAD);
-		gfx_quads_draw(hook_pos.x, hook_pos.y, 24,16);
+		RenderTools()->select_sprite(SPRITE_HOOK_HEAD);
+		Graphics()->QuadsDraw(hook_pos.x, hook_pos.y, 24,16);
 
 		// render chain
-		select_sprite(SPRITE_HOOK_CHAIN);
+		RenderTools()->select_sprite(SPRITE_HOOK_CHAIN);
 		int i = 0;
 		for(float f = 24; f < d && i < 1024; f += 24, i++)
 		{
 			vec2 p = hook_pos + dir*f;
-			gfx_quads_draw(p.x, p.y,24,16);
+			Graphics()->QuadsDraw(p.x, p.y,24,16);
 		}
 
-		gfx_quads_setrotation(0);
-		gfx_quads_end();
+		Graphics()->QuadsSetRotation(0);
+		Graphics()->QuadsEnd();
 
 		render_hand(&render_info, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0));
 	}
 
 	// draw gun
 	{
-		gfx_texture_set(data->images[IMAGE_GAME].id);
-		gfx_quads_begin();
-		gfx_quads_setrotation(state.attach.angle*pi*2+angle);
+		Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+		Graphics()->QuadsBegin();
+		Graphics()->QuadsSetRotation(state.attach.angle*pi*2+angle);
 
 		// normal weapons
 		int iw = clamp(player.weapon, 0, NUM_WEAPONS-1);
-		select_sprite(data->weapons.id[iw].sprite_body, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
+		RenderTools()->select_sprite(data->weapons.id[iw].sprite_body, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
 
 		vec2 dir = direction;
 		float recoil = 0.0f;
@@ -302,14 +303,14 @@ void PLAYERS::render_player(
 			// if attack is under way, bash stuffs
 			if(direction.x < 0)
 			{
-				gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2);
+				Graphics()->QuadsSetRotation(-pi/2-state.attach.angle*pi*2);
 				p.x -= data->weapons.id[iw].offsetx;
 			}
 			else
 			{
-				gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2);
+				Graphics()->QuadsSetRotation(-pi/2+state.attach.angle*pi*2);
 			}
-			draw_sprite(p.x, p.y, data->weapons.id[iw].visual_size);
+			RenderTools()->draw_sprite(p.x, p.y, data->weapons.id[iw].visual_size);
 		}
 		else if (player.weapon == WEAPON_NINJA)
 		{
@@ -318,16 +319,16 @@ void PLAYERS::render_player(
 
 			if(direction.x < 0)
 			{
-				gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2);
+				Graphics()->QuadsSetRotation(-pi/2-state.attach.angle*pi*2);
 				p.x -= data->weapons.id[iw].offsetx;
 				gameclient.effects->powerupshine(p+vec2(32,0), vec2(32,12));
 			}
 			else
 			{
-				gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2);
+				Graphics()->QuadsSetRotation(-pi/2+state.attach.angle*pi*2);
 				gameclient.effects->powerupshine(p-vec2(32,0), vec2(32,12));
 			}
-			draw_sprite(p.x, p.y, data->weapons.id[iw].visual_size);
+			RenderTools()->draw_sprite(p.x, p.y, data->weapons.id[iw].visual_size);
 
 			// HADOKEN
 			if ((client_tick()-player.attacktick) <= (SERVER_TICK_SPEED / 6) && data->weapons.id[iw].num_sprite_muzzles)
@@ -339,14 +340,14 @@ void PLAYERS::render_player(
 					vec2 dir = vec2(player_char->x,player_char->y) - vec2(prev_char->x, prev_char->y);
 					dir = normalize(dir);
 					float hadokenangle = get_angle(dir);
-					gfx_quads_setrotation(hadokenangle);
+					Graphics()->QuadsSetRotation(hadokenangle);
 					//float offsety = -data->weapons[iw].muzzleoffsety;
-					select_sprite(data->weapons.id[iw].sprite_muzzles[itex], 0);
+					RenderTools()->select_sprite(data->weapons.id[iw].sprite_muzzles[itex], 0);
 					vec2 diry(-dir.y,dir.x);
 					p = position;
 					float offsetx = data->weapons.id[iw].muzzleoffsetx;
 					p -= dir * offsetx;
-					draw_sprite(p.x, p.y, 160.0f);
+					RenderTools()->draw_sprite(p.x, p.y, 160.0f);
 				}
 			}
 		}
@@ -359,7 +360,7 @@ void PLAYERS::render_player(
 				recoil = sinf(a*pi);
 			p = position + dir * data->weapons.id[iw].offsetx - dir*recoil*10.0f;
 			p.y += data->weapons.id[iw].offsety;
-			draw_sprite(p.x, p.y, data->weapons.id[iw].visual_size);
+			RenderTools()->draw_sprite(p.x, p.y, data->weapons.id[iw].visual_size);
 		}
 
 		if (player.weapon == WEAPON_GUN || player.weapon == WEAPON_SHOTGUN)
@@ -379,18 +380,18 @@ void PLAYERS::render_player(
 				if (alpha > 0.0f && data->weapons.id[iw].sprite_muzzles[itex])
 				{
 					float offsety = -data->weapons.id[iw].muzzleoffsety;
-					select_sprite(data->weapons.id[iw].sprite_muzzles[itex], direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
+					RenderTools()->select_sprite(data->weapons.id[iw].sprite_muzzles[itex], direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0);
 					if(direction.x < 0)
 						offsety = -offsety;
 
 					vec2 diry(-dir.y,dir.x);
 					vec2 muzzlepos = p + dir * data->weapons.id[iw].muzzleoffsetx + diry * offsety;
 
-					draw_sprite(muzzlepos.x, muzzlepos.y, data->weapons.id[iw].visual_size);
+					RenderTools()->draw_sprite(muzzlepos.x, muzzlepos.y, data->weapons.id[iw].visual_size);
 				}
 			}
 		}
-		gfx_quads_end();
+		Graphics()->QuadsEnd();
 
 		switch (player.weapon)
 		{
@@ -408,27 +409,27 @@ void PLAYERS::render_player(
 		TEE_RENDER_INFO ghost = render_info;
 		ghost.color_body.a = 0.5f;
 		ghost.color_feet.a = 0.5f;
-		render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost
+		RenderTools()->RenderTee(&state, &ghost, player.emote, direction, ghost_position); // render ghost
 	}
 
 	render_info.size = 64.0f; // force some settings
 	render_info.color_body.a = 1.0f;
 	render_info.color_feet.a = 1.0f;
-	render_tee(&state, &render_info, player.emote, direction, position);
+	RenderTools()->RenderTee(&state, &render_info, player.emote, direction, position);
 
 	if(player.player_state == PLAYERSTATE_CHATTING)
 	{
-		gfx_texture_set(data->images[IMAGE_EMOTICONS].id);
-		gfx_quads_begin();
-		select_sprite(SPRITE_DOTDOT);
-		gfx_quads_draw(position.x + 24, position.y - 40, 64,64);
-		gfx_quads_end();
+		Graphics()->TextureSet(data->images[IMAGE_EMOTICONS].id);
+		Graphics()->QuadsBegin();
+		RenderTools()->select_sprite(SPRITE_DOTDOT);
+		Graphics()->QuadsDraw(position.x + 24, position.y - 40, 64,64);
+		Graphics()->QuadsEnd();
 	}
 
 	if (gameclient.clients[info.cid].emoticon_start != -1 && gameclient.clients[info.cid].emoticon_start + 2 * client_tickspeed() > client_tick())
 	{
-		gfx_texture_set(data->images[IMAGE_EMOTICONS].id);
-		gfx_quads_begin();
+		Graphics()->TextureSet(data->images[IMAGE_EMOTICONS].id);
+		Graphics()->QuadsBegin();
 
 		int since_start = client_tick() - gameclient.clients[info.cid].emoticon_start;
 		int from_end = gameclient.clients[info.cid].emoticon_start + 2 * client_tickspeed() - client_tick();
@@ -448,13 +449,13 @@ void PLAYERS::render_player(
 
 		float wiggle_angle = sin(5*wiggle);
 
-		gfx_quads_setrotation(pi/6*wiggle_angle);
+		Graphics()->QuadsSetRotation(pi/6*wiggle_angle);
 
-		gfx_setcolor(1.0f,1.0f,1.0f,a);
+		Graphics()->SetColor(1.0f,1.0f,1.0f,a);
 		// client_datas::emoticon is an offset from the first emoticon
-		select_sprite(SPRITE_OOP + gameclient.clients[info.cid].emoticon);
-		gfx_quads_draw(position.x, position.y - 23 - 32*h, 64, 64*h);
-		gfx_quads_end();
+		RenderTools()->select_sprite(SPRITE_OOP + gameclient.clients[info.cid].emoticon);
+		Graphics()->QuadsDraw(position.x, position.y - 23 - 32*h, 64, 64*h);
+		Graphics()->QuadsEnd();
 	}
 }
 
diff --git a/src/game/client/components/scoreboard.cpp b/src/game/client/components/scoreboard.cpp
index 2978eff9..e8db1aed 100644
--- a/src/game/client/components/scoreboard.cpp
+++ b/src/game/client/components/scoreboard.cpp
@@ -1,5 +1,6 @@
 #include <string.h>
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <game/generated/g_protocol.hpp>
 #include <game/generated/gc_data.hpp>
 #include <game/client/gameclient.hpp>
@@ -33,12 +34,12 @@ void SCOREBOARD::render_goals(float x, float y, float w)
 {
 	float h = 50.0f;
 
-	gfx_blend_normal();
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.5f);
-	draw_round_rect(x-10.f, y-10.f, w, h, 10.0f);
-	gfx_quads_end();
+	Graphics()->BlendNormal();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.5f);
+	RenderTools()->draw_round_rect(x-10.f, y-10.f, w, h, 10.0f);
+	Graphics()->QuadsEnd();
 
 	// render goals
 	//y = ystart+h-54;
@@ -76,12 +77,12 @@ void SCOREBOARD::render_spectators(float x, float y, float w)
 	
 	str_format(buffer, sizeof(buffer), "%s: ", localize("Spectators"));
 
-	gfx_blend_normal();
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.5f);
-	draw_round_rect(x-10.f, y-10.f, w, h, 10.0f);
-	gfx_quads_end();
+	Graphics()->BlendNormal();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.5f);
+	RenderTools()->draw_round_rect(x-10.f, y-10.f, w, h, 10.0f);
+	Graphics()->QuadsEnd();
 	
 	for(int i = 0; i < snap_num_items(SNAP_CURRENT); i++)
 	{
@@ -109,12 +110,12 @@ void SCOREBOARD::render_scoreboard(float x, float y, float w, int team, const ch
 	//float ystart = y;
 	float h = 750.0f;
 
-	gfx_blend_normal();
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(0,0,0,0.5f);
-	draw_round_rect(x-10.f, y-10.f, w, h, 17.0f);
-	gfx_quads_end();
+	Graphics()->BlendNormal();
+	Graphics()->TextureSet(-1);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(0,0,0,0.5f);
+	RenderTools()->draw_round_rect(x-10.f, y-10.f, w, h, 17.0f);
+	Graphics()->QuadsEnd();
 
 	// render title
 	if(!title)
@@ -210,11 +211,11 @@ void SCOREBOARD::render_scoreboard(float x, float y, float w, int team, const ch
 		if(info->local)
 		{
 			// background so it's easy to find the local player
-			gfx_texture_set(-1);
-			gfx_quads_begin();
-			gfx_setcolor(1,1,1,0.25f);
-			draw_round_rect(x, y, w-20, line_height*0.95f, 17.0f);
-			gfx_quads_end();
+			Graphics()->TextureSet(-1);
+			Graphics()->QuadsBegin();
+			Graphics()->SetColor(1,1,1,0.25f);
+			RenderTools()->draw_round_rect(x, y, w-20, line_height*0.95f, 17.0f);
+			Graphics()->QuadsEnd();
 		}
 
 		str_format(buf, sizeof(buf), "%4d", info->score);
@@ -230,21 +231,21 @@ void SCOREBOARD::render_scoreboard(float x, float y, float w, int team, const ch
 		if((gameclient.snap.flags[0] && gameclient.snap.flags[0]->carried_by == info->cid) ||
 			(gameclient.snap.flags[1] && gameclient.snap.flags[1]->carried_by == info->cid))
 		{
-			gfx_blend_normal();
-			gfx_texture_set(data->images[IMAGE_GAME].id);
-			gfx_quads_begin();
+			Graphics()->BlendNormal();
+			Graphics()->TextureSet(data->images[IMAGE_GAME].id);
+			Graphics()->QuadsBegin();
 
-			if(info->team == 0) select_sprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X);
-			else select_sprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
+			if(info->team == 0) RenderTools()->select_sprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X);
+			else RenderTools()->select_sprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
 			
 			float size = 64.0f;
-			gfx_quads_drawTL(x+55, y-15, size/2, size);
-			gfx_quads_end();
+			Graphics()->QuadsDrawTL(x+55, y-15, size/2, size);
+			Graphics()->QuadsEnd();
 		}
 		
 		TEE_RENDER_INFO teeinfo = gameclient.clients[info->cid].render_info;
 		teeinfo.size *= tee_sizemod;
-		render_tee(ANIMSTATE::get_idle(), &teeinfo, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28+tee_offset));
+		RenderTools()->RenderTee(ANIMSTATE::get_idle(), &teeinfo, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28+tee_offset));
 
 		
 		y += line_height;
@@ -278,10 +279,10 @@ void SCOREBOARD::on_render()
 		gameclient.motd->clear();
 	
 
-	float width = 400*3.0f*gfx_screenaspect();
+	float width = 400*3.0f*Graphics()->ScreenAspect();
 	float height = 400*3.0f;
 	
-	gfx_mapscreen(0, 0, width, height);
+	Graphics()->MapScreen(0, 0, width, height);
 
 	float w = 650.0f;
 
diff --git a/src/game/client/components/skins.cpp b/src/game/client/components/skins.cpp
index 451a77f3..ad3607a1 100644
--- a/src/game/client/components/skins.cpp
+++ b/src/game/client/components/skins.cpp
@@ -6,12 +6,10 @@
 #include <base/system.h>
 #include <base/math.hpp>
 
+#include <engine/client/graphics.h>
 #include <engine/e_client_interface.h>
 
-extern "C"
-{
-	#include <engine/e_engine.h>
-}
+#include <engine/e_engine.h>
 
 #include "skins.hpp"
 
@@ -32,13 +30,13 @@ void SKINS::skinscan(const char *name, int is_dir, void *user)
 	char buf[512];
 	str_format(buf, sizeof(buf), "skins/%s", name);
 	IMAGE_INFO info;
-	if(!gfx_load_png(&info, buf))
+	if(!self->Graphics()->LoadPNG(&info, buf))
 	{
 		dbg_msg("game", "failed to load skin from %s", name);
 		return;
 	}
 	
-	self->skins[self->num_skins].org_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data, info.format, 0);
+	self->skins[self->num_skins].org_texture = self->Graphics()->LoadTextureRaw(info.width, info.height, info.format, info.data, info.format, 0);
 	
 	int body_size = 96; // body size
 	unsigned char *d = (unsigned char *)info.data;
@@ -111,7 +109,7 @@ void SKINS::skinscan(const char *name, int is_dir, void *user)
 			}
 	}
 	
-	self->skins[self->num_skins].color_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data, info.format, 0);
+	self->skins[self->num_skins].color_texture = self->Graphics()->LoadTextureRaw(info.width, info.height, info.format, info.data, info.format, 0);
 	mem_free(info.data);
 
 	// set skin data	
diff --git a/src/game/client/components/voting.cpp b/src/game/client/components/voting.cpp
index 190ba224..dcf5c954 100644
--- a/src/game/client/components/voting.cpp
+++ b/src/game/client/components/voting.cpp
@@ -143,30 +143,30 @@ void VOTING::on_render()
 }
 
 
-void VOTING::render_bars(RECT bars, bool text)
+void VOTING::render_bars(CUIRect bars, bool text)
 {
-	ui_draw_rect(&bars, vec4(0.8f,0.8f,0.8f,0.5f), CORNER_ALL, bars.h/3);
+	RenderTools()->DrawUIRect(&bars, vec4(0.8f,0.8f,0.8f,0.5f), CUI::CORNER_ALL, bars.h/3);
 	
-	RECT splitter = bars;
+	CUIRect splitter = bars;
 	splitter.x = splitter.x+splitter.w/2;
 	splitter.w = splitter.h/2.0f;
 	splitter.x -= splitter.w/2;
-	ui_draw_rect(&splitter, vec4(0.4f,0.4f,0.4f,0.5f), CORNER_ALL, splitter.h/4);
+	RenderTools()->DrawUIRect(&splitter, vec4(0.4f,0.4f,0.4f,0.5f), CUI::CORNER_ALL, splitter.h/4);
 			
 	if(total)
 	{
-		RECT pass_area = bars;
+		CUIRect pass_area = bars;
 		if(yes)
 		{
-			RECT yes_area = bars;
+			CUIRect yes_area = bars;
 			yes_area.w *= yes/(float)total;
-			ui_draw_rect(&yes_area, vec4(0.2f,0.9f,0.2f,0.85f), CORNER_ALL, bars.h/3);
+			RenderTools()->DrawUIRect(&yes_area, vec4(0.2f,0.9f,0.2f,0.85f), CUI::CORNER_ALL, bars.h/3);
 			
 			if(text)
 			{
 				char buf[256];
 				str_format(buf, sizeof(buf), "%d", yes);
-				ui_do_label(&yes_area, buf, bars.h*0.75f, 0);
+				UI()->DoLabel(&yes_area, buf, bars.h*0.75f, 0);
 			}
 			
 			pass_area.x += yes_area.w;
@@ -175,16 +175,16 @@ void VOTING::render_bars(RECT bars, bool text)
 		
 		if(no)
 		{
-			RECT no_area = bars;
+			CUIRect no_area = bars;
 			no_area.w *= no/(float)total;
 			no_area.x = (bars.x + bars.w)-no_area.w;
-			ui_draw_rect(&no_area, vec4(0.9f,0.2f,0.2f,0.85f), CORNER_ALL, bars.h/3);
+			RenderTools()->DrawUIRect(&no_area, vec4(0.9f,0.2f,0.2f,0.85f), CUI::CORNER_ALL, bars.h/3);
 			
 			if(text)
 			{
 				char buf[256];
 				str_format(buf, sizeof(buf), "%d", no);
-				ui_do_label(&no_area, buf, bars.h*0.75f, 0);
+				UI()->DoLabel(&no_area, buf, bars.h*0.75f, 0);
 			}
 
 			pass_area.w -= no_area.w;
@@ -194,7 +194,7 @@ void VOTING::render_bars(RECT bars, bool text)
 		{
 			char buf[256];
 			str_format(buf, sizeof(buf), "%d", pass);
-			ui_do_label(&pass_area, buf, bars.h*0.75f, 0);
+			UI()->DoLabel(&pass_area, buf, bars.h*0.75f, 0);
 		}
 	}	
 }
diff --git a/src/game/client/components/voting.hpp b/src/game/client/components/voting.hpp
index 3341edea..e04e1840 100644
--- a/src/game/client/components/voting.hpp
+++ b/src/game/client/components/voting.hpp
@@ -1,10 +1,6 @@
 #include <game/client/component.hpp>
 #include <game/client/ui.hpp>
-
-extern "C"
-{
-	#include <engine/e_memheap.h>
-}
+#include <engine/e_memheap.h>
 
 class VOTING : public COMPONENT
 {
@@ -38,7 +34,7 @@ public:
 	virtual void on_message(int msgtype, void *rawmsg);
 	virtual void on_render();
 	
-	void render_bars(RECT bars, bool text);
+	void render_bars(CUIRect bars, bool text);
 	
 	void callvote_kick(int client_id);
 	void callvote_option(int option);
diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp
index fa2f4de0..25a42620 100644
--- a/src/game/client/gameclient.cpp
+++ b/src/game/client/gameclient.cpp
@@ -1,5 +1,6 @@
 #include <string.h>
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 #include <engine/e_demorec.h>
 
 #include <game/generated/g_protocol.hpp>
@@ -269,6 +270,13 @@ void GAMECLIENT::on_init()
 	// set the language
 	localization.load(config.cl_languagefile);
 	
+	// propagate pointers
+	m_UI.SetGraphics(Graphics());
+	m_RenderTools.m_pGraphics = Graphics();
+	m_RenderTools.m_pUI = UI();
+	for(int i = 0; i < all.num; i++)
+		all.components[i]->client = this;
+	
 	// init all components
 	for(int i = 0; i < all.num; i++)
 		all.components[i]->on_init();
@@ -297,7 +305,7 @@ void GAMECLIENT::on_init()
 	for(int i = 0; i < data->num_images; i++)
 	{
 		gameclient.menus->render_loading(load_current/load_total);
-		data->images[i].id = gfx_load_texture(data->images[i].filename, IMG_AUTO, 0);
+		data->images[i].id = Graphics()->LoadTexture(data->images[i].filename, IMG_AUTO, 0);
 		load_current++;
 	}
 
@@ -366,7 +374,7 @@ void GAMECLIENT::on_connected()
 {
 	layers_init();
 	col_init();
-	render_tilemap_generate_skip();
+	RenderTools()->render_tilemap_generate_skip();
 
 	for(int i = 0; i < all.num; i++)
 	{
@@ -450,6 +458,21 @@ static void evolve(NETOBJ_CHARACTER *character, int tick)
 
 void GAMECLIENT::on_render()
 {
+	/*Graphics()->Clear(1,0,0);
+	
+	menus->render_background();
+	return;*/
+	/*
+	Graphics()->Clear(1,0,0);
+	Graphics()->MapScreen(0,0,100,100);
+	
+	Graphics()->QuadsBegin();
+		Graphics()->SetColor(1,1,1,1);
+		Graphics()->QuadsDraw(50, 50, 30, 30);
+	Graphics()->QuadsEnd();
+	
+	return;*/
+	
 	// update the local character position
 	update_local_character_pos();
 	
@@ -972,3 +995,17 @@ void GAMECLIENT::conchain_special_infoupdate(void *result, void *user_data, CONS
 	if(console_arg_num(result))
 		((GAMECLIENT*)user_data)->send_info(false);
 }
+
+void GAMECLIENT::SetEngine(class IEngine *pEngine)
+{
+	m_pEngine = pEngine;
+	
+	// digg out some pointers
+	m_pGraphics = m_pEngine->Graphics();
+}
+
+IGameClient *CreateGameClient(IEngine *pEngine)
+{
+	gameclient.SetEngine(pEngine);
+	return &gameclient;
+}
diff --git a/src/game/client/gameclient.hpp b/src/game/client/gameclient.hpp
index e354430d..1da40de0 100644
--- a/src/game/client/gameclient.hpp
+++ b/src/game/client/gameclient.hpp
@@ -1,10 +1,13 @@
+#ifndef FILE_GAMECLIENT_HPP
+#define FILE_GAMECLIENT_HPP
 
 #include <base/vmath.hpp>
 #include <engine/e_console.h>
+#include <engine/client/client.h>
 #include <game/gamecore.hpp>
 #include "render.hpp"
 
-class GAMECLIENT
+class GAMECLIENT : public IGameClient
 {
 	class STACK
 	{
@@ -24,6 +27,9 @@ class GAMECLIENT
 	STACK all;
 	STACK input;
 	
+	class IGraphics *m_pGraphics;
+	class IEngine *m_pEngine;
+	CUI m_UI;
 	
 	void dispatch_input();
 	void process_events();
@@ -38,6 +44,12 @@ class GAMECLIENT
 	static void conchain_special_infoupdate(void *result, void *user_data, CONSOLE_CALLBACK cb, void *cbuser);
 	
 public:
+	class IGraphics *Graphics() const { return m_pGraphics; }
+	class CUI *UI() { return &m_UI; }
+	class CRenderTools *RenderTools() { return &m_RenderTools; }
+	
+	void SetEngine(class IEngine *pEngine);
+
 	bool suppress_events;
 	bool new_tick;
 	bool new_predicted_tick;
@@ -120,6 +132,8 @@ public:
 
 	CLIENT_DATA clients[MAX_CLIENTS];
 	
+	CRenderTools m_RenderTools;
+	
 	void on_reset();
 
 	// hooks
@@ -158,6 +172,10 @@ public:
 	class VOTING *voting;
 };
 
+
+// TODO: Refactor: Remove this
 extern GAMECLIENT gameclient;
 
 extern const char *localize(const char *str);
+
+#endif
diff --git a/src/game/client/render.cpp b/src/game/client/render.cpp
index f63e8692..f271c7d2 100644
--- a/src/game/client/render.cpp
+++ b/src/game/client/render.cpp
@@ -5,6 +5,7 @@
 
 #include <engine/e_client_interface.h>
 #include <engine/e_config.h>
+#include <engine/client/graphics.h>
 #include <game/generated/gc_data.hpp>
 #include <game/generated/g_protocol.hpp>
 #include <game/layers.hpp>
@@ -13,13 +14,15 @@
 
 static float sprite_w_scale;
 static float sprite_h_scale;
+
+
 /*
 static void layershot_begin()
 {
 	if(!config.cl_layershot)
 		return;
 
-	gfx_clear(0,0,0);
+	Graphics()->Clear(0,0,0);
 }
 
 static void layershot_end()
@@ -33,7 +36,7 @@ static void layershot_end()
 	config.cl_layershot++;
 }*/
 
-void select_sprite(SPRITE *spr, int flags, int sx, int sy)
+void CRenderTools::select_sprite(SPRITE *spr, int flags, int sx, int sy)
 {
 	int x = spr->x+sx;
 	int y = spr->y+sy;
@@ -66,22 +69,22 @@ void select_sprite(SPRITE *spr, int flags, int sx, int sy)
 		x2 = temp;
 	}
 	
-	gfx_quads_setsubset(x1, y1, x2, y2);
+	Graphics()->QuadsSetSubset(x1, y1, x2, y2);
 }
 
-void select_sprite(int id, int flags, int sx, int sy)
+void CRenderTools::select_sprite(int id, int flags, int sx, int sy)
 {
 	if(id < 0 || id > data->num_sprites)
 		return;
 	select_sprite(&data->sprites[id], flags, sx, sy);
 }
 
-void draw_sprite(float x, float y, float size)
+void CRenderTools::draw_sprite(float x, float y, float size)
 {
-	gfx_quads_draw(x, y, size*sprite_w_scale, size*sprite_h_scale);
+	Graphics()->QuadsDraw(x, y, size*sprite_w_scale, size*sprite_h_scale);
 }
 
-void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners)
+void CRenderTools::draw_round_rect_ext(float x, float y, float w, float h, float r, int corners)
 {
 	int num = 8;
 	for(int i = 0; i < num; i+=2)
@@ -97,69 +100,73 @@ void draw_round_rect_ext(float x, float y, float w, float h, float r, int corner
 		float sa3 = sinf(a3);
 
 		if(corners&1) // TL
-		gfx_quads_draw_freeform(
+		Graphics()->QuadsDrawFreeform(
 			x+r, y+r,
 			x+(1-ca1)*r, y+(1-sa1)*r,
 			x+(1-ca3)*r, y+(1-sa3)*r,
 			x+(1-ca2)*r, y+(1-sa2)*r);
 
 		if(corners&2) // TR
-		gfx_quads_draw_freeform(
+		Graphics()->QuadsDrawFreeform(
 			x+w-r, y+r,
 			x+w-r+ca1*r, y+(1-sa1)*r,
 			x+w-r+ca3*r, y+(1-sa3)*r,
 			x+w-r+ca2*r, y+(1-sa2)*r);
 
 		if(corners&4) // BL
-		gfx_quads_draw_freeform(
+		Graphics()->QuadsDrawFreeform(
 			x+r, y+h-r,
 			x+(1-ca1)*r, y+h-r+sa1*r,
 			x+(1-ca3)*r, y+h-r+sa3*r,
 			x+(1-ca2)*r, y+h-r+sa2*r);
 
 		if(corners&8) // BR
-		gfx_quads_draw_freeform(
+		Graphics()->QuadsDrawFreeform(
 			x+w-r, y+h-r,
 			x+w-r+ca1*r, y+h-r+sa1*r,
 			x+w-r+ca3*r, y+h-r+sa3*r,
 			x+w-r+ca2*r, y+h-r+sa2*r);
 	}
 
-	gfx_quads_drawTL(x+r, y+r, w-r*2, h-r*2); // center
-	gfx_quads_drawTL(x+r, y, w-r*2, r); // top
-	gfx_quads_drawTL(x+r, y+h-r, w-r*2, r); // bottom
-	gfx_quads_drawTL(x, y+r, r, h-r*2); // left
-	gfx_quads_drawTL(x+w-r, y+r, r, h-r*2); // right
+	Graphics()->QuadsDrawTL(x+r, y+r, w-r*2, h-r*2); // center
+	Graphics()->QuadsDrawTL(x+r, y, w-r*2, r); // top
+	Graphics()->QuadsDrawTL(x+r, y+h-r, w-r*2, r); // bottom
+	Graphics()->QuadsDrawTL(x, y+r, r, h-r*2); // left
+	Graphics()->QuadsDrawTL(x+w-r, y+r, r, h-r*2); // right
 	
-	if(!(corners&1)) gfx_quads_drawTL(x, y, r, r); // TL
-	if(!(corners&2)) gfx_quads_drawTL(x+w, y, -r, r); // TR
-	if(!(corners&4)) gfx_quads_drawTL(x, y+h, r, -r); // BL
-	if(!(corners&8)) gfx_quads_drawTL(x+w, y+h, -r, -r); // BR
+	if(!(corners&1)) Graphics()->QuadsDrawTL(x, y, r, r); // TL
+	if(!(corners&2)) Graphics()->QuadsDrawTL(x+w, y, -r, r); // TR
+	if(!(corners&4)) Graphics()->QuadsDrawTL(x, y+h, r, -r); // BL
+	if(!(corners&8)) Graphics()->QuadsDrawTL(x+w, y+h, -r, -r); // BR
 }
 
-void draw_round_rect(float x, float y, float w, float h, float r)
+void CRenderTools::draw_round_rect(float x, float y, float w, float h, float r)
 {
 	draw_round_rect_ext(x,y,w,h,r,0xf);
 }
 
-void ui_draw_rect(const RECT *r, vec4 color, int corners, float rounding)
+void CRenderTools::DrawUIRect(const CUIRect *r, vec4 color, int corners, float rounding)
 {
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(color.r, color.g, color.b, color.a);
-	draw_round_rect_ext(r->x,r->y,r->w,r->h,rounding*ui_scale(), corners);
-	gfx_quads_end();
+	Graphics()->TextureSet(-1);
+	
+	// TODO: FIX US
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(color.r, color.g, color.b, color.a);
+	draw_round_rect_ext(r->x,r->y,r->w,r->h,rounding*UI()->Scale(), corners);
+	Graphics()->QuadsEnd();
 }
 
-void render_tee(ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec2 pos)
+void CRenderTools::RenderTee(ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec2 pos)
 {
 	vec2 direction = dir;
 	vec2 position = pos;
 
-	//gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id);
-	gfx_texture_set(info->texture);
-	gfx_quads_begin();
-	//gfx_quads_draw(pos.x, pos.y-128, 128, 128);
+	//Graphics()->TextureSet(data->images[IMAGE_CHAR_DEFAULT].id);
+	Graphics()->TextureSet(info->texture);
+	
+	// TODO: FIX ME
+	Graphics()->QuadsBegin();
+	//Graphics()->QuadsDraw(pos.x, pos.y-128, 128, 128);
 
 	// first pass we draw the outline
 	// second pass we draw the filling
@@ -173,13 +180,13 @@ void render_tee(ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec
 			float basesize = info->size;
 			if(f == 1)
 			{
-				gfx_quads_setrotation(anim->body.angle*pi*2);
+				Graphics()->QuadsSetRotation(anim->body.angle*pi*2);
 
 				// draw body
-				gfx_setcolor(info->color_body.r, info->color_body.g, info->color_body.b, 1.0f);
+				Graphics()->SetColor(info->color_body.r, info->color_body.g, info->color_body.b, 1.0f);
 				vec2 body_pos = position + vec2(anim->body.x, anim->body.y)*animscale;
 				select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0);
-				gfx_quads_draw(body_pos.x, body_pos.y, basesize, basesize);
+				Graphics()->QuadsDraw(body_pos.x, body_pos.y, basesize, basesize);
 
 				// draw eyes
 				if(p == 1)
@@ -207,8 +214,8 @@ void render_tee(ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec
 					float h = emote == EMOTE_BLINK ? basesize*0.15f : eyescale;
 					float eyeseparation = (0.075f - 0.010f*fabs(direction.x))*basesize;
 					vec2 offset = vec2(direction.x*0.125f, -0.05f+direction.y*0.10f)*basesize;
-					gfx_quads_draw(body_pos.x-eyeseparation+offset.x, body_pos.y+offset.y, eyescale, h);
-					gfx_quads_draw(body_pos.x+eyeseparation+offset.x, body_pos.y+offset.y, -eyescale, h);
+					Graphics()->QuadsDraw(body_pos.x-eyeseparation+offset.x, body_pos.y+offset.y, eyescale, h);
+					Graphics()->QuadsDraw(body_pos.x+eyeseparation+offset.x, body_pos.y+offset.y, -eyescale, h);
 				}
 			}
 
@@ -218,7 +225,7 @@ void render_tee(ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec
 			float w = basesize;
 			float h = basesize/2;
 
-			gfx_quads_setrotation(foot->angle*pi*2);
+			Graphics()->QuadsSetRotation(foot->angle*pi*2);
 			
 			bool indicate = !info->got_airjump && config.cl_airjumpindicator;
 			float cs = 1.0f; // color scale
@@ -232,12 +239,12 @@ void render_tee(ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec
 					cs = 0.5f;
 			}
 				
-			gfx_setcolor(info->color_feet.r*cs, info->color_feet.g*cs, info->color_feet.b*cs, 1.0f);
-			gfx_quads_draw(position.x+foot->x*animscale, position.y+foot->y*animscale, w, h);
+			Graphics()->SetColor(info->color_feet.r*cs, info->color_feet.g*cs, info->color_feet.b*cs, 1.0f);
+			Graphics()->QuadsDraw(position.x+foot->x*animscale, position.y+foot->y*animscale, w, h);
 		}
 	}
 
-	gfx_quads_end();
+	Graphics()->QuadsEnd();
 	
 	
 }
@@ -262,7 +269,7 @@ static void calc_screen_params(float amount, float wmax, float hmax, float aspec
 	}
 }
 
-void mapscreen_to_world(float center_x, float center_y, float parallax_x, float parallax_y,
+void CRenderTools::mapscreen_to_world(float center_x, float center_y, float parallax_x, float parallax_y,
 	float offset_x, float offset_y, float aspect, float zoom, float *points)
 {
 	float width, height;
@@ -277,7 +284,7 @@ void mapscreen_to_world(float center_x, float center_y, float parallax_x, float
 	points[3] = offset_y+center_y+height/2;
 }
 
-void render_tilemap_generate_skip()
+void CRenderTools::render_tilemap_generate_skip()
 {
 	for(int g = 0; g < layers_num_groups(); g++)
 	{
diff --git a/src/game/client/render.hpp b/src/game/client/render.hpp
index 9ce555d2..8e99b432 100644
--- a/src/game/client/render.hpp
+++ b/src/game/client/render.hpp
@@ -7,6 +7,7 @@
 #include "../mapitems.hpp"
 #include "ui.hpp"
 
+
 struct TEE_RENDER_INFO
 {
 	TEE_RENDER_INFO()
@@ -37,32 +38,44 @@ enum
 	TILERENDERFLAG_EXTEND=4,
 };
 
-//typedef struct SPRITE;
 
-void select_sprite(struct SPRITE *spr, int flags=0, int sx=0, int sy=0);
-void select_sprite(int id, int flags=0, int sx=0, int sy=0);
+class CRenderTools
+{
+public:
+	class IGraphics *m_pGraphics;
+	class CUI *m_pUI;
+	
+	class IGraphics *Graphics() const { return m_pGraphics; }
+	class CUI *UI() const { return m_pUI; }
 
-void draw_sprite(float x, float y, float size);
+	//typedef struct SPRITE;
 
-// rects
-void draw_round_rect(float x, float y, float w, float h, float r);
-void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners);
-void ui_draw_rect(const RECT *r, vec4 color, int corners, float rounding);
+	void select_sprite(struct SPRITE *spr, int flags=0, int sx=0, int sy=0);
+	void select_sprite(int id, int flags=0, int sx=0, int sy=0);
 
-// larger rendering methods
-void render_tilemap_generate_skip();
+	void draw_sprite(float x, float y, float size);
 
-// object render methods (gc_render_obj.cpp)
-void render_tee(class ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec2 pos);
+	// rects
+	void draw_round_rect(float x, float y, float w, float h, float r);
+	void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners);
+	
+	void DrawUIRect(const CUIRect *r, vec4 color, int corners, float rounding);
 
-// map render methods (gc_render_map.cpp)
-void render_eval_envelope(ENVPOINT *points, int num_points, int channels, float time, float *result);
-void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, int env, float *channels), int flags);
-void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flags);
+	// larger rendering methods
+	void render_tilemap_generate_skip();
 
-// helpers
-void mapscreen_to_world(float center_x, float center_y, float parallax_x, float parallax_y,
-	float offset_x, float offset_y, float aspect, float zoom, float *points);
+	// object render methods (gc_render_obj.cpp)
+	void RenderTee(class ANIMSTATE *anim, TEE_RENDER_INFO *info, int emote, vec2 dir, vec2 pos);
 
+	// map render methods (gc_render_map.cpp)
+	static void render_eval_envelope(ENVPOINT *points, int num_points, int channels, float time, float *result);
+	void render_quads(QUAD *quads, int num_quads, int flags, void (*eval)(float time_offset, int env, float *channels, void *user), void *user);
+	void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flags);
+
+	// helpers
+	void mapscreen_to_world(float center_x, float center_y, float parallax_x, float parallax_y,
+		float offset_x, float offset_y, float aspect, float zoom, float *points);	
+	
+};
 
 #endif
diff --git a/src/game/client/render_map.cpp b/src/game/client/render_map.cpp
index 118a4d73..ea3b8420 100644
--- a/src/game/client/render_map.cpp
+++ b/src/game/client/render_map.cpp
@@ -2,10 +2,11 @@
 #include <math.h>
 #include <base/math.hpp>
 #include <engine/e_client_interface.h>
+#include <engine/client/graphics.h>
 
 #include "render.hpp"
 
-void render_eval_envelope(ENVPOINT *points, int num_points, int channels, float time, float *result)
+void CRenderTools::render_eval_envelope(ENVPOINT *points, int num_points, int channels, float time, float *result)
 {
 	if(num_points == 0)
 	{
@@ -77,9 +78,9 @@ static void rotate(POINT *center, POINT *point, float rotation)
 	point->y = (int)(x * sinf(rotation) + y * cosf(rotation) + center->y);
 }
 
-void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, int env, float *channels), int renderflags)
+void CRenderTools::render_quads(QUAD *quads, int num_quads, int renderflags, void (*eval)(float time_offset, int env, float *channels, void *user), void *user)
 {
-	gfx_quads_begin();
+	Graphics()->QuadsBegin();
 	float conv = 1/255.0f;
 	for(int i = 0; i < num_quads; i++)
 	{
@@ -90,7 +91,7 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 		if(q->color_env >= 0)
 		{
 			float channels[4];
-			eval(q->color_env_offset/1000.0f, q->color_env, channels);
+			eval(q->color_env_offset/1000.0f, q->color_env, channels, user);
 			r = channels[0];
 			g = channels[1];
 			b = channels[2];
@@ -106,7 +107,7 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 		if(!opaque && !(renderflags&LAYERRENDERFLAG_TRANSPARENT))
 			continue;
 		
-		gfx_quads_setsubset_free(
+		Graphics()->QuadsSetSubsetFree(
 			fx2f(q->texcoords[0].x), fx2f(q->texcoords[0].y),
 			fx2f(q->texcoords[1].x), fx2f(q->texcoords[1].y),
 			fx2f(q->texcoords[2].x), fx2f(q->texcoords[2].y),
@@ -121,17 +122,17 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 		if(q->pos_env >= 0)
 		{
 			float channels[4];
-			eval(q->pos_env_offset/1000.0f, q->pos_env, channels);
+			eval(q->pos_env_offset/1000.0f, q->pos_env, channels, user);
 			offset_x = channels[0];
 			offset_y = channels[1];
 			rot = channels[2]/360.0f*pi*2;
 		}
 		
 		
-		gfx_setcolorvertex(0, q->colors[0].r*conv*r, q->colors[0].g*conv*g, q->colors[0].b*conv*b, q->colors[0].a*conv*a);
-		gfx_setcolorvertex(1, q->colors[1].r*conv*r, q->colors[1].g*conv*g, q->colors[1].b*conv*b, q->colors[1].a*conv*a);
-		gfx_setcolorvertex(2, q->colors[2].r*conv*r, q->colors[2].g*conv*g, q->colors[2].b*conv*b, q->colors[2].a*conv*a);
-		gfx_setcolorvertex(3, q->colors[3].r*conv*r, q->colors[3].g*conv*g, q->colors[3].b*conv*b, q->colors[3].a*conv*a);
+		Graphics()->SetColorVertex(0, q->colors[0].r*conv*r, q->colors[0].g*conv*g, q->colors[0].b*conv*b, q->colors[0].a*conv*a);
+		Graphics()->SetColorVertex(1, q->colors[1].r*conv*r, q->colors[1].g*conv*g, q->colors[1].b*conv*b, q->colors[1].a*conv*a);
+		Graphics()->SetColorVertex(2, q->colors[2].r*conv*r, q->colors[2].g*conv*g, q->colors[2].b*conv*b, q->colors[2].a*conv*a);
+		Graphics()->SetColorVertex(3, q->colors[3].r*conv*r, q->colors[3].g*conv*g, q->colors[3].b*conv*b, q->colors[3].a*conv*a);
 
 		POINT *points = q->points;
 	
@@ -150,30 +151,30 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 			rotate(&q->points[4], &rotated[3], rot);
 		}
 		
-		gfx_quads_draw_freeform(
+		Graphics()->QuadsDrawFreeform(
 			fx2f(points[0].x)+offset_x, fx2f(points[0].y)+offset_y,
 			fx2f(points[1].x)+offset_x, fx2f(points[1].y)+offset_y,
 			fx2f(points[2].x)+offset_x, fx2f(points[2].y)+offset_y,
 			fx2f(points[3].x)+offset_x, fx2f(points[3].y)+offset_y
 		);
 	}
-	gfx_quads_end();	
+	Graphics()->QuadsEnd();	
 }
 
-void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int renderflags)
+void CRenderTools::render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int renderflags)
 {
-	//gfx_texture_set(img_get(tmap->image));
+	//Graphics()->TextureSet(img_get(tmap->image));
 	float screen_x0, screen_y0, screen_x1, screen_y1;
-	gfx_getscreen(&screen_x0, &screen_y0, &screen_x1, &screen_y1);
-	//gfx_mapscreen(screen_x0-50, screen_y0-50, screen_x1+50, screen_y1+50);
+	Graphics()->GetScreen(&screen_x0, &screen_y0, &screen_x1, &screen_y1);
+	//Graphics()->MapScreen(screen_x0-50, screen_y0-50, screen_x1+50, screen_y1+50);
 
 	// calculate the final pixelsize for the tiles	
 	float tile_pixelsize = 1024/32.0f;
-	float final_tilesize = scale/(screen_x1-screen_x0) * gfx_screenwidth();
+	float final_tilesize = scale/(screen_x1-screen_x0) * Graphics()->ScreenWidth();
 	float final_tilesize_scale = final_tilesize/tile_pixelsize;
 	
-	gfx_quads_begin();
-	gfx_setcolor(color.r, color.g, color.b, color.a);
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(color.r, color.g, color.b, color.a);
 	
 	int starty = (int)(screen_y0/scale)-1;
 	int startx = (int)(screen_x0/scale)-1;
@@ -262,13 +263,13 @@ void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int rend
 						v1 = tmp;
 					}
 					
-					gfx_quads_setsubset(u0,v0,u1,v1);
-					gfx_quads_drawTL(x*scale, y*scale, scale, scale);
+					Graphics()->QuadsSetSubset(u0,v0,u1,v1);
+					Graphics()->QuadsDrawTL(x*scale, y*scale, scale, scale);
 				}
 			}
 			x += tiles[c].skip;
 		}
 	
-	gfx_quads_end();
-	gfx_mapscreen(screen_x0, screen_y0, screen_x1, screen_y1);
+	Graphics()->QuadsEnd();
+	Graphics()->MapScreen(screen_x0, screen_y0, screen_x1, screen_y1);
 }
diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp
index 1361b85c..4aaaf32f 100644
--- a/src/game/client/ui.cpp
+++ b/src/game/client/ui.cpp
@@ -3,101 +3,95 @@
 
 #include <engine/e_client_interface.h>
 #include <engine/e_config.h>
+#include <engine/client/graphics.h>
 #include "ui.hpp"
 
 /********************************************************
  UI                                                      
 *********************************************************/
-static const void *hot_item = 0;
-static const void *active_item = 0;
-static const void *last_active_item = 0;
-static const void *becomming_hot_item = 0;
-static float mouse_x, mouse_y; /* in gui space */
-static float mouse_wx, mouse_wy; /* in world space */
-static unsigned mouse_buttons = 0;
-static unsigned last_mouse_buttons = 0;
-
-float ui_mouse_x() { return mouse_x; }
-float ui_mouse_y() { return mouse_y; }
-float ui_mouse_world_x() { return mouse_wx; }
-float ui_mouse_world_y() { return mouse_wy; }
-int ui_mouse_button(int index) { return (mouse_buttons>>index)&1; }
-int ui_mouse_button_clicked(int index) { return ui_mouse_button(index) && !((last_mouse_buttons>>index)&1) ; }
-
-void ui_set_hot_item(const void *id) { becomming_hot_item = id; }
-void ui_set_active_item(const void *id) { active_item = id; if (id) last_active_item = id; }
-void ui_clear_last_active_item() { last_active_item = 0; }
-const void *ui_hot_item() { return hot_item; }
-const void *ui_next_hot_item() { return becomming_hot_item; }
-const void *ui_active_item() { return active_item; }
-const void *ui_last_active_item() { return last_active_item; }
-
-int ui_update(float mx, float my, float mwx, float mwy, int buttons)
+
+CUI::CUI()
+{
+	m_pHotItem = 0;
+	m_pActiveItem = 0;
+	m_pLastActiveItem = 0;
+	m_pBecommingHotItem = 0;
+	
+	m_MouseX = 0;
+	m_MouseY = 0;
+	m_MouseWorldX = 0;
+	m_MouseWorldY = 0;
+	m_MouseButtons = 0;
+	m_LastMouseButtons = 0;	
+	
+	m_Screen.x = 0;
+	m_Screen.y = 0;
+	m_Screen.w = 848.0f;
+	m_Screen.h = 480.0f;
+}
+
+int CUI::Update(float mx, float my, float mwx, float mwy, int Buttons)
 {
-    mouse_x = mx;
-    mouse_y = my;
-    mouse_wx = mwx;
-    mouse_wy = mwy;
-    last_mouse_buttons = mouse_buttons;
-    mouse_buttons = buttons;
-    hot_item = becomming_hot_item;
-    if(active_item)
-    	hot_item = active_item;
-    becomming_hot_item = 0;
+    m_MouseX = mx;
+    m_MouseY = my;
+    m_MouseWorldX = mwx;
+    m_MouseWorldY = mwy;
+    m_LastMouseButtons = m_MouseButtons;
+    m_MouseButtons = Buttons;
+    m_pHotItem = m_pBecommingHotItem;
+    if(m_pActiveItem)
+    	m_pHotItem = m_pActiveItem;
+    m_pBecommingHotItem = 0;
     return 0;
 }
-/*
-bool ui_
-*/
-int ui_mouse_inside(const RECT *r)
+
+int CUI::MouseInside(const CUIRect *r)
 {
-    if(mouse_x >= r->x && mouse_x <= r->x+r->w && mouse_y >= r->y && mouse_y <= r->y+r->h)
+    if(m_MouseX >= r->x && m_MouseX <= r->x+r->w && m_MouseY >= r->y && m_MouseY <= r->y+r->h)
         return 1;
     return 0;
 }
 
-static RECT screen = { 0.0f, 0.0f, 848.0f, 480.0f };
-
-RECT *ui_screen()
+CUIRect *CUI::Screen()
 {
-    float aspect = gfx_screenaspect();
+    float aspect = Graphics()->ScreenAspect();
     float w, h;
 
     h = 600;
     w = aspect*h;
 
-    screen.w = w;
-    screen.h = h;
+    m_Screen.w = w;
+    m_Screen.h = h;
 
-    return &screen;
+    return &m_Screen;
 }
 
-void ui_set_scale(float s)
+void CUI::SetScale(float s)
 {
-    config.ui_scale = (int)(s*100.0f);
+    //config.UI()->Scale = (int)(s*100.0f);
 }
 
-float ui_scale()
+/*float CUI::Scale()
 {
-    return config.ui_scale/100.0f;
-}
+    return config.UI()->Scale/100.0f;
+}*/
 
-void ui_clip_enable(const RECT *r)
+void CUI::ClipEnable(const CUIRect *r)
 {
-	float xscale = gfx_screenwidth()/ui_screen()->w;
-	float yscale = gfx_screenheight()/ui_screen()->h;
-	gfx_clip_enable((int)(r->x*xscale), (int)(r->y*yscale), (int)(r->w*xscale), (int)(r->h*yscale));
+	float xscale = Graphics()->ScreenWidth()/Screen()->w;
+	float yscale = Graphics()->ScreenHeight()/Screen()->h;
+	Graphics()->ClipEnable((int)(r->x*xscale), (int)(r->y*yscale), (int)(r->w*xscale), (int)(r->h*yscale));
 }
 
-void ui_clip_disable()
+void CUI::ClipDisable()
 {
-	gfx_clip_disable();
+	Graphics()->ClipDisable();
 }
 
-void ui_hsplit_t(const RECT *original, float cut, RECT *top, RECT *bottom)
+void CUIRect::HSplitTop(float cut, CUIRect *top, CUIRect *bottom) const
 {
-    RECT r = *original;
-    cut *= ui_scale();
+    CUIRect r = *this;
+    cut *= Scale();
 
     if (top)
     {
@@ -116,10 +110,10 @@ void ui_hsplit_t(const RECT *original, float cut, RECT *top, RECT *bottom)
     }
 }
 
-void ui_hsplit_b(const RECT *original, float cut, RECT *top, RECT *bottom)
+void CUIRect::HSplitBottom(float cut, CUIRect *top, CUIRect *bottom) const
 {
-    RECT r = *original;
-    cut *= ui_scale();
+    CUIRect r = *this;
+    cut *= Scale();
 
     if (top)
     {
@@ -139,9 +133,9 @@ void ui_hsplit_b(const RECT *original, float cut, RECT *top, RECT *bottom)
 }
 
 
-void ui_vsplit_mid(const RECT *original, RECT *left, RECT *right)
+void CUIRect::VSplitMid(CUIRect *left, CUIRect *right) const
 {
-    RECT r = *original;
+    CUIRect r = *this;
     float cut = r.w/2;
 
     if (left)
@@ -161,10 +155,10 @@ void ui_vsplit_mid(const RECT *original, RECT *left, RECT *right)
     }
 }
 
-void ui_vsplit_l(const RECT *original, float cut, RECT *left, RECT *right)
+void CUIRect::VSplitLeft(float cut, CUIRect *left, CUIRect *right) const
 {
-    RECT r = *original;
-    cut *= ui_scale();
+    CUIRect r = *this;
+    cut *= Scale();
 
     if (left)
     {
@@ -183,10 +177,10 @@ void ui_vsplit_l(const RECT *original, float cut, RECT *left, RECT *right)
     }
 }
 
-void ui_vsplit_r(const RECT *original, float cut, RECT *left, RECT *right)
+void CUIRect::VSplitRight(float cut, CUIRect *left, CUIRect *right) const
 {
-    RECT r = *original;
-    cut *= ui_scale();
+    CUIRect r = *this;
+    cut *= Scale();
 
     if (left)
     {
@@ -205,10 +199,10 @@ void ui_vsplit_r(const RECT *original, float cut, RECT *left, RECT *right)
     }
 }
 
-void ui_margin(const RECT *original, float cut, RECT *other_rect)
+void CUIRect::Margin(float cut, CUIRect *other_rect) const
 {
-    RECT r = *original;
-	cut *= ui_scale();
+    CUIRect r = *this;
+	cut *= Scale();
 
     other_rect->x = r.x + cut;
     other_rect->y = r.y + cut;
@@ -216,10 +210,10 @@ void ui_margin(const RECT *original, float cut, RECT *other_rect)
     other_rect->h = r.h - 2*cut;
 }
 
-void ui_vmargin(const RECT *original, float cut, RECT *other_rect)
+void CUIRect::VMargin(float cut, CUIRect *other_rect) const
 {
-    RECT r = *original;
-	cut *= ui_scale();
+    CUIRect r = *this;
+	cut *= Scale();
 
     other_rect->x = r.x + cut;
     other_rect->y = r.y;
@@ -227,10 +221,10 @@ void ui_vmargin(const RECT *original, float cut, RECT *other_rect)
     other_rect->h = r.h;
 }
 
-void ui_hmargin(const RECT *original, float cut, RECT *other_rect)
+void CUIRect::HMargin(float cut, CUIRect *other_rect) const
 {
-    RECT r = *original;
-	cut *= ui_scale();
+    CUIRect r = *this;
+	cut *= Scale();
 
     other_rect->x = r.x;
     other_rect->y = r.y + cut;
@@ -238,50 +232,87 @@ void ui_hmargin(const RECT *original, float cut, RECT *other_rect)
     other_rect->h = r.h - 2*cut;
 }
 
-
-int ui_do_button(const void *id, const char *text, int checked, const RECT *r, ui_draw_button_func draw_func, const void *extra)
+int CUI::DoButtonLogic(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
 {
     /* logic */
+    int ReturnValue = 0;
+    int Inside = MouseInside(pRect);
+	static int ButtonUsed = 0;
+
+	if(ActiveItem() == pID)
+	{
+		if(!MouseButton(ButtonUsed))
+		{
+			if(Inside && Checked >= 0)
+				ReturnValue = 1+ButtonUsed;
+			SetActiveItem(0);
+		}
+	}
+	else if(HotItem() == pID)
+	{
+		if(MouseButton(0))
+		{
+			SetActiveItem(pID);
+			ButtonUsed = 0;
+		}
+		
+		if(MouseButton(1))
+		{
+			SetActiveItem(pID);
+			ButtonUsed = 1;
+		}
+	}
+	
+	if(Inside)
+		SetHotItem(pID);
+
+    return ReturnValue;
+}
+/*
+int CUI::DoButton(const void *id, const char *text, int checked, const CUIRect *r, ui_draw_button_func draw_func, const void *extra)
+{
+    // logic
     int ret = 0;
-    int inside = ui_mouse_inside(r);
+    int inside = ui_MouseInside(r);
 	static int button_used = 0;
 
-	if(ui_active_item() == id)
+	if(ui_ActiveItem() == id)
 	{
-		if(!ui_mouse_button(button_used))
+		if(!ui_MouseButton(button_used))
 		{
 			if(inside && checked >= 0)
 				ret = 1+button_used;
-			ui_set_active_item(0);
+			ui_SetActiveItem(0);
 		}
 	}
-	else if(ui_hot_item() == id)
+	else if(ui_HotItem() == id)
 	{
-		if(ui_mouse_button(0))
+		if(ui_MouseButton(0))
 		{
-			ui_set_active_item(id);
+			ui_SetActiveItem(id);
 			button_used = 0;
 		}
 		
-		if(ui_mouse_button(1))
+		if(ui_MouseButton(1))
 		{
-			ui_set_active_item(id);
+			ui_SetActiveItem(id);
 			button_used = 1;
 		}
 	}
 	
 	if(inside)
-		ui_set_hot_item(id);
+		ui_SetHotItem(id);
 
 	if(draw_func)
     	draw_func(id, text, checked, r, extra);
     return ret;
-}
+}*/
 
-void ui_do_label(const RECT *r, const char *text, float size, int align, int max_width)
+void CUI::DoLabel(const CUIRect *r, const char *text, float size, int align, int max_width)
 {
-    gfx_blend_normal();
-    size *= ui_scale();
+	// TODO: FIX ME!!!!
+    //Graphics()->BlendNormal();
+    size *= Scale();
     if(align == 0)
     {
     	float tw = gfx_text_width(0, size, text, max_width);
diff --git a/src/game/client/ui.hpp b/src/game/client/ui.hpp
index 7a6cb5de..96f6c48b 100644
--- a/src/game/client/ui.hpp
+++ b/src/game/client/ui.hpp
@@ -2,64 +2,93 @@
 #ifndef FILE_GAME_CLIENT_UI_H
 #define FILE_GAME_CLIENT_UI_H
 
-typedef struct 
+class CUIRect
 {
+	// TODO: Refactor: Redo UI scaling
+	float Scale() const { return 1.0f; }
+public:
     float x, y, w, h;
-} RECT;
+	
+	void HSplitTop(float Cut, CUIRect *pTop, CUIRect *pBottom) const;
+	void HSplitBottom(float Cut, CUIRect *pTop, CUIRect *pBottom) const;
+	void VSplitMid(CUIRect *pLeft, CUIRect *pRight) const;
+	void VSplitLeft(float Cut, CUIRect *pLeft, CUIRect *pRight) const;
+	void VSplitRight(float Cut, CUIRect *pLeft, CUIRect *pRight) const;
+
+	void Margin(float Cut, CUIRect *pOtherRect) const;
+	void VMargin(float Cut, CUIRect *pOtherRect) const;
+	void HMargin(float Cut, CUIRect *pOtherRect) const;
+	
+};
 
-enum
+class CUI
 {
-	CORNER_TL=1,
-	CORNER_TR=2,
-	CORNER_BL=4,
-	CORNER_BR=8,
+	const void *m_pHotItem;
+	const void *m_pActiveItem;
+	const void *m_pLastActiveItem;
+	const void *m_pBecommingHotItem;
+	float m_MouseX, m_MouseY; /* in gui space */
+	float m_MouseWorldX, m_MouseWorldY; /* in world space */
+	unsigned m_MouseButtons;
+	unsigned m_LastMouseButtons;
 	
-	CORNER_T=CORNER_TL|CORNER_TR,
-	CORNER_B=CORNER_BL|CORNER_BR,
-	CORNER_R=CORNER_TR|CORNER_BR,
-	CORNER_L=CORNER_TL|CORNER_BL,
+	CUIRect m_Screen;
+	class IGraphics *m_pGraphics;
 	
-	CORNER_ALL=CORNER_T|CORNER_B
-};
+public:
+	// TODO: Refactor: Fill this in
+	void SetGraphics(class IGraphics *pGraphics) { m_pGraphics = pGraphics; }
+	class IGraphics *Graphics() { return m_pGraphics; }
 
-int ui_update(float mx, float my, float mwx, float mwy, int buttons);
+	CUI();
 
-float ui_mouse_x();
-float ui_mouse_y();
-float ui_mouse_world_x();
-float ui_mouse_world_y();
-int ui_mouse_button(int index);
-int ui_mouse_button_clicked(int index);
+	enum
+	{
+		CORNER_TL=1,
+		CORNER_TR=2,
+		CORNER_BL=4,
+		CORNER_BR=8,
+		
+		CORNER_T=CORNER_TL|CORNER_TR,
+		CORNER_B=CORNER_BL|CORNER_BR,
+		CORNER_R=CORNER_TR|CORNER_BR,
+		CORNER_L=CORNER_TL|CORNER_BL,
+		
+		CORNER_ALL=CORNER_T|CORNER_B
+	};
 
-void ui_set_hot_item(const void *id);
-void ui_set_active_item(const void *id);
-void ui_clear_last_active_item();
-const void *ui_hot_item();
-const void *ui_next_hot_item();
-const void *ui_active_item();
-const void *ui_last_active_item();
+	int Update(float mx, float my, float mwx, float mwy, int buttons);
 
-int ui_mouse_inside(const RECT *r);
+	float MouseX() const { return m_MouseX; }
+	float MouseY() const { return m_MouseY; }
+	float MouseWorldX() const { return m_MouseWorldX; }
+	float MouseWorldY() const { return m_MouseWorldY; }
+	int MouseButton(int Index) const { return (m_MouseButtons>>Index)&1; }
+	int MouseButtonClicked(int Index) { return MouseButton(Index) && !((m_LastMouseButtons>>Index)&1) ; }
 
-RECT *ui_screen();
-void ui_set_scale(float s);
-float ui_scale();
-void ui_clip_enable(const RECT *r);
-void ui_clip_disable();
+	void SetHotItem(const void *pID) { m_pBecommingHotItem = pID; }
+	void SetActiveItem(const void *pID) { m_pActiveItem = pID; if (pID) m_pLastActiveItem = pID; }
+	void ClearLastActiveItem() { m_pLastActiveItem = 0; }
+	const void *HotItem() const { return m_pHotItem; }
+	const void *NextHotItem() const { return m_pBecommingHotItem; }
+	const void *ActiveItem() const { return m_pActiveItem; }
+	const void *LastActiveItem() const { return m_pLastActiveItem; }
 
-void ui_hsplit_t(const RECT *original, float cut, RECT *top, RECT *bottom);
-void ui_hsplit_b(const RECT *original, float cut, RECT *top, RECT *bottom);
-void ui_vsplit_mid(const RECT *original, RECT *left, RECT *right);
-void ui_vsplit_l(const RECT *original, float cut, RECT *left, RECT *right);
-void ui_vsplit_r(const RECT *original, float cut, RECT *left, RECT *right);
+	int MouseInside(const CUIRect *r);
 
-void ui_margin(const RECT *original, float cut, RECT *other_rect);
-void ui_vmargin(const RECT *original, float cut, RECT *other_rect);
-void ui_hmargin(const RECT *original, float cut, RECT *other_rect);
+	CUIRect *Screen();
+	void ClipEnable(const CUIRect *r);
+	void ClipDisable();
+	
+	// TODO: Refactor: Redo UI scaling
+	void SetScale(float s);
+	float Scale() const { return 1.0f; }
 
-typedef void (*ui_draw_button_func)(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-int ui_do_button(const void *id, const char *text, int checked, const RECT *r, ui_draw_button_func draw_func, const void *extra);
-void ui_do_label(const RECT *r, const char *text, float size, int align, int max_width = -1);
+	int DoButtonLogic(const void *pID, const char *pText /* TODO: Refactor: Remove */, int Checked, const CUIRect *pRect);
+	
+	// TODO: Refactor: Remove this?
+	void DoLabel(const CUIRect *r, const char *text, float size, int align, int max_width = -1);
+};
 
 
 #endif
diff --git a/src/game/editor/ed_editor.cpp b/src/game/editor/ed_editor.cpp
index d56a0506..17b891fc 100644
--- a/src/game/editor/ed_editor.cpp
+++ b/src/game/editor/ed_editor.cpp
@@ -6,12 +6,11 @@
 #include <stdlib.h>
 #include <string.h>
 
-extern "C" {
-	#include <engine/e_common_interface.h>
-	#include <engine/e_datafile.h>
-	#include <engine/e_config.h>
-	#include <engine/e_engine.h>
-}
+#include <engine/e_common_interface.h>
+#include <engine/e_datafile.h>
+#include <engine/e_config.h>
+#include <engine/e_engine.h>
+#include <engine/client/graphics.h>
 
 #include <game/client/ui.hpp>
 #include <game/gamecore.hpp>
@@ -25,10 +24,19 @@ static int background_texture = 0;
 static int cursor_texture = 0;
 static int entities_texture = 0;
 
+enum
+{
+	BUTTON_CONTEXT=1,
+};
 
-static const void *ui_got_context = 0;
 
-EDITOR editor;
+
+EDITOR_IMAGE::~EDITOR_IMAGE()
+{
+	editor->Graphics()->UnloadTexture(tex_id);
+}
+
+static const void *ui_got_context = 0;
 
 LAYERGROUP::LAYERGROUP()
 {
@@ -52,7 +60,7 @@ LAYERGROUP::~LAYERGROUP()
 	clear();
 }
 
-void LAYERGROUP::convert(RECT *rect)
+void LAYERGROUP::convert(CUIRect *rect)
 {
 	rect->x += offset_x;
 	rect->y += offset_y;
@@ -60,52 +68,53 @@ void LAYERGROUP::convert(RECT *rect)
 
 void LAYERGROUP::mapping(float *points)
 {
-	mapscreen_to_world(
-		editor.world_offset_x, editor.world_offset_y,
+	m_pMap->editor->RenderTools()->mapscreen_to_world(
+		m_pMap->editor->world_offset_x, m_pMap->editor->world_offset_y,
 		parallax_x/100.0f, parallax_y/100.0f,
 		offset_x, offset_y,
-		gfx_screenaspect(), editor.world_zoom, points);
+		m_pMap->editor->Graphics()->ScreenAspect(), m_pMap->editor->world_zoom, points);
 		
-	points[0] += editor.editor_offset_x;
-	points[1] += editor.editor_offset_y;
-	points[2] += editor.editor_offset_x;
-	points[3] += editor.editor_offset_y;
+	points[0] += m_pMap->editor->editor_offset_x;
+	points[1] += m_pMap->editor->editor_offset_y;
+	points[2] += m_pMap->editor->editor_offset_x;
+	points[3] += m_pMap->editor->editor_offset_y;
 }
 
 void LAYERGROUP::mapscreen()
 {
 	float points[4];
 	mapping(points);
-	gfx_mapscreen(points[0], points[1], points[2], points[3]);
+	m_pMap->editor->Graphics()->MapScreen(points[0], points[1], points[2], points[3]);
 }
 
 void LAYERGROUP::render()
 {
 	mapscreen();
+	IGraphics *pGraphics = m_pMap->editor->Graphics();
 	
 	if(use_clipping)
 	{
 		float points[4];
-		editor.map.game_group->mapping(points);
+		m_pMap->game_group->mapping(points);
 		float x0 = (clip_x - points[0]) / (points[2]-points[0]);
 		float y0 = (clip_y - points[1]) / (points[3]-points[1]);
 		float x1 = ((clip_x+clip_w) - points[0]) / (points[2]-points[0]);
 		float y1 = ((clip_y+clip_h) - points[1]) / (points[3]-points[1]);
 		
-		gfx_clip_enable((int)(x0*gfx_screenwidth()), (int)(y0*gfx_screenheight()),
-			(int)((x1-x0)*gfx_screenwidth()), (int)((y1-y0)*gfx_screenheight()));
+		pGraphics->ClipEnable((int)(x0*pGraphics->ScreenWidth()), (int)(y0*pGraphics->ScreenHeight()),
+			(int)((x1-x0)*pGraphics->ScreenWidth()), (int)((y1-y0)*pGraphics->ScreenHeight()));
 	}
 	
 	for(int i = 0; i < layers.len(); i++)
 	{
-		if(layers[i]->visible && layers[i] != editor.map.game_layer)
+		if(layers[i]->visible && layers[i] != m_pMap->game_layer)
 		{
-			if(editor.show_detail || !(layers[i]->flags&LAYERFLAG_DETAIL))
+			if(m_pMap->editor->show_detail || !(layers[i]->flags&LAYERFLAG_DETAIL))
 				layers[i]->render();
 		}
 	}
 	
-	gfx_clip_disable();
+	pGraphics->ClipDisable();
 }
 
 bool LAYERGROUP::is_empty() const { return layers.len() == 0; }
@@ -178,21 +187,105 @@ void EDITOR_IMAGE::analyse_tileflags()
 *********************************************************/
 
 // copied from gc_menu.cpp, should be more generalized
-//extern int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float font_size, bool hidden=false);
+//extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false);
 
-int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float font_size, bool hidden=false)
+int EDITOR::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden)
 {
-    int inside = ui_mouse_inside(rect);
+    int Inside = UI()->MouseInside(pRect);
+	int ReturnValue = 0;
+	static int AtIndex = 0;
+
+	if(UI()->LastActiveItem() == pID)
+	{
+		int Len = strlen(pStr);
+			
+		if(Inside && UI()->MouseButton(0))
+		{
+			int mx_rel = (int)(UI()->MouseX() - pRect->x);
+
+			for (int i = 1; i <= Len; i++)
+			{
+				if (gfx_text_width(0, FontSize, pStr, i) + 10 > mx_rel)
+				{
+					AtIndex = i - 1;
+					break;
+				}
+
+				if (i == Len)
+					AtIndex = Len;
+			}
+		}
+
+		for(int i = 0; i < inp_num_events(); i++)
+		{
+			Len = strlen(pStr);
+			LINEINPUT::manipulate(inp_get_event(i), pStr, StrSize, &Len, &AtIndex);
+		}
+	}
+
+	bool JustGotActive = false;
+	
+	if(UI()->ActiveItem() == pID)
+	{
+		if(!UI()->MouseButton(0))
+			UI()->SetActiveItem(0);
+	}
+	else if(UI()->HotItem() == pID)
+	{
+		if(UI()->MouseButton(0))
+		{
+			if (UI()->LastActiveItem() != pID)
+				JustGotActive = true;
+			UI()->SetActiveItem(pID);
+		}
+	}
+	
+	if(Inside)
+		UI()->SetHotItem(pID);
+
+	CUIRect Textbox = *pRect;
+	RenderTools()->DrawUIRect(&Textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f);
+	Textbox.VMargin(5.0f, &Textbox);
+	
+	const char *pDisplayStr = pStr;
+	char aStars[128];
+	
+	if(Hidden)
+	{
+		unsigned s = strlen(pStr);
+		if(s >= sizeof(aStars))
+			s = sizeof(aStars)-1;
+		memset(aStars, '*', s);
+		aStars[s] = 0;
+		pDisplayStr = aStars;
+	}
+
+	UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1);
+	
+	if (UI()->LastActiveItem() == pID && !JustGotActive)
+	{
+		float w = gfx_text_width(0, FontSize, pDisplayStr, AtIndex);
+		Textbox.x += w*UI()->Scale();
+		UI()->DoLabel(&Textbox, "_", FontSize, -1);
+	}
+
+	return ReturnValue;
+}
+
+/*
+int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false)
+{
+    int inside = UI()->MouseInside(rect);
 	int r = 0;
 	static int at_index = 0;
 
-	if(ui_last_active_item() == id)
+	if(UI()->LastActiveItem() == id)
 	{
 		int len = strlen(str);
 
-		if (inside && ui_mouse_button(0))
+		if (inside && UI()->MouseButton(0))
 		{
-			int mx_rel = (int)(ui_mouse_x() - rect->x);
+			int mx_rel = (int)(UI()->MouseX() - rect->x);
 
 			for (int i = 1; i <= len; i++)
 			{
@@ -218,27 +311,27 @@ int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float fo
 
 	bool just_got_active = false;
 	
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == id)
 	{
-		if(!ui_mouse_button(0))
-			ui_set_active_item(0);
+		if(!UI()->MouseButton(0))
+			UI()->SetActiveItem(0);
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == id)
 	{
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			if (ui_last_active_item() != id)
+			if (UI()->LastActiveItem() != id)
 				just_got_active = true;
-			ui_set_active_item(id);
+			UI()->SetActiveItem(id);
 		}
 	}
 	
 	if(inside)
-		ui_set_hot_item(id);
+		UI()->SetHotItem(id);
 
-	RECT textbox = *rect;
-	ui_draw_rect(&textbox, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f);
-	ui_vmargin(&textbox, 5.0f, &textbox);
+	CUIRect textbox = *rect;
+	RenderTools()->DrawUIRect(&textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f);
+	textbox.VMargin(5.0f, &textbox);
 	
 	const char *display_str = str;
 	char stars[128];
@@ -253,197 +346,251 @@ int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float fo
 		display_str = stars;
 	}
 
-	ui_do_label(&textbox, display_str, font_size, -1);
+	UI()->DoLabel(&textbox, display_str, font_size, -1);
 	
-	if (ui_last_active_item() == id && !just_got_active)
+	if (UI()->LastActiveItem() == id && !just_got_active)
 	{
 		float w = gfx_text_width(0, font_size, display_str, at_index);
-		textbox.x += w*ui_scale();
-		ui_do_label(&textbox, "_", font_size, -1);
+		textbox.x += w*UI()->Scale();
+		UI()->DoLabel(&textbox, "_", font_size, -1);
 	}
 
 	return r;
 }
+*/
 
-vec4 button_color_mul(const void *id)
+vec4 EDITOR::button_color_mul(const void *id)
 {
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == id)
 		return vec4(1,1,1,0.5f);
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == id)
 		return vec4(1,1,1,1.5f);
 	return vec4(1,1,1,1);
 }
 
-float ui_do_scrollbar_v(const void *id, const RECT *rect, float current)
+float EDITOR::ui_do_scrollbar_v(const void *id, const CUIRect *rect, float current)
 {
-	RECT handle;
+	CUIRect handle;
 	static float offset_y;
-	ui_hsplit_t(rect, 33, &handle, 0);
+	rect->HSplitTop(33, &handle, 0);
 
 	handle.y += (rect->h-handle.h)*current;
 
 	/* logic */
     float ret = current;
-    int inside = ui_mouse_inside(&handle);
+    int inside = UI()->MouseInside(&handle);
 
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == id)
 	{
-		if(!ui_mouse_button(0))
-			ui_set_active_item(0);
+		if(!UI()->MouseButton(0))
+			UI()->SetActiveItem(0);
 		
 		float min = rect->y;
 		float max = rect->h-handle.h;
-		float cur = ui_mouse_y()-offset_y;
+		float cur = UI()->MouseY()-offset_y;
 		ret = (cur-min)/max;
 		if(ret < 0.0f) ret = 0.0f;
 		if(ret > 1.0f) ret = 1.0f;
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == id)
 	{
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			ui_set_active_item(id);
-			offset_y = ui_mouse_y()-handle.y;
+			UI()->SetActiveItem(id);
+			offset_y = UI()->MouseY()-handle.y;
 		}
 	}
 	
 	if(inside)
-		ui_set_hot_item(id);
+		UI()->SetHotItem(id);
 
 	// render
-	RECT rail;
-	ui_vmargin(rect, 5.0f, &rail);
-	ui_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f);
+	CUIRect rail;
+	rect->VMargin(5.0f, &rail);
+	RenderTools()->DrawUIRect(&rail, vec4(1,1,1,0.25f), 0, 0.0f);
 
-	RECT slider = handle;
+	CUIRect slider = handle;
 	slider.w = rail.x-slider.x;
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_L, 2.5f);
+	RenderTools()->DrawUIRect(&slider, vec4(1,1,1,0.25f), CUI::CORNER_L, 2.5f);
 	slider.x = rail.x+rail.w;
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_R, 2.5f);
+	RenderTools()->DrawUIRect(&slider, vec4(1,1,1,0.25f), CUI::CORNER_R, 2.5f);
 
 	slider = handle;
-	ui_margin(&slider, 5.0f, &slider);
-	ui_draw_rect(&slider, vec4(1,1,1,0.25f)*button_color_mul(id), CORNER_ALL, 2.5f);
+	slider.Margin(5.0f, &slider);
+	RenderTools()->DrawUIRect(&slider, vec4(1,1,1,0.25f)*button_color_mul(id), CUI::CORNER_ALL, 2.5f);
 	
     return ret;
 }
 
-static vec4 get_button_color(const void *id, int checked)
+vec4 EDITOR::get_button_color(const void *id, int checked)
 {
 	if(checked < 0)
 		return vec4(0,0,0,0.5f);
 		
 	if(checked > 0)
 	{
-		if(ui_hot_item() == id)
+		if(UI()->HotItem() == id)
 			return vec4(1,0,0,0.75f);
 		return vec4(1,0,0,0.5f);
 	}
 	
-	if(ui_hot_item() == id)
+	if(UI()->HotItem() == id)
 		return vec4(1,1,1,0.75f);
 	return vec4(1,1,1,0.5f);
 }
 
-void draw_editor_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	ui_draw_rect(r, get_button_color(id, checked), CORNER_ALL, 3.0f);
-	ui_do_label(r, text, 10, 0, -1);
+	if(UI()->MouseInside(pRect))
+	{
+		if(Flags&BUTTON_CONTEXT)
+			ui_got_context = pID;
+		if(tooltip)
+			tooltip = pToolTip;
+	}
+	
+	if(UI()->HotItem() == pID && pToolTip)
+		tooltip = (const char *)pToolTip;
+	
+	return UI()->DoButtonLogic(pID, pText, Checked, pRect);
+
+	// Draw here
+	//return UI()->DoButton(id, text, checked, r, draw_func, 0);
+}
+
+
+int EDITOR::DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
+{
+	RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_ALL, 3.0f);
+	UI()->DoLabel(pRect, pText, 10, 0, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-static void draw_editor_button_file(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	if(ui_hot_item() == id)
-		ui_draw_rect(r, get_button_color(id, checked), CORNER_ALL, 3.0f);
+	if(UI()->HotItem() == pID)
+		RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_ALL, 3.0f);
 	
-	RECT t = *r;
-	ui_vmargin(&t, 5.0f, &t);
-	ui_do_label(&t, text, 10, -1, -1);
+	CUIRect t = *pRect;
+	t.VMargin(5.0f, &t);
+	UI()->DoLabel(&t, pText, 10, -1, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-static void draw_editor_button_menu(const void *id, const char *text, int checked, const RECT *rect, const void *extra)
+//static void draw_editor_button_menu(const void *id, const char *text, int checked, const CUIRect *rect, const void *extra)
+int EDITOR::DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
 	/*
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	if(ui_hot_item() == id)
-		ui_draw_rect(r, get_button_color(id, checked), CORNER_ALL, 3.0f);
+	if(UI()->HotItem() == id) if(extra) editor.tooltip = (const char *)extra;
+	if(UI()->HotItem() == id)
+		RenderTools()->DrawUIRect(r, get_button_color(id, checked), CUI::CORNER_ALL, 3.0f);
 	*/
 
-	RECT r = *rect;
+	CUIRect r = *pRect;
 	/*
 	if(ui_popups[id == id)
 	{
-		ui_draw_rect(&r, vec4(0.5f,0.5f,0.5f,0.75f), CORNER_T, 3.0f);
-		ui_margin(&r, 1.0f, &r);
-		ui_draw_rect(&r, vec4(0,0,0,0.75f), CORNER_T, 3.0f);
+		RenderTools()->DrawUIRect(&r, vec4(0.5f,0.5f,0.5f,0.75f), CUI::CORNER_T, 3.0f);
+		r.Margin(1.0f, &r);
+		RenderTools()->DrawUIRect(&r, vec4(0,0,0,0.75f), CUI::CORNER_T, 3.0f);
 	}
 	else*/
-		ui_draw_rect(&r, vec4(0.5f,0.5f,0.5f, 1.0f), CORNER_T, 3.0f);
+		RenderTools()->DrawUIRect(&r, vec4(0.5f,0.5f,0.5f, 1.0f), CUI::CORNER_T, 3.0f);
 	
 
-	r = *rect;
-	ui_vmargin(&r, 5.0f, &r);
-	ui_do_label(&r, text, 10, -1, -1);
+	r = *pRect;
+	r.VMargin(5.0f, &r);
+	UI()->DoLabel(&r, pText, 10, -1, -1);
+	
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 	
-	//RECT t = *r;
+	//CUIRect t = *r;
 }
 
-void draw_editor_button_menuitem(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	if(ui_hot_item() == id || checked)
-		ui_draw_rect(r, get_button_color(id, checked), CORNER_ALL, 3.0f);
+	if(UI()->HotItem() == pID || Checked)
+		RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_ALL, 3.0f);
 	
-	RECT t = *r;
-	ui_vmargin(&t, 5.0f, &t);
-	ui_do_label(&t, text, 10, -1, -1);
+	CUIRect t = *pRect;
+	t.VMargin(5.0f, &t);
+	UI()->DoLabel(&t, pText, 10, -1, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, 0, 0);
 }
 
-static void draw_editor_button_l(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_ButtonL(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	ui_draw_rect(r, get_button_color(id, checked), CORNER_L, 3.0f);
-	ui_do_label(r, text, 10, 0, -1);
+	RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_L, 3.0f);
+	UI()->DoLabel(pRect, pText, 10, 0, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-static void draw_editor_button_m(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_ButtonM(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	ui_draw_rect(r, get_button_color(id, checked), 0, 3.0f);
-	ui_do_label(r, text, 10, 0, -1);
+	RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), 0, 3.0f);
+	UI()->DoLabel(pRect, pText, 10, 0, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-static void draw_editor_button_r(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_ButtonR(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item() == id) if(extra) editor.tooltip = (const char *)extra;
-	ui_draw_rect(r, get_button_color(id, checked), CORNER_R, 3.0f);
-	ui_do_label(r, text, 10, 0, -1);
+	RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_R, 3.0f);
+	UI()->DoLabel(pRect, pText, 10, 0, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-static void draw_inc_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item == id) if(extra) editor.tooltip = (const char *)extra;
-	ui_draw_rect(r, get_button_color(id, checked), CORNER_R, 3.0f);
-	ui_do_label(r, text?text:">", 10, 0, -1);
+	RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_R, 3.0f);
+	UI()->DoLabel(pRect, pText?pText:">", 10, 0, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-static void draw_dec_button(const void *id, const char *text, int checked, const RECT *r, const void *extra)
+int EDITOR::DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
 {
-	if(ui_hot_item == id) if(extra) editor.tooltip = (const char *)extra;
-	ui_draw_rect(r, get_button_color(id, checked), CORNER_L, 3.0f);
-	ui_do_label(r, text?text:"<", 10, 0, -1);
+	RenderTools()->DrawUIRect(pRect, get_button_color(pID, Checked), CUI::CORNER_L, 3.0f);
+	UI()->DoLabel(pRect, pText?pText:"<", 10, 0, -1);
+	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-enum
+/*
+static void draw_editor_button_l(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
 {
-	BUTTON_CONTEXT=1,
-};
+	RenderTools()->DrawUIRect(r, get_button_color(id, checked), CUI::CORNER_L, 3.0f);
+	UI()->DoLabel(r, text, 10, 0, -1);
+}
+
+static void draw_editor_button_m(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
+{
+	if(UI()->HotItem() == id) if(extra) editor.tooltip = (const char *)extra;
+	RenderTools()->DrawUIRect(r, get_button_color(id, checked), 0, 3.0f);
+	UI()->DoLabel(r, text, 10, 0, -1);
+}
+
+static void draw_editor_button_r(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
+{
+	if(UI()->HotItem() == id) if(extra) editor.tooltip = (const char *)extra;
+	RenderTools()->DrawUIRect(r, get_button_color(id, checked), CUI::CORNER_R, 3.0f);
+	UI()->DoLabel(r, text, 10, 0, -1);
+}
+
+static void draw_inc_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
+{
+	if(UI()->HotItem == id) if(extra) editor.tooltip = (const char *)extra;
+	RenderTools()->DrawUIRect(r, get_button_color(id, checked), CUI::CORNER_R, 3.0f);
+	UI()->DoLabel(r, text?text:">", 10, 0, -1);
+}
 
-int do_editor_button(const void *id, const char *text, int checked, const RECT *r, ui_draw_button_func draw_func, int flags, const char *tooltip)
+static void draw_dec_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
 {
-	if(ui_mouse_inside(r))
+	if(UI()->HotItem == id) if(extra) editor.tooltip = (const char *)extra;
+	RenderTools()->DrawUIRect(r, get_button_color(id, checked), CUI::CORNER_L, 3.0f);
+	UI()->DoLabel(r, text?text:"<", 10, 0, -1);
+}
+
+int do_editor_button(const void *id, const char *text, int checked, const CUIRect *r, ui_draw_button_func draw_func, int flags, const char *tooltip)
+{
+	if(UI()->MouseInside(r))
 	{
 		if(flags&BUTTON_CONTEXT)
 			ui_got_context = id;
@@ -451,46 +598,46 @@ int do_editor_button(const void *id, const char *text, int checked, const RECT *
 			editor.tooltip = tooltip;
 	}
 	
-	return ui_do_button(id, text, checked, r, draw_func, 0);
-}
+	return UI()->DoButton(id, text, checked, r, draw_func, 0);
+}*/
 
 
-static void render_background(RECT view, int texture, float size, float brightness)
+void EDITOR::render_background(CUIRect view, int texture, float size, float brightness)
 {
-	gfx_texture_set(texture);
-	gfx_blend_normal();
-	gfx_quads_begin();
-	gfx_setcolor(brightness,brightness,brightness,1.0f);
-	gfx_quads_setsubset(0,0, view.w/size, view.h/size);
-	gfx_quads_drawTL(view.x, view.y, view.w, view.h);
-	gfx_quads_end();
+	Graphics()->TextureSet(texture);
+	Graphics()->BlendNormal();
+	Graphics()->QuadsBegin();
+	Graphics()->SetColor(brightness,brightness,brightness,1.0f);
+	Graphics()->QuadsSetSubset(0,0, view.w/size, view.h/size);
+	Graphics()->QuadsDrawTL(view.x, view.y, view.w, view.h);
+	Graphics()->QuadsEnd();
 }
 
 static LAYERGROUP brush;
 static LAYER_TILES tileset_picker(16, 16);
 
-static int ui_do_value_selector(void *id, RECT *r, const char *label, int current, int min, int max, float scale)
+int EDITOR::ui_do_value_selector(void *id, CUIRect *r, const char *label, int current, int min, int max, float scale)
 {
     /* logic */
     static float value;
     int ret = 0;
-    int inside = ui_mouse_inside(r);
+    int inside = UI()->MouseInside(r);
 
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == id)
 	{
-		if(!ui_mouse_button(0))
+		if(!UI()->MouseButton(0))
 		{
 			if(inside)
 				ret = 1;
-			editor.lock_mouse = false;
-			ui_set_active_item(0);
+			lock_mouse = false;
+			UI()->SetActiveItem(0);
 		}
 		else
 		{
 			if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
-				value += editor.mouse_delta_x*0.05f;
+				value += mouse_delta_x*0.05f;
 			else
-				value += editor.mouse_delta_x;
+				value += mouse_delta_x;
 			
 			if(fabs(value) > scale)
 			{
@@ -504,31 +651,31 @@ static int ui_do_value_selector(void *id, RECT *r, const char *label, int curren
 			}
 		}
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == id)
 	{
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			editor.lock_mouse = true;
+			lock_mouse = true;
 			value = 0;
-			ui_set_active_item(id);
+			UI()->SetActiveItem(id);
 		}
 	}
 	
 	if(inside)
-		ui_set_hot_item(id);
+		UI()->SetHotItem(id);
 
 	// render
 	char buf[128];
 	sprintf(buf, "%s %d", label, current);
-	ui_draw_rect(r, get_button_color(id, 0), CORNER_ALL, 5.0f);
-	ui_do_label(r, buf, 10, 0, -1);
+	RenderTools()->DrawUIRect(r, get_button_color(id, 0), CUI::CORNER_ALL, 5.0f);
+	UI()->DoLabel(r, buf, 10, 0, -1);
 	return current;
 }
 
 LAYERGROUP *EDITOR::get_selected_group()
 {
-	if(selected_group >= 0 && selected_group < editor.map.groups.len())
-		return editor.map.groups[selected_group];
+	if(selected_group >= 0 && selected_group < map.groups.len())
+		return map.groups[selected_group];
 	return 0x0;
 }
 
@@ -538,7 +685,7 @@ LAYER *EDITOR::get_selected_layer(int index)
 	if(!group)
 		return 0x0;
 
-	if(selected_layer >= 0 && selected_layer < editor.map.groups[selected_group]->layers.len())
+	if(selected_layer >= 0 && selected_layer < map.groups[selected_group]->layers.len())
 		return group->layers[selected_layer];
 	return 0x0;
 }
@@ -561,108 +708,108 @@ QUAD *EDITOR::get_selected_quad()
 	return 0;
 }
 
-static void callback_open_map(const char *filename) { editor.load(filename); }
-static void callback_append_map(const char *filename) { editor.append(filename); }
-static void callback_save_map(const char *filename) { editor.save(filename); }
+static void callback_open_map(const char *filename, void *user) { ((EDITOR*)user)->load(filename); }
+static void callback_append_map(const char *filename, void *user) { ((EDITOR*)user)->append(filename); }
+static void callback_save_map(const char *filename, void *user) { ((EDITOR*)user)->save(filename); }
 
-static void do_toolbar(RECT toolbar)
+void EDITOR::do_toolbar(CUIRect toolbar)
 {
-	RECT button;
+	CUIRect button;
 	
 	// ctrl+o to open
 	if(inp_key_down('o') && (inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL)))
-		editor.invoke_file_dialog(LISTDIRTYPE_ALL, "Open Map", "Open", "maps/", "", callback_open_map);
+		invoke_file_dialog(LISTDIRTYPE_ALL, "Open Map", "Open", "maps/", "", callback_open_map, this);
 	
 	// ctrl+s to save
 	if(inp_key_down('s') && (inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL)))
-		editor.invoke_file_dialog(LISTDIRTYPE_SAVE, "Save Map", "Save", "maps/", "", callback_save_map);
+		invoke_file_dialog(LISTDIRTYPE_SAVE, "Save Map", "Save", "maps/", "", callback_save_map, this);
 
 	// detail button
-	ui_vsplit_l(&toolbar, 30.0f, &button, &toolbar);
+	toolbar.VSplitLeft(30.0f, &button, &toolbar);
 	static int hq_button = 0;
-	if(do_editor_button(&hq_button, "Detail", editor.show_detail, &button, draw_editor_button, 0, "[ctrl+h] Toggle High Detail") ||
+	if(DoButton_Editor(&hq_button, "Detail", show_detail, &button, 0, "[ctrl+h] Toggle High Detail") ||
 		(inp_key_down('h') && (inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL))))
 	{
-		editor.show_detail = !editor.show_detail;
+		show_detail = !show_detail;
 	}
 
-	ui_vsplit_l(&toolbar, 5.0f, 0, &toolbar);
+	toolbar.VSplitLeft(5.0f, 0, &toolbar);
 	
 	// animation button
-	ui_vsplit_l(&toolbar, 30.0f, &button, &toolbar);
+	toolbar.VSplitLeft(30.0f, &button, &toolbar);
 	static int animate_button = 0;
-	if(do_editor_button(&animate_button, "Anim", editor.animate, &button, draw_editor_button, 0, "[ctrl+m] Toggle animation") ||
+	if(DoButton_Editor(&animate_button, "Anim", animate, &button, 0, "[ctrl+m] Toggle animation") ||
 		(inp_key_down('m') && (inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL))))
 	{
-		editor.animate_start = time_get();
-		editor.animate = !editor.animate;
+		animate_start = time_get();
+		animate = !animate;
 	}
 
-	ui_vsplit_l(&toolbar, 5.0f, 0, &toolbar);
+	toolbar.VSplitLeft(5.0f, 0, &toolbar);
 
 	// proof button
-	ui_vsplit_l(&toolbar, 30.0f, &button, &toolbar);
+	toolbar.VSplitLeft(30.0f, &button, &toolbar);
 	static int proof_button = 0;
-	if(do_editor_button(&proof_button, "Proof", editor.proof_borders, &button, draw_editor_button, 0, "[ctrl-p] Toggles proof borders. These borders represent what a player maximum can see.") ||
+	if(DoButton_Editor(&proof_button, "Proof", proof_borders, &button, 0, "[ctrl-p] Toggles proof borders. These borders represent what a player maximum can see.") ||
 		(inp_key_down('p') && (inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL))))
 	{
-		editor.proof_borders = !editor.proof_borders;
+		proof_borders = !proof_borders;
 	}
 
-	ui_vsplit_l(&toolbar, 15.0f, 0, &toolbar);
+	toolbar.VSplitLeft(15.0f, 0, &toolbar);
 	
 	// zoom group
-	ui_vsplit_l(&toolbar, 16.0f, &button, &toolbar);
+	toolbar.VSplitLeft(16.0f, &button, &toolbar);
 	static int zoom_out_button = 0;
-	if(do_editor_button(&zoom_out_button, "ZO", 0, &button, draw_editor_button_l, 0, "[NumPad-] Zoom out") || inp_key_down(KEY_KP_MINUS))
-		editor.zoom_level += 50;
+	if(DoButton_ButtonL(&zoom_out_button, "ZO", 0, &button, 0, "[NumPad-] Zoom out") || inp_key_down(KEY_KP_MINUS))
+		zoom_level += 50;
 		
-	ui_vsplit_l(&toolbar, 16.0f, &button, &toolbar);
+	toolbar.VSplitLeft(16.0f, &button, &toolbar);
 	static int zoom_normal_button = 0;
-	if(do_editor_button(&zoom_normal_button, "1:1", 0, &button, draw_editor_button_m, 0, "[NumPad*] Zoom to normal and remove editor offset") || inp_key_down(KEY_KP_MULTIPLY))
+	if(DoButton_ButtonM(&zoom_normal_button, "1:1", 0, &button, 0, "[NumPad*] Zoom to normal and remove editor offset") || inp_key_down(KEY_KP_MULTIPLY))
 	{
-		editor.editor_offset_x = 0;
-		editor.editor_offset_y = 0;
-		editor.zoom_level = 100;
+		editor_offset_x = 0;
+		editor_offset_y = 0;
+		zoom_level = 100;
 	}
 		
-	ui_vsplit_l(&toolbar, 16.0f, &button, &toolbar);
+	toolbar.VSplitLeft(16.0f, &button, &toolbar);
 	static int zoom_in_button = 0;
-	if(do_editor_button(&zoom_in_button, "ZI", 0, &button, draw_editor_button_r, 0, "[NumPad+] Zoom in") || inp_key_down(KEY_KP_PLUS))
-		editor.zoom_level -= 50;
+	if(DoButton_ButtonR(&zoom_in_button, "ZI", 0, &button, 0, "[NumPad+] Zoom in") || inp_key_down(KEY_KP_PLUS))
+		zoom_level -= 50;
 	
-	ui_vsplit_l(&toolbar, 15.0f, 0, &toolbar);
+	toolbar.VSplitLeft(15.0f, 0, &toolbar);
 	
 	// animation speed
-	ui_vsplit_l(&toolbar, 16.0f, &button, &toolbar);
+	toolbar.VSplitLeft(16.0f, &button, &toolbar);
 	static int anim_faster_button = 0;
-	if(do_editor_button(&anim_faster_button, "A+", 0, &button, draw_editor_button_l, 0, "Increase animation speed"))
-		editor.animate_speed += 0.5f;
+	if(DoButton_ButtonL(&anim_faster_button, "A+", 0, &button, 0, "Increase animation speed"))
+		animate_speed += 0.5f;
 	
-	ui_vsplit_l(&toolbar, 16.0f, &button, &toolbar);
+	toolbar.VSplitLeft(16.0f, &button, &toolbar);
 	static int anim_normal_button = 0;
-	if(do_editor_button(&anim_normal_button, "1", 0, &button, draw_editor_button_m, 0, "Normal animation speed"))
-		editor.animate_speed = 1.0f;
+	if(DoButton_ButtonM(&anim_normal_button, "1", 0, &button, 0, "Normal animation speed"))
+		animate_speed = 1.0f;
 	
-	ui_vsplit_l(&toolbar, 16.0f, &button, &toolbar);
+	toolbar.VSplitLeft(16.0f, &button, &toolbar);
 	static int anim_slower_button = 0;
-	if(do_editor_button(&anim_slower_button, "A-", 0, &button, draw_editor_button_r, 0, "Decrease animation speed"))
+	if(DoButton_ButtonR(&anim_slower_button, "A-", 0, &button, 0, "Decrease animation speed"))
 	{
-		if(editor.animate_speed > 0.5f)
-			editor.animate_speed -= 0.5f;
+		if(animate_speed > 0.5f)
+			animate_speed -= 0.5f;
 	}
 	
-	if(inp_key_presses(KEY_MOUSE_WHEEL_UP) && editor.dialog == DIALOG_NONE)
-		editor.zoom_level -= 20;
+	if(inp_key_presses(KEY_MOUSE_WHEEL_UP) && dialog == DIALOG_NONE)
+		zoom_level -= 20;
 		
-	if(inp_key_presses(KEY_MOUSE_WHEEL_DOWN) && editor.dialog == DIALOG_NONE)
-		editor.zoom_level += 20;
+	if(inp_key_presses(KEY_MOUSE_WHEEL_DOWN) && dialog == DIALOG_NONE)
+		zoom_level += 20;
 	
-	if(editor.zoom_level < 50)
-		editor.zoom_level = 50;
-	editor.world_zoom = editor.zoom_level/100.0f;
+	if(zoom_level < 50)
+		zoom_level = 50;
+	world_zoom = zoom_level/100.0f;
 
-	ui_vsplit_l(&toolbar, 10.0f, &button, &toolbar);
+	toolbar.VSplitLeft(10.0f, &button, &toolbar);
 
 
 	// brush manipulation
@@ -670,41 +817,41 @@ static void do_toolbar(RECT toolbar)
 		int enabled = brush.is_empty()?-1:0;
 		
 		// flip buttons
-		ui_vsplit_l(&toolbar, 20.0f, &button, &toolbar);
+		toolbar.VSplitLeft(20.0f, &button, &toolbar);
 		static int flipx_button = 0;
-		if(do_editor_button(&flipx_button, "^X", enabled, &button, draw_editor_button_l, 0, "[N] Flip brush horizontal") || inp_key_down('n'))
+		if(DoButton_ButtonL(&flipx_button, "^X", enabled, &button, 0, "[N] Flip brush horizontal") || inp_key_down('n'))
 		{
 			for(int i = 0; i < brush.layers.len(); i++)
 				brush.layers[i]->brush_flip_x();
 		}
 			
-		ui_vsplit_l(&toolbar, 20.0f, &button, &toolbar);
+		toolbar.VSplitLeft(20.0f, &button, &toolbar);
 		static int flipy_button = 0;
-		if(do_editor_button(&flipy_button, "^Y", enabled, &button, draw_editor_button_r, 0, "[M] Flip brush vertical") || inp_key_down('m'))
+		if(DoButton_ButtonR(&flipy_button, "^Y", enabled, &button, 0, "[M] Flip brush vertical") || inp_key_down('m'))
 		{
 			for(int i = 0; i < brush.layers.len(); i++)
 				brush.layers[i]->brush_flip_y();
 		}
 
 		// rotate buttons
-		ui_vsplit_l(&toolbar, 20.0f, &button, &toolbar);
+		toolbar.VSplitLeft(20.0f, &button, &toolbar);
 		
-		ui_vsplit_l(&toolbar, 30.0f, &button, &toolbar);
+		toolbar.VSplitLeft(30.0f, &button, &toolbar);
 		static int rotation_amount = 90;
 		rotation_amount = ui_do_value_selector(&rotation_amount, &button, "", rotation_amount, 1, 360, 2.0f);
 		
-		ui_vsplit_l(&toolbar, 5.0f, &button, &toolbar);
-		ui_vsplit_l(&toolbar, 30.0f, &button, &toolbar);
+		toolbar.VSplitLeft(5.0f, &button, &toolbar);
+		toolbar.VSplitLeft(30.0f, &button, &toolbar);
 		static int ccw_button = 0;
-		if(do_editor_button(&ccw_button, "CCW", enabled, &button, draw_editor_button_l, 0, "[R] Rotates the brush counter clockwise") || inp_key_down('r'))
+		if(DoButton_ButtonL(&ccw_button, "CCW", enabled, &button, 0, "[R] Rotates the brush counter clockwise") || inp_key_down('r'))
 		{
 			for(int i = 0; i < brush.layers.len(); i++)
 				brush.layers[i]->brush_rotate(-rotation_amount/360.0f*pi*2);
 		}
 			
-		ui_vsplit_l(&toolbar, 30.0f, &button, &toolbar);
+		toolbar.VSplitLeft(30.0f, &button, &toolbar);
 		static int cw_button = 0;
-		if(do_editor_button(&cw_button, "CW", enabled, &button, draw_editor_button_r, 0, "[T] Rotates the brush clockwise") || inp_key_down('t'))
+		if(DoButton_ButtonR(&cw_button, "CW", enabled, &button, 0, "[T] Rotates the brush clockwise") || inp_key_down('t'))
 		{
 			for(int i = 0; i < brush.layers.len(); i++)
 				brush.layers[i]->brush_rotate(rotation_amount/360.0f*pi*2);
@@ -714,18 +861,18 @@ static void do_toolbar(RECT toolbar)
 	// quad manipulation
 	{
 		// do add button
-		ui_vsplit_l(&toolbar, 10.0f, &button, &toolbar);
-		ui_vsplit_l(&toolbar, 60.0f, &button, &toolbar);
+		toolbar.VSplitLeft(10.0f, &button, &toolbar);
+		toolbar.VSplitLeft(60.0f, &button, &toolbar);
 		static int new_button = 0;
 		
-		LAYER_QUADS *qlayer = (LAYER_QUADS *)editor.get_selected_layer_type(0, LAYERTYPE_QUADS);
-		//LAYER_TILES *tlayer = (LAYER_TILES *)editor.get_selected_layer_type(0, LAYERTYPE_TILES);
-		if(do_editor_button(&new_button, "Add Quad", qlayer?0:-1, &button, draw_editor_button, 0, "Adds a new quad"))
+		LAYER_QUADS *qlayer = (LAYER_QUADS *)get_selected_layer_type(0, LAYERTYPE_QUADS);
+		//LAYER_TILES *tlayer = (LAYER_TILES *)get_selected_layer_type(0, LAYERTYPE_TILES);
+		if(DoButton_Editor(&new_button, "Add Quad", qlayer?0:-1, &button, 0, "Adds a new quad"))
 		{
 			if(qlayer)
 			{
 				float mapping[4];
-				LAYERGROUP *g = editor.get_selected_group();
+				LAYERGROUP *g = get_selected_group();
 				g->mapping(mapping);
 				int add_x = f2fx(mapping[0] + (mapping[2]-mapping[0])/2);
 				int add_y = f2fx(mapping[1] + (mapping[3]-mapping[1])/2);
@@ -749,7 +896,7 @@ static void rotate(POINT *center, POINT *point, float rotation)
 	point->y = (int)(x * sinf(rotation) + y * cosf(rotation) + center->y);
 }
 
-static void do_quad(QUAD *q, int index)
+void EDITOR::do_quad(QUAD *q, int index)
 {
 	enum
 	{
@@ -767,8 +914,8 @@ static void do_quad(QUAD *q, int index)
 	static float last_wy;
 	static int operation = OP_NONE;
 	static float rotate_angle = 0;
-	float wx = ui_mouse_world_x();
-	float wy = ui_mouse_world_y();
+	float wx = UI()->MouseWorldX();
+	float wy = UI()->MouseWorldY();
 	
 	// get pivot
 	float center_x = fx2f(q->points[4].x);
@@ -777,16 +924,16 @@ static void do_quad(QUAD *q, int index)
 	float dx = (center_x - wx);
 	float dy = (center_y - wy);
 	if(dx*dx+dy*dy < 10*10)
-		ui_set_hot_item(id);
+		UI()->SetHotItem(id);
 
 	// draw selection background	
-	if(editor.selected_quad == index)
+	if(selected_quad == index)
 	{
-		gfx_setcolor(0,0,0,1);
-		gfx_quads_draw(center_x, center_y, 7.0f, 7.0f);
+		Graphics()->SetColor(0,0,0,1);
+		Graphics()->QuadsDraw(center_x, center_y, 7.0f, 7.0f);
 	}
 	
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == id)
 	{
 		// check if we only should move pivot
 		if(operation == OP_MOVE_PIVOT)
@@ -812,47 +959,47 @@ static void do_quad(QUAD *q, int index)
 			}
 		}
 		
-		rotate_angle += (editor.mouse_delta_x) * 0.002f;
+		rotate_angle += (mouse_delta_x) * 0.002f;
 		last_wx = wx;
 		last_wy = wy;
 		
 		if(operation == OP_CONTEXT_MENU)
 		{
-			if(!ui_mouse_button(1))
+			if(!UI()->MouseButton(1))
 			{
 				static int quad_popup_id = 0;
-				ui_invoke_popup_menu(&quad_popup_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 150, popup_quad);
-				editor.lock_mouse = false;
+				ui_invoke_popup_menu(&quad_popup_id, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, popup_quad);
+				lock_mouse = false;
 				operation = OP_NONE;
-				ui_set_active_item(0);
+				UI()->SetActiveItem(0);
 			}
 		}
 		else
 		{
-			if(!ui_mouse_button(0))
+			if(!UI()->MouseButton(0))
 			{
-				editor.lock_mouse = false;
+				lock_mouse = false;
 				operation = OP_NONE;
-				ui_set_active_item(0);
+				UI()->SetActiveItem(0);
 			}
 		}			
 
-		gfx_setcolor(1,1,1,1);
+		Graphics()->SetColor(1,1,1,1);
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == id)
 	{
 		ui_got_context = id;
 		
-		gfx_setcolor(1,1,1,1);
-		editor.tooltip = "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate";
+		Graphics()->SetColor(1,1,1,1);
+		tooltip = "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate";
 		
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
 			if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
 				operation = OP_MOVE_PIVOT;
 			else if(inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL))
 			{
-				editor.lock_mouse = true;
+				lock_mouse = true;
 				operation = OP_ROTATE;
 				rotate_angle = 0;
 				rotate_points[0] = q->points[0];
@@ -863,31 +1010,31 @@ static void do_quad(QUAD *q, int index)
 			else
 				operation = OP_MOVE_ALL;
 				
-			ui_set_active_item(id);
-			editor.selected_quad = index;
+			UI()->SetActiveItem(id);
+			selected_quad = index;
 			last_wx = wx;
 			last_wy = wy;
 		}
 		
-		if(ui_mouse_button(1))
+		if(UI()->MouseButton(1))
 		{
-			editor.selected_quad = index;
+			selected_quad = index;
 			operation = OP_CONTEXT_MENU;
-			ui_set_active_item(id);
+			UI()->SetActiveItem(id);
 		}
 	}
 	else
-		gfx_setcolor(0,1,0,1);
+		Graphics()->SetColor(0,1,0,1);
 
-	gfx_quads_draw(center_x, center_y, 5.0f, 5.0f);
+	Graphics()->QuadsDraw(center_x, center_y, 5.0f, 5.0f);
 }
 
-static void do_quad_point(QUAD *q, int quad_index, int v)
+void EDITOR::do_quad_point(QUAD *q, int quad_index, int v)
 {
 	void *id = &q->points[v];
 
-	float wx = ui_mouse_world_x();
-	float wy = ui_mouse_world_y();
+	float wx = UI()->MouseWorldX();
+	float wy = UI()->MouseWorldY();
 	
 	float px = fx2f(q->points[v].x);
 	float py = fx2f(q->points[v].y);
@@ -895,13 +1042,13 @@ static void do_quad_point(QUAD *q, int quad_index, int v)
 	float dx = (px - wx);
 	float dy = (py - wy);
 	if(dx*dx+dy*dy < 10*10)
-		ui_set_hot_item(id);
+		UI()->SetHotItem(id);
 
 	// draw selection background	
-	if(editor.selected_quad == quad_index && editor.selected_points&(1<<v))
+	if(selected_quad == quad_index && selected_points&(1<<v))
 	{
-		gfx_setcolor(0,0,0,1);
-		gfx_quads_draw(px, py, 7.0f, 7.0f);
+		Graphics()->SetColor(0,0,0,1);
+		Graphics()->QuadsDraw(px, py, 7.0f, 7.0f);
 	}
 	
 	enum
@@ -915,10 +1062,10 @@ static void do_quad_point(QUAD *q, int quad_index, int v)
 	static bool moved;
 	static int operation = OP_NONE;
 
-	if(ui_active_item() == id)
+	if(UI()->ActiveItem() == id)
 	{
-		float dx = editor.mouse_delta_wx;
-		float dy = editor.mouse_delta_wy;
+		float dx = mouse_delta_wx;
+		float dy = mouse_delta_wy;
 		if(!moved)
 		{
 			if(dx*dx+dy*dy > 0.5f)
@@ -930,7 +1077,7 @@ static void do_quad_point(QUAD *q, int quad_index, int v)
 			if(operation == OP_MOVEPOINT)
 			{
 				for(int m = 0; m < 4; m++)
-					if(editor.selected_points&(1<<m))
+					if(selected_points&(1<<m))
 					{
 						q->points[m].x += f2fx(dx);
 						q->points[m].y += f2fx(dy);
@@ -939,7 +1086,7 @@ static void do_quad_point(QUAD *q, int quad_index, int v)
 			else if(operation == OP_MOVEUV)
 			{
 				for(int m = 0; m < 4; m++)
-					if(editor.selected_points&(1<<m))
+					if(selected_points&(1<<m))
 					{
 						q->texcoords[m].x += f2fx(dx*0.001f);
 						q->texcoords[m].y += f2fx(dy*0.001f);
@@ -949,106 +1096,106 @@ static void do_quad_point(QUAD *q, int quad_index, int v)
 		
 		if(operation == OP_CONTEXT_MENU)
 		{
-			if(!ui_mouse_button(1))
+			if(!UI()->MouseButton(1))
 			{
 				static int point_popup_id = 0;
-				ui_invoke_popup_menu(&point_popup_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 150, popup_point);
-				ui_set_active_item(0);
+				ui_invoke_popup_menu(&point_popup_id, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, popup_point);
+				UI()->SetActiveItem(0);
 			}
 		}
 		else
 		{
-			if(!ui_mouse_button(0))
+			if(!UI()->MouseButton(0))
 			{
 				if(!moved)
 				{
 					if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
-						editor.selected_points ^= 1<<v;
+						selected_points ^= 1<<v;
 					else
-						editor.selected_points = 1<<v;
+						selected_points = 1<<v;
 				}
-				editor.lock_mouse = false;
-				ui_set_active_item(0);
+				lock_mouse = false;
+				UI()->SetActiveItem(0);
 			}
 		}
 
-		gfx_setcolor(1,1,1,1);
+		Graphics()->SetColor(1,1,1,1);
 	}
-	else if(ui_hot_item() == id)
+	else if(UI()->HotItem() == id)
 	{
 		ui_got_context = id;
 		
-		gfx_setcolor(1,1,1,1);
-		editor.tooltip = "Left mouse button to move. Hold shift to move the texture.";
+		Graphics()->SetColor(1,1,1,1);
+		tooltip = "Left mouse button to move. Hold shift to move the texture.";
 		
-		if(ui_mouse_button(0))
+		if(UI()->MouseButton(0))
 		{
-			ui_set_active_item(id);
+			UI()->SetActiveItem(id);
 			moved = false;
 			if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
 			{
 				operation = OP_MOVEUV;
-				editor.lock_mouse = true;
+				lock_mouse = true;
 			}
 			else
 				operation = OP_MOVEPOINT;
 				
-			if(!(editor.selected_points&(1<<v)))
+			if(!(selected_points&(1<<v)))
 			{
 				if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
-					editor.selected_points |= 1<<v;
+					selected_points |= 1<<v;
 				else
-					editor.selected_points = 1<<v;
+					selected_points = 1<<v;
 				moved = true;
 			}
 															
-			editor.selected_quad = quad_index;
+			selected_quad = quad_index;
 		}
-		else if(ui_mouse_button(1))
+		else if(UI()->MouseButton(1))
 		{
 			operation = OP_CONTEXT_MENU;
-			editor.selected_quad = quad_index;
-			ui_set_active_item(id);
+			selected_quad = quad_index;
+			UI()->SetActiveItem(id);
 		}
 	}
 	else
-		gfx_setcolor(1,0,0,1);
+		Graphics()->SetColor(1,0,0,1);
 	
-	gfx_quads_draw(px, py, 5.0f, 5.0f);	
+	Graphics()->QuadsDraw(px, py, 5.0f, 5.0f);	
 }
 
-static void do_map_editor(RECT view, RECT toolbar)
+void EDITOR::do_map_editor(CUIRect view, CUIRect toolbar)
 {
-	//ui_clip_enable(&view);
+	//UI()->ClipEnable(&view);
 	
-	bool show_picker = inp_key_pressed(KEY_SPACE) != 0 && editor.dialog == DIALOG_NONE;
+	bool show_picker = inp_key_pressed(KEY_SPACE) != 0 && dialog == DIALOG_NONE;
 
 	// render all good stuff
 	if(!show_picker)
 	{
-		for(int g = 0; g < editor.map.groups.len(); g++)
+		for(int g = 0; g < map.groups.len(); g++)
 		{
-			if(editor.map.groups[g]->visible)
-				editor.map.groups[g]->render();
-			//ui_clip_enable(&view);
+			if(map.groups[g]->visible)
+				map.groups[g]->render();
+			//UI()->ClipEnable(&view);
 		}
 		
 		// render the game above everything else
-		if(editor.map.game_group->visible && editor.map.game_layer->visible)
+		if(map.game_group->visible && map.game_layer->visible)
 		{
-			editor.map.game_group->mapscreen();
-			editor.map.game_layer->render();
+			map.game_group->mapscreen();
+			map.game_layer->render();
 		}
 	}
 
 	static void *editor_id = (void *)&editor_id;
-	int inside = ui_mouse_inside(&view);
+	int inside = UI()->MouseInside(&view);
 
 	// fetch mouse position
-	float wx = ui_mouse_world_x();
-	float wy = ui_mouse_world_y();
-	float mx = ui_mouse_x();
-	float my = ui_mouse_y();
+	float wx = UI()->MouseWorldX();
+	float wy = UI()->MouseWorldY();
+	float mx = UI()->MouseX();
+	float my = UI()->MouseY();
 	
 	static float start_wx = 0;
 	static float start_wy = 0;
@@ -1067,7 +1214,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 	// remap the screen so it can display the whole tileset
 	if(show_picker)
 	{
-		RECT screen = *ui_screen();
+		CUIRect screen = *UI()->Screen();
 		float size = 32.0*16.0f;
 		float w = size*(screen.w/view.w);
 		float h = size*(screen.h/view.h);
@@ -1075,8 +1222,8 @@ static void do_map_editor(RECT view, RECT toolbar)
 		float y = -(view.y/screen.h)*h;
 		wx = x+w*mx/screen.w;
 		wy = y+h*my/screen.h;
-		gfx_mapscreen(x, y, x+w, y+h);
-		LAYER_TILES *t = (LAYER_TILES *)editor.get_selected_layer_type(0, LAYERTYPE_TILES);
+		Graphics()->MapScreen(x, y, x+w, y+h);
+		LAYER_TILES *t = (LAYER_TILES *)get_selected_layer_type(0, LAYERTYPE_TILES);
 		if(t)
 		{
 			tileset_picker.image = t->image;
@@ -1099,11 +1246,11 @@ static void do_map_editor(RECT view, RECT toolbar)
 	}
 	else
 	{
-		edit_layers[0] = editor.get_selected_layer(0);
+		edit_layers[0] = get_selected_layer(0);
 		if(edit_layers[0])
 			num_edit_layers++;
 
-		LAYERGROUP *g = editor.get_selected_group();
+		LAYERGROUP *g = get_selected_group();
 		if(g)
 		{
 			g->mapscreen();
@@ -1116,50 +1263,50 @@ static void do_map_editor(RECT view, RECT toolbar)
 				float w, h;
 				edit_layers[i]->get_size(&w, &h);
 
-				gfx_texture_set(-1);
-				gfx_lines_begin();
-				gfx_lines_draw(0,0, w,0);
-				gfx_lines_draw(w,0, w,h);
-				gfx_lines_draw(w,h, 0,h);
-				gfx_lines_draw(0,h, 0,0);
-				gfx_lines_end();
+				Graphics()->TextureSet(-1);
+				Graphics()->LinesBegin();
+				Graphics()->LinesDraw(0,0, w,0);
+				Graphics()->LinesDraw(w,0, w,h);
+				Graphics()->LinesDraw(w,h, 0,h);
+				Graphics()->LinesDraw(0,h, 0,0);
+				Graphics()->LinesEnd();
 			}
 		}
 	}
 		
 	if(inside)
 	{
-		ui_set_hot_item(editor_id);
+		UI()->SetHotItem(editor_id);
 				
 		// do global operations like pan and zoom
-		if(ui_active_item() == 0 && (ui_mouse_button(0) || ui_mouse_button(2)))
+		if(UI()->ActiveItem() == 0 && (UI()->MouseButton(0) || UI()->MouseButton(2)))
 		{
 			start_wx = wx;
 			start_wy = wy;
 			start_mx = mx;
 			start_my = my;
 					
-			if(inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL) || ui_mouse_button(2))
+			if(inp_key_pressed(KEY_LCTRL) || inp_key_pressed(KEY_RCTRL) || UI()->MouseButton(2))
 			{
 				if(inp_key_pressed(KEY_LSHIFT))
 					operation = OP_PAN_EDITOR;
 				else
 					operation = OP_PAN_WORLD;
-				ui_set_active_item(editor_id);
+				UI()->SetActiveItem(editor_id);
 			}
 		}
 
 		// brush editing
-		if(ui_hot_item() == editor_id)
+		if(UI()->HotItem() == editor_id)
 		{
 			if(brush.is_empty())
-				editor.tooltip = "Use left mouse button to drag and create a brush.";
+				tooltip = "Use left mouse button to drag and create a brush.";
 			else
-				editor.tooltip = "Use left mouse button to paint with the brush. Right button clears the brush.";
+				tooltip = "Use left mouse button to paint with the brush. Right button clears the brush.";
 
-			if(ui_active_item() == editor_id)
+			if(UI()->ActiveItem() == editor_id)
 			{
-				RECT r;
+				CUIRect r;
 				r.x = start_wx;
 				r.y = start_wy;
 				r.w = wx-start_wx;
@@ -1190,7 +1337,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 				}
 				else if(operation == OP_BRUSH_GRAB)
 				{
-					if(!ui_mouse_button(0))
+					if(!UI()->MouseButton(0))
 					{
 						// grab brush
 						dbg_msg("editor", "grabbing %f %f %f %f", r.x, r.y, r.w, r.h);
@@ -1207,18 +1354,18 @@ static void do_map_editor(RECT view, RECT toolbar)
 						//editor.map.groups[selected_group]->mapscreen();
 						for(int k = 0; k < num_edit_layers; k++)
 							edit_layers[k]->brush_selecting(r);
-						gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
+						Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
 					}
 				}
 			}
 			else
 			{
-				if(ui_mouse_button(1))
+				if(UI()->MouseButton(1))
 					brush.clear();
 					
-				if(ui_mouse_button(0) && operation == OP_NONE)
+				if(UI()->MouseButton(0) && operation == OP_NONE)
 				{
-					ui_set_active_item(editor_id);
+					UI()->SetActiveItem(editor_id);
 					
 					if(brush.is_empty())
 						operation = OP_BRUSH_GRAB;
@@ -1248,7 +1395,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 						}
 					}
 				
-					LAYERGROUP *g = editor.get_selected_group();
+					LAYERGROUP *g = get_selected_group();
 					brush.offset_x += g->offset_x;
 					brush.offset_y += g->offset_y;
 					brush.parallax_x = g->parallax_x;
@@ -1257,13 +1404,13 @@ static void do_map_editor(RECT view, RECT toolbar)
 					float w, h;
 					brush.get_size(&w, &h);
 					
-					gfx_texture_set(-1);
-					gfx_lines_begin();
-					gfx_lines_draw(0,0, w,0);
-					gfx_lines_draw(w,0, w,h);
-					gfx_lines_draw(w,h, 0,h);
-					gfx_lines_draw(0,h, 0,0);
-					gfx_lines_end();
+					Graphics()->TextureSet(-1);
+					Graphics()->LinesBegin();
+					Graphics()->LinesDraw(0,0, w,0);
+					Graphics()->LinesDraw(w,0, w,h);
+					Graphics()->LinesDraw(w,h, 0,h);
+					Graphics()->LinesDraw(0,h, 0,0);
+					Graphics()->LinesEnd();
 					
 				}
 			}
@@ -1274,7 +1421,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 			if(!show_picker && brush.is_empty())
 			{
 				// fetch layers
-				LAYERGROUP *g = editor.get_selected_group();
+				LAYERGROUP *g = get_selected_group();
 				if(g)
 					g->mapscreen();
 					
@@ -1284,8 +1431,8 @@ static void do_map_editor(RECT view, RECT toolbar)
 					{
 						LAYER_QUADS *layer = (LAYER_QUADS *)edit_layers[k];
 		
-						gfx_texture_set(-1);
-						gfx_quads_begin();				
+						Graphics()->TextureSet(-1);
+						Graphics()->QuadsBegin();				
 						for(int i = 0; i < layer->quads.len(); i++)
 						{
 							for(int v = 0; v < 4; v++)
@@ -1293,68 +1440,68 @@ static void do_map_editor(RECT view, RECT toolbar)
 								
 							do_quad(&layer->quads[i], i);
 						}
-						gfx_quads_end();
+						Graphics()->QuadsEnd();
 					}
 				}
 				
-				gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
+				Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
 			}		
 			
 			// do panning
-			if(ui_active_item() == editor_id)
+			if(UI()->ActiveItem() == editor_id)
 			{
 				if(operation == OP_PAN_WORLD)
 				{
-					editor.world_offset_x -= editor.mouse_delta_x*editor.world_zoom;
-					editor.world_offset_y -= editor.mouse_delta_y*editor.world_zoom;
+					world_offset_x -= mouse_delta_x*world_zoom;
+					world_offset_y -= mouse_delta_y*world_zoom;
 				}
 				else if(operation == OP_PAN_EDITOR)
 				{
-					editor.editor_offset_x -= editor.mouse_delta_x*editor.world_zoom;
-					editor.editor_offset_y -= editor.mouse_delta_y*editor.world_zoom;
+					editor_offset_x -= mouse_delta_x*world_zoom;
+					editor_offset_y -= mouse_delta_y*world_zoom;
 				}
 
 				// release mouse
-				if(!ui_mouse_button(0))
+				if(!UI()->MouseButton(0))
 				{
 					operation = OP_NONE;
-					ui_set_active_item(0);
+					UI()->SetActiveItem(0);
 				}
 			}
 		}
 	}
 	
-	if(editor.get_selected_group() && editor.get_selected_group()->use_clipping)
+	if(get_selected_group() && get_selected_group()->use_clipping)
 	{
-		LAYERGROUP *g = editor.map.game_group;
+		LAYERGROUP *g = map.game_group;
 		g->mapscreen();
 		
-		gfx_texture_set(-1);
-		gfx_lines_begin();
-
-			RECT r;
-			r.x = editor.get_selected_group()->clip_x;
-			r.y = editor.get_selected_group()->clip_y;
-			r.w = editor.get_selected_group()->clip_w;
-			r.h = editor.get_selected_group()->clip_h;
+		Graphics()->TextureSet(-1);
+		Graphics()->LinesBegin();
+
+			CUIRect r;
+			r.x = get_selected_group()->clip_x;
+			r.y = get_selected_group()->clip_y;
+			r.w = get_selected_group()->clip_w;
+			r.h = get_selected_group()->clip_h;
 			
-			gfx_setcolor(1,0,0,1);
-			gfx_lines_draw(r.x, r.y, r.x+r.w, r.y);
-			gfx_lines_draw(r.x+r.w, r.y, r.x+r.w, r.y+r.h);
-			gfx_lines_draw(r.x+r.w, r.y+r.h, r.x, r.y+r.h);
-			gfx_lines_draw(r.x, r.y+r.h, r.x, r.y);
+			Graphics()->SetColor(1,0,0,1);
+			Graphics()->LinesDraw(r.x, r.y, r.x+r.w, r.y);
+			Graphics()->LinesDraw(r.x+r.w, r.y, r.x+r.w, r.y+r.h);
+			Graphics()->LinesDraw(r.x+r.w, r.y+r.h, r.x, r.y+r.h);
+			Graphics()->LinesDraw(r.x, r.y+r.h, r.x, r.y);
 			
-		gfx_lines_end();
+		Graphics()->LinesEnd();
 	}
 
 	// render screen sizes	
-	if(editor.proof_borders)
+	if(proof_borders)
 	{
-		LAYERGROUP *g = editor.map.game_group;
+		LAYERGROUP *g = map.game_group;
 		g->mapscreen();
 		
-		gfx_texture_set(-1);
-		gfx_lines_begin();
+		Graphics()->TextureSet(-1);
+		Graphics()->LinesBegin();
 		
 		float last_points[4];
 		float start = 1.0f; //9.0f/16.0f;
@@ -1365,28 +1512,28 @@ static void do_map_editor(RECT view, RECT toolbar)
 			float points[4];
 			float aspect = start + (end-start)*(i/(float)num_steps);
 			
-			mapscreen_to_world(
-				editor.world_offset_x, editor.world_offset_y,
+			RenderTools()->mapscreen_to_world(
+				world_offset_x, world_offset_y,
 				1.0f, 1.0f, 0.0f, 0.0f, aspect, 1.0f, points);
 			
 			if(i == 0)
 			{
-				gfx_lines_draw(points[0], points[1], points[2], points[1]);
-				gfx_lines_draw(points[0], points[3], points[2], points[3]);
+				Graphics()->LinesDraw(points[0], points[1], points[2], points[1]);
+				Graphics()->LinesDraw(points[0], points[3], points[2], points[3]);
 			}
 
 			if(i != 0)
 			{
-				gfx_lines_draw(points[0], points[1], last_points[0], last_points[1]);
-				gfx_lines_draw(points[2], points[1], last_points[2], last_points[1]);
-				gfx_lines_draw(points[0], points[3], last_points[0], last_points[3]);
-				gfx_lines_draw(points[2], points[3], last_points[2], last_points[3]);
+				Graphics()->LinesDraw(points[0], points[1], last_points[0], last_points[1]);
+				Graphics()->LinesDraw(points[2], points[1], last_points[2], last_points[1]);
+				Graphics()->LinesDraw(points[0], points[3], last_points[0], last_points[3]);
+				Graphics()->LinesDraw(points[2], points[3], last_points[2], last_points[3]);
 			}
 
 			if(i == num_steps)
 			{
-				gfx_lines_draw(points[0], points[1], points[0], points[3]);
-				gfx_lines_draw(points[2], points[1], points[2], points[3]);
+				Graphics()->LinesDraw(points[0], points[1], points[0], points[3]);
+				Graphics()->LinesDraw(points[2], points[1], points[2], points[3]);
 			}
 			
 			mem_copy(last_points, points, sizeof(points));
@@ -1394,64 +1541,64 @@ static void do_map_editor(RECT view, RECT toolbar)
 
 		if(1)
 		{
-			gfx_setcolor(1,0,0,1);
+			Graphics()->SetColor(1,0,0,1);
 			for(int i = 0; i < 2; i++)
 			{
 				float points[4];
 				float aspects[] = {4.0f/3.0f, 16.0f/10.0f, 5.0f/4.0f, 16.0f/9.0f};
 				float aspect = aspects[i];
 				
-				mapscreen_to_world(
-					editor.world_offset_x, editor.world_offset_y,
+				RenderTools()->mapscreen_to_world(
+					world_offset_x, world_offset_y,
 					1.0f, 1.0f, 0.0f, 0.0f, aspect, 1.0f, points);
 				
-				RECT r;
+				CUIRect r;
 				r.x = points[0];
 				r.y = points[1];
 				r.w = points[2]-points[0];
 				r.h = points[3]-points[1];
 				
-				gfx_lines_draw(r.x, r.y, r.x+r.w, r.y);
-				gfx_lines_draw(r.x+r.w, r.y, r.x+r.w, r.y+r.h);
-				gfx_lines_draw(r.x+r.w, r.y+r.h, r.x, r.y+r.h);
-				gfx_lines_draw(r.x, r.y+r.h, r.x, r.y);
-				gfx_setcolor(0,1,0,1);
+				Graphics()->LinesDraw(r.x, r.y, r.x+r.w, r.y);
+				Graphics()->LinesDraw(r.x+r.w, r.y, r.x+r.w, r.y+r.h);
+				Graphics()->LinesDraw(r.x+r.w, r.y+r.h, r.x, r.y+r.h);
+				Graphics()->LinesDraw(r.x, r.y+r.h, r.x, r.y);
+				Graphics()->SetColor(0,1,0,1);
 			}
 		}
 			
-		gfx_lines_end();
+		Graphics()->LinesEnd();
 	}
 	
-	gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
-	//ui_clip_disable();
+	Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
+	//UI()->ClipDisable();
 }
 
 
-int EDITOR::do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val)
+int EDITOR::do_properties(CUIRect *toolbox, PROPERTY *props, int *ids, int *new_val)
 {
 	int change = -1;
 
 	for(int i = 0; props[i].name; i++)
 	{
-		RECT slot;
-		ui_hsplit_t(toolbox, 13.0f, &slot, toolbox);
-		RECT label, shifter;
-		ui_vsplit_mid(&slot, &label, &shifter);
-		ui_hmargin(&shifter, 1.0f, &shifter);
-		ui_do_label(&label, props[i].name, 10.0f, -1, -1);
+		CUIRect slot;
+		toolbox->HSplitTop(13.0f, &slot, toolbox);
+		CUIRect label, shifter;
+		slot.VSplitMid(&label, &shifter);
+		shifter.HMargin(1.0f, &shifter);
+		UI()->DoLabel(&label, props[i].name, 10.0f, -1, -1);
 		
 		if(props[i].type == PROPTYPE_INT_STEP)
 		{
-			RECT inc, dec;
+			CUIRect inc, dec;
 			char buf[64];
 			
-			ui_vsplit_r(&shifter, 10.0f, &shifter, &inc);
-			ui_vsplit_l(&shifter, 10.0f, &dec, &shifter);
+			shifter.VSplitRight(10.0f, &shifter, &inc);
+			shifter.VSplitLeft(10.0f, &dec, &shifter);
 			sprintf(buf, "%d", props[i].value);
-			ui_draw_rect(&shifter, vec4(1,1,1,0.5f), 0, 0.0f);
-			ui_do_label(&shifter, buf, 10.0f, 0, -1);
+			RenderTools()->DrawUIRect(&shifter, vec4(1,1,1,0.5f), 0, 0.0f);
+			UI()->DoLabel(&shifter, buf, 10.0f, 0, -1);
 			
-			if(do_editor_button(&ids[i], 0, 0, &dec, draw_dec_button, 0, "Decrease"))
+			if(DoButton_ButtonDec(&ids[i], 0, 0, &dec, 0, "Decrease"))
 			{
 				if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
 					*new_val = props[i].value-5;
@@ -1459,7 +1606,7 @@ int EDITOR::do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val
 					*new_val = props[i].value-1;
 				change = i;
 			}
-			if(do_editor_button(((char *)&ids[i])+1, 0, 0, &inc, draw_inc_button, 0, "Increase"))
+			if(DoButton_ButtonInc(((char *)&ids[i])+1, 0, 0, &inc, 0, "Increase"))
 			{
 				if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
 					*new_val = props[i].value+5;
@@ -1470,14 +1617,14 @@ int EDITOR::do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val
 		}
 		else if(props[i].type == PROPTYPE_BOOL)
 		{
-			RECT no, yes;
-			ui_vsplit_mid(&shifter, &no, &yes);
-			if(do_editor_button(&ids[i], "No", !props[i].value, &no, draw_dec_button, 0, ""))
+			CUIRect no, yes;
+			shifter.VSplitMid(&no, &yes);
+			if(DoButton_ButtonDec(&ids[i], "No", !props[i].value, &no, 0, ""))
 			{
 				*new_val = 0;
 				change = i;
 			}
-			if(do_editor_button(((char *)&ids[i])+1, "Yes", props[i].value, &yes, draw_inc_button, 0, ""))
+			if(DoButton_ButtonInc(((char *)&ids[i])+1, "Yes", props[i].value, &yes, 0, ""))
 			{
 				*new_val = 1;
 				change = i;
@@ -1505,9 +1652,9 @@ int EDITOR::do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val
 
 				if(c != 3)
 				{
-					ui_hsplit_t(toolbox, 13.0f, &slot, toolbox);
-					ui_vsplit_mid(&slot, 0, &shifter);
-					ui_hmargin(&shifter, 1.0f, &shifter);
+					toolbox->HSplitTop(13.0f, &slot, toolbox);
+					slot.VSplitMid(0, &shifter);
+					shifter.HMargin(1.0f, &shifter);
 				}
 			}
 			
@@ -1523,10 +1670,10 @@ int EDITOR::do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val
 			if(props[i].value < 0)
 				strcpy(buf, "None");
 			else
-				sprintf(buf, "%s",  editor.map.images[props[i].value]->name);
+				sprintf(buf, "%s",  map.images[props[i].value]->name);
 			
-			if(do_editor_button(&ids[i], buf, 0, &shifter, draw_editor_button, 0, 0))
-				popup_select_image_invoke(props[i].value, ui_mouse_x(), ui_mouse_y());
+			if(DoButton_Editor(&ids[i], buf, 0, &shifter, 0, 0))
+				popup_select_image_invoke(props[i].value, UI()->MouseX(), UI()->MouseY());
 			
 			int r = popup_select_image_result();
 			if(r >= -1)
@@ -1540,90 +1687,90 @@ int EDITOR::do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val
 	return change;
 }
 
-static void render_layers(RECT toolbox, RECT toolbar, RECT view)
+void EDITOR::render_layers(CUIRect toolbox, CUIRect toolbar, CUIRect view)
 {
-	RECT layersbox = toolbox;
+	CUIRect layersbox = toolbox;
 
-	if(!editor.gui_active)
+	if(!gui_active)
 		return;
 			
-	RECT slot, button;
+	CUIRect slot, button;
 	char buf[64];
 
 	int valid_group = 0;
 	int valid_layer = 0;
-	if(editor.selected_group >= 0 && editor.selected_group < editor.map.groups.len())
+	if(selected_group >= 0 && selected_group < map.groups.len())
 		valid_group = 1;
 
-	if(valid_group && editor.selected_layer >= 0 && editor.selected_layer < editor.map.groups[editor.selected_group]->layers.len())
+	if(valid_group && selected_layer >= 0 && selected_layer < map.groups[selected_group]->layers.len())
 		valid_layer = 1;
 		
 	// render layers	
 	{
-		for(int g = 0; g < editor.map.groups.len(); g++)
+		for(int g = 0; g < map.groups.len(); g++)
 		{
-			RECT visible_toggle;
-			ui_hsplit_t(&layersbox, 12.0f, &slot, &layersbox);
-			ui_vsplit_l(&slot, 12, &visible_toggle, &slot);
-			if(do_editor_button(&editor.map.groups[g]->visible, editor.map.groups[g]->visible?"V":"H", 0, &visible_toggle, draw_editor_button_l, 0, "Toggle group visibility"))
-				editor.map.groups[g]->visible = !editor.map.groups[g]->visible;
-
-			sprintf(buf, "#%d %s", g, editor.map.groups[g]->name);
-			if(int result = do_editor_button(&editor.map.groups[g], buf, g==editor.selected_group, &slot, draw_editor_button_r,
+			CUIRect visible_toggle;
+			layersbox.HSplitTop(12.0f, &slot, &layersbox);
+			slot.VSplitLeft(12, &visible_toggle, &slot);
+			if(DoButton_ButtonL(&map.groups[g]->visible, map.groups[g]->visible?"V":"H", 0, &visible_toggle, 0, "Toggle group visibility"))
+				map.groups[g]->visible = !map.groups[g]->visible;
+
+			sprintf(buf, "#%d %s", g, map.groups[g]->name);
+			if(int result = DoButton_ButtonR(&map.groups[g], buf, g==selected_group, &slot,
 				BUTTON_CONTEXT, "Select group. Right click for properties."))
 			{
-				editor.selected_group = g;
-				editor.selected_layer = 0;
+				selected_group = g;
+				selected_layer = 0;
 				
 				static int group_popup_id = 0;
 				if(result == 2)
-					ui_invoke_popup_menu(&group_popup_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 200, popup_group);
+					ui_invoke_popup_menu(&group_popup_id, 0, UI()->MouseX(), UI()->MouseY(), 120, 200, popup_group);
 			}
 			
 			
-			ui_hsplit_t(&layersbox, 2.0f, &slot, &layersbox);
+			layersbox.HSplitTop(2.0f, &slot, &layersbox);
 			
-			for(int i = 0; i < editor.map.groups[g]->layers.len(); i++)
+			for(int i = 0; i < map.groups[g]->layers.len(); i++)
 			{
 				//visible
-				ui_hsplit_t(&layersbox, 12.0f, &slot, &layersbox);
-				ui_vsplit_l(&slot, 12.0f, 0, &button);
-				ui_vsplit_l(&button, 15, &visible_toggle, &button);
+				layersbox.HSplitTop(12.0f, &slot, &layersbox);
+				slot.VSplitLeft(12.0f, 0, &button);
+				button.VSplitLeft(15, &visible_toggle, &button);
 
-				if(do_editor_button(&editor.map.groups[g]->layers[i]->visible, editor.map.groups[g]->layers[i]->visible?"V":"H", 0, &visible_toggle, draw_editor_button_l, 0, "Toggle layer visibility"))
-					editor.map.groups[g]->layers[i]->visible = !editor.map.groups[g]->layers[i]->visible;
+				if(DoButton_ButtonL(&map.groups[g]->layers[i]->visible, map.groups[g]->layers[i]->visible?"V":"H", 0, &visible_toggle, 0, "Toggle layer visibility"))
+					map.groups[g]->layers[i]->visible = !map.groups[g]->layers[i]->visible;
 
-				sprintf(buf, "#%d %s ", i, editor.map.groups[g]->layers[i]->type_name);
-				if(int result = do_editor_button(editor.map.groups[g]->layers[i], buf, g==editor.selected_group&&i==editor.selected_layer, &button, draw_editor_button_r,
+				sprintf(buf, "#%d %s ", i, map.groups[g]->layers[i]->type_name);
+				if(int result = DoButton_ButtonR(map.groups[g]->layers[i], buf, g==selected_group&&i==selected_layer, &button,
 					BUTTON_CONTEXT, "Select layer. Right click for properties."))
 				{
-					editor.selected_layer = i;
-					editor.selected_group = g;
+					selected_layer = i;
+					selected_group = g;
 					static int layer_popup_id = 0;
 					if(result == 2)
-						ui_invoke_popup_menu(&layer_popup_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 150, popup_layer);
+						ui_invoke_popup_menu(&layer_popup_id, 0, UI()->MouseX(), UI()->MouseY(), 120, 150, popup_layer);
 				}
 				
 				
-				ui_hsplit_t(&layersbox, 2.0f, &slot, &layersbox);
+				layersbox.HSplitTop(2.0f, &slot, &layersbox);
 			}
-			ui_hsplit_t(&layersbox, 5.0f, &slot, &layersbox);
+			layersbox.HSplitTop(5.0f, &slot, &layersbox);
 		}
 	}
 	
 
 	{
-		ui_hsplit_t(&layersbox, 12.0f, &slot, &layersbox);
+		layersbox.HSplitTop(12.0f, &slot, &layersbox);
 
 		static int new_group_button = 0;
-		if(do_editor_button(&new_group_button, "Add Group", 0, &slot, draw_editor_button, 0, "Adds a new group"))
+		if(DoButton_Editor(&new_group_button, "Add Group", 0, &slot, 0, "Adds a new group"))
 		{
-			editor.map.new_group();
-			editor.selected_group = editor.map.groups.len()-1;
+			map.new_group();
+			selected_group = map.groups.len()-1;
 		}
 	}
 
-	ui_hsplit_t(&layersbox, 5.0f, &slot, &layersbox);
+	layersbox.HSplitTop(5.0f, &slot, &layersbox);
 	
 }
 
@@ -1659,31 +1806,33 @@ static void extract_name(const char *filename, char *name)
 	dbg_msg("", "%s %s %d %d", filename, name, start, end);
 }
 
-static void replace_image(const char *filename)
+void EDITOR::replace_image(const char *filename, void *user)
 {
-	EDITOR_IMAGE imginfo;
-	if(!gfx_load_png(&imginfo, filename))
+	EDITOR *editor = (EDITOR *)user;
+	EDITOR_IMAGE imginfo(editor);
+	if(!editor->Graphics()->LoadPNG(&imginfo, filename))
 		return;
 	
-	EDITOR_IMAGE *img = editor.map.images[editor.selected_image];
-	gfx_unload_texture(img->tex_id);
+	EDITOR_IMAGE *img = editor->map.images[editor->selected_image];
+	editor->Graphics()->UnloadTexture(img->tex_id);
 	*img = imginfo;
 	extract_name(filename, img->name);
-	img->tex_id = gfx_load_texture_raw(imginfo.width, imginfo.height, imginfo.format, imginfo.data, IMG_AUTO, 0);
+	img->tex_id = editor->Graphics()->LoadTextureRaw(imginfo.width, imginfo.height, imginfo.format, imginfo.data, IMG_AUTO, 0);
 }
 
-static void add_image(const char *filename)
+void EDITOR::add_image(const char *filename, void *user)
 {
-	EDITOR_IMAGE imginfo;
-	if(!gfx_load_png(&imginfo, filename))
+	EDITOR *editor = (EDITOR *)user;
+	EDITOR_IMAGE imginfo(editor);
+	if(!editor->Graphics()->LoadPNG(&imginfo, filename))
 		return;
 
-	EDITOR_IMAGE *img = new EDITOR_IMAGE;
+	EDITOR_IMAGE *img = new EDITOR_IMAGE(editor);
 	*img = imginfo;
-	img->tex_id = gfx_load_texture_raw(imginfo.width, imginfo.height, imginfo.format, imginfo.data, IMG_AUTO, 0);
+	img->tex_id = editor->Graphics()->LoadTextureRaw(imginfo.width, imginfo.height, imginfo.format, imginfo.data, IMG_AUTO, 0);
 	img->external = 1; // external by default
 	extract_name(filename, img->name);
-	editor.map.images.add(img);
+	editor->map.images.add(img);
 }
 
 
@@ -1696,20 +1845,20 @@ static void modify_index_deleted(int *index)
 		*index = *index - 1;
 }
 
-static int popup_image(RECT view)
+int EDITOR::popup_image(EDITOR *pEditor, CUIRect view)
 {
 	static int replace_button = 0;	
 	static int remove_button = 0;	
 
-	RECT slot;
-	ui_hsplit_t(&view, 2.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	EDITOR_IMAGE *img = editor.map.images[editor.selected_image];
+	CUIRect slot;
+	view.HSplitTop(2.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	EDITOR_IMAGE *img = pEditor->map.images[pEditor->selected_image];
 	
 	static int external_button = 0;
 	if(img->external)
 	{
-		if(do_editor_button(&external_button, "Embedd", 0, &slot, draw_editor_button_menuitem, 0, "Embedds the image into the map file."))
+		if(pEditor->DoButton_MenuItem(&external_button, "Embedd", 0, &slot, 0, "Embedds the image into the map file."))
 		{
 			img->external = 0;
 			return 1;
@@ -1717,29 +1866,29 @@ static int popup_image(RECT view)
 	}
 	else
 	{		
-		if(do_editor_button(&external_button, "Make external", 0, &slot, draw_editor_button_menuitem, 0, "Removes the image from the map file."))
+		if(pEditor->DoButton_MenuItem(&external_button, "Make external", 0, &slot, 0, "Removes the image from the map file."))
 		{
 			img->external = 1;
 			return 1;
 		}
 	}
 
-	ui_hsplit_t(&view, 10.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&replace_button, "Replace", 0, &slot, draw_editor_button_menuitem, 0, "Replaces the image with a new one"))
+	view.HSplitTop(10.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&replace_button, "Replace", 0, &slot, 0, "Replaces the image with a new one"))
 	{
-		editor.invoke_file_dialog(LISTDIRTYPE_ALL, "Replace Image", "Replace", "mapres/", "", replace_image);
+		pEditor->invoke_file_dialog(LISTDIRTYPE_ALL, "Replace Image", "Replace", "mapres/", "", replace_image, pEditor);
 		return 1;
 	}
 
-	ui_hsplit_t(&view, 10.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&remove_button, "Remove", 0, &slot, draw_editor_button_menuitem, 0, "Removes the image from the map"))
+	view.HSplitTop(10.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&remove_button, "Remove", 0, &slot, 0, "Removes the image from the map"))
 	{
 		delete img;
-		editor.map.images.removebyindex(editor.selected_image);
-		modify_index_deleted_index = editor.selected_image;
-		editor.map.modify_image_index(modify_index_deleted);
+		pEditor->map.images.removebyindex(pEditor->selected_image);
+		modify_index_deleted_index = pEditor->selected_image;
+		pEditor->map.modify_image_index(modify_index_deleted);
 		return 1;
 	}
 
@@ -1747,76 +1896,77 @@ static int popup_image(RECT view)
 }
 
 
-static void render_images(RECT toolbox, RECT toolbar, RECT view)
+void EDITOR::render_images(CUIRect toolbox, CUIRect toolbar, CUIRect view)
 {
 	for(int e = 0; e < 2; e++) // two passes, first embedded, then external
 	{
-		RECT slot;
-		ui_hsplit_t(&toolbox, 15.0f, &slot, &toolbox);
+		CUIRect slot;
+		toolbox.HSplitTop(15.0f, &slot, &toolbox);
 		if(e == 0)
-			ui_do_label(&slot, "Embedded", 12.0f, 0);
+			UI()->DoLabel(&slot, "Embedded", 12.0f, 0);
 		else
-			ui_do_label(&slot, "External", 12.0f, 0);
+			UI()->DoLabel(&slot, "External", 12.0f, 0);
 		
-		for(int i = 0; i < editor.map.images.len(); i++)
+		for(int i = 0; i < map.images.len(); i++)
 		{
-			if((e && !editor.map.images[i]->external) ||
-				(!e && editor.map.images[i]->external))
+			if((e && !map.images[i]->external) ||
+				(!e && map.images[i]->external))
 			{
 				continue;
 			}
 			
 			char buf[128];
-			sprintf(buf, "%s", editor.map.images[i]->name);
-			ui_hsplit_t(&toolbox, 12.0f, &slot, &toolbox);
+			sprintf(buf, "%s", map.images[i]->name);
+			toolbox.HSplitTop(12.0f, &slot, &toolbox);
 			
-			if(int result = do_editor_button(&editor.map.images[i], buf, editor.selected_image == i, &slot, draw_editor_button,
+			if(int result = DoButton_Editor(&map.images[i], buf, selected_image == i, &slot,
 				BUTTON_CONTEXT, "Select image"))
 			{
-				editor.selected_image = i;
+				selected_image = i;
 				
 				static int popup_image_id = 0;
 				if(result == 2)
-					ui_invoke_popup_menu(&popup_image_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 80, popup_image);
+					ui_invoke_popup_menu(&popup_image_id, 0, UI()->MouseX(), UI()->MouseY(), 120, 80, popup_image);
 			}
 			
-			ui_hsplit_t(&toolbox, 2.0f, 0, &toolbox);
+			toolbox.HSplitTop(2.0f, 0, &toolbox);
 			
 			// render image
-			if(editor.selected_image == i)
+			if(selected_image == i)
 			{
-				RECT r;
-				ui_margin(&view, 10.0f, &r);
+				CUIRect r;
+				view.Margin(10.0f, &r);
 				if(r.h < r.w)
 					r.w = r.h;
 				else
 					r.h = r.w;
-				gfx_texture_set(editor.map.images[i]->tex_id);
-				gfx_blend_normal();
-				gfx_quads_begin();
-				gfx_quads_drawTL(r.x, r.y, r.w, r.h);
-				gfx_quads_end();
+				Graphics()->TextureSet(map.images[i]->tex_id);
+				Graphics()->BlendNormal();
+				Graphics()->QuadsBegin();
+				Graphics()->QuadsDrawTL(r.x, r.y, r.w, r.h);
+				Graphics()->QuadsEnd();
 				
 			}
 		}
 	}
 	
-	RECT slot;
-	ui_hsplit_t(&toolbox, 5.0f, &slot, &toolbox);
+	CUIRect slot;
+	toolbox.HSplitTop(5.0f, &slot, &toolbox);
 	
 	// new image
 	static int new_image_button = 0;
-	ui_hsplit_t(&toolbox, 10.0f, &slot, &toolbox);
-	ui_hsplit_t(&toolbox, 12.0f, &slot, &toolbox);
-	if(do_editor_button(&new_image_button, "Add", 0, &slot, draw_editor_button, 0, "Load a new image to use in the map"))
-		editor.invoke_file_dialog(LISTDIRTYPE_ALL, "Add Image", "Add", "mapres/", "", add_image);
+	toolbox.HSplitTop(10.0f, &slot, &toolbox);
+	toolbox.HSplitTop(12.0f, &slot, &toolbox);
+	if(DoButton_Editor(&new_image_button, "Add", 0, &slot, 0, "Load a new image to use in the map"))
+		invoke_file_dialog(LISTDIRTYPE_ALL, "Add Image", "Add", "mapres/", "", add_image, this);
 }
 
 
 static int file_dialog_dirtypes = 0;
 static const char *file_dialog_title = 0;
 static const char *file_dialog_button_text = 0;
-static void (*file_dialog_func)(const char *filename);
+static void (*file_dialog_func)(const char *filename, void *user);
+static void *file_dialog_user = 0;
 static char file_dialog_filename[512] = {0};
 static char file_dialog_path[512] = {0};
 static char file_dialog_complete_filename[512] = {0};
@@ -1825,6 +1975,12 @@ int files_startat = 0;
 int files_cur = 0;
 int files_stopat = 999;
 
+struct LISTDIRINFO
+{
+	CUIRect *rect;
+	EDITOR *editor;
+};
+
 static void editor_listdir_callback(const char *name, int is_dir, void *user)
 {
 	if(name[0] == '.' || is_dir) // skip this shit!
@@ -1837,13 +1993,14 @@ static void editor_listdir_callback(const char *name, int is_dir, void *user)
 	if(files_cur-1 < files_startat || files_cur > files_stopat)
 		return;
 	
-	RECT *view = (RECT *)user;
-	RECT button;
-	ui_hsplit_t(view, 15.0f, &button, view);
-	ui_hsplit_t(view, 2.0f, 0, view);
+	LISTDIRINFO *info = (LISTDIRINFO *)user;
+	CUIRect *view = info->rect;
+	CUIRect button;
+	view->HSplitTop(15.0f, &button, view);
+	view->HSplitTop(2.0f, 0, view);
 	//char buf[512];
 	
-	if(do_editor_button((void*)(10+(int)button.y), name, 0, &button, draw_editor_button_file, 0, 0))
+	if(info->editor->DoButton_File((void*)(10+(int)button.y), name, 0, &button, 0, 0))
 	{
 		strncpy(file_dialog_filename, name, sizeof(file_dialog_filename));
 		
@@ -1854,43 +2011,43 @@ static void editor_listdir_callback(const char *name, int is_dir, void *user)
 		if(inp_mouse_doubleclick())
 		{
 			if(file_dialog_func)
-				file_dialog_func(file_dialog_complete_filename);
-			editor.dialog = DIALOG_NONE;
+				file_dialog_func(file_dialog_complete_filename, user);
+			info->editor->dialog = DIALOG_NONE;
 		}
 	}
 }
 
-static void render_file_dialog()
+void EDITOR::render_file_dialog()
 {
 	// GUI coordsys
-	gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
-	
-	RECT view = *ui_screen();
-	ui_draw_rect(&view, vec4(0,0,0,0.25f), 0, 0);
-	ui_vmargin(&view, 150.0f, &view);
-	ui_hmargin(&view, 50.0f, &view);
-	ui_draw_rect(&view, vec4(0,0,0,0.75f), CORNER_ALL, 5.0f);
-	ui_margin(&view, 10.0f, &view);
-
-	RECT title, filebox, filebox_label, buttonbar, scroll;
-	ui_hsplit_t(&view, 18.0f, &title, &view);
-	ui_hsplit_t(&view, 5.0f, 0, &view); // some spacing
-	ui_hsplit_b(&view, 14.0f, &view, &buttonbar);
-	ui_hsplit_b(&view, 10.0f, &view, 0); // some spacing
-	ui_hsplit_b(&view, 14.0f, &view, &filebox);
-	ui_vsplit_l(&filebox, 50.0f, &filebox_label, &filebox);
-	ui_vsplit_r(&view, 15.0f, &view, &scroll);
+	Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
+	
+	CUIRect view = *UI()->Screen();
+	RenderTools()->DrawUIRect(&view, vec4(0,0,0,0.25f), 0, 0);
+	view.VMargin(150.0f, &view);
+	view.HMargin(50.0f, &view);
+	RenderTools()->DrawUIRect(&view, vec4(0,0,0,0.75f), CUI::CORNER_ALL, 5.0f);
+	view.Margin(10.0f, &view);
+
+	CUIRect title, filebox, filebox_label, buttonbar, scroll;
+	view.HSplitTop(18.0f, &title, &view);
+	view.HSplitTop(5.0f, 0, &view); // some spacing
+	view.HSplitBottom(14.0f, &view, &buttonbar);
+	view.HSplitBottom(10.0f, &view, 0); // some spacing
+	view.HSplitBottom(14.0f, &view, &filebox);
+	filebox.VSplitLeft(50.0f, &filebox_label, &filebox);
+	view.VSplitRight(15.0f, &view, &scroll);
 	
 	// title
-	ui_draw_rect(&title, vec4(1,1,1,0.25f), CORNER_ALL, 5.0f);
-	ui_vmargin(&title, 10.0f, &title);
-	ui_do_label(&title, file_dialog_title, 14.0f, -1, -1);
+	RenderTools()->DrawUIRect(&title, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 5.0f);
+	title.VMargin(10.0f, &title);
+	UI()->DoLabel(&title, file_dialog_title, 14.0f, -1, -1);
 	
 	// filebox
-	ui_do_label(&filebox_label, "Filename:", 10.0f, -1, -1);
+	UI()->DoLabel(&filebox_label, "Filename:", 10.0f, -1, -1);
 	
 	static int filebox_id = 0;
-	ui_do_edit_box(&filebox_id, &filebox, file_dialog_filename, sizeof(file_dialog_filename), 10.0f);
+	DoEditBox(&filebox_id, &filebox, file_dialog_filename, sizeof(file_dialog_filename), 10.0f);
 
 	file_dialog_complete_filename[0] = 0;
 	strcat(file_dialog_complete_filename, file_dialog_path);
@@ -1899,7 +2056,7 @@ static void render_file_dialog()
 	int num = (int)(view.h/17.0);
 	static float scrollvalue = 0;
 	static int scrollbar = 0;
-	ui_hmargin(&scroll, 5.0f, &scroll);
+	scroll.HMargin(5.0f, &scroll);
 	scrollvalue = ui_do_scrollbar_v(&scrollbar, &scroll, scrollvalue);
 	
 	int scrollnum = files_num-num+10;
@@ -1925,41 +2082,45 @@ static void render_file_dialog()
 	files_cur = 0;
 	
 	// set clipping
-	ui_clip_enable(&view);
+	UI()->ClipEnable(&view);
 	
 	// the list
-	engine_listdir(file_dialog_dirtypes, file_dialog_path, editor_listdir_callback, &view);
+	LISTDIRINFO info;
+	info.rect = &view;
+	info.editor = this;
+	engine_listdir(file_dialog_dirtypes, file_dialog_path, editor_listdir_callback, &info);
 	
 	// disable clipping again
-	ui_clip_disable();
+	UI()->ClipDisable();
 	
 	// the buttons
 	static int ok_button = 0;	
 	static int cancel_button = 0;	
 
-	RECT button;
-	ui_vsplit_r(&buttonbar, 50.0f, &buttonbar, &button);
-	if(do_editor_button(&ok_button, file_dialog_button_text, 0, &button, draw_editor_button, 0, 0) || inp_key_pressed(KEY_RETURN))
+	CUIRect button;
+	buttonbar.VSplitRight(50.0f, &buttonbar, &button);
+	if(DoButton_Editor(&ok_button, file_dialog_button_text, 0, &button, 0, 0) || inp_key_pressed(KEY_RETURN))
 	{
 		if(file_dialog_func)
-			file_dialog_func(file_dialog_complete_filename);
-		editor.dialog = DIALOG_NONE;
+			file_dialog_func(file_dialog_complete_filename, file_dialog_user);
+		dialog = DIALOG_NONE;
 	}
 
-	ui_vsplit_r(&buttonbar, 40.0f, &buttonbar, &button);
-	ui_vsplit_r(&buttonbar, 50.0f, &buttonbar, &button);
-	if(do_editor_button(&cancel_button, "Cancel", 0, &button, draw_editor_button, 0, 0) || inp_key_pressed(KEY_ESCAPE))
-		editor.dialog = DIALOG_NONE;
+	buttonbar.VSplitRight(40.0f, &buttonbar, &button);
+	buttonbar.VSplitRight(50.0f, &buttonbar, &button);
+	if(DoButton_Editor(&cancel_button, "Cancel", 0, &button, 0, 0) || inp_key_pressed(KEY_ESCAPE))
+		dialog = DIALOG_NONE;
 }
 
 void EDITOR::invoke_file_dialog(int listdirtypes, const char *title, const char *button_text,
 	const char *basepath, const char *default_name,
-	void (*func)(const char *filename))
+	void (*func)(const char *filename, void *user), void *user)
 {
 	file_dialog_dirtypes = listdirtypes;
 	file_dialog_title = title;
 	file_dialog_button_text = button_text;
 	file_dialog_func = func;
+	file_dialog_user = user;
 	file_dialog_filename[0] = 0;
 	file_dialog_path[0] = 0;
 	
@@ -1968,78 +2129,78 @@ void EDITOR::invoke_file_dialog(int listdirtypes, const char *title, const char
 	if(basepath)
 		strncpy(file_dialog_path, basepath, sizeof(file_dialog_path));
 		
-	editor.dialog = DIALOG_FILE;
+	dialog = DIALOG_FILE;
 }
 
 
 
-static void render_modebar(RECT view)
+void EDITOR::render_modebar(CUIRect view)
 {
-	RECT button;
+	CUIRect button;
 
 	// mode buttons
 	{
-		ui_vsplit_l(&view, 40.0f, &button, &view);
+		view.VSplitLeft(40.0f, &button, &view);
 		static int tile_button = 0;
-		if(do_editor_button(&tile_button, "Layers", editor.mode == MODE_LAYERS, &button, draw_editor_button_m, 0, "Switch to edit layers."))
-			editor.mode = MODE_LAYERS;
+		if(DoButton_ButtonM(&tile_button, "Layers", mode == MODE_LAYERS, &button, 0, "Switch to edit layers."))
+			mode = MODE_LAYERS;
 
-		ui_vsplit_l(&view, 40.0f, &button, &view);
+		view.VSplitLeft(40.0f, &button, &view);
 		static int img_button = 0;
-		if(do_editor_button(&img_button, "Images", editor.mode == MODE_IMAGES, &button, draw_editor_button_r, 0, "Switch to manage images."))
-			editor.mode = MODE_IMAGES;
+		if(DoButton_ButtonR(&img_button, "Images", mode == MODE_IMAGES, &button, 0, "Switch to manage images."))
+			mode = MODE_IMAGES;
 	}
 
-	ui_vsplit_l(&view, 5.0f, 0, &view);
+	view.VSplitLeft(5.0f, 0, &view);
 	
 	// spacing
-	//ui_vsplit_l(&view, 10.0f, 0, &view);
+	//view.VSplitLeft(10.0f, 0, &view);
 }
 
-static void render_statusbar(RECT view)
+void EDITOR::render_statusbar(CUIRect view)
 {
-	RECT button;
-	ui_vsplit_r(&view, 60.0f, &view, &button);
+	CUIRect button;
+	view.VSplitRight(60.0f, &view, &button);
 	static int envelope_button = 0;
-	if(do_editor_button(&envelope_button, "Envelopes", editor.show_envelope_editor, &button, draw_editor_button, 0, "Toggles the envelope editor."))
-		editor.show_envelope_editor = (editor.show_envelope_editor+1)%4;
+	if(DoButton_Editor(&envelope_button, "Envelopes", show_envelope_editor, &button, 0, "Toggles the envelope editor."))
+		show_envelope_editor = (show_envelope_editor+1)%4;
 	
-	if(editor.tooltip)
+	if(tooltip)
 	{
-		if(ui_got_context && ui_got_context == ui_hot_item())
+		if(ui_got_context && ui_got_context == UI()->HotItem())
 		{
 			char buf[512];
-			sprintf(buf, "%s Right click for context menu.", editor.tooltip);
-			ui_do_label(&view, buf, 10.0f, -1, -1);
+			sprintf(buf, "%s Right click for context menu.", tooltip);
+			UI()->DoLabel(&view, buf, 10.0f, -1, -1);
 		}
 		else
-			ui_do_label(&view, editor.tooltip, 10.0f, -1, -1);
+			UI()->DoLabel(&view, tooltip, 10.0f, -1, -1);
 	}
 }
 
-static void render_envelopeeditor(RECT view)
+void EDITOR::render_envelopeeditor(CUIRect view)
 {
-	if(editor.selected_envelope < 0) editor.selected_envelope = 0;
-	if(editor.selected_envelope >= editor.map.envelopes.len()) editor.selected_envelope--;
+	if(selected_envelope < 0) selected_envelope = 0;
+	if(selected_envelope >= map.envelopes.len()) selected_envelope--;
 
 	ENVELOPE *envelope = 0;
-	if(editor.selected_envelope >= 0 && editor.selected_envelope < editor.map.envelopes.len())
-		envelope = editor.map.envelopes[editor.selected_envelope];
+	if(selected_envelope >= 0 && selected_envelope < map.envelopes.len())
+		envelope = map.envelopes[selected_envelope];
 
 	bool show_colorbar = false;
 	if(envelope && envelope->channels == 4)
 		show_colorbar = true;
 
-	RECT toolbar, curvebar, colorbar;
-	ui_hsplit_t(&view, 15.0f, &toolbar, &view);
-	ui_hsplit_t(&view, 15.0f, &curvebar, &view);
-	ui_margin(&toolbar, 2.0f, &toolbar);
-	ui_margin(&curvebar, 2.0f, &curvebar);
+	CUIRect toolbar, curvebar, colorbar;
+	view.HSplitTop(15.0f, &toolbar, &view);
+	view.HSplitTop(15.0f, &curvebar, &view);
+	toolbar.Margin(2.0f, &toolbar);
+	curvebar.Margin(2.0f, &curvebar);
 
 	if(show_colorbar)
 	{
-		ui_hsplit_t(&view, 20.0f, &colorbar, &view);
-		ui_margin(&colorbar, 2.0f, &colorbar);
+		view.HSplitTop(20.0f, &colorbar, &view);
+		colorbar.Margin(2.0f, &colorbar);
 		render_background(colorbar, checker_texture, 16.0f, 1.0f);
 	}
 
@@ -2047,19 +2208,19 @@ static void render_envelopeeditor(RECT view)
 
 	// do the toolbar
 	{
-		RECT button;
+		CUIRect button;
 		ENVELOPE *new_env = 0;
 		
-		ui_vsplit_r(&toolbar, 50.0f, &toolbar, &button);
+		toolbar.VSplitRight(50.0f, &toolbar, &button);
 		static int new_4d_button = 0;
-		if(do_editor_button(&new_4d_button, "Color+", 0, &button, draw_editor_button, 0, "Creates a new color envelope"))
-			new_env = editor.map.new_envelope(4);
+		if(DoButton_Editor(&new_4d_button, "Color+", 0, &button, 0, "Creates a new color envelope"))
+			new_env = map.new_envelope(4);
 
-		ui_vsplit_r(&toolbar, 5.0f, &toolbar, &button);
-		ui_vsplit_r(&toolbar, 50.0f, &toolbar, &button);
+		toolbar.VSplitRight(5.0f, &toolbar, &button);
+		toolbar.VSplitRight(50.0f, &toolbar, &button);
 		static int new_2d_button = 0;
-		if(do_editor_button(&new_2d_button, "Pos.+", 0, &button, draw_editor_button, 0, "Creates a new pos envelope"))
-			new_env = editor.map.new_envelope(3);
+		if(DoButton_Editor(&new_2d_button, "Pos.+", 0, &button, 0, "Creates a new pos envelope"))
+			new_env = map.new_envelope(3);
 		
 		if(new_env) // add the default points
 		{
@@ -2075,33 +2236,33 @@ static void render_envelopeeditor(RECT view)
 			}
 		}
 		
-		RECT shifter, inc, dec;
-		ui_vsplit_l(&toolbar, 60.0f, &shifter, &toolbar);
-		ui_vsplit_r(&shifter, 15.0f, &shifter, &inc);
-		ui_vsplit_l(&shifter, 15.0f, &dec, &shifter);
+		CUIRect shifter, inc, dec;
+		toolbar.VSplitLeft(60.0f, &shifter, &toolbar);
+		shifter.VSplitRight(15.0f, &shifter, &inc);
+		shifter.VSplitLeft(15.0f, &dec, &shifter);
 		char buf[512];
-		sprintf(buf, "%d/%d", editor.selected_envelope+1, editor.map.envelopes.len());
-		ui_draw_rect(&shifter, vec4(1,1,1,0.5f), 0, 0.0f);
-		ui_do_label(&shifter, buf, 10.0f, 0, -1);
+		sprintf(buf, "%d/%d", selected_envelope+1, map.envelopes.len());
+		RenderTools()->DrawUIRect(&shifter, vec4(1,1,1,0.5f), 0, 0.0f);
+		UI()->DoLabel(&shifter, buf, 10.0f, 0, -1);
 		
 		static int prev_button = 0;
-		if(do_editor_button(&prev_button, 0, 0, &dec, draw_dec_button, 0, "Previous Envelope"))
-			editor.selected_envelope--;
+		if(DoButton_ButtonDec(&prev_button, 0, 0, &dec, 0, "Previous Envelope"))
+			selected_envelope--;
 		
 		static int next_button = 0;
-		if(do_editor_button(&next_button, 0, 0, &inc, draw_inc_button, 0, "Next Envelope"))
-			editor.selected_envelope++;
+		if(DoButton_ButtonInc(&next_button, 0, 0, &inc, 0, "Next Envelope"))
+			selected_envelope++;
 			
 		if(envelope)
 		{
-			ui_vsplit_l(&toolbar, 15.0f, &button, &toolbar);
-			ui_vsplit_l(&toolbar, 35.0f, &button, &toolbar);
-			ui_do_label(&button, "Name:", 10.0f, -1, -1);
+			toolbar.VSplitLeft(15.0f, &button, &toolbar);
+			toolbar.VSplitLeft(35.0f, &button, &toolbar);
+			UI()->DoLabel(&button, "Name:", 10.0f, -1, -1);
 
-			ui_vsplit_l(&toolbar, 80.0f, &button, &toolbar);
+			toolbar.VSplitLeft(80.0f, &button, &toolbar);
 			
 			static int name_box = 0;
-			ui_do_edit_box(&name_box, &button, envelope->name, sizeof(envelope->name), 10.0f);
+			DoEditBox(&name_box, &button, envelope->name, sizeof(envelope->name), 10.0f);
 		}
 	}
 	
@@ -2113,9 +2274,9 @@ static void render_envelopeeditor(RECT view)
 		
 		if(envelope)
 		{
-			RECT button;	
+			CUIRect button;	
 			
-			ui_vsplit_l(&toolbar, 15.0f, &button, &toolbar);
+			toolbar.VSplitLeft(15.0f, &button, &toolbar);
 
 			static const char *names[4][4] = {
 				{"X", "", "", ""},
@@ -2126,17 +2287,17 @@ static void render_envelopeeditor(RECT view)
 			
 			static int channel_buttons[4] = {0};
 			int bit = 1;
-			ui_draw_button_func draw_func;
+			/*ui_draw_button_func draw_func;*/
 			
 			for(int i = 0; i < envelope->channels; i++, bit<<=1)
 			{
-				ui_vsplit_l(&toolbar, 15.0f, &button, &toolbar);
+				toolbar.VSplitLeft(15.0f, &button, &toolbar);
 				
-				if(i == 0) draw_func = draw_editor_button_l;
+				/*if(i == 0) draw_func = draw_editor_button_l;
 				else if(i == envelope->channels-1) draw_func = draw_editor_button_r;
-				else draw_func = draw_editor_button_m;
+				else draw_func = draw_editor_button_m;*/
 				
-				if(do_editor_button(&channel_buttons[i], names[envelope->channels-1][i], active_channels&bit, &button, draw_func, 0, 0))
+				if(DoButton_Editor(&channel_buttons[i], names[envelope->channels-1][i], active_channels&bit, &button, 0, 0))
 					active_channels ^= bit;
 			}
 		}		
@@ -2157,19 +2318,19 @@ static void render_envelopeeditor(RECT view)
 		float timescale = end_time/view.w;
 		float valuescale = (top-bottom)/view.h;
 		
-		if(ui_mouse_inside(&view))
-			ui_set_hot_item(&envelope_editor_id);
+		if(UI()->MouseInside(&view))
+			UI()->SetHotItem(&envelope_editor_id);
 			
-		if(ui_hot_item() == &envelope_editor_id)
+		if(UI()->HotItem() == &envelope_editor_id)
 		{
 			// do stuff
 			if(envelope)
 			{
-				if(ui_mouse_button_clicked(1))
+				if(UI()->MouseButtonClicked(1))
 				{
 					// add point
-					int time = (int)(((ui_mouse_x()-view.x)*timescale)*1000.0f);
-					//float env_y = (ui_mouse_y()-view.y)/timescale;
+					int time = (int)(((UI()->MouseX()-view.x)*timescale)*1000.0f);
+					//float env_y = (UI()->MouseY()-view.y)/timescale;
 					float channels[4];
 					envelope->eval(time, channels);
 					envelope->add_point(time,
@@ -2177,7 +2338,7 @@ static void render_envelopeeditor(RECT view)
 						f2fx(channels[2]), f2fx(channels[3]));
 				}
 				
-				editor.tooltip = "Press right mouse button to create a new point";
+				tooltip = "Press right mouse button to create a new point";
 			}
 		}
 
@@ -2185,22 +2346,22 @@ static void render_envelopeeditor(RECT view)
 
 		// render lines
 		{
-			ui_clip_enable(&view);
-			gfx_texture_set(-1);
-			gfx_lines_begin();
+			UI()->ClipEnable(&view);
+			Graphics()->TextureSet(-1);
+			Graphics()->LinesBegin();
 			for(int c = 0; c < envelope->channels; c++)
 			{
 				if(active_channels&(1<<c))
-					gfx_setcolor(colors[c].r,colors[c].g,colors[c].b,1);
+					Graphics()->SetColor(colors[c].r,colors[c].g,colors[c].b,1);
 				else
-					gfx_setcolor(colors[c].r*0.5f,colors[c].g*0.5f,colors[c].b*0.5f,1);
+					Graphics()->SetColor(colors[c].r*0.5f,colors[c].g*0.5f,colors[c].b*0.5f,1);
 				
 				float prev_x = 0;
 				float results[4];
 				envelope->eval(0.000001f, results);
 				float prev_value = results[c];
 				
-				int steps = (int)((view.w/ui_screen()->w) * gfx_screenwidth());
+				int steps = (int)((view.w/UI()->Screen()->w) * Graphics()->ScreenWidth());
 				for(int i = 1; i <= steps; i++)
 				{
 					float a = i/(float)steps;
@@ -2208,13 +2369,13 @@ static void render_envelopeeditor(RECT view)
 					float v = results[c];
 					v = (v-bottom)/(top-bottom);
 					
-					gfx_lines_draw(view.x + prev_x*view.w, view.y+view.h - prev_value*view.h, view.x + a*view.w, view.y+view.h - v*view.h);
+					Graphics()->LinesDraw(view.x + prev_x*view.w, view.y+view.h - prev_value*view.h, view.x + a*view.w, view.y+view.h - v*view.h);
 					prev_x = a;
 					prev_value = v;
 				}
 			}
-			gfx_lines_end();
-			ui_clip_disable();
+			Graphics()->LinesEnd();
+			UI()->ClipDisable();
 		}
 		
 		// render curve options
@@ -2226,7 +2387,7 @@ static void render_envelopeeditor(RECT view)
 
 				//dbg_msg("", "%f", end_time);
 				
-				RECT v;
+				CUIRect v;
 				v.x = curvebar.x + (t0+(t1-t0)*0.5f) * curvebar.w;
 				v.y = curvebar.y;
 				v.h = curvebar.h;
@@ -2237,7 +2398,7 @@ static void render_envelopeeditor(RECT view)
 					"N", "L", "S", "F", "M"
 					};
 				
-				if(do_editor_button(id, type_name[envelope->points[i].curvetype], 0, &v, draw_editor_button, 0, "Switch curve type"))
+				if(DoButton_Editor(id, type_name[envelope->points[i].curvetype], 0, &v, 0, "Switch curve type"))
 					envelope->points[i].curvetype = (envelope->points[i].curvetype+1)%NUM_CURVETYPES;
 			}
 		}
@@ -2245,8 +2406,8 @@ static void render_envelopeeditor(RECT view)
 		// render colorbar
 		if(show_colorbar)
 		{
-			gfx_texture_set(-1);
-			gfx_quads_begin();
+			Graphics()->TextureSet(-1);
+			Graphics()->QuadsBegin();
 			for(int i = 0; i < envelope->points.len()-1; i++)
 			{
 				float r0 = fx2f(envelope->points[i].values[0]);
@@ -2258,24 +2419,24 @@ static void render_envelopeeditor(RECT view)
 				float b1 = fx2f(envelope->points[i+1].values[2]);
 				float a1 = fx2f(envelope->points[i+1].values[3]);
 
-				gfx_setcolorvertex(0, r0, g0, b0, a0);
-				gfx_setcolorvertex(1, r1, g1, b1, a1);
-				gfx_setcolorvertex(2, r1, g1, b1, a1);
-				gfx_setcolorvertex(3, r0, g0, b0, a0);
+				Graphics()->SetColorVertex(0, r0, g0, b0, a0);
+				Graphics()->SetColorVertex(1, r1, g1, b1, a1);
+				Graphics()->SetColorVertex(2, r1, g1, b1, a1);
+				Graphics()->SetColorVertex(3, r0, g0, b0, a0);
 
 				float x0 = envelope->points[i].time/1000.0f/end_time;
 //				float y0 = (fx2f(envelope->points[i].values[c])-bottom)/(top-bottom);
 				float x1 = envelope->points[i+1].time/1000.0f/end_time;
 				//float y1 = (fx2f(envelope->points[i+1].values[c])-bottom)/(top-bottom);
-				RECT v;
+				CUIRect v;
 				v.x = colorbar.x + x0*colorbar.w;
 				v.y = colorbar.y;
 				v.w = (x1-x0)*colorbar.w;
 				v.h = colorbar.h;
 				
-				gfx_quads_drawTL(v.x, v.y, v.w, v.h);
+				Graphics()->QuadsDrawTL(v.x, v.y, v.w, v.h);
 			}
-			gfx_quads_end();
+			Graphics()->QuadsEnd();
 		}
 		
 		// render handles
@@ -2284,8 +2445,8 @@ static void render_envelopeeditor(RECT view)
 			
 			int current_value = 0, current_time = 0;
 			
-			gfx_texture_set(-1);
-			gfx_quads_begin();
+			Graphics()->TextureSet(-1);
+			Graphics()->QuadsBegin();
 			for(int c = 0; c < envelope->channels; c++)
 			{
 				if(!(active_channels&(1<<c)))
@@ -2295,7 +2456,7 @@ static void render_envelopeeditor(RECT view)
 				{
 					float x0 = envelope->points[i].time/1000.0f/end_time;
 					float y0 = (fx2f(envelope->points[i].values[c])-bottom)/(top-bottom);
-					RECT final;
+					CUIRect final;
 					final.x = view.x + x0*view.w;
 					final.y = view.y+view.h - y0*view.h;
 					final.x -= 2.0f;
@@ -2305,26 +2466,26 @@ static void render_envelopeeditor(RECT view)
 					
 					void *id = &envelope->points[i].values[c];
 					
-					if(ui_mouse_inside(&final))
-						ui_set_hot_item(id);
+					if(UI()->MouseInside(&final))
+						UI()->SetHotItem(id);
 						
 					float colormod = 1.0f;
 
-					if(ui_active_item() == id)
+					if(UI()->ActiveItem() == id)
 					{
-						if(!ui_mouse_button(0))
+						if(!UI()->MouseButton(0))
 						{
-							ui_set_active_item(0);
+							UI()->SetActiveItem(0);
 							move = false;
 						}
 						else
 						{
-							envelope->points[i].values[c] -= f2fx(editor.mouse_delta_y*valuescale);
+							envelope->points[i].values[c] -= f2fx(mouse_delta_y*valuescale);
 							if(inp_key_pressed(KEY_LSHIFT) || inp_key_pressed(KEY_RSHIFT))
 							{
 								if(i != 0)
 								{
-									envelope->points[i].time += (int)((editor.mouse_delta_x*timescale)*1000.0f);
+									envelope->points[i].time += (int)((mouse_delta_x*timescale)*1000.0f);
 									if(envelope->points[i].time < envelope->points[i-1].time)
 										envelope->points[i].time = envelope->points[i-1].time + 1;
 									if(i+1 != envelope->points.len() && envelope->points[i].time > envelope->points[i+1].time)
@@ -2334,46 +2495,46 @@ static void render_envelopeeditor(RECT view)
 						}
 						
 						colormod = 100.0f;
-						gfx_setcolor(1,1,1,1);
+						Graphics()->SetColor(1,1,1,1);
 					}
-					else if(ui_hot_item() == id)
+					else if(UI()->HotItem() == id)
 					{
-						if(ui_mouse_button(0))
+						if(UI()->MouseButton(0))
 						{
 							selection.clear();
 							selection.add(i);
-							ui_set_active_item(id);
+							UI()->SetActiveItem(id);
 						}
 
 						// remove point
-						if(ui_mouse_button_clicked(1))
+						if(UI()->MouseButtonClicked(1))
 							envelope->points.removebyindex(i);
 							
 						colormod = 100.0f;
-						gfx_setcolor(1,0.75f,0.75f,1);
-						editor.tooltip = "Left mouse to drag. Hold shift to alter time point aswell. Right click to delete.";
+						Graphics()->SetColor(1,0.75f,0.75f,1);
+						tooltip = "Left mouse to drag. Hold shift to alter time point aswell. Right click to delete.";
 					}
 
-					if(ui_active_item() == id || ui_hot_item() == id)
+					if(UI()->ActiveItem() == id || UI()->HotItem() == id)
 					{
 						current_time = envelope->points[i].time;
 						current_value = envelope->points[i].values[c];
 					}
 					
-					gfx_setcolor(colors[c].r*colormod, colors[c].g*colormod, colors[c].b*colormod, 1.0f);
-					gfx_quads_drawTL(final.x, final.y, final.w, final.h);
+					Graphics()->SetColor(colors[c].r*colormod, colors[c].g*colormod, colors[c].b*colormod, 1.0f);
+					Graphics()->QuadsDrawTL(final.x, final.y, final.w, final.h);
 				}
 			}
-			gfx_quads_end();
+			Graphics()->QuadsEnd();
 
 			char buf[512];
 			sprintf(buf, "%.3f %.3f", current_time/1000.0f, fx2f(current_value));
-			ui_do_label(&toolbar, buf, 10.0f, 0, -1);
+			UI()->DoLabel(&toolbar, buf, 10.0f, 0, -1);
 		}
 	}
 }
 
-static int popup_menu_file(RECT view)
+int EDITOR::popup_menu_file(EDITOR *pEditor, CUIRect view)
 {
 	static int new_map_button = 0;
 	static int save_button = 0;
@@ -2382,49 +2543,49 @@ static int popup_menu_file(RECT view)
 	static int append_button = 0;
 	static int exit_button = 0;
 
-	RECT slot;
-	ui_hsplit_t(&view, 2.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&new_map_button, "New", 0, &slot, draw_editor_button_menuitem, 0, "Creates a new map"))
+	CUIRect slot;
+	view.HSplitTop(2.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&new_map_button, "New", 0, &slot, 0, "Creates a new map"))
 	{
-		editor.reset();
+		pEditor->reset();
 		return 1;
 	}
 
-	ui_hsplit_t(&view, 10.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&open_button, "Open", 0, &slot, draw_editor_button_menuitem, 0, "Opens a map for editing"))
+	view.HSplitTop(10.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&open_button, "Open", 0, &slot, 0, "Opens a map for editing"))
 	{
-		editor.invoke_file_dialog(LISTDIRTYPE_ALL, "Open Map", "Open", "maps/", "", callback_open_map);
+		pEditor->invoke_file_dialog(LISTDIRTYPE_ALL, "Open Map", "Open", "maps/", "", callback_open_map, pEditor);
 		return 1;
 	}
 
-	ui_hsplit_t(&view, 10.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&append_button, "Append", 0, &slot, draw_editor_button_menuitem, 0, "Opens a map and adds everything from that map to the current one"))
+	view.HSplitTop(10.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&append_button, "Append", 0, &slot, 0, "Opens a map and adds everything from that map to the current one"))
 	{
-		editor.invoke_file_dialog(LISTDIRTYPE_ALL, "Append Map", "Append", "maps/", "", callback_append_map);
+		pEditor->invoke_file_dialog(LISTDIRTYPE_ALL, "Append Map", "Append", "maps/", "", callback_append_map, pEditor);
 		return 1;
 	}
 
-	ui_hsplit_t(&view, 10.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&save_button, "Save (NOT IMPL)", 0, &slot, draw_editor_button_menuitem, 0, "Saves the current map"))
+	view.HSplitTop(10.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&save_button, "Save (NOT IMPL)", 0, &slot, 0, "Saves the current map"))
 	{
 		return 1;
 	}
 
-	ui_hsplit_t(&view, 2.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&save_as_button, "Save As", 0, &slot, draw_editor_button_menuitem, 0, "Saves the current map under a new name"))
+	view.HSplitTop(2.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&save_as_button, "Save As", 0, &slot, 0, "Saves the current map under a new name"))
 	{
-		editor.invoke_file_dialog(LISTDIRTYPE_SAVE, "Save Map", "Save", "maps/", "", callback_save_map);
+		pEditor->invoke_file_dialog(LISTDIRTYPE_SAVE, "Save Map", "Save", "maps/", "", callback_save_map, pEditor);
 		return 1;
 	}
 	
-	ui_hsplit_t(&view, 10.0f, &slot, &view);
-	ui_hsplit_t(&view, 12.0f, &slot, &view);
-	if(do_editor_button(&exit_button, "Exit", 0, &slot, draw_editor_button_menuitem, 0, "Exits from the editor"))
+	view.HSplitTop(10.0f, &slot, &view);
+	view.HSplitTop(12.0f, &slot, &view);
+	if(pEditor->DoButton_MenuItem(&exit_button, "Exit", 0, &slot, 0, "Exits from the editor"))
 	{
 		config.cl_editor = 0;
 		return 1;
@@ -2433,22 +2594,22 @@ static int popup_menu_file(RECT view)
 	return 0;
 }
 
-static void render_menubar(RECT menubar)
+void EDITOR::render_menubar(CUIRect menubar)
 {
-	static RECT file /*, view, help*/;
+	static CUIRect file /*, view, help*/;
 
-	ui_vsplit_l(&menubar, 60.0f, &file, &menubar);
-	if(do_editor_button(&file, "File", 0, &file, draw_editor_button_menu, 0, 0))
-		ui_invoke_popup_menu(&file, 1, file.x, file.y+file.h-1.0f, 120, 150, popup_menu_file);
+	menubar.VSplitLeft(60.0f, &file, &menubar);
+	if(DoButton_Menu(&file, "File", 0, &file, 0, 0))
+		ui_invoke_popup_menu(&file, 1, file.x, file.y+file.h-1.0f, 120, 150, popup_menu_file, this);
 	
 	/*
-	ui_vsplit_l(&menubar, 5.0f, 0, &menubar);
-	ui_vsplit_l(&menubar, 60.0f, &view, &menubar);
+	menubar.VSplitLeft(5.0f, 0, &menubar);
+	menubar.VSplitLeft(60.0f, &view, &menubar);
 	if(do_editor_button(&view, "View", 0, &view, draw_editor_button_menu, 0, 0))
 		(void)0;
 
-	ui_vsplit_l(&menubar, 5.0f, 0, &menubar);
-	ui_vsplit_l(&menubar, 60.0f, &help, &menubar);
+	menubar.VSplitLeft(5.0f, 0, &menubar);
+	menubar.VSplitLeft(60.0f, &help, &menubar);
 	if(do_editor_button(&help, "Help", 0, &help, draw_editor_button_menu, 0, 0))
 		(void)0;
 		*/
@@ -2457,102 +2618,102 @@ static void render_menubar(RECT menubar)
 void EDITOR::render()
 {
 	// basic start
-	gfx_clear(1.0f,0.0f,1.0f);
-	RECT view = *ui_screen();
-	gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
+	Graphics()->Clear(1.0f,0.0f,1.0f);
+	CUIRect view = *UI()->Screen();
+	Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
 	
 	// reset tip
-	editor.tooltip = 0;
+	tooltip = 0;
 	
 	// render checker
 	render_background(view, checker_texture, 32.0f, 1.0f);
 	
-	RECT menubar, modebar, toolbar, statusbar, envelope_editor, toolbox;
+	CUIRect menubar, modebar, toolbar, statusbar, envelope_editor, toolbox;
 	
-	if(editor.gui_active)
+	if(gui_active)
 	{
 		
-		ui_hsplit_t(&view, 16.0f, &menubar, &view);
-		ui_vsplit_l(&view, 80.0f, &toolbox, &view);
-		ui_hsplit_t(&view, 16.0f, &toolbar, &view);
-		ui_hsplit_b(&view, 16.0f, &view, &statusbar);
+		view.HSplitTop(16.0f, &menubar, &view);
+		view.VSplitLeft(80.0f, &toolbox, &view);
+		view.HSplitTop(16.0f, &toolbar, &view);
+		view.HSplitBottom(16.0f, &view, &statusbar);
 
-		if(editor.show_envelope_editor)
+		if(show_envelope_editor)
 		{
 			float size = 125.0f;
-			if(editor.show_envelope_editor == 2)
+			if(show_envelope_editor == 2)
 				size *= 2.0f;
-			else if(editor.show_envelope_editor == 3)
+			else if(show_envelope_editor == 3)
 				size *= 3.0f;
-			ui_hsplit_b(&view, size, &view, &envelope_editor);
+			view.HSplitBottom(size, &view, &envelope_editor);
 		}
 	}
 	
 	//	a little hack for now
-	if(editor.mode == MODE_LAYERS)
+	if(mode == MODE_LAYERS)
 		do_map_editor(view, toolbar);
 	
-	if(editor.gui_active)
+	if(gui_active)
 	{
 		float brightness = 0.25f;
 		render_background(menubar, background_texture, 128.0f, brightness*0);
-		ui_margin(&menubar, 2.0f, &menubar);
+		menubar.Margin(2.0f, &menubar);
 
 		render_background(toolbox, background_texture, 128.0f, brightness);
-		ui_margin(&toolbox, 2.0f, &toolbox);
+		toolbox.Margin(2.0f, &toolbox);
 		
 		render_background(toolbar, background_texture, 128.0f, brightness);
-		ui_margin(&toolbar, 2.0f, &toolbar);
-		ui_vsplit_l(&toolbar, 150.0f, &modebar, &toolbar);
+		toolbar.Margin(2.0f, &toolbar);
+		toolbar.VSplitLeft(150.0f, &modebar, &toolbar);
 
 		render_background(statusbar, background_texture, 128.0f, brightness);
-		ui_margin(&statusbar, 2.0f, &statusbar);
+		statusbar.Margin(2.0f, &statusbar);
 		
 		// do the toolbar
-		if(editor.mode == MODE_LAYERS)
+		if(mode == MODE_LAYERS)
 			do_toolbar(toolbar);
 		
-		if(editor.show_envelope_editor)
+		if(show_envelope_editor)
 		{
 			render_background(envelope_editor, background_texture, 128.0f, brightness);
-			ui_margin(&envelope_editor, 2.0f, &envelope_editor);
+			envelope_editor.Margin(2.0f, &envelope_editor);
 		}
 	}
 		
 	
-	if(editor.mode == MODE_LAYERS)
+	if(mode == MODE_LAYERS)
 		render_layers(toolbox, toolbar, view);
-	else if(editor.mode == MODE_IMAGES)
+	else if(mode == MODE_IMAGES)
 		render_images(toolbox, toolbar, view);
 
-	gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
+	Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
 
-	if(editor.gui_active)
+	if(gui_active)
 	{
 		render_menubar(menubar);
 		
 		render_modebar(modebar);
-		if(editor.show_envelope_editor)
+		if(show_envelope_editor)
 			render_envelopeeditor(envelope_editor);
 	}
 
-	if(editor.dialog == DIALOG_FILE)
+	if(dialog == DIALOG_FILE)
 	{
 		static int null_ui_target = 0;
-		ui_set_hot_item(&null_ui_target);
+		UI()->SetHotItem(&null_ui_target);
 		render_file_dialog();
 	}
 	
 	
 	ui_do_popup_menu();
 
-	if(editor.gui_active)
+	if(gui_active)
 		render_statusbar(statusbar);
 
 	//
 	if(config.ed_showkeys)
 	{
-		gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
+		Graphics()->MapScreen(UI()->Screen()->x, UI()->Screen()->y, UI()->Screen()->w, UI()->Screen()->h);
 		TEXT_CURSOR cursor;
 		gfx_text_set_cursor(&cursor, view.x+10, view.y+view.h-24-10, 24.0f, TEXTFLAG_RENDER);
 		
@@ -2569,28 +2730,28 @@ void EDITOR::render()
 		}
 	}
 	
-	if (editor.show_mouse_pointer)
+	if(show_mouse_pointer)
 	{
 		// render butt ugly mouse cursor
-		float mx = ui_mouse_x();
-		float my = ui_mouse_y();
-		gfx_texture_set(cursor_texture);
-		gfx_quads_begin();
-		if(ui_got_context == ui_hot_item())
-			gfx_setcolor(1,0,0,1);
-		gfx_quads_drawTL(mx,my, 16.0f, 16.0f);
-		gfx_quads_end();
+		float mx = UI()->MouseX();
+		float my = UI()->MouseY();
+		Graphics()->TextureSet(cursor_texture);
+		Graphics()->QuadsBegin();
+		if(ui_got_context == UI()->HotItem())
+			Graphics()->SetColor(1,0,0,1);
+		Graphics()->QuadsDrawTL(mx,my, 16.0f, 16.0f);
+		Graphics()->QuadsEnd();
 	}
 	
 }
 
 void EDITOR::reset(bool create_default)
 {
-	editor.map.clean();
+	map.clean();
 
 	// create default layers
 	if(create_default)
-		editor.map.create_default(entities_texture);
+		map.create_default(entities_texture);
 	
 	/*
 	{
@@ -2636,28 +2797,30 @@ void MAP::create_default(int entities_texture)
 	game_group->add_layer(game_layer);
 }
 
-extern "C" void editor_init()
+void EDITOR::Init(class IGraphics *pGraphics)
 {
-	checker_texture = gfx_load_texture("editor/checker.png", IMG_AUTO, 0);
-	background_texture = gfx_load_texture("editor/background.png", IMG_AUTO, 0);
-	cursor_texture = gfx_load_texture("editor/cursor.png", IMG_AUTO, 0);
-	entities_texture = gfx_load_texture("editor/entities.png", IMG_AUTO, 0);
+	m_pGraphics = pGraphics;
+	
+	checker_texture = Graphics()->LoadTexture("editor/checker.png", IMG_AUTO, 0);
+	background_texture = Graphics()->LoadTexture("editor/background.png", IMG_AUTO, 0);
+	cursor_texture = Graphics()->LoadTexture("editor/cursor.png", IMG_AUTO, 0);
+	entities_texture = Graphics()->LoadTexture("editor/entities.png", IMG_AUTO, 0);
 	
 	tileset_picker.make_palette();
 	tileset_picker.readonly = true;
 	
-	editor.reset();
+	reset();
 }
 
-extern "C" void editor_update_and_render()
+void EDITOR::UpdateAndRender()
 {
 	static int mouse_x = 0;
 	static int mouse_y = 0;
 	
-	if(editor.animate)
-		editor.animate_time = (time_get()-editor.animate_start)/(float)time_freq();
+	if(animate)
+		animate_time = (time_get()-animate_start)/(float)time_freq();
 	else
-		editor.animate_time = 0;
+		animate_time = 0;
 	ui_got_context = 0;
 
 	// handle mouse movement
@@ -2665,10 +2828,10 @@ extern "C" void editor_update_and_render()
 	int rx, ry;
 	{
 		inp_mouse_relative(&rx, &ry);
-		editor.mouse_delta_x = rx;
-		editor.mouse_delta_y = ry;
+		mouse_delta_x = rx;
+		mouse_delta_y = ry;
 		
-		if(!editor.lock_mouse)
+		if(!lock_mouse)
 		{
 			mouse_x += rx;
 			mouse_y += ry;
@@ -2676,8 +2839,8 @@ extern "C" void editor_update_and_render()
 		
 		if(mouse_x < 0) mouse_x = 0;
 		if(mouse_y < 0) mouse_y = 0;
-		if(mouse_x > ui_screen()->w) mouse_x = (int)ui_screen()->w;
-		if(mouse_y > ui_screen()->h) mouse_y = (int)ui_screen()->h;
+		if(mouse_x > UI()->Screen()->w) mouse_x = (int)UI()->Screen()->w;
+		if(mouse_y > UI()->Screen()->h) mouse_y = (int)UI()->Screen()->h;
 
 		// update the ui
 		mx = mouse_x;
@@ -2686,7 +2849,7 @@ extern "C" void editor_update_and_render()
 		mwy = 0;
 		
 		// fix correct world x and y
-		LAYERGROUP *g = editor.get_selected_group();
+		LAYERGROUP *g = get_selected_group();
 		if(g)
 		{
 			float points[4];
@@ -2695,10 +2858,10 @@ extern "C" void editor_update_and_render()
 			float world_width = points[2]-points[0];
 			float world_height = points[3]-points[1];
 			
-			mwx = points[0] + world_width * (mouse_x/ui_screen()->w);
-			mwy = points[1] + world_height * (mouse_y/ui_screen()->h);
-			editor.mouse_delta_wx = editor.mouse_delta_x*(world_width / ui_screen()->w);
-			editor.mouse_delta_wy = editor.mouse_delta_y*(world_height / ui_screen()->h);
+			mwx = points[0] + world_width * (mouse_x/UI()->Screen()->w);
+			mwy = points[1] + world_height * (mouse_y/UI()->Screen()->h);
+			mouse_delta_wx = mouse_delta_x*(world_width / UI()->Screen()->w);
+			mouse_delta_wy = mouse_delta_y*(world_height / UI()->Screen()->h);
 		}
 		
 		int buttons = 0;
@@ -2706,33 +2869,34 @@ extern "C" void editor_update_and_render()
 		if(inp_key_pressed(KEY_MOUSE_2)) buttons |= 2;
 		if(inp_key_pressed(KEY_MOUSE_3)) buttons |= 4;
 		
-		ui_update(mx,my,mwx,mwy,buttons);
+		UI()->Update(mx,my,mwx,mwy,buttons);
 	}
 	
 	// toggle gui
 	if(inp_key_down(KEY_TAB))
-		editor.gui_active = !editor.gui_active;
+		gui_active = !gui_active;
 
 	if(inp_key_down(KEY_F5))
-		editor.save("maps/debug_test2.map");
+		save("maps/debug_test2.map");
 
 	if(inp_key_down(KEY_F6))
-		editor.load("maps/debug_test2.map");
+		load("maps/debug_test2.map");
 	
 	if(inp_key_down(KEY_F8))
-		editor.load("maps/debug_test.map");
+		load("maps/debug_test.map");
 	
 	if(inp_key_down(KEY_F10))
-		editor.show_mouse_pointer = false;
+		show_mouse_pointer = false;
 	
-	editor.render();
+	render();
 	
 	if(inp_key_down(KEY_F10))
 	{
-		gfx_screenshot();
-		editor.show_mouse_pointer = true;
+		Graphics()->TakeScreenshot();
+		show_mouse_pointer = true;
 	}
 	
 	inp_clear_events();
 }
 
+IEditor *CreateEditor() { return new EDITOR; }
diff --git a/src/game/editor/ed_editor.hpp b/src/game/editor/ed_editor.hpp
index 313a381f..98d1d960 100644
--- a/src/game/editor/ed_editor.hpp
+++ b/src/game/editor/ed_editor.hpp
@@ -9,16 +9,17 @@
 #include "../mapitems.hpp"
 #include "../client/render.hpp"
 
-extern "C" {
-	#include <engine/e_client_interface.h>
-	#include <engine/e_datafile.h>
-	#include <engine/e_config.h>
-}
+#include <engine/e_client_interface.h>
+#include <engine/e_datafile.h>
+#include <engine/e_config.h>
+#include <engine/client/editor.h>
 
 #include <game/client/ui.hpp>
 
 typedef void (*INDEX_MODIFY_FUNC)(int *index);
 
+//CRenderTools m_RenderTools;
+
 // EDITOR SPECIFIC
 template<typename T>
 void swap(T &a, T &b)
@@ -96,7 +97,7 @@ public:
 	
 	int eval(float time, float *result)
 	{
-		render_eval_envelope(points.getptr(), points.len(), channels, time, result);
+		CRenderTools::render_eval_envelope(points.getptr(), points.len(), channels, time, result);
 		return channels;
 	}
 	
@@ -129,6 +130,9 @@ class MAP;
 class LAYER
 {
 public:
+	class EDITOR *editor;
+	class IGraphics *Graphics();
+
 	LAYER()
 	{
 		type = LAYERTYPE_INVALID;
@@ -136,6 +140,7 @@ public:
 		visible = true;
 		readonly = false;
 		flags = 0;
+		editor = 0;
 	}
 	
 	virtual ~LAYER()
@@ -143,8 +148,8 @@ public:
 	}
 	
 	
-	virtual void brush_selecting(RECT rect) {}
-	virtual int brush_grab(LAYERGROUP *brush, RECT rect) { return 0; }
+	virtual void brush_selecting(CUIRect rect) {}
+	virtual int brush_grab(LAYERGROUP *brush, CUIRect rect) { return 0; }
 	virtual void brush_draw(LAYER *brush, float x, float y) {}
 	virtual void brush_place(LAYER *brush, float x, float y) {}
 	virtual void brush_flip_x() {}
@@ -152,7 +157,7 @@ public:
 	virtual void brush_rotate(float amount) {}
 	
 	virtual void render() {}
-	virtual int render_properties(RECT *toolbox) { return 0; }
+	virtual int render_properties(CUIRect *toolbox) { return 0; }
 	
 	virtual void modify_image_index(INDEX_MODIFY_FUNC func) {}
 	virtual void modify_envelope_index(INDEX_MODIFY_FUNC func) {}
@@ -170,6 +175,8 @@ public:
 class LAYERGROUP
 {
 public:
+	class MAP *m_pMap;
+	
 	array<LAYER*> layers;
 	
 	int offset_x;
@@ -191,7 +198,7 @@ public:
 	LAYERGROUP();
 	~LAYERGROUP();
 	
-	void convert(RECT *rect);
+	void convert(CUIRect *rect);
 	void render();
 	void mapscreen();
 	void mapping(float *points);
@@ -221,8 +228,11 @@ public:
 class EDITOR_IMAGE : public IMAGE_INFO
 {
 public:
-	EDITOR_IMAGE()
+	EDITOR *editor;
+	
+	EDITOR_IMAGE(EDITOR *ed)
 	{
+		editor = editor;
 		tex_id = -1;
 		name[0] = 0;
 		external = 0;
@@ -232,10 +242,7 @@ public:
 		format = 0;
 	}
 	
-	~EDITOR_IMAGE()
-	{
-		gfx_unload_texture(tex_id);
-	}
+	~EDITOR_IMAGE();
 	
 	void analyse_tileflags();
 	
@@ -250,6 +257,8 @@ class MAP
 	void make_game_group(LAYERGROUP *group);
 	void make_game_layer(LAYER *layer);
 public:
+	EDITOR *editor;
+
 	MAP()
 	{
 		clean();
@@ -272,6 +281,7 @@ public:
 	LAYERGROUP *new_group()
 	{
 		LAYERGROUP *g = new LAYERGROUP;
+		g->m_pMap = this;
 		groups.add(g);
 		return g;
 	}
@@ -333,9 +343,17 @@ enum
 	PROPTYPE_ENVELOPE,
 };
 
-class EDITOR
+class EDITOR : public IEditor
 {
-public:	
+	class IGraphics *m_pGraphics;
+	CRenderTools m_RenderTools;
+	CUI m_UI;
+public:
+	
+	class IGraphics *Graphics() { return m_pGraphics; };
+	CUI *UI() { return &m_UI; }
+	CRenderTools *RenderTools() { return &m_RenderTools; }
+
 	EDITOR()
 	{
 		mode = MODE_LAYERS;
@@ -368,9 +386,12 @@ public:
 		show_envelope_editor = 0;
 	}
 	
+	virtual void Init(class IGraphics *pGraphics);
+	virtual void UpdateAndRender();
+	
 	void invoke_file_dialog(int listdir_type, const char *title, const char *button_text,
 		const char *basepath, const char *default_name,
-		void (*func)(const char *filename));
+		void (*func)(const char *filename, void *user), void *user);
 	
 	void reset(bool create_default=true);
 	int save(const char *filename);
@@ -383,7 +404,7 @@ public:
 	LAYER *get_selected_layer(int index);
 	LAYERGROUP *get_selected_group();
 	
-	int do_properties(RECT *toolbox, PROPERTY *props, int *ids, int *new_val);
+	int do_properties(CUIRect *toolbox, PROPERTY *props, int *ids, int *new_val);
 	
 	int mode;
 	int dialog;
@@ -420,9 +441,70 @@ public:
 	int selected_image;
 	
 	MAP map;
+	
+	int DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+
+	int DoButton_ButtonL(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	int DoButton_ButtonM(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	int DoButton_ButtonR(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	int DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	int DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+
+	int DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	
+	int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
+	int DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags=0, const char *pToolTip=0);
+	
+	int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden=false);
+	//static void draw_editor_button(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+	//static void draw_editor_button_menuitem(const void *id, const char *text, int checked, const CUIRect *r, const void *extra);
+
+	void render_background(CUIRect view, int texture, float size, float brightness);
+
+	void ui_invoke_popup_menu(void *id, int flags, float x, float y, float w, float h, int (*func)(EDITOR *pEditor, CUIRect rect), void *extra=0);
+	void ui_do_popup_menu();
+	
+	int ui_do_value_selector(void *id, CUIRect *r, const char *label, int current, int min, int max, float scale);
+
+	static int popup_group(EDITOR *pEditor, CUIRect view);
+	static int popup_layer(EDITOR *pEditor, CUIRect view);
+	static int popup_quad(EDITOR *pEditor, CUIRect view);
+	static int popup_point(EDITOR *pEditor, CUIRect view);
+	static int popup_select_image(EDITOR *pEditor, CUIRect view);
+	static int popup_image(EDITOR *pEditor, CUIRect view);
+	static int popup_menu_file(EDITOR *pEditor, CUIRect view);
+
+
+	void popup_select_image_invoke(int current, float x, float y);
+	int popup_select_image_result();
+	
+	vec4 button_color_mul(const void *id);
+
+	void do_quad_point(QUAD *q, int quad_index, int v);
+	void do_map_editor(CUIRect view, CUIRect toolbar);
+	void do_toolbar(CUIRect toolbar);
+	void do_quad(QUAD *q, int index);
+	float ui_do_scrollbar_v(const void *id, const CUIRect *rect, float current);
+	vec4 get_button_color(const void *id, int checked);
+	
+	static void replace_image(const char *filename, void *user);
+	static void add_image(const char *filename, void *user);
+	
+	void render_images(CUIRect toolbox, CUIRect toolbar, CUIRect view);
+	void render_layers(CUIRect toolbox, CUIRect toolbar, CUIRect view);
+	void render_modebar(CUIRect view);
+	void render_statusbar(CUIRect view);
+	void render_envelopeeditor(CUIRect view);
+	
+	void render_menubar(CUIRect menubar);
+	void render_file_dialog();
 };
 
-extern EDITOR editor;
+// make sure to inline this function
+inline class IGraphics *LAYER::Graphics() { return editor->Graphics(); }
+
+//extern EDITOR editor;
 
 typedef struct
 {
@@ -443,17 +525,17 @@ public:
 
 	int convert_x(float x) const;
 	int convert_y(float y) const;
-	void convert(RECT rect, RECTi *out);
-	void snap(RECT *rect);
+	void convert(CUIRect rect, RECTi *out);
+	void snap(CUIRect *rect);
 	void clamp(RECTi *rect);
 
-	virtual void brush_selecting(RECT rect);
-	virtual int brush_grab(LAYERGROUP *brush, RECT rect);
+	virtual void brush_selecting(CUIRect rect);
+	virtual int brush_grab(LAYERGROUP *brush, CUIRect rect);
 	virtual void brush_draw(LAYER *brush, float wx, float wy);
 	virtual void brush_flip_x();
 	virtual void brush_flip_y();
 	
-	virtual int render_properties(RECT *toolbox);
+	virtual int render_properties(CUIRect *toolbox);
 
 	virtual void modify_image_index(INDEX_MODIFY_FUNC func);
 	virtual void modify_envelope_index(INDEX_MODIFY_FUNC func);
@@ -479,14 +561,14 @@ public:
 	virtual void render();
 	QUAD *new_quad();
 
-	virtual void brush_selecting(RECT rect);
-	virtual int brush_grab(LAYERGROUP *brush, RECT rect);
+	virtual void brush_selecting(CUIRect rect);
+	virtual int brush_grab(LAYERGROUP *brush, CUIRect rect);
 	virtual void brush_place(LAYER *brush, float wx, float wy);
 	virtual void brush_flip_x();
 	virtual void brush_flip_y();
 	virtual void brush_rotate(float amount);
 	
-	virtual int render_properties(RECT *toolbox);
+	virtual int render_properties(CUIRect *toolbox);
 
 	virtual void modify_image_index(INDEX_MODIFY_FUNC func);
 	virtual void modify_envelope_index(INDEX_MODIFY_FUNC func);
@@ -503,20 +585,5 @@ public:
 	LAYER_GAME(int w, int h);
 	~LAYER_GAME();
 
-	virtual int render_properties(RECT *toolbox);
+	virtual int render_properties(CUIRect *toolbox);
 };
-
-int do_editor_button(const void *id, const char *text, int checked, const RECT *r, ui_draw_button_func draw_func, int flags, const char *tooltip);
-void draw_editor_button(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-void draw_editor_button_menuitem(const void *id, const char *text, int checked, const RECT *r, const void *extra);
-
-void ui_invoke_popup_menu(void *id, int flags, float x, float y, float w, float h, int (*func)(RECT rect), void *extra=0);
-void ui_do_popup_menu();
-
-int popup_group(RECT view);
-int popup_layer(RECT view);
-int popup_quad(RECT view);
-int popup_point(RECT view);
-
-void popup_select_image_invoke(int current, float x, float y);
-int popup_select_image_result();
diff --git a/src/game/editor/ed_io.cpp b/src/game/editor/ed_io.cpp
index dfaa0e2c..b8c025fb 100644
--- a/src/game/editor/ed_io.cpp
+++ b/src/game/editor/ed_io.cpp
@@ -1,5 +1,6 @@
 #include <string.h>
 #include <stdio.h>
+#include <engine/client/graphics.h>
 #include "ed_editor.hpp"
 
 template<typename T>
@@ -7,6 +8,7 @@ static int make_version(int i, const T &v)
 { return (i<<16)+sizeof(T); }
 
 // backwards compatiblity
+/*
 void editor_load_old(DATAFILE *df, MAP *map)
 {
 	class mapres_image
@@ -98,7 +100,7 @@ void editor_load_old(DATAFILE *df, MAP *map)
 				// move game layer to correct position
 				for(int i = 0; i < map->groups[0]->layers.len()-1; i++)
 				{
-					if(map->groups[0]->layers[i] == editor.map.game_layer)
+					if(map->groups[0]->layers[i] == pEditor->map.game_layer)
 						map->groups[0]->swap_layers(i, i+1);
 				}
 				
@@ -141,7 +143,7 @@ void editor_load_old(DATAFILE *df, MAP *map)
 			// copy image data
 			img->data = mem_alloc(img->width*img->height*4, 1);
 			mem_copy(img->data, data, img->width*img->height*4);
-			img->tex_id = gfx_load_texture_raw(img->width, img->height, img->format, img->data, IMG_AUTO, 0);
+			img->tex_id = Graphics()->LoadTextureRaw(img->width, img->height, img->format, img->data, IMG_AUTO, 0);
 			map->images.add(img);
 			
 			// unload image
@@ -186,7 +188,7 @@ void editor_load_old(DATAFILE *df, MAP *map)
 			}
 		}
 	}
-}
+}*/
 
 int EDITOR::save(const char *filename)
 {
@@ -374,9 +376,10 @@ int MAP::load(const char *filename)
 	if(!item)
 	{
 		// import old map
-		MAP old_mapstuff;
-		editor.reset();
+		/*MAP old_mapstuff;
+		editor->reset();
 		editor_load_old(df, this);
+		*/
 	}
 	else if(item->version == 1)
 	{
@@ -392,7 +395,7 @@ int MAP::load(const char *filename)
 				char *name = (char *)datafile_get_data(df, item->image_name);
 
 				// copy base info				
-				EDITOR_IMAGE *img = new EDITOR_IMAGE;
+				EDITOR_IMAGE *img = new EDITOR_IMAGE(editor);
 				img->external = item->external;
 
 				if(item->external)
@@ -401,11 +404,11 @@ int MAP::load(const char *filename)
 					sprintf(buf, "mapres/%s.png", name);
 					
 					// load external
-					EDITOR_IMAGE imginfo;
-					if(gfx_load_png(&imginfo, buf))
+					EDITOR_IMAGE imginfo(editor);
+					if(editor->Graphics()->LoadPNG(&imginfo, buf))
 					{
 						*img = imginfo;
-						img->tex_id = gfx_load_texture_raw(imginfo.width, imginfo.height, imginfo.format, imginfo.data, IMG_AUTO, 0);
+						img->tex_id = editor->Graphics()->LoadTextureRaw(imginfo.width, imginfo.height, imginfo.format, imginfo.data, IMG_AUTO, 0);
 						img->external = 1;
 					}
 				}
@@ -419,7 +422,7 @@ int MAP::load(const char *filename)
 					void *data = datafile_get_data(df, item->image_data);
 					img->data = mem_alloc(img->width*img->height*4, 1);
 					mem_copy(img->data, data, img->width*img->height*4);
-					img->tex_id = gfx_load_texture_raw(img->width, img->height, img->format, img->data, IMG_AUTO, 0);
+					img->tex_id = editor->Graphics()->LoadTextureRaw(img->width, img->height, img->format, img->data, IMG_AUTO, 0);
 				}
 
 				// copy image name
diff --git a/src/game/editor/ed_layer_game.cpp b/src/game/editor/ed_layer_game.cpp
index 60825ec3..9010bc71 100644
--- a/src/game/editor/ed_layer_game.cpp
+++ b/src/game/editor/ed_layer_game.cpp
@@ -12,7 +12,7 @@ LAYER_GAME::~LAYER_GAME()
 {
 }
 
-int LAYER_GAME::render_properties(RECT *toolbox)
+int LAYER_GAME::render_properties(CUIRect *toolbox)
 {
 	int r = LAYER_TILES::render_properties(toolbox);
 	image = -1;
diff --git a/src/game/editor/ed_layer_quads.cpp b/src/game/editor/ed_layer_quads.cpp
index bbe5fb6d..ce1ba4b6 100644
--- a/src/game/editor/ed_layer_quads.cpp
+++ b/src/game/editor/ed_layer_quads.cpp
@@ -1,5 +1,7 @@
 #include <base/math.hpp>
 
+#include <engine/client/graphics.h>
+
 #include "ed_editor.hpp"
 #include <game/generated/gc_data.hpp>
 #include <game/client/render.hpp>
@@ -15,9 +17,10 @@ LAYER_QUADS::~LAYER_QUADS()
 {
 }
 
-static void envelope_eval(float time_offset, int env, float *channels)
+static void envelope_eval(float time_offset, int env, float *channels, void *user)
 {
-	if(env < 0 || env > editor.map.envelopes.len())
+	EDITOR *pEditor = (EDITOR *)user;
+	if(env < 0 || env > pEditor->map.envelopes.len())
 	{
 		channels[0] = 0;
 		channels[1] = 0;
@@ -26,19 +29,19 @@ static void envelope_eval(float time_offset, int env, float *channels)
 		return;
 	}
 		
-	ENVELOPE *e = editor.map.envelopes[env];
-	float t = editor.animate_time+time_offset;
-	t *= editor.animate_speed;
+	ENVELOPE *e = pEditor->map.envelopes[env];
+	float t = pEditor->animate_time+time_offset;
+	t *= pEditor->animate_speed;
 	e->eval(t, channels);
 }
 
 void LAYER_QUADS::render()
 {
-	gfx_texture_set(-1);
-	if(image >= 0 && image < editor.map.images.len())
-		gfx_texture_set(editor.map.images[image]->tex_id);
+	Graphics()->TextureSet(-1);
+	if(image >= 0 && image < editor->map.images.len())
+		Graphics()->TextureSet(editor->map.images[image]->tex_id);
 		
-	render_quads(quads.getptr(), quads.len(), envelope_eval, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT);
+	editor->RenderTools()->render_quads(quads.getptr(), quads.len(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, envelope_eval, editor);
 }
 
 QUAD *LAYER_QUADS::new_quad()
@@ -89,19 +92,19 @@ QUAD *LAYER_QUADS::new_quad()
 	return q;
 }
 
-void LAYER_QUADS::brush_selecting(RECT rect)
+void LAYER_QUADS::brush_selecting(CUIRect rect)
 {
 	// draw selection rectangle
-	gfx_texture_set(-1);
-	gfx_lines_begin();
-	gfx_lines_draw(rect.x, rect.y, rect.x+rect.w, rect.y);
-	gfx_lines_draw(rect.x+rect.w, rect.y, rect.x+rect.w, rect.y+rect.h);
-	gfx_lines_draw(rect.x+rect.w, rect.y+rect.h, rect.x, rect.y+rect.h);
-	gfx_lines_draw(rect.x, rect.y+rect.h, rect.x, rect.y);
-	gfx_lines_end();
+	Graphics()->TextureSet(-1);
+	Graphics()->LinesBegin();
+	Graphics()->LinesDraw(rect.x, rect.y, rect.x+rect.w, rect.y);
+	Graphics()->LinesDraw(rect.x+rect.w, rect.y, rect.x+rect.w, rect.y+rect.h);
+	Graphics()->LinesDraw(rect.x+rect.w, rect.y+rect.h, rect.x, rect.y+rect.h);
+	Graphics()->LinesDraw(rect.x, rect.y+rect.h, rect.x, rect.y);
+	Graphics()->LinesEnd();
 }
 
-int LAYER_QUADS::brush_grab(LAYERGROUP *brush, RECT rect)
+int LAYER_QUADS::brush_grab(LAYERGROUP *brush, CUIRect rect)
 {
 	// create new layers
 	LAYER_QUADS *grabbed = new LAYER_QUADS();
@@ -204,7 +207,7 @@ void LAYER_QUADS::get_size(float *w, float *h)
 
 extern int selected_points;
 
-int LAYER_QUADS::render_properties(RECT *toolbox)
+int LAYER_QUADS::render_properties(CUIRect *toolbox)
 {
 	// layer props
 	enum
@@ -220,12 +223,12 @@ int LAYER_QUADS::render_properties(RECT *toolbox)
 	
 	static int ids[NUM_PROPS] = {0};
 	int new_val = 0;
-	int prop = editor.do_properties(toolbox, props, ids, &new_val);		
+	int prop = editor->do_properties(toolbox, props, ids, &new_val);		
 	
 	if(prop == PROP_IMAGE)
 	{
 		if(new_val >= 0)
-			image = new_val%editor.map.images.len();
+			image = new_val%editor->map.images.len();
 		else
 			image = -1;
 	}
diff --git a/src/game/editor/ed_layer_tiles.cpp b/src/game/editor/ed_layer_tiles.cpp
index 80ccaa3a..0d42cb78 100644
--- a/src/game/editor/ed_layer_tiles.cpp
+++ b/src/game/editor/ed_layer_tiles.cpp
@@ -1,5 +1,7 @@
 #include <base/math.hpp>
 
+#include <engine/client/graphics.h>
+
 #include <game/generated/gc_data.hpp>
 #include <game/client/render.hpp>
 #include "ed_editor.hpp"
@@ -33,7 +35,7 @@ void LAYER_TILES::prepare_for_save()
 	{
 		for(int y = 0; y < height; y++)
 			for(int x = 0; x < width; x++)
-				tiles[y*width+x].flags |= editor.map.images[image]->tileflags[tiles[y*width+x].index];
+				tiles[y*width+x].flags |= editor->map.images[image]->tileflags[tiles[y*width+x].index];
 	}
 }
 
@@ -46,16 +48,16 @@ void LAYER_TILES::make_palette()
 
 void LAYER_TILES::render()
 {
-	if(image >= 0 && image < editor.map.images.len())
-		tex_id = editor.map.images[image]->tex_id;
-	gfx_texture_set(tex_id);
-	render_tilemap(tiles, width, height, 32.0f, vec4(1,1,1,1), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT);
+	if(image >= 0 && image < editor->map.images.len())
+		tex_id = editor->map.images[image]->tex_id;
+	Graphics()->TextureSet(tex_id);
+	editor->RenderTools()->render_tilemap(tiles, width, height, 32.0f, vec4(1,1,1,1), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT);
 }
 
 int LAYER_TILES::convert_x(float x) const { return (int)(x/32.0f); }
 int LAYER_TILES::convert_y(float y) const { return (int)(y/32.0f); }
 
-void LAYER_TILES::convert(RECT rect, RECTi *out)
+void LAYER_TILES::convert(CUIRect rect, RECTi *out)
 {
 	out->x = convert_x(rect.x);
 	out->y = convert_y(rect.y);
@@ -63,7 +65,7 @@ void LAYER_TILES::convert(RECT rect, RECTi *out)
 	out->h = convert_y(rect.y+rect.h+31) - out->y;
 }
 
-void LAYER_TILES::snap(RECT *rect)
+void LAYER_TILES::snap(CUIRect *rect)
 {
 	RECTi out;
 	convert(*rect, &out);
@@ -99,20 +101,20 @@ void LAYER_TILES::clamp(RECTi *rect)
 		rect->w = 0;
 }
 
-void LAYER_TILES::brush_selecting(RECT rect)
+void LAYER_TILES::brush_selecting(CUIRect rect)
 {
-	gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_setcolor(1,1,1,0.4f);
+	Graphics()->TextureSet(-1);
+	editor->Graphics()->QuadsBegin();
+	editor->Graphics()->SetColor(1,1,1,0.4f);
 	snap(&rect);
-	gfx_quads_drawTL(rect.x, rect.y, rect.w, rect.h);
-	gfx_quads_end();
+	editor->Graphics()->QuadsDrawTL(rect.x, rect.y, rect.w, rect.h);
+	editor->Graphics()->QuadsEnd();
 	char buf[16];
 	str_format(buf, sizeof(buf), "%d,%d", convert_x(rect.w), convert_y(rect.h));
-	gfx_text(0, rect.x+3.0f, rect.y+3.0f, 15.0f*editor.world_zoom, buf, -1);
+	gfx_text(0, rect.x+3.0f, rect.y+3.0f, 15.0f*editor->world_zoom, buf, -1);
 }
 
-int LAYER_TILES::brush_grab(LAYERGROUP *brush, RECT rect)
+int LAYER_TILES::brush_grab(LAYERGROUP *brush, CUIRect rect)
 {
 	RECTi r;
 	convert(rect, &r);
@@ -204,17 +206,17 @@ void LAYER_TILES::resize(int new_w, int new_h)
 }
 
 
-int LAYER_TILES::render_properties(RECT *toolbox)
+int LAYER_TILES::render_properties(CUIRect *toolbox)
 {
-	RECT button;
-	ui_hsplit_b(toolbox, 12.0f, toolbox, &button);
-	bool in_gamegroup = editor.map.game_group->layers.find(this) != -1;
-	if(editor.map.game_layer == this)
+	CUIRect button;
+	toolbox->HSplitBottom(12.0f, toolbox, &button);
+	bool in_gamegroup = editor->map.game_group->layers.find(this) != -1;
+	if(editor->map.game_layer == this)
 		in_gamegroup = false;
 	static int colcl_button = 0;
-	if(do_editor_button(&colcl_button, "Clear Collision", in_gamegroup?0:-1, &button, draw_editor_button, 0, "Removes collision from this layer"))
+	if(editor->DoButton_Editor(&colcl_button, "Clear Collision", in_gamegroup?0:-1, &button, 0, "Removes collision from this layer"))
 	{
-		LAYER_TILES *gl = editor.map.game_layer;
+		LAYER_TILES *gl = editor->map.game_layer;
 		int w = min(gl->width, width);
 		int h = min(gl->height, height);
 		for(int y = 0; y < h; y++)
@@ -228,11 +230,11 @@ int LAYER_TILES::render_properties(RECT *toolbox)
 		return 1;
 	}
 	static int col_button = 0;
-	ui_hsplit_b(toolbox, 5.0f, toolbox, &button);
-	ui_hsplit_b(toolbox, 12.0f, toolbox, &button);
-	if(do_editor_button(&col_button, "Make Collision", in_gamegroup?0:-1, &button, draw_editor_button, 0, "Constructs collision from this layer"))
+	toolbox->HSplitBottom(5.0f, toolbox, &button);
+	toolbox->HSplitBottom(12.0f, toolbox, &button);
+	if(editor->DoButton_Editor(&col_button, "Make Collision", in_gamegroup?0:-1, &button, 0, "Constructs collision from this layer"))
 	{
-		LAYER_TILES *gl = editor.map.game_layer;
+		LAYER_TILES *gl = editor->map.game_layer;
 		int w = min(gl->width, width);
 		int h = min(gl->height, height);
 		for(int y = 0; y < h; y++)
@@ -260,12 +262,12 @@ int LAYER_TILES::render_properties(RECT *toolbox)
 		{0},
 	};
 	
-	if(editor.map.game_layer == this) // remove the image from the selection if this is the game layer
+	if(editor->map.game_layer == this) // remove the image from the selection if this is the game layer
 		props[2].name = 0;
 	
 	static int ids[NUM_PROPS] = {0};
 	int new_val = 0;
-	int prop = editor.do_properties(toolbox, props, ids, &new_val);		
+	int prop = editor->do_properties(toolbox, props, ids, &new_val);		
 	
 	if(prop == PROP_WIDTH && new_val > 1)
 		resize(new_val, height);
@@ -279,7 +281,7 @@ int LAYER_TILES::render_properties(RECT *toolbox)
 			image = -1;
 		}
 		else
-			image = new_val%editor.map.images.len();
+			image = new_val%editor->map.images.len();
 	}
 	
 	return 0;
diff --git a/src/game/editor/ed_popups.cpp b/src/game/editor/ed_popups.cpp
index 13bfe243..59140153 100644
--- a/src/game/editor/ed_popups.cpp
+++ b/src/game/editor/ed_popups.cpp
@@ -1,20 +1,21 @@
 #include <stdio.h>
+#include <engine/client/graphics.h>
 #include "ed_editor.hpp"
 
 
 // popup menu handling
 static struct
 {
-	RECT rect;
+	CUIRect rect;
 	void *id;
-	int (*func)(RECT rect);
+	int (*func)(EDITOR *pEditor, CUIRect rect);
 	int is_menu;
 	void *extra;
 } ui_popups[8];
 
 static int ui_num_popups = 0;
 
-void ui_invoke_popup_menu(void *id, int flags, float x, float y, float w, float h, int (*func)(RECT rect), void *extra)
+void EDITOR::ui_invoke_popup_menu(void *id, int flags, float x, float y, float w, float h, int (*func)(EDITOR *pEditor, CUIRect rect), void *extra)
 {
 	dbg_msg("", "invoked");
 	ui_popups[ui_num_popups].id = id;
@@ -28,39 +29,39 @@ void ui_invoke_popup_menu(void *id, int flags, float x, float y, float w, float
 	ui_num_popups++;
 }
 
-void ui_do_popup_menu()
+void EDITOR::ui_do_popup_menu()
 {
 	for(int i = 0; i < ui_num_popups; i++)
 	{
-		bool inside = ui_mouse_inside(&ui_popups[i].rect);
-		ui_set_hot_item(&ui_popups[i].id);
+		bool inside = UI()->MouseInside(&ui_popups[i].rect);
+		UI()->SetHotItem(&ui_popups[i].id);
 		
-		if(ui_active_item() == &ui_popups[i].id)
+		if(UI()->ActiveItem() == &ui_popups[i].id)
 		{
-			if(!ui_mouse_button(0))
+			if(!UI()->MouseButton(0))
 			{
 				if(!inside)
 					ui_num_popups--;
-				ui_set_active_item(0);
+				UI()->SetActiveItem(0);
 			}
 		}
-		else if(ui_hot_item() == &ui_popups[i].id)
+		else if(UI()->HotItem() == &ui_popups[i].id)
 		{
-			if(ui_mouse_button(0))
-				ui_set_active_item(&ui_popups[i].id);
+			if(UI()->MouseButton(0))
+				UI()->SetActiveItem(&ui_popups[i].id);
 		}
 		
-		int corners = CORNER_ALL;
+		int corners = CUI::CORNER_ALL;
 		if(ui_popups[i].is_menu)
-			corners = CORNER_R|CORNER_B;
+			corners = CUI::CORNER_R|CUI::CORNER_B;
 		
-		RECT r = ui_popups[i].rect;
-		ui_draw_rect(&r, vec4(0.5f,0.5f,0.5f,0.75f), corners, 3.0f);
-		ui_margin(&r, 1.0f, &r);
-		ui_draw_rect(&r, vec4(0,0,0,0.75f), corners, 3.0f);
-		ui_margin(&r, 4.0f, &r);
+		CUIRect r = ui_popups[i].rect;
+		RenderTools()->DrawUIRect(&r, vec4(0.5f,0.5f,0.5f,0.75f), corners, 3.0f);
+		r.Margin(1.0f, &r);
+		RenderTools()->DrawUIRect(&r, vec4(0,0,0,0.75f), corners, 3.0f);
+		r.Margin(4.0f, &r);
 		
-		if(ui_popups[i].func(r))
+		if(ui_popups[i].func(this, r))
 			ui_num_popups--;
 			
 		if(inp_key_down(KEY_ESCAPE))
@@ -69,42 +70,42 @@ void ui_do_popup_menu()
 }
 
 
-int popup_group(RECT view)
+int EDITOR::popup_group(EDITOR *pEditor, CUIRect view)
 {
 	// remove group button
-	RECT button;
-	ui_hsplit_b(&view, 12.0f, &view, &button);
+	CUIRect button;
+	view.HSplitBottom(12.0f, &view, &button);
 	static int delete_button = 0;
 	
 	// don't allow deletion of game group
-	if(editor.map.game_group != editor.get_selected_group() &&
-		do_editor_button(&delete_button, "Delete Group", 0, &button, draw_editor_button, 0, "Delete group"))
+	if(pEditor->map.game_group != pEditor->get_selected_group() &&
+		pEditor->DoButton_Editor(&delete_button, "Delete Group", 0, &button, 0, "Delete group"))
 	{
-		editor.map.delete_group(editor.selected_group);
+		pEditor->map.delete_group(pEditor->selected_group);
 		return 1;
 	}
 
 	// new tile layer
-	ui_hsplit_b(&view, 10.0f, &view, &button);
-	ui_hsplit_b(&view, 12.0f, &view, &button);
+	view.HSplitBottom(10.0f, &view, &button);
+	view.HSplitBottom(12.0f, &view, &button);
 	static int new_quad_layer_button = 0;
-	if(do_editor_button(&new_quad_layer_button, "Add Quads Layer", 0, &button, draw_editor_button, 0, "Creates a new quad layer"))
+	if(pEditor->DoButton_Editor(&new_quad_layer_button, "Add Quads Layer", 0, &button, 0, "Creates a new quad layer"))
 	{
 		LAYER *l = new LAYER_QUADS;
-		editor.map.groups[editor.selected_group]->add_layer(l);
-		editor.selected_layer = editor.map.groups[editor.selected_group]->layers.len()-1;
+		pEditor->map.groups[pEditor->selected_group]->add_layer(l);
+		pEditor->selected_layer = pEditor->map.groups[pEditor->selected_group]->layers.len()-1;
 		return 1;
 	}
 
 	// new quad layer
-	ui_hsplit_b(&view, 5.0f, &view, &button);
-	ui_hsplit_b(&view, 12.0f, &view, &button);
+	view.HSplitBottom(5.0f, &view, &button);
+	view.HSplitBottom(12.0f, &view, &button);
 	static int new_tile_layer_button = 0;
-	if(do_editor_button(&new_tile_layer_button, "Add Tile Layer", 0, &button, draw_editor_button, 0, "Creates a new tile layer"))
+	if(pEditor->DoButton_Editor(&new_tile_layer_button, "Add Tile Layer", 0, &button, 0, "Creates a new tile layer"))
 	{
 		LAYER *l = new LAYER_TILES(50, 50);
-		editor.map.groups[editor.selected_group]->add_layer(l);
-		editor.selected_layer = editor.map.groups[editor.selected_group]->layers.len()-1;
+		pEditor->map.groups[pEditor->selected_group]->add_layer(l);
+		pEditor->selected_layer = pEditor->map.groups[pEditor->selected_group]->layers.len()-1;
 		return 1;
 	}
 	
@@ -124,17 +125,17 @@ int popup_group(RECT view)
 	};
 	
 	PROPERTY props[] = {
-		{"Order", editor.selected_group, PROPTYPE_INT_STEP, 0, editor.map.groups.len()-1},
-		{"Pos X", -editor.map.groups[editor.selected_group]->offset_x, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Pos Y", -editor.map.groups[editor.selected_group]->offset_y, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Para X", editor.map.groups[editor.selected_group]->parallax_x, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Para Y", editor.map.groups[editor.selected_group]->parallax_y, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Order", pEditor->selected_group, PROPTYPE_INT_STEP, 0, pEditor->map.groups.len()-1},
+		{"Pos X", -pEditor->map.groups[pEditor->selected_group]->offset_x, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Pos Y", -pEditor->map.groups[pEditor->selected_group]->offset_y, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Para X", pEditor->map.groups[pEditor->selected_group]->parallax_x, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Para Y", pEditor->map.groups[pEditor->selected_group]->parallax_y, PROPTYPE_INT_SCROLL, -1000000, 1000000},
 
-		{"Use Clipping", editor.map.groups[editor.selected_group]->use_clipping, PROPTYPE_BOOL, 0, 1},
-		{"Clip X", editor.map.groups[editor.selected_group]->clip_x, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Clip Y", editor.map.groups[editor.selected_group]->clip_y, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Clip W", editor.map.groups[editor.selected_group]->clip_w, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Clip H", editor.map.groups[editor.selected_group]->clip_h, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Use Clipping", pEditor->map.groups[pEditor->selected_group]->use_clipping, PROPTYPE_BOOL, 0, 1},
+		{"Clip X", pEditor->map.groups[pEditor->selected_group]->clip_x, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Clip Y", pEditor->map.groups[pEditor->selected_group]->clip_y, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Clip W", pEditor->map.groups[pEditor->selected_group]->clip_w, PROPTYPE_INT_SCROLL, -1000000, 1000000},
+		{"Clip H", pEditor->map.groups[pEditor->selected_group]->clip_h, PROPTYPE_INT_SCROLL, -1000000, 1000000},
 		{0},
 	};
 	
@@ -142,49 +143,49 @@ int popup_group(RECT view)
 	int new_val = 0;
 	
 	// cut the properties that isn't needed
-	if(editor.get_selected_group()->game_group)
+	if(pEditor->get_selected_group()->game_group)
 		props[PROP_POS_X].name = 0;
 		
-	int prop = editor.do_properties(&view, props, ids, &new_val);
+	int prop = pEditor->do_properties(&view, props, ids, &new_val);
 	if(prop == PROP_ORDER)
-		editor.selected_group = editor.map.swap_groups(editor.selected_group, new_val);
+		pEditor->selected_group = pEditor->map.swap_groups(pEditor->selected_group, new_val);
 		
 	// these can not be changed on the game group
-	if(!editor.get_selected_group()->game_group)
+	if(!pEditor->get_selected_group()->game_group)
 	{
-		if(prop == PROP_PARA_X) editor.map.groups[editor.selected_group]->parallax_x = new_val;
-		else if(prop == PROP_PARA_Y) editor.map.groups[editor.selected_group]->parallax_y = new_val;
-		else if(prop == PROP_POS_X) editor.map.groups[editor.selected_group]->offset_x = -new_val;
-		else if(prop == PROP_POS_Y) editor.map.groups[editor.selected_group]->offset_y = -new_val;
-		else if(prop == PROP_USE_CLIPPING) editor.map.groups[editor.selected_group]->use_clipping = new_val;
-		else if(prop == PROP_CLIP_X) editor.map.groups[editor.selected_group]->clip_x = new_val;
-		else if(prop == PROP_CLIP_Y) editor.map.groups[editor.selected_group]->clip_y = new_val;
-		else if(prop == PROP_CLIP_W) editor.map.groups[editor.selected_group]->clip_w = new_val;
-		else if(prop == PROP_CLIP_H) editor.map.groups[editor.selected_group]->clip_h = new_val;
+		if(prop == PROP_PARA_X) pEditor->map.groups[pEditor->selected_group]->parallax_x = new_val;
+		else if(prop == PROP_PARA_Y) pEditor->map.groups[pEditor->selected_group]->parallax_y = new_val;
+		else if(prop == PROP_POS_X) pEditor->map.groups[pEditor->selected_group]->offset_x = -new_val;
+		else if(prop == PROP_POS_Y) pEditor->map.groups[pEditor->selected_group]->offset_y = -new_val;
+		else if(prop == PROP_USE_CLIPPING) pEditor->map.groups[pEditor->selected_group]->use_clipping = new_val;
+		else if(prop == PROP_CLIP_X) pEditor->map.groups[pEditor->selected_group]->clip_x = new_val;
+		else if(prop == PROP_CLIP_Y) pEditor->map.groups[pEditor->selected_group]->clip_y = new_val;
+		else if(prop == PROP_CLIP_W) pEditor->map.groups[pEditor->selected_group]->clip_w = new_val;
+		else if(prop == PROP_CLIP_H) pEditor->map.groups[pEditor->selected_group]->clip_h = new_val;
 	}
 	
 	return 0;
 }
 
-int popup_layer(RECT view)
+int EDITOR::popup_layer(EDITOR *pEditor, CUIRect view)
 {
 	// remove layer button
-	RECT button;
-	ui_hsplit_b(&view, 12.0f, &view, &button);
+	CUIRect button;
+	view.HSplitBottom(12.0f, &view, &button);
 	static int delete_button = 0;
 	
 	// don't allow deletion of game layer
-	if(editor.map.game_layer != editor.get_selected_layer(0) &&
-		do_editor_button(&delete_button, "Delete Layer", 0, &button, draw_editor_button, 0, "Deletes the layer"))
+	if(pEditor->map.game_layer != pEditor->get_selected_layer(0) &&
+		pEditor->DoButton_Editor(&delete_button, "Delete Layer", 0, &button, 0, "Deletes the layer"))
 	{
-		editor.map.groups[editor.selected_group]->delete_layer(editor.selected_layer);
+		pEditor->map.groups[pEditor->selected_group]->delete_layer(pEditor->selected_layer);
 		return 1;
 	}
 
-	ui_hsplit_b(&view, 10.0f, &view, 0);
+	view.HSplitBottom(10.0f, &view, 0);
 	
-	LAYERGROUP *current_group = editor.map.groups[editor.selected_group];
-	LAYER *current_layer = editor.get_selected_layer(0);
+	LAYERGROUP *current_group = pEditor->map.groups[pEditor->selected_group];
+	LAYER *current_layer = pEditor->get_selected_layer(0);
 	
 	enum
 	{
@@ -195,26 +196,26 @@ int popup_layer(RECT view)
 	};
 	
 	PROPERTY props[] = {
-		{"Group", editor.selected_group, PROPTYPE_INT_STEP, 0, editor.map.groups.len()-1},
-		{"Order", editor.selected_layer, PROPTYPE_INT_STEP, 0, current_group->layers.len()},
+		{"Group", pEditor->selected_group, PROPTYPE_INT_STEP, 0, pEditor->map.groups.len()-1},
+		{"Order", pEditor->selected_layer, PROPTYPE_INT_STEP, 0, current_group->layers.len()},
 		{"Detail", current_layer->flags&LAYERFLAG_DETAIL, PROPTYPE_BOOL, 0, 1},
 		{0},
 	};
 	
 	static int ids[NUM_PROPS] = {0};
 	int new_val = 0;
-	int prop = editor.do_properties(&view, props, ids, &new_val);		
+	int prop = pEditor->do_properties(&view, props, ids, &new_val);		
 	
 	if(prop == PROP_ORDER)
-		editor.selected_layer = current_group->swap_layers(editor.selected_layer, new_val);
+		pEditor->selected_layer = current_group->swap_layers(pEditor->selected_layer, new_val);
 	else if(prop == PROP_GROUP && current_layer->type != LAYERTYPE_GAME)
 	{
-		if(new_val >= 0 && new_val < editor.map.groups.len())
+		if(new_val >= 0 && new_val < pEditor->map.groups.len())
 		{
 			current_group->layers.remove(current_layer);
-			editor.map.groups[new_val]->layers.add(current_layer);
-			editor.selected_group = new_val;
-			editor.selected_layer = editor.map.groups[new_val]->layers.len()-1;
+			pEditor->map.groups[new_val]->layers.add(current_layer);
+			pEditor->selected_group = new_val;
+			pEditor->selected_layer = pEditor->map.groups[new_val]->layers.len()-1;
 		}
 	}
 	else if(prop == PROP_HQ)
@@ -227,31 +228,31 @@ int popup_layer(RECT view)
 	return current_layer->render_properties(&view);
 }
 
-int popup_quad(RECT view)
+int EDITOR::popup_quad(EDITOR *pEditor, CUIRect view)
 {
-	QUAD *quad = editor.get_selected_quad();
+	QUAD *quad = pEditor->get_selected_quad();
 
-	RECT button;
+	CUIRect button;
 	
 	// delete button
-	ui_hsplit_b(&view, 12.0f, &view, &button);
+	view.HSplitBottom(12.0f, &view, &button);
 	static int delete_button = 0;
-	if(do_editor_button(&delete_button, "Delete", 0, &button, draw_editor_button, 0, "Deletes the current quad"))
+	if(pEditor->DoButton_Editor(&delete_button, "Delete", 0, &button, 0, "Deletes the current quad"))
 	{
-		LAYER_QUADS *layer = (LAYER_QUADS *)editor.get_selected_layer_type(0, LAYERTYPE_QUADS);
+		LAYER_QUADS *layer = (LAYER_QUADS *)pEditor->get_selected_layer_type(0, LAYERTYPE_QUADS);
 		if(layer)
 		{
-			layer->quads.removebyindex(editor.selected_quad);
-			editor.selected_quad--;
+			layer->quads.removebyindex(pEditor->selected_quad);
+			pEditor->selected_quad--;
 		}
 		return 1;
 	}
 
 	// square button
-	ui_hsplit_b(&view, 10.0f, &view, &button);
-	ui_hsplit_b(&view, 12.0f, &view, &button);
+	view.HSplitBottom(10.0f, &view, &button);
+	view.HSplitBottom(12.0f, &view, &button);
 	static int sq_button = 0;
-	if(do_editor_button(&sq_button, "Square", 0, &button, draw_editor_button, 0, "Squares the current quad"))
+	if(pEditor->DoButton_Editor(&sq_button, "Square", 0, &button, 0, "Squares the current quad"))
 	{
 		int top = quad->points[0].y;
 		int left = quad->points[0].x;
@@ -284,9 +285,9 @@ int popup_quad(RECT view)
 	};
 	
 	PROPERTY props[] = {
-		{"Pos. Env", quad->pos_env, PROPTYPE_INT_STEP, -1, editor.map.envelopes.len()},
+		{"Pos. Env", quad->pos_env, PROPTYPE_INT_STEP, -1, pEditor->map.envelopes.len()},
 		{"Pos. TO", quad->pos_env_offset, PROPTYPE_INT_SCROLL, -1000000, 1000000},
-		{"Color Env", quad->color_env, PROPTYPE_INT_STEP, -1, editor.map.envelopes.len()},
+		{"Color Env", quad->color_env, PROPTYPE_INT_STEP, -1, pEditor->map.envelopes.len()},
 		{"Color TO", quad->color_env_offset, PROPTYPE_INT_SCROLL, -1000000, 1000000},
 		
 		{0},
@@ -294,19 +295,19 @@ int popup_quad(RECT view)
 	
 	static int ids[NUM_PROPS] = {0};
 	int new_val = 0;
-	int prop = editor.do_properties(&view, props, ids, &new_val);		
+	int prop = pEditor->do_properties(&view, props, ids, &new_val);		
 	
-	if(prop == PROP_POS_ENV) quad->pos_env = clamp(new_val, -1, editor.map.envelopes.len()-1);
+	if(prop == PROP_POS_ENV) quad->pos_env = clamp(new_val, -1, pEditor->map.envelopes.len()-1);
 	if(prop == PROP_POS_ENV_OFFSET) quad->pos_env_offset = new_val;
-	if(prop == PROP_COLOR_ENV) quad->color_env = clamp(new_val, -1, editor.map.envelopes.len()-1);
+	if(prop == PROP_COLOR_ENV) quad->color_env = clamp(new_val, -1, pEditor->map.envelopes.len()-1);
 	if(prop == PROP_COLOR_ENV_OFFSET) quad->color_env_offset = new_val;
 	
 	return 0;
 }
 
-int popup_point(RECT view)
+int EDITOR::popup_point(EDITOR *pEditor, CUIRect view)
 {
-	QUAD *quad = editor.get_selected_quad();
+	QUAD *quad = pEditor->get_selected_quad();
 	
 	enum
 	{
@@ -318,7 +319,7 @@ int popup_point(RECT view)
 
 	for(int v = 0; v < 4; v++)
 	{
-		if(editor.selected_points&(1<<v))
+		if(pEditor->selected_points&(1<<v))
 		{
 			color = 0;
 			color |= quad->colors[v].r<<24;
@@ -330,18 +331,18 @@ int popup_point(RECT view)
 	
 	
 	PROPERTY props[] = {
-		{"Color", color, PROPTYPE_COLOR, -1, editor.map.envelopes.len()},
+		{"Color", color, PROPTYPE_COLOR, -1, pEditor->map.envelopes.len()},
 		{0},
 	};
 	
 	static int ids[NUM_PROPS] = {0};
 	int new_val = 0;
-	int prop = editor.do_properties(&view, props, ids, &new_val);		
+	int prop = pEditor->do_properties(&view, props, ids, &new_val);		
 	if(prop == PROP_COLOR)
 	{
 		for(int v = 0; v < 4; v++)
 		{
-			if(editor.selected_points&(1<<v))
+			if(pEditor->selected_points&(1<<v))
 			{
 				color = 0;
 				quad->colors[v].r = (new_val>>24)&0xff;
@@ -360,47 +361,47 @@ int popup_point(RECT view)
 static int select_image_selected = -100;
 static int select_image_current = -100;
 
-int popup_select_image(RECT view)
+int EDITOR::popup_select_image(EDITOR *pEditor, CUIRect view)
 {
-	RECT buttonbar, imageview;
-	ui_vsplit_l(&view, 80.0f, &buttonbar, &view);
-	ui_margin(&view, 10.0f, &imageview);
+	CUIRect buttonbar, imageview;
+	view.VSplitLeft(80.0f, &buttonbar, &view);
+	view.Margin(10.0f, &imageview);
 	
 	int show_image = select_image_current;
 	
-	for(int i = -1; i < editor.map.images.len(); i++)
+	for(int i = -1; i < pEditor->map.images.len(); i++)
 	{
-		RECT button;
-		ui_hsplit_t(&buttonbar, 12.0f, &button, &buttonbar);
-		ui_hsplit_t(&buttonbar, 2.0f, 0, &buttonbar);
+		CUIRect button;
+		buttonbar.HSplitTop(12.0f, &button, &buttonbar);
+		buttonbar.HSplitTop(2.0f, 0, &buttonbar);
 		
-		if(ui_mouse_inside(&button))
+		if(pEditor->UI()->MouseInside(&button))
 			show_image = i;
 			
 		if(i == -1)
 		{
-			if(do_editor_button(&editor.map.images[i], "None", i==select_image_current, &button, draw_editor_button_menuitem, 0, 0))
+			if(pEditor->DoButton_MenuItem(&pEditor->map.images[i], "None", i==select_image_current, &button))
 				select_image_selected = -1;
 		}
 		else
 		{
-			if(do_editor_button(&editor.map.images[i], editor.map.images[i]->name, i==select_image_current, &button, draw_editor_button_menuitem, 0, 0))
+			if(pEditor->DoButton_MenuItem(&pEditor->map.images[i], pEditor->map.images[i]->name, i==select_image_current, &button))
 				select_image_selected = i;
 		}
 	}
 	
-	if(show_image >= 0 && show_image < editor.map.images.len())
-		gfx_texture_set(editor.map.images[show_image]->tex_id);
+	if(show_image >= 0 && show_image < pEditor->map.images.len())
+		pEditor->Graphics()->TextureSet(pEditor->map.images[show_image]->tex_id);
 	else
-		gfx_texture_set(-1);
-	gfx_quads_begin();
-	gfx_quads_drawTL(imageview.x, imageview.y, imageview.w, imageview.h);
-	gfx_quads_end();
+		pEditor->Graphics()->TextureSet(-1);
+	pEditor->Graphics()->QuadsBegin();
+	pEditor->Graphics()->QuadsDrawTL(imageview.x, imageview.y, imageview.w, imageview.h);
+	pEditor->Graphics()->QuadsEnd();
 
 	return 0;
 }
 
-void popup_select_image_invoke(int current, float x, float y)
+void EDITOR::popup_select_image_invoke(int current, float x, float y)
 {
 	static int select_image_popup_id = 0;
 	select_image_selected = -100;
@@ -408,7 +409,7 @@ void popup_select_image_invoke(int current, float x, float y)
 	ui_invoke_popup_menu(&select_image_popup_id, 0, x, y, 400, 300, popup_select_image);
 }
 
-int popup_select_image_result()
+int EDITOR::popup_select_image_result()
 {
 	if(select_image_selected == -100)
 		return -100;
diff --git a/src/game/localization.cpp b/src/game/localization.cpp
index 202e6ca0..3a1b0411 100644
--- a/src/game/localization.cpp
+++ b/src/game/localization.cpp
@@ -2,9 +2,7 @@
 #include "localization.hpp"
 #include <base/tl/algorithm.hpp>
 
-extern "C" {
 #include <engine/e_linereader.h>
-}
 
 const char *localize(const char *str)
 {
diff --git a/src/game/server/hooks.cpp b/src/game/server/hooks.cpp
index 1ae38ce2..89c95f79 100644
--- a/src/game/server/hooks.cpp
+++ b/src/game/server/hooks.cpp
@@ -7,10 +7,8 @@
 
 #include <engine/e_config.h>
 #include <engine/e_server_interface.h>
-extern "C"
-{
-	#include <engine/e_memheap.h>
-}
+#include <engine/e_memheap.h>
+
 #include <game/version.hpp>
 #include <game/collision.hpp>
 #include <game/layers.hpp>
@@ -597,5 +595,5 @@ void mods_postsnap()
 	game.events.clear();
 }
 
-extern "C" const char *mods_net_version() { return GAME_NETVERSION; }
-extern "C" const char *mods_version() { return GAME_VERSION; }
+const char *mods_net_version() { return GAME_NETVERSION; }
+const char *mods_version() { return GAME_VERSION; }