mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Editor: Added ability to hide/unhide utility brushes and target lines.
Tweaked path tracing so lighting is more realistic.
This commit is contained in:
@@ -3374,6 +3374,35 @@ float3 LoadSceneSpecularAlbedo(uint2 pixel, float3 baseAlbedo)
|
||||
return Doom3PseudoSpecularMask(baseAlbedo);
|
||||
}
|
||||
|
||||
|
||||
float ComputeDiffuseLightingTerm(float3 N, float3 L)
|
||||
{
|
||||
// Keep the original light volume/range attenuation exactly where it is, but
|
||||
// make the surface response less gamey. The old 0.28-0.32 Half-Lambert wrap
|
||||
// pushed too much light around silhouettes and into back-facing normal-map
|
||||
// detail. This smaller squared wrap keeps Doom/idTech readability while
|
||||
// giving a more Lambert-like, physically plausible rolloff.
|
||||
float rawNoL = dot(normalize(N), normalize(L));
|
||||
|
||||
if (gEnableHalfLambert != 0u)
|
||||
{
|
||||
const float REALISTIC_WRAP = 0.12;
|
||||
float wrapped = saturate((rawNoL + REALISTIC_WRAP) / (1.0 + REALISTIC_WRAP));
|
||||
return wrapped * wrapped;
|
||||
}
|
||||
|
||||
return saturate(rawNoL);
|
||||
}
|
||||
|
||||
float EstimateSpecularRoughness(float3 specularAlbedo)
|
||||
{
|
||||
// No roughness map is available in this G-buffer path, so infer a stable
|
||||
// perceptual roughness from the specular map strength. Brighter spec maps
|
||||
// get tighter highlights; dark/missing maps stay broad and subdued.
|
||||
float peak = SpecularPeak3(saturate(specularAlbedo));
|
||||
return clamp(lerp(0.68, 0.34, peak), 0.28, 0.72);
|
||||
}
|
||||
|
||||
float3 ComputeSpecular(
|
||||
float3 N,
|
||||
float3 V,
|
||||
@@ -3387,47 +3416,66 @@ float3 ComputeSpecular(
|
||||
if (gEnableSpecular == 0)
|
||||
return 0.0;
|
||||
|
||||
if (atten <= 0.0 || shadow <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
N = normalize(N);
|
||||
V = normalize(V);
|
||||
L = normalize(L);
|
||||
|
||||
float NdotL = dot(N, L);
|
||||
float NdotV = dot(N, V);
|
||||
float NoL = saturate(dot(N, L));
|
||||
float NoV = saturate(dot(N, V));
|
||||
|
||||
if (atten <= 0.0 || shadow <= 0.0)
|
||||
if (NoL <= 1.0e-4 || NoV <= 1.0e-4)
|
||||
return 0.0;
|
||||
|
||||
// Keep Doom/idTech's front-side behavior, but make the gate soft. A hard
|
||||
// NdotL/NdotV cutoff was making normal-mapped and grazing surfaces randomly
|
||||
// lose all specular even when the half-angle lobe should still be visible.
|
||||
float lightFacing = smoothstep(-0.08, 0.18, NdotL);
|
||||
float viewFacing = smoothstep(-0.04, 0.14, NdotV);
|
||||
if (lightFacing <= 0.0 || viewFacing <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
// idTech4/Doom 3 interaction shader uses half-angle style specular,
|
||||
// not the reflect(-L,N) Phong vector used in the old code here.
|
||||
float3 H = Doom3SafeNormalizeOr(L + V, N);
|
||||
float NdotH = saturate(dot(N, H));
|
||||
float NoH = saturate(dot(N, H));
|
||||
float VoH = saturate(dot(V, H));
|
||||
|
||||
float specTerm = Doom3SpecularLookup(NdotH) * lightFacing * viewFacing;
|
||||
if (specTerm <= 1.0e-5)
|
||||
if (NoH <= 1.0e-4 || VoH <= 1.0e-4)
|
||||
return 0.0;
|
||||
|
||||
float3 specMask = saturate(specularAlbedo);
|
||||
float specPeak = SpecularPeak3(specMask);
|
||||
if (specPeak <= 0.001)
|
||||
return 0.0;
|
||||
|
||||
// Doom 3's interaction pass is strongly additive. Keep it punchy,
|
||||
// but clamp enough to avoid fireflies with stochastic light sampling.
|
||||
const float DOOM3_SPECULAR_SCALE = 4.75;
|
||||
float roughness = EstimateSpecularRoughness(specMask);
|
||||
float a = roughness * roughness;
|
||||
float a2 = max(a * a, 1.0e-4);
|
||||
|
||||
const float PI = 3.14159265;
|
||||
|
||||
// GGX/Trowbridge-Reitz distribution with Smith masking and Schlick Fresnel.
|
||||
// This is still intentionally stylized for the existing idTech-style assets,
|
||||
// but it produces more believable view-dependent highlights than the previous
|
||||
// additive lookup lobe and does not alter light attenuation distance.
|
||||
float dDenom = NoH * NoH * (a2 - 1.0) + 1.0;
|
||||
float D = a2 / max(PI * dDenom * dDenom, 1.0e-4);
|
||||
|
||||
float k = ((roughness + 1.0) * (roughness + 1.0)) * 0.125;
|
||||
float Gv = NoV / max(NoV * (1.0 - k) + k, 1.0e-4);
|
||||
float Gl = NoL / max(NoL * (1.0 - k) + k, 1.0e-4);
|
||||
float G = Gv * Gl;
|
||||
|
||||
float3 F0 = saturate(lerp(float3(0.025, 0.025, 0.025), specMask, 0.58));
|
||||
float3 F = F0 + (1.0 - F0) * pow(1.0 - VoH, 5.0);
|
||||
|
||||
float specTerm = (D * G) / max(4.0 * NoL * NoV, 1.0e-4);
|
||||
specTerm = min(specTerm, 5.0);
|
||||
|
||||
const float SPECULAR_ENERGY_SCALE = 2.35;
|
||||
|
||||
float3 specular =
|
||||
lightColor *
|
||||
lightIntensity *
|
||||
atten *
|
||||
shadow *
|
||||
specMask *
|
||||
NoL *
|
||||
F *
|
||||
specTerm *
|
||||
DOOM3_SPECULAR_SCALE;
|
||||
SPECULAR_ENERGY_SCALE;
|
||||
|
||||
return clamp(specular, 0.0, 8.0);
|
||||
}
|
||||
@@ -3768,17 +3816,16 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
|
||||
float3 L = toLight / dist;
|
||||
|
||||
float wrap = 0.28;
|
||||
float NdotLWrap = saturate((dot(N, L) + wrap) / (1.0 + wrap));
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
float shadow = 1.0;
|
||||
if (Lgt.samples != 0u && NdotLWrap > 0.0001)
|
||||
if (Lgt.samples != 0u && diffuseNoL > 0.0001)
|
||||
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
|
||||
|
||||
if (Lgt.pointRadiusPad <= 0.5)
|
||||
specAccum += ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
|
||||
diffuseAccum += Lgt.color * (Lgt.intensity * atten * NdotLWrap * shadow);
|
||||
diffuseAccum += Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
|
||||
}
|
||||
|
||||
float invSamples = 1.0 / (float)sampleCount;
|
||||
@@ -3798,17 +3845,16 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
|
||||
float3 L = toLight / dist;
|
||||
float atten = ComputeSpotLightAttenuation(worldPos, Lgt);
|
||||
|
||||
float wrap = 0.28;
|
||||
float NdotLWrap = saturate((dot(N, L) + wrap) / (1.0 + wrap));
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
float shadow = 1.0;
|
||||
if (Lgt.samples != 0u && NdotLWrap > 0.0001 && atten > 0.0)
|
||||
if (Lgt.samples != 0u && diffuseNoL > 0.0001 && atten > 0.0)
|
||||
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
|
||||
|
||||
if (Lgt.pointRadiusPad <= 0.5)
|
||||
specularOut = ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
|
||||
return Lgt.color * (Lgt.intensity * atten * NdotLWrap * shadow);
|
||||
return Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
|
||||
}
|
||||
|
||||
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
|
||||
@@ -3852,7 +3898,7 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
|
||||
continue;
|
||||
|
||||
float3 L = sampleVec / sampleDist;
|
||||
float NdotL = saturate(dot(N, L));
|
||||
float NdotL = ComputeDiffuseLightingTerm(N, L);
|
||||
if (NdotL <= 0.0)
|
||||
continue;
|
||||
|
||||
@@ -4019,8 +4065,7 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
|
||||
if (atten <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
float wrap = 0.32;
|
||||
float nDotL = saturate((dot(hitN, L) + wrap) / (1.0 + wrap));
|
||||
float nDotL = ComputeDiffuseLightingTerm(hitN, L);
|
||||
return clamp(Lgt.color * (Lgt.intensity * atten * nDotL), 0.0, 8.0);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
|
||||
@@ -4035,8 +4080,7 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
|
||||
if (atten <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
float wrap = 0.32;
|
||||
float nDotL = saturate((dot(hitN, L) + wrap) / (1.0 + wrap));
|
||||
float nDotL = ComputeDiffuseLightingTerm(hitN, L);
|
||||
return clamp(Lgt.color * (Lgt.intensity * atten * nDotL), 0.0, 8.0);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
|
||||
@@ -4053,7 +4097,7 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
|
||||
return 0.0;
|
||||
|
||||
float3 L = toCenter / centerDist;
|
||||
float nDotL = saturate(dot(hitN, L));
|
||||
float nDotL = ComputeDiffuseLightingTerm(hitN, L);
|
||||
if (nDotL <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
@@ -4507,8 +4551,8 @@ float3 PathTraceDeterministicLighting(
|
||||
float3 skyColor = skyColorRGB * (0.35 + 0.65 * upness);
|
||||
|
||||
float3 lightingAccum = gAmbientColor.rgb * (gAmbientColor.a * 0.04);
|
||||
lightingAccum += skyColor * (0.70 * skyVis);
|
||||
lightingAccum += ambientSkyVis * (skyColorRGB * 0.15);
|
||||
lightingAccum += skyColor * (0.42 * skyVis);
|
||||
lightingAccum += ambientSkyVis * (skyColorRGB * 0.12);
|
||||
|
||||
// Glow-map emissive is direct/bloom-only for now. It is added after lighting
|
||||
// in RayGen and is intentionally not injected into lightingAccum.
|
||||
@@ -4805,6 +4849,24 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
float3 ApplyRealisticOutputCurve(float3 color)
|
||||
{
|
||||
// Final photographic shoulder only: it does not change light radius or
|
||||
// attenuation, but it prevents intense local lights/specular/bloom from
|
||||
// clipping into a flat white patch. Values below 1.0 are left untouched.
|
||||
color = max(color, 0.0);
|
||||
|
||||
float peak = max(max(color.r, color.g), color.b);
|
||||
if (peak > 1.0)
|
||||
{
|
||||
float over = peak - 1.0;
|
||||
float shoulderPeak = 1.0 + over / (1.0 + over * 0.38);
|
||||
color *= shoulderPeak / max(peak, 1.0e-5);
|
||||
}
|
||||
|
||||
return max(color, 0.0);
|
||||
}
|
||||
|
||||
[shader("raygeneration")]
|
||||
void RayGen()
|
||||
{
|
||||
@@ -4822,7 +4884,7 @@ void RayGen()
|
||||
|
||||
if (depthSample <= 0.0 || depthSample >= 1.0)
|
||||
{
|
||||
gOutputTex[pixel] = float4(albedoSample.rgb + emissiveSurface + emissiveBloom, albedoSample.a);
|
||||
gOutputTex[pixel] = float4(ApplyRealisticOutputCurve(albedoSample.rgb + emissiveSurface + emissiveBloom), albedoSample.a);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4840,7 +4902,7 @@ void RayGen()
|
||||
|
||||
if (isUnlit)
|
||||
{
|
||||
gOutputTex[pixel] = float4(baseAlbedo + emissiveSurface + emissiveBloom, albedoSample.a);
|
||||
gOutputTex[pixel] = float4(ApplyRealisticOutputCurve(baseAlbedo + emissiveSurface + emissiveBloom), albedoSample.a);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4851,8 +4913,8 @@ void RayGen()
|
||||
// then reuse them for every stochastic GI sample.
|
||||
float cavity = ComputeCavity(pixel, worldPos, N);
|
||||
float ao = ComputeAmbientOcclusion(worldPos, N, pixel);
|
||||
float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel); // jmarshall - fix me later
|
||||
float ambientSkyVis = TraceStraightUpToSky(worldPos, N);
|
||||
float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel);
|
||||
float ambientSkyVis = 0; //TraceStraightUpToSky(worldPos, N);
|
||||
float microShadow = lerp(0.75, 1.0, cavity);
|
||||
|
||||
float3 reactiveFinalGather = 0.0;
|
||||
@@ -4947,7 +5009,7 @@ void RayGen()
|
||||
// the eventual swap-chain/backbuffer is LDR.
|
||||
finalColor += emissiveSurface + emissiveBloom;
|
||||
|
||||
gOutputTex[pixel] = float4(max(finalColor * ao, 0.0), albedoSample.a);
|
||||
gOutputTex[pixel] = float4(ApplyRealisticOutputCurve(finalColor), albedoSample.a);
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
@@ -1012,12 +1012,16 @@ static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask";
|
||||
#define CAMWND_MENU_CMD_SHOW_ENTITIES 62104
|
||||
#define CAMWND_MENU_CMD_SHOW_LIGHTS 62105
|
||||
#define CAMWND_MENU_CMD_RESET_FILTERS 62106
|
||||
#define CAMWND_MENU_CMD_SHOW_TARGET_LINES 62107
|
||||
#define CAMWND_MENU_CMD_SHOW_TRIGGER_BRUSHES 62108
|
||||
|
||||
#define CAMWND_FILTER_HIDE_WORLD 0x00000001
|
||||
#define CAMWND_FILTER_HIDE_PATCHES 0x00000002
|
||||
#define CAMWND_FILTER_HIDE_MODELS 0x00000004
|
||||
#define CAMWND_FILTER_HIDE_ENTITIES 0x00000008
|
||||
#define CAMWND_FILTER_HIDE_LIGHTS 0x00000010
|
||||
#define CAMWND_FILTER_HIDE_TARGET_LINES 0x00000020
|
||||
#define CAMWND_FILTER_HIDE_TRIGGER_BRUSHES 0x00000040
|
||||
|
||||
static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
@@ -1186,6 +1190,12 @@ static void CamWnd_HandleMenuCommand(CCamWnd* cam, int command) {
|
||||
case CAMWND_MENU_CMD_SHOW_LIGHTS:
|
||||
CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_LIGHTS);
|
||||
break;
|
||||
case CAMWND_MENU_CMD_SHOW_TARGET_LINES:
|
||||
CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_TARGET_LINES);
|
||||
break;
|
||||
case CAMWND_MENU_CMD_SHOW_TRIGGER_BRUSHES:
|
||||
CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_TRIGGER_BRUSHES);
|
||||
break;
|
||||
case CAMWND_MENU_CMD_RESET_FILTERS:
|
||||
CamWnd_ResetFilters(cam);
|
||||
break;
|
||||
@@ -1241,6 +1251,9 @@ static void CamWnd_ShowFiltersMenu(HWND hWnd, CCamWnd* cam) {
|
||||
CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_ENTITIES, CAMWND_MENU_CMD_SHOW_ENTITIES, "Show entities");
|
||||
CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_LIGHTS, CAMWND_MENU_CMD_SHOW_LIGHTS, "Show lights");
|
||||
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
|
||||
CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_TARGET_LINES, CAMWND_MENU_CMD_SHOW_TARGET_LINES, "Show actor/link lines");
|
||||
CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_TRIGGER_BRUSHES, CAMWND_MENU_CMD_SHOW_TRIGGER_BRUSHES, "Show trigger/utility brushes");
|
||||
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
|
||||
AppendMenu(menu, MF_STRING, CAMWND_MENU_CMD_RESET_FILTERS, "Reset filters");
|
||||
|
||||
command = TrackPopupMenu(menu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL);
|
||||
@@ -1370,6 +1383,154 @@ static void CamWnd_UpdateRuntimeState(CCamWnd* cam, bool renderMode, bool rebuil
|
||||
}
|
||||
}
|
||||
|
||||
static bool CamWnd_StringStartsWithNoCase(const char* text, const char* prefix) {
|
||||
if (text == NULL || prefix == NULL || prefix[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
return idStr::Icmpn(text, prefix, (int)strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static bool CamWnd_StringContainsNoCase(const char* text, const char* needle) {
|
||||
if (text == NULL || needle == NULL || needle[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int needleLen = (int)strlen(needle);
|
||||
for (const char* scan = text; *scan; scan++) {
|
||||
if (idStr::Icmpn(scan, needle, needleLen) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CamWnd_MaterialPathHasSegment(const char* materialName, const char* segment) {
|
||||
if (materialName == NULL || segment == NULL || segment[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int segmentLen = (int)strlen(segment);
|
||||
for (const char* scan = materialName; *scan; scan++) {
|
||||
const bool segmentStart = (scan == materialName || scan[-1] == '/' || scan[-1] == '\\');
|
||||
if (!segmentStart) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (idStr::Icmpn(scan, segment, segmentLen) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char end = scan[segmentLen];
|
||||
if (end == '\0' || end == '/' || end == '\\') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CamWnd_IsUtilityMaterial(const idMaterial* material) {
|
||||
if (material == NULL || material->GetName() == NULL || material->GetName()[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* materialName = material->GetName();
|
||||
|
||||
// Nodraw is the important case here and may appear outside textures/common
|
||||
// in some projects, so match it anywhere in the material name.
|
||||
if (CamWnd_StringContainsNoCase(materialName, "nodraw")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The broader names below are only treated as utility when they live in a
|
||||
// common/editor tool-material folder. This avoids hiding ordinary art
|
||||
// materials that happen to contain words like "clip" or "portal".
|
||||
if (!CamWnd_MaterialPathHasSegment(materialName, "common") &&
|
||||
!CamWnd_MaterialPathHasSegment(materialName, "editor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* const utilityTokens[] = {
|
||||
"caulk",
|
||||
"trigger",
|
||||
"clip",
|
||||
"playerclip",
|
||||
"monsterclip",
|
||||
"moveclip",
|
||||
"missileclip",
|
||||
"aas",
|
||||
"ladder",
|
||||
"origin",
|
||||
"portal",
|
||||
"visportal",
|
||||
"hint",
|
||||
"skip",
|
||||
"collision"
|
||||
};
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(utilityTokens) / sizeof(utilityTokens[0])); i++) {
|
||||
if (CamWnd_StringContainsNoCase(materialName, utilityTokens[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CamWnd_BrushUsesOnlyUtilityMaterials(brush_t* brush) {
|
||||
if (brush == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (brush->pPatch) {
|
||||
return CamWnd_IsUtilityMaterial(brush->pPatch->d_texture);
|
||||
}
|
||||
|
||||
bool foundMaterial = false;
|
||||
for (face_t* face = brush->brush_faces; face; face = face->next) {
|
||||
if (face->face_winding == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (face->d_texture == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foundMaterial = true;
|
||||
if (!CamWnd_IsUtilityMaterial(face->d_texture)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return foundMaterial;
|
||||
}
|
||||
|
||||
static bool CamWnd_IsTriggerLikeBrushEntity(brush_t* brush) {
|
||||
if (brush == NULL || brush->owner == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* className = ValueForKey(brush->owner, "classname");
|
||||
if (className == NULL || className[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// These brush entities are editor/gameplay volumes rather than visible map
|
||||
// geometry, so let the camera filter hide them independently from normal
|
||||
// func_* brush models such as doors, movers, and func_static.
|
||||
return CamWnd_StringStartsWithNoCase(className, "trigger") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "func_trigger") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "func_clip") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "func_playerclip") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "func_monsterclip") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "clip") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "playerclip") ||
|
||||
CamWnd_StringStartsWithNoCase(className, "monsterclip");
|
||||
}
|
||||
|
||||
static bool CamWnd_TargetLinesVisible(CCamWnd* cam) {
|
||||
return (CamWnd_GetFilterMask(cam) & CAMWND_FILTER_HIDE_TARGET_LINES) == 0;
|
||||
}
|
||||
|
||||
static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) {
|
||||
if (!brush) {
|
||||
return false;
|
||||
@@ -1394,8 +1555,13 @@ static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) {
|
||||
const bool isModel = (brush->modelHandle > 0) || (hasOwner && brush->owner->eclass->entityModel) || brush->entityModel;
|
||||
const bool isBrushModel = hasOwner && IsBModel(brush);
|
||||
const bool isFixedEntity = hasOwner && brush->owner->eclass->fixedsize;
|
||||
const bool isTriggerLikeBrushEntity = CamWnd_IsTriggerLikeBrushEntity(brush);
|
||||
const bool isUtilityMaterialBrush = CamWnd_BrushUsesOnlyUtilityMaterials(brush);
|
||||
const bool isEntity = isLight || isModel || isBrushModel || isFixedEntity;
|
||||
|
||||
if ((mask & CAMWND_FILTER_HIDE_TRIGGER_BRUSHES) && (isTriggerLikeBrushEntity || isUtilityMaterialBrush)) {
|
||||
return true;
|
||||
}
|
||||
if ((mask & CAMWND_FILTER_HIDE_LIGHTS) && isLight) {
|
||||
return true;
|
||||
}
|
||||
@@ -2641,7 +2807,9 @@ void CCamWnd::Cam_Draw() {
|
||||
// draw pointfile
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
CamWnd_DrawVisiblePathLines();
|
||||
if (CamWnd_TargetLinesVisible(this)) {
|
||||
CamWnd_DrawVisiblePathLines();
|
||||
}
|
||||
|
||||
if (g_qeglobals.d_pointfile_display_list) {
|
||||
Pointfile_Draw();
|
||||
|
||||
Reference in New Issue
Block a user