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