Merge lp:~widelands-dev/widelands/render_queue into lp:widelands
- render_queue
- Merge into trunk
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 | ||||||||
Related bugs: |
|
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:
RGBAColor instead of uint32_t for clr.
- RenderTarget:
4 integers which are inclusive to the line.
- Only reallocate OpenGL buffers if we need more space.
- Small refactorings in src/graphics/
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:
RGBAColor instead of uint32_t for clr.
- RenderTarget:
4 integers which are inclusive to the line.
- Only reallocate OpenGL buffers if we need more space.
- Small refactorings in src/graphics/
GunChleoc (gunchleoc) wrote : | # |
Some minor nits with my proofreader glasses on.
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?
GunChleoc (gunchleoc) wrote : | # |
Yes, they show up for me. Here they are for convenience:
527 + i.blend_mode = BlendMode:
528 + // RenderQueue:
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 ;)
GunChleoc (gunchleoc) wrote : | # |
Did some more testing - now the roads look funny. I have attached a screenshot to the bug.
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:
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.
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.
kaputtnik (franku) wrote : | # |
I could confirm the fuzzy roads. Additionally the buildings menu is messed up. I put a screenshot into the bug 1425870.
bunnybot (widelandsofficial) wrote : | # |
Hi, I am bunnybot (https:/
I am keeping the source branch lp:~widelands-dev/widelands/render_queue mirrored to
https:/
The latest continuous integration build can always be found here:
https:/
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.
bunnybot (widelandsofficial) wrote : | # |
Travis build 125 has changed state to: failed. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Travis build 167 has changed state to: created. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Travis build 167 has changed state to: started. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Travis build 167 has changed state to: passed. Details: https:/
Tino (tino79) wrote : | # |
On windows the only glitch i can see are the road textures.
Switching from/to fullscreen, menues, everything else seems fine!
bunnybot (widelandsofficial) wrote : | # |
Travis build 167 has changed state to: passed. Details: https:/
SirVer (sirver) wrote : | # |
Okay, I think the road issue is now fixed. Could I get another look?
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...
Tino (tino79) wrote : | # |
Some minor issues with axis, ticks and graphs in the statistics window: https:/
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:/
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.
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:/
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.
SirVer (sirver) wrote : | # |
Followup bug for the line issue: https:/
Thanks for testing, everybody!
@bunnbot merge
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:/
Code LGTM, just smoe minor code style nits and ideas.
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.
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 {
?
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.
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:/
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.
GunChleoc (gunchleoc) wrote : | # |
@kaputtnik: How are the roads? Is the fuzzy roads bug in this branch now fixed?
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...
GunChleoc (gunchleoc) wrote : | # |
Thanks!
@bunnbot merge
GunChleoc (gunchleoc) wrote : | # |
Wasn't merged due to a typo ;)
@bunnybot merge
Preview Diff
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; |
All mentioned bugs fixed