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

Proposed by SirVer
Status: Merged
Merged at revision: 7709
Proposed branch: lp:~widelands-dev/widelands/use_image_cache
Merge into: lp:widelands
Prerequisite: lp:~widelands-dev/widelands/full_texture_atlas
Diff against target: 2683 lines (+657/-944)
40 files modified
src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc (+1/-1)
src/graphic/CMakeLists.txt (+7/-9)
src/graphic/blit_mode.h (+36/-0)
src/graphic/build_texture_atlas.cc (+42/-177)
src/graphic/build_texture_atlas.h (+38/-0)
src/graphic/font_handler1.cc (+2/-2)
src/graphic/font_handler1.h (+3/-3)
src/graphic/gl/blit_program.cc (+131/-298)
src/graphic/gl/blit_program.h (+78/-83)
src/graphic/gl/dither_program.cc (+10/-25)
src/graphic/gl/draw_line_program.cc (+5/-9)
src/graphic/gl/fill_rect_program.cc (+4/-6)
src/graphic/gl/road_program.cc (+7/-15)
src/graphic/gl/terrain_program.cc (+5/-15)
src/graphic/gl/utils.cc (+72/-0)
src/graphic/gl/utils.h (+49/-11)
src/graphic/graphic.cc (+36/-28)
src/graphic/graphic.h (+7/-4)
src/graphic/image_cache.cc (+12/-30)
src/graphic/image_cache.h (+17/-32)
src/graphic/render_queue.cc (+9/-39)
src/graphic/render_queue.h (+4/-11)
src/graphic/screen.cc (+16/-11)
src/graphic/surface.h (+2/-2)
src/graphic/text/test/render_richtext.cc (+2/-1)
src/graphic/texture.cc (+12/-13)
src/logic/CMakeLists.txt (+0/-1)
src/logic/map_info.cc (+2/-1)
src/logic/map_objects/tribes/road_textures.cc (+6/-6)
src/logic/map_objects/tribes/road_textures.h (+7/-7)
src/logic/map_objects/tribes/tribe_descr.cc (+4/-4)
src/logic/map_objects/tribes/tribe_descr.h (+3/-4)
src/logic/map_objects/tribes/tribes.cc (+2/-28)
src/logic/map_objects/tribes/tribes.h (+0/-2)
src/logic/map_objects/world/terrain_description.cc (+3/-3)
src/logic/map_objects/world/terrain_description.h (+3/-3)
src/logic/map_objects/world/world.cc (+1/-24)
src/logic/map_objects/world/world.h (+0/-2)
src/wlapplication.cc (+19/-33)
src/wlapplication.h (+0/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/use_image_cache
Reviewer Review Type Date Requested Status
TiborB Approve
SirVer Needs Resubmitting
Nicolai Hähnle Needs Fixing
Tino Needs Fixing
kaputtnik (community) Approve
Review via email: mp+282106@code.launchpad.net

Commit message

- Build a texture atlas with the most commonly used images on startup.
- Mild refactorings in the graphic initialization.
- Add a caching mechanism to remember OpenGL state like bound textures, framebuffers, and so on. Use this to avoid unneeded calls into the driver.
- Combine all different blit programs into one and use a if in the fragment shader. This allows for more batching, taking load from the CPU and transferring it to the GPU.
- Apply suggestion by nha: Recreate buffers on the GPU on each frame instead of trying to reuse the memory.

These are the improvements that this buys: All benchmarks where run at 60 FPS, 3440x1440 resolution & fullscreen, on a map with lots of buildings, lots of textures on the screen, lots of different map objects. The game was paused, so that no logic code ate CPU. Census & statistics were disabled since they do not benefit from the texture atlas at all.

pre renderqueue (revision 7691): ~90% CPU load, 41000 OpenGL calls per frame.
post renderqueue (revision 7695): ~65% CPU load, 18300 OpenGL calls per frame.
This commit: 28% CPU load, 3000 OpenGL calls per frame.

An experimental version that loaded every image in Widelands into one 16kx16k texture atlas (1 GB of GPU RAMs was needed): 18% CPU load, 209 OpenGL calls. This proved unsustainable for most GPUs so it was dropped again.

Worst to best rendering now only takes 32% CPU and 8% GL calls of what it used to.

Possible improvements: The atlas creating could also compress the images by finding unchanging areas in animation. This would drastically reduce the size of the atlas and the use of GPU memory. This is described in bug 1121982. I am not motivated to work on this now though and I only consider it a nice to have.

Description of the change

Use the texture atlas + GL optimization. I am reasonably happy with the draw performance of Widelands now.

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

Hi, I am bunnybot (https://github.com/widelands/bunnybot).

I am keeping the source branch lp:~widelands-dev/widelands/use_image_cache mirrored to https://github.com/widelands/widelands/tree/_widelands_dev_widelands_use_image_cache

You can give me commands by starting a line with @bunnybot <command>. I understand:
 merge: Merges the source branch into the target branch, closing the merge proposal. I will use the proposed commit message if it is set.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 233 has changed state to: failed. Details: https://travis-ci.org/widelands/widelands/builds/101329419.

Revision history for this message
Nicolai Hähnle (nha) wrote :
Download full text (3.8 KiB)

This is an impressive improvement! Out of curiosity, how large does the texture atlas end up being?

I have mostly looked at the actual drawing code (I did notice a merge conflict marker in world.cc though, and bunnybot probably did, too ;)). As I already said today on IRC, for desktop OpenGL you should really use instancing. You can copy the Arguments structure almost 1:1 into a buffer with per-instance data and use a simple vertex shader to reduce the CPU load. I'd understand if you don't want separate paths for OpenGL ES 2.0 though.

The next-best thing I noticed is using glMapBuffer to avoid an unnecessary copy. Right now you fill the vertices_ vector (first "copy"). Then glBufferData copies the vertex data into the buffer object (second copy). And finally the vertex data gets uploaded to/pulled by the GPU.

Since you know the number of vertices up-front, it would be better to use glBufferData(..., NULL, ...) to reserve the required amount of space, then use glMapBuffer and write the vertex data directly into the buffer object, thus avoiding the second copy. (This would also apply to

(And now that I've written this, I notice that GLES 2.0 apparently doesn't have glMapBuffer... *sigh*)

Third, it would almost certainly be beneficial to use an element array. That would reduce the amount of vertex data you need to write by one third, and would also reduce the vertex shader load on the GPU by up to one third (Widelands almost certainly isn't shader bound, but hey... perhaps it saves some power). The element array can even be completely static - it just needs to grow as needed during application warm-up.

For the buffer handling, the following is actually best for the kind of streaming draw that Widelands is doing:
1. Determine a reasonably large buffer size N.
2. Use a single buffer object, initialized with glBufferData(..., N, NULL, GL_STREAM_DRAW);
3. As you go along drawing a frame, fill the buffer object from front to back. For all vertex data that you write, use glMapBufferRange to map _exactly_ the range that you want to write for the next draw call, then unmap, then do the draw call.
4. When the vertex data for the next draw call wouldn't fit in the remaining space of the buffer, start from the front, but (and this is VERY important, I've seen plenty of applications screw this up) add the GL_MAP_INVALIDATE_BUFFER_BIT.

What happens when you do this is that the driver magically maintains a pool of underlying buffers, all of size N. Whenever you start from 0 with the MAP_INVALIDATE_BUFFER_BIT, the driver switches the underlying buffer to one from the pool that is no longer in-flight. As far as I know, all desktop GL drivers do this.

Now you see that the patch I sent isn't actually optimal. It would be even better to do something like this:

GLsizeiptr bytes = items.size() * sizeof(T);

if (bytes > size_) {
  glBufferData(GL_ARRAY_BUFFER, bytes, items.data(), GL_STREAM_DRAW);
  size_ = bytes;
  filled_ = bytes;
} else {
  GLbitfield access = GL_MAP_WRITE_BIT;

  if (filled_ + bytes > size_) {
    filled_ = 0;
    access |= GL_MAP_INVALIDATE_BUFFER_BIT;
  }

  void *map = glMapBufferRange(GL_ARRAY_BUFFER, filled_, bytes, access);
  memc...

Read more...

Revision history for this message
SirVer (sirver) wrote :

> This is an impressive improvement! Out of curiosity, how large does the texture atlas end up being?

All images fit into 16kx16k, but since most GPUs seem to support 8k we have 2 textures. This could be improved by doing what we started once before, but never finished: compactifying the animations by finding common rectangles. This could be done when the atlas is constructed and would reduce memory foodprint a lot.

[Element Array]
I did experiment with an element array for a bit and it seems to buy some CPU too, but I had trouble keeping this indirection in my head during coding, so I cut it eventually. I agree that it would be better design.

[Buffer magic]
That sounds interesting, but would require some redesign in the current draw approach. I am very weary working on OpenGL related stuff, so I'll call it good enough for now. If you are interested in experimenting further, that would of course be greatly appreciated!

Revision history for this message
kaputtnik (franku) wrote :

Thanks for adding the file :-) I just compile and want to test.

Revision history for this message
Tino (tino79) wrote :

Compiles and runs fine on windows. I would really like to see this land in trunk as soon as possible.

review: Approve
Revision history for this message
kaputtnik (franku) wrote :

Yes, great enhancement. No flickering anymore (which came up with the new font renderer):
- Fixes bug 1509791
- may this could help also fixing the bug related to some wrong colored shadows? See bug 1519361

A suggestion, if possible. After the image atlas is created a black "Loading images" screen appears. It would be nice if the splash screen (the one where one has to click) could be used as the background for "Loading images". And yes, of course, a progress bar when creating the texture atlas ... :-D

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

Currently the images in campaigns are not cached.
Starting any campaign mission fails.

review: Needs Fixing
Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 235 has changed state to: passed. Details: https://travis-ci.org/widelands/widelands/builds/101396647.

Revision history for this message
SirVer (sirver) wrote :

Images in campaigns are fixed now.

review: Needs Resubmitting
Revision history for this message
Nicolai Hähnle (nha) wrote :

I wanted to test this branch on my laptop right now, and I have to say it's a bit of a nightmare, all of which can be roughly summarized as "this is probably not a good idea when VRAM is small". Let me list a number of problems in no particular order:

1) Our driver correctly announces support for textures up to 16384 in size, but when you actually allocate such a texture, it is 1GB large, which is going to fail when VRAM is not that big. So that possibility is something that the code should account for.

2) It seems there are plenty of fun bugs in our driver when textures become gigantic, so on the plus side, this is a great test case for making our driver more robust...

3) When I force max_size to 4096, I no longer hit critical driver bugs (only ones leading to rendering errors, oh well). There is still a problem though because the atlas textures add up to something like 110 million texels, which means that the textures are going to take more than 400MB (okay, maybe slightly under since there are also mask textures), which means that on integrated GPUs, you get texture thrashing. (Mine has a 512MB VRAM reservation, and whether it starts thrashing or not seems to depend on what compiz is currently doing - if I only had a single monitor running Widelands fullscreen it would probably okay, but as is performance is occasionally killed completely.)

Even without texture atlases, an integrated GPU is going to swap textures occasionally, but it's going to happen much less because the working set is smaller. With texture atlases, your working set is going to be everything almost all of the time.

This sucks. Summary:

(1) Trying to reduce the atlas size is more important than you thought.

(2) Probably the best quick fix option you have is to check VRAM size (e.g. using GLX_MESA_query_renderer) and add some heuristic to disable texture atlases below a certain VRAM size. It should be possible to override the heuristic via the command line. It's kind of sad that you then have a performance optimization that doesn't help the hardware that needs it most...

(3) A longer term fix could be some kind of texture streaming. I actually don't know the best way to do this.

review: Needs Fixing
Revision history for this message
SirVer (sirver) wrote :

Nicolai, could you outline what VRAM means in this case? I did not understand a lot of your last post, it is full of things that I have no understanding of.

So far the only feedback I got is that this change improves the performance - I tested it on old macs too which has only integrated graphics.

Revision history for this message
TiborB (tiborb95) wrote :

If there is such problem it must be discussed thoroughly.

I just tested it on my linux box, with integrated intel HD 4000 and 8 GB RAM (this probably matters much) and no visible problems and it seems to be running nicely.

I googled a bit how to find out VRAM or whatever it is and found two commands (for linux):

$ dmesg | grep Memory
......
[ 6.992863] [drm] Memory usable by graphics device = 2048M

$ LC_ALL=C lspci -v | grep -EA10 "3D|VGA" | grep 'prefetchable'
 Memory at f7800000 (64-bit, non-prefetchable) [size=4M]
 Memory at e0000000 (64-bit, prefetchable) [size=256M]

It seems the first one shows maximum (2GB) and second one actual usage (256MB) - but I am not sure of interpretation...

But as I said - it runs OK here. Perhaps if more peoples tested it...

Revision history for this message
Nicolai Hähnle (nha) wrote :

VRAM is Video RAM, which in the case of integrated graphics is a part of the physical RAM which is reserved for the GPU. Run `free` to get an idea of how large it is approximately: the total memory shown will be less than the physical amount of RAM, reflecting how much is available to the CPU.

In addition, there's the GTT or GART, which is a virtual memory aperture through which the GPU can access system RAM. If not all data fits into VRAM, the GPU can still render from the GTT, but it tends to be slower. The 2048M shown in the dmesg log are probably VRAM + GTT.

It's possible that since Widelands doesn't use that much bandwidth, rendering from GTT (typically 1-2GB) would be fine.

Please do provide an option to disable the texture atlas, and I'll see what can be done about our driver.

Revision history for this message
TiborB (tiborb95) wrote :

@nha
Thanks for clarification.
I noticed when experimenting with this that it disabled (crashed ?) compton - this is a lightweight desktop 3D acceleration - but no big deal for me. So perhaps if you disabled compiz...
Also I wonder if the game will be capable to run in VirtualBox, but I dont have any virtual system at hand to test it...

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have a VMWare VM, so I could eventually test it. I want to review the prerequisite branch first though (the VM makes my whole machine slow when linking...)

Revision history for this message
TiborB (tiborb95) wrote :

AFAIK VirtualBox is bit worse in regard to 3D acceleration, but testing in VMWare is also very usefull

Revision history for this message
SirVer (sirver) wrote :

I will look into running with a minimal texture atlas through a commandline option and profile how much performance that cost on my system.

Probably not before the weekend though.

In the meantime, more testing with virtual machines would be great!

Revision history for this message
TiborB (tiborb95) wrote :

I can not start it in VirtualBox (Mint in Arch linux) - I am getting segmentation fault while building the texture. But virtualbox simply is not good enough virtualization tool for running such game inside a guest I think

Revision history for this message
SirVer (sirver) wrote :

I need another round of testing, please.

I modified the code to only pack terrains, roads and tribe borders and the pics/ subdirectory into a texture atlas and load all other graphics as needed from disk. This is what Nicolai requested - the code requires terrains and roads to be in the same texture, so we need this minimal atlas always.

In my tests, the performance for this is comparable to using one atlas with 2048x2048 textures. It needs ~29% CPU and 3300 GL calls per frame. This is still less than half of what trunk currently needs (60% CU, 18300 GL calls), but not as good as one huge atlas (18% CPU, 210 GL calls).

Advantages of this are: building the atlas is very quick and there is no need to cache. Could I get some testing feedback?

Revision history for this message
kaputtnik (franku) wrote :

Runs fine, the time to create the atlas and loading images is very short on my old AMD CPU. Tested editor and a save game. File sizes:

ls -lh
insgesamt 2,4M
-rw-r--r-- 1 kaputtnik users 79K 14. Jan 16:36 texture_atlas.lua
-rw-r--r-- 1 kaputtnik users 2,3M 14. Jan 16:36 texture_atlas_00.png

CPU usage after loading a 5hrs save game:
This branch: ~32%
Current trunk: ~54%

Revision history for this message
TiborB (tiborb95) wrote :

Well, it compiled, building of that cache was fast, BUT I see a lot of output like this in console:

Image with hash tribes/workers/barbarians/lumberjack/walk_ne_08_pc.png not found. Loading from disk.
Image with hash tribes/workers/barbarians/lumberjack/walk_ne_09_pc.png not found. Loading from disk.

???

Revision history for this message
SirVer (sirver) wrote :

I changed the code back to load an image from disk if it was not already loaded. That is the current behavior in trunk too. I just added logging to get a feeling how often that actually happens. I'll remove it before merging.

nicolai, if you undo the last commit you have the originial behavior that creates a huge atlas if it can. I'll rework this branch to no longer cache the texture atlas and instead just regenerate the one with the most common images every time the game launches. We might revisit packing everything into an atlas once we go back to bug 1121982.

Revision history for this message
TiborB (tiborb95) wrote :

So it will not built it at once on start, but instead it will expand it on the fly as new images are needed during the game? Correct?

Revision history for this message
SirVer (sirver) wrote :

no. sorry, that explanation was confusing.

It will immediately on start build a small one (~1024x1200 pixels) that contains frequently used images like the UI elements, buildhelp & the roads and world textures. Every other image will be loaded as needed from disk and put into a separate texture each, i.e. no texture atlas.

Revision history for this message
TiborB (tiborb95) wrote :

OK, I like it.
And I think there will be no more testers, unless GunChleoc shows up.
I am willing to approve it if you think my approval is sufficient.

Of course there is still some NOCOM in diff and you have to mute a logging about images as you mentioned.

BTW, windows builds were tested?

Revision history for this message
SirVer (sirver) wrote :

Okay, I simplified the code as there is no need to cache the images anymore on disk - building the atlas is fast. I updated the commit message, merged trunk and removed codecheck warnings. Tibor, if you approve of the code, could you merge it in?

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

I'm online today, so I can do some testing.

Revision history for this message
kaputtnik (franku) wrote :

Is there a great difference between fullscreen and window mode? I used windowed mode to have the task manager open to see the CPU usage.

I just tested a little game on my laptop and this branch as current trunk uses about 12% CPU... So no difference?

Revision history for this message
SirVer (sirver) wrote :

fullscreen and window will likely not make a huge difference. But the size of the widelands drawing area (i.e. resolution in game) and the amount of objects on it. The more different objects (terrains, roads, buildings, workers, critters and windows) the higher the difference in load.

Also make sure to pause the game, otherwise the game logic will interfere with your benchmark.

If your GPU is super quick at swapping textures, the difference to the renderqueue branch might be small. However, this branch should in no case be slower than trunk.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I gave this a quick spin in my VM and it runs fine. There is a problem with drawing rectangles though - got probably introduced in one of the previous graphics branches.

https://launchpadlibrarian.net/234364565/rectangles.png

Revision history for this message
SirVer (sirver) wrote :

I think this is https://bugs.launchpad.net/widelands/+bug/1531114. I will look into that soonish. Can this branch go in?

Revision history for this message
TiborB (tiborb95) wrote :

I have the same problem as GunChleoc - though I did not notice it.

Otherwise, it works nicely

Revision history for this message
TiborB (tiborb95) wrote :

I am all for merging it.

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

Looks like my bug is https://bugs.launchpad.net/widelands/+bug/1531114 indeed - seems more pronounced with small screen resolutions maybe?

I won't have time to look at the code until end of next week, but if everything has been checked, it can go in.

Revision history for this message
SirVer (sirver) wrote :

Thanks for testing everybody! Thanks for reviewing, Tibor.

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc'
2--- src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2016-01-08 21:00:39 +0000
3+++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2016-01-16 20:47:43 +0000
4@@ -51,7 +51,7 @@
5 std::vector<std::string> tooltips;
6
7 // Blit the main terrain image
8- const Texture& terrain_texture = terrain_descr.get_texture(0);
9+ const Image& terrain_texture = terrain_descr.get_texture(0);
10 Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
11 texture->blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
12 terrain_texture,
13
14=== modified file 'src/graphic/CMakeLists.txt'
15--- src/graphic/CMakeLists.txt 2016-01-07 12:47:17 +0000
16+++ src/graphic/CMakeLists.txt 2016-01-16 20:47:43 +0000
17@@ -3,19 +3,16 @@
18 # TODO(sirver): Separate this directory into a base directory and one
19 # that is Widelands aware (can include logic stuff).
20
21-# A binary that creates and writes out a texture atlas of all images in
22-# a directory.
23-wl_binary(wl_make_texture_atlas
24+wl_library(graphic_build_texture_atlas
25 SRCS
26- make_texture_atlas_main.cc
27+ build_texture_atlas.h
28+ build_texture_atlas.cc
29 DEPENDS
30- base_log
31 graphic
32 graphic_image_io
33+ graphic_surface
34 graphic_texture_atlas
35- helper
36 io_filesystem
37- io_stream
38 )
39
40 wl_library(graphic_color
41@@ -32,7 +29,6 @@
42 DEPENDS
43 base_exceptions
44 base_geometry
45- base_log
46 base_macros
47 graphic_color
48 graphic_terrain_programs
49@@ -128,6 +124,7 @@
50 wl_library(graphic_draw_programs
51 SRCS
52 blend_mode.h
53+ blit_mode.h
54 gl/blit_program.cc
55 gl/blit_program.h
56 gl/draw_line_program.cc
57@@ -244,10 +241,11 @@
58 base_geometry
59 base_i18n
60 base_log
61- graphic_draw_programs
62 base_macros
63 build_info
64+ graphic_build_texture_atlas
65 graphic_color
66+ graphic_draw_programs
67 graphic_gl_utils
68 graphic_image_cache
69 graphic_image_io
70
71=== added file 'src/graphic/blit_mode.h'
72--- src/graphic/blit_mode.h 1970-01-01 00:00:00 +0000
73+++ src/graphic/blit_mode.h 2016-01-16 20:47:43 +0000
74@@ -0,0 +1,36 @@
75+/*
76+ * Copyright (C) 2006-2016 by the Widelands Development Team
77+ *
78+ * This program is free software; you can redistribute it and/or
79+ * modify it under the terms of the GNU General Public License
80+ * as published by the Free Software Foundation; either version 2
81+ * of the License, or (at your option) any later version.
82+ *
83+ * This program is distributed in the hope that it will be useful,
84+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
85+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86+ * GNU General Public License for more details.
87+ *
88+ * You should have received a copy of the GNU General Public License
89+ * along with this program; if not, write to the Free Software
90+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
91+ *
92+ */
93+
94+#ifndef WL_GRAPHIC_BLIT_MODE_H
95+#define WL_GRAPHIC_BLIT_MODE_H
96+
97+// The type of blit performed.
98+enum class BlitMode {
99+ // Blit texture unchanged.
100+ kDirect,
101+
102+ // Blit texture desaturated and maybe tinted with a color.
103+ kMonochrome,
104+
105+ // Blit texture tinted with a color everywhere where a mask is not
106+ // transparent,
107+ kBlendedWithMask,
108+};
109+
110+#endif // end of include guard: WL_GRAPHIC_BLIT_MODE_H
111
112=== renamed file 'src/graphic/make_texture_atlas_main.cc' => 'src/graphic/build_texture_atlas.cc'
113--- src/graphic/make_texture_atlas_main.cc 2016-01-12 21:26:15 +0000
114+++ src/graphic/build_texture_atlas.cc 2016-01-16 20:47:43 +0000
115@@ -17,29 +17,21 @@
116 *
117 */
118
119-#include <fstream>
120-#include <iostream>
121+#include "graphic/build_texture_atlas.h"
122+
123+#include <map>
124 #include <memory>
125-#include <set>
126 #include <string>
127 #include <unordered_set>
128 #include <vector>
129
130-#include <SDL.h>
131 #include <boost/algorithm/string/predicate.hpp>
132-#include <boost/format.hpp>
133-
134-#undef main // No, we do not want SDL_main
135-
136-#include "base/log.h"
137-#include "config.h"
138+
139 #include "graphic/graphic.h"
140 #include "graphic/image_io.h"
141 #include "graphic/texture_atlas.h"
142-#include "helper.h"
143 #include "io/filesystem/filesystem.h"
144 #include "io/filesystem/layered_filesystem.h"
145-#include "io/streamwrite.h"
146
147 namespace {
148
149@@ -47,47 +39,10 @@
150 // threshold, but not background pictures.
151 constexpr int kMaxAreaForTextureAtlas = 240 * 240;
152
153+// A graphics card must at least support this size for texture for Widelands to
154+// run.
155 constexpr int kMinimumSizeForTextures = 2048;
156
157-// An image can either be Type::kPacked inside a texture atlas, in which case
158-// we need to keep track which one and where inside of that one. It can also be
159-// Type::kUnpacked if it is to be loaded from disk.
160-struct PackInfo {
161- enum class Type {
162- kUnpacked,
163- kPacked,
164- };
165-
166- Type type;
167- int texture_atlas;
168- Rect rect;
169-};
170-
171-int parse_arguments(
172- int argc, char** argv, int* max_size)
173-{
174- if (argc < 2) {
175- std::cout << "Usage: wl_make_texture_atlas [max_size]" << std::endl << std::endl
176- << "Will write output.png in the current directory." << std::endl;
177- return 1;
178- }
179- *max_size = atoi(argv[1]);
180- if (*max_size < kMinimumSizeForTextures) {
181- std::cout << "Widelands requires at least 2048 for the smallest texture size." << std::endl;
182- return 1;
183- }
184- return 0;
185-}
186-
187-// Setup the static objects Widelands needs to operate and initializes systems.
188-void initialize() {
189- SDL_Init(SDL_INIT_VIDEO);
190-
191- g_fs = new LayeredFileSystem();
192- g_fs->add_file_system(&FileSystem::create(INSTALL_DATADIR));
193- g_gr = new Graphic(1, 1, false);
194-}
195-
196 // Returns true if 'filename' ends with an image extension.
197 bool is_image(const std::string& filename) {
198 return boost::ends_with(filename, ".png") || boost::ends_with(filename, ".jpg");
199@@ -113,68 +68,34 @@
200 }
201 }
202
203-void dump_result(const std::map<std::string, PackInfo>& pack_info,
204- std::vector<std::unique_ptr<Texture>>* texture_atlases,
205- FileSystem* fs) {
206-
207- for (size_t i = 0; i < texture_atlases->size(); ++i) {
208- std::unique_ptr<StreamWrite> sw(
209- fs->open_stream_write((boost::format("output_%02i.png") % i).str()));
210- save_to_png(texture_atlases->at(i).get(), sw.get(), ColorType::RGBA);
211- }
212-
213- {
214- std::unique_ptr<StreamWrite> sw(fs->open_stream_write("output.lua"));
215- sw->text("return {\n");
216- for (const auto& pair : pack_info) {
217- sw->text(" [\"");
218- sw->text(pair.first);
219- sw->text("\"] = {\n");
220-
221- switch (pair.second.type) {
222- case PackInfo::Type::kPacked:
223- sw->text(" type = \"packed\",\n");
224- sw->text(
225- (boost::format(" texture_atlas = %d,\n") % pair.second.texture_atlas).str());
226- sw->text((boost::format(" rect = { %d, %d, %d, %d },\n") % pair.second.rect.x %
227- pair.second.rect.y % pair.second.rect.w % pair.second.rect.h).str());
228- break;
229-
230- case PackInfo::Type::kUnpacked:
231- sw->text(" type = \"unpacked\",\n");
232- break;
233- }
234- sw->text(" },\n");
235- }
236- sw->text("}\n");
237- }
238+// If 'filename' should end up in the texture atlas, will load it into 'image'
239+// and return true.
240+bool should_be_packed(const std::string& filename, std::unique_ptr<Texture>* image) {
241+ if (boost::ends_with(filename, ".jpg")) {
242+ return false;
243+ }
244+ *image = load_image(filename, g_fs);
245+ const auto area = (*image)->width() * (*image)->height();
246+ if (area > kMaxAreaForTextureAtlas) {
247+ return false;
248+ }
249+ return true;
250 }
251
252 // Pack the images in 'filenames' into texture atlases.
253-std::vector<std::unique_ptr<Texture>> pack_images(const std::vector<std::string>& filenames,
254- const int max_size,
255- std::map<std::string, PackInfo>* pack_info,
256- Texture* first_texture,
257- TextureAtlas::PackedTexture* first_atlas_packed_texture) {
258+std::vector<std::unique_ptr<Texture>>
259+pack_images(const std::vector<std::string>& filenames,
260+ const int max_size,
261+ std::map<std::string, std::unique_ptr<Texture>>* textures_in_atlas) {
262 std::vector<std::pair<std::string, std::unique_ptr<Texture>>> to_be_packed;
263 for (const auto& filename : filenames) {
264- std::unique_ptr<Texture> image = load_image(filename, g_fs);
265- const auto area = image->width() * image->height();
266- if (area < kMaxAreaForTextureAtlas) {
267+ std::unique_ptr<Texture> image;
268+ if (should_be_packed(filename, &image)) {
269 to_be_packed.push_back(std::make_pair(filename, std::move(image)));
270- } else {
271- pack_info->insert(std::make_pair(filename, PackInfo{
272- PackInfo::Type::kUnpacked, 0, Rect(),
273- }));
274 }
275 }
276
277 TextureAtlas atlas;
278- int packed_texture_index = 0;
279- if (first_texture != nullptr) {
280- atlas.add(*first_texture);
281- packed_texture_index = 1;
282- }
283 for (auto& pair : to_be_packed) {
284 atlas.add(*pair.second);
285 }
286@@ -183,92 +104,36 @@
287 std::vector<TextureAtlas::PackedTexture> packed_textures;
288 atlas.pack(max_size, &texture_atlases, &packed_textures);
289
290- if (first_texture != nullptr) {
291- assert(first_atlas_packed_texture != nullptr);
292- *first_atlas_packed_texture = std::move(packed_textures[0]);
293- }
294-
295 for (size_t i = 0; i < to_be_packed.size(); ++i) {
296- const auto& packed_texture = packed_textures.at(packed_texture_index++);
297- pack_info->insert(
298- std::make_pair(to_be_packed[i].first, PackInfo{PackInfo::Type::kPacked,
299- packed_texture.texture_atlas,
300- packed_texture.texture->blit_data().rect}));
301+ textures_in_atlas->insert(
302+ std::make_pair(to_be_packed[i].first, std::move(packed_textures[i].texture)));
303 }
304 return texture_atlases;
305 }
306
307 } // namespace
308
309-int main(int argc, char** argv) {
310- int max_size;
311- if (parse_arguments(argc, argv, &max_size))
312- return 1;
313-
314- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
315- std::cerr << "SDLInit did not succeed: " << SDL_GetError() << std::endl;
316- return 1;
317+std::vector<std::unique_ptr<Texture>>
318+build_texture_atlas(const int max_size,
319+ std::map<std::string, std::unique_ptr<Texture>>* textures_in_atlas) {
320+ if (max_size < kMinimumSizeForTextures) {
321+ throw wexception("The texture atlas must use at least %d as size (%d was given)",
322+ kMinimumSizeForTextures, max_size);
323 }
324- initialize();
325-
326-
327- // For performance reasons, we need to have some images in the first texture
328- // atlas, so that OpenGL texture switches do not happen during (for example)
329- // terrain or road rendering. To ensure this, we separate all images into
330- // two disjunct sets. We than pack all images that should go into the first
331- // texture atlas into a texture atlas. Then, we pack all remaining textures
332- // into a texture atlas, but including the first texture atlas as a singular
333- // image (which will probably be the biggest we allow).
334- //
335- // We have to adjust the sub rectangle rendering for the images in the first
336- // texture atlas in 'pack_info' later, before dumping the results.
337- std::vector<std::string> other_images, images_that_must_be_in_first_atlas;
338+ std::vector<std::string> first_atlas_images;
339 std::unordered_set<std::string> all_images;
340
341 // For terrain textures.
342- find_images("world/terrains", &all_images, &images_that_must_be_in_first_atlas);
343+ find_images("world/terrains", &all_images, &first_atlas_images);
344 // For flags and roads.
345- find_images("tribes/images", &all_images, &images_that_must_be_in_first_atlas);
346+ find_images("tribes/images", &all_images, &first_atlas_images);
347 // For UI elements mostly, but we get more than we need really.
348- find_images("pics", &all_images, &images_that_must_be_in_first_atlas);
349-
350- // Add all other images, we do not really cares about the order for these.
351- find_images("world", &all_images, &other_images);
352- find_images("tribes", &all_images, &other_images);
353- assert(images_that_must_be_in_first_atlas.size() + other_images.size() == all_images.size());
354-
355- std::map<std::string, PackInfo> first_texture_atlas_pack_info;
356- auto first_texture_atlas = pack_images(images_that_must_be_in_first_atlas, max_size,
357- &first_texture_atlas_pack_info, nullptr, nullptr);
358+ find_images("pics", &all_images, &first_atlas_images);
359+
360+ auto first_texture_atlas = pack_images(first_atlas_images, max_size, textures_in_atlas);
361 if (first_texture_atlas.size() != 1) {
362- std::cout << "Not all images that should fit in the first texture atlas did actually fit."
363- << std::endl;
364- return 1;
365- }
366-
367- std::map<std::string, PackInfo> pack_info;
368- TextureAtlas::PackedTexture first_atlas_packed_texture;
369- auto texture_atlases = pack_images(other_images, max_size, &pack_info,
370- first_texture_atlas[0].get(), &first_atlas_packed_texture);
371-
372- const auto& blit_data = first_atlas_packed_texture.texture->blit_data();
373- for (const auto& pair : first_texture_atlas_pack_info) {
374- assert(pack_info.count(pair.first) == 0);
375- pack_info.insert(std::make_pair(pair.first, PackInfo{
376- pair.second.type,
377- first_atlas_packed_texture.texture_atlas,
378- Rect(blit_data.rect.x + pair.second.rect.x,
379- blit_data.rect.y + pair.second.rect.y,
380- pair.second.rect.w, pair.second.rect.h),
381- }));
382- }
383-
384- // Make sure we have all images.
385- assert(all_images.size() == pack_info.size());
386-
387- std::unique_ptr<FileSystem> output_fs(&FileSystem::create("."));
388- dump_result(pack_info, &texture_atlases, output_fs.get());
389-
390- SDL_Quit();
391- return 0;
392+ throw wexception("Not all images that should fit in the first texture atlas did actually "
393+ "fit. Widelands has now more images than before.");
394+ }
395+ return {std::move(first_texture_atlas)};
396 }
397
398=== added file 'src/graphic/build_texture_atlas.h'
399--- src/graphic/build_texture_atlas.h 1970-01-01 00:00:00 +0000
400+++ src/graphic/build_texture_atlas.h 2016-01-16 20:47:43 +0000
401@@ -0,0 +1,38 @@
402+/*
403+ * Copyright (C) 2006-2016 by the Widelands Development Team
404+ *
405+ * This program is free software; you can redistribute it and/or
406+ * modify it under the terms of the GNU General Public License
407+ * as published by the Free Software Foundation; either version 2
408+ * of the License, or (at your option) any later version.
409+ *
410+ * This program is distributed in the hope that it will be useful,
411+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
412+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
413+ * GNU General Public License for more details.
414+ *
415+ * You should have received a copy of the GNU General Public License
416+ * along with this program; if not, write to the Free Software
417+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
418+ *
419+ */
420+
421+#ifndef WL_GRAPHIC_BUILD_TEXTURE_ATLAS_H
422+#define WL_GRAPHIC_BUILD_TEXTURE_ATLAS_H
423+
424+#include <map>
425+#include <memory>
426+#include <vector>
427+
428+#include "graphic/texture.h"
429+
430+// Builds a texture atlas where no texture is bigger than 'max_size' x
431+// 'max_size' using the most commonly used images like UI elements, roads and
432+// textures. Returns the texture_atlases which must be kept around in memory
433+// and fills in 'textures_in_atlas' which is a map from filename to Texture in
434+// the atlas.
435+std::vector<std::unique_ptr<Texture>>
436+build_texture_atlas(
437+ const int max_size, std::map<std::string, std::unique_ptr<Texture>>* textures_in_atlas);
438+
439+#endif // end of include guard: WL_GRAPHIC_BUILD_TEXTURE_ATLAS_H
440
441=== modified file 'src/graphic/font_handler1.cc'
442--- src/graphic/font_handler1.cc 2016-01-04 20:54:08 +0000
443+++ src/graphic/font_handler1.cc 2016-01-16 20:47:43 +0000
444@@ -139,8 +139,8 @@
445 ImageCache* const image_cache_; // not owned
446 };
447
448-IFontHandler1 * create_fonthandler(Graphic* gr) {
449- return new FontHandler1(&gr->images());
450+IFontHandler1 * create_fonthandler(ImageCache* image_cache) {
451+ return new FontHandler1(image_cache);
452 }
453
454 IFontHandler1 * g_fh1 = nullptr;
455
456=== modified file 'src/graphic/font_handler1.h'
457--- src/graphic/font_handler1.h 2014-12-06 09:07:19 +0000
458+++ src/graphic/font_handler1.h 2016-01-16 20:47:43 +0000
459@@ -32,7 +32,7 @@
460
461 class FileSystem;
462 class Image;
463-class Graphic;
464+class ImageCache;
465
466 namespace UI {
467
468@@ -61,8 +61,8 @@
469 DISALLOW_COPY_AND_ASSIGN(IFontHandler1);
470 };
471
472-// Create a new FontHandler1. Ownership for the objects is not taken.
473-IFontHandler1 * create_fonthandler(Graphic* gr);
474+// Create a new FontHandler1.
475+IFontHandler1 * create_fonthandler(ImageCache* image_cache);
476
477 extern IFontHandler1 * g_fh1;
478
479
480=== modified file 'src/graphic/gl/blit_program.cc'
481--- src/graphic/gl/blit_program.cc 2016-01-05 11:28:54 +0000
482+++ src/graphic/gl/blit_program.cc 2016-01-16 20:47:43 +0000
483@@ -22,6 +22,7 @@
484 #include <vector>
485
486 #include "base/log.h"
487+#include "graphic/blit_mode.h"
488 #include "graphic/gl/blit_data.h"
489 #include "graphic/gl/coordinate_conversion.h"
490 #include "graphic/gl/utils.h"
491@@ -36,52 +37,23 @@
492 attribute vec2 attr_texture_position;
493 attribute vec3 attr_position;
494 attribute vec4 attr_blend;
495+attribute float attr_program_flavor;
496
497 varying vec2 out_mask_texture_coordinate;
498 varying vec2 out_texture_coordinate;
499 varying vec4 out_blend;
500+varying float out_program_flavor;
501
502 void main() {
503 out_mask_texture_coordinate = attr_mask_texture_position;
504 out_texture_coordinate = attr_texture_position;
505 out_blend = attr_blend;
506+ out_program_flavor = attr_program_flavor;
507 gl_Position = vec4(attr_position, 1.);
508 }
509 )";
510
511-const char kVanillaBlitFragmentShader[] = R"(
512-#version 120
513-
514-uniform sampler2D u_texture;
515-
516-varying vec2 out_texture_coordinate;
517-varying vec4 out_blend;
518-
519-void main() {
520- vec4 color = texture2D(u_texture, out_texture_coordinate);
521- gl_FragColor = color * out_blend;
522-}
523-)";
524-
525-const char kMonochromeBlitFragmentShader[] = R"(
526-#version 120
527-
528-uniform sampler2D u_texture;
529-
530-varying vec2 out_texture_coordinate;
531-varying vec4 out_blend;
532-
533-void main() {
534- vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
535-
536- // See http://en.wikipedia.org/wiki/YUV.
537- float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
538-
539- gl_FragColor = vec4(vec3(luminance) * out_blend.rgb, out_blend.a * texture_color.a);
540-}
541-)";
542-
543-const char kBlendedBlitFragmentShader[] = R"(
544+const char kBlitFragmentShader[] = R"(
545 #version 120
546
547 uniform sampler2D u_texture;
548@@ -90,16 +62,25 @@
549 varying vec2 out_mask_texture_coordinate;
550 varying vec2 out_texture_coordinate;
551 varying vec4 out_blend;
552+varying float out_program_flavor;
553
554 void main() {
555 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
556- vec4 mask_color = texture2D(u_mask, out_mask_texture_coordinate);
557
558 // See http://en.wikipedia.org/wiki/YUV.
559 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
560- float blend_influence = mask_color.r * mask_color.a;
561- gl_FragColor = vec4(
562- mix(texture_color.rgb, out_blend.rgb * luminance, blend_influence), out_blend.a * texture_color.a);
563+
564+ if (out_program_flavor == 0.) {
565+ gl_FragColor = vec4(texture_color.rgb, out_blend.a * texture_color.a);
566+ } else if (out_program_flavor == 1.) {
567+ gl_FragColor = vec4(vec3(luminance) * out_blend.rgb, out_blend.a * texture_color.a);
568+ } else {
569+ vec4 mask_color = texture2D(u_mask, out_mask_texture_coordinate);
570+ float blend_influence = mask_color.r * mask_color.a;
571+ gl_FragColor = vec4(
572+ mix(texture_color.rgb, out_blend.rgb * luminance, blend_influence),
573+ out_blend.a * texture_color.a);
574+ }
575 }
576 )";
577
578@@ -117,104 +98,31 @@
579
580 } // namespace
581
582-class BlitProgram {
583-public:
584- struct Arguments {
585- FloatRect destination_rect;
586- float z_value;
587- BlitData texture;
588- BlitData mask;
589- RGBAColor blend;
590- BlendMode blend_mode;
591- };
592- BlitProgram(const std::string& fragment_shader);
593-
594- void activate();
595-
596- void draw_and_deactivate(const std::vector<Arguments>& arguments);
597-
598- int program_object() const {
599- return gl_program_.object();
600- }
601-
602-private:
603- struct PerVertexData {
604- PerVertexData(float init_gl_x,
605- float init_gl_y,
606- float init_gl_z,
607- float init_texture_x,
608- float init_texture_y,
609- float init_mask_texture_x,
610- float init_mask_texture_y,
611- float init_blend_r,
612- float init_blend_g,
613- float init_blend_b,
614- float init_blend_a)
615- : gl_x(init_gl_x),
616- gl_y(init_gl_y),
617- gl_z(init_gl_z),
618- texture_x(init_texture_x),
619- texture_y(init_texture_y),
620- mask_texture_x(init_mask_texture_x),
621- mask_texture_y(init_mask_texture_y),
622- blend_r(init_blend_r),
623- blend_g(init_blend_g),
624- blend_b(init_blend_b),
625- blend_a(init_blend_a) {
626- }
627-
628- float gl_x, gl_y, gl_z;
629- float texture_x, texture_y;
630- float mask_texture_x, mask_texture_y;
631- float blend_r, blend_g, blend_b, blend_a;
632- };
633- static_assert(sizeof(PerVertexData) == 44, "Wrong padding.");
634-
635- // The buffer that will contain the quad for rendering.
636- Gl::Buffer<PerVertexData> gl_array_buffer_;
637-
638- // The program.
639- Gl::Program gl_program_;
640-
641- // Attributes.
642- GLint attr_blend_;
643- GLint attr_mask_texture_position_;
644- GLint attr_position_;
645- GLint attr_texture_position_;
646-
647- // Uniforms.
648- GLint u_texture_;
649- GLint u_mask_;
650-
651- // Cached for efficiency.
652- std::vector<PerVertexData> vertices_;
653-
654- DISALLOW_COPY_AND_ASSIGN(BlitProgram);
655-};
656-
657-BlitProgram::BlitProgram(const std::string& fragment_shader) {
658- gl_program_.build(kBlitVertexShader, fragment_shader.c_str());
659+BlitProgram::BlitProgram() {
660+ gl_program_.build(kBlitVertexShader, kBlitFragmentShader);
661
662 attr_blend_ = glGetAttribLocation(gl_program_.object(), "attr_blend");
663 attr_mask_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_mask_texture_position");
664 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
665 attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
666+ attr_program_flavor_ = glGetAttribLocation(gl_program_.object(), "attr_program_flavor");
667
668 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
669 u_mask_ = glGetUniformLocation(gl_program_.object(), "u_mask");
670 }
671
672-void BlitProgram::activate() {
673+BlitProgram::~BlitProgram() {}
674+
675+void BlitProgram::draw(const std::vector<Arguments>& arguments) {
676 glUseProgram(gl_program_.object());
677
678- glEnableVertexAttribArray(attr_blend_);
679- glEnableVertexAttribArray(attr_mask_texture_position_);
680- glEnableVertexAttribArray(attr_position_);
681- glEnableVertexAttribArray(attr_texture_position_);
682-}
683+ auto& gl_state = Gl::State::instance();
684
685-void BlitProgram::draw_and_deactivate(const std::vector<Arguments>& arguments) {
686- size_t i = 0;
687+ gl_state.enable_vertex_attrib_array({attr_blend_,
688+ attr_mask_texture_position_,
689+ attr_position_,
690+ attr_texture_position_,
691+ attr_program_flavor_});
692
693 gl_array_buffer_.bind();
694
695@@ -226,6 +134,8 @@
696 Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
697 Gl::vertex_attrib_pointer(
698 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
699+ Gl::vertex_attrib_pointer(
700+ attr_program_flavor_, 1, sizeof(PerVertexData), offsetof(PerVertexData, program_flavor));
701
702 glUniform1i(u_texture_, 0);
703 glUniform1i(u_mask_, 1);
704@@ -234,15 +144,18 @@
705 std::vector<DrawBatch> draw_batches;
706 int offset = 0;
707 vertices_.clear();
708+
709+ size_t i = 0;
710 while (i < arguments.size()) {
711- const Arguments& template_args = arguments[i];
712+ const auto& template_args = arguments[i];
713
714 // Batch common blit operations up.
715 while (i < arguments.size()) {
716- const Arguments& current_args = arguments[i];
717+ const auto& current_args = arguments[i];
718 if (current_args.blend_mode != template_args.blend_mode ||
719- current_args.texture.texture_id != template_args.texture.texture_id ||
720- current_args.mask.texture_id != template_args.mask.texture_id) {
721+ current_args.texture.texture_id != template_args.texture.texture_id ||
722+ (current_args.mask.texture_id != 0 &&
723+ current_args.mask.texture_id != template_args.mask.texture_id)) {
724 break;
725 }
726
727@@ -253,56 +166,71 @@
728
729 const FloatRect texture_rect = to_gl_texture(current_args.texture);
730 const FloatRect mask_rect = to_gl_texture(current_args.mask);
731- vertices_.emplace_back(current_args.destination_rect.x,
732- current_args.destination_rect.y,
733- current_args.z_value,
734- texture_rect.x,
735- texture_rect.y,
736- mask_rect.x,
737- mask_rect.y,
738- blend_r,
739- blend_g,
740- blend_b,
741- blend_a);
742-
743- vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
744- current_args.destination_rect.y,
745- current_args.z_value,
746- texture_rect.x + texture_rect.w,
747- texture_rect.y,
748- mask_rect.x + mask_rect.w,
749- mask_rect.y,
750- blend_r,
751- blend_g,
752- blend_b,
753- blend_a);
754-
755- vertices_.emplace_back(current_args.destination_rect.x,
756- current_args.destination_rect.y + current_args.destination_rect.h,
757- current_args.z_value,
758- texture_rect.x,
759- texture_rect.y + texture_rect.h,
760- mask_rect.x,
761- mask_rect.y + mask_rect.h,
762- blend_r,
763- blend_g,
764- blend_b,
765- blend_a);
766-
767- vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
768- vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
769-
770- vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
771- current_args.destination_rect.y + current_args.destination_rect.h,
772- current_args.z_value,
773- texture_rect.x + texture_rect.w,
774- texture_rect.y + texture_rect.h,
775- mask_rect.x + mask_rect.w,
776- mask_rect.y + mask_rect.h,
777- blend_r,
778- blend_g,
779- blend_b,
780- blend_a);
781+ float program_flavor = 0;
782+ switch (current_args.blit_mode) {
783+ case BlitMode::kDirect:
784+ program_flavor = 0.;
785+ break;
786+
787+ case BlitMode::kMonochrome:
788+ program_flavor = 1.;
789+ break;
790+
791+ case BlitMode::kBlendedWithMask:
792+ program_flavor = 2.;
793+ break;
794+ }
795+
796+ vertices_.emplace_back(current_args.destination_rect.x,
797+ current_args.destination_rect.y,
798+ current_args.z_value,
799+ texture_rect.x,
800+ texture_rect.y,
801+ mask_rect.x,
802+ mask_rect.y,
803+ blend_r,
804+ blend_g,
805+ blend_b,
806+ blend_a, program_flavor);
807+
808+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
809+ current_args.destination_rect.y,
810+ current_args.z_value,
811+ texture_rect.x + texture_rect.w,
812+ texture_rect.y,
813+ mask_rect.x + mask_rect.w,
814+ mask_rect.y,
815+ blend_r,
816+ blend_g,
817+ blend_b,
818+ blend_a, program_flavor);
819+
820+ vertices_.emplace_back(current_args.destination_rect.x,
821+ current_args.destination_rect.y + current_args.destination_rect.h,
822+ current_args.z_value,
823+ texture_rect.x,
824+ texture_rect.y + texture_rect.h,
825+ mask_rect.x,
826+ mask_rect.y + mask_rect.h,
827+ blend_r,
828+ blend_g,
829+ blend_b,
830+ blend_a, program_flavor);
831+
832+ vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
833+ vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
834+
835+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
836+ current_args.destination_rect.y + current_args.destination_rect.h,
837+ current_args.z_value,
838+ texture_rect.x + texture_rect.w,
839+ texture_rect.y + texture_rect.h,
840+ mask_rect.x + mask_rect.w,
841+ mask_rect.y + mask_rect.h,
842+ blend_r,
843+ blend_g,
844+ blend_b,
845+ blend_a, program_flavor);
846 ++i;
847 }
848
849@@ -317,11 +245,8 @@
850
851 // Now do the draw calls.
852 for (const auto& draw_arg : draw_batches) {
853- glActiveTexture(GL_TEXTURE0);
854- glBindTexture(GL_TEXTURE_2D, draw_arg.texture);
855-
856- glActiveTexture(GL_TEXTURE1);
857- glBindTexture(GL_TEXTURE_2D, draw_arg.mask);
858+ gl_state.bind(GL_TEXTURE0, draw_arg.texture);
859+ gl_state.bind(GL_TEXTURE1, draw_arg.mask);
860
861 if (draw_arg.blend_mode == BlendMode::Copy) {
862 glBlendFunc(GL_ONE, GL_ZERO);
863@@ -332,130 +257,38 @@
864 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
865 }
866 }
867-
868- glDisableVertexAttribArray(attr_blend_);
869- glDisableVertexAttribArray(attr_mask_texture_position_);
870- glDisableVertexAttribArray(attr_position_);
871- glDisableVertexAttribArray(attr_texture_position_);
872-
873- glBindTexture(GL_TEXTURE_2D, 0);
874-
875- glActiveTexture(GL_TEXTURE0);
876- glBindTexture(GL_TEXTURE_2D, 0);
877-
878- glBindBuffer(GL_ARRAY_BUFFER, 0);
879-}
880-
881-// static
882-VanillaBlitProgram& VanillaBlitProgram::instance() {
883- static VanillaBlitProgram blit_program;
884- return blit_program;
885-}
886-
887-VanillaBlitProgram::~VanillaBlitProgram() {
888-}
889-
890-VanillaBlitProgram::VanillaBlitProgram() {
891- blit_program_.reset(new BlitProgram(kVanillaBlitFragmentShader));
892-}
893-
894-void VanillaBlitProgram::draw(const FloatRect& gl_dest_rect,
895+}
896+
897+void BlitProgram::draw(const FloatRect& gl_dest_rect,
898 const float z_value,
899 const BlitData& texture,
900- const float opacity,
901- const BlendMode blend_mode) {
902- draw({Arguments{gl_dest_rect, z_value, texture, opacity, blend_mode}});
903-}
904-
905-void VanillaBlitProgram::draw(const std::vector<Arguments>& arguments) {
906- std::vector<BlitProgram::Arguments> blit_arguments;
907- for (const Arguments arg : arguments) {
908- blit_arguments.emplace_back(BlitProgram::Arguments{
909- arg.destination_rect,
910- arg.z_value,
911- arg.texture,
912- BlitData{0, 0, 0, Rect()},
913- RGBAColor(255, 255, 255, arg.opacity * 255),
914- arg.blend_mode,
915- });
916- }
917-
918- blit_program_->activate();
919- blit_program_->draw_and_deactivate(blit_arguments);
920-}
921-
922-
923-// static
924-MonochromeBlitProgram& MonochromeBlitProgram::instance() {
925- static MonochromeBlitProgram blit_program;
926- return blit_program;
927-}
928-
929-MonochromeBlitProgram::~MonochromeBlitProgram() {
930-}
931-
932-MonochromeBlitProgram::MonochromeBlitProgram() {
933- blit_program_.reset(new BlitProgram(kMonochromeBlitFragmentShader));
934-}
935-
936-void MonochromeBlitProgram::draw(const FloatRect& dest_rect,
937+ const BlitData& mask,
938+ const RGBAColor& blend,
939+ const BlendMode& blend_mode) {
940+ draw({Arguments{gl_dest_rect,
941+ z_value,
942+ texture,
943+ mask,
944+ blend,
945+ blend_mode,
946+ mask.texture_id != 0 ? BlitMode::kBlendedWithMask : BlitMode::kDirect}});
947+}
948+
949+void BlitProgram::draw_monochrome(const FloatRect& dest_rect,
950 const float z_value,
951 const BlitData& texture,
952 const RGBAColor& blend) {
953- draw({Arguments{dest_rect, z_value, texture, blend, BlendMode::UseAlpha}});
954-}
955-
956-void MonochromeBlitProgram::draw(const std::vector<Arguments>& arguments) {
957- std::vector<BlitProgram::Arguments> blit_arguments;
958- for (const Arguments arg : arguments) {
959- blit_arguments.emplace_back(BlitProgram::Arguments{
960- arg.destination_rect,
961- arg.z_value,
962- arg.texture,
963- BlitData{0, 0, 0, Rect()},
964- arg.blend,
965- arg.blend_mode,
966- });
967- }
968-
969- blit_program_->activate();
970- blit_program_->draw_and_deactivate(blit_arguments);
971+ draw({Arguments{dest_rect,
972+ z_value,
973+ texture,
974+ BlitData{0, 0, 0, Rect()},
975+ blend,
976+ BlendMode::UseAlpha,
977+ BlitMode::kMonochrome}});
978 }
979
980 // static
981-BlendedBlitProgram& BlendedBlitProgram::instance() {
982- static BlendedBlitProgram blit_program;
983+BlitProgram& BlitProgram::instance() {
984+ static BlitProgram blit_program;
985 return blit_program;
986 }
987-
988-BlendedBlitProgram::~BlendedBlitProgram() {
989-}
990-
991-BlendedBlitProgram::BlendedBlitProgram() {
992- blit_program_.reset(new BlitProgram(kBlendedBlitFragmentShader));
993-}
994-
995-void BlendedBlitProgram::draw(const FloatRect& gl_dest_rect,
996- const float z_value,
997- const BlitData& texture,
998- const BlitData& mask,
999- const RGBAColor& blend) {
1000- draw({Arguments{gl_dest_rect, z_value, texture, mask, blend, BlendMode::UseAlpha}});
1001-}
1002-
1003-void BlendedBlitProgram::draw(const std::vector<Arguments>& arguments) {
1004- std::vector<BlitProgram::Arguments> blit_arguments;
1005- for (const Arguments arg : arguments) {
1006- blit_arguments.emplace_back(BlitProgram::Arguments{
1007- arg.destination_rect,
1008- arg.z_value,
1009- arg.texture,
1010- arg.mask,
1011- arg.blend,
1012- arg.blend_mode,
1013- });
1014- }
1015-
1016- blit_program_->activate();
1017- blit_program_->draw_and_deactivate(blit_arguments);
1018-}
1019
1020=== modified file 'src/graphic/gl/blit_program.h'
1021--- src/graphic/gl/blit_program.h 2016-01-04 20:54:08 +0000
1022+++ src/graphic/gl/blit_program.h 2016-01-16 20:47:43 +0000
1023@@ -26,84 +26,14 @@
1024 #include "base/macros.h"
1025 #include "base/rect.h"
1026 #include "graphic/blend_mode.h"
1027+#include "graphic/blit_mode.h"
1028 #include "graphic/color.h"
1029 #include "graphic/gl/blit_data.h"
1030 #include "graphic/gl/system_headers.h"
1031-
1032-class BlitProgram;
1033-
1034-
1035-class VanillaBlitProgram {
1036-public:
1037- struct Arguments {
1038- FloatRect destination_rect;
1039- float z_value;
1040- BlitData texture;
1041- float opacity;
1042- BlendMode blend_mode;
1043- };
1044-
1045- // Returns the (singleton) instance of this class.
1046- static VanillaBlitProgram& instance();
1047- ~VanillaBlitProgram();
1048-
1049- // Draws the rectangle 'gl_src_rect' from the texture with the name
1050- // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha
1051- // values are multiplied by 'opacity' during the blit.
1052- // All coordinates are in the OpenGL frame. The 'blend_mode' defines if the
1053- // values are copied or if alpha values are used.
1054- void draw(const FloatRect& gl_dest_rect,
1055- const float z_value,
1056- const BlitData& texture,
1057- float opacity,
1058- const BlendMode blend_mode);
1059-
1060- // Draws a bunch of items at once.
1061- void draw(const std::vector<Arguments>& arguments);
1062-
1063-private:
1064- VanillaBlitProgram();
1065-
1066- std::unique_ptr<BlitProgram> blit_program_;
1067-
1068- DISALLOW_COPY_AND_ASSIGN(VanillaBlitProgram);
1069-};
1070-
1071-class MonochromeBlitProgram {
1072-public:
1073- struct Arguments {
1074- FloatRect destination_rect;
1075- float z_value;
1076- BlitData texture;
1077- RGBAColor blend;
1078- BlendMode blend_mode;
1079- };
1080-
1081- // Returns the (singleton) instance of this class.
1082- static MonochromeBlitProgram& instance();
1083- ~MonochromeBlitProgram();
1084-
1085- // Draws the rectangle 'gl_src_rect' from the texture with the name
1086- // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
1087- // coordinates are in the OpenGL frame. The image is first converted to
1088- // luminance, then all values are multiplied with blend.
1089- void draw(const FloatRect& gl_dest_rect,
1090- const float z_value,
1091- const BlitData& blit_source,
1092- const RGBAColor& blend);
1093-
1094- // Draws a bunch of items at once.
1095- void draw(const std::vector<Arguments>& arguments);
1096-
1097-private:
1098- MonochromeBlitProgram();
1099-
1100- std::unique_ptr<BlitProgram> blit_program_;
1101-
1102- DISALLOW_COPY_AND_ASSIGN(MonochromeBlitProgram);
1103-};
1104-
1105-class BlendedBlitProgram {
1106+#include "graphic/gl/utils.h"
1107+
1108+// Blits images. Can blend them with player color or make them monochrome.
1109+class BlitProgram {
1110 public:
1111 struct Arguments {
1112 FloatRect destination_rect;
1113@@ -112,11 +42,12 @@
1114 BlitData mask;
1115 RGBAColor blend;
1116 BlendMode blend_mode;
1117+ BlitMode blit_mode;
1118 };
1119
1120 // Returns the (singleton) instance of this class.
1121- static BlendedBlitProgram& instance();
1122- ~BlendedBlitProgram();
1123+ static BlitProgram& instance();
1124+ ~BlitProgram();
1125
1126 // Draws the rectangle 'gl_src_rect' from the texture with the name
1127 // 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All
1128@@ -126,17 +57,81 @@
1129 const float z_value,
1130 const BlitData& texture,
1131 const BlitData& mask,
1132- const RGBAColor& blend);
1133+ const RGBAColor& blend,
1134+ const BlendMode& blend_mode);
1135+
1136+ // Draws the rectangle 'gl_src_rect' from the texture with the name
1137+ // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
1138+ // coordinates are in the OpenGL frame. The image is first converted to
1139+ // luminance, then all values are multiplied with blend.
1140+ void draw_monochrome(const FloatRect& gl_dest_rect,
1141+ const float z_value,
1142+ const BlitData& blit_source,
1143+ const RGBAColor& blend);
1144+
1145
1146 // Draws a bunch of items at once.
1147 void draw(const std::vector<Arguments>& arguments);
1148
1149 private:
1150- BlendedBlitProgram();
1151-
1152- std::unique_ptr<BlitProgram> blit_program_;
1153-
1154- DISALLOW_COPY_AND_ASSIGN(BlendedBlitProgram);
1155+ BlitProgram();
1156+
1157+ struct PerVertexData {
1158+ PerVertexData(float init_gl_x,
1159+ float init_gl_y,
1160+ float init_gl_z,
1161+ float init_texture_x,
1162+ float init_texture_y,
1163+ float init_mask_texture_x,
1164+ float init_mask_texture_y,
1165+ float init_blend_r,
1166+ float init_blend_g,
1167+ float init_blend_b,
1168+ float init_blend_a,
1169+ float init_program_flavor)
1170+ : gl_x(init_gl_x),
1171+ gl_y(init_gl_y),
1172+ gl_z(init_gl_z),
1173+ texture_x(init_texture_x),
1174+ texture_y(init_texture_y),
1175+ mask_texture_x(init_mask_texture_x),
1176+ mask_texture_y(init_mask_texture_y),
1177+ blend_r(init_blend_r),
1178+ blend_g(init_blend_g),
1179+ blend_b(init_blend_b),
1180+ blend_a(init_blend_a),
1181+ program_flavor(init_program_flavor) {
1182+ }
1183+
1184+ float gl_x, gl_y, gl_z;
1185+ float texture_x, texture_y;
1186+ float mask_texture_x, mask_texture_y;
1187+ float blend_r, blend_g, blend_b, blend_a;
1188+ float program_flavor;
1189+ };
1190+ static_assert(sizeof(PerVertexData) == 48, "Wrong padding.");
1191+
1192+ // The buffer that will contain the quad for rendering.
1193+ Gl::Buffer<PerVertexData> gl_array_buffer_;
1194+
1195+ // The program.
1196+ Gl::Program gl_program_;
1197+
1198+ // Attributes.
1199+ GLint attr_blend_;
1200+ GLint attr_mask_texture_position_;
1201+ GLint attr_position_;
1202+ GLint attr_texture_position_;
1203+ GLint attr_program_flavor_;
1204+
1205+ // Uniforms.
1206+ GLint u_texture_;
1207+ GLint u_mask_;
1208+
1209+ // Cached for efficiency.
1210+ std::vector<PerVertexData> vertices_;
1211+
1212+ DISALLOW_COPY_AND_ASSIGN(BlitProgram);
1213 };
1214
1215 #endif // end of include guard: WL_GRAPHIC_GL_BLIT_PROGRAM_H
1216
1217=== modified file 'src/graphic/gl/dither_program.cc'
1218--- src/graphic/gl/dither_program.cc 2016-01-05 11:28:54 +0000
1219+++ src/graphic/gl/dither_program.cc 2016-01-16 20:47:43 +0000
1220@@ -22,6 +22,7 @@
1221 #include "base/wexception.h"
1222 #include "graphic/gl/coordinate_conversion.h"
1223 #include "graphic/gl/fields_to_draw.h"
1224+#include "graphic/gl/utils.h"
1225 #include "graphic/image_io.h"
1226 #include "graphic/texture.h"
1227 #include "io/filesystem/layered_filesystem.h"
1228@@ -100,12 +101,11 @@
1229
1230 dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));
1231
1232- glBindTexture(GL_TEXTURE_2D, dither_mask_->blit_data().texture_id);
1233+ Gl::State::instance().bind(GL_TEXTURE0, dither_mask_->blit_data().texture_id);
1234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP_TO_EDGE));
1235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP_TO_EDGE));
1236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(GL_LINEAR));
1237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_NEAREST));
1238- glBindTexture(GL_TEXTURE_2D, 0);
1239 }
1240
1241 DitherProgram::~DitherProgram() {}
1242@@ -169,11 +169,12 @@
1243 void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h, const float z_value) {
1244 glUseProgram(gl_program_.object());
1245
1246- glEnableVertexAttribArray(attr_brightness_);
1247- glEnableVertexAttribArray(attr_dither_texture_position_);
1248- glEnableVertexAttribArray(attr_position_);
1249- glEnableVertexAttribArray(attr_texture_offset_);
1250- glEnableVertexAttribArray(attr_texture_position_);
1251+ auto& gl_state = Gl::State::instance();
1252+ gl_state.enable_vertex_attrib_array({attr_brightness_,
1253+ attr_dither_texture_position_,
1254+ attr_position_,
1255+ attr_texture_offset_,
1256+ attr_texture_position_});
1257
1258 gl_array_buffer_.bind();
1259 gl_array_buffer_.update(vertices_);
1260@@ -190,14 +191,8 @@
1261 Gl::vertex_attrib_pointer(
1262 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
1263
1264- glBindBuffer(GL_ARRAY_BUFFER, 0);
1265-
1266- // Set the sampler texture unit to 0
1267- glActiveTexture(GL_TEXTURE0);
1268- glBindTexture(GL_TEXTURE_2D, dither_mask_->blit_data().texture_id);
1269-
1270- glActiveTexture(GL_TEXTURE1);
1271- glBindTexture(GL_TEXTURE_2D, gl_texture);
1272+ gl_state.bind(GL_TEXTURE0, dither_mask_->blit_data().texture_id);
1273+ gl_state.bind(GL_TEXTURE1, gl_texture);
1274
1275 glUniform1f(u_z_value_, z_value);
1276 glUniform1i(u_dither_texture_, 0);
1277@@ -205,16 +200,6 @@
1278 glUniform2f(u_texture_dimensions_, texture_w, texture_h);
1279
1280 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
1281-
1282- glBindTexture(GL_TEXTURE_2D, 0);
1283- glActiveTexture(GL_TEXTURE0);
1284- glBindTexture(GL_TEXTURE_2D, 0);
1285-
1286- glDisableVertexAttribArray(attr_brightness_);
1287- glDisableVertexAttribArray(attr_dither_texture_position_);
1288- glDisableVertexAttribArray(attr_position_);
1289- glDisableVertexAttribArray(attr_texture_offset_);
1290- glDisableVertexAttribArray(attr_texture_position_);
1291 }
1292
1293 void DitherProgram::draw(const uint32_t gametime,
1294
1295=== modified file 'src/graphic/gl/draw_line_program.cc'
1296--- src/graphic/gl/draw_line_program.cc 2015-03-01 09:23:10 +0000
1297+++ src/graphic/gl/draw_line_program.cc 2016-01-16 20:47:43 +0000
1298@@ -89,8 +89,11 @@
1299 size_t i = 0;
1300
1301 glUseProgram(gl_program_.object());
1302- glEnableVertexAttribArray(attr_position_);
1303- glEnableVertexAttribArray(attr_color_);
1304+
1305+ auto& gl_state = Gl::State::instance();
1306+ gl_state.enable_vertex_attrib_array({
1307+ attr_position_, attr_color_,
1308+ });
1309
1310 gl_array_buffer_.bind();
1311
1312@@ -140,11 +143,4 @@
1313 glLineWidth(draw_arg.line_width);
1314 glDrawArrays(GL_LINES, draw_arg.offset, draw_arg.count);
1315 }
1316-
1317- glBindBuffer(GL_ARRAY_BUFFER, 0);
1318-
1319- glDisableVertexAttribArray(attr_position_);
1320- glDisableVertexAttribArray(attr_color_);
1321-
1322- glUseProgram(0);
1323 }
1324
1325=== modified file 'src/graphic/gl/fill_rect_program.cc'
1326--- src/graphic/gl/fill_rect_program.cc 2015-03-01 09:23:10 +0000
1327+++ src/graphic/gl/fill_rect_program.cc 2016-01-16 20:47:43 +0000
1328@@ -112,8 +112,10 @@
1329
1330 gl_array_buffer_.bind();
1331
1332- glEnableVertexAttribArray(attr_position_);
1333- glEnableVertexAttribArray(attr_color_);
1334+ auto& gl_state = Gl::State::instance();
1335+ gl_state.enable_vertex_attrib_array({
1336+ attr_position_, attr_color_,
1337+ });
1338
1339 // Batch common rectangles up.
1340 while (i < arguments.size()) {
1341@@ -199,8 +201,4 @@
1342 break;
1343 }
1344 }
1345-
1346- glDisableVertexAttribArray(attr_position_);
1347- glDisableVertexAttribArray(attr_color_);
1348- glBindBuffer(GL_ARRAY_BUFFER, 0);
1349 }
1350
1351=== modified file 'src/graphic/gl/road_program.cc'
1352--- src/graphic/gl/road_program.cc 2016-01-04 20:54:08 +0000
1353+++ src/graphic/gl/road_program.cc 2016-01-16 20:47:43 +0000
1354@@ -25,6 +25,7 @@
1355 #include "base/log.h"
1356 #include "graphic/gl/coordinate_conversion.h"
1357 #include "graphic/gl/fields_to_draw.h"
1358+#include "graphic/gl/utils.h"
1359 #include "graphic/graphic.h"
1360 #include "graphic/image_io.h"
1361 #include "graphic/texture.h"
1362@@ -111,7 +112,7 @@
1363 const float road_thickness_x = (-delta_y / vector_length) * kRoadThicknessInPixels;
1364 const float road_thickness_y = (delta_x / vector_length) * kRoadThicknessInPixels;
1365
1366- const Texture& texture =
1367+ const Image& texture =
1368 road_type == Widelands::RoadType::kNormal ?
1369 start.road_textures->get_normal_texture(start.fx, start.fy, direction) :
1370 start.road_textures->get_busy_texture(start.fx, start.fy, direction);
1371@@ -234,9 +235,10 @@
1372
1373 glUseProgram(gl_program_.object());
1374
1375- glEnableVertexAttribArray(attr_position_);
1376- glEnableVertexAttribArray(attr_texture_position_);
1377- glEnableVertexAttribArray(attr_brightness_);
1378+ auto& gl_state = Gl::State::instance();
1379+ gl_state.enable_vertex_attrib_array({
1380+ attr_position_, attr_texture_position_, attr_brightness_
1381+ });
1382
1383 gl_array_buffer_.bind();
1384 gl_array_buffer_.update(vertices_);
1385@@ -248,19 +250,9 @@
1386 Gl::vertex_attrib_pointer(
1387 attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
1388
1389- glBindBuffer(GL_ARRAY_BUFFER, 0);
1390-
1391- // Bind the textures.
1392- glActiveTexture(GL_TEXTURE0);
1393- glBindTexture(GL_TEXTURE_2D, gl_texture);
1394-
1395+ gl_state.bind(GL_TEXTURE0, gl_texture);
1396 glUniform1i(u_texture_, 0);
1397-
1398 glUniform1f(u_z_value_, z_value);
1399
1400 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
1401-
1402- glDisableVertexAttribArray(attr_position_);
1403- glDisableVertexAttribArray(attr_texture_position_);
1404- glDisableVertexAttribArray(attr_brightness_);
1405 }
1406
1407=== modified file 'src/graphic/gl/terrain_program.cc'
1408--- src/graphic/gl/terrain_program.cc 2016-01-04 20:54:08 +0000
1409+++ src/graphic/gl/terrain_program.cc 2016-01-16 20:47:43 +0000
1410@@ -21,6 +21,7 @@
1411
1412 #include "graphic/gl/coordinate_conversion.h"
1413 #include "graphic/gl/fields_to_draw.h"
1414+#include "graphic/gl/utils.h"
1415 #include "graphic/texture.h"
1416
1417 namespace {
1418@@ -103,10 +104,9 @@
1419 void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h, float z_value) {
1420 glUseProgram(gl_program_.object());
1421
1422- glEnableVertexAttribArray(attr_brightness_);
1423- glEnableVertexAttribArray(attr_position_);
1424- glEnableVertexAttribArray(attr_texture_offset_);
1425- glEnableVertexAttribArray(attr_texture_position_);
1426+ auto& gl_state = Gl::State::instance();
1427+ gl_state.enable_vertex_attrib_array(
1428+ {attr_brightness_, attr_position_, attr_texture_offset_, attr_texture_position_});
1429
1430 gl_array_buffer_.bind();
1431 gl_array_buffer_.update(vertices_);
1432@@ -119,23 +119,13 @@
1433 Gl::vertex_attrib_pointer(
1434 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
1435
1436- glBindBuffer(GL_ARRAY_BUFFER, 0);
1437-
1438- glActiveTexture(GL_TEXTURE0);
1439- glBindTexture(GL_TEXTURE_2D, gl_texture);
1440+ gl_state.bind(GL_TEXTURE0, gl_texture);
1441
1442 glUniform1f(u_z_value_, z_value);
1443 glUniform1i(u_terrain_texture_, 0);
1444 glUniform2f(u_texture_dimensions_, texture_w, texture_h);
1445
1446 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
1447-
1448- glBindTexture(GL_TEXTURE_2D, 0);
1449-
1450- glDisableVertexAttribArray(attr_brightness_);
1451- glDisableVertexAttribArray(attr_position_);
1452- glDisableVertexAttribArray(attr_texture_offset_);
1453- glDisableVertexAttribArray(attr_texture_position_);
1454 }
1455
1456 void TerrainProgram::add_vertex(const FieldsToDraw::Field& field,
1457
1458=== modified file 'src/graphic/gl/utils.cc'
1459--- src/graphic/gl/utils.cc 2015-02-20 07:45:49 +0000
1460+++ src/graphic/gl/utils.cc 2016-01-16 20:47:43 +0000
1461@@ -166,6 +166,78 @@
1462 }
1463 }
1464
1465+State::State()
1466+ : last_active_texture_(0), current_framebuffer_(0), current_framebuffer_texture_(0) {
1467+}
1468+
1469+void State::bind(const GLenum target, const GLuint texture) {
1470+ if (texture == 0) {
1471+ return;
1472+ }
1473+ do_bind(target, texture);
1474+}
1475+
1476+void State::do_bind(const GLenum target, const GLuint texture) {
1477+ const auto currently_bound_texture = target_to_texture_[target];
1478+ if (currently_bound_texture == texture) {
1479+ return;
1480+ }
1481+ if (last_active_texture_ != target) {
1482+ glActiveTexture(target);
1483+ last_active_texture_ = target;
1484+ }
1485+ glBindTexture(GL_TEXTURE_2D, texture);
1486+
1487+ target_to_texture_[target] = texture;
1488+ texture_to_target_[currently_bound_texture] = 0;
1489+ texture_to_target_[texture] = target;
1490+}
1491+
1492+void State::unbind_texture_if_bound(const GLuint texture) {
1493+ if (texture == 0) {
1494+ return;
1495+ }
1496+ const auto target = texture_to_target_[texture];
1497+ if (target != 0) {
1498+ do_bind(target, 0);
1499+ }
1500+}
1501+
1502+void State::bind_framebuffer(const GLuint framebuffer, const GLuint texture) {
1503+ if (current_framebuffer_ == framebuffer && current_framebuffer_texture_ == texture) {
1504+ return;
1505+ }
1506+
1507+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1508+ if (framebuffer != 0) {
1509+ unbind_texture_if_bound(texture);
1510+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1511+ }
1512+ current_framebuffer_ = framebuffer;
1513+ current_framebuffer_texture_ = texture;
1514+}
1515+
1516+void State::enable_vertex_attrib_array(std::unordered_set<GLint> entries) {
1517+ for (const auto e : entries) {
1518+ if (!enabled_attrib_arrays_.count(e)) {
1519+ glEnableVertexAttribArray(e);
1520+ }
1521+ }
1522+ for (const auto e : enabled_attrib_arrays_) {
1523+ if (!entries.count(e)) {
1524+ glDisableVertexAttribArray(e);
1525+ }
1526+ }
1527+ enabled_attrib_arrays_ = entries;
1528+}
1529+
1530+// static
1531+State& State::instance() {
1532+ static State binder;
1533+ return binder;
1534+}
1535+
1536+
1537 void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset) {
1538 glVertexAttribPointer(
1539 vertex_index, num_items, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<void*>(offset));
1540
1541=== modified file 'src/graphic/gl/utils.h'
1542--- src/graphic/gl/utils.h 2016-01-05 11:28:54 +0000
1543+++ src/graphic/gl/utils.h 2016-01-16 20:47:43 +0000
1544@@ -20,6 +20,8 @@
1545 #define WL_GRAPHIC_GL_UTILS_H
1546
1547 #include <memory>
1548+#include <unordered_map>
1549+#include <unordered_set>
1550 #include <vector>
1551
1552 #include <stdint.h>
1553@@ -63,10 +65,10 @@
1554 template<typename T>
1555 class Buffer {
1556 public:
1557- Buffer() : buffer_size_(0) {
1558+ Buffer() {
1559 glGenBuffers(1, &object_);
1560 if (!object_) {
1561- throw wexception("Could not create GL program.");
1562+ throw wexception("Could not create GL buffer.");
1563 }
1564 }
1565
1566@@ -82,24 +84,60 @@
1567 }
1568
1569
1570- // Copies 'elements' into the buffer. If the buffer is too small to hold the
1571- // data, it is reallocated. Does not check if the buffer is already bound.
1572+ // Copies 'elements' into the buffer, overwriting what was there before.
1573+ // Does not check if the buffer is already bound.
1574 void update(const std::vector<T>& items) {
1575- if (buffer_size_ < items.size()) {
1576- glBufferData(GL_ARRAY_BUFFER, items.size() * sizeof(T), items.data(), GL_DYNAMIC_DRAW);
1577- buffer_size_ = items.size();
1578- } else {
1579- glBufferSubData(GL_ARRAY_BUFFER, 0, items.size() * sizeof(T), items.data());
1580- }
1581+ // Always re-allocate the buffer. This ends up being much more
1582+ // efficient than trying to do a partial update, because partial
1583+ // updates tend to force the driver to do command buffer flushes.
1584+ glBufferData(GL_ARRAY_BUFFER, items.size() * sizeof(T), items.data(), GL_DYNAMIC_DRAW);
1585 }
1586
1587 private:
1588 GLuint object_;
1589- size_t buffer_size_; // In number of elements.
1590
1591 DISALLOW_COPY_AND_ASSIGN(Buffer);
1592 };
1593
1594+// Some GL drivers do not remember the current pipeline state. If you rebind a
1595+// texture that has already bound to the same target, they will happily stall
1596+// the pipeline. We therefore cache the state of the GL driver in this class
1597+// and skip unneeded GL calls.
1598+class State {
1599+public:
1600+ static State& instance();
1601+
1602+ void bind_framebuffer(GLuint framebuffer, GLuint texture);
1603+
1604+ // Wrapper around glActiveTexture() and glBindTexture(). We never unbind a
1605+ // texture, i.e. calls with texture == 0 are ignored. It costs only time and
1606+ // is only needed when the bounded texture is rendered on - see
1607+ // 'unbind_texture_if_bound'.
1608+ void bind(GLenum target, GLuint texture);
1609+
1610+ // Checks if the texture is bound to any target. If so, unbinds it. This is
1611+ // needed before the texture is used as target for rendering.
1612+ void unbind_texture_if_bound(GLuint texture);
1613+
1614+ // Calls glEnableVertexAttribArray on all 'entries' and disables all others
1615+ // that are activated. 'entries' is taken by value on purpose.
1616+ void enable_vertex_attrib_array(std::unordered_set<GLint> entries);
1617+
1618+private:
1619+ std::unordered_map<GLenum, GLuint> target_to_texture_;
1620+ std::unordered_map<GLuint, GLenum> texture_to_target_;
1621+ std::unordered_set<GLint> enabled_attrib_arrays_;
1622+ GLenum last_active_texture_;
1623+ GLuint current_framebuffer_;
1624+ GLuint current_framebuffer_texture_;
1625+
1626+ State();
1627+
1628+ void do_bind(GLenum target, GLuint texture);
1629+
1630+ DISALLOW_COPY_AND_ASSIGN(State);
1631+};
1632+
1633 // Calls glVertexAttribPointer.
1634 void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset);
1635
1636
1637=== modified file 'src/graphic/graphic.cc'
1638--- src/graphic/graphic.cc 2015-01-28 07:32:57 +0000
1639+++ src/graphic/graphic.cc 2016-01-16 20:47:43 +0000
1640@@ -21,17 +21,23 @@
1641
1642 #include <memory>
1643
1644+#include "base/i18n.h"
1645 #include "base/log.h"
1646 #include "base/wexception.h"
1647 #include "build_info.h"
1648+#include "graphic/align.h"
1649 #include "graphic/animation.h"
1650+#include "graphic/build_texture_atlas.h"
1651+#include "graphic/font.h"
1652 #include "graphic/font_handler.h"
1653+#include "graphic/font_handler1.h"
1654 #include "graphic/gl/system_headers.h"
1655 #include "graphic/image.h"
1656 #include "graphic/image_io.h"
1657 #include "graphic/render_queue.h"
1658 #include "graphic/rendertarget.h"
1659 #include "graphic/screen.h"
1660+#include "graphic/text_layout.h"
1661 #include "graphic/texture.h"
1662 #include "io/filesystem/layered_filesystem.h"
1663 #include "io/streamwrite.h"
1664@@ -57,16 +63,17 @@
1665
1666 } // namespace
1667
1668+Graphic::Graphic() : image_cache_(new ImageCache()), animation_manager_(new AnimationManager()) {
1669+}
1670+
1671 /**
1672 * Initialize the SDL video mode.
1673-*/
1674-Graphic::Graphic(int window_mode_w, int window_mode_h, bool init_fullscreen)
1675- : m_window_mode_width(window_mode_w),
1676- m_window_mode_height(window_mode_h),
1677- m_update(true),
1678- image_cache_(new ImageCache()),
1679- animation_manager_(new AnimationManager())
1680-{
1681+ */
1682+void Graphic::initialize(int window_mode_w, int window_mode_h, bool init_fullscreen) {
1683+ m_window_mode_width = window_mode_w;
1684+ m_window_mode_height = window_mode_h;
1685+ m_requires_update = true;
1686+
1687 // Request an OpenGL 2 context with double buffering.
1688 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
1689 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
1690@@ -74,12 +81,10 @@
1691 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
1692
1693 log("Graphics: Try to set Videomode %ux%u\n", m_window_mode_width, m_window_mode_height);
1694- m_sdl_window = SDL_CreateWindow("Widelands Window",
1695- SDL_WINDOWPOS_UNDEFINED,
1696- SDL_WINDOWPOS_UNDEFINED,
1697- m_window_mode_width,
1698- m_window_mode_height,
1699- SDL_WINDOW_OPENGL);
1700+ m_sdl_window =
1701+ SDL_CreateWindow("Widelands Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
1702+ m_window_mode_width, m_window_mode_height, SDL_WINDOW_OPENGL);
1703+
1704 resolution_changed();
1705 set_fullscreen(init_fullscreen);
1706
1707@@ -96,22 +101,22 @@
1708 glewExperimental = GL_TRUE;
1709 GLenum err = glewInit();
1710 if (err != GLEW_OK) {
1711- log("glewInit returns %i\nYour OpenGL installation must be __very__ broken. %s\n",
1712- err, glewGetErrorString(err));
1713+ log("glewInit returns %i\nYour OpenGL installation must be __very__ broken. %s\n", err,
1714+ glewGetErrorString(err));
1715 throw wexception("glewInit returns %i: Broken OpenGL installation.", err);
1716 }
1717 #endif
1718
1719- log("Graphics: OpenGL: Version \"%s\"\n",
1720- reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1721+ log(
1722+ "Graphics: OpenGL: Version \"%s\"\n", reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1723
1724 GLboolean glBool;
1725 glGetBooleanv(GL_DOUBLEBUFFER, &glBool);
1726 log("Graphics: OpenGL: Double buffering %s\n", (glBool == GL_TRUE) ? "enabled" : "disabled");
1727
1728- GLint glInt;
1729- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glInt);
1730- log("Graphics: OpenGL: Max texture size: %u\n", glInt);
1731+ GLint max_texture_size;
1732+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
1733+ log("Graphics: OpenGL: Max texture size: %u\n", max_texture_size);
1734
1735 glDrawBuffer(GL_BACK);
1736
1737@@ -134,12 +139,15 @@
1738 " pixel fmt %u\n"
1739 " size %d %d\n"
1740 "**** END GRAPHICS REPORT ****\n",
1741- SDL_GetCurrentVideoDriver(),
1742- disp_mode.format,
1743- disp_mode.w,
1744- disp_mode.h);
1745+ SDL_GetCurrentVideoDriver(), disp_mode.format, disp_mode.w, disp_mode.h);
1746 assert(SDL_BYTESPERPIXEL(disp_mode.format) == 4);
1747 }
1748+
1749+
1750+ std::map<std::string, std::unique_ptr<Texture>> textures_in_atlas;
1751+ auto texture_atlases = build_texture_atlas(max_texture_size, &textures_in_atlas);
1752+ image_cache_->fill_with_texture_atlases(
1753+ std::move(texture_atlases), std::move(textures_in_atlas));
1754 }
1755
1756 Graphic::~Graphic()
1757@@ -239,14 +247,14 @@
1758
1759
1760 void Graphic::update() {
1761- m_update = true;
1762+ m_requires_update = true;
1763 }
1764
1765 /**
1766 * Returns true if parts of the screen have been marked for refreshing.
1767 */
1768 bool Graphic::need_update() const {
1769- return m_update;
1770+ return m_requires_update;
1771 }
1772
1773 /**
1774@@ -270,7 +278,7 @@
1775 }
1776
1777 SDL_GL_SwapWindow(m_sdl_window);
1778- m_update = false;
1779+ m_requires_update = false;
1780 }
1781
1782
1783
1784=== modified file 'src/graphic/graphic.h'
1785--- src/graphic/graphic.h 2015-06-10 06:46:40 +0000
1786+++ src/graphic/graphic.h 2016-01-16 20:47:43 +0000
1787@@ -50,11 +50,14 @@
1788 */
1789 class Graphic {
1790 public:
1791- // Creates a new graphic mode with the given resolution if fullscreen is
1792- // false, otherwise a window that fills the screen.
1793- Graphic(int window_mode_w, int window_mode_height, bool fullscreen);
1794+ // Creates a new Graphic object. Must call initialize before first use.
1795+ Graphic();
1796 ~Graphic();
1797
1798+ // Initializes with the given resolution if fullscreen is false, otherwise a
1799+ // window that fills the screen.
1800+ void initialize(int window_mode_w, int window_mode_height, bool fullscreen);
1801+
1802 // Gets and sets the resolution.
1803 void change_resolution(int w, int h);
1804 int get_xres();
1805@@ -96,7 +99,7 @@
1806 /// A RenderTarget for screen_. This is initialized during init()
1807 std::unique_ptr<RenderTarget> m_rendertarget;
1808 /// This marks the complete screen for updating.
1809- bool m_update;
1810+ bool m_requires_update;
1811
1812 /// Non-volatile cache of independent images.
1813 std::unique_ptr<ImageCache> image_cache_;
1814
1815=== modified file 'src/graphic/image_cache.cc'
1816--- src/graphic/image_cache.cc 2016-01-12 21:26:15 +0000
1817+++ src/graphic/image_cache.cc 2016-01-16 20:47:43 +0000
1818@@ -25,36 +25,11 @@
1819 #include <string>
1820
1821 #include <SDL.h>
1822-#include <boost/format.hpp>
1823
1824 #include "graphic/image.h"
1825 #include "graphic/image_io.h"
1826 #include "graphic/texture.h"
1827
1828-ImageCache::ProxyImage::ProxyImage(std::unique_ptr<const Image> original_image)
1829- : image_(std::move(original_image)) {
1830-}
1831-
1832-const Image& ImageCache::ProxyImage::image() {
1833- return *image_;
1834-}
1835-
1836-void ImageCache::ProxyImage::set_image(std::unique_ptr<const Image> original_image) {
1837- image_ = std::move(original_image);
1838-}
1839-
1840-int ImageCache::ProxyImage::width() const {
1841- return image_->width();
1842-}
1843-
1844-int ImageCache::ProxyImage::height() const {
1845- return image_->height();
1846-}
1847-
1848-const BlitData& ImageCache::ProxyImage::blit_data() const {
1849- return image_->blit_data();
1850-}
1851-
1852 ImageCache::ImageCache() {
1853 }
1854
1855@@ -68,16 +43,23 @@
1856 const Image* ImageCache::insert(const std::string& hash, std::unique_ptr<const Image> image) {
1857 assert(!has(hash));
1858 const Image* return_value = image.get();
1859- images_.insert(make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(std::move(image)))));
1860+ images_.insert(std::make_pair(hash, std::move(image)));
1861 return return_value;
1862 }
1863
1864+void ImageCache::fill_with_texture_atlases(
1865+ std::vector<std::unique_ptr<Texture>> texture_atlases,
1866+ std::map<std::string, std::unique_ptr<Texture>> textures_in_atlas) {
1867+ texture_atlases_ = std::move(texture_atlases);
1868+ for (auto& pair : textures_in_atlas) {
1869+ images_.insert(std::move(pair));
1870+ }
1871+}
1872+
1873 const Image* ImageCache::get(const std::string& hash) {
1874- ImageMap::const_iterator it = images_.find(hash);
1875+ auto it = images_.find(hash);
1876 if (it == images_.end()) {
1877- images_.insert(
1878- make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(load_image(hash)))));
1879- return get(hash);
1880+ return images_.insert(std::make_pair(hash, std::move(load_image(hash)))).first->second.get();
1881 }
1882 return it->second.get();
1883 }
1884
1885=== modified file 'src/graphic/image_cache.h'
1886--- src/graphic/image_cache.h 2016-01-07 16:21:36 +0000
1887+++ src/graphic/image_cache.h 2016-01-16 20:47:43 +0000
1888@@ -33,51 +33,36 @@
1889
1890 // For historic reasons, most part of the Widelands code base expect that an
1891 // Image stays valid for the whole duration of the program run. This class is
1892-// the one that keeps ownership of all Images to ensure that this is true. Also
1893-// for historic reasons, this class will try to load in Image from disk when
1894-// its hash is not found. Other parts of Widelands will create images when they
1895-// do not exist in the cache yet and then put it into the cache and therefore
1896-// releasing their ownership.
1897+// the one that keeps ownership of all Images to ensure that this is true.
1898+// Other parts of Widelands will create images when they do not exist in the
1899+// cache yet and then put it into the cache and therefore releasing their
1900+// ownership.
1901 class ImageCache {
1902 public:
1903 ImageCache();
1904 ~ImageCache();
1905
1906- // Insert the given Image into the cache.
1907- // Will return a pointer to the freshly inserted image for convenience.
1908+ // Insert the 'image' into the cache and returns a pointer to the inserted
1909+ // image for convenience.
1910 const Image* insert(const std::string& hash, std::unique_ptr<const Image> image);
1911
1912- // Returns the image associated with the given hash. If no image by this
1913- // hash is known, it will try to load one from disk with the filename =
1914- // hash. If this fails, it will throw an error.
1915+ // Returns the image associated with the 'hash'. If no image by this hash is
1916+ // known, it will try to load one from disk with the filename = hash. If
1917+ // this fails, it will throw an error.
1918 const Image* get(const std::string& hash);
1919
1920- // Returns true if the given hash is stored in the cache.
1921+ // Returns true if the 'hash' is stored in the cache.
1922 bool has(const std::string& hash) const;
1923
1924+ // Fills the image cache with the hash -> Texture map 'textures_in_atlas'
1925+ // and take ownership of 'texture_atlases' so that the textures stay valid.
1926+ void
1927+ fill_with_texture_atlases(std::vector<std::unique_ptr<Texture>> texture_atlases,
1928+ std::map<std::string, std::unique_ptr<Texture>> textures_in_atlas);
1929+
1930 private:
1931- // We return a wrapped Image so that we can swap out the pointer to the
1932- // image under our user. This can happen when we move an Image from a stand
1933- // alone texture into being a subrect of a texture atlas.
1934- class ProxyImage : public Image {
1935- public:
1936- ProxyImage(std::unique_ptr<const Image> image);
1937-
1938- const Image& image();
1939- void set_image(std::unique_ptr<const Image> image);
1940-
1941- int width() const override;
1942- int height() const override;
1943- const BlitData& blit_data() const override;
1944-
1945- private:
1946- std::unique_ptr<const Image> image_;
1947- };
1948-
1949- using ImageMap = std::map<std::string, std::unique_ptr<ProxyImage>>;
1950-
1951 std::vector<std::unique_ptr<Texture>> texture_atlases_;
1952- ImageMap images_; /// hash of cached filename/image pairs
1953+ std::map<std::string, std::unique_ptr<const Image>> images_;
1954
1955 DISALLOW_COPY_AND_ASSIGN(ImageCache);
1956 };
1957
1958=== modified file 'src/graphic/render_queue.cc'
1959--- src/graphic/render_queue.cc 2016-01-10 11:56:27 +0000
1960+++ src/graphic/render_queue.cc 2016-01-16 20:47:43 +0000
1961@@ -22,7 +22,6 @@
1962 #include <algorithm>
1963 #include <limits>
1964
1965-#include "base/log.h"
1966 #include "base/rect.h"
1967 #include "base/wexception.h"
1968 #include "graphic/gl/blit_program.h"
1969@@ -76,25 +75,15 @@
1970 return (z_value << 40) | (program_id << 36) | extra_value;
1971 }
1972
1973-// Construct 'args' used by the individual programs out of 'item'.
1974-inline void from_item(const RenderQueue::Item& item, VanillaBlitProgram::Arguments* args) {
1975- args->texture = item.vanilla_blit_arguments.texture;
1976- args->opacity = item.vanilla_blit_arguments.opacity;
1977-}
1978-
1979-inline void from_item(const RenderQueue::Item& item, MonochromeBlitProgram::Arguments* args) {
1980- args->texture = item.monochrome_blit_arguments.texture;
1981- args->blend = item.monochrome_blit_arguments.blend;
1982-}
1983-
1984 inline void from_item(const RenderQueue::Item& item, FillRectProgram::Arguments* args) {
1985 args->color = item.rect_arguments.color;
1986 }
1987
1988-inline void from_item(const RenderQueue::Item& item, BlendedBlitProgram::Arguments* args) {
1989- args->texture = item.blended_blit_arguments.texture;
1990- args->blend = item.blended_blit_arguments.blend;
1991- args->mask = item.blended_blit_arguments.mask;
1992+inline void from_item(const RenderQueue::Item& item, BlitProgram::Arguments* args) {
1993+ args->texture = item.blit_arguments.texture;
1994+ args->blend = item.blit_arguments.blend;
1995+ args->mask = item.blit_arguments.mask;
1996+ args->blit_mode = item.blit_arguments.mode;
1997 }
1998
1999 inline void from_item(const RenderQueue::Item& item, DrawLineProgram::Arguments* args) {
2000@@ -167,15 +156,7 @@
2001
2002 switch (given_item.program_id) {
2003 case Program::kBlit:
2004- extra_value = given_item.vanilla_blit_arguments.texture.texture_id;
2005- break;
2006-
2007- case Program::kBlitMonochrome:
2008- extra_value = given_item.monochrome_blit_arguments.texture.texture_id;
2009- break;
2010-
2011- case Program::kBlitBlended:
2012- extra_value = given_item.blended_blit_arguments.texture.texture_id;
2013+ extra_value = given_item.blit_arguments.texture.texture_id;
2014 break;
2015
2016 case Program::kLine:
2017@@ -212,7 +193,7 @@
2018 throw wexception("Too many drawn layers. Ran out of z-values.");
2019 }
2020
2021- glBindFramebuffer(GL_FRAMEBUFFER, 0);
2022+ Gl::State::instance().bind_framebuffer(0, 0);
2023 glViewport(0, 0, screen_width, screen_height);
2024
2025 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
2026@@ -231,7 +212,6 @@
2027 blended_items_.clear();
2028
2029 glDepthMask(GL_TRUE);
2030-
2031 next_z_ = 1;
2032 }
2033
2034@@ -241,18 +221,8 @@
2035 const Item& item = items[i];
2036 switch (item.program_id) {
2037 case Program::kBlit:
2038- VanillaBlitProgram::instance().draw(
2039- batch_up<VanillaBlitProgram::Arguments>(Program::kBlit, items, &i));
2040- break;
2041-
2042- case Program::kBlitMonochrome:
2043- MonochromeBlitProgram::instance().draw(
2044- batch_up<MonochromeBlitProgram::Arguments>(Program::kBlitMonochrome, items, &i));
2045- break;
2046-
2047- case Program::kBlitBlended:
2048- BlendedBlitProgram::instance().draw(
2049- batch_up<BlendedBlitProgram::Arguments>(Program::kBlitBlended, items, &i));
2050+ BlitProgram::instance().draw(
2051+ batch_up<BlitProgram::Arguments>(Program::kBlit, items, &i));
2052 break;
2053
2054 case Program::kLine:
2055
2056=== modified file 'src/graphic/render_queue.h'
2057--- src/graphic/render_queue.h 2016-01-08 21:00:39 +0000
2058+++ src/graphic/render_queue.h 2016-01-16 20:47:43 +0000
2059@@ -28,6 +28,7 @@
2060 #include "base/macros.h"
2061 #include "base/rect.h"
2062 #include "graphic/blend_mode.h"
2063+#include "graphic/blit_mode.h"
2064 #include "graphic/color.h"
2065 #include "graphic/gl/fields_to_draw.h"
2066 #include "logic/description_maintainer.h"
2067@@ -82,24 +83,18 @@
2068 kTerrainDither,
2069 kTerrainRoad,
2070 kBlit,
2071- kBlitMonochrome,
2072- kBlitBlended,
2073 kRect,
2074 kLine,
2075 kHighestProgramId,
2076 };
2077
2078- struct VanillaBlitArguments {
2079- BlitData texture;
2080- float opacity;
2081- };
2082-
2083 struct MonochromeBlitArguments {
2084 BlitData texture;
2085 RGBAColor blend;
2086 };
2087
2088- struct BlendedBlitArguments {
2089+ struct BlitArguments {
2090+ BlitMode mode;
2091 BlitData texture;
2092 BlitData mask;
2093 RGBAColor blend;
2094@@ -154,9 +149,7 @@
2095 BlendMode blend_mode;
2096
2097 union {
2098- VanillaBlitArguments vanilla_blit_arguments;
2099- MonochromeBlitArguments monochrome_blit_arguments;
2100- BlendedBlitArguments blended_blit_arguments;
2101+ BlitArguments blit_arguments;
2102 TerrainArguments terrain_arguments;
2103 RectArguments rect_arguments;
2104 LineArguments line_arguments;
2105
2106=== modified file 'src/graphic/screen.cc'
2107--- src/graphic/screen.cc 2016-01-05 11:28:54 +0000
2108+++ src/graphic/screen.cc 2016-01-16 20:47:43 +0000
2109@@ -65,11 +65,13 @@
2110 float opacity,
2111 BlendMode blend_mode) {
2112 RenderQueue::Item i;
2113+ i.destination_rect = dst_rect;
2114 i.program_id = RenderQueue::Program::kBlit;
2115 i.blend_mode = blend_mode;
2116- i.destination_rect = dst_rect;
2117- i.vanilla_blit_arguments.texture = texture;
2118- i.vanilla_blit_arguments.opacity = opacity;
2119+ i.blit_arguments.texture = texture;
2120+ i.blit_arguments.mask.texture_id = 0;
2121+ i.blit_arguments.blend = RGBAColor(0, 0, 0, 255 * opacity);
2122+ i.blit_arguments.mode = BlitMode::kDirect;
2123 RenderQueue::instance().enqueue(i);
2124 }
2125
2126@@ -79,11 +81,12 @@
2127 const RGBColor& blend) {
2128 RenderQueue::Item i;
2129 i.destination_rect = dst_rect;
2130- i.program_id = RenderQueue::Program::kBlitBlended;
2131+ i.program_id = RenderQueue::Program::kBlit;
2132 i.blend_mode = BlendMode::UseAlpha;
2133- i.blended_blit_arguments.texture = texture;
2134- i.blended_blit_arguments.mask = mask;
2135- i.blended_blit_arguments.blend = blend;
2136+ i.blit_arguments.texture = texture;
2137+ i.blit_arguments.mask = mask;
2138+ i.blit_arguments.blend = blend;
2139+ i.blit_arguments.mode = BlitMode::kBlendedWithMask;
2140 RenderQueue::instance().enqueue(i);
2141 }
2142
2143@@ -91,11 +94,13 @@
2144 const BlitData& texture,
2145 const RGBAColor& blend) {
2146 RenderQueue::Item i;
2147- i.program_id = RenderQueue::Program::kBlitMonochrome;
2148+ i.destination_rect = dst_rect;
2149+ i.program_id = RenderQueue::Program::kBlit;
2150 i.blend_mode = BlendMode::UseAlpha;
2151- i.destination_rect = dst_rect;
2152- i.monochrome_blit_arguments.texture = texture;
2153- i.monochrome_blit_arguments.blend = blend;
2154+ i.blit_arguments.texture = texture;
2155+ i.blit_arguments.mask.texture_id = 0;
2156+ i.blit_arguments.blend = blend;
2157+ i.blit_arguments.mode = BlitMode::kMonochrome;
2158 RenderQueue::instance().enqueue(i);
2159 }
2160
2161
2162=== modified file 'src/graphic/surface.h'
2163--- src/graphic/surface.h 2016-01-04 20:54:08 +0000
2164+++ src/graphic/surface.h 2016-01-16 20:47:43 +0000
2165@@ -48,14 +48,14 @@
2166 const float opacity,
2167 BlendMode blend_mode);
2168
2169- /// This draws a playercolor blended image. See BlendedBlitProgram.
2170+ /// This draws a playercolor blended image.
2171 void blit_blended(const Rect& dst,
2172 const Image& image,
2173 const Image& texture_mask,
2174 const Rect& srcrc,
2175 const RGBColor& blend);
2176
2177- /// This draws a grayed out version. See MonochromeBlitProgram.
2178+ /// This draws a grayed out version.
2179 void
2180 blit_monochrome(const Rect& dst, const Image&, const Rect& srcrc, const RGBAColor& multiplier);
2181
2182
2183=== modified file 'src/graphic/text/test/render_richtext.cc'
2184--- src/graphic/text/test/render_richtext.cc 2015-03-01 09:21:20 +0000
2185+++ src/graphic/text/test/render_richtext.cc 2016-01-16 20:47:43 +0000
2186@@ -98,7 +98,8 @@
2187 g_fs = new LayeredFileSystem();
2188 g_fs->add_file_system(&FileSystem::create(INSTALL_DATADIR));
2189
2190- g_gr = new Graphic(1, 1, false);
2191+ g_gr = new Graphic();
2192+ g_gr->initialize(1, 1, false);
2193 }
2194
2195 } // namespace
2196
2197=== modified file 'src/graphic/texture.cc'
2198--- src/graphic/texture.cc 2016-01-12 08:17:04 +0000
2199+++ src/graphic/texture.cc 2016-01-16 20:47:43 +0000
2200@@ -167,6 +167,7 @@
2201 Texture::~Texture()
2202 {
2203 if (m_owns_texture) {
2204+ Gl::State::instance().unbind_texture_if_bound(m_blit_data.texture_id);
2205 glDeleteTextures(1, &m_blit_data.texture_id);
2206 }
2207 }
2208@@ -192,7 +193,7 @@
2209
2210 m_owns_texture = true;
2211 glGenTextures(1, &m_blit_data.texture_id);
2212- glBindTexture(GL_TEXTURE_2D, m_blit_data.texture_id);
2213+ Gl::State::instance().bind(GL_TEXTURE0, m_blit_data.texture_id);
2214
2215 // set texture filter to use linear filtering. This looks nicer for resized
2216 // texture. Most textures and images are not resized so the filtering
2217@@ -215,9 +216,8 @@
2218
2219 m_pixels.reset(new uint8_t[width() * height() * 4]);
2220
2221- glBindTexture(GL_TEXTURE_2D, m_blit_data.texture_id);
2222+ Gl::State::instance().bind(GL_TEXTURE0, m_blit_data.texture_id);
2223 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels.get());
2224- glBindTexture(GL_TEXTURE_2D, 0);
2225 }
2226
2227 void Texture::unlock(UnlockMode mode) {
2228@@ -227,11 +227,9 @@
2229 assert(m_pixels);
2230
2231 if (mode == Unlock_Update) {
2232- glBindTexture(GL_TEXTURE_2D, m_blit_data.texture_id);
2233- glTexImage2D
2234- (GL_TEXTURE_2D, 0, static_cast<GLint>(GL_RGBA), width(), height(), 0, GL_RGBA,
2235- GL_UNSIGNED_BYTE, m_pixels.get());
2236- glBindTexture(GL_TEXTURE_2D, 0);
2237+ Gl::State::instance().bind(GL_TEXTURE0, m_blit_data.texture_id);
2238+ glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(GL_RGBA), width(), height(), 0, GL_RGBA,
2239+ GL_UNSIGNED_BYTE, m_pixels.get());
2240 }
2241
2242 m_pixels.reset(nullptr);
2243@@ -265,8 +263,8 @@
2244
2245
2246 void Texture::setup_gl() {
2247- glBindFramebuffer(GL_FRAMEBUFFER, GlFramebuffer::instance().id());
2248- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_blit_data.texture_id, 0);
2249+ Gl::State::instance().bind_framebuffer(
2250+ GlFramebuffer::instance().id(), m_blit_data.texture_id);
2251 glViewport(0, 0, width(), height());
2252 }
2253
2254@@ -275,7 +273,8 @@
2255 float opacity,
2256 BlendMode blend_mode) {
2257 setup_gl();
2258- VanillaBlitProgram::instance().draw(dst_rect, 0.f, texture, opacity, blend_mode);
2259+ BlitProgram::instance().draw(dst_rect, 0.f, texture, BlitData{0, 0, 0, Rect()},
2260+ RGBAColor(0, 0, 0, 255 * opacity), blend_mode);
2261 }
2262
2263 void Texture::do_blit_blended(const FloatRect& dst_rect,
2264@@ -284,14 +283,14 @@
2265 const RGBColor& blend) {
2266
2267 setup_gl();
2268- BlendedBlitProgram::instance().draw(dst_rect, 0.f, texture, mask, blend);
2269+ BlitProgram::instance().draw(dst_rect, 0.f, texture, mask, blend, BlendMode::UseAlpha);
2270 }
2271
2272 void Texture::do_blit_monochrome(const FloatRect& dst_rect,
2273 const BlitData& texture,
2274 const RGBAColor& blend) {
2275 setup_gl();
2276- MonochromeBlitProgram::instance().draw(dst_rect, 0.f, texture, blend);
2277+ BlitProgram::instance().draw_monochrome(dst_rect, 0.f, texture, blend);
2278 }
2279
2280 void
2281
2282=== modified file 'src/logic/CMakeLists.txt'
2283--- src/logic/CMakeLists.txt 2016-01-10 11:36:05 +0000
2284+++ src/logic/CMakeLists.txt 2016-01-16 20:47:43 +0000
2285@@ -237,7 +237,6 @@
2286 graphic_surface
2287 graphic_text
2288 graphic_text_layout
2289- graphic_texture_atlas
2290 helper
2291 io_fileread
2292 io_filesystem
2293
2294=== modified file 'src/logic/map_info.cc'
2295--- src/logic/map_info.cc 2015-03-01 09:21:20 +0000
2296+++ src/logic/map_info.cc 2016-01-16 20:47:43 +0000
2297@@ -48,7 +48,8 @@
2298 g_fs = new LayeredFileSystem();
2299 g_fs->add_file_system(&FileSystem::create(INSTALL_DATADIR));
2300
2301- g_gr = new Graphic(1, 1, false);
2302+ g_gr = new Graphic();
2303+ g_gr->initialize(1, 1, false);
2304 }
2305
2306 } // namespace
2307
2308=== modified file 'src/logic/map_objects/tribes/road_textures.cc'
2309--- src/logic/map_objects/tribes/road_textures.cc 2015-11-28 22:29:26 +0000
2310+++ src/logic/map_objects/tribes/road_textures.cc 2016-01-16 20:47:43 +0000
2311@@ -21,18 +21,18 @@
2312
2313 #include <memory>
2314
2315-const Texture& RoadTextures::get_normal_texture(int x, int y, int direction) const {
2316+const Image& RoadTextures::get_normal_texture(int x, int y, int direction) const {
2317 return *normal_textures_.at((x + y + direction) % normal_textures_.size());
2318 }
2319
2320-const Texture& RoadTextures::get_busy_texture(int x, int y, int direction) const {
2321+const Image& RoadTextures::get_busy_texture(int x, int y, int direction) const {
2322 return *busy_textures_.at((x + y + direction) % busy_textures_.size());
2323 }
2324
2325-void RoadTextures::add_normal_road_texture(std::unique_ptr<Texture> texture) {
2326- normal_textures_.emplace_back(std::move(texture));
2327+void RoadTextures::add_normal_road_texture(const Image* image) {
2328+ normal_textures_.emplace_back(image);
2329 }
2330
2331-void RoadTextures::add_busy_road_texture(std::unique_ptr<Texture> texture) {
2332- busy_textures_.emplace_back(std::move(texture));
2333+void RoadTextures::add_busy_road_texture(const Image* image) {
2334+ busy_textures_.emplace_back(image);
2335 }
2336
2337=== modified file 'src/logic/map_objects/tribes/road_textures.h'
2338--- src/logic/map_objects/tribes/road_textures.h 2015-11-28 22:29:26 +0000
2339+++ src/logic/map_objects/tribes/road_textures.h 2016-01-16 20:47:43 +0000
2340@@ -23,23 +23,23 @@
2341 #include <memory>
2342 #include <vector>
2343
2344-#include "graphic/texture.h"
2345+#include "graphic/image.h"
2346
2347 // Simple container to give access of the road textures of a tribe.
2348 class RoadTextures {
2349 public:
2350 // Returns the road texture that should be used for the Cooordinate x, y and
2351 // the road going into direction 'direction' (which can be any number).
2352- const Texture& get_normal_texture(int x, int y, int direction) const;
2353- const Texture& get_busy_texture(int x, int y, int direction) const;
2354+ const Image& get_normal_texture(int x, int y, int direction) const;
2355+ const Image& get_busy_texture(int x, int y, int direction) const;
2356
2357 // Adds a new road texture.
2358- void add_normal_road_texture(std::unique_ptr<Texture> texture);
2359- void add_busy_road_texture(std::unique_ptr<Texture> texture);
2360+ void add_normal_road_texture(const Image* texture);
2361+ void add_busy_road_texture(const Image* texture);
2362
2363 private:
2364- std::vector<std::unique_ptr<Texture>> normal_textures_;
2365- std::vector<std::unique_ptr<Texture>> busy_textures_;
2366+ std::vector<const Image*> normal_textures_;
2367+ std::vector<const Image*> busy_textures_;
2368 };
2369
2370 #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_ROAD_TEXTURES_H
2371
2372=== modified file 'src/logic/map_objects/tribes/tribe_descr.cc'
2373--- src/logic/map_objects/tribes/tribe_descr.cc 2016-01-08 21:00:39 +0000
2374+++ src/logic/map_objects/tribes/tribe_descr.cc 2016-01-16 20:47:43 +0000
2375@@ -319,12 +319,12 @@
2376 return busy_road_paths_;
2377 }
2378
2379-void TribeDescr::add_normal_road_texture(std::unique_ptr<Texture> texture) {
2380- road_textures_.add_normal_road_texture(std::move(texture));
2381+void TribeDescr::add_normal_road_texture(const Image* texture) {
2382+ road_textures_.add_normal_road_texture(texture);
2383 }
2384
2385-void TribeDescr::add_busy_road_texture(std::unique_ptr<Texture> texture) {
2386- road_textures_.add_busy_road_texture(std::move(texture));
2387+void TribeDescr::add_busy_road_texture(const Image* texture) {
2388+ road_textures_.add_busy_road_texture(texture);
2389 }
2390
2391 const RoadTextures& TribeDescr::road_textures() const {
2392
2393=== modified file 'src/logic/map_objects/tribes/tribe_descr.h'
2394--- src/logic/map_objects/tribes/tribe_descr.h 2015-11-28 22:29:26 +0000
2395+++ src/logic/map_objects/tribes/tribe_descr.h 2016-01-16 20:47:43 +0000
2396@@ -114,10 +114,9 @@
2397 const std::vector<std::string>& normal_road_paths() const;
2398 const std::vector<std::string>& busy_road_paths() const;
2399
2400- // Add the corresponding texture (which probably resides in a
2401- // texture atlas) for roads.
2402- void add_normal_road_texture(std::unique_ptr<Texture> texture);
2403- void add_busy_road_texture(std::unique_ptr<Texture> texture);
2404+ // Add the corresponding texture for roads.
2405+ void add_normal_road_texture(const Image* texture);
2406+ void add_busy_road_texture(const Image* texture);
2407
2408 // The road textures used for drawing roads.
2409 const RoadTextures& road_textures() const;
2410
2411=== modified file 'src/logic/map_objects/tribes/tribes.cc'
2412--- src/logic/map_objects/tribes/tribes.cc 2016-01-12 21:26:15 +0000
2413+++ src/logic/map_objects/tribes/tribes.cc 2016-01-16 20:47:43 +0000
2414@@ -22,9 +22,6 @@
2415 #include <memory>
2416
2417 #include "graphic/graphic.h"
2418-#include "graphic/image_io.h"
2419-#include "graphic/texture_atlas.h"
2420-#include "io/filesystem/layered_filesystem.h"
2421 #include "logic/game_data_error.h"
2422
2423 namespace Widelands {
2424@@ -343,38 +340,15 @@
2425
2426 void Tribes::load_graphics()
2427 {
2428- // Construct and hold on to the texture atlas that contains all road images.
2429- TextureAtlas ta;
2430-
2431 // These will be deleted at the end of the method.
2432 std::vector<std::unique_ptr<Texture>> individual_textures_;
2433 for (size_t tribeindex = 0; tribeindex < nrtribes(); ++tribeindex) {
2434 TribeDescr* tribe = tribes_->get_mutable(tribeindex);
2435 for (const std::string& texture_path : tribe->normal_road_paths()) {
2436- individual_textures_.emplace_back(load_image(texture_path, g_fs));
2437- ta.add(*individual_textures_.back());
2438+ tribe->add_normal_road_texture(g_gr->images().get(texture_path));
2439 }
2440 for (const std::string& texture_path : tribe->busy_road_paths()) {
2441- individual_textures_.emplace_back(load_image(texture_path, g_fs));
2442- ta.add(*individual_textures_.back());
2443- }
2444- }
2445-
2446- std::vector<TextureAtlas::PackedTexture> packed_texture;
2447- std::vector<std::unique_ptr<Texture>> texture_atlases;
2448- ta.pack(1024, &texture_atlases, &packed_texture);
2449-
2450- assert(texture_atlases.size() == 1);
2451- road_texture_ = std::move(texture_atlases[0]);
2452-
2453- size_t next_texture_to_move = 0;
2454- for (size_t tribeindex = 0; tribeindex < nrtribes(); ++tribeindex) {
2455- TribeDescr* tribe = tribes_->get_mutable(tribeindex);
2456- for (size_t i = 0; i < tribe->normal_road_paths().size(); ++i) {
2457- tribe->add_normal_road_texture(std::move(packed_texture.at(next_texture_to_move++).texture));
2458- }
2459- for (size_t i = 0; i < tribe->busy_road_paths().size(); ++i) {
2460- tribe->add_busy_road_texture(std::move(packed_texture.at(next_texture_to_move++).texture));
2461+ tribe->add_busy_road_texture(g_gr->images().get(texture_path));
2462 }
2463 }
2464 }
2465
2466=== modified file 'src/logic/map_objects/tribes/tribes.h'
2467--- src/logic/map_objects/tribes/tribes.h 2015-11-28 22:29:26 +0000
2468+++ src/logic/map_objects/tribes/tribes.h 2016-01-16 20:47:43 +0000
2469@@ -154,8 +154,6 @@
2470 std::unique_ptr<DescriptionMaintainer<WorkerDescr>> workers_;
2471 std::unique_ptr<DescriptionMaintainer<TribeDescr>> tribes_;
2472
2473- std::unique_ptr<Texture> road_texture_; // Used in loading the road texture graphics
2474-
2475 DISALLOW_COPY_AND_ASSIGN(Tribes);
2476 };
2477
2478
2479=== modified file 'src/logic/map_objects/world/terrain_description.cc'
2480--- src/logic/map_objects/world/terrain_description.cc 2015-12-11 19:06:50 +0000
2481+++ src/logic/map_objects/world/terrain_description.cc 2016-01-16 20:47:43 +0000
2482@@ -160,15 +160,15 @@
2483 TerrainDescription::~TerrainDescription() {
2484 }
2485
2486-const Texture& TerrainDescription::get_texture(uint32_t gametime) const {
2487+const Image& TerrainDescription::get_texture(uint32_t gametime) const {
2488 return *textures_.at((gametime / frame_length_) % textures_.size());
2489 }
2490
2491-void TerrainDescription::add_texture(std::unique_ptr<Texture> texture) {
2492+void TerrainDescription::add_texture(const Image* texture) {
2493 if (texture->width() != kTextureSideLength || texture->height() != kTextureSideLength) {
2494 throw wexception("Tried to add a texture with wrong size.");
2495 }
2496- textures_.emplace_back(std::move(texture));
2497+ textures_.emplace_back(texture);
2498 }
2499
2500 const std::vector<std::string>& TerrainDescription::texture_paths() const {
2501
2502=== modified file 'src/logic/map_objects/world/terrain_description.h'
2503--- src/logic/map_objects/world/terrain_description.h 2015-12-11 19:06:50 +0000
2504+++ src/logic/map_objects/world/terrain_description.h 2016-01-16 20:47:43 +0000
2505@@ -73,8 +73,8 @@
2506 const std::vector<std::string>& texture_paths() const;
2507
2508 /// Returns the texture for the given gametime.
2509- const Texture& get_texture(uint32_t gametime) const;
2510- void add_texture(std::unique_ptr<Texture> texture);
2511+ const Image& get_texture(uint32_t gametime) const;
2512+ void add_texture(const Image* texture);
2513
2514 // Sets the base minimap color.
2515 void set_minimap_color(const RGBColor& color);
2516@@ -140,7 +140,7 @@
2517 double fertility_;
2518 double humidity_;
2519 std::vector<std::string> texture_paths_;
2520- std::vector<std::unique_ptr<Texture>> textures_;
2521+ std::vector<const Image*> textures_;
2522 RGBColor minimap_colors_[256];
2523
2524 DISALLOW_COPY_AND_ASSIGN(TerrainDescription);
2525
2526=== modified file 'src/logic/map_objects/world/world.cc'
2527--- src/logic/map_objects/world/world.cc 2016-01-12 21:26:15 +0000
2528+++ src/logic/map_objects/world/world.cc 2016-01-16 20:47:43 +0000
2529@@ -23,8 +23,6 @@
2530
2531 #include "base/i18n.h"
2532 #include "graphic/image_io.h"
2533-#include "graphic/texture.h"
2534-#include "graphic/texture_atlas.h"
2535 #include "logic/game_data_error.h"
2536 #include "logic/map_objects/bob.h"
2537 #include "logic/map_objects/immovable.h"
2538@@ -49,11 +47,6 @@
2539 }
2540
2541 void World::load_graphics() {
2542- TextureAtlas ta;
2543-
2544- // These will be deleted at the end of the method.
2545- std::vector<std::unique_ptr<Texture>> individual_textures_;
2546-
2547 for (size_t i = 0; i < terrains_->size(); ++i) {
2548 TerrainDescription* terrain = terrains_->get_mutable(i);
2549 for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
2550@@ -67,23 +60,7 @@
2551 terrain->set_minimap_color(
2552 RGBColor(top_left_pixel_color.r, top_left_pixel_color.g, top_left_pixel_color.b));
2553 }
2554- individual_textures_.emplace_back(new Texture(sdl_surface));
2555- ta.add(*individual_textures_.back());
2556- }
2557- }
2558-
2559- std::vector<TextureAtlas::PackedTexture> packed_texture;
2560- std::vector<std::unique_ptr<Texture>> texture_atlases;
2561- ta.pack(1024, &texture_atlases, &packed_texture);
2562-
2563- assert(texture_atlases.size() == 1);
2564- terrain_texture_ = std::move(texture_atlases[0]);
2565-
2566- int next_texture_to_move = 0;
2567- for (size_t i = 0; i < terrains_->size(); ++i) {
2568- TerrainDescription* terrain = terrains_->get_mutable(i);
2569- for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
2570- terrain->add_texture(std::move(packed_texture.at(next_texture_to_move++).texture));
2571+ terrain->add_texture(g_gr->images().get(terrain->texture_paths()[j]));
2572 }
2573 }
2574 }
2575
2576=== modified file 'src/logic/map_objects/world/world.h'
2577--- src/logic/map_objects/world/world.h 2015-11-28 22:29:26 +0000
2578+++ src/logic/map_objects/world/world.h 2016-01-16 20:47:43 +0000
2579@@ -28,7 +28,6 @@
2580
2581 class LuaInterface;
2582 class LuaTable;
2583-class Texture;
2584
2585 namespace Widelands {
2586
2587@@ -99,7 +98,6 @@
2588 std::unique_ptr<DescriptionMaintainer<ResourceDescription>> resources_;
2589 std::unique_ptr<DescriptionMaintainer<EditorCategory>> editor_terrain_categories_;
2590 std::unique_ptr<DescriptionMaintainer<EditorCategory>> editor_immovable_categories_;
2591- std::unique_ptr<Texture> terrain_texture_;
2592
2593 DISALLOW_COPY_AND_ASSIGN(World);
2594 };
2595
2596=== modified file 'src/wlapplication.cc'
2597--- src/wlapplication.cc 2015-11-28 22:29:26 +0000
2598+++ src/wlapplication.cc 2016-01-16 20:47:43 +0000
2599@@ -271,19 +271,32 @@
2600 changedir_on_mac();
2601 cleanup_replays();
2602
2603- // handling of graphics
2604- init_hardware();
2605-
2606- // This might grab the input.
2607- refresh_graphics();
2608+ Section & config = g_options.pull_section("global");
2609+
2610+ //Start the SDL core
2611+ if (SDL_Init(SDL_INIT_VIDEO) == -1)
2612+ throw wexception("Failed to initialize SDL, no valid video driver: %s", SDL_GetError());
2613+
2614+ SDL_ShowCursor(SDL_DISABLE);
2615+ g_gr = new Graphic();
2616
2617 if (TTF_Init() == -1)
2618 throw wexception
2619 ("True Type library did not initialize: %s\n", TTF_GetError());
2620
2621- UI::g_fh1 = UI::create_fonthandler(g_gr); // This will create the fontset, so loading it first.
2622+ UI::g_fh1 =
2623+ UI::create_fonthandler(&g_gr->images()); // This will create the fontset, so loading it first.
2624 UI::g_fh = new UI::FontHandler();
2625
2626+ g_gr->initialize(config.get_int("xres", DEFAULT_RESOLUTION_W),
2627+ config.get_int("yres", DEFAULT_RESOLUTION_H),
2628+ config.get_bool("fullscreen", false));
2629+ g_sound_handler.init(); // TODO(unknown): memory leak!
2630+
2631+
2632+ // This might grab the input.
2633+ refresh_graphics();
2634+
2635 if (SDLNet_Init() == -1)
2636 throw wexception("SDLNet_Init failed: %s\n", SDLNet_GetError());
2637
2638@@ -779,33 +792,6 @@
2639 }
2640 }
2641
2642-/**
2643- * Start the hardware: switch to graphics mode, start sound handler
2644- *
2645- * \pre The locale must be known before calling this
2646- *
2647- * \return true if there were no fatal errors that prevent the game from running
2648- */
2649-bool WLApplication::init_hardware() {
2650- Section & s = g_options.pull_section("global");
2651-
2652- //Start the SDL core
2653- if (SDL_Init(SDL_INIT_VIDEO) == -1)
2654- throw wexception
2655- ("Failed to initialize SDL, no valid video driver: %s",
2656- SDL_GetError());
2657-
2658- SDL_ShowCursor(SDL_DISABLE);
2659-
2660- g_gr = new Graphic(s.get_int("xres", DEFAULT_RESOLUTION_W),
2661- s.get_int("yres", DEFAULT_RESOLUTION_H),
2662- s.get_bool("fullscreen", false));
2663-
2664- g_sound_handler.init(); // TODO(unknown): memory leak!
2665-
2666- return true;
2667-}
2668-
2669 void WLApplication::shutdown_hardware()
2670 {
2671 delete g_gr;
2672
2673=== modified file 'src/wlapplication.h'
2674--- src/wlapplication.h 2015-11-08 17:31:06 +0000
2675+++ src/wlapplication.h 2016-01-16 20:47:43 +0000
2676@@ -191,7 +191,6 @@
2677 void init_language();
2678 void shutdown_settings();
2679
2680- bool init_hardware();
2681 void shutdown_hardware();
2682
2683 void parse_commandline(int argc, char const * const * argv);

Subscribers

People subscribed via source and target branches

to status/vote changes: