From e68b46cb6af371b336fe6f18e6bd491ebf62375b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 17 Jan 2020 21:58:33 +0100 Subject: [PATCH] Implement special colormap support for softpoly --- .../polyrenderer/backend/poly_framebuffer.cpp | 63 +++++++++++++++++++ .../polyrenderer/backend/poly_framebuffer.h | 16 +++++ .../polyrenderer/backend/poly_renderstate.cpp | 16 ++++- .../polyrenderer/backend/poly_renderstate.h | 3 + .../polyrenderer/drawers/poly_thread.cpp | 3 +- .../polyrenderer/drawers/poly_thread.h | 3 +- .../polyrenderer/drawers/poly_triangle.cpp | 9 +-- .../polyrenderer/drawers/poly_triangle.h | 2 +- .../polyrenderer/drawers/screen_blend.cpp | 38 ++++++++++- .../polyrenderer/drawers/screen_shader.cpp | 37 ++++++++++- src/rendering/swrenderer/r_swscene.cpp | 9 ++- 11 files changed, 185 insertions(+), 14 deletions(-) diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp index 00901fe375..c9e157d76b 100644 --- a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp +++ b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp @@ -85,6 +85,9 @@ PolyFrameBuffer::~PolyFrameBuffer() PolyBuffer::ResetAll(); PPResource::ResetAll(); + delete mScreenQuad.VertexBuffer; + delete mScreenQuad.IndexBuffer; + delete mVertexData; delete mSkyData; delete mViewpoints; @@ -111,6 +114,21 @@ void PolyFrameBuffer::InitializeState() mViewpoints = new HWViewpointBuffer; mLights = new FLightBuffer(); + static const FVertexBufferAttribute format[] = + { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(ScreenQuadVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(ScreenQuadVertex, u) }, + { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(ScreenQuadVertex, color0) } + }; + + uint32_t indices[6] = { 0, 1, 2, 1, 3, 2 }; + + mScreenQuad.VertexBuffer = screen->CreateVertexBuffer(); + mScreenQuad.VertexBuffer->SetFormat(1, 3, sizeof(ScreenQuadVertex), format); + + mScreenQuad.IndexBuffer = screen->CreateIndexBuffer(); + mScreenQuad.IndexBuffer->SetData(6 * sizeof(uint32_t), indices, false); + CheckCanvas(); } @@ -436,9 +454,54 @@ void PolyFrameBuffer::DrawScene(HWDrawInfo *di, int drawmode) di->RenderTranslucent(*GetRenderState()); } +static uint8_t ToIntColorComponent(float v) +{ + return clamp((int)(v * 255.0f + 0.5f), 0, 255); +} + void PolyFrameBuffer::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) { afterBloomDrawEndScene2D(); + + if (fixedcm >= CM_FIRSTSPECIALCOLORMAP && fixedcm < CM_MAXCOLORMAP) + { + FSpecialColormap* scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP]; + + mRenderState->SetViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); + screen->mViewpoints->Set2D(*mRenderState, screen->GetWidth(), screen->GetHeight()); + + ScreenQuadVertex vertices[4] = + { + { 0.0f, 0.0f, 0.0f, 0.0f }, + { (float)mScreenViewport.width, 0.0f, 1.0f, 0.0f }, + { 0.0f, (float)mScreenViewport.height, 0.0f, 1.0f }, + { (float)mScreenViewport.width, (float)mScreenViewport.height, 1.0f, 1.0f } + }; + mScreenQuad.VertexBuffer->SetData(4 * sizeof(ScreenQuadVertex), vertices, false); + + mRenderState->SetVertexBuffer(mScreenQuad.VertexBuffer, 0, 0); + mRenderState->SetIndexBuffer(mScreenQuad.IndexBuffer); + + mRenderState->SetObjectColor(PalEntry(255, int(scm->ColorizeStart[0] * 127.5f), int(scm->ColorizeStart[1] * 127.5f), int(scm->ColorizeStart[2] * 127.5f))); + mRenderState->SetAddColor(PalEntry(255, int(scm->ColorizeEnd[0] * 127.5f), int(scm->ColorizeEnd[1] * 127.5f), int(scm->ColorizeEnd[2] * 127.5f))); + + mRenderState->EnableDepthTest(false); + mRenderState->EnableMultisampling(false); + mRenderState->SetCulling(Cull_None); + + mRenderState->SetScissor(-1, -1, -1, -1); + mRenderState->SetColor(1, 1, 1, 1); + mRenderState->AlphaFunc(Alpha_GEqual, 0.f); + mRenderState->EnableTexture(false); + mRenderState->SetColormapShader(true); + mRenderState->DrawIndexed(DT_Triangles, 0, 6); + mRenderState->SetColormapShader(false); + mRenderState->SetObjectColor(0xffffffff); + mRenderState->SetAddColor(0); + mRenderState->SetVertexBuffer(screen->mVertexData); + mRenderState->EnableTexture(true); + mRenderState->ResetColor(); + } } uint32_t PolyFrameBuffer::GetCaps() diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.h b/src/rendering/polyrenderer/backend/poly_framebuffer.h index cd89f531ba..2e06d69062 100644 --- a/src/rendering/polyrenderer/backend/poly_framebuffer.h +++ b/src/rendering/polyrenderer/backend/poly_framebuffer.h @@ -84,6 +84,22 @@ private: std::unique_ptr mDrawCommands; RenderMemory mFrameMemory; + struct ScreenQuadVertex + { + float x, y, z; + float u, v; + PalEntry color0; + + ScreenQuadVertex() = default; + ScreenQuadVertex(float x, float y, float u, float v) : x(x), y(y), z(1.0f), u(u), v(v), color0(0xffffffff) { } + }; + + struct ScreenQuad + { + IVertexBuffer* VertexBuffer = nullptr; + IIndexBuffer* IndexBuffer = nullptr; + } mScreenQuad; + bool cur_vsync = false; }; diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.cpp b/src/rendering/polyrenderer/backend/poly_renderstate.cpp index 7fc5baab59..0ee16f47d0 100644 --- a/src/rendering/polyrenderer/backend/poly_renderstate.cpp +++ b/src/rendering/polyrenderer/backend/poly_renderstate.cpp @@ -204,6 +204,12 @@ void PolyRenderState::EnableDrawBuffers(int count) { } +void PolyRenderState::SetColormapShader(bool enable) +{ + mNeedApply = true; + mColormapShader = enable; +} + void PolyRenderState::EndRenderPass() { mDrawCommands = nullptr; @@ -260,14 +266,18 @@ void PolyRenderState::Apply() mDrawCommands->SetInputAssembly(static_cast(mVertexBuffer)->VertexFormat); mDrawCommands->SetRenderStyle(mRenderStyle); - if (mSpecialEffect > EFF_NONE) + if (mColormapShader) { - mDrawCommands->SetShader(mSpecialEffect, 0, false); + mDrawCommands->SetShader(EFF_NONE, 0, false, true); + } + else if (mSpecialEffect > EFF_NONE) + { + mDrawCommands->SetShader(mSpecialEffect, 0, false, false); } else { int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0); - mDrawCommands->SetShader(EFF_NONE, mTextureEnabled ? effectState : SHADER_NoTexture, mAlphaThreshold >= 0.f); + mDrawCommands->SetShader(EFF_NONE, mTextureEnabled ? effectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, false); } PolyPushConstants constants; diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.h b/src/rendering/polyrenderer/backend/poly_renderstate.h index e6c64bd4e2..6adea29043 100644 --- a/src/rendering/polyrenderer/backend/poly_renderstate.h +++ b/src/rendering/polyrenderer/backend/poly_renderstate.h @@ -45,6 +45,8 @@ public: PolyVertexInputAssembly *GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs); void EndRenderPass(); + void SetColormapShader(bool enable); + private: void Apply(); void ApplyMaterial(); @@ -92,6 +94,7 @@ private: int mStencilOp = SOP_Keep; int mCulling = Cull_None; bool mColorMask[4] = { true, true, true, true }; + bool mColormapShader = false; PolyCommandBuffer* mDrawCommands = nullptr; }; diff --git a/src/rendering/polyrenderer/drawers/poly_thread.cpp b/src/rendering/polyrenderer/drawers/poly_thread.cpp index e90c028790..91d1ef1ca2 100644 --- a/src/rendering/polyrenderer/drawers/poly_thread.cpp +++ b/src/rendering/polyrenderer/drawers/poly_thread.cpp @@ -248,11 +248,12 @@ void PolyTriangleThreadData::SetRenderStyle(FRenderStyle style) RenderStyle = style; } -void PolyTriangleThreadData::SetShader(int specialEffect, int effectState, bool alphaTest) +void PolyTriangleThreadData::SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader) { SpecialEffect = specialEffect; EffectState = effectState; AlphaTest = alphaTest; + ColormapShader = colormapShader; } void PolyTriangleThreadData::SetTexture(int unit, const void *pixels, int width, int height, bool bgra) diff --git a/src/rendering/polyrenderer/drawers/poly_thread.h b/src/rendering/polyrenderer/drawers/poly_thread.h index 326e5790f6..4ce764e10f 100644 --- a/src/rendering/polyrenderer/drawers/poly_thread.h +++ b/src/rendering/polyrenderer/drawers/poly_thread.h @@ -60,7 +60,7 @@ public: void SetScissor(int x, int y, int w, int h); void SetRenderStyle(FRenderStyle style); void SetTexture(int unit, const void *pixels, int width, int height, bool bgra); - void SetShader(int specialEffect, int effectState, bool alphaTest); + void SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader); void UpdateClip(); @@ -141,6 +141,7 @@ public: int SpecialEffect = EFF_NONE; int EffectState = 0; bool AlphaTest = false; + bool ColormapShader = false; uint32_t AlphaThreshold = 0x7f000000; const PolyPushConstants* PushConstants = nullptr; diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.cpp b/src/rendering/polyrenderer/drawers/poly_triangle.cpp index cae71b2af1..8631138038 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.cpp +++ b/src/rendering/polyrenderer/drawers/poly_triangle.cpp @@ -183,13 +183,14 @@ private: class PolySetShaderCommand : public PolyDrawerCommand { public: - PolySetShaderCommand(int specialEffect, int effectState, bool alphaTest) : specialEffect(specialEffect), effectState(effectState), alphaTest(alphaTest) { } - void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetShader(specialEffect, effectState, alphaTest); } + PolySetShaderCommand(int specialEffect, int effectState, bool alphaTest, bool colormapShader) : specialEffect(specialEffect), effectState(effectState), alphaTest(alphaTest), colormapShader(colormapShader) { } + void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetShader(specialEffect, effectState, alphaTest, colormapShader); } private: int specialEffect; int effectState; bool alphaTest; + bool colormapShader; }; class PolySetVertexBufferCommand : public PolyDrawerCommand @@ -429,9 +430,9 @@ void PolyCommandBuffer::SetTexture(int unit, void *pixels, int width, int height mQueue->Push(unit, pixels, width, height, bgra); } -void PolyCommandBuffer::SetShader(int specialEffect, int effectState, bool alphaTest) +void PolyCommandBuffer::SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader) { - mQueue->Push(specialEffect, effectState, alphaTest); + mQueue->Push(specialEffect, effectState, alphaTest, colormapShader); } void PolyCommandBuffer::PushStreamData(const StreamData &data, const PolyPushConstants &constants) diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.h b/src/rendering/polyrenderer/drawers/poly_triangle.h index 80e9427444..0e5cb1f9a6 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.h +++ b/src/rendering/polyrenderer/drawers/poly_triangle.h @@ -67,7 +67,7 @@ public: void SetScissor(int x, int y, int w, int h); void SetRenderStyle(FRenderStyle style); void SetTexture(int unit, void *pixels, int width, int height, bool bgra); - void SetShader(int specialEffect, int effectState, bool alphaTest); + void SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader); void PushStreamData(const StreamData &data, const PolyPushConstants &constants); void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix); void ClearDepth(float value); diff --git a/src/rendering/polyrenderer/drawers/screen_blend.cpp b/src/rendering/polyrenderer/drawers/screen_blend.cpp index 4fb00e2f97..9dee914ca6 100644 --- a/src/rendering/polyrenderer/drawers/screen_blend.cpp +++ b/src/rendering/polyrenderer/drawers/screen_blend.cpp @@ -519,10 +519,46 @@ void BlendColorRevSub_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thr } } +void BlendColorColormap(int y, int x0, int x1, PolyTriangleThreadData* thread) +{ + uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch; + + uint32_t startR = (int)((thread->mainVertexShader.Data.uObjectColor.r) * 255.0f); + uint32_t startG = (int)((thread->mainVertexShader.Data.uObjectColor.g) * 255.0f); + uint32_t startB = (int)((thread->mainVertexShader.Data.uObjectColor.b) * 255.0f); + uint32_t rangeR = (int)((thread->mainVertexShader.Data.uAddColor.r) * 255.0f) - startR; + uint32_t rangeG = (int)((thread->mainVertexShader.Data.uAddColor.g) * 255.0f) - startG; + uint32_t rangeB = (int)((thread->mainVertexShader.Data.uAddColor.b) * 255.0f) - startB; + + int sseend = x0; + for (int x = sseend; x < x1; x++) + { + uint32_t dst = line[x]; + + uint32_t a = APART(dst); + uint32_t r = RPART(dst); + uint32_t g = GPART(dst); + uint32_t b = BPART(dst); + + uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8; + gray += (gray >> 7); // gray*=256/255 + + r = (startR + ((gray * rangeR) >> 8)) << 1; + g = (startG + ((gray * rangeG) >> 8)) << 1; + b = (startB + ((gray * rangeB) >> 8)) << 1; + + line[x] = MAKEARGB(a, r, g, b); + } +} + void SelectWriteColorFunc(PolyTriangleThreadData* thread) { FRenderStyle style = thread->RenderStyle; - if (style.BlendOp == STYLEOP_Add) + if (thread->ColormapShader) + { + thread->WriteColorFunc = &BlendColorColormap; + } + else if (style.BlendOp == STYLEOP_Add) { if (style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero) { diff --git a/src/rendering/polyrenderer/drawers/screen_shader.cpp b/src/rendering/polyrenderer/drawers/screen_shader.cpp index da7e738c0c..aec34f3e09 100644 --- a/src/rendering/polyrenderer/drawers/screen_shader.cpp +++ b/src/rendering/polyrenderer/drawers/screen_shader.cpp @@ -532,13 +532,37 @@ static void MainFP(int x0, int x1, PolyTriangleThreadData* thread) auto vColorA = thread->scanline.vColorA; uint32_t* fragcolor = thread->scanline.FragColor; - if (constants->uTextureMode == TM_FOGLAYER) + if (constants->uTextureMode == TM_FIXEDCOLORMAP) { // float gray = grayscale(frag); // vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2; // frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a); // frag = frag * vColor; // frag.rgb = frag.rgb + uFogColor.rgb; + + uint32_t startR = (int)((thread->mainVertexShader.Data.uObjectColor.r) * 255.0f); + uint32_t startG = (int)((thread->mainVertexShader.Data.uObjectColor.g) * 255.0f); + uint32_t startB = (int)((thread->mainVertexShader.Data.uObjectColor.b) * 255.0f); + uint32_t rangeR = (int)((thread->mainVertexShader.Data.uAddColor.r) * 255.0f) - startR; + uint32_t rangeG = (int)((thread->mainVertexShader.Data.uAddColor.g) * 255.0f) - startG; + uint32_t rangeB = (int)((thread->mainVertexShader.Data.uAddColor.b) * 255.0f) - startB; + + for (int x = x0; x < x1; x++) + { + uint32_t a = APART(fragcolor[x]); + uint32_t r = RPART(fragcolor[x]); + uint32_t g = GPART(fragcolor[x]); + uint32_t b = BPART(fragcolor[x]); + + uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8; + gray += (gray >> 7); // gray*=256/255 + + r = (startR + ((gray * rangeR) >> 8)) << 1; + g = (startG + ((gray * rangeG) >> 8)) << 1; + b = (startB + ((gray * rangeB) >> 8)) << 1; + + fragcolor[x] = MAKEARGB(a, r, g, b); + } } else { @@ -570,11 +594,20 @@ static void MainFP(int x0, int x1, PolyTriangleThreadData* thread) } } +void ColormapFP(int x0, int x1, PolyTriangleThreadData* thread) +{ + // This is implemented in BlendColorColormap. +} + void SelectFragmentShader(PolyTriangleThreadData* thread) { void (*fragshader)(int x0, int x1, PolyTriangleThreadData * thread); - if (thread->SpecialEffect == EFF_FOGBOUNDARY) // fogboundary.fp + if (thread->ColormapShader) + { + fragshader = &ColormapFP; + } + else if (thread->SpecialEffect == EFF_FOGBOUNDARY) // fogboundary.fp { fragshader = &EffectFogBoundary; } diff --git a/src/rendering/swrenderer/r_swscene.cpp b/src/rendering/swrenderer/r_swscene.cpp index 68318f7f5f..7e432fb525 100644 --- a/src/rendering/swrenderer/r_swscene.cpp +++ b/src/rendering/swrenderer/r_swscene.cpp @@ -126,9 +126,16 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) } else { + // With softpoly truecolor we render directly to the target framebuffer + DCanvas *canvas = screen->GetCanvas(); SWRenderer->RenderView(player, canvas, canvas->GetPixels(), canvas->GetPitch()); - // To do: apply swrenderer::CameraLight::Instance()->ShaderColormap(); + + int cm = CM_DEFAULT; + auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); + if (map) cm = (int)(ptrdiff_t)(map - SpecialColormaps.Data()) + CM_FIRSTSPECIALCOLORMAP; + screen->PostProcessScene(cm, [&]() { }); + SWRenderer->DrawRemainingPlayerSprites(); screen->Draw2D(); screen->Clear2D();