Files
UnrealEngineUWP/Engine/Shaders/Private/ShaderPrint.ush
T
Charles deRousiers 50b5894afa * Move compute raster common parameter into a common struct
* Add debug pass for compute raster to visualize settings & binning.

#rb none
#jira none
#preflight 62c5558e3c5171c817fe10ba
#fyi tim.doerries

[CL 20964792 by Charles deRousiers in ue5-main branch]
2022-07-06 07:22:58 -04:00

1390 lines
65 KiB
Plaintext

/*=============================================================================
ShaderPrintCommon.ush:
Include this to be able to call ShaderPrint() from arbitrary shaders
=============================================================================*/
#pragma once
// Include the MiniFont symbol definitions
#include "MiniFontCommon.ush"
///////////////////////////////////////////////////////////////////////////////////////////////////
// Description
// Shader Print allows to print value & text from shaders.
//
// 0. Contex-based state API
// -------------------------
// FShaderPrintContext Context = InitShaderPrintContext(all(SvPosition.xy == float2(100, 100), uint2(50,50))
// ------------------------------------ ------------
// Pixel/thread to filter Coord at which
// to draw
//
// 1. How to print value?
// ----------------------
// First create a context, then print scalar/vector/matrix/text...
//
// FShaderPrintContext Context = InitShaderPrintContext(all(PixelPos.xy == uint2(100, 100), uint2(50,50))
//
// Print(Context, MyFloat);
// Newline(Context);
//
// Print(Context, TEXT("My string for labbelling a float :"), FontOrange);
// Print(Context, MyFloatInYellow, FontYellow);
// Newline(Context);
//
// Numerical values can be further formatted, by configuring the number of digits spanned by a number
// (i.e. the number of written&non-written digits), and the number of wanted decimal for floating value.
//
// Print(Context, 123, FontYellow, 5); // Spanning is show as: .....
// Print(Context, 456, FontYellow, 4); // Spanning is show as: xxxx
// Print(Context, 789, FontYellow, 3); // Spanning is show as: ---
//
// Will be displayed as follow:
// 123 456 789
// ..... xxxx ---
//
// Print(Context, 12.3456, FontYellow, 5, 2); // Spanning is show as: ...
// Print(Context, 12.3456, FontYellow, 5, 1); // Spanning is show as: xxx
//
// Will be displayed as follow:
// 12.34 12.3
// ..... xxxxx
//
// 2. How to add widget?
// ---------------------
// Widget can be added from shader.
// For slider:
//
// const float MySliderValue = AddSlider(Context, DefaultValue, TEXT("My Slider"));
//
// For checkbox:
//
// const bool MyCheckboxValue = AddCheckbox(Context, DefaultValue, TEXT("My Checkbox"));
//
// The value of these widgets can be retrieved/evaluated from *any* thread/pixels, but the
// drawing need to be done from a single thread/pixel. This is done through the ShaderPrintContextcontext,
// which setup which pixel/thread is active/filtered. Example with a compute shader:
//
// [numthreads(8, 8, 1)]
// void MainCS(uint2 DispatchThreadId : SV_DispatchThreadID)
// {
// // Create context which 'add' the widget only on thread (0,0)
// FShaderPrintContext Context = InitShaderPrintContext(all(DispatchThreadId == uint2(0, 0), uint2(50,50))
//
// // Any threads can get the slider value with this call
// const float ScaleValue = AddSlider(Context, 1.f, TEXT("Scale"));
// ...
// }
//
//
// 4. Global-based state API
// -------------------------
// Another API can be used with a more 'global' context accross the shader execution.
//
// This API is used to restrict ShaderPrint to a subset of active threads
// The filter functions can be called once at the start of the shader to filter all later printing
//
// To debug a single pixel:
//
// ShaderPrintFilter(all(SvPosition.xy == float2(100, 100)));
//
// To debug a single compute shader thread:
//
// ShaderPrintFilter(all(DispatchThreadId == uint3(0, 0, 0)));
//
// To debug a single random active thread
//
// ShaderPrintFilterOneThread()
//
// Note that ShaderPrintFilterOneThread() only works for one shader invocation in a view since it relies on a global memory location
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// Input types
// Content of FShaderPrintItem.Type defines what to cast FShaderPrintItem.Value as
// Type of primitives
#define SHADER_PRINT_TYPE_SYMBOL 0
#define SHADER_PRINT_TYPE_FLOAT 1
#define SHADER_PRINT_TYPE_INT 2
#define SHADER_PRINT_TYPE_UINT 3
#define SHADER_PRINT_TYPE_HEX 4
#define SHADER_PRINT_TYPE_SLIDER 5
#define SHADER_PRINT_TYPE_CHECK 6
// Type of primitives (to be merged with the list above once all buffer are merged)
#define SHADER_PRINT_TYPE_LINE 0
#define SHADER_PRINT_TYPE_TRIANGLE 1
// Size of packed data, in uint
#define SHADER_PRINT_UINT_COUNT_SYMBOL 4
#define SHADER_PRINT_UINT_COUNT_LINE 8
#define SHADER_PRINT_UINT_COUNT_TRIANGLE 12
// Counter offset
#define SHADER_PRINT_COUNTER_OFFSET_LINE 0
#define SHADER_PRINT_COUNTER_OFFSET_TRIANGLE 1
#define SHADER_PRINT_COUNTER_OFFSET_SYMBOL 2
#define SHADER_PRINT_COUNTER_OFFSET_FREE 3
#define SHADER_PRINT_COUNTER_COUNT 4
uint GetSymbolOffset(uint InIndex) { return SHADER_PRINT_COUNTER_COUNT + SHADER_PRINT_UINT_COUNT_SYMBOL * InIndex; }
uint GetPrimitiveLineOffset(uint InIndex) { return SHADER_PRINT_COUNTER_COUNT + SHADER_PRINT_UINT_COUNT_SYMBOL * ShaderPrintData.MaxValueCount + SHADER_PRINT_UINT_COUNT_LINE * InIndex; }
uint GetPrimitiveTriangleOffset(uint InIndex) { return SHADER_PRINT_COUNTER_COUNT + SHADER_PRINT_UINT_COUNT_SYMBOL * ShaderPrintData.MaxValueCount + SHADER_PRINT_UINT_COUNT_LINE * ShaderPrintData.MaxLineCount + SHADER_PRINT_UINT_COUNT_TRIANGLE * InIndex; }
void ClearCounters(RWStructuredBuffer<uint> InRWBuffer)
{
// Symbol/print Counter
InRWBuffer[SHADER_PRINT_COUNTER_OFFSET_LINE] = 0;
InRWBuffer[SHADER_PRINT_COUNTER_OFFSET_TRIANGLE] = 0;
InRWBuffer[SHADER_PRINT_COUNTER_OFFSET_SYMBOL] = 0;
InRWBuffer[SHADER_PRINT_COUNTER_OFFSET_FREE] = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// State
#define SHADER_PRINT_STATE_COUNT_OFFSET 0
#define SHADER_PRINT_STATE_VALUE_OFFSET 1
#define SHADER_PRINT_STATE_STRIDE 3
#define SHADER_PRINT_STATE_INDEX_METADATA 0
#define SHADER_PRINT_STATE_INDEX_VALUE 1
#define SHADER_PRINT_STATE_INDEX_FRAME 2
#define SHADER_PRINT_STATE_INVALID_INDEX 0xFF
#define SHADER_PRINT_STATE_HASH_MASK 0xFFFFFF
///////////////////////////////////////////////////////////////////////////////////////////////////
// Output structures
StructuredBuffer<uint> ShaderPrint_StateBuffer;
// Primitive & Symbols layout
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// || Line | Triangle | Symbol | Empty || Symb0 | Symb1 | Symb2 | Symb3 | ... | Line0 | Line1 | Line2 | Line3 | ... | Triangle0 | Triangle1 | Triangle2 | Triangle3 | ...
// || Counter | Counter | Counter | Counter || | | | | ... | | | | | ... | | | | | ...
// || (1uint) | (1uint) | (1uint) | (1uint) || (4uint) | (4uint) | (4uint) | (4uint) | ... | (8uint) | (8uint) | (8uint) | (8uint) | ... | (12uint) | (12uint) | (12uint) | (12uint) | ...
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RWStructuredBuffer<uint> ShaderPrint_RWEntryBuffer;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Font Color
struct FFontColor
{
float3 Color;
};
FFontColor InitFontColor(float InX, float InY, float InZ) { FFontColor Out; Out.Color = float3(InX, InY, InZ); return Out; }
FFontColor InitFontColor(float3 In) { FFontColor Out; Out.Color = In; return Out; }
FFontColor GetDefaultFontColor() { FFontColor Out; Out.Color = float3(1,1,1); return Out; }
// Predefined colors
#define FontWhite InitFontColor(1, 1, 1)
#define FontGrey InitFontColor(0.5, 0.5, 0.5)
#define FontDarkGrey InitFontColor(0.25, 0.25, 0.25)
#define FontBlack InitFontColor(0, 0, 0)
#define FontRed InitFontColor(1, 0, 0)
#define FontGreen InitFontColor(0, 1, 0)
#define FontBlue InitFontColor(0, 0, 1)
#define FontYellow InitFontColor(1, 1, 0)
#define FontCyan InitFontColor(0, 1, 1)
#define FontMagenta InitFontColor(1, 0, 1)
#define FontOrange InitFontColor(243.f / 255.f, 156.f / 255.f, 18.f / 255.f)
#define FontPurple InitFontColor(169.f / 255.f, 7.f / 255.f, 228.f / 255.f)
#define FontTurquoise InitFontColor(26.f / 255.f, 188.f / 255.f, 156.f / 255.f)
#define FontSilver InitFontColor(189.f / 255.f, 195.f / 255.f, 199.f / 255.f)
#define FontEmerald InitFontColor(46.f / 255.f, 204.f / 255.f, 113.f / 255.f)
#define FontLightRed InitFontColor(0.75f, 0.50f, 0.50f)
#define FontLightGreen InitFontColor(0.50f, 0.75f, 0.50f)
#define FontLightBlue InitFontColor(0.50f, 0.50f, 0.75f)
#define FontDarkRed InitFontColor(0.50f, 0.25f, 0.25f)
#define FontDarkGreen InitFontColor(0.25f, 0.50f, 0.25f)
#define FontDarkBlue InitFontColor(0.25f, 0.25f, 0.50f)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Primitive colors
#define ColorWhite float4(1, 1, 1, 1)
#define ColorBlack float4(0, 0, 0, 1)
#define ColorRed float4(1, 0, 0, 1)
#define ColorGreen float4(0, 1, 0, 1)
#define ColorBlue float4(0, 0, 1, 1)
#define ColorYellow float4(1, 1, 0, 1)
#define ColorCyan float4(0, 1, 1, 1)
#define ColorMagenta float4(1, 0, 1, 1)
#define ColorOrange float4(243.f / 255.f, 156.f / 255.f, 18.f / 255.f, 1)
#define ColorPurple float4(169.f / 255.f, 7.f / 255.f, 228.f / 255.f, 1)
#define ColorTurquoise float4( 26.f / 255.f, 188.f / 255.f, 156.f / 255.f, 1)
#define ColorSilver float4(189.f / 255.f, 195.f / 255.f, 199.f / 255.f, 1)
#define ColorEmerald float4( 46.f / 255.f, 204.f / 255.f, 113.f / 255.f, 1)
#define ColorLightRed float4(0.75f, 0.50f, 0.50f, 1.0f)
#define ColorLightGreen float4(0.50f, 0.75f, 0.50f, 1.0f)
#define ColorLightBlue float4(0.50f, 0.50f, 0.75f, 1.0f)
#define ColorDarkRed float4(0.50f, 0.25f, 0.25f, 1.0f)
#define ColorDarkGreen float4(0.25f, 0.50f, 0.25f, 1.0f)
#define ColorDarkBlue float4(0.25f, 0.25f, 0.50f, 1.0f)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Util pack/unpac functions
struct FShaderPrintItem
{
float2 ScreenPos; // Position in normalized coordinates
int Value; // Cast to value or symbol
int Type; // SHADER_PRINT_TYPE_* defines how to read Value
float3 Color; // Color
uint Metadata; // Metadata (used for widget to store extra state data
};
// Needs to match C++ code in ShaderPrint.cpp
struct FPackedShaderPrintItem
{
uint ScreenPos16bits; // Position in normalized coordinates
uint Value; // Cast to value or symbol
uint TypeAndColor; //
uint Metadata; //
};
FPackedShaderPrintItem PackShaderPrintItem(FShaderPrintItem In)
{
const uint3 Color8bits = saturate(In.Color) * 0xFF;
const uint2 ScreenPos16bit = f32tof16(In.ScreenPos);
FPackedShaderPrintItem Out;
Out.ScreenPos16bits = ScreenPos16bit.x | (ScreenPos16bit.y<<16);
Out.Value = asuint(In.Value);
Out.TypeAndColor = (Color8bits.z << 24) | (Color8bits.y << 16) | (Color8bits.x << 8) | (In.Type & 0xFF);
Out.Metadata = In.Metadata;
return Out;
}
FShaderPrintItem UnpackShaderPrintItem(FPackedShaderPrintItem In)
{
const uint2 ScreenPos16bits = uint2(In.ScreenPos16bits & 0xFFFF, (In.ScreenPos16bits>>16) & 0xFFFF);
FShaderPrintItem Out;
Out.ScreenPos = f16tof32(ScreenPos16bits);
Out.Value = asint(In.Value);
Out.Type = (In.TypeAndColor) & 0xFF;
Out.Color.x = float((In.TypeAndColor >> 8) & 0xFF) / 255.f;
Out.Color.y = float((In.TypeAndColor >> 16) & 0xFF) / 255.f;
Out.Color.z = float((In.TypeAndColor >> 24) & 0xFF) / 255.f;
Out.Metadata = In.Metadata;
return Out;
}
void WriteSymbol(uint Offset, FShaderPrintItem In, RWStructuredBuffer<uint> InRWBuffer)
{
const uint Offset4 = GetSymbolOffset(Offset);
const FPackedShaderPrintItem Packed = PackShaderPrintItem(In);
InRWBuffer[Offset4 + 0] = Packed.ScreenPos16bits;
InRWBuffer[Offset4 + 1] = Packed.Value;
InRWBuffer[Offset4 + 2] = Packed.TypeAndColor;
InRWBuffer[Offset4 + 3] = Packed.Metadata;
}
FShaderPrintItem ReadSymbol(uint Offset, StructuredBuffer<uint> InBuffer)
{
const uint Offset4 = GetSymbolOffset(Offset);
FPackedShaderPrintItem Packed = (FPackedShaderPrintItem)0;
Packed.ScreenPos16bits = InBuffer[Offset4 + 0];
Packed.Value = InBuffer[Offset4 + 1];
Packed.TypeAndColor = InBuffer[Offset4 + 2];
Packed.Metadata = InBuffer[Offset4 + 3];
return UnpackShaderPrintItem(Packed);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Global variables
#include "/Engine/Generated/UniformBuffers/ShaderPrintData.ush"
static const float2 ShaderPrintCursorStart = float2(0.05f, 0.05f);
// 'Global' values for tracking printing state (per thread)
static float2 ShaderPrintCursorPos = ShaderPrintCursorStart;
static bool ShaderPrintFilterEnable = true;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Print API (Experimental)
struct FShaderPrintContext
{
bool bIsActive;
float2 StartPos;
float2 Pos;
};
FShaderPrintContext InitShaderPrintContext(bool bActive, float2 InStartPos)
{
FShaderPrintContext Out;
Out.bIsActive = bActive;
Out.StartPos = InStartPos;
Out.Pos = InStartPos;
return Out;
}
FShaderPrintContext InitShaderPrintContext(bool bActive, uint2 InStartCoord) { return InitShaderPrintContext(bActive, float2(InStartCoord) / float2(ShaderPrintData.Resolution)); }
void Newline(inout FShaderPrintContext InContext)
{
InContext.Pos.x = InContext.StartPos.x;
InContext.Pos.y += ShaderPrintData.FontSpacing.y;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Internal helpers
void ShaderPrint_Internal(in FShaderPrintItem Item)
{
// If MaxValueCount is 0 then we don't reset the buffer counter so early out here
if (ShaderPrintData.MaxValueCount == 0)
{
return;
}
// Buffer counter is stored in first element .Value
int IndexToStore = 0;
InterlockedAdd(ShaderPrint_RWEntryBuffer[SHADER_PRINT_COUNTER_OFFSET_SYMBOL], 1, IndexToStore);
// Prevent writing off the buffer
// Note that counter still increases so need clamp when reading it in later passes
if (uint(IndexToStore) >= ShaderPrintData.MaxValueCount)
{
return;
}
WriteSymbol(IndexToStore, Item, ShaderPrint_RWEntryBuffer);
}
void ShaderPrint_Internal(in float2 ScreenPos, in int Value, in FFontColor FontColor, in uint Metadata, in int Type)
{
FShaderPrintItem Item;
Item.ScreenPos = ScreenPos;
Item.Value = Value;
Item.Type = Type;
Item.Color = FontColor.Color;
Item.Metadata = Metadata;
ShaderPrint_Internal(Item);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Symbol printing
float2 ShaderPrintSymbol(in float2 ScreenPos, in int Symbol, in FFontColor Color)
{
if (ShaderPrintFilterEnable)
{
ShaderPrint_Internal(ScreenPos, Symbol, Color, 0u, SHADER_PRINT_TYPE_SYMBOL);
ScreenPos.x += ShaderPrintData.FontSpacing.x;
}
return ScreenPos;
}
float2 ShaderPrintSymbol(in float2 ScreenPos, in int Symbol) { return ShaderPrintSymbol(ScreenPos, Symbol, GetDefaultFontColor()); }
void ShaderPrintSymbol(in int symbol, in FFontColor Color)
{
ShaderPrintCursorPos = ShaderPrintSymbol(ShaderPrintCursorPos, symbol, Color);
}
void ShaderPrintSymbol(in int symbol) { ShaderPrintSymbol(symbol, GetDefaultFontColor()); }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Text & hash
struct FShaderPrintText
{
uint Index;
};
FShaderPrintText InitShaderPrintText(uint InIndex)
{
FShaderPrintText Out;
Out.Index = InIndex;
return Out;
}
// Forward declarations for text accessors
uint ShaderPrintGetChar(uint InIndex);
uint ShaderPrintGetOffset(FShaderPrintText InTextEntry);
uint ShaderPrintGetHash(FShaderPrintText InTextEntry);
// Function for reading global TEXT string
float2 ShaderPrintText_Internal(bool bIsActive, float2 InPos, FShaderPrintText InTextEntry, FFontColor InColor)
{
// If MaxValueCount is 0 then we don't reset the buffer counter so early out here
if (bIsActive && ShaderPrintData.MaxValueCount > 0)
{
const uint Begin = ShaderPrintGetOffset(InTextEntry);
const uint End = ShaderPrintGetOffset(InitShaderPrintText(InTextEntry.Index + 1));
const uint Count = End - Begin;
// Buffer counter is stored in first element .Value
// Prevent writing off the buffer
// Note that counter still increases so need clamp when reading it in later passes
int IndexToStore = 0;
InterlockedAdd(ShaderPrint_RWEntryBuffer[SHADER_PRINT_COUNTER_OFFSET_SYMBOL], Count, IndexToStore);
if (uint(IndexToStore + Count) < ShaderPrintData.MaxValueCount)
{
for (uint i = Begin; i < End; ++i)
{
FShaderPrintItem Item;
Item.ScreenPos = InPos;
Item.Value = ShaderPrintGetChar(i);
Item.Type = SHADER_PRINT_TYPE_SYMBOL;
Item.Color = InColor.Color;
Item.Metadata = 0u;
WriteSymbol(IndexToStore, Item, ShaderPrint_RWEntryBuffer);
++IndexToStore;
InPos.x += ShaderPrintData.FontSpacing.x;
}
}
}
return InPos;
}
float2 ShaderPrintText(float2 InPos, FShaderPrintText InTextEntry, FFontColor InColor) { return ShaderPrintText_Internal(ShaderPrintFilterEnable, InPos, InTextEntry, InColor); }
float2 ShaderPrintText(float2 InPos, FShaderPrintText InTextEntry) { return ShaderPrintText_Internal(ShaderPrintFilterEnable, InPos, InTextEntry, GetDefaultFontColor()); }
void ShaderPrintText(inout FShaderPrintContext InCtx, FShaderPrintText InTextEntry, FFontColor InColor) { InCtx.Pos = ShaderPrintText_Internal(InCtx.bIsActive, InCtx.Pos, InTextEntry, InColor); }
void ShaderPrintText(inout FShaderPrintContext InCtx, FShaderPrintText InTextEntry) { InCtx.Pos = ShaderPrintText_Internal(InCtx.bIsActive, InCtx.Pos, InTextEntry, GetDefaultFontColor()); }
float2 Print(float2 InPos, FShaderPrintText InTextEntry, FFontColor InColor) { return ShaderPrintText_Internal(ShaderPrintFilterEnable, InPos, InTextEntry, InColor); }
float2 Print(float2 InPos, FShaderPrintText InTextEntry) { return ShaderPrintText_Internal(ShaderPrintFilterEnable, InPos, InTextEntry, GetDefaultFontColor()); }
void Print(inout FShaderPrintContext InCtx, FShaderPrintText InTextEntry, FFontColor InColor) { InCtx.Pos = ShaderPrintText_Internal(InCtx.bIsActive, InCtx.Pos, InTextEntry, InColor); }
void Print(inout FShaderPrintContext InCtx, FShaderPrintText InTextEntry) { InCtx.Pos = ShaderPrintText_Internal(InCtx.bIsActive, InCtx.Pos, InTextEntry, GetDefaultFontColor()); }
// Function for reading global TEXT string.
// The data and function are generated by the shader compiler.
GENERATED_SHADER_PRINT
///////////////////////////////////////////////////////////////////////////////////////////////////
// Value printing (common value printing)
#define MAX_DECIMAL_COUNT 5u
#define MAX_DIGIT_COUNT 12u
float2 ShaderPrintValue(float2 ScreenPos, float Value, FFontColor Color, uint MaxDigit, uint MaxDecimal) { ShaderPrint_Internal(ScreenPos, asint(Value), Color, MaxDecimal, SHADER_PRINT_TYPE_FLOAT); ScreenPos.x += ShaderPrintData.FontSpacing.x * MaxDigit; return ScreenPos; }
float2 ShaderPrintValue(float2 ScreenPos, int Value, FFontColor Color, uint MaxDigit, uint MaxDecimal) { ShaderPrint_Internal(ScreenPos, Value, Color, MaxDecimal, SHADER_PRINT_TYPE_INT); ScreenPos.x += ShaderPrintData.FontSpacing.x * MaxDigit; return ScreenPos; }
float2 ShaderPrintValue(float2 ScreenPos, uint Value, FFontColor Color, uint MaxDigit, uint MaxDecimal) { ShaderPrint_Internal(ScreenPos, asint(Value), Color, MaxDecimal, SHADER_PRINT_TYPE_UINT); ScreenPos.x += ShaderPrintData.FontSpacing.x * MaxDigit; return ScreenPos; }
float2 ShaderPrintValue(float2 ScreenPos, bool Value, FFontColor Color, uint MaxDigit, uint MaxDecimal) { ShaderPrint_Internal(ScreenPos, asint(Value ? 1u : 0u), Color, MaxDecimal, SHADER_PRINT_TYPE_UINT); ScreenPos.x += ShaderPrintData.FontSpacing.x * MaxDigit; return ScreenPos; }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Scalar type printing
#define SHADER_PRINT_OVERLOAD_1(InPrefix, InNumComponent, InType) \
void InPrefix##Print(InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (ShaderPrintFilterEnable) { ShaderPrintCursorPos = ShaderPrintValue(ShaderPrintCursorPos, Value, Color, MaxDigit, MaxDecimal); } } \
float2 InPrefix##Print(float2 ScreenPos, InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (ShaderPrintFilterEnable) { ScreenPos = ShaderPrintValue(ScreenPos, Value, Color, MaxDigit, MaxDecimal); } return ScreenPos; } \
void InPrefix##Print(inout FShaderPrintContext InCtx, InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (InCtx.bIsActive) { InCtx.Pos = ShaderPrintValue(InCtx.Pos, Value, Color, MaxDigit, MaxDecimal); } } \
void InPrefix##Print(InType Value) { if (ShaderPrintFilterEnable) { ShaderPrintCursorPos = ShaderPrintValue(ShaderPrintCursorPos, Value, GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); } } \
float2 InPrefix##Print(float2 ScreenPos, InType Value) { if (ShaderPrintFilterEnable) { ScreenPos = ShaderPrintValue(ScreenPos, Value, GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); } return ScreenPos; } \
void InPrefix##Print(inout FShaderPrintContext InCtx, InType Value) { if (InCtx.bIsActive) { InCtx.Pos = ShaderPrintValue(InCtx.Pos, Value, GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Vector type printing
#define SHADER_PRINT_OVERLOAD_N(InPrefix, InNumComponent, InType) \
void InPrefix##Print(InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompIt=0;CompIt<InNumComponent;++CompIt) { ShaderPrintCursorPos = ShaderPrintValue(ShaderPrintCursorPos, Value[CompIt], Color, MaxDigit, MaxDecimal); } } } \
float2 InPrefix##Print(float2 ScreenPos, InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompIt=0;CompIt<InNumComponent;++CompIt) { ScreenPos = ShaderPrintValue(ScreenPos, Value[CompIt], Color, MaxDigit, MaxDecimal); } } return ScreenPos; } \
void InPrefix##Print(inout FShaderPrintContext InCtx, InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (InCtx.bIsActive) { UNROLL for (uint CompIt=0;CompIt<InNumComponent;++CompIt) { InCtx.Pos = ShaderPrintValue(InCtx.Pos, Value[CompIt], Color, MaxDigit, MaxDecimal); } } } \
void InPrefix##Print(InType Value) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompIt=0;CompIt<InNumComponent;++CompIt) { ShaderPrintCursorPos = ShaderPrintValue(ShaderPrintCursorPos, Value[CompIt], GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); } } } \
float2 InPrefix##Print(float2 ScreenPos, InType Value) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompIt=0;CompIt<InNumComponent;++CompIt) { ScreenPos = ShaderPrintValue(ScreenPos, Value[CompIt], GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); } } return ScreenPos; } \
void InPrefix##Print(inout FShaderPrintContext InCtx, InType Value) { if (InCtx.bIsActive) { UNROLL for (uint CompIt=0;CompIt<InNumComponent;++CompIt) { InCtx.Pos = ShaderPrintValue(InCtx.Pos, Value[CompIt], GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); } } }
// ShaderPrint(X) version (legacy)
SHADER_PRINT_OVERLOAD_1(Shader, 1, float)
SHADER_PRINT_OVERLOAD_N(Shader, 2, float2)
SHADER_PRINT_OVERLOAD_N(Shader, 3, float3)
SHADER_PRINT_OVERLOAD_N(Shader, 4, float4)
SHADER_PRINT_OVERLOAD_1(Shader, 1, uint)
SHADER_PRINT_OVERLOAD_N(Shader, 2, uint2)
SHADER_PRINT_OVERLOAD_N(Shader, 3, uint3)
SHADER_PRINT_OVERLOAD_N(Shader, 4, uint4)
SHADER_PRINT_OVERLOAD_1(Shader, 1, int)
SHADER_PRINT_OVERLOAD_N(Shader, 2, int2)
SHADER_PRINT_OVERLOAD_N(Shader, 3, int3)
SHADER_PRINT_OVERLOAD_N(Shader, 4, int4)
SHADER_PRINT_OVERLOAD_1(Shader, 1, bool)
// Print(X) version
SHADER_PRINT_OVERLOAD_1(, 1, float)
SHADER_PRINT_OVERLOAD_N(, 2, float2)
SHADER_PRINT_OVERLOAD_N(, 3, float3)
SHADER_PRINT_OVERLOAD_N(, 4, float4)
SHADER_PRINT_OVERLOAD_1(, 1, uint)
SHADER_PRINT_OVERLOAD_N(, 2, uint2)
SHADER_PRINT_OVERLOAD_N(, 3, uint3)
SHADER_PRINT_OVERLOAD_N(, 4, uint4)
SHADER_PRINT_OVERLOAD_1(, 1, int)
SHADER_PRINT_OVERLOAD_N(, 2, int2)
SHADER_PRINT_OVERLOAD_N(, 3, int3)
SHADER_PRINT_OVERLOAD_N(, 4, int4)
SHADER_PRINT_OVERLOAD_1(, 1, bool)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Matrix type printing
#define SHADER_PRINT_OVERLOAD_NN(InPrefix, InNumComponentX, InNumComponentY, InType) \
void InPrefix##Print(InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompY=0;CompY<InNumComponentY;++CompY) { ShaderPrintCursorPos = InPrefix##Print(ShaderPrintCursorPos, Value[CompY], Color, MaxDigit, MaxDecimal); ShaderPrintCursorPos += float2(0.f, ShaderPrintData.FontSpacing.y); } } } \
float2 InPrefix##Print(float2 ScreenPos, InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompY=0;CompY<InNumComponentY;++CompY) { ScreenPos = InPrefix##Print(ScreenPos, Value[CompY], Color, MaxDigit, MaxDecimal); ScreenPos += float2(0.f, ShaderPrintData.FontSpacing.y); } } return ScreenPos; } \
void InPrefix##Print(inout FShaderPrintContext InCtx, InType Value, FFontColor Color, uint MaxDigit=MAX_DIGIT_COUNT, uint MaxDecimal=MAX_DECIMAL_COUNT) { if (InCtx.bIsActive) { UNROLL for (uint CompY=0;CompY<InNumComponentY;++CompY) { InCtx.Pos = InPrefix##Print(InCtx.Pos, Value[CompY], Color, MaxDigit, MaxDecimal); InCtx.Pos += float2(0.f, ShaderPrintData.FontSpacing.y); } } } \
void InPrefix##Print(InType Value) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompY=0;CompY<InNumComponentY;++CompY) { ShaderPrintCursorPos = InPrefix##Print(ShaderPrintCursorPos, Value[CompY], GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); ShaderPrintCursorPos += float2(0.f, ShaderPrintData.FontSpacing.y); } } } \
float2 InPrefix##Print(float2 ScreenPos, InType Value) { if (ShaderPrintFilterEnable) { UNROLL for (uint CompY=0;CompY<InNumComponentY;++CompY) { ScreenPos = InPrefix##Print(ScreenPos, Value[CompY], GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); ScreenPos += float2(0.f, ShaderPrintData.FontSpacing.y); } } return ScreenPos; } \
void InPrefix##Print(inout FShaderPrintContext InCtx, InType Value) { if (InCtx.bIsActive) { UNROLL for (uint CompY=0;CompY<InNumComponentY;++CompY) { InCtx.Pos = InPrefix##Print(InCtx.Pos, Value[CompY], GetDefaultFontColor(), MAX_DIGIT_COUNT, MAX_DECIMAL_COUNT); InCtx.Pos += float2(0.f, ShaderPrintData.FontSpacing.y); } } }
// ShaderPrint(X) version
SHADER_PRINT_OVERLOAD_NN(Shader, 3, 3, float3x3)
SHADER_PRINT_OVERLOAD_NN(Shader, 4, 3, float4x3)
SHADER_PRINT_OVERLOAD_NN(Shader, 4, 4, float4x4)
// Print(X) version
SHADER_PRINT_OVERLOAD_NN(, 3, 3, float3x3)
SHADER_PRINT_OVERLOAD_NN(, 4, 3, float4x3)
SHADER_PRINT_OVERLOAD_NN(, 4, 4, float4x4)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Formating helpers
float2 ShaderPrintSpace(in float2 ScreenPos, in float Count = 1)
{
if (ShaderPrintFilterEnable)
{
ScreenPos.x += ShaderPrintData.FontSpacing.x * Count;
}
return ScreenPos;
}
void ShaderPrintSpace(in float Count = 1)
{
ShaderPrintCursorPos = ShaderPrintSpace(ShaderPrintCursorPos, Count);
}
float2 ShaderPrintNewline(in float2 ScreenPos)
{
if (ShaderPrintFilterEnable)
{
ScreenPos.x = ShaderPrintCursorStart.x;
ScreenPos.y += ShaderPrintData.FontSpacing.y;
}
return ScreenPos;
}
void ShaderPrintNewline()
{
ShaderPrintCursorPos = ShaderPrintNewline(ShaderPrintCursorPos);
}
float2 ShaderPrintGetCursorPos()
{
return ShaderPrintCursorPos;
}
float2 ShaderPrintSetCursorPos(in float2 ScreenPos)
{
float2 PrevScreenPos = ShaderPrintCursorPos;
ShaderPrintCursorPos = ScreenPos;
return PrevScreenPos;
}
float2 ShaderPrintGetPos(in uint2 PixelCoord)
{
return float2(PixelCoord) / float2(ShaderPrintData.Resolution);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Filter helpers
void ShaderPrintFilter(bool bFilter)
{
ShaderPrintFilterEnable = bFilter;
}
void ShaderPrintFilterOneThread()
{
// Deprecated
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Widgets (experimental)
uint2 GetCheckboxWidgetSize()
{
return uint(ShaderPrintData.FontSpacing.x * ShaderPrintData.Resolution.x).xx;
}
uint2 GetSliderWidgetSize()
{
return uint2(10,1) * uint(ShaderPrintData.FontSpacing.x * ShaderPrintData.Resolution.x);
}
struct FShaderPrintMetadata
{
uint Hash;
uint Index;
};
uint ShaderPrintPackMetadata(uint InHash, uint InIndex)
{
return ((InIndex & 0xFFu) << 24) | (InHash & SHADER_PRINT_STATE_HASH_MASK);
}
uint ShaderPrintPackMetadata(FShaderPrintMetadata In) { return ShaderPrintPackMetadata(In.Hash, In.Index); }
FShaderPrintMetadata ShaderPrintUnpackMetadata(uint Metadata)
{
FShaderPrintMetadata Out;
Out.Hash = (Metadata & SHADER_PRINT_STATE_HASH_MASK);
Out.Index= (Metadata >> 24) & 0xFF;
return Out;
}
// Return true if found, false otherwise
bool ShaderPrintGetStateValue(in uint InHash, inout uint OutIndex, inout uint OutValue)
{
OutIndex = SHADER_PRINT_STATE_INVALID_INDEX;
OutValue = 0;
// Slow linear search among all widget states
const uint MaxCount = min(ShaderPrint_StateBuffer[SHADER_PRINT_STATE_COUNT_OFFSET], ShaderPrintData.MaxStateCount);
for (uint Index = 0; Index < MaxCount; ++Index)
{
const uint Index3 = Index * SHADER_PRINT_STATE_STRIDE + SHADER_PRINT_STATE_VALUE_OFFSET;
const FShaderPrintMetadata Metadata = ShaderPrintUnpackMetadata(ShaderPrint_StateBuffer[Index3 + SHADER_PRINT_STATE_INDEX_METADATA]);
if (Metadata.Hash == InHash)
{
OutIndex = Metadata.Index;
OutValue = ShaderPrint_StateBuffer[Index3 + SHADER_PRINT_STATE_INDEX_VALUE];
return true;
}
}
return false;
}
// Add a checkbox widget
bool AddCheckbox(inout FShaderPrintContext InContext, FShaderPrintText InTextEntry, bool bDefault, in FFontColor InColor)
{
uint Index = 0;
uint RawValue = 0;
const uint Hash = ShaderPrintGetHash(InTextEntry) & SHADER_PRINT_STATE_HASH_MASK; // Trunk hask since metadata has limited storage
const bool bIsValid = ShaderPrintGetStateValue(Hash, Index, RawValue);
RawValue = bIsValid ? RawValue : (bDefault ? 0x1 : 0x0);
if (InContext.bIsActive)
{
const uint2 Coord = InContext.Pos * ShaderPrintData.Resolution;
const uint2 Cusor = ShaderPrintData.CursorCoord;
const uint2 WidgetSize = GetCheckboxWidgetSize();
const uint2 WidgetMax = uint2(Coord.x + WidgetSize.x, Coord.y + WidgetSize.y / 2);
const uint2 WidgetMin = uint2(Coord.x, Coord.y - WidgetSize.y / 2);
const bool bIsInside = all(Cusor >= WidgetMin) && all(Cusor <= WidgetMax);
const bool bWasInside = RawValue & 0x2;
// Update checkbox value
// Track if the cursor was already within the box or not
if (bIsInside)
{
if (!bWasInside)
{
// First time the cursor is within the checkbox
RawValue = ((RawValue & 0x1) == 1 ? 0x0 : 0x1) | 0x2;
}
}
else
{
RawValue = (RawValue & 0x1);
}
FShaderPrintItem E;
E.ScreenPos = InContext.Pos;
E.Value = RawValue;
E.Type = SHADER_PRINT_TYPE_CHECK;
E.Color = bIsInside ? FontYellow.Color : FontWhite.Color;// InColor.Color;
E.Metadata = ShaderPrintPackMetadata(Hash, Index);
ShaderPrint_Internal(E);
InContext.Pos.x += float(WidgetSize.x) / float(ShaderPrintData.Resolution.x) + ShaderPrintData.FontSpacing.x;
// Text
InContext.Pos = ShaderPrintText(InContext.Pos, InTextEntry, InColor);
InContext.Pos.x += ShaderPrintData.FontSpacing.x;
}
return RawValue & 0x1;
}
// Add a slider widget
float AddSlider(inout FShaderPrintContext InContext, FShaderPrintText InTextEntry, float bDefault, in FFontColor InColor, float InMin = 0.f, float InMax = 1.f)
{
// The value is stored as normalized, for displaying slide value correctly. This is not idealy
// as it implies some precision lost due to back&forth conversion between normalized/non-normalized value.
uint Index = 0;
uint RawValue = 0;
const uint Hash = ShaderPrintGetHash(InTextEntry) & SHADER_PRINT_STATE_HASH_MASK; // Trunk hask since metadata has limited storage
const bool bIsValid = ShaderPrintGetStateValue(Hash, Index, RawValue);
float NormalizedValue = bIsValid ? asfloat(RawValue) : bDefault;
float Value = NormalizedValue * (InMax - InMin) + InMin;
if (InContext.bIsActive)
{
const uint2 Coord = InContext.Pos * ShaderPrintData.Resolution;
const uint2 Cusor = ShaderPrintData.CursorCoord;
const uint2 WidgetSize = GetSliderWidgetSize();
const uint2 WidgetMax = uint2(Coord.x + WidgetSize.x, Coord.y + WidgetSize.y / 2);
const uint2 WidgetMin = uint2(Coord.x, Coord.y - WidgetSize.y / 2);
const bool bIsInside = all(Cusor >= WidgetMin) && all(Cusor <= WidgetMax);
// Update slider value
if (bIsInside)
{
const float S = saturate(float(Cusor.x - WidgetMin.x) / float(WidgetMax.x - WidgetMin.x));
Value = lerp(InMin, InMax, S);
}
NormalizedValue = saturate((Value - InMin) / (InMax - InMin));
FShaderPrintItem E;
E.ScreenPos = InContext.Pos;
E.Value = asint(NormalizedValue);
E.Type = SHADER_PRINT_TYPE_SLIDER;
E.Color = bIsInside ? FontYellow.Color : FontWhite.Color; // InColor.Color;
E.Metadata = ShaderPrintPackMetadata(Hash, Index);
ShaderPrint_Internal(E);
InContext.Pos.x += float(WidgetSize.x) / float(ShaderPrintData.Resolution.x) + ShaderPrintData.FontSpacing.x;
// Text
InContext.Pos = ShaderPrintText(InContext.Pos, InTextEntry, InColor);
InContext.Pos.x += ShaderPrintData.FontSpacing.x;
}
return Value;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives types
///////////////////////////////////////////////////////////////////////////////////////////////////
// Triangle-based Primitives (Triangle, Point, ...)
struct FTriangleElement
{
float3 Pos0;
float3 Pos1;
float3 Pos2;
float4 Color;
bool bIsScreenSpace;
};
struct FPackedTriangleElement
{
uint4 Packed0;
uint4 Packed1;
uint4 Packed2;
};
FTriangleElement UnpackTriangleElement(FPackedTriangleElement In)
{
FTriangleElement Out = (FTriangleElement)0;
{
Out.Pos0.x = asfloat(In.Packed0.x);
Out.Pos0.y = asfloat(In.Packed0.y);
Out.Pos0.z = asfloat(In.Packed0.z);
Out.Color = float4((In.Packed0.w >> 24) & 0xFF, (In.Packed0.w >> 16) & 0xFF, (In.Packed0.w >> 8) & 0xFF, (In.Packed0.w) & 0xFF) / 255.0f;
}
{
Out.Pos1.x = asfloat(In.Packed1.x);
Out.Pos1.y = asfloat(In.Packed1.y);
Out.Pos1.z = asfloat(In.Packed1.z);
// The 'space' info is stored into the alpha's LSB
Out.bIsScreenSpace = (In.Packed1.w & 0x1) > 0u;
}
{
Out.Pos2.x = asfloat(In.Packed2.x);
Out.Pos2.y = asfloat(In.Packed2.y);
Out.Pos2.z = asfloat(In.Packed2.z);
}
return Out;
}
FPackedTriangleElement PackTriangleElement(FTriangleElement In)
{
uint4 PackedC = uint4(255.0f * saturate(In.Color));
FPackedTriangleElement Out = (FPackedTriangleElement)0;
Out.Packed0.x = asuint(In.Pos0.x);
Out.Packed0.y = asuint(In.Pos0.y);
Out.Packed0.z = asuint(In.Pos0.z);
Out.Packed0.w = (PackedC.x << 24) | (PackedC.y << 16) | (PackedC.z << 8) | (PackedC.w);
Out.Packed1.x = asuint(In.Pos1.x);
Out.Packed1.y = asuint(In.Pos1.y);
Out.Packed1.z = asuint(In.Pos1.z);
Out.Packed1.w = In.bIsScreenSpace ? 0x1 : 0x0;
Out.Packed2.x = asuint(In.Pos2.x);
Out.Packed2.y = asuint(In.Pos2.y);
Out.Packed2.z = asuint(In.Pos2.z);
Out.Packed2.w = 0;
return Out;
}
FTriangleElement UnpackTriangleElement(StructuredBuffer<uint> InPrimitiveBuffer, uint InIndex)
{
const uint Index12 = GetPrimitiveTriangleOffset(InIndex);
FPackedTriangleElement Out = (FPackedTriangleElement)0;
Out.Packed0.x = InPrimitiveBuffer[Index12 + 0];
Out.Packed0.y = InPrimitiveBuffer[Index12 + 1];
Out.Packed0.z = InPrimitiveBuffer[Index12 + 2];
Out.Packed0.w = InPrimitiveBuffer[Index12 + 3];
Out.Packed1.x = InPrimitiveBuffer[Index12 + 4];
Out.Packed1.y = InPrimitiveBuffer[Index12 + 5];
Out.Packed1.z = InPrimitiveBuffer[Index12 + 6];
Out.Packed1.w = InPrimitiveBuffer[Index12 + 7];
Out.Packed2.x = InPrimitiveBuffer[Index12 + 8];
Out.Packed2.y = InPrimitiveBuffer[Index12 + 9];
Out.Packed2.z = InPrimitiveBuffer[Index12 + 10];
Out.Packed2.w = InPrimitiveBuffer[Index12 + 11];
return UnpackTriangleElement(Out);
}
bool AllocateTriangleElement(uint Count, inout uint OutIndex)
{
OutIndex = 0;
if (ShaderPrintData.MaxTriangleCount == 0)
{
return false;
}
InterlockedAdd(ShaderPrint_RWEntryBuffer[SHADER_PRINT_COUNTER_OFFSET_TRIANGLE], Count, OutIndex);
return (OutIndex + Count) < ShaderPrintData.MaxTriangleCount;
}
void AddTriangleElement(FTriangleElement In, uint Index)
{
const uint Index12 = GetPrimitiveTriangleOffset(Index);
FPackedTriangleElement Out = PackTriangleElement(In);
ShaderPrint_RWEntryBuffer[Index12 + 0] = Out.Packed0.x;
ShaderPrint_RWEntryBuffer[Index12 + 1] = Out.Packed0.y;
ShaderPrint_RWEntryBuffer[Index12 + 2] = Out.Packed0.z;
ShaderPrint_RWEntryBuffer[Index12 + 3] = Out.Packed0.w;
ShaderPrint_RWEntryBuffer[Index12 + 4] = Out.Packed1.x;
ShaderPrint_RWEntryBuffer[Index12 + 5] = Out.Packed1.y;
ShaderPrint_RWEntryBuffer[Index12 + 6] = Out.Packed1.z;
ShaderPrint_RWEntryBuffer[Index12 + 7] = Out.Packed1.w;
ShaderPrint_RWEntryBuffer[Index12 + 8] = Out.Packed2.x;
ShaderPrint_RWEntryBuffer[Index12 + 9] = Out.Packed2.y;
ShaderPrint_RWEntryBuffer[Index12 + 10]= Out.Packed2.z;
ShaderPrint_RWEntryBuffer[Index12 + 11]= Out.Packed2.w;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Filled Triangle
void AddFilledTriangleTWS(float3 Pos0, float3 Pos1, float3 Pos2, float4 Color)
{
uint Offset = 0;
if (AllocateTriangleElement(1, Offset))
{
FTriangleElement Element;
Element.bIsScreenSpace = false;
Element.Color = Color;
Element.Pos0 = Pos0;
Element.Pos1 = Pos1;
Element.Pos2 = Pos2;
AddTriangleElement(Element, Offset + 0);
}
}
void AddFilledTriangleWS (float3 Pos0, float3 Pos1, float3 Pos2, float4 Color) { AddFilledTriangleTWS(Pos0 + ShaderPrintData.TranslatedWorldOffset, Pos1 + ShaderPrintData.TranslatedWorldOffset, Pos2 + ShaderPrintData.TranslatedWorldOffset, Color); }
void AddFilledTriangleTWS(FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float4 Color) { if (Ctx.bIsActive) { AddFilledTriangleTWS(Pos0, Pos1, Pos2, Color); } }
void AddFilledTriangleWS (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float4 Color) { if (Ctx.bIsActive) { AddFilledTriangleTWS(Pos0 + ShaderPrintData.TranslatedWorldOffset, Pos1 + ShaderPrintData.TranslatedWorldOffset, Pos2 + ShaderPrintData.TranslatedWorldOffset, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Filled Quad
void AddFilledQuadTWS(float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color)
{
uint Offset = 0;
if (AllocateTriangleElement(2, Offset))
{
FTriangleElement Element;
Element.bIsScreenSpace = false;
Element.Color = Color;
Element.Pos0 = Pos0;
Element.Pos1 = Pos1;
Element.Pos2 = Pos2;
AddTriangleElement(Element, Offset + 0);
Element.Pos0 = Pos0;
Element.Pos1 = Pos2;
Element.Pos2 = Pos3;
AddTriangleElement(Element, Offset + 1);
}
}
void AddFilledQuadWS (float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { AddFilledQuadTWS(Pos0 + ShaderPrintData.TranslatedWorldOffset, Pos1 + ShaderPrintData.TranslatedWorldOffset, Pos2 + ShaderPrintData.TranslatedWorldOffset, Pos3 + ShaderPrintData.TranslatedWorldOffset, Color); }
void AddFilledQuadTWS(FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { if (Ctx.bIsActive) { AddFilledQuadTWS(Pos0, Pos1, Pos2, Pos3, Color); } }
void AddFilledQuadWS (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { if (Ctx.bIsActive) { AddFilledQuadTWS(Pos0 + ShaderPrintData.TranslatedWorldOffset, Pos1 + ShaderPrintData.TranslatedWorldOffset, Pos2 + ShaderPrintData.TranslatedWorldOffset, Pos3 + ShaderPrintData.TranslatedWorldOffset, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Filled Quad (Screen-Space)
void AddFilledQuadSS(float2 InPosInPixel0, float2 InPosInPixel2, float4 Color)
{
const float2 InPosInPixel1 = float2(InPosInPixel2.x, InPosInPixel0.y);
const float2 InPosInPixel3 = float2(InPosInPixel0.x, InPosInPixel2.y);
const float Depth = 0.5f;
const float3 Pos0 = float3((InPosInPixel0) / float2(ShaderPrintData.Resolution), Depth);
const float3 Pos1 = float3((InPosInPixel1) / float2(ShaderPrintData.Resolution), Depth);
const float3 Pos2 = float3((InPosInPixel2) / float2(ShaderPrintData.Resolution), Depth);
const float3 Pos3 = float3((InPosInPixel3) / float2(ShaderPrintData.Resolution), Depth);
uint Offset = 0;
if (AllocateTriangleElement(2, Offset))
{
FTriangleElement Element;
Element.bIsScreenSpace = true;
Element.Color = Color;
Element.Pos0 = Pos0;
Element.Pos1 = Pos1;
Element.Pos2 = Pos2;
AddTriangleElement(Element, Offset + 0);
Element.Pos0 = Pos0;
Element.Pos1 = Pos2;
Element.Pos2 = Pos3;
AddTriangleElement(Element, Offset + 1);
}
}
void AddFilledQuadSS(FShaderPrintContext Ctx, float2 Pos0, float2 Pos1, float4 Color) { if (Ctx.bIsActive) { AddFilledQuadSS(Pos0, Pos1, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Line-based Primitives (Line, AABB, OBB, Referentials, ...)
struct FLineElement
{
float3 Pos0;
float3 Pos1;
float4 Color0;
float4 Color1;
bool bIsScreenSpace;
};
struct FPackedLineElement
{
uint4 Packed0;
uint4 Packed1;
};
FLineElement UnpackLineElement(FPackedLineElement In)
{
FLineElement Out = (FLineElement)0;
{
Out.Pos0.x = asfloat(In.Packed0.x);
Out.Pos0.y = asfloat(In.Packed0.y);
Out.Pos0.z = asfloat(In.Packed0.z);
Out.Color0 = float4((In.Packed0.w >> 24) & 0xFF, (In.Packed0.w >> 16) & 0xFF, (In.Packed0.w >> 8) & 0xFF, (In.Packed0.w) & 0xFF) / 255.0f;
}
{
Out.Pos1.x = asfloat(In.Packed1.x);
Out.Pos1.y = asfloat(In.Packed1.y);
Out.Pos1.z = asfloat(In.Packed1.z);
Out.Color1 = float4((In.Packed1.w >> 24) & 0xFF, (In.Packed1.w >> 16) & 0xFF, (In.Packed1.w >> 8) & 0xFF, (In.Packed1.w) & 0xFF) / 255.0f;
// The 'space' info is stored into the alpha's LSB
Out.bIsScreenSpace = (In.Packed1.w & 0x1) > 0u;
}
return Out;
}
FPackedLineElement PackLineElement(FLineElement In)
{
uint4 PackedC0 = uint4(255.0f * saturate(In.Color0));
uint4 PackedC1 = uint4(255.0f * saturate(In.Color1));
// Store 'space' info into the alpha's LSB
PackedC1 = PackedC1 & 0xFE;
PackedC1 = PackedC1 | (In.bIsScreenSpace ? 0x1 : 0x0);
FPackedLineElement Out = (FPackedLineElement)0;
Out.Packed0.x = asuint(In.Pos0.x);
Out.Packed0.y = asuint(In.Pos0.y);
Out.Packed0.z = asuint(In.Pos0.z);
Out.Packed0.w = (PackedC0.x << 24) | (PackedC0.y << 16) | (PackedC0.z << 8) | (PackedC0.w);
Out.Packed1.x = asuint(In.Pos1.x);
Out.Packed1.y = asuint(In.Pos1.y);
Out.Packed1.z = asuint(In.Pos1.z);
Out.Packed1.w = (PackedC1.x << 24) | (PackedC1.y << 16) | (PackedC1.z << 8) | (PackedC1.w);
return Out;
}
FLineElement UnpackLineElement(StructuredBuffer<uint> InPrimitiveBuffer, uint InIndex)
{
const uint Index8 = GetPrimitiveLineOffset(InIndex);
FPackedLineElement Out = (FPackedLineElement)0;
Out.Packed0.x = InPrimitiveBuffer[Index8 + 0];
Out.Packed0.y = InPrimitiveBuffer[Index8 + 1];
Out.Packed0.z = InPrimitiveBuffer[Index8 + 2];
Out.Packed0.w = InPrimitiveBuffer[Index8 + 3];
Out.Packed1.x = InPrimitiveBuffer[Index8 + 4];
Out.Packed1.y = InPrimitiveBuffer[Index8 + 5];
Out.Packed1.z = InPrimitiveBuffer[Index8 + 6];
Out.Packed1.w = InPrimitiveBuffer[Index8 + 7];
return UnpackLineElement(Out);
}
bool AllocateLineElement(uint Count, inout uint OutIndex)
{
OutIndex = 0;
if (ShaderPrintData.MaxLineCount == 0)
{
return false;
}
InterlockedAdd(ShaderPrint_RWEntryBuffer[SHADER_PRINT_COUNTER_OFFSET_LINE], Count, OutIndex);
return (OutIndex + Count) < ShaderPrintData.MaxLineCount;
}
void AddLineElement(FLineElement In, uint Index)
{
const uint Index8 = GetPrimitiveLineOffset(Index);
FPackedLineElement Out = PackLineElement(In);
ShaderPrint_RWEntryBuffer[Index8 + 0] = Out.Packed0.x;
ShaderPrint_RWEntryBuffer[Index8 + 1] = Out.Packed0.y;
ShaderPrint_RWEntryBuffer[Index8 + 2] = Out.Packed0.z;
ShaderPrint_RWEntryBuffer[Index8 + 3] = Out.Packed0.w;
ShaderPrint_RWEntryBuffer[Index8 + 4] = Out.Packed1.x;
ShaderPrint_RWEntryBuffer[Index8 + 5] = Out.Packed1.y;
ShaderPrint_RWEntryBuffer[Index8 + 6] = Out.Packed1.z;
ShaderPrint_RWEntryBuffer[Index8 + 7] = Out.Packed1.w;
}
int2 GetCursorPos()
{
return ShaderPrintData.CursorCoord;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Line
void AddLineTWS(float3 Pos0, float3 Pos1, float4 Color0, float4 Color1)
{
uint Offset = 0;
if (AllocateLineElement(1, Offset))
{
FLineElement Element;
Element.Pos0 = Pos0;
Element.Pos1 = Pos1;
Element.Color0 = Color0;
Element.Color1 = Color1;
Element.bIsScreenSpace = false;
AddLineElement(Element, Offset);
}
}
void AddLineTWS(float3 Pos0, float3 Pos1, float4 Color) { AddLineTWS(Pos0, Pos1, Color, Color); }
void AddLineWS (float3 Pos0, float3 Pos1, float4 Color) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color); }
void AddLineWS (float3 Pos0, float3 Pos1, float4 Color0, float4 Color1) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color0, Color1); }
void AddLine (float3 Pos0, float3 Pos1, float4 Color) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color); }
void AddLine (float3 Pos0, float3 Pos1, float4 Color0, float4 Color1) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color0, Color1); }
void AddLineTWS(FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float4 Color0, float4 Color1) { if (Ctx.bIsActive) { AddLineTWS(Pos0, Pos1, Color0, Color1); } }
void AddLineTWS(FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float4 Color) { if (Ctx.bIsActive) { AddLineTWS(Pos0, Pos1, Color, Color); } }
void AddLineWS (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float4 Color) { if (Ctx.bIsActive) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color); } }
void AddLineWS (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float4 Color0, float4 Color1) { if (Ctx.bIsActive) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color0, Color1); } }
void AddLine (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float4 Color) { if (Ctx.bIsActive) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color); } }
void AddLine (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float4 Color0, float4 Color1) { if (Ctx.bIsActive) { AddLineTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Color0, Color1); } }
// Draw 2D line. Input positions are expressed in pixel coordinate
void AddLineSS(float2 InPosInPixel0, float2 InPosInPixel1, float4 Color0, float4 Color1)
{
const float2 Pos0 = float2(InPosInPixel0) / float2(ShaderPrintData.Resolution);
const float2 Pos1 = float2(InPosInPixel1) / float2(ShaderPrintData.Resolution);
uint Offset = 0;
if (AllocateLineElement(1, Offset))
{
FLineElement Element;
Element.Pos0 = float3(Pos0, 0);
Element.Pos1 = float3(Pos1, 0);
Element.Color0 = Color0;
Element.Color1 = Color1;
Element.bIsScreenSpace = true;
AddLineElement(Element, Offset);
}
}
void AddLineSS(float2 Pos0, float2 Pos1, float4 Color) { AddLineSS(Pos0, Pos1, Color, Color); }
void AddLineSS(FShaderPrintContext Ctx, float2 Pos0, float2 Pos1, float4 Color0, float4 Color1) { if (Ctx.bIsActive) { AddLineSS(Pos0, Pos1, Color0, Color1); } }
void AddLineSS(FShaderPrintContext Ctx, float2 Pos0, float2 Pos1, float4 Color) { if (Ctx.bIsActive) { AddLineSS(Pos0, Pos1, Color, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Quad
void AddQuadTWS(float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color)
{
uint Offset = 0;
if (AllocateLineElement(4, Offset))
{
FLineElement Element;
Element.bIsScreenSpace = false;
Element.Color0 = Element.Color1 = Color;
Element.Pos0 = Pos0; Element.Pos1 = Pos1; AddLineElement(Element, Offset + 0);
Element.Pos0 = Pos1; Element.Pos1 = Pos2; AddLineElement(Element, Offset + 1);
Element.Pos0 = Pos2; Element.Pos1 = Pos3; AddLineElement(Element, Offset + 2);
Element.Pos0 = Pos3; Element.Pos1 = Pos0; AddLineElement(Element, Offset + 3);
}
}
void AddQuadWS(float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { AddQuadTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Pos2+ShaderPrintData.TranslatedWorldOffset, Pos3+ShaderPrintData.TranslatedWorldOffset, Color); }
void AddQuad (float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { AddQuadTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Pos2+ShaderPrintData.TranslatedWorldOffset, Pos3+ShaderPrintData.TranslatedWorldOffset, Color); }
void AddQuadTWS(FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { if (Ctx.bIsActive) { AddQuadTWS(Pos0, Pos1, Pos2, Pos3, Color); } }
void AddQuadWS (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { if (Ctx.bIsActive) { AddQuadTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Pos2+ShaderPrintData.TranslatedWorldOffset, Pos3+ShaderPrintData.TranslatedWorldOffset, Color); } }
void AddQuad (FShaderPrintContext Ctx, float3 Pos0, float3 Pos1, float3 Pos2, float3 Pos3, float4 Color) { if (Ctx.bIsActive) { AddQuadTWS(Pos0+ShaderPrintData.TranslatedWorldOffset, Pos1+ShaderPrintData.TranslatedWorldOffset, Pos2+ShaderPrintData.TranslatedWorldOffset, Pos3+ShaderPrintData.TranslatedWorldOffset, Color); } }
// Draw 2D quad line
void AddQuadSS(float2 MinPos, float2 MaxPos, float4 Color)
{
uint Offset = 0;
if (AllocateLineElement(4, Offset))
{
MinPos = float2(MinPos) / float2(ShaderPrintData.Resolution);
MaxPos = float2(MaxPos) / float2(ShaderPrintData.Resolution);
float3 Pos0 = float3(MinPos.x, MinPos.y, 0);
float3 Pos1 = float3(MaxPos.x, MinPos.y, 0);
float3 Pos2 = float3(MaxPos.x, MaxPos.y, 0);
float3 Pos3 = float3(MinPos.x, MaxPos.y, 0);
FLineElement Element;
Element.bIsScreenSpace = true;
Element.Color0 = Element.Color1 = Color;
Element.Pos0 = Pos0; Element.Pos1 = Pos1; AddLineElement(Element, Offset + 0);
Element.Pos0 = Pos1; Element.Pos1 = Pos2; AddLineElement(Element, Offset + 1);
Element.Pos0 = Pos2; Element.Pos1 = Pos3; AddLineElement(Element, Offset + 2);
Element.Pos0 = Pos3; Element.Pos1 = Pos0; AddLineElement(Element, Offset + 3);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// AABB
void AddAABBTWS(float3 Min, float3 Max, float4 Color)
{
uint Offset = 0;
if (AllocateLineElement(12, Offset))
{
float3 P0 = float3(Min.x, Min.y, Min.z);
float3 P1 = float3(Max.x, Min.y, Min.z);
float3 P2 = float3(Max.x, Max.y, Min.z);
float3 P3 = float3(Min.x, Max.y, Min.z);
float3 P4 = float3(Min.x, Min.y, Max.z);
float3 P5 = float3(Max.x, Min.y, Max.z);
float3 P6 = float3(Max.x, Max.y, Max.z);
float3 P7 = float3(Min.x, Max.y, Max.z);
FLineElement Element;
Element.bIsScreenSpace = false;
Element.Color0 = Element.Color1 = Color;
Element.Pos0 = P0; Element.Pos1 = P1; AddLineElement(Element, Offset + 0);
Element.Pos0 = P1; Element.Pos1 = P2; AddLineElement(Element, Offset + 1);
Element.Pos0 = P2; Element.Pos1 = P3; AddLineElement(Element, Offset + 2);
Element.Pos0 = P3; Element.Pos1 = P0; AddLineElement(Element, Offset + 3);
Element.Pos0 = P4; Element.Pos1 = P5; AddLineElement(Element, Offset + 4);
Element.Pos0 = P5; Element.Pos1 = P6; AddLineElement(Element, Offset + 5);
Element.Pos0 = P6; Element.Pos1 = P7; AddLineElement(Element, Offset + 6);
Element.Pos0 = P7; Element.Pos1 = P4; AddLineElement(Element, Offset + 7);
Element.Pos0 = P0; Element.Pos1 = P4; AddLineElement(Element, Offset + 8);
Element.Pos0 = P1; Element.Pos1 = P5; AddLineElement(Element, Offset + 9);
Element.Pos0 = P2; Element.Pos1 = P6; AddLineElement(Element, Offset +10);
Element.Pos0 = P3; Element.Pos1 = P7; AddLineElement(Element, Offset +11);
}
}
void AddAABBWS(float3 Min, float3 Max, float4 Color) { AddAABBTWS(Min + ShaderPrintData.TranslatedWorldOffset, Max + ShaderPrintData.TranslatedWorldOffset, Color); }
void AddAABB (float3 Min, float3 Max, float4 Color) { AddAABBTWS(Min + ShaderPrintData.TranslatedWorldOffset, Max + ShaderPrintData.TranslatedWorldOffset, Color); }
void AddAABBTWS(FShaderPrintContext Ctx, float3 Min, float3 Max, float4 Color) { if (Ctx.bIsActive) { AddAABBTWS(Min, Max, Color); } }
void AddAABBWS (FShaderPrintContext Ctx, float3 Min, float3 Max, float4 Color) { if (Ctx.bIsActive) { AddAABBTWS(Min + ShaderPrintData.TranslatedWorldOffset, Max + ShaderPrintData.TranslatedWorldOffset, Color); } }
void AddAABB (FShaderPrintContext Ctx, float3 Min, float3 Max, float4 Color) { if (Ctx.bIsActive) { AddAABBTWS(Min + ShaderPrintData.TranslatedWorldOffset, Max + ShaderPrintData.TranslatedWorldOffset, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Cross
void AddCrossTWS(float3 Pos, float Size, float4 Color)
{
AddLineTWS(Pos - float3(Size,0,0), Pos + float3(Size,0,0), Color, Color);
AddLineTWS(Pos - float3(0,Size,0), Pos + float3(0,Size,0), Color, Color);
AddLineTWS(Pos - float3(0,0,Size), Pos + float3(0,0,Size), Color, Color);
}
void AddCrossWS(float3 Pos, float Size, float4 Color) { AddCrossTWS(Pos + ShaderPrintData.TranslatedWorldOffset, Size, Color); }
void AddCross (float3 Pos, float Size, float4 Color) { AddCrossTWS(Pos + ShaderPrintData.TranslatedWorldOffset, Size, Color); }
void AddCrossTWS(FShaderPrintContext Ctx, float3 Pos, float Size, float4 Color) { if (Ctx.bIsActive) { AddCrossTWS(Pos, Size, Color); } }
void AddCrossWS (FShaderPrintContext Ctx, float3 Pos, float Size, float4 Color) { if (Ctx.bIsActive) { AddCrossTWS(Pos + ShaderPrintData.TranslatedWorldOffset, Size, Color); } }
void AddCross (FShaderPrintContext Ctx, float3 Pos, float Size, float4 Color) { if (Ctx.bIsActive) { AddCrossTWS(Pos + ShaderPrintData.TranslatedWorldOffset, Size, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Circles
void AddCircleSS(float2 Center, float Radius, float4 Color)
{
const float TStep = 0.05f;
float S, C;
sincos(0.0, S, C);
float2 PrevP = Center + float2(C, S) * Radius;
for (float t = TStep; t <= 1.0; t += TStep)
{
sincos(t * 2 * PI, S, C);
float2 P = Center + float2(C, S) * Radius;
AddLineSS(PrevP, P, Color);
PrevP = P;
}
}
void AddCircleSS(FShaderPrintContext Ctx, float2 Center, float Radius, float4 Color) { if (Ctx.bIsActive) { AddCircleSS(Center, Radius, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Referential
void AddReferentialTWS(float3 Pos, float3 T, float3 B, float3 N, float Scale=1)
{
AddLineTWS(Pos, Pos + normalize(T)*Scale, ColorRed);
AddLineTWS(Pos, Pos + normalize(B)*Scale, ColorGreen);
AddLineTWS(Pos, Pos + normalize(N)*Scale, ColorBlue);
}
void AddReferentialTWS(float3 Pos, float3 TangentZ, float Scale=1)
{
const float Sign = TangentZ.z >= 0 ? 1 : -1;
const float a = -rcp(Sign + TangentZ.z);
const float b = TangentZ.x * TangentZ.y * a;
const float3 TangentX = { 1 + Sign * a * Pow2(TangentZ.x), Sign * b, -Sign * TangentZ.x };
const float3 TangentY = { b, Sign + a * Pow2(TangentZ.y), -TangentZ.y };
AddReferentialTWS(Pos, TangentX, TangentY, TangentZ, Scale);
}
void AddReferentialTWS(float4x4 InM, float Scale = 1)
{
AddReferentialTWS(InM[3].xyz, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale);
}
void AddReferentialWS(float3 Pos, float3x3 InM, float Scale = 1) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); }
void AddReferentialWS(float4x4 InM, float Scale = 1) { AddReferentialTWS(InM[3].xyz + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); }
void AddReferentialWS(float3 Pos, float3 TangentZ, float Scale = 1) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, TangentZ, Scale); }
void AddReferentialWS(float3 Pos, float3 T, float3 B, float3 N, float Scale = 1) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, T, B, N, Scale); }
void AddReferential (float3 Pos, float3x3 InM, float Scale = 1) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); }
void AddReferential (float4x4 InM, float Scale = 1) { AddReferentialTWS(InM[3].xyz + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); }
void AddReferential (float3 Pos, float3 TangentZ, float Scale = 1) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, TangentZ, Scale); }
void AddReferential (float3 Pos, float3 T, float3 B, float3 N, float Scale = 1) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, T, B, N, Scale); }
void AddReferentialTWS(FShaderPrintContext Ctx, float3 Pos, float3 T, float3 B, float3 N, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos, T, B, N, Scale); } }
void AddReferentialTWS(FShaderPrintContext Ctx, float3 Pos, float3 TangentZ, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos, TangentZ, Scale); } }
void AddReferentialTWS(FShaderPrintContext Ctx, float3 Pos, float3x3 InM, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); } }
void AddReferentialTWS(FShaderPrintContext Ctx, float4x4 InM, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(InM[3].xyz, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); } }
void AddReferentialWS (FShaderPrintContext Ctx, float4x4 InM, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(InM[3].xyz + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); } }
void AddReferentialWS (FShaderPrintContext Ctx, float3 Pos, float3x3 InM, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); } }
void AddReferentialWS (FShaderPrintContext Ctx, float3 Pos, float3 TangentZ, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, TangentZ, Scale); } }
void AddReferentialWS (FShaderPrintContext Ctx, float3 Pos, float3 T, float3 B, float3 N, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, T, B, N, Scale); } }
void AddReferential (FShaderPrintContext Ctx, float4x4 InM, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(InM[3].xyz + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); } }
void AddReferential (FShaderPrintContext Ctx, float3 Pos, float3x3 InM, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, InM[0].xyz, InM[1].xyz, InM[2].xyz, Scale); } }
void AddReferential (FShaderPrintContext Ctx, float3 Pos, float3 TangentZ, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, TangentZ, Scale); } }
void AddReferential (FShaderPrintContext Ctx, float3 Pos, float3 T, float3 B, float3 N, float Scale = 1) { if (Ctx.bIsActive) { AddReferentialTWS(Pos + ShaderPrintData.TranslatedWorldOffset, T, B, N, Scale); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// Triangle
void AddLineTriangleTWS(float3 P0, float3 P1, float3 P2, float4 Color)
{
AddLineTWS(P0, P1, Color, Color);
AddLineTWS(P1, P2, Color, Color);
AddLineTWS(P2, P0, Color, Color);
}
void AddLineTriangleWS(float3 P0, float3 P1, float3 P2, float4 Color) { AddLineTriangleTWS(P0 + ShaderPrintData.TranslatedWorldOffset, P1 + ShaderPrintData.TranslatedWorldOffset, P2 + ShaderPrintData.TranslatedWorldOffset, Color); }
void AddLineTriangle (float3 P0, float3 P1, float3 P2, float4 Color) { AddLineTriangleTWS(P0 + ShaderPrintData.TranslatedWorldOffset, P1 + ShaderPrintData.TranslatedWorldOffset, P2 + ShaderPrintData.TranslatedWorldOffset, Color); }
void AddLineTriangleTWS(FShaderPrintContext Ctx, float3 P0, float3 P1, float3 P2, float4 Color) { if (Ctx.bIsActive) { AddLineTriangleTWS(P0, P1, P2, Color); } }
void AddLineTriangleWS (FShaderPrintContext Ctx, float3 P0, float3 P1, float3 P2, float4 Color) { if (Ctx.bIsActive) { AddLineTriangleTWS(P0 + ShaderPrintData.TranslatedWorldOffset, P1 + ShaderPrintData.TranslatedWorldOffset, P2 + ShaderPrintData.TranslatedWorldOffset, Color); } }
void AddLineTriangle (FShaderPrintContext Ctx, float3 P0, float3 P1, float3 P2, float4 Color) { if (Ctx.bIsActive) { AddLineTriangleTWS(P0 + ShaderPrintData.TranslatedWorldOffset, P1 + ShaderPrintData.TranslatedWorldOffset, P2 + ShaderPrintData.TranslatedWorldOffset, Color); } }
///////////////////////////////////////////////////////////////////////////////////////////////////
// OBB
void AddOBBTWS(float3 Min, float3 Max, float4 Color, float4x4 Transform)
{
uint Offset = 0;
if (AllocateLineElement(12, Offset))
{
float3 P0 = mul(float4(Min.x, Min.y, Min.z, 1.0f), Transform).xyz;
float3 P1 = mul(float4(Max.x, Min.y, Min.z, 1.0f), Transform).xyz;
float3 P2 = mul(float4(Max.x, Max.y, Min.z, 1.0f), Transform).xyz;
float3 P3 = mul(float4(Min.x, Max.y, Min.z, 1.0f), Transform).xyz;
float3 P4 = mul(float4(Min.x, Min.y, Max.z, 1.0f), Transform).xyz;
float3 P5 = mul(float4(Max.x, Min.y, Max.z, 1.0f), Transform).xyz;
float3 P6 = mul(float4(Max.x, Max.y, Max.z, 1.0f), Transform).xyz;
float3 P7 = mul(float4(Min.x, Max.y, Max.z, 1.0f), Transform).xyz;
FLineElement Element;
Element.bIsScreenSpace = false;
Element.Color0 = Element.Color1 = Color;
Element.Pos0 = P0; Element.Pos1 = P1; AddLineElement(Element, Offset + 0);
Element.Pos0 = P1; Element.Pos1 = P2; AddLineElement(Element, Offset + 1);
Element.Pos0 = P2; Element.Pos1 = P3; AddLineElement(Element, Offset + 2);
Element.Pos0 = P3; Element.Pos1 = P0; AddLineElement(Element, Offset + 3);
Element.Pos0 = P4; Element.Pos1 = P5; AddLineElement(Element, Offset + 4);
Element.Pos0 = P5; Element.Pos1 = P6; AddLineElement(Element, Offset + 5);
Element.Pos0 = P6; Element.Pos1 = P7; AddLineElement(Element, Offset + 6);
Element.Pos0 = P7; Element.Pos1 = P4; AddLineElement(Element, Offset + 7);
Element.Pos0 = P0; Element.Pos1 = P4; AddLineElement(Element, Offset + 8);
Element.Pos0 = P1; Element.Pos1 = P5; AddLineElement(Element, Offset + 9);
Element.Pos0 = P2; Element.Pos1 = P6; AddLineElement(Element, Offset + 10);
Element.Pos0 = P3; Element.Pos1 = P7; AddLineElement(Element, Offset + 11);
}
}
void AddOBBWS(float3 Min, float3 Max, float4 Color, float4x4 Transform) { Transform[3].xyz += ShaderPrintData.TranslatedWorldOffset; AddOBBTWS(Min, Max, Color, Transform); }
void AddOBB (float3 Min, float3 Max, float4 Color, float4x4 Transform) { Transform[3].xyz += ShaderPrintData.TranslatedWorldOffset; AddOBBTWS(Min, Max, Color, Transform); }
void AddOBBTWS(FShaderPrintContext Ctx, float3 Min, float3 Max, float4 Color, float4x4 Transform) { if (Ctx.bIsActive) { AddOBBTWS(Min, Max, Color, Transform); } }
void AddOBBWS (FShaderPrintContext Ctx, float3 Min, float3 Max, float4 Color, float4x4 Transform) { if (Ctx.bIsActive) { Transform[3].xyz += ShaderPrintData.TranslatedWorldOffset; AddOBBTWS(Min, Max, Color, Transform); } }
void AddOBB (FShaderPrintContext Ctx, float3 Min, float3 Max, float4 Color, float4x4 Transform) { if (Ctx.bIsActive) { Transform[3].xyz += ShaderPrintData.TranslatedWorldOffset; AddOBBTWS(Min, Max, Color, Transform); } }