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

Proposed by Benedikt Straub
Status: Merged
Merged at revision: 9109
Proposed branch: lp:~widelands-dev/widelands/overlapping_workareas
Merge into: lp:widelands
Diff against target: 761 lines (+347/-127)
14 files modified
src/graphic/color.cc (+7/-0)
src/graphic/color.h (+1/-0)
src/graphic/gl/workarea_program.cc (+38/-36)
src/logic/map.cc (+26/-0)
src/logic/map.h (+8/-0)
src/logic/map_objects/tribes/tribes.cc (+11/-1)
src/logic/map_objects/tribes/tribes.h (+4/-0)
src/logic/map_objects/tribes/workarea_info.h (+27/-0)
src/logic/widelands_geometry.h (+1/-4)
src/wui/actionconfirm.cc (+1/-1)
src/wui/buildingwindow.cc (+1/-1)
src/wui/fieldaction.cc (+92/-5)
src/wui/interactive_base.cc (+115/-74)
src/wui/interactive_base.h (+15/-5)
To merge this branch: bzr merge lp:~widelands-dev/widelands/overlapping_workareas
Reviewer Review Type Date Requested Status
GunChleoc Approve
Toni Förster Approve
Review via email: mp+366623@code.launchpad.net

Commit message

Indicate overlapping workareas when placing buildings

Description of the change

When placing a productionsite, only own conflicting productionsites and constructionsites for productionsites will be indicated.
When placing a militarysite or port, own and enemy conflicting milsites and ports and constructionsites for milsites and ports will be indicated.

Some restructuring and efficiency tweaks to workarea drawing code to improve performance.

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

Continuous integration builds have changed state:

Travis build 4830. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/525664696.
Appveyor build 4611. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_overlapping_workareas-4611.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I think we have some room here to get rid of code duplication.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Implemented some of your diff comments and replied to the others

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4834. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/525875233.
Appveyor build 4615. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_overlapping_workareas-4615.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Some replies

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Ah, I misunderstood the point about fieldaction.cc. Implemented your comments.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4840. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/526107870.
Appveyor build 4621. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_overlapping_workareas-4621.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yes, that's looking good now!

Not tested yet.

review: Approve
Revision history for this message
Toni Förster (stonerl) wrote :

Works so far, but the overlapping areas are very hard to see. Could they be a little more saturated?

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Updated the colours, are these better?

Revision history for this message
Toni Förster (stonerl) wrote :

Perfect.

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

LGTM :)

review: Approve
Revision history for this message
hessenfarmer (stephan-lutz) wrote :

Any reason why this hasn't been merged yet?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Because Nordfriese hadn't merged trunk after the latest merges and there was a conflict.

He's done so now, so let's have it :)

@bunnybot merge

Revision history for this message
bunnybot (widelandsofficial) wrote :

Refusing to merge, since Travis is not green. Use @bunnybot merge force for merging anyways.

Travis build 4995. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/533244956.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

A transient travis failure

@bunnybot merge force

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/graphic/color.cc'
2--- src/graphic/color.cc 2019-02-23 11:00:49 +0000
3+++ src/graphic/color.cc 2019-05-16 09:16:36 +0000
4@@ -59,6 +59,13 @@
5 a = 255;
6 }
7
8+RGBAColor::RGBAColor(uint32_t hex)
9+ : r((hex & 0xff0000) >> 16),
10+ g((hex & 0xff00) >> 8),
11+ b((hex & 0xff)),
12+ a((hex & 0xff000000) >> 24) {
13+}
14+
15 std::string RGBAColor::hex_value() const {
16 return (boost::format("%02x%02x%02x%02x>") % int(r) % int(g) % int(b) % int(a)).str();
17 }
18
19=== modified file 'src/graphic/color.h'
20--- src/graphic/color.h 2019-02-23 11:00:49 +0000
21+++ src/graphic/color.h 2019-05-16 09:16:36 +0000
22@@ -49,6 +49,7 @@
23
24 struct RGBAColor {
25 RGBAColor(uint8_t R, uint8_t G, uint8_t B, uint8_t A);
26+ RGBAColor(uint32_t);
27 RGBAColor(const RGBAColor& other) = default;
28
29 // Initializes the color to black.
30
31=== modified file 'src/graphic/gl/workarea_program.cc'
32--- src/graphic/gl/workarea_program.cc 2019-04-25 21:48:17 +0000
33+++ src/graphic/gl/workarea_program.cc 2019-05-16 09:16:36 +0000
34@@ -65,12 +65,21 @@
35 RGBAColor(0, 0, 127, kWorkareaTransparency), // Inner circle
36 };
37 static inline RGBAColor apply_color(RGBAColor c1, RGBAColor c2) {
38+ if (c1.a == 0 && c2.a == 0) {
39+ return RGBAColor((c1.r + c2.r) / 2, (c1.g + c2.g) / 2, (c1.b + c2.b) / 2, 0);
40+ }
41 uint8_t r = (c1.r * c1.a + c2.r * c2.a) / (c1.a + c2.a);
42 uint8_t g = (c1.g * c1.a + c2.g * c2.a) / (c1.a + c2.a);
43 uint8_t b = (c1.b * c1.a + c2.b * c2.a) / (c1.a + c2.a);
44 uint8_t a = (c1.a + c2.a) / 2;
45 return RGBAColor(r, g, b, a);
46 }
47+static inline RGBAColor apply_color_special(RGBAColor base, RGBAColor special) {
48+ uint8_t r = (base.r * base.a + special.r * 255) / (base.a + 255);
49+ uint8_t g = (base.g * base.a + special.g * 255) / (base.a + 255);
50+ uint8_t b = (base.b * base.a + special.b * 255) / (base.a + 255);
51+ return RGBAColor(r, g, b, special.a);
52+}
53
54 void WorkareaProgram::add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay) {
55 vertices_.emplace_back();
56@@ -91,44 +100,37 @@
57 vertices_.clear();
58 vertices_.reserve(fields_to_draw.size() * 3);
59
60+ auto emplace_triangle = [this, workarea, fields_to_draw]
61+ (const FieldsToDraw::Field& field, Widelands::TriangleIndex triangle_index) {
62+ RGBAColor color(0, 0, 0, 0);
63+ for (const WorkareasEntry& wa_map : workarea) {
64+ for (const WorkareaPreviewData& data : wa_map) {
65+ if (data.coords == Widelands::TCoords<>(field.fcoords, triangle_index)) {
66+ RGBAColor color_to_apply = workarea_colors[data.index];
67+ if (data.use_special_coloring) {
68+ color_to_apply = apply_color_special(color_to_apply, RGBAColor(data.special_coloring));
69+ }
70+ color = apply_color(color, color_to_apply);
71+ }
72+ }
73+ }
74+ if (color.a > 0) {
75+ add_vertex(field, color);
76+ add_vertex(fields_to_draw.at(field.brn_index), color);
77+ add_vertex(fields_to_draw.at(triangle_index == Widelands::TriangleIndex::D ?
78+ field.bln_index : field.rn_index), color);
79+ }
80+ };
81+
82 for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
83 const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
84-
85- // The bottom right neighbor fields_to_draw is needed for both triangles
86- // associated with this field. If it is not in fields_to_draw, there is no need to
87- // draw any triangles.
88- if (field.brn_index == FieldsToDraw::kInvalidIndex) {
89- continue;
90- }
91-
92- // Down triangle.
93- if (field.bln_index != FieldsToDraw::kInvalidIndex) {
94- RGBAColor color(0, 0, 0, 0);
95- for (const std::map<Widelands::TCoords<>, uint8_t>& wa_map : workarea) {
96- const auto it =
97- wa_map.find(Widelands::TCoords<>(field.fcoords, Widelands::TriangleIndex::D));
98- if (it != wa_map.end()) {
99- color = apply_color(color, workarea_colors[it->second]);
100- }
101- }
102- add_vertex(fields_to_draw.at(current_index), color);
103- add_vertex(fields_to_draw.at(field.bln_index), color);
104- add_vertex(fields_to_draw.at(field.brn_index), color);
105- }
106-
107- // Right triangle.
108- if (field.rn_index != FieldsToDraw::kInvalidIndex) {
109- RGBAColor color(0, 0, 0, 0);
110- for (const std::map<Widelands::TCoords<>, uint8_t>& wa_map : workarea) {
111- const auto it =
112- wa_map.find(Widelands::TCoords<>(field.fcoords, Widelands::TriangleIndex::R));
113- if (it != wa_map.end()) {
114- color = apply_color(color, workarea_colors[it->second]);
115- }
116- }
117- add_vertex(fields_to_draw.at(current_index), color);
118- add_vertex(fields_to_draw.at(field.brn_index), color);
119- add_vertex(fields_to_draw.at(field.rn_index), color);
120+ if (field.brn_index != FieldsToDraw::kInvalidIndex) {
121+ if (field.bln_index != FieldsToDraw::kInvalidIndex) {
122+ emplace_triangle(field, Widelands::TriangleIndex::D);
123+ }
124+ if (field.rn_index != FieldsToDraw::kInvalidIndex) {
125+ emplace_triangle(field, Widelands::TriangleIndex::R);
126+ }
127 }
128 }
129
130
131=== modified file 'src/logic/map.cc'
132--- src/logic/map.cc 2019-05-05 18:53:14 +0000
133+++ src/logic/map.cc 2019-05-16 09:16:36 +0000
134@@ -2387,4 +2387,30 @@
135 return influence;
136 }
137
138+std::set<Coords> Map::to_set(Area<Coords> area) const {
139+ std::set<Coords> result;
140+ MapRegion<Area<Coords>> mr(*this, area);
141+ do {
142+ result.insert(mr.location());
143+ } while (mr.advance(*this));
144+ return result;
145+}
146+
147+// Returns all triangles whose corners are all in the given area
148+std::set<TCoords<Coords>> Map::triangles_in_region(std::set<Coords> area) const {
149+ std::set<TCoords<Coords>> result;
150+ for (const Coords& c : area) {
151+ if (!area.count(br_n(c))) {
152+ continue;
153+ }
154+ if (area.count(r_n(c))) {
155+ result.insert(TCoords<Coords>(c, TriangleIndex::R));
156+ }
157+ if (area.count(bl_n(c))) {
158+ result.insert(TCoords<Coords>(c, TriangleIndex::D));
159+ }
160+ }
161+ return result;
162+}
163+
164 } // namespace Widelands
165
166=== modified file 'src/logic/map.h'
167--- src/logic/map.h 2019-04-26 05:52:49 +0000
168+++ src/logic/map.h 2019-05-16 09:16:36 +0000
169@@ -332,6 +332,7 @@
170
171 // Field logic
172 static MapIndex get_index(const Coords&, int16_t width);
173+ MapIndex get_index(const Coords&) const;
174 MapIndex max_index() const {
175 return width_ * height_;
176 }
177@@ -381,6 +382,9 @@
178 void get_neighbour(const FCoords&, Direction dir, FCoords*) const;
179 FCoords get_neighbour(const FCoords&, Direction dir) const;
180
181+ std::set<Coords> to_set(Area<Coords> area) const;
182+ std::set<TCoords<Coords>> triangles_in_region(std::set<Coords> area) const;
183+
184 // Pathfinding
185 int32_t findpath(Coords instart,
186 Coords inend,
187@@ -592,6 +596,10 @@
188 return c.y * width + c.x;
189 }
190
191+inline MapIndex Map::get_index(const Coords& c) const {
192+ return get_index(c, width_);
193+}
194+
195 inline Field& Map::operator[](MapIndex const i) const {
196 return fields_[i];
197 }
198
199=== modified file 'src/logic/map_objects/tribes/tribes.cc'
200--- src/logic/map_objects/tribes/tribes.cc 2019-03-01 04:19:53 +0000
201+++ src/logic/map_objects/tribes/tribes.cc 2019-05-16 09:16:36 +0000
202@@ -34,7 +34,8 @@
203 ships_(new DescriptionMaintainer<ShipDescr>()),
204 wares_(new DescriptionMaintainer<WareDescr>()),
205 workers_(new DescriptionMaintainer<WorkerDescr>()),
206- tribes_(new DescriptionMaintainer<TribeDescr>()) {
207+ tribes_(new DescriptionMaintainer<TribeDescr>()),
208+ largest_workarea_(0) {
209 }
210
211 void Tribes::add_constructionsite_type(const LuaTable& table) {
212@@ -314,9 +315,15 @@
213 }
214
215 void Tribes::postload() {
216+ largest_workarea_ = 0;
217 for (DescriptionIndex i = 0; i < buildings_->size(); ++i) {
218 BuildingDescr& building_descr = *buildings_->get_mutable(i);
219
220+ // Calculate largest possible workarea radius
221+ for (const auto& pair : building_descr.workarea_info()) {
222+ largest_workarea_ = std::max(largest_workarea_, pair.first);
223+ }
224+
225 // Add consumers and producers to wares.
226 if (upcast(ProductionSiteDescr, de, &building_descr)) {
227 for (const auto& ware_amount : de->input_wares()) {
228@@ -425,4 +432,7 @@
229 }
230 }
231
232+uint32_t Tribes::get_largest_workarea() const {
233+ return largest_workarea_;
234+}
235 } // namespace Widelands
236
237=== modified file 'src/logic/map_objects/tribes/tribes.h'
238--- src/logic/map_objects/tribes/tribes.h 2019-03-01 04:19:53 +0000
239+++ src/logic/map_objects/tribes/tribes.h 2019-05-16 09:16:36 +0000
240@@ -143,6 +143,8 @@
241 /// Complete the Description objects' information with data from other Description objects.
242 void postload();
243
244+ uint32_t get_largest_workarea() const;
245+
246 private:
247 void postload_calculate_trainingsites_proportions();
248
249@@ -153,6 +155,8 @@
250 std::unique_ptr<DescriptionMaintainer<WorkerDescr>> workers_;
251 std::unique_ptr<DescriptionMaintainer<TribeDescr>> tribes_;
252
253+ uint32_t largest_workarea_;
254+
255 DISALLOW_COPY_AND_ASSIGN(Tribes);
256 };
257
258
259=== modified file 'src/logic/map_objects/tribes/workarea_info.h'
260--- src/logic/map_objects/tribes/workarea_info.h 2019-02-23 11:00:49 +0000
261+++ src/logic/map_objects/tribes/workarea_info.h 2019-05-16 09:16:36 +0000
262@@ -44,4 +44,31 @@
263
264 using WorkareaInfo = std::map<uint32_t, std::set<std::string>>;
265
266+// Visualization-related structs
267+struct WorkareaPreviewData {
268+ WorkareaPreviewData(Widelands::TCoords<> c, uint8_t i)
269+ : coords(c), index(i), use_special_coloring(false), special_coloring(0) {
270+ }
271+ WorkareaPreviewData(Widelands::TCoords<> c, uint8_t i, uint32_t col)
272+ : coords(c), index(i), use_special_coloring(true), special_coloring(col) {
273+ }
274+ WorkareaPreviewData()
275+ : coords(Widelands::TCoords<>(Widelands::Coords::null(), Widelands::TriangleIndex::D)),
276+ index(0), use_special_coloring(false), special_coloring(0) {
277+ }
278+ WorkareaPreviewData(const WorkareaPreviewData& other) = default;
279+ WorkareaPreviewData& operator=(const WorkareaPreviewData&) = default;
280+
281+ // The triangle this data is applied to
282+ Widelands::TCoords<> coords;
283+ // The underlying workarea color
284+ uint8_t index;
285+ // If a "special coloring" is specified, its RGB will be overlayed over the base color as strongly as if it
286+ // had full alpha, and the final transparency of the entire triangle will be set to this color's alpha
287+ bool use_special_coloring;
288+ uint32_t special_coloring;
289+};
290+using WorkareasEntry = std::vector<WorkareaPreviewData>;
291+using Workareas = std::vector<WorkareasEntry>;
292+
293 #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_WORKAREA_INFO_H
294
295=== modified file 'src/logic/widelands_geometry.h'
296--- src/logic/widelands_geometry.h 2019-03-11 14:45:04 +0000
297+++ src/logic/widelands_geometry.h 2019-05-16 09:16:36 +0000
298@@ -21,9 +21,8 @@
299 #define WL_LOGIC_WIDELANDS_GEOMETRY_H
300
301 #include <cmath>
302-#include <map>
303-#include <set>
304 #include <tuple>
305+#include <vector>
306
307 #include <stdint.h>
308
309@@ -157,6 +156,4 @@
310 };
311 } // namespace Widelands
312
313-using Workareas = std::set<std::map<Widelands::TCoords<>, uint8_t>>;
314-
315 #endif // end of include guard: WL_LOGIC_WIDELANDS_GEOMETRY_H
316
317=== modified file 'src/wui/actionconfirm.cc'
318--- src/wui/actionconfirm.cc 2019-02-23 11:00:49 +0000
319+++ src/wui/actionconfirm.cc 2019-05-16 09:16:36 +0000
320@@ -246,7 +246,7 @@
321 if (building && iaplayer().can_act(building->owner().player_number()) &&
322 (building->get_playercaps() & Widelands::Building::PCap_Dismantle)) {
323 game.send_player_dismantle(*todismantle);
324- iaplayer().hide_workarea(building->get_position());
325+ iaplayer().hide_workarea(building->get_position(), false);
326 }
327
328 die();
329
330=== modified file 'src/wui/buildingwindow.cc'
331--- src/wui/buildingwindow.cc 2019-03-25 15:39:52 +0000
332+++ src/wui/buildingwindow.cc 2019-05-16 09:16:36 +0000
333@@ -512,7 +512,7 @@
334 return; // already hidden, nothing to be done
335 }
336
337- igbase()->hide_workarea(building_position_);
338+ igbase()->hide_workarea(building_position_, false);
339 showing_workarea_ = false;
340 if (configure_button) {
341 configure_workarea_button();
342
343=== modified file 'src/wui/fieldaction.cc'
344--- src/wui/fieldaction.cc 2019-05-11 18:19:20 +0000
345+++ src/wui/fieldaction.cc 2019-05-16 09:16:36 +0000
346@@ -193,6 +193,8 @@
347 bool repeating = false);
348 void reset_mouse_and_die();
349
350+ void clear_overlapping_workareas();
351+
352 Widelands::Player* player_;
353 const Widelands::Map& map_;
354
355@@ -202,6 +204,7 @@
356 bool fastclick_; // if true, put the mouse over first button in first tab
357 uint32_t best_tab_;
358 bool showing_workarea_preview_;
359+ std::set<Widelands::Coords> overlapping_workareas_;
360
361 /// Variables to use with attack dialog.
362 AttackBox* attack_box_;
363@@ -255,8 +258,10 @@
364 }
365
366 FieldActionWindow::~FieldActionWindow() {
367- if (showing_workarea_preview_)
368- ibase().hide_workarea(node_);
369+ if (showing_workarea_preview_) {
370+ ibase().hide_workarea(node_, false);
371+ }
372+ clear_overlapping_workareas();
373 ibase().set_sel_freeze(false);
374 delete attack_box_;
375 }
376@@ -267,6 +272,13 @@
377 die();
378 }
379
380+void FieldActionWindow::clear_overlapping_workareas() {
381+ for (const Widelands::Coords& c : overlapping_workareas_) {
382+ ibase().hide_workarea(c, true);
383+ }
384+ overlapping_workareas_.clear();
385+}
386+
387 /*
388 ===============
389 Initialize after buttons have been registered.
390@@ -683,17 +695,92 @@
391
392 void FieldActionWindow::building_icon_mouse_out(Widelands::DescriptionIndex) {
393 if (showing_workarea_preview_) {
394- ibase().hide_workarea(node_);
395+ ibase().hide_workarea(node_, false);
396+ clear_overlapping_workareas();
397 showing_workarea_preview_ = false;
398 }
399 }
400
401 void FieldActionWindow::building_icon_mouse_in(const Widelands::DescriptionIndex idx) {
402 if (!showing_workarea_preview_) {
403- const WorkareaInfo& workarea_info =
404- player_->tribe().get_building_descr(Widelands::DescriptionIndex(idx))->workarea_info();
405+ assert(overlapping_workareas_.empty());
406+ const Widelands::BuildingDescr& descr = *player_->tribe().get_building_descr(idx);
407+ const WorkareaInfo& workarea_info = descr.workarea_info();
408 ibase().show_workarea(workarea_info, node_);
409 showing_workarea_preview_ = true;
410+
411+ const Widelands::Map& map = ibase().egbase().map();
412+ uint32_t workarea_radius = 0;
413+ for (const auto& pair : workarea_info) {
414+ workarea_radius = std::max(workarea_radius, pair.first);
415+ }
416+ if (workarea_radius == 0) {
417+ return;
418+ }
419+ std::set<Widelands::TCoords<>> main_region = map.triangles_in_region(
420+ map.to_set(Widelands::Area<>(node_, workarea_radius)));
421+
422+ Widelands::MapRegion<Widelands::Area<Widelands::FCoords>> mr(map, Widelands::Area<Widelands::FCoords>(
423+ node_, workarea_radius + ibase().egbase().tribes().get_largest_workarea()));
424+ do {
425+ if (player_->vision(map.get_index(mr.location())) > 1) {
426+ if (Widelands::BaseImmovable* imm = mr.location().field->get_immovable()) {
427+ const Widelands::MapObjectType imm_type = imm->descr().type();
428+ if (imm_type < Widelands::MapObjectType::BUILDING) {
429+ // We are not interested in trees and pebbles
430+ continue;
431+ }
432+ const Widelands::BuildingDescr* d = nullptr;
433+ if (imm_type == Widelands::MapObjectType::CONSTRUCTIONSITE) {
434+ upcast(Widelands::ConstructionSite, cs, imm);
435+ d = cs->get_info().becomes;
436+ if ((descr.type() == Widelands::MapObjectType::PRODUCTIONSITE &&
437+ d->type() != Widelands::MapObjectType::PRODUCTIONSITE) ||
438+ ((descr.type() == Widelands::MapObjectType::MILITARYSITE ||
439+ descr.type() == Widelands::MapObjectType::WAREHOUSE) &&
440+ imm_type != Widelands::MapObjectType::MILITARYSITE &&
441+ imm_type != Widelands::MapObjectType::WAREHOUSE)) {
442+ continue;
443+ }
444+ } else if (descr.type() == Widelands::MapObjectType::PRODUCTIONSITE) {
445+ if (imm_type != Widelands::MapObjectType::PRODUCTIONSITE || imm->get_owner() != player_) {
446+ continue;
447+ }
448+ } else if (descr.type() == Widelands::MapObjectType::WAREHOUSE ||
449+ descr.type() == Widelands::MapObjectType::MILITARYSITE) {
450+ if (imm_type != Widelands::MapObjectType::MILITARYSITE &&
451+ imm_type != Widelands::MapObjectType::WAREHOUSE) {
452+ continue;
453+ }
454+ }
455+ upcast(Widelands::Building, bld, imm);
456+ if (bld->get_position() != mr.location()) {
457+ // Don't count big buildings more than once
458+ continue;
459+ }
460+ if (!d) {
461+ d = &bld->descr();
462+ }
463+ const WorkareaInfo& wa = d->workarea_info();
464+ uint32_t wa_radius = 0;
465+ for (const auto& pair : wa) {
466+ wa_radius = std::max(wa_radius, pair.first);
467+ }
468+ if (wa_radius == 0) {
469+ continue;
470+ }
471+ if (map.calc_distance(node_, mr.location()) <= workarea_radius + wa_radius) {
472+ std::map<Widelands::TCoords<>, uint32_t> colors;
473+ for (const Widelands::TCoords<>& t : map.triangles_in_region(
474+ map.to_set(Widelands::Area<>(mr.location(), wa_radius)))) {
475+ colors[t] = main_region.count(t) ? 0xffbf3f3f : 0x7fffffff;
476+ }
477+ ibase().show_workarea(wa, mr.location(), colors);
478+ overlapping_workareas_.insert(mr.location());
479+ }
480+ }
481+ }
482+ } while (mr.advance(map));
483 }
484 }
485
486
487=== modified file 'src/wui/interactive_base.cc'
488--- src/wui/interactive_base.cc 2019-05-04 05:37:07 +0000
489+++ src/wui/interactive_base.cc 2019-05-16 09:16:36 +0000
490@@ -101,6 +101,7 @@
491 chat_overlay_(new ChatOverlay(this, 10, 25, get_w() / 2, get_h() - 25)),
492 toolbar_(this, 0, 0, UI::Box::Horizontal),
493 quick_navigation_(&map_view_),
494+ workareas_cache_(nullptr),
495 egbase_(the_egbase),
496 #ifndef NDEBUG // not in releases
497 display_flags_(dfDebug),
498@@ -204,14 +205,19 @@
499 bool InteractiveBase::has_workarea_preview(const Widelands::Coords& coords,
500 const Widelands::Map* map) const {
501 if (!map) {
502- return workarea_previews_.count(coords) == 1;
503+ for (const auto& preview : workarea_previews_) {
504+ if (preview->coords == coords) {
505+ return true;
506+ }
507+ }
508+ return false;
509 }
510- for (const auto& pair : workarea_previews_) {
511+ for (const auto& preview : workarea_previews_) {
512 uint32_t radius = 0;
513- for (const auto& p : *pair.second) {
514- radius = std::max(radius, p.first);
515+ for (const auto& wa : *preview->info) {
516+ radius = std::max(radius, wa.first);
517 }
518- if (map->calc_distance(coords, pair.first) <= radius) {
519+ if (map->calc_distance(coords, preview->coords) <= radius) {
520 return true;
521 }
522 }
523@@ -321,9 +327,17 @@
524 return false;
525 }
526
527-// Show the given workareas at the given coords and returns the overlay job id associated
528+// Show the given workareas at the given coords
529+void InteractiveBase::show_workarea(const WorkareaInfo& workarea_info,
530+ Widelands::Coords coords,
531+ std::map<Widelands::TCoords<>, uint32_t>& extra_data) {
532+ workarea_previews_.insert(std::unique_ptr<WorkareaPreview>(new WorkareaPreview{coords, &workarea_info, extra_data}));
533+ workareas_cache_.reset(nullptr);
534+}
535+
536 void InteractiveBase::show_workarea(const WorkareaInfo& workarea_info, Widelands::Coords coords) {
537- workarea_previews_[coords] = &workarea_info;
538+ std::map<Widelands::TCoords<>, uint32_t> empty;
539+ show_workarea(workarea_info, coords, empty);
540 }
541
542 /* Helper function to get the correct index for graphic/gl/workarea_program.cc::workarea_colors .
543@@ -367,73 +381,100 @@
544 }
545 }
546
547-Workareas InteractiveBase::get_workarea_overlays(const Widelands::Map& map) const {
548- Workareas result_set;
549- for (const auto& wa_pair : workarea_previews_) {
550- std::map<Coords, uint8_t> intermediate_result;
551- const Coords& coords = wa_pair.first;
552- const WorkareaInfo* workarea_info = wa_pair.second;
553- intermediate_result[coords] = 0;
554- WorkareaInfo::size_type wa_index;
555- switch (workarea_info->size()) {
556- case 0:
557- continue; // no workarea
558- case 1:
559- wa_index = 5;
560- break;
561- case 2:
562- wa_index = 3;
563- break;
564- case 3:
565- wa_index = 0;
566- break;
567- default:
568- throw wexception(
569- "Encountered unexpected WorkareaInfo size %i", static_cast<int>(workarea_info->size()));
570- }
571-
572- Widelands::HollowArea<> hollow_area(Widelands::Area<>(coords, 0), 0);
573-
574- // Iterate through the work areas, from building to its enhancement
575- WorkareaInfo::const_iterator it = workarea_info->begin();
576- for (; it != workarea_info->end(); ++it) {
577- hollow_area.radius = it->first;
578- Widelands::MapHollowRegion<> mr(map, hollow_area);
579- do {
580- intermediate_result[mr.location()] = wa_index;
581- } while (mr.advance(map));
582- wa_index++;
583- hollow_area.hole_radius = hollow_area.radius;
584- }
585-
586- std::map<TCoords<>, uint8_t> result;
587- for (const auto& pair : intermediate_result) {
588- Coords c;
589- map.get_brn(pair.first, &c);
590- const auto brn = intermediate_result.find(c);
591- if (brn == intermediate_result.end()) {
592- continue;
593- }
594- map.get_bln(pair.first, &c);
595- const auto bln = intermediate_result.find(c);
596- map.get_rn(pair.first, &c);
597- const auto rn = intermediate_result.find(c);
598- if (bln != intermediate_result.end()) {
599- result[TCoords<>(pair.first, Widelands::TriangleIndex::D)] =
600- workarea_max(pair.second, brn->second, bln->second);
601- }
602- if (rn != intermediate_result.end()) {
603- result[TCoords<>(pair.first, Widelands::TriangleIndex::R)] =
604- workarea_max(pair.second, brn->second, rn->second);
605- }
606- }
607- result_set.emplace(result);
608- }
609- return result_set;
610-}
611-
612-void InteractiveBase::hide_workarea(const Widelands::Coords& coords) {
613- workarea_previews_.erase(coords);
614+Workareas InteractiveBase::get_workarea_overlays(const Widelands::Map& map) {
615+ if (!workareas_cache_) {
616+ workareas_cache_.reset(new Workareas());
617+ for (const auto& preview : workarea_previews_) {
618+ workareas_cache_->push_back(get_workarea_overlay(map, *preview));
619+ }
620+ }
621+ return Workareas(*workareas_cache_);
622+}
623+
624+// static
625+WorkareasEntry InteractiveBase::get_workarea_overlay(const Widelands::Map& map, const WorkareaPreview& workarea) {
626+ std::map<Coords, uint8_t> intermediate_result;
627+ const Coords& coords = workarea.coords;
628+ const WorkareaInfo* workarea_info = workarea.info;
629+ intermediate_result[coords] = 0;
630+ WorkareaInfo::size_type wa_index;
631+ switch (workarea_info->size()) {
632+ case 0:
633+ return WorkareasEntry(); // no workarea
634+ case 1:
635+ wa_index = 5;
636+ break;
637+ case 2:
638+ wa_index = 3;
639+ break;
640+ case 3:
641+ wa_index = 0;
642+ break;
643+ default:
644+ throw wexception(
645+ "Encountered unexpected WorkareaInfo size %i", static_cast<int>(workarea_info->size()));
646+ }
647+
648+ Widelands::HollowArea<> hollow_area(Widelands::Area<>(coords, 0), 0);
649+
650+ // Iterate through the work areas, from building to its enhancement
651+ WorkareaInfo::const_iterator it = workarea_info->begin();
652+ for (; it != workarea_info->end(); ++it) {
653+ hollow_area.radius = it->first;
654+ Widelands::MapHollowRegion<> mr(map, hollow_area);
655+ do {
656+ intermediate_result[mr.location()] = wa_index;
657+ } while (mr.advance(map));
658+ wa_index++;
659+ hollow_area.hole_radius = hollow_area.radius;
660+ }
661+
662+ WorkareasEntry result;
663+ for (const auto& pair : intermediate_result) {
664+ Coords c;
665+ map.get_brn(pair.first, &c);
666+ const auto brn = intermediate_result.find(c);
667+ if (brn == intermediate_result.end()) {
668+ continue;
669+ }
670+ map.get_bln(pair.first, &c);
671+ const auto bln = intermediate_result.find(c);
672+ map.get_rn(pair.first, &c);
673+ const auto rn = intermediate_result.find(c);
674+ if (bln != intermediate_result.end()) {
675+ TCoords<> tc(pair.first, Widelands::TriangleIndex::D);
676+ WorkareaPreviewData wd(tc, workarea_max(pair.second, brn->second, bln->second));
677+ for (const auto& p : workarea.data) {
678+ if (p.first == tc) {
679+ wd = WorkareaPreviewData(tc, wd.index, p.second);
680+ break;
681+ }
682+ }
683+ result.push_back(wd);
684+ }
685+ if (rn != intermediate_result.end()) {
686+ TCoords<> tc(pair.first, Widelands::TriangleIndex::R);
687+ WorkareaPreviewData wd(tc, workarea_max(pair.second, brn->second, rn->second));
688+ for (const auto& p : workarea.data) {
689+ if (p.first == tc) {
690+ wd = WorkareaPreviewData(tc, wd.index, p.second);
691+ break;
692+ }
693+ }
694+ result.push_back(wd);
695+ }
696+ }
697+ return result;
698+}
699+
700+void InteractiveBase::hide_workarea(const Widelands::Coords& coords, bool is_additional) {
701+ for (auto it = workarea_previews_.begin(); it != workarea_previews_.end(); ++it) {
702+ if (it->get()->coords == coords && (is_additional ^ it->get()->data.empty())) {
703+ workarea_previews_.erase(it);
704+ workareas_cache_.reset(nullptr);
705+ return;
706+ }
707+ }
708 }
709
710 /**
711
712=== modified file 'src/wui/interactive_base.h'
713--- src/wui/interactive_base.h 2019-05-03 09:15:17 +0000
714+++ src/wui/interactive_base.h 2019-05-16 09:16:36 +0000
715@@ -46,6 +46,12 @@
716 class EdgeOverlayManager;
717 class UniqueWindowHandler;
718
719+struct WorkareaPreview {
720+ Widelands::Coords coords;
721+ const WorkareaInfo* info;
722+ std::map<Widelands::TCoords<>, uint32_t> data;
723+};
724+
725 /**
726 * This is used to represent the code that InteractivePlayer and
727 * EditorInteractive share.
728@@ -84,7 +90,10 @@
729 }
730
731 void show_workarea(const WorkareaInfo& workarea_info, Widelands::Coords coords);
732- void hide_workarea(const Widelands::Coords& coords);
733+ void show_workarea(const WorkareaInfo& workarea_info,
734+ Widelands::Coords coords,
735+ std::map<Widelands::TCoords<>, uint32_t>& extra_data);
736+ void hide_workarea(const Widelands::Coords& coords, bool is_additional);
737
738 bool has_expedition_port_space(const Widelands::Coords&) const;
739 std::map<Widelands::Ship*, Widelands::Coords>& get_expedition_port_spaces() {
740@@ -236,7 +245,8 @@
741 TextToDraw get_text_to_draw() const;
742
743 // Returns the current overlays for the work area previews.
744- Workareas get_workarea_overlays(const Widelands::Map& map) const;
745+ Workareas get_workarea_overlays(const Widelands::Map& map);
746+ static WorkareasEntry get_workarea_overlay(const Widelands::Map&, const WorkareaPreview&);
747
748 // Returns the 'BuildhelpOverlay' for 'caps' or nullptr if there is no help
749 // to be displayed on this field.
750@@ -292,9 +302,9 @@
751 MiniMap::Registry minimap_registry_;
752 QuickNavigation quick_navigation_;
753
754- // The currently enabled work area previews. They are keyed by the
755- // coordinate that the building that shows the work area is positioned.
756- std::map<Widelands::Coords, const WorkareaInfo*> workarea_previews_;
757+ // The currently enabled work area previews
758+ std::unordered_set<std::unique_ptr<WorkareaPreview>> workarea_previews_;
759+ std::unique_ptr<Workareas> workareas_cache_;
760
761 std::map<Widelands::Ship*, Widelands::Coords> expedition_port_spaces_;
762

Subscribers

People subscribed via source and target branches

to status/vote changes: