Skip to content

Commit

Permalink
Better portal vis culling - add game settings module #35
Browse files Browse the repository at this point in the history
- fix various culling related issues
- the exit portal is now doing proper area visibility checks resulting in less drawing
- area visible through the exit portal is now culled by default if the entry portal is not visible -> can be tweaked via game_settings.toml
- add game_settings module using file `portal2-rtx/game_settings.toml` (auto generates but accepts valid tweaks to settings
  • Loading branch information
xoxor4d committed Dec 10, 2024
1 parent bf68394 commit e8176ef
Show file tree
Hide file tree
Showing 17 changed files with 996 additions and 324 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,19 @@ If you want to support my work, consider buying me some coffee:
<br>

#### ️ Info:
#### ️ Info:
- See the [Wiki](https://github.com/xoxor4d/p2-rtx/wiki/Compatibility-Mod-Feature-Guide) for in-depth guides on features that come with the compatibility mod 🍓
- Current releases ship with a [custom build of the remix-dxvk runtime](https://github.com/xoxor4d/dxvk-remix/tree/combine/pairs_mask_rs) which includes necessary changes
for Portal 2 (`bin/.trex/d3d9.dll`)
- Releases also include [Ultimate-ASI-Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases) (`bin/winmm.dll`)

<br>

#### ⚠️ Most Noteworthy Issues:
- Some engine tweaks that are required to make the game compatible result in CPU bottlenecks on some maps (software skinning instead of HW skinning). This may or may not improve in future updates.

<br>

#### ⚠️ Troubleshooting:
- Unable to load `_rtx.asi`:
Download and install [DirectX End-User Runtimes (June 2010)](https://www.microsoft.com/en-ie/download/details.aspx?id=8109)
Expand All @@ -89,7 +94,7 @@ Make sure that you installed the `_remix_mod.zip`. See [Issue #13](https://githu
- Game is too dark, sunlight is leaking on certain maps, textures look flat:
This is not an issue with the compatibility mod itself. It's up to the people modding the game using the remix toolset to place proper lights and overhaul textures and meshes.

- Look at [Closed Issues](https://github.com/xoxor4d/p2-rtx/issues?q=is%3Aissue+is%3Aclosed) to see if people had similar but now resolved issues.
- Look at [Closed Issues](https://github.com/xoxor4d/p2-rtx/issues?q=is%3Aissue+is%3Aclosed) or [Discussions](https://github.com/xoxor4d/p2-rtx/discussions) to see if people had similar issues

<br>

Expand Down
25 changes: 14 additions & 11 deletions assets/portal2-rtx/map_settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
sp_a4_finale2 = { distance = 150000, color = [180, 140, 100] }


# Override culling - Specified leafs will always be rendered when in the specified area
# Override culling per game area
# Parameters ---------------------------------------------------------------------------------------------------------------------------------
#
# area: the area the player has to be in
Expand All @@ -30,7 +30,6 @@
# |> areas: area/s to hide [array]
# |> N_leafs: only hide area/s when NOT in specified leaf/s [array]


[CULL]
sp_a1_intro1 = [
{ area = 2, leafs = [436, 950] },
Expand Down Expand Up @@ -88,18 +87,22 @@
]

sp_a4_laser_platform = [
{ area = 1, cull = 1 },
{ area = 1, cull = 1, leafs = [133] },
{ area = 2, hide_leafs = [89, 99, 100, 158, 171, 178, 901], hide_areas = [
{ areas = [0, 3, 4], N_leafs = [] }
]},
]

sp_a4_speed_tb_catch = [
{ area = 5, areas = [1] },
]

sp_a4_finale2 = [
{ area = 1, leafs = [554, 591, 630, 633, 646] },
{ area = 4, leafs = [48, 53, 62, 134, 135, 150, 156] },
{ area = 1, areas = [4] },
{ area = 4, leafs = [48, 53, 62, 134, 135, 150, 156], areas = [1] },

{ area = 9, cull = 2, leafs = [902], hide_areas = [
{ areas = [10], N_leafs = [939, 942, 946] },
{ areas = [10], N_leafs = [938, 939, 942, 946] },
{ areas = [11] },
]},

Expand All @@ -108,7 +111,7 @@
{ areas = [9], N_leafs = [902, 906, 912, 918, 922, 926, 937, 940] },
]},

{ area = 12, cull = 2, hide_areas = [
{ area = 12, cull = 2, areas = [15], hide_areas = [
{ areas = [9] },
]},

Expand All @@ -117,10 +120,10 @@
]},

{ area = 15, cull = 2, leafs = [1536, 1651, 1680], areas = [12], hide_areas = [
{ areas = [9] },
{ areas = [9, 16] },
]},

{ area = 16, areas = [17], leafs = [1536, 1582, 1602, 1603, 1615] },
{ area = 16, areas = [14, 15, 17], leafs = [1536, 1582, 1602, 1603, 1615] },
]


Expand Down Expand Up @@ -192,7 +195,7 @@
]}


# Spawns portals using the remix api - useful for area-connecting portals (between doors / rooms)
# Spawn portals using the remix api - useful for area-connecting portals (between doors / rooms)
# Parameters ---------------------------------------------------------------------------------------------------------------------------------
#
# pair: number of pair (0 to 1 - only two pairs are currently supported)
Expand All @@ -209,7 +212,7 @@
]}
]

# first portal in first pair will be moved to "2108 774 -18" when a certain '.vcd' finishes (because it would be randomly floating in the air otherwise)
# first portal in first pair will be moved to "2108 774 -18" when a certain '.vcd' finishes (because it would be floating in the air otherwise)
sp_a4_finale2 = [
{ pair = 0, portals = [
{ position = [1780, 110, 1340], rotation = [-90, 180, 0], scale = [260, 130], square_mask = 1 },
Expand Down
1 change: 1 addition & 0 deletions src/components/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace components
{
mem_allocator_.clear();
_register(new flags());
_register(new game_settings());
_register(new choreo_events());
_register(new main_module());
_register(new model_render());
Expand Down
1 change: 1 addition & 0 deletions src/components/loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace components
}

#include "modules/flags.hpp"
#include "modules/game_settings.hpp"
#include "modules/choreo_events.hpp"
#include "modules/main_module.hpp"
#include "modules/model_render.hpp"
Expand Down
125 changes: 125 additions & 0 deletions src/components/modules/game_settings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "std_include.hpp"

namespace components
{
void game_settings::write_toml()
{
std::ofstream file;
file.open((game::root_path + "portal2-rtx\\game_settings.toml").c_str());

file << "# This file is autogenerated. Valid modifications of settings are considered and will be written back to the file." << std::endl << std::endl;

const std::uint32_t setting_count = sizeof(var_definitions) / sizeof(variable);
for (auto s = 0u; s < setting_count; s++)
{
auto var = reinterpret_cast<variable*>(reinterpret_cast<char*>(&vars) + s * sizeof(variable));

file << "# " << var->m_desc << std::endl;
file << "# Type: " << var->get_str_type() << " || Default: " << var->get_str_value(true) << std::endl;
file << var->m_name << " = " << var->get_str_value() << std::endl << std::endl;
}

file.close();
}

bool game_settings::parse_toml()
{
std::ifstream file;
if (utils::open_file_homepath("portal2-rtx\\", "game_settings.toml", file))
{
// file exists
file.close();

try
{
auto config = toml::parse("portal2-rtx\\game_settings.toml");

// #
auto to_float = [](const toml::value& entry, float default_setting = 0.0f)
{
if (entry.is_floating()) {
return static_cast<float>(entry.as_floating());
}

if (entry.is_integer()) {
return static_cast<float>(entry.as_integer());
}

try { // this will fail and let the user know whats wrong
return static_cast<float>(entry.as_floating());
}
catch (toml::type_error& err) {
game::console(); printf("%s\n", err.what());
}

return default_setting;
};

// #
auto to_int = [](const toml::value& entry, int default_setting = 0)
{
if (entry.is_floating()) {
return static_cast<int>(entry.as_floating());
}

if (entry.is_integer()) {
return static_cast<int>(entry.as_integer());
}

try { // this will fail and let the user know whats wrong
return static_cast<int>(entry.as_integer());
}
catch (toml::type_error& err) {
game::console(); printf("%s\n", err.what());
}

return default_setting;
};

// ---------------------------------------

#define ASSIGN(name) \
if (config.contains((#name))) { \
switch (vars.##name.get_type()) { \
case (var_type_integer): \
vars.##name.set_var(to_int(config.at(#name), vars.##name.get_as<int>()), true); break; \
case (var_type_value): \
vars.##name.set_var(to_float(config.at(#name), vars.##name.get_as<float>()), true); break; \
} \
}

ASSIGN(portal_visibility_culling);
ASSIGN(check_nodes_for_potential_lights);

#undef ASSIGN
}

catch (const toml::syntax_error& err)
{
game::console();
printf("%s\n", err.what());
printf("[GameSettings] Not writing defaults! Please check 'game_settings.toml' or remove the file to re-generate it on next startup!\n");
return false;
}
}

// always re-write file
write_toml();

return true;
}

ConCommand xo_gamesettings_update {};
void xo_gamesettings_update_fn()
{
game_settings::parse_toml();
}

game_settings::game_settings()
{
parse_toml();

// ----
game::con_add_command(&xo_gamesettings_update, "xo_gamesettings_update", xo_gamesettings_update_fn, "Reloads the game_settings.toml file");
}
}
140 changes: 140 additions & 0 deletions src/components/modules/game_settings.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#pragma once

namespace components
{
class game_settings : public component
{
public:
game_settings();
~game_settings() = default;

static inline game_settings* p_this = nullptr;
static auto get() { return &vars; }

static void write_toml();
static bool parse_toml();

private:
union var_value
{
int integer;
float value;
};

enum var_type : std::uint8_t
{
var_type_integer = 0,
var_type_value = 1,
};

class variable
{
public:
variable(const char* name, const char* desc, const int integer) :
m_name(name), m_desc(desc), m_type(var_type_integer)
{
m_var.integer = integer;
m_var_default.integer = integer;
}

variable(const char* name, const char* desc, const float value) :
m_name(name), m_desc(desc), m_type(var_type_value)
{
m_var.value = value;
m_var_default.value = value;
}

const char* get_str_value(bool get_default = false) const
{
switch (m_type)
{
case var_type_integer:
return utils::va("%d", !get_default ? m_var.integer : m_var_default.integer);

case var_type_value:
return utils::va("%.2f", !get_default ? m_var.value : m_var_default.value);
}

return nullptr;
}

const char* get_str_type() const
{
switch (m_type)
{
case var_type_integer:
return "INT";

case var_type_value:
return "FLOAT";
}

return nullptr;
}

template <typename T>
T get_as(bool default_val = false)
{
if (m_type == var_type_integer) {
return static_cast<T>(!default_val ? m_var.integer : m_var_default.integer);
}

if (m_type == var_type_value) {
return static_cast<T>(!default_val ? m_var.value : m_var_default.value);
}

throw std::runtime_error("Unknown var_type");
}

var_type get_type() const {
return m_type;
}

// sets var and writes toml
void set_var(const int integer, bool no_toml_update = false)
{
m_var.integer = integer;
if (!no_toml_update) {
write_toml();
}
}

// sets var and writes toml
void set_var(const float value, bool no_toml_update = false)
{
m_var.value = value;
if (!no_toml_update) {
write_toml();
}
}

const char* m_name;
const char* m_desc;

private:
var_value m_var;
var_value m_var_default;
var_type m_type;
};


struct var_definitions
{
variable portal_visibility_culling =
{
"portal_visibility_culling",
"Enable culling of exit portal areas when the entry portal is not visible from the players POV (++ performance)",
1
};

variable check_nodes_for_potential_lights =
{
"check_nodes_for_potential_lights",
"Check each node for potential emissive light strips (rectangular with limited depth) & force-draw node on match.",
1
};
}; //STATIC_ASSERT_SIZE(var_definitions, 2 * sizeof(variable));

static inline var_definitions vars = {};
};
}
Loading

0 comments on commit e8176ef

Please sign in to comment.