Added screensapce decal system and stamp placement system in Radiant.

This commit is contained in:
Justin Marshall
2026-05-22 07:54:36 -07:00
parent e8ea0567b0
commit f2e8b0b45e
13 changed files with 962 additions and 32 deletions
+37 -7
View File
@@ -9,7 +9,7 @@
1186 constants
133 enums
579 classes/structs/unions
581 classes/structs/unions
38 templates
7 max inheritance level for 'idAI_Vagary'
@@ -4077,6 +4077,21 @@ static classVariableInfo_t glRaytracingLightingPassDesc_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t glScreenSpaceDecal_t_typeInfo[] = {
{ "glRaytracingVec3_t", "origin", (intptr_t)(&((glScreenSpaceDecal_t *)0)->origin), sizeof( ((glScreenSpaceDecal_t *)0)->origin ) },
{ "float", "halfSize", (intptr_t)(&((glScreenSpaceDecal_t *)0)->halfSize), sizeof( ((glScreenSpaceDecal_t *)0)->halfSize ) },
{ "glRaytracingVec3_t", "normal", (intptr_t)(&((glScreenSpaceDecal_t *)0)->normal), sizeof( ((glScreenSpaceDecal_t *)0)->normal ) },
{ "float", "depth", (intptr_t)(&((glScreenSpaceDecal_t *)0)->depth), sizeof( ((glScreenSpaceDecal_t *)0)->depth ) },
{ "glRaytracingVec3_t", "axisU", (intptr_t)(&((glScreenSpaceDecal_t *)0)->axisU), sizeof( ((glScreenSpaceDecal_t *)0)->axisU ) },
{ "float", "opacity", (intptr_t)(&((glScreenSpaceDecal_t *)0)->opacity), sizeof( ((glScreenSpaceDecal_t *)0)->opacity ) },
{ "glRaytracingVec3_t", "axisV", (intptr_t)(&((glScreenSpaceDecal_t *)0)->axisV), sizeof( ((glScreenSpaceDecal_t *)0)->axisV ) },
{ "float", "pad0", (intptr_t)(&((glScreenSpaceDecal_t *)0)->pad0), sizeof( ((glScreenSpaceDecal_t *)0)->pad0 ) },
{ "float[4]", "color", (intptr_t)(&((glScreenSpaceDecal_t *)0)->color), sizeof( ((glScreenSpaceDecal_t *)0)->color ) },
{ "uint32_t", "textureId", (intptr_t)(&((glScreenSpaceDecal_t *)0)->textureId), sizeof( ((glScreenSpaceDecal_t *)0)->textureId ) },
{ "float[3]", "pad1", (intptr_t)(&((glScreenSpaceDecal_t *)0)->pad1), sizeof( ((glScreenSpaceDecal_t *)0)->pad1 ) },
{ NULL, 0 }
};
static classVariableInfo_t QD3D12NeuralPOMImageRGBA8_typeInfo[] = {
{ "uint32_t", "width", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->width), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->width ) },
{ "uint32_t", "height", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->height), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->height ) },
@@ -4538,6 +4553,19 @@ static classVariableInfo_t modelTrace_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t renderWorldDecal_t_typeInfo[] = {
{ "idStr", "material", (intptr_t)(&((renderWorldDecal_t *)0)->material), sizeof( ((renderWorldDecal_t *)0)->material ) },
{ "idVec3", "origin", (intptr_t)(&((renderWorldDecal_t *)0)->origin), sizeof( ((renderWorldDecal_t *)0)->origin ) },
{ "idVec3", "normal", (intptr_t)(&((renderWorldDecal_t *)0)->normal), sizeof( ((renderWorldDecal_t *)0)->normal ) },
{ "idVec3", "axisU", (intptr_t)(&((renderWorldDecal_t *)0)->axisU), sizeof( ((renderWorldDecal_t *)0)->axisU ) },
{ "idVec3", "axisV", (intptr_t)(&((renderWorldDecal_t *)0)->axisV), sizeof( ((renderWorldDecal_t *)0)->axisV ) },
{ "float", "size", (intptr_t)(&((renderWorldDecal_t *)0)->size), sizeof( ((renderWorldDecal_t *)0)->size ) },
{ "float", "depth", (intptr_t)(&((renderWorldDecal_t *)0)->depth), sizeof( ((renderWorldDecal_t *)0)->depth ) },
{ "float", "opacity", (intptr_t)(&((renderWorldDecal_t *)0)->opacity), sizeof( ((renderWorldDecal_t *)0)->opacity ) },
{ "idVec4", "color", (intptr_t)(&((renderWorldDecal_t *)0)->color), sizeof( ((renderWorldDecal_t *)0)->color ) },
{ NULL, 0 }
};
static classVariableInfo_t idRenderWorld_typeInfo[] = {
{ NULL, 0 }
};
@@ -5168,11 +5196,11 @@ static classVariableInfo_t frameLookup_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t class_283_class_283_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_283::class_283 *)0)->soundShader), sizeof( ((class_283::class_283 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_283::class_283 *)0)->function), sizeof( ((class_283::class_283 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_283::class_283 *)0)->skin), sizeof( ((class_283::class_283 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_283::class_283 *)0)->index), sizeof( ((class_283::class_283 *)0)->index ) },
static classVariableInfo_t class_285_class_285_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_285::class_285 *)0)->soundShader), sizeof( ((class_285::class_285 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_285::class_285 *)0)->function), sizeof( ((class_285::class_285 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_285::class_285 *)0)->skin), sizeof( ((class_285::class_285 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_285::class_285 *)0)->index), sizeof( ((class_285::class_285 *)0)->index ) },
{ NULL, 0 }
};
@@ -8709,6 +8737,7 @@ static classTypeInfo_t classTypeInfo[] = {
// { "glRaytracingLight_s::class_173", "", sizeof(glRaytracingLight_s::class_173), glRaytracingLight_s_class_173_typeInfo },
{ "glRaytracingLight_t", "", sizeof(glRaytracingLight_t), glRaytracingLight_t_typeInfo },
{ "glRaytracingLightingPassDesc_t", "", sizeof(glRaytracingLightingPassDesc_t), glRaytracingLightingPassDesc_t_typeInfo },
{ "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo },
{ "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo },
{ "QD3D12NeuralPOMTrainDesc", "", sizeof(QD3D12NeuralPOMTrainDesc), QD3D12NeuralPOMTrainDesc_typeInfo },
{ "QD3D12NeuralPOMTrainStats", "", sizeof(QD3D12NeuralPOMTrainStats), QD3D12NeuralPOMTrainStats_typeInfo },
@@ -8743,6 +8772,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "exitPortal_t", "", sizeof(exitPortal_t), exitPortal_t_typeInfo },
{ "guiPoint_t", "", sizeof(guiPoint_t), guiPoint_t_typeInfo },
{ "modelTrace_t", "", sizeof(modelTrace_t), modelTrace_t_typeInfo },
{ "renderWorldDecal_t", "", sizeof(renderWorldDecal_t), renderWorldDecal_t_typeInfo },
{ "idRenderWorld", "", sizeof(idRenderWorld), idRenderWorld_typeInfo },
{ "idDeviceContext", "", sizeof(idDeviceContext), idDeviceContext_typeInfo },
{ "jointInfo_t", "", sizeof(jointInfo_t), jointInfo_t_typeInfo },
@@ -8816,7 +8846,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo },
{ "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo },
{ "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo },
// { "class_283::class_283", "", sizeof(class_283::class_283), class_283_class_283_typeInfo },
// { "class_285::class_285", "", sizeof(class_285::class_285), class_285_class_285_typeInfo },
{ "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo },
{ "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo },
{ "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo },
+5 -3
View File
@@ -2461,6 +2461,7 @@ struct glRaytracingLightingConstants_t
float denoisePhiNormal;
float denoisePhiPosition;
float bumpStrength;
};
struct glRaytracingMeshMetadata_t
@@ -2560,7 +2561,6 @@ struct glRaytracingLightingState_t
static glRaytracingLightingState_t g_glRaytracingLighting;
static const DXGI_FORMAT GL_RAYTRACING_DENOISE_FORMAT = DXGI_FORMAT_R16G16B16A16_FLOAT;
enum glRaytracingLightingDescriptorIndex_t
{
GLR_DESC_LIGHTS_SRV = 0,
@@ -3101,6 +3101,8 @@ float3 Doom3SafeNormalizeOr(float3 v, float3 fallbackDir)
return (lenSq > 1e-8) ? (v * rsqrt(lenSq)) : fallbackDir;
}
)"
R"(
float Doom3QuadraticFalloffImage(float texCoord)
{
// Math version of Doom 3 BFG's built-in _quadratic lookup table.
@@ -3122,7 +3124,8 @@ float Doom3QuadraticFalloffImage(float texCoord)
d = saturate(d);
return d * d;
}
)"
R"(
float Doom3QuadraticCentered(float centeredCoord)
{
// centeredCoord is -1 at one side of the light volume, 0 at the light center,
@@ -7220,7 +7223,6 @@ void glRaytracingLightingSetShadowBias(float bias)
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
+253 -3
View File
@@ -466,10 +466,11 @@ static const UINT QD3D12_UploadBufferSize = 128 * 1024 * 1024;
// MSAA has been removed from the G-buffer path. Temporal AA now owns edge cleanup
// after lighting, so all scene/deferred render targets remain single-sample.
static const UINT QD3D12_RequestedGBufferSampleCount = 1;
static constexpr UINT QD3D12_PostSrvCount = 11;
static constexpr UINT QD3D12_PostSrvCount = 14;
static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount;
static constexpr UINT QD3D12_PostConstantDwords = 24;
static constexpr UINT QD3D12_ToneMapTileDim = 64;
static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64;
enum QD3D12RTVSlotGroup
{
@@ -1517,6 +1518,13 @@ struct GLState
uint32_t pathTracingSamplesPerPixel = 1;
uint32_t pathTracingFallbackSamplesPerPixel = 2;
uint32_t pathTracingMaxBounces = 2;
glScreenSpaceDecal_t screenSpaceDecals[QD3D12_MaxScreenSpaceDecals] = {};
uint32_t screenSpaceDecalCount = 0;
ComPtr<ID3D12Resource> screenSpaceDecalBuffer;
void* screenSpaceDecalBufferMapped = nullptr;
UINT screenSpaceDecalSrvIndex = UINT_MAX;
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceDecalSrvCpu{};
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceDecalSrvGpu{};
float jitterX = 0.0f;
float jitterY = 0.0f;
@@ -1696,6 +1704,7 @@ struct GLState
ComPtr<ID3D12PipelineState> postDepthCopyPSO;
ComPtr<ID3D12PipelineState> postDepthResolveMsaaPSO;
ComPtr<ID3D12PipelineState> postGBufferPointResolveMsaaPSO;
ComPtr<ID3D12PipelineState> postScreenDecalPSO;
ComPtr<ID3DBlob> vsMainBlob;
ComPtr<ID3DBlob> hsMainBlob;
@@ -1717,6 +1726,7 @@ struct GLState
ComPtr<ID3DBlob> postPsDepthCopyBlob;
ComPtr<ID3DBlob> postPsDepthResolveMsaaBlob;
ComPtr<ID3DBlob> postPsGBufferPointResolveMsaaBlob;
ComPtr<ID3DBlob> postPsScreenDecalBlob;
TextureResource whiteTexture;
@@ -4381,8 +4391,27 @@ Texture2D gTaaHistory : register(t7);
Texture2D gTaaVelocity : register(t8);
Texture2D<float4> gFogPosition : register(t9);
Texture2D<float> gFogDepth : register(t10);
Texture2D<float4> gScreenDecalNormal : register(t11);
Texture2D<float4> gScreenDecalPosition : register(t12);
SamplerState gSamp0 : register(s0);
struct ScreenSpaceDecal
{
float3 origin;
float halfSize;
float3 normal;
float depth;
float3 axisU;
float opacity;
float3 axisV;
float pad0;
float4 color;
uint textureId;
float3 pad1;
};
StructuredBuffer<ScreenSpaceDecal> gScreenDecals : register(t13);
cbuffer PostCB : register(b0)
{
// gPostParams0: x = sharpen strength, y = history weight, z = TAA reset flag.
@@ -4400,6 +4429,7 @@ cbuffer PostCB : register(b0)
#define gPostSharpness gPostParams0.x
#define gTaaHistoryWeight gPostParams0.y
#define gTaaReset gPostParams0.z
#define gScreenDecalIndex gPostParams0.w
#define gToneMapExposure gPostParams1.x
#define gToneMapWhiteScale gPostParams1.y
#define gToneMapBrightness gPostParams1.z
@@ -4409,6 +4439,7 @@ cbuffer PostCB : register(b0)
#define gPostFogStart gPostParams2.w
#define gPostFogEnd gPostParams3.x
#define gPostFogCameraValid gPostParams3.y
#define gScreenDecalCount gPostFogCameraWorldPos.w
#define QD3D12_TONEMAP_TILE_DIM 64u
struct VSOut
@@ -4470,6 +4501,53 @@ float4 QD3D12_ApplyPostFog(float4 color, float2 uv)
return color;
}
float3 QD3D12_SafeNormalizeOr(float3 v, float3 fallbackDir)
{
float lenSq = dot(v, v);
return (lenSq > 1e-8) ? (v * rsqrt(lenSq)) : fallbackDir;
}
float4 PSScreenDecals(VSOut i) : SV_Target0
{
uint2 pixel = uint2(i.pos.xy);
float3 worldPos = gScreenDecalPosition.Load(int3(pixel, 0)).xyz;
float3 normal = QD3D12_SafeNormalizeOr(gScreenDecalNormal.Load(int3(pixel, 0)).xyz, float3(0.0, 0.0, 1.0));
float3 geometricNormal = QD3D12_SafeNormalizeOr(cross(ddx(worldPos), ddy(worldPos)), normal);
float3 decalColor = 0.0;
float decalAlpha = 0.0;
uint decalIndex = (uint)gScreenDecalIndex;
if (decalIndex >= min((uint)gScreenDecalCount, 64u))
return float4(0.0, 0.0, 0.0, 0.0);
ScreenSpaceDecal d = gScreenDecals[decalIndex];
float3 decalN = QD3D12_SafeNormalizeOr(d.normal, normal);
float facing = saturate(abs(dot(geometricNormal, decalN)) * 4.0);
if (facing <= 0.0)
return float4(0.0, 0.0, 0.0, 0.0);
float3 rel = worldPos - d.origin;
float decalDepth = max(d.depth, 1.0e-3);
float depthDistance = abs(dot(rel, decalN));
float depthFade = 1.0 - smoothstep(decalDepth, decalDepth + max(decalDepth * 0.25, 1.0), depthDistance);
if (depthFade <= 0.0)
return float4(0.0, 0.0, 0.0, 0.0);
float3 axisU = QD3D12_SafeNormalizeOr(d.axisU, float3(1.0, 0.0, 0.0));
float3 axisV = QD3D12_SafeNormalizeOr(d.axisV, cross(decalN, axisU));
float2 uv = float2(dot(rel, axisU), dot(rel, axisV)) / max(d.halfSize, 1.0e-3);
if (abs(uv.x) >= 1.0 || abs(uv.y) >= 1.0)
return float4(0.0, 0.0, 0.0, 0.0);
float2 texUv = float2(uv.x * 0.5 + 0.5, -uv.y * 0.5 + 0.5);
float4 texel = gTex0.Sample(gSamp0, texUv);
float edge = smoothstep(1.0, 0.75, max(abs(uv.x), abs(uv.y)));
float mask = saturate(d.opacity) * facing * depthFade * edge * saturate(d.color.a) * saturate(texel.a);
decalColor = texel.rgb * saturate(d.color.rgb);
decalAlpha = mask;
return float4(decalColor, decalAlpha);
}
float4 PSCopy(VSOut i) : SV_Target0
{
return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv);
@@ -4773,7 +4851,8 @@ struct PSGBufferPointResolveOut
float4 emissive : SV_Target3;
float4 specular : SV_Target4;
};
)HLSL"
R"HLSL(
PSGBufferPointResolveOut PSGBufferPointResolveMS(VSOut i)
{
uint srcW, srcH, sampleCount;
@@ -7617,7 +7696,9 @@ static void QD3D12_SetPostConstants(
float toneMapExposure = 1.0f,
float toneMapWhiteScale = 1.0f,
float toneMapBrightness = 1.0f,
bool applySceneFog = false)
bool applySceneFog = false,
float screenDecalCount = 0.0f,
float screenDecalIndex = 0.0f)
{
if (!cl)
return;
@@ -7626,6 +7707,7 @@ static void QD3D12_SetPostConstants(
constants[0] = sharpness;
constants[1] = taaHistoryWeight;
constants[2] = taaReset;
constants[3] = screenDecalIndex;
constants[4] = toneMapExposure;
constants[5] = toneMapWhiteScale;
constants[6] = toneMapBrightness;
@@ -7645,6 +7727,7 @@ static void QD3D12_SetPostConstants(
constants[21] = g_gl.sceneFogCameraWorldPos[1];
constants[22] = g_gl.sceneFogCameraWorldPos[2];
}
constants[23] = screenDecalCount;
cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0);
}
@@ -7661,6 +7744,77 @@ static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Win
cl->SetGraphicsRootDescriptorTable(10, w.depthSrvGpu);
}
static bool QD3D12_EnsureScreenSpaceDecalBuffer()
{
if (!g_gl.device || !g_gl.srvHeap)
return false;
const UINT64 bufferSize = sizeof(glScreenSpaceDecal_t) * QD3D12_MaxScreenSpaceDecals;
if (!g_gl.screenSpaceDecalBuffer)
{
D3D12_HEAP_PROPERTIES hp{};
hp.Type = D3D12_HEAP_TYPE_UPLOAD;
hp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
hp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
hp.CreationNodeMask = 1;
hp.VisibleNodeMask = 1;
D3D12_RESOURCE_DESC rd{};
rd.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
rd.Alignment = 0;
rd.Width = bufferSize;
rd.Height = 1;
rd.DepthOrArraySize = 1;
rd.MipLevels = 1;
rd.Format = DXGI_FORMAT_UNKNOWN;
rd.SampleDesc.Count = 1;
rd.SampleDesc.Quality = 0;
rd.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
rd.Flags = D3D12_RESOURCE_FLAG_NONE;
QD3D12_CHECK(g_gl.device->CreateCommittedResource(
&hp,
D3D12_HEAP_FLAG_NONE,
&rd,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&g_gl.screenSpaceDecalBuffer)));
QD3D12_CHECK(g_gl.screenSpaceDecalBuffer->Map(0, nullptr, &g_gl.screenSpaceDecalBufferMapped));
}
if (g_gl.screenSpaceDecalSrvIndex == UINT_MAX)
{
g_gl.screenSpaceDecalSrvIndex = g_gl.nextSrvIndex++;
g_gl.screenSpaceDecalSrvCpu = QD3D12_SrvCpu(g_gl.screenSpaceDecalSrvIndex);
g_gl.screenSpaceDecalSrvGpu = QD3D12_SrvGpu(g_gl.screenSpaceDecalSrvIndex);
D3D12_SHADER_RESOURCE_VIEW_DESC sd{};
sd.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
sd.Format = DXGI_FORMAT_UNKNOWN;
sd.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
sd.Buffer.FirstElement = 0;
sd.Buffer.NumElements = QD3D12_MaxScreenSpaceDecals;
sd.Buffer.StructureByteStride = sizeof(glScreenSpaceDecal_t);
sd.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
g_gl.device->CreateShaderResourceView(g_gl.screenSpaceDecalBuffer.Get(), &sd, g_gl.screenSpaceDecalSrvCpu);
}
if (g_gl.screenSpaceDecalBufferMapped)
{
memset(g_gl.screenSpaceDecalBufferMapped, 0, bufferSize);
if (g_gl.screenSpaceDecalCount > 0)
{
memcpy(
g_gl.screenSpaceDecalBufferMapped,
g_gl.screenSpaceDecals,
sizeof(glScreenSpaceDecal_t) * g_gl.screenSpaceDecalCount);
}
}
return true;
}
static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl,
ID3D12PipelineState* pso,
D3D12_GPU_DESCRIPTOR_HANDLE inputSrv,
@@ -7843,6 +7997,91 @@ static void QD3D12_CompositeEmissiveIntoSceneColor(QD3D12Window& w)
scissor);
}
void APIENTRY glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal_t* decals, uint32_t decalCount)
{
const uint32_t count = std::min<uint32_t>(decalCount, QD3D12_MaxScreenSpaceDecals);
g_gl.screenSpaceDecalCount = count;
memset(g_gl.screenSpaceDecals, 0, sizeof(g_gl.screenSpaceDecals));
if (decals && count > 0)
{
memcpy(g_gl.screenSpaceDecals, decals, sizeof(glScreenSpaceDecal_t) * count);
}
}
void APIENTRY glDrawScreenSpaceDecalsQD3D12(void)
{
if (g_gl.screenSpaceDecalCount == 0)
return;
QD3D12Window* window = g_currentWindow;
if (!window || !g_gl.device || !g_gl.cmdList || !g_gl.postScreenDecalPSO)
return;
if (!window->sceneColorBuffers[window->frameIndex] || !window->normalBuffers[window->frameIndex] || !window->positionBuffers[window->frameIndex])
return;
if (!QD3D12_EnsureScreenSpaceDecalBuffer())
return;
QD3D12_EnsureFrameOpen();
QD3D12_FlushQueuedBatches();
QD3D12_ResolveGBufferForCurrentFrame(*window);
const UINT frame = window->frameIndex;
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
QD3D12_TransitionResource(cl, window->sceneColorBuffers[frame].Get(), window->sceneColorState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->normalBuffers[frame].Get(), window->normalBufferState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, window->positionBuffers[frame].Get(), window->positionBufferState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
D3D12_VIEWPORT viewport{};
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = (float)window->renderWidth;
viewport.Height = (float)window->renderHeight;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
D3D12_RECT scissor{};
scissor.left = 0;
scissor.top = 0;
scissor.right = (LONG)window->renderWidth;
scissor.bottom = (LONG)window->renderHeight;
ID3D12DescriptorHeap* heaps[] = { g_gl.srvHeap.Get() };
cl->SetDescriptorHeaps(_countof(heaps), heaps);
cl->SetGraphicsRootSignature(g_gl.postRootSig.Get());
QD3D12_SetPostConstants(cl, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, false, (float)g_gl.screenSpaceDecalCount);
cl->SetPipelineState(g_gl.postScreenDecalPSO.Get());
D3D12_CPU_DESCRIPTOR_HANDLE sceneColorRtv = CurrentResolvedSceneColorRTV();
cl->OMSetRenderTargets(1, &sceneColorRtv, FALSE, nullptr);
cl->RSSetViewports(1, &viewport);
cl->RSSetScissorRects(1, &scissor);
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
for (uint32_t decalIndex = 0; decalIndex < g_gl.screenSpaceDecalCount; ++decalIndex)
{
D3D12_GPU_DESCRIPTOR_HANDLE decalTextureSrv = g_gl.whiteTexture.srvGpu;
const glScreenSpaceDecal_t& decal = g_gl.screenSpaceDecals[decalIndex];
TextureResource* decalTexture = decal.textureId ? QD3D12_FindTextureResource(decal.textureId) : nullptr;
if (decalTexture)
{
EnsureTextureResource(*decalTexture);
if (decalTexture->texture && !decalTexture->gpuValid)
{
UploadTexture(*decalTexture);
}
if (decalTexture->texture && decalTexture->srvIndex != UINT_MAX)
{
decalTextureSrv = decalTexture->srvGpu;
}
}
QD3D12_SetPostConstants(cl, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, false, (float)g_gl.screenSpaceDecalCount, (float)decalIndex);
cl->SetGraphicsRootDescriptorTable(0, decalTextureSrv);
cl->SetGraphicsRootDescriptorTable(11, window->normalSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(12, window->positionSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(13, g_gl.screenSpaceDecalSrvGpu);
cl->DrawInstanced(3, 1, 0, 0);
}
}
static ID3D12Resource* QD3D12_PrepareStreamlineOutputForWrite(QD3D12Window& w)
{
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
@@ -9338,6 +9577,7 @@ static void QD3D12_CompileShaders()
g_gl.postPsDepthCopyBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSDepthCopy", "ps_6_0");
g_gl.postPsDepthResolveMsaaBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSDepthResolveMS", "ps_6_0");
g_gl.postPsGBufferPointResolveMsaaBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSGBufferPointResolveMS", "ps_6_0");
g_gl.postPsScreenDecalBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenDecals", "ps_6_0");
}
static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayout[] =
@@ -9547,6 +9787,14 @@ static void QD3D12_CreatePSOs()
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postAdditivePSO)));
d.PS = { g_gl.postPsScreenDecalBlob->GetBufferPointer(), g_gl.postPsScreenDecalBlob->GetBufferSize() };
d.BlendState.RenderTarget[0].BlendEnable = TRUE;
d.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
d.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
d.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postScreenDecalPSO)));
D3D12_GRAPHICS_PIPELINE_STATE_DESC depthDesc{};
depthDesc.pRootSignature = g_gl.postRootSig.Get();
depthDesc.VS = { g_gl.postVsBlob->GetBufferPointer(), g_gl.postVsBlob->GetBufferSize() };
@@ -16328,6 +16576,8 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "glRaytracingMaterialFlagQD3D12", (PROC)glRaytracingMaterialFlagQD3D12 },
{ "glResolveGBufferQD3D12", (PROC)glResolveGBufferQD3D12 },
{ "QD3D12_ResolveGBufferNow", (PROC)QD3D12_ResolveGBufferNow },
{ "glSetScreenSpaceDecalsQD3D12",(PROC)glSetScreenSpaceDecalsQD3D12 },
{ "glDrawScreenSpaceDecalsQD3D12",(PROC)glDrawScreenSpaceDecalsQD3D12 },
{ "QD3D12_SetUpscalerBackend", (PROC)QD3D12_SetUpscalerBackend },
{ "QD3D12_SetUpscalerQuality", (PROC)QD3D12_SetUpscalerQuality },
{ "QD3D12_SetUpscalerSharpness", (PROC)QD3D12_SetUpscalerSharpness },
+17
View File
@@ -1728,6 +1728,21 @@ typedef struct glRaytracingLightingPassDesc_s
uint32_t height;
} glRaytracingLightingPassDesc_t;
typedef struct glScreenSpaceDecal_s
{
glRaytracingVec3_t origin;
float halfSize;
glRaytracingVec3_t normal;
float depth;
glRaytracingVec3_t axisU;
float opacity;
glRaytracingVec3_t axisV;
float pad0;
float color[4];
uint32_t textureId;
float pad1[3];
} glScreenSpaceDecal_t;
int glRaytracingInit(void);
void glRaytracingShutdown(void);
void glRaytracingClear(void);
@@ -1821,6 +1836,8 @@ glRaytracingLight_t glRaytracingLightingMakeRectLight(
uint32_t glRaytracingLightingGetLightCount(void);
void glLightScene(glRaytracingSceneHandle_t sceneHandle);
void glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal_t* decals, uint32_t decalCount);
void glDrawScreenSpaceDecalsQD3D12(void);
ID3D12Device* QD3D12_GetDevice(void);
ID3D12CommandQueue* QD3D12_GetQueue(void);
+4
View File
@@ -491,6 +491,7 @@ idRenderWorldLocal::ProjectDecalOntoWorld
================
*/
void idRenderWorldLocal::ProjectDecalOntoWorld( const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
#if 0
int i, areas[10], numAreas;
const areaReference_t *ref;
const portalArea_t *area;
@@ -542,6 +543,7 @@ void idRenderWorldLocal::ProjectDecalOntoWorld( const idFixedWinding &winding, c
def->decals->CreateDecal( model, localInfo );
}
}
#endif
}
/*
@@ -550,6 +552,7 @@ idRenderWorldLocal::ProjectDecal
====================
*/
void idRenderWorldLocal::ProjectDecal( qhandle_t entityHandle, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
#if 0
decalProjectionInfo_t info, localInfo;
if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
@@ -588,6 +591,7 @@ void idRenderWorldLocal::ProjectDecal( qhandle_t entityHandle, const idFixedWind
def->decals = idRenderModelDecal::Alloc();
}
def->decals->CreateDecal( model, localInfo );
#endif
}
/*
+20
View File
@@ -579,6 +579,18 @@ typedef struct modelTrace_s {
#endif
} modelTrace_t;
typedef struct renderWorldDecal_s {
idStr material;
idVec3 origin;
idVec3 normal;
idVec3 axisU;
idVec3 axisV;
float size;
float depth;
float opacity;
idVec4 color;
} renderWorldDecal_t;
#ifdef QUAKE4
// RAVEN BEGIN
@@ -817,6 +829,14 @@ public:
// Traces vs the world model bsp tree.
virtual bool FastWorldTrace(modelTrace_t& trace, const idVec3& start, const idVec3& end) const = 0;
// Screen-space world decals consumed by the path tracer.
virtual void ClearWorldDecals() = 0;
virtual int AddWorldDecal(const renderWorldDecal_t& decal) = 0;
virtual void RemoveWorldDecal(int decalIndex) = 0;
virtual int NumWorldDecals() const = 0;
virtual const renderWorldDecal_t* GetWorldDecal(int decalIndex) const = 0;
virtual void SubmitWorldDecalsToScreenSpace() const = 0;
//-------------- Demo Control -----------------
// Writes a loadmap command to the demo, and clears archive counters.
+187
View File
@@ -96,6 +96,7 @@ void idRenderWorldLocal::FreeWorld() {
delete localModels[i];
}
localModels.Clear();
worldDecals.Clear();
areaReferenceAllocator.Shutdown();
//interactionAllocator.Shutdown();
@@ -104,6 +105,190 @@ void idRenderWorldLocal::FreeWorld() {
mapName = "<FREED>";
}
static void R_NormalizeDecalBasis(renderWorldDecal_t& decal) {
if (decal.normal.LengthSqr() < 0.0001f) {
decal.normal.Set(0.0f, 0.0f, 1.0f);
}
decal.normal.Normalize();
decal.axisU -= decal.normal * (decal.axisU * decal.normal);
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(idVec3(0.0f, 0.0f, 1.0f));
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(idVec3(0.0f, 1.0f, 0.0f));
}
}
decal.axisU.Normalize();
decal.axisV = decal.normal.Cross(decal.axisU);
decal.axisV.Normalize();
if (decal.size <= 0.0f) {
decal.size = 64.0f;
}
if (decal.depth <= 0.0f) {
decal.depth = 8.0f;
}
if (decal.opacity <= 0.0f) {
decal.opacity = 1.0f;
}
}
void idRenderWorldLocal::ClearWorldDecals() {
worldDecals.Clear();
}
int idRenderWorldLocal::AddWorldDecal(const renderWorldDecal_t& inDecal) {
renderWorldDecal_t decal = inDecal;
R_NormalizeDecalBasis(decal);
return worldDecals.Append(decal);
}
void idRenderWorldLocal::RemoveWorldDecal(int decalIndex) {
if (decalIndex >= 0 && decalIndex < worldDecals.Num()) {
worldDecals.RemoveIndex(decalIndex);
}
}
int idRenderWorldLocal::NumWorldDecals() const {
return worldDecals.Num();
}
const renderWorldDecal_t* idRenderWorldLocal::GetWorldDecal(int decalIndex) const {
if (decalIndex < 0 || decalIndex >= worldDecals.Num()) {
return NULL;
}
return &worldDecals[decalIndex];
}
void idRenderWorldLocal::SubmitWorldDecalsToScreenSpace() const {
glScreenSpaceDecal_t gpuDecals[64];
const int count = min(worldDecals.Num(), 64);
for (int i = 0; i < count; ++i) {
const renderWorldDecal_t& src = worldDecals[i];
glScreenSpaceDecal_t& dst = gpuDecals[i];
memset(&dst, 0, sizeof(dst));
dst.origin.x = src.origin.x;
dst.origin.y = src.origin.y;
dst.origin.z = src.origin.z;
dst.normal.x = src.normal.x;
dst.normal.y = src.normal.y;
dst.normal.z = src.normal.z;
dst.axisU.x = src.axisU.x;
dst.axisU.y = src.axisU.y;
dst.axisU.z = src.axisU.z;
dst.axisV.x = src.axisV.x;
dst.axisV.y = src.axisV.y;
dst.axisV.z = src.axisV.z;
dst.halfSize = src.size * 0.5f;
dst.depth = src.depth;
dst.opacity = src.opacity;
dst.color[0] = src.color.x;
dst.color[1] = src.color.y;
dst.color[2] = src.color.z;
dst.color[3] = src.color.w;
dst.textureId = 0;
const idMaterial* mat = declManager->FindMaterial(src.material.c_str());
idImage* image = mat ? mat->GetEditorImage() : NULL;
#ifndef QUAKE4
if (mat && src.color.x == 1.0f && src.color.y == 1.0f && src.color.z == 1.0f && src.color.w == 1.0f) {
decalInfo_t decalInfo = mat->GetDecalInfo();
dst.color[0] *= decalInfo.start[0];
dst.color[1] *= decalInfo.start[1];
dst.color[2] *= decalInfo.start[2];
dst.color[3] *= decalInfo.start[3];
}
#endif
if (image) {
image->Bind();
dst.textureId = image->texnum;
}
}
glSetScreenSpaceDecalsQD3D12(gpuDecals, count);
glDrawScreenSpaceDecalsQD3D12();
}
static idStr R_WorldDecalFileName(const char* mapName) {
idStr filename = mapName ? mapName : "";
filename.StripFileExtension();
filename.SetFileExtension(".stamp");
return filename;
}
void idRenderWorldLocal::LoadWorldDecals() {
ClearWorldDecals();
idStr filename = R_WorldDecalFileName(mapName.c_str());
const bool osPath = strstr(filename.c_str(), ":") != NULL;
idLexer src(LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE | LEXFL_ALLOWPATHNAMES);
src.LoadFile(filename.c_str(), osPath);
if (!src.IsLoaded()) {
return;
}
idToken token;
if (!src.ReadToken(&token) || token.Icmp("worldDecals")) {
return;
}
src.ReadToken(&token);
if (token != "{") {
src.ExpectTokenString("{");
}
while (src.ReadToken(&token)) {
if (token == "}") {
break;
}
if (token.Icmp("decal")) {
src.Error("idRenderWorldLocal::LoadWorldDecals: bad token \"%s\"", token.c_str());
break;
}
renderWorldDecal_t decal;
decal.material = "textures/decals/default";
decal.origin.Zero();
decal.normal.Set(0.0f, 0.0f, 1.0f);
decal.axisU.Set(1.0f, 0.0f, 0.0f);
decal.axisV.Set(0.0f, 1.0f, 0.0f);
decal.size = 64.0f;
decal.depth = 8.0f;
decal.opacity = 1.0f;
decal.color.Set(0.05f, 0.05f, 0.05f, 1.0f);
src.ExpectTokenString("{");
while (src.ReadToken(&token)) {
if (token == "}") {
break;
}
if (!token.Icmp("material")) {
src.ExpectAnyToken(&token);
decal.material = token;
} else if (!token.Icmp("origin")) {
src.Parse1DMatrix(3, decal.origin.ToFloatPtr());
} else if (!token.Icmp("normal")) {
src.Parse1DMatrix(3, decal.normal.ToFloatPtr());
} else if (!token.Icmp("axisU")) {
src.Parse1DMatrix(3, decal.axisU.ToFloatPtr());
} else if (!token.Icmp("axisV")) {
src.Parse1DMatrix(3, decal.axisV.ToFloatPtr());
} else if (!token.Icmp("size")) {
decal.size = src.ParseFloat();
} else if (!token.Icmp("depth")) {
decal.depth = src.ParseFloat();
} else if (!token.Icmp("opacity")) {
decal.opacity = src.ParseFloat();
} else if (!token.Icmp("color")) {
src.Parse1DMatrix(4, decal.color.ToFloatPtr());
} else {
src.Error("idRenderWorldLocal::LoadWorldDecals: bad decal key \"%s\"", token.c_str());
}
}
AddWorldDecal(decal);
}
}
/*
================
idRenderWorldLocal::TouchWorldModels
@@ -546,6 +731,7 @@ bool idRenderWorldLocal::InitFromMap( const char *name ) {
common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" );
FreeDefs();
TouchWorldModels();
LoadWorldDecals();
AddWorldModelEntities();
ClearPortalStates();
return true;
@@ -565,6 +751,7 @@ bool idRenderWorldLocal::InitFromMap( const char *name ) {
mapName = name;
mapTimeStamp = currentTimeStamp;
LoadWorldDecals();
// if we are writing a demo, archive the load command
if ( session->writeDemo ) {
+8
View File
@@ -123,6 +123,12 @@ public:
virtual bool ModelTrace( modelTrace_t &trace, qhandle_t entityHandle, const idVec3 &start, const idVec3 &end, const float radius ) const;
virtual bool Trace( modelTrace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, bool skipDynamic = true, bool skipPlayer = false ) const;
virtual bool FastWorldTrace( modelTrace_t &trace, const idVec3 &start, const idVec3 &end ) const;
virtual void ClearWorldDecals();
virtual int AddWorldDecal( const renderWorldDecal_t &decal );
virtual void RemoveWorldDecal( int decalIndex );
virtual int NumWorldDecals() const;
virtual const renderWorldDecal_t *GetWorldDecal( int decalIndex ) const;
virtual void SubmitWorldDecalsToScreenSpace() const;
virtual void DebugClearLines( int time );
virtual void DebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifetime = 0, const bool depthTest = false );
@@ -160,6 +166,7 @@ public:
int numInterAreaPortals;
idList<idRenderModel *> localModels;
idList<renderWorldDecal_t> worldDecals;
idList<idRenderEntityLocal*> entityDefs;
idList<idRenderLightLocal*> lightDefs;
@@ -182,6 +189,7 @@ public:
void TouchWorldModels( void );
void AddWorldModelEntities();
void ClearPortalStates();
void LoadWorldDecals();
virtual bool InitFromMap( const char *mapName );
//--------------------------
+6 -10
View File
@@ -156,7 +156,6 @@ RB_DXDrawInteractions
void RB_DXDrawInteractions(void)
{
viewLight_t* vLight;
bool hasLight = false;
QD3D12_SetToneMapBrightness(r_brightness.GetFloat());
QD3D12_SetFrameGenerationMultiplier(r_frameGen.GetInteger());
@@ -219,18 +218,15 @@ void RB_DXDrawInteractions(void)
common->Warning("Parallel lights are not needed with raytracing! Just place a skybox.");
}
if (supported && glRaytracingLightingAddLight(&light))
{
hasLight = true;
if (supported) {
glRaytracingLightingAddLight(&light);
}
}
if (!hasLight)
if (backEnd.viewDef->renderWorld)
{
return;
backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace();
glLightScene(backEnd.viewDef->renderWorld->dxrWorldId);
glRaytracingLightingClearLights(false);
}
// glFinish();
glLightScene(backEnd.viewDef->renderWorld->dxrWorldId);
glRaytracingLightingClearLights(false);
}
+2 -4
View File
@@ -1359,10 +1359,8 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
}
}
// add the lightweight decal surfaces
for ( idRenderModelDecal *decal = def->decals; decal; decal = decal->Next() ) {
decal->AddDecalDrawSurf( vEntity );
}
// Decals are now submitted as screen-space world projectors before the
// path-traced light pass instead of as projected render-model surfaces.
}
/*
+200 -5
View File
@@ -31,6 +31,7 @@ If you have questions concerning this license or the applicable additional terms
#include "qe3.h"
#include "Radiant.h"
#include "EditorMap.h"
#include "XYWnd.h"
#include "CamWnd.h"
#include "OutlinerDlg.h"
@@ -118,6 +119,52 @@ struct cameraNavState_t {
static cameraNavConfig_t s_cameraNavConfig;
static cameraNavState_t s_cameraNavState;
static void CameraNav_GetIniPath(char* path, int pathSize);
static bool CamWnd_DecalPlacementEnabled() {
char iniPath[MAX_PATH];
CameraNav_GetIniPath(iniPath, sizeof(iniPath));
return GetPrivateProfileInt("decals", "enabled", 0, iniPath) != 0;
}
static float CamWnd_DecalFloat(const char* key, const char* defaultValue) {
char iniPath[MAX_PATH];
char value[64];
CameraNav_GetIniPath(iniPath, sizeof(iniPath));
GetPrivateProfileString("decals", key, defaultValue, value, sizeof(value), iniPath);
return (float)atof(value);
}
static void CamWnd_DecalMaterial(idStr& material) {
const char* selected = g_qeglobals.d_texturewin.texdef.name;
if (selected && selected[0] && selected[0] != '(') {
material = selected;
return;
}
material = "textures/decals/default";
}
static void CamWnd_DecalColorFromSelectedMaterial(const idStr& material, idVec4& color) {
color.Set(
CamWnd_DecalFloat("red", "1"),
CamWnd_DecalFloat("green", "1"),
CamWnd_DecalFloat("blue", "1"),
CamWnd_DecalFloat("alpha", "1"));
const idMaterial* mat = declManager->FindMaterial(material.c_str());
if (mat) {
#ifndef QUAKE4
decalInfo_t decalInfo = mat->GetDecalInfo();
color.x *= decalInfo.start[0];
color.y *= decalInfo.start[1];
color.z *= decalInfo.start[2];
color.w *= decalInfo.start[3];
#endif
if (mat->GetEditorImage()) {
mat->GetEditorImage()->Bind();
}
}
}
static void CameraNav_GetIniPath(char* path, int pathSize) {
if (pathSize <= 0) {
@@ -1010,6 +1057,7 @@ static const char* CAMWND_PROP_RENDER_MODE = "QER_CamWnd_RenderMode";
static const char* CAMWND_PROP_REBUILD_MODE = "QER_CamWnd_RebuildMode";
static const char* CAMWND_PROP_ENTITY_MODE = "QER_CamWnd_EntityMode";
static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask";
static const char* CAMWND_PROP_DECAL_EDITING = "QER_CamWnd_DecalEditing";
#define CAMWND_CAPTION_HEIGHT 30
#define CAMWND_MENU_HEIGHT 22
@@ -1025,6 +1073,7 @@ static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask";
#define CAMWND_MENU_CMD_SHOW_TARGET_LINES 62107
#define CAMWND_MENU_CMD_SHOW_TRIGGER_BRUSHES 62108
#define CAMWND_MENU_CMD_CUBIC_CLIPPING 62109
#define CAMWND_MENU_CMD_DECAL_EDITING 62110
#define CAMWND_FILTER_HIDE_WORLD 0x00000001
#define CAMWND_FILTER_HIDE_PATCHES 0x00000002
@@ -1120,15 +1169,19 @@ static void CamWnd_GetMenuItemRect(HWND hWnd, int item, RECT& rect) {
rect.left = 4;
rect.right = 86;
}
else {
else if (item == 1) {
rect.left = 86;
rect.right = 156;
}
else {
rect.left = 156;
rect.right = 236;
}
}
static int CamWnd_MenuHitTest(HWND hWnd, int x, int y) {
RECT rect;
for (int i = 0; i < 2; i++) {
for (int i = 0; i < 3; i++) {
CamWnd_GetMenuItemRect(hWnd, i, rect);
if (x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom) {
return i;
@@ -1179,6 +1232,25 @@ static void CamWnd_ToggleRealtimeLighting(CCamWnd* cam) {
CamWnd_SetRealtimeLighting(cam, !CamWnd_RealtimeLightingEnabled(cam));
}
static bool CamWnd_DecalEditingEnabled(CCamWnd* cam) {
if (!cam || !cam->GetSafeHwnd()) {
return false;
}
return CamWnd_GetIntProp(cam->GetSafeHwnd(), CAMWND_PROP_DECAL_EDITING, CamWnd_DecalPlacementEnabled() ? 1 : 0) != 0;
}
static void CamWnd_SetDecalEditing(CCamWnd* cam, bool enabled) {
if (!cam || !cam->GetSafeHwnd()) {
return;
}
CamWnd_SetIntProp(cam->GetSafeHwnd(), CAMWND_PROP_DECAL_EDITING, enabled ? 1 : 0);
CamWnd_RequestRedraw(cam);
}
static void CamWnd_ToggleDecalEditing(CCamWnd* cam) {
CamWnd_SetDecalEditing(cam, !CamWnd_DecalEditingEnabled(cam));
}
static void CamWnd_ToggleFilterBit(CCamWnd* cam, int bit) {
int mask = CamWnd_GetFilterMask(cam);
mask ^= bit;
@@ -1211,6 +1283,9 @@ static void CamWnd_HandleMenuCommand(CCamWnd* cam, int command) {
case CAMWND_MENU_CMD_CUBIC_CLIPPING:
CamWnd_ToggleCubicClipping(cam);
break;
case CAMWND_MENU_CMD_DECAL_EDITING:
CamWnd_ToggleDecalEditing(cam);
break;
case CAMWND_MENU_CMD_SHOW_WORLD:
CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_WORLD);
break;
@@ -1268,6 +1343,28 @@ static void CamWnd_ShowLightingMenu(HWND hWnd, CCamWnd* cam) {
}
}
static void CamWnd_ShowDecalsMenu(HWND hWnd, CCamWnd* cam) {
RECT itemRect;
POINT pt;
HMENU menu;
int command;
CamWnd_GetMenuItemRect(hWnd, 2, itemRect);
pt.x = itemRect.left;
pt.y = itemRect.bottom;
ClientToScreen(hWnd, &pt);
menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING | (CamWnd_DecalEditingEnabled(cam) ? MF_CHECKED : 0), CAMWND_MENU_CMD_DECAL_EDITING, "Enable decal editing");
command = TrackPopupMenu(menu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL);
DestroyMenu(menu);
if (command) {
CamWnd_HandleMenuCommand(cam, command);
}
}
static void CamWnd_ShowFiltersMenu(HWND hWnd, CCamWnd* cam) {
RECT itemRect;
POINT pt;
@@ -1313,6 +1410,9 @@ static void CamWnd_ShowTopMenu(HWND hWnd, int item) {
else if (item == 1) {
CamWnd_ShowFiltersMenu(hWnd, cam);
}
else if (item == 2) {
CamWnd_ShowDecalsMenu(hWnd, cam);
}
}
static void CamWnd_RegisterMenuBarClass() {
@@ -1397,6 +1497,7 @@ static void CamWnd_DestroyMenuBar(CCamWnd* cam) {
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_REBUILD_MODE);
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_ENTITY_MODE);
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_FILTER_MASK);
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_DECAL_EDITING);
}
static bool CamWnd_PointInMenuBar(CCamWnd* cam, const CPoint& point) {
@@ -1703,9 +1804,11 @@ static void CamWnd_FaceExtrudeBuildRay(CCamWnd* cam, const CPoint& point, idVec3
float u = 0.0f;
float r = 0.0f;
if (camera.width > 0) {
u = (float)(y - camera.height / 2) / (camera.width / 2);
r = (float)(x - camera.width / 2) / (camera.width / 2);
}
if (camera.width > 0) {
u = (float)(y - camera.height / 2) / (camera.width / 2);
}
for (int i = 0; i < 3; i++) {
dir[i] = camera.vpn[i] + camera.vright[i] * r + camera.vup[i] * u;
@@ -1713,6 +1816,75 @@ static void CamWnd_FaceExtrudeBuildRay(CCamWnd* cam, const CPoint& point, idVec3
dir.Normalize();
}
static bool CamWnd_DecalClick(CCamWnd* cam, const CPoint& point, UINT nFlags) {
if (!CamWnd_DecalEditingEnabled(cam) || cam == NULL) {
return false;
}
idVec3 dir;
CamWnd_FaceExtrudeBuildRay(cam, point, dir);
if (nFlags & MK_SHIFT) {
Map_SelectDecalByRay(cam->Camera().origin, dir);
return true;
}
idVec3 hitPoint;
idVec3 hitNormal;
float hitDist = HUGE_DISTANCE;
bool hitBrush = false;
const char* hitSource = "none";
qertrace_t trace = Test_Ray(cam->Camera().origin, dir, 0);
if (trace.brush != NULL && trace.face != NULL && trace.dist > 0.0f && trace.dist < hitDist) {
hitBrush = true;
hitSource = "brush";
hitDist = trace.dist;
hitPoint = cam->Camera().origin + dir * trace.dist;
hitNormal = trace.face->plane.Normal();
}
if (g_qeglobals.rw) {
modelTrace_t modelTrace;
idVec3 end = cam->Camera().origin + dir * HUGE_DISTANCE;
if (g_qeglobals.rw->Trace(modelTrace, cam->Camera().origin, end, 0.0f, false, false)) {
float modelDist = (modelTrace.point - cam->Camera().origin) * dir;
if (!hitBrush && modelDist > 0.0f && modelDist < hitDist) {
hitSource = "render";
hitDist = modelDist;
hitPoint = modelTrace.point;
hitNormal = modelTrace.normal;
}
}
}
if (hitDist <= 0.0f || hitDist >= HUGE_DISTANCE || hitNormal.LengthSqr() < 0.0001f) {
return true;
}
renderWorldDecal_t decal;
CamWnd_DecalMaterial(decal.material);
CamWnd_DecalColorFromSelectedMaterial(decal.material, decal.color);
decal.origin = hitPoint;
decal.normal = hitNormal;
if ((decal.normal * dir) > 0.0f) {
decal.normal = -decal.normal;
}
decal.axisU = decal.normal.Cross(cam->Camera().vup);
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(cam->Camera().vright);
}
decal.axisV = decal.normal.Cross(decal.axisU);
decal.size = CamWnd_DecalFloat("size", "64");
decal.depth = CamWnd_DecalFloat("depth", "8");
decal.opacity = CamWnd_DecalFloat("opacity", "1");
Map_AddDecal(decal);
Sys_Status(va("Placed decal using %s on %s at %.2f %.2f %.2f\n", decal.material.c_str(), hitSource, decal.origin.x, decal.origin.y, decal.origin.z), 0);
Sys_UpdateWindows(W_CAMERA);
return true;
}
static bool CamWnd_FaceExtrudeBrushAllowed(CCamWnd* cam, brush_t* brush) {
if (brush == NULL || brush->owner == NULL || brush->owner->eclass == NULL) {
return false;
@@ -2665,6 +2837,9 @@ static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam,
CamWnd_GetMenuItemRect(hWnd, 1, itemRect);
RoundRect(hDC, itemRect.left + 3, itemRect.top + 2, itemRect.right - 3, itemRect.bottom - 2, 6, 6);
DrawText(hDC, "Filters", -1, &itemRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
CamWnd_GetMenuItemRect(hWnd, 2, itemRect);
RoundRect(hDC, itemRect.left + 3, itemRect.top + 2, itemRect.right - 3, itemRect.bottom - 2, 6, 6);
DrawText(hDC, "Decals", -1, &itemRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
::SelectObject(hDC, oldPen);
::SelectObject(hDC, oldBrush);
::DeleteObject(borderPen);
@@ -2849,6 +3024,10 @@ void CCamWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
CamWnd_FaceExtrudeEnd(this, false);
return;
}
if (nChar == VK_DELETE && CamWnd_DecalEditingEnabled(this) && Map_GetSelectedDecal() >= 0) {
Map_DeleteSelectedDecal();
return;
}
if (CameraNav_HandleKeyDown(this, nChar)) {
return;
}
@@ -2975,6 +3154,9 @@ void CCamWnd::OnLButtonDown(UINT nFlags, CPoint point) {
if ((nFlags & MK_CONTROL) && (nFlags & MK_SHIFT) && CamWnd_FaceExtrudeBegin(this, point)) {
return;
}
if (CamWnd_DecalClick(this, point, nFlags)) {
return;
}
if (CamWnd_GizmoBegin(this, point, nFlags)) {
return;
}
@@ -3857,7 +4039,6 @@ static void CamWnd_DrawMoveSelectedBrushSides(const camWndBrushFilterContext_t&
glPopAttrib();
}
extern void glLabeledPoint(idVec4& color, idVec3& point, float size, const char* label);
void DrawAxial(face_t* selFace) {
if (g_bAxialMode) {
@@ -4084,6 +4265,9 @@ void CCamWnd::Cam_Draw() {
}
CamWnd_DrawMoveSelectedBrushSides(brushFilter);
if (!renderMode && g_qeglobals.rw && CamWnd_DecalEditingEnabled(this)) {
g_qeglobals.rw->SubmitWorldDecalsToScreenSpace();
}
CamWnd_FaceExtrudeDrawPreview(this);
CamWnd_GizmoDraw(this);
@@ -4141,7 +4325,7 @@ void CCamWnd::Cam_Draw() {
CameraNav_DrawOverlay(this);
glDisable(GL_SCISSOR_TEST);
glFinish();
//glFinish();
QE_CheckOpenGLForErrors();
if (!renderMode) {
@@ -5682,6 +5866,17 @@ void CCamWnd::Cam_Render() {
}
Cam_SetGlobalFogFromWorldspawn(refdef);
if (g_qeglobals.rw && CamWnd_DecalEditingEnabled(this)) {
for (int i = 0; i < g_qeglobals.rw->NumWorldDecals(); ++i) {
const renderWorldDecal_t* decal = g_qeglobals.rw->GetWorldDecal(i);
if (!decal) {
continue;
}
idVec4 color = (i == Map_GetSelectedDecal()) ? idVec4(1.0f, 0.85f, 0.1f, 1.0f) : idVec4(0.1f, 0.8f, 1.0f, 1.0f);
g_qeglobals.rw->DebugCircle(color, decal->origin, decal->normal, decal->size * 0.5f, 32, 0, false);
}
}
g_qeglobals.rw->RenderScene(&refdef);
int frontEnd, backEnd;
+210
View File
@@ -82,6 +82,209 @@ void Map_SaveBetween(void) {
}
static int s_selectedWorldDecal = -1;
static idStr Map_DecalFileName(const char* filename) {
idStr decalFile = filename ? filename : currentmap;
decalFile.StripFileExtension();
decalFile.SetFileExtension(".stamp");
return decalFile;
}
static void Map_NormalizeDecal(renderWorldDecal_t& decal) {
if (decal.normal.LengthSqr() < 0.0001f) {
decal.normal.Set(0.0f, 0.0f, 1.0f);
}
decal.normal.Normalize();
decal.axisU -= decal.normal * (decal.axisU * decal.normal);
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(idVec3(0.0f, 0.0f, 1.0f));
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(idVec3(0.0f, 1.0f, 0.0f));
}
}
decal.axisU.Normalize();
decal.axisV = decal.normal.Cross(decal.axisU);
decal.axisV.Normalize();
if (decal.size <= 0.0f) {
decal.size = 64.0f;
}
if (decal.depth <= 0.0f) {
decal.depth = 8.0f;
}
if (decal.opacity <= 0.0f) {
decal.opacity = 1.0f;
}
}
int Map_AddDecal(const renderWorldDecal_t& inDecal) {
if (!g_qeglobals.rw) {
return -1;
}
renderWorldDecal_t decal = inDecal;
Map_NormalizeDecal(decal);
s_selectedWorldDecal = g_qeglobals.rw->AddWorldDecal(decal);
mapModified = 1;
return s_selectedWorldDecal;
}
int Map_GetSelectedDecal(void) {
return s_selectedWorldDecal;
}
void Map_DeleteSelectedDecal(void) {
if (!g_qeglobals.rw || s_selectedWorldDecal < 0) {
return;
}
g_qeglobals.rw->RemoveWorldDecal(s_selectedWorldDecal);
s_selectedWorldDecal = -1;
mapModified = 1;
Sys_UpdateWindows(W_ALL);
}
int Map_SelectDecalByRay(const idVec3& origin, const idVec3& dir) {
if (!g_qeglobals.rw) {
return -1;
}
float bestT = 1e30f;
int bestIndex = -1;
for (int i = 0; i < g_qeglobals.rw->NumWorldDecals(); ++i) {
const renderWorldDecal_t* decal = g_qeglobals.rw->GetWorldDecal(i);
if (!decal) {
continue;
}
float denom = dir * decal->normal;
if (fabs(denom) < 0.0001f) {
continue;
}
float t = ((decal->origin - origin) * decal->normal) / denom;
if (t <= 0.0f || t >= bestT) {
continue;
}
idVec3 hit = origin + dir * t;
idVec3 rel = hit - decal->origin;
float u = rel * decal->axisU;
float v = rel * decal->axisV;
if (fabs(u) <= decal->size * 0.5f && fabs(v) <= decal->size * 0.5f) {
bestT = t;
bestIndex = i;
}
}
s_selectedWorldDecal = bestIndex;
Sys_UpdateWindows(W_CAMERA);
return bestIndex;
}
void Map_SaveDecals(const char* filename) {
if (!g_qeglobals.rw) {
return;
}
idStr decalFile = Map_DecalFileName(filename);
const bool osPath = strstr(decalFile.c_str(), ":") != NULL;
idFile* file = osPath ? fileSystem->OpenExplicitFileWrite(decalFile.c_str()) : fileSystem->OpenFileWrite(decalFile.c_str());
if (!file) {
common->Warning("Map_SaveDecals: couldn't write %s", decalFile.c_str());
return;
}
file->WriteFloatString("worldDecals 1 {\n");
for (int i = 0; i < g_qeglobals.rw->NumWorldDecals(); ++i) {
const renderWorldDecal_t* d = g_qeglobals.rw->GetWorldDecal(i);
if (!d) {
continue;
}
file->WriteFloatString("\tdecal {\n");
file->WriteFloatString("\t\tmaterial \"%s\"\n", d->material.c_str());
file->WriteFloatString("\t\torigin ( %f %f %f )\n", d->origin.x, d->origin.y, d->origin.z);
file->WriteFloatString("\t\tnormal ( %f %f %f )\n", d->normal.x, d->normal.y, d->normal.z);
file->WriteFloatString("\t\taxisU ( %f %f %f )\n", d->axisU.x, d->axisU.y, d->axisU.z);
file->WriteFloatString("\t\taxisV ( %f %f %f )\n", d->axisV.x, d->axisV.y, d->axisV.z);
file->WriteFloatString("\t\tsize %f\n", d->size);
file->WriteFloatString("\t\tdepth %f\n", d->depth);
file->WriteFloatString("\t\topacity %f\n", d->opacity);
file->WriteFloatString("\t\tcolor ( %f %f %f %f )\n", d->color.x, d->color.y, d->color.z, d->color.w);
file->WriteFloatString("\t}\n");
}
file->WriteFloatString("}\n");
fileSystem->CloseFile(file);
}
void Map_LoadDecals(const char* filename) {
if (!g_qeglobals.rw) {
return;
}
g_qeglobals.rw->ClearWorldDecals();
s_selectedWorldDecal = -1;
idStr decalFile = Map_DecalFileName(filename);
const bool osPath = strstr(decalFile.c_str(), ":") != NULL;
idLexer src(LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE | LEXFL_ALLOWPATHNAMES);
src.LoadFile(decalFile.c_str(), osPath);
if (!src.IsLoaded()) {
return;
}
idToken token;
if (!src.ReadToken(&token) || token.Icmp("worldDecals")) {
return;
}
src.ReadToken(&token);
if (token != "{") {
src.ExpectTokenString("{");
}
while (src.ReadToken(&token)) {
if (token == "}") {
break;
}
if (token.Icmp("decal")) {
break;
}
renderWorldDecal_t decal;
decal.material = "textures/decals/default";
decal.origin.Zero();
decal.normal.Set(0.0f, 0.0f, 1.0f);
decal.axisU.Set(1.0f, 0.0f, 0.0f);
decal.axisV.Set(0.0f, 1.0f, 0.0f);
decal.size = 64.0f;
decal.depth = 8.0f;
decal.opacity = 1.0f;
decal.color.Set(0.05f, 0.05f, 0.05f, 1.0f);
src.ExpectTokenString("{");
while (src.ReadToken(&token)) {
if (token == "}") {
break;
}
if (!token.Icmp("material")) {
src.ExpectAnyToken(&token);
decal.material = token;
} else if (!token.Icmp("origin")) {
src.Parse1DMatrix(3, decal.origin.ToFloatPtr());
} else if (!token.Icmp("normal")) {
src.Parse1DMatrix(3, decal.normal.ToFloatPtr());
} else if (!token.Icmp("axisU")) {
src.Parse1DMatrix(3, decal.axisU.ToFloatPtr());
} else if (!token.Icmp("axisV")) {
src.Parse1DMatrix(3, decal.axisV.ToFloatPtr());
} else if (!token.Icmp("size")) {
decal.size = src.ParseFloat();
} else if (!token.Icmp("depth")) {
decal.depth = src.ParseFloat();
} else if (!token.Icmp("opacity")) {
decal.opacity = src.ParseFloat();
} else if (!token.Icmp("color")) {
src.Parse1DMatrix(4, decal.color.ToFloatPtr());
}
}
Map_AddDecal(decal);
}
s_selectedWorldDecal = -1;
mapModified = 0;
}
/*
=======================================================================================================================
=======================================================================================================================
@@ -546,6 +749,7 @@ void Map_LoadFile(const char *filename) {
if (g_pParentWnd->GetCamera()->GetRenderMode()) {
g_pParentWnd->GetCamera()->BuildRendererState();
}
Map_LoadDecals(filename);
Sys_EndWait();
Sys_UpdateWindows(W_ALL);
@@ -790,6 +994,9 @@ bool Map_SaveFile(const char *filename, bool use_region, bool autosave) {
sprintf(status, "Writing file %s.%s...", mapFile.c_str(), mapExt.c_str());
dlg.SetText(status);
map.Write(mapFile, mapExt, !(autosave || localFile));
if (!use_region) {
Map_SaveDecals(filename);
}
mapModified = 0;
if (use_region) {
@@ -821,6 +1028,9 @@ void Map_New(void) {
world_entity->brushes.onext = world_entity->brushes.oprev = &world_entity->brushes;
SetKeyValue(world_entity, "classname", "worldspawn");
world_entity->eclass = Eclass_ForName("worldspawn", true);
if (g_qeglobals.rw) {
g_qeglobals.rw->ClearWorldDecals();
}
g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0;
g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0;
+13
View File
@@ -26,6 +26,11 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#ifndef __EDITORMAP_H__
#define __EDITORMAP_H__
#include "../../renderer/RenderWorld.h"
extern char currentmap[1024];
// head/tail of doubly linked lists
@@ -52,6 +57,12 @@ void Map_LoadFile (const char *filename);
bool Map_SaveFile (const char *filename, bool use_region, bool autosave = false);
void Map_New (void);
void Map_BuildBrushData(void);
void Map_LoadDecals(const char *filename);
void Map_SaveDecals(const char *filename);
int Map_AddDecal(const renderWorldDecal_t& decal);
void Map_DeleteSelectedDecal(void);
int Map_SelectDecalByRay(const idVec3& origin, const idVec3& dir);
int Map_GetSelectedDecal(void);
void Map_RegionOff (void);
void Map_RegionXY (void);
@@ -65,3 +76,5 @@ void Map_ImportBuffer (char* buf, bool renameEntities = true);
int Map_GetUniqueEntityID(const char *prefix, const char *eclass);
idMapPrimitive *BrushToMapPrimitive( const brush_t *b, const idVec3 &origin );
#endif