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

Proposed by SirVer
Status: Merged
Merged at revision: 7692
Proposed branch: lp:~widelands-dev/widelands/render_queue
Merge into: lp:widelands
Diff against target: 5851 lines (+2481/-1186)
67 files modified
src/base/rect.h (+4/-4)
src/editor/editorinteractive.cc (+1/-0)
src/editor/ui_menus/editor_tool_change_resources_options_menu.cc (+1/-1)
src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc (+4/-5)
src/graphic/CMakeLists.txt (+79/-18)
src/graphic/animation.cc (+8/-25)
src/graphic/blend_mode.h (+6/-2)
src/graphic/color.cc (+1/-1)
src/graphic/color.h (+6/-2)
src/graphic/font_handler1.cc (+2/-6)
src/graphic/game_renderer.cc (+32/-30)
src/graphic/game_renderer.h (+5/-8)
src/graphic/gl/blit_data.h (+44/-0)
src/graphic/gl/blit_program.cc (+292/-132)
src/graphic/gl/blit_program.h (+48/-18)
src/graphic/gl/coordinate_conversion.h (+73/-0)
src/graphic/gl/dither_program.cc (+59/-48)
src/graphic/gl/dither_program.h (+14/-4)
src/graphic/gl/draw_line_program.cc (+84/-28)
src/graphic/gl/draw_line_program.h (+46/-7)
src/graphic/gl/fields_to_draw.h (+20/-14)
src/graphic/gl/fill_rect_program.cc (+146/-52)
src/graphic/gl/fill_rect_program.h (+44/-10)
src/graphic/gl/road_program.cc (+61/-36)
src/graphic/gl/road_program.h (+11/-6)
src/graphic/gl/terrain_program.cc (+39/-26)
src/graphic/gl/terrain_program.h (+7/-4)
src/graphic/gl/utils.cc (+17/-46)
src/graphic/gl/utils.h (+42/-10)
src/graphic/graphic.cc (+9/-7)
src/graphic/image.h (+3/-2)
src/graphic/image_cache.cc (+62/-3)
src/graphic/image_cache.h (+27/-2)
src/graphic/image_io.cc (+3/-3)
src/graphic/make_texture_atlas_main.cc (+101/-0)
src/graphic/minimap_renderer.cc (+84/-126)
src/graphic/render_queue.cc (+299/-0)
src/graphic/render_queue.h (+197/-0)
src/graphic/rendertarget.cc (+33/-43)
src/graphic/rendertarget.h (+1/-2)
src/graphic/richtext.cc (+1/-1)
src/graphic/screen.cc (+63/-20)
src/graphic/screen.h (+18/-2)
src/graphic/surface.cc (+72/-183)
src/graphic/surface.h (+48/-35)
src/graphic/text/rt_render.cc (+16/-16)
src/graphic/texture.cc (+131/-77)
src/graphic/texture.h (+23/-24)
src/graphic/texture_atlas.cc (+13/-13)
src/graphic/texture_atlas.h (+3/-3)
src/logic/bob.h (+1/-1)
src/logic/ship.cc (+4/-5)
src/logic/soldier.cc (+1/-1)
src/scripting/CMakeLists.txt (+1/-0)
src/ui_basic/CMakeLists.txt (+0/-4)
src/ui_basic/panel.cc (+2/-2)
src/ui_basic/scrollbar.cc (+14/-14)
src/ui_basic/table.cc (+4/-5)
src/ui_fsmenu/CMakeLists.txt (+1/-0)
src/ui_fsmenu/options.cc (+0/-1)
src/ui_fsmenu/options.h (+0/-1)
src/wui/CMakeLists.txt (+1/-0)
src/wui/interactive_base.cc (+2/-4)
src/wui/minimap.cc (+3/-3)
src/wui/minimap.h (+8/-2)
src/wui/plot_area.cc (+34/-38)
src/wui/soldierlist.cc (+2/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/render_queue
Reviewer Review Type Date Requested Status
kaputtnik (community) Approve
GunChleoc Approve
Tino Approve
SirVer Needs Resubmitting
Review via email: mp+250524@code.launchpad.net

Commit message

- Implemented a RenderQueue. All drawing operations during drawing only
  register an item into the queue, at the end of the frame, the RenderQueue
  will draw everything onto the screen all at once. This leads to significant
  less OpenGL state changes, but will only make a really big difference when
  all graphics land in texture atlases.
- Textures internal format is now OpenGL ordered (i.e. bottom line is y = 0).
  This needs swapping of rows for pictures on load, but Textures are no longer
  upside down on the GPU which makes working with OpenGL coordinates easier.
- Made all drawing programs z-layer aware and enabled depth testing for OpenGL.
- Made all programs batch aware: The renderqueue batches items for the same
  program into a vector which is passed to the programs. They can then batch
  them together into fewer draw calls if possible.
- An ImageCache now has a compactify() method that builds a texture atlas out
  of all the image that are cached in it while having all Image pointers it
  handed out before staying valid. This was only used for debugging, but in a
  followup branch I will change the ImageTexture to be backed by a texture
  atlas by default.
- Refactored minimap renderer to have less repeated code.
- Remove Texture::get_pixels() and format() and let the (set|get)_pixels pass
  RGBAColor instead of uint32_t for clr.
- RenderTarget::draw_line() and derived methods now take two Points instead of
  4 integers which are inclusive to the line.
- Only reallocate OpenGL buffers if we need more space.
- Small refactorings in src/graphics/CMakeLists.txt.

Description of the change

Okay, here is a mouthful. I apologize for not better splitting this up, but it came together over a bunch of experiments and it is not even quite done. Here it goes:

Suggested commit message:
- Implemented a RenderQueue. All drawing operations during drawing only
  register an item into the queue, at the end of the frame, the RenderQueue
  will draw everything onto the screen all at once. This leads to significant
  less OpenGL state changes, but will only make a really big difference when
  all graphics land in texture atlases.
- Textures internal format is now OpenGL ordered (i.e. bottom line is y = 0).
  This needs swapping of rows for pictures on load, but Textures are no longer
  upside down on the GPU which makes working with OpenGL coordinates easier.
- Made all drawing programs z-layer aware and enabled depth testing for OpenGL.
- Made all programs batch aware: The renderqueue batches items for the same
  program into a vector which is passed to the programs. They can then batch
  them together into fewer draw calls if possible.
- An ImageCache now has a compactify() method that builds a texture atlas out
  of all the image that are cached in it while having all Image pointers it
  handed out before staying valid. This was only used for debugging, but in a
  followup branch I will change the ImageTexture to be backed by a texture
  atlas by default.
- Refactored minimap renderer to have less repeated code.
- Remove Texture::get_pixels() and format() and let the (set|get)_pixels pass
  RGBAColor instead of uint32_t for clr.
- RenderTarget::draw_line() and derived methods now take two Points instead of
  4 integers which are inclusive to the line.
- Only reallocate OpenGL buffers if we need more space.
- Small refactorings in src/graphics/CMakeLists.txt.

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

All mentioned bugs fixed

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

Some minor nits with my proofreader glasses on.

Revision history for this message
SirVer (sirver) wrote :

> Some minor nits with my proofreader glasses on.

They do not show up in Launchpad. Did you submit your changes/add the comments into the diff?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yes, they show up for me. Here they are for convenience:

527 + i.blend_mode = BlendMode::UseAlpha;
528 + // RenderQueue::instance().enqueue(i);
529 +
GunChleoc (gunchleoc) wrote on 2015-03-25:
Why is this commented out?

1412 +// TODO(sirver): This is a hack to make sure we are sampling inside of the
1413 +// terrain texture. This is a common problem with OpenGL and texture atlases.
1414 +#define MARGIN 1e-2
1415 +
GunChleoc (gunchleoc) wrote on 2015-03-25:
Code style: constexpr float kMargin

2270 + // TODO(sirver): This is a hack to make sure we are sampling inside of the
2271 + // terrain texture. This is a common problem with OpenGL and texture atlases.
2272 + const float MARGIN = 5e-2;
2273 +
GunChleoc (gunchleoc) wrote on 2015-03-25:
Code style: constexpr float kMargin

2502 +// TODO(sirver): This is a hack to make sure we are sampling inside of the
2503 +// terrain texture. This is a common problem with OpenGL and texture atlases.
2504 +#define MARGIN 1e-2
2505 +
GunChleoc (gunchleoc) wrote on 2015-03-25:
Code style: constexpr float kMargin

2783 +// on all errors. Also grows the server memory only when needed.
2784 +template<typename T>
2785 +class NewBuffer {
2786 public:
GunChleoc (gunchleoc) wrote on 2015-03-25:
Can this be renamed back to Buffer now? Honest question ;)

Revision history for this message
GunChleoc (gunchleoc) wrote :

Did some more testing - now the roads look funny. I have attached a screenshot to the bug.

Revision history for this message
SirVer (sirver) wrote :

I cannot reproduce the problem with the roads, they look fine on my computer. Could you try out to change the value of MARGIN here:

http://bazaar.launchpad.net/~widelands-dev/widelands/render_queue/view/7400/src/graphic/gl/road_program.cc#L129

It must be as small as possible but it might have artifacts (lines in the roads) if it is too small. start at 0 and make it larger step by step.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Setting MARGIN to 0 gives me the correct size for small roads, but the rendering is still fuzzy.

I also killed the build directory and compiled again from scratch to rule out compiler hiccups.

Revision history for this message
kaputtnik (franku) wrote :

I could confirm the fuzzy roads. Additionally the buildings menu is messed up. I put a screenshot into the bug 1425870.

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

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

The latest continuous integration build can always be found here:
  https://travis-ci.org/widelands/widelands/branches
Please do not merge without making sure that it passes.

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 pull request.

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 167 has changed state to: created. Details: https://travis-ci.org/widelands/widelands/builds/99877641.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 167 has changed state to: started. Details: https://travis-ci.org/widelands/widelands/builds/99877641.

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
Tino (tino79) wrote :

On windows the only glitch i can see are the road textures.
Switching from/to fullscreen, menues, everything else seems fine!

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
SirVer (sirver) wrote :

Okay, I think the road issue is now fixed. Could I get another look?

review: Needs Resubmitting
Revision history for this message
TiborB (tiborb95) wrote :

After quick testing I found nothing bad, only lines in 'General statistics' are now dots or kind of commas...

I will try a long time testing...

Revision history for this message
Tino (tino79) wrote :

Some minor issues with axis, ticks and graphs in the statistics window: https://imgur.com/nkf8VCn

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

Some graphics have very little white artifacts in comparison with trunk. Best to see on the screenshot where left is the render queue branch and right current trunk. Compare the mountain terrains in first column and third row. Some terrains appear clearer (the first two in first row).

https://launchpadlibrarian.net/232998293/render_queu_1.png

Don't know if this is really a bad thing. But if one makes a graphic for the game it should be rendered like it looks in (f.e.) gimp.

Revision history for this message
SirVer (sirver) wrote :

The graph lines are buggy and not intended that way. I will open a bug report for them when merging this branch. I'd like to get it in sooner than later though as it is pretty high maintenance to keep it updated.

You have a keen eye, kaputtnik :)

In fact the 'artifacts' are already in the original image: https://launchpadlibrarian.net/233001063/mountain4_00.png

Trunk is slightly blurring textures while drawing, while the new branch draws them pixel perfect. That means that these white pixels are now more visible. So I'd say that is an improvement.

Revision history for this message
SirVer (sirver) wrote :

Followup bug for the line issue: https://bugs.launchpad.net/widelands/+bug/1531114

Thanks for testing, everybody!

@bunnbot merge

Revision history for this message
GunChleoc (gunchleoc) wrote :

I agree that it is an improvement.

Since I'm still on he dead slow virtual machine, I will give my OK if somebody who can reproduce the fuzzy roads does some testing to confirm that the problem is fixed on their machine - I expect that the problem will have been the same one.

Note to the tester: please check as well if https://bugs.launchpad.net/widelands/+bug/1519361 is fixed. We also shouldn't forget to double-check the minimap, including colors and visibility for both players and observers.

Code LGTM, just smoe minor code style nits and ideas.

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

Thanks for the review. I addressed all comments. I might have made a mistake though, it seems that the buildhelp is now broken. Can somebody repo that?

Bug 1519361 does not happen for me with this branch.

Revision history for this message
GunChleoc (gunchleoc) wrote :

There is nothing obvious on your last commit that should cause the problem with the build help.

We can consider Bug 1519361 to be fixed in this branch, because it appeared on all systems.

I just noticed one more thing:

    class RenderQueue {

    public:
       enum Program {

Any specific reason that the last line isn't

       enum class Program {

?

Revision history for this message
SirVer (sirver) wrote :

The buildhelp is also broken in trunk, so not the fault of this branch. Please test, so we can get it merged.

Revision history for this message
kaputtnik (franku) wrote :

Yes, the build help is broken. When toggeling the build help it shows only the little red house for small buildings for all places and it appears also on mountains and water.

Hm, i don't remember seeing this the first time i test this branch.

https://bugs.launchpad.net/widelands/+bug/1425870/+attachment/4544302/+files/shot0001.png

Revision history for this message
kaputtnik (franku) wrote :

In r7687 the build help is ok. It seems that the latest merge is also the culprit for some compiler warnings about unused variables.

Revision history for this message
GunChleoc (gunchleoc) wrote :

@kaputtnik: How are the roads? Is the fuzzy roads bug in this branch now fixed?

Revision history for this message
kaputtnik (franku) wrote :

The roads looks fine :-)

Sorry that i didn't told this explicitly. I was also confused, because i saw this branch already merged...

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

Thanks!

@bunnbot merge

Revision history for this message
GunChleoc (gunchleoc) wrote :

Wasn't merged due to a typo ;)

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/base/rect.h'
2--- src/base/rect.h 2014-11-26 19:53:52 +0000
3+++ src/base/rect.h 2016-01-05 11:29:18 +0000
4@@ -36,13 +36,13 @@
5 : GenericRect(T(p.x), T(p.y), width, height) {
6 }
7
8- /// The top left point of this rectangle.
9- GenericPoint<T> top_left() const {
10+ /// The Point (x, y).
11+ GenericPoint<T> origin() const {
12 return GenericPoint<T>(x, y);
13 }
14
15- /// The bottom right point of this rectangle.
16- GenericPoint<T> bottom_right() const {
17+ /// The point (x + w, y + h).
18+ GenericPoint<T> opposite_of_origin() const {
19 return GenericPoint<T>(x + w, y + h);
20 }
21
22
23=== modified file 'src/editor/editorinteractive.cc'
24--- src/editor/editorinteractive.cc 2015-12-04 17:58:39 +0000
25+++ src/editor/editorinteractive.cc 2016-01-05 11:29:18 +0000
26@@ -610,6 +610,7 @@
27
28 eia.select_tool(eia.tools.increase_height, EditorTool::First);
29 editor.postload();
30+
31 eia.start();
32
33 if (!script_to_run.empty()) {
34
35=== modified file 'src/editor/ui_menus/editor_tool_change_resources_options_menu.cc'
36--- src/editor/ui_menus/editor_tool_change_resources_options_menu.cc 2016-01-04 20:50:19 +0000
37+++ src/editor/ui_menus/editor_tool_change_resources_options_menu.cc 2016-01-05 11:29:18 +0000
38@@ -29,9 +29,9 @@
39 #include "graphic/graphic.h"
40 #include "logic/map.h"
41 #include "logic/widelands.h"
42+#include "logic/widelands_geometry.h"
43 #include "logic/world/resource_description.h"
44 #include "logic/world/world.h"
45-#include "logic/widelands_geometry.h"
46 #include "ui_basic/button.h"
47 #include "wui/overlay_manager.h"
48
49
50=== modified file 'src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc'
51--- src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2015-12-10 20:52:30 +0000
52+++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2016-01-05 11:29:18 +0000
53@@ -53,11 +53,11 @@
54 // Blit the main terrain image
55 const Texture& terrain_texture = terrain_descr.get_texture(0);
56 Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
57- blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
58+ texture->blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
59 terrain_texture,
60 Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
61 1.,
62- BlendMode::UseAlpha, texture);
63+ BlendMode::UseAlpha);
64 Point pt(1, terrain_texture.height() - kSmallPicSize - 1);
65
66 // Collect tooltips and blit small icons representing "is" values
67@@ -67,12 +67,11 @@
68 terrain_descr.custom_tooltips().end());
69 tooltips.push_back(terrain_type.descname);
70
71- blit(Rect(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
72+ texture->blit(Rect(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
73 *terrain_type.icon,
74 Rect(0, 0, terrain_type.icon->width(), terrain_type.icon->height()),
75 1.,
76- BlendMode::UseAlpha,
77- texture);
78+ BlendMode::UseAlpha);
79 pt.x += kSmallPicSize + 1;
80 }
81 // Make sure we delete this later on.
82
83=== modified file 'src/graphic/CMakeLists.txt'
84--- src/graphic/CMakeLists.txt 2015-02-23 08:54:16 +0000
85+++ src/graphic/CMakeLists.txt 2016-01-05 11:29:18 +0000
86@@ -3,6 +3,21 @@
87 # TODO(sirver): Separate this directory into a base directory and one
88 # that is Widelands aware (can include logic stuff).
89
90+# A binary that creates and writes out a texture atlas of all images in
91+# a directory.
92+wl_binary(wl_make_texture_atlas
93+ SRCS
94+ make_texture_atlas_main.cc
95+ DEPENDS
96+ base_log
97+ graphic
98+ graphic_image_io
99+ graphic_texture_atlas
100+ helper
101+ io_filesystem
102+ io_stream
103+)
104+
105 wl_library(graphic_color
106 SRCS
107 color.h
108@@ -10,6 +25,21 @@
109 USES_SDL2
110 )
111
112+wl_library(graphic_render_queue
113+ SRCS
114+ render_queue.cc
115+ render_queue.h
116+ DEPENDS
117+ base_exceptions
118+ base_geometry
119+ base_log
120+ base_macros
121+ graphic_color
122+ graphic_terrain_programs
123+ graphic_draw_programs
124+ logic
125+)
126+
127 wl_library(graphic_text_layout
128 SRCS
129 text_layout.cc
130@@ -22,7 +52,6 @@
131 graphic_text
132 )
133
134-
135 wl_library(graphic_image_io
136 SRCS
137 image_io.h
138@@ -32,6 +61,7 @@
139 USES_SDL2_IMAGE
140 DEPENDS
141 base_exceptions
142+ base_log
143 graphic_surface
144 io_fileread
145 io_filesystem
146@@ -44,10 +74,10 @@
147 image_cache.h
148 USES_SDL2
149 DEPENDS
150- base_log
151 base_macros
152 graphic_image_io
153 graphic_surface
154+ graphic_texture_atlas
155 )
156
157 wl_library(graphic_sdl_utils
158@@ -59,6 +89,8 @@
159
160 wl_library(graphic_gl_utils
161 SRCS
162+ gl/blit_data.h
163+ gl/coordinate_conversion.h
164 gl/system_headers.h
165 gl/utils.cc
166 gl/utils.h
167@@ -66,11 +98,34 @@
168 USES_OPENGL
169 DEPENDS
170 base_exceptions
171- base_log
172- base_macros
173-)
174-
175-wl_library(graphic_surface
176+ base_geometry
177+ base_log
178+ base_macros
179+)
180+
181+wl_library(graphic_terrain_programs
182+ SRCS
183+ gl/fields_to_draw.h
184+ gl/road_program.cc
185+ gl/road_program.h
186+ gl/terrain_program.cc
187+ gl/terrain_program.h
188+ gl/dither_program.cc
189+ gl/dither_program.h
190+ DEPENDS
191+ base_exceptions
192+ base_geometry
193+ base_log
194+ base_macros
195+ graphic
196+ graphic_gl_utils
197+ graphic_image_io
198+ graphic_surface
199+ io_filesystem
200+ logic
201+)
202+
203+wl_library(graphic_draw_programs
204 SRCS
205 blend_mode.h
206 gl/blit_program.cc
207@@ -79,6 +134,17 @@
208 gl/draw_line_program.h
209 gl/fill_rect_program.cc
210 gl/fill_rect_program.h
211+ DEPENDS
212+ base_exceptions
213+ base_macros
214+ base_geometry
215+ graphic_gl_utils
216+ base_log
217+ graphic_color
218+)
219+
220+wl_library(graphic_surface
221+ SRCS
222 image.h
223 screen.cc
224 screen.h
225@@ -97,7 +163,9 @@
226 base_macros
227 graphic
228 graphic_color
229+ graphic_draw_programs
230 graphic_gl_utils
231+ graphic_render_queue
232 graphic_sdl_utils
233 )
234
235@@ -115,23 +183,14 @@
236 SRCS
237 game_renderer.cc
238 game_renderer.h
239- gl/dither_program.cc
240- gl/dither_program.h
241- gl/fields_to_draw.h
242- gl/road_program.cc
243- gl/road_program.h
244- gl/terrain_program.cc
245- gl/terrain_program.h
246 DEPENDS
247- base_exceptions
248 base_geometry
249- base_log
250 base_macros
251 graphic
252 graphic_gl_utils
253- graphic_image_io
254+ graphic_render_queue
255 graphic_surface
256- io_filesystem
257+ graphic_terrain_programs
258 logic
259 wui_mapview_pixelfunctions
260 wui_overlay_manager
261@@ -183,12 +242,14 @@
262 base_geometry
263 base_i18n
264 base_log
265+ graphic_draw_programs
266 base_macros
267 build_info
268 graphic_color
269 graphic_gl_utils
270 graphic_image_cache
271 graphic_image_io
272+ graphic_render_queue
273 graphic_surface
274 graphic_text
275 graphic_text_layout
276
277=== modified file 'src/graphic/animation.cc'
278--- src/graphic/animation.cc 2015-12-03 19:40:37 +0000
279+++ src/graphic/animation.cc 2016-01-05 11:29:18 +0000
280@@ -231,22 +231,13 @@
281 Texture* rv = new Texture(w, h);
282
283 // Initialize the rectangle
284- ::fill_rect(Rect(Point(0, 0), w, h), RGBAColor(255, 255, 255, 0), rv);
285+ rv->fill_rect(Rect(Point(0, 0), w, h), RGBAColor(255, 255, 255, 0));
286
287 if (!hasplrclrs_ || clr == nullptr) {
288- ::blit(Rect(Point(0, 0), w, h),
289- *image,
290- Rect(Point(0, 0), w, h),
291- 1.,
292- BlendMode::UseAlpha,
293- rv);
294+ rv->blit(Rect(Point(0, 0), w, h), *image, Rect(Point(0, 0), w, h), 1., BlendMode::UseAlpha);
295 } else {
296- blit_blended(Rect(Point(0, 0), w, h),
297- *image,
298- *g_gr->images().get(pc_mask_image_files_[0]),
299- Rect(Point(0, 0), w, h),
300- *clr,
301- rv);
302+ rv->blit_blended(Rect(Point(0, 0), w, h), *image,
303+ *g_gr->images().get(pc_mask_image_files_[0]), Rect(Point(0, 0), w, h), *clr);
304 }
305 return rv;
306 }
307@@ -285,19 +276,11 @@
308 assert(idx < nr_frames());
309
310 if (!hasplrclrs_ || clr == nullptr) {
311- ::blit(Rect(dst.x, dst.y, srcrc.w, srcrc.h),
312- *frames_.at(idx),
313- srcrc,
314- 1.,
315- BlendMode::UseAlpha,
316- target);
317+ target->blit(
318+ Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
319 } else {
320- blit_blended(Rect(dst.x, dst.y, srcrc.w, srcrc.h),
321- *frames_.at(idx),
322- *pcmasks_.at(idx),
323- srcrc,
324- *clr,
325- target);
326+ target->blit_blended(
327+ Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
328 }
329 }
330
331
332=== modified file 'src/graphic/blend_mode.h'
333--- src/graphic/blend_mode.h 2014-12-04 09:00:20 +0000
334+++ src/graphic/blend_mode.h 2016-01-05 11:29:18 +0000
335@@ -24,10 +24,14 @@
336 enum class BlendMode {
337 // Perform a normal blitting operation that respects the alpha channel if
338 // present.
339- UseAlpha = 0,
340+ UseAlpha,
341+
342+ // Used internally for Surface::brighten_rect() if the rect is actually to
343+ // be darkened.
344+ Subtract,
345
346 // Copy all pixel information, including alpha channel information.
347- Copy
348+ Copy,
349 };
350
351 #endif // end of include guard: WL_GRAPHIC_BLEND_MODE_H
352
353=== modified file 'src/graphic/color.cc'
354--- src/graphic/color.cc 2015-05-30 12:19:57 +0000
355+++ src/graphic/color.cc 2016-01-05 11:29:18 +0000
356@@ -21,7 +21,7 @@
357
358 #include <boost/format.hpp>
359
360-RGBColor::RGBColor() {
361+RGBColor::RGBColor() : RGBColor(0, 0, 0) {
362 }
363
364 RGBColor::RGBColor(uint8_t const R, uint8_t const G, uint8_t const B) :
365
366=== modified file 'src/graphic/color.h'
367--- src/graphic/color.h 2015-05-30 12:19:57 +0000
368+++ src/graphic/color.h 2016-01-05 11:29:18 +0000
369@@ -26,6 +26,7 @@
370
371 struct RGBColor {
372 RGBColor(uint8_t R, uint8_t G, uint8_t B);
373+ RGBColor(const RGBColor& other) = default;
374
375 // Initializes the color to black.
376 RGBColor();
377@@ -39,14 +40,16 @@
378 // Set it to the given 'clr' which is interpretes through 'fmt'.
379 void set(SDL_PixelFormat * fmt, uint32_t clr);
380
381+ RGBColor& operator = (const RGBColor& other) = default;
382+ bool operator != (const RGBColor& other) const;
383 bool operator == (const RGBColor& other) const;
384- bool operator != (const RGBColor& other) const;
385
386 uint8_t r, g, b;
387 };
388
389 struct RGBAColor {
390 RGBAColor(uint8_t R, uint8_t G, uint8_t B, uint8_t A);
391+ RGBAColor(const RGBAColor& other) = default;
392
393 // Initializes the color to black.
394 RGBAColor();
395@@ -63,8 +66,9 @@
396 // Set it to the given 'clr' which is interpretes through 'fmt'.
397 void set(const SDL_PixelFormat & fmt, uint32_t clr);
398
399+ RGBAColor& operator = (const RGBAColor& other) = default;
400+ bool operator != (const RGBAColor& other) const;
401 bool operator == (const RGBAColor& other) const;
402- bool operator != (const RGBAColor& other) const;
403
404 uint8_t r;
405 uint8_t g;
406
407=== modified file 'src/graphic/font_handler1.cc'
408--- src/graphic/font_handler1.cc 2015-09-26 09:34:20 +0000
409+++ src/graphic/font_handler1.cc 2016-01-05 11:29:18 +0000
410@@ -70,12 +70,8 @@
411 int width() const override {return texture()->width();}
412 int height() const override {return texture()->height();}
413
414- int get_gl_texture() const override {
415- return texture()->get_gl_texture();
416- }
417-
418- const FloatRect& texture_coordinates() const override {
419- return texture()->texture_coordinates();
420+ const BlitData& blit_data() const override {
421+ return texture()->blit_data();
422 }
423
424 private:
425
426=== modified file 'src/graphic/game_renderer.cc'
427--- src/graphic/game_renderer.cc 2015-02-23 08:54:16 +0000
428+++ src/graphic/game_renderer.cc 2016-01-05 11:29:18 +0000
429@@ -21,11 +21,9 @@
430
431 #include <memory>
432
433-#include "graphic/gl/dither_program.h"
434-#include "graphic/gl/fields_to_draw.h"
435-#include "graphic/gl/road_program.h"
436-#include "graphic/gl/terrain_program.h"
437+#include "graphic/gl/coordinate_conversion.h"
438 #include "graphic/graphic.h"
439+#include "graphic/render_queue.h"
440 #include "graphic/rendertarget.h"
441 #include "graphic/surface.h"
442 #include "logic/editor_game_base.h"
443@@ -66,10 +64,6 @@
444 // d). Example: if r and d have different textures and r.dither_layer >
445 // d.dither_layer, then we will repaint d with the dither texture as mask.
446
447-std::unique_ptr<TerrainProgram> GameRenderer::terrain_program_;
448-std::unique_ptr<DitherProgram> GameRenderer::dither_program_;
449-std::unique_ptr<RoadProgram> GameRenderer::road_program_;
450-
451 namespace {
452
453 using namespace Widelands;
454@@ -142,12 +136,6 @@
455 const EditorGameBase& egbase,
456 const Point& view_offset,
457 const Player* player) {
458- if (terrain_program_ == nullptr) {
459- terrain_program_.reset(new TerrainProgram());
460- dither_program_.reset(new DitherProgram());
461- road_program_.reset(new RoadProgram());
462- }
463-
464 Point tl_map = dst.get_offset() + view_offset;
465
466 assert(tl_map.x >= 0); // divisions involving negative numbers are bad
467@@ -170,22 +158,18 @@
468 return;
469
470 const Rect& bounding_rect = dst.get_rect();
471- const Point surface_offset = bounding_rect.top_left() + dst.get_offset() - view_offset;
472-
473- glScissor(bounding_rect.x,
474- surface->height() - bounding_rect.y - bounding_rect.h,
475- bounding_rect.w,
476- bounding_rect.h);
477- glEnable(GL_SCISSOR_TEST);
478+ const Point surface_offset = bounding_rect.origin() + dst.get_offset() - view_offset;
479+ const int surface_width = surface->width();
480+ const int surface_height = surface->height();
481
482 Map& map = egbase.map();
483 const uint32_t gametime = egbase.get_gametime();
484
485- FieldsToDraw fields_to_draw(minfx, maxfx, minfy, maxfy);
486+ fields_to_draw_.reset(minfx, maxfx, minfy, maxfy);
487 for (int32_t fy = minfy; fy <= maxfy; ++fy) {
488 for (int32_t fx = minfx; fx <= maxfx; ++fx) {
489 FieldsToDraw::Field& f =
490- *fields_to_draw.mutable_field(fields_to_draw.calculate_index(fx, fy));
491+ *fields_to_draw_.mutable_field(fields_to_draw_.calculate_index(fx, fy));
492
493 f.fx = fx;
494 f.fy = fy;
495@@ -202,7 +186,7 @@
496
497 f.gl_x = f.pixel_x = x + surface_offset.x;
498 f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;
499- surface->pixel_to_gl(&f.gl_x, &f.gl_y);
500+ pixel_to_gl_renderbuffer(surface_width, surface_height, &f.gl_x, &f.gl_y);
501
502 f.ter_d = fcoords.field->terrain_d();
503 f.ter_r = fcoords.field->terrain_r();
504@@ -220,14 +204,32 @@
505 }
506 }
507
508- const World& world = egbase.world();
509- terrain_program_->draw(gametime, world.terrains(), fields_to_draw);
510- dither_program_->draw(gametime, world.terrains(), fields_to_draw);
511- road_program_->draw(*surface, fields_to_draw);
512+ // Enqueue the drawing of the terrain.
513+ RenderQueue::Item i;
514+ i.program_id = RenderQueue::Program::kTerrainBase;
515+ i.blend_mode = BlendMode::Copy;
516+ i.destination_rect =
517+ FloatRect(bounding_rect.x,
518+ surface_height - bounding_rect.y - bounding_rect.h,
519+ bounding_rect.w,
520+ bounding_rect.h);
521+ i.terrain_arguments.gametime = gametime;
522+ i.terrain_arguments.renderbuffer_width = surface_width;
523+ i.terrain_arguments.renderbuffer_height = surface_height;
524+ i.terrain_arguments.terrains = &egbase.world().terrains();
525+ i.terrain_arguments.fields_to_draw = &fields_to_draw_;
526+ RenderQueue::instance().enqueue(i);
527+
528+ // Enqueue the drawing of the dither layer.
529+ i.program_id = RenderQueue::Program::kTerrainDither;
530+ i.blend_mode = BlendMode::UseAlpha;
531+ RenderQueue::instance().enqueue(i);
532+
533+ // Enqueue the drawing of the road layer.
534+ i.program_id = RenderQueue::Program::kTerrainRoad;
535+ RenderQueue::instance().enqueue(i);
536
537 draw_objects(dst, egbase, view_offset, player, minfx, maxfx, minfy, maxfy);
538-
539- glDisable(GL_SCISSOR_TEST);
540 }
541
542 void GameRenderer::draw_objects(RenderTarget& dst,
543
544=== modified file 'src/graphic/game_renderer.h'
545--- src/graphic/game_renderer.h 2014-12-04 21:21:05 +0000
546+++ src/graphic/game_renderer.h 2016-01-05 11:29:18 +0000
547@@ -24,17 +24,14 @@
548
549 #include "base/macros.h"
550 #include "base/point.h"
551+#include "graphic/gl/fields_to_draw.h"
552
553 namespace Widelands {
554 class Player;
555 class EditorGameBase;
556 }
557
558-class DitherProgram;
559 class RenderTarget;
560-class RoadProgram;
561-class TerrainProgram;
562-
563
564 /**
565 * This abstract base class renders the main game view into an
566@@ -64,10 +61,6 @@
567 void rendermap(RenderTarget& dst, const Widelands::EditorGameBase& egbase, const Point& view_offset);
568
569 private:
570- static std::unique_ptr<TerrainProgram> terrain_program_;
571- static std::unique_ptr<DitherProgram> dither_program_;
572- static std::unique_ptr<RoadProgram> road_program_;
573-
574 // Draw the map for the given parameters (see rendermap). 'player'
575 // can be nullptr in which case the whole map is drawn.
576 void draw(RenderTarget& dst,
577@@ -85,6 +78,10 @@
578 int minfy,
579 int maxfy);
580
581+ // This is owned and handled by us, but handed to the RenderQueue, so we
582+ // basically promise that this stays valid for one frame.
583+ FieldsToDraw fields_to_draw_;
584+
585 DISALLOW_COPY_AND_ASSIGN(GameRenderer);
586 };
587
588
589=== added file 'src/graphic/gl/blit_data.h'
590--- src/graphic/gl/blit_data.h 1970-01-01 00:00:00 +0000
591+++ src/graphic/gl/blit_data.h 2016-01-05 11:29:18 +0000
592@@ -0,0 +1,44 @@
593+/*
594+ * Copyright (C) 2006-2016 by the Widelands Development Team
595+ *
596+ * This program is free software; you can redistribute it and/or
597+ * modify it under the terms of the GNU General Public License
598+ * as published by the Free Software Foundation; either version 2
599+ * of the License, or (at your option) any later version.
600+ *
601+ * This program is distributed in the hope that it will be useful,
602+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
603+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
604+ * GNU General Public License for more details.
605+ *
606+ * You should have received a copy of the GNU General Public License
607+ * along with this program; if not, write to the Free Software
608+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
609+ *
610+ */
611+
612+#ifndef WL_GRAPHIC_GL_BLIT_DATA_H
613+#define WL_GRAPHIC_GL_BLIT_DATA_H
614+
615+#include <stdint.h>
616+
617+#include "base/rect.h"
618+
619+// Information of the internal OpenGL data needed to properly blit this image.
620+struct BlitData {
621+ // The OpenGl name or id of the parent texture. The parent texture is either
622+ // - the packed texture of the texture atlas, if this texture is part of a texture atlas.
623+ // - the texture itself if it is a standalone texture.
624+ uint32_t texture_id;
625+
626+ // Dimension of the parent texture, For stand alone textures this is the
627+ // dimensions of the texture itself and therefore equal to
628+ // rect.[w|h].
629+ int parent_width;
630+ int parent_height;
631+
632+ // The subrect in the parent texture.
633+ Rect rect;
634+};
635+
636+#endif // end of include guard: WL_GRAPHIC_GL_BLIT_DATA_H
637
638=== modified file 'src/graphic/gl/blit_program.cc'
639--- src/graphic/gl/blit_program.cc 2015-03-01 09:21:20 +0000
640+++ src/graphic/gl/blit_program.cc 2016-01-05 11:29:18 +0000
641@@ -22,6 +22,8 @@
642 #include <vector>
643
644 #include "base/log.h"
645+#include "graphic/gl/blit_data.h"
646+#include "graphic/gl/coordinate_conversion.h"
647 #include "graphic/gl/utils.h"
648
649 namespace {
650@@ -30,42 +32,44 @@
651 #version 120
652
653 // Attributes.
654-attribute vec2 attr_position;
655-
656-// Uniforms.
657-uniform vec4 u_dst_rect;
658-uniform vec4 u_src_rect;
659-
660+attribute vec2 attr_mask_texture_position;
661+attribute vec2 attr_texture_position;
662+attribute vec3 attr_position;
663+attribute vec4 attr_blend;
664+
665+varying vec2 out_mask_texture_coordinate;
666 varying vec2 out_texture_coordinate;
667+varying vec4 out_blend;
668
669 void main() {
670- out_texture_coordinate = u_src_rect.xy + attr_position.xy * u_src_rect.zw;
671- gl_Position = vec4(u_dst_rect.xy + attr_position.xy * u_dst_rect.zw, 0., 1.);
672+ out_mask_texture_coordinate = attr_mask_texture_position;
673+ out_texture_coordinate = attr_texture_position;
674+ out_blend = attr_blend;
675+ gl_Position = vec4(attr_position, 1.);
676 }
677 )";
678
679 const char kVanillaBlitFragmentShader[] = R"(
680 #version 120
681
682-uniform float u_opacity;
683 uniform sampler2D u_texture;
684
685 varying vec2 out_texture_coordinate;
686+varying vec4 out_blend;
687
688 void main() {
689 vec4 color = texture2D(u_texture, out_texture_coordinate);
690- gl_FragColor = vec4(color.rgb, u_opacity * color.a);
691+ gl_FragColor = color * out_blend;
692 }
693 )";
694
695 const char kMonochromeBlitFragmentShader[] = R"(
696 #version 120
697
698-uniform float u_opacity;
699 uniform sampler2D u_texture;
700-uniform vec3 u_blend;
701
702 varying vec2 out_texture_coordinate;
703+varying vec4 out_blend;
704
705 void main() {
706 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
707@@ -73,144 +77,272 @@
708 // See http://en.wikipedia.org/wiki/YUV.
709 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
710
711- gl_FragColor = vec4(vec3(luminance) * u_blend, u_opacity * texture_color.a);
712+ gl_FragColor = vec4(vec3(luminance) * out_blend.rgb, out_blend.a * texture_color.a);
713 }
714 )";
715
716 const char kBlendedBlitFragmentShader[] = R"(
717 #version 120
718
719-uniform float u_opacity;
720 uniform sampler2D u_texture;
721 uniform sampler2D u_mask;
722-uniform vec3 u_blend;
723
724+varying vec2 out_mask_texture_coordinate;
725 varying vec2 out_texture_coordinate;
726+varying vec4 out_blend;
727
728 void main() {
729 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
730- vec4 mask_color = texture2D(u_mask, out_texture_coordinate);
731+ vec4 mask_color = texture2D(u_mask, out_mask_texture_coordinate);
732
733 // See http://en.wikipedia.org/wiki/YUV.
734 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
735 float blend_influence = mask_color.r * mask_color.a;
736 gl_FragColor = vec4(
737- mix(texture_color.rgb, u_blend * luminance, blend_influence), u_opacity * texture_color.a);
738+ mix(texture_color.rgb, out_blend.rgb * luminance, blend_influence), out_blend.a * texture_color.a);
739 }
740 )";
741
742+// While drawing we put all draw calls into a buffer, so that we have to
743+// transfer the buffer to the GPU only once, even though we might need to do
744+// many glDraw* calls. This structure represents the parameters for one glDraw*
745+// call.
746+struct DrawBatch {
747+ int offset;
748+ int count;
749+ uint32_t texture;
750+ uint32_t mask;
751+ BlendMode blend_mode;
752+};
753+
754 } // namespace
755
756 class BlitProgram {
757 public:
758+ struct Arguments {
759+ FloatRect destination_rect;
760+ float z_value;
761+ BlitData texture;
762+ BlitData mask;
763+ RGBAColor blend;
764+ BlendMode blend_mode;
765+ };
766 BlitProgram(const std::string& fragment_shader);
767
768- void activate(const FloatRect& gl_dest_rect,
769- const FloatRect& gl_src_rect,
770- const GLuint gl_texture,
771- const float opacity,
772- const BlendMode blend_mode);
773-
774- void draw();
775- void draw_and_deactivate(BlendMode blend_mode);
776-
777- GLuint program_object() const {
778+ void activate();
779+
780+ void draw_and_deactivate(const std::vector<Arguments>& arguments);
781+
782+ int program_object() const {
783 return gl_program_.object();
784 }
785
786 private:
787 struct PerVertexData {
788- float gl_x, gl_y;
789+ PerVertexData(float init_gl_x,
790+ float init_gl_y,
791+ float init_gl_z,
792+ float init_texture_x,
793+ float init_texture_y,
794+ float init_mask_texture_x,
795+ float init_mask_texture_y,
796+ float init_blend_r,
797+ float init_blend_g,
798+ float init_blend_b,
799+ float init_blend_a)
800+ : gl_x(init_gl_x),
801+ gl_y(init_gl_y),
802+ gl_z(init_gl_z),
803+ texture_x(init_texture_x),
804+ texture_y(init_texture_y),
805+ mask_texture_x(init_mask_texture_x),
806+ mask_texture_y(init_mask_texture_y),
807+ blend_r(init_blend_r),
808+ blend_g(init_blend_g),
809+ blend_b(init_blend_b),
810+ blend_a(init_blend_a) {
811+ }
812+
813+ float gl_x, gl_y, gl_z;
814+ float texture_x, texture_y;
815+ float mask_texture_x, mask_texture_y;
816+ float blend_r, blend_g, blend_b, blend_a;
817 };
818- static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
819+ static_assert(sizeof(PerVertexData) == 44, "Wrong padding.");
820
821 // The buffer that will contain the quad for rendering.
822- Gl::Buffer gl_array_buffer_;
823+ Gl::Buffer<PerVertexData> gl_array_buffer_;
824
825 // The program.
826 Gl::Program gl_program_;
827
828 // Attributes.
829+ GLint attr_blend_;
830+ GLint attr_mask_texture_position_;
831 GLint attr_position_;
832+ GLint attr_texture_position_;
833
834 // Uniforms.
835- GLint u_dst_rect_;
836- GLint u_opacity_;
837- GLint u_src_rect_;
838 GLint u_texture_;
839+ GLint u_mask_;
840+
841+ // Cached for efficiency.
842+ std::vector<PerVertexData> vertices_;
843+
844 DISALLOW_COPY_AND_ASSIGN(BlitProgram);
845 };
846
847 BlitProgram::BlitProgram(const std::string& fragment_shader) {
848 gl_program_.build(kBlitVertexShader, fragment_shader.c_str());
849
850+ attr_blend_ = glGetAttribLocation(gl_program_.object(), "attr_blend");
851+ attr_mask_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_mask_texture_position");
852 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
853+ attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
854
855 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
856- u_opacity_ = glGetUniformLocation(gl_program_.object(), "u_opacity");
857- u_dst_rect_ = glGetUniformLocation(gl_program_.object(), "u_dst_rect");
858- u_src_rect_ = glGetUniformLocation(gl_program_.object(), "u_src_rect");
859-
860- std::vector<PerVertexData> vertices;
861- vertices.push_back(PerVertexData
862- {0., 1.});
863- vertices.push_back(PerVertexData
864- {1., 1.});
865- vertices.push_back(PerVertexData
866- {0., 0.});
867- vertices.push_back(PerVertexData
868- {1., 0.});
869-
870- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
871- glBufferData(
872- GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
873- glVertexAttribPointer(attr_position_,
874- 2,
875- GL_FLOAT,
876- GL_FALSE,
877- sizeof(PerVertexData),
878- reinterpret_cast<void*>(0));
879- glBindBuffer(GL_ARRAY_BUFFER, 0);
880+ u_mask_ = glGetUniformLocation(gl_program_.object(), "u_mask");
881 }
882
883-void BlitProgram::activate(const FloatRect& gl_dest_rect,
884- const FloatRect& gl_src_rect,
885- const GLuint gl_texture,
886- const float opacity,
887- const BlendMode blend_mode) {
888+void BlitProgram::activate() {
889 glUseProgram(gl_program_.object());
890+
891+ glEnableVertexAttribArray(attr_blend_);
892+ glEnableVertexAttribArray(attr_mask_texture_position_);
893 glEnableVertexAttribArray(attr_position_);
894- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
895-
896- glVertexAttribPointer(attr_position_,
897- 2,
898- GL_FLOAT,
899- GL_FALSE,
900- sizeof(PerVertexData),
901- reinterpret_cast<void*>(0));
902-
903+ glEnableVertexAttribArray(attr_texture_position_);
904+}
905+
906+void BlitProgram::draw_and_deactivate(const std::vector<Arguments>& arguments) {
907+ size_t i = 0;
908+
909+ gl_array_buffer_.bind();
910+
911+ Gl::vertex_attrib_pointer(attr_blend_, 4, sizeof(PerVertexData), offsetof(PerVertexData, blend_r));
912+ Gl::vertex_attrib_pointer(attr_mask_texture_position_,
913+ 2,
914+ sizeof(PerVertexData),
915+ offsetof(PerVertexData, mask_texture_x));
916+ Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
917+ Gl::vertex_attrib_pointer(
918+ attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
919
920 glUniform1i(u_texture_, 0);
921- glUniform1f(u_opacity_, opacity);
922- glUniform4f(u_dst_rect_, gl_dest_rect.x, gl_dest_rect.y, gl_dest_rect.w, gl_dest_rect.h);
923- glUniform4f(u_src_rect_, gl_src_rect.x, gl_src_rect.y, gl_src_rect.w, gl_src_rect.h);
924-
925- glActiveTexture(GL_TEXTURE0);
926- glBindTexture(GL_TEXTURE_2D, gl_texture);
927-
928- if (blend_mode == BlendMode::Copy) {
929- glBlendFunc(GL_ONE, GL_ZERO);
930- }
931-}
932-
933-void BlitProgram::draw_and_deactivate(BlendMode blend_mode) {
934- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
935-
936- if (blend_mode == BlendMode::Copy) {
937- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
938- }
939-
940+ glUniform1i(u_mask_, 1);
941+
942+ // Prepare the buffer for many draw calls.
943+ std::vector<DrawBatch> draw_batches;
944+ int offset = 0;
945+ vertices_.clear();
946+ while (i < arguments.size()) {
947+ const Arguments& template_args = arguments[i];
948+
949+ // Batch common blit operations up.
950+ while (i < arguments.size()) {
951+ const Arguments& current_args = arguments[i];
952+ if (current_args.blend_mode != template_args.blend_mode ||
953+ current_args.texture.texture_id != template_args.texture.texture_id ||
954+ current_args.mask.texture_id != template_args.mask.texture_id) {
955+ break;
956+ }
957+
958+ const float blend_r = current_args.blend.r / 255.;
959+ const float blend_g = current_args.blend.g / 255.;
960+ const float blend_b = current_args.blend.b / 255.;
961+ const float blend_a = current_args.blend.a / 255.;
962+
963+ const FloatRect texture_rect = to_gl_texture(current_args.texture);
964+ const FloatRect mask_rect = to_gl_texture(current_args.mask);
965+ vertices_.emplace_back(current_args.destination_rect.x,
966+ current_args.destination_rect.y,
967+ current_args.z_value,
968+ texture_rect.x,
969+ texture_rect.y,
970+ mask_rect.x,
971+ mask_rect.y,
972+ blend_r,
973+ blend_g,
974+ blend_b,
975+ blend_a);
976+
977+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
978+ current_args.destination_rect.y,
979+ current_args.z_value,
980+ texture_rect.x + texture_rect.w,
981+ texture_rect.y,
982+ mask_rect.x + mask_rect.w,
983+ mask_rect.y,
984+ blend_r,
985+ blend_g,
986+ blend_b,
987+ blend_a);
988+
989+ vertices_.emplace_back(current_args.destination_rect.x,
990+ current_args.destination_rect.y + current_args.destination_rect.h,
991+ current_args.z_value,
992+ texture_rect.x,
993+ texture_rect.y + texture_rect.h,
994+ mask_rect.x,
995+ mask_rect.y + mask_rect.h,
996+ blend_r,
997+ blend_g,
998+ blend_b,
999+ blend_a);
1000+
1001+ vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
1002+ vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
1003+
1004+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
1005+ current_args.destination_rect.y + current_args.destination_rect.h,
1006+ current_args.z_value,
1007+ texture_rect.x + texture_rect.w,
1008+ texture_rect.y + texture_rect.h,
1009+ mask_rect.x + mask_rect.w,
1010+ mask_rect.y + mask_rect.h,
1011+ blend_r,
1012+ blend_g,
1013+ blend_b,
1014+ blend_a);
1015+ ++i;
1016+ }
1017+
1018+ draw_batches.emplace_back(DrawBatch{offset,
1019+ static_cast<int>(vertices_.size() - offset),
1020+ template_args.texture.texture_id,
1021+ template_args.mask.texture_id,
1022+ template_args.blend_mode});
1023+ offset = vertices_.size();
1024+ }
1025+ gl_array_buffer_.update(vertices_);
1026+
1027+ // Now do the draw calls.
1028+ for (const auto& draw_arg : draw_batches) {
1029+ glActiveTexture(GL_TEXTURE0);
1030+ glBindTexture(GL_TEXTURE_2D, draw_arg.texture);
1031+
1032+ glActiveTexture(GL_TEXTURE1);
1033+ glBindTexture(GL_TEXTURE_2D, draw_arg.mask);
1034+
1035+ if (draw_arg.blend_mode == BlendMode::Copy) {
1036+ glBlendFunc(GL_ONE, GL_ZERO);
1037+ }
1038+ glDrawArrays(GL_TRIANGLES, draw_arg.offset, draw_arg.count);
1039+
1040+ if (draw_arg.blend_mode == BlendMode::Copy) {
1041+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1042+ }
1043+ }
1044+
1045+ glDisableVertexAttribArray(attr_blend_);
1046+ glDisableVertexAttribArray(attr_mask_texture_position_);
1047 glDisableVertexAttribArray(attr_position_);
1048+ glDisableVertexAttribArray(attr_texture_position_);
1049+
1050+ glBindTexture(GL_TEXTURE_2D, 0);
1051+
1052+ glActiveTexture(GL_TEXTURE0);
1053+ glBindTexture(GL_TEXTURE_2D, 0);
1054+
1055 glBindBuffer(GL_ARRAY_BUFFER, 0);
1056 }
1057
1058@@ -227,15 +359,31 @@
1059 blit_program_.reset(new BlitProgram(kVanillaBlitFragmentShader));
1060 }
1061
1062-
1063 void VanillaBlitProgram::draw(const FloatRect& gl_dest_rect,
1064- const FloatRect& gl_src_rect,
1065- const GLuint gl_texture,
1066- const float opacity,
1067- const BlendMode blend_mode) {
1068- blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture, opacity, blend_mode);
1069- blit_program_->draw_and_deactivate(blend_mode);
1070-}
1071+ const float z_value,
1072+ const BlitData& texture,
1073+ const float opacity,
1074+ const BlendMode blend_mode) {
1075+ draw({Arguments{gl_dest_rect, z_value, texture, opacity, blend_mode}});
1076+}
1077+
1078+void VanillaBlitProgram::draw(const std::vector<Arguments>& arguments) {
1079+ std::vector<BlitProgram::Arguments> blit_arguments;
1080+ for (const Arguments arg : arguments) {
1081+ blit_arguments.emplace_back(BlitProgram::Arguments{
1082+ arg.destination_rect,
1083+ arg.z_value,
1084+ arg.texture,
1085+ BlitData{0, 0, 0, Rect()},
1086+ RGBAColor(255, 255, 255, arg.opacity * 255),
1087+ arg.blend_mode,
1088+ });
1089+ }
1090+
1091+ blit_program_->activate();
1092+ blit_program_->draw_and_deactivate(blit_arguments);
1093+}
1094+
1095
1096 // static
1097 MonochromeBlitProgram& MonochromeBlitProgram::instance() {
1098@@ -248,19 +396,30 @@
1099
1100 MonochromeBlitProgram::MonochromeBlitProgram() {
1101 blit_program_.reset(new BlitProgram(kMonochromeBlitFragmentShader));
1102-
1103- u_blend_ = glGetUniformLocation(blit_program_->program_object(), "u_blend");
1104-}
1105-
1106-void MonochromeBlitProgram::draw(const FloatRect& gl_dest_rect,
1107- const FloatRect& gl_src_rect,
1108- const GLuint gl_texture,
1109- const RGBAColor& blend) {
1110- blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture, blend.a / 255., BlendMode::UseAlpha);
1111-
1112- glUniform3f(u_blend_, blend.r / 255., blend.g / 255., blend.b / 255.);
1113-
1114- blit_program_->draw_and_deactivate(BlendMode::UseAlpha);
1115+}
1116+
1117+void MonochromeBlitProgram::draw(const FloatRect& dest_rect,
1118+ const float z_value,
1119+ const BlitData& texture,
1120+ const RGBAColor& blend) {
1121+ draw({Arguments{dest_rect, z_value, texture, blend, BlendMode::UseAlpha}});
1122+}
1123+
1124+void MonochromeBlitProgram::draw(const std::vector<Arguments>& arguments) {
1125+ std::vector<BlitProgram::Arguments> blit_arguments;
1126+ for (const Arguments arg : arguments) {
1127+ blit_arguments.emplace_back(BlitProgram::Arguments{
1128+ arg.destination_rect,
1129+ arg.z_value,
1130+ arg.texture,
1131+ BlitData{0, 0, 0, Rect()},
1132+ arg.blend,
1133+ arg.blend_mode,
1134+ });
1135+ }
1136+
1137+ blit_program_->activate();
1138+ blit_program_->draw_and_deactivate(blit_arguments);
1139 }
1140
1141 // static
1142@@ -274,28 +433,29 @@
1143
1144 BlendedBlitProgram::BlendedBlitProgram() {
1145 blit_program_.reset(new BlitProgram(kBlendedBlitFragmentShader));
1146- u_blend_ = glGetUniformLocation(blit_program_->program_object(), "u_blend");
1147- u_mask_ = glGetUniformLocation(blit_program_->program_object(), "u_mask");
1148 }
1149
1150 void BlendedBlitProgram::draw(const FloatRect& gl_dest_rect,
1151- const FloatRect& gl_src_rect,
1152- const GLuint gl_texture_image,
1153- const GLuint gl_texture_mask,
1154- const RGBAColor& blend) {
1155- blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture_image, blend.a / 255., BlendMode::UseAlpha);
1156-
1157- glActiveTexture(GL_TEXTURE1);
1158- glBindTexture(GL_TEXTURE_2D, gl_texture_mask);
1159- glUniform1i(u_mask_, 1);
1160-
1161- glUniform3f(u_blend_, blend.r / 255., blend.g / 255., blend.b / 255.);
1162-
1163- blit_program_->draw_and_deactivate(BlendMode::UseAlpha);
1164-
1165- glActiveTexture(GL_TEXTURE1);
1166- glBindTexture(GL_TEXTURE_2D, 0);
1167-
1168- glActiveTexture(GL_TEXTURE0);
1169- glBindTexture(GL_TEXTURE_2D, 0);
1170+ const float z_value,
1171+ const BlitData& texture,
1172+ const BlitData& mask,
1173+ const RGBAColor& blend) {
1174+ draw({Arguments{gl_dest_rect, z_value, texture, mask, blend, BlendMode::UseAlpha}});
1175+}
1176+
1177+void BlendedBlitProgram::draw(const std::vector<Arguments>& arguments) {
1178+ std::vector<BlitProgram::Arguments> blit_arguments;
1179+ for (const Arguments arg : arguments) {
1180+ blit_arguments.emplace_back(BlitProgram::Arguments{
1181+ arg.destination_rect,
1182+ arg.z_value,
1183+ arg.texture,
1184+ arg.mask,
1185+ arg.blend,
1186+ arg.blend_mode,
1187+ });
1188+ }
1189+
1190+ blit_program_->activate();
1191+ blit_program_->draw_and_deactivate(blit_arguments);
1192 }
1193
1194=== modified file 'src/graphic/gl/blit_program.h'
1195--- src/graphic/gl/blit_program.h 2015-03-01 09:21:20 +0000
1196+++ src/graphic/gl/blit_program.h 2016-01-05 11:29:18 +0000
1197@@ -21,32 +21,46 @@
1198 #define WL_GRAPHIC_GL_BLIT_PROGRAM_H
1199
1200 #include <memory>
1201+#include <vector>
1202
1203 #include "base/macros.h"
1204 #include "base/rect.h"
1205 #include "graphic/blend_mode.h"
1206 #include "graphic/color.h"
1207+#include "graphic/gl/blit_data.h"
1208 #include "graphic/gl/system_headers.h"
1209
1210 class BlitProgram;
1211
1212+
1213 class VanillaBlitProgram {
1214 public:
1215+ struct Arguments {
1216+ FloatRect destination_rect;
1217+ float z_value;
1218+ BlitData texture;
1219+ float opacity;
1220+ BlendMode blend_mode;
1221+ };
1222+
1223 // Returns the (singleton) instance of this class.
1224 static VanillaBlitProgram& instance();
1225 ~VanillaBlitProgram();
1226
1227 // Draws the rectangle 'gl_src_rect' from the texture with the name
1228- // 'gl_texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha
1229+ // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha
1230 // values are multiplied by 'opacity' during the blit.
1231 // All coordinates are in the OpenGL frame. The 'blend_mode' defines if the
1232 // values are copied or if alpha values are used.
1233 void draw(const FloatRect& gl_dest_rect,
1234- const FloatRect& gl_src_rect,
1235- const GLuint gl_texture,
1236+ const float z_value,
1237+ const BlitData& texture,
1238 float opacity,
1239 const BlendMode blend_mode);
1240
1241+ // Draws a bunch of items at once.
1242+ void draw(const std::vector<Arguments>& arguments);
1243+
1244 private:
1245 VanillaBlitProgram();
1246
1247@@ -57,55 +71,71 @@
1248
1249 class MonochromeBlitProgram {
1250 public:
1251+ struct Arguments {
1252+ FloatRect destination_rect;
1253+ float z_value;
1254+ BlitData texture;
1255+ RGBAColor blend;
1256+ BlendMode blend_mode;
1257+ };
1258+
1259 // Returns the (singleton) instance of this class.
1260 static MonochromeBlitProgram& instance();
1261 ~MonochromeBlitProgram();
1262
1263 // Draws the rectangle 'gl_src_rect' from the texture with the name
1264- // 'gl_texture' to 'gl_dest_rect' in the currently bound framebuffer. All
1265+ // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
1266 // coordinates are in the OpenGL frame. The image is first converted to
1267 // luminance, then all values are multiplied with blend.
1268 void draw(const FloatRect& gl_dest_rect,
1269- const FloatRect& gl_src_rect,
1270- const GLuint gl_texture,
1271+ const float z_value,
1272+ const BlitData& blit_source,
1273 const RGBAColor& blend);
1274
1275+ // Draws a bunch of items at once.
1276+ void draw(const std::vector<Arguments>& arguments);
1277+
1278 private:
1279 MonochromeBlitProgram();
1280
1281 std::unique_ptr<BlitProgram> blit_program_;
1282
1283- // Uniforms.
1284- GLint u_blend_;
1285-
1286 DISALLOW_COPY_AND_ASSIGN(MonochromeBlitProgram);
1287 };
1288
1289 class BlendedBlitProgram {
1290 public:
1291+ struct Arguments {
1292+ FloatRect destination_rect;
1293+ float z_value;
1294+ BlitData texture;
1295+ BlitData mask;
1296+ RGBAColor blend;
1297+ BlendMode blend_mode;
1298+ };
1299+
1300 // Returns the (singleton) instance of this class.
1301 static BlendedBlitProgram& instance();
1302 ~BlendedBlitProgram();
1303
1304 // Draws the rectangle 'gl_src_rect' from the texture with the name
1305 // 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All
1306- // coordinates are in the OpenGL frame. The 'gl_texture_mask' is used to selectively apply
1307+ // coordinates are in the OpenGL frame. The 'texture_mask' is used to selectively apply
1308 // the 'blend'. This is used for blitting player colored images.
1309 void draw(const FloatRect& gl_dest_rect,
1310- const FloatRect& gl_src_rect,
1311- const GLuint gl_texture_image,
1312- const GLuint gl_texture_mask,
1313- const RGBAColor& blend);
1314+ const float z_value,
1315+ const BlitData& texture,
1316+ const BlitData& mask,
1317+ const RGBAColor& blend);
1318+
1319+ // Draws a bunch of items at once.
1320+ void draw(const std::vector<Arguments>& arguments);
1321
1322 private:
1323 BlendedBlitProgram();
1324
1325 std::unique_ptr<BlitProgram> blit_program_;
1326
1327- // Uniforms.
1328- GLint u_blend_;
1329- GLint u_mask_;
1330-
1331 DISALLOW_COPY_AND_ASSIGN(BlendedBlitProgram);
1332 };
1333
1334
1335=== added file 'src/graphic/gl/coordinate_conversion.h'
1336--- src/graphic/gl/coordinate_conversion.h 1970-01-01 00:00:00 +0000
1337+++ src/graphic/gl/coordinate_conversion.h 2016-01-05 11:29:18 +0000
1338@@ -0,0 +1,73 @@
1339+/*
1340+ * Copyright (C) 2006-2015 by the Widelands Development Team
1341+ *
1342+ * This program is free software; you can redistribute it and/or
1343+ * modify it under the terms of the GNU General Public License
1344+ * as published by the Free Software Foundation; either version 2
1345+ * of the License, or (at your option) any later version.
1346+ *
1347+ * This program is distributed in the hope that it will be useful,
1348+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1349+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1350+ * GNU General Public License for more details.
1351+ *
1352+ * You should have received a copy of the GNU General Public License
1353+ * along with this program; if not, write to the Free Software
1354+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1355+ *
1356+ */
1357+
1358+#ifndef WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
1359+#define WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
1360+
1361+#include "base/rect.h"
1362+#include "graphic/gl/blit_data.h"
1363+
1364+// Converts the pixel (x, y) in a texture to a gl coordinate in [0, 1].
1365+inline void pixel_to_gl_texture(const int width, const int height, float* x, float* y) {
1366+ *x = (*x / width);
1367+ *y = 1. - (*y / height);
1368+}
1369+
1370+// Converts the given pixel into an OpenGl point in the renderbuffer.
1371+inline void pixel_to_gl_renderbuffer(const int width, const int height, float* x, float* y) {
1372+ *x = (*x / width) * 2. - 1.;
1373+ *y = 1. - (*y / height) * 2.;
1374+}
1375+
1376+// Converts 'rect' given on a screen of 'width' x 'height' pixels into a rect
1377+// in opengl coordinates in a renderbuffer, i.e. in [-1, 1]. The returned
1378+// rectangle has positive width and height.
1379+inline FloatRect
1380+rect_to_gl_renderbuffer(const int width, const int height, const Rect& rect) {
1381+ float left = rect.x;
1382+ float top = rect.y;
1383+ float right = rect.x + rect.w;
1384+ float bottom = rect.y + rect.h;
1385+ pixel_to_gl_renderbuffer(width, height, &left, &top);
1386+ pixel_to_gl_renderbuffer(width, height, &right, &bottom);
1387+ return FloatRect(left, bottom, right - left, top - bottom);
1388+}
1389+
1390+// Converts 'rect' given on a texture of 'width' x 'height' pixels into a rect
1391+// in opengl coordinates in a texture, i.e. in [0, 1]. Texture pixels are sampled in their center.
1392+// The returned rectangle has positive width and height.
1393+inline FloatRect
1394+rect_to_gl_texture(const int width, const int height, const FloatRect& rect) {
1395+ float left = rect.x;
1396+ float top = rect.y;
1397+ float right = rect.x + rect.w;
1398+ float bottom = rect.y + rect.h;
1399+ pixel_to_gl_texture(width, height, &left, &top);
1400+ pixel_to_gl_texture(width, height, &right, &bottom);
1401+ return FloatRect(left, bottom, right - left, top - bottom);
1402+}
1403+
1404+// Convert 'blit_data' from pixel space into opengl space.
1405+inline FloatRect to_gl_texture(const BlitData& blit_data) {
1406+ return rect_to_gl_texture(
1407+ blit_data.parent_width, blit_data.parent_height,
1408+ FloatRect(blit_data.rect.x, blit_data.rect.y, blit_data.rect.w, blit_data.rect.h));
1409+}
1410+
1411+#endif // end of include guard: WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
1412
1413=== modified file 'src/graphic/gl/dither_program.cc'
1414--- src/graphic/gl/dither_program.cc 2015-06-07 14:52:11 +0000
1415+++ src/graphic/gl/dither_program.cc 2016-01-05 11:29:18 +0000
1416@@ -20,6 +20,7 @@
1417 #include "graphic/gl/dither_program.h"
1418
1419 #include "base/wexception.h"
1420+#include "graphic/gl/coordinate_conversion.h"
1421 #include "graphic/gl/fields_to_draw.h"
1422 #include "graphic/image_io.h"
1423 #include "graphic/texture.h"
1424@@ -37,6 +38,8 @@
1425 attribute vec2 attr_texture_offset;
1426 attribute vec2 attr_texture_position;
1427
1428+uniform float u_z_value;
1429+
1430 // Output of vertex shader.
1431 varying float var_brightness;
1432 varying vec2 var_dither_texture_position;
1433@@ -48,7 +51,7 @@
1434 var_dither_texture_position = attr_dither_texture_position;
1435 var_texture_offset = attr_texture_offset;
1436 var_texture_position = attr_texture_position;
1437- gl_Position = vec4(attr_position, 0., 1.);
1438+ gl_Position = vec4(attr_position, u_z_value, 1.);
1439 }
1440 )";
1441
1442@@ -64,12 +67,18 @@
1443 varying vec2 var_texture_position;
1444 varying vec2 var_texture_offset;
1445
1446+// TODO(sirver): This is a hack to make sure we are sampling inside of the
1447+// terrain texture. This is a common problem with OpenGL and texture atlases.
1448+#define MARGIN 1e-2
1449+
1450 void main() {
1451- vec4 clr = texture2D(u_terrain_texture,
1452- var_texture_offset + u_texture_dimensions * fract(var_texture_position));
1453- clr.rgb *= var_brightness;
1454- clr.a = 1. - texture2D(u_dither_texture, var_dither_texture_position).a;
1455- gl_FragColor = clr;
1456+ vec2 texture_fract = clamp(
1457+ fract(var_texture_position),
1458+ vec2(MARGIN, MARGIN),
1459+ vec2(1. - MARGIN, 1. - MARGIN));
1460+ vec4 clr = texture2D(u_terrain_texture, var_texture_offset + u_texture_dimensions * texture_fract);
1461+ gl_FragColor = vec4(clr.rgb * var_brightness,
1462+ 1. - texture2D(u_dither_texture, var_dither_texture_position).a);
1463 }
1464 )";
1465
1466@@ -87,21 +96,22 @@
1467 u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");
1468 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
1469 u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
1470+ u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
1471
1472 dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));
1473
1474- glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
1475- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP));
1476- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP));
1477+ glBindTexture(GL_TEXTURE_2D, dither_mask_->blit_data().texture_id);
1478+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP_TO_EDGE));
1479+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP_TO_EDGE));
1480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(GL_LINEAR));
1481- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_LINEAR));
1482+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_NEAREST));
1483 glBindTexture(GL_TEXTURE_2D, 0);
1484 }
1485
1486 DitherProgram::~DitherProgram() {}
1487
1488 void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
1489- const int order_index,
1490+ const TrianglePoint triangle_point,
1491 const FloatPoint& texture_offset) {
1492 vertices_.emplace_back();
1493 PerVertexData& back = vertices_.back();
1494@@ -114,18 +124,18 @@
1495 back.texture_offset_x = texture_offset.x;
1496 back.texture_offset_y = texture_offset.y;
1497
1498- switch (order_index) {
1499- case 0:
1500+ switch (triangle_point) {
1501+ case TrianglePoint::kTopRight:
1502+ back.dither_texture_x = 1.;
1503+ back.dither_texture_y = 1.;
1504+ break;
1505+ case TrianglePoint::kTopLeft:
1506 back.dither_texture_x = 0.;
1507- back.dither_texture_y = 0.;
1508- break;
1509- case 1:
1510- back.dither_texture_x = 1.;
1511- back.dither_texture_y = 0.;
1512- break;
1513- case 2:
1514+ back.dither_texture_y = 1.;
1515+ break;
1516+ case TrianglePoint::kBottomMiddle:
1517 back.dither_texture_x = 0.5;
1518- back.dither_texture_y = 1.;
1519+ back.dither_texture_y = 0.;
1520 break;
1521 default:
1522 throw wexception("Never here.");
1523@@ -149,14 +159,14 @@
1524 if (terrains.get(my_terrain).dither_layer() <
1525 other_terrain_description.dither_layer()) {
1526 const FloatPoint texture_offset =
1527- other_terrain_description.get_texture(gametime).texture_coordinates().top_left();
1528- add_vertex(fields_to_draw.at(idx1), 0, texture_offset);
1529- add_vertex(fields_to_draw.at(idx2), 1, texture_offset);
1530- add_vertex(fields_to_draw.at(idx3), 2, texture_offset);
1531+ to_gl_texture(other_terrain_description.get_texture(gametime).blit_data()).origin();
1532+ add_vertex(fields_to_draw.at(idx1), TrianglePoint::kTopRight, texture_offset);
1533+ add_vertex(fields_to_draw.at(idx2), TrianglePoint::kTopLeft, texture_offset);
1534+ add_vertex(fields_to_draw.at(idx3), TrianglePoint::kBottomMiddle, texture_offset);
1535 }
1536 }
1537
1538-void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
1539+void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h, const float z_value) {
1540 glUseProgram(gl_program_.object());
1541
1542 glEnableVertexAttribArray(attr_brightness_);
1543@@ -165,35 +175,31 @@
1544 glEnableVertexAttribArray(attr_texture_offset_);
1545 glEnableVertexAttribArray(attr_texture_position_);
1546
1547- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
1548- glBufferData(GL_ARRAY_BUFFER,
1549- sizeof(PerVertexData) * vertices_.size(),
1550- vertices_.data(),
1551- GL_STREAM_DRAW);
1552+ gl_array_buffer_.bind();
1553+ gl_array_buffer_.update(vertices_);
1554
1555- const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
1556- glVertexAttribPointer(vertex_index,
1557- num_items,
1558- GL_FLOAT,
1559- GL_FALSE,
1560- sizeof(PerVertexData),
1561- reinterpret_cast<void*>(offset));
1562- };
1563- set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
1564- set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
1565- set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
1566- set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
1567- set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
1568+ Gl::vertex_attrib_pointer(
1569+ attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
1570+ Gl::vertex_attrib_pointer(attr_dither_texture_position_,
1571+ 2,
1572+ sizeof(PerVertexData),
1573+ offsetof(PerVertexData, dither_texture_x));
1574+ Gl::vertex_attrib_pointer(attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
1575+ Gl::vertex_attrib_pointer(
1576+ attr_texture_offset_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_offset_x));
1577+ Gl::vertex_attrib_pointer(
1578+ attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
1579
1580 glBindBuffer(GL_ARRAY_BUFFER, 0);
1581
1582 // Set the sampler texture unit to 0
1583 glActiveTexture(GL_TEXTURE0);
1584- glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
1585+ glBindTexture(GL_TEXTURE_2D, dither_mask_->blit_data().texture_id);
1586
1587 glActiveTexture(GL_TEXTURE1);
1588 glBindTexture(GL_TEXTURE_2D, gl_texture);
1589
1590+ glUniform1f(u_z_value_, z_value);
1591 glUniform1i(u_dither_texture_, 0);
1592 glUniform1i(u_terrain_texture_, 1);
1593 glUniform2f(u_texture_dimensions_, texture_w, texture_h);
1594@@ -213,7 +219,8 @@
1595
1596 void DitherProgram::draw(const uint32_t gametime,
1597 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
1598- const FieldsToDraw& fields_to_draw) {
1599+ const FieldsToDraw& fields_to_draw,
1600+ const float z_value) {
1601 // This method expects that all terrains have the same dimensions and that
1602 // all are packed into the same texture atlas, i.e. all are in the same GL
1603 // texture. It does not check for this invariance for speeds sake.
1604@@ -270,6 +277,10 @@
1605 }
1606 }
1607
1608- const Texture& texture = terrains.get(0).get_texture(0);
1609- gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
1610+ const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
1611+ const FloatRect texture_coordinates = to_gl_texture(blit_data);
1612+ gl_draw(blit_data.texture_id,
1613+ texture_coordinates.w,
1614+ texture_coordinates.h,
1615+ z_value);
1616 }
1617
1618=== modified file 'src/graphic/gl/dither_program.h'
1619--- src/graphic/gl/dither_program.h 2015-03-01 09:21:20 +0000
1620+++ src/graphic/gl/dither_program.h 2016-01-05 11:29:18 +0000
1621@@ -38,9 +38,16 @@
1622 // Draws the terrain.
1623 void draw(uint32_t gametime,
1624 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
1625- const FieldsToDraw& fields_to_draw);
1626+ const FieldsToDraw& fields_to_draw,
1627+ float z_value);
1628
1629 private:
1630+ enum class TrianglePoint {
1631+ kTopLeft,
1632+ kTopRight,
1633+ kBottomMiddle,
1634+ };
1635+
1636 // Adds the triangle between the indexes (which index 'fields_to_draw') to
1637 // vertices_ if the my_terrain != other_terrain and the dither_layer()
1638 // agree.
1639@@ -57,7 +64,9 @@
1640 // Adds the 'field' as an vertex to the 'vertices_'. The 'order_index'
1641 // defines which texture position in the dithering texture will be used for
1642 // this vertex.
1643- void add_vertex(const FieldsToDraw::Field& field, int order_index, const FloatPoint& texture_offset);
1644+ void add_vertex(const FieldsToDraw::Field& field,
1645+ TrianglePoint triangle_point,
1646+ const FloatPoint& texture_offset);
1647
1648 struct PerVertexData {
1649 float gl_x;
1650@@ -72,13 +81,13 @@
1651 };
1652
1653 // Call through to GL.
1654- void gl_draw(int gl_texture, float texture_w, float texture_h);
1655+ void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
1656
1657 // The program used for drawing the terrain.
1658 Gl::Program gl_program_;
1659
1660 // The buffer that contains the data to be rendered.
1661- Gl::Buffer gl_array_buffer_;
1662+ Gl::Buffer<PerVertexData> gl_array_buffer_;
1663
1664 // Attributes.
1665 GLint attr_brightness_;
1666@@ -91,6 +100,7 @@
1667 GLint u_dither_texture_;
1668 GLint u_terrain_texture_;
1669 GLint u_texture_dimensions_;
1670+ GLint u_z_value_;
1671
1672 // The texture mask for the dithering step.
1673 std::unique_ptr<Texture> dither_mask_;
1674
1675=== modified file 'src/graphic/gl/draw_line_program.cc'
1676--- src/graphic/gl/draw_line_program.cc 2015-03-01 09:21:20 +0000
1677+++ src/graphic/gl/draw_line_program.cc 2016-01-05 11:29:18 +0000
1678@@ -19,6 +19,8 @@
1679
1680 #include "graphic/gl/draw_line_program.h"
1681
1682+#include <algorithm>
1683+#include <cassert>
1684 #include <vector>
1685
1686 #include "base/log.h"
1687@@ -29,23 +31,33 @@
1688 #version 120
1689
1690 // Attributes.
1691-attribute vec2 attr_position;
1692+attribute vec3 attr_position;
1693+attribute vec3 attr_color;
1694+
1695+varying vec3 var_color;
1696
1697 void main() {
1698- gl_Position = vec4(attr_position, 0., 1.);
1699+ var_color = attr_color;
1700+ gl_Position = vec4(attr_position, 1.);
1701 }
1702 )";
1703
1704 const char kDrawLineFragmentShader[] = R"(
1705 #version 120
1706
1707-uniform ivec3 u_color;
1708+varying vec3 var_color;
1709
1710 void main() {
1711- gl_FragColor = vec4(vec3(u_color) / 255., 1.);
1712+ gl_FragColor = vec4(var_color.rgb, 1.);
1713 }
1714 )";
1715
1716+struct DrawBatch {
1717+ int offset;
1718+ int count;
1719+ int line_width;
1720+};
1721+
1722 } // namespace
1723
1724 // static
1725@@ -58,37 +70,81 @@
1726 gl_program_.build(kDrawLineVertexShader, kDrawLineFragmentShader);
1727
1728 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
1729- u_color_ = glGetUniformLocation(gl_program_.object(), "u_color");
1730-
1731+ attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
1732 }
1733
1734-void DrawLineProgram::draw(const float x1,
1735- const float y1,
1736- const float x2,
1737- const float y2,
1738+void DrawLineProgram::draw(const FloatPoint& start,
1739+ const FloatPoint& end,
1740+ const float z_value,
1741 const RGBColor& color,
1742- const int line_width) {
1743+ int line_width) {
1744+ draw({Arguments{FloatRect(start.x, start.y, end.x - start.x, end.y - start.y),
1745+ z_value,
1746+ color,
1747+ static_cast<uint8_t>(line_width),
1748+ BlendMode::Copy}});
1749+}
1750+
1751+void DrawLineProgram::draw(std::vector<Arguments> arguments) {
1752+ size_t i = 0;
1753+
1754 glUseProgram(gl_program_.object());
1755 glEnableVertexAttribArray(attr_position_);
1756-
1757- const std::vector<PerVertexData> vertices = {{x1, y1}, {x2, y2}};
1758-
1759- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
1760- glBufferData(
1761- GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STREAM_DRAW);
1762- glVertexAttribPointer(attr_position_,
1763- 2,
1764- GL_FLOAT,
1765- GL_FALSE,
1766- sizeof(PerVertexData),
1767- reinterpret_cast<void*>(0));
1768-
1769- glUniform3i(u_color_, color.r, color.g, color.b);
1770-
1771- glLineWidth(line_width);
1772- glDrawArrays(GL_LINES, 0, 2);
1773+ glEnableVertexAttribArray(attr_color_);
1774+
1775+ gl_array_buffer_.bind();
1776+
1777+ Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
1778+ Gl::vertex_attrib_pointer(attr_color_, 3, sizeof(PerVertexData), offsetof(PerVertexData, color_r));
1779+
1780+ vertices_.clear();
1781+
1782+ std::vector<DrawBatch> draw_batches;
1783+ int offset = 0;
1784+ while (i < arguments.size()) {
1785+ const Arguments& template_args = arguments[i];
1786+
1787+ while (i < arguments.size()) {
1788+ const Arguments& current_args = arguments[i];
1789+ if (current_args.line_width != template_args.line_width) {
1790+ break;
1791+ }
1792+ // We do not support anything else for drawing lines, really.
1793+ assert(current_args.blend_mode == BlendMode::Copy);
1794+
1795+ vertices_.emplace_back(current_args.destination_rect.x,
1796+ current_args.destination_rect.y,
1797+ current_args.z_value,
1798+ current_args.color.r / 255.,
1799+ current_args.color.g / 255.,
1800+ current_args.color.b / 255.);
1801+
1802+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
1803+ current_args.destination_rect.y + current_args.destination_rect.h,
1804+ current_args.z_value,
1805+ current_args.color.r / 255.,
1806+ current_args.color.g / 255.,
1807+ current_args.color.b / 255.);
1808+ ++i;
1809+ }
1810+
1811+ draw_batches.emplace_back(
1812+ DrawBatch{offset, static_cast<int>(vertices_.size() - offset), template_args.line_width});
1813+ offset = vertices_.size();
1814+ }
1815+
1816+ gl_array_buffer_.update(vertices_);
1817+
1818+ // Now do the draw calls.
1819+ for (const auto& draw_arg : draw_batches) {
1820+ glLineWidth(draw_arg.line_width);
1821+ glDrawArrays(GL_LINES, draw_arg.offset, draw_arg.count);
1822+ }
1823
1824 glBindBuffer(GL_ARRAY_BUFFER, 0);
1825+
1826 glDisableVertexAttribArray(attr_position_);
1827+ glDisableVertexAttribArray(attr_color_);
1828+
1829 glUseProgram(0);
1830 }
1831
1832=== modified file 'src/graphic/gl/draw_line_program.h'
1833--- src/graphic/gl/draw_line_program.h 2015-03-01 09:21:20 +0000
1834+++ src/graphic/gl/draw_line_program.h 2016-01-05 11:29:18 +0000
1835@@ -20,37 +20,76 @@
1836 #ifndef WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H
1837 #define WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H
1838
1839+#include <vector>
1840+
1841+#include "base/point.h"
1842+#include "base/rect.h"
1843+#include "graphic/blend_mode.h"
1844 #include "graphic/color.h"
1845 #include "graphic/gl/utils.h"
1846
1847 class DrawLineProgram {
1848 public:
1849+ struct Arguments {
1850+ // The line is drawn from the top left to the bottom right of
1851+ // this rectangle.
1852+ FloatRect destination_rect;
1853+ float z_value;
1854+ RGBAColor color;
1855+ uint8_t line_width;
1856+ BlendMode blend_mode;
1857+ };
1858+
1859 // Returns the (singleton) instance of this class.
1860 static DrawLineProgram& instance();
1861
1862 // Draws a line from (x1, y1) to (x2, y2) which are in gl
1863 // coordinates in 'color' with a 'line_width' in pixels.
1864- void draw(float x1, float y1, float x2, float y2, const RGBColor& color, int line_width);
1865+ void draw(const FloatPoint& start,
1866+ const FloatPoint& end,
1867+ const float z_value,
1868+ const RGBColor& color,
1869+ const int line_width);
1870+
1871+ void draw(std::vector<Arguments> arguments);
1872+
1873
1874 private:
1875 DrawLineProgram();
1876
1877 struct PerVertexData {
1878- float gl_x, gl_y;
1879+ PerVertexData(float init_gl_x,
1880+ float init_gl_y,
1881+ float init_gl_z,
1882+ float init_color_r,
1883+ float init_color_g,
1884+ float init_color_b)
1885+ : gl_x(init_gl_x),
1886+ gl_y(init_gl_y),
1887+ gl_z(init_gl_z),
1888+ color_r(init_color_r),
1889+ color_g(init_color_g),
1890+ color_b(init_color_b) {
1891+ }
1892+
1893+ float gl_x, gl_y, gl_z;
1894+ float color_r, color_g, color_b;
1895 };
1896- static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
1897+ static_assert(sizeof(PerVertexData) == 24, "Wrong padding.");
1898+
1899+ // This is only kept around so that we do not constantly
1900+ // allocate memory for it.
1901+ std::vector<PerVertexData> vertices_;
1902
1903 // The buffer that contains the vertices for rendering.
1904- Gl::Buffer gl_array_buffer_;
1905+ Gl::Buffer<PerVertexData> gl_array_buffer_;
1906
1907 // The program.
1908 Gl::Program gl_program_;
1909
1910 // Attributes.
1911 GLint attr_position_;
1912-
1913- // Uniforms.
1914- GLint u_color_;
1915+ GLint attr_color_;
1916
1917 DISALLOW_COPY_AND_ASSIGN(DrawLineProgram);
1918 };
1919
1920=== modified file 'src/graphic/gl/fields_to_draw.h'
1921--- src/graphic/gl/fields_to_draw.h 2015-03-01 09:21:20 +0000
1922+++ src/graphic/gl/fields_to_draw.h 2016-01-05 11:29:18 +0000
1923@@ -43,14 +43,20 @@
1924 const RoadTextures* road_textures; // Road Textures to use for drawing.
1925 };
1926
1927- FieldsToDraw(int minfx, int maxfx, int minfy, int maxfy)
1928- : min_fx_(minfx),
1929- max_fx_(maxfx),
1930- min_fy_(minfy),
1931- max_fy_(maxfy),
1932- w_(max_fx_ - min_fx_ + 1),
1933- h_(max_fy_ - min_fy_ + 1) {
1934- fields_.resize(w_ * h_);
1935+ FieldsToDraw() = default;
1936+
1937+ // Resize this fields to draw for reuse.
1938+ void reset(int minfx, int maxfx, int minfy, int maxfy) {
1939+ min_fx_ = minfx;
1940+ max_fx_ = maxfx;
1941+ min_fy_ = minfy;
1942+ max_fy_ = maxfy;
1943+ w_ = max_fx_ - min_fx_ + 1;
1944+ h_ = max_fy_ - min_fy_ + 1;
1945+ const size_t size = w_ * h_;
1946+ if (fields_.size() != size) {
1947+ fields_.resize(size);
1948+ }
1949 }
1950
1951 // Calculates the index of the given field with ('fx', 'fy') being geometric
1952@@ -84,14 +90,14 @@
1953
1954 private:
1955 // Minimum and maximum field coordinates (geometric) to render. Can be negative.
1956- const int min_fx_;
1957- const int max_fx_;
1958- const int min_fy_;
1959- const int max_fy_;
1960+ int min_fx_;
1961+ int max_fx_;
1962+ int min_fy_;
1963+ int max_fy_;
1964
1965 // Width and height in number of fields.
1966- const int w_;
1967- const int h_;
1968+ int w_;
1969+ int h_;
1970
1971 std::vector<Field> fields_;
1972 };
1973
1974=== modified file 'src/graphic/gl/fill_rect_program.cc'
1975--- src/graphic/gl/fill_rect_program.cc 2015-03-01 09:21:20 +0000
1976+++ src/graphic/gl/fill_rect_program.cc 2016-01-05 11:29:18 +0000
1977@@ -22,6 +22,7 @@
1978 #include <vector>
1979
1980 #include "base/log.h"
1981+#include "base/wexception.h"
1982
1983 namespace {
1984
1985@@ -29,26 +30,24 @@
1986 #version 120
1987
1988 // Attributes.
1989-attribute vec2 attr_position;
1990-
1991-// Uniforms.
1992-uniform vec4 u_rect;
1993-
1994+attribute vec3 attr_position;
1995+attribute vec4 attr_color;
1996+
1997+varying vec4 var_color;
1998
1999 void main() {
2000- float x = u_rect.x + attr_position.x * u_rect.z;
2001- float y = u_rect.y + attr_position.y * u_rect.w;
2002- gl_Position = vec4(x, y, 0., 1.);
2003+ var_color = attr_color;
2004+ gl_Position = vec4(attr_position, 1.);
2005 }
2006 )";
2007
2008 const char kFillRectFragmentShader[] = R"(
2009 #version 120
2010
2011-uniform ivec4 u_color;
2012+varying vec4 var_color;
2013
2014 void main() {
2015- gl_FragColor = vec4(u_color) / 255.;
2016+ gl_FragColor = var_color;
2017 }
2018 )";
2019
2020@@ -64,49 +63,144 @@
2021 gl_program_.build(kFillRectVertexShader, kFillRectFragmentShader);
2022
2023 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
2024-
2025- u_color_ = glGetUniformLocation(gl_program_.object(), "u_color");
2026- u_rect_ = glGetUniformLocation(gl_program_.object(), "u_rect");
2027-
2028- std::vector<PerVertexData> vertices;
2029- vertices.push_back(PerVertexData
2030- {0., 1.});
2031- vertices.push_back(PerVertexData
2032- {1., 1.});
2033- vertices.push_back(PerVertexData
2034- {0., 0.});
2035- vertices.push_back(PerVertexData
2036- {1., 0.});
2037-
2038- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
2039- glBufferData(
2040- GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
2041- glVertexAttribPointer(attr_position_,
2042- 2,
2043- GL_FLOAT,
2044- GL_FALSE,
2045- sizeof(PerVertexData),
2046- reinterpret_cast<void*>(0));
2047- glBindBuffer(GL_ARRAY_BUFFER, 0);
2048-}
2049-
2050-void FillRectProgram::draw(const FloatRect& gl_dst_rect, const RGBAColor& color) {
2051- glUseProgram(gl_program_.object());
2052- glEnableVertexAttribArray(attr_position_);
2053- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
2054-
2055- glVertexAttribPointer(attr_position_,
2056- 2,
2057- GL_FLOAT,
2058- GL_FALSE,
2059- sizeof(PerVertexData),
2060- reinterpret_cast<void*>(0));
2061-
2062- glUniform4f(u_rect_, gl_dst_rect.x, gl_dst_rect.y, gl_dst_rect.w, gl_dst_rect.h);
2063- glUniform4i(u_color_, color.r, color.g, color.b, color.a);
2064-
2065- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2066+ attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
2067+}
2068+
2069+void FillRectProgram::draw(const FloatRect& destination_rect,
2070+ const float z_value,
2071+ const RGBAColor& color,
2072+ const BlendMode blend_mode) {
2073+ draw({Arguments{destination_rect, z_value, color, blend_mode} });
2074+}
2075+
2076+void FillRectProgram::draw(const std::vector<Arguments>& arguments) {
2077+ size_t i = 0;
2078+
2079+ while (i < arguments.size()) {
2080+ vertices_.clear();
2081+ const Arguments& template_args = arguments[i];
2082+
2083+ // This method does 3 things:
2084+ // - if blend_mode is Copy, we will copy color into the destination
2085+ // pixels without blending.
2086+ // - if blend_mode is Alpha and color.r < 0, we will
2087+ // GL_FUNC_REVERSE_SUBTRACT color.r from all RGB values in the
2088+ // destination buffer. color.a should be 0 for this.
2089+ // - if blend_mode is Alpha and color.r > 0, we will
2090+ // GL_ADD color.r to all RGB values in the destination buffer.
2091+ // color.a should be 0 for this.
2092+
2093+ // The simple trick here is to fill the rect, but using a different glBlendFunc that will sum
2094+ // src and target (or subtract them if factor is negative).
2095+ switch (template_args.blend_mode) {
2096+ case BlendMode::Subtract:
2097+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
2098+ /* fallthrough intended */
2099+ case BlendMode::UseAlpha:
2100+ glBlendFunc(GL_ONE, GL_ONE);
2101+ break;
2102+
2103+ case BlendMode::Copy:
2104+ glDisable(GL_BLEND);
2105+ break;
2106+
2107+ default:
2108+ break;
2109+ }
2110+
2111+ glUseProgram(gl_program_.object());
2112+
2113+ gl_array_buffer_.bind();
2114+
2115+ glEnableVertexAttribArray(attr_position_);
2116+ glEnableVertexAttribArray(attr_color_);
2117+
2118+ // Batch common rectangles up.
2119+ while (i < arguments.size()) {
2120+ const Arguments& current_args = arguments[i];
2121+ if (current_args.blend_mode != template_args.blend_mode) {
2122+ break;
2123+ }
2124+
2125+ const float r = current_args.color.r / 255.;
2126+ const float g = current_args.color.g / 255.;
2127+ const float b = current_args.color.b / 255.;
2128+ const float a = current_args.color.a / 255.;
2129+
2130+ // First triangle.
2131+ vertices_.emplace_back(current_args.destination_rect.x,
2132+ current_args.destination_rect.y,
2133+ current_args.z_value,
2134+ r,
2135+ g,
2136+ b,
2137+ a);
2138+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
2139+ current_args.destination_rect.y,
2140+ current_args.z_value,
2141+ r,
2142+ g,
2143+ b,
2144+ a);
2145+ vertices_.emplace_back(current_args.destination_rect.x,
2146+ current_args.destination_rect.y + current_args.destination_rect.h,
2147+ current_args.z_value,
2148+ r,
2149+ g,
2150+ b,
2151+ a);
2152+
2153+ // Second triangle.
2154+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
2155+ current_args.destination_rect.y,
2156+ current_args.z_value,
2157+ r,
2158+ g,
2159+ b,
2160+ a);
2161+ vertices_.emplace_back(current_args.destination_rect.x,
2162+ current_args.destination_rect.y + current_args.destination_rect.h,
2163+ current_args.z_value,
2164+ r,
2165+ g,
2166+ b,
2167+ a);
2168+ vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
2169+ current_args.destination_rect.y + current_args.destination_rect.h,
2170+ current_args.z_value,
2171+ r,
2172+ g,
2173+ b,
2174+ a);
2175+ ++i;
2176+ }
2177+
2178+ gl_array_buffer_.update(vertices_);
2179+
2180+ Gl::vertex_attrib_pointer(
2181+ attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
2182+ Gl::vertex_attrib_pointer(attr_color_, 4, sizeof(PerVertexData), offsetof(PerVertexData, r));
2183+
2184+ glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
2185+
2186+ switch (template_args.blend_mode) {
2187+ case BlendMode::Subtract:
2188+ glBlendEquation(GL_FUNC_ADD);
2189+ /* fallthrough intended */
2190+ case BlendMode::UseAlpha:
2191+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2192+ break;
2193+
2194+ case BlendMode::Copy:
2195+ glEnable(GL_BLEND);
2196+ break;
2197+
2198+ default:
2199+ break;
2200+ }
2201+ }
2202
2203 glDisableVertexAttribArray(attr_position_);
2204+ glDisableVertexAttribArray(attr_color_);
2205 glBindBuffer(GL_ARRAY_BUFFER, 0);
2206 }
2207
2208=== modified file 'src/graphic/gl/fill_rect_program.h'
2209--- src/graphic/gl/fill_rect_program.h 2015-03-01 09:21:20 +0000
2210+++ src/graphic/gl/fill_rect_program.h 2016-01-05 11:29:18 +0000
2211@@ -20,39 +20,73 @@
2212 #ifndef WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H
2213 #define WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H
2214
2215+#include <vector>
2216+
2217 #include "base/rect.h"
2218+#include "graphic/blend_mode.h"
2219 #include "graphic/color.h"
2220 #include "graphic/gl/utils.h"
2221
2222 class FillRectProgram {
2223 public:
2224+ struct Arguments {
2225+ FloatRect destination_rect;
2226+ float z_value;
2227+ RGBAColor color;
2228+ BlendMode blend_mode;
2229+ };
2230+
2231 // Returns the (singleton) instance of this class.
2232 static FillRectProgram& instance();
2233
2234- // Fills a solid rect in 'color' into the currently activated
2235- // framebuffer.
2236- void draw(const FloatRect& gl_dst_rect, const RGBAColor& color);
2237+ // Fills a solid rect in 'color'. If blend_mode is BlendMode::UseAlpha, this
2238+ // will brighten the rect, if it is BlendMode::Subtract it darkens it.
2239+ void draw(const FloatRect& destination_rect,
2240+ float z_value,
2241+ const RGBAColor& color,
2242+ BlendMode blend_mode);
2243+
2244+
2245+ void draw(const std::vector<Arguments>& arguments);
2246
2247 private:
2248 FillRectProgram();
2249
2250 struct PerVertexData {
2251- float gl_x, gl_y;
2252+ PerVertexData(float init_gl_x,
2253+ float init_gl_y,
2254+ float init_gl_z,
2255+ float init_r,
2256+ float init_g,
2257+ float init_b,
2258+ float init_a)
2259+ : gl_x(init_gl_x),
2260+ gl_y(init_gl_y),
2261+ gl_z(init_gl_z),
2262+ r(init_r),
2263+ g(init_g),
2264+ b(init_b),
2265+ a(init_a) {
2266+ }
2267+
2268+ float gl_x, gl_y, gl_z;
2269+ float r, g, b, a;
2270 };
2271- static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
2272+ static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
2273+
2274+ // This is only kept around so that we do not constantly allocate memory for
2275+ // it.
2276+ std::vector<PerVertexData> vertices_;
2277
2278 // The buffer that will contain the quad for rendering.
2279- Gl::Buffer gl_array_buffer_;
2280+ Gl::Buffer<PerVertexData> gl_array_buffer_;
2281
2282 // The program.
2283 Gl::Program gl_program_;
2284
2285 // Attributes.
2286 GLint attr_position_;
2287-
2288- // Uniforms.
2289- GLint u_rect_;
2290- GLint u_color_;
2291+ GLint attr_color_;
2292
2293 DISALLOW_COPY_AND_ASSIGN(FillRectProgram);
2294 };
2295
2296=== modified file 'src/graphic/gl/road_program.cc'
2297--- src/graphic/gl/road_program.cc 2015-03-01 09:21:20 +0000
2298+++ src/graphic/gl/road_program.cc 2016-01-05 11:29:18 +0000
2299@@ -23,6 +23,7 @@
2300 #include <cmath>
2301
2302 #include "base/log.h"
2303+#include "graphic/gl/coordinate_conversion.h"
2304 #include "graphic/gl/fields_to_draw.h"
2305 #include "graphic/graphic.h"
2306 #include "graphic/image_io.h"
2307@@ -40,6 +41,8 @@
2308 attribute vec2 attr_texture_position;
2309 attribute float attr_brightness;
2310
2311+uniform float u_z_value;
2312+
2313 // Outputs.
2314 varying vec2 out_texture_position;
2315 varying float out_brightness;
2316@@ -47,7 +50,7 @@
2317 void main() {
2318 out_texture_position = attr_texture_position;
2319 out_brightness = attr_brightness;
2320- gl_Position = vec4(attr_position, 0., 1.);
2321+ gl_Position = vec4(attr_position, u_z_value, 1.);
2322 }
2323 )";
2324
2325@@ -73,22 +76,23 @@
2326 gl_program_.build(kRoadVertexShader, kRoadFragmentShader);
2327
2328 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
2329- attr_texture_position_ =
2330- glGetAttribLocation(gl_program_.object(), "attr_texture_position");
2331+ attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
2332 attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
2333
2334+ u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
2335 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
2336 }
2337
2338 RoadProgram::~RoadProgram() {
2339 }
2340
2341-void RoadProgram::add_road(const Surface& surface,
2342+void RoadProgram::add_road(const int renderbuffer_width,
2343+ const int renderbuffer_height,
2344 const FieldsToDraw::Field& start,
2345 const FieldsToDraw::Field& end,
2346 const Widelands::RoadType road_type,
2347 const Direction direction,
2348- int* gl_texture) {
2349+ uint32_t* gl_texture) {
2350 // The thickness of the road in pixels on screen.
2351 static constexpr float kRoadThicknessInPixels = 5.;
2352
2353@@ -111,14 +115,14 @@
2354 road_type == Widelands::RoadType::kNormal ?
2355 start.road_textures->get_normal_texture(start.fx, start.fy, direction) :
2356 start.road_textures->get_busy_texture(start.fx, start.fy, direction);
2357- if (*gl_texture == -1) {
2358- *gl_texture = texture.get_gl_texture();
2359+ if (*gl_texture == 0) {
2360+ *gl_texture = texture.blit_data().texture_id;
2361 }
2362 // We assume that all road textures are in the same OpenGL texture, i.e. in
2363 // one texture atlas.
2364- assert(*gl_texture == texture.get_gl_texture());
2365+ assert(*gl_texture == texture.blit_data().texture_id);
2366
2367- const auto& texture_rect = texture.texture_coordinates();
2368+ const FloatRect texture_rect = to_gl_texture(texture.blit_data());
2369
2370 vertices_.emplace_back(PerVertexData{
2371 start.pixel_x - road_overshoot_x + road_thickness_x,
2372@@ -127,16 +131,18 @@
2373 texture_rect.y,
2374 start.brightness,
2375 });
2376- surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
2377+ pixel_to_gl_renderbuffer(
2378+ renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
2379
2380 vertices_.emplace_back(PerVertexData{
2381 start.pixel_x - road_overshoot_x - road_thickness_x,
2382 start.pixel_y - road_overshoot_y - road_thickness_y,
2383 texture_rect.x,
2384- texture_rect.y + texture_rect.h,
2385+ texture_rect.y + texture_rect.h,
2386 start.brightness,
2387 });
2388- surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
2389+ pixel_to_gl_renderbuffer(
2390+ renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
2391
2392 vertices_.emplace_back(PerVertexData{
2393 end.pixel_x + road_overshoot_x + road_thickness_x,
2394@@ -145,7 +151,8 @@
2395 texture_rect.y,
2396 end.brightness,
2397 });
2398- surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
2399+ pixel_to_gl_renderbuffer(
2400+ renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
2401
2402 // As OpenGl does not support drawing quads in modern days and we have a
2403 // bunch of roads that might not be neighbored, we need to add two triangles
2404@@ -161,13 +168,17 @@
2405 texture_rect.y + texture_rect.h,
2406 end.brightness,
2407 });
2408- surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
2409+ pixel_to_gl_renderbuffer(
2410+ renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
2411 }
2412
2413-void RoadProgram::draw(const Surface& surface, const FieldsToDraw& fields_to_draw) {
2414+void RoadProgram::draw(const int renderbuffer_width,
2415+ const int renderbuffer_height,
2416+ const FieldsToDraw& fields_to_draw,
2417+ float z_value) {
2418 vertices_.clear();
2419
2420- int gl_texture = -1;
2421+ uint32_t gl_texture = 0;
2422 for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
2423 const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
2424
2425@@ -175,9 +186,15 @@
2426 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
2427 if (rn_index != -1) {
2428 const Widelands::RoadType road =
2429- static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
2430+ static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
2431 if (road != Widelands::RoadType::kNone) {
2432- add_road(surface, field, fields_to_draw.at(rn_index), road, kEast, &gl_texture);
2433+ add_road(renderbuffer_width,
2434+ renderbuffer_height,
2435+ field,
2436+ fields_to_draw.at(rn_index),
2437+ road,
2438+ kEast,
2439+ &gl_texture);
2440 }
2441 }
2442
2443@@ -185,9 +202,15 @@
2444 const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
2445 if (brn_index != -1) {
2446 const Widelands::RoadType road =
2447- static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
2448+ static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
2449 if (road != Widelands::RoadType::kNone) {
2450- add_road(surface, field, fields_to_draw.at(brn_index), road, kSouthEast, &gl_texture);
2451+ add_road(renderbuffer_width,
2452+ renderbuffer_height,
2453+ field,
2454+ fields_to_draw.at(brn_index),
2455+ road,
2456+ kSouthEast,
2457+ &gl_texture);
2458 }
2459 }
2460
2461@@ -196,9 +219,15 @@
2462 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
2463 if (bln_index != -1) {
2464 const Widelands::RoadType road =
2465- static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
2466+ static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
2467 if (road != Widelands::RoadType::kNone) {
2468- add_road(surface, field, fields_to_draw.at(bln_index), road, kSouthWest, &gl_texture);
2469+ add_road(renderbuffer_width,
2470+ renderbuffer_height,
2471+ field,
2472+ fields_to_draw.at(bln_index),
2473+ road,
2474+ kSouthWest,
2475+ &gl_texture);
2476 }
2477 }
2478 }
2479@@ -209,21 +238,15 @@
2480 glEnableVertexAttribArray(attr_texture_position_);
2481 glEnableVertexAttribArray(attr_brightness_);
2482
2483- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
2484- glBufferData(
2485- GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices_.size(), vertices_.data(), GL_STREAM_DRAW);
2486+ gl_array_buffer_.bind();
2487+ gl_array_buffer_.update(vertices_);
2488
2489- const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
2490- glVertexAttribPointer(vertex_index,
2491- num_items,
2492- GL_FLOAT,
2493- GL_FALSE,
2494- sizeof(PerVertexData),
2495- reinterpret_cast<void*>(offset));
2496- };
2497- set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
2498- set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
2499- set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
2500+ Gl::vertex_attrib_pointer(
2501+ attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
2502+ Gl::vertex_attrib_pointer(
2503+ attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
2504+ Gl::vertex_attrib_pointer(
2505+ attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
2506
2507 glBindBuffer(GL_ARRAY_BUFFER, 0);
2508
2509@@ -233,6 +256,8 @@
2510
2511 glUniform1i(u_texture_, 0);
2512
2513+ glUniform1f(u_z_value_, z_value);
2514+
2515 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
2516
2517 glDisableVertexAttribArray(attr_position_);
2518
2519=== modified file 'src/graphic/gl/road_program.h'
2520--- src/graphic/gl/road_program.h 2015-03-01 09:21:20 +0000
2521+++ src/graphic/gl/road_program.h 2016-01-05 11:29:18 +0000
2522@@ -37,9 +37,12 @@
2523 RoadProgram();
2524 ~RoadProgram();
2525
2526- // Draws the roads. The 'surface' is needed to convert from pixel space to
2527- // GL space.
2528- void draw(const Surface& surface, const FieldsToDraw& fields_to_draw);
2529+ // Draws the roads. The dimensions of the renderbuffer are needed to convert from pixel to GL
2530+ // space.
2531+ void draw(int renderbuffer_width,
2532+ int renderbuffer_height,
2533+ const FieldsToDraw& fields_to_draw,
2534+ float z_value);
2535
2536 private:
2537 struct PerVertexData {
2538@@ -54,15 +57,16 @@
2539 // Adds a road from 'start' to 'end' to be rendered in this frame using the
2540 // correct texture for 'road_type'.
2541 enum Direction {kEast, kSouthEast, kSouthWest};
2542- void add_road(const Surface& surface,
2543+ void add_road(int renderbuffer_width,
2544+ int renderbuffer_height,
2545 const FieldsToDraw::Field& start,
2546 const FieldsToDraw::Field& end,
2547 const Widelands::RoadType road_type,
2548 const Direction direction,
2549- int* gl_texture);
2550+ uint32_t* gl_texture);
2551
2552 // The buffer that will contain 'vertices_' for rendering.
2553- Gl::Buffer gl_array_buffer_;
2554+ Gl::Buffer<PerVertexData> gl_array_buffer_;
2555
2556 // The program used for drawing the roads.
2557 Gl::Program gl_program_;
2558@@ -74,6 +78,7 @@
2559
2560 // Uniforms.
2561 GLint u_texture_;
2562+ GLint u_z_value_;
2563
2564 // All vertices that get rendered this frame.
2565 std::vector<PerVertexData> vertices_;
2566
2567=== modified file 'src/graphic/gl/terrain_program.cc'
2568--- src/graphic/gl/terrain_program.cc 2015-06-07 14:52:11 +0000
2569+++ src/graphic/gl/terrain_program.cc 2016-01-05 11:29:18 +0000
2570@@ -19,6 +19,7 @@
2571
2572 #include "graphic/gl/terrain_program.h"
2573
2574+#include "graphic/gl/coordinate_conversion.h"
2575 #include "graphic/gl/fields_to_draw.h"
2576 #include "graphic/texture.h"
2577
2578@@ -40,6 +41,8 @@
2579 attribute vec2 attr_texture_offset;
2580 attribute vec2 attr_texture_position;
2581
2582+uniform float u_z_value;
2583+
2584 // Output of vertex shader.
2585 varying float var_brightness;
2586 varying vec2 var_texture_offset;
2587@@ -49,7 +52,7 @@
2588 var_texture_position = attr_texture_position;
2589 var_brightness = attr_brightness;
2590 var_texture_offset = attr_texture_offset;
2591- gl_Position = vec4(attr_position, 0., 1.);
2592+ gl_Position = vec4(attr_position, u_z_value, 1.);
2593 }
2594 )";
2595
2596@@ -63,9 +66,20 @@
2597 varying vec2 var_texture_position;
2598 varying vec2 var_texture_offset;
2599
2600+// TODO(sirver): This is a hack to make sure we are sampling inside of the
2601+// terrain texture. This is a common problem with OpenGL and texture atlases.
2602+#define MARGIN 1e-2
2603+
2604 void main() {
2605- vec4 clr = texture2D(u_terrain_texture,
2606- var_texture_offset + u_texture_dimensions * fract(var_texture_position));
2607+ // The arbitrary multiplication by 0.99 makes sure that we never sample
2608+ // outside of the texture in the texture atlas - this means non-perfect
2609+ // pixel mapping of textures to the screen, but we are pretty meh about that
2610+ // here.
2611+ vec2 texture_fract = clamp(
2612+ fract(var_texture_position),
2613+ vec2(MARGIN, MARGIN),
2614+ vec2(1. - MARGIN, 1. - MARGIN));
2615+ vec4 clr = texture2D(u_terrain_texture, var_texture_offset + u_texture_dimensions * texture_fract);
2616 clr.rgb *= var_brightness;
2617 gl_FragColor = clr;
2618 }
2619@@ -83,9 +97,10 @@
2620
2621 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
2622 u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
2623+ u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
2624 }
2625
2626-void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
2627+void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h, float z_value) {
2628 glUseProgram(gl_program_.object());
2629
2630 glEnableVertexAttribArray(attr_brightness_);
2631@@ -93,30 +108,23 @@
2632 glEnableVertexAttribArray(attr_texture_offset_);
2633 glEnableVertexAttribArray(attr_texture_position_);
2634
2635- glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
2636- glBufferData(GL_ARRAY_BUFFER,
2637- sizeof(TerrainProgram::PerVertexData) * vertices_.size(),
2638- vertices_.data(),
2639- GL_STREAM_DRAW);
2640+ gl_array_buffer_.bind();
2641+ gl_array_buffer_.update(vertices_);
2642
2643- const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
2644- glVertexAttribPointer(vertex_index,
2645- num_items,
2646- GL_FLOAT,
2647- GL_FALSE,
2648- sizeof(TerrainProgram::PerVertexData),
2649- reinterpret_cast<void*>(offset));
2650- };
2651- set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
2652- set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
2653- set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
2654- set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
2655+ Gl::vertex_attrib_pointer(
2656+ attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
2657+ Gl::vertex_attrib_pointer(attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
2658+ Gl::vertex_attrib_pointer(
2659+ attr_texture_offset_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_offset_x));
2660+ Gl::vertex_attrib_pointer(
2661+ attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
2662
2663 glBindBuffer(GL_ARRAY_BUFFER, 0);
2664
2665 glActiveTexture(GL_TEXTURE0);
2666 glBindTexture(GL_TEXTURE_2D, gl_texture);
2667
2668+ glUniform1f(u_z_value_, z_value);
2669 glUniform1i(u_terrain_texture_, 0);
2670 glUniform2f(u_texture_dimensions_, texture_w, texture_h);
2671
2672@@ -146,7 +154,8 @@
2673
2674 void TerrainProgram::draw(uint32_t gametime,
2675 const DescriptionMaintainer<TerrainDescription>& terrains,
2676- const FieldsToDraw& fields_to_draw) {
2677+ const FieldsToDraw& fields_to_draw,
2678+ float z_value) {
2679 // This method expects that all terrains have the same dimensions and that
2680 // all are packed into the same texture atlas, i.e. all are in the same GL
2681 // texture. It does not check for this invariance for speeds sake.
2682@@ -170,7 +179,7 @@
2683 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
2684 if (bln_index != -1) {
2685 const FloatPoint texture_offset =
2686- terrains.get(field.ter_d).get_texture(gametime).texture_coordinates().top_left();
2687+ to_gl_texture(terrains.get(field.ter_d).get_texture(gametime).blit_data()).origin();
2688 add_vertex(fields_to_draw.at(current_index), texture_offset);
2689 add_vertex(fields_to_draw.at(bln_index), texture_offset);
2690 add_vertex(fields_to_draw.at(brn_index), texture_offset);
2691@@ -180,13 +189,17 @@
2692 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
2693 if (rn_index != -1) {
2694 const FloatPoint texture_offset =
2695- terrains.get(field.ter_r).get_texture(gametime).texture_coordinates().top_left();
2696+ to_gl_texture(terrains.get(field.ter_r).get_texture(gametime).blit_data()).origin();
2697 add_vertex(fields_to_draw.at(current_index), texture_offset);
2698 add_vertex(fields_to_draw.at(brn_index), texture_offset);
2699 add_vertex(fields_to_draw.at(rn_index), texture_offset);
2700 }
2701 }
2702
2703- const Texture& texture = terrains.get(0).get_texture(0);
2704- gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
2705+ const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
2706+ const FloatRect texture_coordinates = to_gl_texture(blit_data);
2707+ gl_draw(blit_data.texture_id,
2708+ texture_coordinates.w,
2709+ texture_coordinates.h,
2710+ z_value);
2711 }
2712
2713=== modified file 'src/graphic/gl/terrain_program.h'
2714--- src/graphic/gl/terrain_program.h 2015-03-01 09:21:20 +0000
2715+++ src/graphic/gl/terrain_program.h 2016-01-05 11:29:18 +0000
2716@@ -35,8 +35,10 @@
2717 TerrainProgram();
2718
2719 // Draws the terrain.
2720- void draw(uint32_t gametime, const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
2721- const FieldsToDraw& fields_to_draw);
2722+ void draw(uint32_t gametime,
2723+ const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
2724+ const FieldsToDraw& fields_to_draw,
2725+ float z_value);
2726
2727 private:
2728 struct PerVertexData {
2729@@ -50,7 +52,7 @@
2730 };
2731 static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
2732
2733- void gl_draw(int gl_texture, float texture_w, float texture_h);
2734+ void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
2735
2736 // Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
2737 void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
2738@@ -59,7 +61,7 @@
2739 Gl::Program gl_program_;
2740
2741 // The buffer that will contain 'vertices_' for rendering.
2742- Gl::Buffer gl_array_buffer_;
2743+ Gl::Buffer<PerVertexData> gl_array_buffer_;
2744
2745 // Attributes.
2746 GLint attr_brightness_;
2747@@ -70,6 +72,7 @@
2748 // Uniforms.
2749 GLint u_terrain_texture_;
2750 GLint u_texture_dimensions_;
2751+ GLint u_z_value_;
2752
2753 // Objects below are kept around to avoid memory allocations on each frame.
2754 // They could theoretically also be recreated.
2755
2756=== modified file 'src/graphic/gl/utils.cc'
2757--- src/graphic/gl/utils.cc 2014-09-27 18:53:55 +0000
2758+++ src/graphic/gl/utils.cc 2016-01-05 11:29:18 +0000
2759@@ -21,8 +21,6 @@
2760 #include <memory>
2761 #include <string>
2762
2763-#include <SDL_video.h>
2764-
2765 #include "base/log.h"
2766 #include "base/wexception.h"
2767
2768@@ -41,40 +39,8 @@
2769 return "unknown";
2770 }
2771
2772-// Creates one OpenGL buffer.
2773-GLuint create_buffer() {
2774- GLuint buffer = 0;
2775- glGenBuffers(1, &buffer);
2776- return buffer;
2777-}
2778-
2779 } // namespace
2780
2781-/**
2782- * \return the standard 32-bit RGBA format that we use in OpenGL
2783- */
2784-const SDL_PixelFormat & gl_rgba_format()
2785-{
2786- static SDL_PixelFormat format;
2787- static bool init = false;
2788- if (init)
2789- return format;
2790-
2791- init = true;
2792- memset(&format, 0, sizeof(format));
2793- format.BitsPerPixel = 32;
2794- format.BytesPerPixel = 4;
2795- format.Rmask = 0x000000ff;
2796- format.Gmask = 0x0000ff00;
2797- format.Bmask = 0x00ff0000;
2798- format.Amask = 0xff000000;
2799- format.Rshift = 0;
2800- format.Gshift = 8;
2801- format.Bshift = 16;
2802- format.Ashift = 24;
2803- return format;
2804-}
2805-
2806 GLenum _handle_glerror(const char * file, unsigned int line)
2807 {
2808 GLenum err = glGetError();
2809@@ -162,18 +128,6 @@
2810 }
2811 }
2812
2813-Buffer::Buffer() : buffer_object_(create_buffer()) {
2814- if (!buffer_object_) {
2815- throw wexception("Could not create GL program.");
2816- }
2817-}
2818-
2819-Buffer::~Buffer() {
2820- if (buffer_object_) {
2821- glDeleteBuffers(1, &buffer_object_);
2822- }
2823-}
2824-
2825 Program::Program() : program_object_(glCreateProgram()) {
2826 if (!program_object_) {
2827 throw wexception("Could not create GL program.");
2828@@ -212,4 +166,21 @@
2829 }
2830 }
2831
2832+void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset) {
2833+ glVertexAttribPointer(
2834+ vertex_index, num_items, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<void*>(offset));
2835+}
2836+
2837+void swap_rows(const int width, const int height, const int pitch, const int bpp, uint8_t* pixels) {
2838+ uint8_t* begin_row = pixels;
2839+ uint8_t* end_row = pixels + pitch * (height - 1);
2840+ while (begin_row < end_row) {
2841+ for (int x = 0; x < width * bpp; ++x) {
2842+ std::swap(begin_row[x], end_row[x]);
2843+ }
2844+ begin_row += pitch;
2845+ end_row -= pitch;
2846+ }
2847+}
2848+
2849 } // namespace Gl
2850
2851=== modified file 'src/graphic/gl/utils.h'
2852--- src/graphic/gl/utils.h 2014-11-08 13:59:33 +0000
2853+++ src/graphic/gl/utils.h 2016-01-05 11:29:18 +0000
2854@@ -20,19 +20,19 @@
2855 #define WL_GRAPHIC_GL_UTILS_H
2856
2857 #include <memory>
2858+#include <vector>
2859
2860 #include <stdint.h>
2861
2862+#include "base/log.h"
2863 #include "base/macros.h"
2864+#include "base/wexception.h"
2865 #include "graphic/gl/system_headers.h"
2866
2867-struct SDL_PixelFormat;
2868-
2869 namespace Gl {
2870
2871 class Shader;
2872
2873-const SDL_PixelFormat & gl_rgba_format();
2874 GLenum _handle_glerror(const char * file, unsigned int line);
2875
2876 // Thin wrapper around a OpenGL program object to ensure proper cleanup. Throws
2877@@ -59,22 +59,54 @@
2878 };
2879
2880 // Thin wrapper around a OpenGL buffer object to ensure proper cleanup. Throws
2881-// on all errors.
2882+// on all errors. Also grows the server memory only when needed.
2883+template<typename T>
2884 class Buffer {
2885 public:
2886- Buffer();
2887- ~Buffer();
2888-
2889- GLuint object() const {
2890- return buffer_object_;
2891+ Buffer() : buffer_size_(0) {
2892+ glGenBuffers(1, &object_);
2893+ if (!object_) {
2894+ throw wexception("Could not create GL program.");
2895+ }
2896+ }
2897+
2898+ ~Buffer() {
2899+ if (object_) {
2900+ glDeleteBuffers(1, &object_);
2901+ }
2902+ }
2903+
2904+ // Calls glBindBuffer on the underlying buffer data.
2905+ void bind() const {
2906+ glBindBuffer(GL_ARRAY_BUFFER, object_);
2907+ }
2908+
2909+
2910+ // Copies 'elements' into the buffer. If the buffer is too small to hold the
2911+ // data, it is reallocated. Does not check if the buffer is already bound.
2912+ void update(const std::vector<T>& items) {
2913+ if (buffer_size_ < items.size()) {
2914+ glBufferData(GL_ARRAY_BUFFER, items.size() * sizeof(T), items.data(), GL_DYNAMIC_DRAW);
2915+ buffer_size_ = items.size();
2916+ } else {
2917+ glBufferSubData(GL_ARRAY_BUFFER, 0, items.size() * sizeof(T), items.data());
2918+ }
2919 }
2920
2921 private:
2922- const GLuint buffer_object_;
2923+ GLuint object_;
2924+ size_t buffer_size_; // In number of elements.
2925
2926 DISALLOW_COPY_AND_ASSIGN(Buffer);
2927 };
2928
2929+// Calls glVertexAttribPointer.
2930+void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset);
2931+
2932+// Swap order of rows in m_pixels, to compensate for the upside-down nature of the
2933+// OpenGL coordinate system.
2934+void swap_rows(int width, int height, int pitch, int bpp, uint8_t* pixels);
2935+
2936 } // namespace Gl
2937
2938 /**
2939
2940=== modified file 'src/graphic/graphic.cc'
2941--- src/graphic/graphic.cc 2014-12-27 09:59:12 +0000
2942+++ src/graphic/graphic.cc 2016-01-05 11:29:18 +0000
2943@@ -29,6 +29,7 @@
2944 #include "graphic/gl/system_headers.h"
2945 #include "graphic/image.h"
2946 #include "graphic/image_io.h"
2947+#include "graphic/render_queue.h"
2948 #include "graphic/rendertarget.h"
2949 #include "graphic/screen.h"
2950 #include "graphic/texture.h"
2951@@ -70,6 +71,7 @@
2952 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
2953 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
2954 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
2955+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
2956
2957 log("Graphics: Try to set Videomode %ux%u\n", m_window_mode_width, m_window_mode_height);
2958 m_sdl_window = SDL_CreateWindow("Widelands Window",
2959@@ -111,12 +113,11 @@
2960 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glInt);
2961 log("Graphics: OpenGL: Max texture size: %u\n", glInt);
2962
2963- SDL_GL_SetSwapInterval(1);
2964-
2965 glDrawBuffer(GL_BACK);
2966
2967- glDisable(GL_DEPTH_TEST);
2968- glEnable(GL_TEXTURE_2D);
2969+ glEnable(GL_DEPTH_TEST);
2970+ glDepthFunc(GL_LEQUAL);
2971+
2972 glEnable(GL_BLEND);
2973 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2974
2975@@ -244,9 +245,8 @@
2976 /**
2977 * Returns true if parts of the screen have been marked for refreshing.
2978 */
2979-bool Graphic::need_update() const
2980-{
2981- return m_update;
2982+bool Graphic::need_update() const {
2983+ return m_update;
2984 }
2985
2986 /**
2987@@ -256,6 +256,8 @@
2988 */
2989 void Graphic::refresh()
2990 {
2991+ RenderQueue::instance().draw(screen_->width(), screen_->height());
2992+
2993 // Setting the window size immediately after going out of fullscreen does
2994 // not work properly. We work around this issue by resizing the window in
2995 // refresh() when in window mode.
2996
2997=== modified file 'src/graphic/image.h'
2998--- src/graphic/image.h 2014-12-08 05:22:52 +0000
2999+++ src/graphic/image.h 2016-01-05 11:29:18 +0000
3000@@ -26,6 +26,7 @@
3001
3002 #include "base/macros.h"
3003 #include "base/rect.h"
3004+#include "graphic/gl/blit_data.h"
3005
3006 class Texture;
3007
3008@@ -35,6 +36,7 @@
3009 */
3010 class Image {
3011 public:
3012+
3013 Image() = default;
3014 virtual ~Image() {}
3015
3016@@ -45,8 +47,7 @@
3017 // OpenGL texture and texture coordinates backing this Image. This can
3018 // change at any time, so do not hold one to this value for more than one
3019 // frame.
3020- virtual int get_gl_texture() const = 0;
3021- virtual const FloatRect& texture_coordinates() const = 0;
3022+ virtual const BlitData& blit_data() const = 0;
3023
3024 private:
3025 DISALLOW_COPY_AND_ASSIGN(Image);
3026
3027=== modified file 'src/graphic/image_cache.cc'
3028--- src/graphic/image_cache.cc 2014-12-07 20:52:55 +0000
3029+++ src/graphic/image_cache.cc 2016-01-05 11:29:18 +0000
3030@@ -21,13 +21,44 @@
3031
3032 #include <cassert>
3033 #include <memory>
3034+#include <set>
3035 #include <string>
3036
3037-#include "base/log.h"
3038+#include <SDL.h>
3039+#include <boost/format.hpp>
3040+
3041 #include "graphic/image.h"
3042 #include "graphic/image_io.h"
3043 #include "graphic/texture.h"
3044
3045+namespace {
3046+
3047+constexpr int kBiggestAreaForCompactification = 250 * 250;
3048+
3049+} // namespace
3050+ImageCache::ProxyImage::ProxyImage(std::unique_ptr<const Image> image) : image_(std::move(image)) {
3051+}
3052+
3053+const Image& ImageCache::ProxyImage::image() {
3054+ return *image_;
3055+}
3056+
3057+void ImageCache::ProxyImage::set_image(std::unique_ptr<const Image> image) {
3058+ image_ = std::move(image);
3059+}
3060+
3061+int ImageCache::ProxyImage::width() const {
3062+ return image_->width();
3063+}
3064+
3065+int ImageCache::ProxyImage::height() const {
3066+ return image_->height();
3067+}
3068+
3069+const BlitData& ImageCache::ProxyImage::blit_data() const {
3070+ return image_->blit_data();
3071+}
3072+
3073 ImageCache::ImageCache() {
3074 }
3075
3076@@ -41,15 +72,43 @@
3077 const Image* ImageCache::insert(const std::string& hash, std::unique_ptr<const Image> image) {
3078 assert(!has(hash));
3079 const Image* return_value = image.get();
3080- images_.insert(make_pair(hash, std::move(image)));
3081+ images_.insert(make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(std::move(image)))));
3082 return return_value;
3083 }
3084
3085 const Image* ImageCache::get(const std::string& hash) {
3086 ImageMap::const_iterator it = images_.find(hash);
3087 if (it == images_.end()) {
3088- images_.insert(make_pair(hash, load_image(hash)));
3089+ images_.insert(
3090+ make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(load_image(hash)))));
3091 return get(hash);
3092 }
3093 return it->second.get();
3094 }
3095+
3096+void ImageCache::compactify() {
3097+ TextureAtlas texture_atlas;
3098+
3099+ std::vector<std::string> hashes;
3100+ for (const auto& pair : images_) {
3101+ const auto& image = pair.second->image();
3102+ if (image.width() * image.height() > kBiggestAreaForCompactification) {
3103+ continue;
3104+ }
3105+
3106+ texture_atlas.add(image);
3107+ hashes.push_back(pair.first);
3108+ }
3109+
3110+ std::vector<std::unique_ptr<Texture>> new_textures;
3111+
3112+ // TODO(sirver): Limit the size of the texture atlas to a max GL texture
3113+ // size. This might return more than one packed image. Make sure that the
3114+ // code works also for small max texture sizes.
3115+ texture_atlases_.emplace_back(texture_atlas.pack(&new_textures));
3116+
3117+ assert(new_textures.size() == hashes.size());
3118+ for (size_t i = 0; i < hashes.size(); ++i) {
3119+ images_[hashes[i]]->set_image(std::move(new_textures[i]));
3120+ }
3121+}
3122
3123=== modified file 'src/graphic/image_cache.h'
3124--- src/graphic/image_cache.h 2014-12-07 15:41:39 +0000
3125+++ src/graphic/image_cache.h 2016-01-05 11:29:18 +0000
3126@@ -23,11 +23,13 @@
3127 #include <map>
3128 #include <memory>
3129 #include <string>
3130+#include <vector>
3131
3132 #include <boost/utility.hpp>
3133
3134 #include "base/macros.h"
3135 #include "graphic/image.h"
3136+#include "graphic/texture_atlas.h"
3137
3138 // For historic reasons, most part of the Widelands code base expect that an
3139 // Image stays valid for the whole duration of the program run. This class is
3140@@ -53,9 +55,32 @@
3141 // Returns true if the given hash is stored in the cache.
3142 bool has(const std::string& hash) const;
3143
3144+ // For debug only: Takes all images that are in the ImageCache right now and
3145+ // puts them into one huge texture atlas.
3146+ void compactify();
3147+
3148 private:
3149- using ImageMap = std::map<std::string, std::unique_ptr<const Image>>;
3150-
3151+ // We return a wrapped Image so that we can swap out the pointer to the
3152+ // image under our user. This can happen when we move an Image from a stand
3153+ // alone texture into being a subrect of a texture atlas.
3154+ class ProxyImage : public Image {
3155+ public:
3156+ ProxyImage(std::unique_ptr<const Image> image);
3157+
3158+ const Image& image();
3159+ void set_image(std::unique_ptr<const Image> image);
3160+
3161+ int width() const override;
3162+ int height() const override;
3163+ const BlitData& blit_data() const override;
3164+
3165+ private:
3166+ std::unique_ptr<const Image> image_;
3167+ };
3168+
3169+ using ImageMap = std::map<std::string, std::unique_ptr<ProxyImage>>;
3170+
3171+ std::vector<std::unique_ptr<Texture>> texture_atlases_;
3172 ImageMap images_; /// hash of cached filename/image pairs
3173
3174 DISALLOW_COPY_AND_ASSIGN(ImageCache);
3175
3176=== modified file 'src/graphic/image_io.cc'
3177--- src/graphic/image_io.cc 2014-12-07 21:34:11 +0000
3178+++ src/graphic/image_io.cc 2016-01-05 11:29:18 +0000
3179@@ -25,6 +25,7 @@
3180 #include <SDL_image.h>
3181 #include <png.h>
3182
3183+#include "base/log.h"
3184 #include "base/wexception.h"
3185 #include "graphic/texture.h"
3186 #include "io/fileread.h"
3187@@ -130,7 +131,6 @@
3188 std::unique_ptr<png_byte[]> row(new png_byte[row_size]);
3189
3190 // Write each row
3191- const SDL_PixelFormat& fmt = texture->format();
3192 texture->lock();
3193
3194 // Write each row
3195@@ -138,7 +138,7 @@
3196 if (color_type == ColorType::RGB) {
3197 for (uint32_t y = 0; y < surf_h; ++y) {
3198 for (uint32_t x = 0; x < surf_w; ++x) {
3199- color.set(fmt, texture->get_pixel(x, y));
3200+ color = texture->get_pixel(x, y);
3201 row[3 * x] = color.r;
3202 row[3 * x + 1] = color.g;
3203 row[3 * x + 2] = color.b;
3204@@ -148,7 +148,7 @@
3205 } else {
3206 for (uint32_t y = 0; y < surf_h; ++y) {
3207 for (uint32_t x = 0; x < surf_w; ++x) {
3208- color.set(fmt, texture->get_pixel(x, y));
3209+ color = texture->get_pixel(x, y);
3210 row[4 * x] = color.r;
3211 row[4 * x + 1] = color.g;
3212 row[4 * x + 2] = color.b;
3213
3214=== added file 'src/graphic/make_texture_atlas_main.cc'
3215--- src/graphic/make_texture_atlas_main.cc 1970-01-01 00:00:00 +0000
3216+++ src/graphic/make_texture_atlas_main.cc 2016-01-05 11:29:18 +0000
3217@@ -0,0 +1,101 @@
3218+/*
3219+ * Copyright (C) 2006-2015 by the Widelands Development Team
3220+ *
3221+ * This program is free software; you can redistribute it and/or
3222+ * modify it under the terms of the GNU General Public License
3223+ * as published by the Free Software Foundation; either version 2
3224+ * of the License, or (at your option) any later version.
3225+ *
3226+ * This program is distributed in the hope that it will be useful,
3227+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3228+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3229+ * GNU General Public License for more details.
3230+ *
3231+ * You should have received a copy of the GNU General Public License
3232+ * along with this program; if not, write to the Free Software
3233+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3234+ *
3235+ */
3236+
3237+#include <fstream>
3238+#include <iostream>
3239+#include <memory>
3240+#include <set>
3241+#include <string>
3242+#include <vector>
3243+
3244+#include <SDL.h>
3245+#include <boost/algorithm/string/predicate.hpp>
3246+
3247+#undef main // No, we do not want SDL_main
3248+
3249+#include "base/log.h"
3250+#include "config.h"
3251+#include "graphic/graphic.h"
3252+#include "graphic/image_io.h"
3253+#include "graphic/texture_atlas.h"
3254+#include "helper.h"
3255+#include "io/filesystem/filesystem.h"
3256+#include "io/filesystem/layered_filesystem.h"
3257+#include "io/streamwrite.h"
3258+
3259+namespace {
3260+
3261+int parse_arguments(
3262+ int argc, char** argv, std::string* input_directory)
3263+{
3264+ if (argc < 2) {
3265+ std::cout << "Usage: wl_make_texture_atlas <input directory>" << std::endl << std::endl
3266+ << "Will write output.png in the current directory." << std::endl;
3267+ return 1;
3268+ }
3269+ *input_directory = argv[1];
3270+ return 0;
3271+}
3272+
3273+// Setup the static objects Widelands needs to operate and initializes systems.
3274+void initialize() {
3275+ SDL_Init(SDL_INIT_VIDEO);
3276+
3277+ g_fs = new LayeredFileSystem();
3278+ g_fs->add_file_system(&FileSystem::create(INSTALL_DATADIR));
3279+ g_gr = new Graphic(1, 1, false);
3280+}
3281+
3282+} // namespace
3283+
3284+int main(int argc, char** argv) {
3285+ std::string input_directory;
3286+ if (parse_arguments(argc, argv, &input_directory))
3287+ return 1;
3288+
3289+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
3290+ std::cerr << "SDLInit did not succeed: " << SDL_GetError() << std::endl;
3291+ return 1;
3292+ }
3293+ initialize();
3294+
3295+ std::vector<std::unique_ptr<Texture>> images;
3296+ std::unique_ptr<FileSystem> input_fs(&FileSystem::create(input_directory));
3297+ std::vector<std::string> png_filenames;
3298+ for (const std::string& filename : input_fs->list_directory("")) {
3299+ if (boost::ends_with(filename, ".png")) {
3300+ png_filenames.push_back(filename);
3301+ images.emplace_back(load_image(filename, input_fs.get()));
3302+ }
3303+ }
3304+
3305+ TextureAtlas atlas;
3306+ for (auto& image : images) {
3307+ atlas.add(*image);
3308+ }
3309+ std::vector<std::unique_ptr<Texture>> new_textures;
3310+ auto packed_texture = atlas.pack(&new_textures);
3311+
3312+ std::unique_ptr<FileSystem> output_fs(&FileSystem::create("."));
3313+ std::unique_ptr<StreamWrite> sw(output_fs->open_stream_write("output.png"));
3314+ save_to_png(packed_texture.get(), sw.get(), ColorType::RGBA);
3315+
3316+ SDL_Quit();
3317+ return 0;
3318+}
3319
3320=== modified file 'src/graphic/minimap_renderer.cc'
3321--- src/graphic/minimap_renderer.cc 2014-12-07 21:34:11 +0000
3322+++ src/graphic/minimap_renderer.cc 2016-01-05 11:29:18 +0000
3323@@ -38,68 +38,49 @@
3324
3325 namespace {
3326
3327+const RGBColor kWhite(255, 255, 255);
3328+
3329 // Blend two colors.
3330-inline uint32_t blend_color
3331- (const SDL_PixelFormat& format, uint32_t clr1, uint8_t r2, uint8_t g2, uint8_t b2)
3332-{
3333- uint8_t r1, g1, b1;
3334- SDL_GetRGB(clr1, &const_cast<SDL_PixelFormat &>(format), &r1, &g1, &b1);
3335- return
3336- SDL_MapRGB
3337- (&const_cast<SDL_PixelFormat &>(format), (r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2);
3338+inline RGBColor blend_color(const RGBColor& c1, const RGBColor& c2) {
3339+ return RGBColor((c1.r + c2.r) / 2, (c1.g + c2.g) / 2, (c1.b + c2.b) / 2);
3340 }
3341
3342 // Returns the color to be used in the minimap for the given field.
3343-inline uint32_t calc_minimap_color
3344- (const SDL_PixelFormat& format, const Widelands::EditorGameBase& egbase,
3345- const Widelands::FCoords& f, MiniMapLayer layers, Widelands::PlayerNumber owner,
3346- bool see_details)
3347-{
3348- uint32_t pixelcolor = 0;
3349-
3350+inline RGBColor calc_minimap_color(const Widelands::EditorGameBase& egbase,
3351+ const Widelands::FCoords& f,
3352+ MiniMapLayer layers,
3353+ Widelands::PlayerNumber owner,
3354+ bool see_details) {
3355+ RGBColor color;
3356 if (layers & MiniMapLayer::Terrain) {
3357- const RGBColor& color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
3358+ color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
3359 f.field->get_brightness());
3360-
3361- pixelcolor = SDL_MapRGBA(&format, color.r, color.g, color.b, 255);
3362 }
3363
3364 if (layers & MiniMapLayer::Owner) {
3365- if (0 < owner) { // If owned, get the player's color...
3366- const RGBColor & player_color = egbase.player(owner).get_playercolor();
3367-
3368- // ...and add the player's color to the old color.
3369- pixelcolor = blend_color
3370- (format,
3371- pixelcolor,
3372- player_color.r, player_color.g, player_color.b);
3373+ if (0 < owner) {
3374+ color = blend_color(color, egbase.player(owner).get_playercolor());
3375 }
3376 }
3377
3378 if (see_details) {
3379 // if ownership layer is displayed, it creates enough contrast to
3380 // visualize objects using white color.
3381- // Otherwise, a more contrasting color may be needed:
3382- // * winterland -> orange
3383
3384 if (upcast(PlayerImmovable const, immovable, f.field->get_immovable())) {
3385 if ((layers & MiniMapLayer::Road) && dynamic_cast<Road const *>(immovable)) {
3386- pixelcolor = blend_color(format, pixelcolor, 255, 255, 255);
3387+ color = blend_color(color, kWhite);
3388 }
3389
3390- if
3391- (((layers & MiniMapLayer::Flag) && dynamic_cast<Flag const *>(immovable))
3392- ||
3393- ((layers & MiniMapLayer::Building)
3394- &&
3395- dynamic_cast<Widelands::Building const *>(immovable)))
3396- {
3397- pixelcolor = SDL_MapRGB(&const_cast<SDL_PixelFormat&>(format), 255, 255, 255);
3398+ if (((layers & MiniMapLayer::Flag) && dynamic_cast<Flag const*>(immovable)) ||
3399+ ((layers & MiniMapLayer::Building) &&
3400+ dynamic_cast<Widelands::Building const*>(immovable))) {
3401+ color = kWhite;
3402 }
3403 }
3404 }
3405
3406- return pixelcolor;
3407+ return color;
3408 }
3409
3410 // Draws the dotted frame border onto the minimap.
3411@@ -149,15 +130,13 @@
3412 }
3413
3414 // Does the actual work of drawing the minimap.
3415-void draw_minimap_int
3416- (Texture* texture, const Widelands::EditorGameBase& egbase,
3417- const Widelands::Player* player, const Point& viewpoint, MiniMapLayer layers)
3418-{
3419- const Widelands::Map & map = egbase.map();
3420+void draw_minimap_int(Texture* texture,
3421+ const Widelands::EditorGameBase& egbase,
3422+ const Widelands::Player* player,
3423+ const Point& viewpoint,
3424+ MiniMapLayer layers) {
3425+ const Widelands::Map& map = egbase.map();
3426
3427- uint8_t* const pixels = texture->get_pixels();
3428- const SDL_PixelFormat& format = texture->format();
3429- const uint16_t pitch = texture->get_pitch();
3430 const uint16_t surface_h = texture->height();
3431 const uint16_t surface_w = texture->width();
3432
3433@@ -168,90 +147,69 @@
3434 const int32_t mapwidth = egbase.get_map().get_width();
3435 const int32_t mapheight = map.get_height();
3436
3437- Point ptopleft; // top left point of the current display frame
3438+ Point ptopleft; // top left point of the current display frame
3439 ptopleft.x = viewpoint.x + mapwidth / 2 - xsize;
3440- if (ptopleft.x < 0) ptopleft.x += mapwidth;
3441+ if (ptopleft.x < 0) {
3442+ ptopleft.x += mapwidth;
3443+ }
3444 ptopleft.y = viewpoint.y + mapheight / 2 - ysize;
3445- if (ptopleft.y < 0) ptopleft.y += mapheight;
3446+ if (ptopleft.y < 0) {
3447+ ptopleft.y += mapheight;
3448+ }
3449
3450- Point pbottomright; // bottom right point of the current display frame
3451+ Point pbottomright; // bottom right point of the current display frame
3452 pbottomright.x = viewpoint.x + mapwidth / 2 + xsize;
3453- if (pbottomright.x >= mapwidth) pbottomright.x -= mapwidth;
3454+ if (pbottomright.x >= mapwidth) {
3455+ pbottomright.x -= mapwidth;
3456+ }
3457 pbottomright.y = viewpoint.y + mapheight / 2 + ysize;
3458- if (pbottomright.y >= mapheight) pbottomright.y -= mapheight;
3459+ if (pbottomright.y >= mapheight) {
3460+ pbottomright.y -= mapheight;
3461+ }
3462
3463 uint32_t modx = pbottomright.x % 2;
3464 uint32_t mody = pbottomright.y % 2;
3465
3466- if (!player || player->see_all()) {
3467- for (uint32_t y = 0; y < surface_h; ++y) {
3468- uint8_t * pix = pixels + y * pitch;
3469- Widelands::FCoords f
3470- (Widelands::Coords
3471- (viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
3472- map.normalize_coords(f);
3473- f.field = &map[f];
3474- Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
3475- for (uint32_t x = 0; x < surface_w; ++x, pix += sizeof(uint32_t)) {
3476- if (x % 2 || !(layers & MiniMapLayer::Zoom2))
3477- move_r(mapwidth, f, i);
3478-
3479- if ((layers & MiniMapLayer::ViewWindow) &&
3480- is_minimap_frameborder(
3481- f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
3482- *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
3483- (SDL_MapRGB(&const_cast<SDL_PixelFormat &>(format), 255, 0, 0));
3484- } else {
3485- *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
3486- (calc_minimap_color
3487- (format, egbase, f, layers, f.field->get_owned_by(), true));
3488- }
3489- }
3490- }
3491- } else {
3492- Widelands::Player::Field const * const player_fields = player->fields();
3493- for (uint32_t y = 0; y < surface_h; ++y) {
3494- uint8_t * pix = pixels + y * pitch;
3495- Widelands::FCoords f
3496- (Widelands::Coords
3497- (viewpoint.x, viewpoint.y +
3498- (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
3499- map.normalize_coords(f);
3500- f.field = &map[f];
3501- Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
3502- for (uint32_t x = 0; x < surface_w; ++x, pix += sizeof(uint32_t)) {
3503- if (x % 2 || !(layers & MiniMapLayer::Zoom2))
3504- move_r(mapwidth, f, i);
3505-
3506- if ((layers & MiniMapLayer::ViewWindow) &&
3507- is_minimap_frameborder(
3508- f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
3509- *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
3510- (SDL_MapRGB
3511- (&const_cast<SDL_PixelFormat &>(format), 255, 0, 0));
3512- } else {
3513- const Widelands::Player::Field & player_field = player_fields[i];
3514- Widelands::Vision const vision = player_field.vision;
3515-
3516- *reinterpret_cast<uint32_t *>(pix) =
3517- static_cast<uint32_t>
3518- (vision ?
3519- calc_minimap_color
3520- (format,
3521- egbase,
3522- f,
3523- layers,
3524- player_field.owner,
3525- 1 < vision)
3526- :
3527- SDL_MapRGB(&const_cast<SDL_PixelFormat &>(format), 0, 0, 0));
3528- }
3529+ for (uint32_t y = 0; y < surface_h; ++y) {
3530+ Widelands::FCoords f(
3531+ Widelands::Coords(viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
3532+ map.normalize_coords(f);
3533+ f.field = &map[f];
3534+ Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
3535+ for (uint32_t x = 0; x < surface_w; ++x) {
3536+ if (x % 2 || !(layers & MiniMapLayer::Zoom2)) {
3537+ move_r(mapwidth, f, i);
3538+ }
3539+
3540+ RGBColor pixel_color;
3541+ if ((layers & MiniMapLayer::ViewWindow) &&
3542+ is_minimap_frameborder(f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
3543+ pixel_color = RGBColor(255, 0, 0);
3544+ } else {
3545+ uint16_t vision =
3546+ 0; // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
3547+ Widelands::PlayerNumber owner = 0;
3548+ if (player == nullptr || player->see_all()) {
3549+ vision = 2; // Seen right now.
3550+ owner = f.field->get_owned_by();
3551+ } else if (player != nullptr) {
3552+ const auto& field = player->fields()[i];
3553+ vision = field.vision;
3554+ owner = field.owner;
3555+ }
3556+
3557+ if (vision > 0) {
3558+ pixel_color = calc_minimap_color(egbase, f, layers, owner, vision > 1);
3559+ }
3560+ }
3561+
3562+ if (pixel_color.r != 0 || pixel_color.g != 0 || pixel_color.b != 0) {
3563+ texture->set_pixel(x, y, pixel_color);
3564 }
3565 }
3566 }
3567 }
3568
3569-
3570 } // namespace
3571
3572 std::unique_ptr<Texture> draw_minimap(const EditorGameBase& egbase,
3573@@ -265,17 +223,15 @@
3574 const int16_t map_w = (layers & MiniMapLayer::Zoom2) ? map.get_width() * 2 : map.get_width();
3575 const int16_t map_h = (layers & MiniMapLayer::Zoom2) ? map.get_height() * 2 : map.get_height();
3576
3577- Texture* texture = new Texture(map_w, map_h);
3578- assert(texture->format().BytesPerPixel == sizeof(uint32_t));
3579-
3580- fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255), texture);
3581+ std::unique_ptr<Texture> texture(new Texture(map_w, map_h));
3582+
3583+ texture->fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
3584+
3585 texture->lock();
3586-
3587- draw_minimap_int(texture, egbase, player, viewpoint, layers);
3588-
3589+ draw_minimap_int(texture.get(), egbase, player, viewpoint, layers);
3590 texture->unlock(Texture::Unlock_Update);
3591
3592- return std::unique_ptr<Texture>(texture);
3593+ return texture;
3594 }
3595
3596 void write_minimap_image
3597@@ -293,11 +249,13 @@
3598 const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(egbase.get_map());
3599 // adjust the viewpoint top topleft in map coords
3600 viewpoint.x += g_gr->get_xres() / 2;
3601- if (viewpoint.x >= maxx)
3602+ if (viewpoint.x >= maxx) {
3603 viewpoint.x -= maxx;
3604+ }
3605 viewpoint.y += g_gr->get_yres() / 2;
3606- if (viewpoint.y >= maxy)
3607+ if (viewpoint.y >= maxy) {
3608 viewpoint.y -= maxy;
3609+ }
3610 viewpoint.x /= TRIANGLE_WIDTH;
3611 viewpoint.y /= TRIANGLE_HEIGHT;
3612 viewpoint.x -= map_w / 2;
3613
3614=== added file 'src/graphic/render_queue.cc'
3615--- src/graphic/render_queue.cc 1970-01-01 00:00:00 +0000
3616+++ src/graphic/render_queue.cc 2016-01-05 11:29:18 +0000
3617@@ -0,0 +1,299 @@
3618+/*
3619+ * Copyright (C) 2006-2014 by the Widelands Development Team
3620+ *
3621+ * This program is free software; you can redistribute it and/or
3622+ * modify it under the terms of the GNU General Public License
3623+ * as published by the Free Software Foundation; either version 2
3624+ * of the License, or (at your option) any later version.
3625+ *
3626+ * This program is distributed in the hope that it will be useful,
3627+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3628+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3629+ * GNU General Public License for more details.
3630+ *
3631+ * You should have received a copy of the GNU General Public License
3632+ * along with this program; if not, write to the Free Software
3633+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3634+ *
3635+ */
3636+
3637+#include "graphic/render_queue.h"
3638+
3639+#include <algorithm>
3640+#include <limits>
3641+
3642+#include "base/log.h"
3643+#include "base/rect.h"
3644+#include "base/wexception.h"
3645+#include "graphic/gl/blit_program.h"
3646+#include "graphic/gl/dither_program.h"
3647+#include "graphic/gl/draw_line_program.h"
3648+#include "graphic/gl/fill_rect_program.h"
3649+#include "graphic/gl/road_program.h"
3650+#include "graphic/gl/terrain_program.h"
3651+
3652+namespace {
3653+
3654+constexpr int kMaximumZValue = std::numeric_limits<uint16_t>::max();
3655+constexpr float kOpenGlZDelta = -2.f / kMaximumZValue;
3656+
3657+// Maps [0, kMaximumZValue] linearly to [1., -1.] for use in vertex shaders.
3658+inline float to_opengl_z(const int z) {
3659+ return -(2.f * z) / kMaximumZValue + 1.f;
3660+}
3661+
3662+// The key defines in which order we render things.
3663+//
3664+// For opaque objects, render order makes no difference in the final image, but
3665+// - we batch up by program to have maximal batching.
3666+// - and we want to render frontmost objects first, so that we do not render
3667+// any pixel more than once.
3668+static_assert(RenderQueue::Program::kHighestProgramId <= 8, "Need to change sorting keys."); // 4 bits.
3669+
3670+uint64_t
3671+make_key_opaque(const uint64_t program_id, const uint64_t z_value, const uint64_t extra_value) {
3672+ assert(program_id < RenderQueue::Program::kHighestProgramId);
3673+ assert(z_value < std::numeric_limits<uint16_t>::max());
3674+
3675+ // TODO(sirver): As a higher priority for sorting then z value, texture
3676+ // could be used here. This allows for more batching of GL calls, but in my
3677+ // tests hardly made a difference for Widelands..
3678+ uint64_t sort_z_value = std::numeric_limits<uint16_t>::max() - z_value;
3679+ // IIII0000 EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE ZZZZZZZZ ZZZZZZZZ
3680+ return (program_id << 60) | (extra_value << 16) | (sort_z_value);
3681+}
3682+
3683+// For blended objects, we need to render furthest away objects first, and we
3684+// do not update the z-buffer. This guarantees that the image is correct.
3685+// - if z value is the same, we order by program second to have potential batching.
3686+uint64_t
3687+make_key_blended(const uint64_t program_id, const uint64_t z_value, const uint64_t extra_value) {
3688+ assert(program_id < RenderQueue::Program::kHighestProgramId);
3689+ assert(z_value < std::numeric_limits<uint16_t>::max());
3690+
3691+ // Sort opaque objects increasing, alpha objects decreasing in order.
3692+ // ZZZZZZZZ ZZZZZZZZ IIII0000 EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
3693+ return (z_value << 40) | (program_id << 36) | extra_value;
3694+}
3695+
3696+// Construct 'args' used by the individual programs out of 'item'.
3697+inline void from_item(const RenderQueue::Item& item, VanillaBlitProgram::Arguments* args) {
3698+ args->texture = item.vanilla_blit_arguments.texture;
3699+ args->opacity = item.vanilla_blit_arguments.opacity;
3700+}
3701+
3702+inline void from_item(const RenderQueue::Item& item, MonochromeBlitProgram::Arguments* args) {
3703+ args->texture = item.monochrome_blit_arguments.texture;
3704+ args->blend = item.monochrome_blit_arguments.blend;
3705+}
3706+
3707+inline void from_item(const RenderQueue::Item& item, FillRectProgram::Arguments* args) {
3708+ args->color = item.rect_arguments.color;
3709+}
3710+
3711+inline void from_item(const RenderQueue::Item& item, BlendedBlitProgram::Arguments* args) {
3712+ args->texture = item.blended_blit_arguments.texture;
3713+ args->blend = item.blended_blit_arguments.blend;
3714+ args->mask = item.blended_blit_arguments.mask;
3715+}
3716+
3717+inline void from_item(const RenderQueue::Item& item, DrawLineProgram::Arguments* args) {
3718+ args->color = item.line_arguments.color;
3719+ args->line_width = item.line_arguments.line_width;
3720+}
3721+
3722+// Batches up as many items from 'items' that have the same 'program_id'.
3723+// Increases 'index' and returns an argument vector that can directly be passed
3724+// to the individual program.
3725+template <typename T>
3726+std::vector<T> batch_up(const RenderQueue::Program program_id,
3727+ const std::vector<RenderQueue::Item>& items,
3728+ size_t* index) {
3729+ std::vector<T> all_args;
3730+ while (*index < items.size()) {
3731+ const RenderQueue::Item& current_item = items.at(*index);
3732+ if (current_item.program_id != program_id) {
3733+ break;
3734+ }
3735+ all_args.emplace_back();
3736+ T& args = all_args.back();
3737+ args.destination_rect = current_item.destination_rect;
3738+ args.z_value = current_item.z_value;
3739+ args.blend_mode = current_item.blend_mode;
3740+ from_item(current_item, &args);
3741+ ++(*index);
3742+ }
3743+ return all_args;
3744+}
3745+
3746+// Calls glScissor for the given 'rect' and enables GL_SCISSOR_TEST at
3747+// creation. Disables GL_SCISSOR_TEST at desctruction again.
3748+class ScopedScissor {
3749+public:
3750+ ScopedScissor(const FloatRect& rect);
3751+ ~ScopedScissor();
3752+
3753+private:
3754+ DISALLOW_COPY_AND_ASSIGN(ScopedScissor);
3755+};
3756+
3757+ScopedScissor::ScopedScissor(const FloatRect& rect) {
3758+ glScissor(rect.x, rect.y, rect.w, rect.h);
3759+ glEnable(GL_SCISSOR_TEST);
3760+}
3761+
3762+ScopedScissor::~ScopedScissor() {
3763+ glDisable(GL_SCISSOR_TEST);
3764+}
3765+
3766+} // namespace
3767+
3768+RenderQueue::RenderQueue()
3769+ : next_z_(1),
3770+ terrain_program_(new TerrainProgram()),
3771+ dither_program_(new DitherProgram()),
3772+ road_program_(new RoadProgram()) {
3773+}
3774+
3775+// static
3776+RenderQueue& RenderQueue::instance() {
3777+ static RenderQueue render_queue;
3778+ return render_queue;
3779+}
3780+
3781+void RenderQueue::enqueue(const Item& given_item) {
3782+ Item* item;
3783+ uint32_t extra_value = 0;
3784+
3785+ switch (given_item.program_id) {
3786+ case Program::kBlit:
3787+ extra_value = given_item.vanilla_blit_arguments.texture.texture_id;
3788+ break;
3789+
3790+ case Program::kBlitMonochrome:
3791+ extra_value = given_item.monochrome_blit_arguments.texture.texture_id;
3792+ break;
3793+
3794+ case Program::kBlitBlended:
3795+ extra_value = given_item.blended_blit_arguments.texture.texture_id;
3796+ break;
3797+
3798+ case Program::kLine:
3799+ extra_value = given_item.line_arguments.line_width;
3800+ break;
3801+
3802+ case Program::kRect:
3803+ case Program::kTerrainBase:
3804+ case Program::kTerrainDither:
3805+ case Program::kTerrainRoad:
3806+ /* all fallthroughs intended */
3807+ break;
3808+
3809+ default:
3810+ throw wexception("Unknown given_item.program_id: %d", given_item.program_id);
3811+ }
3812+
3813+ if (given_item.blend_mode == BlendMode::Copy) {
3814+ opaque_items_.emplace_back(given_item);
3815+ item = &opaque_items_.back();
3816+ item->z_value = to_opengl_z(next_z_);
3817+ item->key = make_key_opaque(static_cast<uint64_t>(item->program_id), next_z_, extra_value);
3818+ } else {
3819+ blended_items_.emplace_back(given_item);
3820+ item = &blended_items_.back();
3821+ item->z_value = to_opengl_z(next_z_);
3822+ item->key = make_key_blended(static_cast<uint64_t>(item->program_id), next_z_, extra_value);
3823+ }
3824+ ++next_z_;
3825+}
3826+
3827+void RenderQueue::draw(const int screen_width, const int screen_height) {
3828+ if (next_z_ >= kMaximumZValue) {
3829+ throw wexception("Too many drawn layers. Ran out of z-values.");
3830+ }
3831+
3832+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
3833+ glViewport(0, 0, screen_width, screen_height);
3834+
3835+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
3836+
3837+ glDisable(GL_BLEND);
3838+
3839+ std::sort(opaque_items_.begin(), opaque_items_.end());
3840+ draw_items(opaque_items_);
3841+ opaque_items_.clear();
3842+
3843+ glEnable(GL_BLEND);
3844+ glDepthMask(GL_FALSE);
3845+
3846+ std::sort(blended_items_.begin(), blended_items_.end());
3847+ draw_items(blended_items_);
3848+ blended_items_.clear();
3849+
3850+ glDepthMask(GL_TRUE);
3851+
3852+ next_z_ = 1;
3853+}
3854+
3855+void RenderQueue::draw_items(const std::vector<Item>& items) {
3856+ size_t i = 0;
3857+ while (i < items.size()) {
3858+ const Item& item = items[i];
3859+ switch (item.program_id) {
3860+ case Program::kBlit:
3861+ VanillaBlitProgram::instance().draw(
3862+ batch_up<VanillaBlitProgram::Arguments>(Program::kBlit, items, &i));
3863+ break;
3864+
3865+ case Program::kBlitMonochrome:
3866+ MonochromeBlitProgram::instance().draw(
3867+ batch_up<MonochromeBlitProgram::Arguments>(Program::kBlitMonochrome, items, &i));
3868+ break;
3869+
3870+ case Program::kBlitBlended:
3871+ BlendedBlitProgram::instance().draw(
3872+ batch_up<BlendedBlitProgram::Arguments>(Program::kBlitBlended, items, &i));
3873+ break;
3874+
3875+ case Program::kLine:
3876+ DrawLineProgram::instance().draw(
3877+ batch_up<DrawLineProgram::Arguments>(Program::kLine, items, &i));
3878+ break;
3879+
3880+ case Program::kRect:
3881+ FillRectProgram::instance().draw(
3882+ batch_up<FillRectProgram::Arguments>(Program::kRect, items, &i));
3883+ break;
3884+
3885+ case Program::kTerrainBase: {
3886+ ScopedScissor scoped_scissor(item.destination_rect);
3887+ terrain_program_->draw(item.terrain_arguments.gametime,
3888+ *item.terrain_arguments.terrains,
3889+ *item.terrain_arguments.fields_to_draw,
3890+ item.z_value);
3891+ ++i;
3892+ } break;
3893+
3894+ case Program::kTerrainDither: {
3895+ ScopedScissor scoped_scissor(item.destination_rect);
3896+ dither_program_->draw(item.terrain_arguments.gametime,
3897+ *item.terrain_arguments.terrains,
3898+ *item.terrain_arguments.fields_to_draw,
3899+ item.z_value + kOpenGlZDelta);
3900+ ++i;
3901+ } break;
3902+
3903+ case Program::kTerrainRoad: {
3904+ ScopedScissor scoped_scissor(item.destination_rect);
3905+ road_program_->draw(item.terrain_arguments.renderbuffer_width,
3906+ item.terrain_arguments.renderbuffer_height,
3907+ *item.terrain_arguments.fields_to_draw,
3908+ item.z_value + 2 * kOpenGlZDelta);
3909+ ++i;
3910+ } break;
3911+
3912+ default:
3913+ throw wexception("Unknown item.program_id: %d", item.program_id);
3914+ }
3915+ }
3916+}
3917
3918=== added file 'src/graphic/render_queue.h'
3919--- src/graphic/render_queue.h 1970-01-01 00:00:00 +0000
3920+++ src/graphic/render_queue.h 2016-01-05 11:29:18 +0000
3921@@ -0,0 +1,197 @@
3922+/*
3923+ * Copyright (C) 2006-2014 by the Widelands Development Team
3924+ *
3925+ * This program is free software; you can redistribute it and/or
3926+ * modify it under the terms of the GNU General Public License
3927+ * as published by the Free Software Foundation; either version 2
3928+ * of the License, or (at your option) any later version.
3929+ *
3930+ * This program is distributed in the hope that it will be useful,
3931+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3932+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3933+ * GNU General Public License for more details.
3934+ *
3935+ * You should have received a copy of the GNU General Public License
3936+ * along with this program; if not, write to the Free Software
3937+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3938+ *
3939+ */
3940+
3941+#ifndef WL_GRAPHIC_RENDER_QUEUE_H
3942+#define WL_GRAPHIC_RENDER_QUEUE_H
3943+
3944+#include <memory>
3945+#include <vector>
3946+
3947+#include <stdint.h>
3948+
3949+#include "base/macros.h"
3950+#include "base/rect.h"
3951+#include "graphic/blend_mode.h"
3952+#include "graphic/color.h"
3953+#include "graphic/gl/fields_to_draw.h"
3954+#include "logic/description_maintainer.h"
3955+#include "logic/world/terrain_description.h"
3956+
3957+class DitherProgram;
3958+class RoadProgram;
3959+class TerrainProgram;
3960+
3961+// The RenderQueue is a singleton implementing the concept of deferred
3962+// rendering: Every rendering call that pretends to draw onto the screen will
3963+// instead enqueue an item into the RenderQueue. The Graphic::refresh() will
3964+// then setup OpenGL to render onto the screen and then call
3965+// RenderQueue::draw() which will execute all the draw calls.
3966+//
3967+// The advantage of this design is that render calls can be reordered and
3968+// batched up to avoid OpenGL state changes as much as possible. This can
3969+// reduce the amount of OpenGL calls done in the system per frame by an order
3970+// of magnitude if assets are properly batched up into texture atlases.
3971+//
3972+// Rendering is simple: first everything fully opaque is rendered front to back
3973+// (so that no pixel is drawn twice). This allows for maximum program batching,
3974+// as for example all opaque rectangles can be rendered in one draw call,
3975+// ignoring z-value.
3976+//
3977+// In the second step, all drawing calls with (partially) transparent pixels
3978+// are done. This has to be done strictly in z ordering (back to front), so
3979+// that transparency works correctly. But common operations can still be
3980+// batched - for example the blitting of houses could all be done with the same
3981+// z value and using a common texture atlas. Then they could be drawn in one
3982+// woosh.
3983+//
3984+// Non overlapping rectangles can be drawn in parallel, ignoring z-order. I
3985+// experimented with a linear algorithm to find all overlapping rectangle
3986+// pairs (see bzr history), but it did not buy the performance I was hoping it
3987+// would. So I abandoned this idea again.
3988+//
3989+// Note: all draw calls that target a Texture are not going to the RenderQueue,
3990+// but are still immediately executed. The RenderQueue is only used for
3991+// rendering onto the screen.
3992+//
3993+// TODO(sirver): we could (even) better performance by being z-layer aware
3994+// while drawing. For example the UI could draw non-overlapping windows and
3995+// sibling children with the same z-value for better batching. Also for example
3996+// build-help symbols, buildings, and flags could all be drawn with the same
3997+// z-layer for better batching up. This would also get rid of the z-layer
3998+// issues we are having.
3999+class RenderQueue {
4000+public:
4001+ enum Program {
4002+ kTerrainBase,
4003+ kTerrainDither,
4004+ kTerrainRoad,
4005+ kBlit,
4006+ kBlitMonochrome,
4007+ kBlitBlended,
4008+ kRect,
4009+ kLine,
4010+ kHighestProgramId,
4011+ };
4012+
4013+ struct VanillaBlitArguments {
4014+ BlitData texture;
4015+ float opacity;
4016+ };
4017+
4018+ struct MonochromeBlitArguments {
4019+ BlitData texture;
4020+ RGBAColor blend;
4021+ };
4022+
4023+ struct BlendedBlitArguments {
4024+ BlitData texture;
4025+ BlitData mask;
4026+ RGBAColor blend;
4027+ };
4028+
4029+ struct RectArguments {
4030+ RGBAColor color;
4031+ };
4032+
4033+ struct LineArguments {
4034+ RGBColor color;
4035+ uint8_t line_width;
4036+ };
4037+
4038+ struct TerrainArguments {
4039+ TerrainArguments() {}
4040+
4041+ int gametime;
4042+ int renderbuffer_width;
4043+ int renderbuffer_height;
4044+ const DescriptionMaintainer<Widelands::TerrainDescription>* terrains;
4045+ FieldsToDraw* fields_to_draw;
4046+ };
4047+
4048+ // The union of all possible program arguments represents an Item that is
4049+ // enqueued in the Queue. This is on purpose not done with OOP so that the
4050+ // queue is more cache friendly.
4051+ struct Item {
4052+ Item() {}
4053+
4054+ inline bool operator<(const Item& other) const {
4055+ return key < other.key;
4056+ }
4057+
4058+ // The program that will be used to draw this item. Also defines which
4059+ // union type is filled in.
4060+ int program_id;
4061+
4062+ // The z-value in GL space that will be used for drawing.
4063+ float z_value;
4064+
4065+ // The bounding box in the renderbuffer where this draw will change pixels.
4066+ FloatRect destination_rect;
4067+
4068+ // The key for sorting this item in the queue. It depends on the type of
4069+ // item how this is calculated, but it will contain at least the program,
4070+ // the z-layer, if it is opaque or transparent and program specific
4071+ // options. After ordering the queue by this, it defines the batching.
4072+ uint64_t key;
4073+
4074+ // If this is opaque or, if not, which blend_mode to use.
4075+ BlendMode blend_mode;
4076+
4077+ union {
4078+ VanillaBlitArguments vanilla_blit_arguments;
4079+ MonochromeBlitArguments monochrome_blit_arguments;
4080+ BlendedBlitArguments blended_blit_arguments;
4081+ TerrainArguments terrain_arguments;
4082+ RectArguments rect_arguments;
4083+ LineArguments line_arguments;
4084+ };
4085+ };
4086+
4087+ static RenderQueue& instance();
4088+
4089+ // Enqueues 'item' in the queue with a higher 'z' value than the last enqueued item.
4090+ void enqueue(const Item& item);
4091+
4092+ // Draws all items in the queue in an optimal ordering and as much batching
4093+ // as possible. This will draw one complete frame onto the screen and this
4094+ // function is the only one that actually triggers draws to the screen
4095+ // directly.
4096+ void draw(int screen_width, int screen_height);
4097+
4098+private:
4099+ RenderQueue();
4100+
4101+ void draw_items(const std::vector<Item>& items);
4102+
4103+ // The z value that should be used for the next draw, so that it is on top
4104+ // of everything before.
4105+ int next_z_;
4106+
4107+ std::unique_ptr<TerrainProgram> terrain_program_;
4108+ std::unique_ptr<DitherProgram> dither_program_;
4109+ std::unique_ptr<RoadProgram> road_program_;
4110+
4111+ std::vector<Item> blended_items_;
4112+ std::vector<Item> opaque_items_;
4113+
4114+ DISALLOW_COPY_AND_ASSIGN(RenderQueue);
4115+};
4116+
4117+
4118+#endif // end of include guard: WL_GRAPHIC_RENDER_QUEUE_H
4119
4120=== modified file 'src/graphic/rendertarget.cc'
4121--- src/graphic/rendertarget.cc 2015-09-12 07:53:38 +0000
4122+++ src/graphic/rendertarget.cc 2016-01-05 11:29:18 +0000
4123@@ -97,7 +97,7 @@
4124 *prevofs = m_offset;
4125
4126 // Apply the changes
4127- m_offset = rc.top_left() - (newrect.top_left() - m_rect.top_left() - m_offset);
4128+ m_offset = rc.origin() - (newrect.origin() - m_rect.origin() - m_offset);
4129 m_rect = newrect;
4130
4131 return true;
4132@@ -123,17 +123,14 @@
4133 /**
4134 * This functions draws a line in the target
4135 */
4136-void RenderTarget::draw_line
4137- (int32_t x1, int32_t y1, int32_t x2, int32_t y2,
4138- const RGBColor& color, uint8_t gwidth)
4139-{
4140- ::draw_line(x1 + m_offset.x + m_rect.x,
4141- y1 + m_offset.y + m_rect.y,
4142- x2 + m_offset.x + m_rect.x,
4143- y2 + m_offset.y + m_rect.y,
4144- color,
4145- gwidth,
4146- m_surface);
4147+void RenderTarget::draw_line(const Point& start,
4148+ const Point& end,
4149+ const RGBColor& color,
4150+ uint8_t line_width) {
4151+ m_surface->draw_line(Point(start.x + m_offset.x + m_rect.x, start.y + m_offset.y + m_rect.y),
4152+ Point(end.x + m_offset.x + m_rect.x, end.y + m_offset.y + m_rect.y),
4153+ color,
4154+ line_width);
4155 }
4156
4157 /**
4158@@ -151,14 +148,14 @@
4159 {
4160 Rect r(rect);
4161 if (clip(r))
4162- ::fill_rect(r, clr, m_surface);
4163+ m_surface->fill_rect(r, clr);
4164 }
4165
4166 void RenderTarget::brighten_rect(const Rect& rect, int32_t factor)
4167 {
4168 Rect r(rect);
4169 if (clip(r))
4170- ::brighten_rect(r, factor, m_surface);
4171+ m_surface->brighten_rect(r, factor);
4172 }
4173
4174 /**
4175@@ -175,12 +172,11 @@
4176 Rect srcrc(Point(0, 0), image->width(), image->height());
4177
4178 if (to_surface_geometry(&destination_point, &srcrc)) {
4179- ::blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
4180- *image,
4181- srcrc,
4182- 1.,
4183- blend_mode,
4184- m_surface);
4185+ m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
4186+ *image,
4187+ srcrc,
4188+ 1.,
4189+ blend_mode);
4190 }
4191 }
4192
4193@@ -194,11 +190,8 @@
4194 Rect srcrc(Point(0, 0), image->width(), image->height());
4195
4196 if (to_surface_geometry(&destination_point, &srcrc)) {
4197- ::blit_monochrome(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
4198- *image,
4199- srcrc,
4200- blend_mode,
4201- m_surface);
4202+ m_surface->blit_monochrome(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
4203+ *image, srcrc, blend_mode);
4204 }
4205 }
4206
4207@@ -220,12 +213,11 @@
4208
4209 Point destination_point(dst);
4210 if (to_surface_geometry(&destination_point, &srcrc))
4211- ::blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
4212- *image,
4213- srcrc,
4214- 1.,
4215- blend_mode,
4216- m_surface);
4217+ m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
4218+ *image,
4219+ srcrc,
4220+ 1.,
4221+ blend_mode);
4222 }
4223
4224 void RenderTarget::blitrect_scale(const Rect& dst,
4225@@ -237,12 +229,11 @@
4226 Point destination_point(dst.x, dst.y);
4227 Rect srcrect(source_rect);
4228 if (to_surface_geometry(&destination_point, &srcrect)) {
4229- ::blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),
4230- *image,
4231- source_rect,
4232- opacity,
4233- blend_mode,
4234- m_surface);
4235+ m_surface->blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),
4236+ *image,
4237+ source_rect,
4238+ opacity,
4239+ blend_mode);
4240 }
4241 }
4242
4243@@ -253,12 +244,11 @@
4244 Point destination_point(destination_rect.x, destination_rect.y);
4245 Rect srcrect(source_rect);
4246 if (to_surface_geometry(&destination_point, &srcrect)) {
4247- ::blit_monochrome(
4248+ m_surface->blit_monochrome(
4249 Rect(destination_point.x, destination_point.y, destination_rect.w, destination_rect.h),
4250 *image,
4251 source_rect,
4252- blend,
4253- m_surface);
4254+ blend);
4255 }
4256 }
4257
4258@@ -315,7 +305,7 @@
4259 srcrc.w = r.w - tx;
4260
4261 const Rect dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
4262- ::blit(dst_rect, *image, srcrc, 1., blend_mode, m_surface);
4263+ m_surface->blit(dst_rect, *image, srcrc, 1., blend_mode);
4264
4265 tx += srcrc.w;
4266
4267@@ -368,7 +358,7 @@
4268 const Animation& anim = g_gr->animations().get_animation(animation);
4269
4270 Point destination_point = dst - anim.hotspot();
4271- destination_point += gsrcrc.top_left();
4272+ destination_point += gsrcrc.origin();
4273
4274 Rect srcrc(gsrcrc);
4275
4276@@ -473,6 +463,6 @@
4277 srcrc->h = m_rect.h - dst->y;
4278 }
4279
4280- *dst += m_rect.top_left();
4281+ *dst += m_rect.origin();
4282 return true;
4283 }
4284
4285=== modified file 'src/graphic/rendertarget.h'
4286--- src/graphic/rendertarget.h 2015-09-09 18:49:58 +0000
4287+++ src/graphic/rendertarget.h 2016-01-05 11:29:18 +0000
4288@@ -60,8 +60,7 @@
4289 int32_t width() const;
4290 int32_t height() const;
4291
4292- void draw_line
4293- (int32_t x1, int32_t y1, int32_t x2, int32_t y2, const RGBColor& color, uint8_t width = 1);
4294+ void draw_line(const Point& start, const Point& end, const RGBColor& color, uint8_t width = 1);
4295 void draw_rect(const Rect&, const RGBColor&);
4296 void fill_rect(const Rect&, const RGBAColor&);
4297 void brighten_rect(const Rect&, int32_t factor);
4298
4299=== modified file 'src/graphic/richtext.cc'
4300--- src/graphic/richtext.cc 2015-09-28 06:41:58 +0000
4301+++ src/graphic/richtext.cc 2016-01-05 11:29:18 +0000
4302@@ -512,7 +512,7 @@
4303 {
4304 Rect oldbox;
4305 Point oldofs;
4306- Rect bbox((*elt)->bbox.top_left() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
4307+ Rect bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
4308
4309 if (dst.enter_window(bbox, &oldbox, &oldofs)) {
4310 if (background)
4311
4312=== modified file 'src/graphic/screen.cc'
4313--- src/graphic/screen.cc 2014-12-27 09:59:12 +0000
4314+++ src/graphic/screen.cc 2016-01-05 11:29:18 +0000
4315@@ -24,20 +24,12 @@
4316
4317 #include "base/wexception.h"
4318 #include "graphic/gl/utils.h"
4319+#include "graphic/render_queue.h"
4320 #include "graphic/texture.h"
4321
4322 Screen::Screen(int w, int h) : m_w(w), m_h(h) {
4323 }
4324
4325-void Screen::pixel_to_gl(float* x, float* y) const {
4326- *x = (*x / m_w) * 2. - 1.;
4327- *y = 1. - (*y / m_h) * 2.;
4328-}
4329-
4330-void Screen::setup_gl() {
4331- glBindFramebuffer(GL_FRAMEBUFFER, 0);
4332-}
4333-
4334 int Screen::width() const {
4335 return m_w;
4336 }
4337@@ -50,17 +42,7 @@
4338 std::unique_ptr<uint8_t[]> pixels(new uint8_t[m_w * m_h * 4]);
4339 glReadPixels(0, 0, m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
4340
4341- // Swap order of rows in m_pixels, to compensate for the upside-down nature of the
4342- // OpenGL coordinate system.
4343- uint8_t* begin_row = pixels.get();
4344- uint8_t* end_row = pixels.get() + (m_w * (m_h - 1) * 4);
4345- while (begin_row < end_row) {
4346- for (int x = 0; x < m_w * 4; ++x) {
4347- std::swap(begin_row[x], end_row[x]);
4348- }
4349- begin_row += m_w * 4;
4350- end_row -= m_w * 4;
4351- }
4352+ Gl::swap_rows(m_w, m_h, m_w * 4, 4, pixels.get());
4353
4354 // Ownership of pixels is not taken here. But the Texture() transfers it to
4355 // the GPU, frees the SDL surface and after that we are free to free
4356@@ -77,3 +59,64 @@
4357
4358 return std::unique_ptr<Texture>(new Texture(surface));
4359 }
4360+
4361+void Screen::do_blit(const FloatRect& dst_rect,
4362+ const BlitData& texture,
4363+ float opacity,
4364+ BlendMode blend_mode) {
4365+ RenderQueue::Item i;
4366+ i.program_id = RenderQueue::Program::kBlit;
4367+ i.blend_mode = blend_mode;
4368+ i.destination_rect = dst_rect;
4369+ i.vanilla_blit_arguments.texture = texture;
4370+ i.vanilla_blit_arguments.opacity = opacity;
4371+ RenderQueue::instance().enqueue(i);
4372+}
4373+
4374+void Screen::do_blit_blended(const FloatRect& dst_rect,
4375+ const BlitData& texture,
4376+ const BlitData& mask,
4377+ const RGBColor& blend) {
4378+ RenderQueue::Item i;
4379+ i.destination_rect = dst_rect;
4380+ i.program_id = RenderQueue::Program::kBlitBlended;
4381+ i.blend_mode = BlendMode::UseAlpha;
4382+ i.blended_blit_arguments.texture = texture;
4383+ i.blended_blit_arguments.mask = mask;
4384+ i.blended_blit_arguments.blend = blend;
4385+ RenderQueue::instance().enqueue(i);
4386+}
4387+
4388+void Screen::do_blit_monochrome(const FloatRect& dst_rect,
4389+ const BlitData& texture,
4390+ const RGBAColor& blend) {
4391+ RenderQueue::Item i;
4392+ i.program_id = RenderQueue::Program::kBlitMonochrome;
4393+ i.blend_mode = BlendMode::UseAlpha;
4394+ i.destination_rect = dst_rect;
4395+ i.monochrome_blit_arguments.texture = texture;
4396+ i.monochrome_blit_arguments.blend = blend;
4397+ RenderQueue::instance().enqueue(i);
4398+}
4399+
4400+void Screen::do_draw_line(const FloatPoint& start,
4401+ const FloatPoint& end,
4402+ const RGBColor& color,
4403+ const int line_width) {
4404+ RenderQueue::Item i;
4405+ i.program_id = RenderQueue::Program::kLine;
4406+ i.blend_mode = BlendMode::Copy;
4407+ i.destination_rect = FloatRect(start.x, start.y, end.x - start.x, end.y - start.y);
4408+ i.line_arguments.color = color;
4409+ i.line_arguments.line_width = line_width;
4410+ RenderQueue::instance().enqueue(i);
4411+}
4412+
4413+void Screen::do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
4414+ RenderQueue::Item i;
4415+ i.program_id = RenderQueue::Program::kRect;
4416+ i.blend_mode = blend_mode;
4417+ i.destination_rect = dst_rect;
4418+ i.rect_arguments.color = color;
4419+ RenderQueue::instance().enqueue(i);
4420+}
4421
4422=== modified file 'src/graphic/screen.h'
4423--- src/graphic/screen.h 2014-12-07 21:34:11 +0000
4424+++ src/graphic/screen.h 2016-01-05 11:29:18 +0000
4425@@ -35,8 +35,6 @@
4426 // Implements Surface.
4427 int width() const override;
4428 int height() const override;
4429- void setup_gl() override;
4430- void pixel_to_gl(float* x, float* y) const override;
4431
4432 // Reads out the current pixels in the framebuffer and returns
4433 // them as a texture for screenshots. This is a very slow process,
4434@@ -44,6 +42,24 @@
4435 std::unique_ptr<Texture> to_texture() const;
4436
4437 private:
4438+ void do_blit(const FloatRect& dst_rect,
4439+ const BlitData& texture,
4440+ float opacity,
4441+ BlendMode blend_mode) override;
4442+ void do_blit_blended(const FloatRect& dst_rect,
4443+ const BlitData& texture,
4444+ const BlitData& mask,
4445+ const RGBColor& blend) override;
4446+ void do_blit_monochrome(const FloatRect& dst_rect,
4447+ const BlitData& texture,
4448+ const RGBAColor& blend) override;
4449+ void do_draw_line(const FloatPoint& start,
4450+ const FloatPoint& end,
4451+ const RGBColor& color,
4452+ int width) override;
4453+ void
4454+ do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
4455+
4456 const int m_w, m_h;
4457
4458 DISALLOW_COPY_AND_ASSIGN(Screen);
4459
4460=== modified file 'src/graphic/surface.cc'
4461--- src/graphic/surface.cc 2015-01-15 07:14:53 +0000
4462+++ src/graphic/surface.cc 2016-01-05 11:29:18 +0000
4463@@ -26,197 +26,86 @@
4464 #include <SDL.h>
4465
4466 #include "base/macros.h"
4467-#include "graphic/gl/blit_program.h"
4468-#include "graphic/gl/draw_line_program.h"
4469-#include "graphic/gl/fill_rect_program.h"
4470+#include "base/rect.h"
4471+#include "graphic/gl/coordinate_conversion.h"
4472 #include "graphic/gl/utils.h"
4473-#include "graphic/graphic.h"
4474-#include "graphic/texture.h"
4475-
4476-
4477-namespace {
4478-
4479-// Convert the 'rect' in pixel space into opengl space.
4480-enum class ConversionMode {
4481- // Convert the rect as given.
4482- kExact,
4483-
4484- // Convert the rect so that the borders are in the center
4485- // of the pixels.
4486- kMidPoint,
4487-};
4488-
4489-FloatRect to_opengl(const Surface& surface, const Rect& rect, ConversionMode mode) {
4490- const float delta = mode == ConversionMode::kExact ? 0. : 0.5;
4491- float x1 = rect.x + delta;
4492- float y1 = rect.y + delta;
4493- surface.pixel_to_gl(&x1, &y1);
4494- float x2 = rect.x + rect.w - delta;
4495- float y2 = rect.y + rect.h - delta;
4496- surface.pixel_to_gl(&x2, &y2);
4497- return FloatRect(x1, y1, x2 - x1, y2 - y1);
4498-}
4499-
4500-// Converts the pixel (x, y) in a texture to a gl coordinate in [0, 1].
4501-inline void pixel_to_gl_texture(const int width, const int height, float* x, float* y) {
4502- *x = (*x / width);
4503- *y = (*y / height);
4504-}
4505-
4506-// Convert 'dst' and 'srcrc' from pixel space into opengl space, taking into
4507-// account that we might be a subtexture in a bigger texture.
4508-void src_and_dst_rect_to_gl(const Surface& surface,
4509- const Image& image,
4510- const Rect& dst_rect,
4511- const Rect& src_rect,
4512- FloatRect* gl_dst_rect,
4513- FloatRect* gl_src_rect) {
4514- // Source Rectangle. We have to take into account that the texture might be
4515- // a subtexture in another bigger texture. So we first figure out the pixel
4516- // coordinates given it is a full texture (values between 0 and 1) and then
4517- // adjust these for the texture coordinates in the parent texture.
4518- const FloatRect& texture_coordinates = image.texture_coordinates();
4519-
4520- float x1 = src_rect.x;
4521- float y1 = src_rect.y;
4522- pixel_to_gl_texture(image.width(), image.height(), &x1, &y1);
4523- x1 = texture_coordinates.x + x1 * texture_coordinates.w;
4524- y1 = texture_coordinates.y + y1 * texture_coordinates.h;
4525-
4526- float x2 = src_rect.x + src_rect.w;
4527- float y2 = src_rect.y + src_rect.h;
4528- pixel_to_gl_texture(image.width(), image.height(), &x2, &y2);
4529- x2 = texture_coordinates.x + x2 * texture_coordinates.w;
4530- y2 = texture_coordinates.y + y2 * texture_coordinates.h;
4531-
4532- gl_src_rect->x = x1;
4533- gl_src_rect->y = y1;
4534- gl_src_rect->w = x2 - x1;
4535- gl_src_rect->h = y2 - y1;
4536-
4537- *gl_dst_rect = to_opengl(surface, dst_rect, ConversionMode::kExact);
4538+
4539+namespace {
4540+
4541+// Adjust 'original' so that only 'src_rect' is actually blitted.
4542+BlitData adjust_for_src(BlitData blit_data, const Rect& src_rect) {
4543+ blit_data.rect.x += src_rect.x;
4544+ blit_data.rect.y += src_rect.y;
4545+ blit_data.rect.w = src_rect.w;
4546+ blit_data.rect.h = src_rect.h;
4547+ return blit_data;
4548 }
4549
4550 } // namespace
4551
4552-
4553-void fill_rect(const Rect& rc, const RGBAColor& clr, Surface* surface) {
4554- surface->setup_gl();
4555- glViewport(0, 0, surface->width(), surface->height());
4556-
4557- glBlendFunc(GL_ONE, GL_ZERO);
4558-
4559- FillRectProgram::instance().draw(to_opengl(*surface, rc, ConversionMode::kExact), clr);
4560-
4561- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4562-}
4563-
4564-void brighten_rect(const Rect& rc, const int32_t factor, Surface * surface)
4565+void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
4566+ surface->draw_line(Point(rc.x, rc.y), Point(rc.x + rc.w, rc.y), clr, 1);
4567+ surface->draw_line(Point(rc.x + rc.w, rc.y), Point(rc.x + rc.w, rc.y + rc.h), clr, 1);
4568+ surface->draw_line(Point(rc.x + rc.w, rc.y + rc.h), Point(rc.x, rc.y + rc.h), clr, 1);
4569+ surface->draw_line(Point(rc.x, rc.y + rc.h), Point(rc.x, rc.y), clr, 1);
4570+}
4571+
4572+void Surface::fill_rect(const Rect& rc, const RGBAColor& clr) {
4573+ const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
4574+ do_fill_rect(rect, clr, BlendMode::Copy);
4575+}
4576+
4577+void Surface::brighten_rect(const Rect& rc, const int32_t factor)
4578 {
4579- if (!factor)
4580+ if (!factor) {
4581 return;
4582-
4583- surface->setup_gl();
4584- glViewport(0, 0, surface->width(), surface->height());
4585-
4586- // The simple trick here is to fill the rect, but using a different glBlendFunc that will sum
4587- // src and target (or subtract them if factor is negative).
4588- if (factor < 0) {
4589- glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
4590- }
4591-
4592- glBlendFunc(GL_ONE, GL_ONE);
4593-
4594- const int delta = std::abs(factor);
4595- FillRectProgram::instance().draw(
4596- to_opengl(*surface, rc, ConversionMode::kExact), RGBAColor(delta, delta, delta, 0));
4597-
4598- if (factor < 0) {
4599- glBlendEquation(GL_FUNC_ADD);
4600- }
4601-
4602- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4603+ }
4604+
4605+ const BlendMode blend_mode = factor < 0 ? BlendMode::Subtract : BlendMode::UseAlpha;
4606+ const int abs_factor = std::abs(factor);
4607+ const RGBAColor color(abs_factor, abs_factor, abs_factor, 0);
4608+ const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
4609+ do_fill_rect(rect, color, blend_mode);
4610 }
4611
4612-void draw_line
4613- (int x1, int y1, int x2, int y2, const RGBColor& color, int gwidth, Surface * surface)
4614+void Surface::draw_line
4615+ (const Point& start, const Point& end, const RGBColor& color, int line_width)
4616 {
4617- surface->setup_gl();
4618- glViewport(0, 0, surface->width(), surface->height());
4619-
4620- float gl_x1 = x1 + 0.5;
4621- float gl_y1 = y1 + 0.5;
4622- surface->pixel_to_gl(&gl_x1, &gl_y1);
4623-
4624- float gl_x2 = x2 + 0.5;
4625- float gl_y2 = y2 + 0.5;
4626- surface->pixel_to_gl(&gl_x2, &gl_y2);
4627-
4628- DrawLineProgram::instance().draw(gl_x1, gl_y1, gl_x2, gl_y2, color, gwidth);
4629-}
4630-
4631-void blit_monochrome(const Rect& dst_rect,
4632- const Image& image,
4633- const Rect& src_rect,
4634- const RGBAColor& blend,
4635- Surface* surface) {
4636- surface->setup_gl();
4637- glViewport(0, 0, surface->width(), surface->height());
4638-
4639- FloatRect gl_dst_rect, gl_src_rect;
4640- src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
4641-
4642- MonochromeBlitProgram::instance().draw(
4643- gl_dst_rect, gl_src_rect, image.get_gl_texture(), blend);
4644-
4645- // TODO(sirver): This is a hacky attempt to fix 1409267. It
4646- // should not stick around.
4647- glBindFramebuffer(GL_FRAMEBUFFER, 0);
4648-}
4649-
4650-void blit_blended(const Rect& dst_rect,
4651- const Image& image,
4652- const Image& mask,
4653- const Rect& src_rect,
4654- const RGBColor& blend,
4655- Surface* surface) {
4656- surface->setup_gl();
4657- glViewport(0, 0, surface->width(), surface->height());
4658-
4659- FloatRect gl_dst_rect, gl_src_rect;
4660- src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
4661-
4662- BlendedBlitProgram::instance().draw(
4663- gl_dst_rect, gl_src_rect, image.get_gl_texture(), mask.get_gl_texture(), blend);
4664-
4665- // TODO(sirver): This is a hacky attempt to fix 1409267. It
4666- // should not stick around.
4667- glBindFramebuffer(GL_FRAMEBUFFER, 0);
4668-}
4669-
4670-void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
4671- draw_line(rc.x, rc.y, rc.x + rc.w, rc.y, clr, 1, surface);
4672- draw_line(rc.x + rc.w, rc.y, rc.x + rc.w, rc.y + rc.h, clr, 1, surface);
4673- draw_line(rc.x + rc.w, rc.y + rc.h, rc.x, rc.y + rc.h, clr, 1, surface);
4674- draw_line(rc.x, rc.y + rc.h, rc.x, rc.y, clr, 1, surface);
4675-}
4676-
4677-void blit(const Rect& dst_rect,
4678- const Image& image,
4679- const Rect& src_rect,
4680- float opacity,
4681- BlendMode blend_mode,
4682- Surface* surface) {
4683- glViewport(0, 0, surface->width(), surface->height());
4684- surface->setup_gl();
4685-
4686- FloatRect gl_dst_rect, gl_src_rect;
4687- src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
4688-
4689- VanillaBlitProgram::instance().draw(
4690- gl_dst_rect, gl_src_rect, image.get_gl_texture(), opacity, blend_mode);
4691-
4692- // TODO(sirver): This is a hacky attempt to fix 1409267. It
4693- // should not stick around.
4694- glBindFramebuffer(GL_FRAMEBUFFER, 0);
4695+ float gl_x1 = start.x;
4696+ float gl_y1 = start.y;
4697+
4698+ // Include the end pixel.
4699+ float gl_x2 = end.x + 1.;
4700+ float gl_y2 = end.y + 1.;
4701+ pixel_to_gl_renderbuffer(width(), height(), &gl_x1, &gl_y1);
4702+ pixel_to_gl_renderbuffer(width(), height(), &gl_x2, &gl_y2);
4703+
4704+ do_draw_line(FloatPoint(gl_x1, gl_y1), FloatPoint(gl_x2, gl_y2), color, line_width);
4705+}
4706+
4707+void Surface::blit_monochrome(const Rect& dst_rect,
4708+ const Image& image,
4709+ const Rect& src_rect,
4710+ const RGBAColor& blend) {
4711+ const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
4712+ do_blit_monochrome(rect, adjust_for_src(image.blit_data(), src_rect), blend);
4713+}
4714+
4715+void Surface::blit_blended(const Rect& dst_rect,
4716+ const Image& image,
4717+ const Image& texture_mask,
4718+ const Rect& src_rect,
4719+ const RGBColor& blend) {
4720+ const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
4721+ do_blit_blended(rect, adjust_for_src(image.blit_data(), src_rect),
4722+ adjust_for_src(texture_mask.blit_data(), src_rect), blend);
4723+}
4724+
4725+void Surface::blit(const Rect& dst_rect,
4726+ const Image& image,
4727+ const Rect& src_rect,
4728+ float opacity,
4729+ BlendMode blend_mode) {
4730+ const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
4731+ do_blit(rect, adjust_for_src(image.blit_data(), src_rect), opacity, blend_mode);
4732 }
4733
4734=== modified file 'src/graphic/surface.h'
4735--- src/graphic/surface.h 2014-12-07 21:34:11 +0000
4736+++ src/graphic/surface.h 2016-01-05 11:29:18 +0000
4737@@ -41,47 +41,60 @@
4738 virtual int width() const = 0;
4739 virtual int height() const = 0;
4740
4741- // Converts the given pixel into an OpenGl point. This might
4742- // need some flipping of axis, depending if you want to render
4743- // on the screen or not.
4744- virtual void pixel_to_gl(float* x, float* y) const = 0;
4745-
4746- // Setups OpenGL to render to this surface.
4747- virtual void setup_gl() = 0;
4748+ /// This draws a part of 'texture'.
4749+ void blit(const Rect& dst,
4750+ const Image&,
4751+ const Rect& srcrc,
4752+ const float opacity,
4753+ BlendMode blend_mode);
4754+
4755+ /// This draws a playercolor blended image. See BlendedBlitProgram.
4756+ void blit_blended(const Rect& dst,
4757+ const Image& image,
4758+ const Image& texture_mask,
4759+ const Rect& srcrc,
4760+ const RGBColor& blend);
4761+
4762+ /// This draws a grayed out version. See MonochromeBlitProgram.
4763+ void
4764+ blit_monochrome(const Rect& dst, const Image&, const Rect& srcrc, const RGBAColor& multiplier);
4765+
4766+ /// Draws a filled rect to the destination. No blending takes place, the values
4767+ // in the target are just replaced (i.e. / BlendMode would be BlendMode::Copy).
4768+ void fill_rect(const Rect&, const RGBAColor&);
4769+
4770+ /// draw a line to the destination
4771+ void draw_line(const Point& start, const Point& end, const RGBColor& color, int width);
4772+
4773+ /// makes a rectangle on the destination brighter (or darker).
4774+ void brighten_rect(const Rect&, int factor);
4775
4776 private:
4777+ /// The actual implementation of the methods below.
4778+ virtual void do_blit(const FloatRect& dst_rect,
4779+ const BlitData& texture,
4780+ float opacity,
4781+ BlendMode blend_mode) = 0;
4782+
4783+ virtual void do_blit_blended(const FloatRect& dst_rect,
4784+ const BlitData& texture,
4785+ const BlitData& mask,
4786+ const RGBColor& blend) = 0;
4787+
4788+ virtual void do_blit_monochrome(const FloatRect& dst_rect,
4789+ const BlitData& texture,
4790+ const RGBAColor& blend) = 0;
4791+
4792+ virtual void
4793+ do_draw_line(const FloatPoint& start, const FloatPoint& end, const RGBColor& color, int width) = 0;
4794+
4795+ virtual void
4796+ do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
4797+
4798 DISALLOW_COPY_AND_ASSIGN(Surface);
4799 };
4800
4801 /// Draws a rect (frame only) to the surface.
4802 void draw_rect(const Rect&, const RGBColor&, Surface* destination);
4803
4804-/// This draws a part of 'texture' to 'surface'.
4805-void blit
4806- (const Rect& dst, const Image&, const Rect& srcrc, const float opacity,
4807- BlendMode blend_mode, Surface* destination);
4808-
4809-/// This draws a grayed out version. See MonochromeBlitProgram.
4810-void
4811-blit_monochrome
4812- (const Rect& dst, const Image&, const Rect& srcrc,
4813- const RGBAColor& multiplier, Surface* destination);
4814-
4815-/// This draws a playercolor blended image. See BlendedBlitProgram.
4816-void blit_blended
4817- (const Rect& dst, const Image& image, const Image& mask, const Rect&
4818- srcrc, const RGBColor& blend, Surface* destination);
4819-
4820-/// Draws a filled rect to the destination. No blending takes place, the values
4821-// in the target are just replaced (i.e. / BlendMode would be BlendMode::Copy).
4822-void fill_rect(const Rect&, const RGBAColor&, Surface* destination);
4823-
4824-/// draw a line to the destination
4825-void draw_line
4826- (int x1, int y1, int x2, int y2, const RGBColor& color,
4827- int width, Surface* destination);
4828-
4829-/// makes a rectangle on the destination brighter (or darker).
4830-void brighten_rect(const Rect&, int factor, Surface* destination);
4831-
4832 #endif // end of include guard: WL_GRAPHIC_SURFACE_H
4833
4834=== modified file 'src/graphic/text/rt_render.cc'
4835--- src/graphic/text/rt_render.cc 2015-10-08 06:47:39 +0000
4836+++ src/graphic/text/rt_render.cc 2016-01-05 11:29:18 +0000
4837@@ -347,15 +347,15 @@
4838 uint16_t TextNode::hotspot_y() {
4839 return m_font.ascent(m_s.font_style);
4840 }
4841+
4842 Texture* TextNode::render(TextureCache* texture_cache) {
4843 const Texture& img = m_font.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
4844 Texture* rv = new Texture(img.width(), img.height());
4845- blit(Rect(0, 0, img.width(), img.height()),
4846- img,
4847- Rect(0, 0, img.width(), img.height()),
4848- 1.,
4849- BlendMode::Copy,
4850- rv);
4851+ rv->blit(Rect(0, 0, img.width(), img.height()),
4852+ img,
4853+ Rect(0, 0, img.width(), img.height()),
4854+ 1.,
4855+ BlendMode::Copy);
4856 return rv;
4857 }
4858
4859@@ -383,7 +383,7 @@
4860 Texture* rv = new Texture(m_w, m_h);
4861 for (uint16_t curx = 0; curx < m_w; curx += t.width()) {
4862 Rect srcrect(Point(0, 0), min<int>(t.width(), m_w - curx), m_h);
4863- blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy, rv);
4864+ rv->blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
4865 }
4866 return rv;
4867 }
4868@@ -400,7 +400,7 @@
4869 Texture* render(TextureCache* texture_cache) override {
4870 if (m_show_spaces) {
4871 Texture* rv = new Texture(m_w, m_h);
4872- fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(0xcc, 0, 0, 0xcc), rv);
4873+ rv->fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(0xcc, 0, 0, 0xcc));
4874 return rv;
4875 }
4876 return TextNode::render(texture_cache);
4877@@ -452,10 +452,10 @@
4878 dst.y = 0;
4879 srcrect.w = dst.w = min<int>(m_bg->width(), m_w - curx);
4880 srcrect.h = dst.h = m_h;
4881- blit(dst, *m_bg, srcrect, 1., BlendMode::Copy, rv);
4882+ rv->blit(dst, *m_bg, srcrect, 1., BlendMode::Copy);
4883 }
4884 } else {
4885- fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(255, 255, 255, 0), rv);
4886+ rv->fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(255, 255, 255, 0));
4887 }
4888 return rv;
4889 }
4890@@ -492,12 +492,12 @@
4891 uint16_t hotspot_y() override {return height();}
4892 Texture* render(TextureCache* texture_cache) override {
4893 Texture* rv = new Texture(width(), height());
4894- fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0), rv);
4895+ rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
4896
4897 // Draw Solid background Color
4898 bool set_alpha = true;
4899 if (m_bg_clr_set) {
4900- fill_rect(Rect(Point(m_margin.left, m_margin.top), m_w, m_h), m_bg_clr, rv);
4901+ rv->fill_rect(Rect(Point(m_margin.left, m_margin.top), m_w, m_h), m_bg_clr);
4902 set_alpha = false;
4903 }
4904
4905@@ -512,7 +512,7 @@
4906 dst.y = cury;
4907 src.w = dst.w = min<int>(m_bg_img->width(), m_w + m_margin.left - curx);
4908 src.h = dst.h = min<int>(m_bg_img->height(), m_h + m_margin.top - cury);
4909- blit(dst, *m_bg_img, src, 1., BlendMode::Copy, rv);
4910+ rv->blit(dst, *m_bg_img, src, 1., BlendMode::Copy);
4911 }
4912 }
4913 set_alpha = false;
4914@@ -527,7 +527,7 @@
4915 node_texture->height());
4916 Rect src = Rect(0, 0, node_texture->width(), node_texture->height());
4917
4918- blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha, rv);
4919+ rv->blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha);
4920 delete node_texture;
4921 }
4922 delete n;
4923@@ -578,11 +578,11 @@
4924
4925 Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {
4926 Texture* rv = new Texture(m_image.width(), m_image.height());
4927- blit(Rect(0, 0, m_image.width(), m_image.height()),
4928+ rv->blit(Rect(0, 0, m_image.width(), m_image.height()),
4929 m_image,
4930 Rect(0, 0, m_image.width(), m_image.height()),
4931 1.,
4932- BlendMode::Copy, rv);
4933+ BlendMode::Copy);
4934 return rv;
4935 }
4936 // End: Helper Stuff
4937
4938=== modified file 'src/graphic/texture.cc'
4939--- src/graphic/texture.cc 2014-12-27 09:59:12 +0000
4940+++ src/graphic/texture.cc 2016-01-05 11:29:18 +0000
4941@@ -20,10 +20,15 @@
4942
4943 #include <cassert>
4944
4945+#include <SDL.h>
4946+
4947 #include "base/log.h"
4948 #include "base/macros.h"
4949 #include "base/wexception.h"
4950 #include "graphic/gl/blit_program.h"
4951+#include "graphic/gl/coordinate_conversion.h"
4952+#include "graphic/gl/draw_line_program.h"
4953+#include "graphic/gl/fill_rect_program.h"
4954 #include "graphic/gl/utils.h"
4955 #include "graphic/graphic.h"
4956 #include "graphic/sdl_utils.h"
4957@@ -31,6 +36,36 @@
4958
4959 namespace {
4960
4961+namespace {
4962+
4963+/**
4964+ * \return the standard 32-bit RGBA format that we use for our textures.
4965+ */
4966+const SDL_PixelFormat & rgba_format()
4967+{
4968+ static SDL_PixelFormat format;
4969+ static bool init = false;
4970+ if (init)
4971+ return format;
4972+
4973+ init = true;
4974+ memset(&format, 0, sizeof(format));
4975+ format.BitsPerPixel = 32;
4976+ format.BytesPerPixel = 4;
4977+ format.Rmask = 0x000000ff;
4978+ format.Gmask = 0x0000ff00;
4979+ format.Bmask = 0x00ff0000;
4980+ format.Amask = 0xff000000;
4981+ format.Rshift = 0;
4982+ format.Gshift = 8;
4983+ format.Bshift = 16;
4984+ format.Ashift = 24;
4985+ return format;
4986+}
4987+
4988+} // namespace
4989+
4990+
4991 class GlFramebuffer {
4992 public:
4993 static GlFramebuffer& instance() {
4994@@ -68,11 +103,11 @@
4995 {
4996 init(w, h);
4997
4998- if (m_w <= 0 || m_h <= 0) {
4999+ if (width() <= 0 || height() <= 0) {
5000 return;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: