← Back to team overview

widelands-dev team mailing list archive

Re: [Merge] lp:~widelands-dev/widelands/texture_atlas into lp:widelands

 

Review: Resubmit

Addressed all comments and merged trunk.

Diff comments:

> === modified file 'src/editor/editorinteractive.cc'
> --- src/editor/editorinteractive.cc	2014-11-23 14:34:38 +0000
> +++ src/editor/editorinteractive.cc	2014-11-28 07:21:07 +0000
> @@ -243,8 +243,6 @@
>  	frametime = m_realtime - lasttime;
>  
>  	egbase().get_gametime_pointer() += frametime;
> -
> -	g_gr->animate_maptextures(egbase().get_gametime());
>  }
>  
>  
> 
> === modified file 'src/editor/tools/editor_info_tool.cc'
> --- src/editor/tools/editor_info_tool.cc	2014-10-13 10:48:33 +0000
> +++ src/editor/tools/editor_info_tool.cc	2014-11-28 07:21:07 +0000
> @@ -99,7 +99,6 @@
>  	   center.triangle.t == Widelands::TCoords<>::D ? tf.terrain_d() : tf.terrain_r());
>  
>  	buf += "• " + (boost::format(_("Name: %s")) % ter.descname()).str() + "\n";
> -	buf += "• " + (boost::format(_("Texture Number: %i")) % ter.get_texture()).str() + "\n";
>  
>  	// *** Resources info
>  	buf += std::string("\n") + _("Resources:") + "\n";
> 
> === modified file 'src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc'
> --- src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc	2014-11-24 07:25:21 +0000
> +++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc	2014-11-28 07:21:07 +0000
> @@ -30,7 +30,6 @@
>  #include "graphic/graphic.h"
>  #include "graphic/in_memory_image.h"
>  #include "graphic/rendertarget.h"
> -#include "graphic/terrain_texture.h"
>  #include "graphic/texture.h"
>  #include "logic/map.h"
>  #include "logic/world/editor_category.h"
> @@ -75,11 +74,12 @@
>  		if (ter_is != check[checkfor])
>  			continue;
>  
> -		const Image* tex = g_gr->images().get(
> -		   g_gr->get_maptexture_data(terrain_descr.get_texture())->get_texture_image());
> -		Texture* texture = new Texture(tex->width(), tex->height());
> -		texture->blit(Point(0, 0), tex->texture(), Rect(0, 0, tex->width(), tex->height()), BlendMode::Copy);
> -		Point pt(1, tex->height() - kSmallPicHeight - 1);
> +		const Texture& terrain_texture = terrain_descr.get_texture(0);
> +		Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
> +		texture->blit(Point(0, 0),
> +		              &terrain_texture,
> +		              Rect(0, 0, terrain_texture.width(), terrain_texture.height()));
> +		Point pt(1, terrain_texture.height() - kSmallPicHeight - 1);
>  
>  		if (ter_is == TerrainDescription::GREEN) {
>  			texture->blit(pt, green->texture(), Rect(0, 0, green->width(), green->height()));
> 
> === modified file 'src/graphic/CMakeLists.txt'
> --- src/graphic/CMakeLists.txt	2014-11-24 07:25:21 +0000
> +++ src/graphic/CMakeLists.txt	2014-11-28 07:21:07 +0000
> @@ -28,7 +28,6 @@
>      image_cache.cc
>      image_cache.h
>    USES_SDL2
> -  USES_SDL2_IMAGE
>    DEPENDS
>      base_log
>      base_macros
> @@ -68,6 +67,16 @@
>      graphic_sdl_utils
>  )
>  
> +wl_library(graphic_texture_atlas
> +  SRCS
> +    texture_atlas.h
> +    texture_atlas.cc
> +  DEPENDS
> +    base_exceptions
> +    base_macros
> +    graphic_surface
> +)
> +
>  wl_library(graphic
>    SRCS
>      align.cc
> @@ -116,8 +125,6 @@
>      rendertarget.h
>      richtext.cc
>      richtext.h
> -    terrain_texture.cc
> -    terrain_texture.h
>      text_parser.cc
>      text_parser.h
>      wordwrap.cc
> @@ -125,7 +132,6 @@
>    USES_OPENGL
>    USES_SDL2
>    USES_SDL2_GFX
> -  USES_SDL2_IMAGE
>    USES_SDL2_TTF
>    DEPENDS
>      base_deprecated
> @@ -150,7 +156,6 @@
>      profile
>      scripting
>      sound
> -    ui_basic
>      wui
>      wui_text_layout
>  )
> 
> === modified file 'src/graphic/gl/dither_program.cc'
> --- src/graphic/gl/dither_program.cc	2014-11-24 07:10:03 +0000
> +++ src/graphic/gl/dither_program.cc	2014-11-28 07:21:07 +0000
> @@ -21,35 +21,33 @@
>  
>  #include "base/wexception.h"
>  #include "graphic/gl/fields_to_draw.h"
> -#include "graphic/graphic.h"
>  #include "graphic/image_io.h"
> -#include "graphic/terrain_texture.h"
>  #include "graphic/texture.h"
> -#include "io/fileread.h"
>  #include "io/filesystem/layered_filesystem.h"
>  
>  namespace  {
>  
> -using namespace Widelands;
> -
>  const char kDitherVertexShader[] = R"(
>  #version 120
>  
>  // Attributes.
>  attribute float attr_brightness;
> +attribute vec2 attr_dither_texture_position;
>  attribute vec2 attr_position;
> +attribute vec2 attr_texture_offset;
>  attribute vec2 attr_texture_position;
> -attribute vec2 attr_dither_texture_position;
>  
>  // Output of vertex shader.
> +varying float var_brightness;
> +varying vec2 var_dither_texture_position;
> +varying vec2 var_texture_offset;
>  varying vec2 var_texture_position;
> -varying vec2 var_dither_texture_position;
> -varying float var_brightness;
>  
>  void main() {
> +	var_brightness = attr_brightness;
> +	var_dither_texture_position = attr_dither_texture_position;
> +	var_texture_offset = attr_texture_offset;
>  	var_texture_position = attr_texture_position;
> -	var_dither_texture_position = attr_dither_texture_position;
> -	var_brightness = attr_brightness;
>  	gl_Position = vec4(attr_position, 0., 1.);
>  }
>  )";
> @@ -59,52 +57,62 @@
>  
>  uniform sampler2D u_dither_texture;
>  uniform sampler2D u_terrain_texture;
> +uniform vec2 u_texture_dimensions;
>  
>  varying float var_brightness;
> +varying vec2 var_dither_texture_position;
>  varying vec2 var_texture_position;
> -varying vec2 var_dither_texture_position;
> +varying vec2 var_texture_offset;
>  
>  void main() {
> -	vec4 clr = texture2D(u_terrain_texture, var_texture_position);
> +	vec4 clr = texture2D(u_terrain_texture,
> +			var_texture_offset + u_texture_dimensions * fract(var_texture_position));
>  	clr.rgb *= var_brightness;
>  	clr.a = 1. - texture2D(u_dither_texture, var_dither_texture_position).a;
>  	gl_FragColor = clr;
>  }
>  )";
>  
> -
>  }  // namespace
>  
>  DitherProgram::DitherProgram() {
>  	gl_program_.build(kDitherVertexShader, kDitherFragmentShader);
>  
>  	attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
> -	attr_dither_texture_position_ =
> -	   glGetAttribLocation(gl_program_.object(), "attr_dither_texture_position");
> +	attr_dither_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_dither_texture_position");
>  	attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
> -	attr_texture_position_ =
> -	   glGetAttribLocation(gl_program_.object(), "attr_texture_position");
> +	attr_texture_offset_ = glGetAttribLocation(gl_program_.object(), "attr_texture_offset");
> +	attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
>  
>  	u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");
>  	u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
> -
> -	SDL_Surface* sdlsurf = load_image_as_sdl_surface("world/pics/edge.png", g_fs);
> -	dither_mask_.reset(new Texture(sdlsurf, true));
> +	u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
> +
> +	dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));
> +
> +	glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
> +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
> +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
> +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
> +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
> +	glBindTexture(GL_TEXTURE_2D, 0);
>  }
>  
>  DitherProgram::~DitherProgram() {}
>  
>  void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
>                                 const int order_index,
> -                               const int terrain) {
> -	vertices_[terrain].emplace_back();
> -	PerVertexData& back = vertices_[terrain].back();
> +                               const FloatPoint& texture_offset) {
> +	vertices_.emplace_back();
> +	PerVertexData& back = vertices_.back();
>  
>  	back.gl_x = field.gl_x;
>  	back.gl_y = field.gl_y;
>  	back.texture_x = field.texture_x;
>  	back.texture_y = field.texture_y;
>  	back.brightness = field.brightness;
> +	back.texture_offset_x = texture_offset.x;
> +	back.texture_offset_y = texture_offset.y;
>  
>  	switch (order_index) {
>  	case 0:
> @@ -125,6 +133,7 @@
>  }
>  
>  void DitherProgram::maybe_add_dithering_triangle(
> +   const uint32_t gametime,
>     const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
>     const FieldsToDraw& fields_to_draw,
>     const int idx1,
> @@ -135,29 +144,82 @@
>  	if (my_terrain == other_terrain) {
>  		return;
>  	}
> +	const Widelands::TerrainDescription& other_terrain_description =
> +	   terrains.get_unmutable(other_terrain);
>  	if (terrains.get_unmutable(my_terrain).dither_layer() <
> -	    terrains.get_unmutable(other_terrain).dither_layer()) {
> -		add_vertex(fields_to_draw.at(idx1), 0, other_terrain);
> -		add_vertex(fields_to_draw.at(idx2), 1, other_terrain);
> -		add_vertex(fields_to_draw.at(idx3), 2, other_terrain);
> +	    other_terrain_description.dither_layer()) {
> +		const FloatPoint texture_offset =
> +		   other_terrain_description.get_texture(gametime).texture_coordinates().top_left();
> +		add_vertex(fields_to_draw.at(idx1), 0, texture_offset);
> +		add_vertex(fields_to_draw.at(idx2), 1, texture_offset);
> +		add_vertex(fields_to_draw.at(idx3), 2, texture_offset);
>  	}
>  }
>  
> -void DitherProgram::draw(const DescriptionMaintainer<TerrainDescription>& terrains,
> -                         const FieldsToDraw& fields_to_draw) {
> +void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
>  	glUseProgram(gl_program_.object());
>  
>  	glEnableVertexAttribArray(attr_brightness_);
>  	glEnableVertexAttribArray(attr_dither_texture_position_);
>  	glEnableVertexAttribArray(attr_position_);
> +	glEnableVertexAttribArray(attr_texture_offset_);
>  	glEnableVertexAttribArray(attr_texture_position_);
>  
> -	if (vertices_.size() != terrains.size()) {
> -		vertices_.resize(terrains.size());
> -	}
> -	for (auto& container : vertices_) {
> -		container.clear();
> -	}
> +	glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> +	glBufferData(GL_ARRAY_BUFFER,
> +	             sizeof(PerVertexData) * vertices_.size(),
> +	             vertices_.data(),
> +	             GL_STREAM_DRAW);
> +
> +	const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
> +		glVertexAttribPointer(vertex_index,
> +		                      num_items,
> +		                      GL_FLOAT,
> +		                      GL_FALSE,
> +		                      sizeof(PerVertexData),
> +		                      reinterpret_cast<void*>(offset));
> +	};
> +	set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
> +	set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
> +	set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
> +	set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
> +	set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
> +
> +	glBindBuffer(GL_ARRAY_BUFFER, 0);
> +
> +	// Set the sampler texture unit to 0
> +	glActiveTexture(GL_TEXTURE0);
> +	glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
> +
> +	glActiveTexture(GL_TEXTURE1);
> +	glBindTexture(GL_TEXTURE_2D, gl_texture);
> +
> +	glUniform1i(u_dither_texture_, 0);
> +	glUniform1i(u_terrain_texture_, 1);
> +	glUniform2f(u_texture_dimensions_, texture_w, texture_h);
> +
> +	glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
> +
> +	glBindTexture(GL_TEXTURE_2D, 0);
> +	glActiveTexture(GL_TEXTURE0);
> +	glBindTexture(GL_TEXTURE_2D, 0);
> +
> +	glDisableVertexAttribArray(attr_brightness_);
> +	glDisableVertexAttribArray(attr_dither_texture_position_);
> +	glDisableVertexAttribArray(attr_position_);
> +	glDisableVertexAttribArray(attr_texture_offset_);
> +	glDisableVertexAttribArray(attr_texture_position_);
> +}
> +
> +void DitherProgram::draw(const uint32_t gametime,
> +                         const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> +                         const FieldsToDraw& fields_to_draw) {
> +	// This method expects that all terrains have the same dimensions and that
> +	// all are packed into the same texture atlas, i.e. all are in the same GL
> +	// texture. It does not check for this invariance for speeds sake.
> +
> +	vertices_.clear();
> +	vertices_.reserve(fields_to_draw.size() * 3);
>  
>  	for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
>  		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
> @@ -174,17 +236,17 @@
>  		const int bln_index =
>  		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
>  		if (bln_index != -1) {
> -			maybe_add_dithering_triangle(terrains, fields_to_draw,
> +			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
>  			   brn_index, current_index, bln_index, field.ter_d, field.ter_r);
>  
>  			const int terrain_dd = fields_to_draw.at(bln_index).ter_r;
> -			maybe_add_dithering_triangle(terrains, fields_to_draw,
> +			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
>  			   bln_index, brn_index, current_index, field.ter_d, terrain_dd);
>  
>  			const int ln_index = fields_to_draw.calculate_index(field.fx - 1, field.fy);
>  			if (ln_index != -1) {
>  				const int terrain_l = fields_to_draw.at(ln_index).ter_r;
> -				maybe_add_dithering_triangle(terrains, fields_to_draw,
> +				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
>  				   current_index, bln_index, brn_index, field.ter_d, terrain_l);
>  			}
>  		}
> @@ -192,70 +254,22 @@
>  		// Dithering for right triangle.
>  		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
>  		if (rn_index != -1) {
> -			maybe_add_dithering_triangle(terrains, fields_to_draw,
> +			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
>  			   current_index, brn_index, rn_index, field.ter_r, field.ter_d);
>  			int terrain_rr = fields_to_draw.at(rn_index).ter_d;
> -			maybe_add_dithering_triangle(terrains, fields_to_draw,
> -			   brn_index, rn_index, current_index, field.ter_r, terrain_rr);
> +			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
> +					brn_index, rn_index, current_index, field.ter_r, terrain_rr);
>  
>  			const int trn_index =
> -			   fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
> +				fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
>  			if (trn_index != -1) {
>  				const int terrain_u = fields_to_draw.at(trn_index).ter_d;
> -				maybe_add_dithering_triangle(terrains, fields_to_draw,
> +				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
>  				   rn_index, current_index, brn_index, field.ter_r, terrain_u);
>  			}
>  		}
>  	}
>  
> -	// Set the sampler texture unit to 0
> -	glActiveTexture(GL_TEXTURE0);
> -	glUniform1i(u_dither_texture_, 0);
> -	glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
> -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
> -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
> -
> -	glActiveTexture(GL_TEXTURE1);
> -	glUniform1i(u_terrain_texture_, 1);
> -
> -	// Which triangles to draw?
> -	glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> -	for (size_t i = 0; i < vertices_.size(); ++i) {
> -		const auto& current_data = vertices_[i];
> -		if (current_data.empty()) {
> -			continue;
> -		}
> -		glBindTexture(GL_TEXTURE_2D,
> -		              g_gr->get_maptexture_data(terrains.get_unmutable(i).get_texture())
> -		                 ->texture()
> -		                 .get_gl_texture());
> -
> -		glBufferData(GL_ARRAY_BUFFER,
> -		             sizeof(PerVertexData) * current_data.size(),
> -		             current_data.data(),
> -		             GL_STREAM_DRAW);
> -
> -		const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
> -			glVertexAttribPointer(vertex_index,
> -			                      num_items,
> -			                      GL_FLOAT,
> -			                      GL_FALSE,
> -			                      sizeof(PerVertexData),
> -			                      reinterpret_cast<void*>(offset));
> -		};
> -		set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
> -		set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
> -		set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
> -		set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
> -
> -		glDrawArrays(GL_TRIANGLES, 0, current_data.size());
> -	}
> -	glBindBuffer(GL_ARRAY_BUFFER, 0);
> -
> -	glDisableVertexAttribArray(attr_brightness_);
> -	glDisableVertexAttribArray(attr_dither_texture_position_);
> -	glDisableVertexAttribArray(attr_position_);
> -	glDisableVertexAttribArray(attr_texture_position_);
> -
> -	glActiveTexture(GL_TEXTURE0);
> +	const Texture& texture = terrains.get_unmutable(0).get_texture(0);
> +	gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
>  }
> 
> === modified file 'src/graphic/gl/dither_program.h'
> --- src/graphic/gl/dither_program.h	2014-11-24 07:10:03 +0000
> +++ src/graphic/gl/dither_program.h	2014-11-28 07:21:07 +0000
> @@ -22,6 +22,7 @@
>  
>  #include <memory>
>  
> +#include "base/point.h"
>  #include "graphic/gl/fields_to_draw.h"
>  #include "graphic/gl/utils.h"
>  #include "logic/description_maintainer.h"
> @@ -35,14 +36,16 @@
>  	~DitherProgram();
>  
>  	// Draws the terrain.
> -	void draw(const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> +	void draw(uint32_t gametime,
> +	          const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
>  	          const FieldsToDraw& fields_to_draw);
>  
>  private:
> -	// Adds the triangle between the indexes (which index 'fields_to_draw' to
> +	// Adds the triangle between the indexes (which index 'fields_to_draw') to
>  	// vertices_ if the my_terrain != other_terrain and the dither_layer()
>  	// agree.
>  	void maybe_add_dithering_triangle(
> +	   uint32_t gametime,
>  	   const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
>  	   const FieldsToDraw& fields_to_draw,
>  	   int idx1,
> @@ -51,10 +54,10 @@
>  	   int my_terrain,
>  	   int other_terrain);
>  
> -	// Adds the 'field' as an vertex to the 'vertices_' entry for 'terrain'. The
> -	// 'order_index' defines which texture position will be used for this
> -	// vertcx.
> -	void add_vertex(const FieldsToDraw::Field& field, int order_index, int terrain);
> +	// Adds the 'field' as an vertex to the 'vertices_'. The 'order_index'
> +	// defines which texture position in the dithering texture will be used for
> +	// this vertex.
> +	void add_vertex(const FieldsToDraw::Field& field, int order_index, const FloatPoint& texture_offset);
>  
>  	struct PerVertexData {
>  		float gl_x;
> @@ -64,8 +67,13 @@
>  		float brightness;
>  		float dither_texture_x;
>  		float dither_texture_y;
> +		float texture_offset_x;
> +		float texture_offset_y;
>  	};
>  
> +	// Call through to GL.
> +	void gl_draw(int gl_texture, float texture_w, float texture_h);
> +
>  	// The program used for drawing the terrain.
>  	Gl::Program gl_program_;
>  
> @@ -73,22 +81,23 @@
>  	Gl::Buffer gl_array_buffer_;
>  
>  	// Attributes.
> +	GLint attr_brightness_;
> +	GLint attr_dither_texture_position_;
>  	GLint attr_position_;
> +	GLint attr_texture_offset_;
>  	GLint attr_texture_position_;
> -	GLint attr_dither_texture_position_;
> -	GLint attr_brightness_;
>  
>  	// Uniforms.
> +	GLint u_dither_texture_;
>  	GLint u_terrain_texture_;
> -	GLint u_dither_texture_;
> +	GLint u_texture_dimensions_;
>  
>  	// The texture mask for the dithering step.
>  	std::unique_ptr<Texture> dither_mask_;
>  
>  	// Objects below are here to avoid memory allocations on each frame, they
> -	// could theoretically also always be recreated. Index as follows:
> -	// vertices_[terrain_index][vertex_index]
> -	std::vector<std::vector<PerVertexData>> vertices_;
> +	// could theoretically also always be recreated.
> +	std::vector<PerVertexData> vertices_;
>  };
>  
>  #endif  // end of include guard: WL_GRAPHIC_GL_DITHER_PROGRAM_H
> 
> === modified file 'src/graphic/gl/game_renderer.cc'
> --- src/graphic/gl/game_renderer.cc	2014-11-24 06:21:16 +0000
> +++ src/graphic/gl/game_renderer.cc	2014-11-28 07:21:07 +0000
> @@ -28,7 +28,6 @@
>  #include "graphic/graphic.h"
>  #include "graphic/rendertarget.h"
>  #include "graphic/surface.h"
> -#include "graphic/terrain_texture.h"
>  #include "logic/editor_game_base.h"
>  #include "logic/player.h"
>  #include "logic/world/world.h"
> @@ -165,8 +164,8 @@
>  			map.normalize_coords(coords);
>  			const FCoords& fcoords = map.get_fcoords(coords);
>  
> -			f.texture_x = float(x) / kTextureWidth;
> -			f.texture_y = float(y) / kTextureHeight;
> +			f.texture_x = float(x) / kTextureSideLength;
> +			f.texture_y = float(y) / kTextureSideLength;
>  
>  			f.gl_x = f.pixel_x = x + surface_offset.x;
>  			f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;
> @@ -182,8 +181,8 @@
>  	}
>  
>  	const World& world = m_egbase->world();
> -	terrain_program_->draw(world.terrains(), fields_to_draw);
> -	dither_program_->draw(world.terrains(), fields_to_draw);
> +	terrain_program_->draw(gametime, world.terrains(), fields_to_draw);
> +	dither_program_->draw(gametime, world.terrains(), fields_to_draw);
>  	road_program_->draw(*surface, fields_to_draw);
>  
>  	draw_objects();
> 
> === modified file 'src/graphic/gl/terrain_program.cc'
> --- src/graphic/gl/terrain_program.cc	2014-11-24 07:10:03 +0000
> +++ src/graphic/gl/terrain_program.cc	2014-11-28 07:21:07 +0000
> @@ -20,8 +20,6 @@
>  #include "graphic/gl/terrain_program.h"
>  
>  #include "graphic/gl/fields_to_draw.h"
> -#include "graphic/graphic.h"
> -#include "graphic/terrain_texture.h"
>  #include "graphic/texture.h"
>  
>  namespace  {
> @@ -37,17 +35,20 @@
>  #version 120
>  
>  // Attributes.
> +attribute float attr_brightness;
>  attribute vec2 attr_position;
> -attribute float attr_brightness;
> +attribute vec2 attr_texture_offset;
>  attribute vec2 attr_texture_position;
>  
>  // Output of vertex shader.
>  varying float var_brightness;
> +varying vec2 var_texture_offset;
>  varying vec2 var_texture_position;
>  
>  void main() {
>  	var_texture_position = attr_texture_position;
>  	var_brightness = attr_brightness;
> +	var_texture_offset = attr_texture_offset;
>  	gl_Position = vec4(attr_position, 0., 1.);
>  }
>  )";
> @@ -56,12 +57,15 @@
>  #version 120
>  
>  uniform sampler2D u_terrain_texture;
> +uniform vec2 u_texture_dimensions;
>  
>  varying float var_brightness;
>  varying vec2 var_texture_position;
> +varying vec2 var_texture_offset;
>  
>  void main() {
> -	vec4 clr = texture2D(u_terrain_texture, var_texture_position);
> +	vec4 clr = texture2D(u_terrain_texture,
> +			var_texture_offset + u_texture_dimensions * fract(var_texture_position));
>  	clr.rgb *= var_brightness;
>  	gl_FragColor = clr;
>  }
> @@ -72,25 +76,26 @@
>  TerrainProgram::TerrainProgram() {
>  	gl_program_.build(kTerrainVertexShader, kTerrainFragmentShader);
>  
> +	attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
>  	attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
> -	attr_texture_position_ =
> -	   glGetAttribLocation(gl_program_.object(), "attr_texture_position");
> -	attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
> +	attr_texture_offset_ = glGetAttribLocation(gl_program_.object(), "attr_texture_offset");
> +	attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
>  
>  	u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
> +	u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
>  }
>  
> -void TerrainProgram::gl_draw(int num_vertices,
> -                             const DescriptionMaintainer<TerrainDescription>& terrains) {
> +void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
>  	glUseProgram(gl_program_.object());
>  
> +	glEnableVertexAttribArray(attr_brightness_);
>  	glEnableVertexAttribArray(attr_position_);
> +	glEnableVertexAttribArray(attr_texture_offset_);
>  	glEnableVertexAttribArray(attr_texture_position_);
> -	glEnableVertexAttribArray(attr_brightness_);
>  
>  	glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
>  	glBufferData(GL_ARRAY_BUFFER,
> -	             sizeof(TerrainProgram::PerVertexData) * num_vertices,
> +	             sizeof(TerrainProgram::PerVertexData) * vertices_.size(),
>  	             vertices_.data(),
>  	             GL_STREAM_DRAW);
>  
> @@ -102,55 +107,56 @@
>  		                      sizeof(TerrainProgram::PerVertexData),
>  		                      reinterpret_cast<void*>(offset));
>  	};
> +	set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
>  	set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
> -	set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
> +	set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
>  	set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
>  
>  	glBindBuffer(GL_ARRAY_BUFFER, 0);
>  
> -	// Set the sampler texture unit to 0
>  	glActiveTexture(GL_TEXTURE0);
> +	glBindTexture(GL_TEXTURE_2D, gl_texture);
> +
>  	glUniform1i(u_terrain_texture_, 0);
> -
> -	// Which triangles to draw?
> -	for (size_t i = 0; i < terrains_to_indices_.size(); ++i) {
> -		const auto& indices = terrains_to_indices_[i];
> -		if (indices.empty()) {
> -			continue;
> -		}
> -		glBindTexture(GL_TEXTURE_2D,
> -		              g_gr->get_maptexture_data(terrains.get_unmutable(i).get_texture())
> -		                 ->texture()
> -		                 .get_gl_texture());
> -		glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, indices.data());
> -	}
> -
> +	glUniform2f(u_texture_dimensions_, texture_w, texture_h);
> +
> +	glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
> +
> +	glBindTexture(GL_TEXTURE_2D, 0);
> +
> +	glDisableVertexAttribArray(attr_brightness_);
>  	glDisableVertexAttribArray(attr_position_);
> +	glDisableVertexAttribArray(attr_texture_offset_);
>  	glDisableVertexAttribArray(attr_texture_position_);
> -	glDisableVertexAttribArray(attr_brightness_);
> -}
> -
> -void TerrainProgram::draw(const DescriptionMaintainer<TerrainDescription>& terrains,
> +}
> +
> +void TerrainProgram::add_vertex(const FieldsToDraw::Field& field,
> +                                const FloatPoint& texture_offset) {
> +	vertices_.emplace_back();
> +	PerVertexData& back = vertices_.back();
> +
> +	back.gl_x = field.gl_x;
> +	back.gl_y = field.gl_y;
> +	back.brightness = field.brightness;
> +	back.texture_x = field.texture_x;
> +	back.texture_y = field.texture_y;
> +	back.texture_offset_x = texture_offset.x;
> +	back.texture_offset_y = texture_offset.y;
> +}
> +
> +void TerrainProgram::draw(uint32_t gametime,
> +                          const DescriptionMaintainer<TerrainDescription>& terrains,
>                            const FieldsToDraw& fields_to_draw) {
> -	if (vertices_.size() < fields_to_draw.size()) {
> -		vertices_.resize(fields_to_draw.size());
> -		terrains_to_indices_.resize(terrains.size());
> -	}
> -	for (auto& container : terrains_to_indices_) {
> -		container.clear();
> -		container.reserve(fields_to_draw.size());
> -	}
> +	// This method expects that all terrains have the same dimensions and that
> +	// all are packed into the same texture atlas, i.e. all are in the same GL
> +	// texture. It does not check for this invariance for speeds sake.
> +
> +	vertices_.clear();
> +	vertices_.reserve(fields_to_draw.size() * 3);
>  
>  	for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
>  		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
>  
> -		PerVertexData& vertex = vertices_[current_index];
> -		vertex.texture_x = field.texture_x;
> -		vertex.texture_y = field.texture_y;
> -		vertex.gl_x = field.gl_x;
> -		vertex.gl_y = field.gl_y;
> -		vertex.brightness = field.brightness;
> -
>  		// The bottom right neighbor fields_to_draw is needed for both triangles
>  		// associated with this field. If it is not in fields_to_draw, there is no need to
>  		// draw any triangles.
> @@ -163,19 +169,24 @@
>  		const int bln_index =
>  		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
>  		if (bln_index != -1) {
> -			terrains_to_indices_[field.ter_d].push_back(current_index);
> -			terrains_to_indices_[field.ter_d].push_back(bln_index);
> -			terrains_to_indices_[field.ter_d].push_back(brn_index);
> +			const FloatPoint texture_offset =
> +			   terrains.get_unmutable(field.ter_d).get_texture(gametime).texture_coordinates().top_left();
> +			add_vertex(fields_to_draw.at(current_index), texture_offset);
> +			add_vertex(fields_to_draw.at(bln_index), texture_offset);
> +			add_vertex(fields_to_draw.at(brn_index), texture_offset);
>  		}
>  
>  		// Right triangle.
>  		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
>  		if (rn_index != -1) {
> -			terrains_to_indices_[field.ter_r].push_back(current_index);
> -			terrains_to_indices_[field.ter_r].push_back(brn_index);
> -			terrains_to_indices_[field.ter_r].push_back(rn_index);
> +			const FloatPoint texture_offset =
> +			   terrains.get_unmutable(field.ter_r).get_texture(gametime).texture_coordinates().top_left();
> +			add_vertex(fields_to_draw.at(current_index), texture_offset);
> +			add_vertex(fields_to_draw.at(brn_index), texture_offset);
> +			add_vertex(fields_to_draw.at(rn_index), texture_offset);
>  		}
>  	}
>  
> -	gl_draw(fields_to_draw.size(), terrains);
> +	const Texture& texture = terrains.get_unmutable(0).get_texture(0);
> +	gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
>  }
> 
> === modified file 'src/graphic/gl/terrain_program.h'
> --- src/graphic/gl/terrain_program.h	2014-11-08 18:06:17 +0000
> +++ src/graphic/gl/terrain_program.h	2014-11-28 07:21:07 +0000
> @@ -22,11 +22,12 @@
>  
>  #include <vector>
>  
> +#include "base/point.h"
> +#include "graphic/gl/fields_to_draw.h"
>  #include "graphic/gl/utils.h"
>  #include "logic/description_maintainer.h"
>  #include "logic/world/terrain_description.h"
>  
> -class FieldsToDraw;
>  
>  class TerrainProgram {
>  public:
> @@ -34,7 +35,7 @@
>  	TerrainProgram();
>  
>  	// Draws the terrain.
> -	void draw(const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> +	void draw(uint32_t gametime, const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
>  	          const FieldsToDraw& fields_to_draw);
>  
>  private:
> @@ -44,36 +45,36 @@
>  		float brightness;
>  		float texture_x;
>  		float texture_y;
> +		float texture_offset_x;
> +		float texture_offset_y;
>  	};
> -	static_assert(sizeof(PerVertexData) == 20, "Wrong padding.");
> -
> -	void gl_draw(int num_vertices,
> -	             const DescriptionMaintainer<Widelands::TerrainDescription>& terrains);
> +	static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
> +
> +	void gl_draw(int gl_texture, float texture_w, float texture_h);
> +
> +	// Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
> +	void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
> +
> +	// The program used for drawing the terrain.
> +	Gl::Program gl_program_;
>  
>  	// The buffer that will contain 'vertices_' for rendering.
>  	Gl::Buffer gl_array_buffer_;
>  
> -	// The program used for drawing the terrain.
> -	Gl::Program gl_program_;
> -
>  	// Attributes.
> +	GLint attr_brightness_;
>  	GLint attr_position_;
> +	GLint attr_texture_offset_;
>  	GLint attr_texture_position_;
> -	GLint attr_brightness_;
>  
>  	// Uniforms.
>  	GLint u_terrain_texture_;
> +	GLint u_texture_dimensions_;
>  
>  	// Objects below are kept around to avoid memory allocations on each frame.
>  	// They could theoretically also be recreated.
> -
> -	// All vertices that are going to get rendered this frame.
>  	std::vector<PerVertexData> vertices_;
>  
> -	// A map from terrain index in world.terrains() to indices in 'vertices_'
> -	// that have this terrain type.
> -	std::vector<std::vector<uint16_t>> terrains_to_indices_;
> -
>  	DISALLOW_COPY_AND_ASSIGN(TerrainProgram);
>  };
>  
> 
> === modified file 'src/graphic/graphic.cc'
> --- src/graphic/graphic.cc	2014-11-24 07:10:03 +0000
> +++ src/graphic/graphic.cc	2014-11-28 07:21:07 +0000
> @@ -19,21 +19,10 @@
>  
>  #include "graphic/graphic.h"
>  
> -#include <cstring>
> -#include <iostream>
> -#include <memory>
> -
> -#include <SDL_image.h>
> -
> -#include "base/deprecated.h"
> -#include "base/i18n.h"
>  #include "base/log.h"
> -#include "base/macros.h"
>  #include "base/wexception.h"
>  #include "build_info.h"
> -#include "config.h"
>  #include "graphic/animation.h"
> -#include "graphic/diranimations.h"
>  #include "graphic/font_handler.h"
>  #include "graphic/gl/system_headers.h"
>  #include "graphic/image.h"
> @@ -41,15 +30,11 @@
>  #include "graphic/image_transformations.h"
>  #include "graphic/rendertarget.h"
>  #include "graphic/screen.h"
> -#include "graphic/terrain_texture.h"
>  #include "graphic/texture.h"
>  #include "graphic/texture_cache.h"
> -#include "io/fileread.h"
>  #include "io/filesystem/layered_filesystem.h"
>  #include "io/streamwrite.h"
> -#include "logic/roadtype.h"
>  #include "notifications/notifications.h"
> -#include "ui_basic/progresswindow.h"
>  
>  using namespace std;
>  
> @@ -162,7 +147,6 @@
>  
>  Graphic::~Graphic()
>  {
> -	m_maptextures.clear();
>  	texture_cache_->flush();
>  	// TODO(unknown): this should really not be needed, but currently is :(
>  	if (UI::g_fh)
> @@ -303,22 +287,6 @@
>  	save_surface_to_png(image->texture(), sw);
>  }
>  
> -uint32_t Graphic::new_maptexture(const std::vector<std::string>& texture_files, const uint32_t frametime)
> -{
> -	m_maptextures.emplace_back(new TerrainTexture(texture_files, frametime));
> -	return m_maptextures.size(); // ID 1 is at m_maptextures[0]
> -}
> -
> -/**
> - * Advance frames for animated textures
> -*/
> -void Graphic::animate_maptextures(uint32_t time)
> -{
> -	for (uint32_t i = 0; i < m_maptextures.size(); ++i) {
> -		m_maptextures[i]->animate(time);
> -	}
> -}
> -
>  /**
>   * Save a screenshot to the given file.
>  */
> @@ -329,15 +297,3 @@
>  	save_surface_to_png(screen_.get(), sw);
>  	delete sw;
>  }
> -
> -/**
> - * Retrieve the map texture with the given number
> - * \return the actual texture data associated with the given ID.
> - */
> -TerrainTexture * Graphic::get_maptexture_data(uint32_t id)
> -{
> -	--id; // ID 1 is at m_maptextures[0]
> -
> -	assert(id < m_maptextures.size());
> -	return m_maptextures[id].get();
> -}
> 
> === modified file 'src/graphic/graphic.h'
> --- src/graphic/graphic.h	2014-11-24 07:12:35 +0000
> +++ src/graphic/graphic.h	2014-11-28 07:21:07 +0000
> @@ -20,13 +20,10 @@
>  #ifndef WL_GRAPHIC_GRAPHIC_H
>  #define WL_GRAPHIC_GRAPHIC_H
>  
> -#include <map>
>  #include <memory>
> -#include <vector>
>  
>  #include <SDL.h>
>  
> -#include "base/rect.h"
>  #include "graphic/image_cache.h"
>  #include "notifications/notifications.h"
>  #include "notifications/note_ids.h"
> @@ -38,7 +35,6 @@
>  class Surface;
>  class TextureCache;
>  class StreamWrite;
> -struct TerrainTexture;
>  
>  // Will be send whenever the resolution changes.
>  struct GraphicResolutionChanged {
> @@ -83,13 +79,7 @@
>  
>  	void save_png(const Image*, StreamWrite*) const;
>  
> -	// Creates a new TerrainTexture() with the given 'frametime' and using the given
> -	// 'texture_files' as the images for it and returns it id.
> -	uint32_t new_maptexture(const std::vector<std::string>& texture_files, uint32_t frametime);
> -	void animate_maptextures(uint32_t time);
> -
>  	void screenshot(const std::string& fname) const;
> -	TerrainTexture * get_maptexture_data(uint32_t id);
>  
>  private:
>  	// Called when the resolution (might) have changed.
> @@ -119,8 +109,6 @@
>  	std::unique_ptr<ImageCache> image_cache_;
>  	/// This holds all animations.
>  	std::unique_ptr<AnimationManager> animation_manager_;
> -
> -	std::vector<std::unique_ptr<TerrainTexture>> m_maptextures;
>  };
>  
>  extern Graphic * g_gr;
> 
> === modified file 'src/graphic/minimap_renderer.cc'
> --- src/graphic/minimap_renderer.cc	2014-11-24 07:10:03 +0000
> +++ src/graphic/minimap_renderer.cc	2014-11-28 07:21:07 +0000
> @@ -27,7 +27,6 @@
>  #include "graphic/graphic.h"
>  #include "graphic/image.h"
>  #include "graphic/in_memory_image.h"
> -#include "graphic/terrain_texture.h"
>  #include "graphic/texture.h"
>  #include "logic/field.h"
>  #include "logic/map.h"
> @@ -61,9 +60,8 @@
>  	uint32_t pixelcolor = 0;
>  
>  	if (layers & MiniMapLayer::Terrain) {
> -		const RGBColor color =
> -		   g_gr->get_maptexture_data(egbase.world().terrain_descr(f.field->terrain_d()).get_texture())
> -		      ->get_minimap_color(f.field->get_brightness());
> +		const RGBColor& color =  egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
> +		   f.field->get_brightness());
>  
>  		pixelcolor = SDL_MapRGBA(&format, color.r, color.g, color.b, 255);
>  	}
> 
> === modified file 'src/graphic/surface.cc'
> --- src/graphic/surface.cc	2014-11-24 07:25:21 +0000
> +++ src/graphic/surface.cc	2014-11-28 07:21:07 +0000
> @@ -162,15 +162,26 @@
>  {
>  	glViewport(0, 0, width(), height());
>  
> -	// Source Rectangle.
> +	// Source Rectangle. We have to take into account that the texture might be
> +	// a subtexture in another bigger texture. So we first figure out the pixel
> +	// coordinates given it is a full texture (values between 0 and 1) and then
> +	// adjust these for the texture coordinates in the parent texture.
>  	FloatRect gl_src_rect;
>  	{
> +		const FloatRect& texture_coordinates = texture->texture_coordinates();
> +
>  		float x1 = srcrc.x;
>  		float y1 = srcrc.y;
>  		pixel_to_gl_texture(texture->width(), texture->height(), &x1, &y1);
> +		x1 = texture_coordinates.x + x1 * texture_coordinates.w;
> +		y1 = texture_coordinates.y + y1 * texture_coordinates.h;
> +
>  		float x2 = srcrc.x + srcrc.w;
>  		float y2 = srcrc.y + srcrc.h;
>  		pixel_to_gl_texture(texture->width(), texture->height(), &x2, &y2);
> +		x2 = texture_coordinates.x + x2 * texture_coordinates.w;
> +		y2 = texture_coordinates.y + y2 * texture_coordinates.h;
> +
>  		gl_src_rect.x = x1;
>  		gl_src_rect.y = y1;
>  		gl_src_rect.w = x2 - x1;
> 
> === removed file 'src/graphic/terrain_texture.cc'
> --- src/graphic/terrain_texture.cc	2014-11-24 07:10:03 +0000
> +++ src/graphic/terrain_texture.cc	1970-01-01 00:00:00 +0000
> @@ -1,98 +0,0 @@
> -/*
> - * Copyright (C) 2002-2004, 2006, 2010, 2012 by the Widelands Development Team
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License
> - * as published by the Free Software Foundation; either version 2
> - * of the License, or (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
> - *
> - */
> -
> -#include "graphic/terrain_texture.h"
> -
> -#include <SDL_image.h>
> -
> -#include "base/deprecated.h"
> -#include "base/log.h"
> -#include "base/wexception.h"
> -#include "graphic/image_io.h"
> -#include "graphic/texture.h"
> -#include "io/fileread.h"
> -#include "io/filesystem/layered_filesystem.h"
> -
> -using namespace std;
> -
> -/**
> - * Create a texture, taking the pixel data from an Image.
> - * Currently it converts a 16 bit image to a 8 bit texture. This should
> - * be changed to load a 8 bit file directly, however.
> - */
> -TerrainTexture::TerrainTexture(const std::vector<std::string>& texture_files, const uint32_t frametime)
> -   : m_frame_num(0), m_frametime(frametime) {
> -	if (texture_files.empty()) {
> -		throw wexception("No images for texture.");
> -	}
> -
> -	for (const std::string& fname : texture_files) {
> -		if (!g_fs->file_exists(fname)) {
> -			throw wexception("Could not find %s.", fname.c_str());
> -		}
> -
> -		m_texture_image = fname;
> -		SDL_Surface* sdl_surface = load_image_as_sdl_surface(fname, g_fs);
> -		if (!sdl_surface) {
> -			throw wexception(
> -			   "WARNING: Failed to load texture frame %s: %s\n", fname.c_str(), IMG_GetError());
> -		}
> -		if (sdl_surface->w != kTextureWidth || sdl_surface->h != kTextureHeight) {
> -			SDL_FreeSurface(sdl_surface);
> -			throw wexception("WARNING: %s: texture must be %ix%i pixels big\n",
> -			                 fname.c_str(),
> -			                 kTextureWidth,
> -			                 kTextureHeight);
> -		}
> -
> -		// calculate shades on the first frame
> -		if (m_textures.empty()) {
> -			uint8_t top_left_pixel = static_cast<uint8_t*>(sdl_surface->pixels)[0];
> -			SDL_Color top_left_pixel_color = sdl_surface->format->palette->colors[top_left_pixel];
> -			for (int i = -128; i < 128; i++) {
> -				const int shade = 128 + i;
> -				int32_t r = std::min<int32_t>((top_left_pixel_color.r * shade) >> 7, 255);
> -				int32_t g = std::min<int32_t>((top_left_pixel_color.g * shade) >> 7, 255);
> -				int32_t b = std::min<int32_t>((top_left_pixel_color.b * shade) >> 7, 255);
> -				m_minimap_colors[shade] = RGBColor(r, g, b);
> -			}
> -		}
> -		m_textures.emplace_back(new Texture(sdl_surface));
> -	}
> -
> -	if (m_textures.empty())
> -		throw wexception("TerrainTexture has no frames");
> -}
> -
> -RGBColor TerrainTexture::get_minimap_color(int8_t shade) {
> -	return m_minimap_colors[128 + shade];
> -}
> -
> -void TerrainTexture::animate(uint32_t time)
> -{
> -	m_frame_num = (time / m_frametime) % m_textures.size();
> -}
> -
> -const std::string& TerrainTexture::get_texture_image() const {
> -	return m_texture_image;
> -}
> -
> -const Texture& TerrainTexture::texture() const {
> -	return *m_textures.at(m_frame_num);
> -}
> 
> === removed file 'src/graphic/terrain_texture.h'
> --- src/graphic/terrain_texture.h	2014-11-24 07:10:03 +0000
> +++ src/graphic/terrain_texture.h	1970-01-01 00:00:00 +0000
> @@ -1,62 +0,0 @@
> -/*
> - * Copyright (C) 2002-2004, 2006, 2008-2010, 2012 by the Widelands Development Team
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License
> - * as published by the Free Software Foundation; either version 2
> - * of the License, or (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
> - *
> - */
> -
> -#ifndef WL_GRAPHIC_TERRAIN_TEXTURE_H
> -#define WL_GRAPHIC_TERRAIN_TEXTURE_H
> -
> -#include <memory>
> -#include <string>
> -#include <vector>
> -
> -#include <stdint.h>
> -
> -#include "graphic/colormap.h"
> -
> -class Texture;
> -
> -/// TerrainTextures have a fixed size and are squares.
> -constexpr int kTextureWidth = 64;
> -constexpr int kTextureHeight = kTextureWidth;
> -
> -// TerrainTexture represents are terrain texture, which is strictly kTextureWidth by
> -// kTextureHeight pixels in size.
> -struct TerrainTexture {
> -	TerrainTexture(const std::vector<std::string>& texture_files, uint32_t frametime);
> -
> -	// Returns the path to a representative image for this texture.
> -	const std::string& get_texture_image() const;
> -
> -	// Returns the texture for the current animation phase.
> -	const Texture& texture() const;
> -
> -	// Return the basic terrain colour to be used in the minimap.
> -	RGBColor get_minimap_color(int8_t shade);
> -
> -	// Set the current frame according to the game time.
> -	void animate(uint32_t time);
> -
> -private:
> -	RGBColor    m_minimap_colors[256];
> -	int32_t     m_frame_num;
> -	std::string m_texture_image;
> -	uint32_t    m_frametime;
> -	std::vector<std::unique_ptr<Texture>> m_textures;
> -};
> -
> -#endif  // end of include guard: WL_GRAPHIC_TERRAIN_TEXTURE_H
> 
> === modified file 'src/graphic/texture.cc'
> --- src/graphic/texture.cc	2014-11-24 07:25:21 +0000
> +++ src/graphic/texture.cc	2014-11-28 07:21:07 +0000
> @@ -72,11 +72,6 @@
>  
>  }  // namespace
>  
> -/**
> - * Initialize an OpenGL texture of the given dimensions.
> - *
> - * The initial data of the texture is undefined.
> - */
>  Texture::Texture(int w, int h)
>  {
>  	init(w, h);
> @@ -89,11 +84,6 @@
>  		 GL_UNSIGNED_BYTE, nullptr);
>  }
>  
> -/**
> - * Initialize an OpenGL texture with the contents of the given surface.
> - *
> - * \note Takes ownership of the given surface.
> - */
>  Texture::Texture(SDL_Surface * surface, bool intensity)
>  {
>  	init(surface->w, surface->h);
> @@ -132,9 +122,24 @@
>  	SDL_FreeSurface(surface);
>  }
>  
> +Texture::Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h) {
> +	m_w = subrect.w;
> +	m_h = subrect.h;
> +
> +	m_texture = texture;
> +	m_owns_texture = false;
> +
> +	m_texture_coordinates.w = static_cast<float>(m_w - 1) / parent_w;
> +	m_texture_coordinates.h = static_cast<float>(m_h - 1) / parent_h;
> +	m_texture_coordinates.x = (static_cast<float>(subrect.x) + 0.5) / parent_w;
> +	m_texture_coordinates.y = (static_cast<float>(subrect.y) + 0.5) / parent_h;
> +}
> +
>  Texture::~Texture()
>  {
> -	glDeleteTextures(1, &m_texture);
> +	if (m_owns_texture) {
> +		glDeleteTextures(1, &m_texture);
> +	}
>  }
>  
>  void Texture::pixel_to_gl(float* x, float* y) const {
> @@ -150,6 +155,12 @@
>  		return;
>  	}
>  
> +	m_owns_texture = true;
> +	m_texture_coordinates.x = 0.f;
> +	m_texture_coordinates.y = 0.f;
> +	m_texture_coordinates.w = 1.f;
> +	m_texture_coordinates.h = 1.f;
> +
>  	glGenTextures(1, &m_texture);
>  	glBindTexture(GL_TEXTURE_2D, m_texture);
>  
> @@ -164,13 +175,20 @@
>  	if (m_w <= 0 || m_h <= 0) {
>  		return;
>  	}
> -	assert(!m_pixels);
> +
> +	if (m_pixels) {
> +		throw wexception("Called lock() on locked surface.");
> +	}
> +	if (!m_owns_texture) {
> +		throw wexception("A surface that does not own its pixels can not be locked..");
> +	}
>  
>  	m_pixels.reset(new uint8_t[m_w * m_h * 4]);
>  
>  	if (mode == Lock_Normal) {
>  		glBindTexture(GL_TEXTURE_2D, m_texture);
>  		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels.get());
> +		glBindTexture(GL_TEXTURE_2D, 0);
>  	}
>  }
>  
> @@ -185,6 +203,7 @@
>  		glTexImage2D
>  			(GL_TEXTURE_2D, 0, GL_RGBA, m_w, m_h, 0, GL_RGBA,
>  			 GL_UNSIGNED_BYTE,  m_pixels.get());
> +		glBindTexture(GL_TEXTURE_2D, 0);
>  	}
>  
>  	m_pixels.reset(nullptr);
> 
> === modified file 'src/graphic/texture.h'
> --- src/graphic/texture.h	2014-11-24 07:25:21 +0000
> +++ src/graphic/texture.h	2014-11-28 07:21:07 +0000
> @@ -19,6 +19,7 @@
>  #ifndef WL_GRAPHIC_TEXTURE_H
>  #define WL_GRAPHIC_TEXTURE_H
>  
> +#include "base/rect.h"
>  #include "graphic/gl/system_headers.h"
>  #include "graphic/surface.h"
>  
> @@ -34,6 +35,10 @@
>  	// dimensions.
>  	Texture(int w, int h);
>  
> +	// Create a logical texture that is a 'subrect' (in Pixel) in
> +	// another texture. Ownership of 'texture' is not taken.
> +	Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h);
> +
>  	virtual ~Texture();
>  
>  	/// Interface implementation
> @@ -60,10 +65,20 @@
>  
>  	GLuint get_gl_texture() const {return m_texture;}
>  
> +	const FloatRect& texture_coordinates() const {
> +		return m_texture_coordinates;
> +	}
> +
>  private:
>  	void pixel_to_gl(float* x, float* y) const override;
>  	void init(uint16_t w, uint16_t h);
>  
> +	// True if we own the texture, i.e. if we need to delete it.
> +	bool m_owns_texture;
> +
> +	// Texture coordinates in m_texture.
> +	FloatRect m_texture_coordinates;
> +
>  	GLuint m_texture;
>  };
>  
> 
> === added file 'src/graphic/texture_atlas.cc'
> --- src/graphic/texture_atlas.cc	1970-01-01 00:00:00 +0000
> +++ src/graphic/texture_atlas.cc	2014-11-28 07:21:07 +0000
> @@ -0,0 +1,153 @@
> +/*
> + * Copyright (C) 2006-2014 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#include "graphic/texture_atlas.h"
> +
> +#include <cassert>
> +#include <memory>
> +
> +#include "base/wexception.h"
> +
> +TextureAtlas::Node::Node(const Rect& init_r) : used(false), r(init_r) {
> +}
> +
> +void TextureAtlas::Node::split(int item_w, int item_h) {
> +	assert(!used);
> +
> +	down.reset(new Node(Rect(r.x, r.y + item_h, r.w, r.h - item_h)));
> +	right.reset(new Node(Rect(r.x + item_w, r.y, r.w - item_w, item_h)));
> +	used = true;
> +
> +	// Note: we do not change the size of the root. It is not needed
> +	// for the remaining algorithm, but we use it to remember the
> +	// size of the full canvas.
> +}
> +
> +
> +TextureAtlas::TextureAtlas() :
> +	next_index_(0)
> +{
> +}
> +
> +void TextureAtlas::add(const Texture& texture) {
> +	blocks_.emplace_back(next_index_++, &texture);
> +}
> +
> +// static
> +TextureAtlas::Node* TextureAtlas::find_node(Node* node, int w, int h) {
> +	if (node->used) {
> +		Node* child_node = find_node(node->right.get(), w, h);
> +		if (child_node != nullptr) {
> +			return child_node;
> +		}
> +		return find_node(node->down.get(), w, h);
> +	}
> +	assert(!node->used);
> +
> +	if ((w <= node->r.w) && (h <= node->r.h)) {
> +		return node;
> +	}
> +
> +	return nullptr;
> +}
> +
> +std::unique_ptr<Texture> TextureAtlas::pack(std::vector<std::unique_ptr<Texture>>* textures) {
> +	if (blocks_.empty()) {
> +		throw wexception("Called pack() without blocks.");
> +	}
> +
> +	// Sort blocks by their biggest side length. This heuristically gives the
> +	// best packing.
> +	std::sort(blocks_.begin(), blocks_.end(), [](const Block& i, const Block& j) {
> +		return std::max(i.texture->width(), i.texture->height()) >
> +		       std::max(j.texture->width(), j.texture->height());
> +	});
> +
> +	std::unique_ptr<Node> root(
> +	   new Node(Rect(0, 0, blocks_.begin()->texture->width(), blocks_.begin()->texture->height())));
> +
> +	// TODO(sirver): when growing, keep maximum size of gl textures in mind.
> +	const auto grow_right = [&root](int delta_w) {
> +		std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w + delta_w, root->r.h)));
> +		new_root->used = true;
> +		new_root->right.reset(new Node(Rect(root->r.w, 0, delta_w, root->r.h)));
> +		new_root->down.reset(root.release());
> +		root.reset(new_root.release());
> +	};
> +
> +	const auto grow_down = [&root](int delta_h) {
> +		std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w, root->r.h + delta_h)));
> +		new_root->used = true;
> +		new_root->down.reset(new Node(Rect(0, root->r.h, root->r.w, delta_h)));
> +		new_root->right.reset(root.release());
> +		root.reset(new_root.release());
> +	};
> +
> +	for (Block& block : blocks_) {
> +		const int block_width = block.texture->width();
> +		const int block_height = block.texture->height();
> +
> +		Node* fitting_node = find_node(root.get(), block_width, block_height);
> +		if (fitting_node == nullptr) {
> +			// Atlas is not big enough to contain this. Grow it and try again.
> +			bool can_grow_down = (block_width <= root->r.w);
> +			bool can_grow_right = (block_height <= root->r.h);
> +

This is best explained with a picture: http://codeincomplete.com/posts/2011/5/7/bin_packing/

> +			// Attempt to keep the texture square-ish.
> +			bool should_grow_right = can_grow_right && (root->r.h >= root->r.w + block_width);
> +			bool should_grow_down = can_grow_down && (root->r.w >= root->r.h + block_height);
> +
> +			if (should_grow_right) {
> +				grow_right(block_width);
> +			} else if (should_grow_down) {
> +				grow_down(block_height);
> +			} else if (can_grow_right) {
> +				grow_right(block_width);
> +			} else if (can_grow_down) {
> +				grow_down(block_height);
> +			}
> +			fitting_node = find_node(root.get(), block_width, block_height);
> +		}
> +		if (!fitting_node) {
> +			throw wexception("Unable to fit node in texture atlas.");
> +		}
> +		fitting_node->split(block_width, block_height);
> +		block.node = fitting_node;
> +	}
> +
> +	std::unique_ptr<Texture> packed_texture(new Texture(root->r.w, root->r.h));
> +	packed_texture->fill_rect(Rect(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
> +
> +	// Sort blocks by index so that they come back in the correct ordering.
> +	std::sort(blocks_.begin(), blocks_.end(), [](const Block& i, const Block& j) {
> +		return i.index < j.index;
> +	});
> +
> +	for (Block& block : blocks_) {
> +		packed_texture->blit(block.node->r.top_left(),
> +		                     block.texture,
> +		                     Rect(0, 0, block.texture->width(), block.texture->height()));
> +		textures->emplace_back(new Texture(
> +		   packed_texture->get_gl_texture(),
> +		   Rect(block.node->r.top_left(), block.texture->width(), block.texture->height()),
> +		   root->r.w,
> +		   root->r.h));
> +	}
> +	return packed_texture;
> +}
> 
> === added file 'src/graphic/texture_atlas.h'
> --- src/graphic/texture_atlas.h	1970-01-01 00:00:00 +0000
> +++ src/graphic/texture_atlas.h	2014-11-28 07:21:07 +0000
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright (C) 2006-2014 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#ifndef WL_GRAPHIC_TEXTURE_ATLAS_H
> +#define WL_GRAPHIC_TEXTURE_ATLAS_H
> +
> +#include <memory>
> +#include <vector>
> +
> +#include "base/macros.h"
> +#include "graphic/texture.h"
> +
> +// A 2d bin packer based on the blog post
> +// http://codeincomplete.com/posts/2011/5/7/bin_packing/.
> +class TextureAtlas {
> +public:
> +	TextureAtlas();
> +
> +	// Add 'texture' as one of the textures to be packed. Ownership is
> +	// not taken, but 'texture' must be valid until pack() has been
> +	// called.
> +	void add(const Texture& texture);
> +
> +	// Packs the textures and returns the packed texture. 'textures'
> +	// contains the individual sub textures (that do not own their
> +	// memory) in the order they have been added by 'add'.
> +	std::unique_ptr<Texture> pack(std::vector<std::unique_ptr<Texture>>* textures);
> +
> +private:
> +	struct Node {
> +		Node(const Rect& init_r);
> +		void split(int w, int h);
> +
> +		bool used;
> +		Rect r;
> +		std::unique_ptr<Node> right;
> +		std::unique_ptr<Node> down;
> +
> +		DISALLOW_COPY_AND_ASSIGN(Node);
> +	};
> +
> +	struct Block {
> +		Block(int init_index, const Texture* init_texture)
> +		   : index(init_index), texture(init_texture) {
> +		}
> +
> +		int index;
> +		const Texture* texture;
> +		Node* node;
> +	};
> +
> +	static Node* find_node(Node* root, int w, int h);
> +
> +	int next_index_;
> +
> +	// Unpacked items.
> +	std::vector<Block> blocks_;
> +
> +	DISALLOW_COPY_AND_ASSIGN(TextureAtlas);
> +};
> +
> +#endif  // end of include guard: WL_GRAPHIC_TEXTURE_ATLAS_H
> 
> === modified file 'src/logic/CMakeLists.txt'
> --- src/logic/CMakeLists.txt	2014-10-13 15:04:50 +0000
> +++ src/logic/CMakeLists.txt	2014-11-28 07:21:07 +0000
> @@ -230,6 +230,9 @@
>      game_io
>      graphic
>      graphic_color
> +    graphic_image_io
> +    graphic_surface
> +    graphic_texture_atlas
>      helper
>      io_fileread
>      io_filesystem
> 
> === modified file 'src/logic/description_maintainer.h'
> --- src/logic/description_maintainer.h	2014-09-19 23:33:35 +0000
> +++ src/logic/description_maintainer.h	2014-11-28 07:21:07 +0000
> @@ -55,9 +55,13 @@
>  
>  	// Returns the entry with the given 'idx' or nullptr if 'idx' is out of
>  	// bound. Ownership is retained.
> +	// TODO(sirver): remove get() and use get_mutable
>  	T* get(const int32_t idx) const {
>  		return (idx >= 0 && idx < static_cast<int32_t>(items_.size())) ? items_[idx].get() : nullptr;
>  	}
> +	T* get_mutable(const int32_t idx) const {
> +		return get(idx);
> +	}
>  
>  	// Returns the entry at 'index'. If 'index' is out of bounds the result is
>  	// undefined.
> 
> === modified file 'src/logic/editor_game_base.cc'
> --- src/logic/editor_game_base.cc	2014-09-19 12:54:54 +0000
> +++ src/logic/editor_game_base.cc	2014-11-28 07:21:07 +0000
> @@ -20,6 +20,7 @@
>  #include "logic/editor_game_base.h"
>  
>  #include <algorithm>
> +#include <memory>
>  #include <set>
>  
>  #include "base/i18n.h"
> @@ -113,11 +114,12 @@
>  
>  		try {
>  			lua_->run_script("world/init.lua");
> -		}
> -		catch (const WException& e) {
> +		} catch (const WException& e) {
>  			log("Could not read world information: %s", e.what());
>  			throw;
>  		}
> +
> +		world_->load_graphics();
>  	}
>  	return world_.get();
>  }
> 
> === modified file 'src/logic/field.cc'
> --- src/logic/field.cc	2014-07-22 09:54:49 +0000
> +++ src/logic/field.cc	2014-11-28 07:21:07 +0000
> @@ -50,7 +50,7 @@
>  		b = -128;
>  	else if (b >  127)
>  		b =  127;
> -	brightness = static_cast<int8_t>(b); //TODO(unknown): ARGH !!
> +	brightness = static_cast<int8_t>(b);
>  }
>  
>  }
> 
> === modified file 'src/logic/game.cc'
> --- src/logic/game.cc	2014-10-11 15:56:02 +0000
> +++ src/logic/game.cc	2014-11-28 07:21:07 +0000
> @@ -613,9 +613,6 @@
>  		// the timings of savings.
>  		cmdqueue().run_queue(m_ctrl->get_frametime(), get_gametime_pointer());
>  
> -		if (g_gr) // not in dedicated server mode
> -			g_gr->animate_maptextures(get_gametime());
> -
>  		// check if autosave is needed
>  		m_savehandler.think(*this, WLApplication::get()->get_time());
>  	}
> 
> === modified file 'src/logic/world/terrain_description.cc'
> --- src/logic/world/terrain_description.cc	2014-09-19 12:54:54 +0000
> +++ src/logic/world/terrain_description.cc	2014-11-28 07:21:07 +0000
> @@ -19,9 +19,12 @@
>  
>  #include "logic/world/terrain_description.h"
>  
> +#include <memory>
> +
>  #include <boost/format.hpp>
>  
>  #include "graphic/graphic.h"
> +#include "graphic/texture.h"
>  #include "logic/game_data_error.h"
>  #include "logic/world/editor_category.h"
>  #include "logic/world/world.h"
> @@ -86,19 +89,18 @@
>  		throw GameDataError("%s: temperature is not in Kelvin.", name_.c_str());
>  	}
>  
> -	const std::vector<std::string> textures =
> +	 texture_paths_ =
>  	   table.get_table("textures")->array_entries<std::string>();
> -	int frame_length = FRAME_LENGTH;
> -	if (textures.empty()) {
> +	frame_length_ = FRAME_LENGTH;
> +	if (texture_paths_.empty()) {
>  		throw GameDataError("Terrain %s has no images.", name_.c_str());
> -	} else if (textures.size() == 1) {
> +	} else if (texture_paths_.size() == 1) {
>  		if (table.has_key("fps")) {
>  			throw GameDataError("Terrain %s with one images must not have fps.", name_.c_str());
>  		}
>  	} else {
> -		frame_length = 1000 / get_positive_int(table, "fps");
> +		frame_length_ = 1000 / get_positive_int(table, "fps");
>  	}
> -	texture_ = g_gr->new_maptexture(textures, frame_length);
>  
>  	for (const std::string& resource :
>  	     table.get_table("valid_resources")->array_entries<std::string>()) {
> @@ -121,8 +123,19 @@
>  TerrainDescription::~TerrainDescription() {
>  }
>  
> -uint32_t TerrainDescription::get_texture() const {
> -	return texture_;
> +const Texture& TerrainDescription::get_texture(uint32_t gametime) const {
> +	return *textures_.at((gametime / frame_length_) % textures_.size());
> +}
> +
> +void TerrainDescription::add_texture(std::unique_ptr<Texture> texture) {
> +	if (texture->width() != kTextureSideLength || texture->height() != kTextureSideLength) {
> +		throw wexception("Tried to add a texture with wrong size.");
> +	}
> +	textures_.emplace_back(std::move(texture));
> +}
> +
> +const std::vector<std::string>& TerrainDescription::texture_paths() const {
> +	return texture_paths_;
>  }
>  
>  TerrainDescription::Type TerrainDescription::get_is() const {
> @@ -149,7 +162,7 @@
>  	return valid_resources_.size();
>  }
>  
> -bool TerrainDescription::is_resource_valid(const int32_t res) const {
> +bool TerrainDescription::is_resource_valid(const int res) const {
>  	for (const uint8_t resource_index : valid_resources_) {
>  		if (resource_index == res) {
>  			return true;
> @@ -158,15 +171,15 @@
>  	return false;
>  }
>  
> -int8_t TerrainDescription::get_default_resource() const {
> +int TerrainDescription::get_default_resource() const {
>  	return default_resource_index_;
>  }
>  
> -int32_t TerrainDescription::get_default_resource_amount() const {
> +int TerrainDescription::get_default_resource_amount() const {
>  	return default_resource_amount_;
>  }
>  
> -int32_t TerrainDescription::dither_layer() const {
> +int TerrainDescription::dither_layer() const {
>  	return dither_layer_;
>  }
>  
> @@ -182,4 +195,19 @@
>  	return fertility_;
>  }
>  
> +void TerrainDescription::set_minimap_color(const RGBColor& color) {
> +	for (int i = -128; i < 128; i++) {
> +		const int shade = 128 + i;
> +		int new_r = std::min<int>((color.r * shade) >> 7, 255);
> +		int new_g = std::min<int>((color.g * shade) >> 7, 255);
> +		int new_b = std::min<int>((color.b * shade) >> 7, 255);
> +		minimap_colors_[shade] = RGBColor(new_r, new_g, new_b);
> +	}
> +}
> +
> +const RGBColor& TerrainDescription::get_minimap_color(int shade) {
> +	assert(-128 <= shade && shade <= 127);
> +	return minimap_colors_[128 + shade];
> +}
> +
>  }  // namespace Widelands
> 
> === modified file 'src/logic/world/terrain_description.h'
> --- src/logic/world/terrain_description.h	2014-09-10 10:18:46 +0000
> +++ src/logic/world/terrain_description.h	2014-11-28 07:21:07 +0000
> @@ -20,19 +20,26 @@
>  #ifndef WL_LOGIC_WORLD_TERRAIN_DESCRIPTION_H
>  #define WL_LOGIC_WORLD_TERRAIN_DESCRIPTION_H
>  
> +#include <memory>
>  #include <string>
> +#include <vector>
>  
>  #include "base/macros.h"
> +#include "graphic/color.h"
>  #include "logic/widelands.h"
>  #include "logic/world/resource_description.h"
>  
>  class LuaTable;
> +class Texture;
>  
>  namespace Widelands {
>  
>  class EditorCategory;
>  class World;
>  
> +/// TerrainTextures have a fixed size and are squares.
> +constexpr int kTextureSideLength = 64;
> +
>  class TerrainDescription {
>  public:
>  	enum Type {
> @@ -53,8 +60,19 @@
>  	/// The name showed to users of Widelands. Usually translated.
>  	const std::string& descname() const;
>  
> -	/// Returns the texture index for this terrain.
> -	uint32_t get_texture() const;
> +
> +	const std::vector<std::string>& texture_paths() const;
> +
> +	/// Returns the texture for the given gametime.
> +	const Texture& get_texture(uint32_t gametime) const;
> +	void add_texture(std::unique_ptr<Texture> texture);
> +
> +	// Sets the base minimap color.
> +	void set_minimap_color(const RGBColor& color);
> +
> +	// Return the basic terrain colour to be used in the minimap.
> +	// 'shade' must be a brightness value, i.e. in [-128, 127].
> +	const RGBColor& get_minimap_color(int shade);
>  
>  	/// Returns the type of terrain this is (water, walkable, and so on).
>  	Type get_is() const;
> @@ -70,7 +88,7 @@
>  
>  	/// Returns the resource index that can by default always be found in this
>  	/// terrain.
> -	int8_t get_default_resource() const;
> +	int get_default_resource() const;
>  
>  	/// Returns the default amount of resources you can find in this terrain.
>  	int32_t get_default_resource_amount() const;
> @@ -98,14 +116,16 @@
>  	const EditorCategory* editor_category_;  ///< not owned.
>  	Type is_;
>  	std::vector<uint8_t> valid_resources_;
> -	int8_t default_resource_index_;
> -	int32_t default_resource_amount_;
> -	const std::vector<std::string> texture_paths_;
> -	int32_t dither_layer_;
> -	uint32_t texture_;  ///< renderer's texture
> +	int default_resource_index_;
> +	int default_resource_amount_;
> +	int dither_layer_;
> +	int frame_length_;
>  	double temperature_;
>  	double fertility_;
>  	double humidity_;
> +	std::vector<std::string> texture_paths_;
> +	std::vector<std::unique_ptr<Texture>> textures_;
> +	RGBColor    minimap_colors_[256];
>  
>  	DISALLOW_COPY_AND_ASSIGN(TerrainDescription);
>  };
> 
> === modified file 'src/logic/world/world.cc'
> --- src/logic/world/world.cc	2014-09-10 10:18:46 +0000
> +++ src/logic/world/world.cc	2014-11-28 07:21:07 +0000
> @@ -19,26 +19,18 @@
>  
>  #include "logic/world/world.h"
>  
> -#include <iostream>
>  #include <memory>
> -#include <sstream>
>  
> -#include "base/i18n.h"
> -#include "base/log.h"
> -#include "base/wexception.h"
> -#include "graphic/graphic.h"
> -#include "io/fileread.h"
> -#include "io/filesystem/layered_filesystem.h"
> -#include "io/filewrite.h"
> +#include "graphic/image_io.h"
> +#include "graphic/texture.h"
> +#include "graphic/texture_atlas.h"
> +#include "logic/bob.h"
>  #include "logic/critter.h"
>  #include "logic/game_data_error.h"
>  #include "logic/immovable.h"
> -#include "logic/parse_map_object_types.h"
> -#include "logic/widelands.h"
>  #include "logic/world/editor_category.h"
>  #include "logic/world/resource_description.h"
>  #include "logic/world/terrain_description.h"
> -#include "profile/profile.h"
>  
>  namespace Widelands {
>  
> @@ -54,6 +46,42 @@
>  World::~World() {
>  }
>  
> +void World::load_graphics() {
> +	TextureAtlas ta;
> +
> +	// These will be deleted at the end of the method.
> +	std::vector<std::unique_ptr<Texture>> individual_textures_;
> +
> +	for (size_t i = 0; i < terrains_->size(); ++i) {
> +		TerrainDescription* terrain = terrains_->get_mutable(i);
> +		for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
> +			SDL_Surface* sdl_surface = load_image_as_sdl_surface(terrain->texture_paths()[j]);
> +
> +			// Set the minimap color on the first loaded image.
> +			if (j == 0) {
> +				uint8_t top_left_pixel = static_cast<uint8_t*>(sdl_surface->pixels)[0];
> +				const SDL_Color top_left_pixel_color =
> +				   sdl_surface->format->palette->colors[top_left_pixel];
> +				terrain->set_minimap_color(
> +				   RGBColor(top_left_pixel_color.r, top_left_pixel_color.g, top_left_pixel_color.b));
> +			}
> +			individual_textures_.emplace_back(new Texture(sdl_surface));
> +			ta.add(*individual_textures_.back());
> +		}
> +	}
> +
> +	std::vector<std::unique_ptr<Texture>> textures;
> +	terrain_texture_ = ta.pack(&textures);
> +
> +	int next_texture_to_move = 0;
> +	for (size_t i = 0; i < terrains_->size(); ++i) {
> +		TerrainDescription* terrain = terrains_->get_mutable(i);
> +		for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
> +			terrain->add_texture(std::move(textures.at(next_texture_to_move++)));
> +		}
> +	}
> +}
> +
>  const DescriptionMaintainer<TerrainDescription>& World::terrains() const {
>  	return *terrains_;
>  }
> 
> === modified file 'src/logic/world/world.h'
> --- src/logic/world/world.h	2014-09-10 10:18:46 +0000
> +++ src/logic/world/world.h	2014-11-28 07:21:07 +0000
> @@ -23,11 +23,16 @@
>  #include <memory>
>  
>  #include "base/macros.h"
> -#include "logic/bob.h"
>  #include "logic/description_maintainer.h"
> +#include "logic/widelands.h"
> +
> +class LuaInterface;
> +class LuaTable;
> +class Texture;
>  
>  namespace Widelands {
>  
> +class BobDescr;
>  class EditorCategory;
>  class EditorGameBase;
>  class ResourceDescription;
> @@ -40,7 +45,7 @@
>  class World {
>  public:
>  	World();
> -	~World();  // Defined in .cc because all forward declarations are known then.
> +	~World();
>  
>  	// TODO(sirver): Refactor these to only return the description_maintainer so that world
>  	// becomes a pure container.
> @@ -83,6 +88,10 @@
>  	const DescriptionMaintainer<EditorCategory>& editor_terrain_categories() const;
>  	const DescriptionMaintainer<EditorCategory>& editor_immovable_categories() const;
>  
> +	// Load the graphics for the world. Animations are loaded on
> +	// demand.
> +	void load_graphics();
> +
>  private:
>  	std::unique_ptr<DescriptionMaintainer<BobDescr>> bobs_;
>  	std::unique_ptr<DescriptionMaintainer<ImmovableDescr>> immovables_;
> @@ -90,6 +99,7 @@
>  	std::unique_ptr<DescriptionMaintainer<ResourceDescription>> resources_;
>  	std::unique_ptr<DescriptionMaintainer<EditorCategory>> editor_terrain_categories_;
>  	std::unique_ptr<DescriptionMaintainer<EditorCategory>> editor_immovable_categories_;
> +	std::unique_ptr<Texture> terrain_texture_;
>  
>  	DISALLOW_COPY_AND_ASSIGN(World);
>  };
> 
> === modified file 'src/wui/interactive_base.cc'
> --- src/wui/interactive_base.cc	2014-11-27 11:15:34 +0000
> +++ src/wui/interactive_base.cc	2014-11-28 07:21:07 +0000
> @@ -446,7 +446,10 @@
>  			((fps_format %
>  			  (1000.0 / m_frametime) % (1000.0 / (m_avg_usframetime / 1000)))
>  			 .str(), UI_FONT_SIZE_SMALL);
> -		dst.blit(Point(5, (is_game) ? 25 : 5), UI::g_fh1->render(fps_text), BlendMode::UseAlpha, UI::Align_Left);
> +		dst.blit(Point(5, (is_game) ? 25 : 5),
> +		         UI::g_fh1->render(fps_text),
> +		         BlendMode::UseAlpha,
> +		         UI::Align_Left);
>  	}
>  }
>  
> 


-- 
https://code.launchpad.net/~widelands-dev/widelands/texture_atlas/+merge/243119
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/texture_atlas.


References