/* =========================================================================== 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 . =========================================================================== */ // 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 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