diff --git a/.gitignore b/.gitignore index a956413..ee6efd6 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,6 @@ tags # ctags files used with vim # I don't want to include the noise textures because they originated from the renderer's assets which are kept # elsewhere. d1/assets/textures/noise + +# make sure to include DXC dlls +!RT/Renderer/Backend/DX12/DXC/bin/* diff --git a/CMakeLists.txt b/CMakeLists.txt index d780d3f..4b03ca0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ D1X_RAYTRACER_NAME="D1X_RAYTRACER" D1X_RAYTRACER_VERSION_MAJORi=1 D1X_RAYTRACER_VERSION_MINORi=0 -D1X_RAYTRACER_VERSION_MICROi=0 +D1X_RAYTRACER_VERSION_MICROi=1 #DXX-Retro last used version DXX_VERSION_MAJORi=0 diff --git a/RT/Core/Config.cpp b/RT/Core/Config.cpp index a54f899..75b320f 100644 --- a/RT/Core/Config.cpp +++ b/RT/Core/Config.cpp @@ -202,6 +202,32 @@ bool RT_ConfigReadInt(RT_Config *cfg, RT_String key, int *value) return result; } +bool RT_ConfigReadVec2(RT_Config *cfg, RT_String key, RT_Vec2 *value) +{ + bool result = false; + + RT_String string; + if (RT_ConfigReadString(cfg, key, &string)) + { + RT_ParseFloatResult parse_x = RT_ParseFloat(string); + string = RT_StringAdvance(string, parse_x.advance); + string = RT_StringAdvance(string, RT_StringFindChar(string, ',') + 1); + string = RT_StringAdvance(string, RT_StringFindFirstNonWhitespace(string)); + RT_ParseFloatResult parse_y = RT_ParseFloat(string); + + result = (parse_x.success && + parse_y.success); + + if (result) + { + value->x = parse_x.value; + value->y = parse_y.value; + } + } + + return result; +} + bool RT_ConfigReadVec3(RT_Config *cfg, RT_String key, RT_Vec3 *value) { bool result = false; @@ -264,6 +290,13 @@ void RT_ConfigWriteInt(RT_Config *cfg, RT_String key, int value) cfg->last_modified_time = RT_GetHighResTime().value; } +void RT_ConfigWriteVec2(RT_Config *cfg, RT_String key, RT_Vec2 value) +{ + RT_ConfigKeyValue *kv = RT_ConfigFindOrCreateKeyValue(cfg, key); + kv->value_count = snprintf(kv->value, sizeof(kv->value), "%f, %f", value.x, value.y); + cfg->last_modified_time = RT_GetHighResTime().value; +} + void RT_ConfigWriteVec3(RT_Config *cfg, RT_String key, RT_Vec3 value) { RT_ConfigKeyValue *kv = RT_ConfigFindOrCreateKeyValue(cfg, key); diff --git a/RT/Core/Config.h b/RT/Core/Config.h index 72d67f4..ebde5b8 100644 --- a/RT/Core/Config.h +++ b/RT/Core/Config.h @@ -40,10 +40,12 @@ RT_API void RT_DeserializeConfigFromString(RT_Config *cfg, RT_String string); RT_API bool RT_ConfigReadString(RT_Config *cfg, RT_String key, RT_String *value); RT_API bool RT_ConfigReadFloat(RT_Config *cfg, RT_String key, float *value); RT_API bool RT_ConfigReadInt(RT_Config *cfg, RT_String key, int *value); +RT_API bool RT_ConfigReadVec2(RT_Config *cfg, RT_String key, RT_Vec2 *value); RT_API bool RT_ConfigReadVec3(RT_Config *cfg, RT_String key, RT_Vec3 *value); RT_API void RT_ConfigWriteString(RT_Config *cfg, RT_String key, RT_String value); RT_API void RT_ConfigWriteFloat(RT_Config *cfg, RT_String key, float value); RT_API void RT_ConfigWriteInt(RT_Config *cfg, RT_String key, int value); +RT_API void RT_ConfigWriteVec2(RT_Config *cfg, RT_String key, RT_Vec2 value); RT_API void RT_ConfigWriteVec3(RT_Config *cfg, RT_String key, RT_Vec3 value); RT_API bool RT_ConfigEraseKey(RT_Config *cfg, RT_String key); // Returns true if the key existed RT_API RT_String RT_SerializeConfigToString(RT_Arena *arena, RT_Config *cfg); diff --git a/RT/Game/Lights.c b/RT/Game/Lights.c index 76c6a9f..64f2f8c 100644 --- a/RT/Game/Lights.c +++ b/RT/Game/Lights.c @@ -1,15 +1,56 @@ +#include "physfs.h" + #include "Lights.h" #include "textures.h" -#include "Core/Arena.h" #include "dx12.h" #include "gr.h" #include "RTgr.h" #include "RTmaterials.h" +#include "Core/Arena.h" +#include "Core/Config.h" +#include "Core/String.h" + float g_light_multiplier = 1.0; float g_light_multiplier_default = 1.0; const float FLT_MAX = 3.402823466e+38F; +typedef struct RT_SettingsNotification +{ + float timer; + ImVec4 color; + char *message; +} RT_SettingsNotification; + +static inline void RT_SetSettingsNotification(RT_SettingsNotification *notif, char *name, ImVec4 color) +{ + notif->timer = 2.0f; + notif->color = color; + notif->message = name; +} + +static inline void RT_ShowSettingsNotification(RT_SettingsNotification *notif) +{ + if (notif->timer > 0.0f) + { + ImVec4 color = notif->color; + color.w = notif->timer / 2.0f; + + igPushStyleColor_Vec4(ImGuiCol_Text, color); + igText(notif->message); + igPopStyleColor(1); + + notif->timer -= 1.0f / 60.0f; // hardcoded nonsense + } + else + { + igDummy((ImVec2){0.0f, igGetFontSize()}); + } +} + +static RT_SettingsNotification g_lights_notification; +static RT_SettingsNotification g_headlights_notification; + RT_LightDefinition g_light_definitions[] = { // White light fixtures @@ -152,6 +193,41 @@ RT_LightDefinition g_light_definitions[] = }, }; +static RT_LightDefinition g_default_light_definitions[RT_ARRAY_COUNT(g_light_definitions)]; + +static RT_HeadlightSettings g_default_headlights = { + .pos_offset_horz = 3.0f, + .pos_offset_vert = -2.0f, + .skew_horz = 0.1f, + .skew_vert = 0.06f, + .radius = 0.05f, + .brightness = 1.5f, + .spot_angle = 0.05f, + .spot_softness = 0.05f, +}; + +void RT_InitLightStuff() +{ + memcpy(&g_headlights, &g_default_headlights, sizeof(g_headlights)); + memcpy(g_default_light_definitions, g_light_definitions, sizeof(g_default_light_definitions)); + + RT_LoadLightSettings(); + g_lights_notification.timer = 0.0f; + + RT_LoadHeadLightSettings(); + g_headlights_notification.timer = 0.0f; +} + +void RT_ResetLightSettings() +{ + g_light_multiplier_default = g_light_multiplier = 1.0f; + + memcpy(g_light_definitions, g_default_light_definitions, sizeof(g_default_light_definitions)); + g_pending_light_update = true; + + RT_SetSettingsNotification(&g_lights_notification, "Reset Light Settings", (ImVec4){0.5f, 0.7f, 1.0f, 1.0f}); +} + int RT_IsLight(int tmap) { //TODO: If this starts to become a performance bottleneck, add a hashmap so the lookups can be done in O(1) @@ -228,8 +304,69 @@ RT_Light RT_InitLight(RT_LightDefinition definition, RT_Vertex* vertices, RT_Vec void RT_ShowLightMenu() { - igBegin("Light Explorer", false, ImGuiWindowFlags_AlwaysAutoResize); - if(igSliderFloat("Global brightness: ", &g_light_multiplier_default, 0.000001f, 15.0f, "%f", ImGuiSliderFlags_Logarithmic)){ + igBegin("Light Explorer", NULL, ImGuiWindowFlags_AlwaysAutoResize); + + igText("Headlights"); + igPushID_Str("Headlights"); + { + if (igButton("Load Settings", (ImVec2){0, 0})) + { + RT_LoadHeadLightSettings(); + } + + igSameLine(0.0f, -1.0f); + + if (igButton("Save Settings", (ImVec2){0, 0})) + { + RT_SaveHeadLightSettings(); + } + + igSameLine(0.0f, -1.0f); + + if (igButton("Reset Settings", (ImVec2){0, 0})) + { + RT_ResetHeadLightSettings(); + } + + RT_ShowSettingsNotification(&g_headlights_notification); + + RT_HeadlightSettings *h = &g_headlights; + igSliderFloat("Horizontal Position Offset", &h->pos_offset_horz, 0.0f, 15.0f, "%.02f", 0); + igSliderFloat("Vertical Position Offset", &h->pos_offset_vert, -5.0f, 5.0f, "%.02f", 0); + igSliderFloat("Horizontal Skew", &h->skew_horz, 0.0f, 0.4f, "%.02f", 0); + igSliderFloat("Vertical Skew", &h->skew_vert, -0.2f, 0.2f, "%.02f", 0); + igSliderFloat("Light Radius", &h->radius, 0.01f, 0.4f, "%.02f", 0); + igSliderFloat("Brightness", &h->brightness, 0.0f, 5.0f, "%.02f", 0); + igSliderFloat("Spot Angle", &h->spot_angle, 0.01f, 0.12f, "%.02f", 0); + igSliderFloat("Spot Softness", &h->spot_softness, 0.01f, 0.12f, "%.02f", 0); + igDummy((ImVec2){0.0f, igGetFontSize()}); + } + igPopID(1); + + igText("Level Lights"); + + if (igButton("Load Settings", (ImVec2){0, 0})) + { + RT_LoadLightSettings(); + } + + igSameLine(0.0f, -1.0f); + + if (igButton("Save Settings", (ImVec2){0, 0})) + { + RT_SaveLightSettings(); + } + + igSameLine(0.0f, -1.0f); + + if (igButton("Reset Settings", (ImVec2){0, 0})) + { + RT_ResetLightSettings(); + } + + RT_ShowSettingsNotification(&g_lights_notification); + + if (igSliderFloat("Global brightness", &g_light_multiplier_default, 0.000001f, 15.0f, "%f", ImGuiSliderFlags_Logarithmic)) { g_light_multiplier = g_light_multiplier_default; g_pending_light_update = true; } @@ -321,4 +458,225 @@ void RT_VisualizeLight(RT_Light* light) RT_RasterLineWorld(pos, RT_Vec3Add(pos, RT_Vec3Make(0.0,0.0,-scale.z)), RT_Vec4Make(1.0, 0.0, 0.0, 1.0)); break; } -} \ No newline at end of file +} + +void RT_LoadLightSettings() +{ + PHYSFS_mkdir("lights"); + + bool success = true; + + // ------------------------------------------------------------------ + // Read global light settings + + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + if (RT_DeserializeConfigFromFile(cfg, "lights/global_lights.vars")) + { + RT_ConfigReadFloat(cfg, RT_StringLiteral("global_light_multiplier"), &g_light_multiplier_default); + g_light_multiplier = g_light_multiplier_default; + } + else + { + success = false; + } + } + + // ------------------------------------------------------------------ + // Read all da rest + + for (size_t light_index = 0; light_index < RT_ARRAY_COUNT(g_light_definitions); light_index++) + { + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_LightDefinition *def = &g_light_definitions[light_index]; + + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + char *file_name = RT_ArenaPrintF(&g_thread_arena, "lights/%s.vars", def->name); + if (RT_DeserializeConfigFromFile(cfg, file_name)) + { + RT_ConfigReadInt(cfg, RT_StringLiteral("kind"), &def->kind); + RT_ConfigReadVec3(cfg, RT_StringLiteral("emission"), &def->emission); + RT_ConfigReadFloat(cfg, RT_StringLiteral("radius"), &def->radius); + RT_ConfigReadVec2(cfg, RT_StringLiteral("size"), &def->size); + RT_ConfigReadFloat(cfg, RT_StringLiteral("spot_angle"), &def->spot_angle); + RT_ConfigReadFloat(cfg, RT_StringLiteral("spot_softness"), &def->spot_softness); + } + else + { + success = false; + } + } + } + + if (success) + { + RT_SetSettingsNotification(&g_lights_notification, "Successfully Loaded Light Settings", (ImVec4){0.5f, 1.0f, 0.7f, 1.0f}); + } + else + { + RT_SetSettingsNotification(&g_lights_notification, "Encountered Problems Loading Light Settings!", (ImVec4){1.0f, 0.2f, 0.2f, 1.0f}); + } + + g_pending_light_update = true; +} + +void RT_SaveLightSettings() +{ + PHYSFS_mkdir("lights"); + + bool success = true; + + // ------------------------------------------------------------------ + // Write global light settings + + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + RT_ConfigWriteFloat(cfg, RT_StringLiteral("global_light_multiplier"), g_light_multiplier_default); + + if (!RT_SerializeConfigToFile(cfg, "lights/global_lights.vars")) + { + success = false; + + RT_LOG(RT_LOGSERVERITY_HIGH, "Failed to serialize global_lights.vars:\n"); + for (RT_StringNode *error = cfg->first_error; error; error = error->next) + { + RT_LOGF(RT_LOGSERVERITY_HIGH, " > %.*s\n", RT_ExpandString(error->string)); + } + } + } + + // ------------------------------------------------------------------ + // Write all da rest + + for (size_t light_index = 0; light_index < RT_ARRAY_COUNT(g_light_definitions); light_index++) + { + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_LightDefinition *def = &g_light_definitions[light_index]; + + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + RT_ConfigWriteInt(cfg, RT_StringLiteral("kind"), def->kind); + RT_ConfigWriteVec3(cfg, RT_StringLiteral("emission"), def->emission); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("radius"), def->radius); + RT_ConfigWriteVec2(cfg, RT_StringLiteral("size"), def->size); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("spot_angle"), def->spot_angle); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("spot_softness"), def->spot_softness); + + char *file_name = RT_ArenaPrintF(&g_thread_arena, "lights/%s.vars", def->name); + if (!RT_SerializeConfigToFile(cfg, file_name)) + { + success = false; + + RT_LOG(RT_LOGSERVERITY_HIGH, "Failed to serialize %s:\n", file_name); + for (RT_StringNode *error = cfg->first_error; error; error = error->next) + { + RT_LOGF(RT_LOGSERVERITY_HIGH, " > %.*s\n", RT_ExpandString(error->string)); + } + } + } + } + + if (success) + { + RT_SetSettingsNotification(&g_lights_notification, "Successfully Saved Light Settings", (ImVec4){0.7f, 1.0f, 0.5f, 1.0f}); + } + else + { + RT_SetSettingsNotification(&g_lights_notification, "Encountered Problems Saving Light Settings!", (ImVec4){1.0f, 0.2f, 0.2f, 1.0f}); + } +} + +void RT_ResetHeadLightSettings() +{ + memcpy(&g_headlights, &g_default_headlights, sizeof(g_headlights)); + RT_SetSettingsNotification(&g_headlights_notification, "Reset Headlight Settings", (ImVec4){0.5f, 0.7f, 1.0f, 1.0f}); +} + +void RT_LoadHeadLightSettings(void) +{ + bool success = true; + + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + if (RT_DeserializeConfigFromFile(cfg, "lights/headlights.vars")) + { + RT_ConfigReadFloat(cfg, RT_StringLiteral("pos_offset_horz"), &g_headlights.pos_offset_horz); + RT_ConfigReadFloat(cfg, RT_StringLiteral("pos_offset_vert"), &g_headlights.pos_offset_vert); + RT_ConfigReadFloat(cfg, RT_StringLiteral("skew_horz"), &g_headlights.skew_horz); + RT_ConfigReadFloat(cfg, RT_StringLiteral("skew_vert"), &g_headlights.skew_vert); + RT_ConfigReadFloat(cfg, RT_StringLiteral("radius"), &g_headlights.radius); + RT_ConfigReadFloat(cfg, RT_StringLiteral("brightness"), &g_headlights.brightness); + RT_ConfigReadFloat(cfg, RT_StringLiteral("spot_angle"), &g_headlights.spot_angle); + RT_ConfigReadFloat(cfg, RT_StringLiteral("spot_softness"), &g_headlights.spot_softness); + } + else + { + success = false; + } + } + + if (success) + { + RT_SetSettingsNotification(&g_headlights_notification, "Successfully Loaded Headlight Settings", (ImVec4){0.5f, 1.0f, 0.7f, 1.0f}); + } + else + { + RT_SetSettingsNotification(&g_headlights_notification, "Encountered Problems Loading Headlight Settings!", (ImVec4){1.0f, 0.2f, 0.2f, 1.0f}); + } +} + +void RT_SaveHeadLightSettings(void) +{ + PHYSFS_mkdir("lights"); + + bool success = true; + + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + RT_ConfigWriteFloat(cfg, RT_StringLiteral("pos_offset_horz"), g_headlights.pos_offset_horz); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("pos_offset_vert"), g_headlights.pos_offset_vert); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("skew_horz"), g_headlights.skew_horz); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("skew_vert"), g_headlights.skew_vert); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("radius"), g_headlights.radius); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("brightness"), g_headlights.brightness); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("spot_angle"), g_headlights.spot_angle); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("spot_softness"), g_headlights.spot_softness); + + if (!RT_SerializeConfigToFile(cfg, "lights/headlights.vars")) + { + success = false; + + RT_LOG(RT_LOGSERVERITY_HIGH, "Failed to serialize global_lights.vars:\n"); + for (RT_StringNode *error = cfg->first_error; error; error = error->next) + { + RT_LOGF(RT_LOGSERVERITY_HIGH, " > %.*s\n", RT_ExpandString(error->string)); + } + } + } + + if (success) + { + RT_SetSettingsNotification(&g_headlights_notification, "Successfully Saved Headlight Settings", (ImVec4){0.7f, 1.0f, 0.5f, 1.0f}); + } + else + { + RT_SetSettingsNotification(&g_headlights_notification, "Encountered Problems Saving Headlight Settings!", (ImVec4){1.0f, 0.2f, 0.2f, 1.0f}); + } +} diff --git a/RT/Game/Lights.h b/RT/Game/Lights.h index 7dff805..9bb6ecb 100644 --- a/RT/Game/Lights.h +++ b/RT/Game/Lights.h @@ -15,10 +15,22 @@ float g_light_multiplier; // Default light multiplier (not changed during runtime) float g_light_multiplier_default; +typedef struct RT_HeadlightSettings +{ + float pos_offset_horz; + float pos_offset_vert; + float skew_horz; + float skew_vert; + float radius; + float brightness; + float spot_angle; + float spot_softness; +} RT_HeadlightSettings; + +RT_HeadlightSettings g_headlights; + typedef struct RT_LightDefinition { - // TODO(daniel): These would ideally not be parameterized by the tmap index. - // GameBitmap indices are the canonical indices for the _actual_ textures/bitmaps/materials. const char* name; RT_LightKind kind; RT_Vec3 emission; @@ -30,10 +42,17 @@ typedef struct RT_LightDefinition extern RT_LightDefinition g_light_definitions[]; +void RT_InitLightStuff(void); +void RT_ResetLightSettings(void); // Returns g_light_definition index if light, otherwise -1. int RT_IsLight(int tmap); RT_Light RT_InitLight(RT_LightDefinition definition, RT_Vertex* vertices, RT_Vec3 normal); -void RT_ShowLightMenu(); +void RT_ShowLightMenu(void); void RT_VisualizeLight(RT_Light* light); +void RT_LoadLightSettings(void); +void RT_SaveLightSettings(void); +void RT_ResetHeadLightSettings(void); +void RT_LoadHeadLightSettings(void); +void RT_SaveHeadLightSettings(void); #endif \ No newline at end of file diff --git a/RT/RTgr.c b/RT/RTgr.c index da30703..3d2526d 100644 --- a/RT/RTgr.c +++ b/RT/RTgr.c @@ -61,6 +61,7 @@ CockpitSettings g_rt_cockpit_settings = { .back_cockpit_offset = {0.000f, -0.760f, -2.488f}, .back_cockpit_scale = {1.000f, 1.000f, 1.000f}, }; + RT_GLTFNode* g_rt_cockpit_gltf; RT_FreeCamInfo g_rt_free_cam_info = { 0 }; int light_culling_heuristic = 1; @@ -68,6 +69,9 @@ int max_rec_depth = 32; float max_distance = 600; float max_seg_distance = 500; +static RT_DynamicLightInfo g_rt_default_dynamic_light_info; +static RT_WeaponLightAdjusts g_rt_default_light_adjusts[RT_LIGHT_ADJUST_ARRAY_SIZE]; + uint64_t g_rt_frame_index; // #define RT_DUMP_GAME_BITMAPS @@ -206,7 +210,7 @@ int gr_set_mode(u_int32_t mode) bool g3_draw_bitmap_full(vms_vector* pos, fix width, fix height, grs_bitmap* bm, float r, float g, float b) { // NOTE(daniel): Unfortunate! - uint16_t material_index = ((uintptr_t)bm - (uintptr_t)GameBitmaps) / sizeof(grs_bitmap); + uint16_t material_index = (uint16_t)(bm - GameBitmaps); RT_Vec2 rt_dim = { f2fl(width), f2fl(height) }; RT_Vec3 rt_pos = RT_Vec3Fromvms_vector(pos); @@ -388,6 +392,51 @@ void draw_tmap_flat(grs_bitmap* bm, int nv, g3s_point** vertlist) RT_LOG(RT_LOGSERVERITY_HIGH, "draw_tmap_flat: unhandled"); } +// +// NOTE(daniel): Duplicated from Lights.c +// + +typedef struct RT_SettingsNotification +{ + float timer; + ImVec4 color; + char *message; +} RT_SettingsNotification; + +static inline void RT_SetSettingsNotification(RT_SettingsNotification *notif, char *name, ImVec4 color) +{ + notif->timer = 2.0f; + notif->color = color; + notif->message = name; +} + +static inline void RT_ShowSettingsNotification(RT_SettingsNotification *notif) +{ + if (notif->timer > 0.0f) + { + ImVec4 color = notif->color; + color.w = notif->timer / 2.0f; + + igPushStyleColor_Vec4(ImGuiCol_Text, color); + igText(notif->message); + igPopStyleColor(1); + + notif->timer -= 1.0f / 60.0f; // hardcoded nonsense + } + else + { + igDummy((ImVec2){0.0f, igGetFontSize()}); + } +} + +// + +static RT_SettingsNotification g_dynamic_lights_notification; + +static void RT_LoadDynamicLightSettings(void); +static void RT_SaveDynamicLightSettings(void); +static void RT_ResetDynamicLightSettings(void); + int gr_init(int mode) { SDL_WM_SetCaption(DESCENT_VERSION, "Descent"); @@ -448,6 +497,13 @@ int gr_init(int mode) RT_ConfigReadFloat(RT_GetRendererIO()->config, RT_StringLiteral("fov"), &fov); g_cam.vfov = g_free_cam.vfov = fov; + // Awkward place to do this, but I need to do it somewhere + memcpy(&g_rt_default_dynamic_light_info, &g_rt_dynamic_light_info, sizeof(g_rt_dynamic_light_info)); + memcpy(g_rt_default_light_adjusts, rt_light_adjusts, sizeof(RT_WeaponLightAdjusts)*RT_LIGHT_ADJUST_ARRAY_SIZE); + + RT_LoadDynamicLightSettings(); + g_dynamic_lights_notification.timer = 0.0f; + return 0; } @@ -1093,6 +1149,208 @@ void RT_ResetLightEmission() RT_UpdateMaterial(lightTexture, material); } +static void RT_DoDynamicLightEditorMenus(void) +{ + if (igBegin("Dynamic Light Editor", NULL, 0)) + { + igPushID_Str("Dynamic Lights"); + + if (igButton("Load Settings", (ImVec2){0, 0})) + { + RT_LoadDynamicLightSettings(); + } + + igSameLine(0.0f, -1.0f); + + if (igButton("Save Settings", (ImVec2){0, 0})) + { + RT_SaveDynamicLightSettings(); + } + + igSameLine(0.0f, -1.0f); + + if (igButton("Reset Settings", (ImVec2){0, 0})) + { + RT_ResetDynamicLightSettings(); + } + + RT_ShowSettingsNotification(&g_dynamic_lights_notification); + + igSeparator(); + igText("Weapon Lights"); + igSeparator(); + + igPushID_Int(2); + igCheckbox("Enable Weapon and flare lights", &g_rt_dynamic_light_info.weaponFlareLights); + igSliderFloat("Weapon Brightness modifier", &g_rt_dynamic_light_info.weaponBrightMod, 0, 1000.f, "%.3f", 0); + igSliderFloat("Radius modifier", &g_rt_dynamic_light_info.weaponRadiusMod, 0, 4.f, "%.3f", 0); + for (size_t i = 0; i < RT_LIGHT_ADJUST_ARRAY_SIZE; i++) + { + RT_WeaponLightAdjusts* adj = &rt_light_adjusts[i]; + if (igTreeNode_Str(adj->weapon_name)) + { + igSliderFloat("Brightness", &adj->brightMul, 0, 100.f, "%.3f", 0); + igSliderFloat("Radius", &adj->radiusMul, 0, 10.f, "%.3f", 0); + igTreePop(); + } + } + igPopID(); + + igDummy((ImVec2){0.0f, igGetFontSize()}); + + igSeparator(); + igText("Explosion Lights"); + igSeparator(); + + igPushID_Int(3); + igCheckbox("Enable explosion lights", &g_rt_dynamic_light_info.explosionLights); + igSliderFloat("Brightness modifier", &g_rt_dynamic_light_info.explosionBrightMod, 0, 1000.f, "%.3f", 0); + igSliderFloat("Radius modifier", &g_rt_dynamic_light_info.explosionRadiusMod, 0, 4.f, "%.3f", 0); + igSliderFloat("Type bias modifier", &g_rt_dynamic_light_info.explosionTypeBias, 0.10f, 10.f, "%.3f", 0); + igPopID(); + + igDummy((ImVec2){0.0f, igGetFontSize()}); + + igSeparator(); + igText("Muzzle Flare Lights"); + igSeparator(); + + igPushID_Int(4); + igCheckbox("Enable muzzle flare lights", &g_rt_dynamic_light_info.muzzleLights); + igSliderFloat("Brightness modifier", &g_rt_dynamic_light_info.muzzleBrightMod, 0, 1000.f, "%.3f", 0); + igSliderFloat("Radius modifier", &g_rt_dynamic_light_info.muzzleRadiusMod, 0, 4.f, "%.3f", 0); + igPopID(); + + igPopID(); + } igEnd(); +} + +// Bad thing ahead: +static RT_String RT_FormatString(RT_Arena *arena, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + const char *formatted = RT_ArenaPrintF(arena, fmt, args); + + va_end(args); + + RT_String result = + { + .bytes = formatted, + .count = strlen(formatted), // <--- specifically, this is the bad thing. + }; + + return result; +} + +void RT_LoadDynamicLightSettings(void) +{ + bool success = true; + + RT_DynamicLightInfo *info = &g_rt_dynamic_light_info; + + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + if (RT_DeserializeConfigFromFile(cfg, "lights/dynamic_lights.vars")) + { + RT_ConfigReadInt(cfg, RT_StringLiteral("weapon_flare_lights"), &info->weaponFlareLights); + RT_ConfigReadFloat(cfg, RT_StringLiteral("weapon_brightness"), &info->weaponBrightMod); + RT_ConfigReadFloat(cfg, RT_StringLiteral("weapon_radius"), &info->weaponRadiusMod); + + for (size_t i = 0; i < RT_LIGHT_ADJUST_ARRAY_SIZE; i++) + { + RT_WeaponLightAdjusts *adj = &rt_light_adjusts[i]; + + RT_ConfigReadFloat(cfg, RT_FormatString(&g_thread_arena, "%s_brightness", adj->weapon_name), &adj->brightMul); + RT_ConfigReadFloat(cfg, RT_FormatString(&g_thread_arena, "%s_radius", adj->weapon_name), &adj->radiusMul); + } + + RT_ConfigReadInt(cfg, RT_StringLiteral("explosion_lights"), &info->explosionLights); + RT_ConfigReadFloat(cfg, RT_StringLiteral("explosion_brightness"), &info->explosionBrightMod); + RT_ConfigReadFloat(cfg, RT_StringLiteral("explosion_radius"), &info->explosionRadiusMod); + RT_ConfigReadFloat(cfg, RT_StringLiteral("explosion_type_bias"), &info->explosionTypeBias); + + RT_ConfigReadInt(cfg, RT_StringLiteral("muzzle_lights"), &info->muzzleLights); + RT_ConfigReadFloat(cfg, RT_StringLiteral("muzzle_brightness"), &info->muzzleBrightMod); + RT_ConfigReadFloat(cfg, RT_StringLiteral("muzzle_radius"), &info->muzzleRadiusMod); + } + else + { + success = false; + } + } + + if (success) + { + RT_SetSettingsNotification(&g_dynamic_lights_notification, "Successfully loaded dynamic light settings", (ImVec4){0.5f, 1.0f, 0.7f, 1.0f}); + } + else + { + RT_SetSettingsNotification(&g_dynamic_lights_notification, "Nothing to load!", (ImVec4){1.0f, 0.2f, 0.2f, 1.0f}); + } +} + +void RT_SaveDynamicLightSettings(void) +{ + PHYSFS_mkdir("lights"); + + bool success = true; + + RT_DynamicLightInfo *info = &g_rt_dynamic_light_info; + + RT_ArenaMemoryScope(&g_thread_arena) + { + RT_Config *cfg = RT_ArenaAllocStruct(&g_thread_arena, RT_Config); + RT_InitializeConfig(cfg, &g_thread_arena); + + RT_ConfigWriteInt(cfg, RT_StringLiteral("weapon_flare_lights"), info->weaponFlareLights); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("weapon_brightness"), info->weaponBrightMod); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("weapon_radius"), info->weaponRadiusMod); + + for (size_t i = 0; i < RT_LIGHT_ADJUST_ARRAY_SIZE; i++) + { + RT_WeaponLightAdjusts *adj = &rt_light_adjusts[i]; + + RT_ConfigWriteFloat(cfg, RT_FormatString(&g_thread_arena, "%s_brightness", adj->weapon_name), adj->brightMul); + RT_ConfigWriteFloat(cfg, RT_FormatString(&g_thread_arena, "%s_radius", adj->weapon_name), adj->radiusMul); + } + + RT_ConfigWriteInt(cfg, RT_StringLiteral("explosion_lights"), info->explosionLights); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("explosion_brightness"), info->explosionBrightMod); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("explosion_radius"), info->explosionRadiusMod); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("explosion_type_bias"), info->explosionTypeBias); + + RT_ConfigWriteInt(cfg, RT_StringLiteral("muzzle_lights"), info->muzzleLights); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("muzzle_brightness"), info->muzzleBrightMod); + RT_ConfigWriteFloat(cfg, RT_StringLiteral("muzzle_radius"), info->muzzleRadiusMod); + + if (!RT_SerializeConfigToFile(cfg, "lights/dynamic_lights.vars")) + { + success = false; + } + } + + if (success) + { + RT_SetSettingsNotification(&g_dynamic_lights_notification, "Successfully saved dynamic light settings", (ImVec4){0.7f, 1.0f, 0.5f, 1.0f}); + } + else + { + RT_SetSettingsNotification(&g_dynamic_lights_notification, "Encountered problems saving dynamic light settings!", (ImVec4){1.0f, 0.2f, 0.2f, 1.0f}); + } +} + +void RT_ResetDynamicLightSettings(void) +{ + memcpy(&g_rt_dynamic_light_info, &g_rt_default_dynamic_light_info, sizeof(g_rt_dynamic_light_info)); + memcpy(rt_light_adjusts, g_rt_default_light_adjusts, sizeof(RT_WeaponLightAdjusts)*RT_LIGHT_ADJUST_ARRAY_SIZE); + RT_SetSettingsNotification(&g_dynamic_lights_notification, "Reset dynamic light settings", (ImVec4){0.5f, 0.7f, 1.0f, 1.0f}); +} + void RT_StartImGuiFrame(void) { igStartFrameWin32(); @@ -1137,17 +1395,11 @@ void RT_StartImGuiFrame(void) value_changed |= igDragFloat3("Rear View Offset", &g_rt_cockpit_settings.back_cockpit_offset, 0.001f, -10.0, 10.0, "%.3f", ImGuiTreeNodeFlags_None); value_changed |= igDragFloat3("Rear View Scale", &g_rt_cockpit_settings.back_cockpit_scale, 0.001f, -10.0, 10.0, "%.3f", ImGuiTreeNodeFlags_None); -#ifndef RT_StringLiteral -#define RT_StringLiteral(x) (RT_String){x, sizeof(x)-1} -#endif igPopID(); } igEnd(); if (igBegin("Ingame Tools", NULL, 0)) { - igPushID_Str("Dynamic Lights"); - igIndent(0); - if (igCollapsingHeader_TreeNodeFlags("Light Culling", ImGuiTreeNodeFlags_None)) { igPushID_Int(1); igSliderInt("Light Culling Heuristic", &light_culling_heuristic, 0, 1, "%i", 0); @@ -1157,41 +1409,6 @@ void RT_StartImGuiFrame(void) igPopID(); } - if (igCollapsingHeader_TreeNodeFlags("Weapon Light Settings", ImGuiTreeNodeFlags_None)) - { - igPushID_Int(2); - igCheckbox("Enable Weapon and flare lights", &g_rt_dynamic_light_info.weaponFlareLights); - igSliderFloat("Weapon Brightness modifier", &g_rt_dynamic_light_info.weaponBrightMod, 0, 1000.f, "%.3f", 0); - igSliderFloat("Radius modifier", &g_rt_dynamic_light_info.weaponRadiusMod, 0, 4.f, "%.3f", 0); - for (size_t i = 0; i < RT_LIGHT_ADJUST_ARRAY_SIZE; i++) - { - RT_WeaponLightAdjusts* adj = &rt_light_adjusts[i]; - if (igTreeNode_Str(adj->weapon_name)) - { - igSliderFloat("Brightness", &adj->brightMul, 0, 100.f, "%.3f", 0); - igSliderFloat("Radius", &adj->radiusMul, 0, 10.f, "%.3f", 0); - igTreePop(); - } - } - igPopID(); - } - if (igCollapsingHeader_TreeNodeFlags("Explosion Light Settings", ImGuiTreeNodeFlags_None)) - { - igPushID_Int(3); - igCheckbox("Enable explosion lights", &g_rt_dynamic_light_info.explosionLights); - igSliderFloat("Brightness modifier", &g_rt_dynamic_light_info.explosionBrightMod, 0, 1000.f, "%.3f", 0); - igSliderFloat("Radius modifier", &g_rt_dynamic_light_info.explosionRadiusMod, 0, 4.f, "%.3f", 0); - igSliderFloat("Type bias modifier", &g_rt_dynamic_light_info.explosionTypeBias, 0.10f, 10.f, "%.3f", 0); - igPopID(); - } - if (igCollapsingHeader_TreeNodeFlags("Muzzle fire Light Settings", ImGuiTreeNodeFlags_None)) - { - igPushID_Int(4); - igCheckbox("Enable muzzle flare lights", &g_rt_dynamic_light_info.muzzleLights); - igSliderFloat("Brightness modifier", &g_rt_dynamic_light_info.muzzleBrightMod, 0, 1000.f, "%.3f", 0); - igSliderFloat("Radius modifier", &g_rt_dynamic_light_info.muzzleRadiusMod, 0, 4.f, "%.3f", 0); - igPopID(); - } if (igCollapsingHeader_TreeNodeFlags("Miscellaneous", ImGuiTreeNodeFlags_None)) { igPushID_Str("Miscellaneous"); @@ -1208,10 +1425,9 @@ void RT_StartImGuiFrame(void) igCheckbox("Enable free cam clipping", &g_rt_free_cam_info.g_free_cam_clipping_enabled); } - igPopID(); - igUnindent(0); } igEnd(); + RT_DoDynamicLightEditorMenus(); RT_ShowLightMenu(); RT_DoPolymodelViewerMenus(); diff --git a/RT/Renderer/Backend/DX12/assets/shaders/direct_lighting.hlsli b/RT/Renderer/Backend/DX12/assets/shaders/direct_lighting.hlsli index 106959f..4c3efe0 100644 --- a/RT/Renderer/Backend/DX12/assets/shaders/direct_lighting.hlsli +++ b/RT/Renderer/Backend/DX12/assets/shaders/direct_lighting.hlsli @@ -272,8 +272,11 @@ void CalculateDirectLightingAtSurface(in GeometryRayOutput IN, inout DirectLight float3 sky_color_bot = g_global_cb.sky_color_bottom;//float3(0.15f, 0.35f, 0.65f); float3 sky_color = lerp(sky_color_top, sky_color_bot, abs(IN.view_dir.y)); - OUT.emissive_lighting = sky_color; - OUT.direct_lighting = sky_color; + if (is_indirect) + { + OUT.emissive_lighting = sky_color; + OUT.direct_lighting = sky_color; + } } OUT.albedo = IN.albedo; diff --git a/RT/Renderer/Backend/DX12/assets/shaders/include_shared/shared_tweakvars.hlsl.h b/RT/Renderer/Backend/DX12/assets/shaders/include_shared/shared_tweakvars.hlsl.h index 33f8e5b..fd5a8fb 100644 --- a/RT/Renderer/Backend/DX12/assets/shaders/include_shared/shared_tweakvars.hlsl.h +++ b/RT/Renderer/Backend/DX12/assets/shaders/include_shared/shared_tweakvars.hlsl.h @@ -39,6 +39,7 @@ TWEAK_BOOL ("Use Oren-Nayar BRDF", use_oren_nayar_brdf, false) TWEAK_BOOL ("Path-space Regularization", path_space_regularization, true) TWEAK_BOOL ("Object Motion Vectors", object_motion_vectors, true) TWEAK_BOOL ("Enable Normal Maps", enable_normal_maps, true) +TWEAK_BOOL ("Ignore Me...", smooth_textures, false) TWEAK_OPTIONS("Base Color Sampler", albedo_sample_linear, 0, "Point", "Linear") TWEAK_OPTIONS("Normal Map Sampler", normal_sample_linear, 0, "Point", "Linear") TWEAK_OPTIONS("Metallic/Roughness Sampler",metallic_roughness_sample_linear, 0, "Point", "Linear") diff --git a/RT/Renderer/Backend/DX12/assets/shaders/primary_ray.hlsli b/RT/Renderer/Backend/DX12/assets/shaders/primary_ray.hlsli index 4e047ef..4c3236f 100644 --- a/RT/Renderer/Backend/DX12/assets/shaders/primary_ray.hlsli +++ b/RT/Renderer/Backend/DX12/assets/shaders/primary_ray.hlsli @@ -185,8 +185,8 @@ void GetGeometryDataFromPrimaryRay(RayDesc ray_desc, PrimaryRayPayload ray_paylo normal = -normal; } } - - OUT.normal = EncodeNormalOctahedron(normal); + + OUT.normal = clamp(EncodeNormalOctahedron(normal), 0.0, 1.0); // ------------------------------------------------------------------------------------- // Determine gbuffer depth value diff --git a/RT/Renderer/Backend/DX12/src/GlobalDX.h b/RT/Renderer/Backend/DX12/src/GlobalDX.h index a9a5bb6..cb59b73 100644 --- a/RT/Renderer/Backend/DX12/src/GlobalDX.h +++ b/RT/Renderer/Backend/DX12/src/GlobalDX.h @@ -264,8 +264,6 @@ namespace RT RT_Vec2 halton_samples[HALTON_SAMPLE_COUNT]; float viewport_offset_y; - RT_Vec3 sky_color_top; - RT_Vec3 sky_color_bottom; RT_RendererIO io; uint64_t tweakvars_config_last_modified_time; diff --git a/RT/Renderer/Backend/DX12/src/RenderBackend.cpp b/RT/Renderer/Backend/DX12/src/RenderBackend.cpp index c1ed2a8..90f274c 100644 --- a/RT/Renderer/Backend/DX12/src/RenderBackend.cpp +++ b/RT/Renderer/Backend/DX12/src/RenderBackend.cpp @@ -2814,6 +2814,9 @@ void RenderBackend::BeginScene(const RT_SceneSettings* scene_settings) if (!g_d3d.scene.freezeframe) { g_d3d.scene.camera = *scene_settings->camera; + g_d3d.scene.camera.forward = RT_Vec3Normalize(g_d3d.scene.camera.forward); + g_d3d.scene.camera.right = RT_Vec3Normalize(g_d3d.scene.camera.right); + g_d3d.scene.camera.up = RT_Vec3Normalize(g_d3d.scene.camera.up); g_d3d.scene.hitgroups_table_at = 0; g_d3d.tlas_instance_count = 0; g_d3d.lights_count = 0; @@ -3179,7 +3182,8 @@ RT_ResourceHandle RenderBackend::UploadMesh(const RT_UploadMeshParams& mesh_para void RenderBackend::ReleaseTexture(const RT_ResourceHandle texture_handle) { TextureResource* texture_resource = g_texture_slotmap.Find(texture_handle); - RT_RELEASE_RESOURCE(texture_resource->texture); + // Note (Justin): This is a dirty little hack to have the resources released after the current frame finished rendering + RT_TRACK_TEMP_OBJECT(texture_resource->texture, &g_d3d.command_queue_direct->GetCommandList()); g_d3d.cbv_srv_uav.Free(texture_resource->descriptors); g_texture_slotmap.Remove(texture_handle); } @@ -3187,8 +3191,10 @@ void RenderBackend::ReleaseTexture(const RT_ResourceHandle texture_handle) void RenderBackend::ReleaseMesh(const RT_ResourceHandle mesh_handle) { MeshResource* mesh_resource = g_mesh_slotmap.Find(mesh_handle); - RT_RELEASE_RESOURCE(mesh_resource->triangle_buffer); - RT_RELEASE_RESOURCE(mesh_resource->blas); + CommandList* cmd_list = &g_d3d.command_queue_direct->GetCommandList(); + // Note (Justin): This is a dirty little hack to have the resources released after the current frame finished rendering + RT_TRACK_TEMP_OBJECT(mesh_resource->triangle_buffer, cmd_list); + RT_TRACK_TEMP_OBJECT(mesh_resource->blas, cmd_list); g_d3d.cbv_srv_uav.Free(mesh_resource->triangle_buffer_descriptor); g_mesh_slotmap.Remove(mesh_handle); } @@ -4155,9 +4161,10 @@ void RenderBackend::RaytraceRender() g_d3d.command_queue_direct->ExecuteCommandList(command_list); } -void RenderBackend::RaytraceSetSkyColors(const RT_Vec3 top, const RT_Vec3 bottom) { - g_d3d.sky_color_top = top; - g_d3d.sky_color_bottom = bottom; +void RenderBackend::RaytraceSetSkyColors(const RT_Vec3 top, const RT_Vec3 bottom) +{ + CurrentFrameData()->scene_cb.As()->sky_color_top = top; + CurrentFrameData()->scene_cb.As()->sky_color_bottom = bottom; } void RenderBackend::RasterSetViewport(float x, float y, float width, float height) diff --git a/RT/Renderer/Backend/DX12/src/ResourceTracker.cpp b/RT/Renderer/Backend/DX12/src/ResourceTracker.cpp index 7b23d1d..48375f0 100644 --- a/RT/Renderer/Backend/DX12/src/ResourceTracker.cpp +++ b/RT/Renderer/Backend/DX12/src/ResourceTracker.cpp @@ -230,7 +230,7 @@ void RT::D3D12ResourceTracker::ReleaseStaleTempResources(uint64_t fence_value) for (ResourceEntry** entry_at = &m_resource_table[i]; *entry_at;) { ResourceEntry* entry = *entry_at; - + if (entry->command_list && entry->command_list->GetFenceValue() <= fence_value) { diff --git a/d1/assets/textures/ceil015.material b/d1/assets/textures/ceil015.material deleted file mode 100644 index 196bb60..0000000 --- a/d1/assets/textures/ceil015.material +++ /dev/null @@ -1,2 +0,0 @@ -roughness = 0.548000 -metalness = 1.000000 diff --git a/d1/main/bm.c b/d1/main/bm.c index bfae6ee..0eb152e 100644 --- a/d1/main/bm.c +++ b/d1/main/bm.c @@ -140,6 +140,7 @@ int gamedata_init() #ifdef RT_DX12 RT_InitAllPolyModels(); RT_InitAllBitmaps(); + RT_InitLightStuff(); RT_InitglTFModels(); RT_RaytraceSetSkyColors((RT_Vec3){ 0.0f,0.0f,0.000f }, (RT_Vec3){ 0.0f,0.0f,0.000f }); #endif diff --git a/d1/main/endlevel.c b/d1/main/endlevel.c index 9e83d70..6390466 100644 --- a/d1/main/endlevel.c +++ b/d1/main/endlevel.c @@ -67,6 +67,7 @@ COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "RTutil.h" #include "Core/Arena.h" #include "Game/lights.h" +#include "globvars.h" #endif #ifdef EDITOR @@ -410,6 +411,10 @@ void stop_endlevel_sequence() Endlevel_sequence = EL_OFF; +#ifdef RT_DX12 + RT_RaytraceSetSkyColors(RT_Vec3Make(0.0, 0.0, 0.0), RT_Vec3Make(0.0, 0.0, 0.0)); +#endif + PlayerFinishedLevel(0); } @@ -572,7 +577,6 @@ void do_endlevel_frame() if (ConsoleObject->segnum == transition_segnum) { int objnum; - Endlevel_sequence = EL_LOOKBACK; objnum = obj_create(OBJ_CAMERA, 0, @@ -908,9 +912,9 @@ void render_external_scene(fix eye_offset) } } - #ifdef STATION_ENABLED +#ifdef STATION_ENABLED draw_polygon_model(&station_pos,&vmd_identity_matrix,NULL,station_modelnum,0,lrgb,NULL,NULL, OBJ_NONE); - #endif +#endif #ifdef OGL ogl_toggle_depth_test(0); @@ -1045,7 +1049,7 @@ void endlevel_render_mine(fix eye_offset) else g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom); - render_mine(start_seg_num,eye_offset); + render_mine(start_seg_num, eye_offset); #ifdef RT_DX12 RT_Vec3 player_pos = RT_Vec3Fromvms_vector(&Viewer->pos); RT_RenderLevel(player_pos); @@ -1056,28 +1060,26 @@ void render_endlevel_frame(fix eye_offset) { g3_start_frame(); + #ifdef RT_DX12 RT_Camera camera = { .position = RT_Vec3Fromvms_vector(&Viewer->pos), - .forward = RT_Vec3Fromvms_vector(&Viewer->orient.fvec), - .right = RT_Vec3Fromvms_vector(&Viewer->orient.rvec), - .up = RT_Vec3Fromvms_vector(&Viewer->orient.uvec), + .up = RT_Vec3Fromvms_vector(&View_matrix.uvec), + .forward = RT_Vec3Fromvms_vector(&View_matrix.fvec), + .right = RT_Vec3Fromvms_vector(&View_matrix.rvec), .vfov = 60.0f, .near_plane = 0.1f, .far_plane = 10000.0f - }; - RT_SceneSettings frame_settings = + }; + RT_SceneSettings frame_settings = { - .camera = &camera, - .render_height_override = 0, - .render_width_override = 0, - }; - RT_BeginScene(&frame_settings); - RT_Light light = RT_MakeSphericalLight( - (RT_Vec3){ 10, 10, 10 }, - (RT_Vec3){ f2fl(mine_ground_exit_point.x), f2fl(mine_ground_exit_point.y) + 100.f, f2fl(mine_ground_exit_point.z) }, 10.f); - RT_RaytraceSubmitLight(light); + .camera = &camera, + .render_height_override = 0, + .render_width_override = 0, + }; + RT_BeginScene(&frame_settings); + RT_RaytraceSetSkyColors(RT_Vec3Make(0.5, 0.5, 0.5), RT_Vec3Make(0.5, 0.5, 0.5)); #endif if (Endlevel_sequence < EL_OUTSIDE) @@ -1086,7 +1088,7 @@ void render_endlevel_frame(fix eye_offset) render_external_scene(eye_offset); #ifdef RT_DX12 - RT_EndScene(); + RT_EndScene(); #endif g3_end_frame(); diff --git a/d1/main/gauges.c b/d1/main/gauges.c index 0c6ceb7..fcbff92 100644 --- a/d1/main/gauges.c +++ b/d1/main/gauges.c @@ -3057,6 +3057,11 @@ void render_gauges() draw_player_ship(cloak, SB_SHIP_GAUGE_X, SB_SHIP_GAUGE_Y); draw_weapon_boxes(); } + +#ifdef RT_DX12 + dx12_end_frame(); + dx12_start_frame(); +#endif } // --------------------------------------------------------------------------------------------------------- diff --git a/d1/main/lighting.c b/d1/main/lighting.c index 99ecce3..61c0386 100644 --- a/d1/main/lighting.c +++ b/d1/main/lighting.c @@ -48,6 +48,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #ifdef RT_DX12 #include "RTgr.h" #include "Game/Lights.h" + RT_DynamicLightInfo g_rt_dynamic_light_info = { .explosionLights = true, diff --git a/d1/main/menu.c b/d1/main/menu.c index 8df9fd6..eb6f48e 100644 --- a/d1/main/menu.c +++ b/d1/main/menu.c @@ -80,6 +80,7 @@ COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #define RT_RENDER_SETTINGS_CONFIG_FILE "render_settings.vars" #include "Core/String.h" #include "Core/Config.h" +#include "Game/Lights.h" #endif @@ -1329,11 +1330,11 @@ int raytrace_config_menuset(newmenu *menu, d_event *event, void *userdata) void raytrace_config() { - newmenu_item m[28]; + newmenu_item m[30]; int nitems = 0; // Pathtracing ops - int opt_gr_enable_pathtracing = 0, opt_gr_enable_pbr, opt_gr_important_sample_brdf, opt_gr_use_oren_nayar_brdf, opt_gr_lighting_quality; + int opt_gr_enable_pathtracing = 0, opt_gr_enable_pbr, opt_gr_important_sample_brdf, opt_gr_lighting_quality; // Motion Blur ops int opt_gr_motion_blur_quality = 0, opt_gr_motion_blur_strength; @@ -1366,9 +1367,6 @@ void raytrace_config() opt_gr_enable_pbr = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Enable PBR"; m[nitems].value = RT_GetIntFromConfig(config, RT_StringLiteral("enable_pbr")); nitems++; - opt_gr_use_oren_nayar_brdf = nitems; - m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Use Oren-Nayar BRD"; m[nitems].value = RT_GetIntFromConfig(config, RT_StringLiteral("use_oren_nayar_brdf")); nitems++; - m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Lighting Quality:"; nitems++; opt_gr_lighting_quality = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = " Low"; m[nitems].value = 0; m[nitems].group = 0; nitems++; @@ -1377,6 +1375,9 @@ void raytrace_config() int lighting_mode = RT_GetIntFromConfig(config, RT_StringLiteral("ris")); m[opt_gr_lighting_quality+lighting_mode].value=1; + int opt_gr_bilinear = nitems; + m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Smooth Textures"; m[nitems].value = RT_GetIntFromConfig(config, RT_StringLiteral("smooth_textures")); nitems++; + // --- MOTION BLUR --- m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Motion Blur:"; nitems++; @@ -1417,12 +1418,24 @@ void raytrace_config() opt_gr_vignette_strength = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Vignette Strength:"; m[nitems].value = (int)(RT_GetFloatFromConfig(config, RT_StringLiteral("vignette_strength")) * 10.f); m[nitems].min_value = 0; m[nitems].max_value = 10; nitems++; + // --- OTHER --- + m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; + m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Other:"; nitems++; + + int headlight_brightness = (int)roundf(g_headlights.brightness * 5.0f); + int opt_gr_headlight_brightness = nitems; + m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Headlight Brightness:"; m[nitems].value = headlight_brightness; m[nitems].min_value = 0; m[nitems].max_value = 15; nitems++; + + RT_ASSERT(nitems <= RT_ARRAY_COUNT(m)); + newmenu_do1( NULL, "Raytracing Options", nitems, m, raytrace_config_menuset, NULL, 1 ); + g_headlights.brightness = (float)m[opt_gr_headlight_brightness].value / 5.0f; + RT_SaveHeadLightSettings(); + if (!preset_changed){ RT_ConfigWriteInt(config, RT_StringLiteral("enable_pathtracing"), m[opt_gr_enable_pathtracing].value); RT_ConfigWriteInt(config, RT_StringLiteral("enable_pbr"), m[opt_gr_enable_pbr].value); - RT_ConfigWriteInt(config, RT_StringLiteral("use_oren_nayar_brdf"), m[opt_gr_use_oren_nayar_brdf].value); for(int i = 0; i < 3; i++){ if(m[opt_gr_lighting_quality+i].value == 1){ lighting_mode = i; @@ -1455,6 +1468,21 @@ void raytrace_config() RT_ConfigWriteInt(config, RT_StringLiteral("ris"), lighting_mode); + if (m[opt_gr_bilinear].value) + { + RT_ConfigWriteInt(config, RT_StringLiteral("smooth_textures"), true); + RT_ConfigWriteInt(config, RT_StringLiteral("albedo_sample_linear"), 1); + RT_ConfigWriteInt(config, RT_StringLiteral("normal_sample_linear"), 1); + RT_ConfigWriteInt(config, RT_StringLiteral("metallic_roughness_sample_linear"), 1); + } + else + { + RT_ConfigWriteInt(config, RT_StringLiteral("smooth_textures"), false); + RT_ConfigWriteInt(config, RT_StringLiteral("albedo_sample_linear"), 0); + RT_ConfigWriteInt(config, RT_StringLiteral("normal_sample_linear"), 0); + RT_ConfigWriteInt(config, RT_StringLiteral("metallic_roughness_sample_linear"), 0); + } + RT_ConfigWriteInt(config, RT_StringLiteral("motion_blur_quality"), m[opt_gr_motion_blur_quality].value); RT_ConfigWriteFloat(config, RT_StringLiteral("motion_blur_curve"), m[opt_gr_motion_blur_strength].value/10.0f); diff --git a/d1/main/render.c b/d1/main/render.c index debef48..5800c10 100644 --- a/d1/main/render.c +++ b/d1/main/render.c @@ -1627,19 +1627,20 @@ void render_frame(fix eye_offset) // Player light { - // NOTE(daniel): These would be great tweakables for an ImGui menu. - float pos_offset_horz = 3.0f; - float pos_offset_vert = -2.0f; - float skew_horz = 0.12f; - float skew_vert = 0.06f; + RT_HeadlightSettings *h = &g_headlights; + + float pos_offset_horz = h->pos_offset_horz; + float pos_offset_vert = h->pos_offset_vert; + float skew_horz = h->skew_horz; + float skew_vert = h->skew_vert; RT_Vec3 light_pos_left = RT_Vec3Add3(object_pos, RT_Vec3Muls(g_cam.right, -pos_offset_horz), RT_Vec3Muls(g_cam.up, pos_offset_vert)); RT_Vec3 light_pos_right = RT_Vec3Add3(object_pos, RT_Vec3Muls(g_cam.right, +pos_offset_horz), RT_Vec3Muls(g_cam.up, pos_offset_vert)); - RT_Vec3 light_dir_left = RT_Vec3Normalize(RT_Vec3Add3(g_cam.forward, RT_Vec3Muls(g_cam.right, +0.1f), RT_Vec3Muls(g_cam.up, skew_vert))); - RT_Vec3 light_dir_right = RT_Vec3Normalize(RT_Vec3Add3(g_cam.forward, RT_Vec3Muls(g_cam.right, -0.1f), RT_Vec3Muls(g_cam.up, skew_vert))); - RT_Vec3 light_emission = RT_Vec3FromScalar(1.5f); - float light_radius = 0.05f; - float light_spot_angle = 0.05f; - float light_spot_softness = 0.05f; + RT_Vec3 light_dir_left = RT_Vec3Normalize(RT_Vec3Add3(g_cam.forward, RT_Vec3Muls(g_cam.right, skew_horz), RT_Vec3Muls(g_cam.up, skew_vert))); + RT_Vec3 light_dir_right = RT_Vec3Normalize(RT_Vec3Add3(g_cam.forward, RT_Vec3Muls(g_cam.right, -skew_horz), RT_Vec3Muls(g_cam.up, skew_vert))); + RT_Vec3 light_emission = RT_Vec3FromScalar(h->brightness); + float light_radius = h->radius; + float light_spot_angle = h->spot_angle; + float light_spot_softness = h->spot_softness; RT_RaytraceSubmitLight(RT_MakeSphericalSpotlight(light_emission, light_pos_left, light_dir_left, light_radius, light_spot_angle, light_spot_softness, 0.6f)); RT_RaytraceSubmitLight(RT_MakeSphericalSpotlight(light_emission, light_pos_right, light_dir_right, light_radius,