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