Merge lp:~widelands-dev/widelands/texture_atlas into lp:widelands

Proposed by SirVer
Status: Merged
Merged at revision: 7294
Proposed branch: lp:~widelands-dev/widelands/texture_atlas
Merge into: lp:widelands
Diff against target: 2052 lines (+661/-464)
32 files modified
src/editor/editorinteractive.cc (+0/-2)
src/editor/tools/editor_info_tool.cc (+0/-1)
src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc (+6/-6)
src/graphic/CMakeLists.txt (+10/-5)
src/graphic/gl/dither_program.cc (+107/-93)
src/graphic/gl/dither_program.h (+21/-12)
src/graphic/gl/game_renderer.cc (+4/-5)
src/graphic/gl/terrain_program.cc (+64/-53)
src/graphic/gl/terrain_program.h (+17/-16)
src/graphic/graphic.cc (+0/-43)
src/graphic/graphic.h (+0/-12)
src/graphic/minimap_renderer.cc (+2/-4)
src/graphic/surface.cc (+12/-1)
src/graphic/terrain_texture.cc (+0/-97)
src/graphic/terrain_texture.h (+0/-62)
src/graphic/texture.cc (+35/-12)
src/graphic/texture.h (+15/-0)
src/graphic/texture_atlas.cc (+154/-0)
src/graphic/texture_atlas.h (+78/-0)
src/logic/CMakeLists.txt (+3/-0)
src/logic/description_maintainer.h (+4/-0)
src/logic/editor_game_base.cc (+4/-2)
src/logic/field.cc (+1/-1)
src/logic/game.cc (+0/-3)
src/logic/instances.cc (+1/-0)
src/logic/tribe.cc (+1/-0)
src/logic/world/terrain_description.cc (+40/-12)
src/logic/world/terrain_description.h (+28/-8)
src/logic/world/world.cc (+40/-12)
src/logic/world/world.h (+12/-2)
src/network/nethost.cc (+1/-0)
src/ui_fsmenu/options.cc (+1/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/texture_atlas
Reviewer Review Type Date Requested Status
GunChleoc Approve
SirVer Needs Resubmitting
Tino Needs Fixing
Review via email: mp+243119@code.launchpad.net

Description of the change

Suggested commit message:

- Adds a TextureAtlas bin packer and packs the terrain textures into one OpenGL texture. This needed more features in class Texture: a Texture can now also be a rectangle in another, bigger texture.
- Changed the terrain rendering to use this new texture. This is the fastest terrain rendering we ever had.
- class Graphic no longer owns map textures and animates them. They are owned by their TerrainDescription class and animation is done through handing gametime through to this class. This cleaned it up quite a bit.

To post a comment you must log in.
Revision history for this message
Tino (tino79) wrote :

It does only compile with an additional include, see diff comment.
(Just trying to diff comment the first time ;) )

review: Needs Fixing
Revision history for this message
Tino (tino79) wrote :

Switching to fullscreen is now blazing fast, nice!
800x600 window -> 1920x1200

But:
- F11 does only produce black pngs, both in window and fullscreen mode
- The Debug overlay "Position" moves correctly to the down right edge in fullscreen
- The gamspeed overlay and the chat don't move

Revision history for this message
SirVer (sirver) wrote :

I added the algorithm include. It is needed for std::sort according to the documentation and was missing in other files too.

The other points you mention are unlikely to be caused by this change, so I'd rather not block on it. Could you verify that they are in trunk already and if so file a bug and assign it to me? The moving UI stuff should be easy, the other I have to investigate.

review: Needs Resubmitting
Revision history for this message
GunChleoc (gunchleoc) wrote :

Bugs for Tino's issues have been filed:

https://bugs.launchpad.net/widelands/+bug/1397301
https://bugs.launchpad.net/widelands/+bug/1397302

I am getting compiler warnings:

src/graphic/image_cache.cc:40:13: warning: declaration of ‘texture’ shadows a member of 'this' [-Wshadow]
    Texture* texture = reload_image_();
             ^
src/graphic/image_cache.cc:51:12: warning: declaration of ‘texture’ shadows a member of 'this' [-Wshadow]
   Texture* texture = texture_cache_->get(filename_);
            ^
src/graphic/image_cache.cc:59:12: warning: declaration of ‘texture’ shadows a member of 'this' [-Wshadow]
   Texture* texture = texture_cache_->insert(filename_, load_image(filename_), false);

src/graphic/graphic.cc:66:71: warning: declaration of ‘fullscreen’ shadows a member of 'this' [-Wshadow]
 Graphic::Graphic(int window_mode_w, int window_mode_h, bool fullscreen)

src/graphic/image_transformations.cc:306:12: warning: declaration of ‘texture’ shadows a member of 'this' [-Wshadow]
   Texture* texture = texture_cache_->get(hash_);
            ^
src/graphic/in_memory_image.cc:41:55: warning: declaration of ‘texture’ shadows a member of 'this' [-Wshadow]
  InMemoryImage(const string& ghash, Texture* texture) :
                                                       ^

src/graphic/rendertarget.cc:247:18: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    while (tx < r.w) {
                  ^
src/graphic/rendertarget.cc:251:26: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     if (tx + srcrc.w > r.w)
                          ^

Revision history for this message
GunChleoc (gunchleoc) wrote :

I just noticed that the compiler warnings come up on trunk as well, so they're not caused by this particular branch.

Revision history for this message
SirVer (sirver) wrote :

They do not come up with clang. Could you fix them in trunk?

Can this be merged then? I think all comments are sorted out.

> Am 29.11.2014 um 10:32 schrieb GunChleoc <email address hidden>:
>
> I just noticed that the compiler warnings come up on trunk as well, so they're not caused by this particular branch.
> --
> https://code.launchpad.net/~widelands-dev/widelands/texture_atlas/+merge/243119
> You proposed lp:~widelands-dev/widelands/texture_atlas for merging.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I haven't had time to look over all of the code yet, but I've tested it and it seems to work fine. If you think that's sufficient, go ahead and merge. Otherwise, I'll try to have a look tomorrow. Brain's not working today.

Revision history for this message
SirVer (sirver) wrote :

I'd rather have a code review than having this in quickly. So take your time :).

Revision history for this message
GunChleoc (gunchleoc) wrote :

I added diff comments on lines 1244 and 1467 for things to double-check.

Revision history for this message
SirVer (sirver) wrote :

Addressed all comments and merged trunk.

review: Needs Resubmitting
Revision history for this message
GunChleoc (gunchleoc) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/editor/editorinteractive.cc'
2--- src/editor/editorinteractive.cc 2014-11-30 18:49:38 +0000
3+++ src/editor/editorinteractive.cc 2014-12-01 21:28:54 +0000
4@@ -243,8 +243,6 @@
5 frametime = m_realtime - lasttime;
6
7 egbase().get_gametime_pointer() += frametime;
8-
9- g_gr->animate_maptextures(egbase().get_gametime());
10 }
11
12
13
14=== modified file 'src/editor/tools/editor_info_tool.cc'
15--- src/editor/tools/editor_info_tool.cc 2014-10-13 10:48:33 +0000
16+++ src/editor/tools/editor_info_tool.cc 2014-12-01 21:28:54 +0000
17@@ -99,7 +99,6 @@
18 center.triangle.t == Widelands::TCoords<>::D ? tf.terrain_d() : tf.terrain_r());
19
20 buf += "• " + (boost::format(_("Name: %s")) % ter.descname()).str() + "\n";
21- buf += "• " + (boost::format(_("Texture Number: %i")) % ter.get_texture()).str() + "\n";
22
23 // *** Resources info
24 buf += std::string("\n") + _("Resources:") + "\n";
25
26=== modified file 'src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc'
27--- src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2014-11-24 07:25:21 +0000
28+++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2014-12-01 21:28:54 +0000
29@@ -30,7 +30,6 @@
30 #include "graphic/graphic.h"
31 #include "graphic/in_memory_image.h"
32 #include "graphic/rendertarget.h"
33-#include "graphic/terrain_texture.h"
34 #include "graphic/texture.h"
35 #include "logic/map.h"
36 #include "logic/world/editor_category.h"
37@@ -75,11 +74,12 @@
38 if (ter_is != check[checkfor])
39 continue;
40
41- const Image* tex = g_gr->images().get(
42- g_gr->get_maptexture_data(terrain_descr.get_texture())->get_texture_image());
43- Texture* texture = new Texture(tex->width(), tex->height());
44- texture->blit(Point(0, 0), tex->texture(), Rect(0, 0, tex->width(), tex->height()), BlendMode::Copy);
45- Point pt(1, tex->height() - kSmallPicHeight - 1);
46+ const Texture& terrain_texture = terrain_descr.get_texture(0);
47+ Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
48+ texture->blit(Point(0, 0),
49+ &terrain_texture,
50+ Rect(0, 0, terrain_texture.width(), terrain_texture.height()));
51+ Point pt(1, terrain_texture.height() - kSmallPicHeight - 1);
52
53 if (ter_is == TerrainDescription::GREEN) {
54 texture->blit(pt, green->texture(), Rect(0, 0, green->width(), green->height()));
55
56=== modified file 'src/graphic/CMakeLists.txt'
57--- src/graphic/CMakeLists.txt 2014-11-28 16:40:55 +0000
58+++ src/graphic/CMakeLists.txt 2014-12-01 21:28:54 +0000
59@@ -28,7 +28,6 @@
60 image_cache.cc
61 image_cache.h
62 USES_SDL2
63- USES_SDL2_IMAGE
64 DEPENDS
65 base_log
66 base_macros
67@@ -68,6 +67,16 @@
68 graphic_sdl_utils
69 )
70
71+wl_library(graphic_texture_atlas
72+ SRCS
73+ texture_atlas.h
74+ texture_atlas.cc
75+ DEPENDS
76+ base_exceptions
77+ base_macros
78+ graphic_surface
79+)
80+
81 wl_library(graphic
82 SRCS
83 align.cc
84@@ -116,8 +125,6 @@
85 rendertarget.h
86 richtext.cc
87 richtext.h
88- terrain_texture.cc
89- terrain_texture.h
90 text_parser.cc
91 text_parser.h
92 wordwrap.cc
93@@ -125,7 +132,6 @@
94 USES_OPENGL
95 USES_SDL2
96 USES_SDL2_GFX
97- USES_SDL2_IMAGE
98 USES_SDL2_TTF
99 DEPENDS
100 base_exceptions
101@@ -149,7 +155,6 @@
102 profile
103 scripting
104 sound
105- ui_basic
106 wui
107 wui_text_layout
108 )
109
110=== modified file 'src/graphic/gl/dither_program.cc'
111--- src/graphic/gl/dither_program.cc 2014-11-24 07:10:03 +0000
112+++ src/graphic/gl/dither_program.cc 2014-12-01 21:28:54 +0000
113@@ -21,35 +21,33 @@
114
115 #include "base/wexception.h"
116 #include "graphic/gl/fields_to_draw.h"
117-#include "graphic/graphic.h"
118 #include "graphic/image_io.h"
119-#include "graphic/terrain_texture.h"
120 #include "graphic/texture.h"
121-#include "io/fileread.h"
122 #include "io/filesystem/layered_filesystem.h"
123
124 namespace {
125
126-using namespace Widelands;
127-
128 const char kDitherVertexShader[] = R"(
129 #version 120
130
131 // Attributes.
132 attribute float attr_brightness;
133+attribute vec2 attr_dither_texture_position;
134 attribute vec2 attr_position;
135+attribute vec2 attr_texture_offset;
136 attribute vec2 attr_texture_position;
137-attribute vec2 attr_dither_texture_position;
138
139 // Output of vertex shader.
140+varying float var_brightness;
141+varying vec2 var_dither_texture_position;
142+varying vec2 var_texture_offset;
143 varying vec2 var_texture_position;
144-varying vec2 var_dither_texture_position;
145-varying float var_brightness;
146
147 void main() {
148+ var_brightness = attr_brightness;
149+ var_dither_texture_position = attr_dither_texture_position;
150+ var_texture_offset = attr_texture_offset;
151 var_texture_position = attr_texture_position;
152- var_dither_texture_position = attr_dither_texture_position;
153- var_brightness = attr_brightness;
154 gl_Position = vec4(attr_position, 0., 1.);
155 }
156 )";
157@@ -59,52 +57,62 @@
158
159 uniform sampler2D u_dither_texture;
160 uniform sampler2D u_terrain_texture;
161+uniform vec2 u_texture_dimensions;
162
163 varying float var_brightness;
164+varying vec2 var_dither_texture_position;
165 varying vec2 var_texture_position;
166-varying vec2 var_dither_texture_position;
167+varying vec2 var_texture_offset;
168
169 void main() {
170- vec4 clr = texture2D(u_terrain_texture, var_texture_position);
171+ vec4 clr = texture2D(u_terrain_texture,
172+ var_texture_offset + u_texture_dimensions * fract(var_texture_position));
173 clr.rgb *= var_brightness;
174 clr.a = 1. - texture2D(u_dither_texture, var_dither_texture_position).a;
175 gl_FragColor = clr;
176 }
177 )";
178
179-
180 } // namespace
181
182 DitherProgram::DitherProgram() {
183 gl_program_.build(kDitherVertexShader, kDitherFragmentShader);
184
185 attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
186- attr_dither_texture_position_ =
187- glGetAttribLocation(gl_program_.object(), "attr_dither_texture_position");
188+ attr_dither_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_dither_texture_position");
189 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
190- attr_texture_position_ =
191- glGetAttribLocation(gl_program_.object(), "attr_texture_position");
192+ attr_texture_offset_ = glGetAttribLocation(gl_program_.object(), "attr_texture_offset");
193+ attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
194
195 u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");
196 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
197-
198- SDL_Surface* sdlsurf = load_image_as_sdl_surface("world/pics/edge.png", g_fs);
199- dither_mask_.reset(new Texture(sdlsurf, true));
200+ u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
201+
202+ dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));
203+
204+ glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
205+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
206+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
207+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
208+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
209+ glBindTexture(GL_TEXTURE_2D, 0);
210 }
211
212 DitherProgram::~DitherProgram() {}
213
214 void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
215 const int order_index,
216- const int terrain) {
217- vertices_[terrain].emplace_back();
218- PerVertexData& back = vertices_[terrain].back();
219+ const FloatPoint& texture_offset) {
220+ vertices_.emplace_back();
221+ PerVertexData& back = vertices_.back();
222
223 back.gl_x = field.gl_x;
224 back.gl_y = field.gl_y;
225 back.texture_x = field.texture_x;
226 back.texture_y = field.texture_y;
227 back.brightness = field.brightness;
228+ back.texture_offset_x = texture_offset.x;
229+ back.texture_offset_y = texture_offset.y;
230
231 switch (order_index) {
232 case 0:
233@@ -125,6 +133,7 @@
234 }
235
236 void DitherProgram::maybe_add_dithering_triangle(
237+ const uint32_t gametime,
238 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
239 const FieldsToDraw& fields_to_draw,
240 const int idx1,
241@@ -135,29 +144,82 @@
242 if (my_terrain == other_terrain) {
243 return;
244 }
245+ const Widelands::TerrainDescription& other_terrain_description =
246+ terrains.get_unmutable(other_terrain);
247 if (terrains.get_unmutable(my_terrain).dither_layer() <
248- terrains.get_unmutable(other_terrain).dither_layer()) {
249- add_vertex(fields_to_draw.at(idx1), 0, other_terrain);
250- add_vertex(fields_to_draw.at(idx2), 1, other_terrain);
251- add_vertex(fields_to_draw.at(idx3), 2, other_terrain);
252+ other_terrain_description.dither_layer()) {
253+ const FloatPoint texture_offset =
254+ other_terrain_description.get_texture(gametime).texture_coordinates().top_left();
255+ add_vertex(fields_to_draw.at(idx1), 0, texture_offset);
256+ add_vertex(fields_to_draw.at(idx2), 1, texture_offset);
257+ add_vertex(fields_to_draw.at(idx3), 2, texture_offset);
258 }
259 }
260
261-void DitherProgram::draw(const DescriptionMaintainer<TerrainDescription>& terrains,
262- const FieldsToDraw& fields_to_draw) {
263+void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
264 glUseProgram(gl_program_.object());
265
266 glEnableVertexAttribArray(attr_brightness_);
267 glEnableVertexAttribArray(attr_dither_texture_position_);
268 glEnableVertexAttribArray(attr_position_);
269+ glEnableVertexAttribArray(attr_texture_offset_);
270 glEnableVertexAttribArray(attr_texture_position_);
271
272- if (vertices_.size() != terrains.size()) {
273- vertices_.resize(terrains.size());
274- }
275- for (auto& container : vertices_) {
276- container.clear();
277- }
278+ glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
279+ glBufferData(GL_ARRAY_BUFFER,
280+ sizeof(PerVertexData) * vertices_.size(),
281+ vertices_.data(),
282+ GL_STREAM_DRAW);
283+
284+ const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
285+ glVertexAttribPointer(vertex_index,
286+ num_items,
287+ GL_FLOAT,
288+ GL_FALSE,
289+ sizeof(PerVertexData),
290+ reinterpret_cast<void*>(offset));
291+ };
292+ set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
293+ set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
294+ set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
295+ set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
296+ set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
297+
298+ glBindBuffer(GL_ARRAY_BUFFER, 0);
299+
300+ // Set the sampler texture unit to 0
301+ glActiveTexture(GL_TEXTURE0);
302+ glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
303+
304+ glActiveTexture(GL_TEXTURE1);
305+ glBindTexture(GL_TEXTURE_2D, gl_texture);
306+
307+ glUniform1i(u_dither_texture_, 0);
308+ glUniform1i(u_terrain_texture_, 1);
309+ glUniform2f(u_texture_dimensions_, texture_w, texture_h);
310+
311+ glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
312+
313+ glBindTexture(GL_TEXTURE_2D, 0);
314+ glActiveTexture(GL_TEXTURE0);
315+ glBindTexture(GL_TEXTURE_2D, 0);
316+
317+ glDisableVertexAttribArray(attr_brightness_);
318+ glDisableVertexAttribArray(attr_dither_texture_position_);
319+ glDisableVertexAttribArray(attr_position_);
320+ glDisableVertexAttribArray(attr_texture_offset_);
321+ glDisableVertexAttribArray(attr_texture_position_);
322+}
323+
324+void DitherProgram::draw(const uint32_t gametime,
325+ const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
326+ const FieldsToDraw& fields_to_draw) {
327+ // This method expects that all terrains have the same dimensions and that
328+ // all are packed into the same texture atlas, i.e. all are in the same GL
329+ // texture. It does not check for this invariance for speeds sake.
330+
331+ vertices_.clear();
332+ vertices_.reserve(fields_to_draw.size() * 3);
333
334 for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
335 const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
336@@ -174,17 +236,17 @@
337 const int bln_index =
338 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
339 if (bln_index != -1) {
340- maybe_add_dithering_triangle(terrains, fields_to_draw,
341+ maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
342 brn_index, current_index, bln_index, field.ter_d, field.ter_r);
343
344 const int terrain_dd = fields_to_draw.at(bln_index).ter_r;
345- maybe_add_dithering_triangle(terrains, fields_to_draw,
346+ maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
347 bln_index, brn_index, current_index, field.ter_d, terrain_dd);
348
349 const int ln_index = fields_to_draw.calculate_index(field.fx - 1, field.fy);
350 if (ln_index != -1) {
351 const int terrain_l = fields_to_draw.at(ln_index).ter_r;
352- maybe_add_dithering_triangle(terrains, fields_to_draw,
353+ maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
354 current_index, bln_index, brn_index, field.ter_d, terrain_l);
355 }
356 }
357@@ -192,70 +254,22 @@
358 // Dithering for right triangle.
359 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
360 if (rn_index != -1) {
361- maybe_add_dithering_triangle(terrains, fields_to_draw,
362+ maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
363 current_index, brn_index, rn_index, field.ter_r, field.ter_d);
364 int terrain_rr = fields_to_draw.at(rn_index).ter_d;
365- maybe_add_dithering_triangle(terrains, fields_to_draw,
366- brn_index, rn_index, current_index, field.ter_r, terrain_rr);
367+ maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
368+ brn_index, rn_index, current_index, field.ter_r, terrain_rr);
369
370 const int trn_index =
371- fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
372+ fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
373 if (trn_index != -1) {
374 const int terrain_u = fields_to_draw.at(trn_index).ter_d;
375- maybe_add_dithering_triangle(terrains, fields_to_draw,
376+ maybe_add_dithering_triangle(gametime, terrains, fields_to_draw,
377 rn_index, current_index, brn_index, field.ter_r, terrain_u);
378 }
379 }
380 }
381
382- // Set the sampler texture unit to 0
383- glActiveTexture(GL_TEXTURE0);
384- glUniform1i(u_dither_texture_, 0);
385- glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
386- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
387- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
388-
389- glActiveTexture(GL_TEXTURE1);
390- glUniform1i(u_terrain_texture_, 1);
391-
392- // Which triangles to draw?
393- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
394- for (size_t i = 0; i < vertices_.size(); ++i) {
395- const auto& current_data = vertices_[i];
396- if (current_data.empty()) {
397- continue;
398- }
399- glBindTexture(GL_TEXTURE_2D,
400- g_gr->get_maptexture_data(terrains.get_unmutable(i).get_texture())
401- ->texture()
402- .get_gl_texture());
403-
404- glBufferData(GL_ARRAY_BUFFER,
405- sizeof(PerVertexData) * current_data.size(),
406- current_data.data(),
407- GL_STREAM_DRAW);
408-
409- const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
410- glVertexAttribPointer(vertex_index,
411- num_items,
412- GL_FLOAT,
413- GL_FALSE,
414- sizeof(PerVertexData),
415- reinterpret_cast<void*>(offset));
416- };
417- set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
418- set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
419- set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
420- set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
421-
422- glDrawArrays(GL_TRIANGLES, 0, current_data.size());
423- }
424- glBindBuffer(GL_ARRAY_BUFFER, 0);
425-
426- glDisableVertexAttribArray(attr_brightness_);
427- glDisableVertexAttribArray(attr_dither_texture_position_);
428- glDisableVertexAttribArray(attr_position_);
429- glDisableVertexAttribArray(attr_texture_position_);
430-
431- glActiveTexture(GL_TEXTURE0);
432+ const Texture& texture = terrains.get_unmutable(0).get_texture(0);
433+ gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
434 }
435
436=== modified file 'src/graphic/gl/dither_program.h'
437--- src/graphic/gl/dither_program.h 2014-11-24 07:10:03 +0000
438+++ src/graphic/gl/dither_program.h 2014-12-01 21:28:54 +0000
439@@ -22,6 +22,7 @@
440
441 #include <memory>
442
443+#include "base/point.h"
444 #include "graphic/gl/fields_to_draw.h"
445 #include "graphic/gl/utils.h"
446 #include "logic/description_maintainer.h"
447@@ -35,14 +36,16 @@
448 ~DitherProgram();
449
450 // Draws the terrain.
451- void draw(const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
452+ void draw(uint32_t gametime,
453+ const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
454 const FieldsToDraw& fields_to_draw);
455
456 private:
457- // Adds the triangle between the indexes (which index 'fields_to_draw' to
458+ // Adds the triangle between the indexes (which index 'fields_to_draw') to
459 // vertices_ if the my_terrain != other_terrain and the dither_layer()
460 // agree.
461 void maybe_add_dithering_triangle(
462+ uint32_t gametime,
463 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
464 const FieldsToDraw& fields_to_draw,
465 int idx1,
466@@ -51,10 +54,10 @@
467 int my_terrain,
468 int other_terrain);
469
470- // Adds the 'field' as an vertex to the 'vertices_' entry for 'terrain'. The
471- // 'order_index' defines which texture position will be used for this
472- // vertcx.
473- void add_vertex(const FieldsToDraw::Field& field, int order_index, int terrain);
474+ // Adds the 'field' as an vertex to the 'vertices_'. The 'order_index'
475+ // defines which texture position in the dithering texture will be used for
476+ // this vertex.
477+ void add_vertex(const FieldsToDraw::Field& field, int order_index, const FloatPoint& texture_offset);
478
479 struct PerVertexData {
480 float gl_x;
481@@ -64,8 +67,13 @@
482 float brightness;
483 float dither_texture_x;
484 float dither_texture_y;
485+ float texture_offset_x;
486+ float texture_offset_y;
487 };
488
489+ // Call through to GL.
490+ void gl_draw(int gl_texture, float texture_w, float texture_h);
491+
492 // The program used for drawing the terrain.
493 Gl::Program gl_program_;
494
495@@ -73,22 +81,23 @@
496 Gl::Buffer gl_array_buffer_;
497
498 // Attributes.
499+ GLint attr_brightness_;
500+ GLint attr_dither_texture_position_;
501 GLint attr_position_;
502+ GLint attr_texture_offset_;
503 GLint attr_texture_position_;
504- GLint attr_dither_texture_position_;
505- GLint attr_brightness_;
506
507 // Uniforms.
508+ GLint u_dither_texture_;
509 GLint u_terrain_texture_;
510- GLint u_dither_texture_;
511+ GLint u_texture_dimensions_;
512
513 // The texture mask for the dithering step.
514 std::unique_ptr<Texture> dither_mask_;
515
516 // Objects below are here to avoid memory allocations on each frame, they
517- // could theoretically also always be recreated. Index as follows:
518- // vertices_[terrain_index][vertex_index]
519- std::vector<std::vector<PerVertexData>> vertices_;
520+ // could theoretically also always be recreated.
521+ std::vector<PerVertexData> vertices_;
522 };
523
524 #endif // end of include guard: WL_GRAPHIC_GL_DITHER_PROGRAM_H
525
526=== modified file 'src/graphic/gl/game_renderer.cc'
527--- src/graphic/gl/game_renderer.cc 2014-11-24 06:21:16 +0000
528+++ src/graphic/gl/game_renderer.cc 2014-12-01 21:28:54 +0000
529@@ -28,7 +28,6 @@
530 #include "graphic/graphic.h"
531 #include "graphic/rendertarget.h"
532 #include "graphic/surface.h"
533-#include "graphic/terrain_texture.h"
534 #include "logic/editor_game_base.h"
535 #include "logic/player.h"
536 #include "logic/world/world.h"
537@@ -165,8 +164,8 @@
538 map.normalize_coords(coords);
539 const FCoords& fcoords = map.get_fcoords(coords);
540
541- f.texture_x = float(x) / kTextureWidth;
542- f.texture_y = float(y) / kTextureHeight;
543+ f.texture_x = float(x) / kTextureSideLength;
544+ f.texture_y = float(y) / kTextureSideLength;
545
546 f.gl_x = f.pixel_x = x + surface_offset.x;
547 f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;
548@@ -182,8 +181,8 @@
549 }
550
551 const World& world = m_egbase->world();
552- terrain_program_->draw(world.terrains(), fields_to_draw);
553- dither_program_->draw(world.terrains(), fields_to_draw);
554+ terrain_program_->draw(gametime, world.terrains(), fields_to_draw);
555+ dither_program_->draw(gametime, world.terrains(), fields_to_draw);
556 road_program_->draw(*surface, fields_to_draw);
557
558 draw_objects();
559
560=== modified file 'src/graphic/gl/terrain_program.cc'
561--- src/graphic/gl/terrain_program.cc 2014-11-24 07:10:03 +0000
562+++ src/graphic/gl/terrain_program.cc 2014-12-01 21:28:54 +0000
563@@ -20,8 +20,6 @@
564 #include "graphic/gl/terrain_program.h"
565
566 #include "graphic/gl/fields_to_draw.h"
567-#include "graphic/graphic.h"
568-#include "graphic/terrain_texture.h"
569 #include "graphic/texture.h"
570
571 namespace {
572@@ -37,17 +35,20 @@
573 #version 120
574
575 // Attributes.
576+attribute float attr_brightness;
577 attribute vec2 attr_position;
578-attribute float attr_brightness;
579+attribute vec2 attr_texture_offset;
580 attribute vec2 attr_texture_position;
581
582 // Output of vertex shader.
583 varying float var_brightness;
584+varying vec2 var_texture_offset;
585 varying vec2 var_texture_position;
586
587 void main() {
588 var_texture_position = attr_texture_position;
589 var_brightness = attr_brightness;
590+ var_texture_offset = attr_texture_offset;
591 gl_Position = vec4(attr_position, 0., 1.);
592 }
593 )";
594@@ -56,12 +57,15 @@
595 #version 120
596
597 uniform sampler2D u_terrain_texture;
598+uniform vec2 u_texture_dimensions;
599
600 varying float var_brightness;
601 varying vec2 var_texture_position;
602+varying vec2 var_texture_offset;
603
604 void main() {
605- vec4 clr = texture2D(u_terrain_texture, var_texture_position);
606+ vec4 clr = texture2D(u_terrain_texture,
607+ var_texture_offset + u_texture_dimensions * fract(var_texture_position));
608 clr.rgb *= var_brightness;
609 gl_FragColor = clr;
610 }
611@@ -72,25 +76,26 @@
612 TerrainProgram::TerrainProgram() {
613 gl_program_.build(kTerrainVertexShader, kTerrainFragmentShader);
614
615+ attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
616 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
617- attr_texture_position_ =
618- glGetAttribLocation(gl_program_.object(), "attr_texture_position");
619- attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
620+ attr_texture_offset_ = glGetAttribLocation(gl_program_.object(), "attr_texture_offset");
621+ attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
622
623 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
624+ u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
625 }
626
627-void TerrainProgram::gl_draw(int num_vertices,
628- const DescriptionMaintainer<TerrainDescription>& terrains) {
629+void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
630 glUseProgram(gl_program_.object());
631
632+ glEnableVertexAttribArray(attr_brightness_);
633 glEnableVertexAttribArray(attr_position_);
634+ glEnableVertexAttribArray(attr_texture_offset_);
635 glEnableVertexAttribArray(attr_texture_position_);
636- glEnableVertexAttribArray(attr_brightness_);
637
638 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
639 glBufferData(GL_ARRAY_BUFFER,
640- sizeof(TerrainProgram::PerVertexData) * num_vertices,
641+ sizeof(TerrainProgram::PerVertexData) * vertices_.size(),
642 vertices_.data(),
643 GL_STREAM_DRAW);
644
645@@ -102,55 +107,56 @@
646 sizeof(TerrainProgram::PerVertexData),
647 reinterpret_cast<void*>(offset));
648 };
649+ set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
650 set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
651- set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
652+ set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
653 set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
654
655 glBindBuffer(GL_ARRAY_BUFFER, 0);
656
657- // Set the sampler texture unit to 0
658 glActiveTexture(GL_TEXTURE0);
659+ glBindTexture(GL_TEXTURE_2D, gl_texture);
660+
661 glUniform1i(u_terrain_texture_, 0);
662-
663- // Which triangles to draw?
664- for (size_t i = 0; i < terrains_to_indices_.size(); ++i) {
665- const auto& indices = terrains_to_indices_[i];
666- if (indices.empty()) {
667- continue;
668- }
669- glBindTexture(GL_TEXTURE_2D,
670- g_gr->get_maptexture_data(terrains.get_unmutable(i).get_texture())
671- ->texture()
672- .get_gl_texture());
673- glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, indices.data());
674- }
675-
676+ glUniform2f(u_texture_dimensions_, texture_w, texture_h);
677+
678+ glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
679+
680+ glBindTexture(GL_TEXTURE_2D, 0);
681+
682+ glDisableVertexAttribArray(attr_brightness_);
683 glDisableVertexAttribArray(attr_position_);
684+ glDisableVertexAttribArray(attr_texture_offset_);
685 glDisableVertexAttribArray(attr_texture_position_);
686- glDisableVertexAttribArray(attr_brightness_);
687-}
688-
689-void TerrainProgram::draw(const DescriptionMaintainer<TerrainDescription>& terrains,
690+}
691+
692+void TerrainProgram::add_vertex(const FieldsToDraw::Field& field,
693+ const FloatPoint& texture_offset) {
694+ vertices_.emplace_back();
695+ PerVertexData& back = vertices_.back();
696+
697+ back.gl_x = field.gl_x;
698+ back.gl_y = field.gl_y;
699+ back.brightness = field.brightness;
700+ back.texture_x = field.texture_x;
701+ back.texture_y = field.texture_y;
702+ back.texture_offset_x = texture_offset.x;
703+ back.texture_offset_y = texture_offset.y;
704+}
705+
706+void TerrainProgram::draw(uint32_t gametime,
707+ const DescriptionMaintainer<TerrainDescription>& terrains,
708 const FieldsToDraw& fields_to_draw) {
709- if (vertices_.size() < fields_to_draw.size()) {
710- vertices_.resize(fields_to_draw.size());
711- terrains_to_indices_.resize(terrains.size());
712- }
713- for (auto& container : terrains_to_indices_) {
714- container.clear();
715- container.reserve(fields_to_draw.size());
716- }
717+ // This method expects that all terrains have the same dimensions and that
718+ // all are packed into the same texture atlas, i.e. all are in the same GL
719+ // texture. It does not check for this invariance for speeds sake.
720+
721+ vertices_.clear();
722+ vertices_.reserve(fields_to_draw.size() * 3);
723
724 for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
725 const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
726
727- PerVertexData& vertex = vertices_[current_index];
728- vertex.texture_x = field.texture_x;
729- vertex.texture_y = field.texture_y;
730- vertex.gl_x = field.gl_x;
731- vertex.gl_y = field.gl_y;
732- vertex.brightness = field.brightness;
733-
734 // The bottom right neighbor fields_to_draw is needed for both triangles
735 // associated with this field. If it is not in fields_to_draw, there is no need to
736 // draw any triangles.
737@@ -163,19 +169,24 @@
738 const int bln_index =
739 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
740 if (bln_index != -1) {
741- terrains_to_indices_[field.ter_d].push_back(current_index);
742- terrains_to_indices_[field.ter_d].push_back(bln_index);
743- terrains_to_indices_[field.ter_d].push_back(brn_index);
744+ const FloatPoint texture_offset =
745+ terrains.get_unmutable(field.ter_d).get_texture(gametime).texture_coordinates().top_left();
746+ add_vertex(fields_to_draw.at(current_index), texture_offset);
747+ add_vertex(fields_to_draw.at(bln_index), texture_offset);
748+ add_vertex(fields_to_draw.at(brn_index), texture_offset);
749 }
750
751 // Right triangle.
752 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
753 if (rn_index != -1) {
754- terrains_to_indices_[field.ter_r].push_back(current_index);
755- terrains_to_indices_[field.ter_r].push_back(brn_index);
756- terrains_to_indices_[field.ter_r].push_back(rn_index);
757+ const FloatPoint texture_offset =
758+ terrains.get_unmutable(field.ter_r).get_texture(gametime).texture_coordinates().top_left();
759+ add_vertex(fields_to_draw.at(current_index), texture_offset);
760+ add_vertex(fields_to_draw.at(brn_index), texture_offset);
761+ add_vertex(fields_to_draw.at(rn_index), texture_offset);
762 }
763 }
764
765- gl_draw(fields_to_draw.size(), terrains);
766+ const Texture& texture = terrains.get_unmutable(0).get_texture(0);
767+ gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
768 }
769
770=== modified file 'src/graphic/gl/terrain_program.h'
771--- src/graphic/gl/terrain_program.h 2014-11-08 18:06:17 +0000
772+++ src/graphic/gl/terrain_program.h 2014-12-01 21:28:54 +0000
773@@ -22,11 +22,12 @@
774
775 #include <vector>
776
777+#include "base/point.h"
778+#include "graphic/gl/fields_to_draw.h"
779 #include "graphic/gl/utils.h"
780 #include "logic/description_maintainer.h"
781 #include "logic/world/terrain_description.h"
782
783-class FieldsToDraw;
784
785 class TerrainProgram {
786 public:
787@@ -34,7 +35,7 @@
788 TerrainProgram();
789
790 // Draws the terrain.
791- void draw(const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
792+ void draw(uint32_t gametime, const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
793 const FieldsToDraw& fields_to_draw);
794
795 private:
796@@ -44,36 +45,36 @@
797 float brightness;
798 float texture_x;
799 float texture_y;
800+ float texture_offset_x;
801+ float texture_offset_y;
802 };
803- static_assert(sizeof(PerVertexData) == 20, "Wrong padding.");
804-
805- void gl_draw(int num_vertices,
806- const DescriptionMaintainer<Widelands::TerrainDescription>& terrains);
807+ static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
808+
809+ void gl_draw(int gl_texture, float texture_w, float texture_h);
810+
811+ // Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
812+ void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
813+
814+ // The program used for drawing the terrain.
815+ Gl::Program gl_program_;
816
817 // The buffer that will contain 'vertices_' for rendering.
818 Gl::Buffer gl_array_buffer_;
819
820- // The program used for drawing the terrain.
821- Gl::Program gl_program_;
822-
823 // Attributes.
824+ GLint attr_brightness_;
825 GLint attr_position_;
826+ GLint attr_texture_offset_;
827 GLint attr_texture_position_;
828- GLint attr_brightness_;
829
830 // Uniforms.
831 GLint u_terrain_texture_;
832+ GLint u_texture_dimensions_;
833
834 // Objects below are kept around to avoid memory allocations on each frame.
835 // They could theoretically also be recreated.
836-
837- // All vertices that are going to get rendered this frame.
838 std::vector<PerVertexData> vertices_;
839
840- // A map from terrain index in world.terrains() to indices in 'vertices_'
841- // that have this terrain type.
842- std::vector<std::vector<uint16_t>> terrains_to_indices_;
843-
844 DISALLOW_COPY_AND_ASSIGN(TerrainProgram);
845 };
846
847
848=== modified file 'src/graphic/graphic.cc'
849--- src/graphic/graphic.cc 2014-11-30 18:53:22 +0000
850+++ src/graphic/graphic.cc 2014-12-01 21:28:54 +0000
851@@ -19,20 +19,10 @@
852
853 #include "graphic/graphic.h"
854
855-#include <cstring>
856-#include <iostream>
857-#include <memory>
858-
859-#include <SDL_image.h>
860-
861-#include "base/i18n.h"
862 #include "base/log.h"
863-#include "base/macros.h"
864 #include "base/wexception.h"
865 #include "build_info.h"
866-#include "config.h"
867 #include "graphic/animation.h"
868-#include "graphic/diranimations.h"
869 #include "graphic/font_handler.h"
870 #include "graphic/gl/system_headers.h"
871 #include "graphic/image.h"
872@@ -40,15 +30,11 @@
873 #include "graphic/image_transformations.h"
874 #include "graphic/rendertarget.h"
875 #include "graphic/screen.h"
876-#include "graphic/terrain_texture.h"
877 #include "graphic/texture.h"
878 #include "graphic/texture_cache.h"
879-#include "io/fileread.h"
880 #include "io/filesystem/layered_filesystem.h"
881 #include "io/streamwrite.h"
882-#include "logic/roadtype.h"
883 #include "notifications/notifications.h"
884-#include "ui_basic/progresswindow.h"
885
886 using namespace std;
887
888@@ -161,7 +147,6 @@
889
890 Graphic::~Graphic()
891 {
892- m_maptextures.clear();
893 texture_cache_->flush();
894 // TODO(unknown): this should really not be needed, but currently is :(
895 if (UI::g_fh)
896@@ -302,22 +287,6 @@
897 save_surface_to_png(image->texture(), sw, COLOR_TYPE::RGBA);
898 }
899
900-uint32_t Graphic::new_maptexture(const std::vector<std::string>& texture_files, const uint32_t frametime)
901-{
902- m_maptextures.emplace_back(new TerrainTexture(texture_files, frametime));
903- return m_maptextures.size(); // ID 1 is at m_maptextures[0]
904-}
905-
906-/**
907- * Advance frames for animated textures
908-*/
909-void Graphic::animate_maptextures(uint32_t time)
910-{
911- for (uint32_t i = 0; i < m_maptextures.size(); ++i) {
912- m_maptextures[i]->animate(time);
913- }
914-}
915-
916 /**
917 * Save a screenshot to the given file.
918 */
919@@ -328,15 +297,3 @@
920 save_surface_to_png(screen_.get(), sw, COLOR_TYPE::RGB);
921 delete sw;
922 }
923-
924-/**
925- * Retrieve the map texture with the given number
926- * \return the actual texture data associated with the given ID.
927- */
928-TerrainTexture * Graphic::get_maptexture_data(uint32_t id)
929-{
930- --id; // ID 1 is at m_maptextures[0]
931-
932- assert(id < m_maptextures.size());
933- return m_maptextures[id].get();
934-}
935
936=== modified file 'src/graphic/graphic.h'
937--- src/graphic/graphic.h 2014-11-24 07:12:35 +0000
938+++ src/graphic/graphic.h 2014-12-01 21:28:54 +0000
939@@ -20,13 +20,10 @@
940 #ifndef WL_GRAPHIC_GRAPHIC_H
941 #define WL_GRAPHIC_GRAPHIC_H
942
943-#include <map>
944 #include <memory>
945-#include <vector>
946
947 #include <SDL.h>
948
949-#include "base/rect.h"
950 #include "graphic/image_cache.h"
951 #include "notifications/notifications.h"
952 #include "notifications/note_ids.h"
953@@ -38,7 +35,6 @@
954 class Surface;
955 class TextureCache;
956 class StreamWrite;
957-struct TerrainTexture;
958
959 // Will be send whenever the resolution changes.
960 struct GraphicResolutionChanged {
961@@ -83,13 +79,7 @@
962
963 void save_png(const Image*, StreamWrite*) const;
964
965- // Creates a new TerrainTexture() with the given 'frametime' and using the given
966- // 'texture_files' as the images for it and returns it id.
967- uint32_t new_maptexture(const std::vector<std::string>& texture_files, uint32_t frametime);
968- void animate_maptextures(uint32_t time);
969-
970 void screenshot(const std::string& fname) const;
971- TerrainTexture * get_maptexture_data(uint32_t id);
972
973 private:
974 // Called when the resolution (might) have changed.
975@@ -119,8 +109,6 @@
976 std::unique_ptr<ImageCache> image_cache_;
977 /// This holds all animations.
978 std::unique_ptr<AnimationManager> animation_manager_;
979-
980- std::vector<std::unique_ptr<TerrainTexture>> m_maptextures;
981 };
982
983 extern Graphic * g_gr;
984
985=== modified file 'src/graphic/minimap_renderer.cc'
986--- src/graphic/minimap_renderer.cc 2014-11-24 07:10:03 +0000
987+++ src/graphic/minimap_renderer.cc 2014-12-01 21:28:54 +0000
988@@ -27,7 +27,6 @@
989 #include "graphic/graphic.h"
990 #include "graphic/image.h"
991 #include "graphic/in_memory_image.h"
992-#include "graphic/terrain_texture.h"
993 #include "graphic/texture.h"
994 #include "logic/field.h"
995 #include "logic/map.h"
996@@ -61,9 +60,8 @@
997 uint32_t pixelcolor = 0;
998
999 if (layers & MiniMapLayer::Terrain) {
1000- const RGBColor color =
1001- g_gr->get_maptexture_data(egbase.world().terrain_descr(f.field->terrain_d()).get_texture())
1002- ->get_minimap_color(f.field->get_brightness());
1003+ const RGBColor& color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
1004+ f.field->get_brightness());
1005
1006 pixelcolor = SDL_MapRGBA(&format, color.r, color.g, color.b, 255);
1007 }
1008
1009=== modified file 'src/graphic/surface.cc'
1010--- src/graphic/surface.cc 2014-11-24 07:25:21 +0000
1011+++ src/graphic/surface.cc 2014-12-01 21:28:54 +0000
1012@@ -162,15 +162,26 @@
1013 {
1014 glViewport(0, 0, width(), height());
1015
1016- // Source Rectangle.
1017+ // Source Rectangle. We have to take into account that the texture might be
1018+ // a subtexture in another bigger texture. So we first figure out the pixel
1019+ // coordinates given it is a full texture (values between 0 and 1) and then
1020+ // adjust these for the texture coordinates in the parent texture.
1021 FloatRect gl_src_rect;
1022 {
1023+ const FloatRect& texture_coordinates = texture->texture_coordinates();
1024+
1025 float x1 = srcrc.x;
1026 float y1 = srcrc.y;
1027 pixel_to_gl_texture(texture->width(), texture->height(), &x1, &y1);
1028+ x1 = texture_coordinates.x + x1 * texture_coordinates.w;
1029+ y1 = texture_coordinates.y + y1 * texture_coordinates.h;
1030+
1031 float x2 = srcrc.x + srcrc.w;
1032 float y2 = srcrc.y + srcrc.h;
1033 pixel_to_gl_texture(texture->width(), texture->height(), &x2, &y2);
1034+ x2 = texture_coordinates.x + x2 * texture_coordinates.w;
1035+ y2 = texture_coordinates.y + y2 * texture_coordinates.h;
1036+
1037 gl_src_rect.x = x1;
1038 gl_src_rect.y = y1;
1039 gl_src_rect.w = x2 - x1;
1040
1041=== removed file 'src/graphic/terrain_texture.cc'
1042--- src/graphic/terrain_texture.cc 2014-11-28 16:40:55 +0000
1043+++ src/graphic/terrain_texture.cc 1970-01-01 00:00:00 +0000
1044@@ -1,97 +0,0 @@
1045-/*
1046- * Copyright (C) 2002-2004, 2006, 2010, 2012 by the Widelands Development Team
1047- *
1048- * This program is free software; you can redistribute it and/or
1049- * modify it under the terms of the GNU General Public License
1050- * as published by the Free Software Foundation; either version 2
1051- * of the License, or (at your option) any later version.
1052- *
1053- * This program is distributed in the hope that it will be useful,
1054- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1055- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1056- * GNU General Public License for more details.
1057- *
1058- * You should have received a copy of the GNU General Public License
1059- * along with this program; if not, write to the Free Software
1060- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1061- *
1062- */
1063-
1064-#include "graphic/terrain_texture.h"
1065-
1066-#include <SDL_image.h>
1067-
1068-#include "base/log.h"
1069-#include "base/wexception.h"
1070-#include "graphic/image_io.h"
1071-#include "graphic/texture.h"
1072-#include "io/fileread.h"
1073-#include "io/filesystem/layered_filesystem.h"
1074-
1075-using namespace std;
1076-
1077-/**
1078- * Create a texture, taking the pixel data from an Image.
1079- * Currently it converts a 16 bit image to a 8 bit texture. This should
1080- * be changed to load a 8 bit file directly, however.
1081- */
1082-TerrainTexture::TerrainTexture(const std::vector<std::string>& texture_files, const uint32_t frametime)
1083- : m_frame_num(0), m_frametime(frametime) {
1084- if (texture_files.empty()) {
1085- throw wexception("No images for texture.");
1086- }
1087-
1088- for (const std::string& fname : texture_files) {
1089- if (!g_fs->file_exists(fname)) {
1090- throw wexception("Could not find %s.", fname.c_str());
1091- }
1092-
1093- m_texture_image = fname;
1094- SDL_Surface* sdl_surface = load_image_as_sdl_surface(fname, g_fs);
1095- if (!sdl_surface) {
1096- throw wexception(
1097- "WARNING: Failed to load texture frame %s: %s\n", fname.c_str(), IMG_GetError());
1098- }
1099- if (sdl_surface->w != kTextureWidth || sdl_surface->h != kTextureHeight) {
1100- SDL_FreeSurface(sdl_surface);
1101- throw wexception("WARNING: %s: texture must be %ix%i pixels big\n",
1102- fname.c_str(),
1103- kTextureWidth,
1104- kTextureHeight);
1105- }
1106-
1107- // calculate shades on the first frame
1108- if (m_textures.empty()) {
1109- uint8_t top_left_pixel = static_cast<uint8_t*>(sdl_surface->pixels)[0];
1110- SDL_Color top_left_pixel_color = sdl_surface->format->palette->colors[top_left_pixel];
1111- for (int i = -128; i < 128; i++) {
1112- const int shade = 128 + i;
1113- int32_t r = std::min<int32_t>((top_left_pixel_color.r * shade) >> 7, 255);
1114- int32_t g = std::min<int32_t>((top_left_pixel_color.g * shade) >> 7, 255);
1115- int32_t b = std::min<int32_t>((top_left_pixel_color.b * shade) >> 7, 255);
1116- m_minimap_colors[shade] = RGBColor(r, g, b);
1117- }
1118- }
1119- m_textures.emplace_back(new Texture(sdl_surface));
1120- }
1121-
1122- if (m_textures.empty())
1123- throw wexception("TerrainTexture has no frames");
1124-}
1125-
1126-RGBColor TerrainTexture::get_minimap_color(int8_t shade) {
1127- return m_minimap_colors[128 + shade];
1128-}
1129-
1130-void TerrainTexture::animate(uint32_t time)
1131-{
1132- m_frame_num = (time / m_frametime) % m_textures.size();
1133-}
1134-
1135-const std::string& TerrainTexture::get_texture_image() const {
1136- return m_texture_image;
1137-}
1138-
1139-const Texture& TerrainTexture::texture() const {
1140- return *m_textures.at(m_frame_num);
1141-}
1142
1143=== removed file 'src/graphic/terrain_texture.h'
1144--- src/graphic/terrain_texture.h 2014-11-24 07:10:03 +0000
1145+++ src/graphic/terrain_texture.h 1970-01-01 00:00:00 +0000
1146@@ -1,62 +0,0 @@
1147-/*
1148- * Copyright (C) 2002-2004, 2006, 2008-2010, 2012 by the Widelands Development Team
1149- *
1150- * This program is free software; you can redistribute it and/or
1151- * modify it under the terms of the GNU General Public License
1152- * as published by the Free Software Foundation; either version 2
1153- * of the License, or (at your option) any later version.
1154- *
1155- * This program is distributed in the hope that it will be useful,
1156- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1157- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1158- * GNU General Public License for more details.
1159- *
1160- * You should have received a copy of the GNU General Public License
1161- * along with this program; if not, write to the Free Software
1162- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1163- *
1164- */
1165-
1166-#ifndef WL_GRAPHIC_TERRAIN_TEXTURE_H
1167-#define WL_GRAPHIC_TERRAIN_TEXTURE_H
1168-
1169-#include <memory>
1170-#include <string>
1171-#include <vector>
1172-
1173-#include <stdint.h>
1174-
1175-#include "graphic/colormap.h"
1176-
1177-class Texture;
1178-
1179-/// TerrainTextures have a fixed size and are squares.
1180-constexpr int kTextureWidth = 64;
1181-constexpr int kTextureHeight = kTextureWidth;
1182-
1183-// TerrainTexture represents are terrain texture, which is strictly kTextureWidth by
1184-// kTextureHeight pixels in size.
1185-struct TerrainTexture {
1186- TerrainTexture(const std::vector<std::string>& texture_files, uint32_t frametime);
1187-
1188- // Returns the path to a representative image for this texture.
1189- const std::string& get_texture_image() const;
1190-
1191- // Returns the texture for the current animation phase.
1192- const Texture& texture() const;
1193-
1194- // Return the basic terrain colour to be used in the minimap.
1195- RGBColor get_minimap_color(int8_t shade);
1196-
1197- // Set the current frame according to the game time.
1198- void animate(uint32_t time);
1199-
1200-private:
1201- RGBColor m_minimap_colors[256];
1202- int32_t m_frame_num;
1203- std::string m_texture_image;
1204- uint32_t m_frametime;
1205- std::vector<std::unique_ptr<Texture>> m_textures;
1206-};
1207-
1208-#endif // end of include guard: WL_GRAPHIC_TERRAIN_TEXTURE_H
1209
1210=== modified file 'src/graphic/texture.cc'
1211--- src/graphic/texture.cc 2014-11-24 07:25:21 +0000
1212+++ src/graphic/texture.cc 2014-12-01 21:28:54 +0000
1213@@ -72,11 +72,6 @@
1214
1215 } // namespace
1216
1217-/**
1218- * Initialize an OpenGL texture of the given dimensions.
1219- *
1220- * The initial data of the texture is undefined.
1221- */
1222 Texture::Texture(int w, int h)
1223 {
1224 init(w, h);
1225@@ -89,11 +84,6 @@
1226 GL_UNSIGNED_BYTE, nullptr);
1227 }
1228
1229-/**
1230- * Initialize an OpenGL texture with the contents of the given surface.
1231- *
1232- * \note Takes ownership of the given surface.
1233- */
1234 Texture::Texture(SDL_Surface * surface, bool intensity)
1235 {
1236 init(surface->w, surface->h);
1237@@ -132,9 +122,28 @@
1238 SDL_FreeSurface(surface);
1239 }
1240
1241+Texture::Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h) {
1242+ if (parent_w == 0 || parent_h == 0) {
1243+ throw wexception("Created a sub Texture with zero height and width parent.");
1244+ }
1245+
1246+ m_w = subrect.w;
1247+ m_h = subrect.h;
1248+
1249+ m_texture = texture;
1250+ m_owns_texture = false;
1251+
1252+ m_texture_coordinates.w = static_cast<float>(m_w - 1) / parent_w;
1253+ m_texture_coordinates.h = static_cast<float>(m_h - 1) / parent_h;
1254+ m_texture_coordinates.x = (static_cast<float>(subrect.x) + 0.5) / parent_w;
1255+ m_texture_coordinates.y = (static_cast<float>(subrect.y) + 0.5) / parent_h;
1256+}
1257+
1258 Texture::~Texture()
1259 {
1260- glDeleteTextures(1, &m_texture);
1261+ if (m_owns_texture) {
1262+ glDeleteTextures(1, &m_texture);
1263+ }
1264 }
1265
1266 void Texture::pixel_to_gl(float* x, float* y) const {
1267@@ -150,6 +159,12 @@
1268 return;
1269 }
1270
1271+ m_owns_texture = true;
1272+ m_texture_coordinates.x = 0.f;
1273+ m_texture_coordinates.y = 0.f;
1274+ m_texture_coordinates.w = 1.f;
1275+ m_texture_coordinates.h = 1.f;
1276+
1277 glGenTextures(1, &m_texture);
1278 glBindTexture(GL_TEXTURE_2D, m_texture);
1279
1280@@ -164,13 +179,20 @@
1281 if (m_w <= 0 || m_h <= 0) {
1282 return;
1283 }
1284- assert(!m_pixels);
1285+
1286+ if (m_pixels) {
1287+ throw wexception("Called lock() on locked surface.");
1288+ }
1289+ if (!m_owns_texture) {
1290+ throw wexception("A surface that does not own its pixels can not be locked..");
1291+ }
1292
1293 m_pixels.reset(new uint8_t[m_w * m_h * 4]);
1294
1295 if (mode == Lock_Normal) {
1296 glBindTexture(GL_TEXTURE_2D, m_texture);
1297 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels.get());
1298+ glBindTexture(GL_TEXTURE_2D, 0);
1299 }
1300 }
1301
1302@@ -185,6 +207,7 @@
1303 glTexImage2D
1304 (GL_TEXTURE_2D, 0, GL_RGBA, m_w, m_h, 0, GL_RGBA,
1305 GL_UNSIGNED_BYTE, m_pixels.get());
1306+ glBindTexture(GL_TEXTURE_2D, 0);
1307 }
1308
1309 m_pixels.reset(nullptr);
1310
1311=== modified file 'src/graphic/texture.h'
1312--- src/graphic/texture.h 2014-11-24 07:25:21 +0000
1313+++ src/graphic/texture.h 2014-12-01 21:28:54 +0000
1314@@ -19,6 +19,7 @@
1315 #ifndef WL_GRAPHIC_TEXTURE_H
1316 #define WL_GRAPHIC_TEXTURE_H
1317
1318+#include "base/rect.h"
1319 #include "graphic/gl/system_headers.h"
1320 #include "graphic/surface.h"
1321
1322@@ -34,6 +35,10 @@
1323 // dimensions.
1324 Texture(int w, int h);
1325
1326+ // Create a logical texture that is a 'subrect' (in Pixel) in
1327+ // another texture. Ownership of 'texture' is not taken.
1328+ Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h);
1329+
1330 virtual ~Texture();
1331
1332 /// Interface implementation
1333@@ -60,10 +65,20 @@
1334
1335 GLuint get_gl_texture() const {return m_texture;}
1336
1337+ const FloatRect& texture_coordinates() const {
1338+ return m_texture_coordinates;
1339+ }
1340+
1341 private:
1342 void pixel_to_gl(float* x, float* y) const override;
1343 void init(uint16_t w, uint16_t h);
1344
1345+ // True if we own the texture, i.e. if we need to delete it.
1346+ bool m_owns_texture;
1347+
1348+ // Texture coordinates in m_texture.
1349+ FloatRect m_texture_coordinates;
1350+
1351 GLuint m_texture;
1352 };
1353
1354
1355=== added file 'src/graphic/texture_atlas.cc'
1356--- src/graphic/texture_atlas.cc 1970-01-01 00:00:00 +0000
1357+++ src/graphic/texture_atlas.cc 2014-12-01 21:28:54 +0000
1358@@ -0,0 +1,154 @@
1359+/*
1360+ * Copyright (C) 2006-2014 by the Widelands Development Team
1361+ *
1362+ * This program is free software; you can redistribute it and/or
1363+ * modify it under the terms of the GNU General Public License
1364+ * as published by the Free Software Foundation; either version 2
1365+ * of the License, or (at your option) any later version.
1366+ *
1367+ * This program is distributed in the hope that it will be useful,
1368+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1369+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1370+ * GNU General Public License for more details.
1371+ *
1372+ * You should have received a copy of the GNU General Public License
1373+ * along with this program; if not, write to the Free Software
1374+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1375+ *
1376+ */
1377+
1378+#include "graphic/texture_atlas.h"
1379+
1380+#include <algorithm>
1381+#include <cassert>
1382+#include <memory>
1383+
1384+#include "base/wexception.h"
1385+
1386+TextureAtlas::Node::Node(const Rect& init_r) : used(false), r(init_r) {
1387+}
1388+
1389+void TextureAtlas::Node::split(int item_w, int item_h) {
1390+ assert(!used);
1391+
1392+ down.reset(new Node(Rect(r.x, r.y + item_h, r.w, r.h - item_h)));
1393+ right.reset(new Node(Rect(r.x + item_w, r.y, r.w - item_w, item_h)));
1394+ used = true;
1395+
1396+ // Note: we do not change the size of the root. It is not needed
1397+ // for the remaining algorithm, but we use it to remember the
1398+ // size of the full canvas.
1399+}
1400+
1401+
1402+TextureAtlas::TextureAtlas() :
1403+ next_index_(0)
1404+{
1405+}
1406+
1407+void TextureAtlas::add(const Texture& texture) {
1408+ blocks_.emplace_back(next_index_++, &texture);
1409+}
1410+
1411+// static
1412+TextureAtlas::Node* TextureAtlas::find_node(Node* node, int w, int h) {
1413+ if (node->used) {
1414+ Node* child_node = find_node(node->right.get(), w, h);
1415+ if (child_node != nullptr) {
1416+ return child_node;
1417+ }
1418+ return find_node(node->down.get(), w, h);
1419+ }
1420+ assert(!node->used);
1421+
1422+ if ((w <= node->r.w) && (h <= node->r.h)) {
1423+ return node;
1424+ }
1425+
1426+ return nullptr;
1427+}
1428+
1429+std::unique_ptr<Texture> TextureAtlas::pack(std::vector<std::unique_ptr<Texture>>* textures) {
1430+ if (blocks_.empty()) {
1431+ throw wexception("Called pack() without blocks.");
1432+ }
1433+
1434+ // Sort blocks by their biggest side length. This heuristically gives the
1435+ // best packing.
1436+ std::sort(blocks_.begin(), blocks_.end(), [](const Block& i, const Block& j) {
1437+ return std::max(i.texture->width(), i.texture->height()) >
1438+ std::max(j.texture->width(), j.texture->height());
1439+ });
1440+
1441+ std::unique_ptr<Node> root(
1442+ new Node(Rect(0, 0, blocks_.begin()->texture->width(), blocks_.begin()->texture->height())));
1443+
1444+ // TODO(sirver): when growing, keep maximum size of gl textures in mind.
1445+ const auto grow_right = [&root](int delta_w) {
1446+ std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w + delta_w, root->r.h)));
1447+ new_root->used = true;
1448+ new_root->right.reset(new Node(Rect(root->r.w, 0, delta_w, root->r.h)));
1449+ new_root->down.reset(root.release());
1450+ root.reset(new_root.release());
1451+ };
1452+
1453+ const auto grow_down = [&root](int delta_h) {
1454+ std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w, root->r.h + delta_h)));
1455+ new_root->used = true;
1456+ new_root->down.reset(new Node(Rect(0, root->r.h, root->r.w, delta_h)));
1457+ new_root->right.reset(root.release());
1458+ root.reset(new_root.release());
1459+ };
1460+
1461+ for (Block& block : blocks_) {
1462+ const int block_width = block.texture->width();
1463+ const int block_height = block.texture->height();
1464+
1465+ Node* fitting_node = find_node(root.get(), block_width, block_height);
1466+ if (fitting_node == nullptr) {
1467+ // Atlas is not big enough to contain this. Grow it and try again.
1468+ bool can_grow_down = (block_width <= root->r.w);
1469+ bool can_grow_right = (block_height <= root->r.h);
1470+
1471+ // Attempt to keep the texture square-ish.
1472+ bool should_grow_right = can_grow_right && (root->r.h >= root->r.w + block_width);
1473+ bool should_grow_down = can_grow_down && (root->r.w >= root->r.h + block_height);
1474+
1475+ if (should_grow_right) {
1476+ grow_right(block_width);
1477+ } else if (should_grow_down) {
1478+ grow_down(block_height);
1479+ } else if (can_grow_right) {
1480+ grow_right(block_width);
1481+ } else if (can_grow_down) {
1482+ grow_down(block_height);
1483+ }
1484+ fitting_node = find_node(root.get(), block_width, block_height);
1485+ }
1486+ if (!fitting_node) {
1487+ throw wexception("Unable to fit node in texture atlas.");
1488+ }
1489+ fitting_node->split(block_width, block_height);
1490+ block.node = fitting_node;
1491+ }
1492+
1493+ std::unique_ptr<Texture> packed_texture(new Texture(root->r.w, root->r.h));
1494+ packed_texture->fill_rect(Rect(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
1495+
1496+ // Sort blocks by index so that they come back in the correct ordering.
1497+ std::sort(blocks_.begin(), blocks_.end(), [](const Block& i, const Block& j) {
1498+ return i.index < j.index;
1499+ });
1500+
1501+ for (Block& block : blocks_) {
1502+ packed_texture->blit(block.node->r.top_left(),
1503+ block.texture,
1504+ Rect(0, 0, block.texture->width(), block.texture->height()));
1505+ textures->emplace_back(new Texture(
1506+ packed_texture->get_gl_texture(),
1507+ Rect(block.node->r.top_left(), block.texture->width(), block.texture->height()),
1508+ root->r.w,
1509+ root->r.h));
1510+ }
1511+ return packed_texture;
1512+}
1513
1514=== added file 'src/graphic/texture_atlas.h'
1515--- src/graphic/texture_atlas.h 1970-01-01 00:00:00 +0000
1516+++ src/graphic/texture_atlas.h 2014-12-01 21:28:54 +0000
1517@@ -0,0 +1,78 @@
1518+/*
1519+ * Copyright (C) 2006-2014 by the Widelands Development Team
1520+ *
1521+ * This program is free software; you can redistribute it and/or
1522+ * modify it under the terms of the GNU General Public License
1523+ * as published by the Free Software Foundation; either version 2
1524+ * of the License, or (at your option) any later version.
1525+ *
1526+ * This program is distributed in the hope that it will be useful,
1527+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1528+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1529+ * GNU General Public License for more details.
1530+ *
1531+ * You should have received a copy of the GNU General Public License
1532+ * along with this program; if not, write to the Free Software
1533+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1534+ *
1535+ */
1536+
1537+#ifndef WL_GRAPHIC_TEXTURE_ATLAS_H
1538+#define WL_GRAPHIC_TEXTURE_ATLAS_H
1539+
1540+#include <memory>
1541+#include <vector>
1542+
1543+#include "base/macros.h"
1544+#include "graphic/texture.h"
1545+
1546+// A 2d bin packer based on the blog post
1547+// http://codeincomplete.com/posts/2011/5/7/bin_packing/.
1548+class TextureAtlas {
1549+public:
1550+ TextureAtlas();
1551+
1552+ // Add 'texture' as one of the textures to be packed. Ownership is
1553+ // not taken, but 'texture' must be valid until pack() has been
1554+ // called.
1555+ void add(const Texture& texture);
1556+
1557+ // Packs the textures and returns the packed texture. 'textures'
1558+ // contains the individual sub textures (that do not own their
1559+ // memory) in the order they have been added by 'add'.
1560+ std::unique_ptr<Texture> pack(std::vector<std::unique_ptr<Texture>>* textures);
1561+
1562+private:
1563+ struct Node {
1564+ Node(const Rect& init_r);
1565+ void split(int w, int h);
1566+
1567+ bool used;
1568+ Rect r;
1569+ std::unique_ptr<Node> right;
1570+ std::unique_ptr<Node> down;
1571+
1572+ DISALLOW_COPY_AND_ASSIGN(Node);
1573+ };
1574+
1575+ struct Block {
1576+ Block(int init_index, const Texture* init_texture)
1577+ : index(init_index), texture(init_texture) {
1578+ }
1579+
1580+ int index;
1581+ const Texture* texture;
1582+ Node* node;
1583+ };
1584+
1585+ static Node* find_node(Node* root, int w, int h);
1586+
1587+ int next_index_;
1588+
1589+ // Unpacked items.
1590+ std::vector<Block> blocks_;
1591+
1592+ DISALLOW_COPY_AND_ASSIGN(TextureAtlas);
1593+};
1594+
1595+#endif // end of include guard: WL_GRAPHIC_TEXTURE_ATLAS_H
1596
1597=== modified file 'src/logic/CMakeLists.txt'
1598--- src/logic/CMakeLists.txt 2014-11-28 16:40:55 +0000
1599+++ src/logic/CMakeLists.txt 2014-12-01 21:28:54 +0000
1600@@ -229,6 +229,9 @@
1601 game_io
1602 graphic
1603 graphic_color
1604+ graphic_image_io
1605+ graphic_surface
1606+ graphic_texture_atlas
1607 helper
1608 io_fileread
1609 io_filesystem
1610
1611=== modified file 'src/logic/description_maintainer.h'
1612--- src/logic/description_maintainer.h 2014-09-19 23:33:35 +0000
1613+++ src/logic/description_maintainer.h 2014-12-01 21:28:54 +0000
1614@@ -55,9 +55,13 @@
1615
1616 // Returns the entry with the given 'idx' or nullptr if 'idx' is out of
1617 // bound. Ownership is retained.
1618+ // TODO(sirver): remove get() and use get_mutable
1619 T* get(const int32_t idx) const {
1620 return (idx >= 0 && idx < static_cast<int32_t>(items_.size())) ? items_[idx].get() : nullptr;
1621 }
1622+ T* get_mutable(const int32_t idx) const {
1623+ return get(idx);
1624+ }
1625
1626 // Returns the entry at 'index'. If 'index' is out of bounds the result is
1627 // undefined.
1628
1629=== modified file 'src/logic/editor_game_base.cc'
1630--- src/logic/editor_game_base.cc 2014-09-19 12:54:54 +0000
1631+++ src/logic/editor_game_base.cc 2014-12-01 21:28:54 +0000
1632@@ -20,6 +20,7 @@
1633 #include "logic/editor_game_base.h"
1634
1635 #include <algorithm>
1636+#include <memory>
1637 #include <set>
1638
1639 #include "base/i18n.h"
1640@@ -113,11 +114,12 @@
1641
1642 try {
1643 lua_->run_script("world/init.lua");
1644- }
1645- catch (const WException& e) {
1646+ } catch (const WException& e) {
1647 log("Could not read world information: %s", e.what());
1648 throw;
1649 }
1650+
1651+ world_->load_graphics();
1652 }
1653 return world_.get();
1654 }
1655
1656=== modified file 'src/logic/field.cc'
1657--- src/logic/field.cc 2014-07-22 09:54:49 +0000
1658+++ src/logic/field.cc 2014-12-01 21:28:54 +0000
1659@@ -50,7 +50,7 @@
1660 b = -128;
1661 else if (b > 127)
1662 b = 127;
1663- brightness = static_cast<int8_t>(b); //TODO(unknown): ARGH !!
1664+ brightness = static_cast<int8_t>(b);
1665 }
1666
1667 }
1668
1669=== modified file 'src/logic/game.cc'
1670--- src/logic/game.cc 2014-10-11 15:56:02 +0000
1671+++ src/logic/game.cc 2014-12-01 21:28:54 +0000
1672@@ -613,9 +613,6 @@
1673 // the timings of savings.
1674 cmdqueue().run_queue(m_ctrl->get_frametime(), get_gametime_pointer());
1675
1676- if (g_gr) // not in dedicated server mode
1677- g_gr->animate_maptextures(get_gametime());
1678-
1679 // check if autosave is needed
1680 m_savehandler.think(*this, WLApplication::get()->get_time());
1681 }
1682
1683=== modified file 'src/logic/instances.cc'
1684--- src/logic/instances.cc 2014-11-28 16:40:55 +0000
1685+++ src/logic/instances.cc 2014-12-01 21:28:54 +0000
1686@@ -19,6 +19,7 @@
1687
1688 #include "logic/instances.h"
1689
1690+#include <algorithm>
1691 #include <cstdarg>
1692 #include <cstdio>
1693 #include <cstring>
1694
1695=== modified file 'src/logic/tribe.cc'
1696--- src/logic/tribe.cc 2014-10-27 10:14:10 +0000
1697+++ src/logic/tribe.cc 2014-12-01 21:28:54 +0000
1698@@ -19,6 +19,7 @@
1699
1700 #include "logic/tribe.h"
1701
1702+#include <algorithm>
1703 #include <iostream>
1704 #include <memory>
1705
1706
1707=== modified file 'src/logic/world/terrain_description.cc'
1708--- src/logic/world/terrain_description.cc 2014-09-19 12:54:54 +0000
1709+++ src/logic/world/terrain_description.cc 2014-12-01 21:28:54 +0000
1710@@ -19,9 +19,12 @@
1711
1712 #include "logic/world/terrain_description.h"
1713
1714+#include <memory>
1715+
1716 #include <boost/format.hpp>
1717
1718 #include "graphic/graphic.h"
1719+#include "graphic/texture.h"
1720 #include "logic/game_data_error.h"
1721 #include "logic/world/editor_category.h"
1722 #include "logic/world/world.h"
1723@@ -86,19 +89,18 @@
1724 throw GameDataError("%s: temperature is not in Kelvin.", name_.c_str());
1725 }
1726
1727- const std::vector<std::string> textures =
1728+ texture_paths_ =
1729 table.get_table("textures")->array_entries<std::string>();
1730- int frame_length = FRAME_LENGTH;
1731- if (textures.empty()) {
1732+ frame_length_ = FRAME_LENGTH;
1733+ if (texture_paths_.empty()) {
1734 throw GameDataError("Terrain %s has no images.", name_.c_str());
1735- } else if (textures.size() == 1) {
1736+ } else if (texture_paths_.size() == 1) {
1737 if (table.has_key("fps")) {
1738 throw GameDataError("Terrain %s with one images must not have fps.", name_.c_str());
1739 }
1740 } else {
1741- frame_length = 1000 / get_positive_int(table, "fps");
1742+ frame_length_ = 1000 / get_positive_int(table, "fps");
1743 }
1744- texture_ = g_gr->new_maptexture(textures, frame_length);
1745
1746 for (const std::string& resource :
1747 table.get_table("valid_resources")->array_entries<std::string>()) {
1748@@ -121,8 +123,19 @@
1749 TerrainDescription::~TerrainDescription() {
1750 }
1751
1752-uint32_t TerrainDescription::get_texture() const {
1753- return texture_;
1754+const Texture& TerrainDescription::get_texture(uint32_t gametime) const {
1755+ return *textures_.at((gametime / frame_length_) % textures_.size());
1756+}
1757+
1758+void TerrainDescription::add_texture(std::unique_ptr<Texture> texture) {
1759+ if (texture->width() != kTextureSideLength || texture->height() != kTextureSideLength) {
1760+ throw wexception("Tried to add a texture with wrong size.");
1761+ }
1762+ textures_.emplace_back(std::move(texture));
1763+}
1764+
1765+const std::vector<std::string>& TerrainDescription::texture_paths() const {
1766+ return texture_paths_;
1767 }
1768
1769 TerrainDescription::Type TerrainDescription::get_is() const {
1770@@ -149,7 +162,7 @@
1771 return valid_resources_.size();
1772 }
1773
1774-bool TerrainDescription::is_resource_valid(const int32_t res) const {
1775+bool TerrainDescription::is_resource_valid(const int res) const {
1776 for (const uint8_t resource_index : valid_resources_) {
1777 if (resource_index == res) {
1778 return true;
1779@@ -158,15 +171,15 @@
1780 return false;
1781 }
1782
1783-int8_t TerrainDescription::get_default_resource() const {
1784+int TerrainDescription::get_default_resource() const {
1785 return default_resource_index_;
1786 }
1787
1788-int32_t TerrainDescription::get_default_resource_amount() const {
1789+int TerrainDescription::get_default_resource_amount() const {
1790 return default_resource_amount_;
1791 }
1792
1793-int32_t TerrainDescription::dither_layer() const {
1794+int TerrainDescription::dither_layer() const {
1795 return dither_layer_;
1796 }
1797
1798@@ -182,4 +195,19 @@
1799 return fertility_;
1800 }
1801
1802+void TerrainDescription::set_minimap_color(const RGBColor& color) {
1803+ for (int i = -128; i < 128; i++) {
1804+ const int shade = 128 + i;
1805+ int new_r = std::min<int>((color.r * shade) >> 7, 255);
1806+ int new_g = std::min<int>((color.g * shade) >> 7, 255);
1807+ int new_b = std::min<int>((color.b * shade) >> 7, 255);
1808+ minimap_colors_[shade] = RGBColor(new_r, new_g, new_b);
1809+ }
1810+}
1811+
1812+const RGBColor& TerrainDescription::get_minimap_color(int shade) {
1813+ assert(-128 <= shade && shade <= 127);
1814+ return minimap_colors_[128 + shade];
1815+}
1816+
1817 } // namespace Widelands
1818
1819=== modified file 'src/logic/world/terrain_description.h'
1820--- src/logic/world/terrain_description.h 2014-09-10 10:18:46 +0000
1821+++ src/logic/world/terrain_description.h 2014-12-01 21:28:54 +0000
1822@@ -20,19 +20,26 @@
1823 #ifndef WL_LOGIC_WORLD_TERRAIN_DESCRIPTION_H
1824 #define WL_LOGIC_WORLD_TERRAIN_DESCRIPTION_H
1825
1826+#include <memory>
1827 #include <string>
1828+#include <vector>
1829
1830 #include "base/macros.h"
1831+#include "graphic/color.h"
1832 #include "logic/widelands.h"
1833 #include "logic/world/resource_description.h"
1834
1835 class LuaTable;
1836+class Texture;
1837
1838 namespace Widelands {
1839
1840 class EditorCategory;
1841 class World;
1842
1843+/// TerrainTextures have a fixed size and are squares.
1844+constexpr int kTextureSideLength = 64;
1845+
1846 class TerrainDescription {
1847 public:
1848 enum Type {
1849@@ -53,8 +60,19 @@
1850 /// The name showed to users of Widelands. Usually translated.
1851 const std::string& descname() const;
1852
1853- /// Returns the texture index for this terrain.
1854- uint32_t get_texture() const;
1855+
1856+ const std::vector<std::string>& texture_paths() const;
1857+
1858+ /// Returns the texture for the given gametime.
1859+ const Texture& get_texture(uint32_t gametime) const;
1860+ void add_texture(std::unique_ptr<Texture> texture);
1861+
1862+ // Sets the base minimap color.
1863+ void set_minimap_color(const RGBColor& color);
1864+
1865+ // Return the basic terrain colour to be used in the minimap.
1866+ // 'shade' must be a brightness value, i.e. in [-128, 127].
1867+ const RGBColor& get_minimap_color(int shade);
1868
1869 /// Returns the type of terrain this is (water, walkable, and so on).
1870 Type get_is() const;
1871@@ -70,7 +88,7 @@
1872
1873 /// Returns the resource index that can by default always be found in this
1874 /// terrain.
1875- int8_t get_default_resource() const;
1876+ int get_default_resource() const;
1877
1878 /// Returns the default amount of resources you can find in this terrain.
1879 int32_t get_default_resource_amount() const;
1880@@ -98,14 +116,16 @@
1881 const EditorCategory* editor_category_; ///< not owned.
1882 Type is_;
1883 std::vector<uint8_t> valid_resources_;
1884- int8_t default_resource_index_;
1885- int32_t default_resource_amount_;
1886- const std::vector<std::string> texture_paths_;
1887- int32_t dither_layer_;
1888- uint32_t texture_; ///< renderer's texture
1889+ int default_resource_index_;
1890+ int default_resource_amount_;
1891+ int dither_layer_;
1892+ int frame_length_;
1893 double temperature_;
1894 double fertility_;
1895 double humidity_;
1896+ std::vector<std::string> texture_paths_;
1897+ std::vector<std::unique_ptr<Texture>> textures_;
1898+ RGBColor minimap_colors_[256];
1899
1900 DISALLOW_COPY_AND_ASSIGN(TerrainDescription);
1901 };
1902
1903=== modified file 'src/logic/world/world.cc'
1904--- src/logic/world/world.cc 2014-09-10 10:18:46 +0000
1905+++ src/logic/world/world.cc 2014-12-01 21:28:54 +0000
1906@@ -19,26 +19,18 @@
1907
1908 #include "logic/world/world.h"
1909
1910-#include <iostream>
1911 #include <memory>
1912-#include <sstream>
1913
1914-#include "base/i18n.h"
1915-#include "base/log.h"
1916-#include "base/wexception.h"
1917-#include "graphic/graphic.h"
1918-#include "io/fileread.h"
1919-#include "io/filesystem/layered_filesystem.h"
1920-#include "io/filewrite.h"
1921+#include "graphic/image_io.h"
1922+#include "graphic/texture.h"
1923+#include "graphic/texture_atlas.h"
1924+#include "logic/bob.h"
1925 #include "logic/critter.h"
1926 #include "logic/game_data_error.h"
1927 #include "logic/immovable.h"
1928-#include "logic/parse_map_object_types.h"
1929-#include "logic/widelands.h"
1930 #include "logic/world/editor_category.h"
1931 #include "logic/world/resource_description.h"
1932 #include "logic/world/terrain_description.h"
1933-#include "profile/profile.h"
1934
1935 namespace Widelands {
1936
1937@@ -54,6 +46,42 @@
1938 World::~World() {
1939 }
1940
1941+void World::load_graphics() {
1942+ TextureAtlas ta;
1943+
1944+ // These will be deleted at the end of the method.
1945+ std::vector<std::unique_ptr<Texture>> individual_textures_;
1946+
1947+ for (size_t i = 0; i < terrains_->size(); ++i) {
1948+ TerrainDescription* terrain = terrains_->get_mutable(i);
1949+ for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
1950+ SDL_Surface* sdl_surface = load_image_as_sdl_surface(terrain->texture_paths()[j]);
1951+
1952+ // Set the minimap color on the first loaded image.
1953+ if (j == 0) {
1954+ uint8_t top_left_pixel = static_cast<uint8_t*>(sdl_surface->pixels)[0];
1955+ const SDL_Color top_left_pixel_color =
1956+ sdl_surface->format->palette->colors[top_left_pixel];
1957+ terrain->set_minimap_color(
1958+ RGBColor(top_left_pixel_color.r, top_left_pixel_color.g, top_left_pixel_color.b));
1959+ }
1960+ individual_textures_.emplace_back(new Texture(sdl_surface));
1961+ ta.add(*individual_textures_.back());
1962+ }
1963+ }
1964+
1965+ std::vector<std::unique_ptr<Texture>> textures;
1966+ terrain_texture_ = ta.pack(&textures);
1967+
1968+ int next_texture_to_move = 0;
1969+ for (size_t i = 0; i < terrains_->size(); ++i) {
1970+ TerrainDescription* terrain = terrains_->get_mutable(i);
1971+ for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
1972+ terrain->add_texture(std::move(textures.at(next_texture_to_move++)));
1973+ }
1974+ }
1975+}
1976+
1977 const DescriptionMaintainer<TerrainDescription>& World::terrains() const {
1978 return *terrains_;
1979 }
1980
1981=== modified file 'src/logic/world/world.h'
1982--- src/logic/world/world.h 2014-09-10 10:18:46 +0000
1983+++ src/logic/world/world.h 2014-12-01 21:28:54 +0000
1984@@ -23,11 +23,16 @@
1985 #include <memory>
1986
1987 #include "base/macros.h"
1988-#include "logic/bob.h"
1989 #include "logic/description_maintainer.h"
1990+#include "logic/widelands.h"
1991+
1992+class LuaInterface;
1993+class LuaTable;
1994+class Texture;
1995
1996 namespace Widelands {
1997
1998+class BobDescr;
1999 class EditorCategory;
2000 class EditorGameBase;
2001 class ResourceDescription;
2002@@ -40,7 +45,7 @@
2003 class World {
2004 public:
2005 World();
2006- ~World(); // Defined in .cc because all forward declarations are known then.
2007+ ~World();
2008
2009 // TODO(sirver): Refactor these to only return the description_maintainer so that world
2010 // becomes a pure container.
2011@@ -83,6 +88,10 @@
2012 const DescriptionMaintainer<EditorCategory>& editor_terrain_categories() const;
2013 const DescriptionMaintainer<EditorCategory>& editor_immovable_categories() const;
2014
2015+ // Load the graphics for the world. Animations are loaded on
2016+ // demand.
2017+ void load_graphics();
2018+
2019 private:
2020 std::unique_ptr<DescriptionMaintainer<BobDescr>> bobs_;
2021 std::unique_ptr<DescriptionMaintainer<ImmovableDescr>> immovables_;
2022@@ -90,6 +99,7 @@
2023 std::unique_ptr<DescriptionMaintainer<ResourceDescription>> resources_;
2024 std::unique_ptr<DescriptionMaintainer<EditorCategory>> editor_terrain_categories_;
2025 std::unique_ptr<DescriptionMaintainer<EditorCategory>> editor_immovable_categories_;
2026+ std::unique_ptr<Texture> terrain_texture_;
2027
2028 DISALLOW_COPY_AND_ASSIGN(World);
2029 };
2030
2031=== modified file 'src/network/nethost.cc'
2032--- src/network/nethost.cc 2014-10-31 19:09:53 +0000
2033+++ src/network/nethost.cc 2014-12-01 21:28:54 +0000
2034@@ -19,6 +19,7 @@
2035
2036 #include "network/nethost.h"
2037
2038+#include <algorithm>
2039 #include <memory>
2040 #include <sstream>
2041 #include <string>
2042
2043=== modified file 'src/ui_fsmenu/options.cc'
2044--- src/ui_fsmenu/options.cc 2014-11-23 12:03:04 +0000
2045+++ src/ui_fsmenu/options.cc 2014-12-01 21:28:54 +0000
2046@@ -19,6 +19,7 @@
2047
2048 #include "ui_fsmenu/options.h"
2049
2050+#include <algorithm>
2051 #include <cstdio>
2052 #include <iostream>
2053

Subscribers

People subscribed via source and target branches

to status/vote changes: