Benedikt Straub has proposed merging lp:~widelands-dev/widelands/editor-grid into lp:widelands with lp:~nordfriese/widelands/workareas as a prerequisite.
Commit message: Add a grid overlay to the editor, which can be toggled with a button or the hotkey 'G' Requested reviews: Widelands Developers (widelands-dev) Related bugs: Bug #1529261 in widelands: "Create an overlay which shows a grid" https://bugs.launchpad.net/widelands/+bug/1529261 For more details, see: https://code.launchpad.net/~widelands-dev/widelands/editor-grid/+merge/366482 -- Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/editor-grid into lp:widelands.
=== renamed file 'data/images/wui/overlays/workarea123.png' => 'data/images/wui/buildings/toggle_workarea.png' === added file 'data/images/wui/menus/menu_toggle_grid.png' Binary files data/images/wui/menus/menu_toggle_grid.png 1970-01-01 00:00:00 +0000 and data/images/wui/menus/menu_toggle_grid.png 2019-04-24 17:17:26 +0000 differ === added file 'data/images/wui/overlays/grid_marker.png' Binary files data/images/wui/overlays/grid_marker.png 1970-01-01 00:00:00 +0000 and data/images/wui/overlays/grid_marker.png 2019-04-24 17:17:26 +0000 differ === removed file 'data/images/wui/overlays/workarea1.png' Binary files data/images/wui/overlays/workarea1.png 2019-03-30 06:46:25 +0000 and data/images/wui/overlays/workarea1.png 1970-01-01 00:00:00 +0000 differ === removed file 'data/images/wui/overlays/workarea12.png' Binary files data/images/wui/overlays/workarea12.png 2019-03-30 06:46:25 +0000 and data/images/wui/overlays/workarea12.png 1970-01-01 00:00:00 +0000 differ === removed file 'data/images/wui/overlays/workarea2.png' Binary files data/images/wui/overlays/workarea2.png 2019-03-30 06:46:25 +0000 and data/images/wui/overlays/workarea2.png 1970-01-01 00:00:00 +0000 differ === removed file 'data/images/wui/overlays/workarea23.png' Binary files data/images/wui/overlays/workarea23.png 2019-03-30 06:46:25 +0000 and data/images/wui/overlays/workarea23.png 1970-01-01 00:00:00 +0000 differ === removed file 'data/images/wui/overlays/workarea3.png' Binary files data/images/wui/overlays/workarea3.png 2014-12-03 20:13:06 +0000 and data/images/wui/overlays/workarea3.png 1970-01-01 00:00:00 +0000 differ === added file 'data/shaders/grid.fp' --- data/shaders/grid.fp 1970-01-01 00:00:00 +0000 +++ data/shaders/grid.fp 2019-04-24 17:17:26 +0000 @@ -0,0 +1,5 @@ +#version 120 + +void main() { + gl_FragColor = vec4(.0, .0, .0, .8); +} === added file 'data/shaders/grid.vp' --- data/shaders/grid.vp 1970-01-01 00:00:00 +0000 +++ data/shaders/grid.vp 2019-04-24 17:17:26 +0000 @@ -0,0 +1,10 @@ +#version 120 + +// Attributes. +attribute vec2 attr_position; + +uniform float u_z_value; + +void main() { + gl_Position = vec4(attr_position, u_z_value, 1.); +} === added file 'data/shaders/workarea.fp' --- data/shaders/workarea.fp 1970-01-01 00:00:00 +0000 +++ data/shaders/workarea.fp 2019-04-24 17:17:26 +0000 @@ -0,0 +1,7 @@ +#version 120 + +varying vec4 var_overlay; + +void main() { + gl_FragColor = var_overlay; +} === added file 'data/shaders/workarea.vp' --- data/shaders/workarea.vp 1970-01-01 00:00:00 +0000 +++ data/shaders/workarea.vp 2019-04-24 17:17:26 +0000 @@ -0,0 +1,15 @@ +#version 120 + +// Attributes. +attribute vec2 attr_position; +attribute vec4 attr_overlay; + +uniform float u_z_value; + +// Output of vertex shader. +varying vec4 var_overlay; + +void main() { + var_overlay = attr_overlay; + gl_Position = vec4(attr_position, u_z_value, 1.); +} === modified file 'src/editor/editorinteractive.cc' --- src/editor/editorinteractive.cc 2019-04-24 07:09:29 +0000 +++ src/editor/editorinteractive.cc 2019-04-24 17:17:26 +0000 @@ -98,6 +98,10 @@ toggle_buildhelp_ = add_toolbar_button( "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show building spaces (on/off)")); toggle_buildhelp_->sigclicked.connect(boost::bind(&EditorInteractive::toggle_buildhelp, this)); + toggle_grid_ = + add_toolbar_button("wui/menus/menu_toggle_grid", "grid", _("Show grid (on/off)")); + toggle_grid_->set_perm_pressed(true); + toggle_grid_->sigclicked.connect([this]() { toggle_grid(); }); toggle_immovables_ = add_toolbar_button( "wui/menus/menu_toggle_immovables", "immovables", _("Show immovables (on/off)")); toggle_immovables_->set_perm_pressed(true); @@ -262,7 +266,7 @@ void EditorInteractive::draw(RenderTarget& dst) { const auto& ebase = egbase(); - auto* fields_to_draw = map_view()->draw_terrain(ebase, &dst); + auto* fields_to_draw = map_view()->draw_terrain(ebase, Workareas(), draw_grid_, &dst); const float scale = 1.f / map_view()->view().zoom; const uint32_t gametime = ebase.get_gametime(); @@ -430,6 +434,11 @@ toggle_bobs_->set_perm_pressed(draw_bobs_); } +void EditorInteractive::toggle_grid() { + draw_grid_ = !draw_grid_; + toggle_grid_->set_perm_pressed(draw_grid_); +} + bool EditorInteractive::handle_key(bool const down, SDL_Keysym const code) { if (down) { switch (code.sym) { @@ -504,6 +513,10 @@ toggle_buildhelp(); return true; + case SDLK_g: + toggle_grid(); + return true; + case SDLK_c: set_display_flag( InteractiveBase::dfShowCensus, !get_display_flag(InteractiveBase::dfShowCensus)); === modified file 'src/editor/editorinteractive.h' --- src/editor/editorinteractive.h 2019-04-24 07:09:29 +0000 +++ src/editor/editorinteractive.h 2019-04-24 17:17:26 +0000 @@ -149,6 +149,7 @@ void toggle_resources(); void toggle_immovables(); void toggle_bobs(); + void toggle_grid(); // state variables bool need_save_; @@ -170,6 +171,7 @@ UI::UniqueWindow::Registry helpmenu_; UI::Button* toggle_buildhelp_; + UI::Button* toggle_grid_; UI::Button* toggle_resources_; UI::Button* toggle_immovables_; UI::Button* toggle_bobs_; @@ -182,6 +184,7 @@ bool draw_resources_ = true; bool draw_immovables_ = true; bool draw_bobs_ = true; + bool draw_grid_ = true; }; #endif // end of include guard: WL_EDITOR_EDITORINTERACTIVE_H === modified file 'src/graphic/CMakeLists.txt' --- src/graphic/CMakeLists.txt 2019-04-08 13:32:28 +0000 +++ src/graphic/CMakeLists.txt 2019-04-24 17:17:26 +0000 @@ -225,12 +225,16 @@ wl_library(graphic_terrain_programs SRCS + gl/grid_program.cc + gl/grid_program.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 + gl/workarea_program.cc + gl/workarea_program.h DEPENDS base_exceptions base_geometry === modified file 'src/graphic/game_renderer.cc' --- src/graphic/game_renderer.cc 2019-04-24 06:01:37 +0000 +++ src/graphic/game_renderer.cc 2019-04-24 17:17:26 +0000 @@ -60,6 +60,8 @@ void draw_terrain(const Widelands::EditorGameBase& egbase, const FieldsToDraw& fields_to_draw, const float scale, + Workareas workarea, + bool grid, RenderTarget* dst) { const Recti& bounding_rect = dst->get_rect(); const Surface& surface = dst->get_surface(); @@ -86,6 +88,20 @@ i.blend_mode = BlendMode::UseAlpha; RenderQueue::instance().enqueue(i); + if (!workarea.empty()) { + // Enqueue the drawing of the workarea overlay layer. + i.program_id = RenderQueue::Program::kTerrainWorkarea; + i.terrain_arguments.workareas = workarea; + RenderQueue::instance().enqueue(i); + } + + if (grid) { + // Enqueue the drawing of the grid layer. + i.program_id = RenderQueue::Program::kTerrainGrid; + i.blend_mode = BlendMode::UseAlpha; + RenderQueue::instance().enqueue(i); + } + // Enqueue the drawing of the road layer. i.program_id = RenderQueue::Program::kTerrainRoad; RenderQueue::instance().enqueue(i); === modified file 'src/graphic/game_renderer.h' --- src/graphic/game_renderer.h 2019-02-23 11:00:49 +0000 +++ src/graphic/game_renderer.h 2019-04-24 17:17:26 +0000 @@ -33,6 +33,8 @@ void draw_terrain(const Widelands::EditorGameBase& egbase, const FieldsToDraw& fields_to_draw, const float scale, + Workareas workarea, + bool grid, RenderTarget* dst); // Draw the border stones for 'field' if it is a border and 'visibility' is === added file 'src/graphic/gl/grid_program.cc' --- src/graphic/gl/grid_program.cc 1970-01-01 00:00:00 +0000 +++ src/graphic/gl/grid_program.cc 2019-04-24 17:17:26 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2006-2019 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/gl/grid_program.h" + +#include "graphic/gl/coordinate_conversion.h" +#include "graphic/gl/fields_to_draw.h" +#include "graphic/gl/utils.h" +#include "graphic/texture.h" + +GridProgram::GridProgram() { + gl_program_.build("grid"); + + attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position"); + + u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value"); +} + +void GridProgram::gl_draw(int gl_texture, float z_value) { + glUseProgram(gl_program_.object()); + + auto& gl_state = Gl::State::instance(); + + gl_array_buffer_.bind(); + gl_array_buffer_.update(vertices_); + + Gl::vertex_attrib_pointer( + attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x)); + + gl_state.bind(GL_TEXTURE0, gl_texture); + + glUniform1f(u_z_value_, z_value); + + glDrawArrays(GL_LINES, 0, vertices_.size()); +} + +void GridProgram::add_vertex(const FieldsToDraw::Field& field) { + vertices_.emplace_back(); + PerVertexData& back = vertices_.back(); + back.gl_x = field.gl_position.x; + back.gl_y = field.gl_position.y; +} + +void GridProgram::draw(uint32_t texture_id, + const FieldsToDraw& fields_to_draw, + float z_value) { + vertices_.clear(); + vertices_.reserve(fields_to_draw.size() * 2); + + for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) { + const FieldsToDraw::Field& field = fields_to_draw.at(current_index); + + // Southwestern edge + if (field.bln_index != FieldsToDraw::kInvalidIndex) { + add_vertex(fields_to_draw.at(current_index)); + add_vertex(fields_to_draw.at(field.bln_index)); + } + + // Southeastern edge + if (field.brn_index != FieldsToDraw::kInvalidIndex) { + add_vertex(fields_to_draw.at(current_index)); + add_vertex(fields_to_draw.at(field.brn_index)); + } + + // Eastern edge + if (field.rn_index != FieldsToDraw::kInvalidIndex) { + add_vertex(fields_to_draw.at(current_index)); + add_vertex(fields_to_draw.at(field.rn_index)); + } + } + + gl_draw(texture_id, z_value); +} === added file 'src/graphic/gl/grid_program.h' --- src/graphic/gl/grid_program.h 1970-01-01 00:00:00 +0000 +++ src/graphic/gl/grid_program.h 2019-04-24 17:17:26 +0000 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006-2019 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_GRID_PROGRAM_H +#define WL_GRAPHIC_GL_GRID_PROGRAM_H + +#include <vector> + +#include "base/vector.h" +#include "graphic/gl/fields_to_draw.h" +#include "graphic/gl/utils.h" +#include "logic/description_maintainer.h" +#include "logic/map_objects/world/terrain_description.h" + +class GridProgram { +public: + // Compiles the program. Throws on errors. + GridProgram(); + + // Draws the grid layer + void draw(uint32_t texture_id, + const FieldsToDraw& fields_to_draw, + float z_value); + +private: + struct PerVertexData { + float gl_x; + float gl_y; + }; + static_assert(sizeof(PerVertexData) == 8, "Wrong padding."); + + void gl_draw(int gl_texture, float z_value); + + // Adds a vertex to the end of vertices with data from 'field'. + void add_vertex(const FieldsToDraw::Field& field); + + // The program used for drawing the grid layer + Gl::Program gl_program_; + + // The buffer that will contain 'vertices_' for rendering. + Gl::Buffer<PerVertexData> gl_array_buffer_; + + // Attributes. + GLint attr_position_; + + // Uniforms. + GLint u_z_value_; + + // Objects below are kept around to avoid memory allocations on each frame. + // They could theoretically also be recreated. + std::vector<PerVertexData> vertices_; + + DISALLOW_COPY_AND_ASSIGN(GridProgram); +}; + +#endif // end of include guard: WL_GRAPHIC_GL_GRID_PROGRAM_H === added file 'src/graphic/gl/workarea_program.cc' --- src/graphic/gl/workarea_program.cc 1970-01-01 00:00:00 +0000 +++ src/graphic/gl/workarea_program.cc 2019-04-24 17:17:26 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2006-2019 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/gl/workarea_program.h" + +#include "graphic/gl/coordinate_conversion.h" +#include "graphic/gl/fields_to_draw.h" +#include "graphic/gl/utils.h" +#include "graphic/texture.h" + +WorkareaProgram::WorkareaProgram() { + gl_program_.build("workarea"); + + attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position"); + attr_overlay_ = glGetAttribLocation(gl_program_.object(), "attr_overlay"); + + u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value"); +} + +void WorkareaProgram::gl_draw(int gl_texture, float z_value) { + glUseProgram(gl_program_.object()); + + auto& gl_state = Gl::State::instance(); + gl_state.enable_vertex_attrib_array( + {attr_position_, attr_overlay_}); + + gl_array_buffer_.bind(); + gl_array_buffer_.update(vertices_); + + Gl::vertex_attrib_pointer( + attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x)); + Gl::vertex_attrib_pointer( + attr_overlay_, 4, sizeof(PerVertexData), offsetof(PerVertexData, overlay_r)); + + gl_state.bind(GL_TEXTURE0, gl_texture); + + glUniform1f(u_z_value_, z_value); + + glDrawArrays(GL_TRIANGLES, 0, vertices_.size()); +} + +constexpr uint8_t kWorkareaTransparency = 127; +static RGBAColor workarea_colors[] { + RGBAColor(63, 31, 127, kWorkareaTransparency), // All three circles + RGBAColor(127, 63, 0, kWorkareaTransparency), // Medium and outer circle + RGBAColor(0, 127, 0, kWorkareaTransparency), // Outer circle + RGBAColor(63, 0, 127, kWorkareaTransparency), // Inner and medium circle + RGBAColor(127, 0, 0, kWorkareaTransparency), // Medium circle + RGBAColor(0, 0, 127, kWorkareaTransparency), // Inner circle +}; +static inline RGBAColor apply_color(RGBAColor c1, RGBAColor c2) { + uint8_t r = (c1.r * c1.a + c2.r * c2.a) / (c1.a + c2.a); + uint8_t g = (c1.g * c1.a + c2.g * c2.a) / (c1.a + c2.a); + uint8_t b = (c1.b * c1.a + c2.b * c2.a) / (c1.a + c2.a); + uint8_t a = (c1.a + c2.a) / 2; + return RGBAColor(r, g, b, a); +} + +void WorkareaProgram::add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay) { + vertices_.emplace_back(); + PerVertexData& back = vertices_.back(); + + back.gl_x = field.gl_position.x; + back.gl_y = field.gl_position.y; + back.overlay_r = overlay.r / 255.f; + back.overlay_g = overlay.g / 255.f; + back.overlay_b = overlay.b / 255.f; + back.overlay_a = overlay.a / 255.f; +} + +void WorkareaProgram::draw(uint32_t texture_id, + Workareas workarea, + const FieldsToDraw& fields_to_draw, + float z_value) { + vertices_.clear(); + vertices_.reserve(fields_to_draw.size() * 3); + + for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) { + const FieldsToDraw::Field& field = fields_to_draw.at(current_index); + + // The bottom right neighbor fields_to_draw is needed for both triangles + // associated with this field. If it is not in fields_to_draw, there is no need to + // draw any triangles. + if (field.brn_index == FieldsToDraw::kInvalidIndex) { + continue; + } + + // Down triangle. + if (field.bln_index != FieldsToDraw::kInvalidIndex) { + RGBAColor color(0, 0, 0, 0); + for (const std::map<Widelands::TCoords<>, uint8_t>& wa_map : workarea) { + const auto it = wa_map.find(Widelands::TCoords<>(field.fcoords, Widelands::TriangleIndex::D)); + if (it != wa_map.end()) { + color = apply_color(color, workarea_colors[it->second]); + } + } + add_vertex(fields_to_draw.at(current_index), color); + add_vertex(fields_to_draw.at(field.bln_index), color); + add_vertex(fields_to_draw.at(field.brn_index), color); + } + + // Right triangle. + if (field.rn_index != FieldsToDraw::kInvalidIndex) { + RGBAColor color(0, 0, 0, 0); + for (const std::map<Widelands::TCoords<>, uint8_t>& wa_map : workarea) { + const auto it = wa_map.find(Widelands::TCoords<>(field.fcoords, Widelands::TriangleIndex::R)); + if (it != wa_map.end()) { + color = apply_color(color, workarea_colors[it->second]); + } + } + add_vertex(fields_to_draw.at(current_index), color); + add_vertex(fields_to_draw.at(field.brn_index), color); + add_vertex(fields_to_draw.at(field.rn_index), color); + } + } + + gl_draw(texture_id, z_value); +} === added file 'src/graphic/gl/workarea_program.h' --- src/graphic/gl/workarea_program.h 1970-01-01 00:00:00 +0000 +++ src/graphic/gl/workarea_program.h 2019-04-24 17:17:26 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006-2019 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_WORKAREA_PROGRAM_H +#define WL_GRAPHIC_GL_WORKAREA_PROGRAM_H + +#include <vector> + +#include "base/vector.h" +#include "graphic/gl/fields_to_draw.h" +#include "graphic/gl/utils.h" +#include "logic/description_maintainer.h" +#include "logic/map_objects/world/terrain_description.h" + +class WorkareaProgram { +public: + // Compiles the program. Throws on errors. + WorkareaProgram(); + + // Draws the workarea overlay. + void draw(uint32_t texture_id, + Workareas workarea, + const FieldsToDraw& fields_to_draw, + float z_value); + +private: + struct PerVertexData { + float gl_x; + float gl_y; + float overlay_r; + float overlay_g; + float overlay_b; + float overlay_a; + }; + static_assert(sizeof(PerVertexData) == 24, "Wrong padding."); + + void gl_draw(int gl_texture, float z_value); + + // Adds a vertex to the end of vertices with data from 'field' in order to apply the specified 'overlay'. + void add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay); + + // The program used for drawing the workarea overlay. + Gl::Program gl_program_; + + // The buffer that will contain 'vertices_' for rendering. + Gl::Buffer<PerVertexData> gl_array_buffer_; + + // Attributes. + GLint attr_position_; + GLint attr_overlay_; + + // Uniforms. + GLint u_z_value_; + + // Objects below are kept around to avoid memory allocations on each frame. + // They could theoretically also be recreated. + std::vector<PerVertexData> vertices_; + + DISALLOW_COPY_AND_ASSIGN(WorkareaProgram); +}; + +#endif // end of include guard: WL_GRAPHIC_GL_WORKAREA_PROGRAM_H === modified file 'src/graphic/render_queue.cc' --- src/graphic/render_queue.cc 2019-02-23 11:00:49 +0000 +++ src/graphic/render_queue.cc 2019-04-24 17:17:26 +0000 @@ -28,8 +28,10 @@ #include "graphic/gl/dither_program.h" #include "graphic/gl/draw_line_program.h" #include "graphic/gl/fill_rect_program.h" +#include "graphic/gl/grid_program.h" #include "graphic/gl/road_program.h" #include "graphic/gl/terrain_program.h" +#include "graphic/gl/workarea_program.h" namespace { @@ -142,6 +144,8 @@ : next_z_(1), terrain_program_(new TerrainProgram()), dither_program_(new DitherProgram()), + workarea_program_(new WorkareaProgram()), + grid_program_(new GridProgram()), road_program_(new RoadProgram()) { } @@ -164,6 +168,8 @@ case Program::kRect: case Program::kTerrainBase: case Program::kTerrainDither: + case Program::kTerrainWorkarea: + case Program::kTerrainGrid: case Program::kTerrainRoad: /* all fallthroughs intended */ break; @@ -251,6 +257,20 @@ ++i; } break; + case Program::kTerrainWorkarea: { + ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect); + workarea_program_->draw(item.terrain_arguments.terrains->get(0).get_texture(0).blit_data().texture_id, + item.terrain_arguments.workareas, *item.terrain_arguments.fields_to_draw, item.z_value); + ++i; + } break; + + case Program::kTerrainGrid: { + ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect); + grid_program_->draw(item.terrain_arguments.terrains->get(0).get_texture(0).blit_data().texture_id, + *item.terrain_arguments.fields_to_draw, item.z_value); + ++i; + } break; + case Program::kTerrainRoad: { ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect); road_program_->draw(item.terrain_arguments.renderbuffer_width, === modified file 'src/graphic/render_queue.h' --- src/graphic/render_queue.h 2019-02-23 11:00:49 +0000 +++ src/graphic/render_queue.h 2019-04-24 17:17:26 +0000 @@ -36,8 +36,10 @@ #include "logic/map_objects/world/terrain_description.h" class DitherProgram; +class GridProgram; class RoadProgram; class TerrainProgram; +class WorkareaProgram; // The RenderQueue is a singleton implementing the concept of deferred // rendering: Every rendering call that pretends to draw onto the screen will @@ -82,6 +84,8 @@ enum Program { kTerrainBase, kTerrainDither, + kTerrainWorkarea, + kTerrainGrid, kTerrainRoad, kBlit, kRect, @@ -119,6 +123,7 @@ int renderbuffer_height = 0; const DescriptionMaintainer<Widelands::TerrainDescription>* terrains = nullptr; const FieldsToDraw* fields_to_draw = nullptr; + Workareas workareas; float scale = 1.f; Rectf destination_rect = Rectf(0.f, 0.f, 0.f, 0.f); }; @@ -178,6 +183,8 @@ std::unique_ptr<TerrainProgram> terrain_program_; std::unique_ptr<DitherProgram> dither_program_; + std::unique_ptr<WorkareaProgram> workarea_program_; + std::unique_ptr<GridProgram> grid_program_; std::unique_ptr<RoadProgram> road_program_; std::vector<Item> blended_items_; === modified file 'src/logic/widelands_geometry.h' --- src/logic/widelands_geometry.h 2019-02-23 11:00:49 +0000 +++ src/logic/widelands_geometry.h 2019-04-24 17:17:26 +0000 @@ -21,6 +21,8 @@ #define WL_LOGIC_WIDELANDS_GEOMETRY_H #include <cmath> +#include <map> +#include <set> #include <tuple> #include <stdint.h> @@ -155,4 +157,6 @@ }; } // namespace Widelands +using Workareas = std::set<std::map<Widelands::TCoords<>, uint8_t>>; + #endif // end of include guard: WL_LOGIC_WIDELANDS_GEOMETRY_H === modified file 'src/wui/buildingwindow.cc' --- src/wui/buildingwindow.cc 2019-03-22 18:52:17 +0000 +++ src/wui/buildingwindow.cc 2019-04-24 17:17:26 +0000 @@ -320,7 +320,7 @@ if (!wa_info->empty()) { toggle_workarea_ = new UI::Button(capsbuttons, "workarea", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu, - g_gr->images().get("images/wui/overlays/workarea123.png")); + g_gr->images().get("images/wui/buildings/toggle_workarea.png")); toggle_workarea_->sigclicked.connect( boost::bind(&BuildingWindow::toggle_workarea, boost::ref(*this))); === modified file 'src/wui/interactive_base.cc' --- src/wui/interactive_base.cc 2019-04-24 06:01:37 +0000 +++ src/wui/interactive_base.cc 2019-04-24 17:17:26 +0000 @@ -112,14 +112,7 @@ avg_usframetime_(0), buildroad_(nullptr), road_build_player_(0), - unique_window_handler_(new UniqueWindowHandler()), - // Start at idx 0 for 2 enhancements, idx 3 for 1, idx 5 if none - workarea_pics_{g_gr->images().get("images/wui/overlays/workarea123.png"), - g_gr->images().get("images/wui/overlays/workarea23.png"), - g_gr->images().get("images/wui/overlays/workarea3.png"), - g_gr->images().get("images/wui/overlays/workarea12.png"), - g_gr->images().get("images/wui/overlays/workarea2.png"), - g_gr->images().get("images/wui/overlays/workarea1.png")} { + unique_window_handler_(new UniqueWindowHandler()) { // Load the buildhelp icons. { @@ -200,8 +193,20 @@ return nullptr; } -bool InteractiveBase::has_workarea_preview(const Widelands::Coords& coords) const { - return workarea_previews_.count(coords) == 1; +bool InteractiveBase::has_workarea_preview(const Widelands::Coords& coords, const Widelands::Map* map) const { + if (!map) { + return workarea_previews_.count(coords) == 1; + } + for (const auto& pair : workarea_previews_) { + uint32_t radius = 0; + for (const auto& p : *pair.second) { + radius = std::max(radius, p.first); + } + if (map->calc_distance(coords, pair.first) <= radius) { + return true; + } + } + return false; } UniqueWindowHandler& InteractiveBase::unique_windows() { @@ -303,12 +308,53 @@ workarea_previews_[coords] = &workarea_info; } -std::map<Coords, const Image*> -InteractiveBase::get_workarea_overlays(const Widelands::Map& map) const { - std::map<Coords, const Image*> result; - for (const auto& pair : workarea_previews_) { - const Coords& coords = pair.first; - const WorkareaInfo* workarea_info = pair.second; +/* Helper function to get the correct index for graphic/gl/workarea_program.cc::workarea_colors . + * a, b, c are the indices for the three nodes bordering this triangle. + * This function returns the biggest workarea type that matches all three corners. + * The indices stand for: + * 0 – all three circles + * 1 – medium and outer circle + * 2 – outer circle + * 3 – inner and medium circle + * 4 – medium circle + * 5 – inner circle + * We currently assume that no building will have more than three workarea circles. + */ +static uint8_t workarea_max(uint8_t a, uint8_t b, uint8_t c) { + // Whether all nodes are part of the inner circle + bool inner = (a == 0 || a == 3 || a == 5) && (b == 0 || b == 3 || b == 5) && (c == 0 || c == 3 || c == 5); + // Whether all nodes are part of the medium circle + bool medium = (a == 0 || a == 1 || a == 3 || a == 4) && (b == 0 || b == 1 || b == 3 || b == 4) && + (c == 0 || c == 1 || c == 3 || c == 4); + // Whether all nodes are part of the outer circle + bool outer = a <= 2 && b <= 2 && c <= 2; + + if (medium) { + if (outer && inner) { + return 0; + } else if (inner) { + return 3; + } else if (outer) { + return 1; + } else { + return 4; + } + } else if (outer) { + assert(!inner); + return 2; + } else { + assert(inner); + return 5; + } +} + +Workareas InteractiveBase::get_workarea_overlays(const Widelands::Map& map) const { + Workareas result_set; + for (const auto& wa_pair : workarea_previews_) { + std::map<Coords, uint8_t> intermediate_result; + const Coords& coords = wa_pair.first; + const WorkareaInfo* workarea_info = wa_pair.second; + intermediate_result[coords] = 0; WorkareaInfo::size_type wa_index; switch (workarea_info->size()) { case 0: @@ -335,13 +381,36 @@ hollow_area.radius = it->first; Widelands::MapHollowRegion<> mr(map, hollow_area); do { - result[mr.location()] = workarea_pics_[wa_index]; + intermediate_result[mr.location()] = wa_index; } while (mr.advance(map)); wa_index++; hollow_area.hole_radius = hollow_area.radius; } + + std::map<TCoords<>, uint8_t> result; + for (const auto& pair : intermediate_result) { + Coords c; + map.get_brn(pair.first, &c); + const auto brn = intermediate_result.find(c); + if (brn == intermediate_result.end()) { + continue; + } + map.get_bln(pair.first, &c); + const auto bln = intermediate_result.find(c); + map.get_rn(pair.first, &c); + const auto rn = intermediate_result.find(c); + if (bln != intermediate_result.end()) { + result[TCoords<>(pair.first, Widelands::TriangleIndex::D)] = workarea_max( + pair.second, brn->second, bln->second); + } + if (rn != intermediate_result.end()) { + result[TCoords<>(pair.first, Widelands::TriangleIndex::R)] = workarea_max( + pair.second, brn->second, rn->second); + } + } + result_set.emplace(result); } - return result; + return result_set; } void InteractiveBase::hide_workarea(const Widelands::Coords& coords) { === modified file 'src/wui/interactive_base.h' --- src/wui/interactive_base.h 2019-04-19 07:27:15 +0000 +++ src/wui/interactive_base.h 2019-04-24 17:17:26 +0000 @@ -231,7 +231,7 @@ TextToDraw get_text_to_draw() const; // Returns the current overlays for the work area previews. - std::map<Widelands::Coords, const Image*> get_workarea_overlays(const Widelands::Map& map) const; + Workareas get_workarea_overlays(const Widelands::Map& map) const; // Returns the 'BuildhelpOverlay' for 'caps' or nullptr if there is no help // to be displayed on this field. @@ -241,8 +241,10 @@ return road_building_overlays_; } - /// Returns true if there is a workarea preview being shown at the given coordinates - bool has_workarea_preview(const Widelands::Coords& coords) const; + /// Returns true if there is a workarea preview being shown at the given coordinates. + /// If 'map' is 0, checks only if the given coords are the center of a workarea; + /// otherwise checks if the coords are within any workarea. + bool has_workarea_preview(const Widelands::Coords& coords, const Widelands::Map* map = nullptr) const; /// Returns true if the current player is allowed to hear sounds from map objects on this field virtual bool player_hears_field(const Widelands::Coords& coords) const = 0; @@ -304,7 +306,6 @@ UI::UniqueWindow::Registry debugconsole_; std::unique_ptr<UniqueWindowHandler> unique_window_handler_; - std::vector<const Image*> workarea_pics_; BuildhelpOverlay buildhelp_overlays_[Widelands::Field::Buildhelp_None]; }; === modified file 'src/wui/interactive_player.cc' --- src/wui/interactive_player.cc 2019-04-24 06:01:37 +0000 +++ src/wui/interactive_player.cc 2019-04-24 17:17:26 +0000 @@ -160,7 +160,8 @@ bool const multiplayer) : InteractiveGameBase(g, global_s, NONE, multiplayer), auto_roadbuild_mode_(global_s.get_bool("auto_roadbuild_mode", true)), - flag_to_connect_(Widelands::Coords::null()) { + flag_to_connect_(Widelands::Coords::null()), + grid_marker_pic_(g_gr->images().get("images/wui/overlays/grid_marker.png")) { add_toolbar_button( "wui/menus/menu_options_menu", "options_menu", _("Main menu"), &options_, true); options_.open_window = [this] { new GameOptionsMenu(*this, options_, main_windows_); }; @@ -286,9 +287,9 @@ const Widelands::Map& map = gbase.map(); const uint32_t gametime = gbase.get_gametime(); - auto* fields_to_draw = given_map_view->draw_terrain(gbase, dst); + Workareas workareas = get_workarea_overlays(map); + auto* fields_to_draw = given_map_view->draw_terrain(gbase, workareas, false, dst); const auto& road_building = road_building_overlays(); - const std::map<Widelands::Coords, const Image*> workarea_overlays = get_workarea_overlays(map); const float scale = 1.f / given_map_view->view().zoom; @@ -329,13 +330,10 @@ } } - // Draw work area previews. - { - const auto it = workarea_overlays.find(f->fcoords); - if (it != workarea_overlays.end()) { - blit_field_overlay(dst, *f, it->second, - Vector2i(it->second->width() / 2, it->second->height() / 2), scale); - } + // Draw work area markers. + if (has_workarea_preview(f->fcoords, &map)) { + blit_field_overlay(dst, *f, grid_marker_pic_, + Vector2i(grid_marker_pic_->width() / 2, grid_marker_pic_->height() / 2), scale); } if (f->vision > 0) { === modified file 'src/wui/interactive_player.h' --- src/wui/interactive_player.h 2019-03-14 23:06:02 +0000 +++ src/wui/interactive_player.h 2019-04-24 17:17:26 +0000 @@ -91,6 +91,8 @@ UI::UniqueWindow::Registry objectives_; UI::UniqueWindow::Registry encyclopedia_; UI::UniqueWindow::Registry message_menu_; + + const Image* grid_marker_pic_; }; #endif // end of include guard: WL_WUI_INTERACTIVE_PLAYER_H === modified file 'src/wui/interactive_spectator.cc' --- src/wui/interactive_spectator.cc 2019-04-24 06:01:37 +0000 +++ src/wui/interactive_spectator.cc 2019-04-24 17:17:26 +0000 @@ -116,12 +116,11 @@ const Widelands::Game& the_game = game(); const Widelands::Map& map = the_game.map(); - auto* fields_to_draw = given_map_view->draw_terrain(the_game, dst); + auto* fields_to_draw = given_map_view->draw_terrain(the_game, get_workarea_overlays(map), false, dst); const float scale = 1.f / given_map_view->view().zoom; const uint32_t gametime = the_game.get_gametime(); const auto text_to_draw = get_text_to_draw(); - const std::map<Widelands::Coords, const Image*> workarea_overlays = get_workarea_overlays(map); for (size_t idx = 0; idx < fields_to_draw->size(); ++idx) { const FieldsToDraw::Field& field = fields_to_draw->at(idx); @@ -137,13 +136,6 @@ bob->draw(the_game, text_to_draw, field.rendertarget_pixel, field.fcoords, scale, dst); } - // Draw work area previews. - const auto it = workarea_overlays.find(field.fcoords); - if (it != workarea_overlays.end()) { - const Image* pic = it->second; - blit_field_overlay(dst, field, pic, Vector2i(pic->width() / 2, pic->height() / 2), scale); - } - // Draw build help. if (buildhelp()) { auto caps = Widelands::NodeCaps::CAPS_NONE; === modified file 'src/wui/mapview.cc' --- src/wui/mapview.cc 2019-04-23 16:24:40 +0000 +++ src/wui/mapview.cc 2019-04-24 17:17:26 +0000 @@ -339,7 +339,8 @@ NEVER_HERE(); } -FieldsToDraw* MapView::draw_terrain(const Widelands::EditorGameBase& egbase, RenderTarget* dst) { +FieldsToDraw* MapView::draw_terrain(const Widelands::EditorGameBase& egbase, + Workareas workarea, bool grid, RenderTarget* dst) { uint32_t now = SDL_GetTicks(); while (!view_plans_.empty()) { auto& plan = view_plans_.front(); @@ -383,7 +384,7 @@ fields_to_draw_.reset(egbase, view_.viewpoint, view_.zoom, dst); const float scale = 1.f / view_.zoom; - ::draw_terrain(egbase, fields_to_draw_, scale, dst); + ::draw_terrain(egbase, fields_to_draw_, scale, workarea, grid, dst); return &fields_to_draw_; } === modified file 'src/wui/mapview.h' --- src/wui/mapview.h 2019-03-26 02:56:03 +0000 +++ src/wui/mapview.h 2019-04-24 17:17:26 +0000 @@ -172,7 +172,7 @@ // Schedules drawing of the terrain of this MapView. The returned value can // be used to override contents of 'fields_to_draw' for player knowledge and // visibility, and to correctly draw map objects, overlays and text. - FieldsToDraw* draw_terrain(const Widelands::EditorGameBase& egbase, RenderTarget* dst); + FieldsToDraw* draw_terrain(const Widelands::EditorGameBase& egbase, Workareas workarea, bool grid, RenderTarget* dst); // Not overriden from UI::Panel, instead we expect to be passed the data through. bool handle_mousepress(uint8_t btn, int32_t x, int32_t y);
_______________________________________________ Mailing list: https://launchpad.net/~widelands-dev Post to : widelands-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~widelands-dev More help : https://help.launchpad.net/ListHelp