mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Added screensapce decal system and stamp placement system in Radiant.
This commit is contained in:
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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 );
|
||||
|
||||
//--------------------------
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user