Project Alice
Loading...
Searching...
No Matches
map.cpp
Go to the documentation of this file.
1#include "map.hpp"
2#include "glm/fwd.hpp"
3#include "texture.hpp"
4#include "province.hpp"
5#include <cmath>
6#include <numbers>
7#include <glm/glm.hpp>
8#include <glm/mat3x3.hpp>
9#include <unordered_map>
10#include <glm/gtc/type_ptr.hpp>
11#include <glm/gtx/intersect.hpp>
12#include <glm/gtx/polar_coordinates.hpp>
13#include <glm/gtc/constants.hpp>
14#include <glm/gtx/transform.hpp>
15
16#include "stb_image.h"
17#include "system_state.hpp"
19#include "math_fns.hpp"
20#include "prng.hpp"
21#include "demographics.hpp"
22
23#include "xac.hpp"
24namespace duplicates {
25glm::vec2 get_port_location(sys::state& state, dcon::province_id p) {
26 auto pt = state.world.province_get_port_to(p);
27 if(!pt)
28 return glm::vec2{};
29
30 auto adj = state.world.get_province_adjacency_by_province_pair(p, pt);
31 assert(adj);
32 auto id = adj.index();
33 auto& map_data = state.map_state.map_data;
34 auto& border = map_data.borders[id];
35 auto& vertex = map_data.border_vertices[border.start_index + border.count / 2];
36 glm::vec2 map_size = glm::vec2(map_data.size_x, map_data.size_y);
37
38 return vertex.position * map_size;
39}
40
41bool is_sea_province(sys::state& state, dcon::province_id prov_id) {
42 return prov_id.index() >= state.province_definitions.first_sea_province.index();
43}
44
45glm::vec2 get_navy_location(sys::state& state, dcon::province_id prov_id) {
46 if(is_sea_province(state, prov_id))
47 return state.world.province_get_mid_point(prov_id);
48 else
49 return get_port_location(state, prov_id);
50}
51
52glm::vec2 get_army_location(sys::state& state, dcon::province_id prov_id) {
53 return state.world.province_get_mid_point(prov_id);
54}
55}
56
57namespace map {
58
60
61}
62
63void add_nation_visible_provinces(sys::state& state, std::vector<dcon::province_id>& list, dcon::nation_id n) {
64 for(auto pc : state.world.nation_get_province_control_as_nation(n))
65 list.push_back(pc.get_province());
66 for(auto ac : state.world.nation_get_army_control_as_controller(n))
67 list.push_back(ac.get_army().get_location_from_army_location());
68 for(auto nc : state.world.nation_get_navy_control_as_controller(n))
69 list.push_back(nc.get_navy().get_location_from_navy_location());
70}
71
73 std::vector<dcon::province_id> direct_provinces;
74 add_nation_visible_provinces(state, direct_provinces, state.local_player_nation);
75 for(auto urel : state.world.nation_get_overlord_as_ruler(state.local_player_nation))
76 add_nation_visible_provinces(state, direct_provinces, urel.get_subject());
77 for(auto rel : state.world.nation_get_diplomatic_relation(state.local_player_nation)) {
78 if(rel.get_are_allied()) {
79 auto n = rel.get_related_nations(0) == state.local_player_nation ? rel.get_related_nations(1) : rel.get_related_nations(0);
80 add_nation_visible_provinces(state, direct_provinces, n);
81 for(auto urel : state.world.nation_get_overlord_as_ruler(n))
82 add_nation_visible_provinces(state, direct_provinces, urel.get_subject());
83 }
84 }
85
86 // update fog of war too
87 std::vector<uint32_t> province_fows(state.world.province_size() + 1, 0xFFFFFFFF);
88 if(state.user_settings.fow_enabled || state.network_mode != sys::network_mode_type::single_player) {
89 state.map_state.visible_provinces.clear();
90 state.map_state.visible_provinces.resize(state.world.province_size() + 1, false);
91 for(auto p : direct_provinces) {
92 if(bool(p)) {
93 state.map_state.visible_provinces[province::to_map_id(p)] = true;
94 for(auto c : state.world.province_get_province_adjacency(p)) {
95 auto pc = c.get_connected_provinces(0) == p ? c.get_connected_provinces(1) : c.get_connected_provinces(0);
96 if(bool(pc)) {
97 state.map_state.visible_provinces[province::to_map_id(pc)] = true;
98 }
99 }
100 }
101 }
102 for(auto p : state.world.in_province)
103 province_fows[province::to_map_id(p)] = uint32_t(state.map_state.visible_provinces[province::to_map_id(p)] ? 0xFFFFFFFF : 0x7B7B7B7B);
105 } else {
106 state.map_state.visible_provinces.clear();
107 state.map_state.visible_provinces.resize(state.world.province_size() + 1, true);
109 }
110}
111
112void create_textured_line_vbo(GLuint vbo, std::vector<textured_line_vertex>& data) {
113 // Create and populate the border VBO
114 glBindBuffer(GL_ARRAY_BUFFER, vbo);
115 if(!data.empty())
116 glBufferData(GL_ARRAY_BUFFER, sizeof(textured_line_vertex) * data.size(), data.data(), GL_STATIC_DRAW);
117 // Bind the VBO to 0 of the VAO
118 glBindVertexBuffer(0, vbo, 0, sizeof(textured_line_vertex));
119 // Set up vertex attribute format for the position
120 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex, position_));
121 // Set up vertex attribute format for the normal direction
122 glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex, normal_direction_));
123 // Set up vertex attribute format for the direction
124 glVertexAttribFormat(2, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex, texture_coordinate_));
125 // Set up vertex attribute format for the texture coordinates
126 glVertexAttribFormat(3, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex, distance_));
127 glEnableVertexAttribArray(0);
128 glEnableVertexAttribArray(1);
129 glEnableVertexAttribArray(2);
130 glEnableVertexAttribArray(3);
131 glVertexAttribBinding(0, 0);
132 glVertexAttribBinding(1, 0);
133 glVertexAttribBinding(2, 0);
134 glVertexAttribBinding(3, 0);
135}
136
137void create_textured_line_vbo(GLuint vbo, std::vector<textured_line_with_width_vertex>& data) {
138 // Create and populate the border VBO
139 glBindBuffer(GL_ARRAY_BUFFER, vbo);
140 if(!data.empty())
141 glBufferData(GL_ARRAY_BUFFER, sizeof(textured_line_with_width_vertex) * data.size(), data.data(), GL_STATIC_DRAW);
142 // Bind the VBO to 0 of the VAO
143 glBindVertexBuffer(0, vbo, 0, sizeof(textured_line_with_width_vertex));
144 // Set up vertex attribute format for the position
145 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_with_width_vertex, position_));
146 // Set up vertex attribute format for the normal direction
147 glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_with_width_vertex, normal_direction_));
148 // Set up vertex attribute format for the direction
149 glVertexAttribFormat(2, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_with_width_vertex, texture_coordinate_));
150 // Set up vertex attribute format for the texture coordinates
151 glVertexAttribFormat(3, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_with_width_vertex, distance_));
152 // Set up vertex attribute format for the width
153 glVertexAttribFormat(4, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_with_width_vertex, width_));
154 glEnableVertexAttribArray(0);
155 glEnableVertexAttribArray(1);
156 glEnableVertexAttribArray(2);
157 glEnableVertexAttribArray(3);
158 glEnableVertexAttribArray(4);
159 glVertexAttribBinding(0, 0);
160 glVertexAttribBinding(1, 0);
161 glVertexAttribBinding(2, 0);
162 glVertexAttribBinding(3, 0);
163 glVertexAttribBinding(4, 0);
164}
165
166void create_textured_line_b_vbo(GLuint vbo, std::vector<textured_line_vertex_b>& data) {
167 // Create and populate the border VBO
168 glBindBuffer(GL_ARRAY_BUFFER, vbo);
169 if(!data.empty())
170 glBufferData(GL_ARRAY_BUFFER, sizeof(textured_line_vertex_b) * data.size(), data.data(), GL_STATIC_DRAW);
171 // Bind the VBO to 0 of the VAO
172 glBindVertexBuffer(0, vbo, 0, sizeof(textured_line_vertex_b));
173 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex_b, position));
174 glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex_b, previous_point));
175 glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex_b, next_point));
176 glVertexAttribFormat(3, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex_b, texture_coordinate));
177 glVertexAttribFormat(4, 1, GL_FLOAT, GL_FALSE, offsetof(textured_line_vertex_b, distance));
178 glEnableVertexAttribArray(0);
179 glEnableVertexAttribArray(1);
180 glEnableVertexAttribArray(2);
181 glEnableVertexAttribArray(3);
182 glEnableVertexAttribArray(4);
183 glVertexAttribBinding(0, 0);
184 glVertexAttribBinding(1, 0);
185 glVertexAttribBinding(2, 0);
186 glVertexAttribBinding(3, 0);
187 glVertexAttribBinding(4, 0);
188}
189
190void create_unit_arrow_vbo(GLuint vbo, std::vector<curved_line_vertex>& data) {
191 // Create and populate the border VBO
192 glBindBuffer(GL_ARRAY_BUFFER, vbo);
193 if(!data.empty())
194 glBufferData(GL_ARRAY_BUFFER, sizeof(curved_line_vertex) * data.size(), data.data(), GL_STATIC_DRAW);
195 // Bind the VBO to 0 of the VAO
196 glBindVertexBuffer(0, vbo, 0, sizeof(curved_line_vertex));
197 // Set up vertex attribute format for the position
198 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(curved_line_vertex, position_));
199 // Set up vertex attribute format for the normal direction
200 glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, offsetof(curved_line_vertex, normal_direction_));
201 // Set up vertex attribute format for the direction
202 glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, offsetof(curved_line_vertex, direction_));
203 // Set up vertex attribute format for the texture coordinates
204 glVertexAttribFormat(3, 2, GL_FLOAT, GL_FALSE, offsetof(curved_line_vertex, texture_coord_));
205 // Set up vertex attribute format for the type
206 glVertexAttribFormat(4, 1, GL_FLOAT, GL_FALSE, offsetof(curved_line_vertex, type_));
207 glEnableVertexAttribArray(0);
208 glEnableVertexAttribArray(1);
209 glEnableVertexAttribArray(2);
210 glEnableVertexAttribArray(3);
211 glEnableVertexAttribArray(4);
212 glVertexAttribBinding(0, 0);
213 glVertexAttribBinding(1, 0);
214 glVertexAttribBinding(2, 0);
215 glVertexAttribBinding(3, 0);
216 glVertexAttribBinding(4, 0);
217}
218
219void create_text_line_vbo(GLuint vbo) {
220 // Create and populate the border VBO
221 glBindBuffer(GL_ARRAY_BUFFER, vbo);
222 // Bind the VBO to 0 of the VAO
223 glBindVertexBuffer(0, vbo, 0, sizeof(text_line_vertex));
224 // Set up vertex attribute format for the position
225 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(text_line_vertex, position_));
226 // Set up vertex attribute format for the normal direction
227 glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, offsetof(text_line_vertex, normal_direction_));
228 // Set up vertex attribute format for the direction
229 glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, offsetof(text_line_vertex, direction_));
230 // Set up vertex attribute format for the texture coordinates
231 glVertexAttribFormat(3, 3, GL_FLOAT, GL_FALSE, offsetof(text_line_vertex, texture_coord_));
232 glVertexAttribFormat(4, 1, GL_FLOAT, GL_FALSE, offsetof(text_line_vertex, thickness_));
233 glEnableVertexAttribArray(0);
234 glEnableVertexAttribArray(1);
235 glEnableVertexAttribArray(2);
236 glEnableVertexAttribArray(3);
237 glEnableVertexAttribArray(4);
238 glEnableVertexAttribArray(5);
239 glVertexAttribBinding(0, 0);
240 glVertexAttribBinding(1, 0);
241 glVertexAttribBinding(2, 0);
242 glVertexAttribBinding(3, 0);
243 glVertexAttribBinding(4, 0);
244 glVertexAttribBinding(5, 0);
245}
246
247void create_drag_box_vbo(GLuint vbo) {
248 // Create and populate the border VBO
249 glBindBuffer(GL_ARRAY_BUFFER, vbo);
250 // Bind the VBO to 0 of the VAO
251 glBindVertexBuffer(0, vbo, 0, sizeof(screen_vertex));
252 // Set up vertex attribute format for the position
253 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(screen_vertex, position_));
254 glEnableVertexAttribArray(0);
255 glVertexAttribBinding(0, 0);
256}
257
259 // TODO: remove unused function
260}
261
263 std::vector<map_vertex> land_vertices;
264
265 auto add_vertex = [map_size = glm::vec2(float(size_x), float(size_y))](std::vector<map_vertex>& vertices, glm::vec2 pos0) {
266 vertices.emplace_back(pos0.x, pos0.y);
267 };
268
269 glm::vec2 last_pos(0, 0);
270 glm::vec2 pos(0, 0);
271 glm::vec2 map_size(size_x, size_y);
272 glm::ivec2 sections(200, 200);
273 for(int y = 0; y <= sections.y; y++) {
274 pos.y = float(y) / float(sections.y);
275 for(int x = 0; x <= sections.x; x++) {
276 pos.x = float(x) / float(sections.x);
277 add_vertex(land_vertices, pos);
278 }
279 }
280
281 map_indices.clear();
282 for(int y = 0; y < sections.y; y++) {
283 auto top_row_start = y * (sections.x + 1);
284 auto bottom_row_start = (y + 1) * (sections.x + 1);
285 map_indices.push_back(uint16_t(bottom_row_start + 0));
286 map_indices.push_back(uint16_t(top_row_start + 0));
287 for(int x = 0; x < sections.x; x++) {
288 map_indices.push_back(uint16_t(bottom_row_start + 1 + x));
289 map_indices.push_back(uint16_t(top_row_start + 1 + x));
290 }
291 map_indices.push_back(std::numeric_limits<uint16_t>::max());
292 }
293
294 land_vertex_count = ((uint32_t)land_vertices.size());
295
296 // Fill and bind the VAO
297 glBindVertexArray(vao_array[vo_land]);
298 // Create and populate the VBO
299 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_land]);
300 glBufferData(GL_ARRAY_BUFFER, sizeof(map_vertex) * land_vertices.size(), land_vertices.data(), GL_STATIC_DRAW);
301 // Bind the VBO to 0 of the VAO
302 glBindVertexBuffer(0, vbo_array[vo_land], 0, sizeof(map_vertex));
303 // Set up vertex attribute format for the position
304 glVertexAttribFormat(0, 2, GL_FLOAT, GL_FALSE, offsetof(map_vertex, position_));
305 glEnableVertexAttribArray(0);
306 glVertexAttribBinding(0, 0);
307
308 // Fill and bind the VAOs and VBOs
309 glBindVertexArray(vao_array[vo_border]);
311 glBindVertexArray(vao_array[vo_river]);
313 glBindVertexArray(vao_array[vo_railroad]);
315 glBindVertexArray(vao_array[vo_coastal]);
317 glBindVertexArray(vao_array[vo_unit_arrow]);
319 glBindVertexArray(vao_array[vo_attack_unit_arrow]);
321 glBindVertexArray(vao_array[vo_retreat_unit_arrow]);
323 glBindVertexArray(vao_array[vo_strategy_unit_arrow]);
325 glBindVertexArray(vao_array[vo_objective_unit_arrow]);
327 glBindVertexArray(vao_array[vo_other_objective_unit_arrow]);
329 glBindVertexArray(vao_array[vo_text_line]);
331 glBindVertexArray(vao_array[vo_province_text_line]);
333 glBindVertexArray(vao_array[vo_drag_box]);
335 glBindVertexArray(0);
336}
337
339 /* We don't need to check against 0, since the delete functions already do that for us */
340 if(textures[0])
341 glDeleteTextures(texture_count, textures);
342 if(texture_arrays[0])
343 glDeleteTextures(texture_count, texture_arrays);
344#if 0
346 glDeleteTextures(max_static_meshes, static_mesh_textures);
347#endif
348 if(vao_array[0])
349 glDeleteVertexArrays(vo_count, vao_array);
350 if(vbo_array[0])
351 glDeleteBuffers(vo_count, vbo_array);
352
353 /* Flags shader for deletion, but doesn't delete them until they're no longer in the rendering context */
354 for(const auto shader : shaders) {
355 if(shader)
356 glDeleteProgram(shader);
357 }
358}
359
360std::optional<simple_fs::file> try_load_shader(simple_fs::directory& root, native_string_view name) {
361 auto shader = simple_fs::open_file(root, name);
362 if(!bool(shader))
363 ogl::notify_user_of_fatal_opengl_error("Unable to open a necessary shader file");
364 return shader;
365}
366
367GLuint create_program(simple_fs::file& vshader_file, simple_fs::file& fshader_file) {
368 auto vshader_content = simple_fs::view_contents(vshader_file);
369 auto vshader_string = std::string_view(vshader_content.data, vshader_content.file_size);
370 auto fshader_content = simple_fs::view_contents(fshader_file);
371 auto fshader_string = std::string_view(fshader_content.data, fshader_content.file_size);
372 return ogl::create_program(vshader_string, fshader_string);
373}
374
376 // Map shaders
377 auto map_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/map_v.glsl"));
378 auto map_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/map_f.glsl"));
379 auto screen_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/screen_v.glsl"));
380 auto white_color_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/white_color_f.glsl"));
381
382 // Line shaders
383 auto line_unit_arrow_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/line_unit_arrow_v.glsl"));
384 auto line_unit_arrow_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/line_unit_arrow_f.glsl"));
385
386 auto text_line_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/text_line_v.glsl"));
387 auto text_line_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/text_line_f.glsl"));
388
389 auto tline_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/textured_line_v.glsl"));
390 auto tline_width_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/textured_line_variable_width_v.glsl"));
391 auto tline_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/textured_line_f.glsl"));
392 auto river_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/textured_line_river_f.glsl"));
393
394 auto tlineb_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/textured_line_b_v.glsl"));
395 auto tlineb_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/textured_line_b_f.glsl"));
396
397 auto model3d_vshader = try_load_shader(root, NATIVE("assets/shaders/glsl/model3d_v.glsl"));
398 auto model3d_fshader = try_load_shader(root, NATIVE("assets/shaders/glsl/model3d_f.glsl"));
399
400 shaders[shader_terrain] = create_program(*map_vshader, *map_fshader);
401 shaders[shader_textured_line] = create_program(*tline_vshader, *tline_fshader);
402 shaders[shader_textured_line_with_variable_width] = create_program(*tline_width_vshader, *river_fshader);
403 shaders[shader_railroad_line] = create_program(*tline_vshader, *tlineb_fshader);
404 shaders[shader_borders] = create_program(*tlineb_vshader, *tlineb_fshader);
405 shaders[shader_line_unit_arrow] = create_program(*line_unit_arrow_vshader, *line_unit_arrow_fshader);
406 shaders[shader_text_line] = create_program(*text_line_vshader, *text_line_fshader);
407 shaders[shader_drag_box] = create_program(*screen_vshader, *white_color_fshader);
408 shaders[shader_map_standing_object] = create_program(*model3d_vshader, *model3d_fshader);
409
410 for(uint32_t i = 0; i < shader_count; i++) {
411 if(shaders[i] == 0)
412 continue;
413 shader_uniforms[i][uniform_provinces_texture_sampler] = glGetUniformLocation(shaders[i], "provinces_texture_sampler");
414 shader_uniforms[i][uniform_provinces_sea_mask] = glGetUniformLocation(shaders[i], "provinces_sea_mask");
415 shader_uniforms[i][uniform_offset] = glGetUniformLocation(shaders[i], "offset");
416 shader_uniforms[i][uniform_aspect_ratio] = glGetUniformLocation(shaders[i], "aspect_ratio");
417 shader_uniforms[i][uniform_zoom] = glGetUniformLocation(shaders[i], "zoom");
418 shader_uniforms[i][uniform_map_size] = glGetUniformLocation(shaders[i], "map_size");
419 shader_uniforms[i][uniform_rotation] = glGetUniformLocation(shaders[i], "rotation");
420 shader_uniforms[i][uniform_gamma] = glGetUniformLocation(shaders[i], "gamma");
421 shader_uniforms[i][uniform_subroutines_index] = glGetUniformLocation(shaders[i], "subroutines_index");
422 shader_uniforms[i][uniform_time] = glGetUniformLocation(shaders[i], "time");
423 shader_uniforms[i][uniform_terrain_texture_sampler] = glGetUniformLocation(shaders[i], "terrain_texture_sampler");
424 shader_uniforms[i][uniform_terrainsheet_texture_sampler] = glGetUniformLocation(shaders[i], "terrainsheet_texture_sampler");
425 shader_uniforms[i][uniform_water_normal] = glGetUniformLocation(shaders[i], "water_normal");
426 shader_uniforms[i][uniform_colormap_water] = glGetUniformLocation(shaders[i], "colormap_water");
427 shader_uniforms[i][uniform_colormap_terrain] = glGetUniformLocation(shaders[i], "colormap_terrain");
428 shader_uniforms[i][uniform_overlay] = glGetUniformLocation(shaders[i], "overlay");
429 shader_uniforms[i][uniform_province_color] = glGetUniformLocation(shaders[i], "province_color");
430 shader_uniforms[i][uniform_colormap_political] = glGetUniformLocation(shaders[i], "colormap_political");
431 shader_uniforms[i][uniform_province_highlight] = glGetUniformLocation(shaders[i], "province_highlight");
432 shader_uniforms[i][uniform_stripes_texture] = glGetUniformLocation(shaders[i], "stripes_texture");
433 shader_uniforms[i][uniform_province_fow] = glGetUniformLocation(shaders[i], "province_fow");
434 shader_uniforms[i][uniform_diag_border_identifier] = glGetUniformLocation(shaders[i], "diag_border_identifier");
435 shader_uniforms[i][uniform_subroutines_index_2] = glGetUniformLocation(shaders[i], "subroutines_index_2");
436 shader_uniforms[i][uniform_line_texture] = glGetUniformLocation(shaders[i], "line_texture");
437 shader_uniforms[i][uniform_texture_sampler] = glGetUniformLocation(shaders[i], "texture_sampler");
438 shader_uniforms[i][uniform_opaque] = glGetUniformLocation(shaders[i], "opaque");
439 shader_uniforms[i][uniform_is_black] = glGetUniformLocation(shaders[i], "is_black");
440 shader_uniforms[i][uniform_border_width] = glGetUniformLocation(shaders[i], "border_width");
441 shader_uniforms[i][uniform_unit_arrow] = glGetUniformLocation(shaders[i], "unit_arrow");
442 shader_uniforms[i][uniform_model_offset] = glGetUniformLocation(shaders[i], "model_offset");
443 shader_uniforms[i][uniform_target_facing] = glGetUniformLocation(shaders[i], "target_facing");
444 shader_uniforms[i][uniform_target_topview_fixup] = glGetUniformLocation(shaders[i], "target_topview_fixup");
445 shader_uniforms[i][uniform_width] = glGetUniformLocation(shaders[i], "width");
446 }
447}
448
449void display_data::render(sys::state& state, glm::vec2 screen_size, glm::vec2 offset, float zoom, map_view map_view_mode, map_mode::mode active_map_mode, glm::mat3 globe_rotation, float time_counter) {
450 glEnable(GL_CULL_FACE);
451 glCullFace(GL_BACK);
452
453 if(ogl::msaa_enabled(state)) {
454 glBindFramebuffer(GL_FRAMEBUFFER, state.open_gl.msaa_framebuffer);
455 glClearColor(1.f, 1.f, 1.f, 0.f);
456 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
457 }
458
459 glActiveTexture(GL_TEXTURE0);
460 glBindTexture(GL_TEXTURE_2D, textures[texture_provinces]);
461 glActiveTexture(GL_TEXTURE1);
462 glBindTexture(GL_TEXTURE_2D, textures[texture_terrain]);
463 glActiveTexture(GL_TEXTURE3);
464 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays[texture_array_terrainsheet]);
465 glActiveTexture(GL_TEXTURE4);
466 glBindTexture(GL_TEXTURE_2D, textures[texture_water_normal]);
467 glActiveTexture(GL_TEXTURE5);
468 glBindTexture(GL_TEXTURE_2D, textures[texture_colormap_water]);
469 glActiveTexture(GL_TEXTURE6);
470 glBindTexture(GL_TEXTURE_2D, textures[texture_colormap_terrain]);
471 glActiveTexture(GL_TEXTURE7);
472 glBindTexture(GL_TEXTURE_2D, textures[texture_overlay]);
473 glActiveTexture(GL_TEXTURE8);
474 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays[texture_array_province_color]);
475 glActiveTexture(GL_TEXTURE9);
476 glBindTexture(GL_TEXTURE_2D, textures[texture_colormap_political]);
477 glActiveTexture(GL_TEXTURE10);
478 glBindTexture(GL_TEXTURE_2D, textures[texture_province_highlight]);
479 glActiveTexture(GL_TEXTURE11);
480 glBindTexture(GL_TEXTURE_2D, textures[texture_stripes]);
481 glActiveTexture(GL_TEXTURE13);
482 glBindTexture(GL_TEXTURE_2D, textures[texture_province_fow]);
483 glActiveTexture(GL_TEXTURE14);
484 glBindTexture(GL_TEXTURE_2D, textures[texture_river_body]);
485 glActiveTexture(GL_TEXTURE15);
486 glBindTexture(GL_TEXTURE_2D, textures[texture_diag_border_identifier]);
487
488 // Load general shader stuff, used by both land and borders
489 auto load_shader = [&](GLuint program) {
490 glUseProgram(shaders[program]);
491 glUniform2f(shader_uniforms[program][uniform_offset], offset.x + 0.f, offset.y);
492 glUniform1f(shader_uniforms[program][uniform_aspect_ratio], screen_size.x / screen_size.y);
493 glUniform1f(shader_uniforms[program][uniform_zoom], zoom);
494 glUniform2f(shader_uniforms[program][uniform_map_size], GLfloat(size_x), GLfloat(size_y));
495 glUniformMatrix3fv(shader_uniforms[program][uniform_rotation], 1, GL_FALSE, glm::value_ptr(glm::mat3(globe_rotation)));
496 glUniform1f(shader_uniforms[program][uniform_gamma], state.user_settings.gamma);
497 glUniform1ui(shader_uniforms[program][uniform_subroutines_index], GLuint(map_view_mode));
498 glUniform1f(shader_uniforms[program][uniform_time], time_counter);
499 };
500
501 glEnable(GL_PRIMITIVE_RESTART);
502 //glDisable(GL_CULL_FACE);
503 glPrimitiveRestartIndex(std::numeric_limits<uint16_t>::max());
504
505 load_shader(shader_terrain);
508 //glUniform1i(shader_uniforms[shader_terrain][uniform_unused_texture_2], 2);
518 //glUniform1i(shader_uniforms[shader_terrain][uniform_unused_texture_12], 12);
520 //glUniform1i(shader_uniforms[shader_terrain][uniform_unused_texture_14], 14);
522 { // Land specific shader uniform
523 // get_land()
524 GLuint fragment_subroutines = 0;
525 if(active_map_mode == map_mode::mode::terrain)
526 fragment_subroutines = 0; // get_land_terrain/get_water_terrain()
527 else if(zoom > map::zoom_close)
528 fragment_subroutines = 1; // get_land_political_close/get_water_terrain()
529 else
530 fragment_subroutines = 2; // get_land_political_far/get_water_political()
531 glUniform1ui(shader_uniforms[shader_terrain][uniform_subroutines_index_2], fragment_subroutines);
532 }
533 glBindVertexArray(vao_array[vo_land]);
534 glDrawElements(GL_TRIANGLE_STRIP, GLsizei(map_indices.size() - 1), GL_UNSIGNED_SHORT, map_indices.data());
535
536 //glDrawArrays(GL_TRIANGLES, 0, land_vertex_count);
537 glDisable(GL_PRIMITIVE_RESTART);
538 //glEnable(GL_CULL_FACE);
539 // Draw the rivers
540 if(state.user_settings.rivers_enabled) {
541 glActiveTexture(GL_TEXTURE0);
542 glBindTexture(GL_TEXTURE_2D, textures[texture_river_body]);
543 glActiveTexture(GL_TEXTURE1);
544 glBindTexture(GL_TEXTURE_2D, textures[texture_colormap_water]);
545 glActiveTexture(GL_TEXTURE2);
546 glBindTexture(GL_TEXTURE_2D, textures[texture_sea_mask]);
547 glActiveTexture(GL_TEXTURE3);
548 glBindTexture(GL_TEXTURE_2D, textures[texture_provinces]);
549
550
556
557 glBindVertexArray(vao_array[vo_river]);
558 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_river]);
559 glMultiDrawArrays(GL_TRIANGLE_STRIP, river_starts.data(), river_counts.data(), GLsizei(river_starts.size()));
560 }
561
562 // Draw the railroads
563 if(zoom > map::zoom_close && !railroad_vertices.empty()) {
564 glActiveTexture(GL_TEXTURE0);
565 glBindTexture(GL_TEXTURE_2D, textures[texture_railroad]);
566 glActiveTexture(GL_TEXTURE1);
567 glBindTexture(GL_TEXTURE_2D, textures[texture_colormap_water]);
568
569 load_shader(shader_railroad_line);
572 glUniform1f(shader_uniforms[shader_railroad_line][uniform_width], 0.0001f);
574
575 glBindVertexArray(vao_array[vo_railroad]);
576 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_railroad]);
577 glMultiDrawArrays(GL_TRIANGLE_STRIP, railroad_starts.data(), railroad_counts.data(), GLsizei(railroad_starts.size()));
578 }
579
580 // Default border parameters
581 constexpr float border_type_national = 0.f;
582 constexpr float border_type_provincial = 1.f;
583 constexpr float border_type_regional = 2.f;
584 constexpr float border_type_coastal = 3.f;
585
586 // NORMAL BORDERS
587 load_shader(shader_borders);
591
592 glBindVertexArray(vao_array[vo_border]);
593 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_border]);
594
595 //glMultiDrawArrays(GL_TRIANGLE_STRIP, coastal_starts.data(), coastal_counts.data(), GLsizei(coastal_starts.size()));
596
597 // impassible borders
598 glActiveTexture(GL_TEXTURE0);
599 glBindTexture(GL_TEXTURE_2D, textures[texture_provinces]);
600 glActiveTexture(GL_TEXTURE1);
601 glBindTexture(GL_TEXTURE_2D, textures[texture_province_fow]);
602 if(zoom > map::zoom_close) {
603 if(zoom > map::zoom_very_close) { // Render province borders
604 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0001f); // width
605 glActiveTexture(GL_TEXTURE2);
606 glBindTexture(GL_TEXTURE_2D, textures[texture_prov_border]);
607
608 for(auto b : borders) {
610 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
611 }
612 }
613 }
614 { // Render state borders
615 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0002f); // width
616 glActiveTexture(GL_TEXTURE2);
617 glBindTexture(GL_TEXTURE_2D, textures[texture_state_border]);
618 for(auto b : borders) {
620 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
621 }
622 }
623 }
624 {
625 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.00085f); // width
626 glActiveTexture(GL_TEXTURE2);
627 glBindTexture(GL_TEXTURE_2D, textures[texture_imp_border]);
628 for(auto b : borders) {
630 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
631 }
632 }
633 }
634 // national borders
635 {
636 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0003f); // width
637 glActiveTexture(GL_TEXTURE2);
638 glBindTexture(GL_TEXTURE_2D, textures[texture_national_border]);
639 for(auto b : borders) {
641 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
642 }
643 }
644 }
645 } else {
646 if(zoom > map::zoom_very_close) { // Render province borders
647 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0001f); // width
648 glActiveTexture(GL_TEXTURE2);
649 glBindTexture(GL_TEXTURE_2D, textures[texture_prov_border]);
650 for(auto b : borders) {
652 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
653 }
654 }
655 }
656 if(zoom > map::zoom_close) { // Render state borders
657 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0002f); // width
658 glActiveTexture(GL_TEXTURE2);
659 glBindTexture(GL_TEXTURE_2D, textures[texture_state_border]);
660 for(auto b : borders) {
662 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
663 }
664 }
665 }
666 // national borders
667 {
668 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0003f); // width
669 glActiveTexture(GL_TEXTURE2);
670 glBindTexture(GL_TEXTURE_2D, textures[texture_state_border]);
671 for(auto b : borders) {
673 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
674 }
675 }
676 }
677 }
678 if(state.map_state.selected_province || (state.local_player_nation && state.current_scene.borders == game_scene::borders_granularity::nation)) {
679 glUniform1f(shader_uniforms[shader_borders][uniform_width], zoom > map::zoom_close ? 0.0004f : 0.00085f); // width
680 glActiveTexture(GL_TEXTURE2);
681 glBindTexture(GL_TEXTURE_2D, textures[texture_state_border]);
682 if(state.local_player_nation && state.current_scene.borders == game_scene::borders_granularity::nation) {
683 for(auto b : borders) {
684 auto p0 = state.world.province_adjacency_get_connected_provinces(b.adj, 0);
685 auto p1 = state.world.province_adjacency_get_connected_provinces(b.adj, 1);
686 if((state.world.province_get_nation_from_province_ownership(p0) == state.local_player_nation
687 || state.world.province_get_nation_from_province_ownership(p1) == state.local_player_nation)
688 && (state.world.province_adjacency_get_type(b.adj) & (province::border::non_adjacent_bit | province::border::coastal_bit | province::border::national_bit)) != 0) {
689 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
690 }
691 }
692 } else if(state.current_scene.borders == game_scene::borders_granularity::state) {
693 auto owner = state.world.province_get_nation_from_province_ownership(state.map_state.selected_province);
694 if(owner) {
695 auto siid = state.world.province_get_state_membership(state.map_state.selected_province);
696 //per state
697 for(auto b : borders) {
698 auto p0 = state.world.province_adjacency_get_connected_provinces(b.adj, 0);
699 auto p1 = state.world.province_adjacency_get_connected_provinces(b.adj, 1);
700 if((state.world.province_get_state_membership(p0) == siid
701 || state.world.province_get_state_membership(p1) == siid)
703 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
704 }
705 }
706 }
707 } else if(state.current_scene.borders == game_scene::borders_granularity::province) {
708 for(auto b : borders) {
709 auto p0 = state.world.province_adjacency_get_connected_provinces(b.adj, 0);
710 auto p1 = state.world.province_adjacency_get_connected_provinces(b.adj, 1);
711 if(p0 == state.map_state.selected_province || p1 == state.map_state.selected_province) {
712 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
713 }
714 }
715 }
716 }
717 dcon::province_id prov{};
718 glm::vec2 map_pos;
719 if(!state.ui_state.under_mouse && state.map_state.screen_to_map(glm::vec2(state.mouse_x_position, state.mouse_y_position), screen_size, state.map_state.current_view(state), map_pos)) {
720 map_pos *= glm::vec2(float(state.map_state.map_data.size_x), float(state.map_state.map_data.size_y));
721 auto idx = int32_t(state.map_state.map_data.size_y - map_pos.y) * int32_t(state.map_state.map_data.size_x) + int32_t(map_pos.x);
722 if(0 <= idx && size_t(idx) < state.map_state.map_data.province_id_map.size() && state.map_state.map_data.province_id_map[idx] < province::to_map_id(state.province_definitions.first_sea_province)) {
723 auto fat_id = dcon::fatten(state.world, province::from_map_id(state.map_state.map_data.province_id_map[idx]));
724 prov = province::from_map_id(state.map_state.map_data.province_id_map[idx]);
725 glUniform1f(shader_uniforms[shader_borders][uniform_width], zoom > map::zoom_close ? 0.0004f : 0.00085f); // width
726 glActiveTexture(GL_TEXTURE2);
727 glBindTexture(GL_TEXTURE_2D, textures[texture_hover_border]);
728 auto owner = state.world.province_get_nation_from_province_ownership(prov);
729 if(owner && state.current_scene.borders == game_scene::borders_granularity::nation) {
730 //per nation
731 for(auto b : borders) {
732 auto p0 = state.world.province_adjacency_get_connected_provinces(b.adj, 0);
733 auto p1 = state.world.province_adjacency_get_connected_provinces(b.adj, 1);
734 if((state.world.province_get_nation_from_province_ownership(p0) == owner
735 || state.world.province_get_nation_from_province_ownership(p1) == owner)
736 && (state.world.province_adjacency_get_type(b.adj) & (province::border::non_adjacent_bit | province::border::coastal_bit | province::border::national_bit)) != 0) {
737 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
738 }
739 }
740 } else if(owner && state.current_scene.borders == game_scene::borders_granularity::state) {
741 auto siid = state.world.province_get_state_membership(prov);
742 //per state
743 for(auto b : borders) {
744 auto p0 = state.world.province_adjacency_get_connected_provinces(b.adj, 0);
745 auto p1 = state.world.province_adjacency_get_connected_provinces(b.adj, 1);
746 if((state.world.province_get_state_membership(p0) == siid
747 || state.world.province_get_state_membership(p1) == siid)
749 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
750 }
751 }
752 } else if(owner && state.current_scene.borders == game_scene::borders_granularity::province) {
753 //per province
754 for(auto b : borders) {
755 auto p0 = state.world.province_adjacency_get_connected_provinces(b.adj, 0);
756 auto p1 = state.world.province_adjacency_get_connected_provinces(b.adj, 1);
757 if(p0 == prov || p1 == prov) {
758 glDrawArrays(GL_TRIANGLE_STRIP, b.start_index, b.count);
759 }
760 }
761 }
762 }
763 }
764 // coasts
765 {
766 glUniform1f(shader_uniforms[shader_borders][uniform_width], 0.0004f); // width
767 glActiveTexture(GL_TEXTURE2);
768 glBindTexture(GL_TEXTURE_2D, textures[texture_coastal_border]);
769 glBindVertexArray(vao_array[vo_coastal]);
770 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_coastal]);
771 glMultiDrawArrays(GL_TRIANGLE_STRIP, coastal_starts.data(), coastal_counts.data(), GLsizei(coastal_starts.size()));
772 }
773
774 if(zoom > map::zoom_close) { //only render if close enough
777 load_shader(shader_line_unit_arrow);
778 glUniform1f(shader_uniforms[shader_line_unit_arrow][uniform_border_width], 0.005f); //width
780 }
781 if(!unit_arrow_vertices.empty()) {
782 glActiveTexture(GL_TEXTURE0);
783 glBindTexture(GL_TEXTURE_2D, textures[texture_unit_arrow]);
784 glBindVertexArray(vao_array[vo_unit_arrow]);
785 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_unit_arrow]);
786 glMultiDrawArrays(GL_TRIANGLE_STRIP, unit_arrow_starts.data(), unit_arrow_counts.data(), (GLsizei)unit_arrow_counts.size());
787 }
788 if(!attack_unit_arrow_vertices.empty()) {
789 glActiveTexture(GL_TEXTURE0);
790 glBindTexture(GL_TEXTURE_2D, textures[texture_attack_unit_arrow]);
791 glBindVertexArray(vao_array[vo_attack_unit_arrow]);
792 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_attack_unit_arrow]);
793 glMultiDrawArrays(GL_TRIANGLE_STRIP, attack_unit_arrow_starts.data(), attack_unit_arrow_counts.data(), (GLsizei)attack_unit_arrow_counts.size());
794 }
795 if(!retreat_unit_arrow_vertices.empty()) {
796 glActiveTexture(GL_TEXTURE0);
797 glBindTexture(GL_TEXTURE_2D, textures[texture_retreat_unit_arrow]);
798 glBindVertexArray(vao_array[vo_retreat_unit_arrow]);
799 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_retreat_unit_arrow]);
800 glMultiDrawArrays(GL_TRIANGLE_STRIP, retreat_unit_arrow_starts.data(), retreat_unit_arrow_counts.data(), (GLsizei)retreat_unit_arrow_counts.size());
801 }
802 if(!strategy_unit_arrow_vertices.empty()) {
803 glActiveTexture(GL_TEXTURE0);
804 glBindTexture(GL_TEXTURE_2D, textures[texture_strategy_unit_arrow]);
805 glBindVertexArray(vao_array[vo_strategy_unit_arrow]);
806 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_strategy_unit_arrow]);
807 glMultiDrawArrays(GL_TRIANGLE_STRIP, strategy_unit_arrow_starts.data(), strategy_unit_arrow_counts.data(), (GLsizei)strategy_unit_arrow_counts.size());
808 }
809 if(!objective_unit_arrow_vertices.empty()) {
810 glActiveTexture(GL_TEXTURE0);
811 glBindTexture(GL_TEXTURE_2D, textures[texture_objective_unit_arrow]);
812 glBindVertexArray(vao_array[vo_objective_unit_arrow]);
813 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_objective_unit_arrow]);
814 glMultiDrawArrays(GL_TRIANGLE_STRIP, objective_unit_arrow_starts.data(), objective_unit_arrow_counts.data(), (GLsizei)objective_unit_arrow_counts.size());
815 }
817 glActiveTexture(GL_TEXTURE0);
818 glBindTexture(GL_TEXTURE_2D, textures[texture_other_objective_unit_arrow]);
819 glBindVertexArray(vao_array[vo_other_objective_unit_arrow]);
820 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_other_objective_unit_arrow]);
821 glMultiDrawArrays(GL_TRIANGLE_STRIP, other_objective_unit_arrow_starts.data(), other_objective_unit_arrow_counts.data(), (GLsizei)retreat_unit_arrow_counts.size());
822 }
823 }
824
825 if(!drag_box_vertices.empty()) {
826 glUseProgram(shaders[shader_drag_box]);
827 glUniform1f(shader_uniforms[shader_drag_box][uniform_gamma], state.user_settings.gamma);
828 glBindVertexArray(vao_array[vo_drag_box]);
829 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_drag_box]);
830 glDrawArrays(GL_TRIANGLES, 0, (GLsizei)drag_box_vertices.size());
831 }
832
833 if(state.user_settings.map_label != sys::map_label_mode::none) {
834 auto const& f = state.font_collection.get_font(state, text::font_selection::map_font);
835 load_shader(shader_text_line);
837 glUniform1f(shader_uniforms[shader_text_line][uniform_is_black], state.user_settings.black_map_font ? 1.f : 0.f);
838 if((!state.cheat_data.province_names || zoom < map::zoom_very_close) && !text_line_vertices.empty()) {
840 glBindVertexArray(vao_array[vo_text_line]);
841 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_text_line]);
842 for(uint32_t i = 0; i < uint32_t(text_line_texture_per_quad.size()); i++) {
843 glActiveTexture(GL_TEXTURE0);
844 glBindTexture(GL_TEXTURE_2D, text_line_texture_per_quad[i]);
845 glDrawArrays(GL_TRIANGLES, i * 6, 6);
846 }
847 }
848 }
849
850 /*
851 else if(state.cheat_data.province_names) {
852 glUniform1f(15, 1.f);
853 glBindVertexArray(vao_array[vo_province_text_line]);
854 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_province_text_line]);
855 glDrawArrays(GL_TRIANGLES, 0, (GLsizei)province_text_line_vertices.size());
856 }
857 }*/
858
859#if 0
860 if(zoom > map::zoom_very_close && state.user_settings.render_models) {
861 constexpr float dist_step = 1.77777f;
862 // Render standing objects
863 glEnable(GL_DEPTH_TEST);
864 glClear(GL_DEPTH_BUFFER_BIT);
865 glClearDepth(-1.f);
866 glDepthFunc(GL_GREATER);
867 load_shader(shader_map_standing_object);
868 glBindVertexArray(vao_array[vo_static_mesh]);
869 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_static_mesh]);
870
871 //for(uint32_t i = 0; i < uint32_t(static_mesh_starts.size()); i++) {
872 // glActiveTexture(GL_TEXTURE0);
873 // glBindTexture(GL_TEXTURE_2D, static_mesh_textures[i]);
874 // glUniform2f(12, 0.f, float(i * 8));
875 // glUniform1f(13, 0.f);
876 // glUniform1f(14, -0.75f);
877 // glDrawArrays(GL_TRIANGLES, static_mesh_starts[i], static_mesh_counts[i]);
878 //}
879
880 // Train stations
881 glActiveTexture(GL_TEXTURE0);
882 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[5]);
883 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
884 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
885 auto const level = state.world.province_get_building_level(p, economy::province_building_type::railroad);
886 if(level > 0) {
887 auto center = state.world.province_get_mid_point(p);
888 auto pos = center + glm::vec2(-dist_step, dist_step); //top right (from center)
890 glUniform1f(shader_uniforms[shader_map_standing_object][uniform_target_facing], 2.f * glm::pi<float>() * (float(rng::reduce(p.index() * level, 1000)) / 1000.f));
892 glDrawArrays(GL_TRIANGLES, static_mesh_starts[5], static_mesh_counts[5]);
893 }
894 }
895 struct model_tier {
896 uint32_t index;
897 uint8_t min;
898 uint8_t max;
899 };
900 // Naval base (empty)
901 static const model_tier nbe_tiers[] = {
902 { 30, 1, 2 }, //early
903 { 32, 3, 4 }, //mid
904 { 6, 5, 6 } //late
905 };
906 for(const auto& tier : nbe_tiers) {
907 glActiveTexture(GL_TEXTURE0);
908 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[tier.index]);
909 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
910 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
911 auto units = state.world.province_get_navy_location_as_location(p);
912 auto const level = state.world.province_get_building_level(p, economy::province_building_type::naval_base);
913 if(level >= tier.min && level <= tier.max && units.begin() == units.end()) {
914 auto p1 = duplicates::get_navy_location(state, p);
915 auto p2 = state.world.province_get_mid_point(p);
917 auto theta = glm::atan(p2.y - p1.y, p2.x - p1.x);
920 glDrawArrays(GL_TRIANGLES, static_mesh_starts[tier.index], static_mesh_counts[tier.index]);
921 }
922 }
923 }
924 // Naval base (full)
925 static const model_tier nbf_tiers[] = {
926 { 31, 1, 2 }, //early
927 { 33, 3, 4 }, //mid
928 { 7, 5, 6 } //late
929 };
930 for(const auto& tier : nbf_tiers) {
931 glActiveTexture(GL_TEXTURE0);
932 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[tier.index]);
933 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
934 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
935 auto units = state.world.province_get_navy_location_as_location(p);
936 auto const level = state.world.province_get_building_level(p, economy::province_building_type::naval_base);
937 if(level >= tier.min && level <= tier.max && units.begin() != units.end()) {
938 auto p1 = duplicates::get_navy_location(state, p);
939 auto p2 = state.world.province_get_mid_point(p);
941 auto theta = glm::atan(p2.y - p1.y, p2.x - p1.x);
944 glDrawArrays(GL_TRIANGLES, static_mesh_starts[tier.index], static_mesh_counts[tier.index]);
945 }
946 }
947 }
948 // Fort
949 static const model_tier fort_tiers[] = {
950 { 8, 1, 2 }, //early
951 { 28, 3, 4 }, //mid
952 { 29, 5, 6 } //late
953 };
954 for(const auto& tier : fort_tiers) {
955 glActiveTexture(GL_TEXTURE0);
956 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[tier.index]);
957 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
958 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
959 auto const level = state.world.province_get_building_level(p, economy::province_building_type::fort);
960 if(level >= tier.min && level <= tier.max) {
961 auto center = state.world.province_get_mid_point(p);
962 auto pos = center + glm::vec2(dist_step, -dist_step); //bottom left (from center)
964 glUniform1f(shader_uniforms[shader_map_standing_object][uniform_target_facing], 2.f * glm::pi<float>() * (float(rng::reduce(p.index(), 1000)) / 1000.f));
966 glDrawArrays(GL_TRIANGLES, static_mesh_starts[tier.index], static_mesh_counts[tier.index]);
967 }
968 }
969 }
970 auto render_canal = [&](uint32_t index, uint32_t canal_id, float theta) {
971 if(canal_id >= uint32_t(state.province_definitions.canals.size())
972 && canal_id >= uint32_t(state.province_definitions.canal_provinces.size()))
973 return;
974 auto const adj = state.province_definitions.canals[canal_id];
975 if((state.world.province_adjacency_get_type(adj) & province::border::impassible_bit) != 0)
976 return;
977 glActiveTexture(GL_TEXTURE0);
978 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[index]);
979 glm::vec2 pos = state.world.province_get_mid_point(state.province_definitions.canal_provinces[canal_id]);
983 glDrawArrays(GL_TRIANGLES, static_mesh_starts[index], static_mesh_counts[index]);
984 };
985 render_canal(3, 0, 0.f); //Kiel
986 render_canal(4, 1, glm::pi<float>() / 2.f), //Suez
987 render_canal(2, 2, 0.f); //Panama
988 // Factory
989 glActiveTexture(GL_TEXTURE0);
990 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[9]);
991 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
992 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
993 auto factories = state.world.province_get_factory_location_as_province(p);
994 if(factories.begin() != factories.end()) {
995 auto center = state.world.province_get_mid_point(p);
996 auto pos = center + glm::vec2(-dist_step, -dist_step); //top left (from center)
998 glUniform1f(shader_uniforms[shader_map_standing_object][uniform_target_facing], 2.f * glm::pi<float>() * (float(rng::reduce(p.index(), 1000)) / 1000.f));
1000 glDrawArrays(GL_TRIANGLES, static_mesh_starts[9], static_mesh_counts[9]);
1001 }
1002 }
1003 // Blockaded
1004 glActiveTexture(GL_TEXTURE0);
1005 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[10]);
1006 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
1007 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
1008 if(military::province_is_blockaded(state, p)) {
1009 auto p1 = duplicates::get_navy_location(state, p);
1010 auto p2 = state.world.province_get_mid_point(p);
1012 auto theta = glm::atan(p2.y - p1.y, p2.x - p1.x);
1015 glDrawArrays(GL_TRIANGLES, static_mesh_starts[10], static_mesh_counts[10]);
1016 }
1017 }
1018 // Render armies
1019 auto render_regiment = [&](uint32_t index, military::unit_type type, float space) {
1020 glActiveTexture(GL_TEXTURE0);
1021 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[index]);
1022 for(uint32_t i = 0; i < uint32_t(state.province_definitions.first_sea_province.index()); i++) {
1023 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
1024 auto units = state.world.province_get_army_location_as_location(p);
1025 if(state.map_state.visible_provinces[province::to_map_id(p)]
1026 && units.begin() != units.end()) {
1027 auto p1 = state.world.province_get_mid_point(p);
1028 auto p2 = p1;
1029 bool has_unit = false;
1030 for(const auto unit : units) {
1031 for(const auto sm : unit.get_army().get_army_membership()) {
1032 auto& t = state.military_definitions.unit_base_definitions[sm.get_regiment().get_type()];
1033 if(t.type == type) {
1034 has_unit = true;
1035 break;
1036 }
1037 }
1038 if(has_unit) {
1039 if(auto path = unit.get_army().get_path(); path.size() > 0) {
1040 p2 = state.world.province_get_mid_point(path[path.size() - 1]);
1041 break;
1042 }
1043 }
1044 }
1045 if(has_unit) {
1046 glUniform2f(shader_uniforms[shader_map_standing_object][uniform_model_offset], p1.x, p1.y + space + dist_step);
1047 auto theta = glm::atan(p2.y - p1.y, p2.x - p1.x);
1050 glDrawArrays(GL_TRIANGLES, static_mesh_starts[index], static_mesh_counts[index]);
1051 }
1052 }
1053 }
1054 };
1055 render_regiment(17, military::unit_type::infantry, dist_step); //shadow
1056 render_regiment(17, military::unit_type::cavalry, 0.f); //shadow
1057 render_regiment(17, military::unit_type::support, -dist_step); //shadow
1058 render_regiment(11, military::unit_type::infantry, dist_step); //infantry
1059 render_regiment(15, military::unit_type::cavalry, 0.f); //horse
1060 render_regiment(18, military::unit_type::support, -dist_step); //artillery
1061 // Render navies
1062 auto render_ship = [&](uint32_t index, military::unit_type type, int32_t min_port, float space) {
1063 glActiveTexture(GL_TEXTURE0);
1064 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[index]);
1065 for(uint32_t i = uint32_t(state.province_definitions.first_sea_province.index()); i < state.world.province_size(); i++) {
1066 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
1067 auto units = state.world.province_get_navy_location_as_location(p);
1068 if(state.map_state.visible_provinces[province::to_map_id(p)]
1069 && units.begin() != units.end()) {
1070 auto p1 = duplicates::get_navy_location(state, p);
1071 auto p2 = p1;
1072 bool has_unit = false;
1073 for(const auto unit : units) {
1074 for(const auto sm : unit.get_navy().get_navy_membership()) {
1075 auto& t = state.military_definitions.unit_base_definitions[sm.get_ship().get_type()];
1076 if(t.type == type && t.min_port_level <= min_port) {
1077 has_unit = true;
1078 break;
1079 }
1080 }
1081 if(has_unit) {
1082 if(auto path = unit.get_navy().get_path(); path.size() > 0) {
1083 p2 = duplicates::get_navy_location(state, path[path.size() - 1]);
1084 break;
1085 }
1086 }
1087 }
1088 if(has_unit) {
1089 glUniform2f(shader_uniforms[shader_map_standing_object][uniform_model_offset], p1.x, p1.y + space + dist_step);
1090 auto theta = glm::atan(p2.y - p1.y, p2.x - p1.x);
1093 glDrawArrays(GL_TRIANGLES, static_mesh_starts[index], static_mesh_counts[index]);
1094 }
1095 }
1096 }
1097 };
1098
1099 //ship wakes
1100 render_ship(16, military::unit_type::big_ship, 2, 3.f * dist_step); //raider
1101 render_ship(16, military::unit_type::transport, -1, 2.f * dist_step); //transport
1102 render_ship(16, military::unit_type::big_ship, -1, dist_step); //manowar
1103 render_ship(16, military::unit_type::light_ship, -1, 0.f); //frigate
1104 render_ship(16, military::unit_type::big_ship, 4, -dist_step); //battleship
1105 render_ship(16, military::unit_type::light_ship, 3, -2.f * dist_step); //cruiser
1106 render_ship(16, military::unit_type::big_ship, 3, -3.f * dist_step); //ironclad
1107 //ship themselves
1108 render_ship(37, military::unit_type::big_ship, 2, 3.f * dist_step); //raider
1109 render_ship(14, military::unit_type::transport, -1, 2.f * dist_step); //transport
1110 render_ship(13, military::unit_type::big_ship, -1, dist_step); //manowar
1111 render_ship(12, military::unit_type::light_ship, -1, 0.f); //frigate
1112 render_ship(34, military::unit_type::big_ship, 4, -dist_step); //battleship
1113 render_ship(35, military::unit_type::light_ship, 3, -2.f * dist_step); //cruiser
1114 render_ship(36, military::unit_type::big_ship, 3, -3.f * dist_step); //ironclad
1115
1116 // Floating flags
1117 glActiveTexture(GL_TEXTURE0);
1118 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[38]);
1119 for(uint32_t i = 0; i < state.world.province_size(); i++) {
1120 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
1121 auto units = state.world.province_get_navy_location_as_location(p);
1122 if(state.map_state.visible_provinces[province::to_map_id(p)]
1123 && units.begin() != units.end()) {
1124 auto p1 = state.world.province_get_mid_point(p);
1126 auto theta = glm::atan(0.f, 0.f);
1129 glDrawArrays(GL_TRIANGLES, static_mesh_starts[38], static_mesh_counts[38]);
1130 }
1131 }
1132 glActiveTexture(GL_TEXTURE0);
1133 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[39]);
1134 for(uint32_t i = 0; i < state.world.province_size(); i++) {
1135 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(i));
1136 auto units = state.world.province_get_navy_location_as_location(p);
1137 if(state.map_state.visible_provinces[province::to_map_id(p)]
1138 && units.begin() != units.end()) {
1139 auto p1 = state.world.province_get_mid_point(p);
1141 auto theta = glm::atan(0.f, 0.f);
1144 glDrawArrays(GL_TRIANGLES, static_mesh_starts[39], static_mesh_counts[39]);
1145 }
1146 }
1147
1148 for(uint32_t i = 0; i < 3 * 3; i++) {
1149 auto index = 19 + i;
1150 glActiveTexture(GL_TEXTURE0);
1151 glBindTexture(GL_TEXTURE_2D, static_mesh_textures[index]);
1152 for(uint32_t j = 0; j < uint32_t(state.province_definitions.first_sea_province.index()); j++) {
1153 dcon::province_id p = dcon::province_id(dcon::province_id::value_base_t(j));
1154 if(state.world.province_get_demographics(p, demographics::total) >= float(i * 100000.f)) {
1155 // 1 2 3 -- 1
1156 // 1 2 3 -- 2
1157 // 1 2 3 -- 3
1158 auto center = state.world.province_get_mid_point(p);
1159 auto pos = center;
1160 pos.x += i == 0 ? 0.f : float(i % 3) * 2.5f;
1161 pos.y += i == 0 ? 0.f : float(i / 3) * 2.5f;
1162 pos.x -= 2.5f;
1163 pos.y -= 2.5f;
1165 glUniform1f(shader_uniforms[shader_map_standing_object][uniform_target_facing], 2.f * glm::pi<float>() * (float(rng::reduce(p.index() + j + i, 1000)) / 1000.f));
1167 glDrawArrays(GL_TRIANGLES, static_mesh_starts[index], static_mesh_counts[index]);
1169 glUniform1f(shader_uniforms[shader_map_standing_object][uniform_target_facing], 2.f * glm::pi<float>() * (float(rng::reduce(p.index() + j * i, 1000)) / 1000.f));
1171 glDrawArrays(GL_TRIANGLES, static_mesh_starts[index], static_mesh_counts[index]);
1172 }
1173 }
1174 }
1175 glDisable(GL_DEPTH_TEST);
1176 }
1177#endif
1178
1179 glBindVertexArray(0);
1180 glDisable(GL_CULL_FACE);
1181
1182 if(ogl::msaa_enabled(state)) {
1183 glBindFramebuffer(GL_READ_FRAMEBUFFER, state.open_gl.msaa_framebuffer);
1184 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, state.open_gl.msaa_interbuffer);
1185 glBlitFramebuffer(0, 0, GLint(screen_size.x), GLint(screen_size.y), 0, 0, GLint(screen_size.x), GLint(screen_size.y), GL_COLOR_BUFFER_BIT, GL_NEAREST);
1186 // 3. now render quad with scene's visuals as its texture image
1187 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1188 // draw Screen quad
1189 glUseProgram(state.open_gl.msaa_shader_program);
1190 glUniform1f(state.open_gl.msaa_uniform_gaussian_blur, state.user_settings.gaussianblur_level);
1191 glUniform2f(state.open_gl.msaa_uniform_screen_size, screen_size.x, screen_size.y);
1192 //
1193 glActiveTexture(GL_TEXTURE0);
1194 glBindTexture(GL_TEXTURE_2D, state.open_gl.msaa_texture); // use the now resolved color attachment as the quad's texture
1195 glBindVertexArray(state.open_gl.msaa_vao);
1196 //glBindBuffer(GL_ARRAY_BUFFER, state.open_gl.msaa_vbo);
1197 glDrawArrays(GL_TRIANGLES, 0, 6);
1198 }
1199}
1200
1201GLuint load_province_map(std::vector<uint16_t>& province_index, uint32_t size_x, uint32_t size_y) {
1202 GLuint texture_handle;
1203 glGenTextures(1, &texture_handle);
1204 if(texture_handle) {
1205 glBindTexture(GL_TEXTURE_2D, texture_handle);
1206
1207 // Create a texture with only one byte color
1208 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG8, size_x, size_y);
1209 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_x, size_y, GL_RG, GL_UNSIGNED_BYTE, &province_index[0]);
1210 glBindTexture(GL_TEXTURE_2D, 0);
1211 ogl::set_gltex_parameters(texture_handle, GL_TEXTURE_2D, GL_NEAREST, GL_CLAMP_TO_EDGE);
1212 }
1213 return texture_handle;
1214}
1215
1216void display_data::gen_prov_color_texture(GLuint texture_handle, std::vector<uint32_t> const& prov_color, uint8_t layers) {
1217 if(layers == 1) {
1218 glBindTexture(GL_TEXTURE_2D, texture_handle);
1219 } else {
1220 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_handle);
1221 }
1222 uint32_t rows = ((uint32_t)prov_color.size()) / 256;
1223 uint32_t left_on_last_row = ((uint32_t)prov_color.size()) % 256;
1224
1225 uint32_t x = 0;
1226 uint32_t y = 0;
1227 uint32_t width = 256;
1228 uint32_t height = rows;
1229
1230 if(layers == 1) {
1231 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &prov_color[0]);
1232 } else {
1233 // Set the texture data for each layer
1234 for(int i = 0; i < layers; i++) {
1235 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, i, width, height / layers, 1, GL_RGBA, GL_UNSIGNED_BYTE, &prov_color[i * (prov_color.size() / layers)]);
1236 }
1237 }
1238
1239 x = 0;
1240 y = rows;
1241 width = left_on_last_row;
1242 height = 1;
1243
1244 // SCHOMBERT: added a conditional to block reading from after the end in the case it is evenly divisible by 256
1245 // SCHOMBERT: that looks right to me, but I don't fully understand the intent
1246 if(left_on_last_row > 0 && layers == 1)
1247 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &prov_color[rows * 256]);
1248
1249 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
1250 glBindTexture(GL_TEXTURE_2D, 0);
1251}
1252
1253void display_data::set_selected_province(sys::state& state, dcon::province_id prov_id) {
1254 std::vector<uint32_t> province_highlights(state.world.province_size() + 1, 0);
1255 state.current_scene.update_highlight_texture(state, province_highlights, prov_id);
1257}
1258
1259void display_data::set_province_color(std::vector<uint32_t> const& prov_color) {
1261}
1262
1263void add_drag_box_line(std::vector<screen_vertex>& drag_box_vertices, glm::vec2 pos1, glm::vec2 pos2, glm::vec2 size, bool vertical) {
1264 if(vertical) {
1265 pos1.y -= size.y;
1266 pos2.y += size.y;
1267 size.y = 0;
1268 } else {
1269 pos1.x -= size.x;
1270 pos2.x += size.x;
1271 size.x = 0;
1272 }
1273 drag_box_vertices.emplace_back(pos1.x + size.x, pos1.y - size.y);
1274 drag_box_vertices.emplace_back(pos1.x - size.x, pos1.y + size.y);
1275 drag_box_vertices.emplace_back(pos2.x - size.x, pos2.y + size.y);
1276
1277 drag_box_vertices.emplace_back(pos2.x - size.x, pos2.y + size.y);
1278 drag_box_vertices.emplace_back(pos2.x + size.x, pos2.y - size.y);
1279 drag_box_vertices.emplace_back(pos1.x + size.x, pos1.y - size.y);
1280}
1281
1282void display_data::set_drag_box(bool draw_box, glm::vec2 pos1, glm::vec2 pos2, glm::vec2 pixel_size) {
1283 drag_box_vertices.clear();
1284 if(!draw_box)
1285 return;
1286
1287 if(pos1.x > pos2.x)
1288 std::swap(pos1.x, pos2.x);
1289 if(pos1.y > pos2.y)
1290 std::swap(pos1.y, pos2.y);
1291
1292 glm::vec2 size = pixel_size;
1293 // Vertical lines
1294 add_drag_box_line(drag_box_vertices, { pos1.x, pos1.y }, { pos1.x, pos2.y }, size, true);
1295 add_drag_box_line(drag_box_vertices, { pos2.x, pos1.y }, { pos2.x, pos2.y }, size, true);
1296
1297 // Horizontal lines
1298 add_drag_box_line(drag_box_vertices, { pos1.x, pos1.y }, { pos2.x, pos1.y }, size, false);
1299 add_drag_box_line(drag_box_vertices, { pos1.x, pos2.y }, { pos2.x, pos2.y }, size, false);
1300
1301 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_drag_box]);
1302 assert(!drag_box_vertices.empty());
1303 glBufferData(GL_ARRAY_BUFFER, sizeof(screen_vertex) * drag_box_vertices.size(), &drag_box_vertices[0], GL_STATIC_DRAW);
1304 glBindBuffer(GL_ARRAY_BUFFER, 0);
1305}
1306
1307void add_arrow_to_buffer(std::vector<map::curved_line_vertex>& buffer, glm::vec2 start, glm::vec2 end, glm::vec2 prev_normal_dir, glm::vec2 next_normal_dir, float fill_progress, bool end_arrow, float size_x, float size_y) {
1308 constexpr float type_filled = 2.f;
1309 constexpr float type_unfilled = 0.f;
1310 constexpr float type_end = 3.f;
1311 glm::vec2 curr_dir = glm::normalize(end - start);
1312 start /= glm::vec2(size_x, size_y);
1313 end /= glm::vec2(size_x, size_y);
1314
1315 if(fill_progress != 0) {
1316 if(fill_progress < 1.0f) {
1317 auto pos3 = glm::mix(start, end, fill_progress);
1318 auto midd_normal_dir = glm::vec2(-curr_dir.y, curr_dir.x);
1319
1320 buffer.emplace_back(pos3, +midd_normal_dir, -curr_dir, glm::vec2(1.0f, 0.0f), type_filled);//C
1321 buffer.emplace_back(pos3, -midd_normal_dir, -curr_dir, glm::vec2(1.0f, 1.0f), type_filled);//D
1322 buffer.emplace_back(pos3, +midd_normal_dir, -curr_dir, glm::vec2(1.0f, 0.0f), type_unfilled);//C
1323 buffer.emplace_back(pos3, -midd_normal_dir, -curr_dir, glm::vec2(1.0f, 1.0f), type_unfilled);//D
1324
1325 // Not filled - transition from "filled" to "unfilled"
1326 buffer.emplace_back(end, +next_normal_dir, -curr_dir, glm::vec2(1.0f, 0.0f), type_unfilled);//C
1327 buffer.emplace_back(end, -next_normal_dir, -curr_dir, glm::vec2(1.0f, 1.0f), type_unfilled);//D
1328 } else {
1329 // Not filled - transition from "filled" to "unfilled"
1330 buffer.emplace_back(end, +next_normal_dir, -curr_dir, glm::vec2(1.0f, 0.0f), type_filled);//C
1331 buffer.emplace_back(end, -next_normal_dir, -curr_dir, glm::vec2(1.0f, 1.0f), type_filled);//D
1332 }
1333 } else {
1334 // All unfilled!
1335 if(buffer.back().type_ == type_filled) {
1336 buffer.emplace_back(buffer[buffer.size() - 2]);//C
1337 buffer.emplace_back(buffer[buffer.size() - 2]);//D
1338 buffer[buffer.size() - 2].type_ = type_unfilled;
1339 buffer[buffer.size() - 1].type_ = type_unfilled;
1340 }
1341 buffer.emplace_back(end, +next_normal_dir, -curr_dir, glm::vec2(1.0f, 0.0f), type_unfilled);//C
1342 buffer.emplace_back(end, -next_normal_dir, -curr_dir, glm::vec2(1.0f, 1.0f), type_unfilled);//D
1343 }
1344 if(end_arrow) {
1345 if(buffer.back().type_ == type_filled) {
1346 buffer.emplace_back(buffer[buffer.size() - 2]);//C
1347 buffer.emplace_back(buffer[buffer.size() - 2]);//D
1348 buffer[buffer.size() - 2].type_ = type_unfilled;
1349 buffer[buffer.size() - 1].type_ = type_unfilled;
1350 }
1351 buffer.emplace_back(end, +next_normal_dir, -curr_dir, glm::vec2(1.0f, 0.0f), type_end);//C
1352 buffer.emplace_back(end, -next_normal_dir, -curr_dir, glm::vec2(1.0f, 1.0f), type_end);//D
1353 }
1354}
1355
1356constexpr inline uint32_t default_num_b_segments = 16;
1357constexpr inline float control_point_length_factor = 0.3f;
1358
1359void add_bezier_to_buffer(std::vector<map::curved_line_vertex>& buffer, glm::vec2 start, glm::vec2 end, glm::vec2 start_per, glm::vec2 end_per, float progress, bool last_curve, float size_x, float size_y, uint32_t num_b_segments) {
1360 auto control_point_length = glm::length(end - start) * control_point_length_factor;
1361
1362 auto start_control_point = start_per * control_point_length + start;
1363 auto end_control_point = end_per * control_point_length + end;
1364
1365 auto bpoint = [=](float t) {
1366 auto u = 1.0f - t;
1367 return 0.0f
1368 + (u * u * u) * start
1369 + (3.0f * u * u * t) * start_control_point
1370 + (3.0f * u * t * t) * end_control_point
1371 + (t * t * t) * end;
1372 };
1373
1374 auto last_normal = glm::vec2(-start_per.y, start_per.x);
1375 glm::vec2 next_normal{ 0.0f, 0.0f };
1376
1377 for(uint32_t i = 0; i < num_b_segments - 1; ++i) {
1378 auto t_start = float(i) / float(num_b_segments);
1379 auto t_end = float(i + 1) / float(num_b_segments);
1380 auto t_next = float(i + 2) / float(num_b_segments);
1381
1382 auto start_point = bpoint(t_start);
1383 auto end_point = bpoint(t_end);
1384 auto next_point = bpoint(t_next);
1385
1386 next_normal = glm::normalize(end_point - start_point) + glm::normalize(end_point - next_point);
1387 auto temp = glm::normalize(end_point - start_point);
1388 if(glm::length(next_normal) < 0.00001f) {
1389 next_normal = glm::normalize(glm::vec2(-temp.y, temp.x));
1390 } else {
1391 next_normal = glm::normalize(next_normal);
1392 if(glm::dot(glm::vec2(-temp.y, temp.x), next_normal) < 0) {
1393 next_normal = -next_normal;
1394 }
1395 }
1396
1397 if(progress > 0.0f) {
1398 if(t_end <= progress) { // filled
1399 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, 1.0f, false, size_x, size_y);
1400 } else if(progress < t_start) { // empty
1401 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, 0.0f, false, size_x, size_y);
1402 } else {
1403 auto effective_progress = (progress - t_start) * float(num_b_segments);
1404 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, effective_progress, false, size_x, size_y);
1405 }
1406 } else {
1407 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, 0.0f, false, size_x, size_y);
1408 }
1409
1410 last_normal = next_normal;
1411 }
1412 {
1413 next_normal = glm::vec2(end_per.y, -end_per.x);
1414 auto t_start = float(num_b_segments - 1) / float(num_b_segments);
1415 auto t_end = 1.0f;
1416 auto start_point = bpoint(t_start);
1417 auto end_point = bpoint(t_end);
1418
1419 if(progress > 0.0f) {
1420 if(t_end <= progress) { // filled
1421 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, 1.0f, last_curve, size_x, size_y);
1422 } else if(progress < t_start) { // empty
1423 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, 0.0f, last_curve, size_x, size_y);
1424 } else {
1425 auto effective_progress = (progress - t_start) * float(num_b_segments);
1426 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, effective_progress, last_curve, size_x, size_y);
1427 }
1428 } else {
1429 add_arrow_to_buffer(buffer, start_point, end_point, last_normal, next_normal, 0.0f, last_curve, size_x, size_y);
1430 }
1431 }
1432}
1433
1434void add_tl_segment_buffer(std::vector<map::textured_line_vertex>& buffer, glm::vec2 start, glm::vec2 end, glm::vec2 next_normal_dir, float size_x, float size_y, float& distance) {
1435 start /= glm::vec2(size_x, size_y);
1436 end /= glm::vec2(size_x, size_y);
1437 auto d = start - end;
1438 d.x *= 2.0f;
1439 distance += 0.5f * glm::length(d);
1440 buffer.emplace_back(textured_line_vertex{ end, +next_normal_dir, 0.0f, distance });//C
1441 buffer.emplace_back(textured_line_vertex{ end, -next_normal_dir, 1.0f, distance });//D
1442}
1443
1444void add_tl_segment_buffer(std::vector<map::textured_line_with_width_vertex>& buffer, glm::vec2 start, glm::vec2 end, glm::vec2 next_normal_dir, float size_x, float size_y, float& distance, float width) {
1445 start /= glm::vec2(size_x, size_y);
1446 end /= glm::vec2(size_x, size_y);
1447 auto d = start - end;
1448 distance += glm::length(d);
1449 buffer.emplace_back(textured_line_with_width_vertex{ end, +next_normal_dir, 0.0f, distance, width});//C
1450 buffer.emplace_back(textured_line_with_width_vertex{ end, -next_normal_dir, 1.0f, distance, width});//D
1451}
1452
1453void add_tl_bezier_to_buffer(std::vector<map::textured_line_vertex>& buffer, glm::vec2 start, glm::vec2 end, glm::vec2 start_per, glm::vec2 end_per, float progress, bool last_curve, float size_x, float size_y, uint32_t num_b_segments, float& distance) {
1454 auto control_point_length = glm::length(end - start) * control_point_length_factor;
1455
1456 auto start_control_point = start_per * control_point_length + start;
1457 auto end_control_point = end_per * control_point_length + end;
1458
1459 auto bpoint = [=](float t) {
1460 auto u = 1.0f - t;
1461 return 0.0f
1462 + (u * u * u) * start
1463 + (3.0f * u * u * t) * start_control_point
1464 + (3.0f * u * t * t) * end_control_point
1465 + (t * t * t) * end;
1466 };
1467
1468 auto last_normal = glm::vec2(-start_per.y, start_per.x);
1469 glm::vec2 next_normal{ 0.0f, 0.0f };
1470
1471 for(uint32_t i = 0; i < num_b_segments - 1; ++i) {
1472 auto t_start = float(i) / float(num_b_segments);
1473 auto t_end = float(i + 1) / float(num_b_segments);
1474 auto t_next = float(i + 2) / float(num_b_segments);
1475
1476 auto start_point = bpoint(t_start);
1477 auto end_point = bpoint(t_end);
1478 auto next_point = bpoint(t_next);
1479
1480 next_normal = glm::normalize(end_point - start_point) + glm::normalize(end_point - next_point);
1481 auto temp = glm::normalize(end_point - start_point);
1482 if(glm::length(next_normal) < 0.00001f) {
1483 next_normal = glm::normalize(glm::vec2(-temp.y, temp.x));
1484 } else {
1485 next_normal = glm::normalize(next_normal);
1486 if(glm::dot(glm::vec2(-temp.y, temp.x), next_normal) < 0) {
1487 next_normal = -next_normal;
1488 }
1489 }
1490
1491 add_tl_segment_buffer(buffer, start_point, end_point, next_normal, size_x, size_y, distance);
1492
1493 last_normal = next_normal;
1494 }
1495 {
1496 next_normal = glm::vec2(end_per.y, -end_per.x);
1497 auto t_start = float(num_b_segments - 1) / float(num_b_segments);
1498 auto t_end = 1.0f;
1499 auto start_point = bpoint(t_start);
1500 auto end_point = bpoint(t_end);
1501
1502 add_tl_segment_buffer(buffer, start_point, end_point, next_normal, size_x, size_y, distance);
1503 }
1504}
1505
1506void add_tl_bezier_to_buffer(std::vector<map::textured_line_with_width_vertex>& buffer, glm::vec2 start, glm::vec2 end, glm::vec2 start_tangent, glm::vec2 end_tangent, float progress, bool last_curve, float size_x, float size_y, uint32_t num_b_segments, float& distance, float width_start, float width_end) {
1507 auto control_point_length = glm::length(end - start) * control_point_length_factor * 0.4f;
1508
1509 auto start_control_point = start_tangent * control_point_length + start;
1510 auto end_control_point = -end_tangent * control_point_length + end;
1511
1512 auto bpoint = [=](float t) {
1513 auto u = 1.0f - t;
1514 return 0.0f
1515 + (u * u * u) * start
1516 + (3.0f * u * u * t) * start_control_point
1517 + (3.0f * u * t * t) * end_control_point
1518 + (t * t * t) * end;
1519 };
1520
1521 auto last_normal = glm::vec2(-start_tangent.y, start_tangent.x);
1522 glm::vec2 current_normal{ 0.0f, 0.0f };
1523
1524 for(uint32_t i = 0; i < num_b_segments - 1; ++i) {
1525 auto t_start = float(i) / float(num_b_segments);
1526 auto t_end = float(i + 1) / float(num_b_segments);
1527 auto t_next = float(i + 2) / float(num_b_segments);
1528
1529 auto start_point = bpoint(t_start);
1530 auto end_point = bpoint(t_end);
1531 auto next_point = bpoint(t_next);
1532
1533 auto tangent_part_1 = glm::normalize(end_point - start_point);
1534 auto tangent_part_2 = glm::normalize(next_point - end_point);
1535 auto current_tangent = glm::normalize(tangent_part_1 + tangent_part_2);
1536
1537 current_normal = glm::vec2(-current_tangent.y, current_tangent.x);
1538
1539 auto width = t_start * width_end + (1.f - t_start) * width_start;
1540
1541 if(width != width_end) {
1542 auto help = true;
1543 }
1544
1545 add_tl_segment_buffer(buffer, start_point, end_point, current_normal, size_x, size_y, distance, width);
1546
1547 last_normal = current_normal;
1548 }
1549 {
1550 current_normal = glm::vec2(-end_tangent.y, end_tangent.x);
1551 auto t_start = float(num_b_segments - 1) / float(num_b_segments);
1552 auto t_end = 1.0f;
1553 auto start_point = bpoint(t_start);
1554 auto end_point = bpoint(t_end);
1555 auto width = t_start * width_end + (1.f - t_start) * width_start;
1556
1557 add_tl_segment_buffer(buffer, start_point, end_point, current_normal, size_x, size_y, distance, width);
1558 }
1559}
1560
1561glm::vec2 put_in_local(glm::vec2 new_point, glm::vec2 base_point, float size_x) {
1562 auto uadjx = std::abs(new_point.x - base_point.x);
1563 auto ladjx = std::abs(new_point.x - size_x - base_point.x);
1564 auto radjx = std::abs(new_point.x + size_x - base_point.x);
1565 if(uadjx < ladjx) {
1566 return uadjx < radjx ? new_point : glm::vec2{ new_point.x + size_x, new_point.y };
1567 } else {
1568 return ladjx < radjx ? glm::vec2{ new_point.x - size_x, new_point.y } : glm::vec2{ new_point.x + size_x, new_point.y };
1569 }
1570}
1571
1572void make_navy_path(sys::state& state, std::vector<map::curved_line_vertex>& buffer, dcon::navy_id selected_navy, float size_x, float size_y) {
1573 auto path = state.world.navy_get_path(selected_navy);
1574 if(auto ps = path.size(); ps > 0) {
1575 auto progress = military::fractional_distance_covered(state, selected_navy);
1576
1577 glm::vec2 current_pos = duplicates::get_navy_location(state, state.world.navy_get_location_from_navy_location(selected_navy));
1578 glm::vec2 next_pos = put_in_local(duplicates::get_navy_location(state, path[ps - 1]), current_pos, size_x);
1579 glm::vec2 prev_perpendicular = glm::normalize(next_pos - current_pos);
1580
1581 auto start_normal = glm::vec2(-prev_perpendicular.y, prev_perpendicular.x);
1582 auto norm_pos = current_pos / glm::vec2(size_x, size_y);
1583
1584 buffer.emplace_back(norm_pos, +start_normal, glm::vec2{ 0,0 }, glm::vec2(0.0f, 0.0f), progress > 0.0f ? 2.0f : 0.0f);
1585 buffer.emplace_back(norm_pos, -start_normal, glm::vec2{ 0,0 }, glm::vec2(0.0f, 1.0f), progress > 0.0f ? 2.0f : 0.0f);
1586 for(auto i = ps; i-- > 0;) {
1587 glm::vec2 next_perpendicular{ 0.0f, 0.0f };
1588 next_pos = put_in_local(duplicates::get_navy_location(state, path[i]), current_pos, size_x);
1589
1590 if(i > 0) {
1591 glm::vec2 next_next_pos = put_in_local(duplicates::get_navy_location(state, path[i - 1]), next_pos, size_x);
1592 glm::vec2 a_per = glm::normalize(next_pos - current_pos);
1593 glm::vec2 b_per = glm::normalize(next_pos - next_next_pos);
1594 glm::vec2 temp = a_per + b_per;
1595 if(glm::length(temp) < 0.00001f) {
1596 next_perpendicular = -a_per;
1597 } else {
1598 next_perpendicular = glm::normalize(glm::vec2{ -temp.y, temp.x });
1599 if(glm::dot(a_per, -next_perpendicular) < glm::dot(a_per, next_perpendicular)) {
1600 next_perpendicular *= -1.0f;
1601 }
1602 }
1603 } else {
1604 next_perpendicular = glm::normalize(current_pos - next_pos);
1605 }
1606
1607 add_bezier_to_buffer(buffer, current_pos, next_pos, prev_perpendicular, next_perpendicular, i == ps - 1 ? progress : 0.0f, i == 0, size_x, size_y, default_num_b_segments);
1608
1609 prev_perpendicular = -1.0f * next_perpendicular;
1610 current_pos = duplicates::get_navy_location(state, path[i]);
1611 }
1612 }
1613}
1614
1615
1616void make_army_path(sys::state& state, std::vector<map::curved_line_vertex>& buffer, dcon::army_id selected_army, float size_x, float size_y) {
1617 auto path = state.world.army_get_path(selected_army);
1618 if(auto ps = path.size(); ps > 0) {
1619 auto progress = military::fractional_distance_covered(state, selected_army);
1620
1621 glm::vec2 current_pos = duplicates::get_army_location(state, state.world.army_get_location_from_army_location(selected_army));
1622 glm::vec2 next_pos = put_in_local(duplicates::get_army_location(state, path[ps - 1]), current_pos, size_x);
1623 glm::vec2 prev_perpendicular = glm::normalize(next_pos - current_pos);
1624
1625 auto start_normal = glm::vec2(-prev_perpendicular.y, prev_perpendicular.x);
1626 auto norm_pos = current_pos / glm::vec2(size_x, size_y);
1627
1628 buffer.emplace_back(norm_pos, +start_normal, glm::vec2{0,0}, glm::vec2(0.0f, 0.0f), progress > 0.0f ? 2.0f : 0.0f);
1629 buffer.emplace_back(norm_pos, -start_normal, glm::vec2{ 0,0 }, glm::vec2(0.0f, 1.0f), progress > 0.0f ? 2.0f : 0.0f);
1630 for(auto i = ps; i-- > 0;) {
1631 glm::vec2 next_perpendicular{ 0.0f, 0.0f };
1632 next_pos = put_in_local(duplicates::get_army_location(state, path[i]), current_pos, size_x);
1633
1634 if(i > 0) {
1635 glm::vec2 next_next_pos = put_in_local(duplicates::get_army_location(state, path[i - 1]), next_pos, size_x);
1636 glm::vec2 a_per = glm::normalize(next_pos - current_pos);
1637 glm::vec2 b_per = glm::normalize(next_pos - next_next_pos);
1638 glm::vec2 temp = a_per + b_per;
1639 if(glm::length(temp) < 0.00001f) {
1640 next_perpendicular = -a_per;
1641 } else {
1642 next_perpendicular = glm::normalize(glm::vec2{ -temp.y, temp.x });
1643 if(glm::dot(a_per, -next_perpendicular) < glm::dot(a_per, next_perpendicular)) {
1644 next_perpendicular *= -1.0f;
1645 }
1646 }
1647 } else {
1648 next_perpendicular = glm::normalize(current_pos - next_pos);
1649 }
1650
1651 add_bezier_to_buffer(buffer, current_pos, next_pos, prev_perpendicular, next_perpendicular, i == ps - 1 ? progress : 0.0f, i == 0, size_x, size_y, default_num_b_segments);
1652
1653 prev_perpendicular = -1.0f * next_perpendicular;
1654 current_pos = duplicates::get_army_location(state, path[i]);
1655 }
1656 }
1657}
1658
1659void create_railroad_connection(sys::state& state, std::vector<glm::vec2>& railroad, dcon::province_id p1, dcon::province_id p2) {
1660 auto const m1 = state.world.province_get_mid_point(p1);
1661 auto const m2 = state.world.province_get_mid_point(p2);
1662 railroad.emplace_back(m1);
1663 //
1664 auto mid = ((m1 + m2) / glm::vec2(2.f, 2.f));
1665 const auto rp = rng::get_random(state, p1.index(), p2.index() ^ p1.index());
1666 const float rf = float(rng::reduce(uint32_t(rp), 8192)) / (8192.f * 0.25f);
1667 auto const perpendicular = glm::normalize(m2 - m1) * glm::vec2(rf, rf);
1668 railroad.emplace_back(mid + glm::vec2(-perpendicular.y, perpendicular.x));
1669}
1670
1671bool get_provinces_part_of_rr_path(sys::state& state, std::vector<bool>& visited_adj, std::vector<bool>& visited_prov, std::vector<dcon::province_id>& provinces, dcon::province_id p) {
1672 if(state.world.province_get_building_level(p, uint8_t(economy::province_building_type::railroad)) == 0)
1673 return false;
1674 if(visited_prov[p.index()])
1675 return false;
1676 visited_prov[p.index()] = true;
1677 provinces.push_back(p);
1678
1679 std::vector<dcon::province_adjacency_id> valid_adj;
1680 for(const auto adj : state.world.province_get_province_adjacency_as_connected_provinces(p)) {
1681 auto const pa = adj.get_connected_provinces(adj.get_connected_provinces(0) == p ? 1 : 0);
1682 if(pa.get_building_level(uint8_t(economy::province_building_type::railroad)) == 0
1683 || visited_prov[pa.id.index()])
1684 continue;
1685 // Do not display railroads if it's a strait OR an impassable land border!
1686 if((adj.get_type() & province::border::impassible_bit) != 0
1687 || (adj.get_type() & province::border::non_adjacent_bit) != 0)
1688 continue;
1689 valid_adj.push_back(adj.id);
1690 }
1691 std::sort(valid_adj.begin(), valid_adj.end(), [&](auto const a, auto const b) -> bool {
1692 auto const ad = state.world.province_adjacency_get_distance(a);
1693 auto const bd = state.world.province_adjacency_get_distance(b);
1694 return ad < bd;
1695 });
1696 for(const auto a : valid_adj) {
1697 auto const adj = dcon::fatten(state.world, a);
1698 auto const pa = adj.get_connected_provinces(adj.get_connected_provinces(0) == p ? 1 : 0);
1699 if(get_provinces_part_of_rr_path(state, visited_adj, visited_prov, provinces, pa.id)) {
1700 visited_adj[adj.id.index()] = true;
1701 break;
1702 }
1703 }
1704 return true;
1705}
1706
1708 // Create paths for the main railroad sections
1709 std::vector<bool> visited_prov(state.world.province_size() + 1, false);
1710 std::vector<bool> rr_ends(state.world.province_size() + 1, false);
1711 std::vector<bool> visited_adj(state.world.province_adjacency_size() + 1, false);
1712 std::vector<std::vector<glm::vec2>> railroads;
1713 for(const auto p : state.world.in_province) {
1714 std::vector<dcon::province_id> provinces;
1715 if(get_provinces_part_of_rr_path(state, visited_adj, visited_prov, provinces, p)) {
1716 if(provinces.size() > 1) {
1717 std::vector<glm::vec2> railroad;
1718 for(uint32_t i = 0; i < uint32_t(provinces.size() - 1); i++)
1719 create_railroad_connection(state, railroad, provinces[i], provinces[i + 1]);
1720 railroad.emplace_back(state.world.province_get_mid_point(provinces.back()));
1721 assert(!railroad.empty());
1722 railroads.push_back(railroad);
1723 rr_ends[provinces.front().index()] = true;
1724 rr_ends[provinces.back().index()] = true;
1725 }
1726 }
1727 }
1728
1729 // Populate paths with railroads - only account provinces that have been visited
1730 // but not the adjacencies
1731 for(const auto p1 : state.world.in_province) {
1732 if(visited_prov[p1.id.index()]) {
1733 auto const p1_level = p1.get_building_level(uint8_t(economy::province_building_type::railroad));
1734 auto admin_efficiency = province::state_admin_efficiency(state, p1.get_state_membership());
1735 auto max_adj = std::max<uint32_t>(uint32_t(admin_efficiency * 2.75f), rr_ends[p1.id.index()] ? 3 : 1);
1736 std::vector<dcon::province_adjacency_id> valid_adj;
1737 for(const auto adj : p1.get_province_adjacency_as_connected_provinces()) {
1738 if(max_adj == 0)
1739 break;
1740 auto p2 = adj.get_connected_provinces(adj.get_connected_provinces(0) == p1.id ? 1 : 0);
1741 if(p2.get_building_level(uint8_t(economy::province_building_type::railroad)) == 0)
1742 continue;
1743 max_adj--;
1744 if(visited_adj[adj.id.index()])
1745 continue;
1746 if(rr_ends[p1.id.index()] != rr_ends[p2.id.index()]
1747 && rr_ends[p1.id.index()] == false)
1748 continue;
1749 visited_adj[adj.id.index()] = true;
1750 valid_adj.push_back(adj.id);
1751 }
1752 std::sort(valid_adj.begin(), valid_adj.end(), [&](auto const a, auto const b) -> bool {
1753 auto const ad = state.world.province_adjacency_get_distance(a);
1754 auto const bd = state.world.province_adjacency_get_distance(b);
1755 return ad < bd;
1756 });
1757 for(const auto a : valid_adj) {
1758 auto const adj = dcon::fatten(state.world, a);
1759 auto const p2 = adj.get_connected_provinces(adj.get_connected_provinces(0) == p1.id ? 1 : 0);
1760 //
1761 std::vector<glm::vec2> railroad;
1762 create_railroad_connection(state, railroad, p1.id, p2.id);
1763 railroad.emplace_back(state.world.province_get_mid_point(p2.id));
1764 assert(!railroad.empty());
1765 railroads.push_back(railroad);
1766 }
1767 }
1768 }
1769
1770 railroad_vertices.clear();
1771 railroad_starts.clear();
1772 railroad_counts.clear();
1773 for(const auto& railroad : railroads) {
1774 railroad_starts.push_back(GLint(railroad_vertices.size()));
1775 glm::vec2 current_pos = railroad.back();
1776 glm::vec2 next_pos = put_in_local(railroad[railroad.size() - 2], current_pos, float(size_x));
1777 glm::vec2 prev_perpendicular = glm::normalize(next_pos - current_pos);
1778 auto start_normal = glm::vec2(-prev_perpendicular.y, prev_perpendicular.x);
1779 auto norm_pos = current_pos / glm::vec2(size_x, size_y);
1780 railroad_vertices.emplace_back(textured_line_vertex{ norm_pos, +start_normal, 0.0f, 0.f });//C
1781 railroad_vertices.emplace_back(textured_line_vertex{ norm_pos, -start_normal, 1.0f, 0.f });//D
1782 float distance = 0.0f;
1783 for(auto i = railroad.size() - 1; i-- > 0;) {
1784 glm::vec2 next_perpendicular{ 0.0f, 0.0f };
1785 next_pos = put_in_local(railroad[i], current_pos, float(size_x));
1786 if(i > 0) {
1787 glm::vec2 next_next_pos = put_in_local(railroad[i - 1], next_pos, float(size_x));
1788 glm::vec2 a_per = glm::normalize(next_pos - current_pos);
1789 glm::vec2 b_per = glm::normalize(next_pos - next_next_pos);
1790 glm::vec2 temp = a_per + b_per;
1791 if(glm::length(temp) < 0.00001f) {
1792 next_perpendicular = -a_per;
1793 } else {
1794 next_perpendicular = glm::normalize(glm::vec2{ -temp.y, temp.x });
1795 if(glm::dot(a_per, -next_perpendicular) < glm::dot(a_per, next_perpendicular))
1796 next_perpendicular *= -1.0f;
1797 }
1798 } else {
1799 next_perpendicular = glm::normalize(current_pos - next_pos);
1800 }
1801 add_tl_bezier_to_buffer(railroad_vertices, current_pos, next_pos, prev_perpendicular, next_perpendicular, 0.0f, false, float(size_x), float(size_y), default_num_b_segments, distance);
1802 prev_perpendicular = -1.0f * next_perpendicular;
1803 current_pos = railroad[i];
1804 }
1805 railroad_counts.push_back(GLsizei(railroad_vertices.size() - railroad_starts.back()));
1806 assert(railroad_counts.back() > 1);
1807 }
1808 assert(railroad_counts.size() == railroad_starts.size());
1809
1810 if(!railroad_vertices.empty()) {
1811 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_railroad]);
1812 glBufferData(GL_ARRAY_BUFFER, sizeof(textured_line_vertex) * railroad_vertices.size(), railroad_vertices.data(), GL_STATIC_DRAW);
1813 glBindBuffer(GL_ARRAY_BUFFER, 0);
1814 }
1815}
1816
1817void display_data::set_text_lines(sys::state& state, std::vector<text_line_generator_data> const& data) {
1818 text_line_vertices.clear();
1820
1821 const auto map_x_scaling = float(size_x) / float(size_y);
1822 auto& f = state.font_collection.get_font(state, text::font_selection::map_font);
1823
1824 for(const auto& e : data) {
1825 // omit invalid, nan or infinite coefficients
1826 if(!std::isfinite(e.coeff[0]) || !std::isfinite(e.coeff[1]) || !std::isfinite(e.coeff[2]) || !std::isfinite(e.coeff[3]))
1827 continue;
1828
1829 bool is_linear = true;
1830 if((e.coeff[2] != 0) || (e.coeff[3] != 0)) {
1831 is_linear = false;
1832 }
1833
1834 // y = a + bx + cx^2 + dx^3
1835 // y = mo[0] + mo[1] * x + mo[2] * x * x + mo[3] * x * x * x
1836 auto poly_fn = [&](float x) {
1837 return e.coeff[0] + e.coeff[1] * x + e.coeff[2] * x * x + e.coeff[3] * x * x * x;
1838 };
1839 auto dpoly_fn = [&](float x) {
1840 // y = a + 1bx^1 + 1cx^2 + 1dx^3
1841 // y = 0 + 1bx^0 + 2cx^1 + 3dx^2
1842 return e.coeff[1] + 2.f * e.coeff[2] * x + 3.f * e.coeff[3] * x * x;
1843 };
1844
1845
1846 //cutting box if graph goes outside
1847
1848 float left = 0.f;
1849 float right = 1.f;
1850
1851 if(is_linear) {
1852 if(e.coeff[1] > 0.01f) {
1853 left = (-e.coeff[0]) / e.coeff[1];
1854 right = (1.f - e.coeff[0]) / e.coeff[1];
1855 } else if(e.coeff[1] < -0.01f) {
1856 left = (1.f - e.coeff[0]) / e.coeff[1];
1857 right = (- e.coeff[0]) / e.coeff[1];
1858 }
1859 } else {
1860 while(((poly_fn(left) < 0.f) || (poly_fn(left) > 1.f)) && (left < 1.f)) {
1861 left += 1.f / 300.f;
1862 }
1863 while(((poly_fn(right) < 0.f) || (poly_fn(right) > 1.f)) && (right > 0.f)) {
1864 right -= 1.f / 300.f;
1865 }
1866 }
1867
1868
1869 left = std::clamp(left, 0.f, 1.f);
1870 right = std::clamp(right, 0.f, 1.f);
1871
1872
1873 if(right <= left) {
1874 continue;
1875 }
1876
1877 float result_interval = right - left;
1878 float center = (right + left) / 2.f;
1879
1880 glm::vec2 ratio = e.ratio;
1881 glm::vec2 basis = e.basis;
1882
1883 auto effective_ratio = ratio.x * map_x_scaling / ratio.y;
1884
1885 float text_length = f.text_extent(state, e.text, 0, uint32_t(e.text.glyph_info.size()), 1);
1886 assert(std::isfinite(text_length) && text_length != 0.f);
1887 float x_step = (result_interval / float(e.text.glyph_info.size() * 32.f));
1888 float curve_length = 0.f; //width of whole string polynomial
1889 if(is_linear) {
1890 float height = poly_fn(right) - poly_fn(left);
1891 curve_length = 2.f * glm::length(glm::vec2(height * ratio.y, result_interval * ratio.x));
1892 } else for(float x = left; x <= right; x += x_step) {
1893 curve_length += 2.0f * glm::length(glm::vec2(x_step * ratio.x, (poly_fn(x) - poly_fn(x + x_step)) * ratio.y));
1894 }
1895 float size = (curve_length / text_length) * 0.8f; //* 0.66f;
1896
1897 // typography "golden ratio" steps
1898
1899 float font_size_index = std::round(5.f * log(size) / log(1.618034f));
1900
1901 if(font_size_index > 45.f) {
1902 font_size_index = 45.f;
1903 }
1904 if (font_size_index > 5.f)
1905 font_size_index = 5.f * std::round(font_size_index / 5.f);
1906
1907 size = std::pow(1.618034f, font_size_index / 5.f);
1908
1909 // fixed step
1910
1911 /*
1912 float size_step = 30.f;
1913
1914 if(size > size_step * 6.f) {
1915 size = size_step * 6.f; //+ (size - 200.0f) * 0.5f;
1916 }
1917
1918 if(size > ratio.x / 2.f) {
1919 size = ratio.x / 2.f;
1920 }
1921 if(size > ratio.y / 2.f) {
1922 size = ratio.y / 2.f;
1923 }
1924
1925 size = std::round(size / size_step) * size_step;
1926
1927 if(size < size_step) {
1928 continue;
1929 }
1930 */
1931
1932 auto real_text_size = size / (size_x * 2.0f);
1933
1934 float letter_spacing_map = std::clamp((0.8f * curve_length / text_length - size) / 2.f, 0.f, size * 2.f);
1935 if(state.world.locale_get_prevent_letterspace(state.font_collection.get_current_locale())) {
1936 letter_spacing_map = 0.f;
1937 }
1938
1939 float margin = (curve_length - text_length * (size + letter_spacing_map * 2.f) + letter_spacing_map) / 2.0f;
1940 float x = left;
1941 for(float accumulated_length = 0.f; ; x += x_step) {
1942 auto added_distance = 2.0f * glm::length(glm::vec2(x_step * ratio.x, (poly_fn(x) - poly_fn(x + x_step)) * e.ratio.y));
1943 if(accumulated_length + added_distance >= margin) {
1944 x += x_step * (margin - accumulated_length) / added_distance;
1945 break;
1946 }
1947 accumulated_length += added_distance;
1948 }
1949
1950
1951 unsigned int glyph_count = static_cast<unsigned int>(e.text.glyph_info.size());
1952 for(unsigned int i = 0; i < glyph_count; i++) {
1953 hb_codepoint_t glyphid = e.text.glyph_info[i].codepoint;
1954 auto gso = f.glyph_positions[glyphid];
1955 float x_advance = float(e.text.glyph_info[i].x_advance) / (float((1 << 6) * text::magnification_factor));
1956 float x_offset = float(e.text.glyph_info[i].x_offset) / (float((1 << 6) * text::magnification_factor)) + float(gso.x);
1957 float y_offset = float(gso.y) - float(e.text.glyph_info[i].y_offset) / (float((1 << 6) * text::magnification_factor));
1958 if(glyphid != FT_Get_Char_Index(f.font_face, ' ')) {
1959 // Add up baseline and kerning offsets
1960 glm::vec2 glyph_positions{ x_offset / 64.f, -y_offset / 64.f };
1961
1962 glm::vec2 curr_dir = glm::normalize(glm::vec2(effective_ratio, dpoly_fn(x)));
1963 glm::vec2 curr_normal_dir = glm::vec2(-curr_dir.y, curr_dir.x);
1964 curr_dir.x *= 0.5f;
1965 curr_normal_dir.x *= 0.5f;
1966
1967 glm::vec2 shader_direction = glm::normalize(glm::vec2(ratio.x, dpoly_fn(x) * ratio.y));
1968
1969 auto p0 = glm::vec2(x, poly_fn(x)) * ratio + basis;
1970 p0 /= glm::vec2(size_x, size_y); // Rescale the coordinate to 0-1
1971 p0 -= (1.5f - 2.f * glyph_positions.y) * curr_normal_dir * real_text_size;
1972 p0 += (1.0f + 2.f * glyph_positions.x) * curr_dir * real_text_size;
1973
1974 float type = float((gso.texture_slot >> 6) % text::max_texture_layers);
1975 float step = 1.f / 8.f;
1976 float tx = float(gso.texture_slot & 7) * step;
1977 float ty = float((gso.texture_slot & 63) >> 3) * step;
1978
1979 text_line_vertices.emplace_back(p0, glm::vec2(-1, 1), shader_direction, glm::vec3(tx, ty, type), real_text_size);
1980 text_line_vertices.emplace_back(p0, glm::vec2(-1, -1), shader_direction, glm::vec3(tx, ty + step, type), real_text_size);
1981 text_line_vertices.emplace_back(p0, glm::vec2(1, -1), shader_direction, glm::vec3(tx + step, ty + step, type), real_text_size);
1982
1983 text_line_vertices.emplace_back(p0, glm::vec2(1, -1), shader_direction, glm::vec3(tx + step, ty + step, type), real_text_size);
1984 text_line_vertices.emplace_back(p0, glm::vec2(1, 1), shader_direction, glm::vec3(tx + step, ty, type), real_text_size);
1985 text_line_vertices.emplace_back(p0, glm::vec2(-1, 1), shader_direction, glm::vec3(tx, ty, type), real_text_size);
1986 text_line_texture_per_quad.emplace_back(f.textures[gso.texture_slot >> 6]);
1987 }
1988 float glyph_advance = x_advance * size / 64.f;
1989 for(float glyph_length = 0.f; ; x += x_step) {
1990 auto added_distance = 2.0f * glm::length(glm::vec2(x_step * ratio.x, (poly_fn(x) - poly_fn(x + x_step)) * ratio.y));
1991 if(glyph_length + added_distance >= glyph_advance + letter_spacing_map) {
1992 x += x_step * (glyph_advance + letter_spacing_map - glyph_length) / added_distance;
1993 break;
1994 }
1995 glyph_length += added_distance;
1996 }
1997 }
1998 }
1999 if(text_line_vertices.size() > 0) {
2000 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_text_line]);
2001 glBufferData(GL_ARRAY_BUFFER, sizeof(text_line_vertex) * text_line_vertices.size(), &text_line_vertices[0], GL_STATIC_DRAW);
2002 glBindBuffer(GL_ARRAY_BUFFER, 0);
2003 }
2004}
2005
2006void display_data::set_province_text_lines(sys::state& state, std::vector<text_line_generator_data> const& data) {
2008 const auto map_x_scaling = float(size_x) / float(size_y);
2009 auto& f = state.font_collection.get_font(state, text::font_selection::map_font);
2010
2011 for(const auto& e : data) {
2012 // omit invalid, nan or infinite coefficients
2013 if(!std::isfinite(e.coeff[0]) || !std::isfinite(e.coeff[1]) || !std::isfinite(e.coeff[2]) || !std::isfinite(e.coeff[3]))
2014 continue;
2015
2016 auto effective_ratio = e.ratio.x * map_x_scaling / e.ratio.y;
2017
2018 float text_length = f.text_extent(state, e.text, 0, uint32_t(e.text.glyph_info.size()), 1);
2019 assert(std::isfinite(text_length) && text_length != 0.f);
2020 // y = a + bx + cx^2 + dx^3
2021 // y = mo[0] + mo[1] * x + mo[2] * x * x + mo[3] * x * x * x
2022 auto poly_fn = [&](float x) {
2023 return e.coeff[0] + e.coeff[1] * x + e.coeff[2] * x * x + e.coeff[3] * x * x * x;
2024 };
2025 float x_step = (1.f / float(e.text.glyph_info.size() * 32.f));
2026 float curve_length = 0.f; //width of whole string polynomial
2027 for(float x = 0.f; x <= 1.f; x += x_step)
2028 curve_length += 2.0f * glm::length(glm::vec2(x_step * e.ratio.x, (poly_fn(x) - poly_fn(x + x_step)) * e.ratio.y));
2029
2030 float size = (curve_length / text_length) * 0.85f;
2031 if(size > 200.0f) {
2032 size = 200.0f + (size - 200.0f) * 0.5f;
2033 }
2034 auto real_text_size = size / (size_x * 2.0f);
2035 float margin = (curve_length - text_length * size) / 2.0f;
2036 float x = 0.f;
2037 for(float accumulated_length = 0.f; ; x += x_step) {
2038 auto added_distance = 2.0f * glm::length(glm::vec2(x_step * e.ratio.x, (poly_fn(x) - poly_fn(x + x_step)) * e.ratio.y));
2039 if(accumulated_length + added_distance >= margin) {
2040 x += x_step * (margin - accumulated_length) / added_distance;
2041 break;
2042 }
2043 accumulated_length += added_distance;
2044 }
2045
2046 unsigned int glyph_count = uint32_t(e.text.glyph_info.size());
2047 for(unsigned int i = 0; i < glyph_count; i++) {
2048 hb_codepoint_t glyphid = e.text.glyph_info[i].codepoint;
2049 auto gso = f.glyph_positions[glyphid];
2050 float x_advance = float(gso.x_advance);
2051 float x_offset = float(e.text.glyph_info[i].x_offset) / 4.f + float(gso.x);
2052 float y_offset = float(gso.y) - float(e.text.glyph_info[i].y_offset) / 4.f;
2053 if(glyphid != FT_Get_Char_Index(f.font_face, ' ')) {
2054 // Add up baseline and kerning offsets
2055 glm::vec2 glyph_positions{ x_offset / 64.f, -y_offset / 64.f };
2056 auto dpoly_fn = [&](float x) {
2057 // y = a + 1bx^1 + 1cx^2 + 1dx^3
2058 // y = 0 + 1bx^0 + 2cx^1 + 3dx^2
2059 return e.coeff[1] + 2.f * e.coeff[2] * x + 3.f * e.coeff[3] * x * x;
2060 };
2061 glm::vec2 curr_dir = glm::normalize(glm::vec2(effective_ratio, dpoly_fn(x)));
2062 glm::vec2 curr_normal_dir = glm::vec2(-curr_dir.y, curr_dir.x);
2063 curr_dir.x *= 0.5f;
2064 curr_normal_dir.x *= 0.5f;
2065
2066 glm::vec2 shader_direction = glm::normalize(glm::vec2(e.ratio.x, dpoly_fn(x) * e.ratio.y));
2067
2068 auto p0 = glm::vec2(x, poly_fn(x)) * e.ratio + e.basis;
2069 p0 /= glm::vec2(size_x, size_y); // Rescale the coordinate to 0-1
2070 p0 -= (1.5f - 2.f * glyph_positions.y) * curr_normal_dir * real_text_size;
2071 p0 += (1.0f + 2.f * glyph_positions.x) * curr_dir * real_text_size;
2072
2073 float type = float((gso.texture_slot >> 6) % text::max_texture_layers);
2074 float step = 1.f / 8.f;
2075 float tx = float(gso.texture_slot & 7) * step;
2076 float ty = float((gso.texture_slot & 63) >> 3) * step;
2077
2078 province_text_line_vertices.emplace_back(p0, glm::vec2(-1, 1), shader_direction, glm::vec3(tx, ty, type), real_text_size);
2079 province_text_line_vertices.emplace_back(p0, glm::vec2(-1, -1), shader_direction, glm::vec3(tx, ty + step, type), real_text_size);
2080 province_text_line_vertices.emplace_back(p0, glm::vec2(1, -1), shader_direction, glm::vec3(tx + step, ty + step, type), real_text_size);
2081
2082 province_text_line_vertices.emplace_back(p0, glm::vec2(1, -1), shader_direction, glm::vec3(tx + step, ty + step, type), real_text_size);
2083 province_text_line_vertices.emplace_back(p0, glm::vec2(1, 1), shader_direction, glm::vec3(tx + step, ty, type), real_text_size);
2084 province_text_line_vertices.emplace_back(p0, glm::vec2(-1, 1), shader_direction, glm::vec3(tx, ty, type), real_text_size);
2085 }
2086 float glyph_advance = x_advance * size / 64.f;
2087 for(float glyph_length = 0.f; ; x += x_step) {
2088 auto added_distance = 2.0f * glm::length(glm::vec2(x_step * e.ratio.x, (poly_fn(x) - poly_fn(x + x_step)) * e.ratio.y));
2089 if(glyph_length + added_distance >= glyph_advance) {
2090 x += x_step * (glyph_advance - glyph_length) / added_distance;
2091 break;
2092 }
2093 glyph_length += added_distance;
2094 }
2095 }
2096 }
2097 if(province_text_line_vertices.size() > 0) {
2098 glBindBuffer(GL_ARRAY_BUFFER, vbo_array[vo_province_text_line]);
2099 glBufferData(GL_ARRAY_BUFFER, sizeof(text_line_vertex) * province_text_line_vertices.size(), &province_text_line_vertices[0], GL_STATIC_DRAW);
2100 glBindBuffer(GL_ARRAY_BUFFER, 0);
2101 }
2102}
2103
2105 auto file = simple_fs::open_file(dir, file_name);
2106 if(!bool(file)) {
2107 auto full_message = std::string("Can't load DDS file ") + simple_fs::native_to_utf8(file_name) + "\n";
2108#ifdef _WIN64
2109 OutputDebugStringA(full_message.c_str());
2110#else
2111 std::fprintf(stderr, "%s", full_message.c_str());
2112#endif
2113 return 0;
2114 }
2115 auto content = simple_fs::view_contents(*file);
2116 uint32_t size_x, size_y;
2117 uint8_t const* data = (uint8_t const*)(content.data);
2118 return ogl::SOIL_direct_load_DDS_from_memory(data, content.file_size, size_x, size_y, soil_flags);
2119}
2120
2122 for(const auto& layer : mat.layers) {
2123 if(layer.map_type == emfx::xac_pp_material_map_type::diffuse) {
2124 return layer;
2125 }
2126 }
2127 for(const auto& layer : mat.layers) {
2128 if(strstr(layer.texture.c_str(), "spec") == NULL) {
2129 return layer;
2130 }
2131 }
2132 return mat.layers.empty()
2134 : mat.layers[0];
2135}
2136
2138#if 0
2139 struct static_mesh_vertex {
2140 glm::vec3 position_;
2141 glm::vec2 normal_;
2142 glm::vec2 texture_coord_;
2143 };
2144 std::vector<static_mesh_vertex> static_mesh_vertices;
2145 static const std::array<native_string_view, display_data::max_static_meshes> xac_model_names = {
2146 NATIVE("capital_bigben"), //0
2147 NATIVE("capital_eiffeltower"), //1
2148 NATIVE("Panama_Canel"), //2
2149 NATIVE("Kiel_Canal"), //3
2150 NATIVE("Suez_Canal"), //4
2151 NATIVE("trainstation"), //5 -- railroad present
2152 NATIVE("Navalbase_Late_Empty"), //6 -- naval base with no ships
2153 NATIVE("Navalbase_Late_Full"), //7 -- naval base with a docked ship
2154 NATIVE("Fort_Early"), //8 -- fort
2155 NATIVE("factory"), //9 -- factory
2156 NATIVE("Blockade"), //10 -- blockade
2157 NATIVE("generic_euro_infantry"), //11 -- infantry
2158 NATIVE("Generic_Frigate"), //12 -- frigate
2159 NATIVE("Generic_Manowar"), //13 -- manowar
2160 NATIVE("Generic_Transport_Ship"), //14 -- transport ship
2161 NATIVE("Horse"), // 15 -- horse
2162 NATIVE("wake"), // 16 -- ship wake
2163 NATIVE("Infantry_shadowblob"), // 17 -- shadow blob
2164 NATIVE("Generic_Euro_Infantry2"), // 18 -- artillery
2165 NATIVE("buildings_01_1"), // 19 -- housing
2166 NATIVE("buildings_01_2"), // 20
2167 NATIVE("buildings_01_3"), // 21
2168 NATIVE("buildings_02_1"), // 22
2169 NATIVE("buildings_02_2"), // 23
2170 NATIVE("buildings_02_3"), // 24
2171 NATIVE("buildings_03_1"), // 25
2172 NATIVE("buildings_03_2"), // 26
2173 NATIVE("buildings_03_3"), // 27
2174 NATIVE("Fort_Mid2"), //28 -- fort
2175 NATIVE("Fort_Late"), //29 -- fort
2176 NATIVE("Navalbase_Early_Empty"), //30 -- naval base with no ships
2177 NATIVE("Navalbase_Early_Full"), //31 -- naval base with a docked ship
2178 NATIVE("Navalbase_Mid_Empty"), //32 -- naval base with no ships
2179 NATIVE("Navalbase_Mid_Full"), //33 -- naval base with a docked ship
2180 NATIVE("Generic_Battleship"), //34 -- battleship
2181 NATIVE("Generic_Cruiser"), //35 -- cruiser
2182 NATIVE("Generic_Ironclad"), //36 -- ironclad
2183 NATIVE("Generic_Raider"), //37 -- raider
2184 NATIVE("floating_flag"), //38 -- floating flag
2185 NATIVE("flag"), //39 -- flag
2186 };
2187 static const std::array<float, display_data::max_static_meshes> scaling_factor = {
2188 1.f, //0
2189 1.f, //1
2190 1.f, //2
2191 1.f, //3
2192 1.f, //4
2193 1.f, //5
2194 1.f, //6
2195 1.f, //7
2196 1.f, //8
2197 0.75f, //9
2198 1.5f, //10
2199 1.4f, //11
2200 2.4f, //12
2201 0.8f, //13
2202 1.5f, //14
2203 1.5f, //15
2204 1.f, //16
2205 1.f, //17
2206 0.7f, //18 -- housing
2207 0.7f, //19
2208 0.7f, //20
2209 0.68f, //21
2210 0.68f, //22
2211 0.68f, //23
2212 0.66f, //24
2213 0.66f, //25
2214 0.66f, //26
2215 1.0f, //27
2216 1.0f, //28
2217 1.0f, //29
2218 1.0f, //30
2219 1.0f, //31
2220 1.0f, //32
2221 1.0f, //33
2222 1.0f, //34
2223 1.0f, //35
2224 1.0f, //36
2225 1.0f, //37
2226 1.0f, //38
2227 1.0f, //39
2228 1.0f, //40
2229 1.0f, //41
2230 };
2231 constexpr float no_elim = 9999.f + 0.1f;
2232 constexpr float quad_elim = 9999.f + 0.2f;
2233 static const std::array<float, display_data::max_static_meshes> elim_factor = {
2234 -0.1f, //0
2235 no_elim, //1
2236 no_elim, //2
2237 no_elim, //3
2238 -0.1f, //4
2239 quad_elim, //5
2240 -0.1f, //6
2241 -0.1f, //7
2242 -0.1f, //8
2243 quad_elim, //9
2244 -0.1f, //10
2245 -0.1f, //11
2246 -0.1f, //12
2247 -0.1f, //13
2248 -0.1f, //14
2249 no_elim, //15
2250 -0.1f, //16
2251 -0.1f, //17
2252 -0.1f, //18 -- housing
2253 -0.1f, //19
2254 -0.1f, //20
2255 -0.1f, //21
2256 -0.1f, //22
2257 -0.1f, //23
2258 -0.1f, //24
2259 -0.1f, //25
2260 -0.1f, //26
2261 -0.1f, //27
2262 -0.1f, //28
2263 -0.1f, //29
2264 -0.1f, //30
2265 -0.1f, //31
2266 -0.1f, //32
2267 -0.1f, //33
2268 -0.1f, //34
2269 -0.1f, //35
2270 no_elim, //36
2271 -0.1f, //37
2272 -0.1f, //38
2273 -0.1f, //39
2274 -0.1f, //40
2275 -0.1f, //41
2276 };
2277 auto root = simple_fs::get_root(state.common_fs);
2278 auto gfx_anims = simple_fs::open_directory(root, NATIVE("gfx/anims"));
2279
2280 state.map_state.map_data.static_mesh_counts.resize(display_data::max_static_meshes);
2281 state.map_state.map_data.static_mesh_starts.resize(display_data::max_static_meshes);
2282 for(uint32_t k = 0; k < display_data::max_static_meshes; k++) {
2283 auto old_size = static_mesh_vertices.size();
2284 auto f = simple_fs::open_file(gfx_anims, native_string(xac_model_names[k]) + NATIVE(".xac"));
2285 if(f) {
2287 auto contents = simple_fs::view_contents(*f);
2288 emfx::xac_context context{};
2289 emfx::parse_xac(context, contents.data, contents.data + contents.file_size, err);
2290 emfx::finish(context);
2291
2292 auto& texid = state.map_state.map_data.static_mesh_textures[k];
2293 for(auto const& node : context.nodes) {
2294 int32_t mesh_index = 0;
2295 for(auto const& mesh : node.meshes) {
2296 bool is_collision = node.collision_mesh == mesh_index;
2297 bool is_visual = node.visual_mesh == mesh_index;
2298
2299 uint32_t vertex_offset = 0;
2300 for(auto const& sub : mesh.submeshes) {
2301 for(uint32_t i = 0; i < uint32_t(sub.indices.size()); i += 3) {
2302 static_mesh_vertex triangle_vertices[3];
2303 for(uint32_t j = 0; j < 3; j++) {
2304 static_mesh_vertex smv;
2305 auto index = sub.indices[i + j] + vertex_offset;
2306 auto vv = mesh.vertices[index % mesh.vertices.size()];
2307 auto vn = mesh.normals.empty()
2308 ? emfx::xac_vector3f{ vv.x, vv.y, vv.z }
2309 : mesh.normals[index % mesh.normals.size()];
2310 auto vt = mesh.texcoords.empty()
2311 ? emfx::xac_vector2f{ vv.x, vv.y }
2312 : mesh.texcoords[index % mesh.texcoords.size()];
2313 smv.position_ = glm::vec3(vv.x, vv.y, vv.z);
2314 smv.normal_ = glm::vec3(vn.x, vn.y, vn.z);
2315 smv.texture_coord_ = glm::vec2(vt.x, vt.y);
2316 triangle_vertices[j] = smv;
2317 }
2318 // Clip standing planes (some models have flat planes
2319 // beneath them)
2320 bool keep = is_visual;
2321 if(elim_factor[k] == no_elim) {
2322 if(is_visual) {
2323 for(const auto& smv : triangle_vertices) {
2324 static_mesh_vertex tmp = smv;
2325 tmp.position_ *= scaling_factor[k];
2326 static_mesh_vertices.push_back(tmp);
2327 }
2328 }
2329 } else if(elim_factor[k] == quad_elim) {
2330 if(triangle_vertices[0].position_.y <= -0.1f
2331 || triangle_vertices[1].position_.y <= -0.1f
2332 || triangle_vertices[2].position_.y <= -0.1f) {
2333 for(const auto& smv : triangle_vertices) {
2334 static_mesh_vertex tmp = smv;
2335 tmp.position_ *= scaling_factor[k];
2336 static_mesh_vertices.push_back(tmp);
2337 }
2338 }
2339 } else {
2340 if(triangle_vertices[0].position_.y <= elim_factor[k]
2341 && triangle_vertices[1].position_.y <= elim_factor[k]
2342 && triangle_vertices[2].position_.y <= elim_factor[k]) {
2343 for(const auto& smv : triangle_vertices) {
2344 static_mesh_vertex tmp = smv;
2345 tmp.position_ *= scaling_factor[k];
2346 static_mesh_vertices.push_back(tmp);
2347 }
2348 }
2349 }
2350 }
2351 vertex_offset += sub.num_vertices;
2352 // This is how most models fallback to find their textures...
2353 if(!texid) {
2354 auto const& mat = context.materials[sub.material_id];
2355 auto const& layer = get_diffuse_layer(mat);
2356 if(layer.texture.empty()) {
2357 texid = load_dds_texture(gfx_anims, native_string(xac_model_names[k]) + NATIVE("Diffuse.dds"), 0);
2358 if(!texid) {
2359 texid = load_dds_texture(gfx_anims, native_string(xac_model_names[k]) + NATIVE("_Diffuse.dds"), 0);
2360 if(!texid) {
2361 texid = load_dds_texture(gfx_anims, native_string(xac_model_names[k]) + NATIVE(".dds"), 0);
2362 }
2363 }
2364 } else {
2365 texid = load_dds_texture(gfx_anims, simple_fs::utf8_to_native(layer.texture + "Diffuse.dds"), 0);
2366 if(!texid) {
2367 texid = load_dds_texture(gfx_anims, simple_fs::utf8_to_native(layer.texture + "_Diffuse.dds"), 0);
2368 if(!texid) {
2369 texid = load_dds_texture(gfx_anims, simple_fs::utf8_to_native(layer.texture + ".dds"), 0);
2370 }
2371 }
2372 }
2373 }
2374 }
2375 mesh_index++;
2376 }
2377 }
2378
2379 state.map_state.map_data.static_mesh_starts[k] = GLint(old_size);
2380 state.map_state.map_data.static_mesh_counts[k] = GLsizei(static_mesh_vertices.size() - old_size);
2381 } else {
2382 state.map_state.map_data.static_mesh_starts[k] = GLint(old_size);
2383 state.map_state.map_data.static_mesh_counts[k] = GLsizei(0);
2384 }
2385 }
2386
2387 if(!static_mesh_vertices.empty()) {
2388 glBindBuffer(GL_ARRAY_BUFFER, state.map_state.map_data.vbo_array[state.map_state.map_data.vo_static_mesh]);
2389 glBufferData(GL_ARRAY_BUFFER, sizeof(static_mesh_vertex) * static_mesh_vertices.size(), &static_mesh_vertices[0], GL_STATIC_DRAW);
2390 }
2391 glBindVertexArray(state.map_state.map_data.vao_array[state.map_state.map_data.vo_static_mesh]);
2392 glBindVertexBuffer(0, state.map_state.map_data.vbo_array[state.map_state.map_data.vo_static_mesh], 0, sizeof(static_mesh_vertex)); // Bind the VBO to 0 of the VAO
2393 glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, offsetof(static_mesh_vertex, position_)); // Set up vertex attribute format for the position
2394 glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, offsetof(static_mesh_vertex, normal_)); // Set up vertex attribute format for the normal direction
2395 glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, offsetof(static_mesh_vertex, texture_coord_)); // Set up vertex attribute format for the texture coordinates
2396 glEnableVertexAttribArray(0);
2397 glEnableVertexAttribArray(1);
2398 glEnableVertexAttribArray(2);
2399 glVertexAttribBinding(0, 0);
2400 glVertexAttribBinding(1, 0);
2401 glVertexAttribBinding(2, 0);
2402 glBindVertexArray(0);
2403#endif
2404}
2405
2407 auto root = simple_fs::get_root(state.common_fs);
2408 glGenVertexArrays(vo_count, vao_array);
2409 glGenBuffers(vo_count, vbo_array);
2410 load_shaders(root);
2411 load_static_meshes(state);
2412 create_meshes();
2413
2414 auto assets_dir = simple_fs::open_directory(root, NATIVE("assets"));
2415 auto map_dir = simple_fs::open_directory(root, NATIVE("map"));
2416 auto map_terrain_dir = simple_fs::open_directory(map_dir, NATIVE("terrain"));
2417 auto map_items_dir = simple_fs::open_directory(root, NATIVE("gfx/mapitems"));
2418 auto gfx_anims_dir = simple_fs::open_directory(root, NATIVE("gfx/anims"));
2419
2420 glGenTextures(1, &textures[texture_diag_border_identifier]);
2422 glBindTexture(GL_TEXTURE_2D, textures[texture_diag_border_identifier]);
2423 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8UI, size_x, size_y);
2424 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_x, size_y, GL_RED_INTEGER, GL_UNSIGNED_BYTE, diagonal_borders.data());
2425 glBindTexture(GL_TEXTURE_2D, 0);
2426 }
2427 ogl::set_gltex_parameters(textures[texture_diag_border_identifier], GL_TEXTURE_2D, GL_NEAREST, GL_CLAMP_TO_EDGE);
2428
2430 ogl::set_gltex_parameters(textures[texture_terrain], GL_TEXTURE_2D, GL_NEAREST, GL_CLAMP_TO_EDGE);
2431
2433 auto texturesheet = open_file(map_terrain_dir, NATIVE("texturesheet.tga"));
2434 if(!texturesheet)
2435 texturesheet = open_file(map_terrain_dir, NATIVE("texturesheet.dds"));
2436
2438
2439 textures[texture_water_normal] = load_dds_texture(map_terrain_dir, NATIVE("sea_normal.dds"));
2440 textures[texture_colormap_water] = load_dds_texture(map_terrain_dir, NATIVE("colormap_water.dds"));
2441 textures[texture_colormap_terrain] = load_dds_texture(map_terrain_dir, NATIVE("colormap.dds"));
2442 textures[texture_colormap_political] = load_dds_texture(map_terrain_dir, NATIVE("colormap_political.dds"));
2443 textures[texture_overlay] = load_dds_texture(map_terrain_dir, NATIVE("map_overlay_tile.dds"));
2444 textures[texture_stripes] = load_dds_texture(map_terrain_dir, NATIVE("stripes.dds"));
2445
2446 textures[texture_river_body] = load_dds_texture(assets_dir, NATIVE("river.dds"));
2447 ogl::set_gltex_parameters(textures[texture_river_body], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2448
2449 textures[texture_national_border] = load_dds_texture(assets_dir, NATIVE("nat_border.dds"));
2450 ogl::set_gltex_parameters(textures[texture_national_border], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2451
2452 textures[texture_state_border] = load_dds_texture(assets_dir, NATIVE("state_border.dds"));
2453 ogl::set_gltex_parameters(textures[texture_state_border], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2454
2455 textures[texture_prov_border] = load_dds_texture(assets_dir, NATIVE("prov_border.dds"));
2456 ogl::set_gltex_parameters(textures[texture_prov_border], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2457
2458 textures[texture_imp_border] = load_dds_texture(assets_dir, NATIVE("imp_border.dds"));
2459 ogl::set_gltex_parameters(textures[texture_imp_border], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2460
2461 textures[texture_coastal_border] = load_dds_texture(assets_dir, NATIVE("coastborder.dds"));
2462 ogl::set_gltex_parameters(textures[texture_coastal_border], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2463
2464 textures[texture_railroad] = load_dds_texture(gfx_anims_dir, NATIVE("railroad.dds"));
2465 ogl::set_gltex_parameters(textures[texture_railroad], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2466
2467 textures[texture_unit_arrow] = ogl::make_gl_texture(map_items_dir, NATIVE("movearrow.tga"));
2468 ogl::set_gltex_parameters(textures[texture_unit_arrow], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
2469
2470 textures[texture_attack_unit_arrow] = ogl::make_gl_texture(map_items_dir, NATIVE("attackarrow.tga"));
2471 ogl::set_gltex_parameters(textures[texture_attack_unit_arrow], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
2472
2473 textures[texture_retreat_unit_arrow] = ogl::make_gl_texture(map_items_dir, NATIVE("retreatarrow.tga"));
2474 ogl::set_gltex_parameters(textures[texture_retreat_unit_arrow], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
2475
2476 textures[texture_strategy_unit_arrow] = ogl::make_gl_texture(map_items_dir, NATIVE("stratarrow.tga"));
2477 ogl::set_gltex_parameters(textures[texture_strategy_unit_arrow], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
2478
2479 textures[texture_objective_unit_arrow] = ogl::make_gl_texture(map_items_dir, NATIVE("objectivearrow.tga"));
2480 ogl::set_gltex_parameters(textures[texture_objective_unit_arrow], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
2481
2482 textures[texture_other_objective_unit_arrow] = ogl::make_gl_texture(map_items_dir, NATIVE("otherobjectivearrow.tga"));
2483 ogl::set_gltex_parameters(textures[texture_other_objective_unit_arrow], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP_TO_EDGE);
2484
2485 textures[texture_hover_border] = load_dds_texture(assets_dir, NATIVE("hover_border.dds"));
2486 ogl::set_gltex_parameters(textures[texture_imp_border], GL_TEXTURE_2D, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT);
2487
2488 // Get the province_color handle
2489 // province_color is an array of 2 textures, one for province and the other for stripes
2490 glGenTextures(1, &texture_arrays[texture_array_province_color]);
2491 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays[texture_array_province_color]);
2492 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 256, 256, 2);
2493 ogl::set_gltex_parameters(texture_arrays[texture_array_province_color], GL_TEXTURE_2D_ARRAY, GL_NEAREST, GL_CLAMP_TO_EDGE);
2494
2495 // Get the province_highlight handle
2496 glGenTextures(1, &textures[texture_province_highlight]);
2497 glBindTexture(GL_TEXTURE_2D, textures[texture_province_highlight]);
2498 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
2499 ogl::set_gltex_parameters(textures[texture_province_highlight], GL_TEXTURE_2D, GL_NEAREST, GL_CLAMP_TO_EDGE);
2500
2501 // Get the province_fow handle
2502 glGenTextures(1, &textures[texture_province_fow]);
2503 glBindTexture(GL_TEXTURE_2D, textures[texture_province_fow]);
2504 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
2505 ogl::set_gltex_parameters(textures[texture_province_fow], GL_TEXTURE_2D, GL_NEAREST, GL_CLAMP_TO_EDGE);
2506
2507 // set up sea texture:
2508 glGenTextures(1, &textures[texture_sea_mask]);
2509 glBindTexture(GL_TEXTURE_2D, textures[texture_sea_mask]);
2510 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
2511 ogl::set_gltex_parameters(textures[texture_sea_mask], GL_TEXTURE_2D, GL_NEAREST, GL_CLAMP_TO_EDGE);
2512 province_id_sea_mask.resize(state.world.province_size() + 1);
2513 for(auto p : state.world.in_province) {
2514 if(p.id.index() >= state.province_definitions.first_sea_province.index()) {
2516 } else {
2518 }
2519 }
2521
2522
2523 glBindTexture(GL_TEXTURE_2D, 0);
2524
2525 uint32_t province_size = state.world.province_size() + 1;
2526 province_size += 256 - province_size % 256;
2527
2528 std::vector<uint32_t> test_highlight(province_size);
2530 for(uint32_t i = 0; i < test_highlight.size(); ++i) {
2531 test_highlight[i] = 255;
2532 }
2533 std::vector<uint32_t> test_color(province_size * 4);
2534 for(uint32_t i = 0; i < test_color.size(); ++i) {
2535 test_color[i] = 255;
2536 }
2537 set_province_color(test_color);
2538}
2539
2540} // namespace map
std::vector< textured_line_with_width_vertex > river_vertices
Definition: map.hpp:116
static constexpr uint32_t texture_diag_border_identifier
Definition: map.hpp:209
static constexpr uint32_t uniform_texture_sampler
Definition: map.hpp:264
void update_railroad_paths(sys::state &state)
Definition: map.cpp:1707
static constexpr uint32_t uniform_colormap_water
Definition: map.hpp:252
static constexpr uint32_t shader_textured_line
Definition: map.hpp:228
static constexpr uint32_t texture_strategy_unit_arrow
Definition: map.hpp:213
std::vector< GLsizei > river_counts
Definition: map.hpp:118
void load_shaders(simple_fs::directory &root)
Definition: map.cpp:375
static constexpr uint32_t texture_array_province_color
Definition: map.hpp:222
GLuint texture_arrays[texture_array_count]
Definition: map.hpp:224
static constexpr uint32_t uniform_rotation
Definition: map.hpp:243
static constexpr uint32_t uniform_overlay
Definition: map.hpp:254
static constexpr uint32_t texture_sea_mask
Definition: map.hpp:217
static constexpr uint32_t vo_coastal
Definition: map.hpp:179
std::vector< GLsizei > coastal_counts
Definition: map.hpp:124
void update_fog_of_war(sys::state &state)
Definition: map.cpp:72
GLuint vao_array[vo_count]
Definition: map.hpp:189
static constexpr uint32_t uniform_water_normal
Definition: map.hpp:251
static constexpr uint32_t uniform_stripes_texture
Definition: map.hpp:258
static constexpr uint32_t texture_colormap_water
Definition: map.hpp:195
static constexpr uint32_t texture_coastal_border
Definition: map.hpp:208
std::vector< GLint > coastal_starts
Definition: map.hpp:123
std::vector< text_line_vertex > province_text_line_vertices
Definition: map.hpp:154
std::vector< GLsizei > static_mesh_counts
Definition: map.hpp:126
std::vector< curved_line_vertex > retreat_unit_arrow_vertices
Definition: map.hpp:136
static constexpr uint32_t shader_map_standing_object
Definition: map.hpp:234
void load_map(sys::state &state)
Definition: map.cpp:2406
void set_selected_province(sys::state &state, dcon::province_id province_id)
Definition: map.cpp:1253
static constexpr uint32_t shader_count
Definition: map.hpp:236
std::vector< GLuint > text_line_texture_per_quad
Definition: map.hpp:152
static constexpr uint32_t shader_text_line
Definition: map.hpp:230
std::vector< text_line_vertex > text_line_vertices
Definition: map.hpp:153
static constexpr uint32_t uniform_diag_border_identifier
Definition: map.hpp:260
static constexpr uint32_t texture_imp_border
Definition: map.hpp:205
static constexpr uint32_t vo_count
Definition: map.hpp:188
static constexpr uint32_t texture_province_fow
Definition: map.hpp:207
static constexpr uint32_t uniform_provinces_sea_mask
Definition: map.hpp:272
std::vector< GLsizei > strategy_unit_arrow_counts
Definition: map.hpp:142
static constexpr uint32_t uniform_opaque
Definition: map.hpp:265
static constexpr uint32_t texture_national_border
Definition: map.hpp:202
static constexpr uint32_t vo_land
Definition: map.hpp:173
static constexpr uint32_t vo_objective_unit_arrow
Definition: map.hpp:186
static constexpr uint32_t texture_hover_border
Definition: map.hpp:216
static constexpr uint32_t uniform_border_width
Definition: map.hpp:267
std::vector< border > borders
Definition: map.hpp:114
static constexpr uint32_t shader_line_unit_arrow
Definition: map.hpp:229
static constexpr uint32_t vo_province_text_line
Definition: map.hpp:182
std::vector< curved_line_vertex > attack_unit_arrow_vertices
Definition: map.hpp:132
static constexpr uint32_t vo_unit_arrow
Definition: map.hpp:176
std::vector< GLint > objective_unit_arrow_starts
Definition: map.hpp:145
static constexpr uint32_t shader_railroad_line
Definition: map.hpp:233
std::vector< GLint > river_starts
Definition: map.hpp:117
static constexpr uint32_t uniform_province_highlight
Definition: map.hpp:257
static constexpr uint32_t texture_unit_arrow
Definition: map.hpp:206
void set_province_text_lines(sys::state &state, std::vector< text_line_generator_data > const &data)
Definition: map.cpp:2006
std::vector< uint16_t > province_id_map
Definition: map.hpp:162
static constexpr uint32_t uniform_province_color
Definition: map.hpp:255
std::vector< uint8_t > diagonal_borders
Definition: map.hpp:159
void gen_prov_color_texture(GLuint texture_handle, std::vector< uint32_t > const &prov_color, uint8_t layers=1)
Definition: map.cpp:1216
std::vector< textured_line_vertex_b > border_vertices
Definition: map.hpp:115
std::vector< curved_line_vertex > other_objective_unit_arrow_vertices
Definition: map.hpp:148
std::vector< GLint > static_mesh_starts
Definition: map.hpp:125
static constexpr uint32_t texture_prov_border
Definition: map.hpp:204
std::vector< GLsizei > other_objective_unit_arrow_counts
Definition: map.hpp:150
static constexpr uint32_t texture_terrain
Definition: map.hpp:193
GLuint static_mesh_textures[max_static_meshes]
Definition: map.hpp:278
std::vector< uint16_t > map_indices
Definition: map.hpp:163
static constexpr uint32_t vo_drag_box
Definition: map.hpp:178
static constexpr uint32_t vo_border
Definition: map.hpp:174
static constexpr uint32_t texture_overlay
Definition: map.hpp:198
std::vector< curved_line_vertex > unit_arrow_vertices
Definition: map.hpp:128
std::vector< GLsizei > retreat_unit_arrow_counts
Definition: map.hpp:138
std::vector< curved_line_vertex > strategy_unit_arrow_vertices
Definition: map.hpp:140
static constexpr uint32_t uniform_colormap_terrain
Definition: map.hpp:253
static constexpr uint32_t uniform_aspect_ratio
Definition: map.hpp:240
void update_borders(sys::state &state)
Definition: map.cpp:59
static constexpr uint32_t uniform_time
Definition: map.hpp:246
std::vector< textured_line_vertex_b > coastal_vertices
Definition: map.hpp:122
static constexpr uint32_t uniform_province_fow
Definition: map.hpp:259
static constexpr uint32_t uniform_offset
Definition: map.hpp:239
static constexpr uint32_t vo_attack_unit_arrow
Definition: map.hpp:183
void create_meshes()
Definition: map.cpp:262
static constexpr uint32_t uniform_terrain_texture_sampler
Definition: map.hpp:249
static constexpr uint32_t vo_other_objective_unit_arrow
Definition: map.hpp:187
std::vector< GLint > retreat_unit_arrow_starts
Definition: map.hpp:137
static constexpr uint32_t uniform_zoom
Definition: map.hpp:241
static constexpr uint32_t texture_array_terrainsheet
Definition: map.hpp:221
std::vector< uint8_t > terrain_id_map
Definition: map.hpp:156
static constexpr uint32_t texture_stripes
Definition: map.hpp:200
static constexpr uint32_t uniform_width
Definition: map.hpp:261
std::vector< GLsizei > objective_unit_arrow_counts
Definition: map.hpp:146
static constexpr uint32_t texture_retreat_unit_arrow
Definition: map.hpp:212
static constexpr uint32_t uniform_is_black
Definition: map.hpp:266
static constexpr uint32_t uniform_subroutines_index_2
Definition: map.hpp:262
static constexpr uint32_t max_static_meshes
Definition: map.hpp:277
GLuint shader_uniforms[shader_count][uniform_count]
Definition: map.hpp:274
static constexpr uint32_t uniform_target_topview_fixup
Definition: map.hpp:271
static constexpr uint32_t texture_provinces
Definition: map.hpp:192
static constexpr uint32_t vo_static_mesh
Definition: map.hpp:181
static constexpr uint32_t uniform_map_size
Definition: map.hpp:242
static constexpr uint32_t texture_railroad
Definition: map.hpp:210
GLuint shaders[shader_count]
Definition: map.hpp:237
static constexpr uint32_t vo_railroad
Definition: map.hpp:180
static constexpr uint32_t texture_water_normal
Definition: map.hpp:194
std::vector< GLint > attack_unit_arrow_starts
Definition: map.hpp:133
std::vector< GLsizei > unit_arrow_counts
Definition: map.hpp:130
static constexpr uint32_t texture_other_objective_unit_arrow
Definition: map.hpp:215
static constexpr uint32_t uniform_target_facing
Definition: map.hpp:270
static constexpr uint32_t shader_borders
Definition: map.hpp:232
void render(sys::state &state, glm::vec2 screen_size, glm::vec2 offset, float zoom, map_view map_view_mode, map_mode::mode active_map_mode, glm::mat3 globe_rotation, float time_counter)
Definition: map.cpp:449
static constexpr uint32_t uniform_line_texture
Definition: map.hpp:263
static constexpr uint32_t texture_objective_unit_arrow
Definition: map.hpp:214
static constexpr uint32_t vo_retreat_unit_arrow
Definition: map.hpp:184
void set_text_lines(sys::state &state, std::vector< text_line_generator_data > const &data)
Definition: map.cpp:1817
static constexpr uint32_t uniform_gamma
Definition: map.hpp:244
uint32_t size_y
Definition: map.hpp:169
void create_border_ogl_objects()
Definition: map.cpp:258
static constexpr uint32_t vo_strategy_unit_arrow
Definition: map.hpp:185
static constexpr uint32_t uniform_model_offset
Definition: map.hpp:269
static constexpr uint32_t texture_attack_unit_arrow
Definition: map.hpp:211
static constexpr uint32_t texture_province_highlight
Definition: map.hpp:199
uint32_t land_vertex_count
Definition: map.hpp:170
GLuint vbo_array[vo_count]
Definition: map.hpp:190
std::vector< GLint > railroad_starts
Definition: map.hpp:120
uint32_t size_x
Definition: map.hpp:168
std::vector< GLsizei > attack_unit_arrow_counts
Definition: map.hpp:134
std::vector< GLint > strategy_unit_arrow_starts
Definition: map.hpp:141
std::vector< GLint > unit_arrow_starts
Definition: map.hpp:129
static constexpr uint32_t texture_river_body
Definition: map.hpp:201
static constexpr uint32_t uniform_subroutines_index
Definition: map.hpp:245
std::vector< GLint > other_objective_unit_arrow_starts
Definition: map.hpp:149
static constexpr uint32_t shader_drag_box
Definition: map.hpp:231
static constexpr uint32_t uniform_colormap_political
Definition: map.hpp:256
void set_drag_box(bool draw_box, glm::vec2 pos1, glm::vec2 pos2, glm::vec2 pixel_size)
Definition: map.cpp:1282
static constexpr uint32_t uniform_provinces_texture_sampler
Definition: map.hpp:248
static constexpr uint32_t texture_count
Definition: map.hpp:218
std::vector< screen_vertex > drag_box_vertices
Definition: map.hpp:155
static constexpr uint32_t vo_river
Definition: map.hpp:175
GLuint textures[texture_count]
Definition: map.hpp:219
std::vector< uint32_t > province_id_sea_mask
Definition: map.hpp:166
static constexpr uint32_t vo_text_line
Definition: map.hpp:177
static constexpr uint32_t texture_colormap_terrain
Definition: map.hpp:196
std::vector< GLsizei > railroad_counts
Definition: map.hpp:121
std::vector< curved_line_vertex > objective_unit_arrow_vertices
Definition: map.hpp:144
void set_province_color(std::vector< uint32_t > const &prov_color)
Definition: map.cpp:1259
static constexpr uint32_t shader_textured_line_with_variable_width
Definition: map.hpp:235
static constexpr uint32_t uniform_terrainsheet_texture_sampler
Definition: map.hpp:250
static constexpr uint32_t texture_colormap_political
Definition: map.hpp:197
static constexpr uint32_t texture_state_border
Definition: map.hpp:203
std::vector< textured_line_vertex > railroad_vertices
Definition: map.hpp:119
static constexpr uint32_t uniform_unit_arrow
Definition: map.hpp:268
static constexpr uint32_t shader_terrain
Definition: map.hpp:226
#define assert(condition)
Definition: debug.h:74
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
constexpr dcon::demographics_key total(0)
glm::vec2 get_navy_location(sys::state &state, dcon::province_id prov_id)
Definition: map.cpp:45
bool is_sea_province(sys::state &state, dcon::province_id prov_id)
Definition: map.cpp:41
glm::vec2 get_army_location(sys::state &state, dcon::province_id prov_id)
Definition: map.cpp:52
glm::vec2 get_port_location(sys::state &state, dcon::province_id p)
Definition: map.cpp:25
void parse_xac(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:579
void finish(xac_context &context)
Definition: xac.cpp:670
constexpr float zoom_close
Definition: constants.hpp:605
glm::vec2 put_in_local(glm::vec2 new_point, glm::vec2 base_point, float size_x)
Definition: map.cpp:1561
void create_railroad_connection(sys::state &state, std::vector< glm::vec2 > &railroad, dcon::province_id p1, dcon::province_id p2)
Definition: map.cpp:1659
GLuint create_program(simple_fs::file &vshader_file, simple_fs::file &fshader_file)
Definition: map.cpp:367
void make_army_path(sys::state &state, std::vector< map::curved_line_vertex > &buffer, dcon::army_id selected_army, float size_x, float size_y)
Definition: map.cpp:1616
GLuint load_dds_texture(simple_fs::directory const &dir, native_string_view file_name, int soil_flags=ogl::SOIL_FLAG_TEXTURE_REPEATS)
Definition: map.cpp:2104
void load_static_meshes(sys::state &state)
Definition: map.cpp:2137
std::optional< simple_fs::file > try_load_shader(simple_fs::directory &root, native_string_view name)
Definition: map.cpp:360
emfx::xac_pp_actor_material_layer get_diffuse_layer(emfx::xac_pp_actor_material const &mat)
Definition: map.cpp:2121
map_view
Definition: map_state.hpp:17
void add_bezier_to_buffer(std::vector< map::curved_line_vertex > &buffer, glm::vec2 start, glm::vec2 end, glm::vec2 start_per, glm::vec2 end_per, float progress, bool last_curve, float size_x, float size_y, uint32_t num_b_segments)
Definition: map.cpp:1359
void create_unit_arrow_vbo(GLuint vbo, std::vector< curved_line_vertex > &data)
Definition: map.cpp:190
bool get_provinces_part_of_rr_path(sys::state &state, std::vector< bool > &visited_adj, std::vector< bool > &visited_prov, std::vector< dcon::province_id > &provinces, dcon::province_id p)
Definition: map.cpp:1671
void create_drag_box_vbo(GLuint vbo)
Definition: map.cpp:247
void add_nation_visible_provinces(sys::state &state, std::vector< dcon::province_id > &list, dcon::nation_id n)
Definition: map.cpp:63
constexpr uint32_t default_num_b_segments
Definition: map.cpp:1356
constexpr float control_point_length_factor
Definition: map.cpp:1357
void make_navy_path(sys::state &state, std::vector< map::curved_line_vertex > &buffer, dcon::navy_id selected_navy, float size_x, float size_y)
Definition: map.cpp:1572
void create_text_line_vbo(GLuint vbo)
Definition: map.cpp:219
constexpr float zoom_very_close
Definition: constants.hpp:606
void create_textured_line_b_vbo(GLuint vbo, std::vector< textured_line_vertex_b > &data)
Definition: map.cpp:166
void create_textured_line_vbo(GLuint vbo, std::vector< textured_line_vertex > &data)
Definition: map.cpp:112
void add_tl_segment_buffer(std::vector< map::textured_line_vertex > &buffer, glm::vec2 start, glm::vec2 end, glm::vec2 next_normal_dir, float size_x, float size_y, float &distance)
Definition: map.cpp:1434
void add_arrow_to_buffer(std::vector< map::curved_line_vertex > &buffer, glm::vec2 start, glm::vec2 end, glm::vec2 prev_normal_dir, glm::vec2 next_normal_dir, float fill_progress, bool end_arrow, float size_x, float size_y)
Definition: map.cpp:1307
GLuint load_province_map(std::vector< uint16_t > &province_index, uint32_t size_x, uint32_t size_y)
Definition: map.cpp:1201
void add_drag_box_line(std::vector< screen_vertex > &drag_box_vertices, glm::vec2 pos1, glm::vec2 pos2, glm::vec2 size, bool vertical)
Definition: map.cpp:1263
void add_tl_bezier_to_buffer(std::vector< map::textured_line_vertex > &buffer, glm::vec2 start, glm::vec2 end, glm::vec2 start_per, glm::vec2 end_per, float progress, bool last_curve, float size_x, float size_y, uint32_t num_b_segments, float &distance)
Definition: map.cpp:1453
float fractional_distance_covered(sys::state &state, dcon::army_id a)
Definition: military.cpp:6395
bool province_is_blockaded(sys::state const &state, dcon::province_id ids)
Definition: military.cpp:422
GLuint make_gl_texture(uint8_t *data, uint32_t size_x, uint32_t size_y, uint32_t channels)
bool msaa_enabled(sys::state const &state)
GLuint load_texture_array_from_file(simple_fs::file &file, int32_t tiles_x, int32_t tiles_y)
void set_gltex_parameters(GLuint texture_handle, GLuint texture_type, GLuint filter, GLuint wrap)
GLuint create_program(std::string_view vertex_shader, std::string_view fragment_shader)
GLuint SOIL_direct_load_DDS_from_memory(unsigned char const *const buffer, uint32_t buffer_length, uint32_t &width, uint32_t &height, int soil_flags)
Definition: texture.cpp:100
@ SOIL_FLAG_TEXTURE_REPEATS
Definition: texture.hpp:20
void notify_user_of_fatal_opengl_error(std::string message)
constexpr uint8_t impassible_bit
Definition: constants.hpp:595
constexpr uint8_t non_adjacent_bit
Definition: constants.hpp:596
constexpr uint8_t state_bit
Definition: constants.hpp:592
constexpr uint8_t national_bit
Definition: constants.hpp:593
constexpr uint8_t coastal_bit
Definition: constants.hpp:594
constexpr dcon::province_id from_map_id(uint16_t id)
Definition: province.hpp:13
float state_admin_efficiency(sys::state &state, dcon::state_instance_id id)
Definition: province.cpp:503
constexpr uint16_t to_map_id(dcon::province_id id)
Definition: province.hpp:10
uint32_t reduce(uint32_t value_in, uint32_t upper_bound)
Definition: prng.cpp:46
uint64_t get_random(sys::state const &state, uint32_t value_in)
Definition: prng.cpp:8
directory open_directory(directory const &dir, native_string_view directory_name)
native_string utf8_to_native(std::string_view data_in)
directory get_root(file_system const &fs)
native_string get_full_name(directory const &f)
std::optional< file > open_file(directory const &dir, native_string_view file_name)
std::string native_to_utf8(native_string_view data_in)
file_contents view_contents(file const &f)
constexpr int magnification_factor
Definition: fonts.hpp:17
constexpr uint32_t max_texture_layers
Definition: fonts.hpp:16
#define NATIVE(X)
std::string_view native_string_view
std::string native_string
uint uint32_t
uchar uint8_t
std::vector< xac_pp_actor_material_layer > layers
Definition: xac.hpp:106