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