mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 00:01:49 +02:00
IES profile support and fixed numerous editor crashes.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
ERCO Leuchten GmbH
|
||||
3399_0 - IES format
|
||||
ERCO 89064
|
||||
ERCO Double Focus Downlight
|
||||
DL40-QT12-2HA-SI-DOUBLE
|
||||
1*QT-ax12 100W/12V
|
||||
light output ratio: 0.5912
|
||||
ident no. for symmetry: 1
|
||||
D694
|
||||
TILT=NONE
|
||||
1
|
||||
2200
|
||||
2.2
|
||||
19
|
||||
1
|
||||
1
|
||||
2
|
||||
0
|
||||
0
|
||||
0
|
||||
1
|
||||
1
|
||||
100
|
||||
0
|
||||
5
|
||||
10
|
||||
15
|
||||
20
|
||||
25
|
||||
30
|
||||
35
|
||||
40
|
||||
45
|
||||
50
|
||||
55
|
||||
60
|
||||
65
|
||||
70
|
||||
75
|
||||
80
|
||||
85
|
||||
90
|
||||
0
|
||||
681.879276637
|
||||
557.110079287
|
||||
490.896871945
|
||||
628.387368307
|
||||
682.069349408
|
||||
430.426577604
|
||||
286.398935592
|
||||
254.901162159
|
||||
76.9183773216
|
||||
18.9393939394
|
||||
11.0377973281
|
||||
.488758553275
|
||||
.00678831323993
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
END
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
lights/iesspotlight {
|
||||
lightIESTexture ies/spot1.ies
|
||||
}
|
||||
@@ -4058,6 +4058,9 @@ static classVariableInfo_t glRaytracingLight_t_typeInfo[] = {
|
||||
{ "float", "persistant", (intptr_t)(&((glRaytracingLight_t *)0)->persistant), sizeof( ((glRaytracingLight_t *)0)->persistant ) },
|
||||
{ "glRaytracingVec3_t", "pointRadius", (intptr_t)(&((glRaytracingLight_t *)0)->pointRadius), sizeof( ((glRaytracingLight_t *)0)->pointRadius ) },
|
||||
{ "float", "pointRadiusPad", (intptr_t)(&((glRaytracingLight_t *)0)->pointRadiusPad), sizeof( ((glRaytracingLight_t *)0)->pointRadiusPad ) },
|
||||
{ "uint32_t", "iesTextureId", (intptr_t)(&((glRaytracingLight_t *)0)->iesTextureId), sizeof( ((glRaytracingLight_t *)0)->iesTextureId ) },
|
||||
{ "float", "iesStrength", (intptr_t)(&((glRaytracingLight_t *)0)->iesStrength), sizeof( ((glRaytracingLight_t *)0)->iesStrength ) },
|
||||
{ "float[2]", "iesPad", (intptr_t)(&((glRaytracingLight_t *)0)->iesPad), sizeof( ((glRaytracingLight_t *)0)->iesPad ) },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -4218,6 +4221,7 @@ static classVariableInfo_t idMaterial_typeInfo[] = {
|
||||
{ "idStr", "desc", (intptr_t)(&((idMaterial *)0)->desc), sizeof( ((idMaterial *)0)->desc ) },
|
||||
{ "idStr", "renderBump", (intptr_t)(&((idMaterial *)0)->renderBump), sizeof( ((idMaterial *)0)->renderBump ) },
|
||||
{ "idImage *", "lightFalloffImage", (intptr_t)(&((idMaterial *)0)->lightFalloffImage), sizeof( ((idMaterial *)0)->lightFalloffImage ) },
|
||||
{ "idImage *", "lightIESImage", (intptr_t)(&((idMaterial *)0)->lightIESImage), sizeof( ((idMaterial *)0)->lightIESImage ) },
|
||||
{ "int", "entityGui", (intptr_t)(&((idMaterial *)0)->entityGui), sizeof( ((idMaterial *)0)->entityGui ) },
|
||||
{ "mutable idUserInterface *", "gui", (intptr_t)(&((idMaterial *)0)->gui), sizeof( ((idMaterial *)0)->gui ) },
|
||||
{ "bool", "noFog", (intptr_t)(&((idMaterial *)0)->noFog), sizeof( ((idMaterial *)0)->noFog ) },
|
||||
|
||||
@@ -2469,9 +2469,12 @@ struct glRaytracingMeshMetadata_t
|
||||
float averageColor[4];
|
||||
};
|
||||
|
||||
static const uint32_t GL_RAYTRACING_MAX_IES_TEXTURES = 8;
|
||||
|
||||
struct glRaytracingLightingState_t
|
||||
{
|
||||
std::vector<glRaytracingLight_t> cpuLights;
|
||||
std::vector<glRaytracingLight_t> uploadLights;
|
||||
glRaytracingLightingConstants_t constants;
|
||||
|
||||
ComPtr<ID3D12DescriptorHeap> descriptorHeap;
|
||||
@@ -2522,6 +2525,9 @@ struct glRaytracingLightingState_t
|
||||
DXGI_FORMAT emissiveFormat;
|
||||
ID3D12Resource* specularTexture;
|
||||
DXGI_FORMAT specularFormat;
|
||||
uint32_t iesTextureIds[GL_RAYTRACING_MAX_IES_TEXTURES];
|
||||
ID3D12Resource* iesTextures[GL_RAYTRACING_MAX_IES_TEXTURES];
|
||||
DXGI_FORMAT iesFormats[GL_RAYTRACING_MAX_IES_TEXTURES];
|
||||
bool uploadToCurrentFrameResource;
|
||||
bool initialized;
|
||||
|
||||
@@ -2553,6 +2559,12 @@ struct glRaytracingLightingState_t
|
||||
emissiveFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
specularTexture = nullptr;
|
||||
specularFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
for (uint32_t i = 0; i < GL_RAYTRACING_MAX_IES_TEXTURES; ++i)
|
||||
{
|
||||
iesTextureIds[i] = 0;
|
||||
iesTextures[i] = nullptr;
|
||||
iesFormats[i] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
uploadToCurrentFrameResource = false;
|
||||
initialized = false;
|
||||
}
|
||||
@@ -2577,14 +2589,15 @@ enum glRaytracingLightingDescriptorIndex_t
|
||||
GLR_DESC_EMISSIVE_SRV = 11,
|
||||
GLR_DESC_SPECULAR_SRV = 12,
|
||||
GLR_DESC_MESH_METADATA_SRV = 13,
|
||||
GLR_DESC_PATHTRACE_UAV = 14,
|
||||
GLR_DESC_DENOISE_A_UAV = 15,
|
||||
GLR_DESC_DENOISE_B_UAV = 16,
|
||||
GLR_DESC_OUTPUT_UAV = 17,
|
||||
GLR_DESC_TEMPORAL_UAV = 18,
|
||||
GLR_DESC_HISTORY_UAV = 19,
|
||||
GLR_DESC_COUNT = 20,
|
||||
GLR_DESC_SRV_COUNT = 14,
|
||||
GLR_DESC_IES_TEXTURES_SRV = 14,
|
||||
GLR_DESC_PATHTRACE_UAV = GLR_DESC_IES_TEXTURES_SRV + GL_RAYTRACING_MAX_IES_TEXTURES,
|
||||
GLR_DESC_DENOISE_A_UAV = GLR_DESC_PATHTRACE_UAV + 1,
|
||||
GLR_DESC_DENOISE_B_UAV = GLR_DESC_PATHTRACE_UAV + 2,
|
||||
GLR_DESC_OUTPUT_UAV = GLR_DESC_PATHTRACE_UAV + 3,
|
||||
GLR_DESC_TEMPORAL_UAV = GLR_DESC_PATHTRACE_UAV + 4,
|
||||
GLR_DESC_HISTORY_UAV = GLR_DESC_PATHTRACE_UAV + 5,
|
||||
GLR_DESC_COUNT = GLR_DESC_PATHTRACE_UAV + 6,
|
||||
GLR_DESC_SRV_COUNT = 14 + GL_RAYTRACING_MAX_IES_TEXTURES,
|
||||
GLR_DESC_UAV_COUNT = 6
|
||||
};
|
||||
|
||||
@@ -2631,6 +2644,10 @@ struct Light
|
||||
// as the influence range for rect lights, and as the far clip distance for spot lights.
|
||||
float3 pointRadius;
|
||||
float pointRadiusPad; // non-zero disables specular for this light
|
||||
|
||||
uint iesTextureIndex; // 0 = none, 1..8 = gIesTextures index + 1
|
||||
float iesStrength;
|
||||
float2 iesPad;
|
||||
};
|
||||
|
||||
struct MeshMetadata
|
||||
@@ -2686,6 +2703,7 @@ RaytracingAccelerationStructure gSceneBVH : register(t5);
|
||||
Texture2D<float4> gEmissiveTex : register(t11);
|
||||
Texture2D<float4> gSpecularTex : register(t12);
|
||||
StructuredBuffer<MeshMetadata> gMeshMetadata : register(t13);
|
||||
Texture2D<float4> gIesTextures[8] : register(t14);
|
||||
RWTexture2D<float4> gOutputTex : register(u0);
|
||||
|
||||
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0;
|
||||
@@ -3143,6 +3161,60 @@ float Doom3ProjectionTexture2D(float2 centeredCoord)
|
||||
|
||||
return Doom3QuadraticCentered(centeredCoord.x) * Doom3QuadraticCentered(centeredCoord.y);
|
||||
}
|
||||
|
||||
int WrapIESHorizontalCoord(int x)
|
||||
{
|
||||
x = x % 512;
|
||||
return (x < 0) ? (x + 512) : x;
|
||||
}
|
||||
|
||||
float SampleIESTexture(Light Lgt, float3 lightToSurface)
|
||||
{
|
||||
if (Lgt.iesTextureIndex == 0u || Lgt.iesStrength <= 0.0)
|
||||
return 1.0;
|
||||
|
||||
float3 dir = Doom3SafeNormalizeOr(lightToSurface, Doom3SafeNormalizeOr(Lgt.normal, float3(0.0, 0.0, 1.0)));
|
||||
float3 axisW = Doom3SafeNormalizeOr(Lgt.normal, float3(0.0, 0.0, 1.0));
|
||||
float3 axisU = Doom3SafeNormalizeOr(Lgt.axisU, float3(1.0, 0.0, 0.0));
|
||||
float3 axisV = Doom3SafeNormalizeOr(Lgt.axisV, float3(0.0, 1.0, 0.0));
|
||||
|
||||
float localX = dot(dir, axisU);
|
||||
float localY = dot(dir, axisV);
|
||||
float localZ = dot(dir, axisW);
|
||||
|
||||
float horizontal = atan2(localY, localX) * (0.15915494309189535) + 0.5;
|
||||
float vertical = acos(clamp(localZ, -1.0, 1.0)) * (0.3183098861837907);
|
||||
|
||||
uint texIndex = min(Lgt.iesTextureIndex - 1u, 7u);
|
||||
float u = frac(horizontal) * 512.0 - 0.5;
|
||||
float v = saturate(vertical) * 256.0 - 0.5;
|
||||
int x0 = (int)floor(u);
|
||||
int y0 = (int)floor(v);
|
||||
float tx = frac(u);
|
||||
float ty = frac(v);
|
||||
int x1 = x0 + 1;
|
||||
int y1 = y0 + 1;
|
||||
|
||||
x0 = WrapIESHorizontalCoord(x0);
|
||||
x1 = WrapIESHorizontalCoord(x1);
|
||||
y0 = clamp(y0, 0, 255);
|
||||
y1 = clamp(y1, 0, 255);
|
||||
|
||||
float p00 = gIesTextures[texIndex].Load(int3(x0, y0, 0)).r;
|
||||
float p10 = gIesTextures[texIndex].Load(int3(x1, y0, 0)).r;
|
||||
float p01 = gIesTextures[texIndex].Load(int3(x0, y1, 0)).r;
|
||||
float p11 = gIesTextures[texIndex].Load(int3(x1, y1, 0)).r;
|
||||
float profile = lerp(lerp(p00, p10, tx), lerp(p01, p11, tx), ty);
|
||||
return lerp(1.0, profile, saturate(Lgt.iesStrength));
|
||||
}
|
||||
|
||||
float ApplyIESProfile(float attenuation, Light Lgt, float3 lightToSurface)
|
||||
{
|
||||
if (attenuation <= 0.0 || Lgt.iesTextureIndex == 0u || Lgt.iesStrength <= 0.0)
|
||||
return attenuation;
|
||||
|
||||
return attenuation * SampleIESTexture(Lgt, lightToSurface);
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
float Doom3ProjectedDepthFalloff(float depth, float nearClip, float farClip)
|
||||
@@ -3192,6 +3264,15 @@ float ComputeSpotLightAttenuation(float3 worldPos, Light Lgt)
|
||||
|
||||
float depth = dot(lightToSurface, spotDir);
|
||||
|
||||
if (Lgt.iesTextureIndex != 0u && Lgt.iesStrength > 0.0)
|
||||
{
|
||||
if (depth <= 1e-4 || depth >= farClip)
|
||||
return 0.0;
|
||||
|
||||
float t = saturate(depth / max(farClip, 1e-4));
|
||||
return 1.0 - smoothstep(0.985, 1.0, t);
|
||||
}
|
||||
|
||||
if (depth <= nearClip || depth >= farClip)
|
||||
return 0.0;
|
||||
|
||||
@@ -4023,7 +4104,7 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
float3 tangent, bitangent;
|
||||
BuildOrthonormalBasis(centerDir, tangent, bitangent);
|
||||
|
||||
float atten = ComputePointLightAttenuation(worldPos, Lgt);
|
||||
float atten = ApplyIESProfile(ComputePointLightAttenuation(worldPos, Lgt), Lgt, worldPos - Lgt.position);
|
||||
if (atten <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
@@ -4081,7 +4162,7 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
|
||||
return 0.0;
|
||||
|
||||
float3 L = toLight / dist;
|
||||
float atten = ComputeSpotLightAttenuation(worldPos, Lgt);
|
||||
float atten = ApplyIESProfile(ComputeSpotLightAttenuation(worldPos, Lgt), Lgt, worldPos - Lgt.position);
|
||||
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
@@ -5264,7 +5345,7 @@ void RayGen()
|
||||
reflectionRng);
|
||||
|
||||
float3 albedo = baseAlbedo * cavity;
|
||||
float3 finalColor = (albedo * (lightingAccum + float3(0.08, 0.08, 0.08))) + specularAccum + reflectedSpecular;
|
||||
float3 finalColor = (albedo * (lightingAccum)) + specularAccum + reflectedSpecular;
|
||||
|
||||
if (gMaxBounces > 1u)
|
||||
{
|
||||
@@ -6073,16 +6154,72 @@ static void glRaytracingLightingUpdateLights(void)
|
||||
if (g_glRaytracingLighting.cpuLights.empty())
|
||||
return;
|
||||
|
||||
const size_t bytes = g_glRaytracingLighting.cpuLights.size() * sizeof(glRaytracingLight_t);
|
||||
std::vector<glRaytracingLight_t>& uploadLights = g_glRaytracingLighting.uploadLights;
|
||||
uploadLights = g_glRaytracingLighting.cpuLights;
|
||||
|
||||
for (size_t i = 0; i < uploadLights.size(); ++i)
|
||||
{
|
||||
glRaytracingLight_t& light = uploadLights[i];
|
||||
const uint32_t textureId = light.iesTextureId;
|
||||
if (textureId == 0 || light.iesStrength <= 0.0f)
|
||||
{
|
||||
light.iesTextureId = 0;
|
||||
light.iesStrength = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t slot = GL_RAYTRACING_MAX_IES_TEXTURES;
|
||||
for (uint32_t j = 0; j < GL_RAYTRACING_MAX_IES_TEXTURES; ++j)
|
||||
{
|
||||
if (g_glRaytracingLighting.iesTextureIds[j] == textureId)
|
||||
{
|
||||
slot = j;
|
||||
break;
|
||||
}
|
||||
if (g_glRaytracingLighting.iesTextureIds[j] == 0 && slot == GL_RAYTRACING_MAX_IES_TEXTURES)
|
||||
{
|
||||
slot = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == GL_RAYTRACING_MAX_IES_TEXTURES)
|
||||
{
|
||||
light.iesTextureId = 0;
|
||||
light.iesStrength = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_glRaytracingLighting.iesTextureIds[slot] == 0)
|
||||
{
|
||||
DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
UINT width = 0;
|
||||
UINT height = 0;
|
||||
ID3D12Resource* resource = QD3D12_GetTextureResource((GLuint)textureId, &format, &width, &height, g_glRaytracingCmd.cmdList.Get());
|
||||
if (!resource || width == 0 || height == 0)
|
||||
{
|
||||
light.iesTextureId = 0;
|
||||
light.iesStrength = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
g_glRaytracingLighting.iesTextureIds[slot] = textureId;
|
||||
g_glRaytracingLighting.iesTextures[slot] = resource;
|
||||
g_glRaytracingLighting.iesFormats[slot] = format;
|
||||
}
|
||||
|
||||
light.iesTextureId = slot + 1;
|
||||
}
|
||||
|
||||
const size_t bytes = uploadLights.size() * sizeof(glRaytracingLight_t);
|
||||
if (g_glRaytracingLighting.lightBufferMapped)
|
||||
{
|
||||
memcpy(g_glRaytracingLighting.lightBufferMapped, g_glRaytracingLighting.cpuLights.data(), bytes);
|
||||
memcpy(g_glRaytracingLighting.lightBufferMapped, uploadLights.data(), bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
glRaytracingMapCopy(
|
||||
g_glRaytracingLighting.lightBuffer.resource.Get(),
|
||||
g_glRaytracingLighting.cpuLights.data(),
|
||||
uploadLights.data(),
|
||||
bytes);
|
||||
}
|
||||
|
||||
@@ -6622,6 +6759,21 @@ static void glRaytracingLightingCreatePerPassDescriptors(
|
||||
g_glRaytracingCmd.device->CreateShaderResourceView(specularResource, &specularSrv,
|
||||
glRaytracingOffsetCpu(base, g_glRaytracingLighting.descriptorStride, GLR_DESC_SPECULAR_SRV));
|
||||
|
||||
for (uint32_t i = 0; i < GL_RAYTRACING_MAX_IES_TEXTURES; ++i)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC iesSrv = {};
|
||||
iesSrv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
iesSrv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
iesSrv.Format = g_glRaytracingLighting.iesTextures[i]
|
||||
? g_glRaytracingLighting.iesFormats[i]
|
||||
: DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
iesSrv.Texture2D.MipLevels = 1;
|
||||
g_glRaytracingCmd.device->CreateShaderResourceView(
|
||||
g_glRaytracingLighting.iesTextures[i],
|
||||
&iesSrv,
|
||||
glRaytracingOffsetCpu(base, g_glRaytracingLighting.descriptorStride, GLR_DESC_IES_TEXTURES_SRV + i));
|
||||
}
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC rayOutputUav = {};
|
||||
rayOutputUav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
rayOutputUav.Format = GL_RAYTRACING_DENOISE_FORMAT;
|
||||
|
||||
@@ -373,6 +373,7 @@ void QD3D12_SetCameraInfo(
|
||||
static void QD3D12_CreateUploadRingForWindow(struct QD3D12Window& w);
|
||||
static void QD3D12_DestroyUploadRingForWindow(struct QD3D12Window& w);
|
||||
static void QD3D12_SubmitOpenFrameNoPresentAndWait();
|
||||
static void QD3D12_WaitForGPU();
|
||||
static void QD3D12_EnsureFrameOpen();
|
||||
static void QD3D12_RunUpscalerOrBlit(QD3D12Window& w);
|
||||
static void QD3D12_ExecuteMainCommandListAndWait(QD3D12Window& w);
|
||||
@@ -664,7 +665,7 @@ static void QD3D12_InvalidateTextureMipChain(TextureResource& tex, bool invalida
|
||||
static bool QD3D12_TextureHasNeuralPOMData(const TextureResource& tex);
|
||||
static bool QD3D12_UploadNeuralPOM(TextureResource& tex);
|
||||
static void EnsureTextureResource(TextureResource& tex);
|
||||
static void UploadTexture(TextureResource& tex);
|
||||
static void UploadTexture(TextureResource& tex, ID3D12GraphicsCommandList* commandList = nullptr);
|
||||
static UINT QD3D12_NeuralPOMFallbackSrvIndex();
|
||||
static void QD3D12_CreateNeuralPOMZeroBuffer();
|
||||
|
||||
@@ -1336,17 +1337,6 @@ struct QD3D12Window* AllocD3D12Window() {
|
||||
return new QD3D12Window();
|
||||
}
|
||||
|
||||
void FreeD3D12Window(struct QD3D12Window* wnd) {
|
||||
if (wnd)
|
||||
{
|
||||
QD3D12_DestroyUploadRingForWindow(*wnd);
|
||||
QD3D12_UnregisterWindowDC(wnd->hdc);
|
||||
if (wnd->ownsHdc && wnd->hwnd && wnd->hdc)
|
||||
ReleaseDC(wnd->hwnd, wnd->hdc);
|
||||
}
|
||||
delete wnd;
|
||||
}
|
||||
|
||||
struct ImmediateVertexBuffer
|
||||
{
|
||||
std::vector<GLVertex> storage;
|
||||
@@ -1514,7 +1504,7 @@ struct GLState
|
||||
bool enableRayAIDenoise = false;
|
||||
bool enableDLSSRayReconstruction = false;
|
||||
bool enableFSRRayRegeneration = false;
|
||||
uint32_t frameGenerationMultiplier = 2;
|
||||
uint32_t frameGenerationMultiplier = 0;
|
||||
uint32_t pathTracingSamplesPerPixel = 1;
|
||||
uint32_t pathTracingFallbackSamplesPerPixel = 2;
|
||||
uint32_t pathTracingMaxBounces = 2;
|
||||
@@ -1850,6 +1840,24 @@ static void QD3D12_MatrixMultiplyCM(const float* a, const float* b, float* out)
|
||||
memcpy(out, r, sizeof(r));
|
||||
}
|
||||
|
||||
void FreeD3D12Window(struct QD3D12Window* wnd) {
|
||||
if (wnd)
|
||||
{
|
||||
if ((g_gl.frameOpen && g_gl.frameOwner == wnd) || g_currentWindow == wnd)
|
||||
QD3D12_SubmitOpenFrameNoPresentAndWait();
|
||||
if (g_currentWindow == wnd)
|
||||
g_currentWindow = nullptr;
|
||||
if (g_gl.device && g_gl.queue && g_gl.fence)
|
||||
QD3D12_WaitForGPU();
|
||||
QD3D12_DestroyUploadRingForWindow(*wnd);
|
||||
QD3D12_UnregisterWindowDC(wnd->hdc);
|
||||
if (wnd->ownsHdc && wnd->hwnd && wnd->hdc)
|
||||
ReleaseDC(wnd->hwnd, wnd->hdc);
|
||||
}
|
||||
delete wnd;
|
||||
}
|
||||
|
||||
|
||||
static bool QD3D12_MatrixInvertCM(const float* m, float* out)
|
||||
{
|
||||
if (!QD3D12_MatrixFinite(m) || !out)
|
||||
@@ -2583,6 +2591,32 @@ static TextureResource* QD3D12_FindTextureResource(GLuint id)
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
ID3D12Resource* QD3D12_GetTextureResource(GLuint texture, DXGI_FORMAT* format, UINT* width, UINT* height, ID3D12GraphicsCommandList* commandList)
|
||||
{
|
||||
TextureResource* tex = QD3D12_FindTextureResource(texture);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
EnsureTextureResource(*tex);
|
||||
if (!tex->texture)
|
||||
return nullptr;
|
||||
|
||||
if (!tex->gpuValid && commandList)
|
||||
UploadTexture(*tex, commandList);
|
||||
|
||||
if (!tex->gpuValid)
|
||||
return nullptr;
|
||||
|
||||
if (format)
|
||||
*format = tex->dxgiFormat;
|
||||
if (width)
|
||||
*width = (UINT)tex->width;
|
||||
if (height)
|
||||
*height = (UINT)tex->height;
|
||||
|
||||
return tex->texture.Get();
|
||||
}
|
||||
|
||||
static TextureResource& QD3D12_EnsureTextureName(GLuint id)
|
||||
{
|
||||
auto it = g_gl.textures.find(id);
|
||||
@@ -6842,6 +6876,11 @@ static float QD3D12_QualityRatio(QD3D12UpscalerQuality quality)
|
||||
}
|
||||
}
|
||||
|
||||
static bool QD3D12_IsEmbeddedEditorWindow(const QD3D12Window& w)
|
||||
{
|
||||
return w.hwnd && GetParent(w.hwnd) != nullptr;
|
||||
}
|
||||
|
||||
#if defined(QD3D12_ENABLE_STREAMLINE)
|
||||
struct QD3D12StreamlineState
|
||||
{
|
||||
@@ -7169,6 +7208,7 @@ static bool QD3D12_WantsDLSSRayReconstruction()
|
||||
static bool QD3D12_CanUseDLSSRayReconstructionForLighting(const QD3D12Window& w)
|
||||
{
|
||||
return !w.isPbuffer &&
|
||||
!QD3D12_IsEmbeddedEditorWindow(w) &&
|
||||
g_gl.cameraState.valid &&
|
||||
QD3D12_WantsDLSSRayReconstruction();
|
||||
}
|
||||
@@ -7255,6 +7295,7 @@ static bool QD3D12_WantsDLSSFrameGeneration(const QD3D12Window& w)
|
||||
{
|
||||
return
|
||||
!w.isPbuffer &&
|
||||
!QD3D12_IsEmbeddedEditorWindow(w) &&
|
||||
g_gl.cameraState.valid &&
|
||||
g_qd3d12Sl.deviceBound &&
|
||||
g_qd3d12Sl.dlssGSupported &&
|
||||
@@ -7271,6 +7312,8 @@ static uint32_t QD3D12_GetDLSSFrameGenerationEligibilityMask(const QD3D12Window&
|
||||
uint32_t mask = 0;
|
||||
if (w.isPbuffer)
|
||||
mask |= 1u << 0;
|
||||
if (QD3D12_IsEmbeddedEditorWindow(w))
|
||||
mask |= 1u << 8;
|
||||
if (!g_gl.cameraState.valid)
|
||||
mask |= 1u << 1;
|
||||
if (!g_qd3d12Sl.deviceBound)
|
||||
@@ -7301,9 +7344,10 @@ static void QD3D12_LogDLSSFrameGenerationEligibility(const QD3D12Window& w, uint
|
||||
}
|
||||
|
||||
QD3D12_Log(
|
||||
"DLSS_G inactive: r_frameGen=%u, pbuffer=%d, camera=%d, deviceBound=%d, dlssG=%d, reflex=%d, resources=%d.",
|
||||
"DLSS_G inactive: r_frameGen=%u, pbuffer=%d, embedded=%d, camera=%d, deviceBound=%d, dlssG=%d, reflex=%d, resources=%d.",
|
||||
g_gl.frameGenerationMultiplier,
|
||||
w.isPbuffer ? 1 : 0,
|
||||
QD3D12_IsEmbeddedEditorWindow(w) ? 1 : 0,
|
||||
g_gl.cameraState.valid ? 1 : 0,
|
||||
g_qd3d12Sl.deviceBound ? 1 : 0,
|
||||
(g_qd3d12Sl.dlssGSupported && g_qd3d12Sl.dlssGFeatureLoaded) ? 1 : 0,
|
||||
@@ -11466,11 +11510,15 @@ static void QD3D12_ProcessCompletedTextureMipJobs(UINT maxUploads)
|
||||
}
|
||||
}
|
||||
|
||||
static void UploadTexture(TextureResource& tex)
|
||||
static void UploadTexture(TextureResource& tex, ID3D12GraphicsCommandList* commandList)
|
||||
{
|
||||
if (!tex.texture)
|
||||
return;
|
||||
|
||||
ID3D12GraphicsCommandList* cl = commandList ? commandList : g_gl.cmdList.Get();
|
||||
if (!cl)
|
||||
return;
|
||||
|
||||
if (tex.compressed)
|
||||
{
|
||||
const UINT blockBytes = tex.compressedBlockBytes ? tex.compressedBlockBytes : QD3D12_CompressedTextureBlockBytes(tex.compressedInternalFormat);
|
||||
@@ -11513,7 +11561,7 @@ static void UploadTexture(TextureResource& tex)
|
||||
toCopy.Transition.StateBefore = tex.state;
|
||||
toCopy.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
toCopy.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
g_gl.cmdList->ResourceBarrier(1, &toCopy);
|
||||
cl->ResourceBarrier(1, &toCopy);
|
||||
tex.state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
}
|
||||
|
||||
@@ -11532,17 +11580,17 @@ static void UploadTexture(TextureResource& tex)
|
||||
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
dstLoc.SubresourceIndex = 0;
|
||||
|
||||
g_gl.cmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
|
||||
cl->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
|
||||
|
||||
D3D12_RESOURCE_BARRIER toSrv{};
|
||||
toSrv.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
toSrv.Transition.pResource = tex.texture.Get();
|
||||
toSrv.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
toSrv.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
toSrv.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
toSrv.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
g_gl.cmdList->ResourceBarrier(1, &toSrv);
|
||||
cl->ResourceBarrier(1, &toSrv);
|
||||
|
||||
tex.state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
tex.state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
tex.gpuValid = true;
|
||||
return;
|
||||
}
|
||||
@@ -11561,7 +11609,7 @@ static void UploadTexture(TextureResource& tex)
|
||||
toCopy.Transition.StateBefore = tex.state;
|
||||
toCopy.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
toCopy.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
g_gl.cmdList->ResourceBarrier(1, &toCopy);
|
||||
cl->ResourceBarrier(1, &toCopy);
|
||||
tex.state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
}
|
||||
|
||||
@@ -11593,17 +11641,17 @@ static void UploadTexture(TextureResource& tex)
|
||||
dstLoc.pResource = tex.texture.Get();
|
||||
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
dstLoc.SubresourceIndex = 0;
|
||||
g_gl.cmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
|
||||
cl->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
|
||||
|
||||
D3D12_RESOURCE_BARRIER toSrv{};
|
||||
toSrv.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
toSrv.Transition.pResource = tex.texture.Get();
|
||||
toSrv.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
toSrv.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
toSrv.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
toSrv.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
g_gl.cmdList->ResourceBarrier(1, &toSrv);
|
||||
cl->ResourceBarrier(1, &toSrv);
|
||||
|
||||
tex.state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
tex.state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
tex.gpuValid = true;
|
||||
|
||||
EnsureTextureResource(tex);
|
||||
@@ -12894,12 +12942,20 @@ void APIENTRY glFinish(void)
|
||||
if (!g_gl.device || !g_gl.queue || !g_gl.cmdList)
|
||||
return;
|
||||
|
||||
QD3D12Window* owner = g_gl.frameOwner ? g_gl.frameOwner : g_currentWindow;
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
if (!g_gl.frameOpen && g_gl.queuedBatches.empty())
|
||||
{
|
||||
QD3D12_WaitForGPU();
|
||||
if (!QD3D12_IsEmbeddedEditorWindow(*owner))
|
||||
QD3D12_WaitForGPU();
|
||||
return;
|
||||
}
|
||||
|
||||
QD3D12Window* savedWindow = g_currentWindow;
|
||||
g_currentWindow = owner;
|
||||
|
||||
QD3D12_EnsureFrameOpen();
|
||||
QD3D12_FlushQueuedBatches();
|
||||
|
||||
@@ -12917,16 +12973,17 @@ void APIENTRY glFinish(void)
|
||||
WaitForSingleObject(g_gl.fenceEvent, INFINITE);
|
||||
}
|
||||
|
||||
FrameResources& fr = g_currentWindow->frames[g_currentWindow->frameIndex];
|
||||
FrameResources& fr = owner->frames[owner->frameIndex];
|
||||
fr.fenceValue = signalValue;
|
||||
|
||||
QD3D12_CHECK(fr.cmdAlloc->Reset());
|
||||
QD3D12_CHECK(g_gl.cmdList->Reset(fr.cmdAlloc.Get(), nullptr));
|
||||
|
||||
QD3D12_BindTargetsForCurrentPhase(*g_currentWindow);
|
||||
QD3D12_BindTargetsForCurrentPhase(*owner);
|
||||
|
||||
g_gl.frameOpen = true;
|
||||
g_gl.frameOwner = g_currentWindow;
|
||||
g_gl.frameOwner = owner;
|
||||
g_currentWindow = savedWindow;
|
||||
}
|
||||
|
||||
void APIENTRY glMatrixMode(GLenum mode)
|
||||
@@ -14689,7 +14746,7 @@ void QD3D12_ReleaseWindowSizeResources(QD3D12Window& w)
|
||||
}
|
||||
void QD3D12_Resize()
|
||||
{
|
||||
if (!g_currentWindow)
|
||||
if (!g_currentWindow || !g_currentWindow->swapChain)
|
||||
return;
|
||||
|
||||
RECT rc{};
|
||||
@@ -14718,13 +14775,22 @@ void QD3D12_Resize()
|
||||
|
||||
QD3D12_ReleaseWindowSizeResources(*g_currentWindow);
|
||||
|
||||
QD3D12_CHECK(g_currentWindow->swapChain->ResizeBuffers(
|
||||
HRESULT resizeHr = g_currentWindow->swapChain->ResizeBuffers(
|
||||
QD3D12_FrameCount,
|
||||
width,
|
||||
height,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING
|
||||
));
|
||||
);
|
||||
if (FAILED(resizeHr))
|
||||
{
|
||||
QD3D12_Log("ResizeBuffers failed 0x%08X; recreating swapchain.", (unsigned)resizeHr);
|
||||
g_currentWindow->swapChain.Reset();
|
||||
g_currentWindow->width = width;
|
||||
g_currentWindow->height = height;
|
||||
QD3D12_SelectRenderResolution(*g_currentWindow, width, height);
|
||||
QD3D12_CreateSwapChainForWindow(*g_currentWindow);
|
||||
}
|
||||
|
||||
g_currentWindow->width = width;
|
||||
g_currentWindow->height = height;
|
||||
|
||||
@@ -101,6 +101,7 @@ BOOL WINAPI qd3d12_wglMakeCurrent(HDC hdc, QD3D12_HGLRC hglrc)
|
||||
|
||||
QD3D12FakeContext* ctx = (QD3D12FakeContext*)hglrc;
|
||||
ctx->dc = hdc;
|
||||
const bool wasInitialized = ctx->initialized;
|
||||
|
||||
|
||||
int w = 640, h = 480;
|
||||
@@ -126,16 +127,13 @@ BOOL WINAPI qd3d12_wglMakeCurrent(HDC hdc, QD3D12_HGLRC hglrc)
|
||||
QD3D12_BeginFrame();
|
||||
}
|
||||
|
||||
if (ctx->initialized) {
|
||||
// glFinish();
|
||||
QD3D12_EndFrame();
|
||||
}
|
||||
|
||||
g_currentDC = hdc;
|
||||
g_currentContext = ctx;
|
||||
|
||||
QD3D12_SetCurrentWindow(ctx->window);
|
||||
QD3D12_Resize();
|
||||
if (wasInitialized) {
|
||||
QD3D12_Resize();
|
||||
}
|
||||
|
||||
if (ctx->initialized) {
|
||||
QD3D12_BeginFrame();
|
||||
@@ -162,11 +160,14 @@ BOOL WINAPI qd3d12_wglDeleteContext(QD3D12_HGLRC hglrc)
|
||||
return FALSE;
|
||||
|
||||
QD3D12FakeContext* ctx = (QD3D12FakeContext*)hglrc;
|
||||
const bool embeddedWindow = ctx->hwnd && GetParent(ctx->hwnd) != NULL;
|
||||
|
||||
if (ctx == g_currentContext)
|
||||
{
|
||||
if (ctx->initialized)
|
||||
if (ctx->initialized && !embeddedWindow)
|
||||
QD3D12_ShutdownForQuake();
|
||||
else
|
||||
QD3D12_SetCurrentWindow(NULL);
|
||||
|
||||
g_currentContext = nullptr;
|
||||
g_currentDC = nullptr;
|
||||
@@ -205,4 +206,4 @@ BOOL WINAPI qd3d12_wglSetDeviceGammaRamp3DFX(HDC hdc, LPVOID ramp) {
|
||||
}
|
||||
|
||||
__declspec(dllexport) BOOL WINAPI wglUseFontBitmapsA(HDC, DWORD, DWORD, DWORD) { return FALSE; }
|
||||
__declspec(dllexport) BOOL WINAPI wglUseFontBitmapsW(HDC, DWORD, DWORD, DWORD) { return FALSE; }
|
||||
__declspec(dllexport) BOOL WINAPI wglUseFontBitmapsW(HDC, DWORD, DWORD, DWORD) { return FALSE; }
|
||||
|
||||
@@ -1705,6 +1705,10 @@ typedef struct glRaytracingLight_s
|
||||
// spot: x = near clip, y/z unused
|
||||
// rect : scalar range copy
|
||||
float pointRadiusPad; // non-zero disables specular for this light
|
||||
|
||||
uint32_t iesTextureId; // optional GL texture containing a lat-long IES profile
|
||||
float iesStrength; // 0 disables, 1 uses texture as authored
|
||||
float iesPad[2];
|
||||
} glRaytracingLight_t;
|
||||
|
||||
typedef struct glRaytracingLightingPassDesc_s
|
||||
@@ -1844,6 +1848,7 @@ ID3D12Device* QD3D12_GetDevice(void);
|
||||
ID3D12CommandQueue* QD3D12_GetQueue(void);
|
||||
ID3D12GraphicsCommandList* QD3D12_GetCommandList(void);
|
||||
ID3D12Resource* QD3D12_GetCurrentBackBuffer(void);
|
||||
ID3D12Resource* QD3D12_GetTextureResource(GLuint texture, DXGI_FORMAT* format, UINT* width, UINT* height, ID3D12GraphicsCommandList* commandList);
|
||||
|
||||
static float glRaytracingSqrtf(float x)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
||||
#pragma hdrstop
|
||||
|
||||
#include "tr_local.h"
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
|
||||
@@ -896,6 +897,235 @@ static void LoadPNG(const char* filename, byte** pic, int* width, int* height, I
|
||||
LoadSTBImage(filename, pic, width, height, timestamp);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadIES
|
||||
|
||||
Converts an LM-63 IES photometric profile into a lat-long RGBA8 lookup:
|
||||
X = horizontal angle (0..360), Y = vertical angle (0..180).
|
||||
=============
|
||||
*/
|
||||
static bool IES_ReadFloat(const char*& cursor, const char* end, float& out) {
|
||||
while (cursor < end) {
|
||||
const char c = *cursor;
|
||||
if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.') {
|
||||
break;
|
||||
}
|
||||
cursor++;
|
||||
}
|
||||
if (cursor >= end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* parseEnd = NULL;
|
||||
out = (float)strtod(cursor, &parseEnd);
|
||||
if (parseEnd == cursor) {
|
||||
return false;
|
||||
}
|
||||
cursor = parseEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* IES_FindTiltLine(const char* begin, const char* end) {
|
||||
static const char marker[] = "TILT=";
|
||||
const int markerLen = sizeof(marker) - 1;
|
||||
for (const char* p = begin; p + markerLen <= end; p++) {
|
||||
bool match = true;
|
||||
for (int i = 0; i < markerLen; i++) {
|
||||
char a = p[i];
|
||||
if (a >= 'a' && a <= 'z') {
|
||||
a = a - 'a' + 'A';
|
||||
}
|
||||
if (a != marker[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static float IES_SampleArray(const std::vector<float>& values, int count, float angle) {
|
||||
if (count <= 0 || values.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (count == 1) {
|
||||
return values[0];
|
||||
}
|
||||
|
||||
if (angle <= values[0]) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (angle >= values[count - 1]) {
|
||||
return (angle == values[count - 1]) ? (float)(count - 1) : 0.0f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
const float a0 = values[i];
|
||||
const float a1 = values[i + 1];
|
||||
if (angle >= a0 && angle <= a1) {
|
||||
const float denom = a1 - a0;
|
||||
const float f = denom > 1e-6f ? (angle - a0) / denom : 0.0f;
|
||||
return (float)i + f;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static float IES_CandelaAt(
|
||||
const std::vector<float>& verticalAngles,
|
||||
const std::vector<float>& horizontalAngles,
|
||||
const std::vector<float>& candela,
|
||||
int numVertical,
|
||||
int numHorizontal,
|
||||
float vertical,
|
||||
float horizontal) {
|
||||
if (numVertical <= 0 || numHorizontal <= 0 || candela.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
horizontal = fmodf(horizontal, 360.0f);
|
||||
if (horizontal < 0.0f) {
|
||||
horizontal += 360.0f;
|
||||
}
|
||||
|
||||
const float vf = IES_SampleArray(verticalAngles, numVertical, vertical);
|
||||
const int v0 = idMath::ClampInt(0, numVertical - 1, (int)floorf(vf));
|
||||
const int v1 = idMath::ClampInt(0, numVertical - 1, v0 + 1);
|
||||
const float vt = idMath::ClampFloat(0.0f, 1.0f, vf - (float)v0);
|
||||
|
||||
float hf = 0.0f;
|
||||
if (numHorizontal > 1) {
|
||||
hf = IES_SampleArray(horizontalAngles, numHorizontal, horizontal);
|
||||
}
|
||||
const int h0 = idMath::ClampInt(0, numHorizontal - 1, (int)floorf(hf));
|
||||
const int h1 = idMath::ClampInt(0, numHorizontal - 1, h0 + 1);
|
||||
const float ht = idMath::ClampFloat(0.0f, 1.0f, hf - (float)h0);
|
||||
|
||||
const float c00 = candela[h0 * numVertical + v0];
|
||||
const float c10 = candela[h1 * numVertical + v0];
|
||||
const float c01 = candela[h0 * numVertical + v1];
|
||||
const float c11 = candela[h1 * numVertical + v1];
|
||||
const float c0 = c00 + (c10 - c00) * ht;
|
||||
const float c1 = c01 + (c11 - c01) * ht;
|
||||
return c0 + (c1 - c0) * vt;
|
||||
}
|
||||
|
||||
static void LoadIES(const char* filename, byte** pic, int* width, int* height, ID_TIME_T* timestamp) {
|
||||
byte* fileBuffer = NULL;
|
||||
const int fileLength = fileSystem->ReadFile(filename, (void**)&fileBuffer, timestamp);
|
||||
|
||||
if (pic) {
|
||||
*pic = NULL;
|
||||
}
|
||||
if (width) {
|
||||
*width = 0;
|
||||
}
|
||||
if (height) {
|
||||
*height = 0;
|
||||
}
|
||||
if (!pic || !fileBuffer || fileLength <= 0) {
|
||||
if (fileBuffer) {
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const char* begin = (const char*)fileBuffer;
|
||||
const char* end = begin + fileLength;
|
||||
const char* numeric = IES_FindTiltLine(begin, end);
|
||||
if (!numeric || numeric >= end) {
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
return;
|
||||
}
|
||||
while (numeric < end && *numeric != '\n' && *numeric != '\r') {
|
||||
numeric++;
|
||||
}
|
||||
|
||||
float header[13];
|
||||
for (int i = 0; i < 13; i++) {
|
||||
if (!IES_ReadFloat(numeric, end, header[i])) {
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const int numVertical = idMath::ClampInt(1, 1024, (int)header[3]);
|
||||
const int numHorizontal = idMath::ClampInt(1, 1024, (int)header[4]);
|
||||
const float candelaScale = header[2] > 0.0f ? header[2] : 1.0f;
|
||||
|
||||
std::vector<float> verticalAngles(numVertical);
|
||||
std::vector<float> horizontalAngles(numHorizontal);
|
||||
std::vector<float> candela(numVertical * numHorizontal);
|
||||
|
||||
for (int i = 0; i < numVertical; i++) {
|
||||
if (!IES_ReadFloat(numeric, end, verticalAngles[i])) {
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numHorizontal; i++) {
|
||||
if (!IES_ReadFloat(numeric, end, horizontalAngles[i])) {
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float maxCandela = 0.0f;
|
||||
for (int h = 0; h < numHorizontal; h++) {
|
||||
for (int v = 0; v < numVertical; v++) {
|
||||
float c = 0.0f;
|
||||
if (!IES_ReadFloat(numeric, end, c)) {
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
return;
|
||||
}
|
||||
c *= candelaScale;
|
||||
if (c < 0.0f) {
|
||||
c = 0.0f;
|
||||
}
|
||||
candela[h * numVertical + v] = c;
|
||||
if (c > maxCandela) {
|
||||
maxCandela = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileSystem->FreeFile(fileBuffer);
|
||||
|
||||
if (maxCandela <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int outWidth = 512;
|
||||
const int outHeight = 256;
|
||||
byte* out = (byte*)R_StaticAlloc(outWidth * outHeight * 4);
|
||||
|
||||
for (int y = 0; y < outHeight; y++) {
|
||||
const float vertical = ((float)y + 0.5f) * (180.0f / (float)outHeight);
|
||||
for (int x = 0; x < outWidth; x++) {
|
||||
const float horizontal = ((float)x + 0.5f) * (360.0f / (float)outWidth);
|
||||
const float c = IES_CandelaAt(verticalAngles, horizontalAngles, candela, numVertical, numHorizontal, vertical, horizontal);
|
||||
const byte v = (byte)idMath::ClampInt(0, 255, (int)(255.0f * idMath::ClampFloat(0.0f, 1.0f, c / maxCandela) + 0.5f));
|
||||
byte* dst = out + ((y * outWidth + x) * 4);
|
||||
dst[0] = v;
|
||||
dst[1] = v;
|
||||
dst[2] = v;
|
||||
dst[3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
*pic = out;
|
||||
if (width) {
|
||||
*width = outWidth;
|
||||
}
|
||||
if (height) {
|
||||
*height = outHeight;
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
/*
|
||||
@@ -979,6 +1209,9 @@ void R_LoadImage(const char* cname, byte** pic, int* width, int* height, ID_TIME
|
||||
else if (ext == "png") {
|
||||
LoadPNG(name.c_str(), pic, width, height, timestamp);
|
||||
}
|
||||
else if (ext == "ies") {
|
||||
LoadIES(name.c_str(), pic, width, height, timestamp);
|
||||
}
|
||||
|
||||
if ((width && *width < 1) || (height && *height < 1)) {
|
||||
if (pic && *pic) {
|
||||
@@ -1149,4 +1382,4 @@ bool R_LoadCubeImages(const char* imgName, cubeFiles_t extensions, byte* pics[6]
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ void idMaterial::CommonInit() {
|
||||
stages = NULL;
|
||||
editorImage = NULL;
|
||||
lightFalloffImage = NULL;
|
||||
lightIESImage = NULL;
|
||||
shouldCreateBackSides = false;
|
||||
entityGui = 0;
|
||||
fogLight = false;
|
||||
@@ -2592,6 +2593,9 @@ void idMaterial::ResolveUse(void) {
|
||||
if (lightFalloffImage) {
|
||||
lightFalloffImage->useCount += useCount;
|
||||
}
|
||||
if (lightIESImage) {
|
||||
lightIESImage->useCount += useCount;
|
||||
}
|
||||
if (portalImage) {
|
||||
portalImage->useCount += useCount;
|
||||
}
|
||||
@@ -3030,6 +3034,17 @@ void idMaterial::ParseMaterial(idLexer& src) {
|
||||
lightFalloffImage = globalImages->ImageFromFile(copy, TF_DEFAULT, false, TR_CLAMP /* TR_CLAMP_TO_ZERO */, TD_DEFAULT);
|
||||
continue;
|
||||
}
|
||||
else if (!token.Icmp("iesTexture") || !token.Icmp("lightIESTexture")) {
|
||||
str = R_ParsePastImageProgram(src);
|
||||
idStr copy = str;
|
||||
idStr ext;
|
||||
copy.ExtractFileExtension(ext);
|
||||
if (ext.IsEmpty()) {
|
||||
copy.DefaultFileExtension(".ies");
|
||||
}
|
||||
lightIESImage = globalImages->ImageFromFile(copy, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY);
|
||||
continue;
|
||||
}
|
||||
// guisurf <guifile> | guisurf entity
|
||||
// an entity guisurf must have an idUserInterface
|
||||
// specified in the renderEntity
|
||||
@@ -3256,6 +3271,15 @@ void idMaterial::ParseMaterial(idLexer& src) {
|
||||
}
|
||||
}
|
||||
|
||||
if (lightIESImage && numStages == 0 && !fogLight && !blendLight && !ambientLight) {
|
||||
char buffer[1024];
|
||||
idLexer newSrc;
|
||||
|
||||
idStr::snPrintf(buffer, sizeof(buffer), "blend diffusemap\nmap _white\n}\n");
|
||||
newSrc.LoadMemory(buffer, strlen(buffer), "iesLight");
|
||||
ParseStage(newSrc, trpDefault);
|
||||
}
|
||||
|
||||
// add _flat or _white stages if needed
|
||||
AddImplicitStages();
|
||||
|
||||
|
||||
@@ -764,6 +764,7 @@ public:
|
||||
|
||||
// NULL unless an image is explicitly specified in the shader with "lightFalloffShader <image>"
|
||||
idImage* LightFalloffImage() const { return lightFalloffImage; }
|
||||
idImage* LightIESImage() const { return lightIESImage; }
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
@@ -927,6 +928,7 @@ private:
|
||||
idStr renderBump; // renderbump command options, without the "renderbump" at the start
|
||||
|
||||
idImage* lightFalloffImage;
|
||||
idImage* lightIESImage;
|
||||
|
||||
int entityGui; // draw a gui with the idUserInterface from the renderEntity_t
|
||||
// non zero will draw gui, gui2, or gui3 from renderEnitty_t
|
||||
|
||||
@@ -99,6 +99,7 @@ idRenderLightLocal::idRenderLightLocal() {
|
||||
archived = false;
|
||||
lightShader = NULL;
|
||||
falloffImage = NULL;
|
||||
iesImage = NULL;
|
||||
globalLightOrigin = vec3_zero;
|
||||
frustumTris = NULL;
|
||||
numShadowFrustums = 0;
|
||||
|
||||
@@ -81,7 +81,7 @@ idCVar r_znear( "r_znear", "3", CVAR_RENDERER | CVAR_FLOAT, "near Z clip plane d
|
||||
idCVar r_ignoreGLErrors( "r_ignoreGLErrors", "1", CVAR_RENDERER | CVAR_BOOL, "ignore GL errors" );
|
||||
idCVar r_finish( "r_finish", "0", CVAR_RENDERER | CVAR_BOOL, "force a call to glFinish() every frame" );
|
||||
idCVar r_swapInterval( "r_swapInterval", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "changes wglSwapIntarval" );
|
||||
idCVar r_frameGen( "r_frameGen", "2", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "DLSS frame generation multiplier: 0/1 = off, 2 = 2x, 3 = 3x, 4 = 4x", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> );
|
||||
idCVar r_frameGen( "r_frameGen", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "DLSS frame generation multiplier: 0/1 = off, 2 = 2x, 3 = 3x, 4 = 4x", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> );
|
||||
|
||||
idCVar r_gamma( "r_gamma", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 3.0f );
|
||||
idCVar r_brightness( "r_brightnesspt", "1.5", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 2.0f );
|
||||
|
||||
@@ -201,6 +201,19 @@ void RB_DXDrawInteractions(void)
|
||||
|
||||
light.samples = srcLight.noShadows ? 0u : 1u;
|
||||
light.pointRadiusPad = srcLight.noSpecular ? 1.0f : 0.0f;
|
||||
|
||||
const idVec3 axisU = RB_DXRNormalizeVec3Safe(RB_DXRTransformLightVector(srcLight.axis, RB_DXRMakeVec3(1.0f, 0.0f, 0.0f)), RB_DXRMakeVec3(1.0f, 0.0f, 0.0f));
|
||||
const idVec3 axisV = RB_DXRNormalizeVec3Safe(RB_DXRTransformLightVector(srcLight.axis, RB_DXRMakeVec3(0.0f, 1.0f, 0.0f)), RB_DXRMakeVec3(0.0f, 1.0f, 0.0f));
|
||||
const idVec3 axisW = RB_DXRNormalizeVec3Safe(RB_DXRTransformLightVector(srcLight.axis, RB_DXRMakeVec3(0.0f, 0.0f, 1.0f)), RB_DXRMakeVec3(0.0f, 0.0f, 1.0f));
|
||||
light.axisU.x = axisU.x;
|
||||
light.axisU.y = axisU.y;
|
||||
light.axisU.z = axisU.z;
|
||||
light.axisV.x = axisV.x;
|
||||
light.axisV.y = axisV.y;
|
||||
light.axisV.z = axisV.z;
|
||||
light.normal.x = axisW.x;
|
||||
light.normal.y = axisW.y;
|
||||
light.normal.z = axisW.z;
|
||||
}
|
||||
else if (!srcLight.parallel)
|
||||
{
|
||||
@@ -219,6 +232,13 @@ void RB_DXDrawInteractions(void)
|
||||
}
|
||||
|
||||
if (supported) {
|
||||
if (vLight->iesImage) {
|
||||
vLight->iesImage->Bind();
|
||||
if (vLight->iesImage->texnum != idImage::TEXTURE_NOT_LOADED) {
|
||||
light.iesTextureId = vLight->iesImage->texnum;
|
||||
light.iesStrength = 1.0f;
|
||||
}
|
||||
}
|
||||
glRaytracingLightingAddLight(&light);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,6 +498,7 @@ viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *light ) {
|
||||
vLight->fogPlane = light->frustum[5];
|
||||
vLight->frustumTris = light->frustumTris;
|
||||
vLight->falloffImage = light->falloffImage;
|
||||
vLight->iesImage = light->iesImage;
|
||||
vLight->lightShader = light->lightShader;
|
||||
vLight->shaderRegisters = NULL; // allocated and evaluated in R_AddLightSurfaces
|
||||
|
||||
|
||||
@@ -365,6 +365,7 @@ void R_DeriveLightData( idRenderLightLocal *light ) {
|
||||
|
||||
// get the falloff image
|
||||
light->falloffImage = light->lightShader->LightFalloffImage();
|
||||
light->iesImage = light->lightShader->LightIESImage();
|
||||
if ( !light->falloffImage ) {
|
||||
// use the falloff from the default shader of the correct type
|
||||
const idMaterial *defaultShader;
|
||||
|
||||
@@ -209,6 +209,7 @@ public:
|
||||
|
||||
const idMaterial * lightShader; // guaranteed to be valid, even if parms.shader isn't
|
||||
idImage * falloffImage;
|
||||
idImage * iesImage;
|
||||
|
||||
idVec3 globalLightOrigin; // accounting for lightCenter and parallel
|
||||
|
||||
@@ -322,6 +323,7 @@ typedef struct viewLight_s {
|
||||
const idMaterial * lightShader; // light shader used by backend
|
||||
const float * shaderRegisters; // shader registers used by backend
|
||||
idImage * falloffImage; // falloff image used by backend
|
||||
idImage * iesImage; // optional IES photometric profile
|
||||
|
||||
const struct drawSurf_s *globalShadows; // shadow everything
|
||||
const struct drawSurf_s *localInteractions; // don't get local shadows
|
||||
|
||||
Reference in New Issue
Block a user