Files
UnrealEngine/Engine/Plugins/FX/Niagara/Shaders/Shared/NiagaraStatelessBuiltDistribution.h
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

193 lines
8.1 KiB
C

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#ifndef GPU_SIMULATION
#define uint uint32
typedef FUintVector3 FNiagaraStatelessBuiltDistributionType;
typedef const FUintVector3& FNiagaraStatelessBuiltDistributionTypeIn;
#define UEAsFloat(X) reinterpret_cast<const float&>(X);
#define UEMin(X, Y) FMath::Min(X, Y)
#define UEMax(X, Y) FMath::Max(X, Y)
#define UEFrac(X) FMath::Fractional(X)
#define UERoundToInt(X) FMath::RoundToInt(X)
#define UEOutParam(X) X&
#else
//typedef uint3 FNiagaraStatelessBuiltDistributionType;
#define FNiagaraStatelessBuiltDistributionType uint3
#define FNiagaraStatelessBuiltDistributionTypeIn uint3
#define UEAsFloat(X) asfloat(X)
#define UEMin(X, Y) min(X, Y)
#define UEMax(X, Y) max(X, Y)
#define UEFrac(X) frac(X)
#define UERoundToInt(X) uint(round(X))
#define UEOutParam(X) out X
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct FNiagaraStatelessBuiltDistribution
{
struct EFlags
{
enum
{
BufferOffsetShift = 0u, // Offset in the buffer where the data is stored
BufferOffsetBits = 17u, // 128k max offset
BufferOffsetMask = (1u << BufferOffsetBits) - 1u,
TableLengthShift = 17u, // Length of the table data minus 1
TableLengthBits = 9u, // 512 entries max
TableLengthMask = (1u << TableLengthBits) - 1u,
LookupValueModeShift = 26u, // Lookup Value Mode where all bits set is assumed to be random internally
LookupValueModeBits = 2u, // The caller must decide how to interpret this data
LookupValueModeMask = (1u << LookupValueModeBits) - 1u,
UniformRandom = 1u << 28u, // When true random will be uniform when interpolating vs non-uniform
AddressModeWrap = 1u << 29u, // The address mode, when 0 clamp, when 1 wrap
InterpolationModeLinear = 1u << 30u, // The interpolation mode, when 0 none, when 1 linear
BufferReadModeStatic = 1u << 31u, // The buffer read mode, when 0 dynamic, when 1 static
};
};
static bool IsValid(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return BuiltData[2] != 0; }
static bool IsUniformRandomEnabled(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] & EFlags::UniformRandom) != 0; }
static bool IsAddressModeWrap(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] & EFlags::AddressModeWrap) != 0; }
static bool IsInterpolationModeLinear(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] & EFlags::InterpolationModeLinear) != 0; }
static bool IsBufferReadModeStatic(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] & EFlags::BufferReadModeStatic) != 0; }
static bool IsLookupValueModeRandom(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { const uint Mask = EFlags::LookupValueModeMask << EFlags::LookupValueModeShift; return (BuiltData[0] & Mask) == Mask; }
static uint GetBufferOffset(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] >> EFlags::BufferOffsetShift) & EFlags::BufferOffsetMask; }
static uint GetTableLength(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] >> EFlags::TableLengthShift) & EFlags::TableLengthMask; }
static uint GetLookupValueMode(FNiagaraStatelessBuiltDistributionTypeIn BuiltData) { return (BuiltData[0] >> EFlags::LookupValueModeShift) & EFlags::LookupValueModeMask; }
static void ConvertRandomToLookup(FNiagaraStatelessBuiltDistributionTypeIn BuiltData, float Random, UEOutParam(uint) OutIndexA, UEOutParam(uint) OutIndexB, UEOutParam(float) OutInterp)
{
const uint TableLength = GetTableLength(BuiltData);
const bool bInterpolate = IsInterpolationModeLinear(BuiltData);
const float Index = Random * float(TableLength);
OutIndexA = bInterpolate ? uint(Index) : UERoundToInt(Index);
OutIndexB = OutIndexA + 1;
OutInterp = bInterpolate ? UEFrac(Index) : 0.0f;
if (IsAddressModeWrap(BuiltData))
{
OutIndexB = OutIndexB > TableLength ? 0 : OutIndexB;
}
else
{
OutIndexB = UEMin(OutIndexB, TableLength);
}
}
static void ConvertTimeToLookup(FNiagaraStatelessBuiltDistributionTypeIn BuiltData, float Time, UEOutParam(uint) OutIndexA, UEOutParam(uint) OutIndexB, UEOutParam(float) OutInterp)
{
const float TimeBias = UEAsFloat(BuiltData[1]);
const float TimeScale = UEAsFloat(BuiltData[2]);
const uint TableLength = GetTableLength(BuiltData);
const bool bInterpolate = IsInterpolationModeLinear(BuiltData);
Time = UEMax((Time - TimeBias) * TimeScale, 0.0f);
OutIndexA = bInterpolate ? uint(Time) : UERoundToInt(Time);
OutIndexB = OutIndexA + 1;
if (IsAddressModeWrap(BuiltData))
{
OutIndexA = OutIndexA % (TableLength + 1);
OutIndexB = OutIndexB > TableLength ? 0 : OutIndexB;
}
else
{
OutIndexA = UEMin(OutIndexA, TableLength);
OutIndexB = UEMin(OutIndexB, TableLength);
}
OutInterp = bInterpolate ? UEFrac(Time) : 0.0f;
}
#ifndef GPU_SIMULATION
static FNiagaraStatelessBuiltDistributionType GetDefault() { return FNiagaraStatelessBuiltDistributionType::ZeroValue; }
static void SetInterpolationMode(FNiagaraStatelessBuiltDistributionType& BuiltData, bool bLinearInterpolation)
{
BuiltData[0] &= ~EFlags::InterpolationModeLinear;
BuiltData[0] |= bLinearInterpolation ? EFlags::InterpolationModeLinear : 0;
}
static void SetAddressMode(FNiagaraStatelessBuiltDistributionType& BuiltData, bool bClampAddress)
{
BuiltData[0] &= ~EFlags::AddressModeWrap;
BuiltData[0] |= bClampAddress ? 0 : EFlags::AddressModeWrap;
}
static void SetBufferReadMode(FNiagaraStatelessBuiltDistributionType& BuiltData, bool bStaticBuffer)
{
BuiltData[0] &= ~EFlags::BufferReadModeStatic;
BuiltData[0] |= bStaticBuffer ? EFlags::BufferReadModeStatic : 0;
}
static void SetLookupValueMode(FNiagaraStatelessBuiltDistributionType& BuiltData, uint8 ValueMode)
{
BuiltData[0] &= ~(EFlags::LookupValueModeMask << EFlags::LookupValueModeShift);
if (ValueMode == 0xff)
{
BuiltData[0] |= EFlags::LookupValueModeMask << EFlags::LookupValueModeShift;
}
else
{
checkf(ValueMode <= EFlags::LookupValueModeMask - 1, TEXT("ValueMode (%d) is out of range (0 - %d)"), ValueMode, EFlags::LookupValueModeMask - 1);
BuiltData[0] |= ValueMode << EFlags::LookupValueModeShift;
}
}
static void SetUniformRandom(FNiagaraStatelessBuiltDistributionType& BuiltData, bool bEnabled)
{
BuiltData[0] = (BuiltData[0] & ~EFlags::UniformRandom) | (bEnabled ? EFlags::UniformRandom : 0);
}
static void SetTimeScaleBias(FNiagaraStatelessBuiltDistributionType& BuiltData, float TimeScale, float TimeBias)
{
reinterpret_cast<float&>(BuiltData[1]) = TimeBias;
reinterpret_cast<float&>(BuiltData[2]) = FMath::Max(TimeScale, UE_KINDA_SMALL_NUMBER);
}
static void SetLookupParameters(FNiagaraStatelessBuiltDistributionType& BuiltData, uint BufferOffset, uint TableLength)
{
check(BufferOffset <= EFlags::BufferOffsetMask);
check(TableLength > 0 && TableLength <= EFlags::TableLengthMask);
BuiltData[0] &= ~(EFlags::BufferOffsetMask << EFlags::BufferOffsetShift);
BuiltData[0] |= BufferOffset << EFlags::BufferOffsetShift;
BuiltData[0] &= ~(EFlags::TableLengthMask << EFlags::TableLengthShift);
BuiltData[0] |= (TableLength - 1) << EFlags::TableLengthShift;
SetTimeScaleBias(BuiltData, float(TableLength - 1), 0.0f);
}
static void SetLookupParameters(FNiagaraStatelessBuiltDistributionType& BuiltData, uint BufferOffset, uint TableLength, float MinTime, float MaxTime)
{
check(TableLength > 0);
SetLookupParameters(BuiltData, BufferOffset, TableLength);
const uint TableLengthMinusOne = TableLength - 1;
const float TimeDuration = MaxTime - MinTime;
const float TimeScale = TableLengthMinusOne > 0 && TimeDuration > 0.0f ? float(TableLengthMinusOne) / TimeDuration : 0.0f;
SetTimeScaleBias(BuiltData, TimeScale, MinTime);
}
#endif
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef GPU_SIMULATION
#undef uint
#endif
#undef UEAsFloat
#undef UEMin
#undef UEMax
#undef UEFrac
#undef UERoundToInt
#undef UEOutParam