mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Numerous performance fixes.
This commit is contained in:
@@ -4303,6 +4303,8 @@ static classVariableInfo_t srfTriangles_t_typeInfo[] = {
|
||||
{ "vertCache_s *", "ambientCache", (intptr_t)(&((srfTriangles_t *)0)->ambientCache), sizeof( ((srfTriangles_t *)0)->ambientCache ) },
|
||||
{ "vertCache_s *", "lightingCache", (intptr_t)(&((srfTriangles_t *)0)->lightingCache), sizeof( ((srfTriangles_t *)0)->lightingCache ) },
|
||||
{ "vertCache_s *", "shadowCache", (intptr_t)(&((srfTriangles_t *)0)->shadowCache), sizeof( ((srfTriangles_t *)0)->shadowCache ) },
|
||||
{ "unsigned int", "ambientVbo", (intptr_t)(&((srfTriangles_t *)0)->ambientVbo), sizeof( ((srfTriangles_t *)0)->ambientVbo ) },
|
||||
{ "unsigned int", "indexVbo", (intptr_t)(&((srfTriangles_t *)0)->indexVbo), sizeof( ((srfTriangles_t *)0)->indexVbo ) },
|
||||
{ "bool", "isSkeletal", (intptr_t)(&((srfTriangles_t *)0)->isSkeletal), sizeof( ((srfTriangles_t *)0)->isSkeletal ) },
|
||||
{ "int", "numAllocedVerts", (intptr_t)(&((srfTriangles_t *)0)->numAllocedVerts), sizeof( ((srfTriangles_t *)0)->numAllocedVerts ) },
|
||||
{ "int", "numAllocedIndices", (intptr_t)(&((srfTriangles_t *)0)->numAllocedIndices), sizeof( ((srfTriangles_t *)0)->numAllocedIndices ) },
|
||||
|
||||
@@ -1606,6 +1606,7 @@
|
||||
<ClCompile Include="renderer\tr_font.cpp" />
|
||||
<ClCompile Include="renderer\tr_guisurf.cpp" />
|
||||
<ClCompile Include="renderer\tr_light.cpp" />
|
||||
<ClCompile Include="renderer\tr_masked_occlusion.cpp" />
|
||||
<ClCompile Include="renderer\tr_lightrun.cpp" />
|
||||
<ClCompile Include="renderer\tr_main.cpp" />
|
||||
<ClCompile Include="renderer\tr_polytope.cpp" />
|
||||
@@ -3102,4 +3103,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -782,6 +782,9 @@
|
||||
<ClCompile Include="renderer\tr_light.cpp">
|
||||
<Filter>Renderer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="renderer\tr_masked_occlusion.cpp">
|
||||
<Filter>Renderer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="renderer\tr_lightrun.cpp">
|
||||
<Filter>Renderer</Filter>
|
||||
</ClCompile>
|
||||
@@ -2420,4 +2423,4 @@
|
||||
<Filter>Sys\RC\res</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerCommandArguments>+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 +set fs_game e3</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerWorkingDirectory>D:\projects\Doom3</LocalDebuggerWorkingDirectory>
|
||||
<LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 9|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 |+set r_fullscreen 1 +set r_mode 9 +set sv_pure 0 +set fs_game e3|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 +set fs_game e3|</LocalDebuggerCommandArgumentsHistory>
|
||||
<LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 9|+set r_fullscreen 1 +set r_mode 9 +set sv_pure 0 +set fs_game e3|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 |+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 +set fs_game e3|</LocalDebuggerCommandArgumentsHistory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Q4 Debug|x64'">
|
||||
<LocalDebuggerCommand>D:\projects\Doom3\Quake4.exe</LocalDebuggerCommand>
|
||||
|
||||
@@ -123,6 +123,9 @@ int time_gameFrame;
|
||||
int time_gameDraw;
|
||||
int time_frontend; // renderSystem frontend time
|
||||
int time_backend; // renderSystem backend time
|
||||
float com_lastGameFrameMsec;
|
||||
float com_lastRenderFrameMsec;
|
||||
float com_pathTracingGpuMsec;
|
||||
|
||||
#ifdef QUAKE4
|
||||
int time_waiting; // wait time, surfaced by Quake 4's timing/debug HUD path
|
||||
@@ -3211,6 +3214,9 @@ void idCommonLocal::Frame(void) {
|
||||
session->UpdateScreen(false);
|
||||
}
|
||||
|
||||
com_lastGameFrameMsec = (float)time_gameFrame;
|
||||
com_lastRenderFrameMsec = (float)(time_gameDraw + time_frontend + time_backend);
|
||||
|
||||
// report timing information
|
||||
if (com_speeds.GetBool()) {
|
||||
static int lastTime;
|
||||
@@ -3221,6 +3227,12 @@ void idCommonLocal::Frame(void) {
|
||||
time_gameFrame = 0;
|
||||
time_gameDraw = 0;
|
||||
}
|
||||
else {
|
||||
time_gameFrame = 0;
|
||||
time_gameDraw = 0;
|
||||
time_frontend = 0;
|
||||
time_backend = 0;
|
||||
}
|
||||
|
||||
com_frameNumber++;
|
||||
|
||||
@@ -4051,4 +4063,4 @@ void idCommonLocal::MaterialKeyForBinding(const char* binding, char* materialNam
|
||||
strcpy(keyText, displayName.c_str());
|
||||
*wideKey = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -177,6 +177,9 @@ extern int time_gameFrame; // game logic time
|
||||
extern int time_gameDraw; // game present time
|
||||
extern int time_frontend; // renderer frontend time
|
||||
extern int time_backend; // renderer backend time
|
||||
extern float com_lastGameFrameMsec; // last displayed game CPU time
|
||||
extern float com_lastRenderFrameMsec;// last displayed render CPU time
|
||||
extern float com_pathTracingGpuMsec; // last completed path tracing GPU time
|
||||
#ifdef QUAKE4
|
||||
extern int time_waiting; // time spent waiting
|
||||
#endif
|
||||
|
||||
@@ -212,6 +212,12 @@ float SCR_DrawFPS( float y ) {
|
||||
w = strlen( s ) * BIGCHAR_WIDTH;
|
||||
|
||||
renderSystem->DrawBigStringExt( (SCREEN_WIDTH - 5.0f) - w, idMath::FtoiFast(y) + 2, s, colorWhite, true, localConsole.charSetShader);
|
||||
|
||||
y += BIGCHAR_HEIGHT + 4;
|
||||
s = va( "game cpu:%4.1fms render cpu:%4.1fms pt gpu:%4.1fms", com_lastGameFrameMsec, com_lastRenderFrameMsec, com_pathTracingGpuMsec );
|
||||
w = strlen( s ) * SMALLCHAR_WIDTH;
|
||||
renderSystem->DrawSmallStringExt( (SCREEN_WIDTH - 5.0f) - w, idMath::FtoiFast(y) + 2, s, colorWhite, true, localConsole.charSetShader);
|
||||
return y + SMALLCHAR_HEIGHT + 4;
|
||||
}
|
||||
|
||||
return y + BIGCHAR_HEIGHT + 4;
|
||||
|
||||
@@ -2686,7 +2686,7 @@ void idSessionLocal::UpdateScreen( bool outOfSequence ) {
|
||||
// draw everything
|
||||
Draw();
|
||||
|
||||
if ( com_speeds.GetBool() ) {
|
||||
if ( com_speeds.GetBool() || com_showFPS.GetBool() ) {
|
||||
renderSystem->EndFrame( &time_frontend, &time_backend );
|
||||
} else {
|
||||
renderSystem->EndFrame( NULL, NULL );
|
||||
|
||||
@@ -623,6 +623,8 @@ void idRenderModelStatic::UpdateDXR(uint32_t& dxrBottomAcel, int onlySurface)
|
||||
desc.vertexCount = (uint32_t)numDXRVerts;
|
||||
desc.indices = indices.data();
|
||||
desc.indexCount = (uint32_t)numDXRIndexes;
|
||||
desc.allowUpdate = 1;
|
||||
desc.opaque = 1;
|
||||
|
||||
if (!dxrBottomAcel)
|
||||
{
|
||||
@@ -2223,6 +2225,14 @@ void idRenderModelStatic::FreeVertexCache( void ) {
|
||||
vertexCache.Free( tri->ambientCache );
|
||||
tri->ambientCache = NULL;
|
||||
}
|
||||
if ( tri->ambientVbo ) {
|
||||
glDeleteBuffersARB( 1, &tri->ambientVbo );
|
||||
tri->ambientVbo = 0;
|
||||
}
|
||||
if ( tri->indexVbo ) {
|
||||
glDeleteBuffersARB( 1, &tri->indexVbo );
|
||||
tri->indexVbo = 0;
|
||||
}
|
||||
// static shadows may be present
|
||||
if ( tri->shadowCache ) {
|
||||
vertexCache.Free( tri->shadowCache );
|
||||
|
||||
@@ -138,6 +138,9 @@ typedef struct srfTriangles_s {
|
||||
struct vertCache_s * lightingCache; // lightingCache_t
|
||||
struct vertCache_s * shadowCache; // shadowCache_t
|
||||
|
||||
unsigned int ambientVbo; // model-owned idDrawVert GL buffer
|
||||
unsigned int indexVbo; // model-owned index GL buffer
|
||||
|
||||
bool isSkeletal;
|
||||
int numAllocedVerts;
|
||||
int numAllocedIndices;
|
||||
|
||||
@@ -49,6 +49,8 @@ If you have questions concerning this license or the applicable additional terms
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
extern float com_pathTracingGpuMsec;
|
||||
|
||||
// ============================================================
|
||||
// Logging / checks
|
||||
// ============================================================
|
||||
@@ -407,6 +409,10 @@ struct glRaytracingCmdContext_t
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
HANDLE fenceEvent;
|
||||
UINT64 nextFenceValue;
|
||||
ComPtr<ID3D12QueryHeap> pathTracingTimestampHeap;
|
||||
glRaytracingBuffer_t pathTracingTimestampReadback;
|
||||
UINT64 pathTracingTimestampFrequency;
|
||||
UINT64 pathTracingTimestampFenceRing[GL_RAYTRACING_CMD_RING_SIZE];
|
||||
bool initialized;
|
||||
|
||||
glRaytracingCmdContext_t()
|
||||
@@ -425,9 +431,11 @@ struct glRaytracingCmdContext_t
|
||||
cmdFenceValueRing[i] = 0;
|
||||
blasFenceValueRing[i] = 0;
|
||||
tlasFenceValueRing[i] = 0;
|
||||
pathTracingTimestampFenceRing[i] = 0;
|
||||
}
|
||||
fenceEvent = nullptr;
|
||||
nextFenceValue = 0;
|
||||
pathTracingTimestampFrequency = 0;
|
||||
initialized = false;
|
||||
}
|
||||
};
|
||||
@@ -463,6 +471,66 @@ static void glRaytracingWaitIdle(void)
|
||||
glRaytracingWaitFenceValue(value);
|
||||
}
|
||||
|
||||
static void glRaytracingPollPathTracingTimestamp(UINT slot)
|
||||
{
|
||||
if (!g_glRaytracingCmd.pathTracingTimestampReadback.resource ||
|
||||
!g_glRaytracingCmd.pathTracingTimestampFrequency ||
|
||||
slot >= GL_RAYTRACING_CMD_RING_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const UINT64 fenceValue = g_glRaytracingCmd.pathTracingTimestampFenceRing[slot];
|
||||
if (!fenceValue || !g_glRaytracingCmd.fence || g_glRaytracingCmd.fence->GetCompletedValue() < fenceValue)
|
||||
return;
|
||||
|
||||
const UINT64 offset = sizeof(UINT64) * 2ull * slot;
|
||||
D3D12_RANGE readRange = { offset, offset + sizeof(UINT64) * 2ull };
|
||||
UINT64* timestamps = nullptr;
|
||||
if (SUCCEEDED(g_glRaytracingCmd.pathTracingTimestampReadback.resource->Map(0, &readRange, reinterpret_cast<void**>(×tamps))) && timestamps != nullptr)
|
||||
{
|
||||
const UINT64 begin = timestamps[slot * 2 + 0];
|
||||
const UINT64 end = timestamps[slot * 2 + 1];
|
||||
if (end >= begin)
|
||||
{
|
||||
com_pathTracingGpuMsec = (float)((double)(end - begin) * 1000.0 / (double)g_glRaytracingCmd.pathTracingTimestampFrequency);
|
||||
}
|
||||
|
||||
D3D12_RANGE writeRange = { 0, 0 };
|
||||
g_glRaytracingCmd.pathTracingTimestampReadback.resource->Unmap(0, &writeRange);
|
||||
}
|
||||
g_glRaytracingCmd.pathTracingTimestampFenceRing[slot] = 0;
|
||||
}
|
||||
|
||||
static int glRaytracingCreatePathTracingTimestamps(void)
|
||||
{
|
||||
D3D12_QUERY_HEAP_DESC qh = {};
|
||||
qh.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
|
||||
qh.Count = GL_RAYTRACING_CMD_RING_SIZE * 2;
|
||||
if (FAILED(g_glRaytracingCmd.device->CreateQueryHeap(&qh, IID_PPV_ARGS(&g_glRaytracingCmd.pathTracingTimestampHeap))))
|
||||
return 0;
|
||||
|
||||
g_glRaytracingCmd.pathTracingTimestampReadback = glRaytracingCreateBuffer(
|
||||
g_glRaytracingCmd.device.Get(),
|
||||
sizeof(UINT64) * GL_RAYTRACING_CMD_RING_SIZE * 2ull,
|
||||
D3D12_HEAP_TYPE_READBACK,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
D3D12_RESOURCE_FLAG_NONE);
|
||||
if (!g_glRaytracingCmd.pathTracingTimestampReadback.resource)
|
||||
return 0;
|
||||
|
||||
g_glRaytracingCmd.pathTracingTimestampFrequency = 0;
|
||||
if (FAILED(g_glRaytracingCmd.queue->GetTimestampFrequency(&g_glRaytracingCmd.pathTracingTimestampFrequency)) ||
|
||||
g_glRaytracingCmd.pathTracingTimestampFrequency == 0)
|
||||
{
|
||||
g_glRaytracingCmd.pathTracingTimestampHeap.Reset();
|
||||
g_glRaytracingCmd.pathTracingTimestampReadback = glRaytracingBuffer_t();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int glRaytracingCreateDirectCommandListPair(
|
||||
ID3D12Device5* device,
|
||||
ComPtr<ID3D12CommandAllocator>& allocator,
|
||||
@@ -562,6 +630,11 @@ static int glRaytracingInitCmdContext(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!glRaytracingCreatePathTracingTimestamps())
|
||||
{
|
||||
glRaytracingLog("path tracing timestamp queries unavailable");
|
||||
}
|
||||
|
||||
g_glRaytracingCmd.initialized = true;
|
||||
return 1;
|
||||
}
|
||||
@@ -586,6 +659,7 @@ static int glRaytracingBeginCmd(void)
|
||||
{
|
||||
const UINT slot = (g_glRaytracingCmd.cmdRingIndex + 1u) % GL_RAYTRACING_CMD_RING_SIZE;
|
||||
glRaytracingWaitFenceValue(g_glRaytracingCmd.cmdFenceValueRing[slot]);
|
||||
glRaytracingPollPathTracingTimestamp(slot);
|
||||
|
||||
g_glRaytracingCmd.cmdRingIndex = slot;
|
||||
g_glRaytracingCmd.cmdCurrentSlot = slot;
|
||||
@@ -1965,12 +2039,52 @@ int glRaytracingUpdateMesh(glRaytracingMeshHandle_t meshHandle, const glRaytraci
|
||||
if (!desc->vertices || !desc->indices || desc->vertexCount == 0 || desc->indexCount == 0)
|
||||
return 0;
|
||||
|
||||
const UINT64 vbBytes = UINT64(desc->vertexCount) * sizeof(glRaytracingVertex_t);
|
||||
const UINT64 ibBytes = UINT64(desc->indexCount) * sizeof(uint32_t);
|
||||
const bool sameVertexData =
|
||||
mesh->verticesCpu.size() == desc->vertexCount &&
|
||||
memcmp(mesh->verticesCpu.data(), desc->vertices, (size_t)vbBytes) == 0;
|
||||
const bool sameIndexData =
|
||||
mesh->indicesCpu.size() == desc->indexCount &&
|
||||
memcmp(mesh->indicesCpu.data(), desc->indices, (size_t)ibBytes) == 0;
|
||||
const bool sameDesc =
|
||||
mesh->descCpu.vertexCount == desc->vertexCount &&
|
||||
mesh->descCpu.indexCount == desc->indexCount &&
|
||||
mesh->descCpu.allowUpdate == desc->allowUpdate &&
|
||||
mesh->descCpu.opaque == desc->opaque;
|
||||
|
||||
if (sameDesc && sameVertexData && sameIndexData)
|
||||
return 1;
|
||||
|
||||
const bool canUpdateExistingBuffers =
|
||||
desc->allowUpdate != 0 &&
|
||||
mesh->descCpu.allowUpdate != 0 &&
|
||||
mesh->descCpu.opaque == desc->opaque &&
|
||||
mesh->blasBuilt != 0 &&
|
||||
mesh->vertexBuffer.resource &&
|
||||
mesh->indexBuffer.resource &&
|
||||
mesh->vertexBuffer.size >= vbBytes &&
|
||||
mesh->indexBuffer.size >= ibBytes &&
|
||||
mesh->verticesCpu.size() == desc->vertexCount &&
|
||||
mesh->indicesCpu.size() == desc->indexCount;
|
||||
|
||||
mesh->descCpu = *desc;
|
||||
mesh->verticesCpu.assign(desc->vertices, desc->vertices + desc->vertexCount);
|
||||
mesh->indicesCpu.assign(desc->indices, desc->indices + desc->indexCount);
|
||||
mesh->descCpu.vertices = nullptr;
|
||||
mesh->descCpu.indices = nullptr;
|
||||
|
||||
if (canUpdateExistingBuffers)
|
||||
{
|
||||
glRaytracingMapCopy(mesh->vertexBuffer.resource.Get(), mesh->verticesCpu.data(), (size_t)vbBytes);
|
||||
if (!sameIndexData)
|
||||
glRaytracingMapCopy(mesh->indexBuffer.resource.Get(), mesh->indicesCpu.data(), (size_t)ibBytes);
|
||||
|
||||
mesh->dirty = 1;
|
||||
glRaytracingInvalidateInstancesForMesh(meshHandle, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Updating a mesh destroys/replaces resources that an already submitted frame
|
||||
// may still reference. Wait only for this destructive path; steady-state
|
||||
// rendering remains asynchronous.
|
||||
@@ -2132,6 +2246,9 @@ int glRaytracingUpdateInstanceInScene(glRaytracingSceneHandle_t worldHandle, glR
|
||||
? 0u
|
||||
: glRaytracingNormalizeVisibleInstanceMask(newDesc.mask);
|
||||
|
||||
if (memcmp(&inst->descCpu, &newDesc, sizeof(newDesc)) == 0)
|
||||
return 1;
|
||||
|
||||
inst->descCpu = newDesc;
|
||||
inst->dirty = 1;
|
||||
|
||||
@@ -6440,6 +6557,18 @@ static bool glRaytracingLightingExecuteInternal(
|
||||
g_glRaytracingCmd.cmdList->SetComputeRootConstantBufferView(2, g_glRaytracingLighting.constantBuffer.gpuVA);
|
||||
g_glRaytracingCmd.cmdList->SetPipelineState1(g_glRaytracingLighting.rtStateObject.Get());
|
||||
|
||||
const UINT timestampBase = g_glRaytracingCmd.cmdCurrentSlot * 2u;
|
||||
const bool writeTimestamp =
|
||||
g_glRaytracingCmd.pathTracingTimestampHeap.Get() != nullptr &&
|
||||
g_glRaytracingCmd.pathTracingTimestampReadback.resource.Get() != nullptr;
|
||||
if (writeTimestamp)
|
||||
{
|
||||
g_glRaytracingCmd.cmdList->EndQuery(
|
||||
g_glRaytracingCmd.pathTracingTimestampHeap.Get(),
|
||||
D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
timestampBase + 0u);
|
||||
}
|
||||
|
||||
const UINT shaderRecordSize = (UINT)glRaytracingAlignUp(
|
||||
D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES,
|
||||
D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
|
||||
@@ -6586,9 +6715,27 @@ static bool glRaytracingLightingExecuteInternal(
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
if (writeTimestamp)
|
||||
{
|
||||
g_glRaytracingCmd.cmdList->EndQuery(
|
||||
g_glRaytracingCmd.pathTracingTimestampHeap.Get(),
|
||||
D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
timestampBase + 1u);
|
||||
g_glRaytracingCmd.cmdList->ResolveQueryData(
|
||||
g_glRaytracingCmd.pathTracingTimestampHeap.Get(),
|
||||
D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
timestampBase,
|
||||
2,
|
||||
g_glRaytracingCmd.pathTracingTimestampReadback.resource.Get(),
|
||||
sizeof(UINT64) * timestampBase);
|
||||
}
|
||||
|
||||
if (!glRaytracingEndCmd())
|
||||
return false;
|
||||
|
||||
if (writeTimestamp)
|
||||
g_glRaytracingCmd.pathTracingTimestampFenceRing[g_glRaytracingCmd.cmdCurrentSlot] = g_glRaytracingCmd.cmdLastFenceValue;
|
||||
|
||||
if (useInternalDenoiser)
|
||||
g_glRaytracingLighting.currentHistoryIndex = historyWriteIndex;
|
||||
|
||||
|
||||
+871
-221
File diff suppressed because it is too large
Load Diff
@@ -2328,6 +2328,7 @@ void QD3D12_SetUpscalerSharpness(float sharpness);
|
||||
void QD3D12_SetToneMapBrightness(float brightness);
|
||||
void QD3D12_SetFrameGenerationMultiplier(int multiplier);
|
||||
int QD3D12_GetFrameGenerationMultiplier(void);
|
||||
void QD3D12_SetCurrentWindowDLSSAllowed(int allowed);
|
||||
|
||||
void QD3D12_EnableTAA(int enabled);
|
||||
|
||||
|
||||
@@ -45,7 +45,23 @@
|
||||
<ClCompile Include="gl_d3d12shim.cpp" />
|
||||
<ClCompile Include="gl_d3d12tess.cpp" />
|
||||
<ClCompile Include="gl_d3d12wgl.cpp" />
|
||||
<ClCompile Include="gl_radiant_moc.cpp" />
|
||||
<ClCompile Include="nn_mattrain.cpp" />
|
||||
<ClCompile Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCulling.cpp">
|
||||
<PreprocessorDefinitions>USE_D3D=0;USE_AVX512=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Q4 Debug|x64'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCullingAVX2.cpp">
|
||||
<PreprocessorDefinitions>USE_D3D=0;USE_AVX512=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalOptions>/arch:AVX2 %(AdditionalOptions)</AdditionalOptions>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Q4 Debug|x64'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Prey Debug|x64'">MaxSpeed</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\dict.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Q4 Debug|x64'">MaxSpeed</Optimization>
|
||||
@@ -182,7 +198,11 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DirectInputShim.h" />
|
||||
<ClInclude Include="gl_d3d12arb.h" />
|
||||
<ClInclude Include="gl_radiant_moc.h" />
|
||||
<ClInclude Include="opengl.h" />
|
||||
<ClInclude Include="thirdparty\MaskedOcclusionCulling\CompilerSpecific.inl" />
|
||||
<ClInclude Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCulling.h" />
|
||||
<ClInclude Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCullingCommon.inl" />
|
||||
<ClInclude Include="opengl_nn.h" />
|
||||
<ClInclude Include="tess\dict-list.h" />
|
||||
<ClInclude Include="tess\dict.h" />
|
||||
@@ -373,6 +393,8 @@
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>streamline/include;d3d12/;</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
<Optimization>Full</Optimization>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
|
||||
@@ -44,6 +44,13 @@
|
||||
<ClCompile Include="gl_d3d12arb.cpp" />
|
||||
<ClCompile Include="DirectInputShim.cpp" />
|
||||
<ClCompile Include="nn_mattrain.cpp" />
|
||||
<ClCompile Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCulling.cpp">
|
||||
<Filter>thirdparty\MaskedOcclusionCulling</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCullingAVX2.cpp">
|
||||
<Filter>thirdparty\MaskedOcclusionCulling</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gl_radiant_moc.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="opengl.h" />
|
||||
@@ -98,6 +105,16 @@
|
||||
<ClInclude Include="gl_d3d12arb.h" />
|
||||
<ClInclude Include="DirectInputShim.h" />
|
||||
<ClInclude Include="opengl_nn.h" />
|
||||
<ClInclude Include="thirdparty\MaskedOcclusionCulling\CompilerSpecific.inl">
|
||||
<Filter>thirdparty\MaskedOcclusionCulling</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCulling.h">
|
||||
<Filter>thirdparty\MaskedOcclusionCulling</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="thirdparty\MaskedOcclusionCulling\MaskedOcclusionCullingCommon.inl">
|
||||
<Filter>thirdparty\MaskedOcclusionCulling</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gl_radiant_moc.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="tess">
|
||||
@@ -106,6 +123,12 @@
|
||||
<Filter Include="streamline">
|
||||
<UniqueIdentifier>{ac325e42-ffb4-4bbc-a4ec-b567658773a3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="thirdparty">
|
||||
<UniqueIdentifier>{8e15d873-a9f6-421d-97b5-3bb07f870144}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="thirdparty\MaskedOcclusionCulling">
|
||||
<UniqueIdentifier>{9420a408-8b6e-4ce4-bd61-97537c296ec6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="tess\tessellate.js">
|
||||
@@ -117,4 +140,4 @@
|
||||
<Filter>streamline</Filter>
|
||||
</Library>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -726,7 +726,7 @@ void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec, bool sw
|
||||
*frontEndMsec = pc.frontEndMsec;
|
||||
}
|
||||
if ( backEndMsec ) {
|
||||
*backEndMsec = backEnd.pc.msec;
|
||||
*backEndMsec = backEnd.pc.cpuMsecNoSwap;
|
||||
}
|
||||
|
||||
// print any other statistics and clear all of them
|
||||
|
||||
@@ -118,6 +118,8 @@ idCVar r_ignore2( "r_ignore2", "0", CVAR_RENDERER, "used for random debugging wi
|
||||
idCVar r_usePreciseTriangleInteractions( "r_usePreciseTriangleInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "1 = do winding clipping to determine if each ambiguous tri should be lit" );
|
||||
idCVar r_useCulling( "r_useCulling", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = sphere, 2 = sphere + box", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
|
||||
idCVar r_useLightCulling( "r_useLightCulling", "3", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 = also areas", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
|
||||
idCVar r_useMaskedOcclusionCulling( "r_useMaskedOcclusionCulling", "1", CVAR_RENDERER | CVAR_BOOL, "threaded one-frame-late masked occlusion culling for renderer lights" );
|
||||
idCVar r_mocResolutionScale( "r_mocResolutionScale", "0.5", CVAR_RENDERER | CVAR_FLOAT, "software occlusion buffer resolution scale for masked light culling", 0.125f, 1.0f );
|
||||
idCVar r_useLightScissors( "r_useLightScissors", "1", CVAR_RENDERER | CVAR_BOOL, "1 = use custom scissor rectangle for each light" );
|
||||
idCVar r_useClippedLightScissors( "r_useClippedLightScissors", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
|
||||
idCVar r_useEntityCulling( "r_useEntityCulling", "1", CVAR_RENDERER | CVAR_BOOL, "0 = none, 1 = box" );
|
||||
@@ -1988,6 +1990,8 @@ idRenderSystemLocal::Shutdown
|
||||
void idRenderSystemLocal::Shutdown( void ) {
|
||||
common->Printf( "idRenderSystem::Shutdown()\n" );
|
||||
|
||||
R_MaskedOcclusionCulling_Shutdown();
|
||||
|
||||
R_DoneFreeType( );
|
||||
|
||||
if ( glConfig.isInitialized ) {
|
||||
|
||||
@@ -269,23 +269,17 @@ idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src ) {
|
||||
tri->numIndexes = src->ParseInt();
|
||||
tri->shadowCapPlaneBits = src->ParseInt();
|
||||
|
||||
R_AllocStaticTriSurfShadowVerts( tri, tri->numVerts );
|
||||
tri->bounds.Clear();
|
||||
for ( j = 0 ; j < tri->numVerts ; j++ ) {
|
||||
float vec[8];
|
||||
|
||||
src->Parse1DMatrix( 3, vec );
|
||||
tri->shadowVertexes[j].xyz[0] = vec[0];
|
||||
tri->shadowVertexes[j].xyz[1] = vec[1];
|
||||
tri->shadowVertexes[j].xyz[2] = vec[2];
|
||||
tri->shadowVertexes[j].xyz[3] = 1; // no homogenous value
|
||||
|
||||
tri->bounds.AddPoint( tri->shadowVertexes[j].xyz.ToVec3() );
|
||||
tri->bounds.AddPoint( idVec3( vec[0], vec[1], vec[2] ) );
|
||||
}
|
||||
|
||||
R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
|
||||
for ( j = 0 ; j < tri->numIndexes ; j++ ) {
|
||||
tri->indexes[j] = src->ParseInt();
|
||||
src->ParseInt();
|
||||
}
|
||||
|
||||
// add the completed surface to the model
|
||||
|
||||
@@ -32,6 +32,14 @@ If you have questions concerning this license or the applicable additional terms
|
||||
|
||||
idCVar r_renderNeuralMaterial("r_renderNeuralMaterial", "0", CVAR_BOOL, "");
|
||||
|
||||
static idDrawVert *RB_BindAmbientBuffer( const srfTriangles_t *tri ) {
|
||||
if ( tri->ambientVbo ) {
|
||||
glBindBufferARB( GL_ARRAY_BUFFER_ARB, tri->ambientVbo );
|
||||
return (idDrawVert *)0;
|
||||
}
|
||||
return (idDrawVert *)vertexCache.Position( tri->ambientCache );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
RB_BakeTextureMatrixIntoTexgen
|
||||
@@ -389,7 +397,7 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tri->ambientCache) {
|
||||
if (!tri->ambientVbo && !tri->ambientCache) {
|
||||
common->Printf("RB_T_FillDepthBuffer: !tri->ambientCache\n");
|
||||
return;
|
||||
}
|
||||
@@ -435,7 +443,7 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
|
||||
color[3] = 1.0f;
|
||||
}
|
||||
|
||||
idDrawVert* ac = (idDrawVert*)vertexCache.Position(tri->ambientCache);
|
||||
idDrawVert* ac = RB_BindAmbientBuffer(tri);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(idDrawVert), ac->xyz.ToFloatPtr());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(idDrawVert), reinterpret_cast<void*>(&ac->st));
|
||||
@@ -558,7 +566,7 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
|
||||
// draw it
|
||||
RB_DrawElementsWithCounters(tri);
|
||||
|
||||
RB_FinishStageTexturing(pStage, surf, ac);
|
||||
//RB_FinishStageTexturing(pStage, surf, ac);
|
||||
|
||||
if (glowMapImage) {
|
||||
GL_SelectTexture(3);
|
||||
@@ -642,11 +650,7 @@ void RB_STD_FillDepthBuffer( drawSurf_t **drawSurfs, int numDrawSurfs ) {
|
||||
|
||||
GL_State( GLS_DEPTHFUNC_LESS );
|
||||
|
||||
// Enable stencil test if we are going to be using it for shadows.
|
||||
// If we didn't do this, it would be legal behavior to get z fighting
|
||||
// from the ambient pass and the light passes.
|
||||
glEnable( GL_STENCIL_TEST );
|
||||
glStencilFunc( GL_ALWAYS, 1, 255 );
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
|
||||
RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_T_FillDepthBuffer );
|
||||
|
||||
@@ -827,7 +831,7 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !tri->ambientCache ) {
|
||||
if ( !tri->ambientVbo && !tri->ambientCache ) {
|
||||
common->Printf( "RB_T_RenderShaderPasses: !tri->ambientCache\n" );
|
||||
return;
|
||||
}
|
||||
@@ -852,7 +856,7 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
||||
RB_EnterModelDepthHack( surf->space->modelDepthHack );
|
||||
}
|
||||
|
||||
idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
|
||||
idDrawVert *ac = RB_BindAmbientBuffer( tri );
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
|
||||
glTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast<void *>(&ac->st) );
|
||||
|
||||
@@ -1167,13 +1171,9 @@ static void RB_T_BlendLight( const drawSurf_t *surf ) {
|
||||
glTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() );
|
||||
}
|
||||
|
||||
// this gets used for both blend lights and shadow draws
|
||||
if ( tri->ambientCache ) {
|
||||
idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
|
||||
if ( tri->ambientVbo || tri->ambientCache ) {
|
||||
idDrawVert *ac = RB_BindAmbientBuffer( tri );
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
|
||||
} else if ( tri->shadowCache ) {
|
||||
shadowCache_t *sc = (shadowCache_t *)vertexCache.Position( tri->shadowCache );
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( shadowCache_t ), sc->xyz.ToFloatPtr() );
|
||||
}
|
||||
|
||||
RB_DrawElementsWithCounters( tri );
|
||||
@@ -1323,7 +1323,7 @@ static void RB_FogPass( const drawSurf_t *drawSurfs, const drawSurf_t *drawSurf
|
||||
frustumTris = backEnd.vLight->frustumTris;
|
||||
|
||||
// if we ran out of vertex cache memory, skip it
|
||||
if ( !frustumTris->ambientCache ) {
|
||||
if ( !frustumTris->ambientVbo && !frustumTris->ambientCache ) {
|
||||
return;
|
||||
}
|
||||
memset( &ds, 0, sizeof( ds ) );
|
||||
@@ -1513,9 +1513,6 @@ void RB_STD_DrawView( void ) {
|
||||
// main light renderer
|
||||
RB_DXDrawInteractions();
|
||||
|
||||
// disable stencil shadow test
|
||||
glStencilFunc( GL_ALWAYS, 128, 255 );
|
||||
|
||||
// now draw any non-light dependent shading passes
|
||||
int processed = RB_STD_DrawShaderPasses( drawSurfs, numDrawSurfs );
|
||||
|
||||
|
||||
@@ -174,6 +174,10 @@ void RB_DXDrawInteractions(void)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!R_MaskedOcclusionCulling_LightIsVisible(backEnd.viewDef, vLight->lightDef))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const renderLight_t& srcLight = vLight->lightDef->parms;
|
||||
const float r = srcLight.shaderParms[SHADERPARM_RED];
|
||||
|
||||
@@ -626,6 +626,7 @@ void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) {
|
||||
}
|
||||
|
||||
backEndStartTime = Sys_Milliseconds();
|
||||
int backendCpuNoSwap = 0;
|
||||
|
||||
// needed for editor rendering
|
||||
RB_SetDefaultGLState();
|
||||
@@ -634,7 +635,9 @@ void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) {
|
||||
globalImages->CompleteBackgroundImageLoads();
|
||||
|
||||
for ( ; cmds ; cmds = (const emptyCommand_t *)cmds->next ) {
|
||||
switch ( cmds->commandId ) {
|
||||
const int commandStartTime = Sys_Milliseconds();
|
||||
const renderCommand_t commandId = cmds->commandId;
|
||||
switch ( commandId ) {
|
||||
case RC_NOP:
|
||||
break;
|
||||
case RC_DRAW_VIEW:
|
||||
@@ -662,6 +665,9 @@ void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) {
|
||||
common->Error( "RB_ExecuteBackEndCommands: bad commandId" );
|
||||
break;
|
||||
}
|
||||
if ( commandId != RC_SWAP_BUFFERS ) {
|
||||
backendCpuNoSwap += Sys_Milliseconds() - commandStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
// go back to the default texture so the editor doesn't mess up a bound image
|
||||
@@ -671,6 +677,7 @@ void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) {
|
||||
// stop rendering on this thread
|
||||
backEndFinishTime = Sys_Milliseconds();
|
||||
backEnd.pc.msec = backEndFinishTime - backEndStartTime;
|
||||
backEnd.pc.cpuMsecNoSwap = backendCpuNoSwap;
|
||||
|
||||
if ( r_debugRenderToTexture.GetInteger() == 1 ) {
|
||||
common->Printf( "3d: %i, 2d: %i, SetBuf: %i, SwpBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_swapBuffers, c_copyRenders, backEnd.c_copyFrameBuffer );
|
||||
|
||||
@@ -50,8 +50,8 @@ R_CreateAmbientCache
|
||||
Create it if needed
|
||||
==================
|
||||
*/
|
||||
bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting ) {
|
||||
if ( tri->ambientCache ) {
|
||||
bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting, bool staticCache ) {
|
||||
if ( tri->ambientVbo || tri->ambientCache ) {
|
||||
return true;
|
||||
}
|
||||
// we are going to use it for drawing, so make sure we have the tangents and normals
|
||||
@@ -59,10 +59,40 @@ bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting ) {
|
||||
R_DeriveTangents( tri );
|
||||
}
|
||||
|
||||
vertexCache.Alloc( tri->verts, tri->numVerts * sizeof( tri->verts[0] ), &tri->ambientCache );
|
||||
if ( !tri->ambientCache ) {
|
||||
if ( !tri->verts || tri->numVerts <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( staticCache ) {
|
||||
glGenBuffersARB( 1, &tri->ambientVbo );
|
||||
glBindBufferARB( GL_ARRAY_BUFFER_ARB, tri->ambientVbo );
|
||||
glBufferDataARB( GL_ARRAY_BUFFER_ARB, (GLsizeiptrARB)( tri->numVerts * sizeof( tri->verts[0] ) ), tri->verts, GL_STATIC_DRAW_ARB );
|
||||
return true;
|
||||
}
|
||||
|
||||
vertexCache.Alloc( tri->verts, tri->numVerts * sizeof( tri->verts[0] ), &tri->ambientCache );
|
||||
return tri->ambientCache != NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
R_CreateIndexCache
|
||||
|
||||
Static surfaces own their index buffer directly instead of routing through
|
||||
idVertexCache.
|
||||
==================
|
||||
*/
|
||||
bool R_CreateIndexCache( srfTriangles_t *tri ) {
|
||||
if ( tri->indexVbo ) {
|
||||
return true;
|
||||
}
|
||||
if ( !tri->indexes || tri->numIndexes <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glGenBuffersARB( 1, &tri->indexVbo );
|
||||
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, tri->indexVbo );
|
||||
glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, (GLsizeiptrARB)( tri->numIndexes * sizeof( tri->indexes[0] ) ), tri->indexes, GL_STATIC_DRAW_ARB );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -139,11 +169,7 @@ This is used only for a specific light
|
||||
==================
|
||||
*/
|
||||
void R_CreatePrivateShadowCache( srfTriangles_t *tri ) {
|
||||
if ( !tri->shadowVertexes ) {
|
||||
return;
|
||||
}
|
||||
|
||||
vertexCache.Alloc( tri->shadowVertexes, tri->numVerts * sizeof( *tri->shadowVertexes ), &tri->shadowCache );
|
||||
(void)tri;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -155,35 +181,7 @@ takes care of projecting the verts to infinity.
|
||||
==================
|
||||
*/
|
||||
void R_CreateVertexProgramShadowCache( srfTriangles_t *tri ) {
|
||||
if ( tri->verts == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
shadowCache_t *temp = (shadowCache_t *)_alloca16( tri->numVerts * 2 * sizeof( shadowCache_t ) );
|
||||
|
||||
#if 1
|
||||
|
||||
SIMDProcessor->CreateVertexProgramShadowCache( &temp->xyz, tri->verts, tri->numVerts );
|
||||
|
||||
#else
|
||||
|
||||
int numVerts = tri->numVerts;
|
||||
const idDrawVert *verts = tri->verts;
|
||||
for ( int i = 0; i < numVerts; i++ ) {
|
||||
const float *v = verts[i].xyz.ToFloatPtr();
|
||||
temp[i*2+0].xyz[0] = v[0];
|
||||
temp[i*2+1].xyz[0] = v[0];
|
||||
temp[i*2+0].xyz[1] = v[1];
|
||||
temp[i*2+1].xyz[1] = v[1];
|
||||
temp[i*2+0].xyz[2] = v[2];
|
||||
temp[i*2+1].xyz[2] = v[2];
|
||||
temp[i*2+0].xyz[3] = 1.0f; // on the model surface
|
||||
temp[i*2+1].xyz[3] = 0.0f; // will be projected to infinity
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
vertexCache.Alloc( temp, tri->numVerts * 2 * sizeof( shadowCache_t ), &tri->shadowCache );
|
||||
(void)tri;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -956,55 +954,18 @@ void R_AddLightSurfaces( void ) {
|
||||
// fog lights will need to draw the light frustum triangles, so make sure they
|
||||
// are in the vertex cache
|
||||
if ( lightShader->IsFogLight() ) {
|
||||
if ( !light->frustumTris->ambientCache ) {
|
||||
if ( !light->frustumTris->ambientVbo ) {
|
||||
if ( !R_CreateAmbientCache( light->frustumTris, false ) ) {
|
||||
// skip if we are out of vertex memory
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// touch the surface so it won't get purged
|
||||
vertexCache.Touch( light->frustumTris->ambientCache );
|
||||
if ( r_useIndexBuffers.GetBool() ) {
|
||||
R_CreateIndexCache( light->frustumTris );
|
||||
}
|
||||
}
|
||||
|
||||
// add the prelight shadows for the static world geometry
|
||||
if ( light->parms.prelightModel && r_useOptimizedShadows.GetBool() ) {
|
||||
|
||||
if ( !light->parms.prelightModel->NumSurfaces() ) {
|
||||
common->Error( "no surfs in prelight model '%s'", light->parms.prelightModel->Name() );
|
||||
}
|
||||
|
||||
srfTriangles_t *tri = light->parms.prelightModel->Surface( 0 )->geometry;
|
||||
if ( !tri->shadowVertexes ) {
|
||||
common->Error( "R_AddLightSurfaces: prelight model '%s' without shadowVertexes", light->parms.prelightModel->Name() );
|
||||
}
|
||||
|
||||
// these shadows will all have valid bounds, and can be culled normally
|
||||
if ( r_useShadowCulling.GetBool() ) {
|
||||
if ( R_CullLocalBox( tri->bounds, tr.viewDef->worldSpace.modelMatrix, 5, tr.viewDef->frustum ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have been purged, re-upload the shadowVertexes
|
||||
if ( !tri->shadowCache ) {
|
||||
R_CreatePrivateShadowCache( tri );
|
||||
if ( !tri->shadowCache ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// touch the shadow surface so it won't get purged
|
||||
vertexCache.Touch( tri->shadowCache );
|
||||
|
||||
if ( !tri->indexCache && r_useIndexBuffers.GetBool() ) {
|
||||
vertexCache.Alloc( tri->indexes, tri->numIndexes * sizeof( tri->indexes[0] ), &tri->indexCache, true );
|
||||
}
|
||||
if ( tri->indexCache ) {
|
||||
vertexCache.Touch( tri->indexCache );
|
||||
}
|
||||
|
||||
R_LinkLightSurf( &vLight->globalShadows, tri, NULL, light, NULL, vLight->scissorRect, true /* FIXME? */ );
|
||||
}
|
||||
// Stencil/prelight shadow volumes are not used by the D3D12 lighting path.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1379,18 +1340,14 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
|
||||
def->visibleCount = tr.viewCount;
|
||||
|
||||
// make sure we have an ambient cache
|
||||
if ( !R_CreateAmbientCache( tri, shader->ReceivesLighting() ) ) {
|
||||
const bool staticCache = def->dynamicModel == NULL;
|
||||
const bool needsAmbientTangents = staticCache && shader->ReceivesLighting();
|
||||
if ( !R_CreateAmbientCache( tri, needsAmbientTangents, staticCache ) ) {
|
||||
// don't add anything if the vertex cache was too full to give us an ambient cache
|
||||
return;
|
||||
}
|
||||
// touch it so it won't get purged
|
||||
vertexCache.Touch( tri->ambientCache );
|
||||
|
||||
if ( r_useIndexBuffers.GetBool() && !tri->indexCache ) {
|
||||
vertexCache.Alloc( tri->indexes, tri->numIndexes * sizeof( tri->indexes[0] ), &tri->indexCache, true );
|
||||
}
|
||||
if ( tri->indexCache ) {
|
||||
vertexCache.Touch( tri->indexCache );
|
||||
if ( staticCache && r_useIndexBuffers.GetBool() ) {
|
||||
R_CreateIndexCache( tri );
|
||||
}
|
||||
|
||||
// add the surface for drawing
|
||||
@@ -1519,13 +1476,8 @@ void R_RemoveUnecessaryViewLights( void ) {
|
||||
|
||||
// go through each visible light
|
||||
for ( vLight = tr.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
|
||||
// if the light didn't have any lit surfaces visible, there is no need to
|
||||
// draw any of the shadows. We still keep the vLight for debugging
|
||||
// draws
|
||||
if ( !vLight->localInteractions && !vLight->globalInteractions && !vLight->translucentInteractions ) {
|
||||
vLight->localShadows = NULL;
|
||||
vLight->globalShadows = NULL;
|
||||
}
|
||||
vLight->localShadows = NULL;
|
||||
vLight->globalShadows = NULL;
|
||||
}
|
||||
|
||||
if ( r_useShadowSurfaceScissor.GetBool() ) {
|
||||
@@ -1545,16 +1497,9 @@ void R_RemoveUnecessaryViewLights( void ) {
|
||||
for ( surf = vLight->globalInteractions ; surf ; surf = surf->nextOnLight ) {
|
||||
surfRect.Union( surf->scissorRect );
|
||||
}
|
||||
for ( surf = vLight->localShadows ; surf ; surf = surf->nextOnLight ) {
|
||||
const_cast<drawSurf_t *>(surf)->scissorRect.Intersect( surfRect );
|
||||
}
|
||||
|
||||
for ( surf = vLight->localInteractions ; surf ; surf = surf->nextOnLight ) {
|
||||
surfRect.Union( surf->scissorRect );
|
||||
}
|
||||
for ( surf = vLight->globalShadows ; surf ; surf = surf->nextOnLight ) {
|
||||
const_cast<drawSurf_t *>(surf)->scissorRect.Intersect( surfRect );
|
||||
}
|
||||
|
||||
for ( surf = vLight->translucentInteractions ; surf ; surf = surf->nextOnLight ) {
|
||||
surfRect.Union( surf->scissorRect );
|
||||
|
||||
@@ -628,6 +628,7 @@ typedef struct {
|
||||
|
||||
float maxLightValue; // for light scale
|
||||
int msec; // total msec for backend run
|
||||
int cpuMsecNoSwap; // backend CPU excluding swap/present wait
|
||||
} backEndCounters_t;
|
||||
|
||||
// all state modified by the back end is separated
|
||||
@@ -860,6 +861,8 @@ extern idCVar r_useNodeCommonChildren; // stop pushing reference bounds early wh
|
||||
extern idCVar r_useSilRemap; // 1 = consider verts with the same XYZ, but different ST the same for shadows
|
||||
extern idCVar r_useCulling; // 0 = none, 1 = sphere, 2 = sphere + box
|
||||
extern idCVar r_useLightCulling; // 0 = none, 1 = box, 2 = exact clip of polyhedron faces
|
||||
extern idCVar r_useMaskedOcclusionCulling; // one-frame-late threaded MOC light culling
|
||||
extern idCVar r_mocResolutionScale; // software occlusion resolution relative to view size
|
||||
extern idCVar r_useLightScissors; // 1 = use custom scissor rectangle for each light
|
||||
extern idCVar r_useClippedLightScissors;// 0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always
|
||||
extern idCVar r_useEntityCulling; // 0 = none, 1 = box
|
||||
@@ -1142,6 +1145,9 @@ MAIN
|
||||
*/
|
||||
|
||||
void R_RenderView( viewDef_t *parms );
|
||||
void R_MaskedOcclusionCulling_ProcessView( viewDef_t *parms );
|
||||
bool R_MaskedOcclusionCulling_LightIsVisible( const viewDef_t *viewDef, const idRenderLightLocal *light );
|
||||
void R_MaskedOcclusionCulling_Shutdown( void );
|
||||
|
||||
// performs radius cull first, then corner cull
|
||||
bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes );
|
||||
@@ -1195,7 +1201,8 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const
|
||||
void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space,
|
||||
const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow );
|
||||
|
||||
bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting );
|
||||
bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting, bool staticCache = true );
|
||||
bool R_CreateIndexCache( srfTriangles_t *tri );
|
||||
bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightLocal *light, srfTriangles_t *tri );
|
||||
void R_CreatePrivateShadowCache( srfTriangles_t *tri );
|
||||
void R_CreateVertexProgramShadowCache( srfTriangles_t *tri );
|
||||
|
||||
@@ -1123,6 +1123,10 @@ void R_RenderView( viewDef_t *parms ) {
|
||||
// lightDefs that are in them and pass culling.
|
||||
static_cast<idRenderWorldLocal *>(parms->renderWorld)->FindViewLightsAndEntities();
|
||||
|
||||
// Queue this full light list for next frame, then prune with the last
|
||||
// completed async masked occlusion result.
|
||||
R_MaskedOcclusionCulling_ProcessView( tr.viewDef );
|
||||
|
||||
// constrain the view frustum to the view lights and entities
|
||||
R_ConstrainViewFrustum();
|
||||
|
||||
|
||||
@@ -69,6 +69,14 @@ void RB_DrawElementsImmediate( const srfTriangles_t *tri ) {
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static idDrawVert *RB_BindAmbientBuffer( const srfTriangles_t *tri ) {
|
||||
if ( tri->ambientVbo ) {
|
||||
glBindBufferARB( GL_ARRAY_BUFFER_ARB, tri->ambientVbo );
|
||||
return (idDrawVert *)0;
|
||||
}
|
||||
return (idDrawVert *)vertexCache.Position( tri->ambientCache );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
@@ -90,7 +98,14 @@ void RB_DrawElementsWithCounters( const srfTriangles_t *tri ) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
|
||||
if ( tri->indexVbo && r_useIndexBuffers.GetBool() ) {
|
||||
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, tri->indexVbo );
|
||||
glDrawElements( GL_TRIANGLES,
|
||||
r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
|
||||
GL_INDEX_TYPE,
|
||||
(void *)0 );
|
||||
backEnd.pc.c_vboIndexes += tri->numIndexes;
|
||||
} else if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
|
||||
glDrawElements( GL_TRIANGLES,
|
||||
r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
|
||||
GL_INDEX_TYPE,
|
||||
@@ -119,7 +134,14 @@ void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexe
|
||||
backEnd.pc.c_shadowIndexes += numIndexes;
|
||||
backEnd.pc.c_shadowVertexes += tri->numVerts;
|
||||
|
||||
if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
|
||||
if ( tri->indexVbo && r_useIndexBuffers.GetBool() ) {
|
||||
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, tri->indexVbo );
|
||||
glDrawElements( GL_TRIANGLES,
|
||||
r_singleTriangle.GetBool() ? 3 : numIndexes,
|
||||
GL_INDEX_TYPE,
|
||||
(void *)0 );
|
||||
backEnd.pc.c_vboIndexes += numIndexes;
|
||||
} else if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
|
||||
glDrawElements( GL_TRIANGLES,
|
||||
r_singleTriangle.GetBool() ? 3 : numIndexes,
|
||||
GL_INDEX_TYPE,
|
||||
@@ -145,13 +167,13 @@ Sets texcoord and vertex pointers
|
||||
===============
|
||||
*/
|
||||
void RB_RenderTriangleSurface( const srfTriangles_t *tri ) {
|
||||
if ( !tri->ambientCache ) {
|
||||
if ( !tri->ambientVbo && !tri->ambientCache ) {
|
||||
RB_DrawElementsImmediate( tri );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
|
||||
idDrawVert *ac = RB_BindAmbientBuffer( tri );
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
|
||||
glTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
|
||||
|
||||
@@ -413,7 +435,7 @@ void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *te
|
||||
|
||||
// texgens
|
||||
if ( texture->texgen == TG_DIFFUSE_CUBE ) {
|
||||
glTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
|
||||
glTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), RB_BindAmbientBuffer( surf->geo )->normal.ToFloatPtr() );
|
||||
}
|
||||
if ( texture->texgen == TG_SKYBOX_CUBE || texture->texgen == TG_WOBBLESKY_CUBE ) {
|
||||
glTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) );
|
||||
@@ -426,7 +448,7 @@ void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *te
|
||||
glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
|
||||
glTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
|
||||
glEnableClientState( GL_NORMAL_ARRAY );
|
||||
glNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
|
||||
glNormalPointer( GL_FLOAT, sizeof( idDrawVert ), RB_BindAmbientBuffer( surf->geo )->normal.ToFloatPtr() );
|
||||
|
||||
glMatrixMode( GL_TEXTURE );
|
||||
float mat[16];
|
||||
@@ -452,7 +474,7 @@ void RB_FinishStageTexture( const textureStage_t *texture, const drawSurf_t *sur
|
||||
if ( texture->texgen == TG_DIFFUSE_CUBE || texture->texgen == TG_SKYBOX_CUBE
|
||||
|| texture->texgen == TG_WOBBLESKY_CUBE ) {
|
||||
glTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ),
|
||||
(void *)&(((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->st) );
|
||||
(void *)&(RB_BindAmbientBuffer( surf->geo )->st) );
|
||||
}
|
||||
|
||||
if ( texture->texgen == TG_REFLECT_CUBE ) {
|
||||
@@ -610,12 +632,9 @@ void RB_BeginDrawingView (void) {
|
||||
|
||||
// we don't have to clear the depth / stencil buffer for 2D rendering
|
||||
if ( backEnd.viewDef->viewEntitys ) {
|
||||
glStencilMask( 0xff );
|
||||
// some cards may have 7 bit stencil buffers, so don't assume this
|
||||
// should be 128
|
||||
glClearStencil( 1<<(glConfig.stencilBits-1) );
|
||||
glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
|
||||
glClear( GL_DEPTH_BUFFER_BIT );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
} else {
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
@@ -728,7 +747,7 @@ void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void (*DrawInterac
|
||||
const float *lightRegs = vLight->shaderRegisters;
|
||||
drawInteraction_t inter;
|
||||
|
||||
if ( r_skipInteractions.GetBool() || !surf->geo || !surf->geo->ambientCache ) {
|
||||
if ( r_skipInteractions.GetBool() || !surf->geo || ( !surf->geo->ambientVbo && !surf->geo->ambientCache ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -474,6 +474,14 @@ void RB_ShowDepthBuffer( void ) {
|
||||
R_StaticFree( depthReadback );
|
||||
}
|
||||
|
||||
static idDrawVert *RB_BindToolAmbientBuffer( const srfTriangles_t *tri ) {
|
||||
if ( tri->ambientVbo ) {
|
||||
glBindBufferARB( GL_ARRAY_BUFFER_ARB, tri->ambientVbo );
|
||||
return (idDrawVert *)0;
|
||||
}
|
||||
return (idDrawVert *)vertexCache.Position( tri->ambientCache );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
RB_ShowLightCount
|
||||
@@ -514,11 +522,11 @@ void RB_ShowLightCount( void ) {
|
||||
for ( i = 0 ; i < 2 ; i++ ) {
|
||||
for ( surf = i ? vLight->localInteractions: vLight->globalInteractions; surf; surf = (drawSurf_t *)surf->nextOnLight ) {
|
||||
RB_SimpleSurfaceSetup( surf );
|
||||
if ( !surf->geo->ambientCache ) {
|
||||
if ( !surf->geo->ambientVbo && !surf->geo->ambientCache ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
|
||||
const idDrawVert *ac = RB_BindToolAmbientBuffer( surf->geo );
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), &ac->xyz );
|
||||
RB_DrawElementsWithCounters( surf->geo );
|
||||
}
|
||||
@@ -543,77 +551,7 @@ plane extends from, allowing you to see doubled edges
|
||||
=================
|
||||
*/
|
||||
void RB_ShowSilhouette( void ) {
|
||||
int i;
|
||||
const drawSurf_t *surf;
|
||||
const viewLight_t *vLight;
|
||||
|
||||
if ( !r_showSilhouette.GetBool() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// clear all triangle edges to black
|
||||
//
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
globalImages->BindNull();
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
|
||||
glColor3f( 0, 0, 0 );
|
||||
|
||||
GL_State( GLS_POLYMODE_LINE );
|
||||
|
||||
GL_Cull( CT_TWO_SIDED );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
|
||||
RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs,
|
||||
RB_T_RenderTriangleSurface );
|
||||
|
||||
|
||||
//
|
||||
// now blend in edges that cast silhouettes
|
||||
//
|
||||
RB_SimpleWorldSetup();
|
||||
glColor3f( 0.5, 0, 0 );
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
|
||||
for ( i = 0 ; i < 2 ; i++ ) {
|
||||
for ( surf = i ? vLight->localShadows : vLight->globalShadows
|
||||
; surf ; surf = (drawSurf_t *)surf->nextOnLight ) {
|
||||
RB_SimpleSurfaceSetup( surf );
|
||||
|
||||
const srfTriangles_t *tri = surf->geo;
|
||||
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position( tri->shadowCache ) );
|
||||
glBegin( GL_LINES );
|
||||
|
||||
for ( int j = 0 ; j < tri->numIndexes ; j+=3 ) {
|
||||
int i1 = tri->indexes[j+0];
|
||||
int i2 = tri->indexes[j+1];
|
||||
int i3 = tri->indexes[j+2];
|
||||
|
||||
if ( (i1 & 1) + (i2 & 1) + (i3 & 1) == 1 ) {
|
||||
if ( (i1 & 1) + (i2 & 1) == 0 ) {
|
||||
glArrayElement( i1 );
|
||||
glArrayElement( i2 );
|
||||
} else if ( (i1 & 1 ) + (i3 & 1) == 0 ) {
|
||||
glArrayElement( i1 );
|
||||
glArrayElement( i3 );
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
GL_State( GLS_DEFAULT );
|
||||
glColor3f( 1,1,1 );
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -627,76 +565,7 @@ and count up the total fill usage
|
||||
=================
|
||||
*/
|
||||
static void RB_ShowShadowCount( void ) {
|
||||
int i;
|
||||
const drawSurf_t *surf;
|
||||
const viewLight_t *vLight;
|
||||
|
||||
if ( !r_showShadowCount.GetBool() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
GL_State( GLS_DEFAULT );
|
||||
|
||||
glClearStencil( 0 );
|
||||
glClear( GL_STENCIL_BUFFER_BIT );
|
||||
|
||||
glEnable( GL_STENCIL_TEST );
|
||||
|
||||
glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
|
||||
|
||||
glStencilFunc( GL_ALWAYS, 1, 255 );
|
||||
|
||||
globalImages->defaultImage->Bind();
|
||||
|
||||
// draw both sides
|
||||
GL_Cull( CT_TWO_SIDED );
|
||||
|
||||
for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
|
||||
for ( i = 0 ; i < 2 ; i++ ) {
|
||||
for ( surf = i ? vLight->localShadows : vLight->globalShadows
|
||||
; surf ; surf = (drawSurf_t *)surf->nextOnLight ) {
|
||||
RB_SimpleSurfaceSetup( surf );
|
||||
const srfTriangles_t *tri = surf->geo;
|
||||
if ( !tri->shadowCache ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( r_showShadowCount.GetInteger() == 3 ) {
|
||||
// only show turboshadows
|
||||
if ( tri->numShadowIndexesNoCaps != tri->numIndexes ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( r_showShadowCount.GetInteger() == 4 ) {
|
||||
// only show static shadows
|
||||
if ( tri->numShadowIndexesNoCaps == tri->numIndexes ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
shadowCache_t *cache = (shadowCache_t *)vertexCache.Position( tri->shadowCache );
|
||||
glVertexPointer( 4, GL_FLOAT, sizeof( *cache ), &cache->xyz );
|
||||
RB_DrawElementsWithCounters( tri );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display the results
|
||||
R_ColorByStencilBuffer();
|
||||
|
||||
if ( r_showShadowCount.GetInteger() == 2 ) {
|
||||
common->Printf( "all shadows " );
|
||||
} else if ( r_showShadowCount.GetInteger() == 3 ) {
|
||||
common->Printf( "turboShadows " );
|
||||
} else if ( r_showShadowCount.GetInteger() == 4 ) {
|
||||
common->Printf( "static shadows " );
|
||||
}
|
||||
|
||||
if ( r_showShadowCount.GetInteger() >= 2 ) {
|
||||
RB_CountStencilBuffer();
|
||||
}
|
||||
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -340,6 +340,10 @@ void R_FreeStaticTriSurfVertexCaches( srfTriangles_t *tri ) {
|
||||
// this is a real model surface
|
||||
vertexCache.Free( tri->ambientCache );
|
||||
tri->ambientCache = NULL;
|
||||
if ( tri->ambientVbo ) {
|
||||
glDeleteBuffersARB( 1, &tri->ambientVbo );
|
||||
tri->ambientVbo = 0;
|
||||
}
|
||||
} else {
|
||||
// this is a light interaction surface that references
|
||||
// a different ambient model surface
|
||||
@@ -350,6 +354,10 @@ void R_FreeStaticTriSurfVertexCaches( srfTriangles_t *tri ) {
|
||||
vertexCache.Free( tri->indexCache );
|
||||
tri->indexCache = NULL;
|
||||
}
|
||||
if ( tri->indexVbo ) {
|
||||
glDeleteBuffersARB( 1, &tri->indexVbo );
|
||||
tri->indexVbo = 0;
|
||||
}
|
||||
if ( tri->shadowCache && ( tri->shadowVertexes != NULL || tri->verts != NULL ) ) {
|
||||
// if we don't have tri->shadowVertexes, these are a reference to a
|
||||
// shadowCache on the original surface, which a vertex program
|
||||
@@ -2272,4 +2280,3 @@ int R_DeformInfoMemoryUsed( deformInfo_t *deformInfo ) {
|
||||
total += sizeof( *deformInfo );
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ If you have questions concerning this license or the applicable additional terms
|
||||
#include "OutlinerDlg.h"
|
||||
#include "splines.h"
|
||||
#include <GL/glu.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../../renderer/tr_local.h"
|
||||
#include "../../models/model_local.h" // for idRenderModelMD5
|
||||
@@ -1564,24 +1565,38 @@ static bool CamWnd_IsTriggerLikeBrushEntity(brush_t* brush) {
|
||||
CamWnd_StringStartsWithNoCase(className, "monsterclip");
|
||||
}
|
||||
|
||||
static bool CamWnd_TargetLinesVisible(CCamWnd* cam) {
|
||||
return (CamWnd_GetFilterMask(cam) & CAMWND_FILTER_HIDE_TARGET_LINES) == 0;
|
||||
struct camWndBrushFilterContext_t {
|
||||
CCamWnd* cam;
|
||||
int mask;
|
||||
bool hasHiddenEntities;
|
||||
};
|
||||
|
||||
static camWndBrushFilterContext_t CamWnd_MakeBrushFilterContext(CCamWnd* cam) {
|
||||
camWndBrushFilterContext_t ctx;
|
||||
ctx.cam = cam;
|
||||
ctx.mask = CamWnd_GetFilterMask(cam);
|
||||
ctx.hasHiddenEntities = Outliner_HasHiddenEntities();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) {
|
||||
static bool CamWnd_TargetLinesVisible(const camWndBrushFilterContext_t& filter) {
|
||||
return (filter.mask & CAMWND_FILTER_HIDE_TARGET_LINES) == 0;
|
||||
}
|
||||
|
||||
static bool CamWnd_MenuFilterBrush(const camWndBrushFilterContext_t& filter, brush_t* brush) {
|
||||
if (!brush) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (brush->owner != NULL && !Outliner_IsEntityVisible(brush->owner)) {
|
||||
if (filter.hasHiddenEntities && brush->owner != NULL && !Outliner_IsEntityVisible(brush->owner)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cam) {
|
||||
if (!filter.cam) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int mask = CamWnd_GetFilterMask(cam);
|
||||
const int mask = filter.mask;
|
||||
if (mask == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -1618,6 +1633,11 @@ static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) {
|
||||
const camWndBrushFilterContext_t filter = CamWnd_MakeBrushFilterContext(cam);
|
||||
return CamWnd_MenuFilterBrush(filter, brush);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
@@ -3556,6 +3576,7 @@ void setGLMode(int mode) {
|
||||
break;
|
||||
|
||||
case cd_texture:
|
||||
case cd_light:
|
||||
glCullFace(GL_FRONT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glShadeModel(GL_FLAT);
|
||||
@@ -3577,6 +3598,215 @@ void setGLMode(int mode) {
|
||||
}
|
||||
}
|
||||
|
||||
struct camWndWorldFaceBatch_t {
|
||||
const idMaterial* material;
|
||||
std::vector<face_t*> faces;
|
||||
};
|
||||
|
||||
static bool CamWnd_IsFastWorldBrush(brush_t* brush) {
|
||||
if (brush == NULL || brush->hiddenBrush) {
|
||||
return false;
|
||||
}
|
||||
if (brush->pPatch || brush->modelHandle > 0 || brush->entityModel || brush->forceWireFrame) {
|
||||
return false;
|
||||
}
|
||||
if (brush->owner == NULL || brush->owner != world_entity || brush->owner->curve != NULL) {
|
||||
return false;
|
||||
}
|
||||
if (brush->owner->eclass == NULL || !(brush->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CamWnd_CanFastDrawWorldMode(int drawMode) {
|
||||
return drawMode == cd_solid || drawMode == cd_texture || drawMode == cd_light;
|
||||
}
|
||||
|
||||
static bool CamWnd_ShouldDrawFastFace(face_t* face) {
|
||||
if (face == NULL || face->face_winding == NULL || face->face_winding->GetNumPoints() < 3) {
|
||||
return false;
|
||||
}
|
||||
if ((g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) && strstr(face->texdef.name, "caulk")) {
|
||||
return false;
|
||||
}
|
||||
if ((g_qeglobals.d_savedinfo.exclude & EXCLUDE_VISPORTALS) && strstr(face->texdef.name, "visportal")) {
|
||||
return false;
|
||||
}
|
||||
if ((g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) && strstr(face->texdef.name, "nodraw")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static camWndWorldFaceBatch_t* CamWnd_FindWorldFaceBatch(std::vector<camWndWorldFaceBatch_t>& batches, const idMaterial* material) {
|
||||
for (size_t i = 0; i < batches.size(); i++) {
|
||||
if (batches[i].material == material) {
|
||||
return &batches[i];
|
||||
}
|
||||
}
|
||||
|
||||
camWndWorldFaceBatch_t batch;
|
||||
batch.material = material;
|
||||
batch.faces.reserve(128);
|
||||
batches.push_back(batch);
|
||||
return &batches.back();
|
||||
}
|
||||
|
||||
static void CamWnd_AddFastWorldBrush(std::vector<camWndWorldFaceBatch_t>& batches, brush_t* brush, int drawMode) {
|
||||
const bool textured = (drawMode == cd_texture || drawMode == cd_light);
|
||||
|
||||
for (face_t* face = brush->brush_faces; face; face = face->next) {
|
||||
if (!CamWnd_ShouldDrawFastFace(face)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const idMaterial* material = textured ? face->d_texture : NULL;
|
||||
CamWnd_FindWorldFaceBatch(batches, material)->faces.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
static void CamWnd_EmitFastWorldFaceBatches(const std::vector<camWndWorldFaceBatch_t>& batches, int drawMode) {
|
||||
const bool textured = (drawMode == cd_texture || drawMode == cd_light);
|
||||
|
||||
for (size_t batchIndex = 0; batchIndex < batches.size(); batchIndex++) {
|
||||
const camWndWorldFaceBatch_t& batch = batches[batchIndex];
|
||||
if (batch.faces.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (textured && batch.material != NULL) {
|
||||
batch.material->GetEditorImage()->Bind();
|
||||
}
|
||||
else {
|
||||
globalImages->BindNull();
|
||||
}
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (size_t faceIndex = 0; faceIndex < batch.faces.size(); faceIndex++) {
|
||||
face_t* face = batch.faces[faceIndex];
|
||||
idWinding* w = face->face_winding;
|
||||
const int numPoints = w->GetNumPoints();
|
||||
const float alpha = face->d_texture ? face->d_texture->GetEditorAlpha() : 1.0f;
|
||||
|
||||
glColor4f(face->d_color.x, face->d_color.y, face->d_color.z, alpha);
|
||||
|
||||
for (int i = 2; i < numPoints; i++) {
|
||||
if (textured) {
|
||||
glTexCoord2fv(&(*w)[0][3]);
|
||||
}
|
||||
glVertex3fv((*w)[0].ToFloatPtr());
|
||||
|
||||
if (textured) {
|
||||
glTexCoord2fv(&(*w)[i - 1][3]);
|
||||
}
|
||||
glVertex3fv((*w)[i - 1].ToFloatPtr());
|
||||
|
||||
if (textured) {
|
||||
glTexCoord2fv(&(*w)[i][3]);
|
||||
}
|
||||
glVertex3fv((*w)[i].ToFloatPtr());
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
globalImages->BindNull();
|
||||
}
|
||||
|
||||
static void CamWnd_DrawActiveBrushes(CCamWnd* cam, bool renderMode, bool entityMode, const camWndBrushFilterContext_t& filter) {
|
||||
std::vector<camWndWorldFaceBatch_t> batches;
|
||||
std::vector<brush_t*> slowBrushes;
|
||||
batches.reserve(64);
|
||||
slowBrushes.reserve(64);
|
||||
|
||||
for (brush_t* brush = active_brushes.next; brush != &active_brushes; brush = brush->next) {
|
||||
if (cam->CullBrush(brush, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FilterBrush(brush)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CamWnd_MenuFilterBrush(filter, brush)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (renderMode) {
|
||||
if (!(entityMode && brush->owner->eclass->fixedsize)) {
|
||||
continue;
|
||||
}
|
||||
slowBrushes.push_back(brush);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CamWnd_CanFastDrawWorldMode(cam->Camera().draw_mode) && CamWnd_IsFastWorldBrush(brush)) {
|
||||
CamWnd_AddFastWorldBrush(batches, brush, cam->Camera().draw_mode);
|
||||
}
|
||||
else {
|
||||
slowBrushes.push_back(brush);
|
||||
}
|
||||
}
|
||||
|
||||
if (!batches.empty()) {
|
||||
setGLMode(cam->Camera().draw_mode);
|
||||
CamWnd_EmitFastWorldFaceBatches(batches, cam->Camera().draw_mode);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < slowBrushes.size(); i++) {
|
||||
setGLMode(cam->Camera().draw_mode);
|
||||
Brush_Draw(slowBrushes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void CamWnd_DrawRadiantLightFrustum(const renderLight_t& lightParms, const idVec3& color) {
|
||||
idPlane planes[6];
|
||||
R_RenderLightFrustum(lightParms, planes);
|
||||
srfTriangles_t* tri = R_PolytopeSurface(6, planes, NULL);
|
||||
if (tri == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
glColor3fv(color.ToFloatPtr());
|
||||
for (int i = 0; i < tri->numIndexes; i += 3) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3fv(tri->verts[tri->indexes[i]].xyz.ToFloatPtr());
|
||||
glVertex3fv(tri->verts[tri->indexes[i + 1]].xyz.ToFloatPtr());
|
||||
glVertex3fv(tri->verts[tri->indexes[i + 2]].xyz.ToFloatPtr());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
R_FreeStaticTriSurf(tri);
|
||||
}
|
||||
|
||||
static void CamWnd_DrawRadiantLightFrustums(CCamWnd* cam) {
|
||||
if (cam == NULL || !cam->GetRenderMode() || !(cam->GetEntityMode() || g_bShowLightVolumes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glLineWidth(1.0f);
|
||||
globalImages->BindNull();
|
||||
|
||||
for (entity_t* ent = entities.next; ent != &entities; ent = ent->next) {
|
||||
if (ent->eclass == NULL || !(ent->eclass->nShowFlags & ECLASS_LIGHT) || ent->epairs.GetBool("start_off")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
idDict spawnArgs = ent->epairs;
|
||||
renderLight_t lightParms;
|
||||
gameEdit->ParseSpawnArgsToRenderLight(&spawnArgs, &lightParms);
|
||||
|
||||
CamWnd_DrawRadiantLightFrustum(lightParms, idVec3(1.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
static bool CamWnd_FaceHasAllPlanePointsSelected(face_t* face) {
|
||||
if (face == NULL || face->face_winding == NULL) {
|
||||
return false;
|
||||
@@ -3590,13 +3820,13 @@ static bool CamWnd_FaceHasAllPlanePointsSelected(face_t* face) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CamWnd_DrawMoveSelectedBrushSidesForList(CCamWnd* cam, brush_t* list) {
|
||||
static void CamWnd_DrawMoveSelectedBrushSidesForList(const camWndBrushFilterContext_t& filter, brush_t* list) {
|
||||
if (list == NULL || list->next == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (brush_t* brush = list->next; brush != list; brush = brush->next) {
|
||||
if (CamWnd_MenuFilterBrush(cam, brush)) {
|
||||
if (CamWnd_MenuFilterBrush(filter, brush)) {
|
||||
continue;
|
||||
}
|
||||
if (brush->pPatch || brush->modelHandle > 0 || brush->entityModel) {
|
||||
@@ -3611,7 +3841,7 @@ static void CamWnd_DrawMoveSelectedBrushSidesForList(CCamWnd* cam, brush_t* list
|
||||
}
|
||||
}
|
||||
|
||||
static void CamWnd_DrawMoveSelectedBrushSides(CCamWnd* cam) {
|
||||
static void CamWnd_DrawMoveSelectedBrushSides(const camWndBrushFilterContext_t& filter) {
|
||||
glPushAttrib(GL_CURRENT_BIT);
|
||||
globalImages->BindNull();
|
||||
glDisable(GL_LIGHTING);
|
||||
@@ -3621,8 +3851,8 @@ static void CamWnd_DrawMoveSelectedBrushSides(CCamWnd* cam) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.25f);
|
||||
|
||||
CamWnd_DrawMoveSelectedBrushSidesForList(cam, &active_brushes);
|
||||
CamWnd_DrawMoveSelectedBrushSidesForList(cam, &selected_brushes);
|
||||
CamWnd_DrawMoveSelectedBrushSidesForList(filter, &active_brushes);
|
||||
CamWnd_DrawMoveSelectedBrushSidesForList(filter, &selected_brushes);
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
@@ -3756,29 +3986,10 @@ void CCamWnd::Cam_Draw() {
|
||||
|
||||
Cam_BuildMatrix();
|
||||
|
||||
for (brush = active_brushes.next; brush != &active_brushes; brush = brush->next) {
|
||||
const camWndBrushFilterContext_t brushFilter = CamWnd_MakeBrushFilterContext(this);
|
||||
|
||||
if (CullBrush(brush, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FilterBrush(brush)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CamWnd_MenuFilterBrush(this, brush)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (renderMode) {
|
||||
if (!(entityMode && brush->owner->eclass->fixedsize)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
setGLMode(m_Camera.draw_mode);
|
||||
Brush_Draw(brush);
|
||||
}
|
||||
CamWnd_DrawActiveBrushes(this, renderMode, entityMode, brushFilter);
|
||||
CamWnd_DrawRadiantLightFrustums(this);
|
||||
|
||||
|
||||
//glDepthMask ( 1 ); // Ok, write now
|
||||
@@ -3791,7 +4002,7 @@ void CCamWnd::Cam_Draw() {
|
||||
if (!renderMode) {
|
||||
// draw normally
|
||||
for (brush = pList->next; brush != pList; brush = brush->next) {
|
||||
if (CamWnd_MenuFilterBrush(this, brush)) {
|
||||
if (CamWnd_MenuFilterBrush(brushFilter, brush)) {
|
||||
continue;
|
||||
}
|
||||
if (brush->pPatch) {
|
||||
@@ -3812,7 +4023,7 @@ void CCamWnd::Cam_Draw() {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
globalImages->BindNull();
|
||||
for (brush = pList->next; brush != pList; brush = brush->next) {
|
||||
if (CamWnd_MenuFilterBrush(this, brush)) {
|
||||
if (CamWnd_MenuFilterBrush(brushFilter, brush)) {
|
||||
continue;
|
||||
}
|
||||
if (brush->pPatch || brush->modelHandle > 0) {
|
||||
@@ -3860,7 +4071,7 @@ void CCamWnd::Cam_Draw() {
|
||||
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.25f);
|
||||
for (brush = pList->next; brush != pList; brush = brush->next) {
|
||||
if (CamWnd_MenuFilterBrush(this, brush)) {
|
||||
if (CamWnd_MenuFilterBrush(brushFilter, brush)) {
|
||||
continue;
|
||||
}
|
||||
if (brush->pPatch || brush->modelHandle > 0) {
|
||||
@@ -3872,7 +4083,7 @@ void CCamWnd::Cam_Draw() {
|
||||
}
|
||||
}
|
||||
|
||||
CamWnd_DrawMoveSelectedBrushSides(this);
|
||||
CamWnd_DrawMoveSelectedBrushSides(brushFilter);
|
||||
CamWnd_FaceExtrudeDrawPreview(this);
|
||||
CamWnd_GizmoDraw(this);
|
||||
|
||||
@@ -3913,7 +4124,7 @@ void CCamWnd::Cam_Draw() {
|
||||
// draw pointfile
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if (CamWnd_TargetLinesVisible(this)) {
|
||||
if (CamWnd_TargetLinesVisible(brushFilter)) {
|
||||
CamWnd_DrawVisiblePathLines();
|
||||
}
|
||||
|
||||
@@ -4196,12 +4407,12 @@ static unsigned int EditorHashBrushGeometry(brush_t* brush, const idVec3& origin
|
||||
return hash;
|
||||
}
|
||||
|
||||
static unsigned int EditorHashBModelGeometry(CCamWnd* cam, entity_t* ent) {
|
||||
static unsigned int EditorHashBModelGeometry(entity_t* ent, const camWndBrushFilterContext_t& filter) {
|
||||
unsigned int hash = EDITOR_RENDER_HASH_INIT;
|
||||
hash = EditorHashString(hash, ValueForKey(ent, "name"));
|
||||
|
||||
for (brush_t* brush = ent->brushes.onext; brush != &ent->brushes; brush = brush->onext) {
|
||||
if (FilterBrush(brush) || CamWnd_MenuFilterBrush(cam, brush) || Map_IsBrushFiltered(brush)) {
|
||||
if (FilterBrush(brush) || CamWnd_MenuFilterBrush(filter, brush) || Map_IsBrushFiltered(brush)) {
|
||||
continue;
|
||||
}
|
||||
const unsigned int brushHash = EditorHashBrushGeometry(brush, ent->origin);
|
||||
@@ -4255,12 +4466,12 @@ static idRenderModel* EditorBuildSingleBrushModel(brush_t* brush, const idVec3&
|
||||
return model;
|
||||
}
|
||||
|
||||
static idRenderModel* EditorBuildBModel(CCamWnd* cam, entity_t* ent, const char* name) {
|
||||
static idRenderModel* EditorBuildBModel(entity_t* ent, const char* name, const camWndBrushFilterContext_t& filter) {
|
||||
idTriList tris(1024);
|
||||
idMatList mats(1024);
|
||||
|
||||
for (brush_t* brush = ent->brushes.onext; brush != &ent->brushes; brush = brush->onext) {
|
||||
if (FilterBrush(brush) || CamWnd_MenuFilterBrush(cam, brush) || Map_IsBrushFiltered(brush)) {
|
||||
if (FilterBrush(brush) || CamWnd_MenuFilterBrush(filter, brush) || Map_IsBrushFiltered(brush)) {
|
||||
continue;
|
||||
}
|
||||
Brush_ToTris(brush, &tris, &mats, false, true);
|
||||
@@ -4600,6 +4811,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) {
|
||||
idDict spawnArgs;
|
||||
const char* name = NULL;
|
||||
editorRenderEntityState_t* entityState = EditorTouchEntityState(ent);
|
||||
const camWndBrushFilterContext_t brushFilter = CamWnd_MakeBrushFilterContext(this);
|
||||
|
||||
// The old code used update=false as "tear down and recreate". The
|
||||
// incremental path keeps the handles and uses UpdateEntityDef /
|
||||
@@ -4611,7 +4823,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) {
|
||||
// If the entity is no longer renderable, remove only this entity's defs.
|
||||
if (ent->brushes.onext == &ent->brushes ||
|
||||
FilterBrush(ent->brushes.onext) ||
|
||||
CamWnd_MenuFilterBrush(this, ent->brushes.onext) ||
|
||||
CamWnd_MenuFilterBrush(brushFilter, ent->brushes.onext) ||
|
||||
CullBrush(ent->brushes.onext, true) ||
|
||||
Map_IsBrushFiltered(ent->brushes.onext)) {
|
||||
EditorFreeEntityModelDef(entityState, ent);
|
||||
@@ -4636,7 +4848,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) {
|
||||
// Brush model entity. Rebuild the renderModel only when the
|
||||
// entity-local brush geometry/materials changed. Plain movement
|
||||
// is handled by UpdateEntityDef below.
|
||||
const unsigned int geometryHash = EditorHashBModelGeometry(this, ent);
|
||||
const unsigned int geometryHash = EditorHashBModelGeometry(ent, brushFilter);
|
||||
editorRenderBModelState_t* bmodelState = EditorTouchBModelState(ent);
|
||||
idRenderModel* oldModel = NULL;
|
||||
|
||||
@@ -4646,7 +4858,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) {
|
||||
idStr::Icmp(bmodelState->modelName.c_str(), name) != 0);
|
||||
|
||||
if (geometryChanged) {
|
||||
idRenderModel* newModel = EditorBuildBModel(this, ent, name);
|
||||
idRenderModel* newModel = EditorBuildBModel(ent, name, brushFilter);
|
||||
if (newModel) {
|
||||
oldModel = bmodelState->model;
|
||||
bmodelState->model = newModel;
|
||||
@@ -5348,6 +5560,7 @@ void CCamWnd::DrawEntityData() {
|
||||
idVec3 color(0, 1, 0);
|
||||
glColor3fv(color.ToFloatPtr());
|
||||
|
||||
const camWndBrushFilterContext_t brushFilter = CamWnd_MakeBrushFilterContext(this);
|
||||
brush_t* brushList = &active_brushes;
|
||||
int pass = 0;
|
||||
while (brushList) {
|
||||
@@ -5361,7 +5574,7 @@ void CCamWnd::DrawEntityData() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CamWnd_MenuFilterBrush(this, brush)) {
|
||||
if (CamWnd_MenuFilterBrush(brushFilter, brush)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -5474,97 +5474,140 @@ bool FilterBrush(brush_t *pb) {
|
||||
the lines can be visible when neither end is. Called for both camera view and xy view.
|
||||
=======================================================================================================================
|
||||
*/
|
||||
void DrawPathLines(void) {
|
||||
int i, k;
|
||||
idVec3 mid, mid1;
|
||||
entity_t *se, *te;
|
||||
brush_t *sb, *tb;
|
||||
const char *psz;
|
||||
idVec3 dir, s1, s2;
|
||||
float len, f;
|
||||
int arrows;
|
||||
int num_entities;
|
||||
const char *ent_target[MAX_MAP_ENTITIES];
|
||||
entity_t *ent_entity[MAX_MAP_ENTITIES];
|
||||
struct pathLineNamedEntity_t {
|
||||
const char* name;
|
||||
entity_t* entity;
|
||||
brush_t* brush;
|
||||
};
|
||||
|
||||
static bool DrawPathLines_IsTargetKey(const char* key) {
|
||||
if (key == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idStr::Cmp(key, "target") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (idStr::Cmpn(key, "target", 6) != 0 || key[6] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const char* c = key + 6; *c != '\0'; c++) {
|
||||
if (*c < '0' || *c > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static brush_t* DrawPathLines_FirstBrush(entity_t* ent) {
|
||||
if (ent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
brush_t* brush = ent->brushes.onext;
|
||||
return (brush != &ent->brushes) ? brush : NULL;
|
||||
}
|
||||
|
||||
static void DrawPathLines_AppendNamedEntity(idList<pathLineNamedEntity_t>& namedEntities, idHashIndex& nameHash, entity_t* ent) {
|
||||
const char* name = ValueForKey(ent, "name");
|
||||
if (name == NULL || name[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
brush_t* brush = DrawPathLines_FirstBrush(ent);
|
||||
if (brush == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pathLineNamedEntity_t named;
|
||||
named.name = name;
|
||||
named.entity = ent;
|
||||
named.brush = brush;
|
||||
|
||||
const int index = namedEntities.Append(named);
|
||||
nameHash.Add(nameHash.GenerateKey(name, true), index);
|
||||
}
|
||||
|
||||
static void DrawPathLines_DrawConnection(const pathLineNamedEntity_t& namedTarget, entity_t* source, brush_t* sourceBrush) {
|
||||
if (namedTarget.entity == NULL || namedTarget.entity->eclass == NULL || source == NULL || sourceBrush == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
idVec3 mid = namedTarget.brush->owner->origin;
|
||||
idVec3 mid1 = sourceBrush->owner->origin;
|
||||
idVec3 dir, s1, s2;
|
||||
|
||||
VectorSubtract(mid1, mid, dir);
|
||||
const float len = dir.Normalize();
|
||||
s1[0] = -dir[1] * 8 + dir[0] * 8;
|
||||
s2[0] = dir[1] * 8 + dir[0] * 8;
|
||||
s1[1] = dir[0] * 8 + dir[1] * 8;
|
||||
s2[1] = -dir[0] * 8 + dir[1] * 8;
|
||||
|
||||
glColor3f(namedTarget.entity->eclass->color[0], namedTarget.entity->eclass->color[1], namedTarget.entity->eclass->color[2]);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(mid.ToFloatPtr());
|
||||
glVertex3fv(mid1.ToFloatPtr());
|
||||
|
||||
const int arrows = (int)(len / 256) + 1;
|
||||
for (int i = 0; i < arrows; i++) {
|
||||
const float f = len * (i + 0.5f) / arrows;
|
||||
|
||||
mid1 = mid + (f * dir);
|
||||
|
||||
glVertex3fv(mid1.ToFloatPtr());
|
||||
glVertex3f(mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
|
||||
glVertex3fv(mid1.ToFloatPtr());
|
||||
glVertex3f(mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawPathLines(void) {
|
||||
if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) {
|
||||
return;
|
||||
}
|
||||
|
||||
num_entities = 0;
|
||||
for (te = entities.next; te != &entities && num_entities != MAX_MAP_ENTITIES; te = te->next) {
|
||||
for (int i = 0; i < 2048; i++) {
|
||||
if (i == 0) {
|
||||
ent_target[num_entities] = ValueForKey(te, "target");
|
||||
} else {
|
||||
ent_target[num_entities] = ValueForKey(te, va("target%i", i));
|
||||
}
|
||||
if (ent_target[num_entities][0]) {
|
||||
ent_entity[num_entities] = te;
|
||||
num_entities++;
|
||||
} else if (i > 16) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
idList<pathLineNamedEntity_t> namedEntities;
|
||||
idHashIndex nameHash(1024, 1024);
|
||||
namedEntities.SetGranularity(256);
|
||||
|
||||
for (entity_t* ent = entities.next; ent != &entities; ent = ent->next) {
|
||||
DrawPathLines_AppendNamedEntity(namedEntities, nameHash, ent);
|
||||
}
|
||||
|
||||
for (se = entities.next; se != &entities; se = se->next) {
|
||||
psz = ValueForKey(se, "name");
|
||||
|
||||
if (psz == NULL || psz[0] == '\0') {
|
||||
for (entity_t* source = entities.next; source != &entities; source = source->next) {
|
||||
brush_t* sourceBrush = DrawPathLines_FirstBrush(source);
|
||||
if (sourceBrush == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sb = se->brushes.onext;
|
||||
if (sb == &se->brushes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = 0; k < num_entities; k++) {
|
||||
if (strcmp(ent_target[k], psz)) {
|
||||
const int numKeys = source->epairs.GetNumKeyVals();
|
||||
for (int keyIndex = 0; keyIndex < numKeys; keyIndex++) {
|
||||
const idKeyValue* kv = source->epairs.GetKeyVal(keyIndex);
|
||||
if (kv == NULL || !DrawPathLines_IsTargetKey(kv->GetKey().c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
te = ent_entity[k];
|
||||
tb = te->brushes.onext;
|
||||
if (tb == &te->brushes) {
|
||||
const char* targetName = kv->GetValue().c_str();
|
||||
if (targetName == NULL || targetName[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
mid = sb->owner->origin;
|
||||
mid1 = tb->owner->origin;
|
||||
|
||||
VectorSubtract(mid1, mid, dir);
|
||||
len = dir.Normalize();
|
||||
s1[0] = -dir[1] * 8 + dir[0] * 8;
|
||||
s2[0] = dir[1] * 8 + dir[0] * 8;
|
||||
s1[1] = dir[0] * 8 + dir[1] * 8;
|
||||
s2[1] = -dir[0] * 8 + dir[1] * 8;
|
||||
|
||||
glColor3f(se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(mid.ToFloatPtr());
|
||||
glVertex3fv(mid1.ToFloatPtr());
|
||||
|
||||
arrows = (int)(len / 256) + 1;
|
||||
|
||||
for (i = 0; i < arrows; i++) {
|
||||
f = len * (i + 0.5) / arrows;
|
||||
|
||||
mid1 = mid + (f * dir);
|
||||
|
||||
glVertex3fv(mid1.ToFloatPtr());
|
||||
glVertex3f(mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
|
||||
glVertex3fv(mid1.ToFloatPtr());
|
||||
glVertex3f(mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
|
||||
const int hashKey = nameHash.GenerateKey(targetName, true);
|
||||
for (int index = nameHash.First(hashKey); index != -1; index = nameHash.Next(index)) {
|
||||
const pathLineNamedEntity_t& namedTarget = namedEntities[index];
|
||||
if (strcmp(namedTarget.name, targetName) == 0) {
|
||||
DrawPathLines_DrawConnection(namedTarget, source, sourceBrush);
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user