// Copyright 2020 Phyronnaz #pragma once #include "CoreMinimal.h" #include "VoxelGenerators/VoxelGeneratorInstance.h" #include "VoxelGenerators/VoxelGeneratorInstance.inl" /** * Inherit from TVoxelGeneratorInstanceHelper, and implement: * * For the values: * inline v_flt GetValueImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const * * For the materials: * inline FVoxelMaterial GetMaterialImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const * * And: * TVoxelRange GetValueRangeImpl(const FVoxelIntBox& Bounds, int32 LOD, const FVoxelItemStack& Items) const * { * return { Min, Max }; // Replace this by the possible values in Bounds * } */ template< typename TWorldInstance, typename UWorldObject, typename TParent = FVoxelGeneratorInstance> class TVoxelGeneratorInstanceHelper : public TParent { public: GENERATE_MEMBER_FUNCTION_CHECK(GetValueImpl, v_flt, const, v_flt, v_flt, v_flt, int32, const FVoxelItemStack&); GENERATE_MEMBER_FUNCTION_CHECK(GetMaterialImpl, FVoxelMaterial, const, v_flt, v_flt, v_flt, int32, const FVoxelItemStack&); GENERATE_MEMBER_FUNCTION_CHECK(GetValueRangeImpl, TVoxelRange, const, const FVoxelIntBox&, int32, const FVoxelItemStack&); using FVoxelGeneratorInstance::TOutputFunctionPtr; using FVoxelGeneratorInstance::TRangeOutputFunctionPtr; using FVoxelGeneratorInstance::FBaseFunctionPtrs; using FVoxelGeneratorInstance::FCustomFunctionPtrs; using UStaticClass = UWorldObject; explicit TVoxelGeneratorInstanceHelper(const UWorldObject* Object, const FCustomFunctionPtrs& CustomFunctionPtrs = {}) : TParent( UWorldObject::StaticClass(), Object, FBaseFunctionPtrs { static_cast>(&TWorldInstance::GetValueImpl), static_cast>(&TWorldInstance::GetMaterialImpl), static_cast>(&TWorldInstance::GetValueRangeImpl), }, CustomFunctionPtrs) { // doesn't work with fwd decl static_assert(TIsDerivedFrom::IsDerived, "UWorldObject needs to inherit from UVoxelGenerator"); static_assert(THasMemberFunction_GetValueImpl ::Value, "Missing 'v_flt GetValueImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const'"); static_assert(THasMemberFunction_GetMaterialImpl::Value, "Missing 'FVoxelMaterial GetMaterialImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const'"); static_assert(THasMemberFunction_GetValueRangeImpl::Value, "Missing 'TVoxelRange GetValueRangeImpl(const FVoxelIntBox& Bounds, int32 LOD, const FVoxelItemStack& Items) const'"); } virtual void GetValues(TVoxelQueryZone& QueryZone, int32 LOD, const FVoxelItemStack& Items) const override { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, X)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Y)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Z)) { QueryZone.Set(X, Y, Z, FVoxelValue(This().GetValueImpl(X, Y, Z, LOD, Items))); } } } } virtual void GetMaterials(TVoxelQueryZone& QueryZone, int32 LOD, const FVoxelItemStack& Items) const override { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, X)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Y)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Z)) { QueryZone.Set(X, Y, Z, This().GetMaterialImpl(X, Y, Z, LOD, Items)); } } } } private: inline const TWorldInstance& This() const { return static_cast(*this); } }; /** * If you want your generator to be placeable as an asset, * inherit from TVoxelTransformableGeneratorInstanceHelper, and implement: * * For the values: * template // bCustomTransform is false if LocalToWorld is identity * inline v_flt GetValueImpl(const FTransform& LocalToWorld, v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const * * For the materials: * template * inline FVoxelMaterial GetMaterialImpl(const FTransform& LocalToWorld, v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const * * And: * template * TVoxelRange GetValueRangeImpl(const FTransform& LocalToWorld, const FVoxelIntBox& WorldBounds, int32 LOD, const FVoxelItemStack& Items) const * { * return { Min, Max }; // Replace this by the possible values in Bounds * } */ template< typename TWorldInstance, typename UWorldObject, typename TParent = FVoxelTransformableGeneratorInstance> class TVoxelTransformableGeneratorInstanceHelper : public TParent { public: // doesn't work with fwd decl static_assert(TIsDerivedFrom::IsDerived, "UWorldObject needs to inherit from UVoxelTransformableGenerator"); using FVoxelGeneratorInstance::TOutputFunctionPtr; using FVoxelGeneratorInstance::TRangeOutputFunctionPtr; using FVoxelTransformableGeneratorInstance::TOutputFunctionPtr_Transform; using FVoxelTransformableGeneratorInstance::TRangeOutputFunctionPtr_Transform; using FVoxelGeneratorInstance::FBaseFunctionPtrs; using FVoxelGeneratorInstance::FCustomFunctionPtrs; using FVoxelTransformableGeneratorInstance::FBaseFunctionPtrs_Transform; using FVoxelTransformableGeneratorInstance::FCustomFunctionPtrs_Transform; using UStaticClass = UWorldObject; explicit TVoxelTransformableGeneratorInstanceHelper( const UWorldObject* Object, const FCustomFunctionPtrs& CustomFunctionPtrs = {}, const FCustomFunctionPtrs_Transform& CustomFunctionPtrs_Transform = {}) : TParent( UWorldObject::StaticClass(), Object, FBaseFunctionPtrs { static_cast>(&TWorldInstance::GetValueNoTransformImpl), static_cast>(&TWorldInstance::GetMaterialNoTransformImpl), static_cast>(&TWorldInstance::GetValueRangeNoTransformImpl), }, CustomFunctionPtrs, FBaseFunctionPtrs_Transform { static_cast>(&TWorldInstance::GetValueWithTransformImpl), static_cast>(&TWorldInstance::GetMaterialWithTransformImpl), static_cast>(&TWorldInstance::GetValueRangeWithTransformImpl), }, CustomFunctionPtrs_Transform) { } virtual void GetValues(TVoxelQueryZone& QueryZone, int32 LOD, const FVoxelItemStack& Items) const override { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, X)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Y)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Z)) { QueryZone.Set(X, Y, Z, FVoxelValue(This().GetValueNoTransformImpl(X, Y, Z, LOD, Items))); } } } } virtual void GetMaterials(TVoxelQueryZone& QueryZone, int32 LOD, const FVoxelItemStack& Items) const override { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, X)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Y)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Z)) { QueryZone.Set(X, Y, Z, This().GetMaterialNoTransformImpl(X, Y, Z, LOD, Items)); } } } } virtual void GetValues_Transform(const FTransform& LocalToWorld, TVoxelQueryZone& QueryZone, int32 LOD, const FVoxelItemStack& Items) const override { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, X)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Y)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Z)) { QueryZone.Set(X, Y, Z, FVoxelValue(This().GetValueWithTransformImpl(LocalToWorld, X, Y, Z, LOD, Items))); } } } } virtual void GetMaterials_Transform(const FTransform& LocalToWorld, TVoxelQueryZone& QueryZone, int32 LOD, const FVoxelItemStack& Items) const override { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, X)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Y)) { for (VOXEL_QUERY_ZONE_ITERATE(QueryZone, Z)) { QueryZone.Set(X, Y, Z, This().GetMaterialWithTransformImpl(LocalToWorld, X, Y, Z, LOD, Items)); } } } } v_flt GetValueNoTransformImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const { return This().template GetValueImpl(FTransform(), X, Y, Z, LOD, Items); } v_flt GetValueWithTransformImpl(const FTransform& LocalToWorld, v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const { return This().template GetValueImpl(LocalToWorld, X, Y, Z, LOD, Items); } FVoxelMaterial GetMaterialNoTransformImpl(v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const { return This().template GetMaterialImpl(FTransform(), X, Y, Z, LOD, Items); } FVoxelMaterial GetMaterialWithTransformImpl(const FTransform& LocalToWorld, v_flt X, v_flt Y, v_flt Z, int32 LOD, const FVoxelItemStack& Items) const { return This().template GetMaterialImpl(LocalToWorld, X, Y, Z, LOD, Items); } TVoxelRange GetValueRangeNoTransformImpl(const FVoxelIntBox& WorldBounds, int32 LOD, const FVoxelItemStack& Items) const { return This().template GetValueRangeImpl(FTransform(), WorldBounds, LOD, Items); } TVoxelRange GetValueRangeWithTransformImpl(const FTransform& LocalToWorld, const FVoxelIntBox& WorldBounds, int32 LOD, const FVoxelItemStack& Items) const { return This().template GetValueRangeImpl(LocalToWorld, WorldBounds, LOD, Items); } private: inline const TWorldInstance& This() const { return static_cast(*this); } };