コード例 #1
0
ファイル: DynamicWeather.cpp プロジェクト: cyy1991/carla
void ADynamicWeather::LoadWeatherDescriptionsFromFile(
    const FString &MapName,
    TArray<FWeatherDescription> &Descriptions)
{
  // Try to load config file.
  FString DefaultFilePath;
  if (GetWeatherIniFilePath(GetIniFileName(), DefaultFilePath)) {
    UE_LOG(LogCarla, Log, TEXT("Loading weather description from %s"), *DefaultFilePath);
    FIniFile ConfigFile(DefaultFilePath);

    { // Override map specific presets.
      FString MapOverridesFilePath;
      if (GetWeatherIniFilePath(GetIniFileName(MapName), MapOverridesFilePath)) {
        UE_LOG(LogCarla, Log, TEXT("Loading weather description from %s"), *MapOverridesFilePath);
        ConfigFile.Combine(MapOverridesFilePath);
      }
    }

    // For every section in the config file add a weather description.
    for (auto &Item : ConfigFile.GetFConfigFile()) {
      Descriptions.AddDefaulted(1u);
      Descriptions.Last().ReadFromConfigFile(ConfigFile, Item.Key);
    }
  }

  // If no description was found, append a defaulted one.
  if (Descriptions.Num() == 0) {
    UE_LOG(LogCarla, Warning, TEXT("No weather description found"));
    Descriptions.AddDefaulted(1u);
    Descriptions.Last().Name = TEXT("Default");
  }
}
コード例 #2
0
/**
 * Returns a list of all assets referenced by the specified UObject.
 */
void FFindReferencedAssets::BuildAssetList(UObject *Object, const TArray<UClass*>& IgnoreClasses, const TArray<UObject*>& IgnorePackages, TSet<UObject*>& ReferencedAssets, bool bIncludeDefaultRefs)
{
	TArray<FReferencedAssets> LocalReferencers;

	// Create a new entry for this actor.
	new( LocalReferencers ) FReferencedAssets( Object );

	for (FObjectIterator It; It; ++It)
	{
		// Skip the level, world, and any packages that should be ignored
		if ( ShouldSearchForAssets(*It, IgnoreClasses, IgnorePackages, bIncludeDefaultRefs) )
		{
			It->Mark(OBJECTMARK_TagExp);
		}
		else
		{
			It->UnMark(OBJECTMARK_TagExp);
		}
	}

	// Add to the list of referenced assets.
	FFindAssetsArchive( Object, LocalReferencers.Last().AssetList, NULL, /*MaxRecursion=*/0, /*bIncludeClasses=*/true, bIncludeDefaultRefs );

	ReferencedAssets = LocalReferencers.Last().AssetList;
}
コード例 #3
0
void UPathFindingComponent::DrawPath(FVector start, TArray<FVector>& route, FColor color, float duration, float thickness)
{
	if (duration <= 0.0f)
	{
		DrawDebugLine(GetWorld(), start, route.Last(), color, true, -1.0f, (uint8)'\000', thickness);
		for (auto index = 0; index < route.Num() - 1; index++)
			DrawDebugLine(GetWorld(), route[index], route[index + 1], color, true, -1.0f, (uint8)'\000', thickness);
	}
	else
	{
		DrawDebugLine(GetWorld(), start, route.Last(), color, false, duration, (uint8)'\000', thickness);
		for (auto index = 0; index < route.Num() - 1; index++)
			DrawDebugLine(GetWorld(), route[index], route[index + 1], color, false, duration, (uint8)'\000', thickness);
	}
}
コード例 #4
0
void UMaterialParameterCollectionInstance::GetParameterData(TArray<FVector4>& ParameterData) const
{
	// The memory layout created here must match the index assignment in UMaterialParameterCollection::GetParameterIndex

	if (Collection)
	{
		ParameterData.Empty(FMath::DivideAndRoundUp(Collection->ScalarParameters.Num(), 4) + Collection->VectorParameters.Num());

		for (int32 ParameterIndex = 0; ParameterIndex < Collection->ScalarParameters.Num(); ParameterIndex++)
		{
			const FCollectionScalarParameter& Parameter = Collection->ScalarParameters[ParameterIndex];

			// Add a new vector for each packed vector
			if (ParameterIndex % 4 == 0)
			{
				ParameterData.Add(FVector4(0, 0, 0, 0));
			}

			FVector4& CurrentVector = ParameterData.Last();
			const float* InstanceData = ScalarParameterValues.Find(Parameter.ParameterName);
			// Pack into the appropriate component of this packed vector
			CurrentVector[ParameterIndex % 4] = InstanceData ? *InstanceData : Parameter.DefaultValue;
		}

		for (int32 ParameterIndex = 0; ParameterIndex < Collection->VectorParameters.Num(); ParameterIndex++)
		{
			const FCollectionVectorParameter& Parameter = Collection->VectorParameters[ParameterIndex];
			const FLinearColor* InstanceData = VectorParameterValues.Find(Parameter.ParameterName);
			ParameterData.Add(InstanceData ? *InstanceData : Parameter.DefaultValue);
		}
	}
}
コード例 #5
0
void SSequencerLabelBrowser::ReloadLabelList(bool FullyReload)
{
	LabelList.Reset();
	LabelList.Add(MakeShareable(new FSequencerLabelTreeNode(FString(), FText::GetEmpty())));

	TArray<FString> AllLabels;
	
	if (Sequencer.IsValid() && Sequencer.Pin()->GetLabelManager().GetAllLabels(AllLabels) > 0)
	{
		for (const auto& Label : AllLabels)
		{
			// create new leaf node
			TArray<FString> Strings;
			Label.ParseIntoArray(Strings, TEXT("."), true);

			TSharedRef<FSequencerLabelTreeNode> NewNode = MakeShareable(
				new FSequencerLabelTreeNode(Label, FText::FromString(Strings.Last())));

			// insert node into tree
			TArray<TSharedPtr<FSequencerLabelTreeNode>>* ParentNodes = &LabelList;
			int32 Index = 0;

			while (Index < Strings.Num() - 1)
			{
				TSharedPtr<FSequencerLabelTreeNode> Parent;

				for (const auto& Node : *ParentNodes)
				{
					if (Node->Label == Strings[Index])
					{
						Parent = Node;
						break;
					}
				}

				// create interior node if needed
				if (!Parent.IsValid())
				{
					FString ParentLabel = Strings[0];

					for (int32 SubIndex = 1; SubIndex <= Index; ++SubIndex)
					{
						ParentLabel += TEXT(".") + Strings[SubIndex];
					}

					Parent = MakeShareable(new FSequencerLabelTreeNode(ParentLabel, FText::FromString(Strings[Index])));
					ParentNodes->Add(Parent);
				}

				ParentNodes = &Parent->Children;
				++Index;
			}

			// insert node into tree
			ParentNodes->Add(NewNode);
		}
	}

	LabelTreeView->RequestTreeRefresh();
}
コード例 #6
0
FVector FSCSEditorViewportClient::GetWidgetLocation() const
{
	FVector Location = FVector::ZeroVector;

	AActor* PreviewActor = GetPreviewActor();
	if(PreviewActor)
	{
		TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes();
		if(SelectedNodes.Num() > 0)
		{
			// Use the last selected item for the widget location
			USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes.Last().Get()->FindComponentInstanceInActor(PreviewActor));
			if( SceneComp )
			{
				TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditorPtr.Pin()->CustomizeSCSEditor(SceneComp);
				FVector CustomLocation;
				if(Customization.IsValid() && Customization->HandleGetWidgetLocation(SceneComp, CustomLocation))
				{
					Location = CustomLocation;
				}
				else
				{
					Location = SceneComp->GetComponentLocation();
				}
			}
		}
	}

	return Location;
}
コード例 #7
0
	static void BuildDependencyMapAndCompile(const TArray<UUserDefinedStruct*>& ChangedStructs, FCompilerResultsLog& MessageLog)
	{
		struct FDependencyMapEntry
		{
			UUserDefinedStruct* Struct;
			TSet<UUserDefinedStruct*> StructuresToWaitFor;

			FDependencyMapEntry() : Struct(NULL) {}

			void Initialize(UUserDefinedStruct* ChangedStruct, const TArray<UUserDefinedStruct*>& AllChangedStructs) 
			{ 
				Struct = ChangedStruct;
				check(Struct);

				auto Schema = GetDefault<UEdGraphSchema_K2>();
				for (auto& VarDesc : FStructureEditorUtils::GetVarDesc(Struct))
				{
					auto StructType = Cast<UUserDefinedStruct>(VarDesc.SubCategoryObject.Get());
					if (StructType && (VarDesc.Category == Schema->PC_Struct) && AllChangedStructs.Contains(StructType))
					{
						StructuresToWaitFor.Add(StructType);
					}
				}
			}
		};

		TArray<FDependencyMapEntry> DependencyMap;
		for (auto Iter = ChangedStructs.CreateConstIterator(); Iter; ++Iter)
		{
			DependencyMap.Add(FDependencyMapEntry());
			DependencyMap.Last().Initialize(*Iter, ChangedStructs);
		}

		while (DependencyMap.Num())
		{
			int32 StructureToCompileIndex = INDEX_NONE;
			for (int32 EntryIndex = 0; EntryIndex < DependencyMap.Num(); ++EntryIndex)
			{
				if(0 == DependencyMap[EntryIndex].StructuresToWaitFor.Num())
				{
					StructureToCompileIndex = EntryIndex;
					break;
				}
			}
			check(INDEX_NONE != StructureToCompileIndex);
			UUserDefinedStruct* Struct = DependencyMap[StructureToCompileIndex].Struct;
			check(Struct);

			FUserDefinedStructureCompilerInner::CleanAndSanitizeStruct(Struct);
			FUserDefinedStructureCompilerInner::InnerCompileStruct(Struct, GetDefault<UEdGraphSchema_K2>(), MessageLog);

			DependencyMap.RemoveAtSwap(StructureToCompileIndex);

			for (auto EntryIter = DependencyMap.CreateIterator(); EntryIter; ++EntryIter)
			{
				(*EntryIter).StructuresToWaitFor.Remove(Struct);
			}
		}
	}
コード例 #8
0
/** Generates a Sample from the given step 1D probability distribution function. */
void Sample1dCDF(const TArray<float>& PDFArray, const TArray<float>& CDFArray, float UnnormalizedIntegral, FLMRandomStream& RandomStream, float& PDF, float& Sample)
{
	checkSlow(PDFArray.Num() > 0);
	checkSlow(PDFArray.Num() == CDFArray.Num());
	
	// See pages 641-644 of the "Physically Based Rendering" book for an excellent description of 
	// How to sample from a piecewise-constant 1d function, which this implementation is based on.
	if (PDFArray.Num() > 1)
	{
		// Get a uniformly distributed pseudo-random number
		const float RandomFraction = RandomStream.GetFraction();
		int32 GreaterElementIndex = -1;
		// Find the index of where the step function becomes greater or equal to the generated number
		//@todo - CDFArray is monotonically increasing so we can do better than a linear time search
		for (int32 i = 1; i < CDFArray.Num(); i++)
		{
			if (CDFArray[i] >= RandomFraction)
			{
				GreaterElementIndex = i;
				break;
			}
		}
		if (GreaterElementIndex >= 0)
		{
			check(GreaterElementIndex >= 1 && GreaterElementIndex < CDFArray.Num());
			// Find the fraction that the generated number is from the element before the greater or equal element.
			const float OffsetAlongCDFSegment = (RandomFraction - CDFArray[GreaterElementIndex - 1]) / (CDFArray[GreaterElementIndex] - CDFArray[GreaterElementIndex - 1]);
			// Access the probability that this element was selected and normalize it 
			PDF = PDFArray[GreaterElementIndex - 1] / UnnormalizedIntegral;
			Sample = (GreaterElementIndex - 1 + OffsetAlongCDFSegment) / (float)CDFArray.Num();
		}
		else
		{
			// The last element in the 1d CDF was selected
			const float OffsetAlongCDFSegment = (RandomFraction - CDFArray.Last()) / (1.0f - CDFArray.Last());
			PDF = PDFArray.Last() / UnnormalizedIntegral;
			Sample = FMath::Clamp((CDFArray.Num() - 1 + OffsetAlongCDFSegment) / (float)CDFArray.Num(), 0.0f, 1.0f - DELTA);
		}
	}
	else
	{
		PDF = 1.0f;
		Sample = 0;
	}
}
コード例 #9
0
bool FRawCurveTracks::DuplicateCurveDataImpl(TArray<DataType> & Curves, USkeleton::AnimCurveUID ToCopyUid, USkeleton::AnimCurveUID NewUid)
{
	DataType* ExistingCurve = GetCurveDataImpl<DataType>(Curves, ToCopyUid);
	if(ExistingCurve && GetCurveDataImpl<DataType>(Curves, NewUid) == NULL)
	{
		// Add the curve to the track and set its data to the existing curve
		Curves.Add(DataType(NewUid, ExistingCurve->GetCurveTypeFlags()));
		Curves.Last().CopyCurve(*ExistingCurve);

		return true;
	}
	return false;
}
コード例 #10
0
TArray<FString> USkeleUtilityFunctionLibrary::GetDefaultPlayerNamesFromFile() {
    FString filePath = FPaths::GameDir() + "Config/DefaultPlayerNames.ini";

    FString fileContents = "";
    FFileHelper::LoadFileToString(fileContents, *filePath);

    TArray<FString> items;
    int32 itemCount = fileContents.ParseIntoArray(items, TEXT(","), true);

    if (items.Last().Contains(TEXT("\n"))) {
        items.Pop();
    }

    return items;
}
コード例 #11
0
//------------------------------------------------------------------------------
int32 FLinkerPlaceholderBase::ResolvePlaceholderPropertyValues(UObject* NewObjectValue)
{
	int32 ResolvedTotal = 0;

	UObject* ThisAsUObject = GetPlaceholderAsUObject();
	for (auto& ReferencingPair : ReferencingContainers)
	{
		TWeakObjectPtr<UObject> ContainerPtr = ReferencingPair.Key;
		if (!ContainerPtr.IsValid())
		{
			continue;
		}
		UObject* Container = ContainerPtr.Get();

		for (const UObjectProperty* Property : ReferencingPair.Value)
		{
#if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
			check(Property->GetOwnerClass() == Container->GetClass());
#endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS

			TArray<const UProperty*> PropertyChain;
			LinkerPlaceholderObjectImpl::BuildPropertyChain(Property, PropertyChain);
			const UProperty* OutermostProperty = PropertyChain.Last();

			uint8* OutermostAddress = OutermostProperty->ContainerPtrToValuePtr<uint8>((uint8*)Container, /*ArrayIndex =*/0);
			int32 ResolvedCount = LinkerPlaceholderObjectImpl::ResolvePlaceholderValues(PropertyChain, PropertyChain.Num() - 1, OutermostAddress, ThisAsUObject, NewObjectValue);
			ResolvedTotal += ResolvedCount;

#if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
			// we expect that (because we have had ReferencingProperties added) 
			// there should be at least one reference that is resolved... if 
			// there were none, then a property could have changed its value 
			// after it was set to this
			// 
			// NOTE: this may seem it can be resolved by properties removing 
			//       themselves from ReferencingProperties, but certain 
			//       properties may be the inner of a UArrayProperty (meaning 
			//       there could be multiple references per property)... we'd 
			//       have to inc/decrement a property ref-count to resolve that 
			//       scenario
			check(ResolvedCount > 0);
#endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
		}
	}

	return ResolvedTotal;
}
コード例 #12
0
bool UAirBlueprintLib::GetLastObstaclePosition(const AActor* actor, const FVector& start, const FVector& end,
    FHitResult& hit, const AActor* ignore_actor, ECollisionChannel collision_channel)
{
    TArray<FHitResult> hits;

    FCollisionQueryParams trace_params;
    trace_params.AddIgnoredActor(actor);
    if (ignore_actor != nullptr)
        trace_params.AddIgnoredActor(ignore_actor);

    bool has_hit = actor->GetWorld()->LineTraceMultiByChannel(hits, start, end, collision_channel, trace_params);

    if (hits.Num())
        hit = hits.Last(0);

    return has_hit;
}
コード例 #13
0
	void ParseString(const FString& StringToParse)
	{
		DataIndex = 0;
		DataString = StringToParse;
		if (DataIndex >= DataString.Len())
		{
			return;
		}

		const FString TabString(TEXT("     "));
		FColor TagColor;
		FNode CurrentNode(DefaultColor);

		for (EStringParserToken Token = ReadToken(); Token != EStringParserToken::EndOfString; Token = ReadToken())
		{
			switch (Token)
			{
			case EStringParserToken::RegularChar:
				CurrentNode.String.AppendChar(DataString[DataIndex]);
				break;

			case EStringParserToken::NewLine:
				NodeList.Add(CurrentNode);
				CurrentNode = FNode(NodeList.Last().Color);
				CurrentNode.bNewLine = true;
				break;

			case EStringParserToken::Tab:
				CurrentNode.String.Append(TabString);
				break;

			case EStringParserToken::OpenTag:
				if (ParseTag(TagColor))
				{
					NodeList.Add(CurrentNode);
					CurrentNode = FNode(TagColor);
				}
				break;
			}

			DataIndex++;
		}

		NodeList.Add(CurrentNode);
	}
コード例 #14
0
bool UCrowdManager::SetAgentMovePath(const UCrowdFollowingComponent* AgentComponent, const FNavMeshPath* Path,
	int32 PathSectionStart, int32 PathSectionEnd, const FVector& PathSectionEndLocation) const
{
	SCOPE_CYCLE_COUNTER(STAT_AI_Crowd_AgentUpdateTime);

	bool bSuccess = false;

#if WITH_RECAST
	const FCrowdAgentData* AgentData = ActiveAgents.Find(AgentComponent);
	ARecastNavMesh* RecastNavData = Cast<ARecastNavMesh>(MyNavData);
	if (AgentData && AgentData->bIsSimulated && AgentData->IsValid() && 
		DetourCrowd && RecastNavData &&
		Path && (Path->GetPathPoints().Num() > 1) &&
		Path->PathCorridor.IsValidIndex(PathSectionStart) && Path->PathCorridor.IsValidIndex(PathSectionEnd))
	{
		FVector TargetPos = PathSectionEndLocation;
		if (PathSectionEnd < (Path->PathCorridor.Num() - 1))
		{
			RecastNavData->GetPolyCenter(Path->PathCorridor[PathSectionEnd], TargetPos);
		}

		TArray<dtPolyRef> PathRefs;
		for (int32 Idx = PathSectionStart; Idx <= PathSectionEnd; Idx++)
		{
			PathRefs.Add(Path->PathCorridor[Idx]);
		}

		const INavigationQueryFilterInterface* NavFilter = Path->GetFilter().IsValid() ? Path->GetFilter()->GetImplementation() : MyNavData->GetDefaultQueryFilterImpl();
		const dtQueryFilter* DetourFilter = ((const FRecastQueryFilter*)NavFilter)->GetAsDetourQueryFilter();
		DetourCrowd->updateAgentFilter(AgentData->AgentIndex, DetourFilter);
		DetourCrowd->updateAgentState(AgentData->AgentIndex, false);

		const FVector RcTargetPos = Unreal2RecastPoint(TargetPos);
		bSuccess = DetourCrowd->requestMoveTarget(AgentData->AgentIndex, PathRefs.Last(), &RcTargetPos.X);
		if (bSuccess)
		{
			bSuccess = DetourCrowd->setAgentCorridor(AgentData->AgentIndex, PathRefs.GetData(), PathRefs.Num());
		}
	}
#endif

	return bSuccess;
}
コード例 #15
0
/** Calculates the step 1D cumulative distribution function for the given unnormalized probability distribution function. */
void CalculateStep1dCDF(const TArray<float>& PDF, TArray<float>& CDF, float& UnnormalizedIntegral)
{
	CDF.Empty(PDF.Num());
	float RunningUnnormalizedIntegral = 0;
	CDF.Add(0.0f);
	for (int32 i = 1; i < PDF.Num(); i++)
	{
		RunningUnnormalizedIntegral += PDF[i - 1];
		CDF.Add(RunningUnnormalizedIntegral);
	}
	UnnormalizedIntegral = RunningUnnormalizedIntegral + PDF.Last();
	if (UnnormalizedIntegral > 0.0f)
	{
		// Normalize the CDF
		for (int32 i = 1; i < CDF.Num(); i++)
		{
			CDF[i] /= UnnormalizedIntegral;
		}
	}
	check(CDF.Num() == PDF.Num());
}
コード例 #16
0
void FSCSEditorViewportClient::FocusViewportToSelection()
{
	AActor* PreviewActor = GetPreviewActor();
	if(PreviewActor)
	{
		TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes();
		if(SelectedNodes.Num() > 0)
		{
			// Use the last selected item for the widget location
			USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes.Last()->FindComponentInstanceInActor(PreviewActor));
			if( SceneComp )
			{
				FocusViewportOnBox( SceneComp->Bounds.GetBox() );
			}
		}
		else
		{
			FocusViewportOnBox( PreviewActor->GetComponentsBoundingBox( true ) );
		}
	}
}
コード例 #17
0
void FGroupedKeyCollection::UpdateIndex() const
{
	auto& IndexEntry = GlobalIndex.FindOrAdd(IndexKey);

	TArray<FKeyHandle> NewKeyHandles;
	TArray<float> NewRepresentativeTimes;

	IndexEntry.HandleToGroup.Reset();

	for (int32 GroupIndex = 0; GroupIndex < Groups.Num(); ++GroupIndex)
	{
		float RepresentativeTime = Groups[GroupIndex].RepresentativeTime;

		// Find a key handle we can recycle
		int32 RecycledIndex = IndexEntry.RepresentativeTimes.IndexOfByPredicate([&](float Time){
			// Must be an *exact* match to recycle
			return Time == RepresentativeTime;
		});
		
		if (RecycledIndex != INDEX_NONE)
		{
			NewKeyHandles.Add(IndexEntry.GroupHandles[RecycledIndex]);
			NewRepresentativeTimes.Add(IndexEntry.RepresentativeTimes[RecycledIndex]);

			IndexEntry.GroupHandles.RemoveAt(RecycledIndex, 1, false);
			IndexEntry.RepresentativeTimes.RemoveAt(RecycledIndex, 1, false);
		}
		else
		{
			NewKeyHandles.Add(FKeyHandle());
			NewRepresentativeTimes.Add(RepresentativeTime);
		}

		IndexEntry.HandleToGroup.Add(NewKeyHandles.Last(), GroupIndex);
	}

	IndexEntry.GroupHandles = MoveTemp(NewKeyHandles);
	IndexEntry.RepresentativeTimes = MoveTemp(NewRepresentativeTimes);
}
コード例 #18
0
FMatrix FSCSEditorViewportClient::GetWidgetCoordSystem() const
{
	FMatrix Matrix = FMatrix::Identity;
	if( GetWidgetCoordSystemSpace() == COORD_Local )
	{
		AActor* PreviewActor = GetPreviewActor();
		auto BlueprintEditor = BlueprintEditorPtr.Pin();
		if (PreviewActor && BlueprintEditor.IsValid())
		{
			TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditor->GetSelectedSCSEditorTreeNodes();
			if(SelectedNodes.Num() > 0)
			{
				const auto SelectedNode = SelectedNodes.Last();
				USceneComponent* SceneComp = SelectedNode.IsValid() ? Cast<USceneComponent>(SelectedNode->FindComponentInstanceInActor(PreviewActor)) : NULL;
				if( SceneComp )
				{
					TSharedPtr<ISCSEditorCustomization> Customization = BlueprintEditor->CustomizeSCSEditor(SceneComp);
					FMatrix CustomTransform;
					if(Customization.IsValid() && Customization->HandleGetWidgetTransform(SceneComp, CustomTransform))
					{
						Matrix = CustomTransform;
					}					
					else
					{
						Matrix = FRotationMatrix( SceneComp->GetComponentRotation() );
					}
				}
			}
		}
	}

	if(!Matrix.Equals(FMatrix::Identity))
	{
		Matrix.RemoveScaling();
	}

	return Matrix;
}
コード例 #19
0
void FRawProfilerSession::ProcessStatPacketArray( const FStatPacketArray& StatPacketArray, FProfilerFrame& out_ProfilerFrame, int32 FrameIndex )
{
	// @TODO yrx 2014-03-24 Standardize thread names and id
	// @TODO yrx 2014-04-22 Remove all references to the data provider, event graph etc once data graph can visualize.

	// Raw stats callstack for this stat packet array.
	TMap<FName,FProfilerStackNode*> ThreadNodes;

	const FProfilerStatMetaDataRef MetaData = GetMetaData();
	
	FProfilerSampleArray& MutableCollection = const_cast<FProfilerSampleArray&>(DataProvider->GetCollection());

	// Add a root sample for this frame.
	const uint32 FrameRootSampleIndex = DataProvider->AddHierarchicalSample( 0, MetaData->GetStatByID( 1 ).OwningGroup().ID(), 1, 0.0f, 0.0f, 1 );

	// Iterate through all stats packets and raw stats messages.
	FName GameThreadFName = NAME_None;
	for( int32 PacketIndex = 0; PacketIndex < StatPacketArray.Packets.Num(); PacketIndex++ )
	{
		const FStatPacket& StatPacket = *StatPacketArray.Packets[PacketIndex];
		FName ThreadFName = StatsThreadStats.Threads.FindChecked( StatPacket.ThreadId );
		const uint32 NewThreadID = MetaData->ThreadIDtoStatID.FindChecked( StatPacket.ThreadId );

		// @TODO yrx 2014-04-29 Only game or render thread is supported at this moment.
		if( StatPacket.ThreadType != EThreadType::Game && StatPacket.ThreadType != EThreadType::Renderer )
		{
			continue;
		}

		// Workaround for issue with rendering thread names.
		if( StatPacket.ThreadType == EThreadType::Renderer )
		{
			ThreadFName = NAME_RenderThread;
		}
		else if( StatPacket.ThreadType == EThreadType::Game )
		{
			GameThreadFName = ThreadFName;
		}

		FProfilerStackNode* ThreadNode = ThreadNodes.FindRef( ThreadFName );
		if( !ThreadNode )
		{
			FString ThreadIdName = FStatsUtils::BuildUniqueThreadName( StatPacket.ThreadId );
			FStatMessage ThreadMessage( ThreadFName, EStatDataType::ST_int64, STAT_GROUP_TO_FStatGroup( STATGROUP_Threads )::GetGroupName(), STAT_GROUP_TO_FStatGroup( STATGROUP_Threads )::GetGroupCategory(), *ThreadIdName, true, true );
			//FStatMessage ThreadMessage( ThreadFName, EStatDataType::ST_int64, nullptr, nullptr, TEXT( "" ), true, true );
			ThreadMessage.NameAndInfo.SetFlag( EStatMetaFlags::IsPackedCCAndDuration, true );
			ThreadMessage.Clear();

			// Add a thread sample.
			const uint32 ThreadRootSampleIndex = DataProvider->AddHierarchicalSample
			(
				NewThreadID,
				MetaData->GetStatByID( NewThreadID ).OwningGroup().ID(),
				NewThreadID,
				-1.0f,
				-1.0f,
				1,
				FrameRootSampleIndex
			);

			ThreadNode = ThreadNodes.Add( ThreadFName, new FProfilerStackNode( nullptr, ThreadMessage, ThreadRootSampleIndex, FrameIndex ) );
		}


		TArray<const FStatMessage*> StartStack;
		TArray<FProfilerStackNode*> Stack;
		Stack.Add( ThreadNode );
		FProfilerStackNode* Current = Stack.Last();

		const FStatMessagesArray& Data = StatPacket.StatMessages;
		for( int32 Index = 0; Index < Data.Num(); Index++ )
		{
			const FStatMessage& Item = Data[Index];

			const EStatOperation::Type Op = Item.NameAndInfo.GetField<EStatOperation>();
			const FName LongName = Item.NameAndInfo.GetRawName();
			const FName ShortName = Item.NameAndInfo.GetShortName();

			const FName RenderingThreadTickCommandName = TEXT("RenderingThreadTickCommand");

			// Workaround for render thread hierarchy. EStatOperation::AdvanceFrameEventRenderThread is called within the scope.
			if( ShortName == RenderingThreadTickCommandName )
			{
				continue;
			}

			if( Op == EStatOperation::CycleScopeStart || Op == EStatOperation::CycleScopeEnd || Op == EStatOperation::AdvanceFrameEventRenderThread )
			{
				//check( Item.NameAndInfo.GetFlag( EStatMetaFlags::IsCycle ) );
				if( Op == EStatOperation::CycleScopeStart )
				{
					FProfilerStackNode* ChildNode = new FProfilerStackNode( Current, Item, -1, FrameIndex );
					Current->Children.Add( ChildNode );

					// Add a child sample.
					const uint32 SampleIndex = DataProvider->AddHierarchicalSample
					(
						NewThreadID,
						MetaData->GetStatByFName( ShortName ).OwningGroup().ID(), // GroupID
						MetaData->GetStatByFName( ShortName ).ID(), // StatID
						MetaData->ConvertCyclesToMS( ChildNode->CyclesStart ), // StartMS 
						MetaData->ConvertCyclesToMS( 0 ), // DurationMS
						1,
						Current->SampleIndex
					);
					ChildNode->SampleIndex = SampleIndex;

					Stack.Add( ChildNode );
					StartStack.Add( &Item );
					Current = ChildNode;
				}
				// Workaround for render thread hierarchy. EStatOperation::AdvanceFrameEventRenderThread is called within the scope.
				if( Op == EStatOperation::AdvanceFrameEventRenderThread )
				{
					int k=0;k++;
				}
				if( Op == EStatOperation::CycleScopeEnd )
				{
					const FStatMessage ScopeStart = *StartStack.Pop();
					const FStatMessage ScopeEnd = Item;
					const int64 Delta = int32( uint32( ScopeEnd.GetValue_int64() ) - uint32( ScopeStart.GetValue_int64() ) );
					Current->CyclesEnd = Current->CyclesStart + Delta;

					Current->CycleCounterStartTimeMS = MetaData->ConvertCyclesToMS( Current->CyclesStart );
					Current->CycleCounterEndTimeMS = MetaData->ConvertCyclesToMS( Current->CyclesEnd );

					if( Current->CycleCounterStartTimeMS > Current->CycleCounterEndTimeMS )
					{
						int k=0;k++;
					}

					check( Current->CycleCounterEndTimeMS >= Current->CycleCounterStartTimeMS );

					FProfilerStackNode* ChildNode = Current;

					// Update the child sample's DurationMS.
					MutableCollection[ChildNode->SampleIndex].SetDurationMS( MetaData->ConvertCyclesToMS( Delta ) );

					verify( Current == Stack.Pop() );
					Current = Stack.Last();				
				}
			}
		}
	}

	// Calculate thread times.
	for( auto It = ThreadNodes.CreateIterator(); It; ++It )
	{
		FProfilerStackNode& ThreadNode = *It.Value();
		const int32 ChildrenNum = ThreadNode.Children.Num();
		if( ChildrenNum > 0 )
		{
			const int32 LastChildIndex = ThreadNode.Children.Num() - 1;
			ThreadNode.CyclesStart = ThreadNode.Children[0]->CyclesStart;
			ThreadNode.CyclesEnd = ThreadNode.Children[LastChildIndex]->CyclesEnd;
			ThreadNode.CycleCounterStartTimeMS = MetaData->ConvertCyclesToMS( ThreadNode.CyclesStart );
			ThreadNode.CycleCounterEndTimeMS = MetaData->ConvertCyclesToMS( ThreadNode.CyclesEnd );

			FProfilerSample& ProfilerSample = MutableCollection[ThreadNode.SampleIndex];
			ProfilerSample.SetStartAndEndMS( MetaData->ConvertCyclesToMS( ThreadNode.CyclesStart ), MetaData->ConvertCyclesToMS( ThreadNode.CyclesEnd ) );
		}
	}

	// Get the game thread time.
	check( GameThreadFName != NAME_None );
	const FProfilerStackNode& GameThreadNode = *ThreadNodes.FindChecked( GameThreadFName );
	const double GameThreadStartMS = MetaData->ConvertCyclesToMS( GameThreadNode.CyclesStart );
	const double GameThreadEndMS = MetaData->ConvertCyclesToMS( GameThreadNode.CyclesEnd );
	MutableCollection[FrameRootSampleIndex].SetStartAndEndMS( GameThreadStartMS, GameThreadEndMS );
	
	// Advance frame
	const uint32 LastFrameIndex = DataProvider->GetNumFrames();
	DataProvider->AdvanceFrame( GameThreadEndMS - GameThreadStartMS );
 
	// Update aggregated stats
	UpdateAggregatedStats( LastFrameIndex );
 
	// Update aggregated events.
	UpdateAggregatedEventGraphData( LastFrameIndex );

	// RootNode is the same as the game thread node.
	out_ProfilerFrame.Root->CycleCounterStartTimeMS = GameThreadStartMS;
	out_ProfilerFrame.Root->CycleCounterEndTimeMS = GameThreadEndMS;

	for( auto It = ThreadNodes.CreateIterator(); It; ++It )
	{
		out_ProfilerFrame.AddChild( It.Value() );
	}

	out_ProfilerFrame.SortChildren();
}
コード例 #20
0
	static void BuildDependencyMapAndCompile(TArray<UBlueprintGeneratedStruct*>& ChangedStructs, FCompilerResultsLog& MessageLog)
	{
		struct FFindStructureDescriptionPred
		{
			const UBlueprintGeneratedStruct* const Struct;
			FFindStructureDescriptionPred(const UBlueprintGeneratedStruct* InStruct) : Struct(InStruct) { check(Struct); }
			bool operator()(const FBPStructureDescription& Desc) { return (Desc.CompiledStruct == Struct); }
		};

		struct FDependencyMapEntry
		{
			UBlueprintGeneratedStruct* Struct;
			TSet<UBlueprintGeneratedStruct*> StructuresToWaitFor;

			FDependencyMapEntry() : Struct(NULL) {}

			void Initialize(UBlueprintGeneratedStruct* ChangedStruct, TArray<UBlueprintGeneratedStruct*>& AllChangedStructs) 
			{ 
				Struct = ChangedStruct;
				check(Struct && Struct->StructGeneratedBy);
				FBPStructureDescription* StructureDescription = Struct->StructGeneratedBy->UserDefinedStructures.FindByPredicate(FFindStructureDescriptionPred(Struct));
				check(StructureDescription);

				auto Schema = GetDefault<UEdGraphSchema_K2>();
				for (auto FieldIter = StructureDescription->Fields.CreateIterator(); FieldIter; ++FieldIter)
				{
					FEdGraphPinType FieldType = (*FieldIter).VarType;
					auto StructType = Cast<UBlueprintGeneratedStruct>(FieldType.PinSubCategoryObject.Get());
					if (StructType && (FieldType.PinCategory == Schema->PC_Struct) && AllChangedStructs.Contains(StructType))
					{
						StructuresToWaitFor.Add(StructType);
					}
				}
			}
		};

		TArray<FDependencyMapEntry> DependencyMap;
		for (auto Iter = ChangedStructs.CreateIterator(); Iter; ++Iter)
		{
			DependencyMap.Add(FDependencyMapEntry());
			DependencyMap.Last().Initialize(*Iter, ChangedStructs);
		}

		while (DependencyMap.Num())
		{
			int32 StructureToCompileIndex = INDEX_NONE;
			for (int32 EntryIndex = 0; EntryIndex < DependencyMap.Num(); ++EntryIndex)
			{
				if(0 == DependencyMap[EntryIndex].StructuresToWaitFor.Num())
				{
					StructureToCompileIndex = EntryIndex;
					break;
				}
			}
			check(INDEX_NONE != StructureToCompileIndex);
			UBlueprintGeneratedStruct* Struct = DependencyMap[StructureToCompileIndex].Struct;
			check(Struct->StructGeneratedBy);
			FBPStructureDescription* StructureDescription = Struct->StructGeneratedBy->UserDefinedStructures.FindByPredicate(FFindStructureDescriptionPred(Struct));
			check(StructureDescription);

			FUserDefinedStructureCompilerInner::CleanAndSanitizeStruct(Struct);
			FUserDefinedStructureCompilerInner::InnerCompileStruct(*StructureDescription, GetDefault<UEdGraphSchema_K2>(), MessageLog);

			DependencyMap.RemoveAtSwap(StructureToCompileIndex);

			for (auto EntryIter = DependencyMap.CreateIterator(); EntryIter; ++EntryIter)
			{
				(*EntryIter).StructuresToWaitFor.Remove(Struct);
			}
		}
	}
コード例 #21
0
/**
* Dumps the information held within the EditorPerfCaptureParameters struct into a CSV file.
* @param EditorPerfStats is the name of the struct that holds the needed performance information.
*/
void EditorPerfDump(EditorPerfCaptureParameters& EditorPerfStats)
{
	UE_LOG(LogEditorAutomationTests, Log, TEXT("Begin generating the editor performance charts."));

	//The file location where to save the data.
	FString DataFileLocation = FPaths::Combine(*FPaths::AutomationLogDir(), TEXT("Performance"), *EditorPerfStats.MapName);

	//Get the map load time (in seconds) from the text file that is created when the load map latent command is ran.
	EditorPerfStats.MapLoadTime = 0;
	FString MapLoadTimeFileLocation = FPaths::Combine(*DataFileLocation, TEXT("RAWMapLoadTime.txt"));
	if (FPaths::FileExists(*MapLoadTimeFileLocation))
	{
		TArray<FString> SavedMapLoadTimes;
		FAutomationEditorCommonUtils::CreateArrayFromFile(MapLoadTimeFileLocation, SavedMapLoadTimes);
		EditorPerfStats.MapLoadTime = FCString::Atof(*SavedMapLoadTimes.Last());
	}
	
	//Filename for the RAW csv which holds the data gathered from a single test ran.
	FString RAWCSVFilePath = FString::Printf(TEXT("%s/RAW_%s_%s.csv"), *DataFileLocation, *EditorPerfStats.MapName, *FDateTime::Now().ToString());

	//Filename for the pretty csv file.
	FString PerfCSVFilePath = FString::Printf(TEXT("%s/%s_Performance.csv"), *DataFileLocation, *EditorPerfStats.MapName);

	//Create the raw csv and then add the title row it.
	FArchive* RAWCSVArchive = IFileManager::Get().CreateFileWriter(*RAWCSVFilePath);
	FString RAWCSVLine = (TEXT("Map Name, Changelist, Time Stamp, Map Load Time, Average FPS, Frame Time, Used Physical Memory, Used Virtual Memory, Used Peak Physical, Used Peak Virtual, Available Physical Memory, Available Virtual Memory\n"));
	RAWCSVArchive->Serialize(TCHAR_TO_ANSI(*RAWCSVLine), RAWCSVLine.Len());

	//Dump the stats from each run to the raw csv file and then close it.
	for (int32 i = 0; i < EditorPerfStats.TimeStamp.Num(); i++)
	{
		//If the raw file isn't available to write to then we'll fail back this test.
		if ( FAutomationEditorCommonUtils::IsArchiveWriteable(RAWCSVFilePath, RAWCSVArchive))
		{
			RAWCSVLine = FString::Printf(TEXT("%s,%s,%s,%.3f,%.1f,%.1f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f%s"), *EditorPerfStats.MapName, *FEngineVersion::Current().ToString(EVersionComponent::Changelist), *EditorPerfStats.FormattedTimeStamp[i], EditorPerfStats.MapLoadTime, EditorPerfStats.AverageFPS[i], EditorPerfStats.AverageFrameTime[i], EditorPerfStats.UsedPhysical[i], EditorPerfStats.UsedVirtual[i], EditorPerfStats.PeakUsedPhysical[i], EditorPerfStats.PeakUsedVirtual[i], EditorPerfStats.AvailablePhysical[i], EditorPerfStats.AvailableVirtual[i], LINE_TERMINATOR);
			RAWCSVArchive->Serialize(TCHAR_TO_ANSI(*RAWCSVLine), RAWCSVLine.Len());
		}
	}
	RAWCSVArchive->Close();

	//Get the final pretty data for the Performance csv file.
	float AverageFPS = FAutomationEditorCommonUtils::TotalFromFloatArray(EditorPerfStats.AverageFPS, true);
	float AverageFrameTime = FAutomationEditorCommonUtils::TotalFromFloatArray(EditorPerfStats.AverageFrameTime, true);
	float MemoryUsedPhysical = FAutomationEditorCommonUtils::TotalFromFloatArray(EditorPerfStats.UsedPhysical, true);
	float MemoryAvailPhysAvg = FAutomationEditorCommonUtils::TotalFromFloatArray(EditorPerfStats.AvailablePhysical, true);
	float MemoryAvailVirtualAvg = FAutomationEditorCommonUtils::TotalFromFloatArray(EditorPerfStats.AvailableVirtual, true);
	float MemoryUsedVirtualAvg = FAutomationEditorCommonUtils::TotalFromFloatArray(EditorPerfStats.UsedVirtual, true);
	float MemoryUsedPeak = FAutomationEditorCommonUtils::LargestValueInFloatArray(EditorPerfStats.PeakUsedPhysical);
	float MemoryUsedPeakVirtual = FAutomationEditorCommonUtils::LargestValueInFloatArray(EditorPerfStats.PeakUsedVirtual);

	//TestRunDuration is the length of time the test lasted in ticks.
	FTimespan TestRunDuration = (EditorPerfStats.TimeStamp.Last().GetTicks() - EditorPerfStats.TimeStamp[0].GetTicks()) + ETimespan::TicksPerSecond;

	//The performance csv file will be created if it didn't exist prior to the start of this test.
	if (!FPaths::FileExists(*PerfCSVFilePath))
	{
		FArchive* FinalCSVArchive = IFileManager::Get().CreateFileWriter(*PerfCSVFilePath);
		if ( FAutomationEditorCommonUtils::IsArchiveWriteable(PerfCSVFilePath, FinalCSVArchive))
		{
			FString FinalCSVLine = (TEXT("Date, Map Name, Changelist, Test Run Time , Map Load Time, Average FPS, Average MS, Used Physical KB, Used Virtual KB, Used Peak Physcial KB, Used Peak Virtual KB, Available Physical KB, Available Virtual KB\n"));
			FinalCSVArchive->Serialize(TCHAR_TO_ANSI(*FinalCSVLine), FinalCSVLine.Len());
			FinalCSVArchive->Close();
		}
	}

	//Load the existing performance csv so that it doesn't get saved over and lost.
	FString OldPerformanceCSVFile;
	FFileHelper::LoadFileToString(OldPerformanceCSVFile, *PerfCSVFilePath);
	FArchive* FinalCSVArchive = IFileManager::Get().CreateFileWriter(*PerfCSVFilePath);
	if ( FAutomationEditorCommonUtils::IsArchiveWriteable(PerfCSVFilePath, FinalCSVArchive))
	{
		//Dump the old performance csv file data to the new csv file.
		FinalCSVArchive->Serialize(TCHAR_TO_ANSI(*OldPerformanceCSVFile), OldPerformanceCSVFile.Len());

		//Dump the pretty stats to the Performance CSV file and then close it so we can edit it while the engine is still running.
		FString FinalCSVLine = FString::Printf(TEXT("%s,%s,%s,%.0f,%.3f,%.1f,%.1f,%.0f,%.0f,%.0f,%.0f,%.0f,%.0f%s"), *FDateTime::Now().ToString(), *EditorPerfStats.MapName, *FEngineVersion::Current().ToString(EVersionComponent::Changelist), TestRunDuration.GetTotalSeconds(), EditorPerfStats.MapLoadTime, AverageFPS, AverageFrameTime, MemoryUsedPhysical, MemoryUsedVirtualAvg, MemoryUsedPeak, MemoryUsedPeakVirtual, MemoryAvailPhysAvg, MemoryAvailVirtualAvg, LINE_TERMINATOR);
		FinalCSVArchive->Serialize(TCHAR_TO_ANSI(*FinalCSVLine), FinalCSVLine.Len());
		FinalCSVArchive->Close();
	}

	//Display the test results to the user.
	UE_LOG(LogEditorAutomationTests, Display, TEXT("AVG FPS: '%.1f'"), AverageFPS);
	UE_LOG(LogEditorAutomationTests, Display, TEXT("AVG Frame Time: '%.1f' ms"), AverageFrameTime);
	UE_LOG(LogEditorAutomationTests, Display, TEXT("AVG Used Physical Memory: '%.0f' kb"), MemoryUsedPhysical);
	UE_LOG(LogEditorAutomationTests, Display, TEXT("AVG Used Virtual Memory: '%.0f' kb"), MemoryUsedVirtualAvg);
	UE_LOG(LogEditorAutomationTests, Display, TEXT("Performance csv file is located here: %s"), *FPaths::ConvertRelativePathToFull(PerfCSVFilePath));
	UE_LOG(LogEditorAutomationTests, Log, TEXT("Performance csv file is located here: %s"), *FPaths::ConvertRelativePathToFull(PerfCSVFilePath));
	UE_LOG(LogEditorAutomationTests, Log, TEXT("Raw performance csv file is located here: %s"), *FPaths::ConvertRelativePathToFull(RAWCSVFilePath));
}
コード例 #22
0
void FilterLinearKeysTemplate(
	TArray<T>& Keys,
	TArray<float>& Times,
	TArray<FTransform>& BoneAtoms,
	const TArray<float>* ParentTimes,
	const TArray<FTransform>& RawWorldBones,
	const TArray<FTransform>& NewWorldBones,
	const TArray<int32>& TargetBoneIndices,
	int32 NumFrames,
	int32 BoneIndex,
	int32 ParentBoneIndex,
	float ParentScale,
	float MaxDelta,
	float MaxTargetDelta,
	float EffectorDiffSocket,
	const TArray<FBoneData>& BoneData
	)
{
	const int32 KeyCount = Keys.Num();
	check( Keys.Num() == Times.Num() );
	check( KeyCount >= 1 );
	
	// generate new arrays we will fill with the final keys
	TArray<T> NewKeys;
	TArray<float> NewTimes;
	NewKeys.Empty(KeyCount);
	NewTimes.Empty(KeyCount);

	// Only bother doing anything if we have some keys!
	if(KeyCount > 0)
	{
		int32 LowKey = 0;
		int32 HighKey = KeyCount-1;
		int32 PrevKey = 0;
		
		// copy the low key (this one is a given)
		NewTimes.Add(Times[0]);
		NewKeys.Add(Keys[0]);

		FTransform DummyBone(FQuat::Identity, FVector(END_EFFECTOR_SOCKET_DUMMY_BONE_SIZE, END_EFFECTOR_SOCKET_DUMMY_BONE_SIZE, END_EFFECTOR_SOCKET_DUMMY_BONE_SIZE));

		float const DeltaThreshold = (BoneData[BoneIndex].IsEndEffector() && (BoneData[BoneIndex].bHasSocket || BoneData[BoneIndex].bKeyEndEffector)) ? EffectorDiffSocket : MaxTargetDelta;

		// We will test within a sliding window between LowKey and HighKey.
		// Therefore, we are done when the LowKey exceeds the range
		while (LowKey < KeyCount-1)
		{
			// high key always starts at the top of the range
			HighKey = KeyCount-1;

			// keep testing until the window is closed
			while (HighKey > LowKey+1)
			{
				// get the parameters of the window we are testing
				const float LowTime = Times[LowKey];
				const float HighTime = Times[HighKey];
				const T LowValue = Keys[LowKey];
				const T HighValue = Keys[HighKey];
				const float Range = HighTime - LowTime;
				const float InvRange = 1.0f/Range;

				// iterate through all interpolated members of the window to
				// compute the error when compared to the original raw values
				float MaxLerpError = 0.0f;
				float MaxTargetError = 0.0f;
				for (int32 TestKey = LowKey+1; TestKey< HighKey; ++TestKey)
				{
					// get the parameters of the member being tested
					float TestTime = Times[TestKey];
					T TestValue = Keys[TestKey];

					// compute the proposed, interpolated value for the key
					const float Alpha = (TestTime - LowTime) * InvRange;
					const T LerpValue = Interpolate(LowValue, HighValue, Alpha);

					// compute the error between our interpolated value and the desired value
					float LerpError = CalcDelta(TestValue, LerpValue);

					// if the local-space lerp error is within our tolerances, we will also check the
					// effect this interpolated key will have on our target end effectors
					float TargetError = -1.0f;
					if (LerpError <= MaxDelta)
					{
						// get the raw world transform for this bone (the original world-space position)
						const int32 FrameIndex = TestKey;
						const FTransform& RawBase = RawWorldBones[(BoneIndex*NumFrames) + FrameIndex];
						
						// generate the proposed local bone atom and transform (local space)
						FTransform ProposedTM = UpdateBoneAtom(BoneIndex, BoneAtoms[FrameIndex], LerpValue);

						// convert the proposed local transform to world space using this bone's parent transform
						const FTransform& CurrentParent = ParentBoneIndex != INDEX_NONE ? NewWorldBones[(ParentBoneIndex*NumFrames) + FrameIndex] : FTransform::Identity;
						FTransform ProposedBase = ProposedTM * CurrentParent;
						
						// for each target end effector, compute the error we would introduce with our proposed key
						for (int32 TargetIndex=0; TargetIndex<TargetBoneIndices.Num(); ++TargetIndex)
						{
							// find the offset transform from the raw base to the end effector
							const int32 TargetBoneIndex = TargetBoneIndices[TargetIndex];
							FTransform RawTarget = RawWorldBones[(TargetBoneIndex*NumFrames) + FrameIndex];
							const FTransform& RelTM = RawTarget.GetRelativeTransform(RawBase); 

							// forecast where the new end effector would be using our proposed key
							FTransform ProposedTarget = RelTM * ProposedBase;

							// If this is an EndEffector with a Socket attached to it, add an extra bone, to measure error introduced by effector rotation compression.
							if( BoneData[TargetIndex].bHasSocket || BoneData[TargetIndex].bKeyEndEffector )
							{
								ProposedTarget = DummyBone * ProposedTarget;
								RawTarget = DummyBone * RawTarget;
							}

							// determine the extend of error at the target end effector
							float ThisError = (ProposedTarget.GetTranslation() - RawTarget.GetTranslation()).Size();
							TargetError = FMath::Max(TargetError, ThisError); 

							// exit early when we encounter a large delta
							float const TargetDeltaThreshold = BoneData[TargetIndex].bHasSocket ? EffectorDiffSocket : DeltaThreshold;
							if( TargetError > TargetDeltaThreshold )
							{ 
								break;
							}
						}
					}

					// If the parent has a key at this time, we'll scale our error values as requested.
					// This increases the odds that we will choose keys on the same frames as our parent bone,
					// making the skeleton more uniform in key distribution.
					if (ParentTimes)
					{
						if (ParentTimes->Find(TestTime) != INDEX_NONE)
						{
							// our parent has a key at this time, 
							// inflate our perceived error to increase our sensitivity
							// for also retaining a key at this time
							LerpError *= ParentScale;
							TargetError *= ParentScale;
						}
					}
					
					// keep track of the worst errors encountered for both 
					// the local-space 'lerp' error and the end effector drift we will cause
					MaxLerpError = FMath::Max(MaxLerpError, LerpError);
					MaxTargetError = FMath::Max(MaxTargetError, TargetError);

					// exit early if we have failed in this span
					if (MaxLerpError > MaxDelta ||
						MaxTargetError > DeltaThreshold)
					{
						break;
					}
				}

				// determine if the span succeeded. That is, the worst errors found are within tolerances
				if (MaxLerpError <= MaxDelta &&
					MaxTargetError <= DeltaThreshold)
				{
					// save the high end of the test span as our next key
					NewTimes.Add(Times[HighKey]);
					NewKeys.Add(Keys[HighKey]);

					// start testing a new span
					LowKey = HighKey;
					HighKey =  KeyCount-1;
				}
				else
				{
					// we failed, shrink the test span window and repeat
					--HighKey;
				}
			}

			// if the test window is still valid, accept the high key
			if (HighKey > LowKey)
			{
				NewTimes.Add(Times[HighKey]);
				NewKeys.Add(Keys[HighKey]);
			}
			LowKey= HighKey;
		}

		// The process has ended, but we must make sure the last key is accounted for
		if (NewTimes.Last() != Times.Last() &&
			CalcDelta(Keys.Last(), NewKeys.Last()) >= MaxDelta )
		{
			NewTimes.Add(Times.Last());
			NewKeys.Add(Keys.Last());
		}

		// return the new key set to the caller
		Times= NewTimes;
		Keys= NewKeys;
	}
}
コード例 #23
0
bool UBTCompositeNode::DoDecoratorsAllowExecution(class UBehaviorTreeComponent* OwnerComp, int32 InstanceIdx, int32 ChildIdx) const
{
	const FBTCompositeChild& ChildInfo = Children[ChildIdx];
	bool bResult = true;

	if (ChildInfo.Decorators.Num() == 0)
	{
		return bResult;
	}

	FBehaviorTreeInstance& MyInstance = OwnerComp->InstanceStack[InstanceIdx];

	if (ChildInfo.DecoratorOps.Num() == 0)
	{
		// simple check: all decorators must agree
		for (int32 i = 0; i < ChildInfo.Decorators.Num(); i++)
		{
			const UBTDecorator* TestDecorator = ChildInfo.Decorators[i];
			const bool bIsAllowed = TestDecorator->CanExecute(OwnerComp, TestDecorator->GetNodeMemory<uint8>(MyInstance));
			OwnerComp->StoreDebuggerSearchStep(TestDecorator, InstanceIdx, bIsAllowed);

			if (!bIsAllowed)
			{
				UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("Child[%d] execution forbidden by %s"),
					ChildIdx, *UBehaviorTreeTypes::DescribeNodeHelper(TestDecorator));

				bResult = false;
				break;
			}
		}
	}
	else
	{
		// advanced check: follow decorator logic operations (composite decorator on child link)
		UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("Child[%d] execution test with logic operations"), ChildIdx);

		TArray<FOperationStackInfo> OperationStack;
		FString Indent;

		// debugger data collection:
		// - get index of each decorator from main AND test, they will match graph nodes
		// - if first operator is not AND it means, that there's only single composite decorator on line
		// - while updating top level stack, grab index of first failed node

		int32 NodeDecoratorIdx = INDEX_NONE;
		int32 FailedDecoratorIdx = INDEX_NONE;
		bool bShouldStoreNodeIndex = true;

		for (int32 i = 0; i < ChildInfo.DecoratorOps.Num(); i++)
		{
			const FBTDecoratorLogic& DecoratorOp = ChildInfo.DecoratorOps[i];
			if (IsLogicOp(DecoratorOp))
			{
				OperationStack.Add(FOperationStackInfo(DecoratorOp));
				Indent += TEXT("  ");
				UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("%spushed %s:%d"), *Indent,
					*DescribeLogicOp(DecoratorOp.Operation), DecoratorOp.Number);
			}
			else if (DecoratorOp.Operation == EBTDecoratorLogic::Test)
			{
				const bool bHasOverride = OperationStack.Num() ? OperationStack.Last().bHasForcedResult : false;
				const bool bCurrentOverride = OperationStack.Num() ? OperationStack.Last().bForcedResult : false;

				// debugger: store first decorator of graph node
				if (bShouldStoreNodeIndex)
				{
					bShouldStoreNodeIndex = false;
					NodeDecoratorIdx = DecoratorOp.Number;
				}

				UBTDecorator* TestDecorator = ChildInfo.Decorators[DecoratorOp.Number];
				const bool bIsAllowed = bHasOverride ? bCurrentOverride : TestDecorator->CanExecute(OwnerComp, TestDecorator->GetNodeMemory<uint8>(MyInstance));
				UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("%s%s %s: %s"), *Indent,
					bHasOverride ? TEXT("skipping") : TEXT("testing"),
					*UBehaviorTreeTypes::DescribeNodeHelper(TestDecorator),
					bIsAllowed ? TEXT("allowed") : TEXT("forbidden"));

				bResult = UpdateOperationStack(OwnerComp, Indent, OperationStack, bIsAllowed, FailedDecoratorIdx, NodeDecoratorIdx, bShouldStoreNodeIndex);
				if (OperationStack.Num() == 0)
				{
					UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("finished execution test: %s"),
						bResult ? TEXT("allowed") : TEXT("forbidden"));

					OwnerComp->StoreDebuggerSearchStep(ChildInfo.Decorators[FMath::Max(0, FailedDecoratorIdx)], InstanceIdx, bResult);
					break;
				}
			}
		}
	}

	return bResult;
}
コード例 #24
0
static bool UpdateOperationStack(const class UBehaviorTreeComponent* OwnerComp, FString& Indent,
								 TArray<FOperationStackInfo>& Stack, bool bTestResult,
								 int32& FailedDecoratorIdx, int32& NodeDecoratorIdx, bool& bShouldStoreNodeIndex)
{
	if (Stack.Num() == 0)
	{
		return bTestResult;
	}

	FOperationStackInfo& CurrentOp = Stack.Last();
	CurrentOp.NumLeft--;

	if (CurrentOp.Op == EBTDecoratorLogic::And)
	{
		if (!CurrentOp.bHasForcedResult && !bTestResult)
		{
			CurrentOp.bHasForcedResult = true;
			CurrentOp.bForcedResult = bTestResult;
		}
	}
	else if (CurrentOp.Op == EBTDecoratorLogic::Or)
	{
		if (!CurrentOp.bHasForcedResult && bTestResult)
		{
			CurrentOp.bHasForcedResult = true;
			CurrentOp.bForcedResult = bTestResult;
		}	
	}
	else if (CurrentOp.Op == EBTDecoratorLogic::Not)
	{
		bTestResult = !bTestResult;
	}

	// update debugger while processing top level stack
	if (Stack.Num() == 1)
	{
		// reset node flag and grab next decorator index
		bShouldStoreNodeIndex = true;

		// store first failed node
		if (!bTestResult && FailedDecoratorIdx == INDEX_NONE)
		{
			FailedDecoratorIdx = NodeDecoratorIdx;
		}
	}

	if (CurrentOp.bHasForcedResult)
	{
		bTestResult = CurrentOp.bForcedResult;
	}

	if (CurrentOp.NumLeft == 0)
	{
		UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("%s%s finished: %s"), *Indent,
			*DescribeLogicOp(CurrentOp.Op),
			bTestResult ? TEXT("allowed") : TEXT("forbidden"));
		Indent = Indent.LeftChop(2);

		Stack.RemoveAt(Stack.Num() - 1);
		return UpdateOperationStack(OwnerComp, Indent, Stack, bTestResult, FailedDecoratorIdx, NodeDecoratorIdx, bShouldStoreNodeIndex);
	}

	return bTestResult;
}
コード例 #25
0
// Reads a set of specifiers (with optional values) inside the () of a new-style metadata macro like UPROPERTY or UFUNCTION
void FBaseParser::ReadSpecifierSetInsideMacro(TArray<FPropertySpecifier>& SpecifiersFound, const FString& TypeOfSpecifier, TMap<FName, FString>& MetaData)
{
	int32 FoundSpecifierCount = 0;
	FString ErrorMessage = FString::Printf(TEXT("%s declaration specifier"), *TypeOfSpecifier);

	RequireSymbol(TEXT("("), *ErrorMessage);

	while (!MatchSymbol(TEXT(")")))
	{
		if (FoundSpecifierCount > 0)
		{
			RequireSymbol(TEXT(","), *ErrorMessage);
		}
		++FoundSpecifierCount;

		// Read the specifier key
		FToken Specifier;
		if (!GetToken(Specifier))
		{
			FError::Throwf(TEXT("Expected %s"), *ErrorMessage);
		}

		if (Specifier.Matches(TEXT("meta")))
		{
			RequireSymbol(TEXT("="), *ErrorMessage);
			RequireSymbol(TEXT("("), *ErrorMessage);

			// Keep reading comma-separated metadata pairs
			do 
			{
				// Read a key
				FToken MetaKeyToken;
				if (!GetIdentifier(MetaKeyToken))
				{
					FError::Throwf(TEXT("Expected a metadata key"));
				}

				FString Key = MetaKeyToken.Identifier;

				// Potentially read a value
				FString Value;
				if (MatchSymbol(TEXT("=")))
				{
					Value = ReadNewStyleValue(TypeOfSpecifier);
				}

				// Validate the value is a valid type for the key and insert it into the map
				InsertMetaDataPair(MetaData, Key, Value);
			} while ( MatchSymbol(TEXT(",")) );

			RequireSymbol(TEXT(")"), *ErrorMessage);
		}
		// Look up specifier in metadata dictionary
		else if (FMetadataKeyword* MetadataKeyword = GetMetadataKeyword(Specifier.Identifier))
		{
			if (MatchSymbol(TEXT("=")))
			{
				if (MetadataKeyword->ValueArgument == EMetadataValueArgument::None)
				{
					FError::Throwf(TEXT("Incorrect = after metadata specifier '%s'"), Specifier.Identifier);
				}

				FString Value = ReadNewStyleValue(TypeOfSpecifier);
				MetadataKeyword->ApplyToMetadata(MetaData, &Value);
			}
			else
			{
				if (MetadataKeyword->ValueArgument == EMetadataValueArgument::Required)
				{
					FError::Throwf(TEXT("Missing = after metadata specifier '%s'"), Specifier.Identifier);
				}

				MetadataKeyword->ApplyToMetadata(MetaData);
			}
		}
		else
		{
			// Creating a new specifier
			SpecifiersFound.Emplace(Specifier.Identifier);

			// Look for a value for this specifier
			if (MatchSymbol(TEXT("=")) || PeekSymbol(TEXT("(")))
			{
				TArray<FString>& NewPairValues = SpecifiersFound.Last().Values;
				if (!ReadOptionalCommaSeparatedListInParens(NewPairValues, TypeOfSpecifier))
				{
					FString Value = ReadNewStyleValue(TypeOfSpecifier);
					NewPairValues.Add(Value);
				}
			}
		}
	}
}
コード例 #26
0
void FRCPassPostProcessVisualizeBuffer::Process(FRenderingCompositePassContext& Context)
{
	SCOPED_DRAW_EVENT(VisualizeBuffer, DEC_SCENE_ITEMS);
	const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0);

	if(!InputDesc)
	{
		// input is not hooked up correctly
		return;
	}

	const FSceneView& View = Context.View;
	const FSceneViewFamily& ViewFamily = *(View.Family);
	
	FIntRect SrcRect = View.ViewRect;
	FIntRect DestRect = View.ViewRect;
	FIntPoint SrcSize = InputDesc->Extent;

	const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context);

	// Set the view family's render target/viewport.
	RHISetRenderTarget(DestRenderTarget.TargetableTexture, FTextureRHIRef());	
	Context.SetViewportAndCallRHI(DestRect);

	// set the state
	RHISetBlendState(TStaticBlendState<>::GetRHI());
	RHISetRasterizerState(TStaticRasterizerState<>::GetRHI());
	RHISetDepthStencilState(TStaticDepthStencilState<false,CF_Always>::GetRHI());

	SetShaderTempl<false>(Context);

	// Draw a quad mapping scene color to the view's render target
	DrawRectangle(
		0, 0,
		DestRect.Width(), DestRect.Height(),
		SrcRect.Min.X, SrcRect.Min.Y,
		SrcRect.Width(), SrcRect.Height(),
		DestRect.Size(),
		SrcSize,
		EDRF_UseTriangleOptimization);

	// Now draw the requested tiles into the grid
	TShaderMapRef<FPostProcessVS> VertexShader(GetGlobalShaderMap());
	TShaderMapRef<FPostProcessVisualizeBufferPS<true> > PixelShader(GetGlobalShaderMap());

	RHISetBlendState(TStaticBlendState<CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha>::GetRHI());
	static FGlobalBoundShaderState BoundShaderState;

	SetGlobalBoundShaderState(BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);

	PixelShader->SetPS(Context);

	// Track the name and position of each tile we draw so we can write text labels over them
	struct LabelRecord
	{
		FString Label;
		int32 LocationX;
		int32 LocationY;
	};

	TArray<LabelRecord> Labels;

	const int32 MaxTilesX = 4;
	const int32 MaxTilesY = 4;
	const int32 TileWidth = DestRect.Width() / MaxTilesX;
	const int32 TileHeight = DestRect.Height() / MaxTilesY;
	int32 CurrentTileIndex = 0; 

	for (TArray<TileData>::TConstIterator It = Tiles.CreateConstIterator(); It; ++It, ++CurrentTileIndex)
	{
		FRenderingCompositeOutputRef Tile = It->Source;

		if (Tile.IsValid())
		{
			FTextureRHIRef Texture = Tile.GetOutput()->PooledRenderTarget->GetRenderTargetItem().TargetableTexture;

			int32 TileX = CurrentTileIndex % MaxTilesX;
			int32 TileY = CurrentTileIndex / MaxTilesX;

			PixelShader->SetSourceTexture(Texture);

			DrawRectangle(
				TileX * TileWidth, TileY * TileHeight,
				TileWidth, TileHeight,
				SrcRect.Min.X, SrcRect.Min.Y,
				SrcRect.Width(), SrcRect.Height(),
				DestRect.Size(),
				SrcSize,
				EDRF_Default);

			Labels.Add(LabelRecord());
			Labels.Last().Label = It->Name;
			Labels.Last().LocationX = 8 + TileX * TileWidth;
			Labels.Last().LocationY = (TileY + 1) * TileHeight - 19;
		}
	}

	// Draw tile labels

	// this is a helper class for FCanvas to be able to get screen size
	class FRenderTargetTemp : public FRenderTarget
	{
	public:
		const FSceneView& View;
		const FTexture2DRHIRef Texture;

		FRenderTargetTemp(const FSceneView& InView, const FTexture2DRHIRef InTexture)
			: View(InView), Texture(InTexture)
		{
		}
		virtual FIntPoint GetSizeXY() const
		{
			return View.ViewRect.Size();
		};
		virtual const FTexture2DRHIRef& GetRenderTargetTexture() const
		{
			return Texture;
		}
	} TempRenderTarget(View, (const FTexture2DRHIRef&)DestRenderTarget.TargetableTexture);

	FCanvas Canvas(&TempRenderTarget, NULL, ViewFamily.CurrentRealTime, ViewFamily.CurrentWorldTime, ViewFamily.DeltaWorldTime);
	FLinearColor LabelColor(1, 1, 0);
	for (auto It = Labels.CreateConstIterator(); It; ++It)
	{
		Canvas.DrawShadowedString(It->LocationX, It->LocationY, *It->Label, GetStatsFont(), LabelColor);
	}
	Canvas.Flush();


	RHICopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams());
}
static void ParseUpdateStatusResults(const FP4RecordSet& InRecords, const TArray<FText>& ErrorMessages, TArray<FPerforceSourceControlState>& OutStates)
{
	// Iterate over each record found as a result of the command, parsing it for relevant information
	for (int32 Index = 0; Index < InRecords.Num(); ++Index)
	{
		const FP4Record& ClientRecord = InRecords[Index];
		FString FileName = ClientRecord(TEXT("clientFile"));
		FString DepotFileName = ClientRecord(TEXT("depotFile"));
		FString HeadRev  = ClientRecord(TEXT("headRev"));
		FString HaveRev  = ClientRecord(TEXT("haveRev"));
		FString OtherOpen = ClientRecord(TEXT("otherOpen"));
		FString OpenType = ClientRecord(TEXT("type"));
		FString HeadAction = ClientRecord(TEXT("headAction"));
		FString Action = ClientRecord(TEXT("action"));
		FString HeadType = ClientRecord(TEXT("headType"));
		const bool bUnresolved = ClientRecord.Contains(TEXT("unresolved"));

		FString FullPath(FileName);
		FPaths::NormalizeFilename(FullPath);
		OutStates.Add(FPerforceSourceControlState(FullPath));
		FPerforceSourceControlState& State = OutStates.Last();
		State.DepotFilename = DepotFileName;

		State.State = EPerforceState::ReadOnly;
		if (Action.Len() > 0 && Action == TEXT("add")) 
		{
			State.State = EPerforceState::OpenForAdd;
		}
		else if (Action.Len() > 0 && Action == TEXT("delete")) 
		{
			State.State = EPerforceState::MarkedForDelete;
		}
		else if (OpenType.Len() > 0)
		{
			if(Action.Len() > 0 && Action == TEXT("branch")) 
			{
				State.State = EPerforceState::Branched;
			}
			else
			{
				State.State = EPerforceState::CheckedOut;
			}
		}
		else if (OtherOpen.Len() > 0)
		{
			// OtherOpen just reports the number of developers that have a file open, now add a string for every entry
			int32 OtherOpenNum = FCString::Atoi(*OtherOpen);
			for ( int32 OpenIdx = 0; OpenIdx < OtherOpenNum; ++OpenIdx )
			{
				const FString OtherOpenRecordKey = FString::Printf(TEXT("otherOpen%d"), OpenIdx);
				const FString OtherOpenRecordValue = ClientRecord(OtherOpenRecordKey);

				State.OtherUserCheckedOut += OtherOpenRecordValue;
				if(OpenIdx < OtherOpenNum - 1)
				{
					State.OtherUserCheckedOut += TEXT(", ");
				}
			}

			State.State = EPerforceState::CheckedOutOther;
		}
		//file has been previously deleted, ok to add again
		else if (HeadAction.Len() > 0 && HeadAction == TEXT("delete")) 
		{
			State.State = EPerforceState::NotInDepot;
		}
		
		if (HeadRev.Len() > 0 && HaveRev.Len() > 0)
		{
			TTypeFromString<int>::FromString(State.DepotRevNumber, *HeadRev);
			TTypeFromString<int>::FromString(State.LocalRevNumber, *HaveRev);
			if( bUnresolved )
			{
				int32 ResolveActionNumber = 0;
				for (;;)
				{
					// Extract the revision number
					FString VarName = FString::Printf(TEXT("resolveAction%d"), ResolveActionNumber);
					if (!ClientRecord.Contains(*VarName))
					{
						// No more revisions
						ensureMsgf( ResolveActionNumber > 0, TEXT("Resolve is pending but no resolve actions for file %s"), *FileName );
						break;
					}

					VarName = FString::Printf(TEXT("resolveBaseFile%d"), ResolveActionNumber);
					FString ResolveBaseFile = ClientRecord(VarName);
					VarName = FString::Printf(TEXT("resolveFromFile%d"), ResolveActionNumber);
					FString ResolveFromFile = ClientRecord(VarName);
					if(!ensureMsgf( ResolveFromFile == ResolveBaseFile, TEXT("Text cannot resolve %s with %s, we do not support cross file merging"), *ResolveBaseFile, *ResolveFromFile ) )
					{
						break;
					}

					VarName = FString::Printf(TEXT("resolveBaseRev%d"), ResolveActionNumber);
					FString ResolveBaseRev = ClientRecord(VarName);

					TTypeFromString<int>::FromString(State.PendingResolveRevNumber, *ResolveBaseRev);
					
					++ResolveActionNumber;
				}
			}
		}

		// Check binary status
		State.bBinary = false;
		if (HeadType.Len() > 0 && HeadType.Contains(TEXT("binary")))
		{
			State.bBinary = true;
		}

		// Check exclusive checkout flag
		State.bExclusiveCheckout = false;
		if (HeadType.Len() > 0 && HeadType.Contains(TEXT("+l")))
		{
			State.bExclusiveCheckout = true;
		}
	}

	// also see if we can glean anything from the error messages
	for (int32 Index = 0; Index < ErrorMessages.Num(); ++Index)
	{
		const FText& Error = ErrorMessages[Index];

		//@todo P4 could be returning localized error messages
		int32 NoSuchFilePos = Error.ToString().Find(TEXT(" - no such file(s).\n"), ESearchCase::IgnoreCase, ESearchDir::FromStart);
		if(NoSuchFilePos != INDEX_NONE)
		{
			// found an error about a file that is not in the depot
			FString FullPath(Error.ToString().Left(NoSuchFilePos));
			FPaths::NormalizeFilename(FullPath);
			OutStates.Add(FPerforceSourceControlState(FullPath));
			FPerforceSourceControlState& State = OutStates.Last();
			State.State = EPerforceState::NotInDepot;
		}

		//@todo P4 could be returning localized error messages
		int32 NotUnderClientRootPos = Error.ToString().Find(TEXT("' is not under client's root"), ESearchCase::IgnoreCase, ESearchDir::FromStart);
		if(NotUnderClientRootPos != INDEX_NONE)
		{
			// found an error about a file that is not under the client root
			static const FString Prefix(TEXT("Path \'"));
			FString FullPath(Error.ToString().Mid(Prefix.Len(), NotUnderClientRootPos - Prefix.Len()));
			FPaths::NormalizeFilename(FullPath);
			OutStates.Add(FPerforceSourceControlState(FullPath));
			FPerforceSourceControlState& State = OutStates.Last();
			State.State = EPerforceState::NotUnderClientRoot;	
		}
	}
}
コード例 #28
0
	TOptional<FExpressionError> CompileGroup(const FExpressionToken* GroupStart, const FGuid* StopAt)
	{
		enum class EState { PreUnary, PostUnary, Binary };

		TArray<FWrappedOperator> OperatorStack;
		OperatorStack.Reserve(Tokens.Num() - CurrentTokenIndex);

		bool bFoundEndOfGroup = StopAt == nullptr;

		// Start off looking for a unary operator
		EState State = EState::PreUnary;
		for (; CurrentTokenIndex < Tokens.Num(); ++CurrentTokenIndex)
		{
			auto& Token = Tokens[CurrentTokenIndex];
			const auto& TypeId = Token.Node.GetTypeId();

			if (const FGuid* GroupingEnd = Grammar.GetGrouping(TypeId))
			{
				// Ignore this token
				CurrentTokenIndex++;

				// Start of group - recurse
				auto Error = CompileGroup(&Token, GroupingEnd);

				if (Error.IsSet())
				{
					return Error;
				}

				State = EState::PostUnary;
			}
			else if (StopAt && TypeId == *StopAt)
			{
				// End of group
				bFoundEndOfGroup = true;
				break;
			}
			else if (State == EState::PreUnary)
			{
				if (Grammar.HasPreUnaryOperator(TypeId))
				{
					// Make this a unary op
					OperatorStack.Emplace(FCompiledToken(FCompiledToken::PreUnaryOperator, MoveTemp(Token)));
				}
				else if (Grammar.GetBinaryOperatorPrecedence(TypeId))
				{
					return FExpressionError(FText::Format(LOCTEXT("SyntaxError_NoBinaryOperand", "Syntax error: No operand specified for operator '{0}'"), FText::FromString(Token.Context.GetString())));
				}
				else if (Grammar.HasPostUnaryOperator(TypeId))
				{
					// Found a post-unary operator for the preceeding token
					State = EState::PostUnary;

					// Pop off any pending unary operators
					while (OperatorStack.Num() > 0 && OperatorStack.Last().Precedence <= 0)
					{
						Commands.Add(OperatorStack.Pop(false).Steal());
					}

					// Make this a post-unary op
					OperatorStack.Emplace(FCompiledToken(FCompiledToken::PostUnaryOperator, MoveTemp(Token)));
				}
				else
				{
					// Not an operator, so treat it as an ordinary token
					Commands.Add(FCompiledToken(FCompiledToken::Operand, MoveTemp(Token)));
					State = EState::PostUnary;
				}
			}
			else if (State == EState::PostUnary)
			{
				if (Grammar.HasPostUnaryOperator(TypeId))
				{
					// Pop off any pending unary operators
					while (OperatorStack.Num() > 0 && OperatorStack.Last().Precedence <= 0)
					{
						Commands.Add(OperatorStack.Pop(false).Steal());
					}

					// Make this a post-unary op
					OperatorStack.Emplace(FCompiledToken(FCompiledToken::PostUnaryOperator, MoveTemp(Token)));
				}
				else
				{
					// Checking for binary operators
					if (const int32* Prec = Grammar.GetBinaryOperatorPrecedence(TypeId))
					{
						// Pop off anything of higher precedence than this one onto the command stack
						while (OperatorStack.Num() > 0 && OperatorStack.Last().Precedence < *Prec)
						{
							Commands.Add(OperatorStack.Pop(false).Steal());
						}

						// Add the operator itself to the op stack
						OperatorStack.Emplace(FCompiledToken(FCompiledToken::BinaryOperator, MoveTemp(Token)), *Prec);

						// Check for a unary op again
						State = EState::PreUnary;
					}
					else
					{
						// Just add the token. It's possible that this is a syntax error (there's no binary operator specified between two tokens),
						// But we don't have enough information at this point to say whether or not it is an error
						Commands.Add(FCompiledToken(FCompiledToken::Operand, MoveTemp(Token)));
						State = EState::PreUnary;
					}
				}
			}
		}

		if (!bFoundEndOfGroup)
		{
			return FExpressionError(FText::Format(LOCTEXT("SyntaxError_UnmatchedGroup", "Syntax error: Reached end of expression before matching end of group '{0}' at line {1}:{2}"),
				FText::FromString(GroupStart->Context.GetString()),
				FText::AsNumber(GroupStart->Context.GetLineNumber()),
				FText::AsNumber(GroupStart->Context.GetCharacterIndex())
			));
		}

		// Pop everything off the operator stack, onto the command stack
		while (OperatorStack.Num() > 0)
		{
			Commands.Add(OperatorStack.Pop(false).Token);
		}

		return TOptional<FExpressionError>();
	}
コード例 #29
0
bool GenerateAirMeshes(const TArray<FVector>& Vertices, const TArray<int32>& Indices, TArray<TStaticArray<int32, 4u>>& OutTetrahedra)
{
	check(Indices.Num() % 3 == 0);

#if WITH_EDITOR
	namespace tw = tetgen_wrapper;

	// ================================================================
	// Convert vertex positions to the format readable by tetgen
	// ================================================================

	TArray<double> VerticesForTetgen;

	// 8 points are for bounding box
	VerticesForTetgen.Empty((Vertices.Num() + 8) * 3);

	for (const auto& Vertex : Vertices)
	{
		VerticesForTetgen.Add(Vertex.X);
		VerticesForTetgen.Add(Vertex.Y);
		VerticesForTetgen.Add(Vertex.Z);
	}

	// Generate bounding 8 points

	FBox BoundingBox(Vertices);
	float Extension = BoundingBox.GetExtent().GetAbsMax() * 0.02f;
	BoundingBox.Min -= FVector(Extension);
	BoundingBox.Max += FVector(Extension);

	VerticesForTetgen.Add(BoundingBox.Min.X);
	VerticesForTetgen.Add(BoundingBox.Min.Y);
	VerticesForTetgen.Add(BoundingBox.Min.Z);

	VerticesForTetgen.Add(BoundingBox.Max.X);
	VerticesForTetgen.Add(BoundingBox.Min.Y);
	VerticesForTetgen.Add(BoundingBox.Min.Z);

	VerticesForTetgen.Add(BoundingBox.Min.X);
	VerticesForTetgen.Add(BoundingBox.Max.Y);
	VerticesForTetgen.Add(BoundingBox.Min.Z);

	VerticesForTetgen.Add(BoundingBox.Max.X);
	VerticesForTetgen.Add(BoundingBox.Max.Y);
	VerticesForTetgen.Add(BoundingBox.Min.Z);

	VerticesForTetgen.Add(BoundingBox.Min.X);
	VerticesForTetgen.Add(BoundingBox.Min.Y);
	VerticesForTetgen.Add(BoundingBox.Max.Z);

	VerticesForTetgen.Add(BoundingBox.Max.X);
	VerticesForTetgen.Add(BoundingBox.Min.Y);
	VerticesForTetgen.Add(BoundingBox.Max.Z);

	VerticesForTetgen.Add(BoundingBox.Min.X);
	VerticesForTetgen.Add(BoundingBox.Max.Y);
	VerticesForTetgen.Add(BoundingBox.Max.Z);

	VerticesForTetgen.Add(BoundingBox.Max.X);
	VerticesForTetgen.Add(BoundingBox.Max.Y);
	VerticesForTetgen.Add(BoundingBox.Max.Z);

	// ================================================================
	// Generate polygons for tetgen
	// ================================================================

	int32 NumTriangles = Indices.Num() / 3;

	TArray<tw::polygon> PolygonsForTetgen;
	PolygonsForTetgen.Empty(NumTriangles + 6); // 6 are for bounding box faces
	for (int32 TriangleIndex = 0; TriangleIndex < NumTriangles; TriangleIndex++)
	{
		PolygonsForTetgen.AddUninitialized();
		auto& Added = PolygonsForTetgen.Last();

		Added.num_vertices = 3;
		Added.vertex_list = const_cast<tw::int32*>(&Indices[TriangleIndex * 3]);
	}

	// Indices for bounding box
	int32 BoundingBoxIndices[] =
	{
		0, 1, 3, 2,
		1, 5, 7, 3,
		5, 4, 6, 7,
		4, 0, 2, 6,
		4, 5, 1, 0,
		2, 3, 7, 6,
	};
	check(ARRAYSIZE(BoundingBoxIndices) == 24);

	// add offset
	for (auto& BoundingBoxIndex : BoundingBoxIndices)
	{
		BoundingBoxIndex += Vertices.Num();
	}

	for (int32 FaceIndex = 0; FaceIndex < ARRAYSIZE(BoundingBoxIndices) / 4; FaceIndex++)
	{
		PolygonsForTetgen.AddUninitialized();
		auto& Added = PolygonsForTetgen.Last();

		Added.num_vertices = 4;
		Added.vertex_list = &BoundingBoxIndices[FaceIndex * 4];
	}

	// ================================================================
	// Generate facets for tetgen
	// ================================================================

	TArray<tw::facet> FacetsForTetgen;
	FacetsForTetgen.Empty(PolygonsForTetgen.Num());
	for (auto& Polygon : PolygonsForTetgen)
	{
		FacetsForTetgen.AddUninitialized();
		auto& Added = FacetsForTetgen.Last();

		Added.hole_list = nullptr;
		Added.num_holes = 0;
		Added.polygon_list = &Polygon;
		Added.num_polygons = 1;
	}

	// ================================================================
	// Build tetgen input
	// ================================================================

	tw::input_output InTetgen, OutTetgen;
	InTetgen.automatic_deallocation = false; // pointers are on stack or managed by TArray
	InTetgen.point_list = VerticesForTetgen.GetData();
	InTetgen.num_points = VerticesForTetgen.Num() / 3;
	InTetgen.facet_list = FacetsForTetgen.GetData();
	InTetgen.num_facets = FacetsForTetgen.Num();

	// ================================================================
	// Tetrahedralize
	// ================================================================

	if (0 != tw::tetrahedralize("", InTetgen, OutTetgen))
	{
		return false;
	}

	// ================================================================
	// Gather relevant tetrahedra
	// ================================================================

	int32 NumTetrahedra = 0;

	// Count tetrahedra
	for (tw::int32 TetIndex = 0; TetIndex < OutTetgen.num_tetrahedra; TetIndex++)
	{
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 0] >= Vertices.Num()) { continue; }
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 1] >= Vertices.Num()) { continue; }
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 2] >= Vertices.Num()) { continue; }
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 3] >= Vertices.Num()) { continue; }

		NumTetrahedra++;
	}

	// Gather tetrahedra
	OutTetrahedra.Empty(NumTetrahedra);
	for (tw::int32 TetIndex = 0; TetIndex < OutTetgen.num_tetrahedra; TetIndex++)
	{
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 0] >= Vertices.Num()) { continue; }
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 1] >= Vertices.Num()) { continue; }
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 2] >= Vertices.Num()) { continue; }
		if (OutTetgen.tetrahedron_list[TetIndex * 4 + 3] >= Vertices.Num()) { continue; }

		OutTetrahedra.AddUninitialized();
		auto& Added = OutTetrahedra.Last();
		FMemory::Memcpy(&Added[0], OutTetgen.tetrahedron_list + TetIndex * 4, sizeof(Added));
	}

	for (auto& Tet : OutTetrahedra)
	{
		const auto& P3 = Vertices[Tet[3]];
		const auto& P23 = Vertices[Tet[2]] - P3;
		const auto& P13 = Vertices[Tet[1]] - P3;
		const auto& P03 = Vertices[Tet[0]] - P3;

		float TetVolume = FVector::DotProduct(P03, FVector::CrossProduct(P13, P23));

		if (TetVolume < 0.0f)
		{
			Swap(Tet[2], Tet[3]);
		}
	}

	return true;
#else
	// On UE4Game, tetrahedra are deserialized
	UE_LOG(LogAirMeshCloth, Warning, TEXT("Tetrahedron generation is disabled on UE4Game."));
	return false;
#endif
}
コード例 #30
0
	void UnchunkSkeletalModel(TArray<FSkinnedMeshChunk*>& Chunks, TArray<int32>& PointToOriginalMap, const FSkinnedModelData& SrcModel)
	{
	#if WITH_EDITORONLY_DATA
		const TArray<FSoftSkinVertex>& SrcVertices = SrcModel.Vertices;
		const TArray<uint32>& SrcIndices = SrcModel.Indices;
		TArray<uint32> IndexMap;

		check(Chunks.Num() == 0);
		check(PointToOriginalMap.Num() == 0);

		IndexMap.Empty(SrcVertices.Num());
		IndexMap.AddUninitialized(SrcVertices.Num());
		for (int32 SectionIndex = 0; SectionIndex < SrcModel.Sections.Num(); ++SectionIndex)
		{
			const FSkelMeshSection& Section = SrcModel.Sections[SectionIndex];
			const TArray<FBoneIndexType>& BoneMap = SrcModel.BoneMaps[SectionIndex];
			FSkinnedMeshChunk* DestChunk = Chunks.Num() ? Chunks.Last() : NULL;

			if (DestChunk == NULL || DestChunk->MaterialIndex != Section.MaterialIndex)
			{
				DestChunk = new FSkinnedMeshChunk();
				Chunks.Add(DestChunk);
				DestChunk->MaterialIndex = Section.MaterialIndex;
				DestChunk->OriginalSectionIndex = SectionIndex;

				// When starting a new chunk reset the index map.
				FMemory::Memset(IndexMap.GetData(),0xff,IndexMap.Num()*IndexMap.GetTypeSize());
			}

			int32 NumIndicesThisSection = Section.NumTriangles * 3;
			for (uint32 SrcIndex = Section.BaseIndex; SrcIndex < Section.BaseIndex + NumIndicesThisSection; ++SrcIndex)
			{
				uint32 VertexIndex = SrcIndices[SrcIndex];
				uint32 DestVertexIndex = IndexMap[VertexIndex];
				if (DestVertexIndex == INDEX_NONE)
				{
					FSoftSkinBuildVertex NewVertex;
					const FSoftSkinVertex& SrcVertex = SrcVertices[VertexIndex];
					NewVertex.Position = SrcVertex.Position;
					NewVertex.TangentX = SrcVertex.TangentX;
					NewVertex.TangentY = SrcVertex.TangentY;
					NewVertex.TangentZ = SrcVertex.TangentZ;
					FMemory::Memcpy(NewVertex.UVs, SrcVertex.UVs, sizeof(FVector2D)*MAX_TEXCOORDS);
					NewVertex.Color = SrcVertex.Color;
					for (int32 i = 0; i < MAX_TOTAL_INFLUENCES; ++i)
					{
						uint8 BoneIndex = SrcVertex.InfluenceBones[i];
						check(BoneMap.IsValidIndex(BoneIndex));
						NewVertex.InfluenceBones[i] = BoneMap[BoneIndex];
						NewVertex.InfluenceWeights[i] = SrcVertex.InfluenceWeights[i];
					}
					NewVertex.PointWedgeIdx = SrcModel.RawPointIndices.Num() ? SrcModel.RawPointIndices[VertexIndex] : 0;
					int32 RawVertIndex = SrcModel.MeshToImportVertexMap.Num() ? SrcModel.MeshToImportVertexMap[VertexIndex] : INDEX_NONE;
					if ((int32)NewVertex.PointWedgeIdx >= PointToOriginalMap.Num())
					{
						PointToOriginalMap.AddZeroed(NewVertex.PointWedgeIdx + 1 - PointToOriginalMap.Num());
					}
					PointToOriginalMap[NewVertex.PointWedgeIdx] = RawVertIndex;				
					DestVertexIndex = AddSkinVertex(DestChunk->Vertices,NewVertex,/*bKeepOverlappingVertices=*/ false);
					IndexMap[VertexIndex] = DestVertexIndex;
				}
				DestChunk->Indices.Add(DestVertexIndex);
			}
		}
	#endif // #if WITH_EDITORONLY_DATA
	}