Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@
/Videos

**.generated.h
**.response
**.response

BrickGame.VC.VC.opendb
BrickGame.VC.db
Binary file modified Content/Blueprints/MyCharacter.uasset
Binary file not shown.
Binary file modified Content/Maps/BrickMap.umap
Binary file not shown.
Binary file modified Content/Materials/M_Metal_Gold.uasset
Binary file not shown.
Binary file added Content/Meshes/Tree.uasset
Binary file not shown.
45 changes: 43 additions & 2 deletions Plugins/BrickGrid/Source/BrickGrid/Classes/BrickGridComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,28 +155,40 @@ struct FBrickRegion
UPROPERTY(EditAnywhere,BlueprintReadWrite,Category=Region)
FInt3 Coordinates;


// Contains the material index for each brick, stored in an 8-bit integer.
UPROPERTY()
TArray<uint8> 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<int8> MaxNonEmptyBrickRegionZs;

//Contains the coordinates of the complex bricks in the region, and their MaterialIndexes
TMap<FInt3, uint8> RegionComplexBrickIndexes;
};

/** The parameters for a BrickGridComponent. */
USTRUCT(BlueprintType)
struct FBrickGridParameters
{
GENERATED_USTRUCT_BODY()

// The materials to render for each brick material.
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Materials)
TArray<FBrickMaterial> Materials;

// The materials to render for each brick material.
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Materials)
TArray<UStaticMesh*> 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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -317,6 +341,11 @@ class BRICKGRID_API UBrickGridComponent : public USceneComponent
TMap<FInt3,class UBrickRenderComponent*> RenderChunkCoordinatesToComponent;
TMap<FInt3,class UBrickCollisionComponent*> CollisionChunkCoordinatesToComponent;

// Transient map to help organize the Complex Bricks Instances by Region Coordinate and Shape Index.
TMap<FInt3, TMap<int32, class UInstancedStaticMeshComponent*>> ComplexRenderChunkCoordinatesToComponent;
// Transient map to help lookup the Complex Bricks Instances Shapes and Intance Indexes by having RenderChunkCoordinate and ShapeIndex.
TMap<FInt3, TMap<FInt3, TTuple<int32, int32>>> MapOfBricksCoordinatesToShapeAndInstanceIndexes;

// Initializes the derived constants from the properties they are derived from.
void ComputeDerivedConstants();

Expand All @@ -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);

};
95 changes: 93 additions & 2 deletions Plugins/BrickGrid/Source/BrickGrid/Private/BrickGridComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,30 @@ 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);
if (RegionIndex != NULL)
{
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;
}
}
Expand Down Expand Up @@ -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<int32, int32>(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<int32, int32>(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<UInstancedStaticMeshComponent>(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<int8>& OutHeightMap) const
{
const FInt3 OutputSize = GetMaxBrickCoordinates - GetMinBrickCoordinates + FInt3::Scalar(1);
Expand Down Expand Up @@ -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.
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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])
{
Expand Down
2 changes: 2 additions & 0 deletions Source/BrickGame/BrickGame.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class BrickGame : ModuleRules
{
public BrickGame(TargetInfo Target)
{
MinFilesUsingPrecompiledHeaderOverride = 1;
bFasterWithoutUnity = true;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
}
}