IVSmoke 1.0
Loading...
Searching...
No Matches
IVSmokeGridLibrary.h
1// Copyright (c) 2026, Team SDB. All rights reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Kismet/BlueprintFunctionLibrary.h"
7#include "IVSmokeGridLibrary.generated.h"
8
9/**
10 * Utility library for smoke grid calculations and voxel bit operations.
11 */
12UCLASS()
13class IVSMOKE_API UIVSmokeGridLibrary : public UBlueprintFunctionLibrary
14{
15 GENERATED_BODY()
16
17public:
18 /** Invalid grid pos (-1, -1, -1) */
19 static const FIntVector InvalidGridPos;
20
21 /**
22 * 3D grid coordinate to 1D index.
23 *
24 * @param GridPos 3D grid coordinate.
25 * @param Resolution 3D grid resolution.
26 * @return 1D flattened index
27 */
28 UFUNCTION(BlueprintPure, Category = "IVSmoke | Math")
29 static FORCEINLINE int32 GridToIndex(const FIntVector& GridPos, const FIntVector& Resolution)
30 {
31 return GridPos.X + (GridPos.Y * Resolution.X) + (GridPos.Z * Resolution.X * Resolution.Y);
32 }
33
34 /**
35 * 1D flattened index to 3D grid coordinate.
36 *
37 * @param Index 1D flattened index.
38 * @param Resolution 3D grid resolution.
39 * @return 3D grid coordinate.
40 */
41 UFUNCTION(BlueprintPure, Category = "IVSmoke | Math")
42 static FORCEINLINE FIntVector IndexToGrid(int32 Index, const FIntVector& Resolution)
43 {
44 if (Resolution.X <= 0 || Resolution.Y <= 0 || Resolution.Z <= 0)
45 {
46 return FIntVector::ZeroValue;
47 }
48
49 const int32 BaseArea = Resolution.X * Resolution.Y;
50 const int32 Z = Index / BaseArea;
51 const int32 Remainder = Index % BaseArea;
52 const int32 Y = Remainder / Resolution.X;
53 const int32 X = Remainder % Resolution.X;
54
55 return FIntVector(X, Y, Z);
56 }
57
58 /**
59 * Converts 3D grid coordinate to local space position.
60 *
61 * @param GridPos 3D grid coordinate.
62 * @param VoxelSize Size of each voxel.
63 * @param CenterOffset Grid center offset.
64 * @return Local space position.
65 */
66 UFUNCTION(BlueprintPure, Category = "IVSmoke | Math")
67 static FORCEINLINE FVector GridToLocal(const FIntVector& GridPos, float VoxelSize, const FIntVector& CenterOffset)
68 {
69 return FVector(
70 (GridPos.X - CenterOffset.X) * VoxelSize,
71 (GridPos.Y - CenterOffset.Y) * VoxelSize,
72 (GridPos.Z - CenterOffset.Z) * VoxelSize
73 );
74 }
75
76 /**
77 * Converts local space position to 3D grid coordinate.
78 *
79 * @param LocalPos Local space position.
80 * @param VoxelSize Size of each voxel.
81 * @param CenterOffset Grid center offset.
82 * @param Resolution 3D grid resolution.
83 * @return 3D grid coordinate, or InvalidGridPos if out of bounds.
84 */
85 UFUNCTION(BlueprintPure, Category = "IVSmoke | Math")
86 static FORCEINLINE FIntVector LocalToGrid(const FVector& LocalPos, float VoxelSize, const FIntVector& CenterOffset, const FIntVector& Resolution)
87 {
88 if (VoxelSize <= UE_SMALL_NUMBER)
89 {
90 return InvalidGridPos;
91 }
92
93 const int32 X = FMath::RoundToInt(LocalPos.X / VoxelSize) + CenterOffset.X;
94 const int32 Y = FMath::RoundToInt(LocalPos.Y / VoxelSize) + CenterOffset.Y;
95 const int32 Z = FMath::RoundToInt(LocalPos.Z / VoxelSize) + CenterOffset.Z;
96
97 if (X >= 0 && X < Resolution.X &&
98 Y >= 0 && Y < Resolution.Y &&
99 Z >= 0 && Z < Resolution.Z)
100 {
101 return FIntVector(X, Y, Z);
102 }
103
104 return InvalidGridPos;
105 }
106
107 //~==============================================================================
108 // Bitmask Helpers
109
110 /**
111 * Converts 3D grid coordinate to voxel bit index.
112 *
113 * @param GridPos 3D grid coordinate.
114 * @param Resolution 3D grid resolution.
115 * @return Voxel bit index.
116 */
117 static FORCEINLINE int32 GridToVoxelBitIndex(const FIntVector& GridPos, const FIntVector& Resolution)
118 {
119 return GridToVoxelBitIndex(GridPos.Y, GridPos.Z, Resolution.Y);
120 }
121
122 /**
123 * Converts Y and Z coordinates to voxel bit index.
124 *
125 * @param Y Y coordinate.
126 * @param Z Z coordinate.
127 * @param ResolutionY Y resolution.
128 * @return Voxel bit index.
129 */
130 static FORCEINLINE int32 GridToVoxelBitIndex(int32 Y, int32 Z, int32 ResolutionY)
131 {
132 return Y + (Z * ResolutionY);
133 }
134
135 /**
136 * Checks if a voxel occupancy bit is set at the given 3D grid position.
137 * Internally, X is stored as a bit index in a uint64, while Y and Z are mapped to the array index.
138 *
139 * @param VoxelBitArray Bit-packed voxel occupancy array (uint64 per YZ slice).
140 * @param GridPos 3D grid coordinate.
141 * @param Resolution 3D grid resolution (each axis < 64).
142 * @return True if the voxel bit is set, false otherwise.
143 */
144 static FORCEINLINE bool IsVoxelBitSet(const TArray<uint64>& VoxelBitArray, const FIntVector& GridPos, const FIntVector& Resolution)
145 {
146 // Resolution must be less than 64 for each axis to fit in uint64 bitfield
147 check(Resolution.X >= 0 && Resolution.X < 64 &&
148 Resolution.Y >= 0 && Resolution.Y < 64 &&
149 Resolution.Z >= 0 && Resolution.Z < 64);
150
151 const int32 Index = GridToVoxelBitIndex(GridPos, Resolution);
152
153 if (!VoxelBitArray.IsValidIndex(Index))
154 {
155 return false;
156 }
157
158 return VoxelBitArray[Index] & (1ULL << GridPos.X);
159 }
160
161 /**
162 * Sets a voxel bit value at the given 1D index.
163 *
164 * @param VoxelBitArray Bit-packed voxel occupancy array (uint64 per YZ slice).
165 * @param Index 1D flattened index.
166 * @param Resolution 3D grid resolution (each axis < 64).
167 * @param bValue Value to set (true or false).
168 */
169 static FORCEINLINE void SetVoxelBit(TArray<uint64>& VoxelBitArray, int32 Index, const FIntVector& Resolution, bool bValue)
170 {
171 const FIntVector GridPos = IndexToGrid(Index, Resolution);
172 SetVoxelBit(VoxelBitArray, GridPos, Resolution, bValue);
173 }
174
175 /**
176 * Sets a voxel bit value at the given 3D grid position.
177 * Internally, X is stored as a bit index in a uint64, while Y and Z are mapped to the array index.
178 *
179 * @param VoxelBitArray Bit-packed voxel occupancy array (uint64 per YZ slice).
180 * @param GridPos 3D grid coordinate.
181 * @param Resolution 3D grid resolution (each axis < 64).
182 * @param bValue Value to set (true or false).
183 */
184 static FORCEINLINE void SetVoxelBit(TArray<uint64>& VoxelBitArray, const FIntVector& GridPos, const FIntVector& Resolution, bool bValue)
185 {
186 // Resolution must be less than 64 for each axis to fit in uint64 bitfield
187 check(Resolution.X >= 0 && Resolution.X < 64 &&
188 Resolution.Y >= 0 && Resolution.Y < 64 &&
189 Resolution.Z >= 0 && Resolution.Z < 64);
190
191 const int32 Index = GridToVoxelBitIndex(GridPos, Resolution);
192
193 if (!VoxelBitArray.IsValidIndex(Index))
194 {
195 return;
196 }
197
198 if (bValue)
199 {
200 VoxelBitArray[Index] |= (1ULL << GridPos.X);
201 }
202 else
203 {
204 VoxelBitArray[Index] &= ~(1ULL << GridPos.X);
205 }
206 }
207
208 /**
209 * Toggles a voxel bit value at the given 1D index.
210 *
211 * @param VoxelBitArray Bit-packed voxel occupancy array (uint64 per YZ slice).
212 * @param Index 1D flattened index.
213 * @param Resolution 3D grid resolution (each axis < 64).
214 */
215 static FORCEINLINE void ToggleVoxelBit(TArray<uint64>& VoxelBitArray, int32 Index, const FIntVector& Resolution)
216 {
217 const FIntVector GridPos = IndexToGrid(Index, Resolution);
218 ToggleVoxelBit(VoxelBitArray, GridPos, Resolution);
219 }
220
221 /**
222 * Toggles a voxel bit value at the given 3D grid position.
223 * Internally, X is stored as a bit index in a uint64, while Y and Z are mapped to the array index.
224 *
225 * @param VoxelBitArray Bit-packed voxel occupancy array (uint64 per YZ slice).
226 * @param GridPos 3D grid coordinate.
227 * @param Resolution 3D grid resolution (each axis < 64).
228 */
229 static FORCEINLINE void ToggleVoxelBit(TArray<uint64>& VoxelBitArray, const FIntVector& GridPos, const FIntVector& Resolution)
230 {
231 // Resolution must be less than 64 for each axis to fit in uint64 bitfield
232 check(Resolution.X >= 0 && Resolution.X < 64 &&
233 Resolution.Y >= 0 && Resolution.Y < 64 &&
234 Resolution.Z >= 0 && Resolution.Z < 64);
235
236 const int32 Index = GridToVoxelBitIndex(GridPos, Resolution);
237
238 if (!VoxelBitArray.IsValidIndex(Index))
239 {
240 return;
241 }
242
243 VoxelBitArray[Index] ^= (1ULL << GridPos.X);
244 }
245};
static FORCEINLINE int32 GridToVoxelBitIndex(int32 Y, int32 Z, int32 ResolutionY)
static FORCEINLINE void SetVoxelBit(TArray< uint64 > &VoxelBitArray, int32 Index, const FIntVector &Resolution, bool bValue)
static FORCEINLINE void SetVoxelBit(TArray< uint64 > &VoxelBitArray, const FIntVector &GridPos, const FIntVector &Resolution, bool bValue)
static FORCEINLINE void ToggleVoxelBit(TArray< uint64 > &VoxelBitArray, int32 Index, const FIntVector &Resolution)
static FORCEINLINE void ToggleVoxelBit(TArray< uint64 > &VoxelBitArray, const FIntVector &GridPos, const FIntVector &Resolution)
static FORCEINLINE bool IsVoxelBitSet(const TArray< uint64 > &VoxelBitArray, const FIntVector &GridPos, const FIntVector &Resolution)
static const FIntVector InvalidGridPos
static FORCEINLINE int32 GridToVoxelBitIndex(const FIntVector &GridPos, const FIntVector &Resolution)