widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #03862
Re: [Merge] lp:~widelands-dev/widelands/render_queue into lp:widelands
Some minor nits with my proofreader glasses on.
Diff comments:
> === modified file 'src/base/rect.h'
> --- src/base/rect.h 2014-11-26 19:53:52 +0000
> +++ src/base/rect.h 2015-03-01 10:31:43 +0000
> @@ -36,13 +36,13 @@
> : GenericRect(T(p.x), T(p.y), width, height) {
> }
>
> - /// The top left point of this rectangle.
> - GenericPoint<T> top_left() const {
> + /// The Point (x, y).
> + GenericPoint<T> origin() const {
> return GenericPoint<T>(x, y);
> }
>
> - /// The bottom right point of this rectangle.
> - GenericPoint<T> bottom_right() const {
> + /// The point (x + w, y + h).
> + GenericPoint<T> opposite_of_origin() const {
> return GenericPoint<T>(x + w, y + h);
> }
>
>
> === modified file 'src/editor/editorinteractive.cc'
> --- src/editor/editorinteractive.cc 2015-01-31 16:03:59 +0000
> +++ src/editor/editorinteractive.cc 2015-03-01 10:31:43 +0000
> @@ -604,6 +604,7 @@
>
> eia.select_tool(eia.tools.increase_height, EditorTool::First);
> editor.postload();
> +
> eia.start();
>
> if (!script_to_run.empty()) {
>
> === 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-02-24 13:51:38 +0000
> +++ src/editor/ui_menus/editor_tool_set_terrain_options_menu.cc 2015-03-01 10:31:43 +0000
> @@ -75,75 +75,69 @@
>
> const Texture& terrain_texture = terrain_descr.get_texture(0);
> Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
> - blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
> + texture->blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
> terrain_texture,
> Rect(0, 0, terrain_texture.width(), terrain_texture.height()),
> 1.,
> - BlendMode::UseAlpha, texture);
> + BlendMode::UseAlpha);
> Point pt(1, terrain_texture.height() - kSmallPicHeight - 1);
>
> if (ter_is == TerrainDescription::Type::kGreen) {
> - blit(Rect(pt.x, pt.y, green->width(), green->height()),
> - *green,
> - Rect(0, 0, green->width(), green->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - texture);
> + texture->blit(Rect(pt.x, pt.y, green->width(), green->height()),
> + *green,
> + Rect(0, 0, green->width(), green->height()),
> + 1.,
> + BlendMode::UseAlpha);
> pt.x += kSmallPicWidth + 1;
> /** TRANSLATORS: This is a terrain type tooltip in the editor */
> tooltips.push_back(_("arable"));
> } else {
> if (ter_is & TerrainDescription::Type::kWater) {
> - blit(Rect(pt.x, pt.y, water->width(), water->height()),
> - *water,
> - Rect(0, 0, water->width(), water->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - texture);
> + texture->blit(Rect(pt.x, pt.y, water->width(), water->height()),
> + *water,
> + Rect(0, 0, water->width(), water->height()),
> + 1.,
> + BlendMode::UseAlpha);
> pt.x += kSmallPicWidth + 1;
> /** TRANSLATORS: This is a terrain type tooltip in the editor */
> tooltips.push_back(_("aquatic"));
> }
> else if (ter_is & TerrainDescription::Type::kMountain) {
> - blit(Rect(pt.x, pt.y, mountain->width(), mountain->height()),
> - *mountain,
> - Rect(0, 0, mountain->width(), mountain->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - texture);
> + texture->blit(Rect(pt.x, pt.y, mountain->width(), mountain->height()),
> + *mountain,
> + Rect(0, 0, mountain->width(), mountain->height()),
> + 1.,
> + BlendMode::UseAlpha);
> pt.x += kSmallPicWidth + 1;
> /** TRANSLATORS: This is a terrain type tooltip in the editor */
> tooltips.push_back(_("mountainous"));
> }
> if (ter_is & TerrainDescription::Type::kDead) {
> - blit(Rect(pt.x, pt.y, dead->width(), dead->height()),
> - *dead,
> - Rect(0, 0, dead->width(), dead->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - texture);
> + texture->blit(Rect(pt.x, pt.y, dead->width(), dead->height()),
> + *dead,
> + Rect(0, 0, dead->width(), dead->height()),
> + 1.,
> + BlendMode::UseAlpha);
> pt.x += kSmallPicWidth + 1;
> /** TRANSLATORS: This is a terrain type tooltip in the editor */
> tooltips.push_back(_("dead"));
> }
> if (ter_is & TerrainDescription::Type::kImpassable) {
> - blit(Rect(pt.x, pt.y, impassable->width(), impassable->height()),
> - *impassable,
> - Rect(0, 0, impassable->width(), impassable->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - texture);
> + texture->blit(Rect(pt.x, pt.y, impassable->width(), impassable->height()),
> + *impassable,
> + Rect(0, 0, impassable->width(), impassable->height()),
> + 1.,
> + BlendMode::UseAlpha);
> pt.x += kSmallPicWidth + 1;
> /** TRANSLATORS: This is a terrain type tooltip in the editor */
> tooltips.push_back(_("impassable"));
> }
> if (ter_is & TerrainDescription::Type::kDry) {
> - blit(Rect(pt.x, pt.y, dry->width(), dry->height()),
> - *dry,
> - Rect(0, 0, dry->width(), dry->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - texture);
> + texture->blit(Rect(pt.x, pt.y, dry->width(), dry->height()),
> + *dry,
> + Rect(0, 0, dry->width(), dry->height()),
> + 1.,
> + BlendMode::UseAlpha);
> /** TRANSLATORS: This is a terrain type tooltip in the editor */
> tooltips.push_back(_("treeless"));
> }
>
> === modified file 'src/graphic/CMakeLists.txt'
> --- src/graphic/CMakeLists.txt 2015-02-09 05:57:08 +0000
> +++ src/graphic/CMakeLists.txt 2015-03-01 10:31:43 +0000
> @@ -10,6 +10,21 @@
> USES_SDL2
> )
>
> +wl_library(graphic_render_queue
> + SRCS
> + render_queue.cc
> + render_queue.h
> + DEPENDS
> + base_exceptions
> + base_geometry
> + base_log
> + base_macros
> + graphic_color
> + graphic_terrain_programs
> + graphic_draw_programs
> + logic
> +)
> +
> wl_library(graphic_text_layout
> SRCS
> text_layout.cc
> @@ -22,7 +37,6 @@
> graphic_text
> )
>
> -
> wl_library(graphic_image_io
> SRCS
> image_io.h
> @@ -32,6 +46,7 @@
> USES_SDL2_IMAGE
> DEPENDS
> base_exceptions
> + base_log
> graphic_surface
> io_fileread
> io_filesystem
> @@ -44,10 +59,10 @@
> image_cache.h
> USES_SDL2
> DEPENDS
> - base_log
> base_macros
> graphic_image_io
> graphic_surface
> + graphic_texture_atlas
> )
>
> wl_library(graphic_sdl_utils
> @@ -59,6 +74,7 @@
>
> wl_library(graphic_gl_utils
> SRCS
> + gl/coordinate_conversion.h
> gl/system_headers.h
> gl/utils.cc
> gl/utils.h
> @@ -66,19 +82,54 @@
> USES_OPENGL
> DEPENDS
> base_exceptions
> - base_log
> - base_macros
> -)
> -
> -wl_library(graphic_surface
> + base_geometry
> + base_log
> + base_macros
> +)
> +
> +wl_library(graphic_terrain_programs
> + SRCS
> + gl/fields_to_draw.h
> + gl/road_program.cc
> + gl/road_program.h
> + gl/terrain_program.cc
> + gl/terrain_program.h
> + gl/dither_program.cc
> + gl/dither_program.h
> + DEPENDS
> + base_exceptions
> + base_geometry
> + base_log
> + base_macros
> + graphic
> + graphic_gl_utils
> + graphic_image_io
> + graphic_surface
> + io_filesystem
> + logic
> +)
> +
> +wl_library(graphic_draw_programs
> SRCS
> blend_mode.h
> gl/blit_program.cc
> gl/blit_program.h
> + gl/blit_source.h
> gl/draw_line_program.cc
> gl/draw_line_program.h
> gl/fill_rect_program.cc
> gl/fill_rect_program.h
> + DEPENDS
> + base_exceptions
> + base_macros
> + base_geometry
> + graphic_gl_utils
> + base_log
> + graphic_color
> +)
> +
> +wl_library(graphic_surface
> + SRCS
> image.h
> screen.cc
> screen.h
> @@ -97,7 +148,9 @@
> base_macros
> graphic
> graphic_color
> + graphic_draw_programs
> graphic_gl_utils
> + graphic_render_queue
> graphic_sdl_utils
> )
>
> @@ -115,23 +168,14 @@
> SRCS
> game_renderer.cc
> game_renderer.h
> - gl/dither_program.cc
> - gl/dither_program.h
> - gl/fields_to_draw.h
> - gl/road_program.cc
> - gl/road_program.h
> - gl/terrain_program.cc
> - gl/terrain_program.h
> DEPENDS
> - base_exceptions
> base_geometry
> - base_log
> base_macros
> graphic
> graphic_gl_utils
> - graphic_image_io
> + graphic_render_queue
> graphic_surface
> - io_filesystem
> + graphic_terrain_programs
> logic
> wui_mapview_pixelfunctions
> wui_overlay_manager
> @@ -183,12 +227,14 @@
> base_geometry
> base_i18n
> base_log
> + graphic_draw_programs
> base_macros
> build_info
> graphic_color
> graphic_gl_utils
> graphic_image_cache
> graphic_image_io
> + graphic_render_queue
> graphic_surface
> graphic_text
> graphic_text_layout
>
> === modified file 'src/graphic/animation.cc'
> --- src/graphic/animation.cc 2014-12-08 05:22:52 +0000
> +++ src/graphic/animation.cc 2015-03-01 10:31:43 +0000
> @@ -325,19 +325,11 @@
> assert(idx < nr_frames());
>
> if (!hasplrclrs_ || clr == nullptr) {
> - ::blit(Rect(dst.x, dst.y, srcrc.w, srcrc.h),
> - *frames_.at(idx),
> - srcrc,
> - 1.,
> - BlendMode::UseAlpha,
> - target);
> + target->blit(
> + Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
> } else {
> - blit_blended(Rect(dst.x, dst.y, srcrc.w, srcrc.h),
> - *frames_.at(idx),
> - *pcmasks_.at(idx),
> - srcrc,
> - *clr,
> - target);
> + target->blit_blended(
> + Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
> }
> }
>
>
> === modified file 'src/graphic/blend_mode.h'
> --- src/graphic/blend_mode.h 2014-12-04 09:00:20 +0000
> +++ src/graphic/blend_mode.h 2015-03-01 10:31:43 +0000
> @@ -24,10 +24,14 @@
> enum class BlendMode {
> // Perform a normal blitting operation that respects the alpha channel if
> // present.
> - UseAlpha = 0,
> + UseAlpha,
> +
> + // Used internally for Surface::brighten_rect() if the rect is actually to
> + // be darkened.
> + Subtract,
>
> // Copy all pixel information, including alpha channel information.
> - Copy
> + Copy,
> };
>
> #endif // end of include guard: WL_GRAPHIC_BLEND_MODE_H
>
> === modified file 'src/graphic/color.cc'
> --- src/graphic/color.cc 2015-03-01 09:21:20 +0000
> +++ src/graphic/color.cc 2015-03-01 10:31:43 +0000
> @@ -19,7 +19,7 @@
>
> #include "graphic/color.h"
>
> -RGBColor::RGBColor() {
> +RGBColor::RGBColor() : RGBColor(0, 0, 0) {
> }
>
> RGBColor::RGBColor(uint8_t const R, uint8_t const G, uint8_t const B) :
>
> === modified file 'src/graphic/color.h'
> --- src/graphic/color.h 2014-07-14 10:45:44 +0000
> +++ src/graphic/color.h 2015-03-01 10:31:43 +0000
> @@ -24,6 +24,7 @@
>
> struct RGBColor {
> RGBColor(uint8_t R, uint8_t G, uint8_t B);
> + RGBColor(const RGBColor& other) = default;
>
> // Initializes the color to black.
> RGBColor();
> @@ -34,14 +35,16 @@
> // Set it to the given 'clr' which is interpretes through 'fmt'.
> void set(SDL_PixelFormat * fmt, uint32_t clr);
>
> + RGBColor& operator = (const RGBColor& other) = default;
> + bool operator != (const RGBColor& other) const;
> bool operator == (const RGBColor& other) const;
> - bool operator != (const RGBColor& other) const;
>
> uint8_t r, g, b;
> };
>
> struct RGBAColor {
> RGBAColor(uint8_t R, uint8_t G, uint8_t B, uint8_t A);
> + RGBAColor(const RGBAColor& other) = default;
>
> // Initializes the color to black.
> RGBAColor();
> @@ -55,8 +58,9 @@
> // Set it to the given 'clr' which is interpretes through 'fmt'.
> void set(const SDL_PixelFormat & fmt, uint32_t clr);
>
> + RGBAColor& operator = (const RGBAColor& other) = default;
> + bool operator != (const RGBAColor& other) const;
> bool operator == (const RGBAColor& other) const;
> - bool operator != (const RGBAColor& other) const;
>
> uint8_t r;
> uint8_t g;
>
> === modified file 'src/graphic/game_renderer.cc'
> --- src/graphic/game_renderer.cc 2015-02-08 18:16:41 +0000
> +++ src/graphic/game_renderer.cc 2015-03-01 10:31:43 +0000
> @@ -21,11 +21,9 @@
>
> #include <memory>
>
> -#include "graphic/gl/dither_program.h"
> -#include "graphic/gl/fields_to_draw.h"
> -#include "graphic/gl/road_program.h"
> -#include "graphic/gl/terrain_program.h"
> +#include "graphic/gl/coordinate_conversion.h"
> #include "graphic/graphic.h"
> +#include "graphic/render_queue.h"
> #include "graphic/rendertarget.h"
> #include "graphic/surface.h"
> #include "logic/editor_game_base.h"
> @@ -66,10 +64,6 @@
> // d). Example: if r and d have different textures and r.dither_layer >
> // d.dither_layer, then we will repaint d with the dither texture as mask.
>
> -std::unique_ptr<TerrainProgram> GameRenderer::terrain_program_;
> -std::unique_ptr<DitherProgram> GameRenderer::dither_program_;
> -std::unique_ptr<RoadProgram> GameRenderer::road_program_;
> -
> namespace {
>
> using namespace Widelands;
> @@ -142,12 +136,6 @@
> const EditorGameBase& egbase,
> const Point& view_offset,
> const Player* player) {
> - if (terrain_program_ == nullptr) {
> - terrain_program_.reset(new TerrainProgram());
> - dither_program_.reset(new DitherProgram());
> - road_program_.reset(new RoadProgram());
> - }
> -
> Point tl_map = dst.get_offset() + view_offset;
>
> assert(tl_map.x >= 0); // divisions involving negative numbers are bad
> @@ -170,22 +158,18 @@
> return;
>
> const Rect& bounding_rect = dst.get_rect();
> - const Point surface_offset = bounding_rect.top_left() + dst.get_offset() - view_offset;
> -
> - glScissor(bounding_rect.x,
> - surface->height() - bounding_rect.y - bounding_rect.h,
> - bounding_rect.w,
> - bounding_rect.h);
> - glEnable(GL_SCISSOR_TEST);
> + const Point surface_offset = bounding_rect.origin() + dst.get_offset() - view_offset;
> + const int surface_width = surface->width();
> + const int surface_height = surface->height();
>
> Map& map = egbase.map();
> const uint32_t gametime = egbase.get_gametime();
>
> - FieldsToDraw fields_to_draw(minfx, maxfx, minfy, maxfy);
> + fields_to_draw_.reset(minfx, maxfx, minfy, maxfy);
> for (int32_t fy = minfy; fy <= maxfy; ++fy) {
> for (int32_t fx = minfx; fx <= maxfx; ++fx) {
> FieldsToDraw::Field& f =
> - *fields_to_draw.mutable_field(fields_to_draw.calculate_index(fx, fy));
> + *fields_to_draw_.mutable_field(fields_to_draw_.calculate_index(fx, fy));
>
> f.fx = fx;
> f.fy = fy;
> @@ -202,7 +186,7 @@
>
> f.gl_x = f.pixel_x = x + surface_offset.x;
> f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;
> - surface->pixel_to_gl(&f.gl_x, &f.gl_y);
> + pixel_to_gl_renderbuffer(surface_width, surface_height, &f.gl_x, &f.gl_y);
>
> f.ter_d = fcoords.field->terrain_d();
> f.ter_r = fcoords.field->terrain_r();
> @@ -220,14 +204,32 @@
> }
> }
>
> - const World& world = egbase.world();
> - terrain_program_->draw(gametime, world.terrains(), fields_to_draw);
> - dither_program_->draw(gametime, world.terrains(), fields_to_draw);
> - road_program_->draw(*surface, fields_to_draw);
> + // Enqueue the drawing of the terrain.
> + RenderQueue::Item i;
> + i.program_id = RenderQueue::Program::TERRAIN_BASE;
> + i.blend_mode = BlendMode::Copy;
> + i.destination_rect =
> + FloatRect(bounding_rect.x,
> + surface_height - bounding_rect.y - bounding_rect.h,
> + bounding_rect.w,
> + bounding_rect.h);
> + i.terrain_arguments.gametime = gametime;
> + i.terrain_arguments.renderbuffer_width = surface_width;
> + i.terrain_arguments.renderbuffer_height = surface_height;
> + i.terrain_arguments.terrains = &egbase.world().terrains();
> + i.terrain_arguments.fields_to_draw = &fields_to_draw_;
> + RenderQueue::instance().enqueue(i);
> +
> + // Enqueue the drawing of the dither layer.
> + i.program_id = RenderQueue::Program::TERRAIN_DITHER;
> + i.blend_mode = BlendMode::UseAlpha;
> + // RenderQueue::instance().enqueue(i);
> +
Why is this commented out?
> + // Enqueue the drawing of the road layer.
> + i.program_id = RenderQueue::Program::TERRAIN_ROAD;
> + RenderQueue::instance().enqueue(i);
>
> draw_objects(dst, egbase, view_offset, player, minfx, maxfx, minfy, maxfy);
> -
> - glDisable(GL_SCISSOR_TEST);
> }
>
> void GameRenderer::draw_objects(RenderTarget& dst,
>
> === modified file 'src/graphic/game_renderer.h'
> --- src/graphic/game_renderer.h 2014-12-04 21:21:05 +0000
> +++ src/graphic/game_renderer.h 2015-03-01 10:31:43 +0000
> @@ -24,17 +24,14 @@
>
> #include "base/macros.h"
> #include "base/point.h"
> +#include "graphic/gl/fields_to_draw.h"
>
> namespace Widelands {
> class Player;
> class EditorGameBase;
> }
>
> -class DitherProgram;
> class RenderTarget;
> -class RoadProgram;
> -class TerrainProgram;
> -
>
> /**
> * This abstract base class renders the main game view into an
> @@ -64,10 +61,6 @@
> void rendermap(RenderTarget& dst, const Widelands::EditorGameBase& egbase, const Point& view_offset);
>
> private:
> - static std::unique_ptr<TerrainProgram> terrain_program_;
> - static std::unique_ptr<DitherProgram> dither_program_;
> - static std::unique_ptr<RoadProgram> road_program_;
> -
> // Draw the map for the given parameters (see rendermap). 'player'
> // can be nullptr in which case the whole map is drawn.
> void draw(RenderTarget& dst,
> @@ -85,6 +78,10 @@
> int minfy,
> int maxfy);
>
> + // This is owned and handled by us, but handed to the RenderQueue, so we
> + // basically promise that this stays valid for one frame.
> + FieldsToDraw fields_to_draw_;
> +
> DISALLOW_COPY_AND_ASSIGN(GameRenderer);
> };
>
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -30,42 +30,44 @@
> #version 120
>
> // Attributes.
> -attribute vec2 attr_position;
> -
> -// Uniforms.
> -uniform vec4 u_dst_rect;
> -uniform vec4 u_src_rect;
> -
> +attribute vec2 attr_mask_texture_position;
> +attribute vec2 attr_texture_position;
> +attribute vec3 attr_position;
> +attribute vec4 attr_blend;
> +
> +varying vec2 out_mask_texture_coordinate;
> varying vec2 out_texture_coordinate;
> +varying vec4 out_blend;
>
> void main() {
> - out_texture_coordinate = u_src_rect.xy + attr_position.xy * u_src_rect.zw;
> - gl_Position = vec4(u_dst_rect.xy + attr_position.xy * u_dst_rect.zw, 0., 1.);
> + out_mask_texture_coordinate = attr_mask_texture_position;
> + out_texture_coordinate = attr_texture_position;
> + out_blend = attr_blend;
> + gl_Position = vec4(attr_position, 1.);
> }
> )";
>
> const char kVanillaBlitFragmentShader[] = R"(
> #version 120
>
> -uniform float u_opacity;
> uniform sampler2D u_texture;
>
> varying vec2 out_texture_coordinate;
> +varying vec4 out_blend;
>
> void main() {
> vec4 color = texture2D(u_texture, out_texture_coordinate);
> - gl_FragColor = vec4(color.rgb, u_opacity * color.a);
> + gl_FragColor = color * out_blend;
> }
> )";
>
> const char kMonochromeBlitFragmentShader[] = R"(
> #version 120
>
> -uniform float u_opacity;
> uniform sampler2D u_texture;
> -uniform vec3 u_blend;
>
> varying vec2 out_texture_coordinate;
> +varying vec4 out_blend;
>
> void main() {
> vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
> @@ -73,144 +75,270 @@
> // See http://en.wikipedia.org/wiki/YUV.
> float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
>
> - gl_FragColor = vec4(vec3(luminance) * u_blend, u_opacity * texture_color.a);
> + gl_FragColor = vec4(vec3(luminance) * out_blend.rgb, out_blend.a * texture_color.a);
> }
> )";
>
> const char kBlendedBlitFragmentShader[] = R"(
> #version 120
>
> -uniform float u_opacity;
> uniform sampler2D u_texture;
> uniform sampler2D u_mask;
> -uniform vec3 u_blend;
>
> +varying vec2 out_mask_texture_coordinate;
> varying vec2 out_texture_coordinate;
> +varying vec4 out_blend;
>
> void main() {
> vec4 texture_color = texture2D(u_texture, out_texture_coordinate);
> - vec4 mask_color = texture2D(u_mask, out_texture_coordinate);
> + vec4 mask_color = texture2D(u_mask, out_mask_texture_coordinate);
>
> // See http://en.wikipedia.org/wiki/YUV.
> float luminance = dot(vec3(0.299, 0.587, 0.114), texture_color.rgb);
> float blend_influence = mask_color.r * mask_color.a;
> gl_FragColor = vec4(
> - mix(texture_color.rgb, u_blend * luminance, blend_influence), u_opacity * texture_color.a);
> + mix(texture_color.rgb, out_blend.rgb * luminance, blend_influence), out_blend.a * texture_color.a);
> }
> )";
>
> +// While drawing we put all draw calls into a buffer, so that we have to
> +// transfer the buffer to the GPU only once, even though we might need to do
> +// many glDraw* calls. This structure represents the parameters for one glDraw*
> +// call.
> +struct DrawBatch {
> + int offset;
> + int count;
> + int texture;
> + int mask;
> + BlendMode blend_mode;
> +};
> +
> } // namespace
>
> class BlitProgram {
> public:
> + struct Arguments {
> + FloatRect destination_rect;
> + float z_value;
> + BlitSource texture;
> + BlitSource mask;
> + RGBAColor blend;
> + BlendMode blend_mode;
> + };
> BlitProgram(const std::string& fragment_shader);
>
> - void activate(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture,
> - const float opacity,
> - const BlendMode blend_mode);
> -
> - void draw();
> - void draw_and_deactivate(BlendMode blend_mode);
> -
> - GLuint program_object() const {
> + void activate();
> +
> + void draw_and_deactivate(const std::vector<Arguments>& arguments);
> +
> + int program_object() const {
> return gl_program_.object();
> }
>
> private:
> struct PerVertexData {
> - float gl_x, gl_y;
> + PerVertexData(float init_gl_x,
> + float init_gl_y,
> + float init_gl_z,
> + float init_texture_x,
> + float init_texture_y,
> + float init_mask_texture_x,
> + float init_mask_texture_y,
> + float init_blend_r,
> + float init_blend_g,
> + float init_blend_b,
> + float init_blend_a)
> + : gl_x(init_gl_x),
> + gl_y(init_gl_y),
> + gl_z(init_gl_z),
> + texture_x(init_texture_x),
> + texture_y(init_texture_y),
> + mask_texture_x(init_mask_texture_x),
> + mask_texture_y(init_mask_texture_y),
> + blend_r(init_blend_r),
> + blend_g(init_blend_g),
> + blend_b(init_blend_b),
> + blend_a(init_blend_a) {
> + }
> +
> + float gl_x, gl_y, gl_z;
> + float texture_x, texture_y;
> + float mask_texture_x, mask_texture_y;
> + float blend_r, blend_g, blend_b, blend_a;
> };
> - static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
> + static_assert(sizeof(PerVertexData) == 44, "Wrong padding.");
>
> // The buffer that will contain the quad for rendering.
> - Gl::Buffer gl_array_buffer_;
> + Gl::NewBuffer<PerVertexData> gl_array_buffer_;
>
> // The program.
> Gl::Program gl_program_;
>
> // Attributes.
> + GLint attr_blend_;
> + GLint attr_mask_texture_position_;
> GLint attr_position_;
> + GLint attr_texture_position_;
>
> // Uniforms.
> - GLint u_dst_rect_;
> - GLint u_opacity_;
> - GLint u_src_rect_;
> GLint u_texture_;
> + GLint u_mask_;
> +
> + // Cached for efficiency.
> + std::vector<PerVertexData> vertices_;
> +
> DISALLOW_COPY_AND_ASSIGN(BlitProgram);
> };
>
> BlitProgram::BlitProgram(const std::string& fragment_shader) {
> gl_program_.build(kBlitVertexShader, fragment_shader.c_str());
>
> + attr_blend_ = glGetAttribLocation(gl_program_.object(), "attr_blend");
> + attr_mask_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_mask_texture_position");
> attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
> + attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
>
> u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
> - u_opacity_ = glGetUniformLocation(gl_program_.object(), "u_opacity");
> - u_dst_rect_ = glGetUniformLocation(gl_program_.object(), "u_dst_rect");
> - u_src_rect_ = glGetUniformLocation(gl_program_.object(), "u_src_rect");
> -
> - std::vector<PerVertexData> vertices;
> - vertices.push_back(PerVertexData
> - {0., 1.});
> - vertices.push_back(PerVertexData
> - {1., 1.});
> - vertices.push_back(PerVertexData
> - {0., 0.});
> - vertices.push_back(PerVertexData
> - {1., 0.});
> -
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> - glBufferData(
> - GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
> - glVertexAttribPointer(attr_position_,
> - 2,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(0));
> - glBindBuffer(GL_ARRAY_BUFFER, 0);
> + u_mask_ = glGetUniformLocation(gl_program_.object(), "u_mask");
> }
>
> -void BlitProgram::activate(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture,
> - const float opacity,
> - const BlendMode blend_mode) {
> +void BlitProgram::activate() {
> glUseProgram(gl_program_.object());
> +
> + glEnableVertexAttribArray(attr_blend_);
> + glEnableVertexAttribArray(attr_mask_texture_position_);
> glEnableVertexAttribArray(attr_position_);
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> -
> - glVertexAttribPointer(attr_position_,
> - 2,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(0));
> -
> + glEnableVertexAttribArray(attr_texture_position_);
> +}
> +
> +void BlitProgram::draw_and_deactivate(const std::vector<Arguments>& arguments) {
> + size_t i = 0;
> +
> + gl_array_buffer_.bind();
> +
> + Gl::vertex_attrib_pointer(attr_blend_, 4, sizeof(PerVertexData), offsetof(PerVertexData, blend_r));
> + Gl::vertex_attrib_pointer(attr_mask_texture_position_,
> + 2,
> + sizeof(PerVertexData),
> + offsetof(PerVertexData, mask_texture_x));
> + Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
> + Gl::vertex_attrib_pointer(
> + attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
>
> glUniform1i(u_texture_, 0);
> - glUniform1f(u_opacity_, opacity);
> - glUniform4f(u_dst_rect_, gl_dest_rect.x, gl_dest_rect.y, gl_dest_rect.w, gl_dest_rect.h);
> - glUniform4f(u_src_rect_, gl_src_rect.x, gl_src_rect.y, gl_src_rect.w, gl_src_rect.h);
> -
> - glActiveTexture(GL_TEXTURE0);
> - glBindTexture(GL_TEXTURE_2D, gl_texture);
> -
> - if (blend_mode == BlendMode::Copy) {
> - glBlendFunc(GL_ONE, GL_ZERO);
> - }
> -}
> -
> -void BlitProgram::draw_and_deactivate(BlendMode blend_mode) {
> - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
> -
> - if (blend_mode == BlendMode::Copy) {
> - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> - }
> -
> + glUniform1i(u_mask_, 1);
> +
> + // Prepare the buffer for many draw calls.
> + std::vector<DrawBatch> draw_batches;
> + int offset = 0;
> + vertices_.clear();
> + while (i < arguments.size()) {
> + const Arguments& template_args = arguments[i];
> +
> + // Batch common blit operations up.
> + while (i < arguments.size()) {
> + const Arguments& current_args = arguments[i];
> + if (current_args.blend_mode != template_args.blend_mode ||
> + current_args.texture.name != template_args.texture.name ||
> + current_args.mask.name != template_args.mask.name) {
> + break;
> + }
> +
> + const float blend_r = current_args.blend.r / 255.;
> + const float blend_g = current_args.blend.g / 255.;
> + const float blend_b = current_args.blend.b / 255.;
> + const float blend_a = current_args.blend.a / 255.;
> +
> + vertices_.emplace_back(current_args.destination_rect.x,
> + current_args.destination_rect.y,
> + current_args.z_value,
> + current_args.texture.source_rect.x,
> + current_args.texture.source_rect.y,
> + current_args.mask.source_rect.x,
> + current_args.mask.source_rect.y,
> + blend_r,
> + blend_g,
> + blend_b,
> + blend_a);
> +
> + vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
> + current_args.destination_rect.y,
> + current_args.z_value,
> + current_args.texture.source_rect.x + current_args.texture.source_rect.w,
> + current_args.texture.source_rect.y,
> + current_args.mask.source_rect.x + current_args.mask.source_rect.w,
> + current_args.mask.source_rect.y,
> + blend_r,
> + blend_g,
> + blend_b,
> + blend_a);
> +
> + vertices_.emplace_back(current_args.destination_rect.x,
> + current_args.destination_rect.y + current_args.destination_rect.h,
> + current_args.z_value,
> + current_args.texture.source_rect.x,
> + current_args.texture.source_rect.y + current_args.texture.source_rect.h,
> + current_args.mask.source_rect.x,
> + current_args.mask.source_rect.y + current_args.mask.source_rect.h,
> + blend_r,
> + blend_g,
> + blend_b,
> + blend_a);
> +
> + vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
> + vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
> +
> + vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
> + current_args.destination_rect.y + current_args.destination_rect.h,
> + current_args.z_value,
> + current_args.texture.source_rect.x + current_args.texture.source_rect.w,
> + current_args.texture.source_rect.y + current_args.texture.source_rect.h,
> + current_args.mask.source_rect.x + current_args.mask.source_rect.w,
> + current_args.mask.source_rect.y + current_args.mask.source_rect.h,
> + blend_r,
> + blend_g,
> + blend_b,
> + blend_a);
> + ++i;
> + }
> +
> + draw_batches.emplace_back(DrawBatch{offset,
> + static_cast<int>(vertices_.size() - offset),
> + template_args.texture.name,
> + template_args.mask.name,
> + template_args.blend_mode});
> + offset = vertices_.size();
> + }
> + gl_array_buffer_.update(vertices_);
> +
> + // Now do the draw calls.
> + for (const auto& draw_arg : draw_batches) {
> + glActiveTexture(GL_TEXTURE0);
> + glBindTexture(GL_TEXTURE_2D, draw_arg.texture);
> +
> + glActiveTexture(GL_TEXTURE1);
> + glBindTexture(GL_TEXTURE_2D, draw_arg.mask);
> +
> + if (draw_arg.blend_mode == BlendMode::Copy) {
> + glBlendFunc(GL_ONE, GL_ZERO);
> + }
> + glDrawArrays(GL_TRIANGLES, draw_arg.offset, draw_arg.count);
> +
> + if (draw_arg.blend_mode == BlendMode::Copy) {
> + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> + }
> + }
> +
> + glDisableVertexAttribArray(attr_blend_);
> + glDisableVertexAttribArray(attr_mask_texture_position_);
> glDisableVertexAttribArray(attr_position_);
> + glDisableVertexAttribArray(attr_texture_position_);
> +
> + glBindTexture(GL_TEXTURE_2D, 0);
> +
> + glActiveTexture(GL_TEXTURE0);
> + glBindTexture(GL_TEXTURE_2D, 0);
> +
> glBindBuffer(GL_ARRAY_BUFFER, 0);
> }
>
> @@ -227,15 +355,31 @@
> blit_program_.reset(new BlitProgram(kVanillaBlitFragmentShader));
> }
>
> -
> void VanillaBlitProgram::draw(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture,
> - const float opacity,
> - const BlendMode blend_mode) {
> - blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture, opacity, blend_mode);
> - blit_program_->draw_and_deactivate(blend_mode);
> -}
> + const float z_value,
> + const BlitSource& texture,
> + const float opacity,
> + const BlendMode blend_mode) {
> + draw({Arguments{gl_dest_rect, z_value, texture, opacity, blend_mode}});
> +}
> +
> +void VanillaBlitProgram::draw(const std::vector<Arguments>& arguments) {
> + std::vector<BlitProgram::Arguments> blit_arguments;
> + for (const Arguments arg : arguments) {
> + blit_arguments.emplace_back(BlitProgram::Arguments{
> + arg.destination_rect,
> + arg.z_value,
> + arg.texture,
> + BlitSource{FloatRect(), 0},
> + RGBAColor(255, 255, 255, arg.opacity * 255),
> + arg.blend_mode,
> + });
> + }
> +
> + blit_program_->activate();
> + blit_program_->draw_and_deactivate(blit_arguments);
> +}
> +
>
> // static
> MonochromeBlitProgram& MonochromeBlitProgram::instance() {
> @@ -248,19 +392,30 @@
>
> MonochromeBlitProgram::MonochromeBlitProgram() {
> blit_program_.reset(new BlitProgram(kMonochromeBlitFragmentShader));
> -
> - u_blend_ = glGetUniformLocation(blit_program_->program_object(), "u_blend");
> -}
> -
> -void MonochromeBlitProgram::draw(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture,
> - const RGBAColor& blend) {
> - blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture, blend.a / 255., BlendMode::UseAlpha);
> -
> - glUniform3f(u_blend_, blend.r / 255., blend.g / 255., blend.b / 255.);
> -
> - blit_program_->draw_and_deactivate(BlendMode::UseAlpha);
> +}
> +
> +void MonochromeBlitProgram::draw(const FloatRect& dest_rect,
> + const float z_value,
> + const BlitSource& texture,
> + const RGBAColor& blend) {
> + draw({Arguments{dest_rect, z_value, texture, blend, BlendMode::UseAlpha}});
> +}
> +
> +void MonochromeBlitProgram::draw(const std::vector<Arguments>& arguments) {
> + std::vector<BlitProgram::Arguments> blit_arguments;
> + for (const Arguments arg : arguments) {
> + blit_arguments.emplace_back(BlitProgram::Arguments{
> + arg.destination_rect,
> + arg.z_value,
> + arg.texture,
> + BlitSource{FloatRect(), 0},
> + arg.blend,
> + arg.blend_mode,
> + });
> + }
> +
> + blit_program_->activate();
> + blit_program_->draw_and_deactivate(blit_arguments);
> }
>
> // static
> @@ -274,28 +429,29 @@
>
> BlendedBlitProgram::BlendedBlitProgram() {
> blit_program_.reset(new BlitProgram(kBlendedBlitFragmentShader));
> - u_blend_ = glGetUniformLocation(blit_program_->program_object(), "u_blend");
> - u_mask_ = glGetUniformLocation(blit_program_->program_object(), "u_mask");
> }
>
> void BlendedBlitProgram::draw(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture_image,
> - const GLuint gl_texture_mask,
> - const RGBAColor& blend) {
> - blit_program_->activate(gl_dest_rect, gl_src_rect, gl_texture_image, blend.a / 255., BlendMode::UseAlpha);
> -
> - glActiveTexture(GL_TEXTURE1);
> - glBindTexture(GL_TEXTURE_2D, gl_texture_mask);
> - glUniform1i(u_mask_, 1);
> -
> - glUniform3f(u_blend_, blend.r / 255., blend.g / 255., blend.b / 255.);
> -
> - blit_program_->draw_and_deactivate(BlendMode::UseAlpha);
> -
> - glActiveTexture(GL_TEXTURE1);
> - glBindTexture(GL_TEXTURE_2D, 0);
> -
> - glActiveTexture(GL_TEXTURE0);
> - glBindTexture(GL_TEXTURE_2D, 0);
> + const float z_value,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBAColor& blend) {
> + draw({Arguments{gl_dest_rect, z_value, texture, mask, blend, BlendMode::UseAlpha}});
> +}
> +
> +void BlendedBlitProgram::draw(const std::vector<Arguments>& arguments) {
> + std::vector<BlitProgram::Arguments> blit_arguments;
> + for (const Arguments arg : arguments) {
> + blit_arguments.emplace_back(BlitProgram::Arguments{
> + arg.destination_rect,
> + arg.z_value,
> + arg.texture,
> + arg.mask,
> + arg.blend,
> + arg.blend_mode,
> + });
> + }
> +
> + blit_program_->activate();
> + blit_program_->draw_and_deactivate(blit_arguments);
> }
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -21,32 +21,46 @@
> #define WL_GRAPHIC_GL_BLIT_PROGRAM_H
>
> #include <memory>
> +#include <vector>
>
> #include "base/macros.h"
> #include "base/rect.h"
> #include "graphic/blend_mode.h"
> #include "graphic/color.h"
> +#include "graphic/gl/blit_source.h"
> #include "graphic/gl/system_headers.h"
>
> class BlitProgram;
>
> +
> class VanillaBlitProgram {
> public:
> + struct Arguments {
> + FloatRect destination_rect;
> + float z_value;
> + BlitSource texture;
> + float opacity;
> + BlendMode blend_mode;
> + };
> +
> // Returns the (singleton) instance of this class.
> static VanillaBlitProgram& instance();
> ~VanillaBlitProgram();
>
> // Draws the rectangle 'gl_src_rect' from the texture with the name
> - // 'gl_texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha
> + // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All alpha
> // values are multiplied by 'opacity' during the blit.
> // All coordinates are in the OpenGL frame. The 'blend_mode' defines if the
> // values are copied or if alpha values are used.
> void draw(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture,
> + const float z_value,
> + const BlitSource& texture,
> float opacity,
> const BlendMode blend_mode);
>
> + // Draws a bunch of items at once.
> + void draw(const std::vector<Arguments>& arguments);
> +
> private:
> VanillaBlitProgram();
>
> @@ -57,55 +71,71 @@
>
> class MonochromeBlitProgram {
> public:
> + struct Arguments {
> + FloatRect destination_rect;
> + float z_value;
> + BlitSource texture;
> + RGBAColor blend;
> + BlendMode blend_mode;
> + };
> +
> // Returns the (singleton) instance of this class.
> static MonochromeBlitProgram& instance();
> ~MonochromeBlitProgram();
>
> // Draws the rectangle 'gl_src_rect' from the texture with the name
> - // 'gl_texture' to 'gl_dest_rect' in the currently bound framebuffer. All
> + // 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
> // coordinates are in the OpenGL frame. The image is first converted to
> // luminance, then all values are multiplied with blend.
> void draw(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture,
> + const float z_value,
> + const BlitSource& blit_source,
> const RGBAColor& blend);
>
> + // Draws a bunch of items at once.
> + void draw(const std::vector<Arguments>& arguments);
> +
> private:
> MonochromeBlitProgram();
>
> std::unique_ptr<BlitProgram> blit_program_;
>
> - // Uniforms.
> - GLint u_blend_;
> -
> DISALLOW_COPY_AND_ASSIGN(MonochromeBlitProgram);
> };
>
> class BlendedBlitProgram {
> public:
> + struct Arguments {
> + FloatRect destination_rect;
> + float z_value;
> + BlitSource texture;
> + BlitSource mask;
> + RGBAColor blend;
> + BlendMode blend_mode;
> + };
> +
> // Returns the (singleton) instance of this class.
> static BlendedBlitProgram& instance();
> ~BlendedBlitProgram();
>
> // Draws the rectangle 'gl_src_rect' from the texture with the name
> // 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All
> - // coordinates are in the OpenGL frame. The 'gl_texture_mask' is used to selectively apply
> + // coordinates are in the OpenGL frame. The 'texture_mask' is used to selectively apply
> // the 'blend'. This is used for blitting player colored images.
> void draw(const FloatRect& gl_dest_rect,
> - const FloatRect& gl_src_rect,
> - const GLuint gl_texture_image,
> - const GLuint gl_texture_mask,
> - const RGBAColor& blend);
> + const float z_value,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBAColor& blend);
> +
> + // Draws a bunch of items at once.
> + void draw(const std::vector<Arguments>& arguments);
>
> private:
> BlendedBlitProgram();
>
> std::unique_ptr<BlitProgram> blit_program_;
>
> - // Uniforms.
> - GLint u_blend_;
> - GLint u_mask_;
> -
> DISALLOW_COPY_AND_ASSIGN(BlendedBlitProgram);
> };
>
>
> === added file 'src/graphic/gl/blit_source.h'
> --- src/graphic/gl/blit_source.h 1970-01-01 00:00:00 +0000
> +++ src/graphic/gl/blit_source.h 2015-03-01 10:31:43 +0000
> @@ -0,0 +1,30 @@
> +/*
> + * Copyright (C) 2006-2015 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#ifndef WL_GRAPHIC_GL_BLIT_SOURCE_H
> +#define WL_GRAPHIC_GL_BLIT_SOURCE_H
> +
> +// The tuple of GL texture and rectangle in its locale coordinate frame that
> +// defines the source of a blit operation.
> +struct BlitSource {
> + FloatRect source_rect;
> + int name;
> +};
> +
> +#endif // end of include guard: WL_GRAPHIC_GL_BLIT_SOURCE_H
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -0,0 +1,75 @@
> +/*
> + * Copyright (C) 2006-2015 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#ifndef WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
> +#define WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
> +
> +#include "base/rect.h"
> +
> +// Convert the 'rect' in pixel space into opengl space.
> +enum class ConversionMode {
> + // Convert the rect as given.
> + kLeftBottom,
> +
> + // Convert the rect so that the borders are in the center
> + // of the pixels.
> + kMidPoint,
> +};
> +
> +// Converts the pixel (x, y) in a texture to a gl coordinate in [0, 1].
> +inline void pixel_to_gl_texture(const int width, const int height, float* x, float* y) {
> + *x = (*x / width);
> + *y = 1. - (*y / height);
> +}
> +
> +// Converts the given pixel into an OpenGl point in the renderbuffer.
> +inline void pixel_to_gl_renderbuffer(const int width, const int height, float* x, float* y) {
> + *x = (*x / width) * 2. - 1.;
> + *y = 1. - (*y / height) * 2.;
> +}
> +
> +// Converts 'rect' given on a screen of 'width' x 'height' pixels into a rect
> +// in opengl coordinates in a renderbuffer, i.e. in [-1, 1]. The edges The returned
> +// rectangle has positive width and height.
> +inline FloatRect
> +rect_to_gl_renderbuffer(const int width, const int height, const Rect& rect) {
> + float left = rect.x;
> + float top = rect.y;
> + float right = rect.x + rect.w;
> + float bottom = rect.y + rect.h;
> + pixel_to_gl_renderbuffer(width, height, &left, &top);
> + pixel_to_gl_renderbuffer(width, height, &right, &bottom);
> + return FloatRect(left, bottom, right - left, top - bottom);
> +}
> +
> +// Converts 'rect' given on a texture of 'width' x 'height' pixels into a rect
> +// in opengl coordinates in a texture, i.e. in [0, 1]. Texture pixels are sampled in their center.
> +// The returned rectangle has positive width and height.
> +inline FloatRect
> +rect_to_gl_texture(const int width, const int height, const FloatRect& rect) {
> + float left = rect.x;
> + float top = rect.y;
> + float right = rect.x + rect.w;
> + float bottom = rect.y + rect.h;
> + pixel_to_gl_texture(width, height, &left, &top);
> + pixel_to_gl_texture(width, height, &right, &bottom);
> + return FloatRect(left, bottom, right - left, top - bottom);
> +}
> +
> +#endif // end of include guard: WL_GRAPHIC_GL_COORDINATE_CONVERSION_H
>
> === modified file 'src/graphic/gl/dither_program.cc'
> --- src/graphic/gl/dither_program.cc 2015-03-01 09:21:20 +0000
> +++ src/graphic/gl/dither_program.cc 2015-03-01 10:31:43 +0000
> @@ -37,6 +37,8 @@
> attribute vec2 attr_texture_offset;
> attribute vec2 attr_texture_position;
>
> +uniform float u_z_value;
> +
> // Output of vertex shader.
> varying float var_brightness;
> varying vec2 var_dither_texture_position;
> @@ -48,7 +50,7 @@
> var_dither_texture_position = attr_dither_texture_position;
> var_texture_offset = attr_texture_offset;
> var_texture_position = attr_texture_position;
> - gl_Position = vec4(attr_position, 0., 1.);
> + gl_Position = vec4(attr_position, u_z_value, 1.);
> }
> )";
>
> @@ -64,12 +66,18 @@
> varying vec2 var_texture_position;
> varying vec2 var_texture_offset;
>
> +// TODO(sirver): This is a hack to make sure we are sampling inside of the
> +// terrain texture. This is a common problem with OpenGL and texture atlases.
> +#define MARGIN 1e-2
> +
Code style: constexpr float kMargin
> void main() {
> - vec4 clr = texture2D(u_terrain_texture,
> - var_texture_offset + u_texture_dimensions * fract(var_texture_position));
> - clr.rgb *= var_brightness;
> - clr.a = 1. - texture2D(u_dither_texture, var_dither_texture_position).a;
> - gl_FragColor = clr;
> + vec2 texture_fract = clamp(
> + fract(var_texture_position),
> + vec2(MARGIN, MARGIN),
> + vec2(1. - MARGIN, 1. - MARGIN));
> + vec4 clr = texture2D(u_terrain_texture, var_texture_offset + u_texture_dimensions * texture_fract);
> + gl_FragColor = vec4(clr.rgb * var_brightness,
> + 1. - texture2D(u_dither_texture, var_dither_texture_position).a);
> }
> )";
>
> @@ -87,12 +95,13 @@
> u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");
> u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
> u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
> + u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
>
> dither_mask_.reset(new Texture(load_image_as_sdl_surface("world/pics/edge.png", g_fs), true));
>
> glBindTexture(GL_TEXTURE_2D, dither_mask_->get_gl_texture());
> - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP));
> - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP));
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(GL_CLAMP_TO_EDGE));
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(GL_CLAMP_TO_EDGE));
> glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(GL_LINEAR));
> glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_LINEAR));
> glBindTexture(GL_TEXTURE_2D, 0);
> @@ -116,16 +125,16 @@
>
> switch (order_index) {
> case 0:
> + back.dither_texture_x = 1.;
> + back.dither_texture_y = 1.;
> + break;
> + case 1:
> back.dither_texture_x = 0.;
> - back.dither_texture_y = 0.;
> - break;
> - case 1:
> - back.dither_texture_x = 1.;
> - back.dither_texture_y = 0.;
> + back.dither_texture_y = 1.;
> break;
> case 2:
> back.dither_texture_x = 0.5;
> - back.dither_texture_y = 1.;
> + back.dither_texture_y = 0.;
> break;
> default:
> throw wexception("Never here.");
> @@ -149,14 +158,14 @@
> if (terrains.get_unmutable(my_terrain).dither_layer() <
> other_terrain_description.dither_layer()) {
> const FloatPoint texture_offset =
> - other_terrain_description.get_texture(gametime).texture_coordinates().top_left();
> + other_terrain_description.get_texture(gametime).texture_coordinates().origin();
> add_vertex(fields_to_draw.at(idx1), 0, texture_offset);
> add_vertex(fields_to_draw.at(idx2), 1, texture_offset);
> add_vertex(fields_to_draw.at(idx3), 2, texture_offset);
> }
> }
>
> -void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
> +void DitherProgram::gl_draw(int gl_texture, float texture_w, float texture_h, const float z_value) {
> glUseProgram(gl_program_.object());
>
> glEnableVertexAttribArray(attr_brightness_);
> @@ -165,25 +174,20 @@
> glEnableVertexAttribArray(attr_texture_offset_);
> glEnableVertexAttribArray(attr_texture_position_);
>
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> - glBufferData(GL_ARRAY_BUFFER,
> - sizeof(PerVertexData) * vertices_.size(),
> - vertices_.data(),
> - GL_STREAM_DRAW);
> + gl_array_buffer_.bind();
> + gl_array_buffer_.update(vertices_);
>
> - const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
> - glVertexAttribPointer(vertex_index,
> - num_items,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(offset));
> - };
> - set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
> - set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
> - set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
> - set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
> - set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
> + Gl::vertex_attrib_pointer(
> + attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
> + Gl::vertex_attrib_pointer(attr_dither_texture_position_,
> + 2,
> + sizeof(PerVertexData),
> + offsetof(PerVertexData, dither_texture_x));
> + Gl::vertex_attrib_pointer(attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
> + Gl::vertex_attrib_pointer(
> + attr_texture_offset_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_offset_x));
> + Gl::vertex_attrib_pointer(
> + attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
>
> glBindBuffer(GL_ARRAY_BUFFER, 0);
>
> @@ -194,6 +198,7 @@
> glActiveTexture(GL_TEXTURE1);
> glBindTexture(GL_TEXTURE_2D, gl_texture);
>
> + glUniform1f(u_z_value_, z_value);
> glUniform1i(u_dither_texture_, 0);
> glUniform1i(u_terrain_texture_, 1);
> glUniform2f(u_texture_dimensions_, texture_w, texture_h);
> @@ -213,7 +218,8 @@
>
> void DitherProgram::draw(const uint32_t gametime,
> const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> - const FieldsToDraw& fields_to_draw) {
> + const FieldsToDraw& fields_to_draw,
> + const float z_value) {
> // This method expects that all terrains have the same dimensions and that
> // all are packed into the same texture atlas, i.e. all are in the same GL
> // texture. It does not check for this invariance for speeds sake.
> @@ -271,5 +277,8 @@
> }
>
> const Texture& texture = terrains.get_unmutable(0).get_texture(0);
> - gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
> + gl_draw(texture.get_gl_texture(),
> + texture.texture_coordinates().w,
> + texture.texture_coordinates().h,
> + z_value);
> }
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -38,7 +38,8 @@
> // Draws the terrain.
> void draw(uint32_t gametime,
> const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> - const FieldsToDraw& fields_to_draw);
> + const FieldsToDraw& fields_to_draw,
> + float z_value);
>
> private:
> // Adds the triangle between the indexes (which index 'fields_to_draw') to
> @@ -72,13 +73,13 @@
> };
>
> // Call through to GL.
> - void gl_draw(int gl_texture, float texture_w, float texture_h);
> + void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
>
> // The program used for drawing the terrain.
> Gl::Program gl_program_;
>
> // The buffer that contains the data to be rendered.
> - Gl::Buffer gl_array_buffer_;
> + Gl::NewBuffer<PerVertexData> gl_array_buffer_;
>
> // Attributes.
> GLint attr_brightness_;
> @@ -91,6 +92,7 @@
> GLint u_dither_texture_;
> GLint u_terrain_texture_;
> GLint u_texture_dimensions_;
> + GLint u_z_value_;
>
> // The texture mask for the dithering step.
> std::unique_ptr<Texture> dither_mask_;
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -19,6 +19,8 @@
>
> #include "graphic/gl/draw_line_program.h"
>
> +#include <algorithm>
> +#include <cassert>
> #include <vector>
>
> #include "base/log.h"
> @@ -29,23 +31,33 @@
> #version 120
>
> // Attributes.
> -attribute vec2 attr_position;
> +attribute vec3 attr_position;
> +attribute vec3 attr_color;
> +
> +varying vec3 var_color;
>
> void main() {
> - gl_Position = vec4(attr_position, 0., 1.);
> + var_color = attr_color;
> + gl_Position = vec4(attr_position, 1.);
> }
> )";
>
> const char kDrawLineFragmentShader[] = R"(
> #version 120
>
> -uniform ivec3 u_color;
> +varying vec3 var_color;
>
> void main() {
> - gl_FragColor = vec4(vec3(u_color) / 255., 1.);
> + gl_FragColor = vec4(var_color.rgb, 1.);
> }
> )";
>
> +struct DrawBatch {
> + int offset;
> + int count;
> + int line_width;
> +};
> +
> } // namespace
>
> // static
> @@ -58,37 +70,81 @@
> gl_program_.build(kDrawLineVertexShader, kDrawLineFragmentShader);
>
> attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
> - u_color_ = glGetUniformLocation(gl_program_.object(), "u_color");
> -
> + attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
> }
>
> -void DrawLineProgram::draw(const float x1,
> - const float y1,
> - const float x2,
> - const float y2,
> +void DrawLineProgram::draw(const FloatPoint& start,
> + const FloatPoint& end,
> + const float z_value,
> const RGBColor& color,
> - const int line_width) {
> + int line_width) {
> + draw({Arguments{FloatRect(start.x, start.y, end.x - start.x, end.y - start.y),
> + z_value,
> + color,
> + static_cast<uint8_t>(line_width),
> + BlendMode::Copy}});
> +}
> +
> +void DrawLineProgram::draw(std::vector<Arguments> arguments) {
> + size_t i = 0;
> +
> glUseProgram(gl_program_.object());
> glEnableVertexAttribArray(attr_position_);
> -
> - const std::vector<PerVertexData> vertices = {{x1, y1}, {x2, y2}};
> -
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> - glBufferData(
> - GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STREAM_DRAW);
> - glVertexAttribPointer(attr_position_,
> - 2,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(0));
> -
> - glUniform3i(u_color_, color.r, color.g, color.b);
> -
> - glLineWidth(line_width);
> - glDrawArrays(GL_LINES, 0, 2);
> + glEnableVertexAttribArray(attr_color_);
> +
> + gl_array_buffer_.bind();
> +
> + Gl::vertex_attrib_pointer(attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
> + Gl::vertex_attrib_pointer(attr_color_, 3, sizeof(PerVertexData), offsetof(PerVertexData, color_r));
> +
> + vertices_.clear();
> +
> + std::vector<DrawBatch> draw_batches;
> + int offset = 0;
> + while (i < arguments.size()) {
> + const Arguments& template_args = arguments[i];
> +
> + while (i < arguments.size()) {
> + const Arguments& current_args = arguments[i];
> + if (current_args.line_width != template_args.line_width) {
> + break;
> + }
> + // We do not support anything else for drawing lines, really.
> + assert(current_args.blend_mode == BlendMode::Copy);
> +
> + vertices_.emplace_back(current_args.destination_rect.x,
> + current_args.destination_rect.y,
> + current_args.z_value,
> + current_args.color.r / 255.,
> + current_args.color.g / 255.,
> + current_args.color.b / 255.);
> +
> + vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
> + current_args.destination_rect.y + current_args.destination_rect.h,
> + current_args.z_value,
> + current_args.color.r / 255.,
> + current_args.color.g / 255.,
> + current_args.color.b / 255.);
> + ++i;
> + }
> +
> + draw_batches.emplace_back(
> + DrawBatch{offset, static_cast<int>(vertices_.size() - offset), template_args.line_width});
> + offset = vertices_.size();
> + }
> +
> + gl_array_buffer_.update(vertices_);
> +
> + // Now do the draw calls.
> + for (const auto& draw_arg : draw_batches) {
> + glLineWidth(draw_arg.line_width);
> + glDrawArrays(GL_LINES, draw_arg.offset, draw_arg.count);
> + }
>
> glBindBuffer(GL_ARRAY_BUFFER, 0);
> +
> glDisableVertexAttribArray(attr_position_);
> + glDisableVertexAttribArray(attr_color_);
> +
> glUseProgram(0);
> }
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -20,37 +20,76 @@
> #ifndef WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H
> #define WL_GRAPHIC_GL_DRAW_LINE_PROGRAM_H
>
> +#include <vector>
> +
> +#include "base/point.h"
> +#include "base/rect.h"
> +#include "graphic/blend_mode.h"
> #include "graphic/color.h"
> #include "graphic/gl/utils.h"
>
> class DrawLineProgram {
> public:
> + struct Arguments {
> + // The line is drawn from the top left to the bottom right of
> + // this rectangle.
> + FloatRect destination_rect;
> + float z_value;
> + RGBAColor color;
> + uint8_t line_width;
> + BlendMode blend_mode;
> + };
> +
> // Returns the (singleton) instance of this class.
> static DrawLineProgram& instance();
>
> // Draws a line from (x1, y1) to (x2, y2) which are in gl
> // coordinates in 'color' with a 'line_width' in pixels.
> - void draw(float x1, float y1, float x2, float y2, const RGBColor& color, int line_width);
> + void draw(const FloatPoint& start,
> + const FloatPoint& end,
> + const float z_value,
> + const RGBColor& color,
> + const int line_width);
> +
> + void draw(std::vector<Arguments> arguments);
> +
>
> private:
> DrawLineProgram();
>
> struct PerVertexData {
> - float gl_x, gl_y;
> + PerVertexData(float init_gl_x,
> + float init_gl_y,
> + float init_gl_z,
> + float init_color_r,
> + float init_color_g,
> + float init_color_b)
> + : gl_x(init_gl_x),
> + gl_y(init_gl_y),
> + gl_z(init_gl_z),
> + color_r(init_color_r),
> + color_g(init_color_g),
> + color_b(init_color_b) {
> + }
> +
> + float gl_x, gl_y, gl_z;
> + float color_r, color_g, color_b;
> };
> - static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
> + static_assert(sizeof(PerVertexData) == 24, "Wrong padding.");
> +
> + // This is only kept around so that we do not constantly
> + // allocate memory for it.
> + std::vector<PerVertexData> vertices_;
>
> // The buffer that contains the vertices for rendering.
> - Gl::Buffer gl_array_buffer_;
> + Gl::NewBuffer<PerVertexData> gl_array_buffer_;
>
> // The program.
> Gl::Program gl_program_;
>
> // Attributes.
> GLint attr_position_;
> -
> - // Uniforms.
> - GLint u_color_;
> + GLint attr_color_;
>
> DISALLOW_COPY_AND_ASSIGN(DrawLineProgram);
> };
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -43,14 +43,20 @@
> const RoadTextures* road_textures; // Road Textures to use for drawing.
> };
>
> - FieldsToDraw(int minfx, int maxfx, int minfy, int maxfy)
> - : min_fx_(minfx),
> - max_fx_(maxfx),
> - min_fy_(minfy),
> - max_fy_(maxfy),
> - w_(max_fx_ - min_fx_ + 1),
> - h_(max_fy_ - min_fy_ + 1) {
> - fields_.resize(w_ * h_);
> + FieldsToDraw() = default;
> +
> + // Resize this fields to draw for reuse.
> + void reset(int minfx, int maxfx, int minfy, int maxfy) {
> + min_fx_ = minfx;
> + max_fx_ = maxfx;
> + min_fy_ = minfy;
> + max_fy_ = maxfy;
> + w_ = max_fx_ - min_fx_ + 1;
> + h_ = max_fy_ - min_fy_ + 1;
> + const size_t size = w_ * h_;
> + if (fields_.size() != size) {
> + fields_.resize(size);
> + }
> }
>
> // Calculates the index of the given field with ('fx', 'fy') being geometric
> @@ -84,14 +90,14 @@
>
> private:
> // Minimum and maximum field coordinates (geometric) to render. Can be negative.
> - const int min_fx_;
> - const int max_fx_;
> - const int min_fy_;
> - const int max_fy_;
> + int min_fx_;
> + int max_fx_;
> + int min_fy_;
> + int max_fy_;
>
> // Width and height in number of fields.
> - const int w_;
> - const int h_;
> + int w_;
> + int h_;
>
> std::vector<Field> fields_;
> };
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -22,6 +22,7 @@
> #include <vector>
>
> #include "base/log.h"
> +#include "base/wexception.h"
>
> namespace {
>
> @@ -29,26 +30,24 @@
> #version 120
>
> // Attributes.
> -attribute vec2 attr_position;
> -
> -// Uniforms.
> -uniform vec4 u_rect;
> -
> +attribute vec3 attr_position;
> +attribute vec4 attr_color;
> +
> +varying vec4 var_color;
>
> void main() {
> - float x = u_rect.x + attr_position.x * u_rect.z;
> - float y = u_rect.y + attr_position.y * u_rect.w;
> - gl_Position = vec4(x, y, 0., 1.);
> + var_color = attr_color;
> + gl_Position = vec4(attr_position, 1.);
> }
> )";
>
> const char kFillRectFragmentShader[] = R"(
> #version 120
>
> -uniform ivec4 u_color;
> +varying vec4 var_color;
>
> void main() {
> - gl_FragColor = vec4(u_color) / 255.;
> + gl_FragColor = var_color;
> }
> )";
>
> @@ -64,49 +63,144 @@
> gl_program_.build(kFillRectVertexShader, kFillRectFragmentShader);
>
> attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
> -
> - u_color_ = glGetUniformLocation(gl_program_.object(), "u_color");
> - u_rect_ = glGetUniformLocation(gl_program_.object(), "u_rect");
> -
> - std::vector<PerVertexData> vertices;
> - vertices.push_back(PerVertexData
> - {0., 1.});
> - vertices.push_back(PerVertexData
> - {1., 1.});
> - vertices.push_back(PerVertexData
> - {0., 0.});
> - vertices.push_back(PerVertexData
> - {1., 0.});
> -
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> - glBufferData(
> - GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
> - glVertexAttribPointer(attr_position_,
> - 2,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(0));
> - glBindBuffer(GL_ARRAY_BUFFER, 0);
> -}
> -
> -void FillRectProgram::draw(const FloatRect& gl_dst_rect, const RGBAColor& color) {
> - glUseProgram(gl_program_.object());
> - glEnableVertexAttribArray(attr_position_);
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> -
> - glVertexAttribPointer(attr_position_,
> - 2,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(0));
> -
> - glUniform4f(u_rect_, gl_dst_rect.x, gl_dst_rect.y, gl_dst_rect.w, gl_dst_rect.h);
> - glUniform4i(u_color_, color.r, color.g, color.b, color.a);
> -
> - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
> + attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
> +}
> +
> +void FillRectProgram::draw(const FloatRect& destination_rect,
> + const float z_value,
> + const RGBAColor& color,
> + const BlendMode blend_mode) {
> + draw({Arguments{destination_rect, z_value, color, blend_mode} });
> +}
> +
> +void FillRectProgram::draw(const std::vector<Arguments>& arguments) {
> + size_t i = 0;
> +
> + while (i < arguments.size()) {
> + vertices_.clear();
> + const Arguments& template_args = arguments[i];
> +
> + // This method does 3 things:
> + // - if blend_mode is Copy, we will copy color into the destination
> + // pixels without blending.
> + // - if blend_mode is Alpha and color.r < 0, we will
> + // GL_FUNC_REVERSE_SUBTRACT color.r from all RGB values in the
> + // destination buffer. color.a should be 0 for this.
> + // - if blend_mode is Alpha and color.r > 0, we will
> + // GL_ADD color.r to all RGB values in the destination buffer.
> + // color.a should be 0 for this.
> +
> + // The simple trick here is to fill the rect, but using a different glBlendFunc that will sum
> + // src and target (or subtract them if factor is negative).
> + switch (template_args.blend_mode) {
> + case BlendMode::Subtract:
> + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
> + /* fallthrough intended */
> + case BlendMode::UseAlpha:
> + glBlendFunc(GL_ONE, GL_ONE);
> + break;
> +
> + case BlendMode::Copy:
> + glDisable(GL_BLEND);
> + break;
> +
> + default:
> + break;
> + }
> +
> + glUseProgram(gl_program_.object());
> +
> + gl_array_buffer_.bind();
> +
> + glEnableVertexAttribArray(attr_position_);
> + glEnableVertexAttribArray(attr_color_);
> +
> + // Batch common rectangles up.
> + while (i < arguments.size()) {
> + const Arguments& current_args = arguments[i];
> + if (current_args.blend_mode != template_args.blend_mode) {
> + break;
> + }
> +
> + const float r = current_args.color.r / 255.;
> + const float g = current_args.color.g / 255.;
> + const float b = current_args.color.b / 255.;
> + const float a = current_args.color.a / 255.;
> +
> + // First triangle.
> + vertices_.emplace_back(current_args.destination_rect.x,
> + current_args.destination_rect.y,
> + current_args.z_value,
> + r,
> + g,
> + b,
> + a);
> + vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
> + current_args.destination_rect.y,
> + current_args.z_value,
> + r,
> + g,
> + b,
> + a);
> + vertices_.emplace_back(current_args.destination_rect.x,
> + current_args.destination_rect.y + current_args.destination_rect.h,
> + current_args.z_value,
> + r,
> + g,
> + b,
> + a);
> +
> + // Second triangle.
> + vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
> + current_args.destination_rect.y,
> + current_args.z_value,
> + r,
> + g,
> + b,
> + a);
> + vertices_.emplace_back(current_args.destination_rect.x,
> + current_args.destination_rect.y + current_args.destination_rect.h,
> + current_args.z_value,
> + r,
> + g,
> + b,
> + a);
> + vertices_.emplace_back(current_args.destination_rect.x + current_args.destination_rect.w,
> + current_args.destination_rect.y + current_args.destination_rect.h,
> + current_args.z_value,
> + r,
> + g,
> + b,
> + a);
> + ++i;
> + }
> +
> + gl_array_buffer_.update(vertices_);
> +
> + Gl::vertex_attrib_pointer(
> + attr_position_, 3, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
> + Gl::vertex_attrib_pointer(attr_color_, 4, sizeof(PerVertexData), offsetof(PerVertexData, r));
> +
> + glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
> +
> + switch (template_args.blend_mode) {
> + case BlendMode::Subtract:
> + glBlendEquation(GL_FUNC_ADD);
> + /* fallthrough intended */
> + case BlendMode::UseAlpha:
> + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> + break;
> +
> + case BlendMode::Copy:
> + glEnable(GL_BLEND);
> + break;
> +
> + default:
> + break;
> + }
> + }
>
> glDisableVertexAttribArray(attr_position_);
> + glDisableVertexAttribArray(attr_color_);
> glBindBuffer(GL_ARRAY_BUFFER, 0);
> }
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -20,39 +20,73 @@
> #ifndef WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H
> #define WL_GRAPHIC_GL_FILL_RECT_PROGRAM_H
>
> +#include <vector>
> +
> #include "base/rect.h"
> +#include "graphic/blend_mode.h"
> #include "graphic/color.h"
> #include "graphic/gl/utils.h"
>
> class FillRectProgram {
> public:
> + struct Arguments {
> + FloatRect destination_rect;
> + float z_value;
> + RGBAColor color;
> + BlendMode blend_mode;
> + };
> +
> // Returns the (singleton) instance of this class.
> static FillRectProgram& instance();
>
> - // Fills a solid rect in 'color' into the currently activated
> - // framebuffer.
> - void draw(const FloatRect& gl_dst_rect, const RGBAColor& color);
> + // Fills a solid rect in 'color'. If blend_mode is BlendMode::UseAlpha, this
> + // will brighten the rect, if it is BlendMode::Subtract it darkens it.
> + void draw(const FloatRect& destination_rect,
> + float z_value,
> + const RGBAColor& color,
> + BlendMode blend_mode);
> +
> +
> + void draw(const std::vector<Arguments>& arguments);
>
> private:
> FillRectProgram();
>
> struct PerVertexData {
> - float gl_x, gl_y;
> + PerVertexData(float init_gl_x,
> + float init_gl_y,
> + float init_gl_z,
> + float init_r,
> + float init_g,
> + float init_b,
> + float init_a)
> + : gl_x(init_gl_x),
> + gl_y(init_gl_y),
> + gl_z(init_gl_z),
> + r(init_r),
> + g(init_g),
> + b(init_b),
> + a(init_a) {
> + }
> +
> + float gl_x, gl_y, gl_z;
> + float r, g, b, a;
> };
> - static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
> + static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
> +
> + // This is only kept around so that we do not constantly allocate memory for
> + // it.
> + std::vector<PerVertexData> vertices_;
>
> // The buffer that will contain the quad for rendering.
> - Gl::Buffer gl_array_buffer_;
> + Gl::NewBuffer<PerVertexData> gl_array_buffer_;
>
> // The program.
> Gl::Program gl_program_;
>
> // Attributes.
> GLint attr_position_;
> -
> - // Uniforms.
> - GLint u_rect_;
> - GLint u_color_;
> + GLint attr_color_;
>
> DISALLOW_COPY_AND_ASSIGN(FillRectProgram);
> };
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -23,6 +23,7 @@
> #include <cmath>
>
> #include "base/log.h"
> +#include "graphic/gl/coordinate_conversion.h"
> #include "graphic/gl/fields_to_draw.h"
> #include "graphic/graphic.h"
> #include "graphic/image_io.h"
> @@ -40,6 +41,8 @@
> attribute vec2 attr_texture_position;
> attribute float attr_brightness;
>
> +uniform float u_z_value;
> +
> // Outputs.
> varying vec2 out_texture_position;
> varying float out_brightness;
> @@ -47,7 +50,7 @@
> void main() {
> out_texture_position = attr_texture_position;
> out_brightness = attr_brightness;
> - gl_Position = vec4(attr_position, 0., 1.);
> + gl_Position = vec4(attr_position, u_z_value, 1.);
> }
> )";
>
> @@ -73,17 +76,18 @@
> gl_program_.build(kRoadVertexShader, kRoadFragmentShader);
>
> attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
> - attr_texture_position_ =
> - glGetAttribLocation(gl_program_.object(), "attr_texture_position");
> + attr_texture_position_ = glGetAttribLocation(gl_program_.object(), "attr_texture_position");
> attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
>
> + u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
> u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
> }
>
> RoadProgram::~RoadProgram() {
> }
>
> -void RoadProgram::add_road(const Surface& surface,
> +void RoadProgram::add_road(const int renderbuffer_width,
> + const int renderbuffer_height,
> const FieldsToDraw::Field& start,
> const FieldsToDraw::Field& end,
> const Widelands::RoadType road_type,
> @@ -120,32 +124,39 @@
>
> const auto& texture_rect = texture.texture_coordinates();
>
> + // TODO(sirver): This is a hack to make sure we are sampling inside of the
> + // terrain texture. This is a common problem with OpenGL and texture atlases.
> + const float MARGIN = 5e-2;
> +
Code style: constexpr float kMargin
> vertices_.emplace_back(PerVertexData{
> start.pixel_x - road_overshoot_x + road_thickness_x,
> start.pixel_y - road_overshoot_y + road_thickness_y,
> - texture_rect.x,
> - texture_rect.y,
> + texture_rect.x + MARGIN,
> + texture_rect.y + MARGIN,
> start.brightness,
> });
> - surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
> + pixel_to_gl_renderbuffer(
> + renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
>
> vertices_.emplace_back(PerVertexData{
> start.pixel_x - road_overshoot_x - road_thickness_x,
> start.pixel_y - road_overshoot_y - road_thickness_y,
> - texture_rect.x,
> - texture_rect.y + texture_rect.h,
> + texture_rect.x + MARGIN,
> + texture_rect.y + texture_rect.h - MARGIN,
> start.brightness,
> });
> - surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
> + pixel_to_gl_renderbuffer(
> + renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
>
> vertices_.emplace_back(PerVertexData{
> end.pixel_x + road_overshoot_x + road_thickness_x,
> end.pixel_y + road_overshoot_y + road_thickness_y,
> - texture_rect.x + texture_rect.w,
> - texture_rect.y,
> + texture_rect.x + texture_rect.w - MARGIN,
> + texture_rect.y + MARGIN,
> end.brightness,
> });
> - surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
> + pixel_to_gl_renderbuffer(
> + renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
>
> // As OpenGl does not support drawing quads in modern days and we have a
> // bunch of roads that might not be neighbored, we need to add two triangles
> @@ -157,14 +168,18 @@
> vertices_.emplace_back(PerVertexData{
> end.pixel_x + road_overshoot_x - road_thickness_x,
> end.pixel_y + road_overshoot_y - road_thickness_y,
> - texture_rect.x + texture_rect.w,
> - texture_rect.y + texture_rect.h,
> + texture_rect.x + texture_rect.w - MARGIN,
> + texture_rect.y + texture_rect.h - MARGIN,
> end.brightness,
> });
> - surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
> + pixel_to_gl_renderbuffer(
> + renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
> }
>
> -void RoadProgram::draw(const Surface& surface, const FieldsToDraw& fields_to_draw) {
> +void RoadProgram::draw(const int renderbuffer_width,
> + const int renderbuffer_height,
> + const FieldsToDraw& fields_to_draw,
> + float z_value) {
> vertices_.clear();
>
> int gl_texture = -1;
> @@ -175,9 +190,15 @@
> const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
> if (rn_index != -1) {
> const Widelands::RoadType road =
> - static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
> + static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
> if (road != Widelands::RoadType::kNone) {
> - add_road(surface, field, fields_to_draw.at(rn_index), road, kEast, &gl_texture);
> + add_road(renderbuffer_width,
> + renderbuffer_height,
> + field,
> + fields_to_draw.at(rn_index),
> + road,
> + kEast,
> + &gl_texture);
> }
> }
>
> @@ -185,9 +206,15 @@
> const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
> if (brn_index != -1) {
> const Widelands::RoadType road =
> - static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
> + static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
> if (road != Widelands::RoadType::kNone) {
> - add_road(surface, field, fields_to_draw.at(brn_index), road, kSouthEast, &gl_texture);
> + add_road(renderbuffer_width,
> + renderbuffer_height,
> + field,
> + fields_to_draw.at(brn_index),
> + road,
> + kSouthEast,
> + &gl_texture);
> }
> }
>
> @@ -196,9 +223,15 @@
> fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
> if (bln_index != -1) {
> const Widelands::RoadType road =
> - static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
> + static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
> if (road != Widelands::RoadType::kNone) {
> - add_road(surface, field, fields_to_draw.at(bln_index), road, kSouthWest, &gl_texture);
> + add_road(renderbuffer_width,
> + renderbuffer_height,
> + field,
> + fields_to_draw.at(bln_index),
> + road,
> + kSouthWest,
> + &gl_texture);
> }
> }
> }
> @@ -209,21 +242,15 @@
> glEnableVertexAttribArray(attr_texture_position_);
> glEnableVertexAttribArray(attr_brightness_);
>
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> - glBufferData(
> - GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices_.size(), vertices_.data(), GL_STREAM_DRAW);
> + gl_array_buffer_.bind();
> + gl_array_buffer_.update(vertices_);
>
> - const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
> - glVertexAttribPointer(vertex_index,
> - num_items,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(PerVertexData),
> - reinterpret_cast<void*>(offset));
> - };
> - set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
> - set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
> - set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
> + Gl::vertex_attrib_pointer(
> + attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
> + Gl::vertex_attrib_pointer(
> + attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
> + Gl::vertex_attrib_pointer(
> + attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
>
> glBindBuffer(GL_ARRAY_BUFFER, 0);
>
> @@ -233,6 +260,8 @@
>
> glUniform1i(u_texture_, 0);
>
> + glUniform1f(u_z_value_, z_value);
> +
> glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
>
> glDisableVertexAttribArray(attr_position_);
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -37,9 +37,9 @@
> RoadProgram();
> ~RoadProgram();
>
> - // Draws the roads. The 'surface' is needed to convert from pixel space to
> - // GL space.
> - void draw(const Surface& surface, const FieldsToDraw& fields_to_draw);
> + // Draws the roads. The dimensions of the renderbuffer are needed to convert from pixel to GL
> + // space.
> + void draw(int renderbuffer_width, int renderbuffer_height, const FieldsToDraw& fields_to_draw, float z_value);
>
> private:
> struct PerVertexData {
> @@ -54,15 +54,16 @@
> // Adds a road from 'start' to 'end' to be rendered in this frame using the
> // correct texture for 'road_type'.
> enum Direction {kEast, kSouthEast, kSouthWest};
> - void add_road(const Surface& surface,
> + void add_road(int renderbuffer_width,
> + int renderbuffer_height,
> const FieldsToDraw::Field& start,
> const FieldsToDraw::Field& end,
> const Widelands::RoadType road_type,
> const Direction direction,
> - int* gl_texture);
> + int* gl_texture);
>
> // The buffer that will contain 'vertices_' for rendering.
> - Gl::Buffer gl_array_buffer_;
> + Gl::NewBuffer<PerVertexData> gl_array_buffer_;
>
> // The program used for drawing the roads.
> Gl::Program gl_program_;
> @@ -74,6 +75,7 @@
>
> // Uniforms.
> GLint u_texture_;
> + GLint u_z_value_;
>
> // All vertices that get rendered this frame.
> std::vector<PerVertexData> vertices_;
>
> === modified file 'src/graphic/gl/terrain_program.cc'
> --- src/graphic/gl/terrain_program.cc 2015-03-01 09:21:20 +0000
> +++ src/graphic/gl/terrain_program.cc 2015-03-01 10:31:43 +0000
> @@ -40,6 +40,8 @@
> attribute vec2 attr_texture_offset;
> attribute vec2 attr_texture_position;
>
> +uniform float u_z_value;
> +
> // Output of vertex shader.
> varying float var_brightness;
> varying vec2 var_texture_offset;
> @@ -49,7 +51,7 @@
> var_texture_position = attr_texture_position;
> var_brightness = attr_brightness;
> var_texture_offset = attr_texture_offset;
> - gl_Position = vec4(attr_position, 0., 1.);
> + gl_Position = vec4(attr_position, u_z_value, 1.);
> }
> )";
>
> @@ -63,9 +65,20 @@
> varying vec2 var_texture_position;
> varying vec2 var_texture_offset;
>
> +// TODO(sirver): This is a hack to make sure we are sampling inside of the
> +// terrain texture. This is a common problem with OpenGL and texture atlases.
> +#define MARGIN 1e-2
> +
Code style: constexpr float kMargin
> void main() {
> - vec4 clr = texture2D(u_terrain_texture,
> - var_texture_offset + u_texture_dimensions * fract(var_texture_position));
> + // The arbitrary multiplication by 0.99 makes sure that we never sample
> + // outside of the texture in the texture atlas - this means non-perfect
> + // pixel mapping of textures to the screen, but we are pretty meh about that
> + // here.
> + vec2 texture_fract = clamp(
> + fract(var_texture_position),
> + vec2(MARGIN, MARGIN),
> + vec2(1. - MARGIN, 1. - MARGIN));
> + vec4 clr = texture2D(u_terrain_texture, var_texture_offset + u_texture_dimensions * texture_fract);
> clr.rgb *= var_brightness;
> gl_FragColor = clr;
> }
> @@ -83,9 +96,10 @@
>
> u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
> u_texture_dimensions_ = glGetUniformLocation(gl_program_.object(), "u_texture_dimensions");
> + u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
> }
>
> -void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h) {
> +void TerrainProgram::gl_draw(int gl_texture, float texture_w, float texture_h, float z_value) {
> glUseProgram(gl_program_.object());
>
> glEnableVertexAttribArray(attr_brightness_);
> @@ -93,30 +107,23 @@
> glEnableVertexAttribArray(attr_texture_offset_);
> glEnableVertexAttribArray(attr_texture_position_);
>
> - glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
> - glBufferData(GL_ARRAY_BUFFER,
> - sizeof(TerrainProgram::PerVertexData) * vertices_.size(),
> - vertices_.data(),
> - GL_STREAM_DRAW);
> + gl_array_buffer_.bind();
> + gl_array_buffer_.update(vertices_);
>
> - const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
> - glVertexAttribPointer(vertex_index,
> - num_items,
> - GL_FLOAT,
> - GL_FALSE,
> - sizeof(TerrainProgram::PerVertexData),
> - reinterpret_cast<void*>(offset));
> - };
> - set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
> - set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
> - set_attrib_pointer(attr_texture_offset_, 2, offsetof(PerVertexData, texture_offset_x));
> - set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
> + Gl::vertex_attrib_pointer(
> + attr_brightness_, 1, sizeof(PerVertexData), offsetof(PerVertexData, brightness));
> + Gl::vertex_attrib_pointer(attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
> + Gl::vertex_attrib_pointer(
> + attr_texture_offset_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_offset_x));
> + Gl::vertex_attrib_pointer(
> + attr_texture_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, texture_x));
>
> glBindBuffer(GL_ARRAY_BUFFER, 0);
>
> glActiveTexture(GL_TEXTURE0);
> glBindTexture(GL_TEXTURE_2D, gl_texture);
>
> + glUniform1f(u_z_value_, z_value);
> glUniform1i(u_terrain_texture_, 0);
> glUniform2f(u_texture_dimensions_, texture_w, texture_h);
>
> @@ -146,7 +153,8 @@
>
> void TerrainProgram::draw(uint32_t gametime,
> const DescriptionMaintainer<TerrainDescription>& terrains,
> - const FieldsToDraw& fields_to_draw) {
> + const FieldsToDraw& fields_to_draw,
> + float z_value) {
> // This method expects that all terrains have the same dimensions and that
> // all are packed into the same texture atlas, i.e. all are in the same GL
> // texture. It does not check for this invariance for speeds sake.
> @@ -170,7 +178,7 @@
> fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
> if (bln_index != -1) {
> const FloatPoint texture_offset =
> - terrains.get_unmutable(field.ter_d).get_texture(gametime).texture_coordinates().top_left();
> + terrains.get_unmutable(field.ter_d).get_texture(gametime).texture_coordinates().origin();
> add_vertex(fields_to_draw.at(current_index), texture_offset);
> add_vertex(fields_to_draw.at(bln_index), texture_offset);
> add_vertex(fields_to_draw.at(brn_index), texture_offset);
> @@ -180,7 +188,7 @@
> const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
> if (rn_index != -1) {
> const FloatPoint texture_offset =
> - terrains.get_unmutable(field.ter_r).get_texture(gametime).texture_coordinates().top_left();
> + terrains.get_unmutable(field.ter_r).get_texture(gametime).texture_coordinates().origin();
> add_vertex(fields_to_draw.at(current_index), texture_offset);
> add_vertex(fields_to_draw.at(brn_index), texture_offset);
> add_vertex(fields_to_draw.at(rn_index), texture_offset);
> @@ -188,5 +196,8 @@
> }
>
> const Texture& texture = terrains.get_unmutable(0).get_texture(0);
> - gl_draw(texture.get_gl_texture(), texture.texture_coordinates().w, texture.texture_coordinates().h);
> + gl_draw(texture.get_gl_texture(),
> + texture.texture_coordinates().w,
> + texture.texture_coordinates().h,
> + z_value);
> }
>
> === 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 2015-03-01 10:31:43 +0000
> @@ -35,8 +35,10 @@
> TerrainProgram();
>
> // Draws the terrain.
> - void draw(uint32_t gametime, const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> - const FieldsToDraw& fields_to_draw);
> + void draw(uint32_t gametime,
> + const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
> + const FieldsToDraw& fields_to_draw,
> + float z_value);
>
> private:
> struct PerVertexData {
> @@ -50,7 +52,7 @@
> };
> static_assert(sizeof(PerVertexData) == 28, "Wrong padding.");
>
> - void gl_draw(int gl_texture, float texture_w, float texture_h);
> + void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
>
> // Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
> void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
> @@ -59,7 +61,7 @@
> Gl::Program gl_program_;
>
> // The buffer that will contain 'vertices_' for rendering.
> - Gl::Buffer gl_array_buffer_;
> + Gl::NewBuffer<PerVertexData> gl_array_buffer_;
>
> // Attributes.
> GLint attr_brightness_;
> @@ -70,6 +72,7 @@
> // Uniforms.
> GLint u_terrain_texture_;
> GLint u_texture_dimensions_;
> + GLint u_z_value_;
>
> // Objects below are kept around to avoid memory allocations on each frame.
> // They could theoretically also be recreated.
>
> === modified file 'src/graphic/gl/utils.cc'
> --- src/graphic/gl/utils.cc 2014-09-27 18:53:55 +0000
> +++ src/graphic/gl/utils.cc 2015-03-01 10:31:43 +0000
> @@ -21,8 +21,6 @@
> #include <memory>
> #include <string>
>
> -#include <SDL_video.h>
> -
> #include "base/log.h"
> #include "base/wexception.h"
>
> @@ -41,40 +39,8 @@
> return "unknown";
> }
>
> -// Creates one OpenGL buffer.
> -GLuint create_buffer() {
> - GLuint buffer = 0;
> - glGenBuffers(1, &buffer);
> - return buffer;
> -}
> -
> } // namespace
>
> -/**
> - * \return the standard 32-bit RGBA format that we use in OpenGL
> - */
> -const SDL_PixelFormat & gl_rgba_format()
> -{
> - static SDL_PixelFormat format;
> - static bool init = false;
> - if (init)
> - return format;
> -
> - init = true;
> - memset(&format, 0, sizeof(format));
> - format.BitsPerPixel = 32;
> - format.BytesPerPixel = 4;
> - format.Rmask = 0x000000ff;
> - format.Gmask = 0x0000ff00;
> - format.Bmask = 0x00ff0000;
> - format.Amask = 0xff000000;
> - format.Rshift = 0;
> - format.Gshift = 8;
> - format.Bshift = 16;
> - format.Ashift = 24;
> - return format;
> -}
> -
> GLenum _handle_glerror(const char * file, unsigned int line)
> {
> GLenum err = glGetError();
> @@ -162,18 +128,6 @@
> }
> }
>
> -Buffer::Buffer() : buffer_object_(create_buffer()) {
> - if (!buffer_object_) {
> - throw wexception("Could not create GL program.");
> - }
> -}
> -
> -Buffer::~Buffer() {
> - if (buffer_object_) {
> - glDeleteBuffers(1, &buffer_object_);
> - }
> -}
> -
> Program::Program() : program_object_(glCreateProgram()) {
> if (!program_object_) {
> throw wexception("Could not create GL program.");
> @@ -212,4 +166,21 @@
> }
> }
>
> +void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset) {
> + glVertexAttribPointer(
> + vertex_index, num_items, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<void*>(offset));
> +}
> +
> +void swap_rows(const int width, const int height, const int pitch, const int bpp, uint8_t* pixels) {
> + uint8_t* begin_row = pixels;
> + uint8_t* end_row = pixels + pitch * (height - 1);
> + while (begin_row < end_row) {
> + for (int x = 0; x < width * bpp; ++x) {
> + std::swap(begin_row[x], end_row[x]);
> + }
> + begin_row += pitch;
> + end_row -= pitch;
> + }
> +}
> +
> } // namespace Gl
>
> === modified file 'src/graphic/gl/utils.h'
> --- src/graphic/gl/utils.h 2014-11-08 13:59:33 +0000
> +++ src/graphic/gl/utils.h 2015-03-01 10:31:43 +0000
> @@ -20,19 +20,19 @@
> #define WL_GRAPHIC_GL_UTILS_H
>
> #include <memory>
> +#include <vector>
>
> #include <stdint.h>
>
> +#include "base/log.h"
> #include "base/macros.h"
> +#include "base/wexception.h"
> #include "graphic/gl/system_headers.h"
>
> -struct SDL_PixelFormat;
> -
> namespace Gl {
>
> class Shader;
>
> -const SDL_PixelFormat & gl_rgba_format();
> GLenum _handle_glerror(const char * file, unsigned int line);
>
> // Thin wrapper around a OpenGL program object to ensure proper cleanup. Throws
> @@ -59,22 +59,54 @@
> };
>
> // Thin wrapper around a OpenGL buffer object to ensure proper cleanup. Throws
> -// on all errors.
> -class Buffer {
> +// on all errors. Also grows the server memory only when needed.
> +template<typename T>
> +class NewBuffer {
> public:
Can this be renamed back to Buffer now? Honest question ;)
> - Buffer();
> - ~Buffer();
> -
> - GLuint object() const {
> - return buffer_object_;
> + NewBuffer() : buffer_size_(0) {
> + glGenBuffers(1, &object_);
> + if (!object_) {
> + throw wexception("Could not create GL program.");
> + }
> + }
> +
> + ~NewBuffer() {
> + if (object_) {
> + glDeleteBuffers(1, &object_);
> + }
> + }
> +
> + // Calls glBindBuffer on the underlying buffer data.
> + void bind() const {
> + glBindBuffer(GL_ARRAY_BUFFER, object_);
> + }
> +
> +
> + // Copies 'elements' into the buffer. If the buffer is too small to hold the
> + // data, it is reallocated. Does not check if the buffer is already bound.
> + void update(const std::vector<T>& items) {
> + if (buffer_size_ < items.size()) {
> + glBufferData(GL_ARRAY_BUFFER, items.size() * sizeof(T), items.data(), GL_DYNAMIC_DRAW);
> + buffer_size_ = items.size();
> + } else {
> + glBufferSubData(GL_ARRAY_BUFFER, 0, items.size() * sizeof(T), items.data());
> + }
> }
>
> private:
> - const GLuint buffer_object_;
> + GLuint object_;
> + size_t buffer_size_; // In number of elements.
>
> - DISALLOW_COPY_AND_ASSIGN(Buffer);
> + DISALLOW_COPY_AND_ASSIGN(NewBuffer);
> };
>
> +// Calls glVertexAttribPointer.
> +void vertex_attrib_pointer(int vertex_index, int num_items, int stride, int offset);
> +
> +// Swap order of rows in m_pixels, to compensate for the upside-down nature of the
> +// OpenGL coordinate system.
> +void swap_rows(int width, int height, int pitch, int bpp, uint8_t* pixels);
> +
> } // namespace Gl
>
> /**
>
> === modified file 'src/graphic/graphic.cc'
> --- src/graphic/graphic.cc 2014-12-27 09:59:12 +0000
> +++ src/graphic/graphic.cc 2015-03-01 10:31:43 +0000
> @@ -29,6 +29,7 @@
> #include "graphic/gl/system_headers.h"
> #include "graphic/image.h"
> #include "graphic/image_io.h"
> +#include "graphic/render_queue.h"
> #include "graphic/rendertarget.h"
> #include "graphic/screen.h"
> #include "graphic/texture.h"
> @@ -70,6 +71,7 @@
> SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
> SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
> SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
> + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
>
> log("Graphics: Try to set Videomode %ux%u\n", m_window_mode_width, m_window_mode_height);
> m_sdl_window = SDL_CreateWindow("Widelands Window",
> @@ -111,12 +113,11 @@
> glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glInt);
> log("Graphics: OpenGL: Max texture size: %u\n", glInt);
>
> - SDL_GL_SetSwapInterval(1);
> -
> glDrawBuffer(GL_BACK);
>
> - glDisable(GL_DEPTH_TEST);
> - glEnable(GL_TEXTURE_2D);
> + glEnable(GL_DEPTH_TEST);
> + glDepthFunc(GL_LEQUAL);
> +
> glEnable(GL_BLEND);
> glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
>
> @@ -244,9 +245,8 @@
> /**
> * Returns true if parts of the screen have been marked for refreshing.
> */
> -bool Graphic::need_update() const
> -{
> - return m_update;
> +bool Graphic::need_update() const {
> + return m_update;
> }
>
> /**
> @@ -256,6 +256,8 @@
> */
> void Graphic::refresh()
> {
> + RenderQueue::instance().draw(screen_->width(), screen_->height());
> +
> // Setting the window size immediately after going out of fullscreen does
> // not work properly. We work around this issue by resizing the window in
> // refresh() when in window mode.
>
> === modified file 'src/graphic/image_cache.cc'
> --- src/graphic/image_cache.cc 2014-12-07 20:52:55 +0000
> +++ src/graphic/image_cache.cc 2015-03-01 10:31:43 +0000
> @@ -21,13 +21,47 @@
>
> #include <cassert>
> #include <memory>
> +#include <set>
> #include <string>
>
> -#include "base/log.h"
> +#include <SDL.h>
> +#include <boost/format.hpp>
> +
> #include "graphic/image.h"
> #include "graphic/image_io.h"
> #include "graphic/texture.h"
>
> +namespace {
> +
> +constexpr int kBiggestAreaForCompactification = 250 * 250;
> +
> +} // namespace
> +ImageCache::ProxyImage::ProxyImage(std::unique_ptr<const Image> image) : image_(std::move(image)) {
> +}
> +
> +const Image& ImageCache::ProxyImage::image() {
> + return *image_;
> +}
> +
> +void ImageCache::ProxyImage::set_image(std::unique_ptr<const Image> image) {
> + image_ = std::move(image);
> +}
> +
> +int ImageCache::ProxyImage::width() const {
> + return image_->width();
> +}
> +
> +int ImageCache::ProxyImage::height() const {
> + return image_->height();
> +}
> +int ImageCache::ProxyImage::get_gl_texture() const {
> + return image_->get_gl_texture();
> +}
> +
> +const FloatRect& ImageCache::ProxyImage::texture_coordinates() const {
> + return image_->texture_coordinates();
> +}
> +
> ImageCache::ImageCache() {
> }
>
> @@ -41,15 +75,45 @@
> const Image* ImageCache::insert(const std::string& hash, std::unique_ptr<const Image> image) {
> assert(!has(hash));
> const Image* return_value = image.get();
> - images_.insert(make_pair(hash, std::move(image)));
> + images_.insert(make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(std::move(image)))));
> return return_value;
> }
>
> const Image* ImageCache::get(const std::string& hash) {
> ImageMap::const_iterator it = images_.find(hash);
> if (it == images_.end()) {
> - images_.insert(make_pair(hash, load_image(hash)));
> + images_.insert(
> + make_pair(hash, std::unique_ptr<ProxyImage>(new ProxyImage(load_image(hash)))));
> return get(hash);
> }
> return it->second.get();
> }
> +
> +void ImageCache::compactify() {
> + TextureAtlas texture_atlas;
> +
> + std::vector<std::string> hashes;
> + for (const auto& pair : images_) {
> + const auto& image = pair.second->image();
> + if (image.width() * image.height() > kBiggestAreaForCompactification) {
> + continue;
> + }
> +
> + texture_atlas.add(image);
> + hashes.push_back(pair.first);
> + }
> +
> + std::vector<std::unique_ptr<Texture>> new_textures;
> +
> + // TODO(sirver): Limit the size of the texture atlas to a max GL texture
> + // size. This might return more than one packed image. Make sure that the
> + // code works also for small max texture sizes.
> + texture_atlases_.emplace_back(texture_atlas.pack(&new_textures));
> +
> + assert(new_textures.size() == hashes.size());
> + std::set<int> gl_textures;
> + for (size_t i = 0; i < hashes.size(); ++i) {
> + gl_textures.insert(new_textures[i]->get_gl_texture());
> + images_[hashes[i]]->set_image(std::move(new_textures[i]));
> + }
> +}
>
> === modified file 'src/graphic/image_cache.h'
> --- src/graphic/image_cache.h 2014-12-07 15:41:39 +0000
> +++ src/graphic/image_cache.h 2015-03-01 10:31:43 +0000
> @@ -23,11 +23,13 @@
> #include <map>
> #include <memory>
> #include <string>
> +#include <vector>
>
> #include <boost/utility.hpp>
>
> #include "base/macros.h"
> #include "graphic/image.h"
> +#include "graphic/texture_atlas.h"
>
> // For historic reasons, most part of the Widelands code base expect that an
> // Image stays valid for the whole duration of the program run. This class is
> @@ -53,9 +55,33 @@
> // Returns true if the given hash is stored in the cache.
> bool has(const std::string& hash) const;
>
> + // For debug only: Takes all images that are in the ImageCache right now and
> + // puts them into one huge texture atlas.
> + void compactify();
> +
> private:
> - using ImageMap = std::map<std::string, std::unique_ptr<const Image>>;
> -
> + // We return a wrapped Image so that we can swap out the pointer to the
> + // image under our user. This can happen when we move an Image from a stand
> + // alone texture into being a subrect of a texture atlas.
> + class ProxyImage : public Image {
> + public:
> + ProxyImage(std::unique_ptr<const Image> image);
> +
> + const Image& image();
> + void set_image(std::unique_ptr<const Image> image);
> +
> + int width() const override;
> + int height() const override;
> + int get_gl_texture() const override;
> + const FloatRect& texture_coordinates() const override;
> +
> + private:
> + std::unique_ptr<const Image> image_;
> + };
> +
> + using ImageMap = std::map<std::string, std::unique_ptr<ProxyImage>>;
> +
> + std::vector<std::unique_ptr<Texture>> texture_atlases_;
> ImageMap images_; /// hash of cached filename/image pairs
>
> DISALLOW_COPY_AND_ASSIGN(ImageCache);
>
> === modified file 'src/graphic/image_io.cc'
> --- src/graphic/image_io.cc 2014-12-07 21:34:11 +0000
> +++ src/graphic/image_io.cc 2015-03-01 10:31:43 +0000
> @@ -25,6 +25,7 @@
> #include <SDL_image.h>
> #include <png.h>
>
> +#include "base/log.h"
> #include "base/wexception.h"
> #include "graphic/texture.h"
> #include "io/fileread.h"
> @@ -130,7 +131,6 @@
> std::unique_ptr<png_byte[]> row(new png_byte[row_size]);
>
> // Write each row
> - const SDL_PixelFormat& fmt = texture->format();
> texture->lock();
>
> // Write each row
> @@ -138,7 +138,7 @@
> if (color_type == ColorType::RGB) {
> for (uint32_t y = 0; y < surf_h; ++y) {
> for (uint32_t x = 0; x < surf_w; ++x) {
> - color.set(fmt, texture->get_pixel(x, y));
> + color = texture->get_pixel(x, y);
> row[3 * x] = color.r;
> row[3 * x + 1] = color.g;
> row[3 * x + 2] = color.b;
> @@ -148,7 +148,7 @@
> } else {
> for (uint32_t y = 0; y < surf_h; ++y) {
> for (uint32_t x = 0; x < surf_w; ++x) {
> - color.set(fmt, texture->get_pixel(x, y));
> + color = texture->get_pixel(x, y);
> row[4 * x] = color.r;
> row[4 * x + 1] = color.g;
> row[4 * x + 2] = color.b;
>
> === modified file 'src/graphic/minimap_renderer.cc'
> --- src/graphic/minimap_renderer.cc 2014-12-07 21:34:11 +0000
> +++ src/graphic/minimap_renderer.cc 2015-03-01 10:31:43 +0000
> @@ -38,68 +38,49 @@
>
> namespace {
>
> +const RGBColor kWhite(255, 255, 255);
> +
> // Blend two colors.
> -inline uint32_t blend_color
> - (const SDL_PixelFormat& format, uint32_t clr1, uint8_t r2, uint8_t g2, uint8_t b2)
> -{
> - uint8_t r1, g1, b1;
> - SDL_GetRGB(clr1, &const_cast<SDL_PixelFormat &>(format), &r1, &g1, &b1);
> - return
> - SDL_MapRGB
> - (&const_cast<SDL_PixelFormat &>(format), (r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2);
> +inline RGBColor blend_color(const RGBColor& c1, const RGBColor& c2) {
> + return RGBColor((c1.r + c2.r) / 2, (c1.g + c2.g) / 2, (c1.b + c2.b) / 2);
> }
>
> // Returns the color to be used in the minimap for the given field.
> -inline uint32_t calc_minimap_color
> - (const SDL_PixelFormat& format, const Widelands::EditorGameBase& egbase,
> - const Widelands::FCoords& f, MiniMapLayer layers, Widelands::PlayerNumber owner,
> - bool see_details)
> -{
> - uint32_t pixelcolor = 0;
> -
> +inline RGBColor calc_minimap_color(const Widelands::EditorGameBase& egbase,
> + const Widelands::FCoords& f,
> + MiniMapLayer layers,
> + Widelands::PlayerNumber owner,
> + bool see_details) {
> + RGBColor color;
> if (layers & MiniMapLayer::Terrain) {
> - const RGBColor& color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
> + color = egbase.world().terrain_descr(f.field->terrain_d()).get_minimap_color(
> f.field->get_brightness());
> -
> - pixelcolor = SDL_MapRGBA(&format, color.r, color.g, color.b, 255);
> }
>
> if (layers & MiniMapLayer::Owner) {
> - if (0 < owner) { // If owned, get the player's color...
> - const RGBColor & player_color = egbase.player(owner).get_playercolor();
> -
> - // ...and add the player's color to the old color.
> - pixelcolor = blend_color
> - (format,
> - pixelcolor,
> - player_color.r, player_color.g, player_color.b);
> + if (0 < owner) {
> + color = blend_color(color, egbase.player(owner).get_playercolor());
> }
> }
>
> if (see_details) {
> // if ownership layer is displayed, it creates enough contrast to
> // visualize objects using white color.
> - // Otherwise, a more contrasting color may be needed:
> - // * winterland -> orange
>
> if (upcast(PlayerImmovable const, immovable, f.field->get_immovable())) {
> if ((layers & MiniMapLayer::Road) && dynamic_cast<Road const *>(immovable)) {
> - pixelcolor = blend_color(format, pixelcolor, 255, 255, 255);
> + color = blend_color(color, kWhite);
> }
>
> - if
> - (((layers & MiniMapLayer::Flag) && dynamic_cast<Flag const *>(immovable))
> - ||
> - ((layers & MiniMapLayer::Building)
> - &&
> - dynamic_cast<Widelands::Building const *>(immovable)))
> - {
> - pixelcolor = SDL_MapRGB(&const_cast<SDL_PixelFormat&>(format), 255, 255, 255);
> + if (((layers & MiniMapLayer::Flag) && dynamic_cast<Flag const*>(immovable)) ||
> + ((layers & MiniMapLayer::Building) &&
> + dynamic_cast<Widelands::Building const*>(immovable))) {
> + color = kWhite;
> }
> }
> }
>
> - return pixelcolor;
> + return color;
> }
>
> // Draws the dotted frame border onto the minimap.
> @@ -149,15 +130,13 @@
> }
>
> // Does the actual work of drawing the minimap.
> -void draw_minimap_int
> - (Texture* texture, const Widelands::EditorGameBase& egbase,
> - const Widelands::Player* player, const Point& viewpoint, MiniMapLayer layers)
> -{
> - const Widelands::Map & map = egbase.map();
> +void draw_minimap_int(Texture* texture,
> + const Widelands::EditorGameBase& egbase,
> + const Widelands::Player* player,
> + const Point& viewpoint,
> + MiniMapLayer layers) {
> + const Widelands::Map& map = egbase.map();
>
> - uint8_t* const pixels = texture->get_pixels();
> - const SDL_PixelFormat& format = texture->format();
> - const uint16_t pitch = texture->get_pitch();
> const uint16_t surface_h = texture->height();
> const uint16_t surface_w = texture->width();
>
> @@ -168,90 +147,64 @@
> const int32_t mapwidth = egbase.get_map().get_width();
> const int32_t mapheight = map.get_height();
>
> - Point ptopleft; // top left point of the current display frame
> + Point ptopleft; // top left point of the current display frame
> ptopleft.x = viewpoint.x + mapwidth / 2 - xsize;
> - if (ptopleft.x < 0) ptopleft.x += mapwidth;
> + if (ptopleft.x < 0)
> + ptopleft.x += mapwidth;
> ptopleft.y = viewpoint.y + mapheight / 2 - ysize;
> - if (ptopleft.y < 0) ptopleft.y += mapheight;
> + if (ptopleft.y < 0)
> + ptopleft.y += mapheight;
>
> - Point pbottomright; // bottom right point of the current display frame
> + Point pbottomright; // bottom right point of the current display frame
> pbottomright.x = viewpoint.x + mapwidth / 2 + xsize;
> - if (pbottomright.x >= mapwidth) pbottomright.x -= mapwidth;
> + if (pbottomright.x >= mapwidth)
> + pbottomright.x -= mapwidth;
> pbottomright.y = viewpoint.y + mapheight / 2 + ysize;
> - if (pbottomright.y >= mapheight) pbottomright.y -= mapheight;
> + if (pbottomright.y >= mapheight)
> + pbottomright.y -= mapheight;
>
> uint32_t modx = pbottomright.x % 2;
> uint32_t mody = pbottomright.y % 2;
>
> - if (!player || player->see_all()) {
> - for (uint32_t y = 0; y < surface_h; ++y) {
> - uint8_t * pix = pixels + y * pitch;
> - Widelands::FCoords f
> - (Widelands::Coords
> - (viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
> - map.normalize_coords(f);
> - f.field = &map[f];
> - Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
> - for (uint32_t x = 0; x < surface_w; ++x, pix += sizeof(uint32_t)) {
> - if (x % 2 || !(layers & MiniMapLayer::Zoom2))
> - move_r(mapwidth, f, i);
> -
> - if ((layers & MiniMapLayer::ViewWindow) &&
> - is_minimap_frameborder(
> - f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
> - *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
> - (SDL_MapRGB(&const_cast<SDL_PixelFormat &>(format), 255, 0, 0));
> - } else {
> - *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
> - (calc_minimap_color
> - (format, egbase, f, layers, f.field->get_owned_by(), true));
> + for (uint32_t y = 0; y < surface_h; ++y) {
> + Widelands::FCoords f(
> + Widelands::Coords(viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
> + map.normalize_coords(f);
> + f.field = &map[f];
> + Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
> + for (uint32_t x = 0; x < surface_w; ++x) {
> + if (x % 2 || !(layers & MiniMapLayer::Zoom2))
> + move_r(mapwidth, f, i);
> +
> + RGBColor pixel_color;
> + if ((layers & MiniMapLayer::ViewWindow) &&
> + is_minimap_frameborder(f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
> + pixel_color = RGBColor(255, 0, 0);
> + } else {
> + uint16_t vision =
> + 0; // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
> + Widelands::PlayerNumber owner = 0;
> + if (player == nullptr || player->see_all()) {
> + vision = 2; // Seen right now.
> + owner = f.field->get_owned_by();
> + } else if (player != nullptr) {
> + const auto& field = player->fields()[i];
> + vision = field.vision;
> + owner = field.owner;
> + }
> +
> + if (vision > 0) {
> + pixel_color = calc_minimap_color(egbase, f, layers, owner, vision > 1);
> }
> }
> - }
> - } else {
> - Widelands::Player::Field const * const player_fields = player->fields();
> - for (uint32_t y = 0; y < surface_h; ++y) {
> - uint8_t * pix = pixels + y * pitch;
> - Widelands::FCoords f
> - (Widelands::Coords
> - (viewpoint.x, viewpoint.y +
> - (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
> - map.normalize_coords(f);
> - f.field = &map[f];
> - Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
> - for (uint32_t x = 0; x < surface_w; ++x, pix += sizeof(uint32_t)) {
> - if (x % 2 || !(layers & MiniMapLayer::Zoom2))
> - move_r(mapwidth, f, i);
> -
> - if ((layers & MiniMapLayer::ViewWindow) &&
> - is_minimap_frameborder(
> - f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
> - *reinterpret_cast<uint32_t *>(pix) = static_cast<uint32_t>
> - (SDL_MapRGB
> - (&const_cast<SDL_PixelFormat &>(format), 255, 0, 0));
> - } else {
> - const Widelands::Player::Field & player_field = player_fields[i];
> - Widelands::Vision const vision = player_field.vision;
> -
> - *reinterpret_cast<uint32_t *>(pix) =
> - static_cast<uint32_t>
> - (vision ?
> - calc_minimap_color
> - (format,
> - egbase,
> - f,
> - layers,
> - player_field.owner,
> - 1 < vision)
> - :
> - SDL_MapRGB(&const_cast<SDL_PixelFormat &>(format), 0, 0, 0));
> - }
> +
> + if (pixel_color.r != 0 || pixel_color.g != 0 || pixel_color.b != 0) {
> + texture->set_pixel(x, y, pixel_color);
> }
> }
> }
> }
>
> -
> } // namespace
>
> std::unique_ptr<Texture> draw_minimap(const EditorGameBase& egbase,
> @@ -265,17 +218,15 @@
> const int16_t map_w = (layers & MiniMapLayer::Zoom2) ? map.get_width() * 2 : map.get_width();
> const int16_t map_h = (layers & MiniMapLayer::Zoom2) ? map.get_height() * 2 : map.get_height();
>
> - Texture* texture = new Texture(map_w, map_h);
> - assert(texture->format().BytesPerPixel == sizeof(uint32_t));
> -
> - fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255), texture);
> + std::unique_ptr<Texture> texture(new Texture(map_w, map_h));
> +
> + texture->fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
> +
> texture->lock();
> -
> - draw_minimap_int(texture, egbase, player, viewpoint, layers);
> -
> + draw_minimap_int(texture.get(), egbase, player, viewpoint, layers);
> texture->unlock(Texture::Unlock_Update);
>
> - return std::unique_ptr<Texture>(texture);
> + return texture;
> }
>
> void write_minimap_image
>
> === added file 'src/graphic/render_queue.cc'
> --- src/graphic/render_queue.cc 1970-01-01 00:00:00 +0000
> +++ src/graphic/render_queue.cc 2015-03-01 10:31:43 +0000
> @@ -0,0 +1,300 @@
> +/*
> + * Copyright (C) 2006-2014 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#include "graphic/render_queue.h"
> +
> +#include <algorithm>
> +#include <limits>
> +
> +#include "base/log.h"
> +#include "base/rect.h"
> +#include "base/wexception.h"
> +#include "graphic/gl/blit_program.h"
> +#include "graphic/gl/dither_program.h"
> +#include "graphic/gl/draw_line_program.h"
> +#include "graphic/gl/fill_rect_program.h"
> +#include "graphic/gl/road_program.h"
> +#include "graphic/gl/terrain_program.h"
> +
> +namespace {
> +
> +constexpr int kMaximumZValue = std::numeric_limits<uint16_t>::max();
> +constexpr float kOpenGlZDelta = -2.f / kMaximumZValue;
> +
> +// Maps [0, kMaximumZValue] linearly to [1., -1.] for use in vertex shaders.
> +inline float to_opengl_z(const int z) {
> + return -(2.f * z) / kMaximumZValue + 1.f;
> +}
> +
> +// The key defines in which order we render things.
> +//
> +// For opaque objects, render order makes no difference in the final image, but
> +// - we batch up by program to have maximal batching.
> +// - and we want to render frontmost objects first, so that we do not render
> +// any pixel more than once.
> +static_assert(RenderQueue::Program::HIGHEST_PROGRAM_ID <= 8,
> + "Need to change sorting keys."); // 4 bits.
> +
> +uint64_t
> +make_key_opaque(const uint64_t program_id, const uint64_t z_value, const uint64_t extra_value) {
> + assert(program_id < RenderQueue::Program::HIGHEST_PROGRAM_ID);
> + assert(z_value < std::numeric_limits<uint16_t>::max());
> +
> + // TODO(sirver): As a higher priority for sorting then z value, texture
> + // could be used here. This allows for more batching of GL calls, but in my
> + // tests hardly made a difference for Widelands..
> + uint64_t sort_z_value = std::numeric_limits<uint16_t>::max() - z_value;
> + // IIII0000 EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE ZZZZZZZZ ZZZZZZZZ
> + return (program_id << 60) | (extra_value << 16) | (sort_z_value);
> +}
> +
> +// For blended objects, we need to render furthest away objects first, and we
> +// do not update the z-buffer. This guarantees that the image is correct.
> +// - if z value is the same, we order by program second to have potential batching.
> +uint64_t
> +make_key_blended(const uint64_t program_id, const uint64_t z_value, const uint64_t extra_value) {
> + assert(program_id < RenderQueue::Program::HIGHEST_PROGRAM_ID);
> + assert(z_value < std::numeric_limits<uint16_t>::max());
> +
> + // Sort opaque objects increasing, alpha objects decreasing in order.
> + // ZZZZZZZZ ZZZZZZZZ IIII0000 EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
> + return (z_value << 40) | (program_id << 36) | extra_value;
> +}
> +
> +// Construct 'args' used by the individual programs out of 'item'.
> +inline void from_item(const RenderQueue::Item& item, VanillaBlitProgram::Arguments* args) {
> + args->texture = item.vanilla_blit_arguments.texture;
> + args->opacity = item.vanilla_blit_arguments.opacity;
> +}
> +
> +inline void from_item(const RenderQueue::Item& item, MonochromeBlitProgram::Arguments* args) {
> + args->texture = item.monochrome_blit_arguments.texture;
> + args->blend = item.monochrome_blit_arguments.blend;
> +}
> +
> +inline void from_item(const RenderQueue::Item& item, FillRectProgram::Arguments* args) {
> + args->color = item.rect_arguments.color;
> +}
> +
> +inline void from_item(const RenderQueue::Item& item, BlendedBlitProgram::Arguments* args) {
> + args->texture = item.blended_blit_arguments.texture;
> + args->blend = item.blended_blit_arguments.blend;
> + args->mask = item.blended_blit_arguments.mask;
> +}
> +
> +inline void from_item(const RenderQueue::Item& item, DrawLineProgram::Arguments* args) {
> + args->color = item.line_arguments.color;
> + args->line_width = item.line_arguments.line_width;
> +}
> +
> +// Batches up as many items from 'items' that have the same 'program_id'.
> +// Increases 'index' and returns an argument vector that can directly be passed
> +// to the individual program.
> +template <typename T>
> +std::vector<T> batch_up(const RenderQueue::Program program_id,
> + const std::vector<RenderQueue::Item>& items,
> + size_t* index) {
> + std::vector<T> all_args;
> + while (*index < items.size()) {
> + const RenderQueue::Item& current_item = items.at(*index);
> + if (current_item.program_id != program_id) {
> + break;
> + }
> + all_args.emplace_back();
> + T& args = all_args.back();
> + args.destination_rect = current_item.destination_rect;
> + args.z_value = current_item.z_value;
> + args.blend_mode = current_item.blend_mode;
> + from_item(current_item, &args);
> + ++(*index);
> + }
> + return all_args;
> +}
> +
> +// Calls glScissor for the given 'rect' and enables GL_SCISSOR_TEST at
> +// creation. Disables GL_SCISSOR_TEST at desctruction again.
> +class ScopedScissor {
> +public:
> + ScopedScissor(const FloatRect& rect);
> + ~ScopedScissor();
> +
> +private:
> + DISALLOW_COPY_AND_ASSIGN(ScopedScissor);
> +};
> +
> +ScopedScissor::ScopedScissor(const FloatRect& rect) {
> + glScissor(rect.x, rect.y, rect.w, rect.h);
> + glEnable(GL_SCISSOR_TEST);
> +}
> +
> +ScopedScissor::~ScopedScissor() {
> + glDisable(GL_SCISSOR_TEST);
> +}
> +
> +} // namespace
> +
> +RenderQueue::RenderQueue()
> + : next_z_(1),
> + terrain_program_(new TerrainProgram()),
> + dither_program_(new DitherProgram()),
> + road_program_(new RoadProgram()) {
> +}
> +
> +// static
> +RenderQueue& RenderQueue::instance() {
> + static RenderQueue render_queue;
> + return render_queue;
> +}
> +
> +void RenderQueue::enqueue(const Item& given_item) {
> + Item* item;
> + uint32_t extra_value = 0;
> +
> + switch (given_item.program_id) {
> + case Program::BLIT:
> + extra_value = given_item.vanilla_blit_arguments.texture.name;
> + break;
> +
> + case Program::BLIT_MONOCHROME:
> + extra_value = given_item.monochrome_blit_arguments.texture.name;
> + break;
> +
> + case Program::BLIT_BLENDED:
> + extra_value = given_item.blended_blit_arguments.texture.name;
> + break;
> +
> + case Program::LINE:
> + extra_value = given_item.line_arguments.line_width;
> + break;
> +
> + case Program::RECT:
> + case Program::TERRAIN_BASE:
> + case Program::TERRAIN_DITHER:
> + case Program::TERRAIN_ROAD:
> + /* all fallthroughs intended */
> + break;
> +
> + default:
> + throw wexception("Unknown given_item.program_id: %d", given_item.program_id);
> + }
> +
> + if (given_item.blend_mode == BlendMode::Copy) {
> + opaque_items_.emplace_back(given_item);
> + item = &opaque_items_.back();
> + item->z_value = to_opengl_z(next_z_);
> + item->key = make_key_opaque(static_cast<uint64_t>(item->program_id), next_z_, extra_value);
> + } else {
> + blended_items_.emplace_back(given_item);
> + item = &blended_items_.back();
> + item->z_value = to_opengl_z(next_z_);
> + item->key = make_key_blended(static_cast<uint64_t>(item->program_id), next_z_, extra_value);
> + }
> + ++next_z_;
> +}
> +
> +void RenderQueue::draw(const int screen_width, const int screen_height) {
> + if (next_z_ >= kMaximumZValue) {
> + throw wexception("Too many drawn layers. Ran out of z-values.");
> + }
> +
> + glBindFramebuffer(GL_FRAMEBUFFER, 0);
> + glViewport(0, 0, screen_width, screen_height);
> +
> + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
> +
> + glDisable(GL_BLEND);
> +
> + std::sort(opaque_items_.begin(), opaque_items_.end());
> + draw_items(opaque_items_);
> + opaque_items_.clear();
> +
> + glEnable(GL_BLEND);
> + glDepthMask(GL_FALSE);
> +
> + std::sort(blended_items_.begin(), blended_items_.end());
> + draw_items(blended_items_);
> + blended_items_.clear();
> +
> + glDepthMask(GL_TRUE);
> +
> + next_z_ = 1;
> +}
> +
> +void RenderQueue::draw_items(const std::vector<Item>& items) {
> + size_t i = 0;
> + while (i < items.size()) {
> + const Item& item = items[i];
> + switch (item.program_id) {
> + case Program::BLIT:
> + VanillaBlitProgram::instance().draw(
> + batch_up<VanillaBlitProgram::Arguments>(Program::BLIT, items, &i));
> + break;
> +
> + case Program::BLIT_MONOCHROME:
> + MonochromeBlitProgram::instance().draw(
> + batch_up<MonochromeBlitProgram::Arguments>(Program::BLIT_MONOCHROME, items, &i));
> + break;
> +
> + case Program::BLIT_BLENDED:
> + BlendedBlitProgram::instance().draw(
> + batch_up<BlendedBlitProgram::Arguments>(Program::BLIT_BLENDED, items, &i));
> + break;
> +
> + case Program::LINE:
> + DrawLineProgram::instance().draw(
> + batch_up<DrawLineProgram::Arguments>(Program::LINE, items, &i));
> + break;
> +
> + case Program::RECT:
> + FillRectProgram::instance().draw(
> + batch_up<FillRectProgram::Arguments>(Program::RECT, items, &i));
> + break;
> +
> + case Program::TERRAIN_BASE: {
> + ScopedScissor scoped_scissor(item.destination_rect);
> + terrain_program_->draw(item.terrain_arguments.gametime,
> + *item.terrain_arguments.terrains,
> + *item.terrain_arguments.fields_to_draw,
> + item.z_value);
> + ++i;
> + } break;
> +
> + case Program::TERRAIN_DITHER: {
> + ScopedScissor scoped_scissor(item.destination_rect);
> + dither_program_->draw(item.terrain_arguments.gametime,
> + *item.terrain_arguments.terrains,
> + *item.terrain_arguments.fields_to_draw,
> + item.z_value + kOpenGlZDelta);
> + ++i;
> + } break;
> +
> + case Program::TERRAIN_ROAD: {
> + ScopedScissor scoped_scissor(item.destination_rect);
> + road_program_->draw(item.terrain_arguments.renderbuffer_width,
> + item.terrain_arguments.renderbuffer_height,
> + *item.terrain_arguments.fields_to_draw,
> + item.z_value + 2 * kOpenGlZDelta);
> + ++i;
> + } break;
> +
> + default:
> + throw wexception("Unknown item.program_id: %d", item.program_id);
> + }
> + }
> +}
>
> === added file 'src/graphic/render_queue.h'
> --- src/graphic/render_queue.h 1970-01-01 00:00:00 +0000
> +++ src/graphic/render_queue.h 2015-03-01 10:31:43 +0000
> @@ -0,0 +1,198 @@
> +/*
> + * Copyright (C) 2006-2014 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +#ifndef WL_GRAPHIC_RENDER_QUEUE_H
> +#define WL_GRAPHIC_RENDER_QUEUE_H
> +
> +#include <memory>
> +#include <vector>
> +
> +#include <stdint.h>
> +
> +#include "base/macros.h"
> +#include "base/rect.h"
> +#include "graphic/blend_mode.h"
> +#include "graphic/color.h"
> +#include "graphic/gl/blit_source.h"
> +#include "graphic/gl/fields_to_draw.h"
> +#include "logic/description_maintainer.h"
> +#include "logic/world/terrain_description.h"
> +
> +class DitherProgram;
> +class RoadProgram;
> +class TerrainProgram;
> +
> +// The RenderQueue is a singleton implementing the concept of deferred
> +// rendering: Every rendering call that pretends to draw onto the screen will
> +// instead enqueue an item into the RenderQueue. The Graphic::refresh() will
> +// then setup OpenGL to render onto the screen and then call
> +// RenderQueue::draw() which will execute all the draw calls.
> +//
> +// The advantage of this design is that render calls can be reordered and
> +// batched up to avoid OpenGL state changes as much as possible. This can
> +// reduce the amount of OpenGL calls done in the system per frame by an order
> +// of magnitude if assets are properly batched up into texture atlases.
> +//
> +// Rendering is simple: first everything fully opaque is rendered front to back
> +// (so that no pixel is drawn twice). This allows for maximum program batching,
> +// as for example all opaque rectangles can be rendered in one draw call,
> +// ignoring z-value.
> +//
> +// In the second step, all drawing calls with (partially) transparent pixels
> +// are done. This has to be done strictly in z ordering (back to front), so
> +// that transparency works correctly. But common operations can still be
> +// batched - for example the blitting of houses could all be done with the same
> +// z value and using a common texture atlas. Then they could be drawn in one
> +// woosh.
> +//
> +// Non overlapping rectangles can be drawn in parallel, ignoring z-order. I
> +// experimented with a linear algorithm to find all overlapping rectangle
> +// pairs (see bzr history), but it did not buy the performance I was hoping it
> +// would. So I abandoned this idea again.
> +//
> +// Note: all draw calls that target a Texture are not going to the RenderQueue,
> +// but are still immediately executed. The RenderQueue is only used for
> +// rendering onto the screen.
> +//
> +// TODO(sirver): we could (even) better performance by being z-layer aware
> +// while drawing. For example the UI could draw non-overlapping windows and
> +// sibling children with the same z-value for better batching. Also for example
> +// build-help symbols, buildings, and flags could all be drawn with the same
> +// z-layer for better batching up. This would also get rid of the z-layer
> +// issues we are having.
> +class RenderQueue {
> +public:
> + enum Program {
> + TERRAIN_BASE,
> + TERRAIN_DITHER,
> + TERRAIN_ROAD,
> + BLIT,
> + BLIT_MONOCHROME,
> + BLIT_BLENDED,
> + RECT,
> + LINE,
> + HIGHEST_PROGRAM_ID,
> + };
> +
> + struct VanillaBlitArguments {
> + BlitSource texture;
> + float opacity;
> + };
> +
> + struct MonochromeBlitArguments {
> + BlitSource texture;
> + RGBAColor blend;
> + };
> +
> + struct BlendedBlitArguments {
> + BlitSource texture;
> + BlitSource mask;
> + RGBAColor blend;
> + };
> +
> + struct RectArguments {
> + RGBAColor color;
> + };
> +
> + struct LineArguments {
> + RGBColor color;
> + uint8_t line_width;
> + };
> +
> + struct TerrainArguments {
> + TerrainArguments() {}
> +
> + int gametime;
> + int renderbuffer_width;
> + int renderbuffer_height;
> + const DescriptionMaintainer<Widelands::TerrainDescription>* terrains;
> + FieldsToDraw* fields_to_draw;
> + };
> +
> + // The union of all possible program arguments represents an Item that is
> + // enqueued in the Queue. This is on purpose not done with OOP so that the
> + // queue is more cache friendly.
> + struct Item {
> + Item() {}
> +
> + inline bool operator<(const Item& other) const {
> + return key < other.key;
> + }
> +
> + // The program that will be used to draw this item. Also defines which
> + // union type is filled in.
> + int program_id;
> +
> + // The z-value in GL space that will be used for drawing.
> + float z_value;
> +
> + // The bounding box in the renderbuffer where this draw will change pixels.
> + FloatRect destination_rect;
> +
> + // The key for sorting this item in the queue. It depends on the type of
> + // item how this is calculated, but it will contain at least the program,
> + // the z-layer, if it is opaque or transparent and program specific
> + // options. After ordering the queue by this, it defines the batching.
> + uint64_t key;
> +
> + // If this is opaque or, if not, which blend_mode to use.
> + BlendMode blend_mode;
> +
> + union {
> + VanillaBlitArguments vanilla_blit_arguments;
> + MonochromeBlitArguments monochrome_blit_arguments;
> + BlendedBlitArguments blended_blit_arguments;
> + TerrainArguments terrain_arguments;
> + RectArguments rect_arguments;
> + LineArguments line_arguments;
> + };
> + };
> +
> + static RenderQueue& instance();
> +
> + // Enqueues 'item' in the queue with a higher 'z' value than the last enqueued item.
> + void enqueue(const Item& item);
> +
> + // Draws all items in the queue in an optimal ordering and as much batching
> + // as possible. This will draw one complete frame onto the screen and this
> + // function is the only one that actually triggers draws to the screen
> + // directly.
> + void draw(int screen_width, int screen_height);
> +
> +private:
> + RenderQueue();
> +
> + void draw_items(const std::vector<Item>& items);
> +
> + // The z value that should be used for the next draw, so that it is on top
> + // of everything before.
> + int next_z_;
> +
> + std::unique_ptr<TerrainProgram> terrain_program_;
> + std::unique_ptr<DitherProgram> dither_program_;
> + std::unique_ptr<RoadProgram> road_program_;
> +
> + std::vector<Item> blended_items_;
> + std::vector<Item> opaque_items_;
> +
> + DISALLOW_COPY_AND_ASSIGN(RenderQueue);
> +};
> +
> +
> +#endif // end of include guard: WL_GRAPHIC_RENDER_QUEUE_H
>
> === modified file 'src/graphic/rendertarget.cc'
> --- src/graphic/rendertarget.cc 2014-12-07 20:13:27 +0000
> +++ src/graphic/rendertarget.cc 2015-03-01 10:31:43 +0000
> @@ -97,7 +97,7 @@
> *prevofs = m_offset;
>
> // Apply the changes
> - m_offset = rc.top_left() - (newrect.top_left() - m_rect.top_left() - m_offset);
> + m_offset = rc.origin() - (newrect.origin() - m_rect.origin() - m_offset);
> m_rect = newrect;
>
> return true;
> @@ -123,17 +123,14 @@
> /**
> * This functions draws a line in the target
> */
> -void RenderTarget::draw_line
> - (int32_t x1, int32_t y1, int32_t x2, int32_t y2,
> - const RGBColor& color, uint8_t gwidth)
> -{
> - ::draw_line(x1 + m_offset.x + m_rect.x,
> - y1 + m_offset.y + m_rect.y,
> - x2 + m_offset.x + m_rect.x,
> - y2 + m_offset.y + m_rect.y,
> - color,
> - gwidth,
> - m_surface);
> +void RenderTarget::draw_line(const Point& start,
> + const Point& end,
> + const RGBColor& color,
> + uint8_t line_width) {
> + m_surface->draw_line(Point(start.x + m_offset.x + m_rect.x, start.y + m_offset.y + m_rect.y),
> + Point(end.x + m_offset.x + m_rect.x, end.y + m_offset.y + m_rect.y),
> + color,
> + line_width);
> }
>
> /**
> @@ -151,14 +148,14 @@
> {
> Rect r(rect);
> if (clip(r))
> - ::fill_rect(r, clr, m_surface);
> + m_surface->fill_rect(r, clr);
> }
>
> void RenderTarget::brighten_rect(const Rect& rect, int32_t factor)
> {
> Rect r(rect);
> if (clip(r))
> - ::brighten_rect(r, factor, m_surface);
> + m_surface->brighten_rect(r, factor);
> }
>
> /**
> @@ -175,12 +172,11 @@
> Rect srcrc(Point(0, 0), image->width(), image->height());
>
> if (to_surface_geometry(&destination_point, &srcrc)) {
> - ::blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
> - *image,
> - srcrc,
> - 1.,
> - blend_mode,
> - m_surface);
> + m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
> + *image,
> + srcrc,
> + 1.,
> + blend_mode);
> }
> }
>
> @@ -202,12 +198,11 @@
>
> Point destination_point(dst);
> if (to_surface_geometry(&destination_point, &srcrc))
> - ::blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
> - *image,
> - srcrc,
> - 1.,
> - blend_mode,
> - m_surface);
> + m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
> + *image,
> + srcrc,
> + 1.,
> + blend_mode);
> }
>
> void RenderTarget::blitrect_scale(const Rect& dst,
> @@ -219,12 +214,11 @@
> Point destination_point(dst.x, dst.y);
> Rect srcrect(source_rect);
> if (to_surface_geometry(&destination_point, &srcrect)) {
> - ::blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),
> - *image,
> - source_rect,
> - opacity,
> - blend_mode,
> - m_surface);
> + m_surface->blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),
> + *image,
> + source_rect,
> + opacity,
> + blend_mode);
> }
> }
>
> @@ -235,12 +229,11 @@
> Point destination_point(destination_rect.x, destination_rect.y);
> Rect srcrect(source_rect);
> if (to_surface_geometry(&destination_point, &srcrect)) {
> - blit_monochrome(
> + m_surface->blit_monochrome(
> Rect(destination_point.x, destination_point.y, destination_rect.w, destination_rect.h),
> *image,
> source_rect,
> - blend,
> - m_surface);
> + blend);
> }
> }
>
> @@ -297,7 +290,7 @@
> srcrc.w = r.w - tx;
>
> const Rect dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
> - ::blit(dst_rect, *image, srcrc, 1., blend_mode, m_surface);
> + m_surface->blit(dst_rect, *image, srcrc, 1., blend_mode);
>
> tx += srcrc.w;
>
> @@ -350,7 +343,7 @@
> const Animation& anim = g_gr->animations().get_animation(animation);
>
> Point destination_point = dst - anim.hotspot();
> - destination_point += gsrcrc.top_left();
> + destination_point += gsrcrc.origin();
>
> Rect srcrc(gsrcrc);
>
> @@ -455,6 +448,6 @@
> srcrc->h = m_rect.h - dst->y;
> }
>
> - *dst += m_rect.top_left();
> + *dst += m_rect.origin();
> return true;
> }
>
> === modified file 'src/graphic/rendertarget.h'
> --- src/graphic/rendertarget.h 2014-12-06 15:32:50 +0000
> +++ src/graphic/rendertarget.h 2015-03-01 10:31:43 +0000
> @@ -60,8 +60,7 @@
> int32_t width() const;
> int32_t height() const;
>
> - void draw_line
> - (int32_t x1, int32_t y1, int32_t x2, int32_t y2, const RGBColor& color, uint8_t width = 1);
> + void draw_line(const Point& start, const Point& end, const RGBColor& color, uint8_t width = 1);
> void draw_rect(const Rect&, const RGBColor&);
> void fill_rect(const Rect&, const RGBAColor&);
> void brighten_rect(const Rect&, int32_t factor);
>
> === modified file 'src/graphic/richtext.cc'
> --- src/graphic/richtext.cc 2014-12-06 12:22:35 +0000
> +++ src/graphic/richtext.cc 2015-03-01 10:31:43 +0000
> @@ -482,7 +482,7 @@
> {
> Rect oldbox;
> Point oldofs;
> - Rect bbox((*elt)->bbox.top_left() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
> + Rect bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
>
> if (dst.enter_window(bbox, &oldbox, &oldofs)) {
> if (background)
>
> === modified file 'src/graphic/screen.cc'
> --- src/graphic/screen.cc 2014-12-27 09:59:12 +0000
> +++ src/graphic/screen.cc 2015-03-01 10:31:43 +0000
> @@ -24,20 +24,12 @@
>
> #include "base/wexception.h"
> #include "graphic/gl/utils.h"
> +#include "graphic/render_queue.h"
> #include "graphic/texture.h"
>
> Screen::Screen(int w, int h) : m_w(w), m_h(h) {
> }
>
> -void Screen::pixel_to_gl(float* x, float* y) const {
> - *x = (*x / m_w) * 2. - 1.;
> - *y = 1. - (*y / m_h) * 2.;
> -}
> -
> -void Screen::setup_gl() {
> - glBindFramebuffer(GL_FRAMEBUFFER, 0);
> -}
> -
> int Screen::width() const {
> return m_w;
> }
> @@ -50,17 +42,7 @@
> std::unique_ptr<uint8_t[]> pixels(new uint8_t[m_w * m_h * 4]);
> glReadPixels(0, 0, m_w, m_h, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
>
> - // Swap order of rows in m_pixels, to compensate for the upside-down nature of the
> - // OpenGL coordinate system.
> - uint8_t* begin_row = pixels.get();
> - uint8_t* end_row = pixels.get() + (m_w * (m_h - 1) * 4);
> - while (begin_row < end_row) {
> - for (int x = 0; x < m_w * 4; ++x) {
> - std::swap(begin_row[x], end_row[x]);
> - }
> - begin_row += m_w * 4;
> - end_row -= m_w * 4;
> - }
> + Gl::swap_rows(m_w, m_h, m_w * 4, 4, pixels.get());
>
> // Ownership of pixels is not taken here. But the Texture() transfers it to
> // the GPU, frees the SDL surface and after that we are free to free
> @@ -77,3 +59,64 @@
>
> return std::unique_ptr<Texture>(new Texture(surface));
> }
> +
> +void Screen::do_blit(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + float opacity,
> + BlendMode blend_mode) {
> + RenderQueue::Item i;
> + i.program_id = RenderQueue::Program::BLIT;
> + i.blend_mode = blend_mode;
> + i.destination_rect = dst_rect;
> + i.vanilla_blit_arguments.texture = texture;
> + i.vanilla_blit_arguments.opacity = opacity;
> + RenderQueue::instance().enqueue(i);
> +}
> +
> +void Screen::do_blit_blended(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBColor& blend) {
> + RenderQueue::Item i;
> + i.destination_rect = dst_rect;
> + i.program_id = RenderQueue::Program::BLIT_BLENDED;
> + i.blend_mode = BlendMode::UseAlpha;
> + i.blended_blit_arguments.texture = texture;
> + i.blended_blit_arguments.mask = mask;
> + i.blended_blit_arguments.blend = blend;
> + RenderQueue::instance().enqueue(i);
> +}
> +
> +void Screen::do_blit_monochrome(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const RGBAColor& blend) {
> + RenderQueue::Item i;
> + i.program_id = RenderQueue::Program::BLIT_MONOCHROME;
> + i.blend_mode = BlendMode::UseAlpha;
> + i.destination_rect = dst_rect;
> + i.monochrome_blit_arguments.texture = texture;
> + i.monochrome_blit_arguments.blend = blend;
> + RenderQueue::instance().enqueue(i);
> +}
> +
> +void Screen::do_draw_line(const FloatPoint& start,
> + const FloatPoint& end,
> + const RGBColor& color,
> + const int line_width) {
> + RenderQueue::Item i;
> + i.program_id = RenderQueue::Program::LINE;
> + i.blend_mode = BlendMode::Copy;
> + i.destination_rect = FloatRect(start.x, start.y, end.x - start.x, end.y - start.y);
> + i.line_arguments.color = color;
> + i.line_arguments.line_width = line_width;
> + RenderQueue::instance().enqueue(i);
> +}
> +
> +void Screen::do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
> + RenderQueue::Item i;
> + i.program_id = RenderQueue::Program::RECT;
> + i.blend_mode = blend_mode;
> + i.destination_rect = dst_rect;
> + i.rect_arguments.color = color;
> + RenderQueue::instance().enqueue(i);
> +}
>
> === modified file 'src/graphic/screen.h'
> --- src/graphic/screen.h 2014-12-07 21:34:11 +0000
> +++ src/graphic/screen.h 2015-03-01 10:31:43 +0000
> @@ -35,8 +35,6 @@
> // Implements Surface.
> int width() const override;
> int height() const override;
> - void setup_gl() override;
> - void pixel_to_gl(float* x, float* y) const override;
>
> // Reads out the current pixels in the framebuffer and returns
> // them as a texture for screenshots. This is a very slow process,
> @@ -44,6 +42,24 @@
> std::unique_ptr<Texture> to_texture() const;
>
> private:
> + void do_blit(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + float opacity,
> + BlendMode blend_mode) override;
> + void do_blit_blended(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBColor& blend) override;
> + void do_blit_monochrome(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const RGBAColor& blend) override;
> + void do_draw_line(const FloatPoint& start,
> + const FloatPoint& end,
> + const RGBColor& color,
> + int width) override;
> + void
> + do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
> +
> const int m_w, m_h;
>
> DISALLOW_COPY_AND_ASSIGN(Screen);
>
> === modified file 'src/graphic/surface.cc'
> --- src/graphic/surface.cc 2015-01-15 07:14:53 +0000
> +++ src/graphic/surface.cc 2015-03-01 10:31:43 +0000
> @@ -26,197 +26,100 @@
> #include <SDL.h>
>
> #include "base/macros.h"
> -#include "graphic/gl/blit_program.h"
> -#include "graphic/gl/draw_line_program.h"
> -#include "graphic/gl/fill_rect_program.h"
> +#include "graphic/gl/coordinate_conversion.h"
> #include "graphic/gl/utils.h"
> -#include "graphic/graphic.h"
> -#include "graphic/texture.h"
> -
>
> namespace {
>
> -// Convert the 'rect' in pixel space into opengl space.
> -enum class ConversionMode {
> - // Convert the rect as given.
> - kExact,
> -
> - // Convert the rect so that the borders are in the center
> - // of the pixels.
> - kMidPoint,
> -};
> -
> -FloatRect to_opengl(const Surface& surface, const Rect& rect, ConversionMode mode) {
> - const float delta = mode == ConversionMode::kExact ? 0. : 0.5;
> - float x1 = rect.x + delta;
> - float y1 = rect.y + delta;
> - surface.pixel_to_gl(&x1, &y1);
> - float x2 = rect.x + rect.w - delta;
> - float y2 = rect.y + rect.h - delta;
> - surface.pixel_to_gl(&x2, &y2);
> - return FloatRect(x1, y1, x2 - x1, y2 - y1);
> -}
> -
> -// Converts the pixel (x, y) in a texture to a gl coordinate in [0, 1].
> -inline void pixel_to_gl_texture(const int width, const int height, float* x, float* y) {
> - *x = (*x / width);
> - *y = (*y / height);
> -}
> -
> -// Convert 'dst' and 'srcrc' from pixel space into opengl space, taking into
> -// account that we might be a subtexture in a bigger texture.
> -void src_and_dst_rect_to_gl(const Surface& surface,
> - const Image& image,
> - const Rect& dst_rect,
> - const Rect& src_rect,
> - FloatRect* gl_dst_rect,
> - FloatRect* gl_src_rect) {
> +// Convert 'srcrc' from pixel space into opengl space, taking into account that
> +// it might be a subtexture in a bigger texture.
> +BlitSource to_blit_source(const Image& image, const Rect& src_rect) {
> // Source Rectangle. We have to take into account that the texture might be
> // a subtexture in another bigger texture. So we first figure out the pixel
> // coordinates given it is a full texture (values between 0 and 1) and then
> // adjust these for the texture coordinates in the parent texture.
> +
> + const FloatRect rc(src_rect.x, src_rect.y, src_rect.w, src_rect.h);
> + const FloatRect in_texture = rect_to_gl_texture(image.width(), image.height(), rc);
> const FloatRect& texture_coordinates = image.texture_coordinates();
> -
> - float x1 = src_rect.x;
> - float y1 = src_rect.y;
> - pixel_to_gl_texture(image.width(), image.height(), &x1, &y1);
> - x1 = texture_coordinates.x + x1 * texture_coordinates.w;
> - y1 = texture_coordinates.y + y1 * texture_coordinates.h;
> -
> - float x2 = src_rect.x + src_rect.w;
> - float y2 = src_rect.y + src_rect.h;
> - pixel_to_gl_texture(image.width(), image.height(), &x2, &y2);
> - x2 = texture_coordinates.x + x2 * texture_coordinates.w;
> - y2 = texture_coordinates.y + y2 * texture_coordinates.h;
> -
> - gl_src_rect->x = x1;
> - gl_src_rect->y = y1;
> - gl_src_rect->w = x2 - x1;
> - gl_src_rect->h = y2 - y1;
> -
> - *gl_dst_rect = to_opengl(surface, dst_rect, ConversionMode::kExact);
> + const float left = texture_coordinates.x + in_texture.x * texture_coordinates.w;
> + const float bottom = texture_coordinates.y + in_texture.y * texture_coordinates.h;
> + const float right = texture_coordinates.x + (in_texture.x + in_texture.w) * texture_coordinates.w;
> + const float top = texture_coordinates.y + (in_texture.y + in_texture.h) * texture_coordinates.h;
> +
> + return BlitSource{
> + FloatRect(left, bottom, right - left, top - bottom), image.get_gl_texture(),
> + };
> }
>
> } // namespace
>
> -
> -void fill_rect(const Rect& rc, const RGBAColor& clr, Surface* surface) {
> - surface->setup_gl();
> - glViewport(0, 0, surface->width(), surface->height());
> -
> - glBlendFunc(GL_ONE, GL_ZERO);
> -
> - FillRectProgram::instance().draw(to_opengl(*surface, rc, ConversionMode::kExact), clr);
> -
> - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> -}
> -
> -void brighten_rect(const Rect& rc, const int32_t factor, Surface * surface)
> +void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
> + surface->draw_line(Point(rc.x, rc.y), Point(rc.x + rc.w, rc.y), clr, 1);
> + surface->draw_line(Point(rc.x + rc.w, rc.y), Point(rc.x + rc.w, rc.y + rc.h), clr, 1);
> + surface->draw_line(Point(rc.x + rc.w, rc.y + rc.h), Point(rc.x, rc.y + rc.h), clr, 1);
> + surface->draw_line(Point(rc.x, rc.y + rc.h), Point(rc.x, rc.y), clr, 1);
> +}
> +
> +void Surface::fill_rect(const Rect& rc, const RGBAColor& clr) {
> + const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
> + do_fill_rect(rect, clr, BlendMode::Copy);
> +}
> +
> +void Surface::brighten_rect(const Rect& rc, const int32_t factor)
> {
> - if (!factor)
> + if (!factor) {
> return;
> -
> - surface->setup_gl();
> - glViewport(0, 0, surface->width(), surface->height());
> -
> - // The simple trick here is to fill the rect, but using a different glBlendFunc that will sum
> - // src and target (or subtract them if factor is negative).
> - if (factor < 0) {
> - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
> - }
> -
> - glBlendFunc(GL_ONE, GL_ONE);
> -
> - const int delta = std::abs(factor);
> - FillRectProgram::instance().draw(
> - to_opengl(*surface, rc, ConversionMode::kExact), RGBAColor(delta, delta, delta, 0));
> -
> - if (factor < 0) {
> - glBlendEquation(GL_FUNC_ADD);
> - }
> -
> - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> + }
> +
> + const BlendMode blend_mode = factor < 0 ? BlendMode::Subtract : BlendMode::UseAlpha;
> + const int abs_factor = std::abs(factor);
> + const RGBAColor color(abs_factor, abs_factor, abs_factor, 0);
> + const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
> + do_fill_rect(rect, color, blend_mode);
> }
>
> -void draw_line
> - (int x1, int y1, int x2, int y2, const RGBColor& color, int gwidth, Surface * surface)
> +void Surface::draw_line
> + (const Point& start, const Point& end, const RGBColor& color, int line_width)
> {
> - surface->setup_gl();
> - glViewport(0, 0, surface->width(), surface->height());
> -
> - float gl_x1 = x1 + 0.5;
> - float gl_y1 = y1 + 0.5;
> - surface->pixel_to_gl(&gl_x1, &gl_y1);
> -
> - float gl_x2 = x2 + 0.5;
> - float gl_y2 = y2 + 0.5;
> - surface->pixel_to_gl(&gl_x2, &gl_y2);
> -
> - DrawLineProgram::instance().draw(gl_x1, gl_y1, gl_x2, gl_y2, color, gwidth);
> -}
> -
> -void blit_monochrome(const Rect& dst_rect,
> - const Image& image,
> - const Rect& src_rect,
> - const RGBAColor& blend,
> - Surface* surface) {
> - surface->setup_gl();
> - glViewport(0, 0, surface->width(), surface->height());
> -
> - FloatRect gl_dst_rect, gl_src_rect;
> - src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
> -
> - MonochromeBlitProgram::instance().draw(
> - gl_dst_rect, gl_src_rect, image.get_gl_texture(), blend);
> -
> - // TODO(sirver): This is a hacky attempt to fix 1409267. It
> - // should not stick around.
> - glBindFramebuffer(GL_FRAMEBUFFER, 0);
> -}
> -
> -void blit_blended(const Rect& dst_rect,
> - const Image& image,
> - const Image& mask,
> - const Rect& src_rect,
> - const RGBColor& blend,
> - Surface* surface) {
> - surface->setup_gl();
> - glViewport(0, 0, surface->width(), surface->height());
> -
> - FloatRect gl_dst_rect, gl_src_rect;
> - src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
> -
> - BlendedBlitProgram::instance().draw(
> - gl_dst_rect, gl_src_rect, image.get_gl_texture(), mask.get_gl_texture(), blend);
> -
> - // TODO(sirver): This is a hacky attempt to fix 1409267. It
> - // should not stick around.
> - glBindFramebuffer(GL_FRAMEBUFFER, 0);
> -}
> -
> -void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
> - draw_line(rc.x, rc.y, rc.x + rc.w, rc.y, clr, 1, surface);
> - draw_line(rc.x + rc.w, rc.y, rc.x + rc.w, rc.y + rc.h, clr, 1, surface);
> - draw_line(rc.x + rc.w, rc.y + rc.h, rc.x, rc.y + rc.h, clr, 1, surface);
> - draw_line(rc.x, rc.y + rc.h, rc.x, rc.y, clr, 1, surface);
> -}
> -
> -void blit(const Rect& dst_rect,
> - const Image& image,
> - const Rect& src_rect,
> - float opacity,
> - BlendMode blend_mode,
> - Surface* surface) {
> - glViewport(0, 0, surface->width(), surface->height());
> - surface->setup_gl();
> -
> - FloatRect gl_dst_rect, gl_src_rect;
> - src_and_dst_rect_to_gl(*surface, image, dst_rect, src_rect, &gl_dst_rect, &gl_src_rect);
> -
> - VanillaBlitProgram::instance().draw(
> - gl_dst_rect, gl_src_rect, image.get_gl_texture(), opacity, blend_mode);
> -
> - // TODO(sirver): This is a hacky attempt to fix 1409267. It
> - // should not stick around.
> - glBindFramebuffer(GL_FRAMEBUFFER, 0);
> + float gl_x1 = start.x;
> + float gl_y1 = start.y;
> +
> + // Include the end pixel.
> + float gl_x2 = end.x + 1.;
> + float gl_y2 = end.y + 1.;
> + pixel_to_gl_renderbuffer(width(), height(), &gl_x1, &gl_y1);
> + pixel_to_gl_renderbuffer(width(), height(), &gl_x2, &gl_y2);
> +
> + do_draw_line(FloatPoint(gl_x1, gl_y1), FloatPoint(gl_x2, gl_y2), color, line_width);
> +}
> +
> +void Surface::blit_monochrome(const Rect& dst_rect,
> + const Image& image,
> + const Rect& src_rect,
> + const RGBAColor& blend) {
> + const BlitSource texture = to_blit_source(image, src_rect);
> + const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
> + do_blit_monochrome(rect, texture, blend);
> +}
> +
> +void Surface::blit_blended(const Rect& dst_rect,
> + const Image& image,
> + const Image& texture_mask,
> + const Rect& src_rect,
> + const RGBColor& blend) {
> + const BlitSource texture = to_blit_source(image, src_rect);
> + const BlitSource mask = to_blit_source(texture_mask, src_rect);
> + const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
> + do_blit_blended(rect, texture, mask, blend);
> +}
> +
> +void Surface::blit(const Rect& dst_rect,
> + const Image& image,
> + const Rect& src_rect,
> + float opacity,
> + BlendMode blend_mode) {
> + const BlitSource texture = to_blit_source(image, src_rect);
> + const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
> + do_blit(rect, texture, opacity, blend_mode);
> }
>
> === modified file 'src/graphic/surface.h'
> --- src/graphic/surface.h 2014-12-07 21:34:11 +0000
> +++ src/graphic/surface.h 2015-03-01 10:31:43 +0000
> @@ -26,6 +26,7 @@
> #include "base/rect.h"
> #include "graphic/blend_mode.h"
> #include "graphic/color.h"
> +#include "graphic/gl/blit_source.h"
> #include "graphic/image.h"
>
> class Texture;
> @@ -41,47 +42,60 @@
> virtual int width() const = 0;
> virtual int height() const = 0;
>
> - // Converts the given pixel into an OpenGl point. This might
> - // need some flipping of axis, depending if you want to render
> - // on the screen or not.
> - virtual void pixel_to_gl(float* x, float* y) const = 0;
> -
> - // Setups OpenGL to render to this surface.
> - virtual void setup_gl() = 0;
> + /// This draws a part of 'texture'.
> + void blit(const Rect& dst,
> + const Image&,
> + const Rect& srcrc,
> + const float opacity,
> + BlendMode blend_mode);
> +
> + /// This draws a playercolor blended image. See BlendedBlitProgram.
> + void blit_blended(const Rect& dst,
> + const Image& image,
> + const Image& texture_mask,
> + const Rect& srcrc,
> + const RGBColor& blend);
> +
> + /// This draws a grayed out version. See MonochromeBlitProgram.
> + void
> + blit_monochrome(const Rect& dst, const Image&, const Rect& srcrc, const RGBAColor& multiplier);
> +
> + /// Draws a filled rect to the destination. No blending takes place, the values
> + // in the target are just replaced (i.e. / BlendMode would be BlendMode::Copy).
> + void fill_rect(const Rect&, const RGBAColor&);
> +
> + /// draw a line to the destination
> + void draw_line(const Point& start, const Point& end, const RGBColor& color, int width);
> +
> + /// makes a rectangle on the destination brighter (or darker).
> + void brighten_rect(const Rect&, int factor);
>
> private:
> + /// The actual implementation of the methods below.
> + virtual void do_blit(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + float opacity,
> + BlendMode blend_mode) = 0;
> +
> + virtual void do_blit_blended(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBColor& blend) = 0;
> +
> + virtual void do_blit_monochrome(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const RGBAColor& blend) = 0;
> +
> + virtual void
> + do_draw_line(const FloatPoint& start, const FloatPoint& end, const RGBColor& color, int width) = 0;
> +
> + virtual void
> + do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
> +
> DISALLOW_COPY_AND_ASSIGN(Surface);
> };
>
> /// Draws a rect (frame only) to the surface.
> void draw_rect(const Rect&, const RGBColor&, Surface* destination);
>
> -/// This draws a part of 'texture' to 'surface'.
> -void blit
> - (const Rect& dst, const Image&, const Rect& srcrc, const float opacity,
> - BlendMode blend_mode, Surface* destination);
> -
> -/// This draws a grayed out version. See MonochromeBlitProgram.
> -void
> -blit_monochrome
> - (const Rect& dst, const Image&, const Rect& srcrc,
> - const RGBAColor& multiplier, Surface* destination);
> -
> -/// This draws a playercolor blended image. See BlendedBlitProgram.
> -void blit_blended
> - (const Rect& dst, const Image& image, const Image& mask, const Rect&
> - srcrc, const RGBColor& blend, Surface* destination);
> -
> -/// Draws a filled rect to the destination. No blending takes place, the values
> -// in the target are just replaced (i.e. / BlendMode would be BlendMode::Copy).
> -void fill_rect(const Rect&, const RGBAColor&, Surface* destination);
> -
> -/// draw a line to the destination
> -void draw_line
> - (int x1, int y1, int x2, int y2, const RGBColor& color,
> - int width, Surface* destination);
> -
> -/// makes a rectangle on the destination brighter (or darker).
> -void brighten_rect(const Rect&, int factor, Surface* destination);
> -
> #endif // end of include guard: WL_GRAPHIC_SURFACE_H
>
> === modified file 'src/graphic/text/rt_render.cc'
> --- src/graphic/text/rt_render.cc 2014-12-27 09:59:12 +0000
> +++ src/graphic/text/rt_render.cc 2015-03-01 10:31:43 +0000
> @@ -332,15 +332,15 @@
> uint16_t TextNode::hotspot_y() {
> return m_font.ascent(m_s.font_style);
> }
> +
> Texture* TextNode::render(TextureCache* texture_cache) {
> const Texture& img = m_font.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
> Texture* rv = new Texture(img.width(), img.height());
> - blit(Rect(0, 0, img.width(), img.height()),
> - img,
> - Rect(0, 0, img.width(), img.height()),
> - 1.,
> - BlendMode::Copy,
> - rv);
> + rv->blit(Rect(0, 0, img.width(), img.height()),
> + img,
> + Rect(0, 0, img.width(), img.height()),
> + 1.,
> + BlendMode::Copy);
> return rv;
> }
>
> @@ -368,7 +368,7 @@
> Texture* rv = new Texture(m_w, m_h);
> for (uint16_t curx = 0; curx < m_w; curx += t.width()) {
> Rect srcrect(Point(0, 0), min<int>(t.width(), m_w - curx), m_h);
> - blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy, rv);
> + rv->blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
> }
> return rv;
> }
> @@ -385,7 +385,7 @@
> Texture* render(TextureCache* texture_cache) override {
> if (m_show_spaces) {
> Texture* rv = new Texture(m_w, m_h);
> - fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(0xff, 0, 0, 0xff), rv);
> + rv->fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(0xff, 0, 0, 0xff));
> return rv;
> }
> return TextNode::render(texture_cache);
> @@ -437,10 +437,10 @@
> dst.y = 0;
> srcrect.w = dst.w = min<int>(m_bg->width(), m_w - curx);
> srcrect.h = dst.h = m_h;
> - blit(dst, *m_bg, srcrect, 1., BlendMode::Copy, rv);
> + rv->blit(dst, *m_bg, srcrect, 1., BlendMode::Copy);
> }
> } else {
> - fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(255, 255, 255, 0), rv);
> + rv->fill_rect(Rect(0, 0, m_w, m_h), RGBAColor(255, 255, 255, 0));
> }
> return rv;
> }
> @@ -477,12 +477,12 @@
> uint16_t hotspot_y() override {return height();}
> Texture* render(TextureCache* texture_cache) override {
> Texture* rv = new Texture(width(), height());
> - fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0), rv);
> + rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
>
> // Draw Solid background Color
> bool set_alpha = true;
> if (m_bg_clr_set) {
> - fill_rect(Rect(Point(m_margin.left, m_margin.top), m_w, m_h), m_bg_clr, rv);
> + rv->fill_rect(Rect(Point(m_margin.left, m_margin.top), m_w, m_h), m_bg_clr);
> set_alpha = false;
> }
>
> @@ -497,7 +497,7 @@
> dst.y = cury;
> src.w = dst.w = min<int>(m_bg_img->width(), m_w + m_margin.left - curx);
> src.h = dst.h = min<int>(m_bg_img->height(), m_h + m_margin.top - cury);
> - blit(dst, *m_bg_img, src, 1., BlendMode::Copy, rv);
> + rv->blit(dst, *m_bg_img, src, 1., BlendMode::Copy);
> }
> }
> set_alpha = false;
> @@ -512,7 +512,7 @@
> node_texture->height());
> Rect src = Rect(0, 0, node_texture->width(), node_texture->height());
>
> - blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha, rv);
> + rv->blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha);
> delete node_texture;
> }
> delete n;
> @@ -563,11 +563,11 @@
>
> Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {
> Texture* rv = new Texture(m_image.width(), m_image.height());
> - blit(Rect(0, 0, m_image.width(), m_image.height()),
> + rv->blit(Rect(0, 0, m_image.width(), m_image.height()),
> m_image,
> Rect(0, 0, m_image.width(), m_image.height()),
> 1.,
> - BlendMode::Copy, rv);
> + BlendMode::Copy);
> return rv;
> }
> // End: Helper Stuff
>
> === modified file 'src/graphic/texture.cc'
> --- src/graphic/texture.cc 2014-12-27 09:59:12 +0000
> +++ src/graphic/texture.cc 2015-03-01 10:31:43 +0000
> @@ -20,10 +20,15 @@
>
> #include <cassert>
>
> +#include <SDL.h>
> +
> #include "base/log.h"
> #include "base/macros.h"
> #include "base/wexception.h"
> #include "graphic/gl/blit_program.h"
> +#include "graphic/gl/coordinate_conversion.h"
> +#include "graphic/gl/draw_line_program.h"
> +#include "graphic/gl/fill_rect_program.h"
> #include "graphic/gl/utils.h"
> #include "graphic/graphic.h"
> #include "graphic/sdl_utils.h"
> @@ -31,6 +36,36 @@
>
> namespace {
>
> +namespace {
> +
> +/**
> + * \return the standard 32-bit RGBA format that we use for our textures.
> + */
> +const SDL_PixelFormat & rgba_format()
> +{
> + static SDL_PixelFormat format;
> + static bool init = false;
> + if (init)
> + return format;
> +
> + init = true;
> + memset(&format, 0, sizeof(format));
> + format.BitsPerPixel = 32;
> + format.BytesPerPixel = 4;
> + format.Rmask = 0x000000ff;
> + format.Gmask = 0x0000ff00;
> + format.Bmask = 0x00ff0000;
> + format.Amask = 0xff000000;
> + format.Rshift = 0;
> + format.Gshift = 8;
> + format.Bshift = 16;
> + format.Ashift = 24;
> + return format;
> +}
> +
> +} // namespace
> +
> +
> class GlFramebuffer {
> public:
> static GlFramebuffer& instance() {
> @@ -105,6 +140,8 @@
>
> SDL_LockSurface(surface);
>
> + Gl::swap_rows(m_w, m_h, surface->pitch, bpp, static_cast<uint8_t*>(surface->pixels));
> +
> glTexImage2D
> (GL_TEXTURE_2D, 0, static_cast<GLint>(intensity ? GL_INTENSITY : GL_RGBA), m_w, m_h, 0,
> pixels_format, GL_UNSIGNED_BYTE, surface->pixels);
> @@ -124,10 +161,8 @@
> m_texture = texture;
> m_owns_texture = false;
>
> - m_texture_coordinates.w = static_cast<float>(m_w - 1) / parent_w;
> - m_texture_coordinates.h = static_cast<float>(m_h - 1) / parent_h;
> - m_texture_coordinates.x = (static_cast<float>(subrect.x) + 0.5) / parent_w;
> - m_texture_coordinates.y = (static_cast<float>(subrect.y) + 0.5) / parent_h;
> + m_texture_coordinates =
> + rect_to_gl_texture(parent_w, parent_h, FloatRect(subrect.x, subrect.y, subrect.w, subrect.h));
> }
>
> Texture::~Texture()
> @@ -153,11 +188,6 @@
> return m_texture_coordinates;
> }
>
> -void Texture::pixel_to_gl(float* x, float* y) const {
> - *x = (*x / m_w) * 2. - 1.;
> - *y = (*y / m_h) * 2. - 1.;
> -}
> -
> void Texture::init(uint16_t w, uint16_t h)
> {
> m_w = w;
> @@ -218,40 +248,71 @@
> m_pixels.reset(nullptr);
> }
>
> -uint8_t * Texture::get_pixels() const
> -{
> - return m_pixels.get();
> -}
> -
> -uint32_t Texture::get_pixel(uint16_t x, uint16_t y) {
> - assert(m_pixels);
> - assert(x < m_w);
> - assert(y < m_h);
> -
> - uint8_t * data = &m_pixels[y * get_pitch() + 4 * x];
> - return *(reinterpret_cast<uint32_t *>(data));
> -}
> -
> -uint16_t Texture::get_pitch() const {
> - return 4 * m_w;
> -}
> -
> -const SDL_PixelFormat & Texture::format() const {
> - return Gl::gl_rgba_format();
> -}
> -
> -
> -void Texture::set_pixel(uint16_t x, uint16_t y, uint32_t clr) {
> - assert(m_pixels);
> - assert(x < m_w);
> - assert(y < m_h);
> -
> - uint8_t * data = &m_pixels[y * get_pitch() + 4 * x];
> - *(reinterpret_cast<uint32_t *>(data)) = clr;
> +RGBAColor Texture::get_pixel(uint16_t x, uint16_t y) {
> + assert(m_pixels);
> + assert(x < m_w);
> + assert(y < m_h);
> +
> + RGBAColor color;
> +
> + SDL_GetRGBA(*reinterpret_cast<uint32_t*>(&m_pixels[(m_h - y - 1) * 4 * m_w + 4 * x]),
> + &rgba_format(),
> + &color.r,
> + &color.g,
> + &color.b,
> + &color.a);
> + return color;
> +}
> +
> +void Texture::set_pixel(uint16_t x, uint16_t y, const RGBAColor& color) {
> + assert(m_pixels);
> + assert(x < m_w);
> + assert(y < m_h);
> +
> + uint8_t* data = &m_pixels[(m_h - y - 1) * 4 * m_w + 4 * x];
> + uint32_t packed_color = SDL_MapRGBA(&rgba_format(), color.r, color.g, color.b, color.a);
> + *(reinterpret_cast<uint32_t *>(data)) = packed_color;
> }
>
>
> void Texture::setup_gl() {
> glBindFramebuffer(GL_FRAMEBUFFER, GlFramebuffer::instance().id());
> glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
> + glViewport(0, 0, m_w, m_h);
> +}
> +
> +void Texture::do_blit(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + float opacity,
> + BlendMode blend_mode) {
> + setup_gl();
> + VanillaBlitProgram::instance().draw(dst_rect, 0.f, texture, opacity, blend_mode);
> +}
> +
> +void Texture::do_blit_blended(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBColor& blend) {
> +
> + setup_gl();
> + BlendedBlitProgram::instance().draw(dst_rect, 0.f, texture, mask, blend);
> +}
> +
> +void Texture::do_blit_monochrome(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const RGBAColor& blend) {
> + setup_gl();
> + MonochromeBlitProgram::instance().draw(dst_rect, 0.f, texture, blend);
> +}
> +
> +void
> +Texture::do_draw_line(const FloatPoint& start, const FloatPoint& end, const RGBColor& color, int width) {
> + setup_gl();
> + DrawLineProgram::instance().draw(start, end, 0.f, color, width);
> +}
> +
> +void
> +Texture::do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
> + setup_gl();
> + FillRectProgram::instance().draw(dst_rect, 0.f, color, blend_mode);
> }
>
> === modified file 'src/graphic/texture.h'
> --- src/graphic/texture.h 2014-12-07 21:34:11 +0000
> +++ src/graphic/texture.h 2015-03-01 10:31:43 +0000
> @@ -46,8 +46,6 @@
> // Implements Surface
> int width() const override;
> int height() const override;
> - void setup_gl() override;
> - void pixel_to_gl(float* x, float* y) const override;
>
> // Implements Image.
> int get_gl_texture() const override;
> @@ -69,30 +67,39 @@
> Unlock_NoChange
> };
>
> - /// This returns the pixel format for direct pixel access.
> - const SDL_PixelFormat & format() const;
> -
> - // Number of bytes per row.
> - uint16_t get_pitch() const;
> -
> - // Pointer to the raw pixel data. May only be called inside lock/unlock
> - // pairs.
> - uint8_t * get_pixels() const;
> -
> // Lock/Unlock pairs must guard any of the direct pixel access using the
> // functions below. Lock/Unlock pairs cannot be nested.
> void lock();
> void unlock(UnlockMode);
>
> - // Returns the color of the pixel as a value as defined by 'format()'.
> - uint32_t get_pixel(uint16_t x, uint16_t y);
> + // Returns the color of the pixel.
> + RGBAColor get_pixel(uint16_t x, uint16_t y);
>
> // Sets the pixel to the 'clr'.
> - void set_pixel(uint16_t x, uint16_t y, uint32_t clr);
> + void set_pixel(uint16_t x, uint16_t y, const RGBAColor& color);
>
> private:
> + // Configures OpenGL to draw to this surface.
> + void setup_gl();
> void init(uint16_t w, uint16_t h);
>
> + // Implements surface.
> + void do_blit(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + float opacity,
> + BlendMode blend_mode) override;
> + void do_blit_blended(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const BlitSource& mask,
> + const RGBColor& blend) override;
> + void do_blit_monochrome(const FloatRect& dst_rect,
> + const BlitSource& texture,
> + const RGBAColor& blend) override;
> + void
> + do_draw_line(const FloatPoint& start, const FloatPoint& end, const RGBColor& color, int width) override;
> + void
> + do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
> +
> // Width and height.
> int m_w, m_h;
>
>
> === modified file 'src/graphic/texture_atlas.cc'
> --- src/graphic/texture_atlas.cc 2015-03-01 09:21:20 +0000
> +++ src/graphic/texture_atlas.cc 2015-03-01 10:31:43 +0000
> @@ -46,7 +46,7 @@
> {
> }
>
> -void TextureAtlas::add(const Texture& texture) {
> +void TextureAtlas::add(const Image& texture) {
> blocks_.emplace_back(next_index_++, &texture);
> }
>
> @@ -133,7 +133,7 @@
> }
>
> std::unique_ptr<Texture> packed_texture(new Texture(root->r.w, root->r.h));
> - fill_rect(Rect(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0), packed_texture.get());
> + packed_texture->fill_rect(Rect(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
>
> // Sort blocks by index so that they come back in the correct ordering.
> std::sort(blocks_.begin(), blocks_.end(), [](const Block& i, const Block& j) {
> @@ -141,16 +141,16 @@
> });
>
> for (Block& block : blocks_) {
> - blit(Rect(block.node->r.x, block.node->r.y, block.texture->width(), block.texture->height()),
> - *block.texture,
> - Rect(0, 0, block.texture->width(), block.texture->height()),
> - 1.,
> - BlendMode::UseAlpha,
> - packed_texture.get());
> + packed_texture->blit(
> + Rect(block.node->r.x, block.node->r.y, block.texture->width(), block.texture->height()),
> + *block.texture,
> + Rect(0, 0, block.texture->width(), block.texture->height()),
> + 1.,
> + BlendMode::UseAlpha);
>
> textures->emplace_back(new Texture(
> packed_texture->get_gl_texture(),
> - Rect(block.node->r.top_left(), block.texture->width(), block.texture->height()),
> + Rect(block.node->r.origin(), block.texture->width(), block.texture->height()),
> root->r.w,
> root->r.h));
> }
>
> === modified file 'src/graphic/texture_atlas.h'
> --- src/graphic/texture_atlas.h 2015-03-01 09:21:20 +0000
> +++ src/graphic/texture_atlas.h 2015-03-01 10:31:43 +0000
> @@ -35,7 +35,7 @@
> // Add 'texture' as one of the textures to be packed. Ownership is
> // not taken, but 'texture' must be valid until pack() has been
> // called.
> - void add(const Texture& texture);
> + void add(const Image& texture);
>
> // Packs the textures and returns the packed texture. 'textures'
> // contains the individual sub textures (that do not own their
> @@ -56,12 +56,12 @@
> };
>
> struct Block {
> - Block(int init_index, const Texture* init_texture)
> + Block(int init_index, const Image* init_texture)
> : index(init_index), texture(init_texture) {
> }
>
> int index;
> - const Texture* texture;
> + const Image* texture;
> Node* node;
> };
>
>
> === modified file 'src/logic/CMakeLists.txt'
> --- src/logic/CMakeLists.txt 2015-02-09 05:57:08 +0000
> +++ src/logic/CMakeLists.txt 2015-03-01 10:31:43 +0000
> @@ -26,6 +26,9 @@
> single_player_game_settings_provider.cc
> single_player_game_settings_provider.h
> DEPENDS
> + io_filesystem
> + scripting_lua_interface
> + scripting_lua_table
> logic
> ai
> )
>
> === modified file 'src/logic/ship.cc'
> --- src/logic/ship.cc 2015-02-05 12:11:20 +0000
> +++ src/logic/ship.cc 2015-03-01 10:31:43 +0000
> @@ -648,12 +648,11 @@
> Worker* worker;
> m_items.at(i).get(game, &ware, &worker);
> if (ware) {
> - // no, we don't transfer the wares, we create new ones out of air and remove the old
> - // ones ;)
> - WaresQueue& wq = cs->waresqueue(ware->descr_index());
> - const uint32_t max = wq.get_max_fill();
> + // no, we don't transfer the wares, we create new ones out of
> + // air and remove the old ones ;)
> + WaresQueue & wq = cs->waresqueue(ware->descr_index());
> const uint32_t cur = wq.get_filled();
> - assert(max > cur);
> + assert(wq.get_max_fill() > cur);
> wq.set_filled(cur + 1);
> m_items.at(i).remove(game);
> m_items.resize(i);
>
> === modified file 'src/logic/soldier.cc'
> --- src/logic/soldier.cc 2014-12-08 11:08:38 +0000
> +++ src/logic/soldier.cc 2015-03-01 10:31:43 +0000
> @@ -632,7 +632,7 @@
> uint32_t health_width = 2 * (w - 1) * m_hp_current / get_max_hitpoints();
> Rect energy_inner(Point(pt.x - w + 1, pt.y + 1), health_width, 3);
> Rect energy_complement
> - (energy_inner.top_left() + Point(health_width, 0), 2 * (w - 1) - health_width, 3);
> + (energy_inner.origin() + Point(health_width, 0), 2 * (w - 1) - health_width, 3);
> const RGBColor & color = owner().get_playercolor();
> RGBColor complement_color;
>
>
> === modified file 'src/ui_basic/panel.cc'
> --- src/ui_basic/panel.cc 2014-12-06 12:22:35 +0000
> +++ src/ui_basic/panel.cc 2015-03-01 10:31:43 +0000
> @@ -1201,7 +1201,7 @@
> Rect r
> (WLApplication::get()->get_mouse_position() + Point(2, 32),
> tip_width, tip_height);
> - const Point tooltip_bottom_right = r.bottom_right();
> + const Point tooltip_bottom_right = r.opposite_of_origin();
> const Point screen_bottom_right(g_gr->get_xres(), g_gr->get_yres());
> if (screen_bottom_right.x < tooltip_bottom_right.x)
> r.x -= 4 + r.w;
> @@ -1210,7 +1210,7 @@
>
> dst.fill_rect(r, RGBColor(63, 52, 34));
> dst.draw_rect(r, RGBColor(0, 0, 0));
> - dst.blit(r.top_left() + Point(2, 2), rendered_text);
> + dst.blit(r.origin() + Point(2, 2), rendered_text);
> return true;
> }
>
>
> === modified file 'src/ui_basic/scrollbar.cc'
> --- src/ui_basic/scrollbar.cc 2014-11-22 10:18:20 +0000
> +++ src/ui_basic/scrollbar.cc 2015-03-01 10:31:43 +0000
> @@ -258,7 +258,7 @@
> uint16_t cpw = pic->width();
> uint16_t cph = pic->height();
>
> - dst.blit(r.top_left() + Point((r.w - cpw) / 2, (r.h - cph) / 2), pic);
> + dst.blit(r.origin() + Point((r.w - cpw) / 2, (r.h - cph) / 2), pic);
> }
>
> // Draw border
> @@ -266,35 +266,35 @@
>
> if (area != m_pressed) {
> // top edge
> - dst.brighten_rect(Rect(r.top_left(), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
> + dst.brighten_rect(Rect(r.origin(), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
> // left edge
> dst.brighten_rect
> - (Rect(r.top_left() + Point(0, 2), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
> + (Rect(r.origin() + Point(0, 2), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
> // bottom edge
> - dst.fill_rect(Rect(r.top_left() + Point(2, r.h - 2), r.w - 2, 1), black);
> - dst.fill_rect(Rect(r.top_left() + Point(1, r.h - 1), r.w - 1, 1), black);
> + dst.fill_rect(Rect(r.origin() + Point(2, r.h - 2), r.w - 2, 1), black);
> + dst.fill_rect(Rect(r.origin() + Point(1, r.h - 1), r.w - 1, 1), black);
> // right edge
> - dst.fill_rect(Rect(r.top_left() + Point(r.w - 2, 2), 1, r.h - 2), black);
> - dst.fill_rect(Rect(r.top_left() + Point(r.w - 1, 1), 1, r.h - 1), black);
> + dst.fill_rect(Rect(r.origin() + Point(r.w - 2, 2), 1, r.h - 2), black);
> + dst.fill_rect(Rect(r.origin() + Point(r.w - 1, 1), 1, r.h - 1), black);
> } else {
> // bottom edge
> dst.brighten_rect
> - (Rect(r.top_left() + Point(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
> + (Rect(r.origin() + Point(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
> // right edge
> dst.brighten_rect
> - (Rect(r.top_left() + Point(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
> + (Rect(r.origin() + Point(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
> // top edge
> - dst.fill_rect(Rect(r.top_left(), r.w - 1, 1), black);
> - dst.fill_rect(Rect(r.top_left() + Point(0, 1), r.w - 2, 1), black);
> + dst.fill_rect(Rect(r.origin(), r.w - 1, 1), black);
> + dst.fill_rect(Rect(r.origin() + Point(0, 1), r.w - 2, 1), black);
> // left edge
> - dst.fill_rect(Rect(r.top_left(), 1, r.h - 1), black);
> - dst.fill_rect(Rect(r.top_left() + Point(1, 0), 1, r.h - 2), black);
> + dst.fill_rect(Rect(r.origin(), 1, r.h - 1), black);
> + dst.fill_rect(Rect(r.origin() + Point(1, 0), 1, r.h - 2), black);
> }
> }
>
>
> void Scrollbar::draw_area(RenderTarget & dst, const Area area, const Rect r) {
> - dst.tile(r, m_pic_background, Point(get_x(), get_y()) + r.top_left());
> + dst.tile(r, m_pic_background, Point(get_x(), get_y()) + r.origin());
>
> if (area == m_pressed)
> dst.brighten_rect(r, BUTTON_EDGE_BRIGHT_FACTOR);
>
> === modified file 'src/wui/interactive_base.cc'
> --- src/wui/interactive_base.cc 2015-02-09 05:57:08 +0000
> +++ src/wui/interactive_base.cc 2015-03-01 10:31:43 +0000
> @@ -902,10 +902,8 @@
> return true;
> #ifndef NDEBUG // only in debug builds
> case SDLK_F6:
> - if (get_display_flag(dfDebug)) {
> - GameChatMenu::create_script_console(
> - this, m_debugconsole, *DebugConsole::get_chat_provider());
> - }
> + GameChatMenu::create_script_console(
> + this, m_debugconsole, *DebugConsole::get_chat_provider());
> return true;
> #endif
> default:
>
> === modified file 'src/wui/interactive_gamebase.h'
> --- src/wui/interactive_gamebase.h 2015-02-16 12:42:35 +0000
> +++ src/wui/interactive_gamebase.h 2015-03-01 10:31:43 +0000
> @@ -83,7 +83,8 @@
>
> void show_game_summary();
> void postload() override;
> - void start() override {};
> + void start() override {}
> +
> protected:
> void draw_overlay(RenderTarget &) override;
> virtual int32_t calculate_buildcaps(const Widelands::TCoords<Widelands::FCoords> c) = 0;
>
> === modified file 'src/wui/minimap.cc'
> --- src/wui/minimap.cc 2014-12-07 20:52:55 +0000
> +++ src/wui/minimap.cc 2015-03-01 10:31:43 +0000
> @@ -62,14 +62,14 @@
>
> void MiniMap::View::draw(RenderTarget & dst)
> {
> - std::unique_ptr<Texture> texture(
> + minimap_image_ =
> draw_minimap(m_ibase.egbase(),
> m_ibase.get_player(),
> (*m_flags) & (MiniMapLayer::Zoom2) ?
> Point((m_viewx - get_w() / 4), (m_viewy - get_h() / 4)) :
> Point((m_viewx - get_w() / 2), (m_viewy - get_h() / 2)),
> - *m_flags | MiniMapLayer::ViewWindow));
> - dst.blit(Point(), texture.get());
> + *m_flags | MiniMapLayer::ViewWindow);
> + dst.blit(Point(), minimap_image_.get());
> }
>
>
>
> === modified file 'src/wui/minimap.h'
> --- src/wui/minimap.h 2014-09-27 18:53:55 +0000
> +++ src/wui/minimap.h 2015-03-01 10:31:43 +0000
> @@ -20,6 +20,8 @@
> #ifndef WL_WUI_MINIMAP_H
> #define WL_WUI_MINIMAP_H
>
> +#include <memory>
> +
> #include <boost/signals2.hpp>
>
> #include "graphic/minimap_renderer.h"
> @@ -76,13 +78,17 @@
>
> void set_zoom(int32_t z);
>
> -
> private:
> InteractiveBase & m_ibase;
> int32_t m_viewx, m_viewy;
> const Image* m_pic_map_spot;
> +
> + // This needs to be owned since it will be rendered by the RenderQueue
> + // later, so it must be valid for the whole frame.
> + std::unique_ptr<Texture> minimap_image_;
> +
> public:
> - MiniMapLayer * m_flags;
> + MiniMapLayer* m_flags;
> };
>
> uint32_t number_of_buttons_per_row() const;
>
> === modified file 'src/wui/plot_area.cc'
> --- src/wui/plot_area.cc 2014-12-11 12:38:10 +0000
> +++ src/wui/plot_area.cc 2015-03-01 10:31:43 +0000
> @@ -185,35 +185,34 @@
>
> // Draw coordinate system
> // X Axis
> - dst.draw_line
> - (spacing, inner_h - space_at_bottom,
> - inner_w - space_at_right, inner_h - space_at_bottom,
> - LINE_COLOR, 2);
> + dst.draw_line(Point(spacing, inner_h - space_at_bottom),
> + Point(inner_w - space_at_right, inner_h - space_at_bottom),
> + LINE_COLOR,
> + 2);
> // Arrow
> - dst.draw_line
> - (spacing, inner_h - space_at_bottom,
> - spacing + 5, inner_h - space_at_bottom - 3,
> - LINE_COLOR, 2);
> - dst.draw_line
> - (spacing, inner_h - space_at_bottom,
> - spacing + 5, inner_h - space_at_bottom + 3,
> - LINE_COLOR, 2);
> + dst.draw_line(Point(spacing, inner_h - space_at_bottom),
> + Point(spacing + 5, inner_h - space_at_bottom - 3),
> + LINE_COLOR,
> + 2);
> + dst.draw_line(Point(spacing, inner_h - space_at_bottom),
> + Point(spacing + 5, inner_h - space_at_bottom + 3),
> + LINE_COLOR,
> + 2);
> // Y Axis
> - dst.draw_line
> - (inner_w - space_at_right, spacing,
> - inner_w - space_at_right,
> - inner_h - space_at_bottom,
> - LINE_COLOR, 2);
> + dst.draw_line(Point(inner_w - space_at_right, spacing),
> + Point(inner_w - space_at_right, inner_h - space_at_bottom),
> + LINE_COLOR,
> + 2);
> // No Arrow here, since this doesn't continue.
>
> float sub = (xline_length - space_left_of_label) / how_many_ticks;
> float posx = inner_w - space_at_right;
>
> for (uint32_t i = 0; i <= how_many_ticks; ++i) {
> - dst.draw_line
> - (static_cast<int32_t>(posx), inner_h - space_at_bottom,
> - static_cast<int32_t>(posx), inner_h - space_at_bottom + 3,
> - LINE_COLOR, 2);
> + dst.draw_line(Point(static_cast<int32_t>(posx), inner_h - space_at_bottom),
> + Point(static_cast<int32_t>(posx), inner_h - space_at_bottom + 3),
> + LINE_COLOR,
> + 2);
>
> // The space at the end is intentional to have the tick centered
> // over the number, not to the left
> @@ -227,16 +226,15 @@
> }
>
> // draw yticks, one at full, one at half
> - dst.draw_line
> - (inner_w - space_at_right, spacing,
> - inner_w - space_at_right -3, spacing,
> - LINE_COLOR, 2);
> - dst.draw_line
> - (inner_w - space_at_right,
> - spacing + ((inner_h - space_at_bottom) - spacing) / 2,
> - inner_w - space_at_right - 3,
> - spacing + ((inner_h - space_at_bottom) - spacing) / 2,
> - LINE_COLOR, 2);
> + dst.draw_line(Point(inner_w - space_at_right, spacing),
> + Point(inner_w - space_at_right - 3, spacing),
> + LINE_COLOR,
> + 2);
> + dst.draw_line(
> + Point(inner_w - space_at_right, spacing + ((inner_h - space_at_bottom) - spacing) / 2),
> + Point(inner_w - space_at_right - 3, spacing + ((inner_h - space_at_bottom) - spacing) / 2),
> + LINE_COLOR,
> + 2);
>
> // print the used unit
> const Image* xtick = UI::g_fh1->render(xtick_text_style(get_unit_name(unit)));
> @@ -435,7 +433,7 @@
> cury -= static_cast<int32_t>(length_y);
> }
>
> - dst.draw_line(lx, ly, curx, cury, color, 2);
> + dst.draw_line(Point(lx, ly), Point(curx, cury), color, 2);
>
> posx -= sub;
>
> @@ -514,12 +512,10 @@
> draw_diagram(time_ms, get_inner_w(), get_inner_h(), xline_length, dst);
>
> // draw zero line
> - dst.draw_line
> - (get_inner_w() - space_at_right,
> - yoffset,
> - get_inner_w() - space_at_right - xline_length,
> - yoffset,
> - ZERO_LINE_COLOR, 2);
> + dst.draw_line(Point(get_inner_w() - space_at_right, yoffset),
> + Point(get_inner_w() - space_at_right - xline_length, yoffset),
> + ZERO_LINE_COLOR,
> + 2);
>
> // How many do we take together when relative ploting
> const int32_t how_many = calc_how_many(time_ms, m_sample_rate);
>
> === modified file 'src/wui/soldierlist.cc'
> --- src/wui/soldierlist.cc 2014-12-06 12:22:35 +0000
> +++ src/wui/soldierlist.cc 2015-03-01 10:31:43 +0000
> @@ -495,8 +495,10 @@
> }
>
> void SoldierList::set_soldier_preference(int32_t changed_to) {
> +#ifndef NDEBUG
> upcast(Widelands::MilitarySite, ms, &m_building);
> assert(ms);
> +#endif
> m_igb.game().send_player_militarysite_set_soldier_preference
> (m_building, changed_to == 0 ?
> Widelands::MilitarySite::kPrefersRookies:
>
--
https://code.launchpad.net/~widelands-dev/widelands/render_queue/+merge/250524
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/render_queue.
References