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"
23 #include "vfilesys.hpp"
26 #define STBI_MSC_SECURE_CRT
27 #define STB_IMAGE_WRITE_IMPLEMENTATION
28 #include "stb_image_write.h"
30 #include "GradientMap.hpp"
32 /* Grabs the currently bound framebuffer and saves it to a .png */
33 void render_to_png(int x
, int y
, const char* filepath
){
34 void* data
= malloc(4 * x
* y
);
36 glReadPixels(0, 0, x
, y
, GL_RGBA
, GL_UNSIGNED_BYTE
, data
);
38 stbi_flip_vertically_on_write(true);
39 stbi_write_png(filepath
, x
, y
, 4, data
, x
* 4);
44 /* Grabs the currently bound framebuffer and saves it to a .dds */
45 void save_to_dds(int x
, int y
, const char* filepath
) {
46 void* data
= malloc(4 * x
* y
);
48 glReadPixels(0, 0, x
, y
, GL_RGB
, GL_UNSIGNED_BYTE
, data
);
50 dds_write((uint8_t*)data
, filepath
, x
, y
, IMG::MODE_DXT1
);
55 /* Renders opengl in opaque mode (normal) */
56 void opengl_render_opaque() {
58 glEnable(GL_DEPTH_TEST
);
62 /* Renders opengl in addative mode */
63 void opengl_render_additive() {
67 // I still do not fully understand OPENGL blend modes. However these equations looks nice for the grid floor.
68 glBlendEquationSeparate(GL_FUNC_ADD
, GL_FUNC_ADD
);
69 glBlendFuncSeparate(GL_ONE
, GL_ONE
, GL_ZERO
, GL_ONE
);
72 /* Command line variables */
74 std::string m_mapfile_path
;
75 std::string m_game_path
;
78 std::string m_mapfile_path
= "sample_stuff/de_tavr_test";
79 std::string m_game_path
= "D:/SteamLibrary/steamapps/common/Counter-Strike Global Offensive/csgo_dev";
83 std::string m_mapfile_name
;
84 std::string m_overviews_folder
;
85 std::string m_resources_folder
;
88 bool m_outputMasks
= true;
89 bool m_onlyOutputMasks
;
91 bool m_comp_shadows_enable
= true;
92 bool m_comp_ao_enable
= true;
97 bool m_onlyOutputMasks
;
99 bool m_comp_shadows_enable
;
100 bool m_comp_ao_enable
;
103 //tar_config overrides
104 uint32_t m_renderWidth
= 1024;
105 uint32_t m_renderHeight
= 1024;
106 bool m_enable_maskgen_supersample
= true;
108 bool tar_cfg_enableAO
= true;
109 int tar_cfg_aoSzie
= 16;
111 bool tar_cfg_enableShadows
= false;
113 bool tar_cfg_enableOutline
= false;
114 int tar_cfg_outlineSize
= 2;
116 Texture
* tar_cfg_gradientMap
;
119 int app(int argc
, const char** argv
) {
121 cxxopts::Options
options("AutoRadar", "Auto radar");
122 options
.add_options()
123 ("v,version", "Shows the software version")
124 ("g,game", "(REQUIRED) Specify game path", cxxopts::value
<std::string
>()->default_value(""))
125 ("m,mapfile", "(REQUIRED) Specify the map file (vmf)", cxxopts::value
<std::string
>()->default_value(""))
127 ("d,dumpMasks", "Toggles whether auto radar should output mask images (resources/map_file.resources/)")
128 ("o,onlyMasks", "Specift whether auto radar should only output mask images and do nothing else (resources/map_file.resources)")
130 ("ao", "[OBSOLETE] Turn on AO in the compisotor")
131 ("shadows", "[OBSOLETE] Turn on Shadows in the compositor")
133 ("w,width", "[OBSOLETE] Render width in pixels (experimental)", cxxopts::value
<uint32_t>()->default_value("1024"))
134 ("h,height", "[OBSOLETE] Render height in pixels (experimental)", cxxopts::value
<uint32_t>()->default_value("1024"))
137 ("autoModulate", "Enables automatic height modulation between two levels")
138 ("minHeightDiff", "Minumum height difference(units) to modulate between two levels", cxxopts::value
<int>()->default_value("128"))
141 ("useVBSP", "Use VBSP.exe to pre-process brush unions automatically")
142 ("useLightmaps", "Use lightmaps generated by vvis in the VBSP. (If this flag is set, Auto Radar must be ran after vvis.exe)")
144 ("positional", "Positional parameters", cxxopts::value
<std::vector
<std::string
>>());
146 options
.parse_positional("positional");
147 auto result
= options
.parse(argc
, argv
);
149 /* Check required parameters */
150 if (result
.count("game")) m_game_path
= sutil::ReplaceAll(result
["game"].as
<std::string
>(), "\n", "");
151 else throw cxxopts::option_required_exception("game");
153 if(result
.count("mapfile")) m_mapfile_path
= result
["mapfile"].as
<std::string
>();
154 else if (result
.count("positional")) {
155 auto& positional
= result
["positional"].as
<std::vector
<std::string
>>();
157 m_mapfile_path
= sutil::ReplaceAll(positional
[0], "\n", "");
159 else throw cxxopts::option_required_exception("mapfile"); // We need a map file
161 //Clean paths to what we can deal with
162 m_mapfile_path
= sutil::ReplaceAll(m_mapfile_path
, "\\", "/");
163 m_game_path
= sutil::ReplaceAll(m_game_path
, "\\", "/");
165 /* Check the rest of the flags */
166 m_onlyOutputMasks
= result
["onlyMasks"].as
<bool>();
167 m_outputMasks
= result
["dumpMasks"].as
<bool>() || m_onlyOutputMasks
;
170 m_renderWidth
= result
["width"].as
<uint32_t>();
171 m_renderHeight
= result
["height"].as
<uint32_t>();
173 m_comp_ao_enable
= result
["ao"].as
<bool>();
174 m_comp_shadows_enable
= result
["shadows"].as
<bool>();
179 m_mapfile_name
= split(m_mapfile_path
, '/').back();
180 m_overviews_folder
= m_game_path
+ "/resource/overviews/";
181 m_resources_folder
= m_overviews_folder
+ m_mapfile_name
+ ".resources/";
184 std::cout << "Launching with options:\n";
185 std::cout << " Render width: " << m_renderWidth << "\n";
186 std::cout << " Render height: " << m_renderHeight << "\n";
187 std::cout << " Save masks? " << (m_outputMasks ? "YES" : "NO") << "\n";
188 std::cout << " Output to game? " << (!m_onlyOutputMasks ? "YES" : "NO") << "\n\n";
189 std::cout << " Game path: " << m_game_path << "\n";
190 std::cout << " Map path: " << m_mapfile_path << "\n";
191 std::cout << "\n -------- RENDER SETTINGS -------\n";
192 std::cout << " AO: " << (m_comp_ao_enable ? "YES" : "NO") << "\n";
193 std::cout << " Shadows: " << (m_comp_shadows_enable ? "YES" : "NO") << "\n";
195 vfilesys
* filesys
= NULL
;
197 filesys
= new vfilesys(m_game_path
+ "/gameinfo.txt");
199 catch (std::exception e
) {
200 std::cout
<< "Error creating vfilesys:\n";
201 std::cout
<< e
.what() << "\n";
208 std::cout
<< "Initializing OpenGL\n";
210 #pragma region init_opengl
213 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR
, 3); //We are using version 3.3 of openGL
214 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR
, 3);
215 glfwWindowHint(GLFW_OPENGL_PROFILE
, GLFW_OPENGL_CORE_PROFILE
);
216 glfwWindowHint(GLFW_RESIZABLE
, GL_FALSE
);
217 glfwWindowHint(GLFW_VISIBLE
, GL_FALSE
); // Window le nope
220 GLFWwindow
* window
= glfwCreateWindow(1, 1, "If you are seeing this window, something is broken", NULL
, NULL
);
222 //Check if window open
224 std::cout
<< "Failed to create GLFW window" << std::endl
;
225 glfwTerminate(); return -1;
227 glfwMakeContextCurrent(window
);
230 if (!gladLoadGLLoader((GLADloadproc
)glfwGetProcAddress
)){
231 std::cout
<< "Failed to initialize GLAD" << std::endl
; return -1;
234 const unsigned char* glver
= glGetString(GL_VERSION
);
235 std::cout
<< "(required: min core 3.3.0) opengl version: " << glver
<< "\n";
237 glEnable(GL_DEPTH_TEST
);
239 glViewport(0, 0, m_renderWidth
, m_renderHeight
);
241 glClearColor(0.00f
, 0.00f
, 0.00f
, 0.00f
);
243 std::cout
<< "Creating render buffers\n";
245 FrameBuffer fb_tex_playspace
= FrameBuffer(m_renderWidth
, m_renderHeight
);
246 FrameBuffer fb_tex_objectives
= FrameBuffer(m_renderWidth
, m_renderHeight
);
247 FrameBuffer fb_comp
= FrameBuffer(m_renderWidth
, m_renderHeight
);
248 FrameBuffer fb_comp_1
= FrameBuffer(m_renderWidth
, m_renderHeight
); //Reverse ordered frame buffer
251 std::cout
<< "Creating screenspace mesh\n";
253 std::vector
<float> __meshData
= {
262 Mesh
* mesh_screen_quad
= new Mesh(__meshData
, MeshMode::SCREEN_SPACE_UV
);
266 #pragma region shader_compilation
268 std::cout
<< "Compiling Shaders\n";
269 std::cout
<< "______________________________________________________________\n\n";
271 // Internal engine shaders
272 Shader
shader_depth("shaders/depth.vs", "shaders/depth.fs");
273 Shader
shader_unlit("shaders/unlit.vs", "shaders/unlit.fs");
275 // Compositing shaders
276 Shader
shader_comp_main("shaders/fullscreenbase.vs", "shaders/ss_comp_main.fs"); // le big one
277 Shader
shader_precomp_playspace("shaders/fullscreenbase.vs", "shaders/ss_precomp_playspace.fs"); // computes distance map
278 Shader
shader_precomp_objectives("shaders/fullscreenbase.vs", "shaders/ss_precomp_objectives.fs"); // computes distance map
280 if (shader_depth
.compileUnsuccessful
||
281 shader_unlit
.compileUnsuccessful
||
282 shader_comp_main
.compileUnsuccessful
||
283 shader_precomp_playspace
.compileUnsuccessful
||
284 shader_precomp_objectives
.compileUnsuccessful
) {
286 std::cout
<< "______________________________________________________________\n";
287 std::cout
<< "Shader compilation step failed.\n";
295 std::cout
<< "______________________________________________________________\n";
296 std::cout
<< "Shader compilation successful\n\n";
298 std::cout
<< "Loading textures... ";
300 Texture tex_background
= Texture("textures/grid.png");
301 //Texture tex_gradient = Texture("textures/gradients/gradientmap_6.png", true);
302 Texture tex_height_modulate
= Texture("textures/modulate.png");
304 //GradientTexture gtex_gradient = GradientTexture(std::string("32 68 136 255"), std::string("149 0 0 255"), std::string("178 113 65"));
306 std::cout
<< "done!\n\n";
310 #pragma region map_load
312 std::cout
<< "Loading map file...\n";
314 vmf::vmf
vmf_main(m_mapfile_path
+ ".vmf");
316 std::cout
<< "Generating Meshes...\n";
318 vmf_main
.ComputeGLMeshes();
319 vmf_main
.ComputeDisplacements();
322 std::vector
<vmf::Entity
*> tavr_ent_tar_config
= vmf_main
.findEntitiesByClassName("tar_config");
324 if (tavr_ent_tar_config
.size() > 1) {
325 std::cout
<< "More than 1 tar config found! Currently unsupported... Using last.\n";
328 vmf::Entity
* tar_config
= NULL
;
329 if (tavr_ent_tar_config
.size() > 0) {
330 tar_config
= tavr_ent_tar_config
.back();
333 std::string schemeNum
= kv::tryGetStringValue(tar_config
->keyValues
, "colorScheme", "0");
334 if (schemeNum
== "-1") { // Custom color scheme
335 tar_cfg_gradientMap
= new GradientTexture(
336 kv::tryGetStringValue(tar_config
->keyValues
, "customCol0", "0 0 0 255"),
337 kv::tryGetStringValue(tar_config
->keyValues
, "customCol1", "128 128 128 255"),
338 kv::tryGetStringValue(tar_config
->keyValues
, "customCol2", "255 255 255 255"));
340 tar_cfg_gradientMap
= new Texture("textures/gradients/gradientmap_" + schemeNum
+ ".png", true);
344 tar_cfg_enableAO
= (kv::tryGetStringValue(tar_config
->keyValues
, "enableAO", "1") == "1");
345 tar_cfg_aoSzie
= kv::tryGetValue(tar_config
->keyValues
, "aoSize", 16);
348 tar_cfg_enableOutline
= (kv::tryGetStringValue(tar_config
->keyValues
, "enableOutline", "0") == "1");
349 tar_cfg_outlineSize
= kv::tryGetValue(tar_config
->keyValues
, "outlineWidth", 2);
352 tar_cfg_enableShadows
= (kv::tryGetStringValue(tar_config
->keyValues
, "enableShadows", "0") == "1");
355 tar_cfg_gradientMap
= new Texture("textures/gradients/gradientmap_6.png", true);
358 std::cout
<< "Collecting Objects... \n";
359 std::vector
<vmf::Solid
*> tavr_solids
= vmf_main
.getAllBrushesInVisGroup(tar_config
== NULL
? "tar_layout" : kv::tryGetStringValue(tar_config
->keyValues
, "vgroup_layout", "tar_layout"));
360 std::vector
<vmf::Solid
*> tavr_solids_negative
= vmf_main
.getAllBrushesInVisGroup(tar_config
== NULL
? "tar_mask" : kv::tryGetStringValue(tar_config
->keyValues
, "vgroup_negative", "tar_mask"));
361 std::vector
<vmf::Solid
*> tavr_entire_brushlist
= vmf_main
.getAllRenderBrushes();
362 std::vector
<vmf::Solid
*> tavr_cover
= vmf_main
.getAllBrushesInVisGroup(tar_config
== NULL
? "tar_cover" : kv::tryGetStringValue(tar_config
->keyValues
, "vgroup_cover", "tar_cover"));
363 for (auto && v
: tavr_cover
) { v
->temp_mark
= true; tavr_solids
.push_back(v
); }
365 //std::vector<vmf::Solid*> tavr_solids_funcbrush = vmf_main.getAllBrushesByClassName("func_brush");
366 std::vector
<vmf::Solid
*> tavr_buyzones
= vmf_main
.getAllBrushesByClassName("func_buyzone");
367 std::vector
<vmf::Solid
*> tavr_bombtargets
= vmf_main
.getAllBrushesByClassName("func_bomb_target");
369 std::vector
<vmf::Entity
*> tavr_ent_tavr_height_min
= vmf_main
.findEntitiesByClassName("tar_min");
370 std::vector
<vmf::Entity
*> tavr_ent_tavr_height_max
= vmf_main
.findEntitiesByClassName("tar_max");
373 std::cout
<< "Collecting models... \n";
374 vmf_main
.populateModelDict(filesys
);
375 vmf_main
.populatePropList(tar_config
== NULL
? "tar_cover" : kv::tryGetStringValue(tar_config
->keyValues
, "vgroup_cover", "tar_cover"));
377 std::cout
<< "done!\n";
379 #pragma region bounds
380 std::cout
<< "Calculating bounds... ";
382 vmf::BoundingBox limits
= vmf::getSolidListBounds(tavr_solids
);
383 float z_render_min
= limits
.SEL
.y
;
384 float z_render_max
= limits
.NWU
.y
;
386 // Overide entity heights
387 if (tavr_ent_tavr_height_min
.size()) z_render_min
= tavr_ent_tavr_height_min
[0]->origin
.z
;
388 if (tavr_ent_tavr_height_max
.size()) z_render_max
= tavr_ent_tavr_height_max
[0]->origin
.z
;
390 float padding
= 128.0f
;
392 float x_bounds_min
= -limits
.NWU
.x
- padding
; //inflate distances slightly
393 float x_bounds_max
= -limits
.SEL
.x
+ padding
;
395 float y_bounds_min
= limits
.SEL
.z
- padding
;
396 float y_bounds_max
= limits
.NWU
.z
+ padding
;
398 float dist_x
= x_bounds_max
- x_bounds_min
;
399 float dist_y
= y_bounds_max
- y_bounds_min
;
401 float mx_dist
= glm::max(dist_x
, dist_y
);
403 float justify_x
= (mx_dist
- dist_x
) * 0.5f
;
404 float justify_y
= (mx_dist
- dist_y
) * 0.5f
;
406 float render_ortho_scale
= glm::round((mx_dist
/ 1024.0f
) / 0.01f
) * 0.01f
* 1024.0f
; // Take largest, scale up a tiny bit. Clamp to 1024 min. Do some rounding.
407 glm::vec2 view_origin
= glm::vec2(x_bounds_min
- justify_x
, y_bounds_max
+ justify_y
);
409 std::cout
<< "done\n\n";
414 #pragma region OpenGLRender
416 std::cout
<< "Starting OpenGL Render\n";
418 #pragma region render_playable_space
419 std::cout
<< "Rendering playable space... ";
421 // ======================================================== REGULAR ORDER ========================================================
423 fb_comp
.Bind(); //Bind framebuffer
425 glClearColor(0.00f
, 0.00f
, 0.00f
, 1.00f
);
426 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
427 glPolygonMode(GL_FRONT
, GL_FILL
);
430 shader_depth
.setMatrix("projection", glm::ortho(view_origin
.x
, view_origin
.x
+ render_ortho_scale
, view_origin
.y
- render_ortho_scale
, view_origin
.y
, -1024.0f
, 1024.0f
));
431 shader_depth
.setMatrix("view", glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(0, -1.0f
, 0), glm::vec3(0, 0, 1)));
433 glm::mat4 model
= glm::mat4();
434 shader_depth
.setMatrix("model", model
);
436 shader_depth
.setFloat("HEIGHT_MIN", z_render_min
);
437 shader_depth
.setFloat("HEIGHT_MAX", z_render_max
);
438 shader_depth
.setFloat("write_playable", 0.0f
);
440 // Render entire map first
441 for (auto && brush
: tavr_entire_brushlist
) {
442 shader_depth
.setFloat("write_cover", brush
->temp_mark
? 1.0f
: 0.0f
);
445 glClear(GL_DEPTH_BUFFER_BIT
);
447 // Render playable area over it
448 shader_depth
.setFloat("write_playable", 1.0f
);
449 for (auto && s_solid
: tavr_solids
) {
450 shader_depth
.setFloat("write_cover", s_solid
->temp_mark
? 1.0f
: 0.0f
);
451 if (!s_solid
->containsDisplacements
)
452 s_solid
->mesh
->Draw();
454 for (auto && f
: s_solid
->faces
) {
455 if (f
.displacement
!= NULL
) {
456 f
.displacement
->glMesh
->Draw();
463 std::cout
<< "Rendering props\n";
464 shader_depth
.setFloat("write_cover", 1.0f
);
465 for (auto && s_prop
: vmf_main
.props
) {
466 if (vmf_main
.modelCache
[s_prop
.modelID
] == NULL
) continue; // Skip uncanched / errored models. This shouldn't happen if the vmf references everything normally and all files exist.
469 model
= glm::translate(model
, s_prop
.origin
); // Position
470 model
= glm::rotate(model
, glm::radians(s_prop
.rotation
.y
), glm::vec3(0, 1, 0)); // Yaw
471 model
= glm::rotate(model
, glm::radians(s_prop
.rotation
.x
), glm::vec3(0, 0, 1)); // ROOOOOLLLLL
472 model
= glm::rotate(model
, -glm::radians(s_prop
.rotation
.z
), glm::vec3(1, 0, 0)); // Pitch
473 model
= glm::scale(model
, glm::vec3(s_prop
.unifromScale
)); // Scale
475 shader_depth
.setMatrix("model", model
);
476 vmf_main
.modelCache
[s_prop
.modelID
]->Draw();
480 shader_depth
.setMatrix("model", model
);
482 // Re render subtractive brushes
483 shader_depth
.setFloat("write_playable", 0.0f
);
484 for (auto && s_solid
: tavr_solids_negative
) {
485 shader_depth
.setFloat("write_cover", s_solid
->temp_mark
? 1.0f
: 0.0f
);
486 if (!s_solid
->containsDisplacements
)
487 s_solid
->mesh
->Draw();
489 for (auto && f
: s_solid
->faces
) {
490 if (f
.displacement
!= NULL
) {
491 f
.displacement
->glMesh
->Draw();
497 // ======================================================== REVERSE ORDER ========================================================
503 glEnable(GL_CULL_FACE
);
504 glDepthFunc(GL_GREATER
);
506 glClearColor(0.00f
, 0.00f
, 0.00f
, 1.00f
);
507 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
508 glPolygonMode(GL_FRONT
, GL_FILL
);
510 shader_depth
.setFloat("HEIGHT_MIN", z_render_min
);
511 shader_depth
.setFloat("HEIGHT_MAX", z_render_max
);
512 shader_depth
.setFloat("write_playable", 0.0f
);
514 for (auto && s_solid
: tavr_solids
) {
515 if (!s_solid
->containsDisplacements
)
516 s_solid
->mesh
->Draw();
518 for (auto && f
: s_solid
->faces
) {
519 if (f
.displacement
!= NULL
) {
520 f
.displacement
->glMesh
->Draw();
526 // regular depth testing
528 glDepthFunc(GL_LESS
);
529 glDisable(GL_CULL_FACE
);
531 // ========================================================== PRE-COMP ===========================================================
534 fb_tex_playspace
.Bind();
536 glClearColor(0.00f
, 0.00f
, 0.00f
, 0.00f
);
537 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
538 glDisable(GL_DEPTH_TEST
);
539 glPolygonMode(GL_FRONT
, GL_FILL
);
541 shader_precomp_playspace
.use();
543 //shader_precomp_playspace.setFloat("HEIGHT_MIN", z_render_min);
544 //shader_precomp_playspace.setFloat("HEIGHT_MAX", z_render_max);
546 fb_comp
.BindRTtoTexSlot(0);
547 shader_precomp_playspace
.setInt("tex_in", 0);
549 fb_comp_1
.BindRTtoTexSlot(1);
550 shader_precomp_playspace
.setInt("tex_in_1", 1);
552 //tex_height_modulate.bindOnSlot(2);
553 //shader_precomp_playspace.setInt("tex_modulate", 2);
555 mesh_screen_quad
->Draw();
557 glEnable(GL_DEPTH_TEST
);
560 render_to_png(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ ".resources.playable_space.png").c_str());
562 std::cout
<< "done!\n";
565 #pragma region render_objectives
566 std::cout
<< "Rendering bombsites & buyzones space... ";
570 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
571 glPolygonMode(GL_FRONT
, GL_FILL
);
572 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
575 shader_unlit
.setMatrix("projection", glm::ortho(view_origin
.x
, view_origin
.x
+ render_ortho_scale
, view_origin
.y
- render_ortho_scale
, view_origin
.y
, -1024.0f
, 1024.0f
));
576 shader_unlit
.setMatrix("view", glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(0, -1.0f
, 0), glm::vec3(0, 0, 1)));
577 shader_unlit
.setMatrix("model", model
);
579 shader_unlit
.setVec3("color", 0.0f
, 1.0f
, 0.0f
);
581 for (auto && s_solid
: tavr_buyzones
) {
582 s_solid
->mesh
->Draw();
586 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
588 shader_unlit
.setVec3("color", 1.0f
, 0.0f
, 0.0f
);
590 for (auto && s_solid
: tavr_bombtargets
) {
591 s_solid
->mesh
->Draw();
595 fb_tex_objectives
.Bind();
597 glClearColor(0.00f
, 0.00f
, 0.00f
, 0.00f
);
598 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
599 glDisable(GL_DEPTH_TEST
);
600 glPolygonMode(GL_FRONT
, GL_FILL
);
602 shader_precomp_objectives
.use();
604 fb_comp
.BindRTtoTexSlot(0);
605 shader_precomp_objectives
.setInt("tex_in", 0);
607 fb_comp_1
.BindRTtoTexSlot(1);
608 shader_precomp_objectives
.setInt("tex_in_1", 1);
610 mesh_screen_quad
->Draw();
613 render_to_png(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ ".resources.buyzone_bombtargets.png").c_str());
615 glEnable(GL_DEPTH_TEST
);
616 std::cout
<< "done!\n";
619 #pragma region compositing
620 std::cout
<< "Compositing... \n";
624 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
625 glPolygonMode(GL_FRONT
, GL_FILL
);
627 shader_comp_main
.use();
629 /* Fill out shader uniforms */
631 vec3 bounds_NWU North-West-Upper coordinate of the playspace (worldspace)
632 vec3 bounds_SEL South-East-Lower coordinate of the playspace (worldspace)
633 **vec2 bounds_NWU_SS North-West coordinate of the playspace (screen space)
634 **vec2 bounds_SEL_SS South-East coordinate of the playspace (screen space)
636 **vec2 pos_spawn_ct Location of the CT Spawn (0-1)
637 **vec2 pos_spawn_t Location of the T Spawn (0-1)
638 **vec2 bombsite_a Location of bomsite A (0-1)
639 **vec2 bombsite_b Location of bombsite B (0-1)
641 shader_comp_main
.setVec3("bounds_NWU", glm::vec3(x_bounds_min
, y_bounds_max
, z_render_max
));
642 shader_comp_main
.setVec3("bounds_SEL", glm::vec3(x_bounds_max
, y_bounds_min
, z_render_min
));
645 shader_comp_main
.setInt("cmdl_shadows_enable", tar_cfg_enableShadows
? 1 : 0);
646 shader_comp_main
.setInt("cmdl_ao_enable", tar_cfg_enableAO
? 1 : 0);
647 shader_comp_main
.setInt("cmdl_ao_size", tar_cfg_aoSzie
);
648 shader_comp_main
.setInt("cmdl_outline_enable", tar_cfg_enableOutline
);
649 shader_comp_main
.setInt("cmdl_outline_size", tar_cfg_outlineSize
);
651 /* Bind texture samplers */
652 tex_background
.bindOnSlot(0);
653 shader_comp_main
.setInt("tex_background", 0);
655 fb_tex_playspace
.BindRTtoTexSlot(1);
656 shader_comp_main
.setInt("tex_playspace", 1);
658 fb_tex_objectives
.BindRTtoTexSlot(2);
659 shader_comp_main
.setInt("tex_objectives", 2);
661 tar_cfg_gradientMap
->bindOnSlot(4);
662 shader_comp_main
.setInt("tex_gradient", 4);
664 mesh_screen_quad
->Draw();
666 std::cout
<< "done!\n";
672 #pragma region auto_export_game
673 if (!m_onlyOutputMasks
) {
674 save_to_dds(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ "_radar.dds").c_str());
678 render_to_png(m_renderWidth
, m_renderHeight
, std::string(m_overviews_folder
+ m_mapfile_name
+ ".resources.final_raw.png").c_str());
680 #pragma region generate_radar_txt
682 std::cout
<< "Generating radar .TXT... ";
684 kv::DataBlock node_radar
= kv::DataBlock();
685 node_radar
.name
= m_mapfile_name
;
686 node_radar
.Values
.insert({ "material", "overviews/" + m_mapfile_name
});
688 node_radar
.Values
.insert({ "pos_x", std::to_string(view_origin
.x
) });
689 node_radar
.Values
.insert({ "pos_y", std::to_string(view_origin
.y
) });
690 node_radar
.Values
.insert({ "scale", std::to_string(render_ortho_scale
/ 1024.0f
) });
692 // Try resolve spawn positions
693 glm::vec3
* loc_spawnCT
= vmf_main
.calculateSpawnLocation(vmf::team::counter_terrorist
);
694 glm::vec3
* loc_spawnT
= vmf_main
.calculateSpawnLocation(vmf::team::terrorist
);
696 if (loc_spawnCT
!= NULL
) {
697 node_radar
.Values
.insert({ "CTSpawn_x", std::to_string(glm::round(remap(loc_spawnCT
->x
, view_origin
.x
, view_origin
.x
+ render_ortho_scale
, 0.0f
, 1.0f
) / 0.01f
) * 0.01f
) });
698 node_radar
.Values
.insert({ "CTSpawn_y", std::to_string(glm::round(remap(loc_spawnCT
->y
, view_origin
.y
, view_origin
.y
- render_ortho_scale
, 0.0f
, 1.0f
) / 0.01f
) * 0.01f
) });
700 if (loc_spawnT
!= NULL
) {
701 node_radar
.Values
.insert({ "TSpawn_x", std::to_string(glm::round(remap(loc_spawnT
->x
, view_origin
.x
, view_origin
.x
+ render_ortho_scale
, 0.0f
, 1.0f
) / 0.01f
) * 0.01f
) });
702 node_radar
.Values
.insert({ "TSpawn_y", std::to_string(glm::round(remap(loc_spawnT
->y
, view_origin
.y
, view_origin
.y
- render_ortho_scale
, 0.0f
, 1.0f
) / 0.01f
) * 0.01f
) });
705 std::ofstream
out(std::string(m_overviews_folder
+ m_mapfile_name
+ ".txt").c_str());
706 out
<< "// TAVR - AUTO RADAR. v 2.0.0\n";
707 node_radar
.Serialize(out
);
710 std::cout
<< "done!";
715 std::cout
<< "\n- Radar generation successful... cleaning up. -\n";
727 #ifndef entry_point_testing
728 int main(int argc
, const char** argv
) {
730 return app(argc
, argv
);
732 catch (cxxopts::OptionException
& e
) {
733 std::cerr
<< "Parse error: " << e
.what() << "\n";