Add menu for configuring raytracing options.

This commit is contained in:
Dario 2021-04-25 15:25:14 -03:00
parent 87b9c716d9
commit a68bffc544
6 changed files with 89 additions and 118 deletions

View File

@ -127,10 +127,15 @@ typedef struct {
float attenuationExponent;
float flickerIntensity;
unsigned int groupBits;
unsigned int minSamples;
unsigned int maxSamples;
} RT64_LIGHT;
typedef struct {
float resolutionScale;
unsigned int softLightSamples;
unsigned int giBounces;
float ambGiMixWeight;
bool denoiserEnabled;
} RT64_VIEW_CONFIG;
// Forward declaration of types.
typedef struct RT64_DEVICE RT64_DEVICE;
@ -201,6 +206,7 @@ typedef void(*DrawDevicePtr)(RT64_DEVICE* device, int vsyncInterval);
typedef void(*DestroyDevicePtr)(RT64_DEVICE* device);
typedef RT64_VIEW* (*CreateViewPtr)(RT64_SCENE* scenePtr);
typedef void(*SetViewPerspectivePtr)(RT64_VIEW *viewPtr, RT64_MATRIX4 viewMatrix, float fovRadians, float nearDist, float farDist);
typedef void(*SetViewConfigurationPtr)(RT64_VIEW *viewPtr, RT64_VIEW_CONFIG viewConfig);
typedef RT64_INSTANCE* (*GetViewRaytracedInstanceAtPtr)(RT64_VIEW *viewPtr, int x, int y);
typedef void(*DestroyViewPtr)(RT64_VIEW* viewPtr);
typedef RT64_SCENE* (*CreateScenePtr)(RT64_DEVICE* devicePtr);
@ -229,6 +235,7 @@ typedef struct {
DestroyDevicePtr DestroyDevice;
CreateViewPtr CreateView;
SetViewPerspectivePtr SetViewPerspective;
SetViewConfigurationPtr SetViewConfiguration;
GetViewRaytracedInstanceAtPtr GetViewRaytracedInstanceAt;
DestroyViewPtr DestroyView;
CreateScenePtr CreateScene;
@ -265,6 +272,7 @@ inline RT64_LIBRARY RT64_LoadLibrary() {
lib.DestroyDevice = (DestroyDevicePtr)(GetProcAddress(lib.handle, "RT64_DestroyDevice"));
lib.CreateView = (CreateViewPtr)(GetProcAddress(lib.handle, "RT64_CreateView"));
lib.SetViewPerspective = (SetViewPerspectivePtr)(GetProcAddress(lib.handle, "RT64_SetViewPerspective"));
lib.SetViewConfiguration = (SetViewConfigurationPtr)(GetProcAddress(lib.handle, "RT64_SetViewConfiguration"));
lib.GetViewRaytracedInstanceAt = (GetViewRaytracedInstanceAtPtr)(GetProcAddress(lib.handle, "RT64_GetViewRaytracedInstanceAt"));
lib.DestroyView = (DestroyViewPtr)(GetProcAddress(lib.handle, "RT64_DestroyView"));
lib.CreateScene = (CreateScenePtr)(GetProcAddress(lib.handle, "RT64_CreateScene"));

View File

@ -1,29 +0,0 @@
{
"presets" : [
{
"name": "Simple",
"lightSampleSettings": [
]
},
{
"name": "Soft",
"lightSampleSettings": [
{
"groupBits": 1,
"minSamples": 8,
"maxSamples": 32
},
{
"groupBits": 2,
"minSamples": 8,
"maxSamples": 16
},
{
"groupBits": 16,
"minSamples": 8,
"maxSamples": 8
}
]
}
]
}

View File

@ -55,6 +55,7 @@ static const u8 optSmallStr[][32] = {
static const u8 menuStr[][32] = {
{ TEXT_OPT_OPTIONS },
{ TEXT_OPT_CAMERA },
{ TEXT_OPT_RT64 },
{ TEXT_OPT_CONTROLS },
{ TEXT_OPT_VIDEO },
{ TEXT_OPT_AUDIO },
@ -75,6 +76,16 @@ static const u8 optsCameraStr[][32] = {
{ TEXT_OPT_CAMON },
};
#ifdef RAPI_RT64
static const u8 optsRT64Str[][32] = {
{ TEXT_OPT_RESSCALE },
{ TEXT_OPT_SPHEREL },
{ TEXT_OPT_GI },
{ TEXT_OPT_GIWEIGHT },
{ TEXT_OPT_DENOISER },
};
#endif
static const u8 optsVideoStr[][32] = {
{ TEXT_OPT_FSCREEN },
{ TEXT_OPT_TEXFILTER },
@ -235,6 +246,17 @@ static struct Option optsCamera[] = {
};
#endif
#ifdef RAPI_RT64
static struct Option optsRT64[] = {
DEF_OPT_SCROLL( optsRT64Str[0], &configRT64ResScale, 10, 200, 1 ),
DEF_OPT_TOGGLE( optsRT64Str[1], &configRT64SphereLights ),
DEF_OPT_TOGGLE( optsRT64Str[2], &configRT64GI ),
DEF_OPT_SCROLL( optsRT64Str[3], &configRT64GIStrength, 5, 95, 1 ),
DEF_OPT_TOGGLE( optsRT64Str[4], &configRT64Denoiser ),
DEF_OPT_BUTTON( optsVideoStr[9], optvideo_apply ),
};
#endif
static struct Option optsControls[] = {
DEF_OPT_BIND( bindStr[ 2], configKeyA ),
DEF_OPT_BIND( bindStr[ 3], configKeyB ),
@ -290,10 +312,13 @@ static struct Option optsCheats[] = {
#ifdef BETTERCAMERA
static struct SubMenu menuCamera = DEF_SUBMENU( menuStr[1], optsCamera );
#endif
static struct SubMenu menuControls = DEF_SUBMENU( menuStr[2], optsControls );
static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[3], optsVideo );
static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[4], optsAudio );
static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[6], optsCheats );
#ifdef RAPI_RT64
static struct SubMenu menuRT64 = DEF_SUBMENU( menuStr[2], optsRT64 );
#endif
static struct SubMenu menuControls = DEF_SUBMENU( menuStr[3], optsControls );
static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[4], optsVideo );
static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[5], optsAudio );
static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[7], optsCheats );
/* main options menu definition */
@ -301,12 +326,15 @@ static struct Option optsMain[] = {
#ifdef BETTERCAMERA
DEF_OPT_SUBMENU( menuStr[1], &menuCamera ),
#endif
DEF_OPT_SUBMENU( menuStr[2], &menuControls ),
DEF_OPT_SUBMENU( menuStr[3], &menuVideo ),
DEF_OPT_SUBMENU( menuStr[4], &menuAudio ),
DEF_OPT_BUTTON ( menuStr[5], optmenu_act_exit ),
#ifdef RAPI_RT64
DEF_OPT_SUBMENU( menuStr[2], &menuRT64 ),
#endif
DEF_OPT_SUBMENU( menuStr[3], &menuControls ),
DEF_OPT_SUBMENU( menuStr[4], &menuVideo ),
DEF_OPT_SUBMENU( menuStr[5], &menuAudio ),
DEF_OPT_BUTTON ( menuStr[6], optmenu_act_exit ),
// NOTE: always keep cheats the last option here because of the half-assed way I toggle them
DEF_OPT_SUBMENU( menuStr[6], &menuCheats )
DEF_OPT_SUBMENU( menuStr[7], &menuCheats )
};
static struct SubMenu menuMain = DEF_SUBMENU( menuStr[0], optsMain );

View File

@ -93,6 +93,13 @@ bool configHUD = true;
#ifdef DISCORDRPC
bool configDiscordRPC = true;
#endif
#ifdef RAPI_RT64
unsigned int configRT64ResScale = 100;
bool configRT64SphereLights = false;
bool configRT64GI = false;
unsigned int configRT64GIStrength = 80;
bool configRT64Denoiser = false;
#endif
static const struct ConfigOption options[] = {
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen},
@ -140,7 +147,14 @@ static const struct ConfigOption options[] = {
{.name = "skip_intro", .type = CONFIG_TYPE_BOOL, .boolValue = &configSkipIntro},
#ifdef DISCORDRPC
{.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC},
#endif
#endif
#ifdef RAPI_RT64
{.name = "rt64_res_scale", .type = CONFIG_TYPE_UINT, .uintValue = &configRT64ResScale},
{.name = "rt64_sphere_lights", .type = CONFIG_TYPE_BOOL, .boolValue = &configRT64SphereLights},
{.name = "rt64_gi", .type = CONFIG_TYPE_BOOL, .boolValue = &configRT64GI},
{.name = "rt64_gi_strength", .type = CONFIG_TYPE_UINT, .uintValue = &configRT64GIStrength},
{.name = "rt64_denoiser", .type = CONFIG_TYPE_BOOL, .boolValue = &configRT64Denoiser},
#endif
};
// Reads an entire line from a file (excluding the newline character) and returns an allocated string

View File

@ -59,6 +59,13 @@ extern bool configSkipIntro;
#ifdef DISCORDRPC
extern bool configDiscordRPC;
#endif
#ifdef RAPI_RT64
extern unsigned int configRT64ResScale;
extern bool configRT64SphereLights;
extern bool configRT64GI;
extern unsigned int configRT64GIStrength;
extern bool configRT64Denoiser;
#endif
void configfile_load(const char *filename);
void configfile_save(const char *filename);

View File

@ -7,6 +7,7 @@
#endif
extern "C" {
# include "../configfile.h"
# include "../../game/area.h"
# include "../../game/level_update.h"
# include "../fs/fs.h"
@ -49,10 +50,8 @@ using json = nlohmann::json;
#define MAX_AREAS 3
#define MAX_LEVEL_LIGHTS 128
#define LEVEL_LIGHTS_FILENAME FS_BASEDIR "/rt64/level_lights.json"
#define LIGHT_SAMPLE_PRESETS_FILENAME FS_BASEDIR "/rt64/light_sample_presets.json"
#define GEO_LAYOUT_MODS_FILENAME FS_BASEDIR "/rt64/geo_layout_mods.json"
#define TEXTURE_MODS_FILENAME FS_BASEDIR "/rt64/texture_mods.json"
#define LIGHT_SAMPLE_PRESET_DEFAULT "Simple"
struct ShaderProgram {
uint32_t shader_id;
@ -90,7 +89,6 @@ struct RecordedMod {
};
// Convention of bits for different lights.
// The tiers allow more detailed control over the performance of areas of the game that are more demanding than others.
// 1 - Directional Tier A
// 2 - Directional Tier B
// 4 - Stage Tier A
@ -100,16 +98,6 @@ struct RecordedMod {
// 64 - Particles Tier A
// 128 - Particles Tier B
struct LightSampleSetting {
unsigned int groupBits;
unsigned int minSamples;
unsigned int maxSamples;
};
struct LightSamplePreset {
std::vector<LightSampleSetting> settings;
};
struct {
HWND hwnd;
@ -130,8 +118,6 @@ struct {
std::unordered_map<uint64_t, RecordedMesh> dynamicMeshes;
std::unordered_map<uint64_t, RecordedMeshKey> dynamicMeshKeys;
std::unordered_map<uint32_t, ShaderProgram *> shaderPrograms;
LightSamplePreset activeLightSamplePreset;
std::map<std::string, LightSamplePreset> lightSamplePresets;
int cachedMeshesPerFrame;
RT64_LIGHT lights[MAX_LIGHTS];
unsigned int lightCount;
@ -219,49 +205,6 @@ void gfx_rt64_load_light(const json &jlight, RT64_LIGHT *light) {
light->groupBits = jlight["groupBits"];
}
void gfx_rt64_set_light_samples(RT64_LIGHT *light) {
unsigned int minSamples = 1;
unsigned int maxSamples = 1;
for (const auto &it : RT64.activeLightSamplePreset.settings) {
if (it.groupBits & light->groupBits) {
minSamples = std::max(minSamples, it.minSamples);
maxSamples = std::max(maxSamples, it.maxSamples);
}
}
light->minSamples = minSamples;
light->maxSamples = std::max(minSamples, maxSamples);
}
LightSamplePreset gfx_rt64_load_light_sample_preset(const json &jpreset) {
LightSamplePreset preset;
for (const json &jsetting : jpreset["lightSampleSettings"]) {
LightSampleSetting setting;
setting.groupBits = jsetting["groupBits"];
setting.minSamples =jsetting["minSamples"];
setting.maxSamples =jsetting["maxSamples"];
preset.settings.push_back(setting);
}
return preset;
}
void gfx_rt64_load_light_sample_presets() {
std::ifstream i(LIGHT_SAMPLE_PRESETS_FILENAME);
if (i.is_open()) {
json j;
i >> j;
for (const json &jpreset : j["presets"]) {
const std::string name = jpreset["name"];
RT64.lightSamplePresets[name] = gfx_rt64_load_light_sample_preset(jpreset);
}
}
else {
fprintf(stderr, "Unable to load " LIGHT_SAMPLE_PRESETS_FILENAME ". Defaulting to hard shadows only.\n");
}
}
uint64_t gfx_rt64_load_normal_map_mod(const json &jnormal) {
return gfx_rt64_get_texture_name_hash(jnormal["name"]);
}
@ -333,16 +276,6 @@ void gfx_rt64_load_level_lights() {
}
}
void gfx_rt64_set_samples_level_lights() {
for (int l = 0; l < MAX_LEVELS; l++) {
for (int a = 0; a < MAX_AREAS; a++) {
for (int i = 0; i < RT64.levelLightCounts[l][a]; i++) {
gfx_rt64_set_light_samples(&RT64.levelLights[l][a][i]);
}
}
}
}
void gfx_rt64_save_level_lights() {
std::ofstream o(LEVEL_LIGHTS_FILENAME);
if (o.is_open()) {
@ -746,6 +679,16 @@ static void onkeyup(WPARAM w_param, LPARAM l_param) {
}
}
void gfx_rt64_apply_config() {
RT64_VIEW_CONFIG config;
config.resolutionScale = configRT64ResScale / 100.0f;
config.softLightSamples = configRT64SphereLights ? 1 : 0;
config.giBounces = configRT64GI ? 1 : 0;
config.ambGiMixWeight = configRT64GIStrength / 100.0f;
config.denoiserEnabled = configRT64Denoiser;
RT64.lib.SetViewConfiguration(RT64.view, config);
}
LRESULT CALLBACK gfx_rt64_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if ((RT64.inspector != nullptr) && RT64.lib.HandleMessageInspector(RT64.inspector, message, wParam, lParam)) {
return true;
@ -795,6 +738,11 @@ LRESULT CALLBACK gfx_rt64_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARA
onkeyup(wParam, lParam);
break;
case WM_PAINT: {
if (configWindow.settings_changed) {
gfx_rt64_apply_config();
configWindow.settings_changed = false;
}
LARGE_INTEGER ElapsedMicroseconds;
// Run one game iteration.
@ -864,7 +812,7 @@ static void gfx_rt64_wapi_init(const char *window_title) {
wc.lpfnWndProc = gfx_rt64_wnd_proc;
wc.hInstance = GetModuleHandle(0);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = "RT64Sample";
wc.lpszClassName = "RT64";
RegisterClass(&wc);
// Create window.
@ -1001,13 +949,8 @@ static void gfx_rt64_wapi_init(const char *window_title) {
}
}
// Load the light sample presets and choose the default preset.
gfx_rt64_load_light_sample_presets();
RT64.activeLightSamplePreset = RT64.lightSamplePresets[LIGHT_SAMPLE_PRESET_DEFAULT];
// Load the global lights from a file.
gfx_rt64_load_level_lights();
gfx_rt64_set_samples_level_lights();
// Initialize camera.
RT64.viewMatrix = RT64.identityTransform;
@ -1020,6 +963,9 @@ static void gfx_rt64_wapi_init(const char *window_title) {
// Load the texture mods from a file.
gfx_rt64_load_texture_mods();
// Apply loaded configuration.
gfx_rt64_apply_config();
}
static void gfx_rt64_wapi_shutdown(void) {
@ -1376,8 +1322,6 @@ static void gfx_rt64_add_light(RT64_LIGHT *lightMod, RT64_MATRIX4 transform) {
auto &light = RT64.lights[RT64.lightCount++];
light = *lightMod;
gfx_rt64_set_light_samples(&light);
light.position = transform_position_affine(transform, lightMod->position);
// Use a vector that points in all three axes in case the node uses non-uniform scaling to get an estimate.
@ -1532,7 +1476,6 @@ static void gfx_rt64_rapi_start_frame(void) {
RT64.lib.SetLightsInspector(RT64.inspector, lights, lightCount, MAX_LEVEL_LIGHTS);
}
gfx_rt64_set_samples_level_lights();
memcpy(RT64.lights, lights, sizeof(RT64_LIGHT) * (*lightCount));
RT64.lightCount = *lightCount;
}