widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #17471
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
Benedikt Straub has proposed merging lp:~widelands-dev/widelands/workarea-fixes into lp:widelands.
Commit message:
· Draw a narrow border around workareas for better visibility
· Improve performance by only recalculating the workarea shader data when needed
· Add the hotkey W to enable/disable highlighting workarea overlaps
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #1830345 in widelands: "overlapping workareas are very performance hungry"
https://bugs.launchpad.net/widelands/+bug/1830345
Bug #1830647 in widelands: "Indicate workarea border more clearly"
https://bugs.launchpad.net/widelands/+bug/1830647
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/workarea-fixes/+merge/368083
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/workarea-fixes into lp:widelands.
=== added file 'data/images/wui/fieldaction/menu_show_workarea_overlap.png'
Binary files data/images/wui/fieldaction/menu_show_workarea_overlap.png 1970-01-01 00:00:00 +0000 and data/images/wui/fieldaction/menu_show_workarea_overlap.png 2019-05-29 18:00:02 +0000 differ
=== modified file 'src/graphic/gl/fields_to_draw.h'
--- src/graphic/gl/fields_to_draw.h 2019-02-27 19:00:36 +0000
+++ src/graphic/gl/fields_to_draw.h 2019-05-29 18:00:02 +0000
@@ -96,7 +96,6 @@
return &fields_[index];
}
-private:
// Calculates the index of the given field with ('fx', 'fy') being geometric
// coordinates in the map. Returns INVALID_INDEX if this field is not in the
// fields_to_draw.
@@ -112,6 +111,7 @@
return yidx * w_ + xidx;
}
+private:
// Minimum and maximum field coordinates (geometric) to render. Can be negative.
int min_fx_ = 0;
int max_fx_ = 0;
=== modified file 'src/graphic/gl/workarea_program.cc'
--- src/graphic/gl/workarea_program.cc 2019-05-17 07:13:04 +0000
+++ src/graphic/gl/workarea_program.cc 2019-05-29 18:00:02 +0000
@@ -24,7 +24,8 @@
#include "graphic/gl/utils.h"
#include "graphic/texture.h"
-WorkareaProgram::WorkareaProgram() {
+WorkareaProgram::WorkareaProgram()
+ : cache_(nullptr) {
gl_program_.build("workarea");
attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
@@ -36,22 +37,32 @@
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());
+ {
+ 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());
+ }
+ {
+ auto& gl_state = Gl::State::instance();
+ gl_state.enable_vertex_attrib_array({attr_position_, attr_overlay_});
+ gl_array_buffer_.bind();
+ gl_array_buffer_.update(outer_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_LINES, 0, outer_vertices_.size());
+ }
}
constexpr uint8_t kWorkareaTransparency = 127;
@@ -81,9 +92,9 @@
return RGBAColor(r, g, b, special.a);
}
-void WorkareaProgram::add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay) {
- vertices_.emplace_back();
- PerVertexData& back = vertices_.back();
+void WorkareaProgram::add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay, std::vector<PerVertexData>* v) {
+ v->emplace_back();
+ PerVertexData& back = v->back();
back.gl_x = field.gl_position.x;
back.gl_y = field.gl_position.y;
@@ -97,15 +108,34 @@
Workareas workarea,
const FieldsToDraw& fields_to_draw,
float z_value) {
+ const FieldsToDraw::Field& topleft = fields_to_draw.at(0);
+ if (cache_ && cache_->fcoords == topleft.fcoords && cache_->surface_pixel == topleft.surface_pixel &&
+ cache_->workareas == workarea) {
+ return gl_draw(texture_id, z_value);
+ }
+ cache_.reset(new WorkareasCache(workarea, topleft.fcoords, topleft.surface_pixel));
+
vertices_.clear();
- vertices_.reserve(fields_to_draw.size() * 3);
+ outer_vertices_.clear();
+ {
+ size_t estimate_inner = 0;
+ size_t estimate_outer = 0;
+ for (const WorkareasEntry& wa_map : workarea) {
+ estimate_inner += 3 * wa_map.first.size();
+ for (const auto& vector : wa_map.second) {
+ estimate_outer += 2 * vector.size();
+ }
+ }
+ vertices_.reserve(estimate_inner);
+ outer_vertices_.reserve(estimate_outer);
+ }
auto emplace_triangle = [this, workarea, fields_to_draw](
const FieldsToDraw::Field& field,
Widelands::TriangleIndex triangle_index) {
RGBAColor color(0, 0, 0, 0);
for (const WorkareasEntry& wa_map : workarea) {
- for (const WorkareaPreviewData& data : wa_map) {
+ for (const WorkareaPreviewData& data : wa_map.first) {
if (data.coords == Widelands::TCoords<>(field.fcoords, triangle_index)) {
RGBAColor color_to_apply = workarea_colors[data.index];
if (data.use_special_coloring) {
@@ -117,12 +147,12 @@
}
}
if (color.a > 0) {
- add_vertex(field, color);
- add_vertex(fields_to_draw.at(field.brn_index), color);
+ add_vertex(field, color, &vertices_);
+ add_vertex(fields_to_draw.at(field.brn_index), color, &vertices_);
add_vertex(
fields_to_draw.at(triangle_index == Widelands::TriangleIndex::D ? field.bln_index :
field.rn_index),
- color);
+ color, &vertices_);
}
};
@@ -138,5 +168,41 @@
}
}
+ {
+ for (const WorkareasEntry& wa_map : workarea) {
+ int32_t index = 5;
+ for (const auto& border : wa_map.second) {
+ assert(index == 5 || index == 4 || index == 2);
+ for (auto it = border.begin(); it != border.end(); ++it) {
+ int f1 = fields_to_draw.calculate_index(it->x, it->y);
+ if (f1 == FieldsToDraw::kInvalidIndex) {
+ continue;
+ }
+ int f2;
+ if (it + 1 == border.end()) {
+ f2 = fields_to_draw.calculate_index(border.begin()->x, border.begin()->y);
+ } else {
+ f2 = fields_to_draw.calculate_index((it + 1)->x, (it + 1)->y);
+ }
+ if (f2 != FieldsToDraw::kInvalidIndex) {
+ add_vertex(fields_to_draw.at(f1), workarea_colors[index], &outer_vertices_);
+ add_vertex(fields_to_draw.at(f2), workarea_colors[index], &outer_vertices_);
+ }
+ }
+ switch (index) {
+ case 5:
+ index = 4;
+ break;
+ case 4:
+ index = 2;
+ break;
+ default:
+ index = -1;
+ break;
+ }
+ }
+ }
+ }
+
gl_draw(texture_id, z_value);
}
=== modified file 'src/graphic/gl/workarea_program.h'
--- src/graphic/gl/workarea_program.h 2019-04-26 05:52:49 +0000
+++ src/graphic/gl/workarea_program.h 2019-05-29 18:00:02 +0000
@@ -20,6 +20,7 @@
#ifndef WL_GRAPHIC_GL_WORKAREA_PROGRAM_H
#define WL_GRAPHIC_GL_WORKAREA_PROGRAM_H
+#include <memory>
#include <vector>
#include "base/vector.h"
@@ -52,7 +53,7 @@
// 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);
+ void add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay, std::vector<PerVertexData>*);
// The program used for drawing the workarea overlay.
Gl::Program gl_program_;
@@ -70,6 +71,20 @@
// Objects below are kept around to avoid memory allocations on each frame.
// They could theoretically also be recreated.
std::vector<PerVertexData> vertices_;
+ std::vector<PerVertexData> outer_vertices_;
+
+ // Calculating the workareas is a bit slow, so we only recalculate when we have to
+ struct WorkareasCache {
+ WorkareasCache(const Workareas& wa, const Widelands::FCoords f, const Vector2f v)
+ : workareas(wa), fcoords(f), surface_pixel(v) {
+ }
+
+ const Workareas workareas;
+ // Viewpoint data
+ const Widelands::FCoords fcoords;
+ const Vector2f surface_pixel;
+ };
+ std::unique_ptr<WorkareasCache> cache_;
DISALLOW_COPY_AND_ASSIGN(WorkareaProgram);
};
=== modified file 'src/logic/map_objects/tribes/workarea_info.h'
--- src/logic/map_objects/tribes/workarea_info.h 2019-05-17 07:13:04 +0000
+++ src/logic/map_objects/tribes/workarea_info.h 2019-05-29 18:00:02 +0000
@@ -61,6 +61,11 @@
WorkareaPreviewData(const WorkareaPreviewData& other) = default;
WorkareaPreviewData& operator=(const WorkareaPreviewData&) = default;
+ bool operator==(const WorkareaPreviewData& d) const {
+ return index == d.index && coords == d.coords && use_special_coloring == d.use_special_coloring &&
+ (!use_special_coloring || special_coloring == d.special_coloring);
+ }
+
// The triangle this data is applied to
Widelands::TCoords<> coords;
// The underlying workarea color
@@ -71,7 +76,8 @@
bool use_special_coloring;
uint32_t special_coloring;
};
-using WorkareasEntry = std::vector<WorkareaPreviewData>;
+// Pair of interior information and a per-circle list of border coords
+using WorkareasEntry = std::pair<std::vector<WorkareaPreviewData>, std::vector<std::vector<Widelands::Coords>>>;
using Workareas = std::vector<WorkareasEntry>;
#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_WORKAREA_INFO_H
=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc 2019-05-26 17:21:15 +0000
+++ src/wui/fieldaction.cc 2019-05-29 18:00:02 +0000
@@ -165,6 +165,7 @@
void act_watch();
void act_show_census();
void act_show_statistics();
+ void act_show_workarea_overlap();
void act_debug();
void act_buildflag();
void act_configure_economy();
@@ -206,6 +207,7 @@
uint32_t best_tab_;
bool showing_workarea_preview_;
std::set<Widelands::Coords> overlapping_workareas_;
+ bool is_showing_workarea_overlaps_;
/// Variables to use with attack dialog.
AttackBox* attack_box_;
@@ -231,6 +233,7 @@
static const char* const pic_watchfield = "images/wui/fieldaction/menu_watch_field.png";
static const char* const pic_showcensus = "images/wui/fieldaction/menu_show_census.png";
static const char* const pic_showstatistics = "images/wui/fieldaction/menu_show_statistics.png";
+static const char* const pic_showworkareaoverlap = "images/wui/fieldaction/menu_show_workarea_overlap.png";
static const char* const pic_debug = "images/wui/fieldaction/menu_debug.png";
static const char* const pic_abort = "images/wui/menu_abort.png";
static const char* const pic_geologist = "images/wui/fieldaction/menu_geologist.png";
@@ -253,6 +256,7 @@
fastclick_(true),
best_tab_(0),
showing_workarea_preview_(false),
+ is_showing_workarea_overlaps_(ib->get_display_flag(InteractiveBase::dfShowWorkareaOverlap)),
attack_box_(nullptr) {
ib->set_sel_freeze(true);
set_center_panel(&tabpanel_);
@@ -262,15 +266,28 @@
if (showing_workarea_preview_) {
ibase().hide_workarea(node_, false);
}
+ showing_workarea_preview_ = false;
clear_overlapping_workareas();
ibase().set_sel_freeze(false);
delete attack_box_;
}
void FieldActionWindow::think() {
- if (player_ && player_->vision(node_.field - &ibase().egbase().map()[0]) <= 1 &&
- !player_->see_all())
+ if (is_showing_workarea_overlaps_ != ibase().get_display_flag(InteractiveBase::dfShowWorkareaOverlap)) {
+ is_showing_workarea_overlaps_ = !is_showing_workarea_overlaps_;
+ if (!is_showing_workarea_overlaps_) {
+ clear_overlapping_workareas();
+ }
+#ifndef NDEBUG
+ else {
+ // Desired overlaps will be shown as soon as the user moves the mouse
+ assert(overlapping_workareas_.empty());
+ }
+#endif
+ }
+ if (player_ && player_->vision(node_.field - &ibase().egbase().map()[0]) <= 1 && !player_->see_all()) {
die();
+ }
}
void FieldActionWindow::clear_overlapping_workareas() {
@@ -372,6 +389,11 @@
}
add_button(&watchbox, "census", pic_showcensus, &FieldActionWindow::act_show_census,
_("Toggle building label display"));
+ if (is_a(InteractivePlayer, &ibase())) {
+ add_button(&watchbox, "workarea_overlap", pic_showworkareaoverlap,
+ &FieldActionWindow::act_show_workarea_overlap,
+ _("Toggle whether overlapping workareas are indicated when placing a constructionsite"));
+ }
if (ibase().get_display_flag(InteractiveBase::dfDebug))
add_button(
@@ -570,6 +592,12 @@
reset_mouse_and_die();
}
+void FieldActionWindow::act_show_workarea_overlap() {
+ ibase().set_display_flag(InteractiveBase::dfShowWorkareaOverlap,
+ !ibase().get_display_flag(InteractiveBase::dfShowWorkareaOverlap));
+ reset_mouse_and_die();
+}
+
/*
===============
Show a debug widow for this field.
@@ -697,8 +725,8 @@
void FieldActionWindow::building_icon_mouse_out(Widelands::DescriptionIndex) {
if (showing_workarea_preview_) {
ibase().hide_workarea(node_, false);
+ showing_workarea_preview_ = false;
clear_overlapping_workareas();
- showing_workarea_preview_ = false;
}
}
@@ -709,6 +737,9 @@
const WorkareaInfo& workarea_info = descr.workarea_info();
ibase().show_workarea(workarea_info, node_);
showing_workarea_preview_ = true;
+ if (!is_showing_workarea_overlaps_) {
+ return;
+ }
const Widelands::Map& map = ibase().egbase().map();
uint32_t workarea_radius = 0;
=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc 2019-05-26 17:21:15 +0000
+++ src/wui/interactive_base.cc 2019-05-29 18:00:02 +0000
@@ -383,7 +383,8 @@
const WorkareaInfo* workarea_info = workarea.info;
intermediate_result[coords] = 0;
WorkareaInfo::size_type wa_index;
- switch (workarea_info->size()) {
+ const size_t workarea_size = workarea_info->size();
+ switch (workarea_size) {
case 0:
return WorkareasEntry(); // no workarea
case 1:
@@ -435,7 +436,7 @@
break;
}
}
- result.push_back(wd);
+ result.first.push_back(wd);
}
if (rn != intermediate_result.end()) {
TCoords<> tc(pair.first, Widelands::TriangleIndex::R);
@@ -446,8 +447,40 @@
break;
}
}
- result.push_back(wd);
- }
+ result.first.push_back(wd);
+ }
+ }
+ for (const auto& pair : *workarea_info) {
+ std::vector<Coords> border;
+ Coords c = coords;
+ for (uint32_t i = pair.first; i > 0; --i) {
+ map.get_tln(c, &c);
+ }
+ for (uint32_t i = pair.first; i > 0; --i) {
+ border.push_back(c);
+ map.get_rn(c, &c);
+ }
+ for (uint32_t i = pair.first; i > 0; --i) {
+ border.push_back(c);
+ map.get_brn(c, &c);
+ }
+ for (uint32_t i = pair.first; i > 0; --i) {
+ border.push_back(c);
+ map.get_bln(c, &c);
+ }
+ for (uint32_t i = pair.first; i > 0; --i) {
+ border.push_back(c);
+ map.get_ln(c, &c);
+ }
+ for (uint32_t i = pair.first; i > 0; --i) {
+ border.push_back(c);
+ map.get_tln(c, &c);
+ }
+ for (uint32_t i = pair.first; i > 0; --i) {
+ border.push_back(c);
+ map.get_trn(c, &c);
+ }
+ result.second.push_back(border);
}
return result;
}
=== modified file 'src/wui/interactive_base.h'
--- src/wui/interactive_base.h 2019-05-16 09:15:03 +0000
+++ src/wui/interactive_base.h 2019-05-29 18:00:02 +0000
@@ -62,6 +62,7 @@
dfShowCensus = 1, ///< show census report on buildings
dfShowStatistics = 2, ///< show statistics report on buildings
dfDebug = 4, ///< general debugging info
+ dfShowWorkareaOverlap = 8, ///< highlight overlapping workareas when placing a constructionsite
};
// Overlays displayed while a road is under construction.
=== modified file 'src/wui/interactive_player.cc'
--- src/wui/interactive_player.cc 2019-05-04 10:47:44 +0000
+++ src/wui/interactive_player.cc 2019-05-29 18:00:02 +0000
@@ -172,6 +172,8 @@
new GameStatisticsMenu(*this, statisticsmenu_, main_windows_);
};
+ set_display_flag(InteractiveBase::dfShowWorkareaOverlap, true); // enable by default
+
toolbar()->add_space(15);
add_toolbar_button(
@@ -473,6 +475,10 @@
set_display_flag(dfShowStatistics, !get_display_flag(dfShowStatistics));
return true;
+ case SDLK_w:
+ set_display_flag(dfShowWorkareaOverlap, !get_display_flag(dfShowWorkareaOverlap));
+ return true;
+
case SDLK_KP_7:
if (code.mod & KMOD_NUM)
break;
Follow ups
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: noreply, 2019-05-31
-
Re: [Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: Benedikt Straub, 2019-05-31
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: bunnybot, 2019-05-31
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: bunnybot, 2019-05-31
-
Re: [Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: Benedikt Straub, 2019-05-31
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: bunnybot, 2019-05-31
-
Re: [Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: Benedikt Straub, 2019-05-31
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: bunnybot, 2019-05-30
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: bunnybot, 2019-05-30
-
Re: [Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: GunChleoc, 2019-05-30
-
Re: [Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: Benedikt Straub, 2019-05-30
-
Re: [Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: GunChleoc, 2019-05-30
-
[Merge] lp:~widelands-dev/widelands/workarea-fixes into lp:widelands
From: bunnybot, 2019-05-30