widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #03241
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