mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 17:56:04 +08:00
229 lines
7.6 KiB
C++
229 lines
7.6 KiB
C++
// Copyright 2016 Chris Conway (Koderz). All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Engine.h"
|
|
#include "Components/MeshComponent.h"
|
|
#include "RuntimeMeshProfiling.h"
|
|
#include "RuntimeMeshVersion.h"
|
|
#include "RuntimeMeshCore.h"
|
|
#include "RuntimeMeshRendering.h"
|
|
#include "RuntimeMeshUpdateCommands.h"
|
|
|
|
|
|
/** Interface class for the RT proxy of a single mesh section */
|
|
class FRuntimeMeshSectionProxyInterface : public FRuntimeMeshVisibilityInterface
|
|
{
|
|
public:
|
|
|
|
FRuntimeMeshSectionProxyInterface() {}
|
|
virtual ~FRuntimeMeshSectionProxyInterface() {}
|
|
|
|
virtual bool ShouldRender() = 0;
|
|
virtual bool WantsToRenderInStaticPath() const = 0;
|
|
|
|
virtual bool ShouldUseAdjacencyIndexBuffer() const = 0;
|
|
|
|
virtual FMaterialRelevance GetMaterialRelevance() const = 0;
|
|
|
|
virtual void CreateMeshBatch(FMeshBatch& MeshBatch, FMaterialRenderProxy* WireframeMaterial, bool bIsSelected) = 0;
|
|
|
|
|
|
virtual void FinishCreate_RenderThread(FRuntimeMeshSectionCreateDataInterface* UpdateData) = 0;
|
|
virtual void FinishUpdate_RenderThread(FRuntimeMeshRenderThreadCommandInterface* UpdateData) = 0;
|
|
virtual void FinishPositionUpdate_RenderThread(FRuntimeMeshRenderThreadCommandInterface* UpdateData) = 0;
|
|
virtual void FinishPropertyUpdate_RenderThread(FRuntimeMeshRenderThreadCommandInterface* UpdateData) = 0;
|
|
|
|
};
|
|
|
|
/** Templated class for the RT proxy of a single mesh section */
|
|
template <typename VertexType, bool NeedsPositionOnlyBuffer>
|
|
class FRuntimeMeshSectionProxy : public FRuntimeMeshSectionProxyInterface
|
|
{
|
|
protected:
|
|
/** Whether this section is currently visible */
|
|
bool bIsVisible;
|
|
|
|
/** Should this section cast a shadow */
|
|
bool bCastsShadow;
|
|
|
|
/** Whether this section should be using an adjacency index buffer */
|
|
bool bShouldUseAdjacency;
|
|
|
|
/** Whether this section is using a tessellation adjacency index buffer */
|
|
bool bIsUsingAdjacency;
|
|
|
|
/** Update frequency of this section */
|
|
const EUpdateFrequency UpdateFrequency;
|
|
|
|
/** Material applied to this section */
|
|
UMaterialInterface* Material;
|
|
|
|
FMaterialRelevance MaterialRelevance;
|
|
|
|
FRuntimeMeshVertexBuffer<FVector>* PositionVertexBuffer;
|
|
|
|
/** Vertex buffer for this section */
|
|
FRuntimeMeshVertexBuffer<VertexType> VertexBuffer;
|
|
|
|
/** Index buffer for this section */
|
|
FRuntimeMeshIndexBuffer IndexBuffer;
|
|
|
|
/** Vertex factory for this section */
|
|
FRuntimeMeshVertexFactory VertexFactory;
|
|
|
|
public:
|
|
FRuntimeMeshSectionProxy(FSceneInterface* InScene, EUpdateFrequency InUpdateFrequency, bool bInIsVisible, bool bInCastsShadow, UMaterialInterface* InMaterial, FMaterialRelevance InMaterialRelevance) :
|
|
bIsVisible(bInIsVisible), bCastsShadow(bInCastsShadow), UpdateFrequency(InUpdateFrequency), Material(InMaterial), MaterialRelevance(InMaterialRelevance),
|
|
PositionVertexBuffer(nullptr), VertexBuffer(InUpdateFrequency), IndexBuffer(InUpdateFrequency), VertexFactory(this)
|
|
{
|
|
bShouldUseAdjacency = RequiresAdjacencyInformation(InMaterial, VertexFactory.GetType(), InScene->GetFeatureLevel());
|
|
}
|
|
|
|
virtual ~FRuntimeMeshSectionProxy() override
|
|
{
|
|
VertexBuffer.ReleaseResource();
|
|
IndexBuffer.ReleaseResource();
|
|
VertexFactory.ReleaseResource();
|
|
|
|
if (PositionVertexBuffer)
|
|
{
|
|
PositionVertexBuffer->ReleaseResource();
|
|
delete PositionVertexBuffer;
|
|
}
|
|
}
|
|
|
|
|
|
virtual bool ShouldRender() override { return bIsVisible && VertexBuffer.Num() > 0 && IndexBuffer.Num() > 0; }
|
|
|
|
virtual bool WantsToRenderInStaticPath() const override { return UpdateFrequency == EUpdateFrequency::Infrequent; }
|
|
|
|
virtual bool ShouldUseAdjacencyIndexBuffer() const override { return bShouldUseAdjacency; }
|
|
|
|
virtual FMaterialRelevance GetMaterialRelevance() const { return MaterialRelevance; }
|
|
|
|
virtual void CreateMeshBatch(FMeshBatch& MeshBatch, FMaterialRenderProxy* WireframeMaterial, bool bIsSelected) override
|
|
{
|
|
MeshBatch.VertexFactory = &VertexFactory;
|
|
MeshBatch.bWireframe = WireframeMaterial != nullptr;
|
|
MeshBatch.MaterialRenderProxy = MeshBatch.bWireframe ? WireframeMaterial : Material->GetRenderProxy(bIsSelected);
|
|
|
|
if (bIsUsingAdjacency && WireframeMaterial == nullptr)
|
|
{
|
|
MeshBatch.Type = PT_12_ControlPointPatchList;
|
|
}
|
|
else
|
|
{
|
|
MeshBatch.Type = PT_TriangleList;
|
|
}
|
|
|
|
MeshBatch.DepthPriorityGroup = SDPG_World;
|
|
MeshBatch.CastShadow = bCastsShadow;
|
|
|
|
FMeshBatchElement& BatchElement = MeshBatch.Elements[0];
|
|
BatchElement.IndexBuffer = &IndexBuffer;
|
|
BatchElement.FirstIndex = 0;
|
|
BatchElement.NumPrimitives = bIsUsingAdjacency? IndexBuffer.Num() / 12 : IndexBuffer.Num() / 3;
|
|
BatchElement.MinVertexIndex = 0;
|
|
BatchElement.MaxVertexIndex = VertexBuffer.Num() - 1;
|
|
}
|
|
|
|
|
|
virtual void FinishCreate_RenderThread(FRuntimeMeshSectionCreateDataInterface* UpdateData) override
|
|
{
|
|
check(IsInRenderingThread());
|
|
|
|
auto* SectionUpdateData = UpdateData->As<FRuntimeMeshSectionCreateData<VertexType>>();
|
|
check(SectionUpdateData);
|
|
|
|
if (NeedsPositionOnlyBuffer)
|
|
{
|
|
// Initialize the position buffer
|
|
PositionVertexBuffer = new FRuntimeMeshVertexBuffer<FVector>(UpdateFrequency);
|
|
|
|
// Get and adjust the vertex structure
|
|
auto VertexStructure = VertexType::GetVertexStructure(VertexBuffer);
|
|
VertexStructure.PositionComponent = FVertexStreamComponent(PositionVertexBuffer, 0, sizeof(FVector), VET_Float3);
|
|
VertexFactory.Init(VertexStructure);
|
|
}
|
|
else
|
|
{
|
|
// Get and submit the vertex structure
|
|
auto VertexStructure = VertexType::GetVertexStructure(VertexBuffer);
|
|
VertexFactory.Init(VertexStructure);
|
|
}
|
|
|
|
// Initialize the vertex factory
|
|
VertexFactory.InitResource();
|
|
|
|
auto& Vertices = SectionUpdateData->VertexBuffer;
|
|
VertexBuffer.SetNum(Vertices.Num());
|
|
VertexBuffer.SetData(Vertices);
|
|
|
|
if (NeedsPositionOnlyBuffer)
|
|
{
|
|
auto& PositionVertices = SectionUpdateData->PositionVertexBuffer;
|
|
PositionVertexBuffer->SetNum(PositionVertices.Num());
|
|
PositionVertexBuffer->SetData(PositionVertices);
|
|
}
|
|
|
|
auto& Indices = SectionUpdateData->IndexBuffer;
|
|
IndexBuffer.SetNum(Indices.Num());
|
|
IndexBuffer.SetData(Indices);
|
|
bIsUsingAdjacency = SectionUpdateData->bIsAdjacencyIndexBuffer;
|
|
}
|
|
|
|
virtual void FinishUpdate_RenderThread(FRuntimeMeshRenderThreadCommandInterface* UpdateData) override
|
|
{
|
|
check(IsInRenderingThread());
|
|
|
|
auto* SectionUpdateData = UpdateData->As<FRuntimeMeshSectionUpdateData<VertexType>>();
|
|
check(SectionUpdateData);
|
|
|
|
if (SectionUpdateData->bIncludeVertexBuffer)
|
|
{
|
|
auto& VertexBufferData = SectionUpdateData->VertexBuffer;
|
|
VertexBuffer.SetNum(VertexBufferData.Num());
|
|
VertexBuffer.SetData(VertexBufferData);
|
|
}
|
|
|
|
if (NeedsPositionOnlyBuffer && SectionUpdateData->bIncludePositionBuffer)
|
|
{
|
|
auto& PositionVertices = SectionUpdateData->PositionVertexBuffer;
|
|
PositionVertexBuffer->SetNum(PositionVertices.Num());
|
|
PositionVertexBuffer->SetData(PositionVertices);
|
|
}
|
|
|
|
if (SectionUpdateData->bIncludeIndices)
|
|
{
|
|
auto& IndexBufferData = SectionUpdateData->IndexBuffer;
|
|
IndexBuffer.SetNum(IndexBufferData.Num());
|
|
IndexBuffer.SetData(IndexBufferData);
|
|
bIsUsingAdjacency = SectionUpdateData->bIsAdjacencyIndexBuffer;
|
|
}
|
|
}
|
|
|
|
virtual void FinishPositionUpdate_RenderThread(FRuntimeMeshRenderThreadCommandInterface* UpdateData) override
|
|
{
|
|
check(IsInRenderingThread());
|
|
|
|
// Get the Position Only update data
|
|
auto* SectionUpdateData = UpdateData->As<FRuntimeMeshSectionPositionOnlyUpdateData<VertexType>>();
|
|
check(SectionUpdateData);
|
|
|
|
// Copy the new data to the gpu
|
|
PositionVertexBuffer->SetData(SectionUpdateData->PositionVertexBuffer);
|
|
}
|
|
|
|
virtual void FinishPropertyUpdate_RenderThread(FRuntimeMeshRenderThreadCommandInterface* UpdateData) override
|
|
{
|
|
auto* SectionUpdateData = UpdateData->As<FRuntimeMeshSectionPropertyUpdateData>();
|
|
check(SectionUpdateData);
|
|
|
|
// Copy visibility/shadow
|
|
bIsVisible = SectionUpdateData->bIsVisible;
|
|
bCastsShadow = SectionUpdateData->bCastsShadow;
|
|
}
|
|
|
|
};
|