8 #include <GLFW\glfw3.h>
10 #include "GLFWUtil.hpp"
12 // Engine header files
14 #include "Texture.hpp"
15 #include "FrameBuffer.hpp"
21 #include "cxxopts.hpp"
22 #include "interpolation.h"
25 #define STBI_MSC_SECURE_CRT
26 #define STB_IMAGE_WRITE_IMPLEMENTATION
27 #include "stb_image_write.h"
29 #include "GradientMap.hpp"
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
);
35 glReadPixels(0, 0, x
, y
, GL_RGBA
, GL_UNSIGNED_BYTE
, data
);
37 stbi_flip_vertically_on_write(true);
38 stbi_write_png(filepath
, x
, y
, 4, data
, x
* 4);
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
);
47 glReadPixels(0, 0, x
, y
, GL_RGB
, GL_UNSIGNED_BYTE
, data
);
49 dds_write((uint8_t*)data
, filepath
, x
, y
, IMG::MODE_DXT1
);
54 /* Command line variables */
56 std::string m_mapfile_path
;
57 std::string m_game_path
;
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";
65 std::string m_mapfile_name
;
66 std::string m_overviews_folder
;
67 std::string m_resources_folder
;
70 bool m_outputMasks
= true;
71 bool m_onlyOutputMasks
;
73 bool m_comp_shadows_enable
= true;
74 bool m_comp_ao_enable
= true;
79 bool m_onlyOutputMasks
;
81 bool m_comp_shadows_enable
;
82 bool m_comp_ao_enable
;
85 //tar_config overrides
86 uint32_t m_renderWidth
= 1024;
87 uint32_t m_renderHeight
= 1024;
88 bool m_enable_maskgen_supersample
= true;
90 bool tar_cfg_enableAO
= true;
91 int tar_cfg_aoSzie
= 16;
93 bool tar_cfg_enableShadows
= false;
95 bool tar_cfg_enableOutline
= false;
96 int tar_cfg_outlineSize
= 2;
98 Texture
* tar_cfg_gradientMap
;
101 int app(int argc
, const char** argv
) {
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(""))
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)")
112 ("ao", "Turn on AO in the compisotor")
113 ("shadows", "Turn on Shadows in the compositor")
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"))
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"))
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)")
126 ("positional", "Positional parameters", cxxopts::value
<std::vector
<std::string
>>());
128 options
.parse_positional("positional");
129 auto result
= options
.parse(argc
, argv
);
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");
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
>>();
139 m_mapfile_path
= positional
[0];
141 else throw cxxopts::option_required_exception("mapfile"); // We need a map file
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
, "\\", "/");
147 /* Check the rest of the flags */
148 m_onlyOutputMasks
= result
["onlyMasks"].as
<bool>();
149 m_outputMasks
= result
["dumpMasks"].as
<bool>() || m_onlyOutputMasks
;
152 m_renderWidth
= result
["width"].as
<uint32_t>();
153 m_renderHeight
= result
["height"].as
<uint32_t>();
155 m_comp_ao_enable
= result
["ao"].as
<bool>();
156 m_comp_shadows_enable
= result
["shadows"].as
<bool>();
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/";
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";
176 std::cout
<< "Initializing OpenGL\n";
178 #pragma region init_opengl
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
188 GLFWwindow
* window
= glfwCreateWindow(1, 1, "If you are seeing this window, something is broken", NULL
, NULL
);
190 //Check if window open
192 std::cout
<< "Failed to create GLFW window" << std::endl
;
193 glfwTerminate(); return -1;
195 glfwMakeContextCurrent(window
);
198 if (!gladLoadGLLoader((GLADloadproc
)glfwGetProcAddress
)){
199 std::cout
<< "Failed to initialize GLAD" << std::endl
; return -1;
202 glEnable(GL_DEPTH_TEST
);
204 glViewport(0, 0, m_renderWidth
, m_renderHeight
);
206 glClearColor(0.00f
, 0.00f
, 0.00f
, 0.00f
);
208 std::cout
<< "Creating render buffers\n";
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
216 std::cout
<< "Creating screenspace mesh\n";
218 std::vector
<float> __meshData
= {
227 Mesh
* mesh_screen_quad
= new Mesh(__meshData
, MeshMode::SCREEN_SPACE_UV
);
231 #pragma region shader_compilation
233 std::cout
<< "Compiling Shaders\n";
234 std::cout
<< "______________________________________________________________\n\n";
236 // Internal engine shaders
237 Shader
shader_depth("shaders/depth.vs", "shaders/depth.fs");
238 Shader
shader_unlit("shaders/unlit.vs", "shaders/unlit.fs");
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
245 if (shader_depth
.compileUnsuccessful
||
246 shader_unlit
.compileUnsuccessful
||
247 shader_comp_main
.compileUnsuccessful
||
248 shader_precomp_playspace
.compileUnsuccessful
||
249 shader_precomp_objectives
.compileUnsuccessful
) {
251 std::cout
<< "______________________________________________________________\n";
252 std::cout
<< "Shader compilation step failed.\n";
260 std::cout
<< "______________________________________________________________\n";
261 std::cout
<< "Shader compilation successful\n\n";
263 std::cout
<< "Loading textures... ";
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");
269 //GradientTexture gtex_gradient = GradientTexture(std::string("32 68 136 255"), std::string("149 0 0 255"), std::string("178 113 65"));
271 std::cout
<< "done!\n\n";
275 #pragma region map_load
277 std::cout
<< "Loading map file...\n";
279 vmf::vmf
vmf_main(m_mapfile_path
+ ".vmf");
281 std::cout
<< "Generating Meshes...\n";
283 vmf_main
.ComputeGLMeshes();
284 vmf_main
.ComputeDisplacements();
287 std::vector
<vmf::Entity
*> tavr_ent_tar_config
= vmf_main
.findEntitiesByClassName("tar_config");
289 if (tavr_ent_tar_config
.size() > 1) {
290 std::cout
<< "More than 1 tar config found! Currently unsupported... Using last.\n";
293 vmf::Entity
* tar_config
= NULL
;
294 if (tavr_ent_tar_config
.size() > 0) {
295 tar_config
= tavr_ent_tar_config
.back();
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"));
305 tar_cfg_gradientMap
= new Texture("textures/gradients/gradientmap_" + schemeNum
+ ".png", true);
309 tar_cfg_enableAO
= (kv::tryGetStringValue(tar_config
->keyValues
, "enableAO", "1") == "1");
310 tar_cfg_aoSzie
= kv::tryGetValue(tar_config
->keyValues
, "aoSize", 16);
313 tar_cfg_enableOutline
= (kv::tryGetStringValue(tar_config
->keyValues
, "enableOutline", "0") == "1");
314 tar_cfg_outlineSize
= kv::tryGetValue(tar_config
->keyValues
, "outlineWidth", 2);
317 tar_cfg_enableShadows
= (kv::tryGetStringValue(tar_config
->keyValues
, "enableShadows", "0") == "1");
320 tar_cfg_gradientMap
= new Texture("textures/gradients/gradientmap_6.png", true);
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
); }
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");
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");
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"));
342 std::cout
<< "done!\n";
344 #pragma region bounds
345 std::cout
<< "Calculating bounds... ";
347 vmf::BoundingBox limits
= vmf::getSolidListBounds(tavr_solids
);
348 float z_render_min
= limits
.SEL
.y
;
349 float z_render_max
= limits
.NWU
.y
;
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
;
355 float padding
= 128.0f
;
357 float x_bounds_min
= -limits
.NWU
.x
- padding
; //inflate distances slightly
358 float x_bounds_max
= -limits
.SEL
.x
+ padding
;
360 float y_bounds_min
= limits
.SEL
.z
- padding
;
361 float y_bounds_max
= limits
.NWU
.z
+ padding
;
363 float dist_x
= x_bounds_max
- x_bounds_min
;
364 float dist_y
= y_bounds_max
- y_bounds_min
;
366 float mx_dist
= glm::max(dist_x
, dist_y
);
368 float justify_x
= (mx_dist
- dist_x
) * 0.5f
;
369 float justify_y
= (mx_dist
- dist_y
) * 0.5f
;
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
);
374 std::cout
<< "done\n\n";
379 #pragma region OpenGLRender
381 std::cout
<< "Starting OpenGL Render\n";
383 #pragma region render_playable_space
384 std::cout
<< "Rendering playable space... ";
386 // ======================================================== REGULAR ORDER ========================================================
388 fb_comp
.Bind(); //Bind framebuffer
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
);
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)));
398 glm::mat4 model
= glm::mat4();
399 shader_depth
.setMatrix("model", model
);
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
);
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
);
410 glClear(GL_DEPTH_BUFFER_BIT
);
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();
419 for (auto && f
: s_solid
->faces
) {
420 if (f
.displacement
!= NULL
) {
421 f
.displacement
->glMesh
->Draw();
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.
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
440 shader_depth
.setMatrix("model", model
);
441 vmf_main
.modelCache
[s_prop
.modelID
]->Draw();
445 shader_depth
.setMatrix("model", model
);
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();
454 for (auto && f
: s_solid
->faces
) {
455 if (f
.displacement
!= NULL
) {
456 f
.displacement
->glMesh
->Draw();
462 // ======================================================== REVERSE ORDER ========================================================
468 glEnable(GL_CULL_FACE
);
469 glDepthFunc(GL_GREATER
);
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
);
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
);
479 for (auto && s_solid
: tavr_solids
) {
480 if (!s_solid
->containsDisplacements
)
481 s_solid
->mesh
->Draw();
483 for (auto && f
: s_solid
->faces
) {
484 if (f
.displacement
!= NULL
) {
485 f
.displacement
->glMesh
->Draw();
491 // regular depth testing
493 glDepthFunc(GL_LESS
);
494 glDisable(GL_CULL_FACE
);
496 // ========================================================== PRE-COMP ===========================================================
499 fb_tex_playspace
.Bind();
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
);
506 shader_precomp_playspace
.use();
508 //shader_precomp_playspace.setFloat("HEIGHT_MIN", z_render_min);
509 //shader_precomp_playspace.setFloat("HEIGHT_MAX", z_render_max);
511 fb_comp
.BindRTtoTexSlot(0);
512 shader_precomp_playspace
.setInt("tex_in", 0);
514 fb_comp_1
.BindRTtoTexSlot(1);
515 shader_precomp_playspace
.setInt("tex_in_1", 1);
517 //tex_height_modulate.bindOnSlot(2);
518 //shader_precomp_playspace.setInt("tex_modulate", 2);
520 mesh_screen_quad
->Draw();
522 glEnable(GL_DEPTH_TEST
);
525 render_to_png(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ ".resources.playable_space.png").c_str());
527 std::cout
<< "done!\n";
530 #pragma region render_objectives
531 std::cout
<< "Rendering bombsites & buyzones space... ";
535 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
536 glPolygonMode(GL_FRONT
, GL_FILL
);
537 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
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
);
544 shader_unlit
.setVec3("color", 0.0f
, 1.0f
, 0.0f
);
546 for (auto && s_solid
: tavr_buyzones
) {
547 s_solid
->mesh
->Draw();
550 shader_unlit
.setVec3("color", 1.0f
, 0.0f
, 0.0f
);
552 for (auto && s_solid
: tavr_bombtargets
) {
553 s_solid
->mesh
->Draw();
557 fb_tex_objectives
.Bind();
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
);
564 shader_precomp_objectives
.use();
566 fb_comp
.BindRTtoTexSlot(0);
567 shader_precomp_objectives
.setInt("tex_in", 0);
569 mesh_screen_quad
->Draw();
572 render_to_png(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ ".resources.buyzone_bombtargets.png").c_str());
574 glEnable(GL_DEPTH_TEST
);
575 std::cout
<< "done!\n";
578 #pragma region compositing
579 std::cout
<< "Compositing... \n";
583 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
584 glPolygonMode(GL_FRONT
, GL_FILL
);
586 shader_comp_main
.use();
588 /* Fill out shader uniforms */
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)
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)
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
));
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
);
610 /* Bind texture samplers */
611 tex_background
.bindOnSlot(0);
612 shader_comp_main
.setInt("tex_background", 0);
614 fb_tex_playspace
.BindRTtoTexSlot(1);
615 shader_comp_main
.setInt("tex_playspace", 1);
617 fb_tex_objectives
.BindRTtoTexSlot(2);
618 shader_comp_main
.setInt("tex_objectives", 2);
620 tar_cfg_gradientMap
->bindOnSlot(4);
621 shader_comp_main
.setInt("tex_gradient", 4);
623 mesh_screen_quad
->Draw();
625 std::cout
<< "done!\n";
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());
637 render_to_png(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ ".resources.final_raw.png").c_str());
639 #pragma region generate_radar_txt
641 std::cout
<< "Generating radar .TXT... ";
643 kv::DataBlock node_radar
= kv::DataBlock();
644 node_radar
.name
= m_mapfile_name
;
645 node_radar
.Values
.insert({ "material", "overviews/" + m_mapfile_name
});
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
) });
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
);
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
) });
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
) });
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
);
669 std::cout
<< "done!";
674 std::cout
<< "\n- Radar generation successful... cleaning up. -\n";
686 #ifndef entry_point_testing
687 int main(int argc
, const char** argv
) {
689 return app(argc
, argv
);
691 catch (cxxopts::OptionException
& e
) {
692 std::cerr
<< "Parse error: " << e
.what() << "\n";