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