Project Alice
Loading...
Searching...
No Matches
map_borders.cpp
Go to the documentation of this file.
1#include "map.hpp"
2
3#include "province.hpp"
4#include "system_state.hpp"
6
7namespace map {
9 UP_LEFT = 1 << 7,
10 UP_RIGHT = 1 << 6,
11 DOWN_LEFT = 1 << 5,
12 DOWN_RIGHT = 1 << 4,
13 UP = 1 << 3,
14 DOWN = 1 << 2,
15 LEFT = 1 << 1,
16 RIGHT = 1 << 0,
17};
18
20 UP_LEFT = 0x01,
21 UP_RIGHT = uint8_t(0x01 << 2),
22 DOWN_LEFT = uint8_t(0x01 << 4),
23 DOWN_RIGHT = uint8_t(0x01 << 6),
24 NOTHING = 0,
25};
26
29 struct information {
31 information(int32_t index_, int32_t id_) : index{ index_ }, id{ id_ } {}
32 int32_t index = -1;
33 int32_t id = -1;
34 };
39};
40
41// Will check if there is an border there already and extend if it can
42bool extend_if_possible(uint32_t x, int32_t border_id, direction dir, std::vector<border_direction>& last_row, std::vector<border_direction>& current_row, glm::vec2 map_size, std::vector<curved_line_vertex>& border_vertices) {
43 if((dir & direction::LEFT) != 0 && x == 0)
44 return false;
45
46 border_direction::information direction_information;
47 switch(dir) {
48 case direction::UP:
49 direction_information = last_row[x].down;
50 break;
51 case direction::DOWN:
52 direction_information = current_row[x].up;
53 break;
54 case direction::LEFT:
55 direction_information = current_row[x - 1].right;
56 break;
58 direction_information = current_row[x].left;
59 break;
60 default:
61 return false;
62 }
63 if(direction_information.id != border_id)
64 return false;
65
66 auto border_index = direction_information.index;
67 if(border_index == -1)
68 return false;
69
70 switch(dir) {
71 case direction::UP:
72 case direction::DOWN:
73 border_vertices[border_index + 2].position_.y += 0.5f / map_size.y;
74 border_vertices[border_index + 3].position_.y += 0.5f / map_size.y;
75 border_vertices[border_index + 4].position_.y += 0.5f / map_size.y;
76 break;
77 case direction::LEFT:
79 border_vertices[border_index + 2].position_.x += 0.5f / map_size.x;
80 border_vertices[border_index + 3].position_.x += 0.5f / map_size.x;
81 border_vertices[border_index + 4].position_.x += 0.5f / map_size.x;
82 break;
83 default:
84 break;
85 }
86 switch(dir) {
87 case direction::UP:
88 current_row[x].up = direction_information;
89 break;
90 case direction::DOWN:
91 current_row[x].down = direction_information;
92 break;
93 case direction::LEFT:
94 current_row[x].left = direction_information;
95 break;
97 current_row[x].right = direction_information;
98 break;
99 default:
100 break;
101 }
102 return true;
103};
104
105// Get the index of the border from the province ids and create a new one if one doesn't exist
106int32_t get_border_index(uint16_t map_province_id1, uint16_t map_province_id2, parsers::scenario_building_context& context) {
107 auto province_id1 = province::from_map_id(map_province_id1);
108 auto province_id2 = province::from_map_id(map_province_id2);
109 auto border_index = context.state.world.get_province_adjacency_by_province_pair(province_id1, province_id2);
110 if(!border_index)
111 border_index = context.state.world.force_create_province_adjacency(province_id1, province_id2);
112 if(!province_id1 || !province_id2) {
113 context.state.world.province_adjacency_set_type(border_index, province::border::impassible_bit);
114 }
115 return border_index.index();
116}
117
119 border_vertices.clear();
120
121 glm::vec2 map_size(size_x, size_y);
122
123 diagonal_borders = std::vector<uint8_t>(size_x * size_y, 0);
124
125 // The borders of the current row and last row
126 for(uint32_t y = 0; y < size_y - 1; y++) {
127 for(uint32_t x = 0; x < size_x - 1; x++) {
128 auto prov_id_ul = province_id_map[(x + 0) + (y + 0) * size_x];
129 auto prov_id_ur = province_id_map[(x + 1) + (y + 0) * size_x];
130 auto prov_id_dl = province_id_map[(x + 0) + (y + 1) * size_x];
131 auto prov_id_dr = province_id_map[(x + 1) + (y + 1) * size_x];
132
133 if(prov_id_ur == prov_id_ul && prov_id_dl == prov_id_ul && prov_id_dr != prov_id_ur) { // Upper left
134 diagonal_borders[(x + 1) + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_LEFT);
135 }
136 if(prov_id_ul == prov_id_dl && prov_id_dl == prov_id_dr && prov_id_ur != prov_id_dr) { // Lower left
137 diagonal_borders[(x + 1) + y * uint32_t(map_size.x)] |= uint8_t(diagonal_border::DOWN_LEFT);
138 }
139 if(prov_id_ul == prov_id_ur && prov_id_ur == prov_id_dr && prov_id_dl != prov_id_ul) { // Upper right
140 diagonal_borders[x + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_RIGHT);
141 }
142 if(prov_id_dl == prov_id_dr && prov_id_ur == prov_id_dr && prov_id_ul != prov_id_dl) { // Lower right
144 }
145 if(prov_id_ul == prov_id_dr && prov_id_ur == prov_id_dl && prov_id_ul != prov_id_ur) {
146 if((prov_id_ul >= province::to_map_id(context.state.province_definitions.first_sea_province) || prov_id_ul == 0)
147 && (prov_id_ur < province::to_map_id(context.state.province_definitions.first_sea_province) && prov_id_ur != 0)) {
148
149 diagonal_borders[x + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_RIGHT);
150 diagonal_borders[(x + 1) + y * uint32_t(map_size.x)] |= uint8_t(diagonal_border::DOWN_LEFT);
151
152 } else if((prov_id_ur >= province::to_map_id(context.state.province_definitions.first_sea_province) || prov_id_ur == 0)
153 && (prov_id_ul < province::to_map_id(context.state.province_definitions.first_sea_province) && prov_id_ul != 0)) {
154
155 diagonal_borders[(x + 1) + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_LEFT);
157 }
158 }
159
160 if(prov_id_ul != prov_id_ur || prov_id_ul != prov_id_dl || prov_id_ul != prov_id_dr) {
161 if(prov_id_ul != prov_id_ur && prov_id_ur != 0 && prov_id_ul != 0) {
162 context.state.world.try_create_province_adjacency(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_ur));
163
164 auto aval = context.state.world.get_province_adjacency_by_province_pair(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_ur));
165 if((context.state.world.province_adjacency_get_type(aval) & province::border::non_adjacent_bit) != 0)
166 context.state.world.province_adjacency_get_type(aval) &= ~(province::border::non_adjacent_bit | province::border::impassible_bit);
167
168 }
169 if(prov_id_ul != prov_id_dl && prov_id_dl != 0 && prov_id_ul != 0) {
170 context.state.world.try_create_province_adjacency(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_dl));
171
172 auto aval = context.state.world.get_province_adjacency_by_province_pair(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_dl));
173 if((context.state.world.province_adjacency_get_type(aval) & province::border::non_adjacent_bit) != 0)
174 context.state.world.province_adjacency_get_type(aval) &= ~(province::border::non_adjacent_bit | province::border::impassible_bit);
175
176 }
177 if(prov_id_ul != prov_id_dr && prov_id_dr != 0 && prov_id_ul != 0) {
178 context.state.world.try_create_province_adjacency(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_dr));
179
180 auto aval = context.state.world.get_province_adjacency_by_province_pair(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_dr));
181 if((context.state.world.province_adjacency_get_type(aval) & province::border::non_adjacent_bit) != 0)
182 context.state.world.province_adjacency_get_type(aval) &= ~(province::border::non_adjacent_bit | province::border::impassible_bit);
183
184 }
185 }
186 }
187
188 {
189 // handle the international date line
190 auto prov_id_ul = province_id_map[((size_x - 1) + 0) + (y + 0) * size_x];
191 auto prov_id_ur = province_id_map[0 + (y + 0) * size_x];
192 auto prov_id_dl = province_id_map[((size_x - 1) + 0) + (y + 1) * size_x];
193 auto prov_id_dr = province_id_map[0 + (y + 1) * size_x];
194
195 if(prov_id_ur == prov_id_ul && prov_id_dl == prov_id_ul && prov_id_dr != prov_id_ur) { // Upper left
196 diagonal_borders[0 + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_LEFT);
197 }
198 if(prov_id_ul == prov_id_dl && prov_id_dl == prov_id_dr && prov_id_ur != prov_id_dr) { // Lower left
200 }
201 if(prov_id_ul == prov_id_ur && prov_id_ur == prov_id_dr && prov_id_dl != prov_id_ul) { // Upper right
202 diagonal_borders[(size_x - 1) + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_RIGHT);
203 }
204 if(prov_id_dl == prov_id_dr && prov_id_ur == prov_id_dr && prov_id_ul != prov_id_dl) { // Lower right
206 }
207 if(prov_id_ul == prov_id_dr && prov_id_ur == prov_id_dl && prov_id_ul != prov_id_ur) {
208 if((prov_id_ul >= province::to_map_id(context.state.province_definitions.first_sea_province) || prov_id_ul == 0)
209 && (prov_id_ur < province::to_map_id(context.state.province_definitions.first_sea_province) && prov_id_ur != 0)) {
210
211 diagonal_borders[(size_x - 1) + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_RIGHT);
213
214 } else if((prov_id_ur >= province::to_map_id(context.state.province_definitions.first_sea_province) || prov_id_ur == 0)
215 && (prov_id_ul < province::to_map_id(context.state.province_definitions.first_sea_province) && prov_id_ul != 0)) {
216
217 diagonal_borders[0 + (y + 1) * uint32_t(map_size.x)] |= uint8_t(diagonal_border::UP_LEFT);
219 }
220 }
221
222 if(prov_id_ul != prov_id_ur || prov_id_ul != prov_id_dl || prov_id_ul != prov_id_dr) {
223
224 if(prov_id_ul != prov_id_ur && prov_id_ur != 0 && prov_id_ul != 0) {
225 context.state.world.try_create_province_adjacency(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_ur));
226 }
227 if(prov_id_ul != prov_id_dl && prov_id_dl != 0 && prov_id_ul != 0) {
228 context.state.world.try_create_province_adjacency(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_dl));
229 }
230 if(prov_id_ul != prov_id_dr && prov_id_dr != 0 && prov_id_ul != 0) {
231 context.state.world.try_create_province_adjacency(province::from_map_id(prov_id_ul), province::from_map_id(prov_id_dr));
232 }
233 }
234 }
235 }
236}
237
238bool is_river(uint8_t river_data) {
239 return river_data < 250;
240}
241int32_t river_width(uint8_t river_data) {
242 auto result = 255 - (int32_t)(river_data) + 40;
243 assert(result >= 0);
244 return result;
245}
246bool is_river_source(uint8_t river_data) {
247 return river_data == 0;
248}
249bool is_river_merge(uint8_t river_data) {
250 return river_data == 1;
251}
252
253uint16_t display_data::safe_get_province(glm::ivec2 pt) {
254 while(pt.x < 0) {
255 pt.x += int32_t(size_x);
256 }
257 while(pt.x >= int32_t(size_x)) {
258 pt.x -= int32_t(size_x);
259 }
260 if(pt.y < 0) {
261 pt.y = 0;
262 }
263 if(pt.y >= int32_t(size_y)) {
264 pt.y = int32_t(size_y - 1);
265 }
266 return province_id_map[pt.x + pt.y * size_x];
267}
268
269bool coastal_point(sys::state& state, uint16_t a, uint16_t b) {
270 bool a_sea = a == 0 || province::from_map_id(a).index() >= state.province_definitions.first_sea_province.index();
271 bool b_sea = b == 0 || province::from_map_id(b).index() >= state.province_definitions.first_sea_province.index();
272 return a_sea != b_sea;
273}
274
275bool order_indifferent_compare(uint16_t a, uint16_t b, uint16_t c, uint16_t d) {
276 return (a == c && b == d) || (a == d && b == c);
277}
278
279std::vector<glm::vec2> make_border_section(display_data& dat, sys::state& state, std::vector<bool>& visited, uint16_t prov_prim, uint16_t prov_sec, int32_t start_x, int32_t start_y) {
280 std::vector<glm::vec2> points;
281
282 auto add_next = [&](int32_t i, int32_t j, bool& next_found) {
283 if(next_found)
284 return glm::ivec2(0, 0);
285 if(visited[i + j * dat.size_x])
286 return glm::ivec2(0, 0);
287 if(j % 2 == 0) {
288 if(order_indifferent_compare(prov_prim, prov_sec, dat.safe_get_province(glm::ivec2(i, j / 2)), dat.safe_get_province(glm::ivec2(i - 1, j / 2)))) {
289 visited[i + j * dat.size_x] = true;
290
291 points.push_back(glm::vec2(float(i), 0.5f + float(j) / 2.0f));
292 next_found = true;
293 return glm::ivec2(i, j);
294 }
295 } else {
296 if(order_indifferent_compare(prov_prim, prov_sec, dat.safe_get_province(glm::ivec2(i, j / 2)), dat.safe_get_province(glm::ivec2(i, j / 2 + 1)))) {
297 visited[i + j * dat.size_x] = true;
298
299 points.push_back(glm::vec2(float(i) + 0.5f, 0.5f + float(j) / 2.0f));
300 next_found = true;
301 return glm::ivec2(i, j);
302 }
303 }
304
305 return glm::ivec2(0, 0);
306 };
307
308
309 points.push_back(glm::vec2(float(start_x) + (start_y % 2 == 0 ? 0.0f : 0.5f), 0.5f + float(start_y) / 2.0f));
310 visited[start_x + start_y * dat.size_x] = true;
311
312 int32_t cur_x = start_x;
313 int32_t cur_y = start_y;
314
315 bool progress = false;
316 // clockwise
317 do {
318 progress = false;
319 glm::ivec2 temp{ 0, 0 };
320
321 if(cur_y % 2 == 0) {
322 bool left_is_s = dat.safe_get_province(glm::ivec2(cur_x - 1, cur_y / 2)) == prov_sec;
323 if(left_is_s) {
324 temp += add_next(cur_x, cur_y + 1, progress);
325 temp += add_next(cur_x, cur_y + 2, progress);
326 temp += add_next(cur_x - 1, cur_y + 1, progress);
327 } else {
328 temp += add_next(cur_x - 1, cur_y - 1, progress);
329 temp += add_next(cur_x, cur_y - 2, progress);
330 temp += add_next(cur_x, cur_y - 1, progress);
331 }
332 } else {
333 bool top_is_s = dat.safe_get_province(glm::ivec2(cur_x, cur_y / 2)) == prov_sec;
334 if(top_is_s) {
335 temp += add_next(cur_x, cur_y + 1, progress);
336 temp += add_next(cur_x - 1, cur_y, progress);
337 temp += add_next(cur_x, cur_y - 1, progress);
338 } else {
339 temp += add_next(cur_x + 1, cur_y - 1, progress);
340 temp += add_next(cur_x + 1, cur_y, progress);
341 temp += add_next(cur_x + 1, cur_y + 1, progress);
342 }
343 }
344 if(progress) {
345 cur_x = temp.x;
346 cur_y = temp.y;
347 }
348 } while(progress);
349
350 //terminal point
351 if(cur_y % 2 == 0) {
352 bool left_is_s = dat.safe_get_province(glm::ivec2(cur_x - 1, cur_y / 2)) == prov_sec;
353 if(left_is_s) {
354 points.push_back(glm::vec2(float(cur_x), 1.0f + float(cur_y) / 2.0f));
355 } else {
356 points.push_back(glm::vec2(float(cur_x), 0.0f + float(cur_y) / 2.0f));
357 }
358 } else {
359 bool top_is_s = dat.safe_get_province(glm::ivec2(cur_x, cur_y / 2)) == prov_sec;
360 if(top_is_s) {
361 points.push_back(glm::vec2(float(cur_x), 0.5f + float(cur_y) / 2.0f));
362 } else {
363 points.push_back(glm::vec2(1.0f + float(cur_x), 0.5f + float(cur_y) / 2.0f));
364 }
365 }
366
367 cur_x = start_x;
368 cur_y = start_y;
369
370 std::reverse(points.begin(), points.end());
371 //counter clockwise
372 progress = false;
373 do {
374 progress = false;
375 glm::ivec2 temp{ 0, 0 };
376
377 if(cur_y % 2 == 0) {
378 bool left_is_s = dat.safe_get_province(glm::ivec2(cur_x - 1, cur_y / 2)) == prov_sec;
379 if(!left_is_s) {
380 temp += add_next(cur_x, cur_y + 1, progress);
381 temp += add_next(cur_x, cur_y + 2, progress);
382 temp += add_next(cur_x - 1, cur_y + 1, progress);
383 } else {
384 temp += add_next(cur_x - 1, cur_y - 1, progress);
385 temp += add_next(cur_x, cur_y - 2, progress);
386 temp += add_next(cur_x, cur_y - 1, progress);
387 }
388 } else {
389 bool top_is_s = dat.safe_get_province(glm::ivec2(cur_x, cur_y / 2)) == prov_sec;
390 if(!top_is_s) {
391 temp += add_next(cur_x, cur_y + 1, progress);
392 temp += add_next(cur_x - 1, cur_y, progress);
393 temp += add_next(cur_x, cur_y - 1, progress);
394 } else {
395 temp += add_next(cur_x + 1, cur_y - 1, progress);
396 temp += add_next(cur_x + 1, cur_y, progress);
397 temp += add_next(cur_x + 1, cur_y + 1, progress);
398 }
399 }
400 if(progress) {
401 cur_x = temp.x;
402 cur_y = temp.y;
403 }
404 } while(progress);
405
406 //terminal point
407 if(cur_y % 2 == 0) {
408 bool left_is_s = dat.safe_get_province(glm::ivec2(cur_x - 1, cur_y / 2)) == prov_sec;
409 if(!left_is_s) {
410 points.push_back(glm::vec2(float(cur_x), 1.0f + float(cur_y) / 2.0f));
411 } else {
412 points.push_back(glm::vec2(float(cur_x), 0.0f + float(cur_y) / 2.0f));
413 }
414 } else {
415 bool top_is_s = dat.safe_get_province(glm::ivec2(cur_x, cur_y / 2)) == prov_sec;
416 if(!top_is_s) {
417 points.push_back(glm::vec2(float(cur_x), 0.5f + float(cur_y) / 2.0f));
418 } else {
419 points.push_back(glm::vec2(1.0f + float(cur_x), 0.5f + float(cur_y) / 2.0f));
420 }
421 }
422
423 return points;
424}
425
426void add_border_segment_vertices(display_data& dat, std::vector<glm::vec2> const& points) {
427 if(points.size() < 3)
428 return;
429
430 auto first = dat.border_vertices.size();
431
432 glm::vec2 current_pos = glm::vec2(points.back().x, points.back().y);
433 glm::vec2 next_pos = put_in_local(glm::vec2(points[points.size() - 2].x, points[points.size() - 2].y), current_pos, float(dat.size_x));
434
435 float distance = 0.0f;
436 glm::vec2 old_pos;
437 glm::vec2 raw_dist;
438 auto norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
439
440 {
441 old_pos = 2.0f * current_pos - next_pos;
442
443 dat.border_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
444 dat.border_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
445
446 raw_dist = (current_pos - next_pos) / glm::vec2(dat.size_x, dat.size_y);
447 raw_dist.x *= 2.0f;
448 distance += 0.5f * glm::length(raw_dist);
449 }
450
451 for(auto i = points.size() - 1; i-- > 1; ) {
452 old_pos = current_pos;
453 current_pos = glm::vec2(points[i].x, points[i].y);
454 old_pos = put_in_local(old_pos, current_pos, float(dat.size_x));
455 next_pos = put_in_local(glm::vec2(points[i - 1].x, points[i - 1].y), current_pos, float(dat.size_x));
456 auto next_direction = glm::normalize(next_pos - current_pos);
457
458 norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
459
460 dat.border_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
461 dat.border_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
462
463 raw_dist = (current_pos - next_pos) / glm::vec2(dat.size_x, dat.size_y);
464 raw_dist.x *= 2.0f;
465 distance += 0.5f * glm::length(raw_dist);
466 }
467
468 // case i == 0
469 {
470 old_pos = current_pos;
471 current_pos = glm::vec2(points[0].x, points[0].y);
472
473 next_pos = 2.0f * current_pos - old_pos;
474
475 auto next_direction = glm::normalize(next_pos - current_pos);
476
477 norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
478
479 dat.border_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
480 dat.border_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
481
482 raw_dist = (current_pos - next_pos) / glm::vec2(dat.size_x, dat.size_y);
483 raw_dist.x *= 2.0f;
484 distance += 0.5f * glm::length(raw_dist);
485
486 }
487}
488
489void display_data::make_borders(sys::state& state, std::vector<bool>& visited) {
490
491 borders.resize(state.world.province_adjacency_size());
492 for(auto adj : state.world.in_province_adjacency) {
493 borders[adj.id.index()].adj = adj;
494 }
495
496 for(int32_t j = 0; j < int32_t(size_y); ++j) {
497 for(int32_t i = 0; i < int32_t(size_x); ++i) {
498 // left verticals
499 {
500 bool was_visited = visited[i + (j * 2) * size_x];
501
502 auto prim = province::from_map_id(safe_get_province(glm::ivec2(i, j)));
503 auto sec = province::from_map_id(safe_get_province(glm::ivec2(i - 1, j)));
504
505 if(!was_visited && prim != sec && prim && sec) {
506 auto adj = state.world.get_province_adjacency_by_province_pair(prim, sec);
507 assert(adj);
508 int32_t border_index = adj.index();
509 if(borders[border_index].count != 0) {
510 border_index = int32_t(borders.size());
511 borders.emplace_back();
512 borders.back().adj = adj;
513 }
514
515 borders[border_index].start_index = int32_t(border_vertices.size());
516
517 auto res = make_border_section(*this, state, visited, province::to_map_id(prim), province::to_map_id(sec), i, j * 2);
518 add_border_segment_vertices(*this, res);
519
520 borders[border_index].count = int32_t(border_vertices.size() - borders[border_index].start_index);
521 }
522 }
523
524 // horizontals
525 if(j < int32_t(size_y) - 1) {
526 bool was_visited = visited[i + (j * 2 + 1) * size_x];
527 auto prim = province::from_map_id(safe_get_province(glm::ivec2(i, j)));
528 auto sec = province::from_map_id(safe_get_province(glm::ivec2(i, j + 1)));
529
530 if(!was_visited && prim != sec && prim && sec) {
531 auto adj = state.world.get_province_adjacency_by_province_pair(prim, sec);
532 assert(adj);
533 int32_t border_index = adj.index();
534 if(borders[border_index].count != 0) {
535 border_index = int32_t(borders.size());
536 borders.emplace_back();
537 borders.back().adj = adj;
538 }
539
540 borders[border_index].start_index = int32_t(border_vertices.size());
541
542 auto res = make_border_section(*this, state, visited, province::to_map_id(prim), province::to_map_id(sec), i, j * 2 + 1);
543 add_border_segment_vertices(*this, res);
544
545 borders[border_index].count = int32_t(border_vertices.size() - borders[border_index].start_index);
546 }
547 }
548 }
549 }
550}
551
552std::vector<glm::vec2> make_coastal_loop(display_data& dat, sys::state& state, std::vector<bool>& visited, int32_t start_x, int32_t start_y) {
553 std::vector<glm::vec2> points;
554
555 int32_t dropped_points_counter = 0;
556 constexpr int32_t dropped_points_max = 64;
557
558 auto add_next = [&](int32_t i, int32_t j, bool& next_found) {
559 if(next_found)
560 return glm::ivec2(0, 0);
561 if(visited[i + j * dat.size_x])
562 return glm::ivec2(0, 0);
563 if(j % 2 == 0) {
564 if(coastal_point(state, dat.safe_get_province(glm::ivec2(i, j / 2)), dat.safe_get_province(glm::ivec2(i - 1, j / 2)))) {
565 visited[i + j * dat.size_x] = true;
566
567 // test for colinearity
568 // this works, but it can result in the border textures being "slanted" because the normals are carried over between two corners
569
570 if(points.size() > 2) {
571 auto l = points[points.size() - 1];
572 auto n = points[points.size() - 2];
573 if(dropped_points_counter < dropped_points_max &&
574 std::sqrt((l.x - n.x) * (l.x - n.x) + (l.y - n.y) * (l.y - n.y)) + std::sqrt((l.x - float(i)) * (l.x - float(i)) + (l.y - 0.5f - float(j) / 2.0f) * (l.y - 0.5f - float(j) / 2.0f))
575 == std::sqrt((n.x - float(i)) * (n.x - float(i)) + (n.y - 0.5f - float(j) / 2.0f) * (n.y - 0.5f - float(j) / 2.0f))) {
576 ++dropped_points_counter;
577 points.pop_back();
578 } else {
579 dropped_points_counter = 0;
580 }
581 }
582
583 points.push_back(glm::vec2(float(i), 0.5f + float(j) / 2.0f));
584 next_found = true;
585 return glm::ivec2(i, j);
586 }
587 } else {
588 if(coastal_point(state, dat.safe_get_province(glm::ivec2(i, j / 2)), dat.safe_get_province(glm::ivec2(i, j / 2 + 1)))) {
589 visited[i + j * dat.size_x] = true;
590
591 // test for colinearity
592 // this works, but it can result in the border textures being "slanted" because the normals are carried over between two corners
593
594 if(points.size() > 2) {
595 auto l = points[points.size() - 1];
596 auto n = points[points.size() - 2];
597 if(dropped_points_counter < dropped_points_max &&
598 std::sqrt((l.x - n.x) * (l.x - n.x) + (l.y - n.y) * (l.y - n.y)) + std::sqrt((l.x - 0.5f - float(i)) * (l.x - 0.5f - float(i)) + (l.y - 0.5f - float(j) / 2.0f) * (l.y - 0.5f - float(j) / 2.0f))
599 == std::sqrt((n.x - 0.5f - float(i)) * (n.x - 0.5f - float(i)) + (n.y - 0.5f - float(j) / 2.0f) * (n.y - 0.5f - float(j) / 2.0f))) {
600 ++dropped_points_counter;
601 points.pop_back();
602 } else {
603 dropped_points_counter = 0;
604 }
605 }
606
607 points.push_back(glm::vec2(float(i) + 0.5f, 0.5f + float(j) / 2.0f));
608 next_found = true;
609 return glm::ivec2(i, j);
610 }
611 }
612
613 return glm::ivec2(0, 0);
614 };
615
616 points.push_back(glm::vec2(float(start_x) + (start_y % 2 == 0 ? 0.0f : 0.5f), 0.5f + float(start_y) / 2.0f));
617 visited[start_x + start_y * dat.size_x] = true;
618
619 bool progress = false;
620 do {
621 progress = false;
622 glm::ivec2 temp{ 0, 0 };
623
624 if(start_y % 2 == 0) {
625 bool left_is_sea = dat.safe_get_province(glm::ivec2(start_x - 1, start_y / 2)) == 0 || province::from_map_id(dat.safe_get_province(glm::ivec2(start_x - 1, start_y / 2))).index() >= state.province_definitions.first_sea_province.index();
626 if(left_is_sea) {
627 temp += add_next(start_x, start_y + 1, progress);
628 temp += add_next(start_x, start_y + 2, progress);
629 temp += add_next(start_x - 1, start_y + 1, progress);
630 } else {
631 temp += add_next(start_x - 1, start_y - 1, progress);
632 temp += add_next(start_x, start_y - 2, progress);
633 temp += add_next(start_x, start_y - 1, progress);
634 }
635 } else {
636 bool top_is_sea = dat.safe_get_province(glm::ivec2(start_x, start_y / 2)) == 0 || province::from_map_id(dat.safe_get_province(glm::ivec2(start_x, start_y / 2))).index() >= state.province_definitions.first_sea_province.index();
637 if(top_is_sea) {
638 temp += add_next(start_x, start_y + 1, progress);
639 temp += add_next(start_x - 1, start_y, progress);
640 temp += add_next(start_x, start_y - 1, progress);
641 } else {
642 temp += add_next(start_x + 1, start_y - 1, progress);
643 temp += add_next(start_x + 1, start_y, progress);
644 temp += add_next(start_x + 1, start_y + 1, progress);
645 }
646 }
647 if(progress) {
648 start_x = temp.x;
649 start_y = temp.y;
650 }
651 } while(progress);
652
653 return points;
654}
655
656void add_coastal_loop_vertices(display_data& dat, std::vector<glm::vec2> const& points) {
657 if(points.size() < 3)
658 return;
659
660 auto first = dat.coastal_vertices.size();
661 dat.coastal_starts.push_back(GLint(first));
662
663 glm::vec2 current_pos = glm::vec2(points.back().x, points.back().y);
664 glm::vec2 next_pos = put_in_local(glm::vec2(points[points.size() - 2].x, points[points.size() - 2].y), current_pos, float(dat.size_x));
665 glm::vec2 prev_direction = glm::normalize(next_pos - current_pos);
666 float distance = 0.0f;
667
668 auto norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
669 auto old_pos = glm::vec2{ 0,0 };
670
671 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
672 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
673
674 auto raw_dist = (current_pos - next_pos) / glm::vec2(dat.size_x, dat.size_y);
675 raw_dist.x *= 2.0f;
676 distance += glm::length(raw_dist);
677
678 for(auto i = points.size() - 1; i-- > 1; ) {
679 old_pos = current_pos;
680 current_pos = glm::vec2(points[i].x, points[i].y);
681 old_pos = put_in_local(old_pos, current_pos, float(dat.size_x));
682 next_pos = put_in_local(glm::vec2(points[i - 1].x, points[i - 1].y), current_pos, float(dat.size_x));
683 auto next_direction = glm::normalize(next_pos - current_pos);
684
685 norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
686
687 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
688 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
689
690 raw_dist = (current_pos - next_pos) / glm::vec2(dat.size_x, dat.size_y);
691 raw_dist.x *= 2.0f;
692 distance += glm::length(raw_dist);
693 }
694
695 // case i == 0
696 {
697 old_pos = current_pos;
698 current_pos = glm::vec2(points[0].x, points[0].y);
699 old_pos = put_in_local(old_pos, current_pos, float(dat.size_x));
700 next_pos = put_in_local(glm::vec2(points.back().x, points.back().y), current_pos, float(dat.size_x));
701 auto next_direction = glm::normalize(next_pos - current_pos);
702
703 norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
704
705 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
706 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
707
708 raw_dist = (current_pos - next_pos) / glm::vec2(dat.size_x, dat.size_y);
709 raw_dist.x *= 2.0f;
710 distance += glm::length(raw_dist);
711
712 }
713
714 // wrap-around
715 {
716 old_pos = current_pos;
717 current_pos = glm::vec2(points.back().x, points.back().y);
718 old_pos = put_in_local(old_pos, current_pos, float(dat.size_x));
719 next_pos = put_in_local(glm::vec2(points[points.size() - 2].x, points[points.size() - 2].y), current_pos, float(dat.size_x));
720 auto next_direction = glm::normalize(next_pos - current_pos);
721 auto next_normal = glm::vec2(-next_direction.y, next_direction.x);
722
723 norm_pos = current_pos / glm::vec2(dat.size_x, dat.size_y);
724
725 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, old_pos / glm::vec2(dat.size_x, dat.size_y), next_pos / glm::vec2(dat.size_x, dat.size_y), 0.0f, distance });
726 dat.coastal_vertices.emplace_back(textured_line_vertex_b{ norm_pos, next_pos / glm::vec2(dat.size_x, dat.size_y), old_pos / glm::vec2(dat.size_x, dat.size_y), 1.0f, distance });
727
728 dat.coastal_vertices[first].previous_point = old_pos / glm::vec2(dat.size_x, dat.size_y);
729 dat.coastal_vertices[first + 1].next_point = old_pos / glm::vec2(dat.size_x, dat.size_y);
730 }
731
732 dat.coastal_counts.push_back(GLsizei(dat.coastal_vertices.size() - dat.coastal_starts.back()));
733}
734
735void display_data::make_coastal_borders(sys::state& state, std::vector<bool>& visited) {
736 for(int32_t j = 0; j < int32_t(size_y); ++j) {
737 for(int32_t i = 0; i < int32_t(size_x); ++i) {
738 // left verticals
739 {
740 bool was_visited = visited[i + (j * 2) * size_x];
741 if(!was_visited && coastal_point(state, safe_get_province(glm::ivec2(i, j)), safe_get_province(glm::ivec2(i - 1, j)))) {
742 auto res = make_coastal_loop(*this, state, visited, i, j * 2);
743 add_coastal_loop_vertices(*this, res);
744 }
745 }
746
747 // horizontals
748 if(j < int32_t(size_y) - 1) {
749 bool was_visited = visited[i + (j * 2 + 1) * size_x];
750 if(!was_visited && coastal_point(state, safe_get_province(glm::ivec2(i, j)), safe_get_province(glm::ivec2(i, j + 1)))) {
751 auto res = make_coastal_loop(*this, state, visited, i, j * 2 + 1);
752 add_coastal_loop_vertices(*this, res);
753 }
754 }
755 }
756 }
757}
758
759
760// Set the river crossing bit for the province adjacencies
761// Will march a line between each adjacent province centroid. If it hits a river it will set the bit
762void load_river_crossings(parsers::scenario_building_context& context, std::vector<uint8_t> const& river_data, glm::ivec2 map_size) {
763 auto& world = context.state.world;
764 world.for_each_province_adjacency([&](dcon::province_adjacency_id id) {
765 auto frel = dcon::fatten(world, id);
766 auto prov_a = frel.get_connected_provinces(0);
767 auto prov_b = frel.get_connected_provinces(1);
768
769 if(!prov_a || !prov_b)
770 return; // goto next
771
772 glm::vec2 mid_point_a = world.province_get_mid_point(prov_a.id);
773 glm::vec2 mid_point_b = world.province_get_mid_point(prov_b.id);
774 glm::ivec2 tile_pos_a = glm::round(mid_point_a);
775 glm::ivec2 tile_pos_b = glm::round(mid_point_b);
776 glm::ivec2 diff = glm::abs(tile_pos_a - tile_pos_b);
777
778 bool is_river_crossing = false;
779 if(diff.x > diff.y) {
780 if(tile_pos_a.x > tile_pos_b.x)
781 std::swap(tile_pos_a, tile_pos_b);
782 int x_difference = std::max(tile_pos_b.x - tile_pos_a.x, 1);
783 int y_difference = tile_pos_a.y - tile_pos_b.y;
784 int min_y = std::min(tile_pos_a.y, tile_pos_b.y);
785 int max_y = std::max(tile_pos_a.y, tile_pos_b.y);
786 for(int x = tile_pos_a.x; x <= tile_pos_b.x; x++) {
787 float t = float(x - tile_pos_a.x) / x_difference;
788 for(int k = -2; k <= 2; k++) {
789 int y = tile_pos_b.y + int(y_difference * t) + k;
790 y = std::clamp(y, min_y, max_y);
791 if(x < 0 || y < 0)
792 continue;
793 is_river_crossing |= is_river(river_data[x + y * map_size.x]);
794 }
795 if(is_river_crossing)
796 break;
797 }
798 } else {
799 if(tile_pos_a.y > tile_pos_b.y)
800 std::swap(tile_pos_a, tile_pos_b);
801 int y_difference = std::max(tile_pos_b.y - tile_pos_a.y, 1);
802 int x_difference = tile_pos_a.x - tile_pos_b.x;
803 int min_x = std::min(tile_pos_a.x, tile_pos_b.x);
804 int max_x = std::max(tile_pos_a.x, tile_pos_b.x);
805 for(int y = tile_pos_a.y; y <= tile_pos_b.y; y++) {
806 float t = float(y - tile_pos_a.y) / y_difference;
807 for(int k = -2; k <= 2; k++) {
808 int x = tile_pos_b.x + int(x_difference * t) + k;
809 x = std::clamp(x, min_x, max_x);
810 if(x < 0 || y < 0)
811 continue;
812 is_river_crossing |= is_river(river_data[x + y * map_size.x]);
813 }
814 if(is_river_crossing)
815 break;
816 }
817 }
818
819 uint8_t& buffer = world.province_adjacency_get_type(id);
820 if(is_river_crossing)
822 });
823}
824
826 float x = 0.0f;
827 float y = 0.0f;
828 float width = 0.0f;
829 std::vector<river_vertex*> parents = { };
830 std::vector<river_vertex*> children = { };
831 bool visited = false;
832 bool skip_visited = false;
833
834 bool operator==(const river_vertex& other) {
835 return x == other.x && y == other.y;
836 }
837};
838
839
845 bool done;
846};
847
849 for(uint8_t index = 0; index < vertex->children.size(); index++) {
850 auto child = vertex->children[index];
851 if((child->x - float(x) - 0.5f) > 0.1f) {
852 continue;
853 }
854 if((child->y - float(y) - 0.5f) > 0.1f) {
855 continue;
856 }
857 return true;
858 }
859 return false;
860}
861
863 for(uint8_t index = 0; index < vertex->parents.size(); index++) {
864 auto parent = vertex->parents[index];
865 if(abs(parent->x - float(x) - 0.5f) > 0.1f) {
866 continue;
867 }
868 if(abs(parent->y - float(y) - 0.5f) > 0.1f) {
869 continue;
870 }
871 return true;
872 }
873 return false;
874}
875
876bool check_for_river(std::vector<uint8_t> const& river_data, river_runner& runner, int32_t x, int32_t y, glm::ivec2 size) {
877 if(x < 0) {
878 return false;
879 }
880 if(x >= size.x) {
881 return false;
882 }
883 if(y < 0) {
884 return false;
885 }
886 if(y >= size.y) {
887 return false;
888 }
889
890 if(is_river(river_data[x + y * size.x])) {
891 if(!check_for_parent(runner.position, x, y)) {
892 return true;
893 }
894 }
895 return false;
896}
897
898std::vector<glm::ivec2> check_for_potential_child(std::vector<uint8_t> const& river_data, river_runner& runner, glm::ivec2 size) {
899 std::vector<glm::ivec2> results;
900 if(check_for_river(river_data, runner, runner.x + 1, runner.y, size)) {
901 results.push_back({ runner.x + 1, runner.y });
902 }
903 if(check_for_river(river_data, runner, runner.x - 1, runner.y, size)) {
904 results.push_back({ runner.x - 1, runner.y });
905 }
906 if(check_for_river(river_data, runner, runner.x, runner.y + 1, size)) {
907 results.push_back({ runner.x, runner.y + 1 });
908 }
909 if(check_for_river(river_data, runner, runner.x, runner.y - 1, size)) {
910 results.push_back({ runner.x, runner.y - 1});
911 }
912
913 return results;
914}
915
916//static std::vector<std::vector<river_vertex>> pool_of_constructed_rivers;
917/*
918std::vector<river_vertex> make_directional_river(int32_t x, int32_t y, std::vector<std::vector<river_vertex>>& rivers, std::vector<uint8_t> const& river_data, std::vector<uint8_t> const& terrain_data, std::vector<bool>& marked, glm::ivec2 size, int32_t old_x = -1, int32_t old_y = -1, int32_t width = 1, int32_t old_width = 1) {
919 //auto available_index = pool_of_constructed_rivers.size();
920 //pool_of_constructed_rivers.push_back({ });
921 std::vector<river_vertex> constructed = {};// pool_of_constructed_rivers[available_index];
922
923 if(old_x != -1 && old_y != -1) {
924 constructed.push_back(river_vertex{ float(old_x + 0.5f), float(old_y + 0.5f), (float)width, false });
925 }
926
927 marked[x + y * size.x] = true;
928 auto process_non_merge = [&](int32_t xin, int32_t yin, bool& forward_found) {
929 if(xin >= 0 && yin >= 0 && xin < size.x && yin < size.y && (xin != old_x || yin != old_y) && is_river(river_data[xin + yin * size.x]) && !marked[xin + yin * size.x] && !is_river_merge(river_data[xin + yin * size.x]) && !is_river_source(river_data[xin + yin * size.x])) {
930
931 marked[xin + yin * size.x] = true;
932 auto local_width = river_width(river_data[xin + yin * size.x]);
933 if(!forward_found) {
934 forward_found = true;
935 return glm::ivec3{xin, yin, local_width };
936 } else {
937 constructed.back().keep = true;
938 rivers.emplace_back(make_directional_river(xin, yin, rivers, river_data, terrain_data, marked, size, x, y, local_width));
939 }
940 }
941 return glm::ivec3{ 0, 0, 0 };
942 };
943 auto process_merge = [&](int32_t xin, int32_t yin, bool& merge_found) {
944 if(merge_found)
945 return glm::ivec2{ 0, 0 };
946
947 if(xin >= 0 && yin >= 0 && xin < size.x && yin < size.y && (xin != old_x || yin != old_y) && is_river(river_data[xin + yin * size.x]) && !marked[xin + yin * size.x] && is_river_merge(river_data[xin + yin * size.x]) && !is_river_source(river_data[xin + yin * size.x])) {
948
949 marked[xin + yin * size.x] = true;
950 merge_found = true;
951 return glm::ivec2{ xin, yin };
952 }
953 return glm::ivec2{ 0, 0 };
954 };
955 auto process_post_merge = [&](int32_t xin, int32_t yin, bool& forward_found) {
956 if(xin >= 0 && yin >= 0 && xin < size.x && yin < size.y && (xin != old_x || yin != old_y) && is_river(river_data[xin + yin * size.x]) && !is_river_merge(river_data[xin + yin * size.x]) && !is_river_source(river_data[xin + yin * size.x])) {
957 if(!forward_found) {
958 forward_found = true;
959 return glm::ivec3{ xin, yin, river_width(river_data[xin + yin * size.x]) };
960 }
961 }
962 return glm::ivec3{ 0, 0, 0 };
963 };
964 auto process_sea_extend = [&](int32_t xin, int32_t yin, bool& merge_found) {
965 if(merge_found)
966 return glm::ivec2{ 0, 0 };
967
968 if(xin >= 0 && yin >= 0 && xin < size.x && yin < size.y && (xin != old_x || yin != old_y) && terrain_data[xin + yin * size.x] == 255) {
969 merge_found = true;
970 return glm::ivec2{ xin, yin };
971 }
972 return glm::ivec2{ 0, 0 };
973 };
974
975 bool forward_progress = false;
976 do {
977 forward_progress = false;
978 constructed.push_back(river_vertex{ float(x + 0.5f), float(y + 0.5f), (float)width, false });
979
980 auto res = process_non_merge(x - 1, y, forward_progress);
981 res += process_non_merge(x + 1, y, forward_progress);
982 res += process_non_merge(x, y - 1, forward_progress);
983 res += process_non_merge(x, y + 1, forward_progress);
984
985 if(forward_progress) {
986 old_x = x;
987 old_y = y;
988 old_width = width;
989 x = res.x;
990 y = res.y;
991 width = res.z;
992 }
993
994 } while(forward_progress);
995
996 bool merge_found = false;
997 auto resb = process_merge(x - 1, y, merge_found);
998 resb += process_merge(x + 1, y, merge_found);
999 resb += process_merge(x, y - 1, merge_found);
1000 resb += process_merge(x, y + 1, merge_found);
1001
1002 if(merge_found) {
1003 constructed.push_back(river_vertex{ float(resb.x + 0.5f), float(resb.y + 0.5f), (float)width, false });
1004
1005 old_x = x;
1006 old_y = y;
1007 x = resb.x;
1008 y = resb.y;
1009
1010 bool post_progress = false;
1011 auto resc = process_post_merge(x - 1, y, post_progress);
1012 resc += process_post_merge(x + 1, y, post_progress);
1013 resc += process_post_merge(x, y - 1, post_progress);
1014 resc += process_post_merge(x, y + 1, post_progress);
1015
1016 if(post_progress) {
1017 constructed.push_back(river_vertex{ float(resc.x + 0.5f), float(resc.y + 0.5f), (float)resc.z, false });
1018 }
1019 } else if(terrain_data[x + y * size.x] != 255) {
1020 bool post_progress = false;
1021 auto resc = process_sea_extend(x - 1, y, post_progress);
1022 resc += process_sea_extend(x + 1, y, post_progress);
1023 resc += process_sea_extend(x, y - 1, post_progress);
1024 resc += process_sea_extend(x, y + 1, post_progress);
1025
1026 if(post_progress) {
1027 constructed.push_back(river_vertex{ float(resc.x + 0.5f), float(resc.y + 0.5f), (float)width, false });
1028 }
1029 }
1030 if(!constructed.empty()) {
1031 constructed.front().keep = true;
1032 constructed.back().keep = true;
1033 }
1034 return constructed;
1035}
1036*/
1037
1038
1039void display_data::create_curved_river_vertices(parsers::scenario_building_context & context, std::vector<uint8_t> const& river_data, std::vector<uint8_t> const& terrain_data) {
1040
1041 std::vector<river_vertex> rivers;
1042
1043
1044 std::vector<bool> marked(size_x * size_y, false);
1045
1046 std::vector<river_vertex*> sources;
1047 std::vector<river_vertex*> mouths;
1048 std::map<uint32_t, river_vertex*> vertex_by_pixel_index = {};
1049 std::vector<river_runner> runners;
1050 std::vector<river_runner> new_runners;
1051
1052
1053 auto size = glm::ivec2(int32_t(size_x), int32_t(size_y));
1054
1055
1056
1057 for(uint32_t y = 0; y < size_y; y++) {
1058 for(uint32_t x = 0; x < size_x; x++) {
1059 auto index = x + y * size_x;
1060 if(is_river_source(river_data[index])) {
1061 river_vertex * source = new river_vertex { float(x) + 0.5f, float(y) + 0.5f, 40.f };
1062 sources.push_back(source);
1063 vertex_by_pixel_index[index] = source;
1064 river_runner r = { source, x, y, false, false };
1065 runners.push_back(r);
1066 }
1067 }
1068 }
1069
1070
1071 bool exists_running_runner = true;
1072
1073
1074
1075 while(exists_running_runner) {
1076 exists_running_runner = false;
1077
1078 for(auto & item : new_runners) {
1079 runners.push_back(item);
1080 }
1081 new_runners.clear();
1082
1083
1084 for(auto & runner : runners) {
1085 if(runner.done) {
1086 continue;
1087 }
1088
1089 auto potential_children = check_for_potential_child(river_data, runner, size);
1090
1091 if(potential_children.size() == 0) {
1092 // extend to the sea:
1093
1094 for(int32_t i = -1; i <= 1; i++) {
1095 for(int32_t j = -1; j <= 1; j++) {
1096 auto x = (int32_t)runner.x + i;
1097 auto y = (int32_t)runner.y + j;
1098 if(x < 0) {
1099 continue;
1100 }
1101 if(y < 0) {
1102 continue;
1103 }
1104 if(x >= size.x) {
1105 continue;
1106 }
1107 if(y >= size.y) {
1108 continue;
1109 }
1110 auto index = uint32_t(x) + uint32_t(y) * size_x;
1111
1112 bool is_sea = terrain_data[index] == 255;
1113 if(!is_sea) {
1114 continue;
1115 }
1116
1117 if(!vertex_by_pixel_index.contains(index)) {
1118 river_vertex* new_river_vertex = new river_vertex{
1119 float(x) + 0.5f,
1120 float(y) + 0.5f,
1121 runner.position->width * 2.f
1122 };
1123 vertex_by_pixel_index[index] = new_river_vertex;
1124 new_river_vertex->parents.push_back(runner.position);
1125 runner.position->children.push_back(new_river_vertex);
1126
1127 i = 3;
1128 j = 3;
1129 break;
1130 }
1131 }
1132 }
1133
1134 runner.done = true;
1135 mouths.push_back(runner.position);
1136 } else if(runner.waiting_for_merge) {
1137 for(auto target_coord : potential_children) {
1138 auto target_index = target_coord.x + target_coord.y * size_x;
1139 if(vertex_by_pixel_index.contains(target_index)) {
1140 auto target_vertex = vertex_by_pixel_index[target_index];
1141 target_vertex->parents.push_back(runner.position);
1142 runner.position->children.push_back(target_vertex);
1143 runner.waiting_for_merge = false;
1144 runner.done = true;
1145 }
1146 }
1147 } else {
1148 exists_running_runner = true;
1149 if(is_river_merge(river_data[runner.x + runner.y * size_x])) {
1150 runner.waiting_for_merge = true;
1151 } else {
1152 bool first_child = true;
1153 uint32_t next_x = 0;
1154 uint32_t next_y = 0;
1155 river_vertex* next_position = nullptr;
1156
1157 for(auto candidate : potential_children) {
1158 auto x = (uint32_t)candidate.x;
1159 auto y = (uint32_t)candidate.y;
1160 auto index = x + y * size_x;
1161 auto width = float(river_width(river_data[index]));
1162
1163 if(is_river_merge(river_data[index])) {
1164 if(potential_children.size() > 1) {
1165 continue;
1166 }
1167 width = runner.position->width;
1168 }
1169
1170 river_vertex* new_river_vertex = nullptr;
1171
1172 bool we_will_move_forward = false;
1173
1174 if(vertex_by_pixel_index.contains(index)) {
1175 new_river_vertex = vertex_by_pixel_index[index];
1176 } else {
1177 new_river_vertex = new river_vertex{
1178 float(x) + 0.5f,
1179 float(y) + 0.5f,
1180 width
1181 };
1182 vertex_by_pixel_index[index] = new_river_vertex;
1183 we_will_move_forward = true;
1184 }
1185
1186 new_river_vertex->parents.push_back(runner.position);
1187 runner.position->children.push_back(new_river_vertex);
1188
1189 if(we_will_move_forward) {
1190 if(first_child) {
1191 next_x = x;
1192 next_y = y;
1193 next_position = new_river_vertex;
1194 first_child = false;
1195 } else {
1196 river_runner r = { new_river_vertex, x, y, false, false };
1197 new_runners.push_back(r);
1198 }
1199 } else {
1200 runner.done = true;
1201 }
1202 }
1203
1204 if(next_position != nullptr) {
1205 runner.x = next_x;
1206 runner.y = next_y;
1207 runner.position = next_position;
1208 }
1209 }
1210 }
1211 }
1212 }
1213
1214
1215
1216 /*
1217 for(uint32_t y = 0; y < size_y; y++) {
1218 for(uint32_t x = 0; x < size_x; x++) {
1219 if(is_river_source(river_data[x + y * size_x]))
1220 rivers.emplace_back(make_directional_river(x, y, rivers, river_data, terrain_data, marked, glm::ivec2(int32_t(size_x), int32_t(size_y))));
1221 }
1222 }
1223
1224
1225 // remove empty rivers or rivers with 1 vertex
1226 for(auto i = rivers.size(); i-- > 0; ) {
1227 if(rivers[i].size() <= 1) {
1228 rivers[i] = std::move(rivers.back());
1229 rivers.pop_back();
1230 }
1231 }
1232
1233 // mark merge points as keep
1234 // boy, this sure is wildly inefficient ...
1235
1236 for(const auto& river : rivers) {
1237 auto back_point = river.back();
1238 for(auto& other_river : rivers) {
1239 bool found_merge = false;
1240 for(auto& pt : other_river) {
1241 if(pt.x == back_point.x && pt.y == back_point.y) {
1242 pt.keep = true;
1243 found_merge = true;
1244 break;
1245 }
1246 }
1247 if(found_merge)
1248 break;
1249 }
1250 }
1251
1252
1253
1254 for(const auto& river : rivers) {
1255 river_starts.push_back(GLint(river_vertices.size()));
1256
1257 glm::vec2 current_pos = glm::vec2(river.back().x, river.back().y);
1258 glm::vec2 next_pos = put_in_local(glm::vec2(river[river.size() - 2].x, river[river.size() - 2].y), current_pos, float(size_x));
1259
1260 float current_width = river.back().width;
1261 float next_width = river[river.size() - 2].width;
1262
1263 glm::vec2 tangent_prev = glm::normalize(next_pos - current_pos);
1264 float distance = 0.0f;
1265
1266 auto start_normal = glm::vec2(-tangent_prev.y, tangent_prev.x);
1267 auto norm_pos = current_pos / glm::vec2(size_x, size_y);
1268 river_vertices.emplace_back(textured_line_with_width_vertex{ norm_pos, +start_normal, 0.0f, distance, river.back().width });//C
1269 river_vertices.emplace_back(textured_line_with_width_vertex{ norm_pos, -start_normal, 1.0f, distance, river.back().width });//D
1270
1271 for(auto i = river.size() - 1; i-- > 0;) {
1272 //if(!river[i].keep && i % 3 != 0) {
1273 // continue; // skip
1274 //}
1275 glm::vec2 tangent_next{ 0.0f, 0.0f };
1276 next_pos = put_in_local(glm::vec2(river[i].x, river[i].y), current_pos, float(size_x));
1277
1278 current_width = river[i].width;
1279 if(i > 0) {
1280 auto nexti = i - 1;
1281 //while(!river[nexti].keep && nexti % 3 != 0) {
1282 // nexti--;
1283 //}
1284
1285 glm::vec2 next_next_pos = put_in_local(glm::vec2(river[nexti].x, river[nexti].y), next_pos, float(size_x));
1286
1287
1288 glm::vec2 tangent_current_to_next = glm::normalize(next_pos - current_pos);
1289 glm::vec2 tangent_next_to_next_next = glm::normalize(next_next_pos - next_pos);
1290 tangent_next = glm::normalize(tangent_current_to_next + tangent_next_to_next_next);
1291 next_width = river[nexti].width;
1292 } else {
1293 tangent_next = glm::normalize(next_pos - current_pos);
1294 next_width = current_width;
1295 }
1296 float save_distance = distance;
1297 add_tl_bezier_to_buffer(river_vertices, current_pos, next_pos, tangent_prev, tangent_next, 0.0f, false, float(size_x), float(size_y), 4, distance, current_width, next_width);
1298 assert(abs((distance - save_distance) * size_x) > 0.5);
1299 assert(abs((distance - save_distance) * size_x) < 4.0);
1300 tangent_prev = tangent_next;
1301 current_pos = glm::vec2(river[i].x, river[i].y);
1302 }
1303 river_counts.push_back(GLsizei(river_vertices.size() - river_starts.back()));
1304 }
1305
1306 */
1307
1308 std::vector<river_vertex*> current_path = { };
1309 std::vector<river_vertex*> nodes_to_skip = { };
1310
1311 current_path.clear();
1312
1313 uint32_t skip_nodes_counter = 0;
1314
1315
1316 // to avoid "squareness" we walk around the graph and "forget" some of nodes:
1317 // optimally, we want to forget a few nodes before nodes with multiple parents
1318 // to create smooth "confluence"
1319 for(auto source : sources) {
1320 //skip one pixel rivers
1321 if(source->children.size() == 0) {
1322 continue;
1323 }
1324
1325 current_path.push_back(source);
1326
1327
1328 // walk around to find a confluence
1329 while(current_path.size() > 0) {
1330 auto current_node = current_path.back();
1331 current_node->skip_visited = true;
1332
1333 // check if one of our child is a confluence:
1334 bool has_confluence_further = false;
1335
1336 for(auto potential_confluence : current_node->children) {
1337 if(
1338 potential_confluence->parents.size() > 1
1339 && potential_confluence->children.size() > 0
1340 ) {
1341 has_confluence_further = true;
1342 }
1343 }
1344
1345 if(has_confluence_further) {
1346 // we found a confluence!
1347 // backtrack and mark a few nodes for removal
1348 auto backrunner = current_path[current_path.size() - 1];
1349 for(int steps = 0; steps < 2; steps++) {
1350 if(current_path.size() - 1 - steps <= 0) {
1351 break;
1352 }
1353 if(backrunner->parents.size() == 0) {
1354 break;
1355 }
1356 nodes_to_skip.push_back(backrunner);
1357 backrunner = current_path[current_path.size() - 1 - steps];
1358 }
1359 }
1360
1361 if(current_path.size() > 2) {
1362 auto prev_node = current_path[current_path.size() - 2];
1363
1364 if(current_node->parents.size() > 1 && current_node->children.size() > 0) {
1365 // we are the confluence!
1366 // skip three nodes
1367 skip_nodes_counter = 2;
1368 //nodes_to_skip.push_back(current_node);
1369 } else {
1370 // we are not at special node
1371 bool node_was_skipped = false;
1372 if(current_node->children.size() == 1)
1373 if(current_node->parents.size() == 1)
1374 if(current_node->children[0]->parents.size() == 1)
1375 if(current_node->parents[0]->children.size() == 1) {
1376 assert(current_node->children[0]->parents[0] == current_node);
1377 assert(current_node->parents[0]->children[0] == current_node);
1378 if(current_path.size() % 3 == 0) {
1379 nodes_to_skip.push_back(current_node);
1380 node_was_skipped = true;
1381 if(skip_nodes_counter > 0) {
1382 skip_nodes_counter -= 1;
1383 }
1384 };
1385 }
1386 if(current_node->children.size() > 0)
1387 if(current_node->parents.size() > 0)
1388 if(!node_was_skipped && skip_nodes_counter > 0) {
1389 //nodes_to_skip.push_back(current_node);
1390 skip_nodes_counter -= 1;
1391 }
1392 }
1393 }
1394 bool pop_back = true;
1395 for(auto candidate : current_node->children) {
1396 if(!candidate->skip_visited) {
1397 current_path.push_back(candidate);
1398 pop_back = false;
1399 }
1400 }
1401
1402 if(pop_back) {
1403 current_path.pop_back();
1404 }
1405 }
1406 }
1407
1408
1409 std::vector<river_vertex*> parents;
1410 std::vector<river_vertex*> children;
1411 std::vector<river_vertex*> temp;
1412 for(auto item : nodes_to_skip) {
1413 parents.clear();
1414 children.clear();
1415
1416 // collect all children:
1417 for(auto child : item->children) {
1418 children.push_back(child);
1419 }
1420 // collect all parents:
1421 for(auto parent : item->parents) {
1422 parents.push_back(parent);
1423 }
1424
1425 // attach children to parents:
1426 for(auto parent : parents) {
1427 temp.clear();
1428
1429 // save old children to temp
1430 for(auto parent_child : parent->children) {
1431 if(parent_child->x == item->x)
1432 if(parent_child->y == item->y)
1433 continue;
1434 temp.push_back(parent_child);
1435 }
1436
1437 for(auto child_to_attach : children) {
1438 // check that they don't have this child already
1439 bool skip_child = false;
1440 for(auto parent_child : parent->children) {
1441 if(parent_child->x == child_to_attach->x)
1442 if(parent_child->y == child_to_attach->y) {
1443 skip_child = true;
1444 break;
1445 }
1446 }
1447
1448 if(skip_child) {
1449 continue;
1450 } else {
1451 temp.push_back(child_to_attach);
1452 }
1453 }
1454
1455 parent->children.clear();
1456
1457 for(auto saved_item : temp) {
1458 parent->children.push_back(saved_item);
1459 }
1460 }
1461
1462 // attach parents to children
1463 for(auto child : children) {
1464 temp.clear();
1465
1466 // save old parents to temp
1467 for(auto child_parent : child->parents) {
1468 if(child_parent->x == item->x)
1469 if(child_parent->y == item->y)
1470 continue;
1471 temp.push_back(child_parent);
1472 }
1473
1474 for(auto parent_to_attach : parents) {
1475 // check that they don't have this child already
1476 bool skip_parent = false;
1477 for(auto child_parent : child->parents) {
1478 if(child_parent->x == parent_to_attach->x)
1479 if(child_parent->y == parent_to_attach->y) {
1480 skip_parent = true;
1481 break;
1482 }
1483 }
1484
1485 if(skip_parent) {
1486 continue;
1487 } else {
1488 temp.push_back(parent_to_attach);
1489 }
1490 }
1491
1492 child->parents.clear();
1493
1494 for(auto saved_item : temp) {
1495 //assert(saved_item->children[0] == child);
1496 child->parents.push_back(saved_item);
1497 }
1498 }
1499
1500 item->children.clear();
1501 item->parents.clear();
1502 }
1503
1504
1505 // now we generate quads for rivers:
1506 // basic idea is to proceed from sources to children
1507 // every segment is a bezier curve with control points being the tangent vectors of rivers
1508 // in result, segments should share tangent lines at the merge/split points
1509 // we assume that "main" child is always at index 0
1510
1511 current_path.clear();
1512 std::vector<glm::vec2> vertex_stabilized_history;
1513 vertex_stabilized_history.clear();
1514
1515 for(auto source : sources) {
1516 //skip one pixel rivers
1517 if(source->children.size() == 0) {
1518 continue;
1519 }
1520
1521 current_path.push_back(source);
1522 vertex_stabilized_history.push_back({ source->x, source->y });
1523
1524 // we explore current river and create paths along it
1525 // until we explore all downstream nodes
1526 while(current_path.size() > 0) {
1527 // we start by tracking back along the river until we find
1528 // a node with not visited child
1529 bool can_start_here = false;
1530
1531
1532 river_vertex* runner = current_path.back();
1533 if(!runner->visited) {
1534 can_start_here = true;
1535 }
1536
1537 while(!can_start_here) {
1538 if(current_path.size() == 0) {
1539 break;
1540 }
1541
1542 runner = current_path.back();
1543 current_path.pop_back();
1544 vertex_stabilized_history.pop_back();
1545
1546 for(auto child : runner->children) {
1547 if(child->visited) {
1548 continue;
1549 }
1550
1551 can_start_here = true;
1552 }
1553 }
1554
1555 if(!can_start_here) {
1556 break;
1557 }
1558
1559 // we start running along the river
1560 // to create a new path and save it in a buffer
1561
1562 // save current offset
1563 river_starts.push_back(GLint(river_vertices.size()));
1564
1565 //init distance from the source
1566 float distance = 0.0f;
1567 // it will store distance local to current source
1568 // which will lead to incontinuities in distances in river basins
1569 // these problems should be probably solved in a separate pass ?
1570
1571 glm::vec2 vertex = { runner->x, runner->y };
1572 glm::vec2 vertex_stabilized = vertex;
1573 if(vertex_stabilized_history.size() > 0) {
1574 vertex_stabilized = vertex_stabilized_history.back();
1575 }
1576 glm::vec2 vertex_stabilized_speed = { 0.f, 0.f };
1577 float friction = 0.932f;
1578 uint8_t steps = 8;
1579 float weight = 0.005f;
1580
1581 uint8_t count_back = 16;
1582
1583 bool can_continue = true;
1584 while(can_continue) {
1585 runner->visited = true;
1586
1587 can_continue = false;
1588 bool stop = true;
1589
1590 river_vertex* next_node = nullptr;
1591
1592 for(auto candidate : runner->children) {
1593 if(candidate->visited) {
1594 can_continue = true;
1595 next_node = candidate;
1596 continue;
1597 } else {
1598 next_node = candidate;
1599 can_continue = true;
1600 stop = false;
1601 break;
1602 }
1603 }
1604
1605 if(!can_continue) {
1606 // no children at all: give up
1607 break;
1608 }
1609 // otherwise we have an already visited children
1610 // which we could use to finish the curve
1611
1612 // we care about mouths:
1613 if(next_node->children.size() == 0) {
1614 can_continue = false;
1615 next_node->visited = true;
1616
1617 auto current_point = glm::vec2(runner->x, runner->y);
1618 auto next_point = glm::vec2(next_node->x, next_node->y);
1619
1620 auto current_tangent = glm::normalize(next_point - current_point);
1621 next_point = next_point + current_tangent * 5.f;
1622 auto current_normal = glm::vec2{ -current_tangent.y, current_tangent.x };
1623 auto next_tangent = glm::normalize(current_tangent);
1624
1625 for(uint8_t step = 0; step <= steps; step++) {
1626 auto t = (float(step) / float(steps));
1627 vertex =
1628 t * next_point
1629 + (1.f - t) * current_point;
1630 auto width = t * next_node->width + (1.f - t) * runner->width;
1631
1632 auto current_weight = weight * width;
1633
1634 auto acceleration = (vertex - vertex_stabilized) / current_weight;
1635 vertex_stabilized_speed += acceleration;
1636 vertex_stabilized_speed *= (1.f - friction * 0.9f);
1637
1638 auto vertex_old_opengl_coords = vertex_stabilized / glm::vec2(size_x, size_y);
1639 vertex_stabilized = vertex_stabilized + vertex_stabilized_speed;
1640 auto vertex_opengl_coords = vertex_stabilized / glm::vec2(size_x, size_y);
1641 auto speed_opengl_coords = vertex_opengl_coords - vertex_old_opengl_coords;
1642 auto normal_opengl_coords = glm::normalize(glm::vec2{ -speed_opengl_coords.y, speed_opengl_coords.x });
1643 distance += glm::length(speed_opengl_coords);
1644
1645 river_vertices.emplace_back(textured_line_with_width_vertex{ vertex_opengl_coords, +normal_opengl_coords, 0.0f, distance, width });//C
1646 river_vertices.emplace_back(textured_line_with_width_vertex{ vertex_opengl_coords, -normal_opengl_coords, 1.0f, distance, width });//D
1647 }
1648
1649 /*
1650 add_tl_bezier_to_buffer(
1651 river_vertices,
1652 current_point,
1653 next_point,
1654 current_tangent,
1655 next_tangent,
1656 0.0f,
1657 false,
1658 float(size_x),
1659 float(size_y),
1660 8,
1661 distance,
1662 runner->width,
1663 next_node->width
1664 );
1665 */
1666
1667 break;
1668 }
1669
1670 // backtrack for a while to connect to previous parent?
1671
1672 river_vertex* next_next_node = next_node->children[0];
1673
1674 auto current_point = glm::vec2(runner->x, runner->y);
1675 auto next_point = glm::vec2(next_node->x, next_node->y);
1676 auto next_next_point = glm::vec2(next_next_node->x, next_next_node->y);
1677
1678 auto current_tangent = next_point - current_point;
1679 auto next_tangent = next_next_point - next_point;
1680
1681 for(uint8_t step = 0; step <= steps; step++) {
1682 auto t = (float(step) / float(steps));
1683 vertex =
1684 t * next_point
1685 + (1.f - t) * current_point;
1686 auto width = t * next_node->width + (1.f - t) * runner->width;
1687
1688 auto current_weight = weight * width;
1689
1690 auto acceleration = (vertex - vertex_stabilized) / current_weight;
1691 vertex_stabilized_speed += acceleration;
1692 vertex_stabilized_speed *= (1.f - friction);
1693
1694 auto vertex_old_opengl_coords = vertex_stabilized / glm::vec2(size_x, size_y);
1695 vertex_stabilized = vertex_stabilized + vertex_stabilized_speed;
1696 auto vertex_opengl_coords = vertex_stabilized / glm::vec2(size_x, size_y);
1697 auto speed_opengl_coords = vertex_opengl_coords - vertex_old_opengl_coords;
1698 auto normal_opengl_coords = glm::normalize(glm::vec2{ -speed_opengl_coords.y, speed_opengl_coords.x });
1699 distance += glm::length(speed_opengl_coords);
1700
1701 river_vertices.emplace_back(textured_line_with_width_vertex{ vertex_opengl_coords, +normal_opengl_coords, 0.0f, distance, width });//C
1702 river_vertices.emplace_back(textured_line_with_width_vertex{ vertex_opengl_coords, -normal_opengl_coords, 1.0f, distance, width });//D
1703 }
1704
1705 /*
1706 add_tl_bezier_to_buffer(
1707 river_vertices,
1708 current_point,
1709 next_point,
1710 current_tangent,
1711 next_tangent,
1712 0.0f,
1713 false,
1714 float(size_x),
1715 float(size_y),
1716 8,
1717 distance,
1718 runner->width,
1719 next_node->width
1720 );
1721 */
1722
1723 if(stop) {
1724 count_back -= 1;
1725 }
1726
1727 if(count_back == 0) {
1728 // we already visited the next node
1729 // and used it only to have a smooth merge
1730 break;
1731 }
1732
1733 runner = next_node;
1734 current_path.push_back(runner);
1735 vertex_stabilized_history.push_back( vertex_stabilized );
1736 }
1737
1738 // save count of vertices in current batch
1739 river_counts.push_back(GLsizei(river_vertices.size() - river_starts.back()));
1740 }
1741
1742 glm::vec2 current_pos = glm::vec2(source->x, source->y);
1743 glm::vec2 next_pos = glm::vec2(0, 0);
1744
1745
1746
1747
1748 }
1749}
1750
1751}
std::vector< textured_line_with_width_vertex > river_vertices
Definition: map.hpp:116
std::vector< GLsizei > river_counts
Definition: map.hpp:118
std::vector< GLsizei > coastal_counts
Definition: map.hpp:124
std::vector< GLint > coastal_starts
Definition: map.hpp:123
uint16_t safe_get_province(glm::ivec2 pt)
std::vector< border > borders
Definition: map.hpp:114
std::vector< GLint > river_starts
Definition: map.hpp:117
std::vector< uint16_t > province_id_map
Definition: map.hpp:162
std::vector< uint8_t > diagonal_borders
Definition: map.hpp:159
std::vector< textured_line_vertex_b > border_vertices
Definition: map.hpp:115
std::vector< textured_line_vertex_b > coastal_vertices
Definition: map.hpp:122
void make_coastal_borders(sys::state &state, std::vector< bool > &visited)
void load_border_data(parsers::scenario_building_context &context)
void make_borders(sys::state &state, std::vector< bool > &visited)
void create_curved_river_vertices(parsers::scenario_building_context &context, std::vector< uint8_t > const &river_data, std::vector< uint8_t > const &terrain_data)
uint32_t size_y
Definition: map.hpp:169
uint32_t size_x
Definition: map.hpp:168
#define assert(condition)
Definition: debug.h:74
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
glm::vec2 put_in_local(glm::vec2 new_point, glm::vec2 base_point, float size_x)
Definition: map.cpp:1561
bool is_river_merge(uint8_t river_data)
bool is_river_source(uint8_t river_data)
int32_t river_width(uint8_t river_data)
bool check_for_river(std::vector< uint8_t > const &river_data, river_runner &runner, int32_t x, int32_t y, glm::ivec2 size)
std::vector< glm::vec2 > make_border_section(display_data &dat, sys::state &state, std::vector< bool > &visited, uint16_t prov_prim, uint16_t prov_sec, int32_t start_x, int32_t start_y)
int32_t get_border_index(uint16_t map_province_id1, uint16_t map_province_id2, parsers::scenario_building_context &context)
bool check_for_parent(river_vertex *vertex, uint32_t x, uint32_t y)
bool coastal_point(sys::state &state, uint16_t a, uint16_t b)
std::vector< glm::vec2 > make_coastal_loop(display_data &dat, sys::state &state, std::vector< bool > &visited, int32_t start_x, int32_t start_y)
direction
Definition: map_borders.cpp:8
@ UP_LEFT
Definition: map_borders.cpp:9
@ DOWN_RIGHT
Definition: map_borders.cpp:12
@ LEFT
Definition: map_borders.cpp:15
@ UP_RIGHT
Definition: map_borders.cpp:10
@ DOWN
Definition: map_borders.cpp:14
@ DOWN_LEFT
Definition: map_borders.cpp:11
@ RIGHT
Definition: map_borders.cpp:16
bool check_for_child(river_vertex *vertex, uint32_t x, uint32_t y)
void add_border_segment_vertices(display_data &dat, std::vector< glm::vec2 > const &points)
std::vector< glm::ivec2 > check_for_potential_child(std::vector< uint8_t > const &river_data, river_runner &runner, glm::ivec2 size)
bool order_indifferent_compare(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
void add_coastal_loop_vertices(display_data &dat, std::vector< glm::vec2 > const &points)
diagonal_border
Definition: map_borders.cpp:19
bool extend_if_possible(uint32_t x, int32_t border_id, direction dir, std::vector< border_direction > &last_row, std::vector< border_direction > &current_row, glm::vec2 map_size, std::vector< curved_line_vertex > &border_vertices)
Definition: map_borders.cpp:42
void load_river_crossings(parsers::scenario_building_context &context, std::vector< uint8_t > const &river_data, glm::ivec2 map_size)
bool is_river(uint8_t river_data)
constexpr uint8_t impassible_bit
Definition: constants.hpp:595
constexpr uint8_t non_adjacent_bit
Definition: constants.hpp:596
constexpr uint8_t river_crossing_bit
Definition: constants.hpp:597
constexpr dcon::province_id from_map_id(uint16_t id)
Definition: province.hpp:13
constexpr uint16_t to_map_id(dcon::province_id id)
Definition: province.hpp:10
uint uint32_t
uchar uint8_t
information(int32_t index_, int32_t id_)
Definition: map_borders.cpp:31
river_vertex * position
std::vector< river_vertex * > parents
bool operator==(const river_vertex &other)
std::vector< river_vertex * > children
dcon::province_id first_sea_province
Definition: province.hpp:26
dcon::data_container world
province::global_provincial_state province_definitions