// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MuR/ParallelExecutionUtils.h" #include "MuR/ImagePrivate.h" #include "MuR/Platform.h" #include "MuR/MeshPrivate.h" #include "MuR/Raster.h" #include "MuR/ConvertData.h" namespace UE::Mutable::Private { class WhitePixelProcessor { public: inline void ProcessPixel(uint8* pBufferPos, float[1]) const { pBufferPos[0] = 255; } inline void operator()(uint8* BufferPos, float Interpolators[1]) const { ProcessPixel(BufferPos, Interpolators); } }; inline void ImageRasterMesh( const FMesh* pMesh, FImage* pImage, int32 LayoutIndex, uint64 BlockId, UE::Math::TIntVector2 CropMin, UE::Math::TIntVector2 UncroppedSize ) { MUTABLE_CPUPROFILER_SCOPE(ImageRasterMesh); if (pMesh->GetVertexCount() == 0) { return; } check( pImage->GetFormat()== EImageFormat::L_UByte ); int32 sizeX = pImage->GetSizeX(); int32 sizeY = pImage->GetSizeY(); // Get the vertices int32 vertexCount = pMesh->GetVertexCount(); TArray< RasterVertex<1> > vertices; vertices.SetNumZeroed(vertexCount); UntypedMeshBufferIteratorConst texIt( pMesh->GetVertexBuffers(), EMeshBufferSemantic::TexCoords, 0 ); if (!texIt.ptr()) { ensure(false); return; } for ( int32 v=0; v 0; if (bUseCropping) { vertices[v].x = uv[0] * UncroppedSize[0] - CropMin[0]; vertices[v].y = uv[1] * UncroppedSize[1] - CropMin[1]; } else { vertices[v].x = uv[0] * sizeX; vertices[v].y = uv[1] * sizeY; } ++texIt; } // Get the indices const int32 NumFaces = pMesh->GetFaceCount(); TArrayView IndicesView; TArray FormatedIndices; UntypedMeshBufferIteratorConst indIt(pMesh->GetIndexBuffers(), EMeshBufferSemantic::VertexIndex, 0); if (indIt.GetFormat() == EMeshBufferFormat::UInt32) { IndicesView = TArrayView(reinterpret_cast(indIt.ptr()), NumFaces * 3); } else { FormatedIndices.SetNumZeroed(NumFaces * 3); for (int32 i = 0; i < NumFaces * 3; ++i) { uint32_t index = 0; ConvertData(0, &index, EMeshBufferFormat::UInt32, indIt.ptr(), indIt.GetFormat()); FormatedIndices[i] = index; ++indIt; } IndicesView = TArrayView(FormatedIndices); } UntypedMeshBufferIteratorConst bloIt( pMesh->GetVertexBuffers(), EMeshBufferSemantic::LayoutBlock, LayoutIndex ); constexpr int32 NumBatchElems = 1 << 5; // Small batches perform better. const int32 NumBatches = FMath::DivideAndRoundUp(NumFaces, NumBatchElems); if (BlockId== FLayoutBlock::InvalidBlockId || bloIt.GetElementSize()==0 ) { // Raster all the faces WhitePixelProcessor pixelProc; const TArrayView ImageData = pImage->DataStorage.GetLOD(0); ParallelExecutionUtils::InvokeBatchParallelFor(NumBatches, [ &vertices, IndicesView, ImageData, sizeX, sizeY, pixelProc, NumFaces, NumBatchElems ] (int32 BatchId) { const int32 BatchBeginFaceIndex = BatchId * NumBatchElems; const int32 BatchEndFaceIndex = FMath::Min(BatchBeginFaceIndex + NumBatchElems, NumFaces); for (int32 FaceIndex = BatchBeginFaceIndex; FaceIndex < BatchEndFaceIndex; ++FaceIndex) { constexpr int32 NumInterpolators = 1; Triangle(ImageData.GetData(), ImageData.Num(), sizeX, sizeY, 1, vertices[IndicesView[FaceIndex * 3 + 0]], vertices[IndicesView[FaceIndex * 3 + 1]], vertices[IndicesView[FaceIndex * 3 + 2]], pixelProc, false); } }); } else { // Raster only the faces in the selected block check(bloIt.GetComponents() == 1); // Get the block per vertex TArray VertexBlockIds; VertexBlockIds.SetNumZeroed(vertexCount); if (bloIt.GetFormat() == EMeshBufferFormat::UInt16) { // Relative blocks. const uint16* SourceIds = reinterpret_cast(bloIt.ptr()); for (int32 i = 0; i < vertexCount; ++i) { uint64 Id = SourceIds[i]; Id = Id | (uint64(pMesh->MeshIDPrefix)<<32); VertexBlockIds[i] = Id; } } else if (bloIt.GetFormat() == EMeshBufferFormat::UInt64) { // Absolute blocks. const uint64* SourceIds = reinterpret_cast(bloIt.ptr()); for (int32 i = 0; i < vertexCount; ++i) { uint64 Id = SourceIds[i]; VertexBlockIds[i] = Id; } } else { // Format not supported check(false); } WhitePixelProcessor pixelProc; const TArrayView ImageData = pImage->DataStorage.GetLOD(0); ParallelExecutionUtils::InvokeBatchParallelFor(NumBatches, [ &vertices, IndicesView, VertexBlockIds, BlockId, ImageData, sizeX, sizeY, pixelProc, NumFaces, NumBatchElems ] (int32 BatchId) { const int32 BatchBeginFaceIndex = BatchId * NumBatchElems; const int32 BatchEndFaceIndex = FMath::Min(BatchBeginFaceIndex + NumBatchElems, NumFaces); for (int32 FaceIndex = BatchBeginFaceIndex; FaceIndex < BatchEndFaceIndex; ++FaceIndex) { // TODO: Select faces outside for loop? if (VertexBlockIds[IndicesView[FaceIndex * 3 + 0]] == BlockId) { constexpr int32 NumInterpolators = 1; Triangle(ImageData.GetData(), ImageData.Num(), sizeX, sizeY, 1, vertices[IndicesView[FaceIndex * 3 + 0]], vertices[IndicesView[FaceIndex * 3 + 1]], vertices[IndicesView[FaceIndex * 3 + 2]], pixelProc, false); } } }); } } }