cnq3/code/renderer/shaders/common/im3d.hlsli
2024-07-23 18:24:44 +02:00

162 lines
4.7 KiB
HLSL

/*
===========================================================================
Copyright (C) 2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3).
Challenge Quake 3 is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Challenge Quake 3 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
===========================================================================
*/
// Im3d integration
#define kAntialiasing 2.0
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR0;
#if defined(POINTS) || defined(LINES)
float size : SIZE;
#endif
#if defined(POINTS)
float2 texCoords : UV;
#endif
#if defined(LINES)
float edgeDistance : EDGEDISTANCE;
#endif
};
#if VERTEX_SHADER
struct Vertex
{
float3 position;
float size;
uint color;
};
struct Im3dVertexShaderInput
{
matrix viewMatrix;
matrix projectionMatrix;
float2 viewport;
uint vertexOffset;
StructuredBuffer<Vertex> vertexBuffer;
uint vertexId;
};
float4 UnpackIm3dColor(uint c)
{
uint4 u = uint4((c >> 24) & 0xFFu, (c >> 16) & 0xFFu, (c >> 8) & 0xFFu, c & 0xFFu);
float4 r = float4(u) / 255.0;
return r;
}
float2 PositionFromVertexId(uint vertexId)
{
// 0 -> -1, -1
// 1 -> 1, -1
// 2 -> 1, 1
// 3 -> -1, 1
float2 result;
result.x = (2 - vertexId) <= 1 ? 1.0 : -1.0;
result.y = vertexId >= 2 ? 1.0 : -1.0;
return result;
}
VOut VertexShader(Im3dVertexShaderInput input)
{
VOut output;
#if defined(POINTS)
uint pointIndex = input.vertexOffset + (input.vertexId / 4);
Vertex vertex = input.vertexBuffer[NonUniformResourceIndex(pointIndex)];
float outSize = max(vertex.size, kAntialiasing);
float2 scale = outSize.xx / input.viewport;
float2 localPosition = PositionFromVertexId(input.vertexId % 4);
float4 position = mul(input.projectionMatrix, mul(input.viewMatrix, float4(vertex.position, 1)));
position.xy += localPosition * scale * position.w;
output.position = position;
output.color = UnpackIm3dColor(vertex.color);
output.size = outSize;
output.texCoords = localPosition * 0.5 + 0.5;
#endif
#if defined(LINES)
uint localVertexId = input.vertexId % 4;
bool lineStart = localVertexId == 0 || localVertexId == 3;
uint lineId = input.vertexId / 4;
uint vid0 = input.vertexOffset + lineId * 2; // line start, x negative (0 or 3)
uint vid1 = vid0 + 1; // line end, x positive (1 or 2)
uint vid = lineStart ? vid0 : vid1; // data for this vertex
Vertex vertex = input.vertexBuffer[NonUniformResourceIndex(vid)];
Vertex vertex0 = input.vertexBuffer[NonUniformResourceIndex(vid0)];
Vertex vertex1 = input.vertexBuffer[NonUniformResourceIndex(vid1)];
float2 localPosition = PositionFromVertexId(localVertexId);
float4 outColor = UnpackIm3dColor(vertex.color);
float outSize = vertex.size;
outColor.a *= smoothstep(0.0, 1.0, outSize / kAntialiasing);
outSize = max(outSize, kAntialiasing);
float edgeDistance = outSize * localPosition.y;
float4 pos0 = mul(input.projectionMatrix, mul(input.viewMatrix, float4(vertex0.position, 1)));
float4 pos1 = mul(input.projectionMatrix, mul(input.viewMatrix, float4(vertex1.position, 1)));
float2 dir = (pos0.xy / pos0.w) - (pos1.xy / pos1.w);
dir = normalize(float2(dir.x, dir.y * input.viewport.y / input.viewport.x)); // correct for aspect ratio
float2 tng = float2(-dir.y, dir.x) * outSize / input.viewport;
float4 position = lineStart ? pos0 : pos1;
position.xy += tng * localPosition.y * position.w;
output.position = position;
output.color = outColor;
output.size = outSize;
output.edgeDistance = edgeDistance;
#endif
#if defined(TRIANGLES)
Vertex vertex = input.vertexBuffer[NonUniformResourceIndex(input.vertexOffset + input.vertexId)];
output.position = mul(input.projectionMatrix, mul(input.viewMatrix, float4(vertex.position, 1)));
output.color = UnpackIm3dColor(vertex.color);
#endif
return output;
}
#endif
#if PIXEL_SHADER
float4 PixelShader(VOut input)
{
// we scale the color here to counter the post-process gamma/brightness
float4 result = float4(input.color.rgb * 0.5, input.color.a);
#if defined(POINTS)
float d = length(input.texCoords - float2(0.5, 0.5));
d = smoothstep(0.5, 0.5 - (kAntialiasing / input.size), d);
result.a *= d;
#endif
#if defined(LINES)
float d = abs(input.edgeDistance) / input.size;
d = smoothstep(1.0, 1.0 - (kAntialiasing / input.size), d);
result.a *= d;
#endif
return result;
}
#endif