// Copyright 2020 Phyronnaz #pragma once #include "CoreMinimal.h" #include "VoxelGenerators/VoxelGeneratorHelpers.h" #include "VoxelUtilities/VoxelDataItemUtilities.h" #include "VoxelFlatGenerator.generated.h" class UVoxelFlatGenerator; USTRUCT(BlueprintType) struct FVoxelFlatGeneratorDataItemConfig { GENERATED_BODY() // In voxels, how smooth the intersection with the existing terrain and these items should be UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config") float Smoothness = 10; // Only items matching this mask will be added UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config", meta = (Bitmask, BitmaskEnum = EVoxel32BitMask)) int32 Mask = 0; // If true, will subtract the items from the world and will invert their values // If false, will add the items to the world and will not invert their values UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config") bool bSubtractItems = false; }; /** * Flat world */ UCLASS(Blueprintable) class VOXEL_API UVoxelFlatGenerator : public UVoxelGenerator { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel") FLinearColor Color = FLinearColor::Transparent; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel") TArray DataItemConfigs = { { 2, 1 << 0, true }, { 2, 1 << 1, false }, }; //~ Begin UVoxelGenerator Interface TVoxelSharedRef GetInstance() override; //~ End UVoxelGenerator Interface }; class FVoxelFlatGeneratorInstance : public TVoxelGeneratorInstanceHelper { public: using Super = TVoxelGeneratorInstanceHelper; const FVoxelMaterial Material; const TArray DataItemConfigs; explicit FVoxelFlatGeneratorInstance(UVoxelFlatGenerator& Object) : Super(&Object) , Material(FVoxelMaterial::CreateFromColor(Object.Color)) , DataItemConfigs(Object.DataItemConfigs) { } //~ Begin FVoxelGeneratorInstance Interface inline v_flt GetValueImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const { v_flt Density = Z + 0.001f; // Try to avoid having 0 as density, as it behaves weirdly if (Items.ItemHolder.GetDataItems().Num() > 0) { for (auto& DataItemConfig : DataItemConfigs) { if (DataItemConfig.bSubtractItems) { Density = FVoxelUtilities::CombineDataItemDistance(Density, Items.ItemHolder, X, Y, Z, DataItemConfig.Smoothness, DataItemConfig.Mask, EVoxelDataItemCombineMode::Max); } else { Density = FVoxelUtilities::CombineDataItemDistance(Density, Items.ItemHolder, X, Y, Z, DataItemConfig.Smoothness, DataItemConfig.Mask, EVoxelDataItemCombineMode::Min); } } } return Density; } TVoxelRange GetValueRangeImpl(const FVoxelIntBox& Bounds, int32 LOD, const FVoxelItemStack& Items) const { const auto X = TVoxelRange(Bounds.Min.X, Bounds.Max.X); const auto Y = TVoxelRange(Bounds.Min.Y, Bounds.Max.Y); const auto Z = TVoxelRange(Bounds.Min.Z, Bounds.Max.Z); auto Density = Z + 0.001f; if (Items.ItemHolder.GetDataItems().Num() > 0) { for (auto& DataItemConfig : DataItemConfigs) { if (DataItemConfig.bSubtractItems) { Density = FVoxelUtilities::CombineDataItemDistanceRange(Density, Items.ItemHolder, X, Y, Z, DataItemConfig.Smoothness, DataItemConfig.Mask, EVoxelDataItemCombineMode::Max); } else { Density = FVoxelUtilities::CombineDataItemDistanceRange(Density, Items.ItemHolder, X, Y, Z, DataItemConfig.Smoothness, DataItemConfig.Mask, EVoxelDataItemCombineMode::Min); } } } return Density; } inline FVoxelMaterial GetMaterialImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const { return Material; } FVector GetUpVector(v_flt X, v_flt Y, v_flt Z) const override final { return FVector::UpVector; } //~ End FVoxelGeneratorInstance Interface }; inline TVoxelSharedRef UVoxelFlatGenerator::GetInstance() { return MakeVoxelShared(*this); }