Numerous performance fixes.

This commit is contained in:
Justin Marshall
2026-05-21 15:36:02 -07:00
parent 2e4265f5a1
commit a89d43628c
29 changed files with 1632 additions and 636 deletions
+2
View File
@@ -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 ) },
+2 -1
View File
@@ -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>
+4 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+13 -1
View File
@@ -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
+3
View File
@@ -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
+6
View File
@@ -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;
+1 -1
View File
@@ -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 );
+10
View File
@@ -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 );
+3
View File
@@ -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;
+147
View File
@@ -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**>(&timestamps))) && 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;
File diff suppressed because it is too large Load Diff
+1
View File
@@ -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);
+22
View File
@@ -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>
+24 -1
View File
@@ -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>
+1 -1
View File
@@ -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 ) {
+2 -8
View File
@@ -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
+17 -20
View File
@@ -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 );
+4
View File
@@ -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];
+8 -1
View File
@@ -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 );
+48 -103
View File
@@ -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 );
+8 -1
View File
@@ -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 );
+4
View File
@@ -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();
+32 -13
View File
@@ -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;
}
+12 -143
View File
@@ -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;
}
+8 -1
View File
@@ -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;
}
+259 -46
View File
@@ -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;
}
+115 -72
View File
@@ -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;
}
//