diff --git a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h index 1078acc2e..62575e46d 100644 --- a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h +++ b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h @@ -399,6 +399,8 @@ public: GraphicsPipelineBuilder& AddDynamicState(VkDynamicState state); + GraphicsPipelineBuilder& PolygonMode(VkPolygonMode mode) {rasterizer.polygonMode = mode; return *this;}; + GraphicsPipelineBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp index fc8c715b3..7dc6b6791 100644 --- a/src/common/console/c_cvars.cpp +++ b/src/common/console/c_cvars.cpp @@ -994,6 +994,22 @@ int FColorCVar::ToInt2 (UCVarValue value, ECVarType type) return ret; } +DVector4 FColorCVar::asDV4() const +{ + PalEntry col; + col.d = Value; + + return {col.r / 255.0, col.g / 255.0, col.b / 255.0, col.a / 255.0}; +} + +FVector4 FColorCVar::asFV4() const +{ + PalEntry col; + col.d = Value; + + return {col.r / 255.0f, col.g / 255.0f, col.b / 255.0f, col.a / 255.0f}; +} + // // More base cvar stuff // diff --git a/src/common/console/c_cvars.h b/src/common/console/c_cvars.h index c52af0aeb..ab1984939 100644 --- a/src/common/console/c_cvars.h +++ b/src/common/console/c_cvars.h @@ -38,6 +38,7 @@ #include "autosegs.h" #include "name.h" #include "dobjgc.h" +#include "vectors.h" class FSerializer; // this needs to go away. /* @@ -452,6 +453,10 @@ public: inline operator uint32_t () const { return Value; } inline uint32_t operator *() const { return Value; } + DVector4 asDV4() const; + + FVector4 asFV4() const; + protected: virtual void DoSet (UCVarValue value, ECVarType type); diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.cpp b/src/common/rendering/hwrenderer/data/hw_cvars.cpp index db0da86ac..f3e89e432 100644 --- a/src/common/rendering/hwrenderer/data/hw_cvars.cpp +++ b/src/common/rendering/hwrenderer/data/hw_cvars.cpp @@ -159,4 +159,7 @@ CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } -CVAR(Bool, gl_strict_gldefs, true, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) \ No newline at end of file +CVAR(Bool, gl_strict_gldefs, true, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) + +CVAR(Int, gl_wireframe, 0, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +CVAR(Color, gl_wireframecolor, -1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) \ No newline at end of file diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.h b/src/common/rendering/hwrenderer/data/hw_cvars.h index 54688884d..715ffc7cd 100644 --- a/src/common/rendering/hwrenderer/data/hw_cvars.h +++ b/src/common/rendering/hwrenderer/data/hw_cvars.h @@ -59,4 +59,6 @@ EXTERN_CVAR(Bool, gl_notexturefill) EXTERN_CVAR(Bool, r_radarclipper) EXTERN_CVAR(Bool, r_dithertransparency) -EXTERN_CVAR(Bool, gl_strict_gldefs) \ No newline at end of file +EXTERN_CVAR(Bool, gl_strict_gldefs) +EXTERN_CVAR(Int, gl_wireframe) +EXTERN_CVAR(Color, gl_wireframecolor) \ No newline at end of file diff --git a/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp b/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp index a3cdcc74e..95d6145eb 100644 --- a/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp +++ b/src/common/rendering/hwrenderer/data/hw_meshbuilder.cpp @@ -24,7 +24,7 @@ void MeshBuilder::SetShadowData(const TArray& vertices, const TArra mIndexes = indexes; } -void MeshBuilder::Draw(int dt, int index, int count, bool apply) +void MeshBuilder::DoDraw(int dt, int index, int count, bool apply) { if (apply) Apply(); @@ -37,7 +37,7 @@ void MeshBuilder::Draw(int dt, int index, int count, bool apply) mDrawLists->mDraws.Push(command); } -void MeshBuilder::DrawIndexed(int dt, int index, int count, bool apply) +void MeshBuilder::DoDrawIndexed(int dt, int index, int count, bool apply) { if (apply) Apply(); diff --git a/src/common/rendering/hwrenderer/data/hw_meshbuilder.h b/src/common/rendering/hwrenderer/data/hw_meshbuilder.h index eca48c522..91af5e351 100644 --- a/src/common/rendering/hwrenderer/data/hw_meshbuilder.h +++ b/src/common/rendering/hwrenderer/data/hw_meshbuilder.h @@ -83,8 +83,8 @@ public: int UploadFogballs(const TArray& balls) override { return -1; } // Draw commands - void Draw(int dt, int index, int count, bool apply = true) override; - void DrawIndexed(int dt, int index, int count, bool apply = true) override; + void DoDraw(int dt, int index, int count, bool apply = true) override; + void DoDrawIndexed(int dt, int index, int count, bool apply = true) override; // Immediate render state change commands. These only change infrequently and should not clutter the render state. void SetDepthFunc(int func) override; diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index 4e22ed3e4..c23e5a6f8 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -138,6 +138,10 @@ protected: uint8_t mGradientEnabled : 1; uint8_t mSplitEnabled : 1; uint8_t mBrightmapEnabled : 1; + uint8_t mWireframe : 2; + + FVector4 mWireframeColor; + FVector4 uObjectColor; int mLightIndex; int mBoneIndexBase; @@ -166,12 +170,16 @@ protected: EPassType mPassType = NORMAL_PASS; + virtual void DoDraw(int dt, int index, int count, bool apply) = 0; + virtual void DoDrawIndexed(int dt, int index, int count, bool apply) = 0; public: uint64_t firstFrame = 0; void Reset() { + mWireframe = 0; + mWireframeColor = toFVector4(PalEntry(0xffffffff)); mTextureEnabled = true; mBrightmapEnabled = mGradientEnabled = mFogEnabled = mGlowEnabled = false; mFogColor = 0xffffffff; @@ -183,7 +191,7 @@ public: mSurfaceUniforms.uAlphaThreshold = 0.5f; mSplitEnabled = false; mSurfaceUniforms.uAddColor = toFVector4(PalEntry(0)); - mSurfaceUniforms.uObjectColor = toFVector4(PalEntry(0xffffffff)); + uObjectColor = toFVector4(PalEntry(0xffffffff)); mSurfaceUniforms.uObjectColor2 = toFVector4(PalEntry(0)); mSurfaceUniforms.uTextureBlendColor = toFVector4(PalEntry(0)); mSurfaceUniforms.uTextureAddColor = toFVector4(PalEntry(0)); @@ -233,6 +241,12 @@ public: mSurfaceUniforms.uVertexNormal = { norm.X, norm.Y, norm.Z, 0.f }; } + void SetWireframe(int mode, FVector4 color) + { + mWireframe = mode; + mWireframeColor = color; + } + void SetNormal(float x, float y, float z) { mSurfaceUniforms.uVertexNormal = { x, y, z, 0.f }; @@ -409,7 +423,7 @@ public: void SetObjectColor(PalEntry pe) { - mSurfaceUniforms.uObjectColor = toFVector4(pe); + uObjectColor = toFVector4(pe); } void SetObjectColor2(PalEntry pe) @@ -672,8 +686,59 @@ public: // Draw commands virtual void ClearScreen() = 0; - virtual void Draw(int dt, int index, int count, bool apply = true) = 0; - virtual void DrawIndexed(int dt, int index, int count, bool apply = true) = 0; + + void Draw(int dt, int index, int count, bool apply = true) + { + if(mWireframe == 0) + { + mSurfaceUniforms.uObjectColor = uObjectColor; + DoDraw(dt, index, count, apply); + } + else if(mWireframe == 1) + { + mSurfaceUniforms.uObjectColor = mWireframeColor; + DoDraw(dt, index, count, apply); + } + else //if(mWireframe == 2) + { + mWireframe = 0; + mSurfaceUniforms.uObjectColor = uObjectColor; + DoDraw(dt, index, count, true); + + mWireframe = 1; + mSurfaceUniforms.uObjectColor = mWireframeColor; + DoDraw(dt, index, count, true); + + mWireframe = 2; + } + } + + void DrawIndexed(int dt, int index, int count, bool apply = true) + { + if(mWireframe == 0) + { + mSurfaceUniforms.uObjectColor = uObjectColor; + DoDrawIndexed(dt, index, count, apply); + } + else if(mWireframe == 1) + { + mSurfaceUniforms.uObjectColor = mWireframeColor; + DoDrawIndexed(dt, index, count, apply); + } + else //if(mWireframe == 2) + { + mWireframe = 0; + mSurfaceUniforms.uObjectColor = uObjectColor; + DoDrawIndexed(dt, index, count, true); + + mWireframe = 1; + mSurfaceUniforms.uObjectColor = mWireframeColor; + DoDrawIndexed(dt, index, count, true); + + mWireframe = 2; + } + } + // Immediate render state change commands. These only change infrequently and should not clutter the render state. virtual bool SetDepthClamp(bool on) = 0; // Deactivated only by skyboxes. diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp index 0fa751f00..f293d47f8 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp @@ -302,6 +302,8 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli GraphicsPipelineBuilder builder; builder.Cache(fb->GetRenderPassManager()->GetCache()); + builder.PolygonMode(key.DrawLine ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL); + VkShaderProgram *program = fb->GetShaderManager()->Get(key.ShaderKey); builder.AddVertexShader(program->vert.get()); if (program->frag) diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.h b/src/common/rendering/vulkan/pipelines/vk_renderpass.h index 2b1fe62dd..433ba8a98 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.h +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.h @@ -34,7 +34,8 @@ public: uint64_t DepthFunc : 2; uint64_t StencilTest : 1; uint64_t StencilPassOp : 2; - uint64_t Unused : 46; + uint64_t DrawLine : 1; + uint64_t Unused : 45; }; uint64_t AsQWORD = 0; }; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index c749715d0..292e67246 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -252,11 +252,7 @@ void VulkanRenderDevice::InitializeState() mDescriptorSetManager->Init(); -#ifdef __APPLE__ - mRenderState = std::make_unique(this); -#else mRenderState = std::make_unique(this); -#endif } void VulkanRenderDevice::Update() diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index 7c76b98ec..21709ca16 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -71,15 +71,37 @@ void VkRenderState::ClearScreen() mCommandBuffer->draw(4, 1, vertices.second, 0); } -void VkRenderState::Draw(int dt, int index, int count, bool apply) +void VkRenderState::DoDraw(int dt, int index, int count, bool apply) { - if (apply || mNeedApply) - Apply(dt); + #ifdef __APPLE__ + // moltenvk doesn't support drawing triangle fans + if (dt == DT_TriangleFan) + { + IBuffer* oldIndexBuffer = mIndexBuffer; + mIndexBuffer = fb->GetBufferManager()->FanToTrisIndexBuffer.get(); - mCommandBuffer->draw(count, 1, index, 0); + if (apply || mNeedApply) + Apply(DT_Triangles); + else + ApplyVertexBuffers(); + + mCommandBuffer->drawIndexed((count - 2) * 3, 1, 0, index, 0); + + mIndexBuffer = oldIndexBuffer; + } + else + { + #endif + if (apply || mNeedApply) + Apply(dt); + + mCommandBuffer->draw(count, 1, index, 0); + #ifdef __APPLE__ + } + #endif } -void VkRenderState::DrawIndexed(int dt, int index, int count, bool apply) +void VkRenderState::DoDrawIndexed(int dt, int index, int count, bool apply) { if (apply || mNeedApply) Apply(dt); @@ -226,10 +248,11 @@ void VkRenderState::ApplyRenderPass(int dt) // Find a pipeline that matches our state VkPipelineKey pipelineKey; pipelineKey.DrawType = dt; + pipelineKey.DrawLine = mDrawLine || mWireframe; pipelineKey.VertexFormat = mVertexBuffer ? static_cast(mVertexBuffer)->VertexFormat : mRSBuffers->Flatbuffer.VertexFormat; pipelineKey.RenderStyle = mRenderStyle; - pipelineKey.DepthTest = mDepthTest; - pipelineKey.DepthWrite = mDepthTest && mDepthWrite; + pipelineKey.DepthTest = mDepthTest && !mWireframe; + pipelineKey.DepthWrite = mDepthTest && !mWireframe && mDepthWrite; pipelineKey.DepthFunc = mDepthFunc; pipelineKey.DepthClamp = mDepthClamp; pipelineKey.DepthBias = !(mBias.mFactor == 0 && mBias.mUnits == 0); @@ -247,7 +270,7 @@ void VkRenderState::ApplyRenderPass(int dt) { int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0); pipelineKey.ShaderKey.SpecialEffect = EFF_NONE; - pipelineKey.ShaderKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture; + pipelineKey.ShaderKey.EffectState = (mTextureEnabled && !mWireframe) ? effectState : SHADER_NoTexture; if (r_skipmats && pipelineKey.ShaderKey.EffectState >= 3 && pipelineKey.ShaderKey.EffectState <= 4) pipelineKey.ShaderKey.EffectState = 0; pipelineKey.ShaderKey.AlphaTest = mSurfaceUniforms.uAlphaThreshold >= 0.f; @@ -1080,15 +1103,16 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip pipelineKey.ShaderKey.GBufferPass = mRenderTarget.DrawBuffers > 1; // State overridden by the renderstate drawing the mesh - pipelineKey.DepthTest = mDepthTest; - pipelineKey.DepthWrite = mDepthTest && mDepthWrite; + pipelineKey.DrawLine = mDrawLine || mWireframe; + pipelineKey.DepthTest = mDepthTest && !mWireframe; + pipelineKey.DepthWrite = mDepthTest && !mWireframe && mDepthWrite; pipelineKey.DepthClamp = mDepthClamp; pipelineKey.DepthBias = !(mBias.mFactor == 0 && mBias.mUnits == 0); pipelineKey.StencilTest = mStencilTest; pipelineKey.StencilPassOp = mStencilOp; pipelineKey.ColorMask = mColorMask; pipelineKey.CullMode = mCullMode; - if (!mTextureEnabled) + if (!mTextureEnabled || mWireframe) pipelineKey.ShaderKey.EffectState = SHADER_NoTexture; mPipelineKey = pipelineKey; @@ -1110,30 +1134,3 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet()); cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants); } - -///////////////////////////////////////////////////////////////////////////// - -void VkRenderStateMolten::Draw(int dt, int index, int count, bool apply) -{ - if (dt == DT_TriangleFan) - { - IBuffer* oldIndexBuffer = mIndexBuffer; - mIndexBuffer = fb->GetBufferManager()->FanToTrisIndexBuffer.get(); - - if (apply || mNeedApply) - Apply(DT_Triangles); - else - ApplyVertexBuffers(); - - mCommandBuffer->drawIndexed((count - 2) * 3, 1, 0, index, 0); - - mIndexBuffer = oldIndexBuffer; - } - else - { - if (apply || mNeedApply) - Apply(dt); - - mCommandBuffer->draw(count, 1, index, 0); - } -} diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index ca5fc87f9..4bee19175 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -22,8 +22,8 @@ public: // Draw commands void ClearScreen() override; - void Draw(int dt, int index, int count, bool apply = true) override; - void DrawIndexed(int dt, int index, int count, bool apply = true) override; + void DoDraw(int dt, int index, int count, bool apply) override; + void DoDrawIndexed(int dt, int index, int count, bool apply) override; // Immediate render state change commands. These only change infrequently and should not clutter the render state. bool SetDepthClamp(bool on) override; @@ -105,6 +105,7 @@ protected: VkRenderPassSetup* mPassSetup = nullptr; int mClearTargets = 0; bool mNeedApply = true; + bool mDrawLine = false; int mScissorX = 0, mScissorY = 0, mScissorWidth = -1, mScissorHeight = -1; int mViewportX = 0, mViewportY = 0, mViewportWidth = -1, mViewportHeight = -1; @@ -154,12 +155,4 @@ protected: } mRenderTarget; TArray mQueryResultsBuffer; -}; - -class VkRenderStateMolten : public VkRenderState -{ -public: - using VkRenderState::VkRenderState; - - void Draw(int dt, int index, int count, bool apply = true) override; -}; +}; \ No newline at end of file diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 0aadab029..8c4ac8f83 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -1215,6 +1215,8 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state) state.SetDepthMask(true); if (!gl_no_skyclear && !gl_levelmesh) drawctx->portalState.RenderFirstSkyPortal(recursion, this, state); + state.SetWireframe(gl_wireframe, gl_wireframecolor.get()->asFV4()); + RenderScene(state); screen->UpdateLinearDepthTexture(); @@ -1237,6 +1239,9 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state) { state.SetFogballIndex(-1); } + + state.SetWireframe(0, {}); + } //-----------------------------------------------------------------------------