153 lines
4.8 KiB
Plaintext
153 lines
4.8 KiB
Plaintext
static const int kProbeCount = 8;
|
|
static const int kMetadataIndex = 8;
|
|
|
|
float2 probeUvForIndex(int index)
|
|
{
|
|
if (index == 0)
|
|
return float2(0.18, 0.28);
|
|
if (index == 1)
|
|
return float2(0.39, 0.28);
|
|
if (index == 2)
|
|
return float2(0.61, 0.28);
|
|
if (index == 3)
|
|
return float2(0.82, 0.28);
|
|
if (index == 4)
|
|
return float2(0.18, 0.72);
|
|
if (index == 5)
|
|
return float2(0.39, 0.72);
|
|
if (index == 6)
|
|
return float2(0.61, 0.72);
|
|
return float2(0.82, 0.72);
|
|
}
|
|
|
|
float2 cellCenterPixelForIndex(int index)
|
|
{
|
|
return float2(1.0 + float(index) * 3.0, 1.0);
|
|
}
|
|
|
|
float2 cellCenterUvForIndex(ShaderContext context, int index)
|
|
{
|
|
return (cellCenterPixelForIndex(index) + 0.5) / context.outputResolution;
|
|
}
|
|
|
|
bool pixelIsInsideCell(float2 pixelCoord, int index)
|
|
{
|
|
float minX = float(index) * 3.0;
|
|
float maxX = minX + 3.0;
|
|
return pixelCoord.x >= minX && pixelCoord.x < maxX && pixelCoord.y >= 0.0 && pixelCoord.y < 3.0;
|
|
}
|
|
|
|
float4 readStoredCell(ShaderContext context, int index)
|
|
{
|
|
if (context.feedbackAvailable <= 0)
|
|
return float4(0.0, 0.0, 0.0, 0.0);
|
|
return sampleFeedback(cellCenterUvForIndex(context, index));
|
|
}
|
|
|
|
bool shouldRefreshStoredData(ShaderContext context)
|
|
{
|
|
if (context.feedbackAvailable <= 0)
|
|
return true;
|
|
|
|
float4 metadata = readStoredCell(context, kMetadataIndex);
|
|
float previousRefreshBucket = metadata.r;
|
|
float previousTriggerCount = metadata.g;
|
|
float refreshInterval = max(refreshSeconds, 0.001);
|
|
float currentRefreshBucket = floor(context.time / refreshInterval);
|
|
float currentTriggerCount = float(refresh);
|
|
|
|
return currentRefreshBucket > previousRefreshBucket + 0.5 || currentTriggerCount > previousTriggerCount + 0.5;
|
|
}
|
|
|
|
float4 metadataValueForFrame(ShaderContext context, bool refreshNow)
|
|
{
|
|
float refreshInterval = max(refreshSeconds, 0.001);
|
|
float currentRefreshBucket = floor(context.time / refreshInterval);
|
|
float currentTriggerCount = float(refresh);
|
|
|
|
if (!refreshNow && context.feedbackAvailable > 0)
|
|
return readStoredCell(context, kMetadataIndex);
|
|
|
|
return float4(currentRefreshBucket, currentTriggerCount, refreshTime, 1.0);
|
|
}
|
|
|
|
float4 storedProbeValueForFrame(ShaderContext context, int index, bool refreshNow)
|
|
{
|
|
float3 liveColor = sampleLayerInput(probeUvForIndex(index)).rgb;
|
|
if (refreshNow || context.feedbackAvailable <= 0)
|
|
return float4(liveColor, 1.0);
|
|
return readStoredCell(context, index);
|
|
}
|
|
|
|
float4 storeProbeData(ShaderContext context)
|
|
{
|
|
// Reserve nine 3x3 texel cells along the top edge of the feedback surface:
|
|
// eight cells for visible probe colors and one hidden metadata cell that
|
|
// tracks the timed refresh bucket and last trigger count.
|
|
float2 pixelCoord = floor(context.uv * context.outputResolution);
|
|
bool refreshNow = shouldRefreshStoredData(context);
|
|
|
|
for (int index = 0; index < kProbeCount; ++index)
|
|
{
|
|
if (pixelIsInsideCell(pixelCoord, index))
|
|
return storedProbeValueForFrame(context, index, refreshNow);
|
|
}
|
|
|
|
if (pixelIsInsideCell(pixelCoord, kMetadataIndex))
|
|
return metadataValueForFrame(context, refreshNow);
|
|
|
|
return float4(0.0, 0.0, 0.0, 1.0);
|
|
}
|
|
|
|
float rectMask(float2 uv, float2 minUv, float2 maxUv)
|
|
{
|
|
if (uv.x < minUv.x || uv.x > maxUv.x)
|
|
return 0.0;
|
|
if (uv.y < minUv.y || uv.y > maxUv.y)
|
|
return 0.0;
|
|
return 1.0;
|
|
}
|
|
|
|
float borderMask(float2 uv, float2 minUv, float2 maxUv, float thickness)
|
|
{
|
|
float outer = rectMask(uv, minUv, maxUv);
|
|
float inner = rectMask(uv, minUv + thickness, maxUv - thickness);
|
|
return saturate(outer - inner);
|
|
}
|
|
|
|
float4 displayProbeData(ShaderContext context)
|
|
{
|
|
float3 baseColor = sampleLayerInput(context.uv).rgb;
|
|
float3 swatchColor = baseColor;
|
|
float swatchMask = 0.0;
|
|
|
|
float2 panelOrigin = float2(0.03, 0.04);
|
|
float2 gap = float2(swatchSize.x + 0.012, swatchSize.y + 0.012);
|
|
float borderThickness = min(swatchSize.x, swatchSize.y) * 0.08;
|
|
|
|
for (int index = 0; index < kProbeCount; ++index)
|
|
{
|
|
int column = index % 4;
|
|
int row = index / 4;
|
|
float2 swatchMin = panelOrigin + float2(float(column) * gap.x, float(row) * gap.y);
|
|
float2 swatchMax = swatchMin + swatchSize;
|
|
float3 storedColor = sampleVideo(cellCenterUvForIndex(context, index)).rgb;
|
|
float fill = rectMask(context.uv, swatchMin, swatchMax);
|
|
float outline = borderMask(context.uv, swatchMin, swatchMax, borderThickness);
|
|
if (fill > 0.5)
|
|
{
|
|
swatchColor = storedColor;
|
|
swatchMask = 1.0;
|
|
}
|
|
if (outline > 0.5)
|
|
{
|
|
swatchColor = float3(0.0, 0.0, 0.0);
|
|
swatchMask = 1.0;
|
|
}
|
|
}
|
|
|
|
float opacity = saturate(overlayOpacity) * swatchMask;
|
|
float3 displayColor = lerp(baseColor, swatchColor, opacity);
|
|
return float4(saturate(displayColor), 1.0);
|
|
}
|