From 8f996cd439b42f834c3263f518d73c4a3e630929 Mon Sep 17 00:00:00 2001
From: Stijn Buys <ingar@osirion.org>
Date: Sat, 10 Jan 2015 23:30:34 +0000
Subject: Use a draw list for entities and globes.

---
 src/render/draw.cc | 160 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 109 insertions(+), 51 deletions(-)

diff --git a/src/render/draw.cc b/src/render/draw.cc
index 47fcb40..5fcc740 100644
--- a/src/render/draw.cc
+++ b/src/render/draw.cc
@@ -57,8 +57,39 @@ core::Zone *zone = 0;
 bool draw_particles = true;
 bool draw_lights = true;
 
-typedef std::map<float, core::EntityGlobe *> Globes;
-Globes globes_list;
+typedef std::list<core::Entity *> DrawlistEntities;
+typedef std::list<core::EntityGlobe *> DrawlistGlobes;
+
+DrawlistEntities	drawlist_entities;
+DrawlistGlobes		drawlist_globes;
+
+bool compare_globe_distance(const core::EntityGlobe * globefirst, const core::EntityGlobe * globesecond)
+{
+	const float d1 = ext_render(globefirst)->distance();
+	const float d2 = ext_render(globesecond)->distance();
+	if (d1 < d2)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+bool compare_entity_distance(const core::Entity * entityfirst, const core::Entity * entitysecond)
+{
+	const float d1 = ext_render(entityfirst)->distance();
+	const float d2 = ext_render(entitysecond)->distance();
+	if (d1 < d2)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
 
 LightEnvironment lightenv_zone;
 
@@ -82,9 +113,6 @@ void pass_prepare(float seconds)
 	// initialize lights
 	lightenv_zone.clear();
 
-	// clear current list of globes
-	globes_list.clear();
-
 	// zone ambient light
 	GLfloat zone_ambient[4];
 	for (size_t i = 0; i < 3; i++) {
@@ -93,40 +121,63 @@ void pass_prepare(float seconds)
 	zone_ambient[3] = 1.0f;
 	gl::lightmodel(GL_LIGHT_MODEL_AMBIENT, zone_ambient);
 
-	// zone light sources
-	for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+	// initialize draw lists
+	drawlist_entities.clear();
+	drawlist_globes.clear();
+	
+	for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); ++it)
+	{
 		core::Entity *entity = (*it);
+		
+		if (entity->visible() && !entity->serverside())
+		{
+			// add render extension if required
+			if (!ext_render(entity)) {
+				new RenderExt(entity);
+			}
+			entity->extension((size_t) core::Extension::Render)->frame(seconds);
 
-		if (!ext_render(entity)) {
-			new RenderExt(entity);
-		}
-		entity->extension((size_t) core::Extension::Render)->frame(seconds);
+			if (entity->type() == core::Entity::Globe)
+			{
+				core::EntityGlobe *globe = static_cast<core::EntityGlobe *>(entity);
 
-		// globes
-		if (entity->type() == core::Entity::Globe) {
-			core::EntityGlobe *globe = static_cast<core::EntityGlobe *>(entity);
+				// add the globe to the draw list
+				if (globe->visible() && !ext_render(globe)->behind())
+				{
+					drawlist_globes.push_back(globe);
+				}
 
-			// add the globe to the globes list
-			if (globe->visible() && !ext_render(globe)->behind()) {
-				globes_list[ext_render(globe)->distance()] = globe;
-			}
+				// add zone lights to the light environment
+				if (globe->has_flag(core::Entity::Bright))
+				{
+					float zone_light_brightness = math::max(globe->color().r, math::max(globe->color().g, globe->color().b));
+					Light *zone_light = new Light(globe->location(), globe->color());
+					zone_light->set_attenuation(zone_light_brightness * 1.5f, zone_light_brightness * 0.00001f, zone_light_brightness * 0.000000001f);
+					lightenv_zone.add(zone_light);
+				}
 
-			// add zone lights
-			if (globe->has_flag(core::Entity::Bright)) {
-				float zone_light_brightness = math::max(globe->color().r, math::max(globe->color().g, globe->color().b));
-				Light *zone_light = new Light(globe->location(), globe->color());
-				zone_light->set_attenuation(zone_light_brightness * 1.5f, zone_light_brightness * 0.00001f, zone_light_brightness * 0.000000001f);
-				lightenv_zone.add(zone_light);
 			}
-
-		} else {
-			// this reloads entity models if required by r_restart
-			if (!entity->model() && entity->modelname().size()) {
-				entity->set_model(model::Model::load(entity->modelname()));
+			else
+			{
+				// add entity to draw lists
+				if (entity->visible() || !ext_render(entity)->behind())
+				{
+					drawlist_entities.push_back(entity);
+				}
+				
+				//  loads entity models if required
+				if (!entity->model() && entity->modelname().size()) {
+					
+					entity->set_model(model::Model::load(entity->modelname()));
+				}
 			}
 		}
 	}
 	
+	// sort draw lists by distance
+	drawlist_entities.sort(compare_entity_distance);
+	drawlist_globes.sort(compare_globe_distance);
+	
 	// zone lights are draw in world space coordinates
 	lightenv_zone.draw();
 	lightenv_zone.enable();
@@ -366,8 +417,9 @@ void draw_pass_globes()
 
 	// Globes have to be rendered distance sorted, closest last.
 	// Globes behind farplane are rescaled and repositioned.
-	for (Globes::reverse_iterator rit = globes_list.rbegin(); rit != globes_list.rend(); rit++) {
-		const core::EntityGlobe *globe = (*rit).second;
+	for (DrawlistGlobes::const_iterator it = drawlist_globes.begin(); it != drawlist_globes.end(); ++it)
+	{
+		const core::EntityGlobe *globe = (*it);
 		
 		math::Vector3f location(globe->location());	
 		float radius = globe->radius();
@@ -590,20 +642,22 @@ void draw_entity_axis(const core::Entity* entity)
 
 void draw_pass_default()
 {
-	for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); ++it) {
-
-		core::Entity *entity = (*it);
-		if (!entity->model() && (entity->type() != core::Entity::Globe) && !entity->serverside() && !ext_render(entity)->behind()) {
-
+	for (DrawlistEntities::const_iterator it = drawlist_entities.begin(); it != drawlist_entities.end(); ++it)
+	{
+		const core::Entity *entity = (*it);
+		if (!entity->model() && ext_render(entity)->visible())
+		{
 			gl::push();
 			gl::translate(entity->location());
 			gl::multmatrix(entity->axis());
 
-			if (entity->has_flag(core::Entity::Bright)) {
+			if (entity->has_flag(core::Entity::Bright))
+			{
 				gl::disable(GL_LIGHTING);
 			}
 
-			switch (entity->shape()) {
+			switch (entity->shape())
+			{
 				case core::Entity::Sphere:
 					draw_entity_sphere(entity);
 					break;
@@ -623,7 +677,8 @@ void draw_pass_default()
 					break;
 			}
 
-			if (entity->has_flag(core::Entity::Bright)) {
+			if (entity->has_flag(core::Entity::Bright))
+			{
 				gl::enable(GL_LIGHTING);
 			}
 
@@ -710,8 +765,8 @@ void draw_model_fragments(model::Model *model,
 	State::set_color_engine(model->enginecolor() * thrust);
 	State::set_power(power);
 			
-	for (model::Model::Groups::const_iterator git = model->groups().begin(); git != model->groups().end(); git++) {
-
+	for (model::Model::Groups::const_iterator git = model->groups().begin(); git != model->groups().end(); git++)
+	{
 		const model::FragmentGroup *group = (*git);
 		gl::push();
 
@@ -733,17 +788,20 @@ void draw_model_fragments(model::Model *model,
 			gl::translate(translation);
 		}
 
-		for (model::FragmentGroup::Fragments::const_iterator fit = group->fragments().begin(); fit != group->fragments().end(); fit++) {
+		for (model::FragmentGroup::Fragments::const_iterator fit = group->fragments().begin(); fit != group->fragments().end(); fit++)
+		{
 
 			const model::Fragment *fragment = (*fit);
 			
-			for (model::Material::Layers::const_iterator lit = fragment->material()->layers().begin(); lit != fragment->material()->layers().end(); ++lit) {
+			for (model::Material::Layers::const_iterator lit = fragment->material()->layers().begin(); lit != fragment->material()->layers().end(); ++lit)
+			{
 				State::use_material_layer(fragment->material(), (*lit));
 				draw_fragment(fragment, detail);
 				State::reset();
 			}
 			
-			if (r_normals->value()) {
+			if (r_normals->value())
+			{
 				// force reset of material settings for the next fragment
 				State::reset();
 				gl::color(0.75f, 0.0f, 0.0f);
@@ -804,10 +862,11 @@ void draw_pass_model_fragments()
 	 * 	to sync core and render movement of fragmentgroups without sacrificing
 	 * 	the functionality of the FragmentGroup::engine() flag. 
 	 */
-	for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+	for (DrawlistEntities::iterator it = drawlist_entities.begin(); it != drawlist_entities.end(); ++it)
+	{
 		core::Entity *entity = (*it);
 
-		if (entity->model() && ext_render(entity)->visible() && !ext_render(entity)->behind()) {
+		if (entity->model() && ext_render(entity)->visible()) {
 			gl::push();
 			gl::translate(entity->location());
 			gl::multmatrix(entity->axis());
@@ -1087,7 +1146,8 @@ void draw_pass_model_fx(float elapsed)
 	// enable texturing
 	gl::enable(GL_TEXTURE_2D);
 
-	for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+	for (DrawlistEntities::iterator it = drawlist_entities.begin(); it != drawlist_entities.end(); ++it)
+	{
 		core::Entity *entity = (*it);
 	
 		if (entity->model() && ext_render(entity)->detailvisible()) {
@@ -1123,7 +1183,8 @@ void draw_pass_model_fx(float elapsed)
 
 void draw_pass_model_radius()
 {
-	for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) {
+	for (DrawlistEntities::iterator it = drawlist_entities.begin(); it != drawlist_entities.end(); ++it)
+	{
 		core::Entity *entity = (*it);
 
 		if (entity->model() && ext_render(entity)->visible()) {
@@ -1320,9 +1381,6 @@ void draw(float seconds)
 	// clear current zone light environment
 	lightenv_zone.disable();
 	lightenv_zone.clear();
-
-	// clear current list of globes
-	globes_list.clear();
 }
 
 
-- 
cgit v1.2.3