46d21264adfbb7318491ca00fc4042058bf78ed6
[tar-legacy.git] / MCDV / main.cpp
1 #include "globals.h"
2
3 // STDLib
4 #include <iostream>
5
6 // OPENGL related
7 #include <glad\glad.h>
8 #include <GLFW\glfw3.h>
9 #include <glm\glm.hpp>
10 #include "GLFWUtil.hpp"
11
12 // Engine header files
13 #include "Shader.hpp"
14 #include "Texture.hpp"
15 #include "FrameBuffer.hpp"
16
17 // Valve header files
18 #include "vmf.hpp"
19
20 // Util
21 #include "cxxopts.hpp"
22 #include "interpolation.h"
23
24 // Image stuff
25 #define STBI_MSC_SECURE_CRT
26 #define STB_IMAGE_WRITE_IMPLEMENTATION
27 #include "stb_image_write.h"
28 #include "dds.hpp"
29 #include "GradientMap.hpp"
30
31 /* Grabs the currently bound framebuffer and saves it to a .png */
32 void render_to_png(int x, int y, const char* filepath){
33 void* data = malloc(4 * x * y);
34
35 glReadPixels(0, 0, x, y, GL_RGBA, GL_UNSIGNED_BYTE, data);
36
37 stbi_flip_vertically_on_write(true);
38 stbi_write_png(filepath, x, y, 4, data, x * 4);
39
40 free(data);
41 }
42
43 /* Grabs the currently bound framebuffer and saves it to a .dds */
44 void save_to_dds(int x, int y, const char* filepath) {
45 void* data = malloc(4 * x * y);
46
47 glReadPixels(0, 0, x, y, GL_RGB, GL_UNSIGNED_BYTE, data);
48
49 dds_write((uint8_t*)data, filepath, x, y, IMG::MODE_DXT1);
50
51 free(data);
52 }
53
54 /* Renders opengl in opaque mode (normal) */
55 void opengl_render_opaque() {
56 glDisable(GL_BLEND);
57 glEnable(GL_DEPTH_TEST);
58 glDepthMask(GL_TRUE);
59 }
60
61 /* Renders opengl in addative mode */
62 void opengl_render_additive() {
63 glDepthMask(GL_TRUE);
64 glEnable(GL_BLEND);
65
66 // I still do not fully understand OPENGL blend modes. However these equations looks nice for the grid floor.
67 glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
68 glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE);
69 }
70
71 /* Command line variables */
72 #ifndef _DEBUG
73 std::string m_mapfile_path;
74 std::string m_game_path;
75 #endif
76 #ifdef _DEBUG
77 std::string m_mapfile_path = "sample_stuff/de_crimson_v16";
78 std::string m_game_path = "D:/SteamLibrary/steamapps/common/Counter-Strike Global Offensive/csgo";
79 #endif
80
81 //derived strings
82 std::string m_mapfile_name;
83 std::string m_overviews_folder;
84 std::string m_resources_folder;
85
86 #ifdef _DEBUG
87 bool m_outputMasks = true;
88 bool m_onlyOutputMasks;
89
90 bool m_comp_shadows_enable = true;
91 bool m_comp_ao_enable = true;
92 #endif
93
94 #ifndef _DEBUG
95 bool m_outputMasks;
96 bool m_onlyOutputMasks;
97
98 bool m_comp_shadows_enable;
99 bool m_comp_ao_enable;
100 #endif
101
102 //tar_config overrides
103 uint32_t m_renderWidth = 1024;
104 uint32_t m_renderHeight = 1024;
105 bool m_enable_maskgen_supersample = true;
106
107 bool tar_cfg_enableAO = true;
108 int tar_cfg_aoSzie = 16;
109
110 bool tar_cfg_enableShadows = false;
111
112 bool tar_cfg_enableOutline = false;
113 int tar_cfg_outlineSize = 2;
114
115 Texture* tar_cfg_gradientMap;
116
117 /* Main program */
118 int app(int argc, const char** argv) {
119 #ifndef _DEBUG
120 cxxopts::Options options("AutoRadar", "Auto radar");
121 options.add_options()
122 ("v,version", "Shows the software version")
123 ("g,game", "(REQUIRED) Specify game path", cxxopts::value<std::string>()->default_value(""))
124 ("m,mapfile", "(REQUIRED) Specify the map file (vmf)", cxxopts::value<std::string>()->default_value(""))
125
126 ("d,dumpMasks", "Toggles whether auto radar should output mask images (resources/map_file.resources/)")
127 ("o,onlyMasks", "Specift whether auto radar should only output mask images and do nothing else (resources/map_file.resources)")
128
129 ("ao", "[OBSOLETE] Turn on AO in the compisotor")
130 ("shadows", "[OBSOLETE] Turn on Shadows in the compositor")
131
132 ("w,width", "[OBSOLETE] Render width in pixels (experimental)", cxxopts::value<uint32_t>()->default_value("1024"))
133 ("h,height", "[OBSOLETE] Render height in pixels (experimental)", cxxopts::value<uint32_t>()->default_value("1024"))
134
135 // Experimental
136 ("autoModulate", "Enables automatic height modulation between two levels")
137 ("minHeightDiff", "Minumum height difference(units) to modulate between two levels", cxxopts::value<int>()->default_value("128"))
138
139 // Future
140 ("useVBSP", "Use VBSP.exe to pre-process brush unions automatically")
141 ("useLightmaps", "Use lightmaps generated by vvis in the VBSP. (If this flag is set, Auto Radar must be ran after vvis.exe)")
142
143 ("positional", "Positional parameters", cxxopts::value<std::vector<std::string>>());
144
145 options.parse_positional("positional");
146 auto result = options.parse(argc, argv);
147
148 /* Check required parameters */
149 if (result.count("game")) m_game_path = sutil::ReplaceAll(result["game"].as<std::string>(), "\n", "");
150 else throw cxxopts::option_required_exception("game");
151
152 if(result.count("mapfile")) m_mapfile_path = result["mapfile"].as<std::string>();
153 else if (result.count("positional")) {
154 auto& positional = result["positional"].as<std::vector<std::string>>();
155
156 m_mapfile_path = sutil::ReplaceAll(positional[0], "\n", "");
157 }
158 else throw cxxopts::option_required_exception("mapfile"); // We need a map file
159
160 //Clean paths to what we can deal with
161 m_mapfile_path = sutil::ReplaceAll(m_mapfile_path, "\\", "/");
162 m_game_path = sutil::ReplaceAll(m_game_path, "\\", "/");
163
164 /* Check the rest of the flags */
165 m_onlyOutputMasks = result["onlyMasks"].as<bool>();
166 m_outputMasks = result["dumpMasks"].as<bool>() || m_onlyOutputMasks;
167
168 /* Render options */
169 m_renderWidth = result["width"].as<uint32_t>();
170 m_renderHeight = result["height"].as<uint32_t>();
171
172 m_comp_ao_enable = result["ao"].as<bool>();
173 m_comp_shadows_enable = result["shadows"].as<bool>();
174
175 #endif
176
177 //Derive the ones
178 m_mapfile_name = split(m_mapfile_path, '/').back();
179 m_overviews_folder = m_game_path + "/resource/overviews/";
180 m_resources_folder = m_overviews_folder + m_mapfile_name + ".resources/";
181
182 std::cout << "Launching with options:\n";
183 std::cout << " Render width: " << m_renderWidth << "\n";
184 std::cout << " Render height: " << m_renderHeight << "\n";
185 std::cout << " Save masks? " << (m_outputMasks ? "YES" : "NO") << "\n";
186 std::cout << " Output to game? " << (!m_onlyOutputMasks ? "YES" : "NO") << "\n\n";
187 std::cout << " Game path: " << m_game_path << "\n";
188 std::cout << " Map path: " << m_mapfile_path << "\n";
189 std::cout << "\n -------- RENDER SETTINGS -------\n";
190 std::cout << " AO: " << (m_comp_ao_enable ? "YES" : "NO") << "\n";
191 std::cout << " Shadows: " << (m_comp_shadows_enable ? "YES" : "NO") << "\n";
192
193 std::cout << "Initializing OpenGL\n";
194
195 #pragma region init_opengl
196
197 glfwInit();
198 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //We are using version 3.3 of openGL
199 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
200 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
201 glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
202 glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Window le nope
203
204 //Create window
205 GLFWwindow* window = glfwCreateWindow(1, 1, "If you are seeing this window, something is broken", NULL, NULL);
206
207 //Check if window open
208 if (window == NULL){
209 std::cout << "Failed to create GLFW window" << std::endl;
210 glfwTerminate(); return -1;
211 }
212 glfwMakeContextCurrent(window);
213
214 //Settingn up glad
215 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
216 std::cout << "Failed to initialize GLAD" << std::endl; return -1;
217 }
218
219 const unsigned char* glver = glGetString(GL_VERSION);
220 std::cout << "(required: min core 3.3.0) opengl version: " << glver << "\n";
221
222 glEnable(GL_DEPTH_TEST);
223
224 glViewport(0, 0, m_renderWidth, m_renderHeight);
225
226 glClearColor(0.00f, 0.00f, 0.00f, 0.00f);
227
228 std::cout << "Creating render buffers\n";
229
230 FrameBuffer fb_tex_playspace = FrameBuffer(m_renderWidth, m_renderHeight);
231 FrameBuffer fb_tex_objectives = FrameBuffer(m_renderWidth, m_renderHeight);
232 FrameBuffer fb_comp = FrameBuffer(m_renderWidth, m_renderHeight);
233 FrameBuffer fb_comp_1 = FrameBuffer(m_renderWidth, m_renderHeight); //Reverse ordered frame buffer
234
235 // Screenspace quad
236 std::cout << "Creating screenspace mesh\n";
237
238 std::vector<float> __meshData = {
239 -1, -1,
240 -1, 1,
241 1, -1,
242 -1, 1,
243 1, 1,
244 1, -1
245 };
246
247 Mesh* mesh_screen_quad = new Mesh(__meshData, MeshMode::SCREEN_SPACE_UV);
248
249 #pragma endregion
250
251 #pragma region shader_compilation
252
253 std::cout << "Compiling Shaders\n";
254 std::cout << "______________________________________________________________\n\n";
255
256 // Internal engine shaders
257 Shader shader_depth("shaders/depth.vs", "shaders/depth.fs");
258 Shader shader_unlit("shaders/unlit.vs", "shaders/unlit.fs");
259
260 // Compositing shaders
261 Shader shader_comp_main("shaders/fullscreenbase.vs", "shaders/ss_comp_main.fs"); // le big one
262 Shader shader_precomp_playspace("shaders/fullscreenbase.vs", "shaders/ss_precomp_playspace.fs"); // computes distance map
263 Shader shader_precomp_objectives("shaders/fullscreenbase.vs", "shaders/ss_precomp_objectives.fs"); // computes distance map
264
265 if (shader_depth.compileUnsuccessful ||
266 shader_unlit.compileUnsuccessful ||
267 shader_comp_main.compileUnsuccessful ||
268 shader_precomp_playspace.compileUnsuccessful ||
269 shader_precomp_objectives.compileUnsuccessful) {
270
271 std::cout << "______________________________________________________________\n";
272 std::cout << "Shader compilation step failed.\n";
273 glfwTerminate();
274 #ifdef _DEBUG
275 system("PAUSE");
276 #endif
277 return 1;
278 }
279
280 std::cout << "______________________________________________________________\n";
281 std::cout << "Shader compilation successful\n\n";
282
283 std::cout << "Loading textures... ";
284
285 Texture tex_background = Texture("textures/grid.png");
286 //Texture tex_gradient = Texture("textures/gradients/gradientmap_6.png", true);
287 Texture tex_height_modulate = Texture("textures/modulate.png");
288
289 //GradientTexture gtex_gradient = GradientTexture(std::string("32 68 136 255"), std::string("149 0 0 255"), std::string("178 113 65"));
290
291 std::cout << "done!\n\n";
292
293 #pragma endregion
294
295 #pragma region map_load
296
297 std::cout << "Loading map file...\n";
298
299 vmf::vmf vmf_main(m_mapfile_path + ".vmf");
300
301 std::cout << "Generating Meshes...\n";
302
303 vmf_main.ComputeGLMeshes();
304 vmf_main.ComputeDisplacements();
305
306 // TAR entities
307 std::vector<vmf::Entity*> tavr_ent_tar_config = vmf_main.findEntitiesByClassName("tar_config");
308
309 if (tavr_ent_tar_config.size() > 1) {
310 std::cout << "More than 1 tar config found! Currently unsupported... Using last.\n";
311 }
312
313 vmf::Entity* tar_config = NULL;
314 if (tavr_ent_tar_config.size() > 0) {
315 tar_config = tavr_ent_tar_config.back();
316
317 // Color scheme
318 std::string schemeNum = kv::tryGetStringValue(tar_config->keyValues, "colorScheme", "0");
319 if (schemeNum == "-1") { // Custom color scheme
320 tar_cfg_gradientMap = new GradientTexture(
321 kv::tryGetStringValue(tar_config->keyValues, "customCol0", "0 0 0 255"),
322 kv::tryGetStringValue(tar_config->keyValues, "customCol1", "128 128 128 255"),
323 kv::tryGetStringValue(tar_config->keyValues, "customCol2", "255 255 255 255"));
324 } else {
325 tar_cfg_gradientMap = new Texture("textures/gradients/gradientmap_" + schemeNum + ".png", true);
326 }
327
328 // Ambient occlusion
329 tar_cfg_enableAO = (kv::tryGetStringValue(tar_config->keyValues, "enableAO", "1") == "1");
330 tar_cfg_aoSzie = kv::tryGetValue(tar_config->keyValues, "aoSize", 16);
331
332 // Outline
333 tar_cfg_enableOutline = (kv::tryGetStringValue(tar_config->keyValues, "enableOutline", "0") == "1");
334 tar_cfg_outlineSize = kv::tryGetValue(tar_config->keyValues, "outlineWidth", 2);
335
336 // Shadows
337 tar_cfg_enableShadows = (kv::tryGetStringValue(tar_config->keyValues, "enableShadows", "0") == "1");
338 }
339 else {
340 tar_cfg_gradientMap = new Texture("textures/gradients/gradientmap_6.png", true);
341 }
342
343 std::cout << "Collecting Objects... \n";
344 std::vector<vmf::Solid*> tavr_solids = vmf_main.getAllBrushesInVisGroup(tar_config == NULL? "tar_layout" : kv::tryGetStringValue(tar_config->keyValues, "vgroup_layout", "tar_layout"));
345 std::vector<vmf::Solid*> tavr_solids_negative = vmf_main.getAllBrushesInVisGroup(tar_config == NULL? "tar_mask" : kv::tryGetStringValue(tar_config->keyValues, "vgroup_negative", "tar_mask"));
346 std::vector<vmf::Solid*> tavr_entire_brushlist = vmf_main.getAllRenderBrushes();
347 std::vector<vmf::Solid*> tavr_cover = vmf_main.getAllBrushesInVisGroup(tar_config == NULL ? "tar_cover" : kv::tryGetStringValue(tar_config->keyValues, "vgroup_cover", "tar_cover"));
348 for (auto && v : tavr_cover) { v->temp_mark = true; tavr_solids.push_back(v); }
349
350 //std::vector<vmf::Solid*> tavr_solids_funcbrush = vmf_main.getAllBrushesByClassName("func_brush");
351 std::vector<vmf::Solid*> tavr_buyzones = vmf_main.getAllBrushesByClassName("func_buyzone");
352 std::vector<vmf::Solid*> tavr_bombtargets = vmf_main.getAllBrushesByClassName("func_bomb_target");
353
354 std::vector<vmf::Entity*> tavr_ent_tavr_height_min = vmf_main.findEntitiesByClassName("tar_min");
355 std::vector<vmf::Entity*> tavr_ent_tavr_height_max = vmf_main.findEntitiesByClassName("tar_max");
356
357 //Collect models
358 std::cout << "Collecting models... \n";
359 vmf_main.populateModelDict(m_game_path + "/");
360 vmf_main.populatePropList(tar_config == NULL ? "tar_cover" : kv::tryGetStringValue(tar_config->keyValues, "vgroup_cover", "tar_cover"));
361
362 std::cout << "done!\n";
363
364 #pragma region bounds
365 std::cout << "Calculating bounds... ";
366
367 vmf::BoundingBox limits = vmf::getSolidListBounds(tavr_solids);
368 float z_render_min = limits.SEL.y;
369 float z_render_max = limits.NWU.y;
370
371 // Overide entity heights
372 if (tavr_ent_tavr_height_min.size()) z_render_min = tavr_ent_tavr_height_min[0]->origin.z;
373 if (tavr_ent_tavr_height_max.size()) z_render_max = tavr_ent_tavr_height_max[0]->origin.z;
374
375 float padding = 128.0f;
376
377 float x_bounds_min = -limits.NWU.x - padding; //inflate distances slightly
378 float x_bounds_max = -limits.SEL.x + padding;
379
380 float y_bounds_min = limits.SEL.z - padding;
381 float y_bounds_max = limits.NWU.z + padding;
382
383 float dist_x = x_bounds_max - x_bounds_min;
384 float dist_y = y_bounds_max - y_bounds_min;
385
386 float mx_dist = glm::max(dist_x, dist_y);
387
388 float justify_x = (mx_dist - dist_x) * 0.5f;
389 float justify_y = (mx_dist - dist_y) * 0.5f;
390
391 float render_ortho_scale = glm::round((mx_dist / 1024.0f) / 0.01f) * 0.01f * 1024.0f; // Take largest, scale up a tiny bit. Clamp to 1024 min. Do some rounding.
392 glm::vec2 view_origin = glm::vec2(x_bounds_min - justify_x, y_bounds_max + justify_y);
393
394 std::cout << "done\n\n";
395 #pragma endregion
396
397 #pragma endregion
398
399 #pragma region OpenGLRender
400
401 std::cout << "Starting OpenGL Render\n";
402
403 #pragma region render_playable_space
404 std::cout << "Rendering playable space... ";
405
406 // ======================================================== REGULAR ORDER ========================================================
407
408 fb_comp.Bind(); //Bind framebuffer
409
410 glClearColor(0.00f, 0.00f, 0.00f, 1.00f);
411 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
412 glPolygonMode(GL_FRONT, GL_FILL);
413
414 shader_depth.use();
415 shader_depth.setMatrix("projection", glm::ortho(view_origin.x, view_origin.x + render_ortho_scale , view_origin.y - render_ortho_scale, view_origin.y, -1024.0f, 1024.0f));
416 shader_depth.setMatrix("view", glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(0, -1.0f, 0), glm::vec3(0, 0, 1)));
417
418 glm::mat4 model = glm::mat4();
419 shader_depth.setMatrix("model", model);
420
421 shader_depth.setFloat("HEIGHT_MIN", z_render_min);
422 shader_depth.setFloat("HEIGHT_MAX", z_render_max);
423 shader_depth.setFloat("write_playable", 0.0f);
424
425 // Render entire map first
426 for (auto && brush : tavr_entire_brushlist) {
427 shader_depth.setFloat("write_cover", brush->temp_mark ? 1.0f : 0.0f);
428 brush->mesh->Draw();
429 }
430 glClear(GL_DEPTH_BUFFER_BIT);
431
432 // Render playable area over it
433 shader_depth.setFloat("write_playable", 1.0f);
434 for (auto && s_solid : tavr_solids) {
435 shader_depth.setFloat("write_cover", s_solid->temp_mark ? 1.0f : 0.0f);
436 if (!s_solid->containsDisplacements)
437 s_solid->mesh->Draw();
438 else {
439 for (auto && f : s_solid->faces) {
440 if (f.displacement != NULL) {
441 f.displacement->glMesh->Draw();
442 }
443 }
444 }
445 }
446
447 // Render props
448 std::cout << "Rendering props\n";
449 shader_depth.setFloat("write_cover", 1.0f);
450 for (auto && s_prop : vmf_main.props) {
451 if (vmf_main.modelCache[s_prop.modelID] == NULL) continue; // Skip uncanched / errored models. This shouldn't happen if the vmf references everything normally and all files exist.
452
453 model = glm::mat4();
454 model = glm::translate(model, s_prop.origin); // Position
455 model = glm::rotate(model, glm::radians(s_prop.rotation.y), glm::vec3(0, 1, 0)); // Yaw
456 model = glm::rotate(model, glm::radians(s_prop.rotation.x), glm::vec3(0, 0, 1)); // ROOOOOLLLLL
457 model = glm::rotate(model, -glm::radians(s_prop.rotation.z), glm::vec3(1, 0, 0)); // Pitch
458 model = glm::scale(model, glm::vec3(s_prop.unifromScale)); // Scale
459
460 shader_depth.setMatrix("model", model);
461 vmf_main.modelCache[s_prop.modelID]->Draw();
462 }
463
464 model = glm::mat4();
465 shader_depth.setMatrix("model", model);
466
467 // Re render subtractive brushes
468 shader_depth.setFloat("write_playable", 0.0f);
469 for (auto && s_solid : tavr_solids_negative) {
470 shader_depth.setFloat("write_cover", s_solid->temp_mark ? 1.0f : 0.0f);
471 if (!s_solid->containsDisplacements)
472 s_solid->mesh->Draw();
473 else {
474 for (auto && f : s_solid->faces) {
475 if (f.displacement != NULL) {
476 f.displacement->glMesh->Draw();
477 }
478 }
479 }
480 }
481
482 // ======================================================== REVERSE ORDER ========================================================
483
484 fb_comp_1.Bind();
485
486 // Reverse rendering
487 glClearDepth(0);
488 glEnable(GL_CULL_FACE);
489 glDepthFunc(GL_GREATER);
490
491 glClearColor(0.00f, 0.00f, 0.00f, 1.00f);
492 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
493 glPolygonMode(GL_FRONT, GL_FILL);
494
495 shader_depth.setFloat("HEIGHT_MIN", z_render_min);
496 shader_depth.setFloat("HEIGHT_MAX", z_render_max);
497 shader_depth.setFloat("write_playable", 0.0f);
498
499 for (auto && s_solid : tavr_solids) {
500 if (!s_solid->containsDisplacements)
501 s_solid->mesh->Draw();
502 else {
503 for (auto && f : s_solid->faces) {
504 if (f.displacement != NULL) {
505 f.displacement->glMesh->Draw();
506 }
507 }
508 }
509 }
510
511 // regular depth testing
512 glClearDepth(1);
513 glDepthFunc(GL_LESS);
514 glDisable(GL_CULL_FACE);
515
516 // ========================================================== PRE-COMP ===========================================================
517
518 // Apply diffusion
519 fb_tex_playspace.Bind();
520
521 glClearColor(0.00f, 0.00f, 0.00f, 0.00f);
522 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
523 glDisable(GL_DEPTH_TEST);
524 glPolygonMode(GL_FRONT, GL_FILL);
525
526 shader_precomp_playspace.use();
527
528 //shader_precomp_playspace.setFloat("HEIGHT_MIN", z_render_min);
529 //shader_precomp_playspace.setFloat("HEIGHT_MAX", z_render_max);
530
531 fb_comp.BindRTtoTexSlot(0);
532 shader_precomp_playspace.setInt("tex_in", 0);
533
534 fb_comp_1.BindRTtoTexSlot(1);
535 shader_precomp_playspace.setInt("tex_in_1", 1);
536
537 //tex_height_modulate.bindOnSlot(2);
538 //shader_precomp_playspace.setInt("tex_modulate", 2);
539
540 mesh_screen_quad->Draw();
541
542 glEnable(GL_DEPTH_TEST);
543
544 if(m_outputMasks)
545 render_to_png(m_renderWidth, m_renderHeight, std::string(m_overviews_folder + m_mapfile_name + ".resources.playable_space.png").c_str());
546
547 std::cout << "done!\n";
548 #pragma endregion
549
550 #pragma region render_objectives
551 std::cout << "Rendering bombsites & buyzones space... ";
552
553 fb_comp.Bind();
554
555 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
556 glPolygonMode(GL_FRONT, GL_FILL);
557 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
558
559 shader_unlit.use();
560 shader_unlit.setMatrix("projection", glm::ortho(view_origin.x, view_origin.x + render_ortho_scale, view_origin.y - render_ortho_scale, view_origin.y, -1024.0f, 1024.0f));
561 shader_unlit.setMatrix("view", glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(0, -1.0f, 0), glm::vec3(0, 0, 1)));
562 shader_unlit.setMatrix("model", model);
563
564 shader_unlit.setVec3("color", 0.0f, 1.0f, 0.0f);
565
566 for (auto && s_solid : tavr_buyzones) {
567 s_solid->mesh->Draw();
568 }
569
570 fb_comp_1.Bind();
571 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
572
573 shader_unlit.setVec3("color", 1.0f, 0.0f, 0.0f);
574
575 for (auto && s_solid : tavr_bombtargets) {
576 s_solid->mesh->Draw();
577 }
578
579 // Apply diffusion
580 fb_tex_objectives.Bind();
581
582 glClearColor(0.00f, 0.00f, 0.00f, 0.00f);
583 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
584 glDisable(GL_DEPTH_TEST);
585 glPolygonMode(GL_FRONT, GL_FILL);
586
587 shader_precomp_objectives.use();
588
589 fb_comp.BindRTtoTexSlot(0);
590 shader_precomp_objectives.setInt("tex_in", 0);
591
592 fb_comp_1.BindRTtoTexSlot(1);
593 shader_precomp_objectives.setInt("tex_in_1", 1);
594
595 mesh_screen_quad->Draw();
596
597 if (m_outputMasks)
598 render_to_png(m_renderWidth, m_renderHeight, std::string(m_overviews_folder + m_mapfile_name + ".resources.buyzone_bombtargets.png").c_str());
599
600 glEnable(GL_DEPTH_TEST);
601 std::cout << "done!\n";
602 #pragma endregion
603
604 #pragma region compositing
605 std::cout << "Compositing... \n";
606
607 fb_comp.Bind();
608
609 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
610 glPolygonMode(GL_FRONT, GL_FILL);
611
612 shader_comp_main.use();
613
614 /* Fill out shader uniforms */
615 /*
616 vec3 bounds_NWU North-West-Upper coordinate of the playspace (worldspace)
617 vec3 bounds_SEL South-East-Lower coordinate of the playspace (worldspace)
618 **vec2 bounds_NWU_SS North-West coordinate of the playspace (screen space)
619 **vec2 bounds_SEL_SS South-East coordinate of the playspace (screen space)
620
621 **vec2 pos_spawn_ct Location of the CT Spawn (0-1)
622 **vec2 pos_spawn_t Location of the T Spawn (0-1)
623 **vec2 bombsite_a Location of bomsite A (0-1)
624 **vec2 bombsite_b Location of bombsite B (0-1)
625 */
626 shader_comp_main.setVec3("bounds_NWU", glm::vec3(x_bounds_min, y_bounds_max, z_render_max));
627 shader_comp_main.setVec3("bounds_SEL", glm::vec3(x_bounds_max, y_bounds_min, z_render_min));
628
629 /* Render flags */
630 shader_comp_main.setInt("cmdl_shadows_enable", tar_cfg_enableShadows ? 1 : 0);
631 shader_comp_main.setInt("cmdl_ao_enable", tar_cfg_enableAO ? 1 : 0);
632 shader_comp_main.setInt("cmdl_ao_size", tar_cfg_aoSzie);
633 shader_comp_main.setInt("cmdl_outline_enable", tar_cfg_enableOutline);
634 shader_comp_main.setInt("cmdl_outline_size", tar_cfg_outlineSize);
635
636 /* Bind texture samplers */
637 tex_background.bindOnSlot(0);
638 shader_comp_main.setInt("tex_background", 0);
639
640 fb_tex_playspace.BindRTtoTexSlot(1);
641 shader_comp_main.setInt("tex_playspace", 1);
642
643 fb_tex_objectives.BindRTtoTexSlot(2);
644 shader_comp_main.setInt("tex_objectives", 2);
645
646 tar_cfg_gradientMap->bindOnSlot(4);
647 shader_comp_main.setInt("tex_gradient", 4);
648
649 mesh_screen_quad->Draw();
650
651 std::cout << "done!\n";
652
653 #pragma endregion
654
655 #pragma endregion
656
657 #pragma region auto_export_game
658 if (!m_onlyOutputMasks) {
659 save_to_dds(m_renderWidth, m_renderHeight, std::string(m_overviews_folder + m_mapfile_name + "_radar.dds").c_str());
660 }
661
662 if (m_outputMasks)
663 render_to_png(m_renderWidth, m_renderHeight, std::string(m_overviews_folder + m_mapfile_name + ".resources.final_raw.png").c_str());
664
665 #pragma region generate_radar_txt
666
667 std::cout << "Generating radar .TXT... ";
668
669 kv::DataBlock node_radar = kv::DataBlock();
670 node_radar.name = m_mapfile_name;
671 node_radar.Values.insert({ "material", "overviews/" + m_mapfile_name });
672
673 node_radar.Values.insert({ "pos_x", std::to_string(view_origin.x) });
674 node_radar.Values.insert({ "pos_y", std::to_string(view_origin.y) });
675 node_radar.Values.insert({ "scale", std::to_string(render_ortho_scale / 1024.0f) });
676
677 // Try resolve spawn positions
678 glm::vec3* loc_spawnCT = vmf_main.calculateSpawnLocation(vmf::team::counter_terrorist);
679 glm::vec3* loc_spawnT = vmf_main.calculateSpawnLocation(vmf::team::terrorist);
680
681 if (loc_spawnCT != NULL) {
682 node_radar.Values.insert({ "CTSpawn_x", std::to_string(glm::round(remap(loc_spawnCT->x, view_origin.x, view_origin.x + render_ortho_scale, 0.0f, 1.0f) / 0.01f) * 0.01f) });
683 node_radar.Values.insert({ "CTSpawn_y", std::to_string(glm::round(remap(loc_spawnCT->y, view_origin.y, view_origin.y - render_ortho_scale, 0.0f, 1.0f) / 0.01f) * 0.01f) });
684 }
685 if (loc_spawnT != NULL) {
686 node_radar.Values.insert({ "TSpawn_x", std::to_string(glm::round(remap(loc_spawnT->x, view_origin.x, view_origin.x + render_ortho_scale, 0.0f, 1.0f) / 0.01f) * 0.01f) });
687 node_radar.Values.insert({ "TSpawn_y", std::to_string(glm::round(remap(loc_spawnT->y, view_origin.y, view_origin.y - render_ortho_scale, 0.0f, 1.0f) / 0.01f) * 0.01f) });
688 }
689
690 std::ofstream out(std::string(m_overviews_folder + m_mapfile_name + ".txt").c_str());
691 out << "// TAVR - AUTO RADAR. v 2.0.0\n";
692 node_radar.Serialize(out);
693 out.close();
694
695 std::cout << "done!";
696
697 #pragma endregion
698 #pragma endregion
699
700 std::cout << "\n- Radar generation successful... cleaning up. -\n";
701
702 //Exit safely
703 glfwTerminate();
704 #ifdef _DEBUG
705 system("PAUSE");
706 #endif
707
708 return 0;
709 }
710
711 /* Entry point */
712 #ifndef entry_point_testing
713 int main(int argc, const char** argv) {
714 try {
715 return app(argc, argv);
716 }
717 catch (cxxopts::OptionException& e) {
718 std::cerr << "Parse error: " << e.what() << "\n";
719 }
720
721 return 1;
722 }
723 #endif