You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
7.4 KiB
Plaintext

/******************************************************************************/
/*
Project - MudBun
Publisher - Long Bunny Labs
http://LongBunnyLabs.com
Author - Ming-Lun "Allen" Chou
http://AllenChou.net
*/
/******************************************************************************/
#ifndef MUDBUN_DECAL
#define MUDBUN_DECAL
#include "Render/ShaderCommon.cginc"
#if MUDBUN_VALID
#include "BrushFuncs.cginc"
struct DecalResults
{
bool hit;
float3 pos;
SdfBrushMaterial mat;
float sdfValue;
};
#define SDF_DECAL_MASKED_BRUSHES(res, p, brushMask, mat) \
{ \
int iStack = -1; \
float3 pStack[kMaxBrushGroupDepth]; \
float resStack[kMaxBrushGroupDepth]; \
SdfBrushMaterial matStack[kMaxBrushGroupDepth]; \
\
res = kInfinity; \
mat = init_brush_material(); \
float3 groupP = p; \
float groupRes = kInfinity; \
SdfBrushMaterial groupMat = init_brush_material(); \
FOR_EACH_BRUSH_EXTERN_MASK(brushMask, \
switch (aBrush[iBrush].type) \
{ \
case kSdfBeginGroup: \
iStack = min(kMaxBrushGroupDepth - 1, iStack + 1); \
pStack[iStack] = p; \
resStack[iStack] = res; \
matStack[iStack] = mat; \
res = kInfinity; \
mat = init_brush_material(); \
break; \
case kSdfEndGroup: \
groupP = p; \
groupRes = res; \
groupMat = mat; \
p = pStack[iStack]; \
res = resStack[iStack]; \
mat = matStack[iStack]; \
break; \
} \
res = sdf_brush_apply(res, groupRes, groupMat, groupP, aBrush[iBrush], mat); \
switch (aBrush[iBrush].type) \
{ \
case kSdfEndGroup: \
iStack = max(-1, iStack - 1); \
break; \
} \
); \
}
bool sdf_decal_aabb_contains(Aabb aabb, float3 p)
{
// TODO: use max blend
aabb.boundsMin -= 5.0f;
aabb.boundsMax += 5.0f;
return aabb_contains(aabb, p);
}
// stmt = statements processing "iData" of hit leaf AABB nodes
// will gracefully handle maxed-out stacks
#define SDF_DECAL_AABB_TREE_CONTAINS(tree, root, p, stmt) \
{ \
int stackTop = 0; \
int stack[kAabbTreeNodeStackSize]; \
stack[stackTop] = root; \
\
int numIters = 0; \
while (stackTop >= 0 && numIters < 128 /* safeguard */) \
{ \
int index = stack[stackTop--]; \
if (index < 0) \
continue; \
\
if (!sdf_decal_aabb_contains(tree[index].aabb, p)) \
continue; \
\
if (tree[index].iChildA < 0) \
{ \
int iData = tree[index].iData; \
\
stmt \
} \
else \
{ \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildA; \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildB; \
} \
} \
}
DecalResults sdf_decal
(
float3 p
)
{
p = mul(worldToLocal, float4(p, 1.0f)).xyz;
DecalResults res;
res.hit = false;
res.pos = p;
res.mat = init_brush_material();
res.sdfValue = kInfinity;
// don't crash Unity previews
#ifdef MUDBUN_PROCEDURAL
BRUSH_MASK(brushMask);
BRUSH_MASK_CLEAR_ALL(brushMask);
SDF_DECAL_AABB_TREE_CONTAINS(aabbTree, aabbRoot, p,
BRUSH_MASK_SET(brushMask, iData);
);
float d = kInfinity;
SDF_DECAL_MASKED_BRUSHES(d, p, brushMask, res.mat);
if (d > 0.0f)
discard;
res.sdfValue = d;
#endif
return res;
}
#else
struct SdfBrushMaterialDummy
{
float4 color;
float4 emissionHash;
float4 metallicSmoothnessSizeTightness;
float4 textureWeight;
};
struct DecalResults
{
bool hit;
float3 pos;
SdfBrushMaterialDummy mat;
float sdfValue;
};
DecalResults sdf_decal
(
float3 p
)
{
DecalResults res;
res.hit = false;
res.pos = p;
res.mat.color = 0.0f;
res.mat.emissionHash = 0.0f;
res.mat.metallicSmoothnessSizeTightness = 0.0f;
res.mat.textureWeight = 0.0f;
res.sdfValue = 0.0f;
return res;
}
#endif
#endif