Project Alice
Loading...
Searching...
No Matches
map_data_loading.cpp
Go to the documentation of this file.
1#include "map.hpp"
2
3#include "province.hpp"
4#include "system_state.hpp"
6#include "opengl_wrapper.hpp"
7
8#ifdef _WIN64
9
10#ifndef UNICODE
11#define UNICODE
12#endif
13#define NOMINMAX
14#define WIN32_LEAN_AND_MEAN
15
16#include "Windows.h"
17
18#endif
19
20namespace map {
21
27};
28
29// Used to load the terrain.bmp and the rivers.bmp
30std::vector<uint8_t> load_bmp(parsers::scenario_building_context& context, native_string_view name, glm::ivec2 map_size, uint8_t fill, std::vector<bmp_pixel_data> * color_table) {
31 std::vector<uint8_t> output_data(map_size.x * map_size.y, fill);
32
33 auto root = simple_fs::get_root(context.state.common_fs);
34 auto map_dir = simple_fs::open_directory(root, NATIVE("map"));
35 auto terrain_bmp = open_file(map_dir, name);
36
37 if(!terrain_bmp)
38 return output_data;
39
40 auto content = simple_fs::view_contents(*terrain_bmp);
41 uint8_t const* start = (uint8_t const*)(content.data);
42
43#ifdef __linux__
44
45 //Ported from Microsoft's documentation
46 //Replaced DWORD into uint32_t, WORD into uint16_t
47 //LONG into int32_t
48 typedef struct {
49 int32_t ciexyzX;
50 int32_t ciexyzY;
51 int32_t ciexyzZ;
52 } CIEXYZ;
53
54 typedef struct {
55 CIEXYZ ciexyzRed;
56 CIEXYZ ciexyzGreen;
57 CIEXYZ ciexyzBlue;
58 } CIEXYZTRIPLE;
59
60 typedef struct {
61 uint16_t bfType;
62 uint32_t bfSize;
63 uint16_t bfReserved1;
64 uint16_t bfReserved2;
65 uint32_t bfOffBits;
66 } __attribute__((__packed__))
67 BITMAPFILEHEADER;
68
69 typedef struct {
70 uint32_t biSize;
71 int32_t biWidth;
72 int32_t biHeight;
73 uint16_t biPlanes;
74 uint16_t biBitCount;
75 uint32_t biCompression;
76 uint32_t biSizeImage;
77 int32_t biXPelsPerMeter;
78 int32_t biYPelsPerMeter;
79 uint32_t biClrUsed;
80 uint32_t biClrImportant;
81 } __attribute__((__packed__))
82 BITMAPINFOHEADER;
83
84 typedef struct {
85 uint32_t bcSize;
86 uint16_t bcWidth;
87 uint16_t bcHeight;
88 uint16_t bcPlanes;
89 uint16_t bcBitCount;
90 } BITMAPCOREHEADER;
91
92 typedef struct {
93 uint32_t bV4Size;
94 int32_t bV4Width;
95 int32_t bV4Height;
96 uint16_t bV4Planes;
97 uint16_t bV4BitCount;
98 uint32_t bV4V4Compression;
99 uint32_t bV4SizeImage;
100 int32_t bV4XPelsPerMeter;
101 int32_t bV4YPelsPerMeter;
102 uint32_t bV4ClrUsed;
103 uint32_t bV4ClrImportant;
104 uint32_t bV4RedMask;
105 uint32_t bV4GreenMask;
106 uint32_t bV4BlueMask;
107 uint32_t bV4AlphaMask;
108 uint32_t bV4CSType;
109 uint32_t bV4GammaRed;
110 uint32_t bV4GammaGreen;
111 uint32_t bV4GammaBlue;
112 } BITMAPV4HEADER;
113
114 typedef struct {
115 uint32_t bV5Size;
116 int32_t bV5Width;
117 int32_t bV5Height;
118 uint16_t bV5Planes;
119 uint16_t bV5BitCount;
120 uint32_t bV5Compression;
121 uint32_t bV5SizeImage;
122 int32_t bV5XPelsPerMeter;
123 int32_t bV5YPelsPerMeter;
124 uint32_t bV5ClrUsed;
125 uint32_t bV5ClrImportant;
126 uint32_t bV5RedMask;
127 uint32_t bV5GreenMask;
128 uint32_t bV5BlueMask;
129 uint32_t bV5AlphaMask;
130 uint32_t bV5CSType;
131 CIEXYZTRIPLE bV5Endpoints;
132 uint32_t bV5GammaRed;
133 uint32_t bV5GammaGreen;
134 uint32_t bV5GammaBlue;
135 uint32_t bV5Intent;
136 uint32_t bV5ProfileData;
137 uint32_t bV5ProfileSize;
138 uint32_t bV5Reserved;
139 } BITMAPV5HEADER;
140
141 const int BI_RGB = 0;
142 const int BI_RLE8 = 1;
143 const int BI_RLE4 = 2;
144
145#endif
146
147 int32_t compression_type = 0;
148 int32_t size_x = 0;
149 int32_t size_y = 0;
150
151 uint32_t num_of_colors = 2;
152
153 bool has_BI_BITFIELDS = false;
154 bool has_BI_ALPHABITFIELDS = false;
155
156 BITMAPFILEHEADER const* fh = (BITMAPFILEHEADER const*)(start);
157 uint8_t const* data = start + fh->bfOffBits;
158 std::unique_ptr<uint8_t[]> decompressed_data;
159
160 auto color_table_offset = start + sizeof(BITMAPFILEHEADER);
161
162 BITMAPCOREHEADER const* core_h = (BITMAPCOREHEADER const*)(start + sizeof(BITMAPFILEHEADER));
163 if(core_h->bcSize == sizeof(BITMAPINFOHEADER)) {
164 BITMAPINFOHEADER const* h = (BITMAPINFOHEADER const*)(start + sizeof(BITMAPFILEHEADER));
165 size_x = h->biWidth;
166 size_y = h->biHeight;
167 num_of_colors = h->biClrUsed;
168 if(num_of_colors == 0) {
169 num_of_colors = 1 << h->biBitCount;
170 }
171 if(h->biCompression == BI_RLE8) {
172 compression_type = 1;
173 }
174 color_table_offset += sizeof(BITMAPINFOHEADER);
175 } else if(core_h->bcSize == sizeof(BITMAPV5HEADER)) {
176 BITMAPV5HEADER const* h = (BITMAPV5HEADER const*)(start + sizeof(BITMAPFILEHEADER));
177 if(h->bV5Compression == BI_RLE8) {
178 compression_type = 1;
179 }
180 size_x = h->bV5Width;
181 size_y = h->bV5Height;
182 num_of_colors = h->bV5ClrUsed;
183 if(num_of_colors == 0) {
184 num_of_colors = 1 << h->bV5BitCount;
185 }
186 color_table_offset += sizeof(BITMAPV5HEADER);
187 } else if(core_h->bcSize == sizeof(BITMAPV4HEADER)) {
188 BITMAPV4HEADER const* h = (BITMAPV4HEADER const*)(start + sizeof(BITMAPFILEHEADER));
189 if(h->bV4V4Compression == BI_RLE8) {
190 compression_type = 1;
191 }
192 size_x = h->bV4Width;
193 size_y = h->bV4Height;
194 num_of_colors = h->bV4ClrUsed;
195 if(num_of_colors == 0) {
196 num_of_colors = 1 << h->bV4BitCount;
197 }
198 color_table_offset += sizeof(BITMAPV4HEADER);
199 } else if(core_h->bcSize == sizeof(BITMAPCOREHEADER)) {
200 BITMAPCOREHEADER const* h = (BITMAPCOREHEADER const*)(start + sizeof(BITMAPFILEHEADER));
201 size_x = h->bcWidth;
202 size_y = h->bcHeight;
203 num_of_colors = 1 << h->bcBitCount;
204 color_table_offset += sizeof(BITMAPCOREHEADER);
205 } else {
206 std::abort(); // unknown bitmap type
207 }
208
209 // reading color table:
210 if(color_table != nullptr) {
211 for(uint32_t color_entry_index = 0; color_entry_index < num_of_colors; color_entry_index++) {
212 bmp_pixel_data const* new_color =
213 (bmp_pixel_data const*)
214 (color_table_offset + color_entry_index * sizeof(bmp_pixel_data));
215 color_table->push_back(*new_color);
216 }
217 }
218
219 if(compression_type == 1) {
220 decompressed_data.reset(new uint8_t[std::abs(size_x) * std::abs(size_y)]);
221 memset(decompressed_data.get(), 0xFF, std::abs(size_x) * std::abs(size_y));
222 auto out_ptr = decompressed_data.get();
223 int32_t out_x = 0;;
224 int32_t out_y = 0;
225
226 for(auto ptr = data; ptr < start + content.file_size; ) {
227 if(ptr[0] == 0) {
228 if(ptr[1] == 0) { // end of line
229 auto offset = out_ptr - decompressed_data.get();
230 auto line = (offset - 1) / std::abs(size_x);
231 out_ptr = decompressed_data.get() + (line + 1) * std::abs(size_x);
232 ptr += 2;
233 } else if(ptr[1] == 1) { // end of bitmap
234 break;
235 } else if(ptr[1] == 2) { // move cursor
236 auto right = ptr[2];
237 auto up = ptr[3];
238 auto offset = out_ptr - decompressed_data.get();
239 auto line = offset / std::abs(size_x);
240 auto x = out_ptr - (decompressed_data.get() + line * std::abs(size_x));
241 auto new_line = line + up;
242 out_ptr = decompressed_data.get() + new_line * std::abs(size_x) + x + right;
243 ptr += 4;
244 } else { // absolute mode
245 auto num_pixels = int32_t(ptr[1]);
246 auto amount_to_copy = std::min(ptrdiff_t(num_pixels),
247 std::min(
248 decompressed_data.get() + std::abs(size_x) * std::abs(size_y) - out_ptr,
249 start + content.file_size - (ptr + 2)
250 ));
251 memcpy(out_ptr, ptr + 2, amount_to_copy);
252 ptr += 2 + int32_t(ptr[1]) + ((ptr[1] & 1) != 0);
253 out_ptr += num_pixels;
254 }
255 } else {
256 auto num_pixels = ptr[0];
257 auto color_index = ptr[1];
258
259 while(num_pixels > 0 && out_ptr < decompressed_data.get() + std::abs(size_x) * std::abs(size_y)) {
260 *out_ptr = color_index;
261 ++out_ptr;
262 --num_pixels;
263 }
264 ptr += 2;
265 }
266 }
267 data = decompressed_data.get();
268 }
269
270 assert(size_x == int32_t(map_size.x));
271 uint32_t free_space = uint32_t(std::max(0, map_size.y - size_y)); // schombert: find out how much water we need to add
272
273 // Calculate how much extra we add at the poles
274 uint32_t top_free_space = (free_space * 3) / 5;
275
276 // Fill the output with the given data - copy over the bmp data to the middle of the output_data
277 for(uint32_t y = top_free_space + size_y - 1; y >= uint32_t(top_free_space); --y) {
278 for(uint32_t x = 0; x < uint32_t(size_x); ++x) {
279 output_data[y * size_x + x] = *data;
280 data++;
281 }
282 }
283 return output_data;
284}
285
286ankerl::unordered_dense::map<uint32_t, uint8_t> internal_make_index_map() {
287 ankerl::unordered_dense::map<uint32_t, uint8_t> m;
288
289 m.insert_or_assign(sys::pack_color(0xEC, 0xEC, 0xEC), uint8_t(0));
290 m.insert_or_assign(sys::pack_color(0xD2, 0xD2, 0xD2), uint8_t(1));
291 m.insert_or_assign(sys::pack_color(0xB0, 0xB0, 0xB0), uint8_t(2));
292 m.insert_or_assign(sys::pack_color(0x8C, 0x8C, 0x8C), uint8_t(3));
293 m.insert_or_assign(sys::pack_color(0x70, 0x70, 0x70), uint8_t(4));
294 m.insert_or_assign(sys::pack_color(0x56, 0x56, 0x56), uint8_t(5));
295 m.insert_or_assign(sys::pack_color(0x4E, 0x4E, 0x4E), uint8_t(6));
296 m.insert_or_assign(sys::pack_color(0x38, 0x38, 0x38), uint8_t(7));
297 m.insert_or_assign(sys::pack_color(0x98, 0xD3, 0x83), uint8_t(8));
298 m.insert_or_assign(sys::pack_color(0x86, 0xBF, 0x5C), uint8_t(9));
299 m.insert_or_assign(sys::pack_color(0x6F, 0xA2, 0x39), uint8_t(10));
300 m.insert_or_assign(sys::pack_color(0x56, 0x7C, 0x1B), uint8_t(11));
301 m.insert_or_assign(sys::pack_color(0x40, 0x61, 0x0C), uint8_t(12));
302 m.insert_or_assign(sys::pack_color(0x4C, 0x56, 0x04), uint8_t(13));
303 m.insert_or_assign(sys::pack_color(0x27, 0x42, 0x00), uint8_t(14));
304 m.insert_or_assign(sys::pack_color(0x21, 0x28, 0x00), uint8_t(15));
305 m.insert_or_assign(sys::pack_color(0xA0, 0xD4, 0xDC), uint8_t(16));
306 m.insert_or_assign(sys::pack_color(0x78, 0xB4, 0xCA), uint8_t(17));
307 m.insert_or_assign(sys::pack_color(0x4B, 0x93, 0xAE), uint8_t(18));
308 m.insert_or_assign(sys::pack_color(0x2D, 0x77, 0x92), uint8_t(19));
309 m.insert_or_assign(sys::pack_color(0x25, 0x60, 0x7E), uint8_t(20));
310 m.insert_or_assign(sys::pack_color(0x0F, 0x3F, 0x5A), uint8_t(21));
311 m.insert_or_assign(sys::pack_color(0x06, 0x29, 0x4E), uint8_t(22));
312 m.insert_or_assign(sys::pack_color(0x02, 0x14, 0x29), uint8_t(23));
313 m.insert_or_assign(sys::pack_color(0xEB, 0xB3, 0xE9), uint8_t(24));
314 m.insert_or_assign(sys::pack_color(0xD5, 0x90, 0xC7), uint8_t(25));
315 m.insert_or_assign(sys::pack_color(0xB5, 0x6F, 0xB1), uint8_t(26));
316 m.insert_or_assign(sys::pack_color(0xB4, 0x56, 0xB3), uint8_t(27));
317 m.insert_or_assign(sys::pack_color(0xC0, 0x5A, 0x75), uint8_t(28));
318 m.insert_or_assign(sys::pack_color(0xAD, 0x3B, 0x53), uint8_t(29));
319 m.insert_or_assign(sys::pack_color(0xA2, 0x27, 0x53), uint8_t(30));
320 m.insert_or_assign(sys::pack_color(0x7F, 0x18, 0x3C), uint8_t(31));
321 m.insert_or_assign(sys::pack_color(0xE7, 0x20, 0x37), uint8_t(32));
322 m.insert_or_assign(sys::pack_color(0xB3, 0x0B, 0x1B), uint8_t(33));
323 m.insert_or_assign(sys::pack_color(0x8A, 0x0B, 0x1A), uint8_t(34));
324 m.insert_or_assign(sys::pack_color(0x45, 0x0B, 0x10), uint8_t(35));
325 m.insert_or_assign(sys::pack_color(0x63, 0x07, 0x0B), uint8_t(36));
326 m.insert_or_assign(sys::pack_color(0x52, 0x04, 0x08), uint8_t(37));
327 m.insert_or_assign(sys::pack_color(0x3E, 0x02, 0x05), uint8_t(38));
328 m.insert_or_assign(sys::pack_color(0x27, 0x00, 0x02), uint8_t(39));
329 m.insert_or_assign(sys::pack_color(0x76, 0xF5, 0xD9), uint8_t(40));
330 m.insert_or_assign(sys::pack_color(0x61, 0xDC, 0xC1), uint8_t(41));
331 m.insert_or_assign(sys::pack_color(0x38, 0xC7, 0xA7), uint8_t(42));
332 m.insert_or_assign(sys::pack_color(0x30, 0xAF, 0x93), uint8_t(43));
333 m.insert_or_assign(sys::pack_color(0x1F, 0x9A, 0x7F), uint8_t(44));
334 m.insert_or_assign(sys::pack_color(0x10, 0x7A, 0x63), uint8_t(45));
335 m.insert_or_assign(sys::pack_color(0x02, 0x5E, 0x4A), uint8_t(46));
336 m.insert_or_assign(sys::pack_color(0x00, 0x49, 0x39), uint8_t(47));
337 m.insert_or_assign(sys::pack_color(0xF1, 0xD2, 0x97), uint8_t(48));
338 m.insert_or_assign(sys::pack_color(0xE1, 0xC0, 0x82), uint8_t(49));
339 m.insert_or_assign(sys::pack_color(0xCE, 0xA9, 0x63), uint8_t(50));
340 m.insert_or_assign(sys::pack_color(0xAC, 0x88, 0x43), uint8_t(51));
341 m.insert_or_assign(sys::pack_color(0x96, 0x71, 0x29), uint8_t(52));
342 m.insert_or_assign(sys::pack_color(0x7B, 0x5A, 0x1B), uint8_t(53));
343 m.insert_or_assign(sys::pack_color(0x65, 0x47, 0x0F), uint8_t(54));
344 m.insert_or_assign(sys::pack_color(0x49, 0x32, 0x06), uint8_t(55));
345 m.insert_or_assign(sys::pack_color(0x9C, 0x8B, 0x54), uint8_t(56));
346 m.insert_or_assign(sys::pack_color(0x88, 0x77, 0xD2), uint8_t(57));
347 m.insert_or_assign(sys::pack_color(0x75, 0x63, 0xC2), uint8_t(58));
348 m.insert_or_assign(sys::pack_color(0x50, 0x41, 0x92), uint8_t(59));
349 m.insert_or_assign(sys::pack_color(0x41, 0x34, 0x79), uint8_t(60));
350 m.insert_or_assign(sys::pack_color(0x2D, 0x22, 0x5F), uint8_t(61));
351 m.insert_or_assign(sys::pack_color(0x1A, 0x11, 0x43), uint8_t(62));
352 m.insert_or_assign(sys::pack_color(0x10, 0x0B, 0x29), uint8_t(63));
353
354 m.insert_or_assign(sys::pack_color(0xFF, 0xFF, 0xFF), uint8_t(255));
355
356 return m;
357}
358
360 if(!context.new_maps) {
361 terrain_id_map = load_bmp(context, NATIVE("terrain.bmp"), glm::ivec2(size_x, size_y), 255, nullptr);
362 } else {
363 auto root = simple_fs::get_root(context.state.common_fs);
364 auto map_dir = simple_fs::open_directory(root, NATIVE("map"));
365 auto terrain_file = open_file(map_dir, NATIVE("alice_terrain.png"));
366 terrain_id_map.resize(size_x * size_y, uint8_t(255));
367
368 ogl::image terrain_data;
369 if(terrain_file)
370 terrain_data = ogl::load_stb_image(*terrain_file);
371
372 auto terrain_resolution = internal_make_index_map();
373
374 if(terrain_data.size_x == int32_t(size_x) && terrain_data.size_y == int32_t(size_y)) {
375 for(uint32_t ty = 0; ty < size_y; ++ty) {
376 uint32_t y = size_y - ty - 1;
377 for(uint32_t x = 0; x < size_x; ++x) {
378
379
380 uint8_t* ptr = terrain_data.data + (x + size_x * y) * 4;
381 auto color = sys::pack_color(ptr[0], ptr[1], ptr[2]);
382
383 if(auto it = terrain_resolution.find(color); it != terrain_resolution.end()) {
384 terrain_id_map[ty * size_x + x] = it->second;
385 } else {
386 bool found_neightbor = false;
387
388 if(x > 0) {
389 uint8_t* ptrb = terrain_data.data + (x - 1 + size_x * y) * 4;
390 auto colorb = sys::pack_color(ptrb[0], ptrb[1], ptrb[2]);
391
392 if(auto itb = terrain_resolution.find(colorb); itb != terrain_resolution.end()) {
393 terrain_id_map[ty * size_x + x] = itb->second;
394 found_neightbor = true;
395 }
396 }
397 if(!found_neightbor && y > 0) {
398 uint8_t* ptrb = terrain_data.data + (x + size_x * (y-1)) * 4;
399 auto colorb = sys::pack_color(ptrb[0], ptrb[1], ptrb[2]);
400
401 if(auto itb = terrain_resolution.find(colorb); itb != terrain_resolution.end()) {
402 terrain_id_map[ty * size_x + x] = itb->second;
403 found_neightbor = true;
404 }
405 }
406 if(!found_neightbor && x < size_x - 1) {
407 uint8_t* ptrb = terrain_data.data + (x + 1 + size_x * y) * 4;
408 auto colorb = sys::pack_color(ptrb[0], ptrb[1], ptrb[2]);
409
410 if(auto itb = terrain_resolution.find(colorb); itb != terrain_resolution.end()) {
411 terrain_id_map[ty * size_x + x] = itb->second;
412 found_neightbor = true;
413 }
414 }
415 if(!found_neightbor && y < size_y - 1) {
416 uint8_t* ptrb = terrain_data.data + (x + size_x * (y + 1)) * 4;
417 auto colorb = sys::pack_color(ptrb[0], ptrb[1], ptrb[2]);
418
419 if(auto itb = terrain_resolution.find(colorb); itb != terrain_resolution.end()) {
420 terrain_id_map[ty * size_x + x] = itb->second;
421 found_neightbor = true;
422 }
423 }
424
425 if(!found_neightbor) {
426 uint8_t resolved_index = 255;
427 int32_t min_distance = std::numeric_limits<int32_t>::max();
428 for(auto& p : terrain_resolution) {
429 if(p.second == 255)
430 continue;
431 auto c = p.first;
432 auto r = sys::int_red_from_int(c);
433 auto g = sys::int_green_from_int(c);
434 auto b = sys::int_blue_from_int(c);
435 auto dist = (r - ptr[0]) * (r - ptr[0]) + (b - ptr[1]) * (b - ptr[1]) + (g - ptr[2]) * (g - ptr[2]);
436 if(dist < min_distance) {
437 min_distance = dist;
438 resolved_index = p.second;
439 }
440 }
441 terrain_id_map[ty * size_x + x] = resolved_index;
442 }
443
444 }
445 }
446 }
447 }
448 }
449
450 // Gets rid of any stray land terrain that has been painted outside the borders
451 for(uint32_t y = 0; y < size_y; ++y) {
452 for(uint32_t x = 0; x < size_x; ++x) {
453 if(province_id_map[y * size_x + x] == 0) { // If there is no province define at that location
454 terrain_id_map[y * size_x + x] = uint8_t(255);
455 } else if(province_id_map[y * size_x + x] >= province::to_map_id(context.state.province_definitions.first_sea_province)) { // sea province
456 terrain_id_map[y * size_x + x] = uint8_t(255);
457 } else { // land province
458 if(terrain_id_map[y * size_x + x] >= 64) {
459 terrain_id_map[y * size_x + x] = uint8_t(5); // ocean terrain -> plains
460 }
461 }
462 }
463 }
464
465 // Load the terrain
467}
468
469
471 median_terrain_type.resize(context.state.world.province_size() + 1);
472 province_area.resize(context.state.world.province_size() + 1);
473 std::vector<std::array<int, 64>> terrain_histogram(context.state.world.province_size() + 1, std::array<int, 64>{});
474 for(int i = size_x * size_y - 1; i-- > 0;) {
475 auto prov_id = province_id_map[i];
476 auto terrain_id = terrain_id_map[i];
477 if(terrain_id < 64)
478 terrain_histogram[prov_id][terrain_id] += 1;
479 }
480
481 for(int i = context.state.world.province_size(); i-- > 1;) { // map-id province 0 == the invalid province; we don't need to collect data for it
482 int max_index = 64;
483 int max = 0;
484 province_area[i] = 0;
485 for(int j = max_index; j-- > 0;) {
486 province_area[i] += terrain_histogram[i][j];
487 if(terrain_histogram[i][j] > max) {
488 max_index = j;
489 max = terrain_histogram[i][j];
490 }
491 }
492 median_terrain_type[i] = uint8_t(max_index);
493 province_area[i] = std::max(province_area[i], uint32_t(1));
494 }
495}
496
498 std::vector<glm::ivec2> accumulated_tile_positions(context.state.world.province_size() + 1, glm::vec2(0));
499 std::vector<int> tiles_number(context.state.world.province_size() + 1, 0);
500 for(int i = size_x * size_y - 1; i-- > 0;) {
501 auto prov_id = province_id_map[i];
502 int x = i % size_x;
503 int y = i / size_x;
504 accumulated_tile_positions[prov_id] += glm::vec2(x, y);
505 tiles_number[prov_id]++;
506 }
507 // schombert: needs to start from +1 here or you don't catch the last province
508 for(int i = context.state.world.province_size() + 1; i-- > 1;) { // map-id province 0 == the invalid province; we don't need to collect data for it
509
510 glm::vec2 tile_pos;
511
512 // OK, so some mods do in fact define provinces that aren't on the map.
513 //assert(tiles_number[i] > 0); // yeah but a province without tiles is no bueno
514
515 if(tiles_number[i] == 0) {
516 tile_pos = glm::vec2(0, 0);
517 } else {
518 tile_pos = accumulated_tile_positions[i] / tiles_number[i];
519 }
520 context.state.world.province_set_mid_point(province::from_map_id(uint16_t(i)), tile_pos);
521 }
522}
523
525 uint32_t imsz = uint32_t(size_x * size_y);
526 if(!context.new_maps) {
527 auto free_space = std::max(uint32_t(0), size_y - image.size_y); // schombert: find out how much water we need to add
528 auto top_free_space = (free_space * 3) / 5;
529
530 province_id_map.resize(imsz);
531 uint32_t i = 0;
532 for(; i < top_free_space * size_x; ++i) { // schombert: fill with nothing until the start of the real data
533 province_id_map[i] = 0;
534 }
535 auto first_actual_map_pixel = top_free_space * size_x; // schombert: where the real data starts
536 for(; i < first_actual_map_pixel + image.size_x * image.size_y; ++i) {
537 uint8_t* ptr = image.data + (i - first_actual_map_pixel) * 4; // schombert: subtract to find our offset in the actual image data
538 auto color = sys::pack_color(ptr[0], ptr[1], ptr[2]);
539 if(auto it = context.map_color_to_province_id.find(color); it != context.map_color_to_province_id.end()) {
540 assert(it->second);
541 province_id_map[i] = province::to_map_id(it->second);
542 } else {
543 province_id_map[i] = 0;
544 }
545 }
546 for(; i < imsz; ++i) { // schombert: fill remainder with nothing
547 province_id_map[i] = 0;
548 }
549 } else {
550 province_id_map.resize(imsz);
551 for(uint32_t i = 0; i < imsz; ++i) {
552 auto map_x = i % size_x;
553 auto map_y = i / size_x;
554 uint8_t* ptr = image.data + (map_x + size_x * (size_y - map_y - 1)) * 4;
555 auto color = sys::pack_color(ptr[0], ptr[1], ptr[2]);
556 if(auto it = context.map_color_to_province_id.find(color); it != context.map_color_to_province_id.end()) {
557 assert(it->second);
558 province_id_map[i] = province::to_map_id(it->second);
559 } else {
560 province_id_map[i] = 0;
561 }
562 }
563 }
564
566}
567
569 auto root = simple_fs::get_root(context.state.common_fs);
570 auto map_dir = simple_fs::open_directory(root, NATIVE("map"));
571
572 // Load the province map
573 auto provinces_png = simple_fs::open_file(map_dir, NATIVE("alice_provinces.png"));
574 ogl::image provinces_image;
575 if(provinces_png) {
576 provinces_image = ogl::load_stb_image(*provinces_png);
577 size_x = uint32_t(provinces_image.size_x);
578 size_y = uint32_t(provinces_image.size_y);
579 context.new_maps = true;
580 } else {
581 auto provinces_bmp = simple_fs::open_file(map_dir, NATIVE("provinces.bmp"));
582 if(provinces_bmp) {
583 provinces_image = ogl::load_stb_image(*provinces_bmp);
584 size_x = uint32_t(provinces_image.size_x);
585 size_y = uint32_t(provinces_image.size_y * 1.3); // schombert: force the correct map size
586 } else {
587 return; // no map
588 }
589 }
590
591 load_province_data(context, provinces_image);
592 load_terrain_data(context);
593 load_border_data(context);
594
595 std::vector<uint8_t> river_data;
596 if(!context.new_maps) {
597 auto size = glm::ivec2(size_x, size_y);
598 std::vector<bmp_pixel_data> color_table;
599 river_data = load_bmp(context, NATIVE("rivers.bmp"), size, 255, &color_table);
600
601 for(uint32_t ty = 0; ty < size_y; ++ty) {
602 //uint32_t y = size_y - ty - 1;
603 for(uint32_t x = 0; x < size_x; ++x) {
604 uint8_t color_index = river_data[x + size_x * ty];
605 auto r = color_table[color_index].red;
606 auto g = color_table[color_index].green;
607 auto b = color_table[color_index].blue;
608 if(r == 255 && g == 0 && b == 128) {
609 river_data[ty * size_x + x] = 255; // sea
610 } else if(r == 255 && g == 255 && b == 255) {
611 river_data[ty * size_x + x] = 255; // land
612 } else if(color_index == 0 /* && terrain_id_map[x + size_x * ty] != uint8_t(255)*/)
613 river_data[ty * size_x + x] = 0; // source
614 else if(color_index == 1 /* && terrain_id_map[x + size_x * ty] != uint8_t(255)*/)
615 river_data[ty * size_x + x] = 1; // merge
616 else {
617 river_data[ty * size_x + x] = std::min<uint8_t>((uint8_t)250, std::max<uint8_t>((uint8_t)2, r / 3 + g / 3 + b / 3));
618 }
619 }
620 }
621
622 } else {
623 auto river_file = simple_fs::open_file(map_dir, NATIVE("alice_rivers.png"));
624 river_data.resize(size_x * size_y, uint8_t(255));
625
626 ogl::image river_image_data;
627 if(river_file)
628 river_image_data = ogl::load_stb_image(*river_file);
629
630 auto terrain_resolution = internal_make_index_map();
631
632 if(river_image_data.size_x == int32_t(size_x) && river_image_data.size_y == int32_t(size_y)) {
633 for(uint32_t ty = 0; ty < size_y; ++ty) {
634 uint32_t y = size_y - ty - 1;
635
636 for(uint32_t x = 0; x < size_x; ++x) {
637
638 uint8_t* ptr = river_image_data.data + (x + size_x * y) * 4;
639 if(ptr[0] + ptr[2] < 128 * 2 && ptr[1] > 128 /* && terrain_id_map[x + size_x * ty] != uint8_t(255)*/)
640 river_data[ty * size_x + x] = 0; // source
641 else if(ptr[1] + ptr[2] < 128 * 2 && ptr[0] > 128 /* && terrain_id_map[x + size_x * ty] != uint8_t(255)*/ )
642 river_data[ty * size_x + x] = 1; // merge
643 else if(ptr[0] + ptr[1] + ptr[2] < 128 * 3 /*&& terrain_id_map[x + size_x * ty] != uint8_t(255)*/)
644 river_data[ty * size_x + x] = std::min<uint8_t>((uint8_t)250, std::max<uint8_t>((uint8_t)2, ptr[0] / 3 + ptr[1] / 3 + ptr[2] / 3));
645 else
646 river_data[ty * size_x + x] = 255;
647
648 }
649 }
650 }
651 }
652
653
654 load_river_crossings(context, river_data, glm::vec2(float(size_x), float(size_y)));
655
656 create_curved_river_vertices(context, river_data, terrain_id_map);
657 {
658 std::vector<bool> borders_visited;
659 borders_visited.resize(size_x * size_y * 2, false);
660 make_coastal_borders(context.state, borders_visited);
661 }
662 {
663 std::vector<bool> borders_visited;
664 borders_visited.resize(size_x * size_y * 2, false);
665 make_borders(context.state, borders_visited);
666 }
667}
668
669// Called to load the terrain and province map data
671 map_data.load_map_data(context);
672}
673
674
675}
void load_terrain_data(parsers::scenario_building_context &context)
std::vector< uint8_t > median_terrain_type
Definition: map.hpp:157
std::vector< uint16_t > province_id_map
Definition: map.hpp:162
void make_coastal_borders(sys::state &state, std::vector< bool > &visited)
std::vector< uint8_t > terrain_id_map
Definition: map.hpp:156
void load_border_data(parsers::scenario_building_context &context)
void load_provinces_mid_point(parsers::scenario_building_context &context)
void load_median_terrain_type(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)
void load_map_data(parsers::scenario_building_context &context)
uint32_t size_y
Definition: map.hpp:169
uint32_t size_x
Definition: map.hpp:168
std::vector< uint32_t > province_area
Definition: map.hpp:158
void load_province_data(parsers::scenario_building_context &context, ogl::image &image)
void load_map_data(parsers::scenario_building_context &context)
display_data map_data
Definition: map_state.hpp:60
#define assert(condition)
Definition: debug.h:74
ankerl::unordered_dense::map< uint32_t, uint8_t > internal_make_index_map()
std::vector< uint8_t > load_bmp(parsers::scenario_building_context &context, native_string_view name, glm::ivec2 map_size, uint8_t fill, std::vector< bmp_pixel_data > *color_table)
void load_river_crossings(parsers::scenario_building_context &context, std::vector< uint8_t > const &river_data, glm::ivec2 map_size)
image load_stb_image(simple_fs::file &file)
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
directory open_directory(directory const &dir, native_string_view directory_name)
directory get_root(file_system const &fs)
std::optional< file > open_file(directory const &dir, native_string_view file_name)
file_contents view_contents(file const &f)
uint32_t pack_color(float r, float g, float b)
int32_t int_red_from_int(uint32_t v)
int32_t int_blue_from_int(uint32_t v)
int32_t int_green_from_int(uint32_t v)
#define NATIVE(X)
std::string_view native_string_view
uint uint32_t
uchar uint8_t
int32_t size_y
int32_t size_x
uint8_t * data
ankerl::unordered_dense::map< uint32_t, dcon::province_id > map_color_to_province_id
dcon::province_id first_sea_province
Definition: province.hpp:26
dcon::data_container world
simple_fs::file_system common_fs
province::global_provincial_state province_definitions