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