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