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

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

Commit message

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

Description of the change

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

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

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

All mentioned bugs fixed

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

Some minor nits with my proofreader glasses on.

Revision history for this message
SirVer (sirver) wrote :

> Some minor nits with my proofreader glasses on.

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

Revision history for this message
GunChleoc (gunchleoc) wrote :

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

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

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

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

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

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

Revision history for this message
GunChleoc (gunchleoc) wrote :

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

Revision history for this message
SirVer (sirver) wrote :

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

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

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

Revision history for this message
GunChleoc (gunchleoc) wrote :

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

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

Revision history for this message
kaputtnik (franku) wrote :

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

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

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

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

You can give me commands by starting a line with @bunnybot <command>. I understand:
 merge: Merges the source branch into the target branch, closing the pull request.

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
Tino (tino79) wrote :

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

Revision history for this message
bunnybot (widelandsofficial) wrote :

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

Revision history for this message
SirVer (sirver) wrote :

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

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

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

I will try a long time testing...

Revision history for this message
Tino (tino79) wrote :

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

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

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

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

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

Revision history for this message
SirVer (sirver) wrote :

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

You have a keen eye, kaputtnik :)

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

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

Revision history for this message
SirVer (sirver) wrote :

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

Thanks for testing, everybody!

@bunnbot merge

Revision history for this message
GunChleoc (gunchleoc) wrote :

I agree that it is an improvement.

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

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

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

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

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

Bug 1519361 does not happen for me with this branch.

Revision history for this message
GunChleoc (gunchleoc) wrote :

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

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

I just noticed one more thing:

    class RenderQueue {

    public:
       enum Program {

Any specific reason that the last line isn't

       enum class Program {

?

Revision history for this message
SirVer (sirver) wrote :

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

Revision history for this message
kaputtnik (franku) wrote :

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

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

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

Revision history for this message
kaputtnik (franku) wrote :

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

Revision history for this message
GunChleoc (gunchleoc) wrote :

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

Revision history for this message
kaputtnik (franku) wrote :

The roads looks fine :-)

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

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

Thanks!

@bunnbot merge

Revision history for this message
GunChleoc (gunchleoc) wrote :

Wasn't merged due to a typo ;)

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/base/rect.h'
--- src/base/rect.h 2014-11-26 19:53:52 +0000
+++ src/base/rect.h 2016-01-05 11:29:18 +0000
@@ -36,13 +36,13 @@
36 : GenericRect(T(p.x), T(p.y), width, height) {36 : GenericRect(T(p.x), T(p.y), width, height) {
37 }37 }
3838
39 /// The top left point of this rectangle.39 /// The Point (x, y).
40 GenericPoint<T> top_left() const {40 GenericPoint<T> origin() const {
41 return GenericPoint<T>(x, y);41 return GenericPoint<T>(x, y);
42 }42 }
4343
44 /// The bottom right point of this rectangle.44 /// The point (x + w, y + h).
45 GenericPoint<T> bottom_right() const {45 GenericPoint<T> opposite_of_origin() const {
46 return GenericPoint<T>(x + w, y + h);46 return GenericPoint<T>(x + w, y + h);
47 }47 }
4848
4949
=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc 2015-12-04 17:58:39 +0000
+++ src/editor/editorinteractive.cc 2016-01-05 11:29:18 +0000
@@ -610,6 +610,7 @@
610610
611 eia.select_tool(eia.tools.increase_height, EditorTool::First);611 eia.select_tool(eia.tools.increase_height, EditorTool::First);
612 editor.postload();612 editor.postload();
613
613 eia.start();614 eia.start();
614615
615 if (!script_to_run.empty()) {616 if (!script_to_run.empty()) {
616617
=== modified file 'src/editor/ui_menus/editor_tool_change_resources_options_menu.cc'
--- src/editor/ui_menus/editor_tool_change_resources_options_menu.cc 2016-01-04 20:50:19 +0000
+++ src/editor/ui_menus/editor_tool_change_resources_options_menu.cc 2016-01-05 11:29:18 +0000
@@ -29,9 +29,9 @@
29#include "graphic/graphic.h"29#include "graphic/graphic.h"
30#include "logic/map.h"30#include "logic/map.h"
31#include "logic/widelands.h"31#include "logic/widelands.h"
32#include "logic/widelands_geometry.h"
32#include "logic/world/resource_description.h"33#include "logic/world/resource_description.h"
33#include "logic/world/world.h"34#include "logic/world/world.h"
34#include "logic/widelands_geometry.h"
35#include "ui_basic/button.h"35#include "ui_basic/button.h"
36#include "wui/overlay_manager.h"36#include "wui/overlay_manager.h"
3737
3838
=== modified file 'src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc'
--- src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2015-12-10 20:52:30 +0000
+++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2016-01-05 11:29:18 +0000
@@ -53,11 +53,11 @@
53 // Blit the main terrain image53 // Blit the main terrain image
54 const Texture& terrain_texture = terrain_descr.get_texture(0);54 const Texture& terrain_texture = terrain_descr.get_texture(0);
55 Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());55 Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
56 blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),56 texture->blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
57 terrain_texture,57 terrain_texture,
58 Rect(0, 0, terrain_texture.width(), terrain_texture.height()),58 Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
59 1.,59 1.,
60 BlendMode::UseAlpha, texture);60 BlendMode::UseAlpha);
61 Point pt(1, terrain_texture.height() - kSmallPicSize - 1);61 Point pt(1, terrain_texture.height() - kSmallPicSize - 1);
6262
63 // Collect tooltips and blit small icons representing "is" values63 // Collect tooltips and blit small icons representing "is" values
@@ -67,12 +67,11 @@
67 terrain_descr.custom_tooltips().end());67 terrain_descr.custom_tooltips().end());
68 tooltips.push_back(terrain_type.descname);68 tooltips.push_back(terrain_type.descname);
6969
70 blit(Rect(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),70 texture->blit(Rect(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
71 *terrain_type.icon,71 *terrain_type.icon,
72 Rect(0, 0, terrain_type.icon->width(), terrain_type.icon->height()),72 Rect(0, 0, terrain_type.icon->width(), terrain_type.icon->height()),
73 1.,73 1.,
74 BlendMode::UseAlpha,74 BlendMode::UseAlpha);
75 texture);
76 pt.x += kSmallPicSize + 1;75 pt.x += kSmallPicSize + 1;
77 }76 }
78 // Make sure we delete this later on.77 // Make sure we delete this later on.
7978
=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt 2015-02-23 08:54:16 +0000
+++ src/graphic/CMakeLists.txt 2016-01-05 11:29:18 +0000
@@ -3,6 +3,21 @@
3# TODO(sirver): Separate this directory into a base directory and one3# TODO(sirver): Separate this directory into a base directory and one
4# that is Widelands aware (can include logic stuff).4# that is Widelands aware (can include logic stuff).
55
6# A binary that creates and writes out a texture atlas of all images in
7# a directory.
8wl_binary(wl_make_texture_atlas
9 SRCS
10 make_texture_atlas_main.cc
11 DEPENDS
12 base_log
13 graphic
14 graphic_image_io
15 graphic_texture_atlas
16 helper
17 io_filesystem
18 io_stream
19)
20
6wl_library(graphic_color21wl_library(graphic_color
7 SRCS22 SRCS
8 color.h23 color.h
@@ -10,6 +25,21 @@
10 USES_SDL225 USES_SDL2
11)26)
1227
28wl_library(graphic_render_queue
29 SRCS
30 render_queue.cc
31 render_queue.h
32 DEPENDS
33 base_exceptions
34 base_geometry
35 base_log
36 base_macros
37 graphic_color
38 graphic_terrain_programs
39 graphic_draw_programs
40 logic
41)
42
13wl_library(graphic_text_layout43wl_library(graphic_text_layout
14 SRCS44 SRCS
15 text_layout.cc45 text_layout.cc
@@ -22,7 +52,6 @@
22 graphic_text52 graphic_text
23)53)
2454
25
26wl_library(graphic_image_io55wl_library(graphic_image_io
27 SRCS56 SRCS
28 image_io.h57 image_io.h
@@ -32,6 +61,7 @@
32 USES_SDL2_IMAGE61 USES_SDL2_IMAGE
33 DEPENDS62 DEPENDS
34 base_exceptions63 base_exceptions
64 base_log
35 graphic_surface65 graphic_surface
36 io_fileread66 io_fileread
37 io_filesystem67 io_filesystem
@@ -44,10 +74,10 @@
44 image_cache.h74 image_cache.h
45 USES_SDL275 USES_SDL2
46 DEPENDS76 DEPENDS
47 base_log
48 base_macros77 base_macros
49 graphic_image_io78 graphic_image_io
50 graphic_surface79 graphic_surface
80 graphic_texture_atlas
51)81)
5282
53wl_library(graphic_sdl_utils83wl_library(graphic_sdl_utils
@@ -59,6 +89,8 @@
5989
60wl_library(graphic_gl_utils90wl_library(graphic_gl_utils
61 SRCS91 SRCS
92 gl/blit_data.h
93 gl/coordinate_conversion.h
62 gl/system_headers.h94 gl/system_headers.h
63 gl/utils.cc95 gl/utils.cc
64 gl/utils.h96 gl/utils.h
@@ -66,11 +98,34 @@
66 USES_OPENGL98 USES_OPENGL
67 DEPENDS99 DEPENDS
68 base_exceptions100 base_exceptions
69 base_log101 base_geometry
70 base_macros102 base_log
71)103 base_macros
72104)
73wl_library(graphic_surface105
106wl_library(graphic_terrain_programs
107 SRCS
108 gl/fields_to_draw.h
109 gl/road_program.cc
110 gl/road_program.h
111 gl/terrain_program.cc
112 gl/terrain_program.h
113 gl/dither_program.cc
114 gl/dither_program.h
115 DEPENDS
116 base_exceptions
117 base_geometry
118 base_log
119 base_macros
120 graphic
121 graphic_gl_utils
122 graphic_image_io
123 graphic_surface
124 io_filesystem
125 logic
126)
127
128wl_library(graphic_draw_programs
74 SRCS129 SRCS
75 blend_mode.h130 blend_mode.h
76 gl/blit_program.cc131 gl/blit_program.cc
@@ -79,6 +134,17 @@
79 gl/draw_line_program.h134 gl/draw_line_program.h
80 gl/fill_rect_program.cc135 gl/fill_rect_program.cc
81 gl/fill_rect_program.h136 gl/fill_rect_program.h
137 DEPENDS
138 base_exceptions
139 base_macros
140 base_geometry
141 graphic_gl_utils
142 base_log
143 graphic_color
144)
145
146wl_library(graphic_surface
147 SRCS
82 image.h148 image.h
83 screen.cc149 screen.cc
84 screen.h150 screen.h
@@ -97,7 +163,9 @@
97 base_macros163 base_macros
98 graphic164 graphic
99 graphic_color165 graphic_color
166 graphic_draw_programs
100 graphic_gl_utils167 graphic_gl_utils
168 graphic_render_queue
101 graphic_sdl_utils169 graphic_sdl_utils
102)170)
103171
@@ -115,23 +183,14 @@
115 SRCS183 SRCS
116 game_renderer.cc184 game_renderer.cc
117 game_renderer.h185 game_renderer.h
118 gl/dither_program.cc
119 gl/dither_program.h
120 gl/fields_to_draw.h
121 gl/road_program.cc
122 gl/road_program.h
123 gl/terrain_program.cc
124 gl/terrain_program.h
125 DEPENDS186 DEPENDS
126 base_exceptions
127 base_geometry187 base_geometry
128 base_log
129 base_macros188 base_macros
130 graphic189 graphic
131 graphic_gl_utils190 graphic_gl_utils
132 graphic_image_io191 graphic_render_queue
133 graphic_surface192 graphic_surface
134 io_filesystem193 graphic_terrain_programs
135 logic194 logic
136 wui_mapview_pixelfunctions195 wui_mapview_pixelfunctions
137 wui_overlay_manager196 wui_overlay_manager
@@ -183,12 +242,14 @@
183 base_geometry242 base_geometry
184 base_i18n243 base_i18n
185 base_log244 base_log
245 graphic_draw_programs
186 base_macros246 base_macros
187 build_info247 build_info
188 graphic_color248 graphic_color
189 graphic_gl_utils249 graphic_gl_utils
190 graphic_image_cache250 graphic_image_cache
191 graphic_image_io251 graphic_image_io
252 graphic_render_queue
192 graphic_surface253 graphic_surface
193 graphic_text254 graphic_text
194 graphic_text_layout255 graphic_text_layout
195256
=== modified file 'src/graphic/animation.cc'
--- src/graphic/animation.cc 2015-12-03 19:40:37 +0000
+++ src/graphic/animation.cc 2016-01-05 11:29:18 +0000
@@ -231,22 +231,13 @@
231 Texture* rv = new Texture(w, h);231 Texture* rv = new Texture(w, h);
232232
233 // Initialize the rectangle233 // Initialize the rectangle
234 ::fill_rect(Rect(Point(0, 0), w, h), RGBAColor(255, 255, 255, 0), rv);234 rv->fill_rect(Rect(Point(0, 0), w, h), RGBAColor(255, 255, 255, 0));
235235
236 if (!hasplrclrs_ || clr == nullptr) {236 if (!hasplrclrs_ || clr == nullptr) {
237 ::blit(Rect(Point(0, 0), w, h),237 rv->blit(Rect(Point(0, 0), w, h), *image, Rect(Point(0, 0), w, h), 1., BlendMode::UseAlpha);
238 *image,
239 Rect(Point(0, 0), w, h),
240 1.,
241 BlendMode::UseAlpha,
242 rv);
243 } else {238 } else {
244 blit_blended(Rect(Point(0, 0), w, h),239 rv->blit_blended(Rect(Point(0, 0), w, h), *image,
245 *image,240 *g_gr->images().get(pc_mask_image_files_[0]), Rect(Point(0, 0), w, h), *clr);
246 *g_gr->images().get(pc_mask_image_files_[0]),
247 Rect(Point(0, 0), w, h),
248 *clr,
249 rv);
250 }241 }
251 return rv;242 return rv;
252}243}
@@ -285,19 +276,11 @@
285 assert(idx < nr_frames());276 assert(idx < nr_frames());
286277
287 if (!hasplrclrs_ || clr == nullptr) {278 if (!hasplrclrs_ || clr == nullptr) {
288 ::blit(Rect(dst.x, dst.y, srcrc.w, srcrc.h),279 target->blit(
289 *frames_.at(idx),280 Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
290 srcrc,
291 1.,
292 BlendMode::UseAlpha,
293 target);
294 } else {281 } else {
295 blit_blended(Rect(dst.x, dst.y, srcrc.w, srcrc.h),282 target->blit_blended(
296 *frames_.at(idx),283 Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
297 *pcmasks_.at(idx),
298 srcrc,
299 *clr,
300 target);
301 }284 }
302}285}
303286
304287
=== modified file 'src/graphic/blend_mode.h'
--- src/graphic/blend_mode.h 2014-12-04 09:00:20 +0000
+++ src/graphic/blend_mode.h 2016-01-05 11:29:18 +0000
@@ -24,10 +24,14 @@
24enum class BlendMode {24enum class BlendMode {
25 // Perform a normal blitting operation that respects the alpha channel if25 // Perform a normal blitting operation that respects the alpha channel if
26 // present.26 // present.
27 UseAlpha = 0,27 UseAlpha,
28
29 // Used internally for Surface::brighten_rect() if the rect is actually to
30 // be darkened.
31 Subtract,
2832
29 // Copy all pixel information, including alpha channel information.33 // Copy all pixel information, including alpha channel information.
30 Copy34 Copy,
31};35};
3236
33#endif // end of include guard: WL_GRAPHIC_BLEND_MODE_H37#endif // end of include guard: WL_GRAPHIC_BLEND_MODE_H
3438
=== modified file 'src/graphic/color.cc'
--- src/graphic/color.cc 2015-05-30 12:19:57 +0000
+++ src/graphic/color.cc 2016-01-05 11:29:18 +0000
@@ -21,7 +21,7 @@
2121
22#include <boost/format.hpp>22#include <boost/format.hpp>
2323
24RGBColor::RGBColor() {24RGBColor::RGBColor() : RGBColor(0, 0, 0) {
25}25}
2626
27RGBColor::RGBColor(uint8_t const R, uint8_t const G, uint8_t const B) :27RGBColor::RGBColor(uint8_t const R, uint8_t const G, uint8_t const B) :
2828
=== modified file 'src/graphic/color.h'
--- src/graphic/color.h 2015-05-30 12:19:57 +0000
+++ src/graphic/color.h 2016-01-05 11:29:18 +0000
@@ -26,6 +26,7 @@
2626
27struct RGBColor {27struct RGBColor {
28 RGBColor(uint8_t R, uint8_t G, uint8_t B);28 RGBColor(uint8_t R, uint8_t G, uint8_t B);
29 RGBColor(const RGBColor& other) = default;
2930
30 // Initializes the color to black.31 // Initializes the color to black.
31 RGBColor();32 RGBColor();
@@ -39,14 +40,16 @@
39 // Set it to the given 'clr' which is interpretes through 'fmt'.40 // Set it to the given 'clr' which is interpretes through 'fmt'.
40 void set(SDL_PixelFormat * fmt, uint32_t clr);41 void set(SDL_PixelFormat * fmt, uint32_t clr);
4142
43 RGBColor& operator = (const RGBColor& other) = default;
44 bool operator != (const RGBColor& other) const;
42 bool operator == (const RGBColor& other) const;45 bool operator == (const RGBColor& other) const;
43 bool operator != (const RGBColor& other) const;
4446
45 uint8_t r, g, b;47 uint8_t r, g, b;
46};48};
4749
48struct RGBAColor {50struct RGBAColor {
49 RGBAColor(uint8_t R, uint8_t G, uint8_t B, uint8_t A);51 RGBAColor(uint8_t R, uint8_t G, uint8_t B, uint8_t A);
52 RGBAColor(const RGBAColor& other) = default;
5053
51 // Initializes the color to black.54 // Initializes the color to black.
52 RGBAColor();55 RGBAColor();
@@ -63,8 +66,9 @@
63 // Set it to the given 'clr' which is interpretes through 'fmt'.66 // Set it to the given 'clr' which is interpretes through 'fmt'.
64 void set(const SDL_PixelFormat & fmt, uint32_t clr);67 void set(const SDL_PixelFormat & fmt, uint32_t clr);
6568
69 RGBAColor& operator = (const RGBAColor& other) = default;
70 bool operator != (const RGBAColor& other) const;
66 bool operator == (const RGBAColor& other) const;71 bool operator == (const RGBAColor& other) const;
67 bool operator != (const RGBAColor& other) const;
6872
69 uint8_t r;73 uint8_t r;
70 uint8_t g;74 uint8_t g;
7175
=== modified file 'src/graphic/font_handler1.cc'
--- src/graphic/font_handler1.cc 2015-09-26 09:34:20 +0000
+++ src/graphic/font_handler1.cc 2016-01-05 11:29:18 +0000
@@ -70,12 +70,8 @@
70 int width() const override {return texture()->width();}70 int width() const override {return texture()->width();}
71 int height() const override {return texture()->height();}71 int height() const override {return texture()->height();}
7272
73 int get_gl_texture() const override {73 const BlitData& blit_data() const override {
74 return texture()->get_gl_texture();74 return texture()->blit_data();
75 }
76
77 const FloatRect& texture_coordinates() const override {
78 return texture()->texture_coordinates();
79 }75 }
8076
81private:77private:
8278
=== modified file 'src/graphic/game_renderer.cc'
--- src/graphic/game_renderer.cc 2015-02-23 08:54:16 +0000
+++ src/graphic/game_renderer.cc 2016-01-05 11:29:18 +0000
@@ -21,11 +21,9 @@
2121
22#include <memory>22#include <memory>
2323
24#include "graphic/gl/dither_program.h"24#include "graphic/gl/coordinate_conversion.h"
25#include "graphic/gl/fields_to_draw.h"
26#include "graphic/gl/road_program.h"
27#include "graphic/gl/terrain_program.h"
28#include "graphic/graphic.h"25#include "graphic/graphic.h"
26#include "graphic/render_queue.h"
29#include "graphic/rendertarget.h"27#include "graphic/rendertarget.h"
30#include "graphic/surface.h"28#include "graphic/surface.h"
31#include "logic/editor_game_base.h"29#include "logic/editor_game_base.h"
@@ -66,10 +64,6 @@
66// d). Example: if r and d have different textures and r.dither_layer >64// d). Example: if r and d have different textures and r.dither_layer >
67// d.dither_layer, then we will repaint d with the dither texture as mask.65// d.dither_layer, then we will repaint d with the dither texture as mask.
6866
69std::unique_ptr<TerrainProgram> GameRenderer::terrain_program_;
70std::unique_ptr<DitherProgram> GameRenderer::dither_program_;
71std::unique_ptr<RoadProgram> GameRenderer::road_program_;
72
73namespace {67namespace {
7468
75using namespace Widelands;69using namespace Widelands;
@@ -142,12 +136,6 @@
142 const EditorGameBase& egbase,136 const EditorGameBase& egbase,
143 const Point& view_offset,137 const Point& view_offset,
144 const Player* player) {138 const Player* player) {
145 if (terrain_program_ == nullptr) {
146 terrain_program_.reset(new TerrainProgram());
147 dither_program_.reset(new DitherProgram());
148 road_program_.reset(new RoadProgram());
149 }
150
151 Point tl_map = dst.get_offset() + view_offset;139 Point tl_map = dst.get_offset() + view_offset;
152140
153 assert(tl_map.x >= 0); // divisions involving negative numbers are bad141 assert(tl_map.x >= 0); // divisions involving negative numbers are bad
@@ -170,22 +158,18 @@
170 return;158 return;
171159
172 const Rect& bounding_rect = dst.get_rect();160 const Rect& bounding_rect = dst.get_rect();
173 const Point surface_offset = bounding_rect.top_left() + dst.get_offset() - view_offset;161 const Point surface_offset = bounding_rect.origin() + dst.get_offset() - view_offset;
174162 const int surface_width = surface->width();
175 glScissor(bounding_rect.x,163 const int surface_height = surface->height();
176 surface->height() - bounding_rect.y - bounding_rect.h,
177 bounding_rect.w,
178 bounding_rect.h);
179 glEnable(GL_SCISSOR_TEST);
180164
181 Map& map = egbase.map();165 Map& map = egbase.map();
182 const uint32_t gametime = egbase.get_gametime();166 const uint32_t gametime = egbase.get_gametime();
183167
184 FieldsToDraw fields_to_draw(minfx, maxfx, minfy, maxfy);168 fields_to_draw_.reset(minfx, maxfx, minfy, maxfy);
185 for (int32_t fy = minfy; fy <= maxfy; ++fy) {169 for (int32_t fy = minfy; fy <= maxfy; ++fy) {
186 for (int32_t fx = minfx; fx <= maxfx; ++fx) {170 for (int32_t fx = minfx; fx <= maxfx; ++fx) {
187 FieldsToDraw::Field& f =171 FieldsToDraw::Field& f =
188 *fields_to_draw.mutable_field(fields_to_draw.calculate_index(fx, fy));172 *fields_to_draw_.mutable_field(fields_to_draw_.calculate_index(fx, fy));
189173
190 f.fx = fx;174 f.fx = fx;
191 f.fy = fy;175 f.fy = fy;
@@ -202,7 +186,7 @@
202186
203 f.gl_x = f.pixel_x = x + surface_offset.x;187 f.gl_x = f.pixel_x = x + surface_offset.x;
204 f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;188 f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;
205 surface->pixel_to_gl(&f.gl_x, &f.gl_y);189 pixel_to_gl_renderbuffer(surface_width, surface_height, &f.gl_x, &f.gl_y);
206190
207 f.ter_d = fcoords.field->terrain_d();191 f.ter_d = fcoords.field->terrain_d();
208 f.ter_r = fcoords.field->terrain_r();192 f.ter_r = fcoords.field->terrain_r();
@@ -220,14 +204,32 @@
220 }204 }
221 }205 }
222206
223 const World& world = egbase.world();207 // Enqueue the drawing of the terrain.
224 terrain_program_->draw(gametime, world.terrains(), fields_to_draw);208 RenderQueue::Item i;
225 dither_program_->draw(gametime, world.terrains(), fields_to_draw);209 i.program_id = RenderQueue::Program::kTerrainBase;
226 road_program_->draw(*surface, fields_to_draw);210 i.blend_mode = BlendMode::Copy;
211 i.destination_rect =
212 FloatRect(bounding_rect.x,
213 surface_height - bounding_rect.y - bounding_rect.h,
214 bounding_rect.w,
215 bounding_rect.h);
216 i.terrain_arguments.gametime = gametime;
217 i.terrain_arguments.renderbuffer_width = surface_width;
218 i.terrain_arguments.renderbuffer_height = surface_height;
219 i.terrain_arguments.terrains = &egbase.world().terrains();
220 i.terrain_arguments.fields_to_draw = &fields_to_draw_;
221 RenderQueue::instance().enqueue(i);
222
223 // Enqueue the drawing of the dither layer.
224 i.program_id = RenderQueue::Program::kTerrainDither;
225 i.blend_mode = BlendMode::UseAlpha;
226 RenderQueue::instance().enqueue(i);
227
228 // Enqueue the drawing of the road layer.
229 i.program_id = RenderQueue::Program::kTerrainRoad;
230 RenderQueue::instance().enqueue(i);
227231
228 draw_objects(dst, egbase, view_offset, player, minfx, maxfx, minfy, maxfy);232 draw_objects(dst, egbase, view_offset, player, minfx, maxfx, minfy, maxfy);
229
230 glDisable(GL_SCISSOR_TEST);
231}233}
232234
233void GameRenderer::draw_objects(RenderTarget& dst,235void GameRenderer::draw_objects(RenderTarget& dst,
234236
=== modified file 'src/graphic/game_renderer.h'
--- src/graphic/game_renderer.h 2014-12-04 21:21:05 +0000
+++ src/graphic/game_renderer.h 2016-01-05 11:29:18 +0000
@@ -24,17 +24,14 @@
2424
25#include "base/macros.h"25#include "base/macros.h"
26#include "base/point.h"26#include "base/point.h"
27#include "graphic/gl/fields_to_draw.h"
2728
28namespace Widelands {29namespace Widelands {
29 class Player;30 class Player;
30 class EditorGameBase;31 class EditorGameBase;
31}32}
3233
33class DitherProgram;
34class RenderTarget;34class RenderTarget;
35class RoadProgram;
36class TerrainProgram;
37
3835
39/**36/**
40 * This abstract base class renders the main game view into an37 * This abstract base class renders the main game view into an
@@ -64,10 +61,6 @@
64 void rendermap(RenderTarget& dst, const Widelands::EditorGameBase& egbase, const Point& view_offset);61 void rendermap(RenderTarget& dst, const Widelands::EditorGameBase& egbase, const Point& view_offset);
6562
66private:63private:
67 static std::unique_ptr<TerrainProgram> terrain_program_;
68 static std::unique_ptr<DitherProgram> dither_program_;
69 static std::unique_ptr<RoadProgram> road_program_;
70
71 // Draw the map for the given parameters (see rendermap). 'player'64 // Draw the map for the given parameters (see rendermap). 'player'
72 // can be nullptr in which case the whole map is drawn.65 // can be nullptr in which case the whole map is drawn.
73 void draw(RenderTarget& dst,66 void draw(RenderTarget& dst,
@@ -85,6 +78,10 @@
85 int minfy,78 int minfy,
86 int maxfy);79 int maxfy);
8780
81 // This is owned and handled by us, but handed to the RenderQueue, so we
82 // basically promise that this stays valid for one frame.
83 FieldsToDraw fields_to_draw_;
84
88 DISALLOW_COPY_AND_ASSIGN(GameRenderer);85 DISALLOW_COPY_AND_ASSIGN(GameRenderer);
89};86};
9087
9188
=== added file 'src/graphic/gl/blit_data.h'
--- src/graphic/gl/blit_data.h 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/blit_data.h 2016-01-05 11:29:18 +0000
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2006-2016 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20#ifndef WL_GRAPHIC_GL_BLIT_DATA_H
21#define WL_GRAPHIC_GL_BLIT_DATA_H
22
23#include <stdint.h>
24
25#include "base/rect.h"
26
27// Information of the internal OpenGL data needed to properly blit this image.
28struct BlitData {
29 // The OpenGl name or id of the parent texture. The parent texture is either
30 // - the packed texture of the texture atlas, if this texture is part of a texture atlas.
31 // - the texture itself if it is a standalone texture.
32 uint32_t texture_id;
33
34 // Dimension of the parent texture, For stand alone textures this is the
35 // dimensions of the texture itself and therefore equal to
36 // rect.[w|h].
37 int parent_width;
38 int parent_height;
39
40 // The subrect in the parent texture.
41 Rect rect;
42};
43
44#endif // end of include guard: WL_GRAPHIC_GL_BLIT_DATA_H
045
=== modified file 'src/graphic/gl/blit_program.cc'
--- src/graphic/gl/blit_program.cc 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/blit_program.cc 2016-01-05 11:29:18 +0000
@@ -22,6 +22,8 @@
22#include <vector>22#include <vector>
2323
24#include "base/log.h"24#include "base/log.h"
25#include "graphic/gl/blit_data.h"
26#include "graphic/gl/coordinate_conversion.h"
25#include "graphic/gl/utils.h"27#include "graphic/gl/utils.h"
2628
27namespace {29namespace {
@@ -30,42 +32,44 @@
30#version 12032#version 120
3133
32// Attributes.34// Attributes.
33attribute vec2 attr_position;35attribute vec2 attr_mask_texture_position;
3436attribute vec2 attr_texture_position;
35// Uniforms.37attribute vec3 attr_position;
36uniform vec4 u_dst_rect;38attribute vec4 attr_blend;
37uniform vec4 u_src_rect;39
3840varying vec2 out_mask_texture_coordinate;
39varying vec2 out_texture_coordinate;41varying vec2 out_texture_coordinate;
42varying vec4 out_blend;
4043
41void main() {44void main() {
42 out_texture_coordinate = u_src_rect.xy + attr_position.xy * u_src_rect.zw;45 out_mask_texture_coordinate = attr_mask_texture_position;
43 gl_Position = vec4(u_dst_rect.xy + attr_position.xy * u_dst_rect.zw, 0., 1.);46 out_texture_coordinate = attr_texture_position;
47 out_blend = attr_blend;
48 gl_Position = vec4(attr_position, 1.);
44}49}
45)";50)";
4651
47const char kVanillaBlitFragmentShader[] = R"(52const char kVanillaBlitFragmentShader[] = R"(
48#version 12053#version 120
4954
50uniform float u_opacity;
51uniform sampler2D u_texture;55uniform sampler2D u_texture;
5256
53varying vec2 out_texture_coordinate;57varying vec2 out_texture_coordinate;
58varying vec4 out_blend;
5459
55void main() {60void main() {
56 vec4 color = texture2D(u_texture, out_texture_coordinate);61 vec4 color = texture2D(u_texture, out_texture_coordinate);
57 gl_FragColor = vec4(color.rgb, u_opacity * color.a);62 gl_FragColor = color * out_blend;
58}63}
59)";64)";
6065
61const char kMonochromeBlitFragmentShader[] = R"(66const char kMonochromeBlitFragmentShader[] = R"(
62#version 12067#version 120
6368
64uniform float u_opacity;
65uniform sampler2D u_texture;69uniform sampler2D u_texture;
66uniform vec3 u_blend;
6770
68varying vec2 out_texture_coordinate;71varying vec2 out_texture_coordinate;
72varying vec4 out_blend;
6973
70void main() {74void main() {
71 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);75 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
@@ -73,144 +77,272 @@
73 // See http://en.wikipedia.org/wiki/YUV.77 // See http://en.wikipedia.org/wiki/YUV.
74 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);78 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
7579
76 gl_FragColor = vec4(vec3(luminance) * u_blend, u_opacity * texture_color.a);80 gl_FragColor = vec4(vec3(luminance) * out_blend.rgb, out_blend.a * texture_color.a);
77}81}
78)";82)";
7983
80const char kBlendedBlitFragmentShader[] = R"(84const char kBlendedBlitFragmentShader[] = R"(
81#version 12085#version 120
8286
83uniform float u_opacity;
84uniform sampler2D u_texture;87uniform sampler2D u_texture;
85uniform sampler2D u_mask;88uniform sampler2D u_mask;
86uniform vec3 u_blend;
8789
90varying vec2 out_mask_texture_coordinate;
88varying vec2 out_texture_coordinate;91varying vec2 out_texture_coordinate;
92varying vec4 out_blend;
8993
90void main() {94void main() {
91 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);95 vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
92 vec4 mask_color = texture2D(u_mask, out_texture_coordinate);96 vec4 mask_color = texture2D(u_mask, out_mask_texture_coordinate);
9397
94 // See http://en.wikipedia.org/wiki/YUV.98 // See http://en.wikipedia.org/wiki/YUV.
95 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);99 float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
96 float blend_influence = mask_color.r * mask_color.a;100 float blend_influence = mask_color.r * mask_color.a;
97 gl_FragColor = vec4(101 gl_FragColor = vec4(
98 mix(texture_color.rgb, u_blend * luminance, blend_influence), u_opacity * texture_color.a);102 mix(texture_color.rgb, out_blend.rgb * luminance, blend_influence), out_blend.a * texture_color.a);
99}103}
100)";104)";
101105
106// While drawing we put all draw calls into a buffer, so that we have to
107// transfer the buffer to the GPU only once, even though we might need to do
108// many glDraw* calls. This structure represents the parameters for one glDraw*
109// call.
110struct DrawBatch {
111 int offset;
112 int count;
113 uint32_t texture;
114 uint32_t mask;
115 BlendMode blend_mode;
116};
117
102} // namespace118} // namespace
103119
104class BlitProgram {120class BlitProgram {
105public:121public:
122 struct Arguments {
123 FloatRect destination_rect;
124 float z_value;
125 BlitData texture;
126 BlitData mask;
127 RGBAColor blend;
128 BlendMode blend_mode;
129 };
106 BlitProgram(const std::string& fragment_shader);130 BlitProgram(const std::string& fragment_shader);
107131
108 void activate(const FloatRect& gl_dest_rect,132 void activate();
109 const FloatRect& gl_src_rect,133
110 const GLuint gl_texture,134 void draw_and_deactivate(const std::vector<Arguments>& arguments);
111 const float opacity,135
112 const BlendMode blend_mode);136 int program_object() const {
113
114 void draw();
115 void draw_and_deactivate(BlendMode blend_mode);
116
117 GLuint program_object() const {
118 return gl_program_.object();137 return gl_program_.object();
119 }138 }
120139
121private:140private:
122 struct PerVertexData {141 struct PerVertexData {
123 float gl_x, gl_y;142 PerVertexData(float init_gl_x,
143 float init_gl_y,
144 float init_gl_z,
145 float init_texture_x,
146 float init_texture_y,
147 float init_mask_texture_x,
148 float init_mask_texture_y,
149 float init_blend_r,
150 float init_blend_g,
151 float init_blend_b,
152 float init_blend_a)
153 : gl_x(init_gl_x),
154 gl_y(init_gl_y),
155 gl_z(init_gl_z),
156 texture_x(init_texture_x),
157 texture_y(init_texture_y),
158 mask_texture_x(init_mask_texture_x),
159 mask_texture_y(init_mask_texture_y),
160 blend_r(init_blend_r),
161 blend_g(init_blend_g),
162 blend_b(init_blend_b),
163 blend_a(init_blend_a) {
164 }
165
166 float gl_x, gl_y, gl_z;
167 float texture_x, texture_y;
168 float mask_texture_x, mask_texture_y;
169 float blend_r, blend_g, blend_b, blend_a;
124 };170 };
125 static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");171 static_assert(sizeof(PerVertexData) == 44, "Wrong padding.");
126172
127 // The buffer that will contain the quad for rendering.173 // The buffer that will contain the quad for rendering.
128 Gl::Buffer gl_array_buffer_;174 Gl::Buffer<PerVertexData> gl_array_buffer_;
129175
130 // The program.176 // The program.
131 Gl::Program gl_program_;177 Gl::Program gl_program_;
132178
133 // Attributes.179 // Attributes.
180 GLint attr_blend_;
181 GLint attr_mask_texture_position_;
134 GLint attr_position_;182 GLint attr_position_;
183 GLint attr_texture_position_;
135184
136 // Uniforms.185 // Uniforms.
137 GLint u_dst_rect_;
138 GLint u_opacity_;
139 GLint u_src_rect_;
140 GLint u_texture_;186 GLint u_texture_;
187 GLint u_mask_;
188
189 // Cached for efficiency.
190 std::vector<PerVertexData> vertices_;
191
141 DISALLOW_COPY_AND_ASSIGN(BlitProgram);192 DISALLOW_COPY_AND_ASSIGN(BlitProgram);
142};193};
143194
144BlitProgram::BlitProgram(const std::string& fragment_shader) {195BlitProgram::BlitProgram(const std::string& fragment_shader) {
145 gl_program_.build(kBlitVertexShader, fragment_shader.c_str());196 gl_program_.build(kBlitVertexShader, fragment_shader.c_str());
146197
198 attr_blend_ = glGetAttribLocation(gl_program_.object(), "attr_blend");
199 attr_mask_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_mask_texture_position");
147 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");200 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
201 attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
148202
149 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");203 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
150 u_opacity_ = glGetUniformLocation(gl_program_.object(), "u_opacity");204 u_mask_ = glGetUniformLocation(gl_program_.object(), "u_mask");
151 u_dst_rect_ = glGetUniformLocation(gl_program_.object(), "u_dst_rect");
152 u_src_rect_ = glGetUniformLocation(gl_program_.object(), "u_src_rect");
153
154 std::vector<PerVertexData> vertices;
155 vertices.push_back(PerVertexData
156 {0., 1.});
157 vertices.push_back(PerVertexData
158 {1., 1.});
159 vertices.push_back(PerVertexData
160 {0., 0.});
161 vertices.push_back(PerVertexData
162 {1., 0.});
163
164 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
165 glBufferData(
166 GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
167 glVertexAttribPointer(attr_position_,
168 2,
169 GL_FLOAT,
170 GL_FALSE,
171 sizeof(PerVertexData),
172 reinterpret_cast<void*>(0));
173 glBindBuffer(GL_ARRAY_BUFFER, 0);
174}205}
175206
176void BlitProgram::activate(const FloatRect& gl_dest_rect,207void BlitProgram::activate() {
177 const FloatRect& gl_src_rect,
178 const GLuint gl_texture,
179 const float opacity,
180 const BlendMode blend_mode) {
181 glUseProgram(gl_program_.object());208 glUseProgram(gl_program_.object());
209
210 glEnableVertexAttribArray(attr_blend_);
211 glEnableVertexAttribArray(attr_mask_texture_position_);
182 glEnableVertexAttribArray(attr_position_);212 glEnableVertexAttribArray(attr_position_);
183 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());213 glEnableVertexAttribArray(attr_texture_position_);
184214}
185 glVertexAttribPointer(attr_position_,215
186 2,216void BlitProgram::draw_and_deactivate(const std::vector<Arguments>& arguments) {
187 GL_FLOAT,217 size_t i = 0;
188 GL_FALSE,218
189 sizeof(PerVertexData),219 gl_array_buffer_.bind();
190 reinterpret_cast<void*>(0));220
191221 Gl::vertex_attrib_pointer(attr_blend_, 4, sizeof(PerVertexData), offsetof(PerVertexData, blend_r));
222 Gl::vertex_attrib_pointer(attr_mask_texture_position_,
223 2,
224 sizeof(PerVertexData),
225 offsetof(PerVertexData, mask_texture_x));
226 Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
227 Gl::vertex_attrib_pointer(
228 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
192229
193 glUniform1i(u_texture_, 0);230 glUniform1i(u_texture_, 0);
194 glUniform1f(u_opacity_, opacity);231 glUniform1i(u_mask_, 1);
195 glUniform4f(u_dst_rect_, gl_dest_rect.x, gl_dest_rect.y, gl_dest_rect.w, gl_dest_rect.h);232
196 glUniform4f(u_src_rect_, gl_src_rect.x, gl_src_rect.y, gl_src_rect.w, gl_src_rect.h);233 // Prepare the buffer for many draw calls.
197234 std::vector<DrawBatch> draw_batches;
198 glActiveTexture(GL_TEXTURE0);235 int offset = 0;
199 glBindTexture(GL_TEXTURE_2D, gl_texture);236 vertices_.clear();
200237 while (i < arguments.size()) {
201 if (blend_mode == BlendMode::Copy) {238 const Arguments& template_args = arguments[i];
202 glBlendFunc(GL_ONE, GL_ZERO);239
203 }240 // Batch common blit operations up.
204}241 while (i < arguments.size()) {
205242 const Arguments& current_args = arguments[i];
206void BlitProgram::draw_and_deactivate(BlendMode blend_mode) {243 if (current_args.blend_mode != template_args.blend_mode ||
207 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);244 current_args.texture.texture_id != template_args.texture.texture_id ||
208245 current_args.mask.texture_id != template_args.mask.texture_id) {
209 if (blend_mode == BlendMode::Copy) {246 break;
210 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);247 }
211 }248
212249 const float blend_r = current_args.blend.r / 255.;
250 const float blend_g = current_args.blend.g / 255.;
251 const float blend_b = current_args.blend.b / 255.;
252 const float blend_a = current_args.blend.a / 255.;
253
254 const FloatRect texture_rect = to_gl_texture(current_args.texture);
255 const FloatRect mask_rect = to_gl_texture(current_args.mask);
256 vertices_.emplace_back(current_args.destination_rect.x,
257 current_args.destination_rect.y,
258 current_args.z_value,
259 texture_rect.x,
260 texture_rect.y,
261 mask_rect.x,
262 mask_rect.y,
263 blend_r,
264 blend_g,
265 blend_b,
266 blend_a);
267
268 vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
269 current_args.destination_rect.y,
270 current_args.z_value,
271 texture_rect.x + texture_rect.w,
272 texture_rect.y,
273 mask_rect.x + mask_rect.w,
274 mask_rect.y,
275 blend_r,
276 blend_g,
277 blend_b,
278 blend_a);
279
280 vertices_.emplace_back(current_args.destination_rect.x,
281 current_args.destination_rect.y + current_args.destination_rect.h,
282 current_args.z_value,
283 texture_rect.x,
284 texture_rect.y + texture_rect.h,
285 mask_rect.x,
286 mask_rect.y + mask_rect.h,
287 blend_r,
288 blend_g,
289 blend_b,
290 blend_a);
291
292 vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
293 vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
294
295 vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
296 current_args.destination_rect.y + current_args.destination_rect.h,
297 current_args.z_value,
298 texture_rect.x + texture_rect.w,
299 texture_rect.y + texture_rect.h,
300 mask_rect.x + mask_rect.w,
301 mask_rect.y + mask_rect.h,
302 blend_r,
303 blend_g,
304 blend_b,
305 blend_a);
306 ++i;
307 }
308
309 draw_batches.emplace_back(DrawBatch{offset,
310 static_cast<int>(vertices_.size() - offset),
311 template_args.texture.texture_id,
312 template_args.mask.texture_id,
313 template_args.blend_mode});
314 offset = vertices_.size();
315 }
316 gl_array_buffer_.update(vertices_);
317
318 // Now do the draw calls.
319 for (const auto& draw_arg : draw_batches) {
320 glActiveTexture(GL_TEXTURE0);
321 glBindTexture(GL_TEXTURE_2D, draw_arg.texture);
322
323 glActiveTexture(GL_TEXTURE1);
324 glBindTexture(GL_TEXTURE_2D, draw_arg.mask);
325
326 if (draw_arg.blend_mode == BlendMode::Copy) {
327 glBlendFunc(GL_ONE, GL_ZERO);
328 }
329 glDrawArrays(GL_TRIANGLES, draw_arg.offset, draw_arg.count);
330
331 if (draw_arg.blend_mode == BlendMode::Copy) {
332 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
333 }
334 }
335
336 glDisableVertexAttribArray(attr_blend_);
337 glDisableVertexAttribArray(attr_mask_texture_position_);
213 glDisableVertexAttribArray(attr_position_);338 glDisableVertexAttribArray(attr_position_);
339 glDisableVertexAttribArray(attr_texture_position_);
340
341 glBindTexture(GL_TEXTURE_2D, 0);
342
343 glActiveTexture(GL_TEXTURE0);
344 glBindTexture(GL_TEXTURE_2D, 0);
345
214 glBindBuffer(GL_ARRAY_BUFFER, 0);346 glBindBuffer(GL_ARRAY_BUFFER, 0);
215}347}
216348
@@ -227,15 +359,31 @@
227 blit_program_.reset(new BlitProgram(kVanillaBlitFragmentShader));359 blit_program_.reset(new BlitProgram(kVanillaBlitFragmentShader));
228}360}
229361
230
231void VanillaBlitProgram::draw(const FloatRect& gl_dest_rect,362void VanillaBlitProgram::draw(const FloatRect& gl_dest_rect,
232 const FloatRect& gl_src_rect,363 const float z_value,
233 const GLuint gl_texture,364 const BlitData& texture,
234 const float opacity,365 const float opacity,
235 const BlendMode blend_mode) {366 const BlendMode blend_mode) {
236 blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture, opacity, blend_mode);367 draw({Arguments{gl_dest_rect, z_value, texture, opacity, blend_mode}});
237 blit_program_->draw_and_deactivate(blend_mode);368}
238}369
370void VanillaBlitProgram::draw(const std::vector<Arguments>& arguments) {
371 std::vector<BlitProgram::Arguments> blit_arguments;
372 for (const Arguments arg : arguments) {
373 blit_arguments.emplace_back(BlitProgram::Arguments{
374 arg.destination_rect,
375 arg.z_value,
376 arg.texture,
377 BlitData{0, 0, 0, Rect()},
378 RGBAColor(255, 255, 255, arg.opacity * 255),
379 arg.blend_mode,
380 });
381 }
382
383 blit_program_->activate();
384 blit_program_->draw_and_deactivate(blit_arguments);
385}
386
239387
240// static388// static
241MonochromeBlitProgram& MonochromeBlitProgram::instance() {389MonochromeBlitProgram& MonochromeBlitProgram::instance() {
@@ -248,19 +396,30 @@
248396
249MonochromeBlitProgram::MonochromeBlitProgram() {397MonochromeBlitProgram::MonochromeBlitProgram() {
250 blit_program_.reset(new BlitProgram(kMonochromeBlitFragmentShader));398 blit_program_.reset(new BlitProgram(kMonochromeBlitFragmentShader));
251399}
252 u_blend_ = glGetUniformLocation(blit_program_->program_object(), "u_blend");400
253}401void MonochromeBlitProgram::draw(const FloatRect& dest_rect,
254402 const float z_value,
255void MonochromeBlitProgram::draw(const FloatRect& gl_dest_rect,403 const BlitData& texture,
256 const FloatRect& gl_src_rect,404 const RGBAColor& blend) {
257 const GLuint gl_texture,405 draw({Arguments{dest_rect, z_value, texture, blend, BlendMode::UseAlpha}});
258 const RGBAColor& blend) {406}
259 blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture, blend.a / 255., BlendMode::UseAlpha);407
260408void MonochromeBlitProgram::draw(const std::vector<Arguments>& arguments) {
261 glUniform3f(u_blend_, blend.r / 255., blend.g / 255., blend.b / 255.);409 std::vector<BlitProgram::Arguments> blit_arguments;
262410 for (const Arguments arg : arguments) {
263 blit_program_->draw_and_deactivate(BlendMode::UseAlpha);411 blit_arguments.emplace_back(BlitProgram::Arguments{
412 arg.destination_rect,
413 arg.z_value,
414 arg.texture,
415 BlitData{0, 0, 0, Rect()},
416 arg.blend,
417 arg.blend_mode,
418 });
419 }
420
421 blit_program_->activate();
422 blit_program_->draw_and_deactivate(blit_arguments);
264}423}
265424
266// static425// static
@@ -274,28 +433,29 @@
274433
275BlendedBlitProgram::BlendedBlitProgram() {434BlendedBlitProgram::BlendedBlitProgram() {
276 blit_program_.reset(new BlitProgram(kBlendedBlitFragmentShader));435 blit_program_.reset(new BlitProgram(kBlendedBlitFragmentShader));
277 u_blend_ = glGetUniformLocation(blit_program_->program_object(), "u_blend");
278 u_mask_ = glGetUniformLocation(blit_program_->program_object(), "u_mask");
279}436}
280437
281void BlendedBlitProgram::draw(const FloatRect& gl_dest_rect,438void BlendedBlitProgram::draw(const FloatRect& gl_dest_rect,
282 const FloatRect& gl_src_rect,439 const float z_value,
283 const GLuint gl_texture_image,440 const BlitData& texture,
284 const GLuint gl_texture_mask,441 const BlitData& mask,
285 const RGBAColor& blend) {442 const RGBAColor& blend) {
286 blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture_image, blend.a / 255., BlendMode::UseAlpha);443 draw({Arguments{gl_dest_rect, z_value, texture, mask, blend, BlendMode::UseAlpha}});
287444}
288 glActiveTexture(GL_TEXTURE1);445
289 glBindTexture(GL_TEXTURE_2D, gl_texture_mask);446void BlendedBlitProgram::draw(const std::vector<Arguments>& arguments) {
290 glUniform1i(u_mask_, 1);447 std::vector<BlitProgram::Arguments> blit_arguments;
291448 for (const Arguments arg : arguments) {
292 glUniform3f(u_blend_, blend.r / 255., blend.g / 255., blend.b / 255.);449 blit_arguments.emplace_back(BlitProgram::Arguments{
293450 arg.destination_rect,
294 blit_program_->draw_and_deactivate(BlendMode::UseAlpha);451 arg.z_value,
295452 arg.texture,
296 glActiveTexture(GL_TEXTURE1);453 arg.mask,
297 glBindTexture(GL_TEXTURE_2D, 0);454 arg.blend,
298455 arg.blend_mode,
299 glActiveTexture(GL_TEXTURE0);456 });
300 glBindTexture(GL_TEXTURE_2D, 0);457 }
458
459 blit_program_->activate();
460 blit_program_->draw_and_deactivate(blit_arguments);
301}461}
302462
=== modified file 'src/graphic/gl/blit_program.h'
--- src/graphic/gl/blit_program.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/blit_program.h 2016-01-05 11:29:18 +0000
@@ -21,32 +21,46 @@
21#define WL_GRAPHIC_GL_BLIT_PROGRAM_H21#define WL_GRAPHIC_GL_BLIT_PROGRAM_H
2222
23#include <memory>23#include <memory>
24#include <vector>
2425
25#include "base/macros.h"26#include "base/macros.h"
26#include "base/rect.h"27#include "base/rect.h"
27#include "graphic/blend_mode.h"28#include "graphic/blend_mode.h"
28#include "graphic/color.h"29#include "graphic/color.h"
30#include "graphic/gl/blit_data.h"
29#include "graphic/gl/system_headers.h"31#include "graphic/gl/system_headers.h"
3032
31class BlitProgram;33class BlitProgram;
3234
35
33class VanillaBlitProgram {36class VanillaBlitProgram {
34public:37public:
38 struct Arguments {
39 FloatRect destination_rect;
40 float z_value;
41 BlitData texture;
42 float opacity;
43 BlendMode blend_mode;
44 };
45
35 // Returns the (singleton) instance of this class.46 // Returns the (singleton) instance of this class.
36 static VanillaBlitProgram& instance();47 static VanillaBlitProgram& instance();
37 ~VanillaBlitProgram();48 ~VanillaBlitProgram();
3849
39 // Draws the rectangle 'gl_src_rect' from the texture with the name50 // Draws the rectangle 'gl_src_rect' from the texture with the name
40 // 'gl_texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha51 // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha
41 // values are multiplied by 'opacity' during the blit.52 // values are multiplied by 'opacity' during the blit.
42 // All coordinates are in the OpenGL frame. The 'blend_mode' defines if the53 // All coordinates are in the OpenGL frame. The 'blend_mode' defines if the
43 // values are copied or if alpha values are used.54 // values are copied or if alpha values are used.
44 void draw(const FloatRect& gl_dest_rect,55 void draw(const FloatRect& gl_dest_rect,
45 const FloatRect& gl_src_rect,56 const float z_value,
46 const GLuint gl_texture,57 const BlitData& texture,
47 float opacity,58 float opacity,
48 const BlendMode blend_mode);59 const BlendMode blend_mode);
4960
61 // Draws a bunch of items at once.
62 void draw(const std::vector<Arguments>& arguments);
63
50private:64private:
51 VanillaBlitProgram();65 VanillaBlitProgram();
5266
@@ -57,55 +71,71 @@
5771
58class MonochromeBlitProgram {72class MonochromeBlitProgram {
59public:73public:
74 struct Arguments {
75 FloatRect destination_rect;
76 float z_value;
77 BlitData texture;
78 RGBAColor blend;
79 BlendMode blend_mode;
80 };
81
60 // Returns the (singleton) instance of this class.82 // Returns the (singleton) instance of this class.
61 static MonochromeBlitProgram& instance();83 static MonochromeBlitProgram& instance();
62 ~MonochromeBlitProgram();84 ~MonochromeBlitProgram();
6385
64 // Draws the rectangle 'gl_src_rect' from the texture with the name86 // Draws the rectangle 'gl_src_rect' from the texture with the name
65 // 'gl_texture' to 'gl_dest_rect' in the currently bound framebuffer. All87 // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
66 // coordinates are in the OpenGL frame. The image is first converted to88 // coordinates are in the OpenGL frame. The image is first converted to
67 // luminance, then all values are multiplied with blend.89 // luminance, then all values are multiplied with blend.
68 void draw(const FloatRect& gl_dest_rect,90 void draw(const FloatRect& gl_dest_rect,
69 const FloatRect& gl_src_rect,91 const float z_value,
70 const GLuint gl_texture,92 const BlitData& blit_source,
71 const RGBAColor& blend);93 const RGBAColor& blend);
7294
95 // Draws a bunch of items at once.
96 void draw(const std::vector<Arguments>& arguments);
97
73private:98private:
74 MonochromeBlitProgram();99 MonochromeBlitProgram();
75100
76 std::unique_ptr<BlitProgram> blit_program_;101 std::unique_ptr<BlitProgram> blit_program_;
77102
78 // Uniforms.
79 GLint u_blend_;
80
81 DISALLOW_COPY_AND_ASSIGN(MonochromeBlitProgram);103 DISALLOW_COPY_AND_ASSIGN(MonochromeBlitProgram);
82};104};
83105
84class BlendedBlitProgram {106class BlendedBlitProgram {
85public:107public:
108 struct Arguments {
109 FloatRect destination_rect;
110 float z_value;
111 BlitData texture;
112 BlitData mask;
113 RGBAColor blend;
114 BlendMode blend_mode;
115 };
116
86 // Returns the (singleton) instance of this class.117 // Returns the (singleton) instance of this class.
87 static BlendedBlitProgram& instance();118 static BlendedBlitProgram& instance();
88 ~BlendedBlitProgram();119 ~BlendedBlitProgram();
89120
90 // Draws the rectangle 'gl_src_rect' from the texture with the name121 // Draws the rectangle 'gl_src_rect' from the texture with the name
91 // 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All122 // 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All
92 // coordinates are in the OpenGL frame. The 'gl_texture_mask' is used to selectively apply123 // coordinates are in the OpenGL frame. The 'texture_mask' is used to selectively apply
93 // the 'blend'. This is used for blitting player colored images.124 // the 'blend'. This is used for blitting player colored images.
94 void draw(const FloatRect& gl_dest_rect,125 void draw(const FloatRect& gl_dest_rect,
95 const FloatRect& gl_src_rect,126 const float z_value,
96 const GLuint gl_texture_image,127 const BlitData& texture,
97 const GLuint gl_texture_mask,128 const BlitData& mask,
98 const RGBAColor& blend);129 const RGBAColor& blend);
130
131 // Draws a bunch of items at once.
132 void draw(const std::vector<Arguments>& arguments);
99133
100private:134private:
101 BlendedBlitProgram();135 BlendedBlitProgram();
102136
103 std::unique_ptr<BlitProgram> blit_program_;137 std::unique_ptr<BlitProgram> blit_program_;
104138
105 // Uniforms.
106 GLint u_blend_;
107 GLint u_mask_;
108
109 DISALLOW_COPY_AND_ASSIGN(BlendedBlitProgram);139 DISALLOW_COPY_AND_ASSIGN(BlendedBlitProgram);
110};140};
111141
112142
=== added file 'src/graphic/gl/coordinate_conversion.h'
--- src/graphic/gl/coordinate_conversion.h 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/coordinate_conversion.h 2016-01-05 11:29:18 +0000
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2006-2015 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20#ifndef WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
21#define WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
22
23#include "base/rect.h"
24#include "graphic/gl/blit_data.h"
25
26// Converts the pixel (x, y) in a texture to a gl coordinate in [0, 1].
27inline void pixel_to_gl_texture(const int width, const int height, float* x, float* y) {
28 *x = (*x / width);
29 *y = 1. - (*y / height);
30}
31
32// Converts the given pixel into an OpenGl point in the renderbuffer.
33inline void pixel_to_gl_renderbuffer(const int width, const int height, float* x, float* y) {
34 *x = (*x / width) * 2. - 1.;
35 *y = 1. - (*y / height) * 2.;
36}
37
38// Converts 'rect' given on a screen of 'width' x 'height' pixels into a rect
39// in opengl coordinates in a renderbuffer, i.e. in [-1, 1]. The returned
40// rectangle has positive width and height.
41inline FloatRect
42rect_to_gl_renderbuffer(const int width, const int height, const Rect& rect) {
43 float left = rect.x;
44 float top = rect.y;
45 float right = rect.x + rect.w;
46 float bottom = rect.y + rect.h;
47 pixel_to_gl_renderbuffer(width, height, &left, &top);
48 pixel_to_gl_renderbuffer(width, height, &right, &bottom);
49 return FloatRect(left, bottom, right - left, top - bottom);
50}
51
52// Converts 'rect' given on a texture of 'width' x 'height' pixels into a rect
53// in opengl coordinates in a texture, i.e. in [0, 1]. Texture pixels are sampled in their center.
54// The returned rectangle has positive width and height.
55inline FloatRect
56rect_to_gl_texture(const int width, const int height, const FloatRect& rect) {
57 float left = rect.x;
58 float top = rect.y;
59 float right = rect.x + rect.w;
60 float bottom = rect.y + rect.h;
61 pixel_to_gl_texture(width, height, &left, &top);
62 pixel_to_gl_texture(width, height, &right, &bottom);
63 return FloatRect(left, bottom, right - left, top - bottom);
64}
65
66// Convert 'blit_data' from pixel space into opengl space.
67inline FloatRect to_gl_texture(const BlitData& blit_data) {
68 return rect_to_gl_texture(
69 blit_data.parent_width, blit_data.parent_height,
70 FloatRect(blit_data.rect.x, blit_data.rect.y, blit_data.rect.w, blit_data.rect.h));
71}
72
73#endif // end of include guard: WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
074
=== modified file 'src/graphic/gl/dither_program.cc'
--- src/graphic/gl/dither_program.cc 2015-06-07 14:52:11 +0000
+++ src/graphic/gl/dither_program.cc 2016-01-05 11:29:18 +0000
@@ -20,6 +20,7 @@
20#include "graphic/gl/dither_program.h"20#include "graphic/gl/dither_program.h"
2121
22#include "base/wexception.h"22#include "base/wexception.h"
23#include "graphic/gl/coordinate_conversion.h"
23#include "graphic/gl/fields_to_draw.h"24#include "graphic/gl/fields_to_draw.h"
24#include "graphic/image_io.h"25#include "graphic/image_io.h"
25#include "graphic/texture.h"26#include "graphic/texture.h"
@@ -37,6 +38,8 @@
37attribute vec2 attr_texture_offset;38attribute vec2 attr_texture_offset;
38attribute vec2 attr_texture_position;39attribute vec2 attr_texture_position;
3940
41uniform float u_z_value;
42
40// Output of vertex shader.43// Output of vertex shader.
41varying float var_brightness;44varying float var_brightness;
42varying vec2 var_dither_texture_position;45varying vec2 var_dither_texture_position;
@@ -48,7 +51,7 @@
48 var_dither_texture_position = attr_dither_texture_position;51 var_dither_texture_position = attr_dither_texture_position;
49 var_texture_offset = attr_texture_offset;52 var_texture_offset = attr_texture_offset;
50 var_texture_position = attr_texture_position;53 var_texture_position = attr_texture_position;
51 gl_Position = vec4(attr_position, 0., 1.);54 gl_Position = vec4(attr_position, u_z_value, 1.);
52}55}
53)";56)";
5457
@@ -64,12 +67,18 @@
64varying vec2 var_texture_position;67varying vec2 var_texture_position;
65varying vec2 var_texture_offset;68varying vec2 var_texture_offset;
6669
70// TODO(sirver): This is a hack to make sure we are sampling inside of the
71// terrain texture. This is a common problem with OpenGL and texture atlases.
72#define MARGIN 1e-2
73
67void main() {74void main() {
68 vec4 clr = texture2D(u_terrain_texture,75 vec2 texture_fract = clamp(
69 var_texture_offset + u_texture_dimensions * fract(var_texture_position));76 fract(var_texture_position),
70 clr.rgb *= var_brightness;77 vec2(MARGIN, MARGIN),
71 clr.a = 1. - texture2D(u_dither_texture, var_dither_texture_position).a;78 vec2(1. - MARGIN, 1. - MARGIN));
72 gl_FragColor = clr;79 vec4 clr = texture2D(u_terrain_texture, var_texture_offset + u_texture_dimensions * texture_fract);
80 gl_FragColor = vec4(clr.rgb * var_brightness,
81 1. - texture2D(u_dither_texture, var_dither_texture_position).a);
73}82}
74)";83)";
7584
@@ -87,21 +96,22 @@
87 u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");96 u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");
88 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");97 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
89 u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");98 u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
99 u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
90100
91 dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));101 dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));
92102
93 glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());103 glBindTexture(GL_TEXTURE_2D, dither_mask_->blit_data().texture_id);
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP));104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP_TO_EDGE));
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP));105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP_TO_EDGE));
96 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(GL_LINEAR));106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(GL_LINEAR));
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_LINEAR));107 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_NEAREST));
98 glBindTexture(GL_TEXTURE_2D, 0);108 glBindTexture(GL_TEXTURE_2D, 0);
99}109}
100110
101DitherProgram::~DitherProgram() {}111DitherProgram::~DitherProgram() {}
102112
103void DitherProgram::add_vertex(const FieldsToDraw::Field& field,113void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
104 const int order_index,114 const TrianglePoint triangle_point,
105 const FloatPoint& texture_offset) {115 const FloatPoint& texture_offset) {
106 vertices_.emplace_back();116 vertices_.emplace_back();
107 PerVertexData& back = vertices_.back();117 PerVertexData& back = vertices_.back();
@@ -114,18 +124,18 @@
114 back.texture_offset_x = texture_offset.x;124 back.texture_offset_x = texture_offset.x;
115 back.texture_offset_y = texture_offset.y;125 back.texture_offset_y = texture_offset.y;
116126
117 switch (order_index) {127 switch (triangle_point) {
118 case 0:128 case TrianglePoint::kTopRight:
129 back.dither_texture_x = 1.;
130 back.dither_texture_y = 1.;
131 break;
132 case TrianglePoint::kTopLeft:
119 back.dither_texture_x = 0.;133 back.dither_texture_x = 0.;
120 back.dither_texture_y = 0.;134 back.dither_texture_y = 1.;
121 break;135 break;
122 case 1:136 case TrianglePoint::kBottomMiddle:
123 back.dither_texture_x = 1.;
124 back.dither_texture_y = 0.;
125 break;
126 case 2:
127 back.dither_texture_x = 0.5;137 back.dither_texture_x = 0.5;
128 back.dither_texture_y = 1.;138 back.dither_texture_y = 0.;
129 break;139 break;
130 default:140 default:
131 throw wexception("Never here.");141 throw wexception("Never here.");
@@ -149,14 +159,14 @@
149 if (terrains.get(my_terrain).dither_layer() <159 if (terrains.get(my_terrain).dither_layer() <
150 other_terrain_description.dither_layer()) {160 other_terrain_description.dither_layer()) {
151 const FloatPoint texture_offset =161 const FloatPoint texture_offset =
152 other_terrain_description.get_texture(gametime).texture_coordinates().top_left();162 to_gl_texture(other_terrain_description.get_texture(gametime).blit_data()).origin();
153 add_vertex(fields_to_draw.at(idx1), 0, texture_offset);163 add_vertex(fields_to_draw.at(idx1), TrianglePoint::kTopRight, texture_offset);
154 add_vertex(fields_to_draw.at(idx2), 1, texture_offset);164 add_vertex(fields_to_draw.at(idx2), TrianglePoint::kTopLeft, texture_offset);
155 add_vertex(fields_to_draw.at(idx3), 2, texture_offset);165 add_vertex(fields_to_draw.at(idx3), TrianglePoint::kBottomMiddle, texture_offset);
156 }166 }
157}167}
158168
159void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {169void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h, const float z_value) {
160 glUseProgram(gl_program_.object());170 glUseProgram(gl_program_.object());
161171
162 glEnableVertexAttribArray(attr_brightness_);172 glEnableVertexAttribArray(attr_brightness_);
@@ -165,35 +175,31 @@
165 glEnableVertexAttribArray(attr_texture_offset_);175 glEnableVertexAttribArray(attr_texture_offset_);
166 glEnableVertexAttribArray(attr_texture_position_);176 glEnableVertexAttribArray(attr_texture_position_);
167177
168 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());178 gl_array_buffer_.bind();
169 glBufferData(GL_ARRAY_BUFFER,179 gl_array_buffer_.update(vertices_);
170 sizeof(PerVertexData) * vertices_.size(),
171 vertices_.data(),
172 GL_STREAM_DRAW);
173180
174 const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {181 Gl::vertex_attrib_pointer(
175 glVertexAttribPointer(vertex_index,182 attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
176 num_items,183 Gl::vertex_attrib_pointer(attr_dither_texture_position_,
177 GL_FLOAT,184 2,
178 GL_FALSE,185 sizeof(PerVertexData),
179 sizeof(PerVertexData),186 offsetof(PerVertexData, dither_texture_x));
180 reinterpret_cast<void*>(offset));187 Gl::vertex_attrib_pointer(attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
181 };188 Gl::vertex_attrib_pointer(
182 set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));189 attr_texture_offset_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_offset_x));
183 set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));190 Gl::vertex_attrib_pointer(
184 set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));191 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
185 set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
186 set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
187192
188 glBindBuffer(GL_ARRAY_BUFFER, 0);193 glBindBuffer(GL_ARRAY_BUFFER, 0);
189194
190 // Set the sampler texture unit to 0195 // Set the sampler texture unit to 0
191 glActiveTexture(GL_TEXTURE0);196 glActiveTexture(GL_TEXTURE0);
192 glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());197 glBindTexture(GL_TEXTURE_2D, dither_mask_->blit_data().texture_id);
193198
194 glActiveTexture(GL_TEXTURE1);199 glActiveTexture(GL_TEXTURE1);
195 glBindTexture(GL_TEXTURE_2D, gl_texture);200 glBindTexture(GL_TEXTURE_2D, gl_texture);
196201
202 glUniform1f(u_z_value_, z_value);
197 glUniform1i(u_dither_texture_, 0);203 glUniform1i(u_dither_texture_, 0);
198 glUniform1i(u_terrain_texture_, 1);204 glUniform1i(u_terrain_texture_, 1);
199 glUniform2f(u_texture_dimensions_, texture_w, texture_h);205 glUniform2f(u_texture_dimensions_, texture_w, texture_h);
@@ -213,7 +219,8 @@
213219
214void DitherProgram::draw(const uint32_t gametime,220void DitherProgram::draw(const uint32_t gametime,
215 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,221 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
216 const FieldsToDraw& fields_to_draw) {222 const FieldsToDraw& fields_to_draw,
223 const float z_value) {
217 // This method expects that all terrains have the same dimensions and that224 // This method expects that all terrains have the same dimensions and that
218 // all are packed into the same texture atlas, i.e. all are in the same GL225 // all are packed into the same texture atlas, i.e. all are in the same GL
219 // texture. It does not check for this invariance for speeds sake.226 // texture. It does not check for this invariance for speeds sake.
@@ -270,6 +277,10 @@
270 }277 }
271 }278 }
272279
273 const Texture& texture = terrains.get(0).get_texture(0);280 const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
274 gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);281 const FloatRect texture_coordinates = to_gl_texture(blit_data);
282 gl_draw(blit_data.texture_id,
283 texture_coordinates.w,
284 texture_coordinates.h,
285 z_value);
275}286}
276287
=== modified file 'src/graphic/gl/dither_program.h'
--- src/graphic/gl/dither_program.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/dither_program.h 2016-01-05 11:29:18 +0000
@@ -38,9 +38,16 @@
38 // Draws the terrain.38 // Draws the terrain.
39 void draw(uint32_t gametime,39 void draw(uint32_t gametime,
40 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,40 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
41 const FieldsToDraw& fields_to_draw);41 const FieldsToDraw& fields_to_draw,
42 float z_value);
4243
43private:44private:
45 enum class TrianglePoint {
46 kTopLeft,
47 kTopRight,
48 kBottomMiddle,
49 };
50
44 // Adds the triangle between the indexes (which index 'fields_to_draw') to51 // Adds the triangle between the indexes (which index 'fields_to_draw') to
45 // vertices_ if the my_terrain != other_terrain and the dither_layer()52 // vertices_ if the my_terrain != other_terrain and the dither_layer()
46 // agree.53 // agree.
@@ -57,7 +64,9 @@
57 // Adds the 'field' as an vertex to the 'vertices_'. The 'order_index'64 // Adds the 'field' as an vertex to the 'vertices_'. The 'order_index'
58 // defines which texture position in the dithering texture will be used for65 // defines which texture position in the dithering texture will be used for
59 // this vertex.66 // this vertex.
60 void add_vertex(const FieldsToDraw::Field& field, int order_index, const FloatPoint& texture_offset);67 void add_vertex(const FieldsToDraw::Field& field,
68 TrianglePoint triangle_point,
69 const FloatPoint& texture_offset);
6170
62 struct PerVertexData {71 struct PerVertexData {
63 float gl_x;72 float gl_x;
@@ -72,13 +81,13 @@
72 };81 };
7382
74 // Call through to GL.83 // Call through to GL.
75 void gl_draw(int gl_texture, float texture_w, float texture_h);84 void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
7685
77 // The program used for drawing the terrain.86 // The program used for drawing the terrain.
78 Gl::Program gl_program_;87 Gl::Program gl_program_;
7988
80 // The buffer that contains the data to be rendered.89 // The buffer that contains the data to be rendered.
81 Gl::Buffer gl_array_buffer_;90 Gl::Buffer<PerVertexData> gl_array_buffer_;
8291
83 // Attributes.92 // Attributes.
84 GLint attr_brightness_;93 GLint attr_brightness_;
@@ -91,6 +100,7 @@
91 GLint u_dither_texture_;100 GLint u_dither_texture_;
92 GLint u_terrain_texture_;101 GLint u_terrain_texture_;
93 GLint u_texture_dimensions_;102 GLint u_texture_dimensions_;
103 GLint u_z_value_;
94104
95 // The texture mask for the dithering step.105 // The texture mask for the dithering step.
96 std::unique_ptr<Texture> dither_mask_;106 std::unique_ptr<Texture> dither_mask_;
97107
=== modified file 'src/graphic/gl/draw_line_program.cc'
--- src/graphic/gl/draw_line_program.cc 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/draw_line_program.cc 2016-01-05 11:29:18 +0000
@@ -19,6 +19,8 @@
1919
20#include "graphic/gl/draw_line_program.h"20#include "graphic/gl/draw_line_program.h"
2121
22#include <algorithm>
23#include <cassert>
22#include <vector>24#include <vector>
2325
24#include "base/log.h"26#include "base/log.h"
@@ -29,23 +31,33 @@
29#version 12031#version 120
3032
31// Attributes.33// Attributes.
32attribute vec2 attr_position;34attribute vec3 attr_position;
35attribute vec3 attr_color;
36
37varying vec3 var_color;
3338
34void main() {39void main() {
35 gl_Position = vec4(attr_position, 0., 1.);40 var_color = attr_color;
41 gl_Position = vec4(attr_position, 1.);
36}42}
37)";43)";
3844
39const char kDrawLineFragmentShader[] = R"(45const char kDrawLineFragmentShader[] = R"(
40#version 12046#version 120
4147
42uniform ivec3 u_color;48varying vec3 var_color;
4349
44void main() {50void main() {
45 gl_FragColor = vec4(vec3(u_color) / 255., 1.);51 gl_FragColor = vec4(var_color.rgb, 1.);
46}52}
47)";53)";
4854
55struct DrawBatch {
56 int offset;
57 int count;
58 int line_width;
59};
60
49} // namespace61} // namespace
5062
51// static63// static
@@ -58,37 +70,81 @@
58 gl_program_.build(kDrawLineVertexShader, kDrawLineFragmentShader);70 gl_program_.build(kDrawLineVertexShader, kDrawLineFragmentShader);
5971
60 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");72 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
61 u_color_ = glGetUniformLocation(gl_program_.object(), "u_color");73 attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
62
63}74}
6475
65void DrawLineProgram::draw(const float x1,76void DrawLineProgram::draw(const FloatPoint& start,
66 const float y1,77 const FloatPoint& end,
67 const float x2,78 const float z_value,
68 const float y2,
69 const RGBColor& color,79 const RGBColor& color,
70 const int line_width) {80 int line_width) {
81 draw({Arguments{FloatRect(start.x, start.y, end.x - start.x, end.y - start.y),
82 z_value,
83 color,
84 static_cast<uint8_t>(line_width),
85 BlendMode::Copy}});
86}
87
88void DrawLineProgram::draw(std::vector<Arguments> arguments) {
89 size_t i = 0;
90
71 glUseProgram(gl_program_.object());91 glUseProgram(gl_program_.object());
72 glEnableVertexAttribArray(attr_position_);92 glEnableVertexAttribArray(attr_position_);
7393 glEnableVertexAttribArray(attr_color_);
74 const std::vector<PerVertexData> vertices = {{x1, y1}, {x2, y2}};94
7595 gl_array_buffer_.bind();
76 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());96
77 glBufferData(97 Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
78 GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STREAM_DRAW);98 Gl::vertex_attrib_pointer(attr_color_, 3, sizeof(PerVertexData), offsetof(PerVertexData, color_r));
79 glVertexAttribPointer(attr_position_,99
80 2,100 vertices_.clear();
81 GL_FLOAT,101
82 GL_FALSE,102 std::vector<DrawBatch> draw_batches;
83 sizeof(PerVertexData),103 int offset = 0;
84 reinterpret_cast<void*>(0));104 while (i < arguments.size()) {
85105 const Arguments& template_args = arguments[i];
86 glUniform3i(u_color_, color.r, color.g, color.b);106
87107 while (i < arguments.size()) {
88 glLineWidth(line_width);108 const Arguments& current_args = arguments[i];
89 glDrawArrays(GL_LINES, 0, 2);109 if (current_args.line_width != template_args.line_width) {
110 break;
111 }
112 // We do not support anything else for drawing lines, really.
113 assert(current_args.blend_mode == BlendMode::Copy);
114
115 vertices_.emplace_back(current_args.destination_rect.x,
116 current_args.destination_rect.y,
117 current_args.z_value,
118 current_args.color.r / 255.,
119 current_args.color.g / 255.,
120 current_args.color.b / 255.);
121
122 vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
123 current_args.destination_rect.y + current_args.destination_rect.h,
124 current_args.z_value,
125 current_args.color.r / 255.,
126 current_args.color.g / 255.,
127 current_args.color.b / 255.);
128 ++i;
129 }
130
131 draw_batches.emplace_back(
132 DrawBatch{offset, static_cast<int>(vertices_.size() - offset), template_args.line_width});
133 offset = vertices_.size();
134 }
135
136 gl_array_buffer_.update(vertices_);
137
138 // Now do the draw calls.
139 for (const auto& draw_arg : draw_batches) {
140 glLineWidth(draw_arg.line_width);
141 glDrawArrays(GL_LINES, draw_arg.offset, draw_arg.count);
142 }
90143
91 glBindBuffer(GL_ARRAY_BUFFER, 0);144 glBindBuffer(GL_ARRAY_BUFFER, 0);
145
92 glDisableVertexAttribArray(attr_position_);146 glDisableVertexAttribArray(attr_position_);
147 glDisableVertexAttribArray(attr_color_);
148
93 glUseProgram(0);149 glUseProgram(0);
94}150}
95151
=== modified file 'src/graphic/gl/draw_line_program.h'
--- src/graphic/gl/draw_line_program.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/draw_line_program.h 2016-01-05 11:29:18 +0000
@@ -20,37 +20,76 @@
20#ifndef WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H20#ifndef WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H
21#define WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H21#define WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H
2222
23#include <vector>
24
25#include "base/point.h"
26#include "base/rect.h"
27#include "graphic/blend_mode.h"
23#include "graphic/color.h"28#include "graphic/color.h"
24#include "graphic/gl/utils.h"29#include "graphic/gl/utils.h"
2530
26class DrawLineProgram {31class DrawLineProgram {
27public:32public:
33 struct Arguments {
34 // The line is drawn from the top left to the bottom right of
35 // this rectangle.
36 FloatRect destination_rect;
37 float z_value;
38 RGBAColor color;
39 uint8_t line_width;
40 BlendMode blend_mode;
41 };
42
28 // Returns the (singleton) instance of this class.43 // Returns the (singleton) instance of this class.
29 static DrawLineProgram& instance();44 static DrawLineProgram& instance();
3045
31 // Draws a line from (x1, y1) to (x2, y2) which are in gl46 // Draws a line from (x1, y1) to (x2, y2) which are in gl
32 // coordinates in 'color' with a 'line_width' in pixels.47 // coordinates in 'color' with a 'line_width' in pixels.
33 void draw(float x1, float y1, float x2, float y2, const RGBColor& color, int line_width);48 void draw(const FloatPoint& start,
49 const FloatPoint& end,
50 const float z_value,
51 const RGBColor& color,
52 const int line_width);
53
54 void draw(std::vector<Arguments> arguments);
55
3456
35private:57private:
36 DrawLineProgram();58 DrawLineProgram();
3759
38 struct PerVertexData {60 struct PerVertexData {
39 float gl_x, gl_y;61 PerVertexData(float init_gl_x,
62 float init_gl_y,
63 float init_gl_z,
64 float init_color_r,
65 float init_color_g,
66 float init_color_b)
67 : gl_x(init_gl_x),
68 gl_y(init_gl_y),
69 gl_z(init_gl_z),
70 color_r(init_color_r),
71 color_g(init_color_g),
72 color_b(init_color_b) {
73 }
74
75 float gl_x, gl_y, gl_z;
76 float color_r, color_g, color_b;
40 };77 };
41 static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");78 static_assert(sizeof(PerVertexData) == 24, "Wrong padding.");
79
80 // This is only kept around so that we do not constantly
81 // allocate memory for it.
82 std::vector<PerVertexData> vertices_;
4283
43 // The buffer that contains the vertices for rendering.84 // The buffer that contains the vertices for rendering.
44 Gl::Buffer gl_array_buffer_;85 Gl::Buffer<PerVertexData> gl_array_buffer_;
4586
46 // The program.87 // The program.
47 Gl::Program gl_program_;88 Gl::Program gl_program_;
4889
49 // Attributes.90 // Attributes.
50 GLint attr_position_;91 GLint attr_position_;
5192 GLint attr_color_;
52 // Uniforms.
53 GLint u_color_;
5493
55 DISALLOW_COPY_AND_ASSIGN(DrawLineProgram);94 DISALLOW_COPY_AND_ASSIGN(DrawLineProgram);
56};95};
5796
=== modified file 'src/graphic/gl/fields_to_draw.h'
--- src/graphic/gl/fields_to_draw.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/fields_to_draw.h 2016-01-05 11:29:18 +0000
@@ -43,14 +43,20 @@
43 const RoadTextures* road_textures; // Road Textures to use for drawing.43 const RoadTextures* road_textures; // Road Textures to use for drawing.
44 };44 };
4545
46 FieldsToDraw(int minfx, int maxfx, int minfy, int maxfy)46 FieldsToDraw() = default;
47 : min_fx_(minfx),47
48 max_fx_(maxfx),48 // Resize this fields to draw for reuse.
49 min_fy_(minfy),49 void reset(int minfx, int maxfx, int minfy, int maxfy) {
50 max_fy_(maxfy),50 min_fx_ = minfx;
51 w_(max_fx_ - min_fx_ + 1),51 max_fx_ = maxfx;
52 h_(max_fy_ - min_fy_ + 1) {52 min_fy_ = minfy;
53 fields_.resize(w_ * h_);53 max_fy_ = maxfy;
54 w_ = max_fx_ - min_fx_ + 1;
55 h_ = max_fy_ - min_fy_ + 1;
56 const size_t size = w_ * h_;
57 if (fields_.size() != size) {
58 fields_.resize(size);
59 }
54 }60 }
5561
56 // Calculates the index of the given field with ('fx', 'fy') being geometric62 // Calculates the index of the given field with ('fx', 'fy') being geometric
@@ -84,14 +90,14 @@
8490
85private:91private:
86 // Minimum and maximum field coordinates (geometric) to render. Can be negative.92 // Minimum and maximum field coordinates (geometric) to render. Can be negative.
87 const int min_fx_;93 int min_fx_;
88 const int max_fx_;94 int max_fx_;
89 const int min_fy_;95 int min_fy_;
90 const int max_fy_;96 int max_fy_;
9197
92 // Width and height in number of fields.98 // Width and height in number of fields.
93 const int w_;99 int w_;
94 const int h_;100 int h_;
95101
96 std::vector<Field> fields_;102 std::vector<Field> fields_;
97};103};
98104
=== modified file 'src/graphic/gl/fill_rect_program.cc'
--- src/graphic/gl/fill_rect_program.cc 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/fill_rect_program.cc 2016-01-05 11:29:18 +0000
@@ -22,6 +22,7 @@
22#include <vector>22#include <vector>
2323
24#include "base/log.h"24#include "base/log.h"
25#include "base/wexception.h"
2526
26namespace {27namespace {
2728
@@ -29,26 +30,24 @@
29#version 12030#version 120
3031
31// Attributes.32// Attributes.
32attribute vec2 attr_position;33attribute vec3 attr_position;
3334attribute vec4 attr_color;
34// Uniforms.35
35uniform vec4 u_rect;36varying vec4 var_color;
36
3737
38void main() {38void main() {
39 float x = u_rect.x + attr_position.x * u_rect.z;39 var_color = attr_color;
40 float y = u_rect.y + attr_position.y * u_rect.w;40 gl_Position = vec4(attr_position, 1.);
41 gl_Position = vec4(x, y, 0., 1.);
42}41}
43)";42)";
4443
45const char kFillRectFragmentShader[] = R"(44const char kFillRectFragmentShader[] = R"(
46#version 12045#version 120
4746
48uniform ivec4 u_color;47varying vec4 var_color;
4948
50void main() {49void main() {
51 gl_FragColor = vec4(u_color) / 255.;50 gl_FragColor = var_color;
52}51}
53)";52)";
5453
@@ -64,49 +63,144 @@
64 gl_program_.build(kFillRectVertexShader, kFillRectFragmentShader);63 gl_program_.build(kFillRectVertexShader, kFillRectFragmentShader);
6564
66 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");65 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
6766 attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
68 u_color_ = glGetUniformLocation(gl_program_.object(), "u_color");67}
69 u_rect_ = glGetUniformLocation(gl_program_.object(), "u_rect");68
7069void FillRectProgram::draw(const FloatRect& destination_rect,
71 std::vector<PerVertexData> vertices;70 const float z_value,
72 vertices.push_back(PerVertexData71 const RGBAColor& color,
73 {0., 1.});72 const BlendMode blend_mode) {
74 vertices.push_back(PerVertexData73 draw({Arguments{destination_rect, z_value, color, blend_mode} });
75 {1., 1.});74}
76 vertices.push_back(PerVertexData75
77 {0., 0.});76void FillRectProgram::draw(const std::vector<Arguments>& arguments) {
78 vertices.push_back(PerVertexData77 size_t i = 0;
79 {1., 0.});78
8079 while (i < arguments.size()) {
81 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());80 vertices_.clear();
82 glBufferData(81 const Arguments& template_args = arguments[i];
83 GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);82
84 glVertexAttribPointer(attr_position_,83 // This method does 3 things:
85 2,84 // - if blend_mode is Copy, we will copy color into the destination
86 GL_FLOAT,85 // pixels without blending.
87 GL_FALSE,86 // - if blend_mode is Alpha and color.r < 0, we will
88 sizeof(PerVertexData),87 // GL_FUNC_REVERSE_SUBTRACT color.r from all RGB values in the
89 reinterpret_cast<void*>(0));88 // destination buffer. color.a should be 0 for this.
90 glBindBuffer(GL_ARRAY_BUFFER, 0);89 // - if blend_mode is Alpha and color.r > 0, we will
91}90 // GL_ADD color.r to all RGB values in the destination buffer.
9291 // color.a should be 0 for this.
93void FillRectProgram::draw(const FloatRect& gl_dst_rect, const RGBAColor& color) {92
94 glUseProgram(gl_program_.object());93 // The simple trick here is to fill the rect, but using a different glBlendFunc that will sum
95 glEnableVertexAttribArray(attr_position_);94 // src and target (or subtract them if factor is negative).
96 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());95 switch (template_args.blend_mode) {
9796 case BlendMode::Subtract:
98 glVertexAttribPointer(attr_position_,97 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
99 2,98 /* fallthrough intended */
100 GL_FLOAT,99 case BlendMode::UseAlpha:
101 GL_FALSE,100 glBlendFunc(GL_ONE, GL_ONE);
102 sizeof(PerVertexData),101 break;
103 reinterpret_cast<void*>(0));102
104103 case BlendMode::Copy:
105 glUniform4f(u_rect_, gl_dst_rect.x, gl_dst_rect.y, gl_dst_rect.w, gl_dst_rect.h);104 glDisable(GL_BLEND);
106 glUniform4i(u_color_, color.r, color.g, color.b, color.a);105 break;
107106
108 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);107 default:
108 break;
109 }
110
111 glUseProgram(gl_program_.object());
112
113 gl_array_buffer_.bind();
114
115 glEnableVertexAttribArray(attr_position_);
116 glEnableVertexAttribArray(attr_color_);
117
118 // Batch common rectangles up.
119 while (i < arguments.size()) {
120 const Arguments& current_args = arguments[i];
121 if (current_args.blend_mode != template_args.blend_mode) {
122 break;
123 }
124
125 const float r = current_args.color.r / 255.;
126 const float g = current_args.color.g / 255.;
127 const float b = current_args.color.b / 255.;
128 const float a = current_args.color.a / 255.;
129
130 // First triangle.
131 vertices_.emplace_back(current_args.destination_rect.x,
132 current_args.destination_rect.y,
133 current_args.z_value,
134 r,
135 g,
136 b,
137 a);
138 vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
139 current_args.destination_rect.y,
140 current_args.z_value,
141 r,
142 g,
143 b,
144 a);
145 vertices_.emplace_back(current_args.destination_rect.x,
146 current_args.destination_rect.y + current_args.destination_rect.h,
147 current_args.z_value,
148 r,
149 g,
150 b,
151 a);
152
153 // Second triangle.
154 vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
155 current_args.destination_rect.y,
156 current_args.z_value,
157 r,
158 g,
159 b,
160 a);
161 vertices_.emplace_back(current_args.destination_rect.x,
162 current_args.destination_rect.y + current_args.destination_rect.h,
163 current_args.z_value,
164 r,
165 g,
166 b,
167 a);
168 vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
169 current_args.destination_rect.y + current_args.destination_rect.h,
170 current_args.z_value,
171 r,
172 g,
173 b,
174 a);
175 ++i;
176 }
177
178 gl_array_buffer_.update(vertices_);
179
180 Gl::vertex_attrib_pointer(
181 attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
182 Gl::vertex_attrib_pointer(attr_color_, 4, sizeof(PerVertexData), offsetof(PerVertexData, r));
183
184 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
185
186 switch (template_args.blend_mode) {
187 case BlendMode::Subtract:
188 glBlendEquation(GL_FUNC_ADD);
189 /* fallthrough intended */
190 case BlendMode::UseAlpha:
191 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
192 break;
193
194 case BlendMode::Copy:
195 glEnable(GL_BLEND);
196 break;
197
198 default:
199 break;
200 }
201 }
109202
110 glDisableVertexAttribArray(attr_position_);203 glDisableVertexAttribArray(attr_position_);
204 glDisableVertexAttribArray(attr_color_);
111 glBindBuffer(GL_ARRAY_BUFFER, 0);205 glBindBuffer(GL_ARRAY_BUFFER, 0);
112}206}
113207
=== modified file 'src/graphic/gl/fill_rect_program.h'
--- src/graphic/gl/fill_rect_program.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/fill_rect_program.h 2016-01-05 11:29:18 +0000
@@ -20,39 +20,73 @@
20#ifndef WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H20#ifndef WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H
21#define WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H21#define WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H
2222
23#include <vector>
24
23#include "base/rect.h"25#include "base/rect.h"
26#include "graphic/blend_mode.h"
24#include "graphic/color.h"27#include "graphic/color.h"
25#include "graphic/gl/utils.h"28#include "graphic/gl/utils.h"
2629
27class FillRectProgram {30class FillRectProgram {
28public:31public:
32 struct Arguments {
33 FloatRect destination_rect;
34 float z_value;
35 RGBAColor color;
36 BlendMode blend_mode;
37 };
38
29 // Returns the (singleton) instance of this class.39 // Returns the (singleton) instance of this class.
30 static FillRectProgram& instance();40 static FillRectProgram& instance();
3141
32 // Fills a solid rect in 'color' into the currently activated42 // Fills a solid rect in 'color'. If blend_mode is BlendMode::UseAlpha, this
33 // framebuffer.43 // will brighten the rect, if it is BlendMode::Subtract it darkens it.
34 void draw(const FloatRect& gl_dst_rect, const RGBAColor& color);44 void draw(const FloatRect& destination_rect,
45 float z_value,
46 const RGBAColor& color,
47 BlendMode blend_mode);
48
49
50 void draw(const std::vector<Arguments>& arguments);
3551
36private:52private:
37 FillRectProgram();53 FillRectProgram();
3854
39 struct PerVertexData {55 struct PerVertexData {
40 float gl_x, gl_y;56 PerVertexData(float init_gl_x,
57 float init_gl_y,
58 float init_gl_z,
59 float init_r,
60 float init_g,
61 float init_b,
62 float init_a)
63 : gl_x(init_gl_x),
64 gl_y(init_gl_y),
65 gl_z(init_gl_z),
66 r(init_r),
67 g(init_g),
68 b(init_b),
69 a(init_a) {
70 }
71
72 float gl_x, gl_y, gl_z;
73 float r, g, b, a;
41 };74 };
42 static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");75 static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
76
77 // This is only kept around so that we do not constantly allocate memory for
78 // it.
79 std::vector<PerVertexData> vertices_;
4380
44 // The buffer that will contain the quad for rendering.81 // The buffer that will contain the quad for rendering.
45 Gl::Buffer gl_array_buffer_;82 Gl::Buffer<PerVertexData> gl_array_buffer_;
4683
47 // The program.84 // The program.
48 Gl::Program gl_program_;85 Gl::Program gl_program_;
4986
50 // Attributes.87 // Attributes.
51 GLint attr_position_;88 GLint attr_position_;
5289 GLint attr_color_;
53 // Uniforms.
54 GLint u_rect_;
55 GLint u_color_;
5690
57 DISALLOW_COPY_AND_ASSIGN(FillRectProgram);91 DISALLOW_COPY_AND_ASSIGN(FillRectProgram);
58};92};
5993
=== modified file 'src/graphic/gl/road_program.cc'
--- src/graphic/gl/road_program.cc 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/road_program.cc 2016-01-05 11:29:18 +0000
@@ -23,6 +23,7 @@
23#include <cmath>23#include <cmath>
2424
25#include "base/log.h"25#include "base/log.h"
26#include "graphic/gl/coordinate_conversion.h"
26#include "graphic/gl/fields_to_draw.h"27#include "graphic/gl/fields_to_draw.h"
27#include "graphic/graphic.h"28#include "graphic/graphic.h"
28#include "graphic/image_io.h"29#include "graphic/image_io.h"
@@ -40,6 +41,8 @@
40attribute vec2 attr_texture_position;41attribute vec2 attr_texture_position;
41attribute float attr_brightness;42attribute float attr_brightness;
4243
44uniform float u_z_value;
45
43// Outputs.46// Outputs.
44varying vec2 out_texture_position;47varying vec2 out_texture_position;
45varying float out_brightness;48varying float out_brightness;
@@ -47,7 +50,7 @@
47void main() {50void main() {
48 out_texture_position = attr_texture_position;51 out_texture_position = attr_texture_position;
49 out_brightness = attr_brightness;52 out_brightness = attr_brightness;
50 gl_Position = vec4(attr_position, 0., 1.);53 gl_Position = vec4(attr_position, u_z_value, 1.);
51}54}
52)";55)";
5356
@@ -73,22 +76,23 @@
73 gl_program_.build(kRoadVertexShader, kRoadFragmentShader);76 gl_program_.build(kRoadVertexShader, kRoadFragmentShader);
7477
75 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");78 attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
76 attr_texture_position_ =79 attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
77 glGetAttribLocation(gl_program_.object(), "attr_texture_position");
78 attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");80 attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
7981
82 u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
80 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");83 u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
81}84}
8285
83RoadProgram::~RoadProgram() {86RoadProgram::~RoadProgram() {
84}87}
8588
86void RoadProgram::add_road(const Surface& surface,89void RoadProgram::add_road(const int renderbuffer_width,
90 const int renderbuffer_height,
87 const FieldsToDraw::Field& start,91 const FieldsToDraw::Field& start,
88 const FieldsToDraw::Field& end,92 const FieldsToDraw::Field& end,
89 const Widelands::RoadType road_type,93 const Widelands::RoadType road_type,
90 const Direction direction,94 const Direction direction,
91 int* gl_texture) {95 uint32_t* gl_texture) {
92 // The thickness of the road in pixels on screen.96 // The thickness of the road in pixels on screen.
93 static constexpr float kRoadThicknessInPixels = 5.;97 static constexpr float kRoadThicknessInPixels = 5.;
9498
@@ -111,14 +115,14 @@
111 road_type == Widelands::RoadType::kNormal ?115 road_type == Widelands::RoadType::kNormal ?
112 start.road_textures->get_normal_texture(start.fx, start.fy, direction) :116 start.road_textures->get_normal_texture(start.fx, start.fy, direction) :
113 start.road_textures->get_busy_texture(start.fx, start.fy, direction);117 start.road_textures->get_busy_texture(start.fx, start.fy, direction);
114 if (*gl_texture == -1) {118 if (*gl_texture == 0) {
115 *gl_texture = texture.get_gl_texture();119 *gl_texture = texture.blit_data().texture_id;
116 }120 }
117 // We assume that all road textures are in the same OpenGL texture, i.e. in121 // We assume that all road textures are in the same OpenGL texture, i.e. in
118 // one texture atlas.122 // one texture atlas.
119 assert(*gl_texture == texture.get_gl_texture());123 assert(*gl_texture == texture.blit_data().texture_id);
120124
121 const auto& texture_rect = texture.texture_coordinates();125 const FloatRect texture_rect = to_gl_texture(texture.blit_data());
122126
123 vertices_.emplace_back(PerVertexData{127 vertices_.emplace_back(PerVertexData{
124 start.pixel_x - road_overshoot_x + road_thickness_x,128 start.pixel_x - road_overshoot_x + road_thickness_x,
@@ -127,16 +131,18 @@
127 texture_rect.y,131 texture_rect.y,
128 start.brightness,132 start.brightness,
129 });133 });
130 surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);134 pixel_to_gl_renderbuffer(
135 renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
131136
132 vertices_.emplace_back(PerVertexData{137 vertices_.emplace_back(PerVertexData{
133 start.pixel_x - road_overshoot_x - road_thickness_x,138 start.pixel_x - road_overshoot_x - road_thickness_x,
134 start.pixel_y - road_overshoot_y - road_thickness_y,139 start.pixel_y - road_overshoot_y - road_thickness_y,
135 texture_rect.x,140 texture_rect.x,
136 texture_rect.y + texture_rect.h,141 texture_rect.y + texture_rect.h,
137 start.brightness,142 start.brightness,
138 });143 });
139 surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);144 pixel_to_gl_renderbuffer(
145 renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
140146
141 vertices_.emplace_back(PerVertexData{147 vertices_.emplace_back(PerVertexData{
142 end.pixel_x + road_overshoot_x + road_thickness_x,148 end.pixel_x + road_overshoot_x + road_thickness_x,
@@ -145,7 +151,8 @@
145 texture_rect.y,151 texture_rect.y,
146 end.brightness,152 end.brightness,
147 });153 });
148 surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);154 pixel_to_gl_renderbuffer(
155 renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
149156
150 // As OpenGl does not support drawing quads in modern days and we have a157 // As OpenGl does not support drawing quads in modern days and we have a
151 // bunch of roads that might not be neighbored, we need to add two triangles158 // bunch of roads that might not be neighbored, we need to add two triangles
@@ -161,13 +168,17 @@
161 texture_rect.y + texture_rect.h,168 texture_rect.y + texture_rect.h,
162 end.brightness,169 end.brightness,
163 });170 });
164 surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);171 pixel_to_gl_renderbuffer(
172 renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
165}173}
166174
167void RoadProgram::draw(const Surface& surface, const FieldsToDraw& fields_to_draw) {175void RoadProgram::draw(const int renderbuffer_width,
176 const int renderbuffer_height,
177 const FieldsToDraw& fields_to_draw,
178 float z_value) {
168 vertices_.clear();179 vertices_.clear();
169180
170 int gl_texture = -1;181 uint32_t gl_texture = 0;
171 for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {182 for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
172 const FieldsToDraw::Field& field = fields_to_draw.at(current_index);183 const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
173184
@@ -175,9 +186,15 @@
175 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);186 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
176 if (rn_index != -1) {187 if (rn_index != -1) {
177 const Widelands::RoadType road =188 const Widelands::RoadType road =
178 static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);189 static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
179 if (road != Widelands::RoadType::kNone) {190 if (road != Widelands::RoadType::kNone) {
180 add_road(surface, field, fields_to_draw.at(rn_index), road, kEast, &gl_texture);191 add_road(renderbuffer_width,
192 renderbuffer_height,
193 field,
194 fields_to_draw.at(rn_index),
195 road,
196 kEast,
197 &gl_texture);
181 }198 }
182 }199 }
183200
@@ -185,9 +202,15 @@
185 const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);202 const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
186 if (brn_index != -1) {203 if (brn_index != -1) {
187 const Widelands::RoadType road =204 const Widelands::RoadType road =
188 static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);205 static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
189 if (road != Widelands::RoadType::kNone) {206 if (road != Widelands::RoadType::kNone) {
190 add_road(surface, field, fields_to_draw.at(brn_index), road, kSouthEast, &gl_texture);207 add_road(renderbuffer_width,
208 renderbuffer_height,
209 field,
210 fields_to_draw.at(brn_index),
211 road,
212 kSouthEast,
213 &gl_texture);
191 }214 }
192 }215 }
193216
@@ -196,9 +219,15 @@
196 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);219 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
197 if (bln_index != -1) {220 if (bln_index != -1) {
198 const Widelands::RoadType road =221 const Widelands::RoadType road =
199 static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);222 static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
200 if (road != Widelands::RoadType::kNone) {223 if (road != Widelands::RoadType::kNone) {
201 add_road(surface, field, fields_to_draw.at(bln_index), road, kSouthWest, &gl_texture);224 add_road(renderbuffer_width,
225 renderbuffer_height,
226 field,
227 fields_to_draw.at(bln_index),
228 road,
229 kSouthWest,
230 &gl_texture);
202 }231 }
203 }232 }
204 }233 }
@@ -209,21 +238,15 @@
209 glEnableVertexAttribArray(attr_texture_position_);238 glEnableVertexAttribArray(attr_texture_position_);
210 glEnableVertexAttribArray(attr_brightness_);239 glEnableVertexAttribArray(attr_brightness_);
211240
212 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());241 gl_array_buffer_.bind();
213 glBufferData(242 gl_array_buffer_.update(vertices_);
214 GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices_.size(), vertices_.data(), GL_STREAM_DRAW);
215243
216 const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {244 Gl::vertex_attrib_pointer(
217 glVertexAttribPointer(vertex_index,245 attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
218 num_items,246 Gl::vertex_attrib_pointer(
219 GL_FLOAT,247 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
220 GL_FALSE,248 Gl::vertex_attrib_pointer(
221 sizeof(PerVertexData),249 attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
222 reinterpret_cast<void*>(offset));
223 };
224 set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
225 set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
226 set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
227250
228 glBindBuffer(GL_ARRAY_BUFFER, 0);251 glBindBuffer(GL_ARRAY_BUFFER, 0);
229252
@@ -233,6 +256,8 @@
233256
234 glUniform1i(u_texture_, 0);257 glUniform1i(u_texture_, 0);
235258
259 glUniform1f(u_z_value_, z_value);
260
236 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());261 glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
237262
238 glDisableVertexAttribArray(attr_position_);263 glDisableVertexAttribArray(attr_position_);
239264
=== modified file 'src/graphic/gl/road_program.h'
--- src/graphic/gl/road_program.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/road_program.h 2016-01-05 11:29:18 +0000
@@ -37,9 +37,12 @@
37 RoadProgram();37 RoadProgram();
38 ~RoadProgram();38 ~RoadProgram();
3939
40 // Draws the roads. The 'surface' is needed to convert from pixel space to40 // Draws the roads. The dimensions of the renderbuffer are needed to convert from pixel to GL
41 // GL space.41 // space.
42 void draw(const Surface& surface, const FieldsToDraw& fields_to_draw);42 void draw(int renderbuffer_width,
43 int renderbuffer_height,
44 const FieldsToDraw& fields_to_draw,
45 float z_value);
4346
44private:47private:
45 struct PerVertexData {48 struct PerVertexData {
@@ -54,15 +57,16 @@
54 // Adds a road from 'start' to 'end' to be rendered in this frame using the57 // Adds a road from 'start' to 'end' to be rendered in this frame using the
55 // correct texture for 'road_type'.58 // correct texture for 'road_type'.
56 enum Direction {kEast, kSouthEast, kSouthWest};59 enum Direction {kEast, kSouthEast, kSouthWest};
57 void add_road(const Surface& surface,60 void add_road(int renderbuffer_width,
61 int renderbuffer_height,
58 const FieldsToDraw::Field& start,62 const FieldsToDraw::Field& start,
59 const FieldsToDraw::Field& end,63 const FieldsToDraw::Field& end,
60 const Widelands::RoadType road_type,64 const Widelands::RoadType road_type,
61 const Direction direction,65 const Direction direction,
62 int* gl_texture);66 uint32_t* gl_texture);
6367
64 // The buffer that will contain 'vertices_' for rendering.68 // The buffer that will contain 'vertices_' for rendering.
65 Gl::Buffer gl_array_buffer_;69 Gl::Buffer<PerVertexData> gl_array_buffer_;
6670
67 // The program used for drawing the roads.71 // The program used for drawing the roads.
68 Gl::Program gl_program_;72 Gl::Program gl_program_;
@@ -74,6 +78,7 @@
7478
75 // Uniforms.79 // Uniforms.
76 GLint u_texture_;80 GLint u_texture_;
81 GLint u_z_value_;
7782
78 // All vertices that get rendered this frame.83 // All vertices that get rendered this frame.
79 std::vector<PerVertexData> vertices_;84 std::vector<PerVertexData> vertices_;
8085
=== modified file 'src/graphic/gl/terrain_program.cc'
--- src/graphic/gl/terrain_program.cc 2015-06-07 14:52:11 +0000
+++ src/graphic/gl/terrain_program.cc 2016-01-05 11:29:18 +0000
@@ -19,6 +19,7 @@
1919
20#include "graphic/gl/terrain_program.h"20#include "graphic/gl/terrain_program.h"
2121
22#include "graphic/gl/coordinate_conversion.h"
22#include "graphic/gl/fields_to_draw.h"23#include "graphic/gl/fields_to_draw.h"
23#include "graphic/texture.h"24#include "graphic/texture.h"
2425
@@ -40,6 +41,8 @@
40attribute vec2 attr_texture_offset;41attribute vec2 attr_texture_offset;
41attribute vec2 attr_texture_position;42attribute vec2 attr_texture_position;
4243
44uniform float u_z_value;
45
43// Output of vertex shader.46// Output of vertex shader.
44varying float var_brightness;47varying float var_brightness;
45varying vec2 var_texture_offset;48varying vec2 var_texture_offset;
@@ -49,7 +52,7 @@
49 var_texture_position = attr_texture_position;52 var_texture_position = attr_texture_position;
50 var_brightness = attr_brightness;53 var_brightness = attr_brightness;
51 var_texture_offset = attr_texture_offset;54 var_texture_offset = attr_texture_offset;
52 gl_Position = vec4(attr_position, 0., 1.);55 gl_Position = vec4(attr_position, u_z_value, 1.);
53}56}
54)";57)";
5558
@@ -63,9 +66,20 @@
63varying vec2 var_texture_position;66varying vec2 var_texture_position;
64varying vec2 var_texture_offset;67varying vec2 var_texture_offset;
6568
69// TODO(sirver): This is a hack to make sure we are sampling inside of the
70// terrain texture. This is a common problem with OpenGL and texture atlases.
71#define MARGIN 1e-2
72
66void main() {73void main() {
67 vec4 clr = texture2D(u_terrain_texture,74 // The arbitrary multiplication by 0.99 makes sure that we never sample
68 var_texture_offset + u_texture_dimensions * fract(var_texture_position));75 // outside of the texture in the texture atlas - this means non-perfect
76 // pixel mapping of textures to the screen, but we are pretty meh about that
77 // here.
78 vec2 texture_fract = clamp(
79 fract(var_texture_position),
80 vec2(MARGIN, MARGIN),
81 vec2(1. - MARGIN, 1. - MARGIN));
82 vec4 clr = texture2D(u_terrain_texture, var_texture_offset + u_texture_dimensions * texture_fract);
69 clr.rgb *= var_brightness;83 clr.rgb *= var_brightness;
70 gl_FragColor = clr;84 gl_FragColor = clr;
71}85}
@@ -83,9 +97,10 @@
8397
84 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");98 u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
85 u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");99 u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
100 u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
86}101}
87102
88void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {103void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h, float z_value) {
89 glUseProgram(gl_program_.object());104 glUseProgram(gl_program_.object());
90105
91 glEnableVertexAttribArray(attr_brightness_);106 glEnableVertexAttribArray(attr_brightness_);
@@ -93,30 +108,23 @@
93 glEnableVertexAttribArray(attr_texture_offset_);108 glEnableVertexAttribArray(attr_texture_offset_);
94 glEnableVertexAttribArray(attr_texture_position_);109 glEnableVertexAttribArray(attr_texture_position_);
95110
96 glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());111 gl_array_buffer_.bind();
97 glBufferData(GL_ARRAY_BUFFER,112 gl_array_buffer_.update(vertices_);
98 sizeof(TerrainProgram::PerVertexData) * vertices_.size(),
99 vertices_.data(),
100 GL_STREAM_DRAW);
101113
102 const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {114 Gl::vertex_attrib_pointer(
103 glVertexAttribPointer(vertex_index,115 attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
104 num_items,116 Gl::vertex_attrib_pointer(attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
105 GL_FLOAT,117 Gl::vertex_attrib_pointer(
106 GL_FALSE,118 attr_texture_offset_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_offset_x));
107 sizeof(TerrainProgram::PerVertexData),119 Gl::vertex_attrib_pointer(
108 reinterpret_cast<void*>(offset));120 attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
109 };
110 set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
111 set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
112 set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
113 set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
114121
115 glBindBuffer(GL_ARRAY_BUFFER, 0);122 glBindBuffer(GL_ARRAY_BUFFER, 0);
116123
117 glActiveTexture(GL_TEXTURE0);124 glActiveTexture(GL_TEXTURE0);
118 glBindTexture(GL_TEXTURE_2D, gl_texture);125 glBindTexture(GL_TEXTURE_2D, gl_texture);
119126
127 glUniform1f(u_z_value_, z_value);
120 glUniform1i(u_terrain_texture_, 0);128 glUniform1i(u_terrain_texture_, 0);
121 glUniform2f(u_texture_dimensions_, texture_w, texture_h);129 glUniform2f(u_texture_dimensions_, texture_w, texture_h);
122130
@@ -146,7 +154,8 @@
146154
147void TerrainProgram::draw(uint32_t gametime,155void TerrainProgram::draw(uint32_t gametime,
148 const DescriptionMaintainer<TerrainDescription>& terrains,156 const DescriptionMaintainer<TerrainDescription>& terrains,
149 const FieldsToDraw& fields_to_draw) {157 const FieldsToDraw& fields_to_draw,
158 float z_value) {
150 // This method expects that all terrains have the same dimensions and that159 // This method expects that all terrains have the same dimensions and that
151 // all are packed into the same texture atlas, i.e. all are in the same GL160 // all are packed into the same texture atlas, i.e. all are in the same GL
152 // texture. It does not check for this invariance for speeds sake.161 // texture. It does not check for this invariance for speeds sake.
@@ -170,7 +179,7 @@
170 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);179 fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
171 if (bln_index != -1) {180 if (bln_index != -1) {
172 const FloatPoint texture_offset =181 const FloatPoint texture_offset =
173 terrains.get(field.ter_d).get_texture(gametime).texture_coordinates().top_left();182 to_gl_texture(terrains.get(field.ter_d).get_texture(gametime).blit_data()).origin();
174 add_vertex(fields_to_draw.at(current_index), texture_offset);183 add_vertex(fields_to_draw.at(current_index), texture_offset);
175 add_vertex(fields_to_draw.at(bln_index), texture_offset);184 add_vertex(fields_to_draw.at(bln_index), texture_offset);
176 add_vertex(fields_to_draw.at(brn_index), texture_offset);185 add_vertex(fields_to_draw.at(brn_index), texture_offset);
@@ -180,13 +189,17 @@
180 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);189 const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
181 if (rn_index != -1) {190 if (rn_index != -1) {
182 const FloatPoint texture_offset =191 const FloatPoint texture_offset =
183 terrains.get(field.ter_r).get_texture(gametime).texture_coordinates().top_left();192 to_gl_texture(terrains.get(field.ter_r).get_texture(gametime).blit_data()).origin();
184 add_vertex(fields_to_draw.at(current_index), texture_offset);193 add_vertex(fields_to_draw.at(current_index), texture_offset);
185 add_vertex(fields_to_draw.at(brn_index), texture_offset);194 add_vertex(fields_to_draw.at(brn_index), texture_offset);
186 add_vertex(fields_to_draw.at(rn_index), texture_offset);195 add_vertex(fields_to_draw.at(rn_index), texture_offset);
187 }196 }
188 }197 }
189198
190 const Texture& texture = terrains.get(0).get_texture(0);199 const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
191 gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);200 const FloatRect texture_coordinates = to_gl_texture(blit_data);
201 gl_draw(blit_data.texture_id,
202 texture_coordinates.w,
203 texture_coordinates.h,
204 z_value);
192}205}
193206
=== modified file 'src/graphic/gl/terrain_program.h'
--- src/graphic/gl/terrain_program.h 2015-03-01 09:21:20 +0000
+++ src/graphic/gl/terrain_program.h 2016-01-05 11:29:18 +0000
@@ -35,8 +35,10 @@
35 TerrainProgram();35 TerrainProgram();
3636
37 // Draws the terrain.37 // Draws the terrain.
38 void draw(uint32_t gametime, const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,38 void draw(uint32_t gametime,
39 const FieldsToDraw& fields_to_draw);39 const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
40 const FieldsToDraw& fields_to_draw,
41 float z_value);
4042
41private:43private:
42 struct PerVertexData {44 struct PerVertexData {
@@ -50,7 +52,7 @@
50 };52 };
51 static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");53 static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
5254
53 void gl_draw(int gl_texture, float texture_w, float texture_h);55 void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
5456
55 // Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.57 // Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
56 void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);58 void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
@@ -59,7 +61,7 @@
59 Gl::Program gl_program_;61 Gl::Program gl_program_;
6062
61 // The buffer that will contain 'vertices_' for rendering.63 // The buffer that will contain 'vertices_' for rendering.
62 Gl::Buffer gl_array_buffer_;64 Gl::Buffer<PerVertexData> gl_array_buffer_;
6365
64 // Attributes.66 // Attributes.
65 GLint attr_brightness_;67 GLint attr_brightness_;
@@ -70,6 +72,7 @@
70 // Uniforms.72 // Uniforms.
71 GLint u_terrain_texture_;73 GLint u_terrain_texture_;
72 GLint u_texture_dimensions_;74 GLint u_texture_dimensions_;
75 GLint u_z_value_;
7376
74 // Objects below are kept around to avoid memory allocations on each frame.77 // Objects below are kept around to avoid memory allocations on each frame.
75 // They could theoretically also be recreated.78 // They could theoretically also be recreated.
7679
=== modified file 'src/graphic/gl/utils.cc'
--- src/graphic/gl/utils.cc 2014-09-27 18:53:55 +0000
+++ src/graphic/gl/utils.cc 2016-01-05 11:29:18 +0000
@@ -21,8 +21,6 @@
21#include <memory>21#include <memory>
22#include <string>22#include <string>
2323
24#include <SDL_video.h>
25
26#include "base/log.h"24#include "base/log.h"
27#include "base/wexception.h"25#include "base/wexception.h"
2826
@@ -41,40 +39,8 @@
41 return "unknown";39 return "unknown";
42}40}
4341
44// Creates one OpenGL buffer.
45GLuint create_buffer() {
46 GLuint buffer = 0;
47 glGenBuffers(1, &buffer);
48 return buffer;
49}
50
51} // namespace42} // namespace
5243
53/**
54 * \return the standard 32-bit RGBA format that we use in OpenGL
55 */
56const SDL_PixelFormat & gl_rgba_format()
57{
58 static SDL_PixelFormat format;
59 static bool init = false;
60 if (init)
61 return format;
62
63 init = true;
64 memset(&format, 0, sizeof(format));
65 format.BitsPerPixel = 32;
66 format.BytesPerPixel = 4;
67 format.Rmask = 0x000000ff;
68 format.Gmask = 0x0000ff00;
69 format.Bmask = 0x00ff0000;
70 format.Amask = 0xff000000;
71 format.Rshift = 0;
72 format.Gshift = 8;
73 format.Bshift = 16;
74 format.Ashift = 24;
75 return format;
76}
77
78GLenum _handle_glerror(const char * file, unsigned int line)44GLenum _handle_glerror(const char * file, unsigned int line)
79{45{
80 GLenum err = glGetError();46 GLenum err = glGetError();
@@ -162,18 +128,6 @@
162 }128 }
163}129}
164130
165Buffer::Buffer() : buffer_object_(create_buffer()) {
166 if (!buffer_object_) {
167 throw wexception("Could not create GL program.");
168 }
169}
170
171Buffer::~Buffer() {
172 if (buffer_object_) {
173 glDeleteBuffers(1, &buffer_object_);
174 }
175}
176
177Program::Program() : program_object_(glCreateProgram()) {131Program::Program() : program_object_(glCreateProgram()) {
178 if (!program_object_) {132 if (!program_object_) {
179 throw wexception("Could not create GL program.");133 throw wexception("Could not create GL program.");
@@ -212,4 +166,21 @@
212 }166 }
213}167}
214168
169void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset) {
170 glVertexAttribPointer(
171 vertex_index, num_items, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<void*>(offset));
172}
173
174void swap_rows(const int width, const int height, const int pitch, const int bpp, uint8_t* pixels) {
175 uint8_t* begin_row = pixels;
176 uint8_t* end_row = pixels + pitch * (height - 1);
177 while (begin_row < end_row) {
178 for (int x = 0; x < width * bpp; ++x) {
179 std::swap(begin_row[x], end_row[x]);
180 }
181 begin_row += pitch;
182 end_row -= pitch;
183 }
184}
185
215} // namespace Gl186} // namespace Gl
216187
=== modified file 'src/graphic/gl/utils.h'
--- src/graphic/gl/utils.h 2014-11-08 13:59:33 +0000
+++ src/graphic/gl/utils.h 2016-01-05 11:29:18 +0000
@@ -20,19 +20,19 @@
20#define WL_GRAPHIC_GL_UTILS_H20#define WL_GRAPHIC_GL_UTILS_H
2121
22#include <memory>22#include <memory>
23#include <vector>
2324
24#include <stdint.h>25#include <stdint.h>
2526
27#include "base/log.h"
26#include "base/macros.h"28#include "base/macros.h"
29#include "base/wexception.h"
27#include "graphic/gl/system_headers.h"30#include "graphic/gl/system_headers.h"
2831
29struct SDL_PixelFormat;
30
31namespace Gl {32namespace Gl {
3233
33class Shader;34class Shader;
3435
35const SDL_PixelFormat & gl_rgba_format();
36GLenum _handle_glerror(const char * file, unsigned int line);36GLenum _handle_glerror(const char * file, unsigned int line);
3737
38// Thin wrapper around a OpenGL program object to ensure proper cleanup. Throws38// Thin wrapper around a OpenGL program object to ensure proper cleanup. Throws
@@ -59,22 +59,54 @@
59};59};
6060
61// Thin wrapper around a OpenGL buffer object to ensure proper cleanup. Throws61// Thin wrapper around a OpenGL buffer object to ensure proper cleanup. Throws
62// on all errors.62// on all errors. Also grows the server memory only when needed.
63template<typename T>
63class Buffer {64class Buffer {
64public:65public:
65 Buffer();66 Buffer() : buffer_size_(0) {
66 ~Buffer();67 glGenBuffers(1, &object_);
6768 if (!object_) {
68 GLuint object() const {69 throw wexception("Could not create GL program.");
69 return buffer_object_;70 }
71 }
72
73 ~Buffer() {
74 if (object_) {
75 glDeleteBuffers(1, &object_);
76 }
77 }
78
79 // Calls glBindBuffer on the underlying buffer data.
80 void bind() const {
81 glBindBuffer(GL_ARRAY_BUFFER, object_);
82 }
83
84
85 // Copies 'elements' into the buffer. If the buffer is too small to hold the
86 // data, it is reallocated. Does not check if the buffer is already bound.
87 void update(const std::vector<T>& items) {
88 if (buffer_size_ < items.size()) {
89 glBufferData(GL_ARRAY_BUFFER, items.size() * sizeof(T), items.data(), GL_DYNAMIC_DRAW);
90 buffer_size_ = items.size();
91 } else {
92 glBufferSubData(GL_ARRAY_BUFFER, 0, items.size() * sizeof(T), items.data());
93 }
70 }94 }
7195
72private:96private:
73 const GLuint buffer_object_;97 GLuint object_;
98 size_t buffer_size_; // In number of elements.
7499
75 DISALLOW_COPY_AND_ASSIGN(Buffer);100 DISALLOW_COPY_AND_ASSIGN(Buffer);
76};101};
77102
103// Calls glVertexAttribPointer.
104void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset);
105
106// Swap order of rows in m_pixels, to compensate for the upside-down nature of the
107// OpenGL coordinate system.
108void swap_rows(int width, int height, int pitch, int bpp, uint8_t* pixels);
109
78} // namespace Gl110} // namespace Gl
79111
80/**112/**
81113
=== modified file 'src/graphic/graphic.cc'
--- src/graphic/graphic.cc 2014-12-27 09:59:12 +0000
+++ src/graphic/graphic.cc 2016-01-05 11:29:18 +0000
@@ -29,6 +29,7 @@
29#include "graphic/gl/system_headers.h"29#include "graphic/gl/system_headers.h"
30#include "graphic/image.h"30#include "graphic/image.h"
31#include "graphic/image_io.h"31#include "graphic/image_io.h"
32#include "graphic/render_queue.h"
32#include "graphic/rendertarget.h"33#include "graphic/rendertarget.h"
33#include "graphic/screen.h"34#include "graphic/screen.h"
34#include "graphic/texture.h"35#include "graphic/texture.h"
@@ -70,6 +71,7 @@
70 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);71 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
71 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);72 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
72 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);73 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
74 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
7375
74 log("Graphics: Try to set Videomode %ux%u\n", m_window_mode_width, m_window_mode_height);76 log("Graphics: Try to set Videomode %ux%u\n", m_window_mode_width, m_window_mode_height);
75 m_sdl_window = SDL_CreateWindow("Widelands Window",77 m_sdl_window = SDL_CreateWindow("Widelands Window",
@@ -111,12 +113,11 @@
111 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glInt);113 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glInt);
112 log("Graphics: OpenGL: Max texture size: %u\n", glInt);114 log("Graphics: OpenGL: Max texture size: %u\n", glInt);
113115
114 SDL_GL_SetSwapInterval(1);
115
116 glDrawBuffer(GL_BACK);116 glDrawBuffer(GL_BACK);
117117
118 glDisable(GL_DEPTH_TEST);118 glEnable(GL_DEPTH_TEST);
119 glEnable(GL_TEXTURE_2D);119 glDepthFunc(GL_LEQUAL);
120
120 glEnable(GL_BLEND);121 glEnable(GL_BLEND);
121 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);122 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
122123
@@ -244,9 +245,8 @@
244/**245/**
245 * Returns true if parts of the screen have been marked for refreshing.246 * Returns true if parts of the screen have been marked for refreshing.
246*/247*/
247bool Graphic::need_update() const248bool Graphic::need_update() const {
248{249 return m_update;
249 return m_update;
250}250}
251251
252/**252/**
@@ -256,6 +256,8 @@
256*/256*/
257void Graphic::refresh()257void Graphic::refresh()
258{258{
259 RenderQueue::instance().draw(screen_->width(), screen_->height());
260
259 // Setting the window size immediately after going out of fullscreen does261 // Setting the window size immediately after going out of fullscreen does
260 // not work properly. We work around this issue by resizing the window in262 // not work properly. We work around this issue by resizing the window in
261 // refresh() when in window mode.263 // refresh() when in window mode.
262264
=== modified file 'src/graphic/image.h'
--- src/graphic/image.h 2014-12-08 05:22:52 +0000
+++ src/graphic/image.h 2016-01-05 11:29:18 +0000
@@ -26,6 +26,7 @@
2626
27#include "base/macros.h"27#include "base/macros.h"
28#include "base/rect.h"28#include "base/rect.h"
29#include "graphic/gl/blit_data.h"
2930
30class Texture;31class Texture;
3132
@@ -35,6 +36,7 @@
35 */36 */
36class Image {37class Image {
37public:38public:
39
38 Image() = default;40 Image() = default;
39 virtual ~Image() {}41 virtual ~Image() {}
4042
@@ -45,8 +47,7 @@
45 // OpenGL texture and texture coordinates backing this Image. This can47 // OpenGL texture and texture coordinates backing this Image. This can
46 // change at any time, so do not hold one to this value for more than one48 // change at any time, so do not hold one to this value for more than one
47 // frame.49 // frame.
48 virtual int get_gl_texture() const = 0;50 virtual const BlitData& blit_data() const = 0;
49 virtual const FloatRect& texture_coordinates() const = 0;
5051
51private:52private:
52 DISALLOW_COPY_AND_ASSIGN(Image);53 DISALLOW_COPY_AND_ASSIGN(Image);
5354
=== modified file 'src/graphic/image_cache.cc'
--- src/graphic/image_cache.cc 2014-12-07 20:52:55 +0000
+++ src/graphic/image_cache.cc 2016-01-05 11:29:18 +0000
@@ -21,13 +21,44 @@
2121
22#include <cassert>22#include <cassert>
23#include <memory>23#include <memory>
24#include <set>
24#include <string>25#include <string>
2526
26#include "base/log.h"27#include <SDL.h>
28#include <boost/format.hpp>
29
27#include "graphic/image.h"30#include "graphic/image.h"
28#include "graphic/image_io.h"31#include "graphic/image_io.h"
29#include "graphic/texture.h"32#include "graphic/texture.h"
3033
34namespace {
35
36constexpr int kBiggestAreaForCompactification = 250 * 250;
37
38} // namespace
39ImageCache::ProxyImage::ProxyImage(std::unique_ptr<const Image> image) : image_(std::move(image)) {
40}
41
42const Image& ImageCache::ProxyImage::image() {
43 return *image_;
44}
45
46void ImageCache::ProxyImage::set_image(std::unique_ptr<const Image> image) {
47 image_ = std::move(image);
48}
49
50int ImageCache::ProxyImage::width() const {
51 return image_->width();
52}
53
54int ImageCache::ProxyImage::height() const {
55 return image_->height();
56}
57
58const BlitData& ImageCache::ProxyImage::blit_data() const {
59 return image_->blit_data();
60}
61
31ImageCache::ImageCache() {62ImageCache::ImageCache() {
32}63}
3364
@@ -41,15 +72,43 @@
41const Image* ImageCache::insert(const std::string& hash, std::unique_ptr<const Image> image) {72const Image* ImageCache::insert(const std::string& hash, std::unique_ptr<const Image> image) {
42 assert(!has(hash));73 assert(!has(hash));
43 const Image* return_value = image.get();74 const Image* return_value = image.get();
44 images_.insert(make_pair(hash, std::move(image)));75 images_.insert(make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(std::move(image)))));
45 return return_value;76 return return_value;
46}77}
4778
48const Image* ImageCache::get(const std::string& hash) {79const Image* ImageCache::get(const std::string& hash) {
49 ImageMap::const_iterator it = images_.find(hash);80 ImageMap::const_iterator it = images_.find(hash);
50 if (it == images_.end()) {81 if (it == images_.end()) {
51 images_.insert(make_pair(hash, load_image(hash)));82 images_.insert(
83 make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(load_image(hash)))));
52 return get(hash);84 return get(hash);
53 }85 }
54 return it->second.get();86 return it->second.get();
55}87}
88
89void ImageCache::compactify() {
90 TextureAtlas texture_atlas;
91
92 std::vector<std::string> hashes;
93 for (const auto& pair : images_) {
94 const auto& image = pair.second->image();
95 if (image.width() * image.height() > kBiggestAreaForCompactification) {
96 continue;
97 }
98
99 texture_atlas.add(image);
100 hashes.push_back(pair.first);
101 }
102
103 std::vector<std::unique_ptr<Texture>> new_textures;
104
105 // TODO(sirver): Limit the size of the texture atlas to a max GL texture
106 // size. This might return more than one packed image. Make sure that the
107 // code works also for small max texture sizes.
108 texture_atlases_.emplace_back(texture_atlas.pack(&new_textures));
109
110 assert(new_textures.size() == hashes.size());
111 for (size_t i = 0; i < hashes.size(); ++i) {
112 images_[hashes[i]]->set_image(std::move(new_textures[i]));
113 }
114}
56115
=== modified file 'src/graphic/image_cache.h'
--- src/graphic/image_cache.h 2014-12-07 15:41:39 +0000
+++ src/graphic/image_cache.h 2016-01-05 11:29:18 +0000
@@ -23,11 +23,13 @@
23#include <map>23#include <map>
24#include <memory>24#include <memory>
25#include <string>25#include <string>
26#include <vector>
2627
27#include <boost/utility.hpp>28#include <boost/utility.hpp>
2829
29#include "base/macros.h"30#include "base/macros.h"
30#include "graphic/image.h"31#include "graphic/image.h"
32#include "graphic/texture_atlas.h"
3133
32// For historic reasons, most part of the Widelands code base expect that an34// For historic reasons, most part of the Widelands code base expect that an
33// Image stays valid for the whole duration of the program run. This class is35// Image stays valid for the whole duration of the program run. This class is
@@ -53,9 +55,32 @@
53 // Returns true if the given hash is stored in the cache.55 // Returns true if the given hash is stored in the cache.
54 bool has(const std::string& hash) const;56 bool has(const std::string& hash) const;
5557
58 // For debug only: Takes all images that are in the ImageCache right now and
59 // puts them into one huge texture atlas.
60 void compactify();
61
56private:62private:
57 using ImageMap = std::map<std::string, std::unique_ptr<const Image>>;63 // We return a wrapped Image so that we can swap out the pointer to the
5864 // image under our user. This can happen when we move an Image from a stand
65 // alone texture into being a subrect of a texture atlas.
66 class ProxyImage : public Image {
67 public:
68 ProxyImage(std::unique_ptr<const Image> image);
69
70 const Image& image();
71 void set_image(std::unique_ptr<const Image> image);
72
73 int width() const override;
74 int height() const override;
75 const BlitData& blit_data() const override;
76
77 private:
78 std::unique_ptr<const Image> image_;
79 };
80
81 using ImageMap = std::map<std::string, std::unique_ptr<ProxyImage>>;
82
83 std::vector<std::unique_ptr<Texture>> texture_atlases_;
59 ImageMap images_; /// hash of cached filename/image pairs84 ImageMap images_; /// hash of cached filename/image pairs
6085
61 DISALLOW_COPY_AND_ASSIGN(ImageCache);86 DISALLOW_COPY_AND_ASSIGN(ImageCache);
6287
=== modified file 'src/graphic/image_io.cc'
--- src/graphic/image_io.cc 2014-12-07 21:34:11 +0000
+++ src/graphic/image_io.cc 2016-01-05 11:29:18 +0000
@@ -25,6 +25,7 @@
25#include <SDL_image.h>25#include <SDL_image.h>
26#include <png.h>26#include <png.h>
2727
28#include "base/log.h"
28#include "base/wexception.h"29#include "base/wexception.h"
29#include "graphic/texture.h"30#include "graphic/texture.h"
30#include "io/fileread.h"31#include "io/fileread.h"
@@ -130,7 +131,6 @@
130 std::unique_ptr<png_byte[]> row(new png_byte[row_size]);131 std::unique_ptr<png_byte[]> row(new png_byte[row_size]);
131132
132 // Write each row133 // Write each row
133 const SDL_PixelFormat& fmt = texture->format();
134 texture->lock();134 texture->lock();
135135
136 // Write each row136 // Write each row
@@ -138,7 +138,7 @@
138 if (color_type == ColorType::RGB) {138 if (color_type == ColorType::RGB) {
139 for (uint32_t y = 0; y < surf_h; ++y) {139 for (uint32_t y = 0; y < surf_h; ++y) {
140 for (uint32_t x = 0; x < surf_w; ++x) {140 for (uint32_t x = 0; x < surf_w; ++x) {
141 color.set(fmt, texture->get_pixel(x, y));141 color = texture->get_pixel(x, y);
142 row[3 * x] = color.r;142 row[3 * x] = color.r;
143 row[3 * x + 1] = color.g;143 row[3 * x + 1] = color.g;
144 row[3 * x + 2] = color.b;144 row[3 * x + 2] = color.b;
@@ -148,7 +148,7 @@
148 } else {148 } else {
149 for (uint32_t y = 0; y < surf_h; ++y) {149 for (uint32_t y = 0; y < surf_h; ++y) {
150 for (uint32_t x = 0; x < surf_w; ++x) {150 for (uint32_t x = 0; x < surf_w; ++x) {
151 color.set(fmt, texture->get_pixel(x, y));151 color = texture->get_pixel(x, y);
152 row[4 * x] = color.r;152 row[4 * x] = color.r;
153 row[4 * x + 1] = color.g;153 row[4 * x + 1] = color.g;
154 row[4 * x + 2] = color.b;154 row[4 * x + 2] = color.b;
155155
=== added file 'src/graphic/make_texture_atlas_main.cc'
--- src/graphic/make_texture_atlas_main.cc 1970-01-01 00:00:00 +0000
+++ src/graphic/make_texture_atlas_main.cc 2016-01-05 11:29:18 +0000
@@ -0,0 +1,101 @@
1/*
2 * Copyright (C) 2006-2015 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20#include <fstream>
21#include <iostream>
22#include <memory>
23#include <set>
24#include <string>
25#include <vector>
26
27#include <SDL.h>
28#include <boost/algorithm/string/predicate.hpp>
29
30#undef main // No, we do not want SDL_main
31
32#include "base/log.h"
33#include "config.h"
34#include "graphic/graphic.h"
35#include "graphic/image_io.h"
36#include "graphic/texture_atlas.h"
37#include "helper.h"
38#include "io/filesystem/filesystem.h"
39#include "io/filesystem/layered_filesystem.h"
40#include "io/streamwrite.h"
41
42namespace {
43
44int parse_arguments(
45 int argc, char** argv, std::string* input_directory)
46{
47 if (argc < 2) {
48 std::cout << "Usage: wl_make_texture_atlas <input directory>" << std::endl << std::endl
49 << "Will write output.png in the current directory." << std::endl;
50 return 1;
51 }
52 *input_directory = argv[1];
53 return 0;
54}
55
56// Setup the static objects Widelands needs to operate and initializes systems.
57void initialize() {
58 SDL_Init(SDL_INIT_VIDEO);
59
60 g_fs = new LayeredFileSystem();
61 g_fs->add_file_system(&FileSystem::create(INSTALL_DATADIR));
62 g_gr = new Graphic(1, 1, false);
63}
64
65} // namespace
66
67int main(int argc, char** argv) {
68 std::string input_directory;
69 if (parse_arguments(argc, argv, &input_directory))
70 return 1;
71
72 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
73 std::cerr << "SDLInit did not succeed: " << SDL_GetError() << std::endl;
74 return 1;
75 }
76 initialize();
77
78 std::vector<std::unique_ptr<Texture>> images;
79 std::unique_ptr<FileSystem> input_fs(&FileSystem::create(input_directory));
80 std::vector<std::string> png_filenames;
81 for (const std::string& filename : input_fs->list_directory("")) {
82 if (boost::ends_with(filename, ".png")) {
83 png_filenames.push_back(filename);
84 images.emplace_back(load_image(filename, input_fs.get()));
85 }
86 }
87
88 TextureAtlas atlas;
89 for (auto& image : images) {
90 atlas.add(*image);
91 }
92 std::vector<std::unique_ptr<Texture>> new_textures;
93 auto packed_texture = atlas.pack(&new_textures);
94
95 std::unique_ptr<FileSystem> output_fs(&FileSystem::create("."));
96 std::unique_ptr<StreamWrite> sw(output_fs->open_stream_write("output.png"));
97 save_to_png(packed_texture.get(), sw.get(), ColorType::RGBA);
98
99 SDL_Quit();
100 return 0;
101}
0102
=== modified file 'src/graphic/minimap_renderer.cc'
--- src/graphic/minimap_renderer.cc 2014-12-07 21:34:11 +0000
+++ src/graphic/minimap_renderer.cc 2016-01-05 11:29:18 +0000
@@ -38,68 +38,49 @@
3838
39namespace {39namespace {
4040
41const RGBColor kWhite(255, 255, 255);
42
41// Blend two colors.43// Blend two colors.
42inline uint32_t blend_color44inline RGBColor blend_color(const RGBColor& c1, const RGBColor& c2) {
43 (const SDL_PixelFormat& format, uint32_t clr1, uint8_t r2, uint8_t g2, uint8_t b2)45 return RGBColor((c1.r + c2.r) / 2, (c1.g + c2.g) / 2, (c1.b + c2.b) / 2);
44{
45 uint8_t r1, g1, b1;
46 SDL_GetRGB(clr1, &const_cast<SDL_PixelFormat &>(format), &r1, &g1, &b1);
47 return
48 SDL_MapRGB
49 (&const_cast<SDL_PixelFormat &>(format), (r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2);
50}46}
5147
52// Returns the color to be used in the minimap for the given field.48// Returns the color to be used in the minimap for the given field.
53inline uint32_t calc_minimap_color49inline RGBColor calc_minimap_color(const Widelands::EditorGameBase& egbase,
54 (const SDL_PixelFormat& format, const Widelands::EditorGameBase& egbase,50 const Widelands::FCoords& f,
55 const Widelands::FCoords& f, MiniMapLayer layers, Widelands::PlayerNumber owner,51 MiniMapLayer layers,
56 bool see_details)52 Widelands::PlayerNumber owner,
57{53 bool see_details) {
58 uint32_t pixelcolor = 0;54 RGBColor color;
59
60 if (layers & MiniMapLayer::Terrain) {55 if (layers & MiniMapLayer::Terrain) {
61 const RGBColor& color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(56 color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
62 f.field->get_brightness());57 f.field->get_brightness());
63
64 pixelcolor = SDL_MapRGBA(&format, color.r, color.g, color.b, 255);
65 }58 }
6659
67 if (layers & MiniMapLayer::Owner) {60 if (layers & MiniMapLayer::Owner) {
68 if (0 < owner) { // If owned, get the player's color...61 if (0 < owner) {
69 const RGBColor & player_color = egbase.player(owner).get_playercolor();62 color = blend_color(color, egbase.player(owner).get_playercolor());
70
71 // ...and add the player's color to the old color.
72 pixelcolor = blend_color
73 (format,
74 pixelcolor,
75 player_color.r, player_color.g, player_color.b);
76 }63 }
77 }64 }
7865
79 if (see_details) {66 if (see_details) {
80 // if ownership layer is displayed, it creates enough contrast to67 // if ownership layer is displayed, it creates enough contrast to
81 // visualize objects using white color.68 // visualize objects using white color.
82 // Otherwise, a more contrasting color may be needed:
83 // * winterland -> orange
8469
85 if (upcast(PlayerImmovable const, immovable, f.field->get_immovable())) {70 if (upcast(PlayerImmovable const, immovable, f.field->get_immovable())) {
86 if ((layers & MiniMapLayer::Road) && dynamic_cast<Road const *>(immovable)) {71 if ((layers & MiniMapLayer::Road) && dynamic_cast<Road const *>(immovable)) {
87 pixelcolor = blend_color(format, pixelcolor, 255, 255, 255);72 color = blend_color(color, kWhite);
88 }73 }
8974
90 if75 if (((layers & MiniMapLayer::Flag) && dynamic_cast<Flag const*>(immovable)) ||
91 (((layers & MiniMapLayer::Flag) && dynamic_cast<Flag const *>(immovable))76 ((layers & MiniMapLayer::Building) &&
92 ||77 dynamic_cast<Widelands::Building const*>(immovable))) {
93 ((layers & MiniMapLayer::Building)78 color = kWhite;
94 &&
95 dynamic_cast<Widelands::Building const *>(immovable)))
96 {
97 pixelcolor = SDL_MapRGB(&const_cast<SDL_PixelFormat&>(format), 255, 255, 255);
98 }79 }
99 }80 }
100 }81 }
10182
102 return pixelcolor;83 return color;
103}84}
10485
105// Draws the dotted frame border onto the minimap.86// Draws the dotted frame border onto the minimap.
@@ -149,15 +130,13 @@
149}130}
150131
151// Does the actual work of drawing the minimap.132// Does the actual work of drawing the minimap.
152void draw_minimap_int133void draw_minimap_int(Texture* texture,
153 (Texture* texture, const Widelands::EditorGameBase& egbase,134 const Widelands::EditorGameBase& egbase,
154 const Widelands::Player* player, const Point& viewpoint, MiniMapLayer layers)135 const Widelands::Player* player,
155{136 const Point& viewpoint,
156 const Widelands::Map & map = egbase.map();137 MiniMapLayer layers) {
138 const Widelands::Map& map = egbase.map();
157139
158 uint8_t* const pixels = texture->get_pixels();
159 const SDL_PixelFormat& format = texture->format();
160 const uint16_t pitch = texture->get_pitch();
161 const uint16_t surface_h = texture->height();140 const uint16_t surface_h = texture->height();
162 const uint16_t surface_w = texture->width();141 const uint16_t surface_w = texture->width();
163142
@@ -168,90 +147,69 @@
168 const int32_t mapwidth = egbase.get_map().get_width();147 const int32_t mapwidth = egbase.get_map().get_width();
169 const int32_t mapheight = map.get_height();148 const int32_t mapheight = map.get_height();
170149
171 Point ptopleft; // top left point of the current display frame150 Point ptopleft; // top left point of the current display frame
172 ptopleft.x = viewpoint.x + mapwidth / 2 - xsize;151 ptopleft.x = viewpoint.x + mapwidth / 2 - xsize;
173 if (ptopleft.x < 0) ptopleft.x += mapwidth;152 if (ptopleft.x < 0) {
153 ptopleft.x += mapwidth;
154 }
174 ptopleft.y = viewpoint.y + mapheight / 2 - ysize;155 ptopleft.y = viewpoint.y + mapheight / 2 - ysize;
175 if (ptopleft.y < 0) ptopleft.y += mapheight;156 if (ptopleft.y < 0) {
157 ptopleft.y += mapheight;
158 }
176159
177 Point pbottomright; // bottom right point of the current display frame160 Point pbottomright; // bottom right point of the current display frame
178 pbottomright.x = viewpoint.x + mapwidth / 2 + xsize;161 pbottomright.x = viewpoint.x + mapwidth / 2 + xsize;
179 if (pbottomright.x >= mapwidth) pbottomright.x -= mapwidth;162 if (pbottomright.x >= mapwidth) {
163 pbottomright.x -= mapwidth;
164 }
180 pbottomright.y = viewpoint.y + mapheight / 2 + ysize;165 pbottomright.y = viewpoint.y + mapheight / 2 + ysize;
181 if (pbottomright.y >= mapheight) pbottomright.y -= mapheight;166 if (pbottomright.y >= mapheight) {
167 pbottomright.y -= mapheight;
168 }
182169
183 uint32_t modx = pbottomright.x % 2;170 uint32_t modx = pbottomright.x % 2;
184 uint32_t mody = pbottomright.y % 2;171 uint32_t mody = pbottomright.y % 2;
185172
186 if (!player || player->see_all()) {173 for (uint32_t y = 0; y < surface_h; ++y) {
187 for (uint32_t y = 0; y < surface_h; ++y) {174 Widelands::FCoords f(
188 uint8_t * pix = pixels + y * pitch;175 Widelands::Coords(viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
189 Widelands::FCoords f176 map.normalize_coords(f);
190 (Widelands::Coords177 f.field = &map[f];
191 (viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));178 Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
192 map.normalize_coords(f);179 for (uint32_t x = 0; x < surface_w; ++x) {
193 f.field = &map[f];180 if (x % 2 || !(layers & MiniMapLayer::Zoom2)) {
194 Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);181 move_r(mapwidth, f, i);
195 for (uint32_t x = 0; x < surface_w; ++x, pix += sizeof(uint32_t)) {182 }
196 if (x % 2 || !(layers & MiniMapLayer::Zoom2))183
197 move_r(mapwidth, f, i);184 RGBColor pixel_color;
198185 if ((layers & MiniMapLayer::ViewWindow) &&
199 if ((layers & MiniMapLayer::ViewWindow) &&186 is_minimap_frameborder(f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
200 is_minimap_frameborder(187 pixel_color = RGBColor(255, 0, 0);
201 f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {188 } else {
202 *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>189 uint16_t vision =
203 (SDL_MapRGB(&const_cast<SDL_PixelFormat &>(format), 255, 0, 0));190 0; // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
204 } else {191 Widelands::PlayerNumber owner = 0;
205 *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>192 if (player == nullptr || player->see_all()) {
206 (calc_minimap_color193 vision = 2; // Seen right now.
207 (format, egbase, f, layers, f.field->get_owned_by(), true));194 owner = f.field->get_owned_by();
208 }195 } else if (player != nullptr) {
209 }196 const auto& field = player->fields()[i];
210 }197 vision = field.vision;
211 } else {198 owner = field.owner;
212 Widelands::Player::Field const * const player_fields = player->fields();199 }
213 for (uint32_t y = 0; y < surface_h; ++y) {200
214 uint8_t * pix = pixels + y * pitch;201 if (vision > 0) {
215 Widelands::FCoords f202 pixel_color = calc_minimap_color(egbase, f, layers, owner, vision > 1);
216 (Widelands::Coords203 }
217 (viewpoint.x, viewpoint.y +204 }
218 (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));205
219 map.normalize_coords(f);206 if (pixel_color.r != 0 || pixel_color.g != 0 || pixel_color.b != 0) {
220 f.field = &map[f];207 texture->set_pixel(x, y, pixel_color);
221 Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
222 for (uint32_t x = 0; x < surface_w; ++x, pix += sizeof(uint32_t)) {
223 if (x % 2 || !(layers & MiniMapLayer::Zoom2))
224 move_r(mapwidth, f, i);
225
226 if ((layers & MiniMapLayer::ViewWindow) &&
227 is_minimap_frameborder(
228 f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
229 *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
230 (SDL_MapRGB
231 (&const_cast<SDL_PixelFormat &>(format), 255, 0, 0));
232 } else {
233 const Widelands::Player::Field & player_field = player_fields[i];
234 Widelands::Vision const vision = player_field.vision;
235
236 *reinterpret_cast<uint32_t *>(pix) =
237 static_cast<uint32_t>
238 (vision ?
239 calc_minimap_color
240 (format,
241 egbase,
242 f,
243 layers,
244 player_field.owner,
245 1 < vision)
246 :
247 SDL_MapRGB(&const_cast<SDL_PixelFormat &>(format), 0, 0, 0));
248 }
249 }208 }
250 }209 }
251 }210 }
252}211}
253212
254
255} // namespace213} // namespace
256214
257std::unique_ptr<Texture> draw_minimap(const EditorGameBase& egbase,215std::unique_ptr<Texture> draw_minimap(const EditorGameBase& egbase,
@@ -265,17 +223,15 @@
265 const int16_t map_w = (layers & MiniMapLayer::Zoom2) ? map.get_width() * 2 : map.get_width();223 const int16_t map_w = (layers & MiniMapLayer::Zoom2) ? map.get_width() * 2 : map.get_width();
266 const int16_t map_h = (layers & MiniMapLayer::Zoom2) ? map.get_height() * 2 : map.get_height();224 const int16_t map_h = (layers & MiniMapLayer::Zoom2) ? map.get_height() * 2 : map.get_height();
267225
268 Texture* texture = new Texture(map_w, map_h);226 std::unique_ptr<Texture> texture(new Texture(map_w, map_h));
269 assert(texture->format().BytesPerPixel == sizeof(uint32_t));227
270228 texture->fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
271 fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255), texture);229
272 texture->lock();230 texture->lock();
273231 draw_minimap_int(texture.get(), egbase, player, viewpoint, layers);
274 draw_minimap_int(texture, egbase, player, viewpoint, layers);
275
276 texture->unlock(Texture::Unlock_Update);232 texture->unlock(Texture::Unlock_Update);
277233
278 return std::unique_ptr<Texture>(texture);234 return texture;
279}235}
280236
281void write_minimap_image237void write_minimap_image
@@ -293,11 +249,13 @@
293 const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(egbase.get_map());249 const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(egbase.get_map());
294 // adjust the viewpoint top topleft in map coords250 // adjust the viewpoint top topleft in map coords
295 viewpoint.x += g_gr->get_xres() / 2;251 viewpoint.x += g_gr->get_xres() / 2;
296 if (viewpoint.x >= maxx)252 if (viewpoint.x >= maxx) {
297 viewpoint.x -= maxx;253 viewpoint.x -= maxx;
254 }
298 viewpoint.y += g_gr->get_yres() / 2;255 viewpoint.y += g_gr->get_yres() / 2;
299 if (viewpoint.y >= maxy)256 if (viewpoint.y >= maxy) {
300 viewpoint.y -= maxy;257 viewpoint.y -= maxy;
258 }
301 viewpoint.x /= TRIANGLE_WIDTH;259 viewpoint.x /= TRIANGLE_WIDTH;
302 viewpoint.y /= TRIANGLE_HEIGHT;260 viewpoint.y /= TRIANGLE_HEIGHT;
303 viewpoint.x -= map_w / 2;261 viewpoint.x -= map_w / 2;
304262
=== added file 'src/graphic/render_queue.cc'
--- src/graphic/render_queue.cc 1970-01-01 00:00:00 +0000
+++ src/graphic/render_queue.cc 2016-01-05 11:29:18 +0000
@@ -0,0 +1,299 @@
1/*
2 * Copyright (C) 2006-2014 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20#include "graphic/render_queue.h"
21
22#include <algorithm>
23#include <limits>
24
25#include "base/log.h"
26#include "base/rect.h"
27#include "base/wexception.h"
28#include "graphic/gl/blit_program.h"
29#include "graphic/gl/dither_program.h"
30#include "graphic/gl/draw_line_program.h"
31#include "graphic/gl/fill_rect_program.h"
32#include "graphic/gl/road_program.h"
33#include "graphic/gl/terrain_program.h"
34
35namespace {
36
37constexpr int kMaximumZValue = std::numeric_limits<uint16_t>::max();
38constexpr float kOpenGlZDelta = -2.f / kMaximumZValue;
39
40// Maps [0, kMaximumZValue] linearly to [1., -1.] for use in vertex shaders.
41inline float to_opengl_z(const int z) {
42 return -(2.f * z) / kMaximumZValue + 1.f;
43}
44
45// The key defines in which order we render things.
46//
47// For opaque objects, render order makes no difference in the final image, but
48// - we batch up by program to have maximal batching.
49// - and we want to render frontmost objects first, so that we do not render
50// any pixel more than once.
51static_assert(RenderQueue::Program::kHighestProgramId <= 8, "Need to change sorting keys."); // 4 bits.
52
53uint64_t
54make_key_opaque(const uint64_t program_id, const uint64_t z_value, const uint64_t extra_value) {
55 assert(program_id < RenderQueue::Program::kHighestProgramId);
56 assert(z_value < std::numeric_limits<uint16_t>::max());
57
58 // TODO(sirver): As a higher priority for sorting then z value, texture
59 // could be used here. This allows for more batching of GL calls, but in my
60 // tests hardly made a difference for Widelands..
61 uint64_t sort_z_value = std::numeric_limits<uint16_t>::max() - z_value;
62 // IIII0000 EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE ZZZZZZZZ ZZZZZZZZ
63 return (program_id << 60) | (extra_value << 16) | (sort_z_value);
64}
65
66// For blended objects, we need to render furthest away objects first, and we
67// do not update the z-buffer. This guarantees that the image is correct.
68// - if z value is the same, we order by program second to have potential batching.
69uint64_t
70make_key_blended(const uint64_t program_id, const uint64_t z_value, const uint64_t extra_value) {
71 assert(program_id < RenderQueue::Program::kHighestProgramId);
72 assert(z_value < std::numeric_limits<uint16_t>::max());
73
74 // Sort opaque objects increasing, alpha objects decreasing in order.
75 // ZZZZZZZZ ZZZZZZZZ IIII0000 EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
76 return (z_value << 40) | (program_id << 36) | extra_value;
77}
78
79// Construct 'args' used by the individual programs out of 'item'.
80inline void from_item(const RenderQueue::Item& item, VanillaBlitProgram::Arguments* args) {
81 args->texture = item.vanilla_blit_arguments.texture;
82 args->opacity = item.vanilla_blit_arguments.opacity;
83}
84
85inline void from_item(const RenderQueue::Item& item, MonochromeBlitProgram::Arguments* args) {
86 args->texture = item.monochrome_blit_arguments.texture;
87 args->blend = item.monochrome_blit_arguments.blend;
88}
89
90inline void from_item(const RenderQueue::Item& item, FillRectProgram::Arguments* args) {
91 args->color = item.rect_arguments.color;
92}
93
94inline void from_item(const RenderQueue::Item& item, BlendedBlitProgram::Arguments* args) {
95 args->texture = item.blended_blit_arguments.texture;
96 args->blend = item.blended_blit_arguments.blend;
97 args->mask = item.blended_blit_arguments.mask;
98}
99
100inline void from_item(const RenderQueue::Item& item, DrawLineProgram::Arguments* args) {
101 args->color = item.line_arguments.color;
102 args->line_width = item.line_arguments.line_width;
103}
104
105// Batches up as many items from 'items' that have the same 'program_id'.
106// Increases 'index' and returns an argument vector that can directly be passed
107// to the individual program.
108template <typename T>
109std::vector<T> batch_up(const RenderQueue::Program program_id,
110 const std::vector<RenderQueue::Item>& items,
111 size_t* index) {
112 std::vector<T> all_args;
113 while (*index < items.size()) {
114 const RenderQueue::Item& current_item = items.at(*index);
115 if (current_item.program_id != program_id) {
116 break;
117 }
118 all_args.emplace_back();
119 T& args = all_args.back();
120 args.destination_rect = current_item.destination_rect;
121 args.z_value = current_item.z_value;
122 args.blend_mode = current_item.blend_mode;
123 from_item(current_item, &args);
124 ++(*index);
125 }
126 return all_args;
127}
128
129// Calls glScissor for the given 'rect' and enables GL_SCISSOR_TEST at
130// creation. Disables GL_SCISSOR_TEST at desctruction again.
131class ScopedScissor {
132public:
133 ScopedScissor(const FloatRect& rect);
134 ~ScopedScissor();
135
136private:
137 DISALLOW_COPY_AND_ASSIGN(ScopedScissor);
138};
139
140ScopedScissor::ScopedScissor(const FloatRect& rect) {
141 glScissor(rect.x, rect.y, rect.w, rect.h);
142 glEnable(GL_SCISSOR_TEST);
143}
144
145ScopedScissor::~ScopedScissor() {
146 glDisable(GL_SCISSOR_TEST);
147}
148
149} // namespace
150
151RenderQueue::RenderQueue()
152 : next_z_(1),
153 terrain_program_(new TerrainProgram()),
154 dither_program_(new DitherProgram()),
155 road_program_(new RoadProgram()) {
156}
157
158// static
159RenderQueue& RenderQueue::instance() {
160 static RenderQueue render_queue;
161 return render_queue;
162}
163
164void RenderQueue::enqueue(const Item& given_item) {
165 Item* item;
166 uint32_t extra_value = 0;
167
168 switch (given_item.program_id) {
169 case Program::kBlit:
170 extra_value = given_item.vanilla_blit_arguments.texture.texture_id;
171 break;
172
173 case Program::kBlitMonochrome:
174 extra_value = given_item.monochrome_blit_arguments.texture.texture_id;
175 break;
176
177 case Program::kBlitBlended:
178 extra_value = given_item.blended_blit_arguments.texture.texture_id;
179 break;
180
181 case Program::kLine:
182 extra_value = given_item.line_arguments.line_width;
183 break;
184
185 case Program::kRect:
186 case Program::kTerrainBase:
187 case Program::kTerrainDither:
188 case Program::kTerrainRoad:
189 /* all fallthroughs intended */
190 break;
191
192 default:
193 throw wexception("Unknown given_item.program_id: %d", given_item.program_id);
194 }
195
196 if (given_item.blend_mode == BlendMode::Copy) {
197 opaque_items_.emplace_back(given_item);
198 item = &opaque_items_.back();
199 item->z_value = to_opengl_z(next_z_);
200 item->key = make_key_opaque(static_cast<uint64_t>(item->program_id), next_z_, extra_value);
201 } else {
202 blended_items_.emplace_back(given_item);
203 item = &blended_items_.back();
204 item->z_value = to_opengl_z(next_z_);
205 item->key = make_key_blended(static_cast<uint64_t>(item->program_id), next_z_, extra_value);
206 }
207 ++next_z_;
208}
209
210void RenderQueue::draw(const int screen_width, const int screen_height) {
211 if (next_z_ >= kMaximumZValue) {
212 throw wexception("Too many drawn layers. Ran out of z-values.");
213 }
214
215 glBindFramebuffer(GL_FRAMEBUFFER, 0);
216 glViewport(0, 0, screen_width, screen_height);
217
218 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
219
220 glDisable(GL_BLEND);
221
222 std::sort(opaque_items_.begin(), opaque_items_.end());
223 draw_items(opaque_items_);
224 opaque_items_.clear();
225
226 glEnable(GL_BLEND);
227 glDepthMask(GL_FALSE);
228
229 std::sort(blended_items_.begin(), blended_items_.end());
230 draw_items(blended_items_);
231 blended_items_.clear();
232
233 glDepthMask(GL_TRUE);
234
235 next_z_ = 1;
236}
237
238void RenderQueue::draw_items(const std::vector<Item>& items) {
239 size_t i = 0;
240 while (i < items.size()) {
241 const Item& item = items[i];
242 switch (item.program_id) {
243 case Program::kBlit:
244 VanillaBlitProgram::instance().draw(
245 batch_up<VanillaBlitProgram::Arguments>(Program::kBlit, items, &i));
246 break;
247
248 case Program::kBlitMonochrome:
249 MonochromeBlitProgram::instance().draw(
250 batch_up<MonochromeBlitProgram::Arguments>(Program::kBlitMonochrome, items, &i));
251 break;
252
253 case Program::kBlitBlended:
254 BlendedBlitProgram::instance().draw(
255 batch_up<BlendedBlitProgram::Arguments>(Program::kBlitBlended, items, &i));
256 break;
257
258 case Program::kLine:
259 DrawLineProgram::instance().draw(
260 batch_up<DrawLineProgram::Arguments>(Program::kLine, items, &i));
261 break;
262
263 case Program::kRect:
264 FillRectProgram::instance().draw(
265 batch_up<FillRectProgram::Arguments>(Program::kRect, items, &i));
266 break;
267
268 case Program::kTerrainBase: {
269 ScopedScissor scoped_scissor(item.destination_rect);
270 terrain_program_->draw(item.terrain_arguments.gametime,
271 *item.terrain_arguments.terrains,
272 *item.terrain_arguments.fields_to_draw,
273 item.z_value);
274 ++i;
275 } break;
276
277 case Program::kTerrainDither: {
278 ScopedScissor scoped_scissor(item.destination_rect);
279 dither_program_->draw(item.terrain_arguments.gametime,
280 *item.terrain_arguments.terrains,
281 *item.terrain_arguments.fields_to_draw,
282 item.z_value + kOpenGlZDelta);
283 ++i;
284 } break;
285
286 case Program::kTerrainRoad: {
287 ScopedScissor scoped_scissor(item.destination_rect);
288 road_program_->draw(item.terrain_arguments.renderbuffer_width,
289 item.terrain_arguments.renderbuffer_height,
290 *item.terrain_arguments.fields_to_draw,
291 item.z_value + 2 * kOpenGlZDelta);
292 ++i;
293 } break;
294
295 default:
296 throw wexception("Unknown item.program_id: %d", item.program_id);
297 }
298 }
299}
0300
=== added file 'src/graphic/render_queue.h'
--- src/graphic/render_queue.h 1970-01-01 00:00:00 +0000
+++ src/graphic/render_queue.h 2016-01-05 11:29:18 +0000
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2006-2014 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20#ifndef WL_GRAPHIC_RENDER_QUEUE_H
21#define WL_GRAPHIC_RENDER_QUEUE_H
22
23#include <memory>
24#include <vector>
25
26#include <stdint.h>
27
28#include "base/macros.h"
29#include "base/rect.h"
30#include "graphic/blend_mode.h"
31#include "graphic/color.h"
32#include "graphic/gl/fields_to_draw.h"
33#include "logic/description_maintainer.h"
34#include "logic/world/terrain_description.h"
35
36class DitherProgram;
37class RoadProgram;
38class TerrainProgram;
39
40// The RenderQueue is a singleton implementing the concept of deferred
41// rendering: Every rendering call that pretends to draw onto the screen will
42// instead enqueue an item into the RenderQueue. The Graphic::refresh() will
43// then setup OpenGL to render onto the screen and then call
44// RenderQueue::draw() which will execute all the draw calls.
45//
46// The advantage of this design is that render calls can be reordered and
47// batched up to avoid OpenGL state changes as much as possible. This can
48// reduce the amount of OpenGL calls done in the system per frame by an order
49// of magnitude if assets are properly batched up into texture atlases.
50//
51// Rendering is simple: first everything fully opaque is rendered front to back
52// (so that no pixel is drawn twice). This allows for maximum program batching,
53// as for example all opaque rectangles can be rendered in one draw call,
54// ignoring z-value.
55//
56// In the second step, all drawing calls with (partially) transparent pixels
57// are done. This has to be done strictly in z ordering (back to front), so
58// that transparency works correctly. But common operations can still be
59// batched - for example the blitting of houses could all be done with the same
60// z value and using a common texture atlas. Then they could be drawn in one
61// woosh.
62//
63// Non overlapping rectangles can be drawn in parallel, ignoring z-order. I
64// experimented with a linear algorithm to find all overlapping rectangle
65// pairs (see bzr history), but it did not buy the performance I was hoping it
66// would. So I abandoned this idea again.
67//
68// Note: all draw calls that target a Texture are not going to the RenderQueue,
69// but are still immediately executed. The RenderQueue is only used for
70// rendering onto the screen.
71//
72// TODO(sirver): we could (even) better performance by being z-layer aware
73// while drawing. For example the UI could draw non-overlapping windows and
74// sibling children with the same z-value for better batching. Also for example
75// build-help symbols, buildings, and flags could all be drawn with the same
76// z-layer for better batching up. This would also get rid of the z-layer
77// issues we are having.
78class RenderQueue {
79public:
80 enum Program {
81 kTerrainBase,
82 kTerrainDither,
83 kTerrainRoad,
84 kBlit,
85 kBlitMonochrome,
86 kBlitBlended,
87 kRect,
88 kLine,
89 kHighestProgramId,
90 };
91
92 struct VanillaBlitArguments {
93 BlitData texture;
94 float opacity;
95 };
96
97 struct MonochromeBlitArguments {
98 BlitData texture;
99 RGBAColor blend;
100 };
101
102 struct BlendedBlitArguments {
103 BlitData texture;
104 BlitData mask;
105 RGBAColor blend;
106 };
107
108 struct RectArguments {
109 RGBAColor color;
110 };
111
112 struct LineArguments {
113 RGBColor color;
114 uint8_t line_width;
115 };
116
117 struct TerrainArguments {
118 TerrainArguments() {}
119
120 int gametime;
121 int renderbuffer_width;
122 int renderbuffer_height;
123 const DescriptionMaintainer<Widelands::TerrainDescription>* terrains;
124 FieldsToDraw* fields_to_draw;
125 };
126
127 // The union of all possible program arguments represents an Item that is
128 // enqueued in the Queue. This is on purpose not done with OOP so that the
129 // queue is more cache friendly.
130 struct Item {
131 Item() {}
132
133 inline bool operator<(const Item& other) const {
134 return key < other.key;
135 }
136
137 // The program that will be used to draw this item. Also defines which
138 // union type is filled in.
139 int program_id;
140
141 // The z-value in GL space that will be used for drawing.
142 float z_value;
143
144 // The bounding box in the renderbuffer where this draw will change pixels.
145 FloatRect destination_rect;
146
147 // The key for sorting this item in the queue. It depends on the type of
148 // item how this is calculated, but it will contain at least the program,
149 // the z-layer, if it is opaque or transparent and program specific
150 // options. After ordering the queue by this, it defines the batching.
151 uint64_t key;
152
153 // If this is opaque or, if not, which blend_mode to use.
154 BlendMode blend_mode;
155
156 union {
157 VanillaBlitArguments vanilla_blit_arguments;
158 MonochromeBlitArguments monochrome_blit_arguments;
159 BlendedBlitArguments blended_blit_arguments;
160 TerrainArguments terrain_arguments;
161 RectArguments rect_arguments;
162 LineArguments line_arguments;
163 };
164 };
165
166 static RenderQueue& instance();
167
168 // Enqueues 'item' in the queue with a higher 'z' value than the last enqueued item.
169 void enqueue(const Item& item);
170
171 // Draws all items in the queue in an optimal ordering and as much batching
172 // as possible. This will draw one complete frame onto the screen and this
173 // function is the only one that actually triggers draws to the screen
174 // directly.
175 void draw(int screen_width, int screen_height);
176
177private:
178 RenderQueue();
179
180 void draw_items(const std::vector<Item>& items);
181
182 // The z value that should be used for the next draw, so that it is on top
183 // of everything before.
184 int next_z_;
185
186 std::unique_ptr<TerrainProgram> terrain_program_;
187 std::unique_ptr<DitherProgram> dither_program_;
188 std::unique_ptr<RoadProgram> road_program_;
189
190 std::vector<Item> blended_items_;
191 std::vector<Item> opaque_items_;
192
193 DISALLOW_COPY_AND_ASSIGN(RenderQueue);
194};
195
196
197#endif // end of include guard: WL_GRAPHIC_RENDER_QUEUE_H
0198
=== modified file 'src/graphic/rendertarget.cc'
--- src/graphic/rendertarget.cc 2015-09-12 07:53:38 +0000
+++ src/graphic/rendertarget.cc 2016-01-05 11:29:18 +0000
@@ -97,7 +97,7 @@
97 *prevofs = m_offset;97 *prevofs = m_offset;
9898
99 // Apply the changes99 // Apply the changes
100 m_offset = rc.top_left() - (newrect.top_left() - m_rect.top_left() - m_offset);100 m_offset = rc.origin() - (newrect.origin() - m_rect.origin() - m_offset);
101 m_rect = newrect;101 m_rect = newrect;
102102
103 return true;103 return true;
@@ -123,17 +123,14 @@
123/**123/**
124 * This functions draws a line in the target124 * This functions draws a line in the target
125 */125 */
126void RenderTarget::draw_line126void RenderTarget::draw_line(const Point& start,
127 (int32_t x1, int32_t y1, int32_t x2, int32_t y2,127 const Point& end,
128 const RGBColor& color, uint8_t gwidth)128 const RGBColor& color,
129{129 uint8_t line_width) {
130 ::draw_line(x1 + m_offset.x + m_rect.x,130 m_surface->draw_line(Point(start.x + m_offset.x + m_rect.x, start.y + m_offset.y + m_rect.y),
131 y1 + m_offset.y + m_rect.y,131 Point(end.x + m_offset.x + m_rect.x, end.y + m_offset.y + m_rect.y),
132 x2 + m_offset.x + m_rect.x,132 color,
133 y2 + m_offset.y + m_rect.y,133 line_width);
134 color,
135 gwidth,
136 m_surface);
137}134}
138135
139/**136/**
@@ -151,14 +148,14 @@
151{148{
152 Rect r(rect);149 Rect r(rect);
153 if (clip(r))150 if (clip(r))
154 ::fill_rect(r, clr, m_surface);151 m_surface->fill_rect(r, clr);
155}152}
156153
157void RenderTarget::brighten_rect(const Rect& rect, int32_t factor)154void RenderTarget::brighten_rect(const Rect& rect, int32_t factor)
158{155{
159 Rect r(rect);156 Rect r(rect);
160 if (clip(r))157 if (clip(r))
161 ::brighten_rect(r, factor, m_surface);158 m_surface->brighten_rect(r, factor);
162}159}
163160
164/**161/**
@@ -175,12 +172,11 @@
175 Rect srcrc(Point(0, 0), image->width(), image->height());172 Rect srcrc(Point(0, 0), image->width(), image->height());
176173
177 if (to_surface_geometry(&destination_point, &srcrc)) {174 if (to_surface_geometry(&destination_point, &srcrc)) {
178 ::blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),175 m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
179 *image,176 *image,
180 srcrc,177 srcrc,
181 1.,178 1.,
182 blend_mode,179 blend_mode);
183 m_surface);
184 }180 }
185}181}
186182
@@ -194,11 +190,8 @@
194 Rect srcrc(Point(0, 0), image->width(), image->height());190 Rect srcrc(Point(0, 0), image->width(), image->height());
195191
196 if (to_surface_geometry(&destination_point, &srcrc)) {192 if (to_surface_geometry(&destination_point, &srcrc)) {
197 ::blit_monochrome(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),193 m_surface->blit_monochrome(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
198 *image,194 *image, srcrc, blend_mode);
199 srcrc,
200 blend_mode,
201 m_surface);
202 }195 }
203}196}
204197
@@ -220,12 +213,11 @@
220213
221 Point destination_point(dst);214 Point destination_point(dst);
222 if (to_surface_geometry(&destination_point, &srcrc))215 if (to_surface_geometry(&destination_point, &srcrc))
223 ::blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),216 m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
224 *image,217 *image,
225 srcrc,218 srcrc,
226 1.,219 1.,
227 blend_mode,220 blend_mode);
228 m_surface);
229}221}
230222
231void RenderTarget::blitrect_scale(const Rect& dst,223void RenderTarget::blitrect_scale(const Rect& dst,
@@ -237,12 +229,11 @@
237 Point destination_point(dst.x, dst.y);229 Point destination_point(dst.x, dst.y);
238 Rect srcrect(source_rect);230 Rect srcrect(source_rect);
239 if (to_surface_geometry(&destination_point, &srcrect)) {231 if (to_surface_geometry(&destination_point, &srcrect)) {
240 ::blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),232 m_surface->blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),
241 *image,233 *image,
242 source_rect,234 source_rect,
243 opacity,235 opacity,
244 blend_mode,236 blend_mode);
245 m_surface);
246 }237 }
247}238}
248239
@@ -253,12 +244,11 @@
253 Point destination_point(destination_rect.x, destination_rect.y);244 Point destination_point(destination_rect.x, destination_rect.y);
254 Rect srcrect(source_rect);245 Rect srcrect(source_rect);
255 if (to_surface_geometry(&destination_point, &srcrect)) {246 if (to_surface_geometry(&destination_point, &srcrect)) {
256 ::blit_monochrome(247 m_surface->blit_monochrome(
257 Rect(destination_point.x, destination_point.y, destination_rect.w, destination_rect.h),248 Rect(destination_point.x, destination_point.y, destination_rect.w, destination_rect.h),
258 *image,249 *image,
259 source_rect,250 source_rect,
260 blend,251 blend);
261 m_surface);
262 }252 }
263}253}
264254
@@ -315,7 +305,7 @@
315 srcrc.w = r.w - tx;305 srcrc.w = r.w - tx;
316306
317 const Rect dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);307 const Rect dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
318 ::blit(dst_rect, *image, srcrc, 1., blend_mode, m_surface);308 m_surface->blit(dst_rect, *image, srcrc, 1., blend_mode);
319309
320 tx += srcrc.w;310 tx += srcrc.w;
321311
@@ -368,7 +358,7 @@
368 const Animation& anim = g_gr->animations().get_animation(animation);358 const Animation& anim = g_gr->animations().get_animation(animation);
369359
370 Point destination_point = dst - anim.hotspot();360 Point destination_point = dst - anim.hotspot();
371 destination_point += gsrcrc.top_left();361 destination_point += gsrcrc.origin();
372362
373 Rect srcrc(gsrcrc);363 Rect srcrc(gsrcrc);
374364
@@ -473,6 +463,6 @@
473 srcrc->h = m_rect.h - dst->y;463 srcrc->h = m_rect.h - dst->y;
474 }464 }
475465
476 *dst += m_rect.top_left();466 *dst += m_rect.origin();
477 return true;467 return true;
478}468}
479469
=== modified file 'src/graphic/rendertarget.h'
--- src/graphic/rendertarget.h 2015-09-09 18:49:58 +0000
+++ src/graphic/rendertarget.h 2016-01-05 11:29:18 +0000
@@ -60,8 +60,7 @@
60 int32_t width() const;60 int32_t width() const;
61 int32_t height() const;61 int32_t height() const;
6262
63 void draw_line63 void draw_line(const Point& start, const Point& end, const RGBColor& color, uint8_t width = 1);
64 (int32_t x1, int32_t y1, int32_t x2, int32_t y2, const RGBColor& color, uint8_t width = 1);
65 void draw_rect(const Rect&, const RGBColor&);64 void draw_rect(const Rect&, const RGBColor&);
66 void fill_rect(const Rect&, const RGBAColor&);65 void fill_rect(const Rect&, const RGBAColor&);
67 void brighten_rect(const Rect&, int32_t factor);66 void brighten_rect(const Rect&, int32_t factor);
6867
=== modified file 'src/graphic/richtext.cc'
--- src/graphic/richtext.cc 2015-09-28 06:41:58 +0000
+++ src/graphic/richtext.cc 2016-01-05 11:29:18 +0000
@@ -512,7 +512,7 @@
512 {512 {
513 Rect oldbox;513 Rect oldbox;
514 Point oldofs;514 Point oldofs;
515 Rect bbox((*elt)->bbox.top_left() + offset, (*elt)->bbox.w, (*elt)->bbox.h);515 Rect bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
516516
517 if (dst.enter_window(bbox, &oldbox, &oldofs)) {517 if (dst.enter_window(bbox, &oldbox, &oldofs)) {
518 if (background)518 if (background)
519519
=== modified file 'src/graphic/screen.cc'
--- src/graphic/screen.cc 2014-12-27 09:59:12 +0000
+++ src/graphic/screen.cc 2016-01-05 11:29:18 +0000
@@ -24,20 +24,12 @@
2424
25#include "base/wexception.h"25#include "base/wexception.h"
26#include "graphic/gl/utils.h"26#include "graphic/gl/utils.h"
27#include "graphic/render_queue.h"
27#include "graphic/texture.h"28#include "graphic/texture.h"
2829
29Screen::Screen(int w, int h) : m_w(w), m_h(h) {30Screen::Screen(int w, int h) : m_w(w), m_h(h) {
30}31}
3132
32void Screen::pixel_to_gl(float* x, float* y) const {
33 *x = (*x / m_w) * 2. - 1.;
34 *y = 1. - (*y / m_h) * 2.;
35}
36
37void Screen::setup_gl() {
38 glBindFramebuffer(GL_FRAMEBUFFER, 0);
39}
40
41int Screen::width() const {33int Screen::width() const {
42 return m_w;34 return m_w;
43}35}
@@ -50,17 +42,7 @@
50 std::unique_ptr<uint8_t[]> pixels(new uint8_t[m_w * m_h * 4]);42 std::unique_ptr<uint8_t[]> pixels(new uint8_t[m_w * m_h * 4]);
51 glReadPixels(0, 0, m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());43 glReadPixels(0, 0, m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
5244
53 // Swap order of rows in m_pixels, to compensate for the upside-down nature of the45 Gl::swap_rows(m_w, m_h, m_w * 4, 4, pixels.get());
54 // OpenGL coordinate system.
55 uint8_t* begin_row = pixels.get();
56 uint8_t* end_row = pixels.get() + (m_w * (m_h - 1) * 4);
57 while (begin_row < end_row) {
58 for (int x = 0; x < m_w * 4; ++x) {
59 std::swap(begin_row[x], end_row[x]);
60 }
61 begin_row += m_w * 4;
62 end_row -= m_w * 4;
63 }
6446
65 // Ownership of pixels is not taken here. But the Texture() transfers it to47 // Ownership of pixels is not taken here. But the Texture() transfers it to
66 // the GPU, frees the SDL surface and after that we are free to free48 // the GPU, frees the SDL surface and after that we are free to free
@@ -77,3 +59,64 @@
7759
78 return std::unique_ptr<Texture>(new Texture(surface));60 return std::unique_ptr<Texture>(new Texture(surface));
79}61}
62
63void Screen::do_blit(const FloatRect& dst_rect,
64 const BlitData& texture,
65 float opacity,
66 BlendMode blend_mode) {
67 RenderQueue::Item i;
68 i.program_id = RenderQueue::Program::kBlit;
69 i.blend_mode = blend_mode;
70 i.destination_rect = dst_rect;
71 i.vanilla_blit_arguments.texture = texture;
72 i.vanilla_blit_arguments.opacity = opacity;
73 RenderQueue::instance().enqueue(i);
74}
75
76void Screen::do_blit_blended(const FloatRect& dst_rect,
77 const BlitData& texture,
78 const BlitData& mask,
79 const RGBColor& blend) {
80 RenderQueue::Item i;
81 i.destination_rect = dst_rect;
82 i.program_id = RenderQueue::Program::kBlitBlended;
83 i.blend_mode = BlendMode::UseAlpha;
84 i.blended_blit_arguments.texture = texture;
85 i.blended_blit_arguments.mask = mask;
86 i.blended_blit_arguments.blend = blend;
87 RenderQueue::instance().enqueue(i);
88}
89
90void Screen::do_blit_monochrome(const FloatRect& dst_rect,
91 const BlitData& texture,
92 const RGBAColor& blend) {
93 RenderQueue::Item i;
94 i.program_id = RenderQueue::Program::kBlitMonochrome;
95 i.blend_mode = BlendMode::UseAlpha;
96 i.destination_rect = dst_rect;
97 i.monochrome_blit_arguments.texture = texture;
98 i.monochrome_blit_arguments.blend = blend;
99 RenderQueue::instance().enqueue(i);
100}
101
102void Screen::do_draw_line(const FloatPoint& start,
103 const FloatPoint& end,
104 const RGBColor& color,
105 const int line_width) {
106 RenderQueue::Item i;
107 i.program_id = RenderQueue::Program::kLine;
108 i.blend_mode = BlendMode::Copy;
109 i.destination_rect = FloatRect(start.x, start.y, end.x - start.x, end.y - start.y);
110 i.line_arguments.color = color;
111 i.line_arguments.line_width = line_width;
112 RenderQueue::instance().enqueue(i);
113}
114
115void Screen::do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
116 RenderQueue::Item i;
117 i.program_id = RenderQueue::Program::kRect;
118 i.blend_mode = blend_mode;
119 i.destination_rect = dst_rect;
120 i.rect_arguments.color = color;
121 RenderQueue::instance().enqueue(i);
122}
80123
=== modified file 'src/graphic/screen.h'
--- src/graphic/screen.h 2014-12-07 21:34:11 +0000
+++ src/graphic/screen.h 2016-01-05 11:29:18 +0000
@@ -35,8 +35,6 @@
35 // Implements Surface.35 // Implements Surface.
36 int width() const override;36 int width() const override;
37 int height() const override;37 int height() const override;
38 void setup_gl() override;
39 void pixel_to_gl(float* x, float* y) const override;
4038
41 // Reads out the current pixels in the framebuffer and returns39 // Reads out the current pixels in the framebuffer and returns
42 // them as a texture for screenshots. This is a very slow process,40 // them as a texture for screenshots. This is a very slow process,
@@ -44,6 +42,24 @@
44 std::unique_ptr<Texture> to_texture() const;42 std::unique_ptr<Texture> to_texture() const;
4543
46private:44private:
45 void do_blit(const FloatRect& dst_rect,
46 const BlitData& texture,
47 float opacity,
48 BlendMode blend_mode) override;
49 void do_blit_blended(const FloatRect& dst_rect,
50 const BlitData& texture,
51 const BlitData& mask,
52 const RGBColor& blend) override;
53 void do_blit_monochrome(const FloatRect& dst_rect,
54 const BlitData& texture,
55 const RGBAColor& blend) override;
56 void do_draw_line(const FloatPoint& start,
57 const FloatPoint& end,
58 const RGBColor& color,
59 int width) override;
60 void
61 do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
62
47 const int m_w, m_h;63 const int m_w, m_h;
4864
49 DISALLOW_COPY_AND_ASSIGN(Screen);65 DISALLOW_COPY_AND_ASSIGN(Screen);
5066
=== modified file 'src/graphic/surface.cc'
--- src/graphic/surface.cc 2015-01-15 07:14:53 +0000
+++ src/graphic/surface.cc 2016-01-05 11:29:18 +0000
@@ -26,197 +26,86 @@
26#include <SDL.h>26#include <SDL.h>
2727
28#include "base/macros.h"28#include "base/macros.h"
29#include "graphic/gl/blit_program.h"29#include "base/rect.h"
30#include "graphic/gl/draw_line_program.h"30#include "graphic/gl/coordinate_conversion.h"
31#include "graphic/gl/fill_rect_program.h"
32#include "graphic/gl/utils.h"31#include "graphic/gl/utils.h"
33#include "graphic/graphic.h"32
34#include "graphic/texture.h"33namespace {
3534
3635// Adjust 'original' so that only 'src_rect' is actually blitted.
37namespace {36BlitData adjust_for_src(BlitData blit_data, const Rect& src_rect) {
3837 blit_data.rect.x += src_rect.x;
39// Convert the 'rect' in pixel space into opengl space.38 blit_data.rect.y += src_rect.y;
40enum class ConversionMode {39 blit_data.rect.w = src_rect.w;
41 // Convert the rect as given.40 blit_data.rect.h = src_rect.h;
42 kExact,41 return blit_data;
43
44 // Convert the rect so that the borders are in the center
45 // of the pixels.
46 kMidPoint,
47};
48
49FloatRect to_opengl(const Surface& surface, const Rect& rect, ConversionMode mode) {
50 const float delta = mode == ConversionMode::kExact ? 0. : 0.5;
51 float x1 = rect.x + delta;
52 float y1 = rect.y + delta;
53 surface.pixel_to_gl(&x1, &y1);
54 float x2 = rect.x + rect.w - delta;
55 float y2 = rect.y + rect.h - delta;
56 surface.pixel_to_gl(&x2, &y2);
57 return FloatRect(x1, y1, x2 - x1, y2 - y1);
58}
59
60// Converts the pixel (x, y) in a texture to a gl coordinate in [0, 1].
61inline void pixel_to_gl_texture(const int width, const int height, float* x, float* y) {
62 *x = (*x / width);
63 *y = (*y / height);
64}
65
66// Convert 'dst' and 'srcrc' from pixel space into opengl space, taking into
67// account that we might be a subtexture in a bigger texture.
68void src_and_dst_rect_to_gl(const Surface& surface,
69 const Image& image,
70 const Rect& dst_rect,
71 const Rect& src_rect,
72 FloatRect* gl_dst_rect,
73 FloatRect* gl_src_rect) {
74 // Source Rectangle. We have to take into account that the texture might be
75 // a subtexture in another bigger texture. So we first figure out the pixel
76 // coordinates given it is a full texture (values between 0 and 1) and then
77 // adjust these for the texture coordinates in the parent texture.
78 const FloatRect& texture_coordinates = image.texture_coordinates();
79
80 float x1 = src_rect.x;
81 float y1 = src_rect.y;
82 pixel_to_gl_texture(image.width(), image.height(), &x1, &y1);
83 x1 = texture_coordinates.x + x1 * texture_coordinates.w;
84 y1 = texture_coordinates.y + y1 * texture_coordinates.h;
85
86 float x2 = src_rect.x + src_rect.w;
87 float y2 = src_rect.y + src_rect.h;
88 pixel_to_gl_texture(image.width(), image.height(), &x2, &y2);
89 x2 = texture_coordinates.x + x2 * texture_coordinates.w;
90 y2 = texture_coordinates.y + y2 * texture_coordinates.h;
91
92 gl_src_rect->x = x1;
93 gl_src_rect->y = y1;
94 gl_src_rect->w = x2 - x1;
95 gl_src_rect->h = y2 - y1;
96
97 *gl_dst_rect = to_opengl(surface, dst_rect, ConversionMode::kExact);
98}42}
9943
100} // namespace44} // namespace
10145
10246void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
103void fill_rect(const Rect& rc, const RGBAColor& clr, Surface* surface) {47 surface->draw_line(Point(rc.x, rc.y), Point(rc.x + rc.w, rc.y), clr, 1);
104 surface->setup_gl();48 surface->draw_line(Point(rc.x + rc.w, rc.y), Point(rc.x + rc.w, rc.y + rc.h), clr, 1);
105 glViewport(0, 0, surface->width(), surface->height());49 surface->draw_line(Point(rc.x + rc.w, rc.y + rc.h), Point(rc.x, rc.y + rc.h), clr, 1);
10650 surface->draw_line(Point(rc.x, rc.y + rc.h), Point(rc.x, rc.y), clr, 1);
107 glBlendFunc(GL_ONE, GL_ZERO);51}
10852
109 FillRectProgram::instance().draw(to_opengl(*surface, rc, ConversionMode::kExact), clr);53void Surface::fill_rect(const Rect& rc, const RGBAColor& clr) {
11054 const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
111 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);55 do_fill_rect(rect, clr, BlendMode::Copy);
112}56}
11357
114void brighten_rect(const Rect& rc, const int32_t factor, Surface * surface)58void Surface::brighten_rect(const Rect& rc, const int32_t factor)
115{59{
116 if (!factor)60 if (!factor) {
117 return;61 return;
11862 }
119 surface->setup_gl();63
120 glViewport(0, 0, surface->width(), surface->height());64 const BlendMode blend_mode = factor < 0 ? BlendMode::Subtract : BlendMode::UseAlpha;
12165 const int abs_factor = std::abs(factor);
122 // The simple trick here is to fill the rect, but using a different glBlendFunc that will sum66 const RGBAColor color(abs_factor, abs_factor, abs_factor, 0);
123 // src and target (or subtract them if factor is negative).67 const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
124 if (factor < 0) {68 do_fill_rect(rect, color, blend_mode);
125 glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
126 }
127
128 glBlendFunc(GL_ONE, GL_ONE);
129
130 const int delta = std::abs(factor);
131 FillRectProgram::instance().draw(
132 to_opengl(*surface, rc, ConversionMode::kExact), RGBAColor(delta, delta, delta, 0));
133
134 if (factor < 0) {
135 glBlendEquation(GL_FUNC_ADD);
136 }
137
138 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
139}69}
14070
141void draw_line71void Surface::draw_line
142 (int x1, int y1, int x2, int y2, const RGBColor& color, int gwidth, Surface * surface)72 (const Point& start, const Point& end, const RGBColor& color, int line_width)
143{73{
144 surface->setup_gl();74 float gl_x1 = start.x;
145 glViewport(0, 0, surface->width(), surface->height());75 float gl_y1 = start.y;
14676
147 float gl_x1 = x1 + 0.5;77 // Include the end pixel.
148 float gl_y1 = y1 + 0.5;78 float gl_x2 = end.x + 1.;
149 surface->pixel_to_gl(&gl_x1, &gl_y1);79 float gl_y2 = end.y + 1.;
15080 pixel_to_gl_renderbuffer(width(), height(), &gl_x1, &gl_y1);
151 float gl_x2 = x2 + 0.5;81 pixel_to_gl_renderbuffer(width(), height(), &gl_x2, &gl_y2);
152 float gl_y2 = y2 + 0.5;82
153 surface->pixel_to_gl(&gl_x2, &gl_y2);83 do_draw_line(FloatPoint(gl_x1, gl_y1), FloatPoint(gl_x2, gl_y2), color, line_width);
15484}
155 DrawLineProgram::instance().draw(gl_x1, gl_y1, gl_x2, gl_y2, color, gwidth);85
156}86void Surface::blit_monochrome(const Rect& dst_rect,
15787 const Image& image,
158void blit_monochrome(const Rect& dst_rect,88 const Rect& src_rect,
159 const Image& image,89 const RGBAColor& blend) {
160 const Rect& src_rect,90 const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
161 const RGBAColor& blend,91 do_blit_monochrome(rect, adjust_for_src(image.blit_data(), src_rect), blend);
162 Surface* surface) {92}
163 surface->setup_gl();93
164 glViewport(0, 0, surface->width(), surface->height());94void Surface::blit_blended(const Rect& dst_rect,
16595 const Image& image,
166 FloatRect gl_dst_rect, gl_src_rect;96 const Image& texture_mask,
167 src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);97 const Rect& src_rect,
16898 const RGBColor& blend) {
169 MonochromeBlitProgram::instance().draw(99 const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
170 gl_dst_rect, gl_src_rect, image.get_gl_texture(), blend);100 do_blit_blended(rect, adjust_for_src(image.blit_data(), src_rect),
171101 adjust_for_src(texture_mask.blit_data(), src_rect), blend);
172 // TODO(sirver): This is a hacky attempt to fix 1409267. It102}
173 // should not stick around.103
174 glBindFramebuffer(GL_FRAMEBUFFER, 0);104void Surface::blit(const Rect& dst_rect,
175}105 const Image& image,
176106 const Rect& src_rect,
177void blit_blended(const Rect& dst_rect,107 float opacity,
178 const Image& image,108 BlendMode blend_mode) {
179 const Image& mask,109 const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
180 const Rect& src_rect,110 do_blit(rect, adjust_for_src(image.blit_data(), src_rect), opacity, blend_mode);
181 const RGBColor& blend,
182 Surface* surface) {
183 surface->setup_gl();
184 glViewport(0, 0, surface->width(), surface->height());
185
186 FloatRect gl_dst_rect, gl_src_rect;
187 src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
188
189 BlendedBlitProgram::instance().draw(
190 gl_dst_rect, gl_src_rect, image.get_gl_texture(), mask.get_gl_texture(), blend);
191
192 // TODO(sirver): This is a hacky attempt to fix 1409267. It
193 // should not stick around.
194 glBindFramebuffer(GL_FRAMEBUFFER, 0);
195}
196
197void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
198 draw_line(rc.x, rc.y, rc.x + rc.w, rc.y, clr, 1, surface);
199 draw_line(rc.x + rc.w, rc.y, rc.x + rc.w, rc.y + rc.h, clr, 1, surface);
200 draw_line(rc.x + rc.w, rc.y + rc.h, rc.x, rc.y + rc.h, clr, 1, surface);
201 draw_line(rc.x, rc.y + rc.h, rc.x, rc.y, clr, 1, surface);
202}
203
204void blit(const Rect& dst_rect,
205 const Image& image,
206 const Rect& src_rect,
207 float opacity,
208 BlendMode blend_mode,
209 Surface* surface) {
210 glViewport(0, 0, surface->width(), surface->height());
211 surface->setup_gl();
212
213 FloatRect gl_dst_rect, gl_src_rect;
214 src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
215
216 VanillaBlitProgram::instance().draw(
217 gl_dst_rect, gl_src_rect, image.get_gl_texture(), opacity, blend_mode);
218
219 // TODO(sirver): This is a hacky attempt to fix 1409267. It
220 // should not stick around.
221 glBindFramebuffer(GL_FRAMEBUFFER, 0);
222}111}
223112
=== modified file 'src/graphic/surface.h'
--- src/graphic/surface.h 2014-12-07 21:34:11 +0000
+++ src/graphic/surface.h 2016-01-05 11:29:18 +0000
@@ -41,47 +41,60 @@
41 virtual int width() const = 0;41 virtual int width() const = 0;
42 virtual int height() const = 0;42 virtual int height() const = 0;
4343
44 // Converts the given pixel into an OpenGl point. This might44 /// This draws a part of 'texture'.
45 // need some flipping of axis, depending if you want to render45 void blit(const Rect& dst,
46 // on the screen or not.46 const Image&,
47 virtual void pixel_to_gl(float* x, float* y) const = 0;47 const Rect& srcrc,
4848 const float opacity,
49 // Setups OpenGL to render to this surface.49 BlendMode blend_mode);
50 virtual void setup_gl() = 0;50
51 /// This draws a playercolor blended image. See BlendedBlitProgram.
52 void blit_blended(const Rect& dst,
53 const Image& image,
54 const Image& texture_mask,
55 const Rect& srcrc,
56 const RGBColor& blend);
57
58 /// This draws a grayed out version. See MonochromeBlitProgram.
59 void
60 blit_monochrome(const Rect& dst, const Image&, const Rect& srcrc, const RGBAColor& multiplier);
61
62 /// Draws a filled rect to the destination. No blending takes place, the values
63 // in the target are just replaced (i.e. / BlendMode would be BlendMode::Copy).
64 void fill_rect(const Rect&, const RGBAColor&);
65
66 /// draw a line to the destination
67 void draw_line(const Point& start, const Point& end, const RGBColor& color, int width);
68
69 /// makes a rectangle on the destination brighter (or darker).
70 void brighten_rect(const Rect&, int factor);
5171
52private:72private:
73 /// The actual implementation of the methods below.
74 virtual void do_blit(const FloatRect& dst_rect,
75 const BlitData& texture,
76 float opacity,
77 BlendMode blend_mode) = 0;
78
79 virtual void do_blit_blended(const FloatRect& dst_rect,
80 const BlitData& texture,
81 const BlitData& mask,
82 const RGBColor& blend) = 0;
83
84 virtual void do_blit_monochrome(const FloatRect& dst_rect,
85 const BlitData& texture,
86 const RGBAColor& blend) = 0;
87
88 virtual void
89 do_draw_line(const FloatPoint& start, const FloatPoint& end, const RGBColor& color, int width) = 0;
90
91 virtual void
92 do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
93
53 DISALLOW_COPY_AND_ASSIGN(Surface);94 DISALLOW_COPY_AND_ASSIGN(Surface);
54};95};
5596
56/// Draws a rect (frame only) to the surface.97/// Draws a rect (frame only) to the surface.
57void draw_rect(const Rect&, const RGBColor&, Surface* destination);98void draw_rect(const Rect&, const RGBColor&, Surface* destination);
5899
59/// This draws a part of 'texture' to 'surface'.
60void blit
61 (const Rect& dst, const Image&, const Rect& srcrc, const float opacity,
62 BlendMode blend_mode, Surface* destination);
63
64/// This draws a grayed out version. See MonochromeBlitProgram.
65void
66blit_monochrome
67 (const Rect& dst, const Image&, const Rect& srcrc,
68 const RGBAColor& multiplier, Surface* destination);
69
70/// This draws a playercolor blended image. See BlendedBlitProgram.
71void blit_blended
72 (const Rect& dst, const Image& image, const Image& mask, const Rect&
73 srcrc, const RGBColor& blend, Surface* destination);
74
75/// Draws a filled rect to the destination. No blending takes place, the values
76// in the target are just replaced (i.e. / BlendMode would be BlendMode::Copy).
77void fill_rect(const Rect&, const RGBAColor&, Surface* destination);
78
79/// draw a line to the destination
80void draw_line
81 (int x1, int y1, int x2, int y2, const RGBColor& color,
82 int width, Surface* destination);
83
84/// makes a rectangle on the destination brighter (or darker).
85void brighten_rect(const Rect&, int factor, Surface* destination);
86
87#endif // end of include guard: WL_GRAPHIC_SURFACE_H100#endif // end of include guard: WL_GRAPHIC_SURFACE_H
88101
=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc 2015-10-08 06:47:39 +0000
+++ src/graphic/text/rt_render.cc 2016-01-05 11:29:18 +0000
@@ -347,15 +347,15 @@
347uint16_t TextNode::hotspot_y() {347uint16_t TextNode::hotspot_y() {
348 return m_font.ascent(m_s.font_style);348 return m_font.ascent(m_s.font_style);
349}349}
350
350Texture* TextNode::render(TextureCache* texture_cache) {351Texture* TextNode::render(TextureCache* texture_cache) {
351 const Texture& img = m_font.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);352 const Texture& img = m_font.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
352 Texture* rv = new Texture(img.width(), img.height());353 Texture* rv = new Texture(img.width(), img.height());
353 blit(Rect(0, 0, img.width(), img.height()),354 rv->blit(Rect(0, 0, img.width(), img.height()),
354 img,355 img,
355 Rect(0, 0, img.width(), img.height()),356 Rect(0, 0, img.width(), img.height()),
356 1.,357 1.,
357 BlendMode::Copy,358 BlendMode::Copy);
358 rv);
359 return rv;359 return rv;
360}360}
361361
@@ -383,7 +383,7 @@
383 Texture* rv = new Texture(m_w, m_h);383 Texture* rv = new Texture(m_w, m_h);
384 for (uint16_t curx = 0; curx < m_w; curx += t.width()) {384 for (uint16_t curx = 0; curx < m_w; curx += t.width()) {
385 Rect srcrect(Point(0, 0), min<int>(t.width(), m_w - curx), m_h);385 Rect srcrect(Point(0, 0), min<int>(t.width(), m_w - curx), m_h);
386 blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy, rv);386 rv->blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
387 }387 }
388 return rv;388 return rv;
389}389}
@@ -400,7 +400,7 @@
400 Texture* render(TextureCache* texture_cache) override {400 Texture* render(TextureCache* texture_cache) override {
401 if (m_show_spaces) {401 if (m_show_spaces) {
402 Texture* rv = new Texture(m_w, m_h);402 Texture* rv = new Texture(m_w, m_h);
403 fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(0xcc, 0, 0, 0xcc), rv);403 rv->fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(0xcc, 0, 0, 0xcc));
404 return rv;404 return rv;
405 }405 }
406 return TextNode::render(texture_cache);406 return TextNode::render(texture_cache);
@@ -452,10 +452,10 @@
452 dst.y = 0;452 dst.y = 0;
453 srcrect.w = dst.w = min<int>(m_bg->width(), m_w - curx);453 srcrect.w = dst.w = min<int>(m_bg->width(), m_w - curx);
454 srcrect.h = dst.h = m_h;454 srcrect.h = dst.h = m_h;
455 blit(dst, *m_bg, srcrect, 1., BlendMode::Copy, rv);455 rv->blit(dst, *m_bg, srcrect, 1., BlendMode::Copy);
456 }456 }
457 } else {457 } else {
458 fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(255, 255, 255, 0), rv);458 rv->fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(255, 255, 255, 0));
459 }459 }
460 return rv;460 return rv;
461 }461 }
@@ -492,12 +492,12 @@
492 uint16_t hotspot_y() override {return height();}492 uint16_t hotspot_y() override {return height();}
493 Texture* render(TextureCache* texture_cache) override {493 Texture* render(TextureCache* texture_cache) override {
494 Texture* rv = new Texture(width(), height());494 Texture* rv = new Texture(width(), height());
495 fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0), rv);495 rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
496496
497 // Draw Solid background Color497 // Draw Solid background Color
498 bool set_alpha = true;498 bool set_alpha = true;
499 if (m_bg_clr_set) {499 if (m_bg_clr_set) {
500 fill_rect(Rect(Point(m_margin.left, m_margin.top), m_w, m_h), m_bg_clr, rv);500 rv->fill_rect(Rect(Point(m_margin.left, m_margin.top), m_w, m_h), m_bg_clr);
501 set_alpha = false;501 set_alpha = false;
502 }502 }
503503
@@ -512,7 +512,7 @@
512 dst.y = cury;512 dst.y = cury;
513 src.w = dst.w = min<int>(m_bg_img->width(), m_w + m_margin.left - curx);513 src.w = dst.w = min<int>(m_bg_img->width(), m_w + m_margin.left - curx);
514 src.h = dst.h = min<int>(m_bg_img->height(), m_h + m_margin.top - cury);514 src.h = dst.h = min<int>(m_bg_img->height(), m_h + m_margin.top - cury);
515 blit(dst, *m_bg_img, src, 1., BlendMode::Copy, rv);515 rv->blit(dst, *m_bg_img, src, 1., BlendMode::Copy);
516 }516 }
517 }517 }
518 set_alpha = false;518 set_alpha = false;
@@ -527,7 +527,7 @@
527 node_texture->height());527 node_texture->height());
528 Rect src = Rect(0, 0, node_texture->width(), node_texture->height());528 Rect src = Rect(0, 0, node_texture->width(), node_texture->height());
529529
530 blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha, rv);530 rv->blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha);
531 delete node_texture;531 delete node_texture;
532 }532 }
533 delete n;533 delete n;
@@ -578,11 +578,11 @@
578578
579Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {579Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {
580 Texture* rv = new Texture(m_image.width(), m_image.height());580 Texture* rv = new Texture(m_image.width(), m_image.height());
581 blit(Rect(0, 0, m_image.width(), m_image.height()),581 rv->blit(Rect(0, 0, m_image.width(), m_image.height()),
582 m_image,582 m_image,
583 Rect(0, 0, m_image.width(), m_image.height()),583 Rect(0, 0, m_image.width(), m_image.height()),
584 1.,584 1.,
585 BlendMode::Copy, rv);585 BlendMode::Copy);
586 return rv;586 return rv;
587}587}
588// End: Helper Stuff588// End: Helper Stuff
589589
=== modified file 'src/graphic/texture.cc'
--- src/graphic/texture.cc 2014-12-27 09:59:12 +0000
+++ src/graphic/texture.cc 2016-01-05 11:29:18 +0000
@@ -20,10 +20,15 @@
2020
21#include <cassert>21#include <cassert>
2222
23#include <SDL.h>
24
23#include "base/log.h"25#include "base/log.h"
24#include "base/macros.h"26#include "base/macros.h"
25#include "base/wexception.h"27#include "base/wexception.h"
26#include "graphic/gl/blit_program.h"28#include "graphic/gl/blit_program.h"
29#include "graphic/gl/coordinate_conversion.h"
30#include "graphic/gl/draw_line_program.h"
31#include "graphic/gl/fill_rect_program.h"
27#include "graphic/gl/utils.h"32#include "graphic/gl/utils.h"
28#include "graphic/graphic.h"33#include "graphic/graphic.h"
29#include "graphic/sdl_utils.h"34#include "graphic/sdl_utils.h"
@@ -31,6 +36,36 @@
3136
32namespace {37namespace {
3338
39namespace {
40
41/**
42 * \return the standard 32-bit RGBA format that we use for our textures.
43 */
44const SDL_PixelFormat & rgba_format()
45{
46 static SDL_PixelFormat format;
47 static bool init = false;
48 if (init)
49 return format;
50
51 init = true;
52 memset(&format, 0, sizeof(format));
53 format.BitsPerPixel = 32;
54 format.BytesPerPixel = 4;
55 format.Rmask = 0x000000ff;
56 format.Gmask = 0x0000ff00;
57 format.Bmask = 0x00ff0000;
58 format.Amask = 0xff000000;
59 format.Rshift = 0;
60 format.Gshift = 8;
61 format.Bshift = 16;
62 format.Ashift = 24;
63 return format;
64}
65
66} // namespace
67
68
34class GlFramebuffer {69class GlFramebuffer {
35public:70public:
36 static GlFramebuffer& instance() {71 static GlFramebuffer& instance() {
@@ -68,11 +103,11 @@
68{103{
69 init(w, h);104 init(w, h);
70105
71 if (m_w <= 0 || m_h <= 0) {106 if (width() <= 0 || height() <= 0) {
72 return;107 return;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: