bool FGameplayTagContainer::DoesTagContainerMatchComplex(const FGameplayTagContainer& OtherContainer, TEnumAsByte<EGameplayTagMatchType::Type> TagMatchType, TEnumAsByte<EGameplayTagMatchType::Type> OtherTagMatchType, EGameplayContainerMatchType ContainerMatchType) const { UGameplayTagsManager& TagManager = IGameplayTagsModule::GetGameplayTagsManager(); for (TArray<FGameplayTag>::TConstIterator OtherIt(OtherContainer.GameplayTags); OtherIt; ++OtherIt) { bool bTagFound = false; for (TArray<FGameplayTag>::TConstIterator It(this->GameplayTags); It; ++It) { if (TagManager.GameplayTagsMatch(*It, TagMatchType, *OtherIt, OtherTagMatchType) == true) { if (ContainerMatchType == EGameplayContainerMatchType::Any) { return true; } bTagFound = true; // we only need one match per tag in OtherContainer, so don't bother looking for more break; } } if (ContainerMatchType == EGameplayContainerMatchType::All && bTagFound == false) { return false; } } // if we've reached this far then either we are looking for any match and didn't find one (return false) or we're looking for all matches and didn't miss one (return true). check(ContainerMatchType == EGameplayContainerMatchType::All || ContainerMatchType == EGameplayContainerMatchType::Any); return ContainerMatchType == EGameplayContainerMatchType::All; }
FGameplayTagContainer FGameplayTagContainer::Filter(const FGameplayTagContainer& OtherContainer, TEnumAsByte<EGameplayTagMatchType::Type> TagMatchType, TEnumAsByte<EGameplayTagMatchType::Type> OtherTagMatchType) const { SCOPE_CYCLE_COUNTER(STAT_FGameplayTagContainer_Filter); FGameplayTagContainer ResultContainer; UGameplayTagsManager& TagManager = IGameplayTagsModule::GetGameplayTagsManager(); for (TArray<FGameplayTag>::TConstIterator OtherIt(OtherContainer.GameplayTags); OtherIt; ++OtherIt) { for (TArray<FGameplayTag>::TConstIterator It(this->GameplayTags); It; ++It) { if (TagManager.GameplayTagsMatch(*It, TagMatchType, *OtherIt, OtherTagMatchType) == true) { ResultContainer.AddTag(*It); } } } return ResultContainer; }
void ULightComponent::ReassignStationaryLightChannels(UWorld* TargetWorld, bool bAssignForLightingBuild) { TMap<FLightAndChannel*, TArray<FLightAndChannel*> > LightToOverlapMap; // Build an array of all static shadowing lights that need to be assigned for(TObjectIterator<ULightComponent> LightIt(RF_ClassDefaultObject|RF_PendingKill); LightIt; ++LightIt) { ULightComponent* const LightComponent = *LightIt; const bool bLightIsInWorld = LightComponent->GetOwner() && TargetWorld->ContainsActor(LightComponent->GetOwner()) && !LightComponent->GetOwner()->IsPendingKill(); if (bLightIsInWorld // Only operate on stationary light components (static shadowing only) && LightComponent->HasStaticShadowing() && !LightComponent->HasStaticLighting()) { if (LightComponent->bAffectsWorld && LightComponent->CastShadows && LightComponent->CastStaticShadows) { LightToOverlapMap.Add(new FLightAndChannel(LightComponent), TArray<FLightAndChannel*>()); } else { // Reset the preview channel of stationary light components that shouldn't get a channel // This is necessary to handle a light being newly disabled LightComponent->PreviewShadowMapChannel = INDEX_NONE; #if WITH_EDITOR LightComponent->UpdateLightSpriteTexture(); #endif } } } // Build an array of overlapping lights for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It) { ULightComponent* CurrentLight = It.Key()->Light; TArray<FLightAndChannel*>& OverlappingLights = It.Value(); if (bAssignForLightingBuild) { // This should have happened during lighting invalidation at the beginning of the build anyway CurrentLight->ShadowMapChannel = INDEX_NONE; } for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator OtherIt(LightToOverlapMap); OtherIt; ++OtherIt) { ULightComponent* OtherLight = OtherIt.Key()->Light; if (CurrentLight != OtherLight // Testing both directions because the spotlight <-> spotlight test is just cone vs bounding sphere //@todo - more accurate spotlight <-> spotlight intersection && CurrentLight->AffectsBounds(FBoxSphereBounds(OtherLight->GetBoundingSphere())) && OtherLight->AffectsBounds(FBoxSphereBounds(CurrentLight->GetBoundingSphere()))) { OverlappingLights.Add(OtherIt.Key()); } } } // Sort lights with the most overlapping lights first LightToOverlapMap.ValueSort(FCompareLightsByArrayCount()); TMap<FLightAndChannel*, TArray<FLightAndChannel*> > SortedLightToOverlapMap; // Add directional lights to the beginning so they always get channels for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It) { FLightAndChannel* CurrentLight = It.Key(); if (CurrentLight->Light->GetLightType() == LightType_Directional) { SortedLightToOverlapMap.Add(It.Key(), It.Value()); } } // Add everything else, which has been sorted by descending overlaps for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It) { FLightAndChannel* CurrentLight = It.Key(); if (CurrentLight->Light->GetLightType() != LightType_Directional) { SortedLightToOverlapMap.Add(It.Key(), It.Value()); } } // Go through lights and assign shadowmap channels //@todo - retry with different ordering heuristics when it fails for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(SortedLightToOverlapMap); It; ++It) { bool bChannelUsed[4] = {0}; FLightAndChannel* CurrentLight = It.Key(); const TArray<FLightAndChannel*>& OverlappingLights = It.Value(); // Mark which channels have already been assigned to overlapping lights for (int32 OverlappingIndex = 0; OverlappingIndex < OverlappingLights.Num(); OverlappingIndex++) { FLightAndChannel* OverlappingLight = OverlappingLights[OverlappingIndex]; if (OverlappingLight->Channel != INDEX_NONE) { bChannelUsed[OverlappingLight->Channel] = true; } } // Use the lowest free channel for (int32 ChannelIndex = 0; ChannelIndex < ARRAY_COUNT(bChannelUsed); ChannelIndex++) { if (!bChannelUsed[ChannelIndex]) { CurrentLight->Channel = ChannelIndex; break; } } } // Go through the assigned lights and update their render state and icon for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(SortedLightToOverlapMap); It; ++It) { FLightAndChannel* CurrentLight = It.Key(); if (CurrentLight->Light->PreviewShadowMapChannel != CurrentLight->Channel) { CurrentLight->Light->PreviewShadowMapChannel = CurrentLight->Channel; CurrentLight->Light->MarkRenderStateDirty(); } #if WITH_EDITOR CurrentLight->Light->UpdateLightSpriteTexture(); #endif if (bAssignForLightingBuild) { CurrentLight->Light->ShadowMapChannel = CurrentLight->Channel; if (CurrentLight->Light->ShadowMapChannel == INDEX_NONE) { FMessageLog("LightingResults").Error() ->AddToken(FUObjectToken::Create(CurrentLight->Light->GetOwner())) ->AddToken(FTextToken::Create( NSLOCTEXT("Lightmass", "LightmassError_FailedToAllocateShadowmapChannel", "Severe performance loss: Failed to allocate shadowmap channel for stationary light due to overlap - light will fall back to dynamic shadows!") ) ); } } delete CurrentLight; } }