about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2008-03-29 11:44:03 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2008-03-29 11:44:03 +0000
commit7a3874745ca370a799d95b5f86e85fcc8eadefbb (patch)
tree16f1e28f2f499279496866a63cabf88e2f2ad6c4
parent171d6b1c206c0488b59d157bc266319bf4ab482b (diff)
downloadzcatch-7a3874745ca370a799d95b5f86e85fcc8eadefbb.tar.gz
zcatch-7a3874745ca370a799d95b5f86e85fcc8eadefbb.zip
fixed loads of graphical optimizations
-rw-r--r--data/maps/ctf1.mapbin4401 -> 4510 bytes
-rw-r--r--data/maps/ctf2.mapbin10701 -> 10716 bytes
-rw-r--r--data/maps/dm1.mapbin4399 -> 4519 bytes
-rw-r--r--data/maps/dm2.mapbin7580 -> 7704 bytes
-rw-r--r--data/maps/dm6.mapbin5296 -> 5333 bytes
-rw-r--r--src/engine/client/ec_client.c4
-rw-r--r--src/engine/client/ec_gfx.c50
-rw-r--r--src/engine/e_config_variables.h1
-rw-r--r--src/engine/e_engine.c9
-rw-r--r--src/engine/e_if_gfx.h17
-rw-r--r--src/engine/e_system.c6
-rw-r--r--src/engine/server/es_register.c2
-rw-r--r--src/game/client/gc_client.cpp12
-rw-r--r--src/game/client/gc_render.cpp118
-rw-r--r--src/game/client/gc_render.h7
-rw-r--r--src/game/client/gc_render_map.cpp103
-rw-r--r--src/game/editor/ed_editor.cpp125
-rw-r--r--src/game/editor/ed_editor.hpp11
-rw-r--r--src/game/editor/ed_io.cpp27
-rw-r--r--src/game/editor/ed_layer_quads.cpp2
-rw-r--r--src/game/editor/ed_layer_tiles.cpp16
-rw-r--r--src/game/editor/ed_popups.cpp28
-rw-r--r--src/game/g_layers.cpp23
-rw-r--r--src/game/g_mapitems.h19
24 files changed, 384 insertions, 196 deletions
diff --git a/data/maps/ctf1.map b/data/maps/ctf1.map
index 5e00a4e7..f41e903b 100644
--- a/data/maps/ctf1.map
+++ b/data/maps/ctf1.map
Binary files differdiff --git a/data/maps/ctf2.map b/data/maps/ctf2.map
index 81705329..35abdc79 100644
--- a/data/maps/ctf2.map
+++ b/data/maps/ctf2.map
Binary files differdiff --git a/data/maps/dm1.map b/data/maps/dm1.map
index 292d85a2..27877cba 100644
--- a/data/maps/dm1.map
+++ b/data/maps/dm1.map
Binary files differdiff --git a/data/maps/dm2.map b/data/maps/dm2.map
index 8c68850d..e49cdb04 100644
--- a/data/maps/dm2.map
+++ b/data/maps/dm2.map
Binary files differdiff --git a/data/maps/dm6.map b/data/maps/dm6.map
index 436b8a72..0cf170d0 100644
--- a/data/maps/dm6.map
+++ b/data/maps/dm6.map
Binary files differdiff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c
index a8da7457..72b5536f 100644
--- a/src/engine/client/ec_client.c
+++ b/src/engine/client/ec_client.c
@@ -585,7 +585,9 @@ const char *client_error_string()
 
 static void client_render()
 {
-	gfx_clear(0.0f,0.0f,0.0f);
+	if(config.gfx_clear)	
+		gfx_clear(1,1,0);
+
 	modc_render();
 	client_debug_render();
 }
diff --git a/src/engine/client/ec_gfx.c b/src/engine/client/ec_gfx.c
index 53fe1790..3efcdac7 100644
--- a/src/engine/client/ec_gfx.c
+++ b/src/engine/client/ec_gfx.c
@@ -88,7 +88,7 @@ static void flush()
 	if(num_vertices == 0)
 		return;
 		
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	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,
@@ -216,11 +216,14 @@ int gfx_init()
 	glDisable(GL_DEPTH_TEST);
 	glMatrixMode(GL_MODELVIEW);
 	glLoadIdentity();
-/*	glAlphaFunc(GL_GREATER, 0);
-	glEnable(GL_ALPHA_TEST);*/
-
-
+	
+	glAlphaFunc(GL_GREATER, 0);
+	glEnable(GL_ALPHA_TEST);
+	glDepthMask(0);
+	
 	gfx_mask_op(MASK_NONE, 0);
+	/*glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);*/
+
 	
 	/* Set all z to -5.0f */
 	for (i = 0; i < vertex_buffer_size; i++)
@@ -342,13 +345,21 @@ int gfx_unload_texture(int index)
 	return 0;
 }
 
+void gfx_blend_none()
+{
+	glDisable(GL_BLEND);
+}
+
+
 void gfx_blend_normal()
 {
+	glEnable(GL_BLEND);
 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 }
 
 void gfx_blend_additive()
 {
+	glEnable(GL_BLEND);
 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 }
 
@@ -636,24 +647,27 @@ void gfx_swap()
 	{
 		static PERFORMACE_INFO pscope = {"glfwSwapBuffers", 0};
 		perf_start(&pscope);
-		glFinish();
 		glfwSwapBuffers();
 		perf_end();
 	}
-	
-	{
-		static PERFORMACE_INFO pscope = {"glFlush", 0};
-		perf_start(&pscope);
-		glFlush();
-		perf_end();
-	}
 
+	/*	
+	if(inp_key_pressed('P'))
 	{
-		static PERFORMACE_INFO pscope = {"glFinish", 0};
-		perf_start(&pscope);
-		glFinish();
-		perf_end();
-	}
+		{
+			static PERFORMACE_INFO pscope = {"glFlush", 0};
+			perf_start(&pscope);
+			glFlush();
+			perf_end();
+		}
+
+		{
+			static PERFORMACE_INFO pscope = {"glFinish", 0};
+			perf_start(&pscope);
+			glFinish();
+			perf_end();
+		}
+	}*/
 
 	{
 		static PERFORMACE_INFO pscope = {"glfwPollEvents", 0};
diff --git a/src/engine/e_config_variables.h b/src/engine/e_config_variables.h
index 773093dc..5e355492 100644
--- a/src/engine/e_config_variables.h
+++ b/src/engine/e_config_variables.h
@@ -34,6 +34,7 @@ MACRO_CONFIG_INT(gfx_screen_width, 800, 0, 0)
 MACRO_CONFIG_INT(gfx_screen_height, 600, 0, 0)
 MACRO_CONFIG_INT(gfx_fullscreen, 1, 0, 1)
 MACRO_CONFIG_INT(gfx_color_depth, 24, 16, 24)
+MACRO_CONFIG_INT(gfx_clear, 0, 0, 1)
 MACRO_CONFIG_INT(gfx_vsync, 1, 0, 1)
 MACRO_CONFIG_INT(gfx_display_all_modes, 0, 0, 1)
 MACRO_CONFIG_INT(gfx_texture_compression, 0, 0, 1)
diff --git a/src/engine/e_engine.c b/src/engine/e_engine.c
index a9e0e86e..d356fd4b 100644
--- a/src/engine/e_engine.c
+++ b/src/engine/e_engine.c
@@ -300,7 +300,9 @@ void mastersrv_update()
 		{
 			/* we got a result from the lookup ready */
 			if(master_servers[i].lookup.result == 0)
+			{
 				master_servers[i].addr = master_servers[i].lookup.addr;
+			}
 			master_servers[i].lookup.state = STATE_PROCESSED;
 		}
 
@@ -311,6 +313,13 @@ void mastersrv_update()
 	
 	if(!needs_update)
 	{
+		/* make sure to destroy the threads */
+		for(i = 0; i < NUM_LOOKUP_THREADS; i++)
+		{
+			thread_destroy(master_servers[i].lookup.thread);
+			master_servers[i].lookup.thread = 0;
+		}
+			
 		dbg_msg("engine/mastersrv", "saving addresses");
 		mastersrv_save();
 	}
diff --git a/src/engine/e_if_gfx.h b/src/engine/e_if_gfx.h
index 265d41d3..525633b4 100644
--- a/src/engine/e_if_gfx.h
+++ b/src/engine/e_if_gfx.h
@@ -455,7 +455,7 @@ void gfx_mapscreen(float tl_x, float tl_y, float br_x, float br_y);
 		This is equal to glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
 	
 	See Also:
-		<gfx_blend_additive>
+		<gfx_blend_additive,gfx_blend_none>
 */
 void gfx_blend_normal();
 
@@ -468,11 +468,24 @@ void gfx_blend_normal();
 		This is equal to glBlendFunc(GL_SRC_ALPHA, GL_ONE).
 	
 	See Also:
-		<gfx_blend_normal>
+		<gfx_blend_normal,gfx_blend_none>
 */
 void gfx_blend_additive();
 
 /*
+	Function: gfx_blend_none
+		Disables blending
+
+	Remarks:
+		This must be used before calling <gfx_quads_begin>.
+	
+	See Also:
+		<gfx_blend_normal,gfx_blend_additive>
+*/
+void gfx_blend_none();
+
+
+/*
 	Function: gfx_setcolorvertex
 		Sets the color of a vertex.
 		
diff --git a/src/engine/e_system.c b/src/engine/e_system.c
index ef1ddda2..5075c062 100644
--- a/src/engine/e_system.c
+++ b/src/engine/e_system.c
@@ -330,6 +330,12 @@ void thread_wait(void *thread)
 
 void thread_destroy(void *thread)
 {
+#if defined(CONF_FAMILY_UNIX)
+	void *r = 0;
+	pthread_join((pthread_t)thread, &r);
+#else
+	/*#error not implemented*/
+#endif
 }
 
 void thread_yield()
diff --git a/src/engine/server/es_register.c b/src/engine/server/es_register.c
index 2d482359..fe8cd959 100644
--- a/src/engine/server/es_register.c
+++ b/src/engine/server/es_register.c
@@ -202,7 +202,7 @@ void register_update()
 		register_first = 0;
 		
 		/* check if we should send new heartbeat again */
-		if(now > register_state_start+freq*30)
+		if(now > register_state_start+freq)
 		{
 			if(register_count == 120) /* redo the whole process after 60 minutes to balance out the master servers */
 				register_new_state(REGISTERSTATE_START);
diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp
index 4fe312c5..6bc83af9 100644
--- a/src/game/client/gc_client.cpp
+++ b/src/game/client/gc_client.cpp
@@ -983,10 +983,7 @@ void render_game()
 
 	// render the world
 	float zoom = 1.0f;
-	if(inp_key_pressed('E'))
-		zoom = 0.5f;
-	
-	gfx_clear(0.65f,0.78f,0.9f);
+
 	if(spectate)
 		render_world(mouse_pos.x, mouse_pos.y, zoom);
 	else
@@ -1485,7 +1482,12 @@ void render_game()
 		float ramp = velocity_ramp(velspeed, tuning.velramp_start, tuning.velramp_range, tuning.velramp_curvature);
 		
 		char buf[512];
-		str_format(buf, sizeof(buf), "%.0f\n%.0f\n%.2f\n%d %s", velspeed, velspeed*ramp, ramp, netobj_num_corrections(), netobj_corrected_on());
+		str_format(buf, sizeof(buf), "%.0f\n%.0f\n%.2f\n%d %s\n%d %d",
+			velspeed, velspeed*ramp, ramp,
+			netobj_num_corrections(), netobj_corrected_on(),
+			netobjects.local_character->x,
+			netobjects.local_character->y
+		);
 		gfx_text(0, 150, 50, 12, buf, -1);
 	}
 
diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp
index 8cbc3b2e..33187f62 100644
--- a/src/game/client/gc_render.cpp
+++ b/src/game/client/gc_render.cpp
@@ -297,10 +297,26 @@ static void envelope_eval(float time_offset, int env, float *channels)
 void render_layers(float center_x, float center_y, int pass)
 {
 	bool passed_gamelayer = false;
+
 	for(int g = 0; g < layers_num_groups(); g++)
 	{
 		MAPITEM_GROUP *group = layers_get_group(g);
 		
+		if(group->version >= 2 && group->use_clipping)
+		{
+			// 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]);
+			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()));
+		}		
+		
 		mapscreen_to_group(center_x, center_y, group);
 		
 		for(int l = 0; l < group->num_layers; l++)
@@ -319,7 +335,9 @@ void render_layers(float center_x, float center_y, int pass)
 				passed_gamelayer = 1;
 			}
 				
-			if(pass == 0)
+			if(pass == -1)
+				render = true;
+			else if(pass == 0)
 			{
 				if(passed_gamelayer)
 					return;
@@ -331,7 +349,7 @@ void render_layers(float center_x, float center_y, int pass)
 					render = true;
 			}
 			
-			if(render)
+			if(render && !is_game_layer)
 			{
 				if(layer->type == LAYERTYPE_TILES)
 				{
@@ -340,8 +358,12 @@ void render_layers(float center_x, float center_y, int pass)
 						gfx_texture_set(-1);
 					else
 						gfx_texture_set(img_get(tmap->image));
+						
 					TILE *tiles = (TILE *)map_get_data(tmap->data);
-					render_tilemap(tiles, tmap->width, tmap->height, 32.0f, vec4(1,1,1,1), 1);
+					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);
 				}
 				else if(layer->type == LAYERTYPE_QUADS)
 				{
@@ -350,11 +372,19 @@ void render_layers(float center_x, float center_y, int pass)
 						gfx_texture_set(-1);
 					else
 						gfx_texture_set(img_get(qlayer->image));
+
 					QUAD *quads = (QUAD *)map_get_data_swapped(qlayer->data);
-					render_quads(quads, qlayer->num_quads, envelope_eval);
+					
+					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);
+						
 				}
 			}
 		}
+		
+		gfx_clip_disable();
 	}
 }
 
@@ -464,10 +494,11 @@ static void render_players()
 
 // renders the complete game world
 void render_world(float center_x, float center_y, float zoom)
-{
+{	
 	// render background layers
 	render_layers(center_x, center_y, 0);
-
+	gfx_clip_disable();
+	
 	// render trails
 	particle_render(PARTGROUP_PROJECTILE_TRAIL);
 
@@ -486,81 +517,8 @@ void render_world(float center_x, float center_y, float zoom)
 
 	// render foreground layers
 	render_layers(center_x, center_y, 1);
+	gfx_clip_disable();
 
 	// render damage indications
 	render_damage_indicators();
-	
-	
-	
-	// render screen sizes	
-	if(false)
-	{
-		gfx_texture_set(-1);
-		gfx_lines_begin();
-		
-		float last_points[4];
-		float start = 1.0f; //9.0f/16.0f;
-		float end = 16.0f/9.0f;
-		const int num_steps = 20;
-		for(int i = 0; i <= num_steps; i++)
-		{
-			float points[4];
-			float aspect = start + (end-start)*(i/(float)num_steps);
-			
-			mapscreen_to_world(
-				center_x, center_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]);
-			}
-
-			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]);
-			}
-
-			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]);
-			}
-			
-			mem_copy(last_points, points, sizeof(points));
-		}
-
-		if(1)
-		{
-			gfx_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(
-					center_x, center_y,
-					1.0f, 1.0f, 0.0f, 0.0f, aspect, 1.0f, points);
-				
-				RECT 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);
-			}
-		}
-			
-		gfx_lines_end();
-	}	
 }
diff --git a/src/game/client/gc_render.h b/src/game/client/gc_render.h
index 53b6510a..b3439e93 100644
--- a/src/game/client/gc_render.h
+++ b/src/game/client/gc_render.h
@@ -29,6 +29,11 @@ enum
 {
 	SPRITE_FLAG_FLIP_Y=1,
 	SPRITE_FLAG_FLIP_X=2,
+	
+	LAYERRENDERFLAG_OPAQUE=1,
+	LAYERRENDERFLAG_TRANSPARENT=2,
+	
+	TILERENDERFLAG_EXTEND=4,
 };
 
 typedef struct sprite;
@@ -66,7 +71,7 @@ void render_player(
 	
 // 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));
+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);
 
 // helpers
diff --git a/src/game/client/gc_render_map.cpp b/src/game/client/gc_render_map.cpp
index 8693ed18..2ad3ad94 100644
--- a/src/game/client/gc_render_map.cpp
+++ b/src/game/client/gc_render_map.cpp
@@ -75,7 +75,7 @@ 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))
+void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, int env, float *channels), int renderflags)
 {
 	gfx_quads_begin();
 	float conv = 1/255.0f;
@@ -83,6 +83,27 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 	{
 		QUAD *q = &quads[i];
 		
+		float r=1, g=1, b=1, a=1;
+
+		if(q->color_env >= 0)
+		{
+			float channels[4];
+			eval(q->color_env_offset/1000.0f, q->color_env, channels);
+			r = channels[0];
+			g = channels[1];
+			b = channels[2];
+			a = channels[3];
+		}		
+		
+		bool opaque = false;
+		if(a < 0.01f || (q->colors[0].a < 0.01f && q->colors[1].a < 0.01f && q->colors[2].a < 0.01f && q->colors[3].a < 0.01f))
+			opaque = true;
+			
+		if(opaque && !(renderflags&LAYERRENDERFLAG_OPAQUE))
+			continue;
+		if(!opaque && !(renderflags&LAYERRENDERFLAG_TRANSPARENT))
+			continue;
+		
 		gfx_quads_setsubset_free(
 			fx2f(q->texcoords[0].x), fx2f(q->texcoords[0].y),
 			fx2f(q->texcoords[1].x), fx2f(q->texcoords[1].y),
@@ -90,7 +111,6 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 			fx2f(q->texcoords[3].x), fx2f(q->texcoords[3].y)
 		);
 
-		float r=1, g=1, b=1, a=1;
 		float offset_x = 0;
 		float offset_y = 0;
 		float rot = 0;
@@ -105,15 +125,6 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 			rot = channels[2]/360.0f*pi*2;
 		}
 		
-		if(q->color_env >= 0)
-		{
-			float channels[4];
-			eval(q->color_env_offset/1000.0f, q->color_env, channels);
-			r = channels[0];
-			g = channels[1];
-			b = channels[2];
-			a = channels[3];
-		}
 		
 		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);
@@ -147,12 +158,12 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in
 	gfx_quads_end();	
 }
 
-
-void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flags)
+void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int renderflags)
 {
-			//gfx_texture_set(img_get(tmap->image));
+	//gfx_texture_set(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);
 
 	// calculate the final pixelsize for the tiles	
 	float tile_pixelsize = 1024/32.0f;
@@ -178,7 +189,7 @@ void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flag
 			int mx = x;
 			int my = y;
 			
-			if(flags)
+			if(renderflags&TILERENDERFLAG_EXTEND)
 			{
 				if(mx<0)
 					mx = 0;
@@ -207,39 +218,55 @@ void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flag
 			if(index)
 			{
 				unsigned char flags = tiles[c].flags;
-				int tx = index%16;
-				int ty = index/16;
-				int px0 = tx*(1024/16);
-				int py0 = ty*(1024/16);
-				int px1 = (tx+1)*(1024/16)-1;
-				int py1 = (ty+1)*(1024/16)-1;
-				
-				float u0 = nudge + px0/texsize+frac;
-				float v0 = nudge + py0/texsize+frac;
-				float u1 = nudge + px1/texsize-frac;
-				float v1 = nudge + py1/texsize-frac;
 				
-				if(flags&TILEFLAG_VFLIP)
+				bool render = false;
+				if(flags&TILEFLAG_OPAQUE)
 				{
-					float tmp = u0;
-					u0 = u1;
-					u1 = tmp;
+					if(renderflags&LAYERRENDERFLAG_OPAQUE)
+						render = true;
 				}
-
-				if(flags&TILEFLAG_HFLIP)
+				else
 				{
-					float tmp = v0;
-					v0 = v1;
-					v1 = tmp;
+					if(renderflags&LAYERRENDERFLAG_TRANSPARENT)
+						render = true;
 				}
 				
-				gfx_quads_setsubset(u0,v0,u1,v1);
+				if(render)
+				{
+					
+					int tx = index%16;
+					int ty = index/16;
+					int px0 = tx*(1024/16);
+					int py0 = ty*(1024/16);
+					int px1 = (tx+1)*(1024/16)-1;
+					int py1 = (ty+1)*(1024/16)-1;
+					
+					float u0 = nudge + px0/texsize+frac;
+					float v0 = nudge + py0/texsize+frac;
+					float u1 = nudge + px1/texsize-frac;
+					float v1 = nudge + py1/texsize-frac;
+					
+					if(flags&TILEFLAG_VFLIP)
+					{
+						float tmp = u0;
+						u0 = u1;
+						u1 = tmp;
+					}
 
-				gfx_quads_drawTL(x*scale, y*scale, scale, scale);
+					if(flags&TILEFLAG_HFLIP)
+					{
+						float tmp = v0;
+						v0 = v1;
+						v1 = tmp;
+					}
+					
+					gfx_quads_setsubset(u0,v0,u1,v1);
+					gfx_quads_drawTL(x*scale, y*scale, scale, scale);
+				}
 			}
-			
 			x += tiles[c].skip;
 		}
 	
 	gfx_quads_end();
+	gfx_mapscreen(screen_x0, screen_y0, screen_x1, screen_y1);
 }
diff --git a/src/game/editor/ed_editor.cpp b/src/game/editor/ed_editor.cpp
index 1e9a0de9..7ae46f0b 100644
--- a/src/game/editor/ed_editor.cpp
+++ b/src/game/editor/ed_editor.cpp
@@ -37,6 +37,12 @@ LAYERGROUP::LAYERGROUP()
 	offset_y = 0;
 	parallax_x = 100;
 	parallax_y = 100;
+	
+	use_clipping = 0;
+	clip_x = 0;
+	clip_y = 0;
+	clip_w = 0;
+	clip_h = 0;
 }
 
 LAYERGROUP::~LAYERGROUP()
@@ -75,6 +81,19 @@ void LAYERGROUP::render()
 {
 	mapscreen();
 	
+	if(use_clipping)
+	{
+		float points[4];
+		editor.map.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()));
+	}
+	
 	for(int i = 0; i < layers.len(); i++)
 	{
 		if(layers[i]->visible && layers[i] != editor.map.game_layer)
@@ -83,6 +102,8 @@ void LAYERGROUP::render()
 				layers[i]->render();
 		}
 	}
+	
+	gfx_clip_disable();
 }
 
 bool LAYERGROUP::is_empty() const { return layers.len() == 0; }
@@ -116,7 +137,37 @@ int LAYERGROUP::swap_layers(int index0, int index1)
 	if(index0 == index1) return index0;
 	swap(layers[index0], layers[index1]);
 	return index1;
-}	
+}
+
+void IMAGE::analyse_tileflags()
+{
+	mem_zero(tileflags, sizeof(tileflags));
+	
+	int tw = width/16; // tilesizes
+	int th = height/16;
+	unsigned char *pixeldata = (unsigned char *)data;
+	
+	int tile_id = 0;
+	for(int ty = 0; ty < 16; ty++)
+		for(int tx = 0; tx < 16; tx++, tile_id++)
+		{
+			bool opaque = true;
+			for(int x = 0; x < tw; x++)
+				for(int y = 0; y < th; y++)
+				{
+					int p = (ty*tw+y)*width + tx*tw+x;
+					if(pixeldata[p*4+3] < 250)
+					{
+						opaque = false;
+						break;
+					}
+				}
+				
+			if(opaque)
+				tileflags[tile_id] |= TILEFLAG_OPAQUE;
+		}
+	
+}
 
 /********************************************************
  OTHER
@@ -777,11 +828,7 @@ static void do_quad_point(QUAD *q, int quad_index, int v)
 
 static void do_map_editor(RECT view, RECT toolbar)
 {
-	// do the toolbar
-	if(editor.gui_active)
-		do_toolbar(toolbar);
-	
-	ui_clip_enable(&view);
+	//ui_clip_enable(&view);
 	
 	bool show_picker = inp_key_pressed(KEY_SPACE) != 0;
 
@@ -792,6 +839,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 		{
 			if(editor.map.groups[g]->visible)
 				editor.map.groups[g]->render();
+			//ui_clip_enable(&view);
 		}
 		
 		// render the game above everything else
@@ -805,7 +853,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 	static void *editor_id = (void *)&editor_id;
 	int inside = ui_mouse_inside(&view);
 
-	// fetch mouse position		
+	// fetch mouse position
 	float wx = ui_mouse_world_x();
 	float wy = ui_mouse_world_y();
 	float mx = ui_mouse_x();
@@ -1084,6 +1132,29 @@ static void do_map_editor(RECT view, RECT toolbar)
 			}
 		}
 	}
+	
+	if(editor.get_selected_group() && editor.get_selected_group()->use_clipping)
+	{
+		LAYERGROUP *g = editor.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;
+			
+			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);
+			
+		gfx_lines_end();
+	}
 
 	// render screen sizes	
 	if(editor.proof_borders)
@@ -1161,7 +1232,7 @@ static void do_map_editor(RECT view, RECT toolbar)
 	}
 	
 	gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
-	ui_clip_disable();
+	//ui_clip_disable();
 }
 
 
@@ -1282,8 +1353,6 @@ static void render_layers(RECT toolbox, RECT toolbar, RECT view)
 {
 	RECT layersbox = toolbox;
 
-	do_map_editor(view, toolbar);
-	
 	if(!editor.gui_active)
 		return;
 			
@@ -1317,7 +1386,7 @@ static void render_layers(RECT toolbox, RECT toolbar, RECT view)
 				
 				static int group_popup_id = 0;
 				if(result == 2)
-					ui_invoke_popup_menu(&group_popup_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 150, popup_group);
+					ui_invoke_popup_menu(&group_popup_id, 0, ui_mouse_x(), ui_mouse_y(), 120, 200, popup_group);
 			}
 			
 			
@@ -2163,12 +2232,27 @@ void EDITOR::render()
 		ui_hsplit_t(&view, 16.0f, &toolbar, &view);
 		ui_hsplit_b(&view, 16.0f, &view, &statusbar);
 
-				
+		if(editor.show_envelope_editor)
+		{
+			float size = 125.0f;
+			if(editor.show_envelope_editor == 2)
+				size *= 2.0f;
+			else if(editor.show_envelope_editor == 3)
+				size *= 3.0f;
+			ui_hsplit_b(&view, size, &view, &envelope_editor);
+		}
+	}
+	
+	//	a little hack for now
+	if(editor.mode == MODE_LAYERS)
+		do_map_editor(view, toolbar);
+	
+	if(editor.gui_active)
+	{
 		float brightness = 0.25f;
-
 		render_background(menubar, background_texture, 128.0f, brightness*0);
 		ui_margin(&menubar, 2.0f, &menubar);
-		
+
 		render_background(toolbox, background_texture, 128.0f, brightness);
 		ui_margin(&toolbox, 2.0f, &toolbox);
 		
@@ -2179,24 +2263,23 @@ void EDITOR::render()
 		render_background(statusbar, background_texture, 128.0f, brightness);
 		ui_margin(&statusbar, 2.0f, &statusbar);
 		
+		// do the toolbar
+		if(editor.mode == MODE_LAYERS)
+			do_toolbar(toolbar);
+		
 		if(editor.show_envelope_editor)
 		{
-			float size = 125.0f;
-			if(editor.show_envelope_editor == 2)
-				size *= 2.0f;
-			else if(editor.show_envelope_editor == 3)
-				size *= 3.0f;
-			ui_hsplit_b(&view, size, &view, &envelope_editor);
 			render_background(envelope_editor, background_texture, 128.0f, brightness);
 			ui_margin(&envelope_editor, 2.0f, &envelope_editor);
 		}
 	}
+		
 	
 	if(editor.mode == MODE_LAYERS)
 		render_layers(toolbox, toolbar, view);
 	else if(editor.mode == MODE_IMAGES)
 		render_images(toolbox, toolbar, view);
-		
+
 	gfx_mapscreen(ui_screen()->x, ui_screen()->y, ui_screen()->w, ui_screen()->h);
 
 	if(editor.gui_active)
diff --git a/src/game/editor/ed_editor.hpp b/src/game/editor/ed_editor.hpp
index e2fda9ef..23dbd382 100644
--- a/src/game/editor/ed_editor.hpp
+++ b/src/game/editor/ed_editor.hpp
@@ -177,6 +177,12 @@ public:
 	int parallax_x;
 	int parallax_y;
 	
+	int use_clipping;
+	int clip_x;
+	int clip_y;
+	int clip_w;
+	int clip_h;
+	
 	const char *name;
 	bool game_group;
 	bool visible;
@@ -230,9 +236,12 @@ public:
 		gfx_unload_texture(tex_id);
 	}
 	
+	void analyse_tileflags();
+	
 	int tex_id;
 	int external;
 	char name[128];
+	unsigned char tileflags[256];
 };
 
 class MAP
@@ -443,6 +452,8 @@ public:
 
 	virtual void modify_image_index(INDEX_MODIFY_FUNC func);
 	virtual void modify_envelope_index(INDEX_MODIFY_FUNC func);
+	
+	void prepare_for_save();
 
 	void get_size(float *w, float *h) { *w = width*32.0f;  *h = height*32.0f; }
 	
diff --git a/src/game/editor/ed_io.cpp b/src/game/editor/ed_io.cpp
index b805b0b5..3fd4fcac 100644
--- a/src/game/editor/ed_io.cpp
+++ b/src/game/editor/ed_io.cpp
@@ -214,6 +214,11 @@ int MAP::save(const char *filename)
 	for(int i = 0; i < images.len(); i++)
 	{
 		IMAGE *img = images[i];
+		
+		// analyse the image for when saving (should be done when we load the image)
+		// TODO!
+		img->analyse_tileflags();
+		
 		MAPITEM_IMAGE item;
 		item.version = 1;
 		
@@ -234,12 +239,17 @@ int MAP::save(const char *filename)
 	{
 		LAYERGROUP *group = groups[g];
 		MAPITEM_GROUP gitem;
-		gitem.version = 1;
+		gitem.version = MAPITEM_GROUP::CURRENT_VERSION;
 		
 		gitem.parallax_x = group->parallax_x;
 		gitem.parallax_y = group->parallax_y;
 		gitem.offset_x = group->offset_x;
 		gitem.offset_y = group->offset_y;
+		gitem.use_clipping = group->use_clipping;
+		gitem.clip_x = group->clip_x;
+		gitem.clip_y = group->clip_y;
+		gitem.clip_w = group->clip_w;
+		gitem.clip_h = group->clip_h;
 		gitem.start_layer = layer_count;
 		gitem.num_layers = 0;
 		
@@ -249,6 +259,8 @@ int MAP::save(const char *filename)
 			{
 				dbg_msg("editor", "saving tiles layer");
 				LAYER_TILES *layer = (LAYER_TILES *)group->layers[l];
+				layer->prepare_for_save();
+				
 				MAPITEM_LAYER_TILEMAP item;
 				item.version = 2;
 				
@@ -432,12 +444,25 @@ int MAP::load(const char *filename)
 			for(int g = 0; g < num; g++)
 			{
 				MAPITEM_GROUP *gitem = (MAPITEM_GROUP *)datafile_get_item(df, start+g, 0, 0);
+				
+				if(gitem->version < 1 || gitem->version > MAPITEM_GROUP::CURRENT_VERSION)
+					continue;
+				
 				LAYERGROUP *group = new_group();
 				group->parallax_x = gitem->parallax_x;
 				group->parallax_y = gitem->parallax_y;
 				group->offset_x = gitem->offset_x;
 				group->offset_y = gitem->offset_y;
 				
+				if(gitem->version >= 2)
+				{
+					group->use_clipping = gitem->use_clipping;
+					group->clip_x = gitem->clip_x;
+					group->clip_y = gitem->clip_y;
+					group->clip_w = gitem->clip_w;
+					group->clip_h = gitem->clip_h;
+				}
+				
 				for(int l = 0; l < gitem->num_layers; l++)
 				{
 					LAYER *layer = 0;
diff --git a/src/game/editor/ed_layer_quads.cpp b/src/game/editor/ed_layer_quads.cpp
index bf203ebb..f3df3818 100644
--- a/src/game/editor/ed_layer_quads.cpp
+++ b/src/game/editor/ed_layer_quads.cpp
@@ -36,7 +36,7 @@ void LAYER_QUADS::render()
 	if(image >= 0 && image < editor.map.images.len())
 		gfx_texture_set(editor.map.images[image]->tex_id);
 		
-	render_quads(quads.getptr(), quads.len(), envelope_eval);
+	render_quads(quads.getptr(), quads.len(), envelope_eval, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT);
 }
 
 QUAD *LAYER_QUADS::new_quad()
diff --git a/src/game/editor/ed_layer_tiles.cpp b/src/game/editor/ed_layer_tiles.cpp
index 555c26a3..18e3b695 100644
--- a/src/game/editor/ed_layer_tiles.cpp
+++ b/src/game/editor/ed_layer_tiles.cpp
@@ -22,6 +22,20 @@ LAYER_TILES::~LAYER_TILES()
 	delete [] tiles;
 }
 
+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 &= TILEFLAG_VFLIP|TILEFLAG_HFLIP;
+
+	if(image != -1)
+	{
+		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];
+	}
+}
+
 void LAYER_TILES::make_palette()
 {
 	for(int y = 0; y < height; y++)
@@ -34,7 +48,7 @@ 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), 0);
+	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); }
diff --git a/src/game/editor/ed_popups.cpp b/src/game/editor/ed_popups.cpp
index bcd26092..813dfd50 100644
--- a/src/game/editor/ed_popups.cpp
+++ b/src/game/editor/ed_popups.cpp
@@ -115,6 +115,11 @@ int popup_group(RECT view)
 		PROP_POS_Y,
 		PROP_PARA_X,
 		PROP_PARA_Y,
+		PROP_USE_CLIPPING,
+		PROP_CLIP_X,
+		PROP_CLIP_Y,
+		PROP_CLIP_W,
+		PROP_CLIP_H,
 		NUM_PROPS,
 	};
 	
@@ -124,6 +129,12 @@ int popup_group(RECT view)
 		{"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},
+
+		{"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},
 		{0},
 	};
 	
@@ -141,14 +152,15 @@ int popup_group(RECT view)
 	// these can not be changed on the game group
 	if(!editor.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;
+		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;
 	}
 	
 	return 0;
diff --git a/src/game/g_layers.cpp b/src/game/g_layers.cpp
index 6614bc90..07ffec4b 100644
--- a/src/game/g_layers.cpp
+++ b/src/game/g_layers.cpp
@@ -12,31 +12,24 @@ static int layers_num = 0;
 void layers_init()
 {
 	map_get_type(MAPITEMTYPE_GROUP, &groups_start, &groups_num);
+	map_get_type(MAPITEMTYPE_LAYER, &layers_start, &layers_num);
 	
+	for(int g = 0; g < layers_num_groups(); g++)
 	{
-		int p = 0;
-		map_get_type(MAPITEMTYPE_LAYER, &layers_start, &layers_num);
-			
-		for(int i = 0; i < layers_num; i++)
+		MAPITEM_GROUP *group = layers_get_group(g);
+		for(int l = 0; l < group->num_layers; l++)
 		{
-			MAPITEM_LAYER *layer = (MAPITEM_LAYER *)map_get_item(layers_start+i, 0, 0);
+			MAPITEM_LAYER *layer = layers_get_layer(group->start_layer+l);
+			
 			if(layer->type == LAYERTYPE_TILES)
 			{
 				MAPITEM_LAYER_TILEMAP *tilemap = (MAPITEM_LAYER_TILEMAP *)layer;
-				
-				if(p)
-				{
-					p--;
-					if(p == 0)
-						tilemap->flags |= 2;
-				}
-				
 				if(tilemap->flags&1)
 				{
 					game_layer = tilemap;
-					p = 2;
+					game_group = group;
 				}
-			}
+			}			
 		}
 	}
 }
diff --git a/src/game/g_mapitems.h b/src/game/g_mapitems.h
index 3caa5303..8093435a 100644
--- a/src/game/g_mapitems.h
+++ b/src/game/g_mapitems.h
@@ -47,6 +47,7 @@ enum
 	
 	TILEFLAG_VFLIP=1,
 	TILEFLAG_HFLIP=2,
+	TILEFLAG_OPAQUE=4,
 	
 	LAYERFLAG_DETAIL=1,
 	
@@ -81,7 +82,7 @@ typedef struct
 	unsigned char index;
 	unsigned char flags;
 	unsigned char skip;
-	unsigned char reserved2;
+	unsigned char reserved;
 } TILE;
 
 typedef struct 
@@ -94,7 +95,7 @@ typedef struct
 	int image_data;
 } MAPITEM_IMAGE;
 
-typedef struct
+struct MAPITEM_GROUP_v1
 {
 	int version;
 	int offset_x;
@@ -104,7 +105,19 @@ typedef struct
 
 	int start_layer;
 	int num_layers;
-} MAPITEM_GROUP;
+} ;
+
+
+struct MAPITEM_GROUP : public MAPITEM_GROUP_v1
+{
+	enum { CURRENT_VERSION=2 };
+	
+	int use_clipping;
+	int clip_x;
+	int clip_y;
+	int clip_w;
+	int clip_h;
+} ;
 
 typedef struct
 {