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