mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
537 lines
14 KiB
C++
537 lines
14 KiB
C++
// SONIC ROBO BLAST 2
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "i_video.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <vector>
|
|
|
|
#include <imgui.h>
|
|
|
|
#include "cxxutil.hpp"
|
|
#include "f_finale.h"
|
|
#include "hwr2/pass_blit_rect.hpp"
|
|
#include "hwr2/pass_imgui.hpp"
|
|
#include "hwr2/pass_manager.hpp"
|
|
#include "hwr2/pass_postprocess.hpp"
|
|
#include "hwr2/pass_resource_managers.hpp"
|
|
#include "hwr2/pass_screenshot.hpp"
|
|
#include "hwr2/pass_software.hpp"
|
|
#include "hwr2/pass_twodee.hpp"
|
|
#include "hwr2/twodee.hpp"
|
|
#include "v_video.h"
|
|
|
|
// KILL THIS WHEN WE KILL OLD OGL SUPPORT PLEASE
|
|
#include "d_netcmd.h" // kill
|
|
#include "discord.h" // kill
|
|
#include "doomstat.h" // kill
|
|
#include "s_sound.h" // kill
|
|
#include "sdl/ogl_sdl.h"
|
|
#include "st_stuff.h" // kill
|
|
|
|
// Legacy FinishUpdate Draws
|
|
#include "d_netcmd.h"
|
|
#ifdef HAVE_DISCORDRPC
|
|
#include "discord.h"
|
|
#endif
|
|
#include "doomstat.h"
|
|
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
|
|
#include "m_avrecorder.h"
|
|
#endif
|
|
#include "st_stuff.h"
|
|
#include "s_sound.h"
|
|
#include "st_stuff.h"
|
|
#include "v_video.h"
|
|
|
|
using namespace srb2;
|
|
using namespace srb2::hwr2;
|
|
using namespace srb2::rhi;
|
|
|
|
namespace
|
|
{
|
|
struct InternalPassData
|
|
{
|
|
std::shared_ptr<PassManager> resource_passmanager;
|
|
std::shared_ptr<PassManager> normal_rendering;
|
|
std::shared_ptr<PassManager> wipe_capture_start_rendering;
|
|
std::shared_ptr<PassManager> wipe_capture_end_rendering;
|
|
std::shared_ptr<PassManager> wipe_rendering;
|
|
};
|
|
} // namespace
|
|
|
|
static std::unique_ptr<InternalPassData> g_passes;
|
|
static Rhi* g_last_known_rhi = nullptr;
|
|
static bool g_imgui_frame_active = false;
|
|
|
|
Handle<Rhi> srb2::sys::g_current_rhi = kNullHandle;
|
|
|
|
static bool rhi_changed(Rhi* rhi)
|
|
{
|
|
return g_last_known_rhi != rhi;
|
|
}
|
|
|
|
#ifdef HWRENDER
|
|
static void finish_legacy_ogl_update()
|
|
{
|
|
int player;
|
|
|
|
SCR_CalculateFPS();
|
|
|
|
if (st_overlay)
|
|
{
|
|
if (cv_songcredits.value)
|
|
HU_DrawSongCredits();
|
|
|
|
if (cv_ticrate.value)
|
|
SCR_DisplayTicRate();
|
|
|
|
if (cv_showping.value && netgame && (consoleplayer != serverplayer || !server_lagless))
|
|
{
|
|
if (server_lagless)
|
|
{
|
|
if (consoleplayer != serverplayer)
|
|
SCR_DisplayLocalPing();
|
|
}
|
|
else
|
|
{
|
|
for (player = 1; player < MAXPLAYERS; player++)
|
|
{
|
|
if (D_IsPlayerHumanAndGaming(player))
|
|
{
|
|
SCR_DisplayLocalPing();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (cv_mindelay.value && consoleplayer == serverplayer && Playing())
|
|
SCR_DisplayLocalPing();
|
|
}
|
|
|
|
if (marathonmode)
|
|
SCR_DisplayMarathonInfo();
|
|
|
|
// draw captions if enabled
|
|
if (cv_closedcaptioning.value)
|
|
SCR_ClosedCaptions();
|
|
|
|
#ifdef HAVE_DISCORDRPC
|
|
if (discordRequestList != NULL)
|
|
ST_AskToJoinEnvelope();
|
|
#endif
|
|
|
|
OglSdlFinishUpdate(cv_vidwait.value);
|
|
}
|
|
#endif
|
|
|
|
static void temp_legacy_finishupdate_draws()
|
|
{
|
|
SCR_CalculateFPS();
|
|
if (st_overlay)
|
|
{
|
|
if (cv_songcredits.value)
|
|
HU_DrawSongCredits();
|
|
|
|
if (cv_ticrate.value)
|
|
SCR_DisplayTicRate();
|
|
|
|
if (cv_showping.value && netgame && (consoleplayer != serverplayer || !server_lagless))
|
|
{
|
|
if (server_lagless)
|
|
{
|
|
if (consoleplayer != serverplayer)
|
|
SCR_DisplayLocalPing();
|
|
}
|
|
else
|
|
{
|
|
for (int player = 1; player < MAXPLAYERS; player++)
|
|
{
|
|
if (D_IsPlayerHumanAndGaming(player))
|
|
{
|
|
SCR_DisplayLocalPing();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (cv_mindelay.value && consoleplayer == serverplayer && Playing())
|
|
SCR_DisplayLocalPing();
|
|
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
|
|
M_AVRecorder_DrawFrameRate();
|
|
#endif
|
|
}
|
|
|
|
if (marathonmode)
|
|
SCR_DisplayMarathonInfo();
|
|
|
|
// draw captions if enabled
|
|
if (cv_closedcaptioning.value)
|
|
SCR_ClosedCaptions();
|
|
|
|
#ifdef HAVE_DISCORDRPC
|
|
if (discordRequestList != NULL)
|
|
ST_AskToJoinEnvelope();
|
|
#endif
|
|
}
|
|
|
|
static InternalPassData build_pass_manager()
|
|
{
|
|
auto framebuffer_manager = std::make_shared<FramebufferManager>();
|
|
auto palette_manager = std::make_shared<MainPaletteManager>();
|
|
auto common_resources_manager = std::make_shared<CommonResourcesManager>();
|
|
auto flat_texture_manager = std::make_shared<FlatTextureManager>();
|
|
auto resource_manager = std::make_shared<PassManager>();
|
|
|
|
resource_manager->insert("framebuffer_manager", framebuffer_manager);
|
|
resource_manager->insert("palette_manager", palette_manager);
|
|
resource_manager->insert("common_resources_manager", common_resources_manager);
|
|
resource_manager->insert("flat_texture_manager", flat_texture_manager);
|
|
|
|
// Basic Rendering is responsible for drawing 3d, 2d, and postprocessing the image.
|
|
// This is drawn to an alternating internal color buffer.
|
|
// Normal Rendering will output the result via final composite and present.
|
|
// Wipe Start Screen and Wipe End Screen will save to special color buffers used for Wipe Rendering.
|
|
auto basic_rendering = std::make_shared<PassManager>();
|
|
|
|
auto software_pass = std::make_shared<SoftwarePass>();
|
|
auto blit_sw_pass = std::make_shared<BlitRectPass>(palette_manager, true);
|
|
auto twodee = std::make_shared<TwodeePass>();
|
|
twodee->flat_manager_ = flat_texture_manager;
|
|
twodee->data_ = make_twodee_pass_data();
|
|
twodee->ctx_ = &g_2d;
|
|
auto pp_simple_blit_pass = std::make_shared<BlitRectPass>(false);
|
|
auto screenshot_pass = std::make_shared<ScreenshotPass>();
|
|
auto imgui_pass = std::make_shared<ImguiPass>();
|
|
auto final_composite_pass = std::make_shared<BlitRectPass>(true);
|
|
|
|
basic_rendering->insert(
|
|
"3d_prepare",
|
|
[framebuffer_manager](PassManager& mgr, Rhi&)
|
|
{
|
|
const bool sw_enabled = rendermode == render_soft && gamestate != GS_NULL;
|
|
|
|
mgr.set_pass_enabled("software", sw_enabled);
|
|
mgr.set_pass_enabled("blit_sw_prepare", sw_enabled);
|
|
mgr.set_pass_enabled("blit_sw", sw_enabled && !g_wipeskiprender);
|
|
}
|
|
);
|
|
basic_rendering->insert("software", software_pass);
|
|
basic_rendering->insert(
|
|
"blit_sw_prepare",
|
|
[blit_sw_pass, software_pass, framebuffer_manager](PassManager&, Rhi&)
|
|
{
|
|
blit_sw_pass->set_texture(software_pass->screen_texture(), vid.width, vid.height);
|
|
blit_sw_pass->set_output(framebuffer_manager->main_color(), vid.width, vid.height, false, false);
|
|
}
|
|
);
|
|
basic_rendering->insert("blit_sw", blit_sw_pass);
|
|
|
|
basic_rendering->insert(
|
|
"2d_prepare",
|
|
[twodee, framebuffer_manager, palette_manager](PassManager& mgr, Rhi&)
|
|
{
|
|
twodee->output_ = framebuffer_manager->main_color();
|
|
twodee->palette_manager_ = palette_manager;
|
|
twodee->output_width_ = vid.width;
|
|
twodee->output_height_ = vid.height;
|
|
}
|
|
);
|
|
basic_rendering->insert("2d", twodee);
|
|
|
|
basic_rendering->insert(
|
|
"pp_final_simple_blit_prepare",
|
|
[pp_simple_blit_pass, framebuffer_manager](PassManager&, Rhi&)
|
|
{
|
|
framebuffer_manager->swap_post();
|
|
pp_simple_blit_pass->set_texture(framebuffer_manager->main_color(), vid.width, vid.height);
|
|
pp_simple_blit_pass
|
|
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, false);
|
|
}
|
|
);
|
|
basic_rendering->insert("pp_final_simple_blit", pp_simple_blit_pass);
|
|
|
|
auto screenshot_rendering = std::make_shared<PassManager>();
|
|
|
|
screenshot_rendering->insert(
|
|
"screenshot_prepare",
|
|
[screenshot_pass, framebuffer_manager](PassManager&, Rhi&)
|
|
{
|
|
screenshot_pass->set_source(framebuffer_manager->current_post_color(), vid.width, vid.height);
|
|
}
|
|
);
|
|
screenshot_rendering->insert("screenshot", screenshot_pass);
|
|
|
|
// Composite-present takes the current postprocess result and outputs it to the default framebuffer.
|
|
// It also renders imgui and presents the screen.
|
|
auto composite_present_rendering = std::make_shared<PassManager>();
|
|
|
|
composite_present_rendering->insert(
|
|
"final_composite_prepare",
|
|
[final_composite_pass, framebuffer_manager](PassManager&, Rhi&)
|
|
{
|
|
final_composite_pass->set_texture(framebuffer_manager->current_post_color(), vid.width, vid.height);
|
|
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, false);
|
|
}
|
|
);
|
|
composite_present_rendering->insert("final_composite", final_composite_pass);
|
|
composite_present_rendering->insert("imgui", imgui_pass);
|
|
composite_present_rendering->insert(
|
|
"present",
|
|
[](PassManager&, Rhi& rhi) {},
|
|
[framebuffer_manager](PassManager&, Rhi& rhi)
|
|
{
|
|
g_imgui_frame_active = false;
|
|
rhi.present();
|
|
rhi.finish();
|
|
framebuffer_manager->reset_post();
|
|
I_NewImguiFrame();
|
|
}
|
|
);
|
|
|
|
// Normal rendering combines basic rendering and composite-present.
|
|
auto normal_rendering = std::make_shared<PassManager>();
|
|
|
|
normal_rendering->insert("resource_manager", resource_manager);
|
|
normal_rendering->insert("basic_rendering", basic_rendering);
|
|
normal_rendering->insert("screenshot_rendering", screenshot_rendering);
|
|
normal_rendering->insert("composite_present_rendering", composite_present_rendering);
|
|
|
|
// Wipe Start Screen Capture rendering
|
|
auto wipe_capture_start_rendering = std::make_shared<PassManager>();
|
|
auto wipe_start_blit = std::make_shared<BlitRectPass>();
|
|
|
|
wipe_capture_start_rendering->insert("resource_manager", resource_manager);
|
|
wipe_capture_start_rendering->insert("basic_rendering", basic_rendering);
|
|
wipe_capture_start_rendering->insert(
|
|
"wipe_capture_prepare",
|
|
[framebuffer_manager, wipe_start_blit](PassManager&, Rhi&)
|
|
{
|
|
wipe_start_blit->set_texture(framebuffer_manager->previous_post_color(), vid.width, vid.height);
|
|
wipe_start_blit->set_output(framebuffer_manager->wipe_start_color(), vid.width, vid.height, false, true);
|
|
}
|
|
);
|
|
wipe_capture_start_rendering->insert("wipe_capture", wipe_start_blit);
|
|
|
|
// Wipe End Screen Capture rendering
|
|
auto wipe_capture_end_rendering = std::make_shared<PassManager>();
|
|
auto wipe_end_blit = std::make_shared<BlitRectPass>();
|
|
auto wipe_end_blit_start_to_main = std::make_shared<BlitRectPass>();
|
|
|
|
wipe_capture_end_rendering->insert("resource_manager", resource_manager);
|
|
wipe_capture_end_rendering->insert("basic_rendering", basic_rendering);
|
|
wipe_capture_end_rendering->insert(
|
|
"wipe_capture_prepare",
|
|
[framebuffer_manager, wipe_end_blit, wipe_end_blit_start_to_main](PassManager&, Rhi&)
|
|
{
|
|
wipe_end_blit->set_texture(framebuffer_manager->current_post_color(), vid.width, vid.height);
|
|
wipe_end_blit->set_output(framebuffer_manager->wipe_end_color(), vid.width, vid.height, false, true);
|
|
|
|
wipe_end_blit_start_to_main->set_texture(
|
|
framebuffer_manager->wipe_start_color(),
|
|
vid.width,
|
|
vid.height
|
|
);
|
|
wipe_end_blit_start_to_main->set_output(
|
|
framebuffer_manager->main_color(),
|
|
vid.width,
|
|
vid.height,
|
|
false,
|
|
true
|
|
);
|
|
}
|
|
);
|
|
wipe_capture_end_rendering->insert("wipe_capture", wipe_end_blit);
|
|
wipe_capture_end_rendering->insert("wipe_end_blit_start_to_main", wipe_end_blit_start_to_main);
|
|
|
|
// Wipe rendering only runs the wipe shader on the start and end screens, and adds composite-present.
|
|
auto wipe_rendering = std::make_shared<PassManager>();
|
|
|
|
auto pp_wipe_pass = std::make_shared<PostprocessWipePass>();
|
|
|
|
wipe_rendering->insert("resource_manager", resource_manager);
|
|
wipe_rendering->insert(
|
|
"pp_final_wipe_prepare",
|
|
[pp_wipe_pass, framebuffer_manager, common_resources_manager](PassManager&, Rhi&)
|
|
{
|
|
framebuffer_manager->swap_post();
|
|
Handle<Texture> start = framebuffer_manager->main_color();
|
|
Handle<Texture> end = framebuffer_manager->wipe_end_color();
|
|
if (g_wipereverse)
|
|
{
|
|
std::swap(start, end);
|
|
}
|
|
pp_wipe_pass->set_start(start);
|
|
pp_wipe_pass->set_end(end);
|
|
pp_wipe_pass->set_target(framebuffer_manager->current_post_color(), vid.width, vid.height);
|
|
}
|
|
);
|
|
wipe_rendering->insert("pp_final_wipe", pp_wipe_pass);
|
|
wipe_rendering->insert("screenshot_rendering", screenshot_rendering);
|
|
wipe_rendering->insert("composite_present_rendering", composite_present_rendering);
|
|
|
|
InternalPassData ret;
|
|
ret.resource_passmanager = resource_manager;
|
|
ret.normal_rendering = normal_rendering;
|
|
ret.wipe_capture_start_rendering = wipe_capture_start_rendering;
|
|
ret.wipe_capture_end_rendering = wipe_capture_end_rendering;
|
|
ret.wipe_rendering = wipe_rendering;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void I_NewTwodeeFrame(void)
|
|
{
|
|
g_2d = Twodee();
|
|
}
|
|
|
|
void I_NewImguiFrame(void)
|
|
{
|
|
if (g_imgui_frame_active)
|
|
{
|
|
ImGui::EndFrame();
|
|
g_imgui_frame_active = false;
|
|
}
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
io.DisplaySize.x = vid.realwidth;
|
|
io.DisplaySize.y = vid.realheight;
|
|
ImGui::NewFrame();
|
|
g_imgui_frame_active = true;
|
|
}
|
|
|
|
static void maybe_reinit_passes(Rhi* rhi)
|
|
{
|
|
if (rhi_changed(rhi) || !g_passes)
|
|
{
|
|
g_last_known_rhi = rhi;
|
|
g_passes = std::make_unique<InternalPassData>(build_pass_manager());
|
|
}
|
|
}
|
|
|
|
void I_FinishUpdate(void)
|
|
{
|
|
if (rendermode == render_none)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef HWRENDER
|
|
if (rendermode == render_opengl)
|
|
{
|
|
finish_legacy_ogl_update();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
temp_legacy_finishupdate_draws();
|
|
|
|
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
|
|
|
if (rhi == nullptr)
|
|
{
|
|
// ???
|
|
return;
|
|
}
|
|
|
|
maybe_reinit_passes(rhi);
|
|
|
|
g_passes->normal_rendering->render(*rhi);
|
|
}
|
|
|
|
void I_FinishUpdateWipeStartScreen(void)
|
|
{
|
|
if (rendermode == render_none)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef HWRENDER
|
|
if (rendermode == render_opengl)
|
|
{
|
|
finish_legacy_ogl_update();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
temp_legacy_finishupdate_draws();
|
|
|
|
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
|
|
|
if (rhi == nullptr)
|
|
{
|
|
// ???
|
|
return;
|
|
}
|
|
|
|
maybe_reinit_passes(rhi);
|
|
|
|
g_passes->wipe_capture_start_rendering->render(*rhi);
|
|
I_NewImguiFrame();
|
|
}
|
|
|
|
void I_FinishUpdateWipeEndScreen(void)
|
|
{
|
|
if (rendermode == render_none)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef HWRENDER
|
|
if (rendermode == render_opengl)
|
|
{
|
|
finish_legacy_ogl_update();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
temp_legacy_finishupdate_draws();
|
|
|
|
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
|
|
|
if (rhi == nullptr)
|
|
{
|
|
// ???
|
|
return;
|
|
}
|
|
|
|
maybe_reinit_passes(rhi);
|
|
|
|
g_passes->wipe_capture_end_rendering->render(*rhi);
|
|
I_NewImguiFrame();
|
|
}
|
|
|
|
void I_FinishUpdateWipe(void)
|
|
{
|
|
if (rendermode == render_none)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef HWRENDER
|
|
if (rendermode == render_opengl)
|
|
{
|
|
finish_legacy_ogl_update();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
temp_legacy_finishupdate_draws();
|
|
|
|
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
|
|
|
if (rhi == nullptr)
|
|
{
|
|
// ???
|
|
return;
|
|
}
|
|
|
|
maybe_reinit_passes(rhi);
|
|
|
|
g_passes->wipe_rendering->render(*rhi);
|
|
}
|