Merge lp:~widelands-dev/widelands/editor-grid into lp:widelands

Proposed by Benedikt Straub
Status: Superseded
Proposed branch: lp:~widelands-dev/widelands/editor-grid
Merge into: lp:widelands
Diff against target: 1036 lines (+588/-46)
24 files modified
data/shaders/grid.fp (+5/-0)
data/shaders/grid.vp (+10/-0)
data/shaders/workarea.fp (+7/-0)
data/shaders/workarea.vp (+15/-0)
src/editor/editorinteractive.cc (+14/-1)
src/editor/editorinteractive.h (+3/-0)
src/graphic/CMakeLists.txt (+4/-0)
src/graphic/game_renderer.cc (+16/-0)
src/graphic/game_renderer.h (+2/-0)
src/graphic/gl/grid_program.cc (+89/-0)
src/graphic/gl/grid_program.h (+72/-0)
src/graphic/gl/workarea_program.cc (+134/-0)
src/graphic/gl/workarea_program.h (+78/-0)
src/graphic/render_queue.cc (+20/-0)
src/graphic/render_queue.h (+7/-0)
src/logic/widelands_geometry.h (+4/-0)
src/wui/buildingwindow.cc (+1/-1)
src/wui/interactive_base.cc (+87/-18)
src/wui/interactive_base.h (+5/-4)
src/wui/interactive_player.cc (+8/-10)
src/wui/interactive_player.h (+2/-0)
src/wui/interactive_spectator.cc (+1/-9)
src/wui/mapview.cc (+3/-2)
src/wui/mapview.h (+1/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/editor-grid
Reviewer Review Type Date Requested Status
Widelands Developers Pending
Review via email: mp+366481@code.launchpad.net

Commit message

Add a grid overlay to the editor, which can be toggled with a button or the hotkey 'G'

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'data/images/wui/overlays/workarea123.png' => 'data/images/wui/buildings/toggle_workarea.png'
2=== added file 'data/images/wui/menus/menu_toggle_grid.png'
3Binary 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:07:20 +0000 differ
4=== added file 'data/images/wui/overlays/grid_marker.png'
5Binary 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:07:20 +0000 differ
6=== removed file 'data/images/wui/overlays/workarea1.png'
7Binary 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
8=== removed file 'data/images/wui/overlays/workarea12.png'
9Binary 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
10=== removed file 'data/images/wui/overlays/workarea2.png'
11Binary 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
12=== removed file 'data/images/wui/overlays/workarea23.png'
13Binary 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
14=== removed file 'data/images/wui/overlays/workarea3.png'
15Binary 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
16=== added file 'data/shaders/grid.fp'
17--- data/shaders/grid.fp 1970-01-01 00:00:00 +0000
18+++ data/shaders/grid.fp 2019-04-24 17:07:20 +0000
19@@ -0,0 +1,5 @@
20+#version 120
21+
22+void main() {
23+ gl_FragColor = vec4(.0, .0, .0, .8);
24+}
25
26=== added file 'data/shaders/grid.vp'
27--- data/shaders/grid.vp 1970-01-01 00:00:00 +0000
28+++ data/shaders/grid.vp 2019-04-24 17:07:20 +0000
29@@ -0,0 +1,10 @@
30+#version 120
31+
32+// Attributes.
33+attribute vec2 attr_position;
34+
35+uniform float u_z_value;
36+
37+void main() {
38+ gl_Position = vec4(attr_position, u_z_value, 1.);
39+}
40
41=== added file 'data/shaders/workarea.fp'
42--- data/shaders/workarea.fp 1970-01-01 00:00:00 +0000
43+++ data/shaders/workarea.fp 2019-04-24 17:07:20 +0000
44@@ -0,0 +1,7 @@
45+#version 120
46+
47+varying vec4 var_overlay;
48+
49+void main() {
50+ gl_FragColor = var_overlay;
51+}
52
53=== added file 'data/shaders/workarea.vp'
54--- data/shaders/workarea.vp 1970-01-01 00:00:00 +0000
55+++ data/shaders/workarea.vp 2019-04-24 17:07:20 +0000
56@@ -0,0 +1,15 @@
57+#version 120
58+
59+// Attributes.
60+attribute vec2 attr_position;
61+attribute vec4 attr_overlay;
62+
63+uniform float u_z_value;
64+
65+// Output of vertex shader.
66+varying vec4 var_overlay;
67+
68+void main() {
69+ var_overlay = attr_overlay;
70+ gl_Position = vec4(attr_position, u_z_value, 1.);
71+}
72
73=== modified file 'src/editor/editorinteractive.cc'
74--- src/editor/editorinteractive.cc 2019-04-24 07:09:29 +0000
75+++ src/editor/editorinteractive.cc 2019-04-24 17:07:20 +0000
76@@ -98,6 +98,10 @@
77 toggle_buildhelp_ = add_toolbar_button(
78 "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show building spaces (on/off)"));
79 toggle_buildhelp_->sigclicked.connect(boost::bind(&EditorInteractive::toggle_buildhelp, this));
80+ toggle_grid_ =
81+ add_toolbar_button("wui/menus/menu_toggle_grid", "grid", _("Show grid (on/off)"));
82+ toggle_grid_->set_perm_pressed(true);
83+ toggle_grid_->sigclicked.connect([this]() { toggle_grid(); });
84 toggle_immovables_ = add_toolbar_button(
85 "wui/menus/menu_toggle_immovables", "immovables", _("Show immovables (on/off)"));
86 toggle_immovables_->set_perm_pressed(true);
87@@ -262,7 +266,7 @@
88
89 void EditorInteractive::draw(RenderTarget& dst) {
90 const auto& ebase = egbase();
91- auto* fields_to_draw = map_view()->draw_terrain(ebase, &dst);
92+ auto* fields_to_draw = map_view()->draw_terrain(ebase, Workareas(), draw_grid_, &dst);
93
94 const float scale = 1.f / map_view()->view().zoom;
95 const uint32_t gametime = ebase.get_gametime();
96@@ -430,6 +434,11 @@
97 toggle_bobs_->set_perm_pressed(draw_bobs_);
98 }
99
100+void EditorInteractive::toggle_grid() {
101+ draw_grid_ = !draw_grid_;
102+ toggle_grid_->set_perm_pressed(draw_grid_);
103+}
104+
105 bool EditorInteractive::handle_key(bool const down, SDL_Keysym const code) {
106 if (down) {
107 switch (code.sym) {
108@@ -504,6 +513,10 @@
109 toggle_buildhelp();
110 return true;
111
112+ case SDLK_g:
113+ toggle_grid();
114+ return true;
115+
116 case SDLK_c:
117 set_display_flag(
118 InteractiveBase::dfShowCensus, !get_display_flag(InteractiveBase::dfShowCensus));
119
120=== modified file 'src/editor/editorinteractive.h'
121--- src/editor/editorinteractive.h 2019-04-24 07:09:29 +0000
122+++ src/editor/editorinteractive.h 2019-04-24 17:07:20 +0000
123@@ -149,6 +149,7 @@
124 void toggle_resources();
125 void toggle_immovables();
126 void toggle_bobs();
127+ void toggle_grid();
128
129 // state variables
130 bool need_save_;
131@@ -170,6 +171,7 @@
132 UI::UniqueWindow::Registry helpmenu_;
133
134 UI::Button* toggle_buildhelp_;
135+ UI::Button* toggle_grid_;
136 UI::Button* toggle_resources_;
137 UI::Button* toggle_immovables_;
138 UI::Button* toggle_bobs_;
139@@ -182,6 +184,7 @@
140 bool draw_resources_ = true;
141 bool draw_immovables_ = true;
142 bool draw_bobs_ = true;
143+ bool draw_grid_ = true;
144 };
145
146 #endif // end of include guard: WL_EDITOR_EDITORINTERACTIVE_H
147
148=== modified file 'src/graphic/CMakeLists.txt'
149--- src/graphic/CMakeLists.txt 2019-04-08 13:32:28 +0000
150+++ src/graphic/CMakeLists.txt 2019-04-24 17:07:20 +0000
151@@ -225,12 +225,16 @@
152
153 wl_library(graphic_terrain_programs
154 SRCS
155+ gl/grid_program.cc
156+ gl/grid_program.h
157 gl/road_program.cc
158 gl/road_program.h
159 gl/terrain_program.cc
160 gl/terrain_program.h
161 gl/dither_program.cc
162 gl/dither_program.h
163+ gl/workarea_program.cc
164+ gl/workarea_program.h
165 DEPENDS
166 base_exceptions
167 base_geometry
168
169=== modified file 'src/graphic/game_renderer.cc'
170--- src/graphic/game_renderer.cc 2019-04-24 06:01:37 +0000
171+++ src/graphic/game_renderer.cc 2019-04-24 17:07:20 +0000
172@@ -60,6 +60,8 @@
173 void draw_terrain(const Widelands::EditorGameBase& egbase,
174 const FieldsToDraw& fields_to_draw,
175 const float scale,
176+ Workareas workarea,
177+ bool grid,
178 RenderTarget* dst) {
179 const Recti& bounding_rect = dst->get_rect();
180 const Surface& surface = dst->get_surface();
181@@ -86,6 +88,20 @@
182 i.blend_mode = BlendMode::UseAlpha;
183 RenderQueue::instance().enqueue(i);
184
185+ if (!workarea.empty()) {
186+ // Enqueue the drawing of the workarea overlay layer.
187+ i.program_id = RenderQueue::Program::kTerrainWorkarea;
188+ i.terrain_arguments.workareas = workarea;
189+ RenderQueue::instance().enqueue(i);
190+ }
191+
192+ if (grid) {
193+ // Enqueue the drawing of the grid layer.
194+ i.program_id = RenderQueue::Program::kTerrainGrid;
195+ i.blend_mode = BlendMode::UseAlpha;
196+ RenderQueue::instance().enqueue(i);
197+ }
198+
199 // Enqueue the drawing of the road layer.
200 i.program_id = RenderQueue::Program::kTerrainRoad;
201 RenderQueue::instance().enqueue(i);
202
203=== modified file 'src/graphic/game_renderer.h'
204--- src/graphic/game_renderer.h 2019-02-23 11:00:49 +0000
205+++ src/graphic/game_renderer.h 2019-04-24 17:07:20 +0000
206@@ -33,6 +33,8 @@
207 void draw_terrain(const Widelands::EditorGameBase& egbase,
208 const FieldsToDraw& fields_to_draw,
209 const float scale,
210+ Workareas workarea,
211+ bool grid,
212 RenderTarget* dst);
213
214 // Draw the border stones for 'field' if it is a border and 'visibility' is
215
216=== added file 'src/graphic/gl/grid_program.cc'
217--- src/graphic/gl/grid_program.cc 1970-01-01 00:00:00 +0000
218+++ src/graphic/gl/grid_program.cc 2019-04-24 17:07:20 +0000
219@@ -0,0 +1,89 @@
220+/*
221+ * Copyright (C) 2006-2019 by the Widelands Development Team
222+ *
223+ * This program is free software; you can redistribute it and/or
224+ * modify it under the terms of the GNU General Public License
225+ * as published by the Free Software Foundation; either version 2
226+ * of the License, or (at your option) any later version.
227+ *
228+ * This program is distributed in the hope that it will be useful,
229+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
230+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
231+ * GNU General Public License for more details.
232+ *
233+ * You should have received a copy of the GNU General Public License
234+ * along with this program; if not, write to the Free Software
235+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
236+ *
237+ */
238+
239+#include "graphic/gl/grid_program.h"
240+
241+#include "graphic/gl/coordinate_conversion.h"
242+#include "graphic/gl/fields_to_draw.h"
243+#include "graphic/gl/utils.h"
244+#include "graphic/texture.h"
245+
246+GridProgram::GridProgram() {
247+ gl_program_.build("grid");
248+
249+ attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
250+
251+ u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
252+}
253+
254+void GridProgram::gl_draw(int gl_texture, float z_value) {
255+ glUseProgram(gl_program_.object());
256+
257+ auto& gl_state = Gl::State::instance();
258+
259+ gl_array_buffer_.bind();
260+ gl_array_buffer_.update(vertices_);
261+
262+ Gl::vertex_attrib_pointer(
263+ attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
264+
265+ gl_state.bind(GL_TEXTURE0, gl_texture);
266+
267+ glUniform1f(u_z_value_, z_value);
268+
269+ glDrawArrays(GL_LINES, 0, vertices_.size());
270+}
271+
272+void GridProgram::add_vertex(const FieldsToDraw::Field& field) {
273+ vertices_.emplace_back();
274+ PerVertexData& back = vertices_.back();
275+ back.gl_x = field.gl_position.x;
276+ back.gl_y = field.gl_position.y;
277+}
278+
279+void GridProgram::draw(uint32_t texture_id,
280+ const FieldsToDraw& fields_to_draw,
281+ float z_value) {
282+ vertices_.clear();
283+ vertices_.reserve(fields_to_draw.size() * 2);
284+
285+ for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
286+ const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
287+
288+ // Southwestern edge
289+ if (field.bln_index != FieldsToDraw::kInvalidIndex) {
290+ add_vertex(fields_to_draw.at(current_index));
291+ add_vertex(fields_to_draw.at(field.bln_index));
292+ }
293+
294+ // Southeastern edge
295+ if (field.brn_index != FieldsToDraw::kInvalidIndex) {
296+ add_vertex(fields_to_draw.at(current_index));
297+ add_vertex(fields_to_draw.at(field.brn_index));
298+ }
299+
300+ // Eastern edge
301+ if (field.rn_index != FieldsToDraw::kInvalidIndex) {
302+ add_vertex(fields_to_draw.at(current_index));
303+ add_vertex(fields_to_draw.at(field.rn_index));
304+ }
305+ }
306+
307+ gl_draw(texture_id, z_value);
308+}
309
310=== added file 'src/graphic/gl/grid_program.h'
311--- src/graphic/gl/grid_program.h 1970-01-01 00:00:00 +0000
312+++ src/graphic/gl/grid_program.h 2019-04-24 17:07:20 +0000
313@@ -0,0 +1,72 @@
314+/*
315+ * Copyright (C) 2006-2019 by the Widelands Development Team
316+ *
317+ * This program is free software; you can redistribute it and/or
318+ * modify it under the terms of the GNU General Public License
319+ * as published by the Free Software Foundation; either version 2
320+ * of the License, or (at your option) any later version.
321+ *
322+ * This program is distributed in the hope that it will be useful,
323+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
324+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
325+ * GNU General Public License for more details.
326+ *
327+ * You should have received a copy of the GNU General Public License
328+ * along with this program; if not, write to the Free Software
329+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
330+ *
331+ */
332+
333+#ifndef WL_GRAPHIC_GL_GRID_PROGRAM_H
334+#define WL_GRAPHIC_GL_GRID_PROGRAM_H
335+
336+#include <vector>
337+
338+#include "base/vector.h"
339+#include "graphic/gl/fields_to_draw.h"
340+#include "graphic/gl/utils.h"
341+#include "logic/description_maintainer.h"
342+#include "logic/map_objects/world/terrain_description.h"
343+
344+class GridProgram {
345+public:
346+ // Compiles the program. Throws on errors.
347+ GridProgram();
348+
349+ // Draws the grid layer
350+ void draw(uint32_t texture_id,
351+ const FieldsToDraw& fields_to_draw,
352+ float z_value);
353+
354+private:
355+ struct PerVertexData {
356+ float gl_x;
357+ float gl_y;
358+ };
359+ static_assert(sizeof(PerVertexData) == 8, "Wrong padding.");
360+
361+ void gl_draw(int gl_texture, float z_value);
362+
363+ // Adds a vertex to the end of vertices with data from 'field'.
364+ void add_vertex(const FieldsToDraw::Field& field);
365+
366+ // The program used for drawing the grid layer
367+ Gl::Program gl_program_;
368+
369+ // The buffer that will contain 'vertices_' for rendering.
370+ Gl::Buffer<PerVertexData> gl_array_buffer_;
371+
372+ // Attributes.
373+ GLint attr_position_;
374+
375+ // Uniforms.
376+ GLint u_z_value_;
377+
378+ // Objects below are kept around to avoid memory allocations on each frame.
379+ // They could theoretically also be recreated.
380+ std::vector<PerVertexData> vertices_;
381+
382+ DISALLOW_COPY_AND_ASSIGN(GridProgram);
383+};
384+
385+#endif // end of include guard: WL_GRAPHIC_GL_GRID_PROGRAM_H
386
387=== added file 'src/graphic/gl/workarea_program.cc'
388--- src/graphic/gl/workarea_program.cc 1970-01-01 00:00:00 +0000
389+++ src/graphic/gl/workarea_program.cc 2019-04-24 17:07:20 +0000
390@@ -0,0 +1,134 @@
391+/*
392+ * Copyright (C) 2006-2019 by the Widelands Development Team
393+ *
394+ * This program is free software; you can redistribute it and/or
395+ * modify it under the terms of the GNU General Public License
396+ * as published by the Free Software Foundation; either version 2
397+ * of the License, or (at your option) any later version.
398+ *
399+ * This program is distributed in the hope that it will be useful,
400+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
401+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
402+ * GNU General Public License for more details.
403+ *
404+ * You should have received a copy of the GNU General Public License
405+ * along with this program; if not, write to the Free Software
406+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
407+ *
408+ */
409+
410+#include "graphic/gl/workarea_program.h"
411+
412+#include "graphic/gl/coordinate_conversion.h"
413+#include "graphic/gl/fields_to_draw.h"
414+#include "graphic/gl/utils.h"
415+#include "graphic/texture.h"
416+
417+WorkareaProgram::WorkareaProgram() {
418+ gl_program_.build("workarea");
419+
420+ attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
421+ attr_overlay_ = glGetAttribLocation(gl_program_.object(), "attr_overlay");
422+
423+ u_z_value_ = glGetUniformLocation(gl_program_.object(), "u_z_value");
424+}
425+
426+void WorkareaProgram::gl_draw(int gl_texture, float z_value) {
427+ glUseProgram(gl_program_.object());
428+
429+ auto& gl_state = Gl::State::instance();
430+ gl_state.enable_vertex_attrib_array(
431+ {attr_position_, attr_overlay_});
432+
433+ gl_array_buffer_.bind();
434+ gl_array_buffer_.update(vertices_);
435+
436+ Gl::vertex_attrib_pointer(
437+ attr_position_, 2, sizeof(PerVertexData), offsetof(PerVertexData, gl_x));
438+ Gl::vertex_attrib_pointer(
439+ attr_overlay_, 4, sizeof(PerVertexData), offsetof(PerVertexData, overlay_r));
440+
441+ gl_state.bind(GL_TEXTURE0, gl_texture);
442+
443+ glUniform1f(u_z_value_, z_value);
444+
445+ glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
446+}
447+
448+constexpr uint8_t kWorkareaTransparency = 127;
449+static RGBAColor workarea_colors[] {
450+ RGBAColor(63, 31, 127, kWorkareaTransparency), // All three circles
451+ RGBAColor(127, 63, 0, kWorkareaTransparency), // Medium and outer circle
452+ RGBAColor(0, 127, 0, kWorkareaTransparency), // Outer circle
453+ RGBAColor(63, 0, 127, kWorkareaTransparency), // Inner and medium circle
454+ RGBAColor(127, 0, 0, kWorkareaTransparency), // Medium circle
455+ RGBAColor(0, 0, 127, kWorkareaTransparency), // Inner circle
456+};
457+static inline RGBAColor apply_color(RGBAColor c1, RGBAColor c2) {
458+ uint8_t r = (c1.r * c1.a + c2.r * c2.a) / (c1.a + c2.a);
459+ uint8_t g = (c1.g * c1.a + c2.g * c2.a) / (c1.a + c2.a);
460+ uint8_t b = (c1.b * c1.a + c2.b * c2.a) / (c1.a + c2.a);
461+ uint8_t a = (c1.a + c2.a) / 2;
462+ return RGBAColor(r, g, b, a);
463+}
464+
465+void WorkareaProgram::add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay) {
466+ vertices_.emplace_back();
467+ PerVertexData& back = vertices_.back();
468+
469+ back.gl_x = field.gl_position.x;
470+ back.gl_y = field.gl_position.y;
471+ back.overlay_r = overlay.r / 255.f;
472+ back.overlay_g = overlay.g / 255.f;
473+ back.overlay_b = overlay.b / 255.f;
474+ back.overlay_a = overlay.a / 255.f;
475+}
476+
477+void WorkareaProgram::draw(uint32_t texture_id,
478+ Workareas workarea,
479+ const FieldsToDraw& fields_to_draw,
480+ float z_value) {
481+ vertices_.clear();
482+ vertices_.reserve(fields_to_draw.size() * 3);
483+
484+ for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
485+ const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
486+
487+ // The bottom right neighbor fields_to_draw is needed for both triangles
488+ // associated with this field. If it is not in fields_to_draw, there is no need to
489+ // draw any triangles.
490+ if (field.brn_index == FieldsToDraw::kInvalidIndex) {
491+ continue;
492+ }
493+
494+ // Down triangle.
495+ if (field.bln_index != FieldsToDraw::kInvalidIndex) {
496+ RGBAColor color(0, 0, 0, 0);
497+ for (const std::map<Widelands::TCoords<>, uint8_t>& wa_map : workarea) {
498+ const auto it = wa_map.find(Widelands::TCoords<>(field.fcoords, Widelands::TriangleIndex::D));
499+ if (it != wa_map.end()) {
500+ color = apply_color(color, workarea_colors[it->second]);
501+ }
502+ }
503+ add_vertex(fields_to_draw.at(current_index), color);
504+ add_vertex(fields_to_draw.at(field.bln_index), color);
505+ add_vertex(fields_to_draw.at(field.brn_index), color);
506+ }
507+
508+ // Right triangle.
509+ if (field.rn_index != FieldsToDraw::kInvalidIndex) {
510+ RGBAColor color(0, 0, 0, 0);
511+ for (const std::map<Widelands::TCoords<>, uint8_t>& wa_map : workarea) {
512+ const auto it = wa_map.find(Widelands::TCoords<>(field.fcoords, Widelands::TriangleIndex::R));
513+ if (it != wa_map.end()) {
514+ color = apply_color(color, workarea_colors[it->second]);
515+ }
516+ }
517+ add_vertex(fields_to_draw.at(current_index), color);
518+ add_vertex(fields_to_draw.at(field.brn_index), color);
519+ add_vertex(fields_to_draw.at(field.rn_index), color);
520+ }
521+ }
522+
523+ gl_draw(texture_id, z_value);
524+}
525
526=== added file 'src/graphic/gl/workarea_program.h'
527--- src/graphic/gl/workarea_program.h 1970-01-01 00:00:00 +0000
528+++ src/graphic/gl/workarea_program.h 2019-04-24 17:07:20 +0000
529@@ -0,0 +1,78 @@
530+/*
531+ * Copyright (C) 2006-2019 by the Widelands Development Team
532+ *
533+ * This program is free software; you can redistribute it and/or
534+ * modify it under the terms of the GNU General Public License
535+ * as published by the Free Software Foundation; either version 2
536+ * of the License, or (at your option) any later version.
537+ *
538+ * This program is distributed in the hope that it will be useful,
539+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
540+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
541+ * GNU General Public License for more details.
542+ *
543+ * You should have received a copy of the GNU General Public License
544+ * along with this program; if not, write to the Free Software
545+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
546+ *
547+ */
548+
549+#ifndef WL_GRAPHIC_GL_WORKAREA_PROGRAM_H
550+#define WL_GRAPHIC_GL_WORKAREA_PROGRAM_H
551+
552+#include <vector>
553+
554+#include "base/vector.h"
555+#include "graphic/gl/fields_to_draw.h"
556+#include "graphic/gl/utils.h"
557+#include "logic/description_maintainer.h"
558+#include "logic/map_objects/world/terrain_description.h"
559+
560+class WorkareaProgram {
561+public:
562+ // Compiles the program. Throws on errors.
563+ WorkareaProgram();
564+
565+ // Draws the workarea overlay.
566+ void draw(uint32_t texture_id,
567+ Workareas workarea,
568+ const FieldsToDraw& fields_to_draw,
569+ float z_value);
570+
571+private:
572+ struct PerVertexData {
573+ float gl_x;
574+ float gl_y;
575+ float overlay_r;
576+ float overlay_g;
577+ float overlay_b;
578+ float overlay_a;
579+ };
580+ static_assert(sizeof(PerVertexData) == 24, "Wrong padding.");
581+
582+ void gl_draw(int gl_texture, float z_value);
583+
584+ // Adds a vertex to the end of vertices with data from 'field' in order to apply the specified 'overlay'.
585+ void add_vertex(const FieldsToDraw::Field& field, RGBAColor overlay);
586+
587+ // The program used for drawing the workarea overlay.
588+ Gl::Program gl_program_;
589+
590+ // The buffer that will contain 'vertices_' for rendering.
591+ Gl::Buffer<PerVertexData> gl_array_buffer_;
592+
593+ // Attributes.
594+ GLint attr_position_;
595+ GLint attr_overlay_;
596+
597+ // Uniforms.
598+ GLint u_z_value_;
599+
600+ // Objects below are kept around to avoid memory allocations on each frame.
601+ // They could theoretically also be recreated.
602+ std::vector<PerVertexData> vertices_;
603+
604+ DISALLOW_COPY_AND_ASSIGN(WorkareaProgram);
605+};
606+
607+#endif // end of include guard: WL_GRAPHIC_GL_WORKAREA_PROGRAM_H
608
609=== modified file 'src/graphic/render_queue.cc'
610--- src/graphic/render_queue.cc 2019-02-23 11:00:49 +0000
611+++ src/graphic/render_queue.cc 2019-04-24 17:07:20 +0000
612@@ -28,8 +28,10 @@
613 #include "graphic/gl/dither_program.h"
614 #include "graphic/gl/draw_line_program.h"
615 #include "graphic/gl/fill_rect_program.h"
616+#include "graphic/gl/grid_program.h"
617 #include "graphic/gl/road_program.h"
618 #include "graphic/gl/terrain_program.h"
619+#include "graphic/gl/workarea_program.h"
620
621 namespace {
622
623@@ -142,6 +144,8 @@
624 : next_z_(1),
625 terrain_program_(new TerrainProgram()),
626 dither_program_(new DitherProgram()),
627+ workarea_program_(new WorkareaProgram()),
628+ grid_program_(new GridProgram()),
629 road_program_(new RoadProgram()) {
630 }
631
632@@ -164,6 +168,8 @@
633 case Program::kRect:
634 case Program::kTerrainBase:
635 case Program::kTerrainDither:
636+ case Program::kTerrainWorkarea:
637+ case Program::kTerrainGrid:
638 case Program::kTerrainRoad:
639 /* all fallthroughs intended */
640 break;
641@@ -251,6 +257,20 @@
642 ++i;
643 } break;
644
645+ case Program::kTerrainWorkarea: {
646+ ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
647+ workarea_program_->draw(item.terrain_arguments.terrains->get(0).get_texture(0).blit_data().texture_id,
648+ item.terrain_arguments.workareas, *item.terrain_arguments.fields_to_draw, item.z_value);
649+ ++i;
650+ } break;
651+
652+ case Program::kTerrainGrid: {
653+ ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
654+ grid_program_->draw(item.terrain_arguments.terrains->get(0).get_texture(0).blit_data().texture_id,
655+ *item.terrain_arguments.fields_to_draw, item.z_value);
656+ ++i;
657+ } break;
658+
659 case Program::kTerrainRoad: {
660 ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
661 road_program_->draw(item.terrain_arguments.renderbuffer_width,
662
663=== modified file 'src/graphic/render_queue.h'
664--- src/graphic/render_queue.h 2019-02-23 11:00:49 +0000
665+++ src/graphic/render_queue.h 2019-04-24 17:07:20 +0000
666@@ -36,8 +36,10 @@
667 #include "logic/map_objects/world/terrain_description.h"
668
669 class DitherProgram;
670+class GridProgram;
671 class RoadProgram;
672 class TerrainProgram;
673+class WorkareaProgram;
674
675 // The RenderQueue is a singleton implementing the concept of deferred
676 // rendering: Every rendering call that pretends to draw onto the screen will
677@@ -82,6 +84,8 @@
678 enum Program {
679 kTerrainBase,
680 kTerrainDither,
681+ kTerrainWorkarea,
682+ kTerrainGrid,
683 kTerrainRoad,
684 kBlit,
685 kRect,
686@@ -119,6 +123,7 @@
687 int renderbuffer_height = 0;
688 const DescriptionMaintainer<Widelands::TerrainDescription>* terrains = nullptr;
689 const FieldsToDraw* fields_to_draw = nullptr;
690+ Workareas workareas;
691 float scale = 1.f;
692 Rectf destination_rect = Rectf(0.f, 0.f, 0.f, 0.f);
693 };
694@@ -178,6 +183,8 @@
695
696 std::unique_ptr<TerrainProgram> terrain_program_;
697 std::unique_ptr<DitherProgram> dither_program_;
698+ std::unique_ptr<WorkareaProgram> workarea_program_;
699+ std::unique_ptr<GridProgram> grid_program_;
700 std::unique_ptr<RoadProgram> road_program_;
701
702 std::vector<Item> blended_items_;
703
704=== modified file 'src/logic/widelands_geometry.h'
705--- src/logic/widelands_geometry.h 2019-02-23 11:00:49 +0000
706+++ src/logic/widelands_geometry.h 2019-04-24 17:07:20 +0000
707@@ -21,6 +21,8 @@
708 #define WL_LOGIC_WIDELANDS_GEOMETRY_H
709
710 #include <cmath>
711+#include <map>
712+#include <set>
713 #include <tuple>
714
715 #include <stdint.h>
716@@ -155,4 +157,6 @@
717 };
718 } // namespace Widelands
719
720+using Workareas = std::set<std::map<Widelands::TCoords<>, uint8_t>>;
721+
722 #endif // end of include guard: WL_LOGIC_WIDELANDS_GEOMETRY_H
723
724=== modified file 'src/wui/buildingwindow.cc'
725--- src/wui/buildingwindow.cc 2019-03-22 18:52:17 +0000
726+++ src/wui/buildingwindow.cc 2019-04-24 17:07:20 +0000
727@@ -320,7 +320,7 @@
728 if (!wa_info->empty()) {
729 toggle_workarea_ =
730 new UI::Button(capsbuttons, "workarea", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
731- g_gr->images().get("images/wui/overlays/workarea123.png"));
732+ g_gr->images().get("images/wui/buildings/toggle_workarea.png"));
733 toggle_workarea_->sigclicked.connect(
734 boost::bind(&BuildingWindow::toggle_workarea, boost::ref(*this)));
735
736
737=== modified file 'src/wui/interactive_base.cc'
738--- src/wui/interactive_base.cc 2019-04-24 06:01:37 +0000
739+++ src/wui/interactive_base.cc 2019-04-24 17:07:20 +0000
740@@ -112,14 +112,7 @@
741 avg_usframetime_(0),
742 buildroad_(nullptr),
743 road_build_player_(0),
744- unique_window_handler_(new UniqueWindowHandler()),
745- // Start at idx 0 for 2 enhancements, idx 3 for 1, idx 5 if none
746- workarea_pics_{g_gr->images().get("images/wui/overlays/workarea123.png"),
747- g_gr->images().get("images/wui/overlays/workarea23.png"),
748- g_gr->images().get("images/wui/overlays/workarea3.png"),
749- g_gr->images().get("images/wui/overlays/workarea12.png"),
750- g_gr->images().get("images/wui/overlays/workarea2.png"),
751- g_gr->images().get("images/wui/overlays/workarea1.png")} {
752+ unique_window_handler_(new UniqueWindowHandler()) {
753
754 // Load the buildhelp icons.
755 {
756@@ -200,8 +193,20 @@
757 return nullptr;
758 }
759
760-bool InteractiveBase::has_workarea_preview(const Widelands::Coords& coords) const {
761- return workarea_previews_.count(coords) == 1;
762+bool InteractiveBase::has_workarea_preview(const Widelands::Coords& coords, const Widelands::Map* map) const {
763+ if (!map) {
764+ return workarea_previews_.count(coords) == 1;
765+ }
766+ for (const auto& pair : workarea_previews_) {
767+ uint32_t radius = 0;
768+ for (const auto& p : *pair.second) {
769+ radius = std::max(radius, p.first);
770+ }
771+ if (map->calc_distance(coords, pair.first) <= radius) {
772+ return true;
773+ }
774+ }
775+ return false;
776 }
777
778 UniqueWindowHandler& InteractiveBase::unique_windows() {
779@@ -303,12 +308,53 @@
780 workarea_previews_[coords] = &workarea_info;
781 }
782
783-std::map<Coords, const Image*>
784-InteractiveBase::get_workarea_overlays(const Widelands::Map& map) const {
785- std::map<Coords, const Image*> result;
786- for (const auto& pair : workarea_previews_) {
787- const Coords& coords = pair.first;
788- const WorkareaInfo* workarea_info = pair.second;
789+/* Helper function to get the correct index for graphic/gl/workarea_program.cc::workarea_colors .
790+ * a, b, c are the indices for the three nodes bordering this triangle.
791+ * This function returns the biggest workarea type that matches all three corners.
792+ * The indices stand for:
793+ * 0 – all three circles
794+ * 1 – medium and outer circle
795+ * 2 – outer circle
796+ * 3 – inner and medium circle
797+ * 4 – medium circle
798+ * 5 – inner circle
799+ * We currently assume that no building will have more than three workarea circles.
800+ */
801+static uint8_t workarea_max(uint8_t a, uint8_t b, uint8_t c) {
802+ // Whether all nodes are part of the inner circle
803+ bool inner = (a == 0 || a == 3 || a == 5) && (b == 0 || b == 3 || b == 5) && (c == 0 || c == 3 || c == 5);
804+ // Whether all nodes are part of the medium circle
805+ bool medium = (a == 0 || a == 1 || a == 3 || a == 4) && (b == 0 || b == 1 || b == 3 || b == 4) &&
806+ (c == 0 || c == 1 || c == 3 || c == 4);
807+ // Whether all nodes are part of the outer circle
808+ bool outer = a <= 2 && b <= 2 && c <= 2;
809+
810+ if (medium) {
811+ if (outer && inner) {
812+ return 0;
813+ } else if (inner) {
814+ return 3;
815+ } else if (outer) {
816+ return 1;
817+ } else {
818+ return 4;
819+ }
820+ } else if (outer) {
821+ assert(!inner);
822+ return 2;
823+ } else {
824+ assert(inner);
825+ return 5;
826+ }
827+}
828+
829+Workareas InteractiveBase::get_workarea_overlays(const Widelands::Map& map) const {
830+ Workareas result_set;
831+ for (const auto& wa_pair : workarea_previews_) {
832+ std::map<Coords, uint8_t> intermediate_result;
833+ const Coords& coords = wa_pair.first;
834+ const WorkareaInfo* workarea_info = wa_pair.second;
835+ intermediate_result[coords] = 0;
836 WorkareaInfo::size_type wa_index;
837 switch (workarea_info->size()) {
838 case 0:
839@@ -335,13 +381,36 @@
840 hollow_area.radius = it->first;
841 Widelands::MapHollowRegion<> mr(map, hollow_area);
842 do {
843- result[mr.location()] = workarea_pics_[wa_index];
844+ intermediate_result[mr.location()] = wa_index;
845 } while (mr.advance(map));
846 wa_index++;
847 hollow_area.hole_radius = hollow_area.radius;
848 }
849+
850+ std::map<TCoords<>, uint8_t> result;
851+ for (const auto& pair : intermediate_result) {
852+ Coords c;
853+ map.get_brn(pair.first, &c);
854+ const auto brn = intermediate_result.find(c);
855+ if (brn == intermediate_result.end()) {
856+ continue;
857+ }
858+ map.get_bln(pair.first, &c);
859+ const auto bln = intermediate_result.find(c);
860+ map.get_rn(pair.first, &c);
861+ const auto rn = intermediate_result.find(c);
862+ if (bln != intermediate_result.end()) {
863+ result[TCoords<>(pair.first, Widelands::TriangleIndex::D)] = workarea_max(
864+ pair.second, brn->second, bln->second);
865+ }
866+ if (rn != intermediate_result.end()) {
867+ result[TCoords<>(pair.first, Widelands::TriangleIndex::R)] = workarea_max(
868+ pair.second, brn->second, rn->second);
869+ }
870+ }
871+ result_set.emplace(result);
872 }
873- return result;
874+ return result_set;
875 }
876
877 void InteractiveBase::hide_workarea(const Widelands::Coords& coords) {
878
879=== modified file 'src/wui/interactive_base.h'
880--- src/wui/interactive_base.h 2019-04-19 07:27:15 +0000
881+++ src/wui/interactive_base.h 2019-04-24 17:07:20 +0000
882@@ -231,7 +231,7 @@
883 TextToDraw get_text_to_draw() const;
884
885 // Returns the current overlays for the work area previews.
886- std::map<Widelands::Coords, const Image*> get_workarea_overlays(const Widelands::Map& map) const;
887+ Workareas get_workarea_overlays(const Widelands::Map& map) const;
888
889 // Returns the 'BuildhelpOverlay' for 'caps' or nullptr if there is no help
890 // to be displayed on this field.
891@@ -241,8 +241,10 @@
892 return road_building_overlays_;
893 }
894
895- /// Returns true if there is a workarea preview being shown at the given coordinates
896- bool has_workarea_preview(const Widelands::Coords& coords) const;
897+ /// Returns true if there is a workarea preview being shown at the given coordinates.
898+ /// If 'map' is 0, checks only if the given coords are the center of a workarea;
899+ /// otherwise checks if the coords are within any workarea.
900+ bool has_workarea_preview(const Widelands::Coords& coords, const Widelands::Map* map = nullptr) const;
901
902 /// Returns true if the current player is allowed to hear sounds from map objects on this field
903 virtual bool player_hears_field(const Widelands::Coords& coords) const = 0;
904@@ -304,7 +306,6 @@
905
906 UI::UniqueWindow::Registry debugconsole_;
907 std::unique_ptr<UniqueWindowHandler> unique_window_handler_;
908- std::vector<const Image*> workarea_pics_;
909 BuildhelpOverlay buildhelp_overlays_[Widelands::Field::Buildhelp_None];
910 };
911
912
913=== modified file 'src/wui/interactive_player.cc'
914--- src/wui/interactive_player.cc 2019-04-24 06:01:37 +0000
915+++ src/wui/interactive_player.cc 2019-04-24 17:07:20 +0000
916@@ -160,7 +160,8 @@
917 bool const multiplayer)
918 : InteractiveGameBase(g, global_s, NONE, multiplayer),
919 auto_roadbuild_mode_(global_s.get_bool("auto_roadbuild_mode", true)),
920- flag_to_connect_(Widelands::Coords::null()) {
921+ flag_to_connect_(Widelands::Coords::null()),
922+ grid_marker_pic_(g_gr->images().get("images/wui/overlays/grid_marker.png")) {
923 add_toolbar_button(
924 "wui/menus/menu_options_menu", "options_menu", _("Main menu"), &options_, true);
925 options_.open_window = [this] { new GameOptionsMenu(*this, options_, main_windows_); };
926@@ -286,9 +287,9 @@
927 const Widelands::Map& map = gbase.map();
928 const uint32_t gametime = gbase.get_gametime();
929
930- auto* fields_to_draw = given_map_view->draw_terrain(gbase, dst);
931+ Workareas workareas = get_workarea_overlays(map);
932+ auto* fields_to_draw = given_map_view->draw_terrain(gbase, workareas, false, dst);
933 const auto& road_building = road_building_overlays();
934- const std::map<Widelands::Coords, const Image*> workarea_overlays = get_workarea_overlays(map);
935
936 const float scale = 1.f / given_map_view->view().zoom;
937
938@@ -329,13 +330,10 @@
939 }
940 }
941
942- // Draw work area previews.
943- {
944- const auto it = workarea_overlays.find(f->fcoords);
945- if (it != workarea_overlays.end()) {
946- blit_field_overlay(dst, *f, it->second,
947- Vector2i(it->second->width() / 2, it->second->height() / 2), scale);
948- }
949+ // Draw work area markers.
950+ if (has_workarea_preview(f->fcoords, &map)) {
951+ blit_field_overlay(dst, *f, grid_marker_pic_,
952+ Vector2i(grid_marker_pic_->width() / 2, grid_marker_pic_->height() / 2), scale);
953 }
954
955 if (f->vision > 0) {
956
957=== modified file 'src/wui/interactive_player.h'
958--- src/wui/interactive_player.h 2019-03-14 23:06:02 +0000
959+++ src/wui/interactive_player.h 2019-04-24 17:07:20 +0000
960@@ -91,6 +91,8 @@
961 UI::UniqueWindow::Registry objectives_;
962 UI::UniqueWindow::Registry encyclopedia_;
963 UI::UniqueWindow::Registry message_menu_;
964+
965+ const Image* grid_marker_pic_;
966 };
967
968 #endif // end of include guard: WL_WUI_INTERACTIVE_PLAYER_H
969
970=== modified file 'src/wui/interactive_spectator.cc'
971--- src/wui/interactive_spectator.cc 2019-04-24 06:01:37 +0000
972+++ src/wui/interactive_spectator.cc 2019-04-24 17:07:20 +0000
973@@ -116,12 +116,11 @@
974
975 const Widelands::Game& the_game = game();
976 const Widelands::Map& map = the_game.map();
977- auto* fields_to_draw = given_map_view->draw_terrain(the_game, dst);
978+ auto* fields_to_draw = given_map_view->draw_terrain(the_game, get_workarea_overlays(map), false, dst);
979 const float scale = 1.f / given_map_view->view().zoom;
980 const uint32_t gametime = the_game.get_gametime();
981
982 const auto text_to_draw = get_text_to_draw();
983- const std::map<Widelands::Coords, const Image*> workarea_overlays = get_workarea_overlays(map);
984 for (size_t idx = 0; idx < fields_to_draw->size(); ++idx) {
985 const FieldsToDraw::Field& field = fields_to_draw->at(idx);
986
987@@ -137,13 +136,6 @@
988 bob->draw(the_game, text_to_draw, field.rendertarget_pixel, field.fcoords, scale, dst);
989 }
990
991- // Draw work area previews.
992- const auto it = workarea_overlays.find(field.fcoords);
993- if (it != workarea_overlays.end()) {
994- const Image* pic = it->second;
995- blit_field_overlay(dst, field, pic, Vector2i(pic->width() / 2, pic->height() / 2), scale);
996- }
997-
998 // Draw build help.
999 if (buildhelp()) {
1000 auto caps = Widelands::NodeCaps::CAPS_NONE;
1001
1002=== modified file 'src/wui/mapview.cc'
1003--- src/wui/mapview.cc 2019-04-23 16:24:40 +0000
1004+++ src/wui/mapview.cc 2019-04-24 17:07:20 +0000
1005@@ -339,7 +339,8 @@
1006 NEVER_HERE();
1007 }
1008
1009-FieldsToDraw* MapView::draw_terrain(const Widelands::EditorGameBase& egbase, RenderTarget* dst) {
1010+FieldsToDraw* MapView::draw_terrain(const Widelands::EditorGameBase& egbase,
1011+ Workareas workarea, bool grid, RenderTarget* dst) {
1012 uint32_t now = SDL_GetTicks();
1013 while (!view_plans_.empty()) {
1014 auto& plan = view_plans_.front();
1015@@ -383,7 +384,7 @@
1016
1017 fields_to_draw_.reset(egbase, view_.viewpoint, view_.zoom, dst);
1018 const float scale = 1.f / view_.zoom;
1019- ::draw_terrain(egbase, fields_to_draw_, scale, dst);
1020+ ::draw_terrain(egbase, fields_to_draw_, scale, workarea, grid, dst);
1021 return &fields_to_draw_;
1022 }
1023
1024
1025=== modified file 'src/wui/mapview.h'
1026--- src/wui/mapview.h 2019-03-26 02:56:03 +0000
1027+++ src/wui/mapview.h 2019-04-24 17:07:20 +0000
1028@@ -172,7 +172,7 @@
1029 // Schedules drawing of the terrain of this MapView. The returned value can
1030 // be used to override contents of 'fields_to_draw' for player knowledge and
1031 // visibility, and to correctly draw map objects, overlays and text.
1032- FieldsToDraw* draw_terrain(const Widelands::EditorGameBase& egbase, RenderTarget* dst);
1033+ FieldsToDraw* draw_terrain(const Widelands::EditorGameBase& egbase, Workareas workarea, bool grid, RenderTarget* dst);
1034
1035 // Not overriden from UI::Panel, instead we expect to be passed the data through.
1036 bool handle_mousepress(uint8_t btn, int32_t x, int32_t y);

Subscribers

People subscribed via source and target branches

to status/vote changes: