Merge lp:~widelands-dev/widelands/overlapping_workareas into lp:widelands
- overlapping_workareas
- Merge into trunk
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 |
Related bugs: |
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.
bunnybot (widelandsofficial) wrote : | # |
GunChleoc (gunchleoc) wrote : | # |
I think we have some room here to get rid of code duplication.
Benedikt Straub (nordfriese) wrote : | # |
Implemented some of your diff comments and replied to the others
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 4834. State: passed. Details: https:/
Appveyor build 4615. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
Some replies
Benedikt Straub (nordfriese) wrote : | # |
Ah, I misunderstood the point about fieldaction.cc. Implemented your comments.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 4840. State: failed. Details: https:/
Appveyor build 4621. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
Yes, that's looking good now!
Not tested yet.
Toni Förster (stonerl) wrote : | # |
Works so far, but the overlapping areas are very hard to see. Could they be a little more saturated?
Benedikt Straub (nordfriese) wrote : | # |
Updated the colours, are these better?
hessenfarmer (stephan-lutz) wrote : | # |
Any reason why this hasn't been merged yet?
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
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:/
Benedikt Straub (nordfriese) wrote : | # |
A transient travis failure
@bunnybot merge force
Preview Diff
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 |
Continuous integration builds have changed state:
Travis build 4830. State: failed. Details: https:/ /travis- ci.org/ widelands/ widelands/ builds/ 525664696. /ci.appveyor. com/project/ widelands- dev/widelands/ build/_ widelands_ dev_widelands_ overlapping_ workareas- 4611.
Appveyor build 4611. State: success. Details: https:/