diff --git a/.gitignore b/.gitignore index 741113f..41668ec 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ /Videos **.generated.h -**.response \ No newline at end of file +**.response + +BrickGame.VC.VC.opendb +BrickGame.VC.db \ No newline at end of file diff --git a/Content/Blueprints/MyCharacter.uasset b/Content/Blueprints/MyCharacter.uasset index b3d52d2..42f4ced 100644 Binary files a/Content/Blueprints/MyCharacter.uasset and b/Content/Blueprints/MyCharacter.uasset differ diff --git a/Content/Maps/BrickMap.umap b/Content/Maps/BrickMap.umap index 025bb5b..ee9d81f 100644 Binary files a/Content/Maps/BrickMap.umap and b/Content/Maps/BrickMap.umap differ diff --git a/Content/Materials/M_Metal_Gold.uasset b/Content/Materials/M_Metal_Gold.uasset index ddd6c1b..48d8af3 100644 Binary files a/Content/Materials/M_Metal_Gold.uasset and b/Content/Materials/M_Metal_Gold.uasset differ diff --git a/Content/Meshes/Tree.uasset b/Content/Meshes/Tree.uasset new file mode 100644 index 0000000..2e88149 Binary files /dev/null and b/Content/Meshes/Tree.uasset differ diff --git a/Plugins/BrickGrid/Source/BrickGrid/Classes/BrickGridComponent.h b/Plugins/BrickGrid/Source/BrickGrid/Classes/BrickGridComponent.h index 99cdd77..fca1306 100644 --- a/Plugins/BrickGrid/Source/BrickGrid/Classes/BrickGridComponent.h +++ b/Plugins/BrickGrid/Source/BrickGrid/Classes/BrickGridComponent.h @@ -155,12 +155,16 @@ struct FBrickRegion UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=Region) FInt3 Coordinates; + // Contains the material index for each brick, stored in an 8-bit integer. UPROPERTY() TArray BrickContents; // Contains the occupied brick with highest Z in this region for each XY coordinate in the region. -1 means no non-empty bricks in this region at that XY. TArray MaxNonEmptyBrickRegionZs; + + //Contains the coordinates of the complex bricks in the region, and their MaterialIndexes + TMap RegionComplexBrickIndexes; }; /** The parameters for a BrickGridComponent. */ @@ -168,15 +172,23 @@ USTRUCT(BlueprintType) struct FBrickGridParameters { GENERATED_USTRUCT_BODY() - + // The materials to render for each brick material. UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Materials) TArray Materials; + // The materials to render for each brick material. + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Materials) + TArray ComplexMeshes; + // The material index that means "empty". UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Materials) int32 EmptyMaterialIndex; + // Separates the normal from the complex bricks + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Materials) + int32 firstComplexBrickIndex; + // The number of bricks along each axis of a region is 2^BricksPerChunkLog2 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Chunks) FInt3 BricksPerRegionLog2; @@ -262,6 +274,10 @@ class BRICKGRID_API UBrickGridComponent : public USceneComponent UFUNCTION(BlueprintCallable,Category = "Brick Grid") void Update(const FVector& WorldViewPosition,float MaxDrawDistance,float MaxCollisionDistance,float MaxDesiredUpdateTime,FBrickGrid_InitRegion InitRegion); + // Updates the visible chunks for a given view position. + UFUNCTION(BlueprintCallable, Category = "Brick Grid") + void RenderRegionComplexBricks(const FInt3 RegionCoordinates); + // The parameters for the grid. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Brick Grid") FBrickGridParameters Parameters; @@ -297,7 +313,15 @@ class BRICKGRID_API UBrickGridComponent : public USceneComponent } inline FInt3 BrickToRegionCoordinates(const FInt3& BrickCoordinates) const { - return FInt3::SignedShiftRight(BrickCoordinates,Parameters.BricksPerRegionLog2); + return FInt3::SignedShiftRight(BrickCoordinates, Parameters.BricksPerRegionLog2); + } + inline bool IsBrickComplexByMaterialIndex(const int32& MaterialIndex) const + { + return MaterialIndex > Parameters.Materials.Num(); + } + inline int32 GetComplexBrickShapeIndex(const int32& MaterialIndex) const + { + return MaterialIndex - Parameters.Materials.Num(); } // USceneComponent interface. @@ -317,6 +341,11 @@ class BRICKGRID_API UBrickGridComponent : public USceneComponent TMap RenderChunkCoordinatesToComponent; TMap CollisionChunkCoordinatesToComponent; + // Transient map to help organize the Complex Bricks Instances by Region Coordinate and Shape Index. + TMap> ComplexRenderChunkCoordinatesToComponent; + // Transient map to help lookup the Complex Bricks Instances Shapes and Intance Indexes by having RenderChunkCoordinate and ShapeIndex. + TMap>> MapOfBricksCoordinatesToShapeAndInstanceIndexes; + // Initializes the derived constants from the properties they are derived from. void ComputeDerivedConstants(); @@ -336,7 +365,19 @@ class BRICKGRID_API UBrickGridComponent : public USceneComponent return SubregionBrickCoordinatesToRegionBrickIndex(BrickCoordinates - (RegionCoordinates << Parameters.BricksPerRegionLog2)); } + inline FInt3 LocalBrickCoordinatesToBrickCoordinates(const FInt3& BrickCoordinates, const FInt3& RegionCoordinates) const + { + return FInt3(BrickCoordinates + RegionCoordinates * BricksPerRegion); + } // Updates the non-empty height map for a single region. void UpdateMaxNonEmptyBrickMap(FBrickRegion& Region,const FInt3 MinDirtyBrickCoordinates,const FInt3 MaxDirtyBrickCoordinates) const; + + //Deletes a static mesh instance on a Brick coordinate + void DeleteComplexBrick(const FInt3 RegionCoordinates, const FInt3 Coordinates); + //Renders a static mesh instance on a Brick coordinate + void RenderComplexBrick(const FInt3 RegionCoordinates, const FInt3 Coordinates, const int32 ShapeIndex); + //Adds a ComplexRenderComponent to a specific RenderChunk + void AddComplexRenderComponent(const FInt3 RenderChunkCoordinates, const int32 ShapeIndex); + }; diff --git a/Plugins/BrickGrid/Source/BrickGrid/Private/BrickGridComponent.cpp b/Plugins/BrickGrid/Source/BrickGrid/Private/BrickGridComponent.cpp index 77aa2b1..7487c52 100644 --- a/Plugins/BrickGrid/Source/BrickGrid/Private/BrickGridComponent.cpp +++ b/Plugins/BrickGrid/Source/BrickGrid/Private/BrickGridComponent.cpp @@ -177,7 +177,7 @@ void UBrickGridComponent::SetBrickMaterialArray(const FInt3& SetMinBrickCoordina bool UBrickGridComponent::SetBrick(const FInt3& BrickCoordinates, int32 MaterialIndex) { - if(FInt3::All(BrickCoordinates >= MinBrickCoordinates) && FInt3::All(BrickCoordinates <= MaxBrickCoordinates) && MaterialIndex < Parameters.Materials.Num()) + if(FInt3::All(BrickCoordinates >= MinBrickCoordinates) && FInt3::All(BrickCoordinates <= MaxBrickCoordinates)) { const FInt3 RegionCoordinates = BrickToRegionCoordinates(BrickCoordinates); const int32* const RegionIndex = RegionCoordinatesToIndex.Find(RegionCoordinates); @@ -185,8 +185,22 @@ bool UBrickGridComponent::SetBrick(const FInt3& BrickCoordinates, int32 Material { const uint32 BrickIndex = BrickCoordinatesToRegionBrickIndex(RegionCoordinates,BrickCoordinates); FBrickRegion& Region = Regions[*RegionIndex]; + + if (IsBrickComplexByMaterialIndex(MaterialIndex)) + { + int32 ShapeIndex = GetComplexBrickShapeIndex(MaterialIndex); + Region.RegionComplexBrickIndexes.Add(BrickCoordinates, 0); + + RenderComplexBrick(RegionCoordinates, BrickCoordinates, 0); + } + else if (MaterialIndex == Parameters.EmptyMaterialIndex && IsBrickComplexByMaterialIndex(Region.BrickContents[BrickIndex])) + { + //delete complex brick + UE_LOG(LogStats, Log, TEXT("deleteting complex brick")); + DeleteComplexBrick(RegionCoordinates, BrickCoordinates); + } Region.BrickContents[BrickIndex] = MaterialIndex; - InvalidateChunkComponents(BrickCoordinates,BrickCoordinates); + InvalidateChunkComponents(BrickCoordinates, BrickCoordinates); return true; } } @@ -220,6 +234,70 @@ void UBrickGridComponent::UpdateMaxNonEmptyBrickMap(FBrickRegion& Region,const F } } +void UBrickGridComponent::DeleteComplexBrick(const FInt3 RegionCoordinates, const FInt3 Coordinates) +{ + const int32* const RegionIndex = RegionCoordinatesToIndex.Find(RegionCoordinates); + if (RegionIndex) + { + FInt3 RenderChunkCoordinates = BrickToRenderChunkCoordinates(LocalBrickCoordinatesToBrickCoordinates(Coordinates, RegionCoordinates)); + if (ComplexRenderChunkCoordinatesToComponent.Contains(RenderChunkCoordinates)) + { + if (MapOfBricksCoordinatesToShapeAndInstanceIndexes[RenderChunkCoordinates].Contains(Coordinates)) + { + int32 ShapeIndex = MapOfBricksCoordinatesToShapeAndInstanceIndexes[RenderChunkCoordinates][Coordinates].Get<0>(); + int32 InstanceIndex = MapOfBricksCoordinatesToShapeAndInstanceIndexes[RenderChunkCoordinates][Coordinates].Get<1>(); + + ComplexRenderChunkCoordinatesToComponent[RenderChunkCoordinates][ShapeIndex]->RemoveInstance(InstanceIndex); + for (auto& Elem : MapOfBricksCoordinatesToShapeAndInstanceIndexes[RenderChunkCoordinates]) + { + if (Elem.Value.Get<1>() > InstanceIndex) + { + Elem.Value = TTuple(Elem.Value.Get<0>(), Elem.Value.Get<1>() - 1); + } + } + } + } + } +} + +void UBrickGridComponent::RenderComplexBrick(const FInt3 RegionCoordinates, const FInt3 Coordinates, const int32 ShapeIndex) +{ + int32 MaterialIndex = 7; + UInstancedStaticMeshComponent* ComplexRenderComponent = nullptr; + FInt3 RenderChunkCoordinates = BrickToRenderChunkCoordinates(LocalBrickCoordinatesToBrickCoordinates(Coordinates, RegionCoordinates)); + + if (!ComplexRenderChunkCoordinatesToComponent.Contains(RenderChunkCoordinates)) + { + ComplexRenderChunkCoordinatesToComponent.Add(RenderChunkCoordinates); + MapOfBricksCoordinatesToShapeAndInstanceIndexes.Add(RenderChunkCoordinates); + } + if (!ComplexRenderChunkCoordinatesToComponent[RenderChunkCoordinates].Contains(ShapeIndex)) + { + AddComplexRenderComponent(RenderChunkCoordinates, ShapeIndex); + } + MapOfBricksCoordinatesToShapeAndInstanceIndexes[RenderChunkCoordinates] + .Add(Coordinates, TTuple(ShapeIndex, ComplexRenderChunkCoordinatesToComponent[RenderChunkCoordinates][ShapeIndex]->GetInstanceCount())); + ComplexRenderComponent = ComplexRenderChunkCoordinatesToComponent[RenderChunkCoordinates][ShapeIndex]; + + ComplexRenderComponent->SetMaterial(0, Parameters.Materials[MaterialIndex].SurfaceMaterial); + FTransform Transform; + Transform.SetLocation(FVector(Coordinates.X + .5, Coordinates.Y + .5, Coordinates.Z + .5)); + Transform.SetScale3D(FVector(1, 1, 1)); + ComplexRenderComponent->AddInstance(Transform); +} + +void UBrickGridComponent::AddComplexRenderComponent(const FInt3 RenderChunkCoordinates, const int32 ShapeIndex) +{ + UInstancedStaticMeshComponent* ComplexRenderComponent = nullptr; + ComplexRenderChunkCoordinatesToComponent[RenderChunkCoordinates].Add(ShapeIndex); + + ComplexRenderComponent = NewObject(GetOwner()); + ComplexRenderComponent->AttachToComponent(this, FAttachmentTransformRules(EAttachmentRule::KeepRelative, false)); + ComplexRenderComponent->RegisterComponent(); + ComplexRenderComponent->SetStaticMesh(Parameters.ComplexMeshes[ShapeIndex]); + ComplexRenderChunkCoordinatesToComponent[RenderChunkCoordinates][ShapeIndex] = ComplexRenderComponent; +} + void UBrickGridComponent::GetMaxNonEmptyBrickZ(const FInt3& GetMinBrickCoordinates,const FInt3& GetMaxBrickCoordinates,TArray& OutHeightMap) const { const FInt3 OutputSize = GetMaxBrickCoordinates - GetMinBrickCoordinates + FInt3::Scalar(1); @@ -499,6 +577,18 @@ void UBrickGridComponent::Update(const FVector& WorldViewPosition,float MaxDrawD } } +void UBrickGridComponent::RenderRegionComplexBricks(const FInt3 RegionCoordinates) +{ + const int32* const RegionIndex = RegionCoordinatesToIndex.Find(RegionCoordinates); + if (RegionIndex) + { + for (auto& Elem : Regions[*RegionIndex].RegionComplexBrickIndexes) + { + RenderComplexBrick(RegionCoordinates, Elem.Key, Elem.Value); + } + } +} + FBoxSphereBounds UBrickGridComponent::CalcBounds(const FTransform & LocalToWorld) const { // Return a bounds that fills the world. @@ -507,6 +597,7 @@ FBoxSphereBounds UBrickGridComponent::CalcBounds(const FTransform & LocalToWorld FBrickGridParameters::FBrickGridParameters() : EmptyMaterialIndex(0) +, firstComplexBrickIndex(250) , BricksPerRegionLog2(5,5,7) , RenderChunksPerRegionLog2(0,0,2) , CollisionChunksPerRegionLog2(1,1,2) diff --git a/Plugins/BrickGrid/Source/BrickGrid/Private/BrickRenderComponent.cpp b/Plugins/BrickGrid/Source/BrickGrid/Private/BrickRenderComponent.cpp index 5169004..2f8f6f1 100644 --- a/Plugins/BrickGrid/Source/BrickGrid/Private/BrickRenderComponent.cpp +++ b/Plugins/BrickGrid/Source/BrickGrid/Private/BrickRenderComponent.cpp @@ -429,7 +429,15 @@ FPrimitiveSceneProxy* UBrickRenderComponent::CreateSceneProxy() const FInt3 LocalBrickCoordinates = LocalVertexCoordinates + GetCornerVertexOffset(AdjacentBrickIndex) + LocalBrickExpansion - FInt3::Scalar(1); const uint32 LocalBrickIndex = (LocalBrickCoordinates.Y * LocalBricksDim.X + LocalBrickCoordinates.X) * LocalBricksDim.Z + LocalBrickCoordinates.Z; - const uint32 BrickClass = (uint32)BrickClassByMaterial[LocalBrickMaterials[LocalBrickIndex]]; + uint32 BrickClass; + if (LocalBrickMaterials[LocalBrickIndex] < BrickClassByMaterial.Num()) + { + BrickClass = (uint32)BrickClassByMaterial[LocalBrickMaterials[LocalBrickIndex]]; + } + else + { + BrickClass = (uint32)BrickClassByMaterial[0]; + } HasAdjacentBrickOfClass[BrickClass] = 1; } @@ -464,7 +472,7 @@ FPrimitiveSceneProxy* UBrickRenderComponent::CreateSceneProxy() { // Only draw faces of bricks that aren't empty. const uint32 LocalBrickIndex = (LocalBrickY * LocalBricksDim.X + LocalBrickX) * LocalBricksDim.Z + LocalBrickZ; - const uint8 BrickMaterial = LocalBrickMaterials[LocalBrickIndex]; + const uint8 BrickMaterial = (LocalBrickMaterials[LocalBrickIndex] < (uint32)BrickClassByMaterial.Num()) ? LocalBrickMaterials[LocalBrickIndex] : 0; if (BrickMaterial != EmptyMaterialIndex) { const FInt3 RelativeBrickCoordinates = FInt3(LocalBrickX,LocalBrickY,LocalBrickZ) - LocalBrickExpansion; @@ -475,7 +483,7 @@ FPrimitiveSceneProxy* UBrickRenderComponent::CreateSceneProxy() const int32 FacingLocalBrickY = LocalBrickY + FaceNormals[FaceIndex].Y; const int32 FacingLocalBrickZ = LocalBrickZ + FaceNormals[FaceIndex].Z; const uint32 FacingLocalBrickIndex = (FacingLocalBrickY * LocalBricksDim.X + FacingLocalBrickX) * LocalBricksDim.Z + FacingLocalBrickZ; - const uint32 FrontBrickMaterial = LocalBrickMaterials[FacingLocalBrickIndex]; + const uint32 FrontBrickMaterial = (LocalBrickMaterials[FacingLocalBrickIndex] < (uint32)BrickClassByMaterial.Num()) ? LocalBrickMaterials[FacingLocalBrickIndex] : 0; if (BrickClassByMaterial[BrickMaterial] > BrickClassByMaterial[FrontBrickMaterial]) { diff --git a/Source/BrickGame/BrickGame.Build.cs b/Source/BrickGame/BrickGame.Build.cs index f2f6fca..9fe1060 100644 --- a/Source/BrickGame/BrickGame.Build.cs +++ b/Source/BrickGame/BrickGame.Build.cs @@ -6,6 +6,8 @@ public class BrickGame : ModuleRules { public BrickGame(TargetInfo Target) { + MinFilesUsingPrecompiledHeaderOverride = 1; + bFasterWithoutUnity = true; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } }