Use the tonemap PP pass to convert blended render styles back to palette colors

This commit is contained in:
Magnus Norddahl 2025-05-20 04:09:31 +02:00
commit a85cd66747
9 changed files with 27 additions and 19 deletions

View file

@ -574,10 +574,10 @@ void PPColormap::Render(PPRenderState *renderstate, int fixedcm, float flash)
/////////////////////////////////////////////////////////////////////////////
void PPTonemap::UpdateTextures()
void PPTonemap::UpdateTextures(bool palettePostprocess)
{
// level.info->tonemap cannot be ETonemapMode::Palette, so it's fine to only check gl_tonemap here
if (ETonemapMode((int)gl_tonemap) == ETonemapMode::Palette && !PaletteTexture.Data)
if ((palettePostprocess || ETonemapMode((int)gl_tonemap) == ETonemapMode::Palette) && !PaletteTexture.Data)
{
std::shared_ptr<void> data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; });
@ -588,8 +588,13 @@ void PPTonemap::UpdateTextures()
{
for (int b = 0; b < 64; b++)
{
// Use the exact math from the software renderer.
// Hardware renderer palette emulation needs a post process pass to fix up translucent stuff.
PalEntry color = GPalette.BaseColors[ColorMatcher.Pick((r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4))];
/*
PalEntry color = GPalette.BaseColors[(uint8_t)PTM_BestColor((uint32_t *)GPalette.BaseColors, (r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4),
gl_paltonemap_reverselookup, gl_paltonemap_powtable, 0, 256)];
*/
int index = ((r * 64 + g) * 64 + b) * 4;
lut[index] = color.r;
lut[index + 1] = color.g;
@ -603,16 +608,19 @@ void PPTonemap::UpdateTextures()
}
}
void PPTonemap::Render(PPRenderState *renderstate)
void PPTonemap::Render(PPRenderState *renderstate, bool palettePostprocess)
{
ETonemapMode current_tonemap = (level_tonemap != ETonemapMode::None) ? level_tonemap : ETonemapMode((int)gl_tonemap);
if (palettePostprocess)
current_tonemap = ETonemapMode::Palette;
if (current_tonemap == ETonemapMode::None)
{
return;
}
UpdateTextures();
UpdateTextures(palettePostprocess);
PPShader *shader = nullptr;
switch (current_tonemap)
@ -1167,9 +1175,9 @@ void Postprocess::Pass1(PPRenderState* state, int fixedcm, int sceneWidth, int s
bloom.RenderBloom(state, sceneWidth, sceneHeight, fixedcm);
}
void Postprocess::Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight)
void Postprocess::Pass2(PPRenderState* state, int fixedcm, float flash, bool palettePostprocess, int sceneWidth, int sceneHeight)
{
tonemap.Render(state);
tonemap.Render(state, palettePostprocess);
colormap.Render(state, fixedcm, flash);
lens.Render(state);
fxaa.Render(state);

View file

@ -531,11 +531,11 @@ class PPTonemap
{
public:
void SetTonemapMode(ETonemapMode tm) { level_tonemap = tm; }
void Render(PPRenderState *renderstate);
void Render(PPRenderState *renderstate, bool palettePostprocess);
void ClearTonemapPalette() { PaletteTexture = {}; }
private:
void UpdateTextures();
void UpdateTextures(bool palettePostprocess);
PPTexture PaletteTexture;
@ -827,7 +827,7 @@ public:
void SetTonemapMode(ETonemapMode tm) { tonemap.SetTonemapMode(tm); }
void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight);
void Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight);
void Pass2(PPRenderState* state, int fixedcm, float flash, bool palettePostprocess, int sceneWidth, int sceneHeight);
};

View file

@ -236,7 +236,7 @@ public:
virtual FTexture *WipeStartScreen();
virtual FTexture *WipeEndScreen();
virtual void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D) { if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); }
virtual void PostProcessScene(bool swscene, int fixedcm, float flash, bool palettePostprocess, const std::function<void()> &afterBloomDrawEndScene2D) { if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); }
virtual int GetLevelMeshPipelineID(const MeshApplyData& applyData, const SurfaceUniforms& surfaceUniforms, const FMaterialState& material) { return 0; }
virtual void DownloadLightmap(int arrayIndex, uint16_t* buffer) { }

View file

@ -64,7 +64,7 @@ void VkPostprocess::SetActiveRenderTarget()
fb->GetRenderState()->SetRenderTarget(&buffers->PipelineImage[mCurrentPipelineImage], buffers->PipelineDepthStencil.View.get(), buffers->GetWidth(), buffers->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT);
}
void VkPostprocess::PostProcessScene(int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D)
void VkPostprocess::PostProcessScene(int fixedcm, float flash, bool palettePostprocess, const std::function<void()> &afterBloomDrawEndScene2D)
{
fb->GetRenderState()->EndRenderPass();
fb->GetCommands()->FlushCommands(false);
@ -77,7 +77,7 @@ void VkPostprocess::PostProcessScene(int fixedcm, float flash, const std::functi
hw_postprocess.Pass1(&renderstate, fixedcm, sceneWidth, sceneHeight);
SetActiveRenderTarget();
afterBloomDrawEndScene2D();
hw_postprocess.Pass2(&renderstate, fixedcm, flash, sceneWidth, sceneHeight);
hw_postprocess.Pass2(&renderstate, fixedcm, flash, palettePostprocess, sceneWidth, sceneHeight);
}
void VkPostprocess::BlitSceneToPostprocess()

View file

@ -24,7 +24,7 @@ public:
~VkPostprocess();
void SetActiveRenderTarget();
void PostProcessScene(int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D);
void PostProcessScene(int fixedcm, float flash, bool palettePostprocess, const std::function<void()> &afterBloomDrawEndScene2D);
void UpdateLinearDepthTexture();
void AmbientOccludeScene(float m5);

View file

@ -403,10 +403,10 @@ void VulkanRenderDevice::UploadEnvironmentMaps(int cubemapCount, const TArray<ui
mTextureManager->CreatePrefiltermap(128, 6 * cubemapCount, prefilterMaps);
}
void VulkanRenderDevice::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D)
void VulkanRenderDevice::PostProcessScene(bool swscene, int fixedcm, float flash, bool palettePostprocess, const std::function<void()> &afterBloomDrawEndScene2D)
{
if (!swscene) mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture
mPostprocess->PostProcessScene(fixedcm, flash, afterBloomDrawEndScene2D);
mPostprocess->PostProcessScene(fixedcm, flash, palettePostprocess, afterBloomDrawEndScene2D);
}
const char* VulkanRenderDevice::DeviceName() const

View file

@ -66,7 +66,7 @@ public:
void StartPrecaching() override;
void BeginFrame() override;
void BlurScene(float amount) override;
void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D) override;
void PostProcessScene(bool swscene, int fixedcm, float flash, bool palettePostprocess, const std::function<void()> &afterBloomDrawEndScene2D) override;
void UpdateLinearDepthTexture() override;
void AmbientOccludeScene(float m5) override;
void SetSceneRenderTarget(bool useSSAO) override;

View file

@ -207,7 +207,7 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
RenderState.EnableDrawBuffers(1);
}
screen->PostProcessScene(false, cm, flash, [&]() { di->DrawEndScene2D(mainvp.sector, RenderState); });
screen->PostProcessScene(false, cm, flash, !V_IsTrueColor(), [&]() { di->DrawEndScene2D(mainvp.sector, RenderState); });
PostProcess.Unclock();
}
// Reset colormap so 2D drawing isn't affected

View file

@ -118,7 +118,7 @@ sector_t *SWSceneDrawer::RenderView(player_t *player)
DrawTexture(twod, fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE);
screen->Draw2D();
twod->Clear();
screen->PostProcessScene(true, CM_DEFAULT, 1.f, [&]() {
screen->PostProcessScene(true, CM_DEFAULT, 1.f, false, [&]() {
SWRenderer->DrawRemainingPlayerSprites();
screen->Draw2D();
twod->Clear();
@ -134,7 +134,7 @@ sector_t *SWSceneDrawer::RenderView(player_t *player)
int cm = CM_DEFAULT;
auto map = swrenderer::CameraLight::Instance()->ShaderColormap();
if (map) cm = (int)(ptrdiff_t)(map - SpecialColormaps.Data()) + CM_FIRSTSPECIALCOLORMAP;
screen->PostProcessScene(true, cm, 1.f, [&]() { });
screen->PostProcessScene(true, cm, 1.f, false, [&]() { });
SWRenderer->DrawRemainingPlayerSprites();
screen->Draw2D();