281 lines
9.1 KiB
C++
281 lines
9.1 KiB
C++
|
|
// Copyright 2017 Mike Fricker. All Rights Reserved.
|
||
|
|
|
||
|
|
#include "StreetMapRuntime.h"
|
||
|
|
#include "StreetMapSceneProxy.h"
|
||
|
|
#include "StreetMapComponent.h"
|
||
|
|
#include "Runtime/Engine/Public/SceneManagement.h"
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapVertexBuffer::InitRHI()
|
||
|
|
{
|
||
|
|
if( Vertices.Num() > 0 )
|
||
|
|
{
|
||
|
|
// Allocate our vertex buffer
|
||
|
|
FRHIResourceCreateInfo CreateInfo;
|
||
|
|
VertexBufferRHI = RHICreateVertexBuffer( Vertices.Num() * sizeof( Vertices[0] ), BUF_Static, CreateInfo );
|
||
|
|
|
||
|
|
// Load the vertex buffer with data
|
||
|
|
void* VertexBufferData = RHILockVertexBuffer( VertexBufferRHI, 0, Vertices.Num() * sizeof( Vertices[0] ), RLM_WriteOnly );
|
||
|
|
FMemory::Memcpy( VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof( FStreetMapVertex ) );
|
||
|
|
RHIUnlockVertexBuffer( VertexBufferRHI );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapIndexBuffer::InitRHI()
|
||
|
|
{
|
||
|
|
const int IndexCount = FMath::Max( Indices16.Num(), Indices32.Num() );
|
||
|
|
if( IndexCount > 0 )
|
||
|
|
{
|
||
|
|
const bool b32BitIndices = Indices32.Num() > Indices16.Num();
|
||
|
|
const uint8 IndexSize = b32BitIndices ? sizeof( Indices32[ 0 ] ) : sizeof( Indices16[ 0 ] );
|
||
|
|
const void* IndexSourceData;
|
||
|
|
if( b32BitIndices )
|
||
|
|
{
|
||
|
|
IndexSourceData = Indices32.GetData();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
IndexSourceData = Indices16.GetData();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Allocate our index buffer and load it with data
|
||
|
|
FRHIResourceCreateInfo CreateInfo;
|
||
|
|
IndexBufferRHI = RHICreateIndexBuffer( IndexSize, IndexCount * IndexSize, BUF_Static, CreateInfo );
|
||
|
|
void* IndexBufferData = RHILockIndexBuffer( IndexBufferRHI, 0, IndexCount * IndexSize, RLM_WriteOnly );
|
||
|
|
FMemory::Memcpy( IndexBufferData, IndexSourceData, IndexCount * IndexSize );
|
||
|
|
RHIUnlockIndexBuffer( IndexBufferRHI );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapVertexFactory::InitVertexFactory( const FStreetMapVertexBuffer& VertexBuffer )
|
||
|
|
{
|
||
|
|
// Setup the vertex factory streams
|
||
|
|
FDataType DataType;
|
||
|
|
DataType.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT( &VertexBuffer, FStreetMapVertex, Position, VET_Float3 );
|
||
|
|
DataType.TextureCoordinates.Add( STRUCTMEMBER_VERTEXSTREAMCOMPONENT( &VertexBuffer, FStreetMapVertex, TextureCoordinate, VET_Float2 ) );
|
||
|
|
DataType.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT( &VertexBuffer, FStreetMapVertex, TangentX, VET_PackedNormal);
|
||
|
|
DataType.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT( &VertexBuffer, FStreetMapVertex, TangentZ, VET_PackedNormal);
|
||
|
|
DataType.ColorComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT( &VertexBuffer, FStreetMapVertex, Color, VET_Color );
|
||
|
|
|
||
|
|
// Send it off to the rendering thread
|
||
|
|
check( !IsInActualRenderingThread() );
|
||
|
|
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
|
||
|
|
InitStreetMapVertexFactory,
|
||
|
|
FStreetMapVertexFactory*, VertexFactory, this,
|
||
|
|
FDataType, DataType, DataType,
|
||
|
|
{
|
||
|
|
VertexFactory->SetData( DataType );
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
FStreetMapSceneProxy::FStreetMapSceneProxy(const UStreetMapComponent* InComponent)
|
||
|
|
: FPrimitiveSceneProxy(InComponent),
|
||
|
|
StreetMapComp(InComponent),
|
||
|
|
CollisionResponse(InComponent->GetCollisionResponseToChannels())
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::Init( const UStreetMapComponent* InComponent, const TArray< FStreetMapVertex >& Vertices, const TArray< uint16 >& Indices )
|
||
|
|
{
|
||
|
|
// Copy 16-bit index data
|
||
|
|
IndexBuffer.Indices16 = Indices;
|
||
|
|
|
||
|
|
InitAfterIndexBuffer( InComponent, Vertices );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::Init( const UStreetMapComponent* InComponent, const TArray< FStreetMapVertex >& Vertices, const TArray< uint32 >& Indices )
|
||
|
|
{
|
||
|
|
// If we fit into a 16-bit index buffer, just use that
|
||
|
|
if( Vertices.Num() < 0xffff )
|
||
|
|
{
|
||
|
|
const int32 IndexCount = Indices.Num();
|
||
|
|
IndexBuffer.Indices16.AddUninitialized( IndexCount );
|
||
|
|
for( int32 Index = 0; Index < IndexCount; ++Index )
|
||
|
|
{
|
||
|
|
IndexBuffer.Indices16[ Index ] = Indices[ Index ];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Copy 32-bit index data
|
||
|
|
IndexBuffer.Indices32 = Indices;
|
||
|
|
}
|
||
|
|
|
||
|
|
InitAfterIndexBuffer( InComponent, Vertices );
|
||
|
|
}
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::InitAfterIndexBuffer( const UStreetMapComponent* StreetMapComponent, const TArray< FStreetMapVertex >& Vertices )
|
||
|
|
{
|
||
|
|
MaterialInterface = nullptr;
|
||
|
|
this->MaterialRelevance = StreetMapComponent->GetMaterialRelevance( GetScene().GetFeatureLevel() );
|
||
|
|
|
||
|
|
// Copy vertex data
|
||
|
|
VertexBuffer.Vertices = Vertices;
|
||
|
|
InitResources();
|
||
|
|
|
||
|
|
// Set a material
|
||
|
|
{
|
||
|
|
if( StreetMapComponent->GetNumMaterials() > 0 )
|
||
|
|
{
|
||
|
|
MaterialInterface = StreetMapComponent->GetMaterial( 0 );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Use the default material if we don't have one set
|
||
|
|
if( MaterialInterface == nullptr )
|
||
|
|
{
|
||
|
|
MaterialInterface = UMaterial::GetDefaultMaterial( MD_Surface );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
FStreetMapSceneProxy::~FStreetMapSceneProxy()
|
||
|
|
{
|
||
|
|
VertexBuffer.ReleaseResource();
|
||
|
|
IndexBuffer.ReleaseResource();
|
||
|
|
VertexFactory.ReleaseResource();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::InitResources()
|
||
|
|
{
|
||
|
|
// Start initializing our vertex buffer, index buffer, and vertex factory. This will be kicked off on the render thread.
|
||
|
|
BeginInitResource( &VertexBuffer );
|
||
|
|
BeginInitResource( &IndexBuffer );
|
||
|
|
|
||
|
|
VertexFactory.InitVertexFactory( VertexBuffer );
|
||
|
|
BeginInitResource( &VertexFactory );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool FStreetMapSceneProxy::MustDrawMeshDynamically( const FSceneView& View ) const
|
||
|
|
{
|
||
|
|
return ( AllowDebugViewmodes() && View.Family->EngineShowFlags.Wireframe ) || IsSelected();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool FStreetMapSceneProxy::IsInCollisionView(const FEngineShowFlags& EngineShowFlags) const
|
||
|
|
{
|
||
|
|
return EngineShowFlags.CollisionVisibility || EngineShowFlags.CollisionPawn;
|
||
|
|
}
|
||
|
|
|
||
|
|
FPrimitiveViewRelevance FStreetMapSceneProxy::GetViewRelevance( const FSceneView* View ) const
|
||
|
|
{
|
||
|
|
FPrimitiveViewRelevance Result;
|
||
|
|
Result.bDrawRelevance = IsShown(View);
|
||
|
|
Result.bShadowRelevance = IsShadowCast(View);
|
||
|
|
|
||
|
|
const bool bAlwaysHasDynamicData = false;
|
||
|
|
|
||
|
|
// Only draw dynamically if we're drawing in wireframe or we're selected in the editor
|
||
|
|
Result.bDynamicRelevance = MustDrawMeshDynamically( *View ) || bAlwaysHasDynamicData;
|
||
|
|
Result.bStaticRelevance = !MustDrawMeshDynamically( *View );
|
||
|
|
|
||
|
|
MaterialRelevance.SetPrimitiveViewRelevance(Result);
|
||
|
|
return Result;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool FStreetMapSceneProxy::CanBeOccluded() const
|
||
|
|
{
|
||
|
|
return !MaterialRelevance.bDisableDepthTest;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::MakeMeshBatch( FMeshBatch& Mesh, FMaterialRenderProxy* WireframeMaterialRenderProxyOrNull, bool bDrawCollision) const
|
||
|
|
{
|
||
|
|
FMaterialRenderProxy* MaterialProxy = NULL;
|
||
|
|
if( WireframeMaterialRenderProxyOrNull != nullptr )
|
||
|
|
{
|
||
|
|
MaterialProxy = WireframeMaterialRenderProxyOrNull;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (bDrawCollision)
|
||
|
|
{
|
||
|
|
MaterialProxy = new FColoredMaterialRenderProxy(GEngine->ShadedLevelColorationUnlitMaterial->GetRenderProxy(IsSelected(), IsHovered()), FColor::Cyan);
|
||
|
|
}
|
||
|
|
else if (MaterialProxy == nullptr)
|
||
|
|
{
|
||
|
|
MaterialProxy = StreetMapComp->GetDefaultMaterial()->GetRenderProxy(IsSelected());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
FMeshBatchElement& BatchElement = Mesh.Elements[0];
|
||
|
|
BatchElement.IndexBuffer = &IndexBuffer;
|
||
|
|
Mesh.bWireframe = WireframeMaterialRenderProxyOrNull != nullptr;
|
||
|
|
Mesh.VertexFactory = &VertexFactory;
|
||
|
|
Mesh.MaterialRenderProxy = MaterialProxy;
|
||
|
|
Mesh.CastShadow = true;
|
||
|
|
BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, UseEditorDepthTest());
|
||
|
|
BatchElement.FirstIndex = 0;
|
||
|
|
const int IndexCount = FMath::Max( IndexBuffer.Indices16.Num(), IndexBuffer.Indices32.Num() );
|
||
|
|
BatchElement.NumPrimitives = IndexCount / 3;
|
||
|
|
BatchElement.MinVertexIndex = 0;
|
||
|
|
BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1;
|
||
|
|
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
|
||
|
|
Mesh.Type = PT_TriangleList;
|
||
|
|
Mesh.DepthPriorityGroup = SDPG_World;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::DrawStaticElements( FStaticPrimitiveDrawInterface* PDI )
|
||
|
|
{
|
||
|
|
const int IndexCount = FMath::Max( IndexBuffer.Indices16.Num(), IndexBuffer.Indices32.Num() );
|
||
|
|
if( VertexBuffer.Vertices.Num() > 0 && IndexCount > 0 )
|
||
|
|
{
|
||
|
|
const float ScreenSize = 1.0f;
|
||
|
|
|
||
|
|
FMeshBatch MeshBatch;
|
||
|
|
MakeMeshBatch( MeshBatch, nullptr);
|
||
|
|
PDI->DrawMesh( MeshBatch, ScreenSize );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void FStreetMapSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, class FMeshElementCollector& Collector) const
|
||
|
|
{
|
||
|
|
const int IndexCount = FMath::Max(IndexBuffer.Indices16.Num(), IndexBuffer.Indices32.Num());
|
||
|
|
if (VertexBuffer.Vertices.Num() > 0 && IndexCount > 0)
|
||
|
|
{
|
||
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
|
||
|
|
{
|
||
|
|
const FSceneView& View = *Views[ViewIndex];
|
||
|
|
|
||
|
|
const bool bIsWireframe = AllowDebugViewmodes() && View.Family->EngineShowFlags.Wireframe;
|
||
|
|
|
||
|
|
FColoredMaterialRenderProxy* WireframeMaterialRenderProxy = GEngine->WireframeMaterial && bIsWireframe ? new FColoredMaterialRenderProxy(GEngine->WireframeMaterial->GetRenderProxy(IsSelected()), FLinearColor(0, 0.5f, 1.f)) : NULL;
|
||
|
|
|
||
|
|
|
||
|
|
if (MustDrawMeshDynamically(View))
|
||
|
|
{
|
||
|
|
const bool bInCollisionView = IsInCollisionView(ViewFamily.EngineShowFlags);
|
||
|
|
const bool bCanDrawCollision = bInCollisionView && IsCollisionEnabled();
|
||
|
|
|
||
|
|
if (!IsCollisionEnabled() && bInCollisionView)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Draw the mesh!
|
||
|
|
FMeshBatch& MeshBatch = Collector.AllocateMesh();
|
||
|
|
MakeMeshBatch(MeshBatch, WireframeMaterialRenderProxy, bCanDrawCollision);
|
||
|
|
Collector.AddMesh(ViewIndex, MeshBatch);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
uint32 FStreetMapSceneProxy::GetMemoryFootprint( void ) const
|
||
|
|
{
|
||
|
|
return sizeof( *this ) + GetAllocatedSize();
|
||
|
|
}
|