void SAnimSegmentsPanel::Construct(const FArguments& InArgs) { bDragging = false; const int32 NumTracks = 2; AnimTrack = InArgs._AnimTrack; ViewInputMin = InArgs._ViewInputMin; ViewInputMax = InArgs._ViewInputMax; OnAnimSegmentNodeClickedDelegate = InArgs._OnAnimSegmentNodeClicked; OnPreAnimUpdateDelegate = InArgs._OnPreAnimUpdate; OnPostAnimUpdateDelegate = InArgs._OnPostAnimUpdate; // Animation Segment tracks TArray<TSharedPtr<STrack>> AnimSTracks; TArray<TSharedPtr<STrackNode>> AnimNodes; FLinearColor SelectedColor = FLinearColor(1.0f,0.65,0.0f); TSharedPtr<SVerticalBox> AnimSegmentTracks; ChildSlot [ SAssignNew(AnimSegmentTracks, SVerticalBox) ]; for (int32 TrackIdx=0; TrackIdx < NumTracks; TrackIdx++) { TSharedPtr<STrack> AnimSegmentTrack; AnimSegmentTracks->AddSlot() .AutoHeight() .VAlign(VAlign_Center) .Padding( FMargin(0.5f, 0.5f) ) [ SAssignNew(AnimSegmentTrack, STrack) .TrackColor( InArgs._ColorTracker->GetNextColor() ) .ViewInputMin(ViewInputMin) .ViewInputMax(ViewInputMax) .TrackMaxValue( InArgs._TrackMaxValue) //section stuff .OnBarDrag(InArgs._OnBarDrag) .OnBarDrop(InArgs._OnBarDrop) .OnBarClicked(InArgs._OnBarClicked) .DraggableBars(InArgs._DraggableBars) .DraggableBarSnapPositions(InArgs._DraggableBarSnapPositions) .TrackNumDiscreteValues(InArgs._TrackNumDiscreteValues) .OnTrackRightClickContextMenu( InArgs._OnTrackRightClickContextMenu ) .ScrubPosition( InArgs._ScrubPosition ) .OnTrackDragDrop( this, &SAnimSegmentsPanel::OnTrackDragDrop ) ]; AnimSTracks.Add(AnimSegmentTrack); } // Generate Nodes and map them to tracks for ( int32 SegmentIdx=0; SegmentIdx < AnimTrack->AnimSegments.Num(); SegmentIdx++ ) { AnimSTracks[ SegmentIdx % AnimSTracks.Num() ]->AddTrackNode( SNew(STrackNode) .ViewInputMax(this->ViewInputMax) .ViewInputMin(this->ViewInputMin) .NodeColor(InArgs._NodeColor) .SelectedNodeColor(SelectedColor) .DataLength(this, &SAnimSegmentsPanel::GetSegmentLength, SegmentIdx) .DataStartPos(this, &SAnimSegmentsPanel::GetSegmentStartPos, SegmentIdx) .NodeName(this, &SAnimSegmentsPanel::GetAnimSegmentName, SegmentIdx) .ToolTipText(this, &SAnimSegmentsPanel::GetAnimSegmentDetailedInfo, SegmentIdx) .OnTrackNodeDragged( this, &SAnimSegmentsPanel::SetSegmentStartPos, SegmentIdx ) .OnTrackNodeDropped( this, &SAnimSegmentsPanel::OnSegmentDropped, SegmentIdx) .OnNodeRightClickContextMenu( this, &SAnimSegmentsPanel::SummonSegmentNodeContextMenu, SegmentIdx) .OnTrackNodeClicked( this, &SAnimSegmentsPanel::OnAnimSegmentNodeClicked, SegmentIdx ) .NodeSelectionSet(InArgs._NodeSelectionSet) ); } }
void FAnimNode_TwoBoneIK::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms) { check(OutBoneTransforms.Num() == 0); // Get indices of the lower and upper limb bones and check validity. bool bInvalidLimb = false; const int32 EndBoneIndex = IKBone.BoneIndex; const int32 LowerLimbIndex = RequiredBones.GetParentBoneIndex(EndBoneIndex); if (LowerLimbIndex == INDEX_NONE) { bInvalidLimb = true; } const int32 UpperLimbIndex = RequiredBones.GetParentBoneIndex(LowerLimbIndex); if (UpperLimbIndex == INDEX_NONE) { bInvalidLimb = true; } const bool bInBoneSpace = (EffectorLocationSpace == BCS_ParentBoneSpace) || (EffectorLocationSpace == BCS_BoneSpace); const int32 EffectorSpaceBoneIndex = bInBoneSpace ? RequiredBones.GetPoseBoneIndexForBoneName(EffectorSpaceBoneName) : INDEX_NONE; if (bInBoneSpace && ((EffectorSpaceBoneIndex == INDEX_NONE) || !RequiredBones.Contains(EffectorSpaceBoneIndex))) { bInvalidLimb = true; } // If we walked past the root, this controlled is invalid, so return no affected bones. if( bInvalidLimb ) { return; } // Get Local Space transforms for our bones. We do this first in case they already are local. // As right after we get them in component space. (And that does the auto conversion). // We might save one transform by doing local first... const FTransform EndBoneLocalTransform = MeshBases.GetLocalSpaceTransform(IKBone.BoneIndex); // Now get those in component space... FTransform UpperLimbCSTransform = MeshBases.GetComponentSpaceTransform(UpperLimbIndex); FTransform LowerLimbCSTransform = MeshBases.GetComponentSpaceTransform(LowerLimbIndex); FTransform EndBoneCSTransform = MeshBases.GetComponentSpaceTransform(IKBone.BoneIndex); // Get current position of root of limb. // All position are in Component space. const FVector RootPos = UpperLimbCSTransform.GetTranslation(); const FVector InitialJointPos = LowerLimbCSTransform.GetTranslation(); const FVector InitialEndPos = EndBoneCSTransform.GetTranslation(); // Transform EffectorLocation from EffectorLocationSpace to ComponentSpace. FTransform EffectorTransform(EffectorLocation); FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, EffectorTransform, EffectorSpaceBoneIndex, EffectorLocationSpace); // This is our reach goal. FVector DesiredPos = EffectorTransform.GetTranslation(); FVector DesiredDelta = DesiredPos - RootPos; float DesiredLength = DesiredDelta.Size(); // Check to handle case where DesiredPos is the same as RootPos. FVector DesiredDir; if (DesiredLength < (float)KINDA_SMALL_NUMBER) { DesiredLength = (float)KINDA_SMALL_NUMBER; DesiredDir = FVector(1,0,0); } else { DesiredDir = DesiredDelta / DesiredLength; } // Get joint target (used for defining plane that joint should be in). FTransform JointTargetTransform(JointTargetLocation); const int32 JointTargetSpaceBoneIndex = (JointTargetLocationSpace == BCS_ParentBoneSpace || JointTargetLocationSpace == BCS_BoneSpace) ? RequiredBones.GetPoseBoneIndexForBoneName(JointTargetSpaceBoneName) : INDEX_NONE; FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, JointTargetTransform, JointTargetSpaceBoneIndex, JointTargetLocationSpace); FVector JointTargetPos = JointTargetTransform.GetTranslation(); FVector JointTargetDelta = JointTargetPos - RootPos; float JointTargetLength = JointTargetDelta.Size(); // Same check as above, to cover case when JointTarget position is the same as RootPos. FVector JointPlaneNormal, JointBendDir; if (JointTargetLength < (float)KINDA_SMALL_NUMBER) { JointBendDir = FVector(0,1,0); JointPlaneNormal = FVector(0,0,1); } else { JointPlaneNormal = DesiredDir ^ JointTargetDelta; // If we are trying to point the limb in the same direction that we are supposed to displace the joint in, // we have to just pick 2 random vector perp to DesiredDir and each other. if (JointPlaneNormal.Size() < (float)KINDA_SMALL_NUMBER) { DesiredDir.FindBestAxisVectors(JointPlaneNormal, JointBendDir); } else { JointPlaneNormal.Normalize(); // Find the final member of the reference frame by removing any component of JointTargetDelta along DesiredDir. // This should never leave a zero vector, because we've checked DesiredDir and JointTargetDelta are not parallel. JointBendDir = JointTargetDelta - ((JointTargetDelta | DesiredDir) * DesiredDir); JointBendDir.Normalize(); } } // Find lengths of upper and lower limb in the ref skeleton. // Use actual sizes instead of ref skeleton, so we take into account translation and scaling from other bone controllers. float LowerLimbLength = (InitialEndPos - InitialJointPos).Size(); float UpperLimbLength = (InitialJointPos - RootPos).Size(); float MaxLimbLength = LowerLimbLength + UpperLimbLength; if (bAllowStretching) { const float ScaleRange = StretchLimits.Y - StretchLimits.X; if( ScaleRange > KINDA_SMALL_NUMBER && MaxLimbLength > KINDA_SMALL_NUMBER ) { const float ReachRatio = DesiredLength / MaxLimbLength; const float ScalingFactor = (StretchLimits.Y - 1.f) * FMath::Clamp<float>((ReachRatio - StretchLimits.X) / ScaleRange, 0.f, 1.f); if (ScalingFactor > KINDA_SMALL_NUMBER) { LowerLimbLength *= (1.f + ScalingFactor); UpperLimbLength *= (1.f + ScalingFactor); MaxLimbLength *= (1.f + ScalingFactor); } } } FVector OutEndPos = DesiredPos; FVector OutJointPos = InitialJointPos; // If we are trying to reach a goal beyond the length of the limb, clamp it to something solvable and extend limb fully. if (DesiredLength > MaxLimbLength) { OutEndPos = RootPos + (MaxLimbLength * DesiredDir); OutJointPos = RootPos + (UpperLimbLength * DesiredDir); } else { // So we have a triangle we know the side lengths of. We can work out the angle between DesiredDir and the direction of the upper limb // using the sin rule: const float TwoAB = 2.f * UpperLimbLength * DesiredLength; const float CosAngle = (TwoAB != 0.f) ? ((UpperLimbLength*UpperLimbLength) + (DesiredLength*DesiredLength) - (LowerLimbLength*LowerLimbLength)) / TwoAB : 0.f; // If CosAngle is less than 0, the upper arm actually points the opposite way to DesiredDir, so we handle that. const bool bReverseUpperBone = (CosAngle < 0.f); // If CosAngle is greater than 1.f, the triangle could not be made - we cannot reach the target. // We just have the two limbs double back on themselves, and EndPos will not equal the desired EffectorLocation. if ((CosAngle > 1.f) || (CosAngle < -1.f)) { // Because we want the effector to be a positive distance down DesiredDir, we go back by the smaller section. if (UpperLimbLength > LowerLimbLength) { OutJointPos = RootPos + (UpperLimbLength * DesiredDir); OutEndPos = OutJointPos - (LowerLimbLength * DesiredDir); } else { OutJointPos = RootPos - (UpperLimbLength * DesiredDir); OutEndPos = OutJointPos + (LowerLimbLength * DesiredDir); } } else { // Angle between upper limb and DesiredDir const float Angle = FMath::Acos(CosAngle); // Now we calculate the distance of the joint from the root -> effector line. // This forms a right-angle triangle, with the upper limb as the hypotenuse. const float JointLineDist = UpperLimbLength * FMath::Sin(Angle); // And the final side of that triangle - distance along DesiredDir of perpendicular. // ProjJointDistSqr can't be neg, because JointLineDist must be <= UpperLimbLength because appSin(Angle) is <= 1. const float ProjJointDistSqr = (UpperLimbLength*UpperLimbLength) - (JointLineDist*JointLineDist); // although this shouldn't be ever negative, sometimes Xbox release produces -0.f, causing ProjJointDist to be NaN // so now I branch it. float ProjJointDist = (ProjJointDistSqr>0.f)? FMath::Sqrt(ProjJointDistSqr) : 0.f; if( bReverseUpperBone ) { ProjJointDist *= -1.f; } // So now we can work out where to put the joint! OutJointPos = RootPos + (ProjJointDist * DesiredDir) + (JointLineDist * JointBendDir); } } // Update transform for upper bone. { // Get difference in direction for old and new joint orientations FVector const OldDir = (InitialJointPos - RootPos).GetSafeNormal(); FVector const NewDir = (OutJointPos - RootPos).GetSafeNormal(); // Find Delta Rotation take takes us from Old to New dir FQuat const DeltaRotation = FQuat::FindBetween(OldDir, NewDir); // Rotate our Joint quaternion by this delta rotation UpperLimbCSTransform.SetRotation( DeltaRotation * UpperLimbCSTransform.GetRotation() ); // And put joint where it should be. UpperLimbCSTransform.SetTranslation( RootPos ); // Order important. First bone is upper limb. OutBoneTransforms.Add( FBoneTransform(UpperLimbIndex, UpperLimbCSTransform) ); } // Update transform for lower bone. { // Get difference in direction for old and new joint orientations FVector const OldDir = (InitialEndPos - InitialJointPos).GetSafeNormal(); FVector const NewDir = (OutEndPos - OutJointPos).GetSafeNormal(); // Find Delta Rotation take takes us from Old to New dir FQuat const DeltaRotation = FQuat::FindBetween(OldDir, NewDir); // Rotate our Joint quaternion by this delta rotation LowerLimbCSTransform.SetRotation( DeltaRotation * LowerLimbCSTransform.GetRotation() ); // And put joint where it should be. LowerLimbCSTransform.SetTranslation( OutJointPos ); // Order important. Second bone is lower limb. OutBoneTransforms.Add( FBoneTransform(LowerLimbIndex, LowerLimbCSTransform) ); } // Update transform for end bone. { if( bTakeRotationFromEffectorSpace ) { EndBoneCSTransform.SetRotation( EffectorTransform.GetRotation() ); } else if( bMaintainEffectorRelRot ) { EndBoneCSTransform = EndBoneLocalTransform * LowerLimbCSTransform; } // Set correct location for end bone. EndBoneCSTransform.SetTranslation(OutEndPos); // Order important. Third bone is End Bone. OutBoneTransforms.Add( FBoneTransform(IKBone.BoneIndex, EndBoneCSTransform) ); } // Make sure we have correct number of bones check(OutBoneTransforms.Num() == 3); }
void FPhysxSharedData::DumpSharedMemoryUsage(FOutputDevice* Ar) { struct FSharedResourceEntry { uint64 MemorySize; uint64 Count; }; struct FSortBySize { FORCEINLINE bool operator()( const FSharedResourceEntry& A, const FSharedResourceEntry& B ) const { // Sort descending return B.MemorySize < A.MemorySize; } }; TMap<FString, FSharedResourceEntry> AllocationsByType; uint64 OverallSize = 0; int32 OverallCount = 0; TMap<FString, TArray<PxBase*> > ObjectsByType; for (int32 i=0; i < (int32)SharedObjects->getNbObjects(); ++i) { PxBase& Obj = SharedObjects->getObject(i); FString TypeName = ANSI_TO_TCHAR(Obj.getConcreteTypeName()); TArray<PxBase*>* ObjectsArray = ObjectsByType.Find(TypeName); if (ObjectsArray == NULL) { ObjectsByType.Add(TypeName, TArray<PxBase*>()); ObjectsArray = ObjectsByType.Find(TypeName); } check(ObjectsArray); ObjectsArray->Add(&Obj); } TArray<FString> TypeNames; ObjectsByType.GetKeys(TypeNames); for (int32 TypeIdx=0; TypeIdx < TypeNames.Num(); ++TypeIdx) { const FString& TypeName = TypeNames[TypeIdx]; TArray<PxBase*>* ObjectsArray = ObjectsByType.Find(TypeName); check(ObjectsArray); PxSerializationRegistry* Sr = PxSerialization::createSerializationRegistry(*GPhysXSDK); PxCollection* Collection = PxCreateCollection(); for (int32 i=0; i < ObjectsArray->Num(); ++i) { Collection->add(*((*ObjectsArray)[i]));; } PxSerialization::complete(*Collection, *Sr); // chase all other stuff (shared shaps, materials, etc) needed to serialize this collection FPhysXCountMemoryStream Out; PxSerialization::serializeCollectionToBinary(Out, *Collection, *Sr); Collection->release(); Sr->release(); OverallSize += Out.UsedMemory; OverallCount += ObjectsArray->Num(); FSharedResourceEntry NewEntry; NewEntry.Count = ObjectsArray->Num(); NewEntry.MemorySize = Out.UsedMemory; AllocationsByType.Add(TypeName, NewEntry); } Ar->Logf(TEXT("")); Ar->Logf(TEXT("Shared Resources:")); Ar->Logf(TEXT("")); AllocationsByType.ValueSort(FSortBySize()); Ar->Logf(TEXT("%-10d %s (%d)"), OverallSize, TEXT("Overall"), OverallCount ); for( auto It=AllocationsByType.CreateConstIterator(); It; ++It ) { Ar->Logf(TEXT("%-10d %s (%d)"), It.Value().MemorySize, *It.Key(), It.Value().Count ); } }
void FMovieSceneSkeletalAnimationTrackInstance::Update( EMovieSceneUpdateData& UpdateData, const TArray<TWeakObjectPtr<UObject>>& RuntimeObjects, class IMovieScenePlayer& Player, FMovieSceneSequenceInstance& SequenceInstance ) { if (UpdateData.UpdatePass == MSUP_PreUpdate) { UpdateRefreshBones(RuntimeObjects); return; } // @todo Sequencer gameplay update has a different code path than editor update for animation for ( TWeakObjectPtr<UObject> RuntimeObjectPtr : RuntimeObjects ) { USkeletalMeshComponent* SkeletalMeshComponent = GetSkeletalMeshComponentFromRuntimeObjectPtr( RuntimeObjectPtr ); if ( SkeletalMeshComponent ) { TArray<UMovieSceneSection*> AnimSections = AnimationTrack->GetAnimSectionsAtTime( UpdateData.Position ); // cbb: If there is no overlapping section, evaluate the closest section only if the current time is before it. if (AnimSections.Num() == 0) { UMovieSceneSection* NearestSection = MovieSceneHelpers::FindNearestSectionAtTime( AnimationTrack->GetAllSections(), UpdateData.Position ); if (NearestSection) { AnimSections.Add(NearestSection); } } for (int32 AnimSectionIndex = 0; AnimSectionIndex < AnimSections.Num(); ++AnimSectionIndex) { UMovieSceneSkeletalAnimationSection* AnimSection = Cast<UMovieSceneSkeletalAnimationSection>( AnimSections[AnimSectionIndex] ); if ( AnimSection && AnimSection->IsActive() ) { UAnimSequenceBase* AnimSequence = AnimSection->GetAnimSequence(); if ( AnimSequence ) { float EvalTime = MapTimeToAnimation( UpdateData.Position, AnimSection ); int32 ChannelIndex = 0; const bool bLooping = false; if ( ShouldUsePreviewPlayback( Player, SkeletalMeshComponent ) ) { // If the playback status is jumping, ie. one such occurrence is setting the time for thumbnail generation, disable anim notifies updates because it could fire audio const bool bFireNotifies = Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Jumping || Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Stopped ? false : true; float DeltaTime = UpdateData.Position > UpdateData.LastPosition ? UpdateData.Position - UpdateData.LastPosition : 0.f; // When jumping from one cut to another cut, the delta time should be 0 so that anim notifies before the current position are not evaluated. Note, anim notifies at the current time should still be evaluated. if ( UpdateData.bJumpCut ) { DeltaTime = 0.f; } const bool bResetDynamics = Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Stepping || Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Jumping || Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Scrubbing || ( DeltaTime == 0.0f && Player.GetPlaybackStatus() != EMovieScenePlayerStatus::Stopped ); PreviewSetAnimPosition( SkeletalMeshComponent, AnimSection->GetSlotName(), ChannelIndex, AnimSequence, EvalTime, bLooping, bFireNotifies, DeltaTime, Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Playing, bResetDynamics ); } else { // Don't fire notifies at runtime since they will be fired through the standard animation tick path. const bool bFireNotifies = false; SetAnimPosition( SkeletalMeshComponent, AnimSection->GetSlotName(), ChannelIndex, AnimSequence, EvalTime, bLooping, bFireNotifies ); } } } } } } }
void FogWorker::Update(float time) { // Debug stuff static const FName TraceTag(TEXT("FOWTrace")); const UWorld* world = Manager.GetWorld(); if(!world) { return; } UpdateRenderOrigin(); FVector origin, SurfaceExtent; Manager.GetActorBounds(false, origin, SurfaceExtent); if(FMath::IsNearlyZero(SurfaceExtent.Size2D())) { return; } ForgetOldLocations(time); // Cache observers location TArray<FVector> observers; observers.Reserve(Manager.Observers.Num()); for(const auto& o : Manager.Observers) { if(o->IsValidLowLevel()) { observers.Add(o->GetActorLocation()); } } // iterate through observers to unveil fog for(auto& observerLocation : observers) { FVector2D observerTexLoc(observerLocation - Manager.CameraPosition); TArray<FVector2D> sightShape; observerTexLoc /= FVector2D(SurfaceExtent); observerTexLoc *= TextureSize / 2.0f; observerTexLoc += FVector2D(TextureSize / 2.0f, TextureSize / 2.0f); FCollisionQueryParams queryParams(TraceTag, true); for(float i = 0; i < 2 * PI; i += HALF_PI / 100.0f) { auto x = Manager.SightRange * FMath::Cos(i); auto y = Manager.SightRange * FMath::Sin(i); FVector sightLoc = observerLocation + FVector(x, y, 0); FHitResult hit; if(world->LineTraceSingleByChannel(hit, observerLocation, sightLoc, ECC_GameTraceChannel2, queryParams)) { sightLoc = hit.Location; } FVector2D hitTexLoc; if(FSceneView::ProjectWorldToScreen(sightLoc, FIntRect(0, 0, 1024, 768), FMatrix::Identity, hitTexLoc)) { // hitTexLoc = FVector2D(sightLoc - Manager.CameraPosition); hitTexLoc /= FVector2D(SurfaceExtent); hitTexLoc *= TextureSize / 2.0f; hitTexLoc += FVector2D(TextureSize / 2.0f, TextureSize / 2.0f); sightShape.AddUnique(hitTexLoc); } } // draw a unveil shape DrawUnveilShape(observerTexLoc, sightShape); // flood fill area // FloodFill(observerTexLoc.X, observerTexLoc.Y); } UpdateTextureData(); }
void MaterialExpressionClasses::InitMaterialExpressionClasses() { if( !bInitialized ) { UMaterialEditorOptions* TempEditorOptions = ConstructObject<UMaterialEditorOptions>( UMaterialEditorOptions::StaticClass() ); UClass* BaseType = UMaterialExpression::StaticClass(); if( BaseType ) { TArray<UStructProperty*> ExpressionInputs; const UStruct* ExpressionInputStruct = GetExpressionInputStruct(); for( TObjectIterator<UClass> It ; It ; ++It ) { UClass* Class = *It; if( !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated) ) { if( Class->IsChildOf(UMaterialExpression::StaticClass()) ) { ExpressionInputs.Empty(); // Exclude comments from the expression list, as well as the base parameter expression, as it should not be used directly if ( Class != UMaterialExpressionComment::StaticClass() && Class != UMaterialExpressionParameter::StaticClass() ) { FMaterialExpression MaterialExpression; // Trim the material expression name and add it to the list used for filtering. MaterialExpression.Name = FString(*Class->GetName()).Mid(FCString::Strlen(TEXT("MaterialExpression"))); MaterialExpression.MaterialClass = Class; AllExpressionClasses.Add(MaterialExpression); // Initialize the expression class input map. for( TFieldIterator<UStructProperty> InputIt(Class) ; InputIt ; ++InputIt ) { UStructProperty* StructProp = *InputIt; if( StructProp->Struct == ExpressionInputStruct ) { ExpressionInputs.Add( StructProp ); } } // See if it is in the favorites array... for (int32 FavoriteIndex = 0; FavoriteIndex < TempEditorOptions->FavoriteExpressions.Num(); FavoriteIndex++) { if (Class->GetName() == TempEditorOptions->FavoriteExpressions[FavoriteIndex]) { FavoriteExpressionClasses.AddUnique(MaterialExpression); } } // Category fill... UMaterialExpression* TempObject = Cast<UMaterialExpression>(Class->GetDefaultObject()); if (TempObject) { if (TempObject->MenuCategories.Num() == 0) { UnassignedExpressionClasses.Add(MaterialExpression); } else { for (int32 CategoryIndex = 0; CategoryIndex < TempObject->MenuCategories.Num(); CategoryIndex++) { FCategorizedMaterialExpressionNode* CategoryNode = GetCategoryNode(TempObject->MenuCategories[CategoryIndex], true); check(CategoryNode); CategoryNode->MaterialExpressions.AddUnique(MaterialExpression); } } } } } } } } struct FCompareFMaterialExpression { FORCEINLINE bool operator()( const FMaterialExpression& A, const FMaterialExpression& B ) const { return A.Name < B.Name; } }; AllExpressionClasses.Sort(FCompareFMaterialExpression()); struct FCompareFCategorizedMaterialExpressionNode { FORCEINLINE bool operator()( const FCategorizedMaterialExpressionNode& A, const FCategorizedMaterialExpressionNode& B ) const { return A.CategoryName < B.CategoryName; } }; CategorizedExpressionClasses.Sort( FCompareFCategorizedMaterialExpressionNode() ); bInitialized = true; } }
void D3DObjectImage::EndCache(D3DDevice *d3d) { if (!_cache_enabled || _cache.Length() == 0) return; D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYUVC); D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_UV_COLOR); D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_TEX_COLOR_FILTER); static TArray<Vertex> sorted; static TArray<GroupDesc> groups; sorted.Allocate(0); groups.Allocate(0); bool found = true; while (found) { found = false; int cur_id = -1; int num = 0; for (int i = 0; i < _cache.Length(); i++) { // We have processed this if (_cache[i]->_image_id < 0) continue; found = true; if (cur_id < 0) cur_id = _cache[i]->_image_id; if (_cache[i]->_image_id == cur_id) { if (!_cache[i]->_with_border) { Vertex *data = _cache[i]->MakeData(); sorted.Add(data[0]); sorted.Add(data[1]); sorted.Add(data[2]); sorted.Add(data[3]); sorted.Add(data[4]); sorted.Add(data[5]); _cache[i]->_image_id = -_cache[i]->_image_id - 1; num++; } else { Vertex *data = _cache[i]->MakeDataBorder(); int last_len = sorted.Length(); sorted.Allocate(last_len + 6 * 9); CopyMemory(&sorted[last_len], data, sizeof(Vertex) * 6 * 9); _cache[i]->_image_id = -_cache[i]->_image_id - 1; num += 9; } } } if (num > 0) { GroupDesc gd = {num, cur_id}; groups.Add(gd); } } // Restore ids for (int i = 0; i < _cache.Length(); i++) _cache[i]->_image_id = -_cache[i]->_image_id - 1; D3DVertexBufferCache::CacheEntryInfo ce_info; if (!D3DVertexBufferCache::Current()->InitBuffer(d3d, (BYTE *)sorted.Data(), sorted.Length() * sizeof(Vertex), ce_info)) { return; } D3DVertexBufferCache::Current()->SelectBufferToDevice(d3d, ce_info.id, sizeof(Vertex)); HRESULT hr; for (int i = 0, cur = 0; i < groups.Length(); i++) { if (FAILED(hr = D3DImageCache::Current()->SelectImageToDevice(d3d, groups[i].id))) { Log("Failed to select texture: %X", (DWORD)hr); } // d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, groups[i].num * 2, // &sorted[cur], sizeof(Vertex)); d3d->GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST, cur, groups[i].num * 2); cur += groups[i].num * 6; } DBG("Image cache drawn: %d items, %d groups", _cache.Length(), groups.Length()); _cache_enabled = false; }
/** UI_COMMAND takes long for the compile to optimize */ PRAGMA_DISABLE_OPTIMIZATION void FLevelViewportCommands::RegisterCommands() { UI_COMMAND( ToggleMaximize, "Maximize Viewport", "Toggles the Maximize state of the current viewport", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ToggleGameView, "Game View", "Toggles game view. Game view shows the scene as it appears in game", EUserInterfaceActionType::ToggleButton, FInputChord( EKeys::G ) ); UI_COMMAND( ToggleImmersive, "Immersive Mode", "Switches this viewport between immersive mode and regular mode", EUserInterfaceActionType::ToggleButton, FInputChord( EKeys::F11 ) ); UI_COMMAND( CreateCamera, "Create Camera Here", "Creates a new camera actor at the current location of this viewport's camera", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( HighResScreenshot, "High Resolution Screenshot...", "Opens the control panel for high resolution screenshots", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( UseDefaultShowFlags, "Use Defaults", "Resets all show flags to default", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( PilotSelectedActor, "Pilot Selected Actor", "Move the selected actor around using the viewport controls, and bind the viewport to the actor's location and orientation.", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control | EModifierKey::Shift, EKeys::P ) ); UI_COMMAND( EjectActorPilot, "Eject from Actor Pilot", "Stop piloting an actor with the current viewport. Unlocks the viewport's position and orientation from the actor the viewport is currently piloting.", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( ToggleActorPilotCameraView, "Actor Pilot Camera View", "Toggles showing the exact camera view when using the viewport to pilot a camera", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Control | EModifierKey::Shift, EKeys::C ) ); UI_COMMAND( ViewportConfig_OnePane, "Layout One Pane", "Changes the viewport arrangement to one pane", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_TwoPanesH, "Layout Two Panes (horizontal)", "Changes the viewport arrangement to two panes, side-by-side", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_TwoPanesV, "Layout Two Panes (vertical)", "Changes the viewport arrangement to two panes, one above the other", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_ThreePanesLeft, "Layout Three Panes (one left, two right)", "Changes the viewport arrangement to three panes, one on the left, two on the right", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_ThreePanesRight, "Layout Three Panes (one right, two left)", "Changes the viewport arrangement to three panes, one on the right, two on the left", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_ThreePanesTop, "Layout Three Panes (one top, two bottom)", "Changes the viewport arrangement to three panes, one on the top, two on the bottom", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_ThreePanesBottom, "Layout Three Panes (one bottom, two top)", "Changes the viewport arrangement to three panes, one on the bottom, two on the top", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_FourPanesLeft, "Layout Four Panes (one left, three right)", "Changes the viewport arrangement to four panes, one on the left, three on the right", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_FourPanesRight, "Layout Four Panes (one right, three left)", "Changes the viewport arrangement to four panes, one on the right, three on the left", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_FourPanesTop, "Layout Four Panes (one top, three bottom)", "Changes the viewport arrangement to four panes, one on the top, three on the bottom", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_FourPanesBottom, "Layout Four Panes (one bottom, three top)", "Changes the viewport arrangement to four panes, one on the bottom, three on the top", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ViewportConfig_FourPanes2x2, "Layout Four Panes (2x2)", "Changes the viewport arrangement to four panes, in a 2x2 grid", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ApplyMaterialToActor, "Apply Material", "Attempts to apply a dropped material to this object", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( ToggleCinematicPreview, "Toggles Cinematic Preview", "If enabled, allows Matinee or Sequencer previews to play in this viewport", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( FindInLevelScriptBlueprint, "Find In Level Script", "Finds references of a selected actor in the level script blueprint", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::K) ); UI_COMMAND( AdvancedSettings, "Advanced Settings...", "Opens the advanced viewport settings", EUserInterfaceActionType::Button, FInputChord()); // Generate a command for each buffer visualization mode { struct FMaterialIterator { const TSharedRef<class FBindingContext> Parent; FLevelViewportCommands::TBufferVisualizationModeCommandMap& CommandMap; FMaterialIterator(const TSharedRef<class FBindingContext> InParent, FLevelViewportCommands::TBufferVisualizationModeCommandMap& InCommandMap) : Parent(InParent) , CommandMap(InCommandMap) { } void ProcessValue(const FString& InMaterialName, const UMaterial* InMaterial, const FText& InDisplayName) { FName ViewportCommandName = *(FString(TEXT("BufferVisualizationMenu")) + InMaterialName); FBufferVisualizationRecord& Record = CommandMap.Add(ViewportCommandName, FBufferVisualizationRecord()); Record.Name = *InMaterialName; const FText MaterialNameText = FText::FromString( InMaterialName ); Record.Command = FUICommandInfoDecl( Parent, ViewportCommandName, MaterialNameText, MaterialNameText ) .UserInterfaceType( EUserInterfaceActionType::RadioButton ) .DefaultChord( FInputChord() ); } }; BufferVisualizationModeCommands.Empty(); FName ViewportCommandName = *(FString(TEXT("BufferVisualizationOverview"))); FBufferVisualizationRecord& OverviewRecord = BufferVisualizationModeCommands.Add(ViewportCommandName, FBufferVisualizationRecord()); OverviewRecord.Name = NAME_None; OverviewRecord.Command = FUICommandInfoDecl( this->AsShared(), ViewportCommandName, LOCTEXT("BufferVisualization", "Overview"), LOCTEXT("BufferVisualization", "Overview") ) .UserInterfaceType( EUserInterfaceActionType::RadioButton ) .DefaultChord( FInputChord() ); FMaterialIterator It(this->AsShared(), BufferVisualizationModeCommands); GetBufferVisualizationData().IterateOverAvailableMaterials(It); } const TArray<FShowFlagData>& ShowFlagData = GetShowFlagMenuItems(); // Generate a command for each show flag for( int32 ShowFlag = 0; ShowFlag < ShowFlagData.Num(); ++ShowFlag ) { const FShowFlagData& SFData = ShowFlagData[ShowFlag]; FFormatNamedArguments Args; Args.Add( TEXT("ShowFlagName"), SFData.DisplayName ); FText LocalizedName; switch( SFData.Group ) { case SFG_Visualize: LocalizedName = FText::Format( LOCTEXT("VisualizeFlagLabel", "Visualize {ShowFlagName}"), Args ); break; default: LocalizedName = FText::Format( LOCTEXT("ShowFlagLabel", "Show {ShowFlagName}"), Args ); break; } //@todo Slate: The show flags system does not support descriptions currently const FText ShowFlagDesc; TSharedPtr<FUICommandInfo> ShowFlagCommand = FUICommandInfoDecl( this->AsShared(), SFData.ShowFlagName, LocalizedName, ShowFlagDesc ) .UserInterfaceType( EUserInterfaceActionType::ToggleButton ) .DefaultChord( SFData.InputChord ) .Icon(SFData.Group == EShowFlagGroup::SFG_Normal ? FSlateIcon(FEditorStyle::GetStyleSetName(), FEditorStyle::Join( GetContextName(), TCHAR_TO_ANSI( *FString::Printf( TEXT(".%s"), *SFData.ShowFlagName.ToString() ) ) ) ) : FSlateIcon()); ShowFlagCommands.Add( FLevelViewportCommands::FShowMenuCommand( ShowFlagCommand, SFData.DisplayName ) ); } // Generate a command for each volume class { UI_COMMAND( ShowAllVolumes, "Show All Volumes", "Shows all volumes", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( HideAllVolumes, "Hide All Volumes", "Hides all volumes", EUserInterfaceActionType::Button, FInputChord() ); TArray< UClass* > VolumeClasses; UUnrealEdEngine::GetSortedVolumeClasses(&VolumeClasses); for( int32 VolumeClassIndex = 0; VolumeClassIndex < VolumeClasses.Num(); ++VolumeClassIndex ) { //@todo Slate: The show flags system does not support descriptions currently const FText VolumeDesc; const FName VolumeName = VolumeClasses[VolumeClassIndex]->GetFName(); FText DisplayName; FEngineShowFlags::FindShowFlagDisplayName( VolumeName.ToString(), DisplayName ); FFormatNamedArguments Args; Args.Add( TEXT("ShowFlagName"), DisplayName ); const FText LocalizedName = FText::Format( LOCTEXT("ShowFlagLabel_Visualize", "Visualize {ShowFlagName}"), Args ); TSharedPtr<FUICommandInfo> ShowVolumeCommand = FUICommandInfoDecl( this->AsShared(), VolumeName, LocalizedName, VolumeDesc ) .UserInterfaceType( EUserInterfaceActionType::ToggleButton ); ShowVolumeCommands.Add( FLevelViewportCommands::FShowMenuCommand( ShowVolumeCommand, DisplayName ) ); } } // Generate a command for show/hide all layers { UI_COMMAND( ShowAllLayers, "Show All Layers", "Shows all layers", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( HideAllLayers, "Hide All Layers", "Hides all layers", EUserInterfaceActionType::Button, FInputChord() ); } // Generate a command for each sprite category { UI_COMMAND( ShowAllSprites, "Show All Sprites", "Shows all sprites", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( HideAllSprites, "Hide All Sprites", "Hides all sprites", EUserInterfaceActionType::Button, FInputChord() ); // get all the known layers // Get a fresh list as GUnrealEd->SortedSpriteInfo may not yet be built. TArray<FSpriteCategoryInfo> SortedSpriteInfo; UUnrealEdEngine::MakeSortedSpriteInfo(SortedSpriteInfo); FString SpritePrefix = TEXT("ShowSprite_"); for( int32 InfoIndex = 0; InfoIndex < SortedSpriteInfo.Num(); ++InfoIndex ) { const FSpriteCategoryInfo& SpriteInfo = SortedSpriteInfo[InfoIndex]; const FName CommandName = FName( *(SpritePrefix + SpriteInfo.Category.ToString()) ); FFormatNamedArguments Args; Args.Add( TEXT("SpriteName"), SpriteInfo.DisplayName ); const FText LocalizedName = FText::Format( NSLOCTEXT("UICommands", "SpriteShowFlagName", "Show {SpriteName} Sprites"), Args ); TSharedPtr<FUICommandInfo> ShowSpriteCommand = FUICommandInfoDecl( this->AsShared(), CommandName, LocalizedName, SpriteInfo.Description ) .UserInterfaceType( EUserInterfaceActionType::ToggleButton ); ShowSpriteCommands.Add( FLevelViewportCommands::FShowMenuCommand( ShowSpriteCommand, SpriteInfo.DisplayName ) ); } } // Generate a command for each Stat category { UI_COMMAND(HideAllStats, "Hide All Stats", "Hides all Stats", EUserInterfaceActionType::Button, FInputChord()); // Bind a listener here for any additional stat commands that get registered later. UEngine::NewStatDelegate.AddRaw(this, &FLevelViewportCommands::HandleNewStat); #if STATS FStatGroupGameThreadNotifier::Get().NewStatGroupDelegate.BindRaw(this, &FLevelViewportCommands::HandleNewStatGroup); #endif } // Map the bookmark index to default key. // If the max bookmark number ever increases the new bookmarks will not have default keys TArray< FKey > NumberKeyNames; NumberKeyNames.Add( EKeys::Zero ); NumberKeyNames.Add( EKeys::One ); NumberKeyNames.Add( EKeys::Two ); NumberKeyNames.Add( EKeys::Three ); NumberKeyNames.Add( EKeys::Four ); NumberKeyNames.Add( EKeys::Five ); NumberKeyNames.Add( EKeys::Six ); NumberKeyNames.Add( EKeys::Seven ); NumberKeyNames.Add( EKeys::Eight ); NumberKeyNames.Add( EKeys::Nine ); for( int32 BookmarkIndex = 0; BookmarkIndex < AWorldSettings::MAX_BOOKMARK_NUMBER; ++BookmarkIndex ) { TSharedRef< FUICommandInfo > JumpToBookmark = FUICommandInfoDecl( this->AsShared(), //Command class FName( *FString::Printf( TEXT( "JumpToBookmark%i" ), BookmarkIndex ) ), //CommandName FText::Format( NSLOCTEXT("LevelEditorCommands", "JumpToBookmark", "Jump to Bookmark {0}"), FText::AsNumber( BookmarkIndex ) ), //Localized label FText::Format( NSLOCTEXT("LevelEditorCommands", "JumpToBookmark_ToolTip", "Moves the viewport to the location and orientation stored at bookmark {0}"), FText::AsNumber( BookmarkIndex ) ) )//Localized tooltip .UserInterfaceType( EUserInterfaceActionType::Button ) //interface type .DefaultChord( FInputChord( NumberKeyNames.IsValidIndex( BookmarkIndex ) ? NumberKeyNames[BookmarkIndex] : EKeys::Invalid ) ); //default chord JumpToBookmarkCommands.Add( JumpToBookmark ); TSharedRef< FUICommandInfo > SetBookmark = FUICommandInfoDecl( this->AsShared(), //Command class FName( *FString::Printf( TEXT( "SetBookmark%i" ), BookmarkIndex ) ), //CommandName FText::Format( NSLOCTEXT("LevelEditorCommands", "SetBookmark", "Set Bookmark {0}"), FText::AsNumber( BookmarkIndex ) ), //Localized label FText::Format( NSLOCTEXT("LevelEditorCommands", "SetBookmark_ToolTip", "Stores the viewports location and orientation in bookmark {0}"), FText::AsNumber( BookmarkIndex ) ) )//Localized tooltip .UserInterfaceType( EUserInterfaceActionType::Button ) //interface type .DefaultChord( FInputChord( EModifierKey::Control, NumberKeyNames.IsValidIndex( BookmarkIndex ) ? NumberKeyNames[BookmarkIndex] : EKeys::Invalid ) ); //default chord SetBookmarkCommands.Add( SetBookmark ); TSharedRef< FUICommandInfo > ClearBookMark = FUICommandInfoDecl( this->AsShared(), //Command class FName( *FString::Printf( TEXT( "ClearBookmark%i" ), BookmarkIndex ) ), //CommandName FText::Format( NSLOCTEXT("LevelEditorCommands", "ClearBookmark", "Clear Bookmark {0}"), FText::AsNumber( BookmarkIndex ) ), //Localized label FText::Format( NSLOCTEXT("LevelEditorCommands", "ClearBookmark_ToolTip", "Clears the viewports location and orientation in bookmark {0}"), FText::AsNumber( BookmarkIndex ) ) )//Localized tooltip .UserInterfaceType( EUserInterfaceActionType::Button ) //interface type .DefaultChord( FInputChord() ); //default chord ClearBookmarkCommands.Add( ClearBookMark ); } UI_COMMAND( ClearAllBookMarks, "Clear All Bookmarks", "Clears all the bookmarks", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( EnablePreviewMesh, "Hold To Enable Preview Mesh", "When held down a preview mesh appears under the cursor", EUserInterfaceActionType::Button, FInputChord(EKeys::Backslash) ); UI_COMMAND( CyclePreviewMesh, "Cycles Preview Mesh", "Cycles available preview meshes", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift, EKeys::Backslash ) ); }
void AActor::RerunConstructionScripts() { // don't allow (re)running construction scripts on dying actors bool bAllowReconstruction = !IsPendingKill() && !HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed); #if WITH_EDITOR if(bAllowReconstruction && GIsEditor) { // Generate the blueprint hierarchy for this actor TArray<UBlueprint*> ParentBPStack; bAllowReconstruction = UBlueprint::GetBlueprintHierarchyFromClass(GetClass(), ParentBPStack); if(bAllowReconstruction) { for(int i = ParentBPStack.Num() - 1; i > 0 && bAllowReconstruction; --i) { const UBlueprint* ParentBP = ParentBPStack[i]; if(ParentBP && ParentBP->bBeingCompiled) { // don't allow (re)running construction scripts if a parent BP is being compiled bAllowReconstruction = false; } } } } #endif if(bAllowReconstruction) { // Temporarily suspend the undo buffer; we don't need to record reconstructed component objects into the current transaction ITransaction* CurrentTransaction = GUndo; GUndo = NULL; // Create cache to store component data across rerunning construction scripts FComponentInstanceDataCache InstanceDataCache(this); // If there are attached objects detach them and store the socket names TArray<AActor*> AttachedActors; GetAttachedActors(AttachedActors); // Struct to store info about attached actors struct FAttachedActorInfo { AActor* AttachedActor; FName AttachedToSocket; }; // Save info about attached actors TArray<FAttachedActorInfo> AttachedActorInfos; for( AActor* AttachedActor : AttachedActors) { USceneComponent* EachRoot = AttachedActor->GetRootComponent(); // If the component we are attached to is about to go away... if( EachRoot && EachRoot->AttachParent && EachRoot->AttachParent->bCreatedByConstructionScript ) { // Save info about actor to reattach FAttachedActorInfo Info; Info.AttachedActor = AttachedActor; Info.AttachedToSocket = EachRoot->AttachSocketName; AttachedActorInfos.Add(Info); // Now detach it AttachedActor->Modify(); EachRoot->DetachFromParent(true); } } // Save off original pose of the actor FTransform OldTransform = FTransform::Identity; FName SocketName; AActor* Parent = NULL; if (RootComponent != NULL) { // Do not need to detach if root component is not going away if(RootComponent->AttachParent != NULL && RootComponent->bCreatedByConstructionScript) { Parent = RootComponent->AttachParent->GetOwner(); // Root component should never be attached to another component in the same actor! if(Parent == this) { UE_LOG(LogActor, Warning, TEXT("RerunConstructionScripts: RootComponent (%s) attached to another component in this Actor (%s)."), *RootComponent->GetPathName(), *Parent->GetPathName()); Parent = NULL; } SocketName = RootComponent->AttachSocketName; //detach it to remove any scaling RootComponent->DetachFromParent(true); } OldTransform = RootComponent->ComponentToWorld; } // Destroy existing components DestroyConstructedComponents(); // Reset random streams ResetPropertiesForConstruction(); // Run the construction scripts OnConstruction(OldTransform); if(Parent) { USceneComponent* ChildRoot = GetRootComponent(); USceneComponent* ParentRoot = Parent->GetRootComponent(); if(ChildRoot != NULL && ParentRoot != NULL) { ChildRoot->AttachTo( ParentRoot, SocketName, EAttachLocation::KeepWorldPosition ); } } // Apply per-instance data. InstanceDataCache.ApplyToActor(this); // If we had attached children reattach them now - unless they are already attached for(FAttachedActorInfo& Info : AttachedActorInfos) { // If this actor is no longer attached to anything, reattach if (Info.AttachedActor->GetAttachParentActor() == NULL) { USceneComponent* ChildRoot = Info.AttachedActor->GetRootComponent(); if (ChildRoot && ChildRoot->AttachParent != RootComponent) { ChildRoot->AttachTo(RootComponent, Info.AttachedToSocket, EAttachLocation::KeepWorldPosition); ChildRoot->UpdateComponentToWorld(); } } } // Restore the undo buffer GUndo = CurrentTransaction; } }
void FMoveSection::OnDrag( const FPointerEvent& MouseEvent, const FVector2D& LocalMousePos, const FTimeToPixel& TimeToPixelConverter, TSharedPtr<FTrackNode> SequencerNode ) { if( Section.IsValid() ) { auto Sections = SequencerNode->GetSections(); TArray<UMovieSceneSection*> MovieSceneSections; for (int32 i = 0; i < Sections.Num(); ++i) { MovieSceneSections.Add(Sections[i]->GetSectionObject()); } FVector2D TotalDelta = LocalMousePos - DragOffset; float DistanceMoved = TotalDelta.X / TimeToPixelConverter.GetPixelsPerInput(); float DeltaTime = DistanceMoved; if ( Settings->GetIsSnapEnabled() ) { bool bSnappedToSection = false; if ( Settings->GetSnapSectionTimesToSections() ) { TArray<float> TimesToSnapTo; GetSectionSnapTimes(TimesToSnapTo, Section.Get(), SequencerNode, true); TArray<float> TimesToSnap; TimesToSnap.Add(DistanceMoved + Section->GetStartTime()); TimesToSnap.Add(DistanceMoved + Section->GetEndTime()); float OutSnappedTime = 0.f; float OutNewTime = 0.f; if (SnapToTimes(TimesToSnap, TimesToSnapTo, TimeToPixelConverter, OutSnappedTime, OutNewTime)) { DeltaTime = OutNewTime - (OutSnappedTime - DistanceMoved); bSnappedToSection = true; } } if ( bSnappedToSection == false && Settings->GetSnapSectionTimesToInterval() ) { float NewStartTime = DistanceMoved + Section->GetStartTime(); DeltaTime = Settings->SnapTimeToInterval( NewStartTime ) - Section->GetStartTime(); } } int32 TargetRowIndex = Section->GetRowIndex(); // vertical dragging - master tracks only if (SequencerNode->GetTrack()->SupportsMultipleRows() && Sections.Num() > 1) { float TrackHeight = Sections[0]->GetSectionHeight(); if (LocalMousePos.Y < 0.f || LocalMousePos.Y > TrackHeight) { int32 MaxRowIndex = 0; for (int32 i = 0; i < Sections.Num(); ++i) { if (Sections[i]->GetSectionObject() != Section.Get()) { MaxRowIndex = FMath::Max(MaxRowIndex, Sections[i]->GetSectionObject()->GetRowIndex()); } } TargetRowIndex = FMath::Clamp(Section->GetRowIndex() + FMath::FloorToInt(LocalMousePos.Y / TrackHeight), 0, MaxRowIndex + 1); } } bool bDeltaX = !FMath::IsNearlyZero(TotalDelta.X); bool bDeltaY = TargetRowIndex != Section->GetRowIndex(); if (bDeltaX && bDeltaY && !Section->OverlapsWithSections(MovieSceneSections, TargetRowIndex - Section->GetRowIndex(), DeltaTime)) { Section->MoveSection(DeltaTime, DraggedKeyHandles); Section->SetRowIndex(TargetRowIndex); } else { if (bDeltaY && !Section->OverlapsWithSections(MovieSceneSections, TargetRowIndex - Section->GetRowIndex(), 0.f)) { Section->SetRowIndex(TargetRowIndex); } if (bDeltaX) { if (!Section->OverlapsWithSections(MovieSceneSections, 0, DeltaTime)) { Section->MoveSection(DeltaTime, DraggedKeyHandles); } else { // Find the borders of where you can move to TRange<float> SectionBoundaries = GetSectionBoundaries(Section.Get(), SequencerNode); float LeftMovementMaximum = SectionBoundaries.GetLowerBoundValue() - Section->GetStartTime(); float RightMovementMaximum = SectionBoundaries.GetUpperBoundValue() - Section->GetEndTime(); // Tell the section to move itself and any data it has Section->MoveSection( FMath::Clamp(DeltaTime, LeftMovementMaximum, RightMovementMaximum), DraggedKeyHandles ); } } } } }
void FMoveKeys::OnDrag( const FPointerEvent& MouseEvent, const FVector2D& LocalMousePos, const FTimeToPixel& TimeToPixelConverter, TSharedPtr<FTrackNode> SequencerNode ) { // Convert the delta position to a delta time amount that was moved float MouseTime = TimeToPixelConverter.PixelToTime(LocalMousePos.X); float SelectedKeyTime = DraggedKey.KeyArea->GetKeyTime(DraggedKey.KeyHandle.GetValue()); float DistanceMoved = MouseTime - SelectedKeyTime; if( DistanceMoved != 0.0f ) { float TimeDelta = DistanceMoved; // Snapping if ( Settings->GetIsSnapEnabled() ) { bool bSnappedToKeyTime = false; if ( Settings->GetSnapKeyTimesToKeys() ) { TArray<float> OutSnapTimes; GetKeySnapTimes(OutSnapTimes, SequencerNode); TArray<float> InitialTimes; for ( FSelectedKey SelectedKey : SelectedKeys ) { InitialTimes.Add(SelectedKey.KeyArea->GetKeyTime(SelectedKey.KeyHandle.GetValue()) + DistanceMoved); } float OutInitialTime = 0.f; float OutSnapTime = 0.f; if ( SnapToTimes( InitialTimes, OutSnapTimes, TimeToPixelConverter, OutInitialTime, OutSnapTime ) ) { bSnappedToKeyTime = true; TimeDelta = OutSnapTime - (OutInitialTime - DistanceMoved); } } if ( bSnappedToKeyTime == false && Settings->GetSnapKeyTimesToInterval() ) { TimeDelta = Settings->SnapTimeToInterval( MouseTime ) - SelectedKeyTime; } } for( FSelectedKey SelectedKey : SelectedKeys ) { UMovieSceneSection* Section = SelectedKey.Section; TSharedPtr<IKeyArea>& KeyArea = SelectedKey.KeyArea; // Tell the key area to move the key. We reset the key index as a result of the move because moving a key can change it's internal index KeyArea->MoveKey( SelectedKey.KeyHandle.GetValue(), TimeDelta ); // Update the key that moved float NewKeyTime = KeyArea->GetKeyTime( SelectedKey.KeyHandle.GetValue() ); // If the key moves outside of the section resize the section to fit the key // @todo Sequencer - Doesn't account for hitting other sections if( NewKeyTime > Section->GetEndTime() ) { Section->SetEndTime( NewKeyTime ); } else if( NewKeyTime < Section->GetStartTime() ) { Section->SetStartTime( NewKeyTime ); } } } }
TSharedRef< SWidget > FLevelEditorToolBar::GenerateQuickSettingsMenu( TSharedRef<FUICommandList> InCommandList ) { #define LOCTEXT_NAMESPACE "LevelToolBarViewMenu" // Get all menu extenders for this context menu from the level editor module FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") ); TArray<FLevelEditorModule::FLevelEditorMenuExtender> MenuExtenderDelegates = LevelEditorModule.GetAllLevelEditorToolbarViewMenuExtenders(); TArray<TSharedPtr<FExtender>> Extenders; for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i) { if (MenuExtenderDelegates[i].IsBound()) { Extenders.Add(MenuExtenderDelegates[i].Execute(InCommandList)); } } TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders); const bool bShouldCloseWindowAfterMenuSelection = true; FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, InCommandList, MenuExtender ); MenuBuilder.BeginSection("LevelEditorSelection", LOCTEXT("SelectionHeading","Selection") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().AllowTranslucentSelection ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().AllowGroupSelection ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().StrictBoxSelect ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorEditing", LOCTEXT("EditingHeading", "Editing") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ShowTransformWidget ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().DrawBrushMarkerPolys ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorPreview", LOCTEXT("PreviewHeading", "Previewing") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OnlyLoadVisibleInPIE ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ToggleParticleSystemLOD ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ToggleParticleSystemHelpers ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ToggleFreezeParticleSimulation ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ToggleLODViewLocking ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LevelStreamingVolumePrevis ); MenuBuilder.AddSubMenu( LOCTEXT( "ScalabilitySubMenu", "Engine Scalability Settings" ), LOCTEXT( "ScalabilitySubMenu_ToolTip", "Open the engine scalability settings" ), FNewMenuDelegate::CreateStatic( &MakeScalabilityMenu ) ); MenuBuilder.AddSubMenu( LOCTEXT( "MaterialQualityLevelSubMenu", "Material Quality Level" ), LOCTEXT( "MaterialQualityLevelSubMenu_ToolTip", "Sets the value of the CVar \"r.MaterialQualityLevel\" (low=0, high=1). This affects materials via the QualitySwitch material expression." ), FNewMenuDelegate::CreateStatic( &MakeMaterialQualityLevelMenu ) ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorAudio", LOCTEXT("AudioHeading", "Real Time Audio") ); { TSharedRef<SWidget> VolumeItem = SNew(SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(0.9f) .Padding( FMargin(2.0f, 0.0f, 0.0f, 0.0f) ) [ SNew(SVolumeControl) .ToolTipText_Static(&FLevelEditorActionCallbacks::GetAudioVolumeToolTip) .Volume_Static(&FLevelEditorActionCallbacks::GetAudioVolume) .OnVolumeChanged_Static(&FLevelEditorActionCallbacks::OnAudioVolumeChanged) .Muted_Static(&FLevelEditorActionCallbacks::GetAudioMuted) .OnMuteChanged_Static(&FLevelEditorActionCallbacks::OnAudioMutedChanged) ] +SHorizontalBox::Slot() .FillWidth(0.1f); MenuBuilder.AddWidget(VolumeItem, LOCTEXT("VolumeControlLabel","Volume")); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorActorSnap", LOCTEXT("ActorSnapHeading","Actor Snap") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().EnableActorSnap ); TSharedRef<SWidget> SnapItem = SNew(SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(0.9f) [ SNew(SSlider) .ToolTipText_Static(&FLevelEditorActionCallbacks::GetActorSnapTooltip) .Value_Static(&FLevelEditorActionCallbacks::GetActorSnapSetting) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetActorSnapSetting) ] +SHorizontalBox::Slot() .FillWidth(0.1f); MenuBuilder.AddWidget(SnapItem, LOCTEXT("ActorSnapLabel","Distance")); } MenuBuilder.EndSection(); MenuBuilder.BeginSection( "Snapping", LOCTEXT("SnappingHeading","Snapping") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ToggleSocketSnapping ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().EnableVertexSnap ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorViewport", LOCTEXT("ViewportHeading", "Viewport") ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().ToggleHideViewportUI ); } MenuBuilder.EndSection(); #undef LOCTEXT_NAMESPACE return MenuBuilder.MakeWidget(); }
TSharedRef< SWidget > FLevelEditorToolBar::GenerateBuildMenuContent( TSharedRef<FUICommandList> InCommandList ) { #define LOCTEXT_NAMESPACE "LevelToolBarBuildMenu" // Get all menu extenders for this context menu from the level editor module FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") ); TArray<FLevelEditorModule::FLevelEditorMenuExtender> MenuExtenderDelegates = LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders(); TArray<TSharedPtr<FExtender>> Extenders; for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i) { if (MenuExtenderDelegates[i].IsBound()) { Extenders.Add(MenuExtenderDelegates[i].Execute(InCommandList)); } } TSharedPtr<FExtender> MenuExtender = FExtender::Combine(Extenders); const bool bShouldCloseWindowAfterMenuSelection = true; FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, InCommandList, MenuExtender ); struct FLightingMenus { /** Generates a lighting quality sub-menu */ static void MakeLightingQualityMenu( FMenuBuilder& InMenuBuilder ) { InMenuBuilder.BeginSection("LevelEditorBuildLightingQuality", LOCTEXT( "LightingQualityHeading", "Quality Level" ) ); { InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingQuality_Production ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingQuality_High ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingQuality_Medium ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingQuality_Preview ); } InMenuBuilder.EndSection(); } /** Generates a lighting tools sub-menu */ static void MakeLightingToolsMenu( FMenuBuilder& InMenuBuilder ) { InMenuBuilder.BeginSection("LevelEditorBuildLightingTools", LOCTEXT( "LightingToolsHeading", "Light Environments" ) ); { InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingTools_ShowBounds ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingTools_ShowTraces ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingTools_ShowDirectOnly ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingTools_ShowIndirectOnly ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingTools_ShowIndirectSamples ); } InMenuBuilder.EndSection(); } /** Generates a lighting density sub-menu */ static void MakeLightingDensityMenu( FMenuBuilder& InMenuBuilder ) { InMenuBuilder.BeginSection("LevelEditorBuildLightingDensity", LOCTEXT( "LightingDensityHeading", "Density Rendering" ) ); { TSharedRef<SWidget> Ideal = SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding( FMargin( 27.0f, 0.0f, 0.0f, 0.0f ) ) .FillWidth(1.0f) [ SNew(SSpinBox<float>) .MinValue(0.f) .MaxValue(100.f) .Value(FLevelEditorActionCallbacks::GetLightingDensityIdeal()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingDensityIdeal) ]; InMenuBuilder.AddWidget(Ideal, LOCTEXT("LightingDensity_Ideal","Ideal Density")); TSharedRef<SWidget> Maximum = SNew(SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(1.0f) [ SNew(SSpinBox<float>) .MinValue(0.01f) .MaxValue(100.01f) .Value(FLevelEditorActionCallbacks::GetLightingDensityMaximum()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingDensityMaximum) ]; InMenuBuilder.AddWidget(Maximum, LOCTEXT("LightingDensity_Maximum","Maximum Density")); TSharedRef<SWidget> ClrScale = SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding( FMargin( 35.0f, 0.0f, 0.0f, 0.0f ) ) .FillWidth(1.0f) [ SNew(SSpinBox<float>) .MinValue(0.f) .MaxValue(10.f) .Value(FLevelEditorActionCallbacks::GetLightingDensityColorScale()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingDensityColorScale) ]; InMenuBuilder.AddWidget(ClrScale, LOCTEXT("LightingDensity_ColorScale","Color Scale")); TSharedRef<SWidget> GrayScale = SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding( FMargin( 11.0f, 0.0f, 0.0f, 0.0f ) ) .FillWidth(1.0f) [ SNew(SSpinBox<float>) .MinValue(0.f) .MaxValue(10.f) .Value(FLevelEditorActionCallbacks::GetLightingDensityGrayscaleScale()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingDensityGrayscaleScale) ]; InMenuBuilder.AddWidget(GrayScale, LOCTEXT("LightingDensity_GrayscaleScale","Grayscale Scale")); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingDensity_RenderGrayscale ); } InMenuBuilder.EndSection(); } /** Generates a lighting resolution sub-menu */ static void MakeLightingResolutionMenu( FMenuBuilder& InMenuBuilder ) { InMenuBuilder.BeginSection("LevelEditorBuildLightingResolution1", LOCTEXT( "LightingResolutionHeading1", "Primitive Types" ) ); { TSharedRef<SWidget> Meshes = SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() [ SNew( SCheckBox ) .Style( FEditorStyle::Get(), "Menu.CheckBox" ) .ToolTipText(LOCTEXT( "StaticMeshesToolTip", "Static Meshes will be adjusted if checked." )) .IsChecked_Static(&FLevelEditorActionCallbacks::IsLightingResolutionStaticMeshesChecked) .OnCheckStateChanged_Static(&FLevelEditorActionCallbacks::SetLightingResolutionStaticMeshes) .Content() [ SNew( STextBlock ) .Text( LOCTEXT("StaticMeshes", "Static Meshes") ) ] ] +SHorizontalBox::Slot() .AutoWidth() .Padding( FMargin( 4.0f, 0.0f, 11.0f, 0.0f ) ) [ SNew(SSpinBox<float>) .MinValue(4.f) .MaxValue(4096.f) .ToolTipText(LOCTEXT( "LightingResolutionStaticMeshesMinToolTip", "The minimum lightmap resolution for static mesh adjustments. Anything outside of Min/Max range will not be touched when adjusting." )) .Value(FLevelEditorActionCallbacks::GetLightingResolutionMinSMs()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingResolutionMinSMs) ] +SHorizontalBox::Slot() .AutoWidth() [ SNew(SSpinBox<float>) .MinValue(4.f) .MaxValue(4096.f) .ToolTipText(LOCTEXT( "LightingResolutionStaticMeshesMaxToolTip", "The maximum lightmap resolution for static mesh adjustments. Anything outside of Min/Max range will not be touched when adjusting." )) .Value(FLevelEditorActionCallbacks::GetLightingResolutionMaxSMs()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingResolutionMaxSMs) ]; InMenuBuilder.AddWidget(Meshes, FText::GetEmpty(), true); TSharedRef<SWidget> BSPs = SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() [ SNew( SCheckBox ) .Style(FEditorStyle::Get(), "Menu.CheckBox") .ToolTipText(LOCTEXT( "BSPSurfacesToolTip", "BSP Surfaces will be adjusted if checked." )) .IsChecked_Static(&FLevelEditorActionCallbacks::IsLightingResolutionBSPSurfacesChecked) .OnCheckStateChanged_Static(&FLevelEditorActionCallbacks::SetLightingResolutionBSPSurfaces) .Content() [ SNew( STextBlock ) .Text( LOCTEXT("BSPSurfaces", "BSP Surfaces") ) ] ] +SHorizontalBox::Slot() .AutoWidth() .Padding( FMargin( 6.0f, 0.0f, 4.0f, 0.0f ) ) [ SNew(SSpinBox<float>) .MinValue(1.f) .MaxValue(63556.f) .ToolTipText(LOCTEXT( "LightingResolutionBSPsMinToolTip", "The minimum lightmap resolution of a BSP surface to adjust. When outside of the Min/Max range, the BSP surface will no be altered." )) .Value(FLevelEditorActionCallbacks::GetLightingResolutionMinBSPs()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingResolutionMinBSPs) ] +SHorizontalBox::Slot() .AutoWidth() [ SNew(SSpinBox<float>) .MinValue(1.f) .MaxValue(63556.f) .ToolTipText(LOCTEXT( "LightingResolutionBSPsMaxToolTip", "The maximum lightmap resolution of a BSP surface to adjust. When outside of the Min/Max range, the BSP surface will no be altered." )) .Value(FLevelEditorActionCallbacks::GetLightingResolutionMaxBSPs()) .OnValueChanged_Static(&FLevelEditorActionCallbacks::SetLightingResolutionMaxBSPs) ]; InMenuBuilder.AddWidget(BSPs, FText::GetEmpty(), true); } InMenuBuilder.EndSection(); //LevelEditorBuildLightingResolution1 InMenuBuilder.BeginSection("LevelEditorBuildLightingResolution2", LOCTEXT( "LightingResolutionHeading2", "Select Options" ) ); { InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingResolution_CurrentLevel ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingResolution_SelectedLevels ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingResolution_AllLoadedLevels ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingResolution_SelectedObjectsOnly ); } InMenuBuilder.EndSection(); InMenuBuilder.BeginSection("LevelEditorBuildLightingResolution3", LOCTEXT( "LightingResolutionHeading3", "Ratio" ) ); { TSharedRef<SWidget> Ratio = SNew(SSpinBox<int32>) .MinValue(0) .MaxValue(400) .ToolTipText(LOCTEXT( "LightingResolutionRatioToolTip", "Ratio to apply (New Resolution = Ratio / 100.0f * CurrentResolution)." )) .Value(FLevelEditorActionCallbacks::GetLightingResolutionRatio()) .OnEndSliderMovement_Static(&FLevelEditorActionCallbacks::SetLightingResolutionRatio) .OnValueCommitted_Static(&FLevelEditorActionCallbacks::SetLightingResolutionRatioCommit); InMenuBuilder.AddWidget(Ratio, LOCTEXT( "LightingResolutionRatio", "Ratio" )); } InMenuBuilder.EndSection(); } /** Generates a lighting info dialogs sub-menu */ static void MakeLightingInfoMenu( FMenuBuilder& InMenuBuilder ) { InMenuBuilder.BeginSection("LevelEditorBuildLightingInfo", LOCTEXT( "LightingInfoHeading", "Lighting Info Dialogs" ) ); { InMenuBuilder.AddSubMenu( LOCTEXT( "LightingToolsSubMenu", "Lighting Tools" ), LOCTEXT( "LightingToolsSubMenu_ToolTip", "Shows the Lighting Tools options." ), FNewMenuDelegate::CreateStatic( &FLightingMenus::MakeLightingToolsMenu ) ); InMenuBuilder.AddSubMenu( LOCTEXT( "LightingDensityRenderingSubMenu", "LightMap Density Rendering Options" ), LOCTEXT( "LightingDensityRenderingSubMenu_ToolTip", "Shows the LightMap Density Rendering viewmode options." ), FNewMenuDelegate::CreateStatic( &FLightingMenus::MakeLightingDensityMenu ) ); InMenuBuilder.AddSubMenu( LOCTEXT( "LightingResolutionAdjustmentSubMenu", "LightMap Resolution Adjustment" ), LOCTEXT( "LightingResolutionAdjustmentSubMenu_ToolTip", "Shows the LightMap Resolution Adjustment options." ), FNewMenuDelegate::CreateStatic( &FLightingMenus::MakeLightingResolutionMenu ) ); InMenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingStaticMeshInfo, NAME_None, LOCTEXT( "BuildLightingInfo_LightingStaticMeshInfo", "Lighting StaticMesh Info..." ) ); } InMenuBuilder.EndSection(); } }; MenuBuilder.BeginSection("LevelEditorLighting", LOCTEXT( "LightingHeading", "Lighting" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildLightingOnly, NAME_None, LOCTEXT( "BuildLightingOnlyHeading", "Build Lighting Only" ) ); MenuBuilder.AddSubMenu( LOCTEXT( "LightingQualitySubMenu", "Lighting Quality" ), LOCTEXT( "LightingQualitySubMenu_ToolTip", "Allows you to select the quality level for precomputed lighting" ), FNewMenuDelegate::CreateStatic( &FLightingMenus::MakeLightingQualityMenu ) ); MenuBuilder.AddSubMenu( LOCTEXT( "BuildLightingInfoSubMenu", "Lighting Info" ), LOCTEXT( "BuildLightingInfoSubMenu_ToolTip", "Access the lighting info dialogs" ), FNewMenuDelegate::CreateStatic( &FLightingMenus::MakeLightingInfoMenu ) ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingBuildOptions_UseErrorColoring ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().LightingBuildOptions_ShowLightingStats ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorReflections", LOCTEXT( "ReflectionHeading", "Reflections" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildReflectionCapturesOnly ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorVisibility", LOCTEXT( "VisibilityHeading", "Visibility" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildLightingOnly_VisibilityOnly ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorGeometry", LOCTEXT( "GeometryHeading", "Geometry" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildGeometryOnly ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildGeometryOnly_OnlyCurrentLevel ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorNavigation", LOCTEXT( "NavigationHeading", "Navigation" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildPathsOnly ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection("LevelEditorAutomation", LOCTEXT( "AutomationHeading", "Automation" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().BuildAndSubmitToSourceControl ); } MenuBuilder.EndSection(); // Texture Stats MenuBuilder.BeginSection("LevelEditorStatistics", LOCTEXT( "Statistics", "Statistics" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().SceneStats, NAME_None, LOCTEXT("OpenSceneStats", "Scene Stats") ); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().TextureStats, NAME_None, LOCTEXT("OpenTextureStats", "TextureStats Stats") ); } MenuBuilder.EndSection(); // Map Check MenuBuilder.BeginSection("LevelEditorVerification", LOCTEXT( "VerificationHeading", "Verification" ) ); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().MapCheck, NAME_None, LOCTEXT("OpenMapCheck", "Map Check") ); } MenuBuilder.EndSection(); #undef LOCTEXT_NAMESPACE return MenuBuilder.MakeWidget(); }
virtual void GetSupportedFormats(TArray<FName>& OutFormats) const { OutFormats.Add(NAME_SF_METAL); OutFormats.Add(NAME_SF_METAL_MRT); OutFormats.Add(NAME_SF_METAL_SM5); }
int32 FAnimationSection::OnPaintSection( const FGeometry& AllottedGeometry, const FSlateRect& SectionClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, bool bParentEnabled ) const { UMovieSceneAnimationSection* AnimSection = Cast<UMovieSceneAnimationSection>(&Section); FTimeToPixel TimeToPixelConverter( AllottedGeometry, TRange<float>( Section.GetStartTime(), Section.GetEndTime() ) ); // Add a box for the section FSlateDrawElement::MakeBox( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(), FEditorStyle::GetBrush("Sequencer.GenericSection.Background"), SectionClippingRect, ESlateDrawEffect::None, FLinearColor(0.7f, 0.4f, 0.7f, 1.f) ); // Darken the part that doesn't have animation if (AnimSection->GetAnimationStartTime() > AnimSection->GetStartTime()) { float StartDarkening = AnimSection->GetStartTime(); float EndDarkening = FMath::Min(AnimSection->GetAnimationStartTime(), AnimSection->GetEndTime()); float StartPixels = TimeToPixelConverter.TimeToPixel(StartDarkening); float EndPixels = TimeToPixelConverter.TimeToPixel(EndDarkening); FSlateDrawElement::MakeBox( OutDrawElements, LayerId + 1, AllottedGeometry.ToPaintGeometry(FVector2D(StartPixels, 0), FVector2D(EndPixels - StartPixels, AllottedGeometry.Size.Y)), FEditorStyle::GetBrush("WhiteTexture"), SectionClippingRect, ESlateDrawEffect::None, FLinearColor(0.f, 0.f, 0.f, 0.3f) ); } // Add lines where the animation starts and ends/loops float CurrentTime = AnimSection->GetAnimationStartTime(); while (CurrentTime < AnimSection->GetEndTime()) { if (CurrentTime > AnimSection->GetStartTime()) { float CurrentPixels = TimeToPixelConverter.TimeToPixel(CurrentTime); TArray<FVector2D> Points; Points.Add(FVector2D(CurrentPixels, 0)); Points.Add(FVector2D(CurrentPixels, AllottedGeometry.Size.Y)); FSlateDrawElement::MakeLines( OutDrawElements, LayerId + 2, AllottedGeometry.ToPaintGeometry(), Points, SectionClippingRect ); } CurrentTime += AnimSection->GetAnimationDuration(); } return LayerId+3; }
void FSoundCueGraphConnectionDrawingPolicy::BuildAudioFlowRoadmap() { UAudioComponent* PreviewAudioComponent = GEditor->GetPreviewAudioComponent(); FAudioDevice* AudioDevice = PreviewAudioComponent ? PreviewAudioComponent->GetAudioDevice() : nullptr; if (AudioDevice) { USoundCueGraph* SoundCueGraph = CastChecked<USoundCueGraph>(GraphObj); USoundCue* SoundCue = SoundCueGraph->GetSoundCue(); if (PreviewAudioComponent && PreviewAudioComponent->IsPlaying() && PreviewAudioComponent->Sound == SoundCue) { TArray<FWaveInstance*> WaveInstances; const int32 FirstActiveIndex = AudioDevice->GetSortedActiveWaveInstances(WaveInstances, ESortedActiveWaveGetType::QueryOnly); // Run through the active instances and cull out anything that isn't related to this graph if (FirstActiveIndex > 0) { WaveInstances.RemoveAt(0, FirstActiveIndex + 1); } for (int32 WaveIndex = WaveInstances.Num() - 1; WaveIndex >= 0 ; --WaveIndex) { UAudioComponent* WaveInstanceAudioComponent = UAudioComponent::GetAudioComponentFromID(WaveInstances[WaveIndex]->ActiveSound->GetAudioComponentID()); if (WaveInstanceAudioComponent != PreviewAudioComponent) { WaveInstances.RemoveAtSwap(WaveIndex); } } for (int32 WaveIndex = 0; WaveIndex < WaveInstances.Num(); ++WaveIndex) { TArray<USoundNode*> PathToWaveInstance; if (SoundCue->FindPathToNode(WaveInstances[WaveIndex]->WaveInstanceHash, PathToWaveInstance)) { TArray<USoundCueGraphNode_Root*> RootNode; TArray<UEdGraphNode*> GraphNodes; SoundCueGraph->GetNodesOfClass<USoundCueGraphNode_Root>(RootNode); check(RootNode.Num() == 1); GraphNodes.Add(RootNode[0]); TArray<double> NodeTimes; NodeTimes.Add(FApp::GetCurrentTime()); // Time for the root node for (int32 i = 0; i < PathToWaveInstance.Num(); ++i) { const double ObservationTime = FApp::GetCurrentTime() + 1.f; NodeTimes.Add(ObservationTime); GraphNodes.Add(PathToWaveInstance[i]->GraphNode); } // Record the unique node->node pairings, keeping only the most recent times for each pairing for (int32 i = GraphNodes.Num() - 1; i >= 1; --i) { UEdGraphNode* CurNode = GraphNodes[i]; double CurNodeTime = NodeTimes[i]; UEdGraphNode* NextNode = GraphNodes[i-1]; double NextNodeTime = NodeTimes[i-1]; FExecPairingMap& Predecessors = PredecessorNodes.FindOrAdd(NextNode); // Update the timings if this is a more recent pairing FTimePair& Timings = Predecessors.FindOrAdd(CurNode); if (Timings.ThisExecTime < NextNodeTime) { Timings.PredExecTime = CurNodeTime; Timings.ThisExecTime = NextNodeTime; } } } } } } }
void FIOSTargetPlatform::GetTextureFormats( const UTexture* Texture, TArray<FName>& OutFormats ) const { check(Texture); // we remap some of the defaults (with PVRTC and ASTC formats) static FName FormatRemap[] = { // original PVRTC ASTC FName(TEXT("DXT1")), FName(TEXT("PVRTC2")), FName(TEXT("ASTC_RGB")), FName(TEXT("DXT5")), FName(TEXT("PVRTC4")), FName(TEXT("ASTC_RGBA")), FName(TEXT("DXT5n")), FName(TEXT("PVRTCN")), FName(TEXT("ASTC_NormalAG")), FName(TEXT("BC5")), FName(TEXT("PVRTCN")), FName(TEXT("ASTC_NormalRG")), FName(TEXT("AutoDXT")), FName(TEXT("AutoPVRTC")), FName(TEXT("ASTC_RGBAuto")), }; static FName NameBGRA8(TEXT("BGRA8")); static FName NamePOTERROR(TEXT("POTERROR")); FName TextureFormatName = NAME_None; // forward rendering only needs one channel for shadow maps if (Texture->LODGroup == TEXTUREGROUP_Shadowmap && !SupportsMetalMRT()) { TextureFormatName = FName(TEXT("G8")); } // if we didn't assign anything specially, then use the defaults if (TextureFormatName == NAME_None) { TextureFormatName = GetDefaultTextureFormatName(Texture, EngineSettings, false); } // perform any remapping away from defaults bool bFoundRemap = false; bool bIncludePVRTC = CookPVRTC(); bool bIncludeASTC = CookASTC(); for (int32 RemapIndex = 0; RemapIndex < ARRAY_COUNT(FormatRemap); RemapIndex += 3) { if (TextureFormatName == FormatRemap[RemapIndex]) { // we found a remapping bFoundRemap = true; // include the formats we want (use ASTC first so that it is preferred at runtime if they both exist and it's supported) if (bIncludeASTC) { OutFormats.AddUnique(FormatRemap[RemapIndex + 2]); } if (bIncludePVRTC) { // handle non-power of 2 textures if (!Texture->Source.IsPowerOfTwo()) { // option 1: Uncompress, but users will get very large textures unknowningly // OutFormats.AddUnique(NameBGRA8); // option 2: Use an "error message" texture so they see it in game OutFormats.AddUnique(NamePOTERROR); } else { OutFormats.AddUnique(FormatRemap[RemapIndex + 1]); } } } } // if we didn't already remap above, add it now if (!bFoundRemap) { OutFormats.Add(TextureFormatName); } }
TSharedRef<FAssetDragDropOp> FAssetDragDropOp::New(const FAssetData& InAssetData, UActorFactory* ActorFactory /*= NULL*/) { TArray<FAssetData> AssetDataArray; AssetDataArray.Add(InAssetData); return New(AssetDataArray, ActorFactory); }
int32 FPoly::Triangulate( ABrush* InOwnerBrush, TArray<FPoly>& OutTriangles ) { #if WITH_EDITOR if( Vertices.Num() < 3 ) { return 0; } FClipSMPolygon Polygon(0); for( int32 v = 0 ; v < Vertices.Num() ; ++v ) { FClipSMVertex vtx; vtx.Pos = Vertices[v]; // Init other data so that VertsAreEqual won't compare garbage vtx.TangentX = FVector::ZeroVector; vtx.TangentY = FVector::ZeroVector; vtx.TangentZ = FVector::ZeroVector; vtx.Color = FColor(0, 0, 0); for( int32 uvIndex=0; uvIndex<ARRAY_COUNT(vtx.UVs); ++uvIndex ) { vtx.UVs[uvIndex] = FVector2D(0.f, 0.f); } Polygon.Vertices.Add( vtx ); } Polygon.FaceNormal = Normal; // Attempt to triangulate this polygon TArray<FClipSMTriangle> Triangles; if( TriangulatePoly( Triangles, Polygon ) ) { // Create a set of FPolys from the triangles OutTriangles.Empty(); FPoly TrianglePoly; for( int32 p = 0 ; p < Triangles.Num() ; ++p ) { FClipSMTriangle* tri = &(Triangles[p]); TrianglePoly.Init(); TrianglePoly.Base = tri->Vertices[0].Pos; TrianglePoly.Vertices.Add( tri->Vertices[0].Pos ); TrianglePoly.Vertices.Add( tri->Vertices[1].Pos ); TrianglePoly.Vertices.Add( tri->Vertices[2].Pos ); if( TrianglePoly.Finalize( InOwnerBrush, 0 ) == 0 ) { OutTriangles.Add( TrianglePoly ); } } } #endif return OutTriangles.Num(); }
void FSpriteAssetTypeActions::ExecuteCreateFlipbook(TArray<TWeakObjectPtr<UPaperSprite>> Objects) { FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools"); FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser"); TArray<UPaperSprite*> AllSprites; for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) { UPaperSprite *Object = (*ObjIt).Get(); if (Object && Object->IsValidLowLevel()) { AllSprites.Add(Object); } } TMap<FString, TArray<UPaperSprite*> > SpriteFlipbookMap; FPaperFlipbookHelpers::ExtractFlipbooksFromSprites(/*out*/SpriteFlipbookMap, AllSprites, TArray<FString>()); TArray<UObject*> ObjectsToSync; if (SpriteFlipbookMap.Num() > 0) { GWarn->BeginSlowTask(NSLOCTEXT("Paper2D", "Paper2D_CreateFlipbooks", "Creating flipbooks from selection"), true, true); int Progress = 0; int TotalProgress = SpriteFlipbookMap.Num(); // Create the flipbook bool bOneFlipbookCreated = SpriteFlipbookMap.Num() == 1; for (auto Iter : SpriteFlipbookMap) { GWarn->UpdateProgress(Progress++, TotalProgress); const FString& FlipbookName = Iter.Key; TArray<UPaperSprite*> Sprites = Iter.Value; const FString SpritePathName = AllSprites[0]->GetOutermost()->GetPathName(); const FString LongPackagePath = FPackageName::GetLongPackagePath(AllSprites[0]->GetOutermost()->GetPathName()); const FString NewFlipBookDefaultPath = LongPackagePath + TEXT("/") + FlipbookName; FString DefaultSuffix; FString AssetName; FString PackageName; UPaperFlipbookFactory* FlipbookFactory = NewObject<UPaperFlipbookFactory>(); for (int32 SpriteIndex = 0; SpriteIndex < Sprites.Num(); ++SpriteIndex) { UPaperSprite* Sprite = Sprites[SpriteIndex]; FPaperFlipbookKeyFrame* KeyFrame = new (FlipbookFactory->KeyFrames) FPaperFlipbookKeyFrame(); KeyFrame->Sprite = Sprite; KeyFrame->FrameRun = 1; } AssetToolsModule.Get().CreateUniqueAssetName(NewFlipBookDefaultPath, /*out*/ DefaultSuffix, /*out*/ PackageName, /*out*/ AssetName); const FString PackagePath = FPackageName::GetLongPackagePath(PackageName); if (bOneFlipbookCreated) { ContentBrowserModule.Get().CreateNewAsset(AssetName, PackagePath, UPaperFlipbook::StaticClass(), FlipbookFactory); } else { if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(AssetName, PackagePath, UPaperFlipbook::StaticClass(), FlipbookFactory)) { ObjectsToSync.Add(NewAsset); } } if (GWarn->ReceivedUserCancel()) { break; } } GWarn->EndSlowTask(); if (ObjectsToSync.Num() > 0) { ContentBrowserModule.Get().SyncBrowserToAssets(ObjectsToSync); } } }
/** * Fill an FSkeletalMeshImportData with data from an APEX Destructible Asset. * * @param ImportData - SkeletalMesh import data into which we are extracting information * @param ApexDestructibleAsset - the Apex Destructible Asset * @param bHaveAllNormals - if the function is successful, this value is true iff every submesh has a normal channel * @param bHaveAllTangents - if the function is successful, this value is true iff every submesh has a tangent channel * * @return Boolean true iff the operation is successful */ static bool FillSkelMeshImporterFromApexDestructibleAsset(FSkeletalMeshImportData& ImportData, const NxDestructibleAsset& ApexDestructibleAsset, bool& bHaveAllNormals, bool& bHaveAllTangents) { // The APEX Destructible Asset contains an APEX Render Mesh Asset, get a pointer to this const physx::NxRenderMeshAsset* ApexRenderMesh = ApexDestructibleAsset.getRenderMeshAsset(); if (ApexRenderMesh == NULL) { return false; } if (ApexDestructibleAsset.getChunkCount() != ApexRenderMesh->getPartCount()) { UE_LOG(LogApexDestructibleAssetImport, Warning,TEXT("Chunk count does not match part count. APEX Destructible Asset with chunk instancing not yet supported.")); return false; } // Apex Render Mesh uses triangle lists only, currently. No need to triangulate. // Assume there are no vertex colors ImportData.bHasVertexColors = false; // Different submeshes can have different UV counts. Get the max. uint32 UniqueUVCount = 0; // Count vertices and triangles uint32 VertexCount = 0; uint32 TriangleCount = 0; for (uint32 SubmeshIndex = 0; SubmeshIndex < ApexRenderMesh->getSubmeshCount(); ++SubmeshIndex) { const NxRenderSubmesh& Submesh = ApexRenderMesh->getSubmesh(SubmeshIndex); const NxVertexBuffer& VB = Submesh.getVertexBuffer(); const NxVertexFormat& VBFormat = VB.getFormat(); // Count UV channels in this VB uint32 UVNum; for (UVNum = 0; UVNum < NxVertexFormat::MAX_UV_COUNT; ++UVNum) { const NxVertexFormat::BufferID BufferID = VBFormat.getSemanticID((NxRenderVertexSemantic::Enum)(NxRenderVertexSemantic::TEXCOORD0 + UVNum)); if (VBFormat.getBufferIndexFromID(BufferID) < 0) { break; } } UniqueUVCount = FMath::Max<uint32>( UniqueUVCount, UVNum ); // See if this VB has a color channel const NxVertexFormat::BufferID BufferID = VBFormat.getSemanticID(NxRenderVertexSemantic::COLOR); if (VBFormat.getBufferIndexFromID(BufferID) >= 0) { ImportData.bHasVertexColors = true; } // Count vertices VertexCount += VB.getVertexCount(); // Count triangles uint32 IndexCount = 0; for (uint32 PartIndex = 0; PartIndex < ApexRenderMesh->getPartCount(); ++PartIndex) { IndexCount += Submesh.getIndexCount(PartIndex); } check(IndexCount%3 == 0); TriangleCount += IndexCount/3; } // One UV set is required but only import up to MAX_TEXCOORDS number of uv layers ImportData.NumTexCoords = FMath::Clamp<uint32>(UniqueUVCount, 1, MAX_TEXCOORDS); // Expand buffers in ImportData: ImportData.Points.AddUninitialized(VertexCount); ImportData.Influences.AddUninitialized(VertexCount); ImportData.Wedges.AddUninitialized(3*TriangleCount); uint32 WedgeIndex = 0; ImportData.Faces.AddUninitialized(TriangleCount); uint32 TriangleIndex = 0; uint32 VertexIndexBase = 0; // True until proven otherwise bHaveAllNormals = true; bHaveAllTangents = true; TArray<VMaterial> UniqueMaterials; for (int32 CurMatIdx=0; CurMatIdx < ImportData.Materials.Num(); ++CurMatIdx) { bool bHasMaterial = false; for (int32 CurUniqueMatIdx=0; CurUniqueMatIdx < UniqueMaterials.Num(); ++CurUniqueMatIdx) { if (ImportData.Materials[CurMatIdx].MaterialName == UniqueMaterials[CurUniqueMatIdx].MaterialName) { bHasMaterial = true; break; } } if (!bHasMaterial) { UniqueMaterials.Add(ImportData.Materials[CurMatIdx]); } } // APEX render meshes are organized by submesh (render elements) // Looping through submeshes first, can be done either way for (uint32 SubmeshIndex = 0; SubmeshIndex < ApexRenderMesh->getSubmeshCount(); ++SubmeshIndex) { // Submesh data const NxRenderSubmesh& Submesh = ApexRenderMesh->getSubmesh(SubmeshIndex); const NxVertexBuffer& VB = Submesh.getVertexBuffer(); const NxVertexFormat& VBFormat = VB.getFormat(); const physx::PxU32 SubmeshVertexCount = VB.getVertexCount(); // Get VB data semantic indices: // Positions const PxI32 PositionBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID(NxRenderVertexSemantic::POSITION)); if (!VB.getBufferData(&ImportData.Points[VertexIndexBase], physx::NxRenderDataFormat::FLOAT3, sizeof(FVector), PositionBufferIndex, 0, SubmeshVertexCount)) { return false; // Need a position buffer! } #if INVERT_Y_AND_V for (uint32 VertexNum = 0; VertexNum < SubmeshVertexCount; ++VertexNum) { ImportData.Points[VertexIndexBase + VertexNum].Y *= -1.0f; } #endif // Normals const PxI32 NormalBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID(NxRenderVertexSemantic::NORMAL)); TArray<FVector> Normals; Normals.AddUninitialized(SubmeshVertexCount); const bool bHaveNormals = VB.getBufferData(Normals.GetTypedData(), physx::NxRenderDataFormat::FLOAT3, sizeof(FVector), NormalBufferIndex, 0, SubmeshVertexCount); if (!bHaveNormals) { FMemory::Memset(Normals.GetTypedData(), 0, SubmeshVertexCount*sizeof(FVector)); // Fill with zeros } // Tangents const PxI32 TangentBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID(NxRenderVertexSemantic::TANGENT)); TArray<FVector> Tangents; Tangents.AddUninitialized(SubmeshVertexCount); const bool bHaveTangents = VB.getBufferData(Tangents.GetTypedData(), physx::NxRenderDataFormat::FLOAT3, sizeof(FVector), TangentBufferIndex, 0, SubmeshVertexCount); if (!bHaveTangents) { FMemory::Memset(Tangents.GetTypedData(), 0, SubmeshVertexCount*sizeof(FVector)); // Fill with zeros } // Update bHaveAllNormals and bHaveAllTangents bHaveAllNormals = bHaveAllNormals && bHaveNormals; bHaveAllTangents = bHaveAllTangents && bHaveTangents; // Binromals const PxI32 BinormalBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID(NxRenderVertexSemantic::BINORMAL)); TArray<FVector> Binormals; Binormals.AddUninitialized(SubmeshVertexCount); bool bHaveBinormals = VB.getBufferData(Binormals.GetTypedData(), physx::NxRenderDataFormat::FLOAT3, sizeof(FVector), BinormalBufferIndex, 0, SubmeshVertexCount); if (!bHaveBinormals) { bHaveBinormals = bHaveNormals && bHaveTangents; for (uint32 i = 0; i < SubmeshVertexCount; ++i) { Binormals[i] = Normals[i]^Tangents[i]; // Build from normals and tangents. If one of these doesn't exist we'll get (0,0,0)'s } } // Colors const PxI32 ColorBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID(NxRenderVertexSemantic::COLOR)); TArray<FColor> Colors; Colors.AddUninitialized(SubmeshVertexCount); const bool bHaveColors = VB.getBufferData(Colors.GetTypedData(), physx::NxRenderDataFormat::B8G8R8A8, sizeof(FColor), ColorBufferIndex, 0, SubmeshVertexCount); if (!bHaveColors) { FMemory::Memset(Colors.GetTypedData(), 0xFF, SubmeshVertexCount*sizeof(FColor)); // Fill with 0xFF } // UVs TArray<FVector2D> UVs[NxVertexFormat::MAX_UV_COUNT]; for (uint32 UVNum = 0; UVNum < ImportData.NumTexCoords; ++UVNum) { const PxI32 UVBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID((NxRenderVertexSemantic::Enum)(NxRenderVertexSemantic::TEXCOORD0 + UVNum))); UVs[UVNum].AddUninitialized(SubmeshVertexCount); if (!VB.getBufferData(&UVs[UVNum][0].X, physx::NxRenderDataFormat::FLOAT2, sizeof(FVector2D), UVBufferIndex, 0, SubmeshVertexCount)) { FMemory::Memset(&UVs[UVNum][0].X, 0, SubmeshVertexCount*sizeof(FVector2D)); // Fill with zeros } } // Bone indices will not be imported - they're implicitly the PartIndex // Each submesh is partitioned into parts. Currently we're assuming a 1-1 correspondence between chunks and parts, // which means that instanced chunks are not supported. However, we will not assume that the chunk and part ordering is the same. // Therefore, instead of looping through parts, we loop through chunks here, and get the part index. for (uint32 ChunkIndex = 0; ChunkIndex < ApexDestructibleAsset.getChunkCount(); ++ChunkIndex) { const physx::PxU32 PartIndex = ApexDestructibleAsset.getPartIndex(ChunkIndex); const physx::PxU32* PartIndexBuffer = Submesh.getIndexBuffer(PartIndex); const physx::PxU32* PartIndexBufferStop = PartIndexBuffer + Submesh.getIndexCount(PartIndex); while (PartIndexBuffer < PartIndexBufferStop) { physx::PxU32 SubmeshVertexIndex[3]; #if !INVERT_Y_AND_V SubmeshVertexIndex[2] = *PartIndexBuffer++; SubmeshVertexIndex[1] = *PartIndexBuffer++; SubmeshVertexIndex[0] = *PartIndexBuffer++; #else SubmeshVertexIndex[0] = *PartIndexBuffer++; SubmeshVertexIndex[1] = *PartIndexBuffer++; SubmeshVertexIndex[2] = *PartIndexBuffer++; #endif // Fill triangle VTriangle& Triangle = ImportData.Faces[TriangleIndex++]; // set the face smoothing by default. It could be any number, but not zero Triangle.SmoothingGroups = 255; // Material index int32 MatIdx = 0; check(ImportData.Materials.Num() > 0); if (SubmeshIndex < (uint32)ImportData.Materials.Num()) { const FString& MaterialName = ImportData.Materials[SubmeshIndex].MaterialName; for (int32 UniqueMaterialIdx = 0; UniqueMaterialIdx < UniqueMaterials.Num(); ++UniqueMaterialIdx) { if (UniqueMaterials[UniqueMaterialIdx].MaterialName == MaterialName) { MatIdx = UniqueMaterialIdx; break; } } } Triangle.MatIndex = MatIdx; Triangle.AuxMatIndex = 0; // Per-vertex for (uint32 V = 0; V < 3; ++V) { // Tangent basis Triangle.TangentX[V] = Binormals[SubmeshVertexIndex[V]]; Triangle.TangentY[V] = Tangents[SubmeshVertexIndex[V]]; Triangle.TangentZ[V] = Normals[SubmeshVertexIndex[V]]; #if INVERT_Y_AND_V Triangle.TangentX[V].Y *= -1.0f; Triangle.TangentY[V].Y *= -1.0f; Triangle.TangentZ[V].Y *= -1.0f; #endif // Wedges Triangle.WedgeIndex[V] = WedgeIndex; VVertex& Wedge = ImportData.Wedges[WedgeIndex++]; Wedge.VertexIndex = VertexIndexBase + SubmeshVertexIndex[V]; Wedge.MatIndex = Triangle.MatIndex; Wedge.Color = Colors[SubmeshVertexIndex[V]]; Wedge.Reserved = 0; for (uint32 UVNum = 0; UVNum < ImportData.NumTexCoords; ++UVNum) { const FVector2D& UV = UVs[UVNum][SubmeshVertexIndex[V]]; #if !INVERT_Y_AND_V Wedge.UVs[UVNum] = UV; #else Wedge.UVs[UVNum] = FVector2D(UV.X, 1.0f-UV.Y); #endif } } } // Bone influences const physx::PxU32 PartVertexStart = Submesh.getFirstVertexIndex(PartIndex); const physx::PxU32 PartVertexStop = PartVertexStart + Submesh.getVertexCount(PartIndex); for (uint32 PartVertexIndex = PartVertexStart; PartVertexIndex < PartVertexStop; ++PartVertexIndex) { const physx::PxU32 VertexIndex = VertexIndexBase + PartVertexIndex; // Note, by using ChunkIndex instead of PartInedx we are effectively setting PartIndex = ChunkIndex, which is OK since we won't be supporting instancing with the SkeletalMesh. ImportData.Influences[VertexIndex].BoneIndex = ChunkIndex + 1; // Adding 1, since the 0 bone will have no geometry from the Apex Destructible Asset. ImportData.Influences[VertexIndex].Weight = 1.0; ImportData.Influences[VertexIndex].VertexIndex = VertexIndex; } } VertexIndexBase += SubmeshVertexCount; } // Switch material arrays so we have a list with unique materials ImportData.Materials = UniqueMaterials; // Create mapping from import to raw- @TODO trivial at the moment, do we need this info for destructibles? ImportData.PointToRawMap.AddUninitialized(ImportData.Points.Num()); for(int32 PointIdx=0; PointIdx<ImportData.PointToRawMap.Num(); PointIdx++) { ImportData.PointToRawMap[PointIdx] = PointIdx; } return true; }
TSharedRef<SWidget> FLevelViewportLayout2x2::MakeViewportLayout(const FString& LayoutString) { FString SpecificLayoutString = GetTypeSpecificLayoutString(LayoutString); TSharedPtr< SLevelViewport > ViewportWidgetTL; TSharedPtr< SLevelViewport > ViewportWidgetTR; TSharedPtr< SLevelViewport > ViewportWidgetBL; TSharedPtr< SLevelViewport > ViewportWidgetBR; FString TopLeftKey, BottomLeftKey, TopRightKey, BottomRightKey; TArray<FVector2D> SplitterPercentages; if (!SpecificLayoutString.IsEmpty()) { // The Layout String only holds the unique ID of the Additional Layout Configs to use const FString& IniSection = FLayoutSaveRestore::GetAdditionalLayoutConfigIni(); TopLeftKey = SpecificLayoutString + TEXT(".Viewport0"); BottomLeftKey = SpecificLayoutString + TEXT(".Viewport1"); TopRightKey = SpecificLayoutString + TEXT(".Viewport2"); BottomRightKey = SpecificLayoutString + TEXT(".Viewport3"); for (int32 i = 0; i < 4; ++i) { FString PercentageString; FVector2D NewPercentage = ViewportLayout2x2Defs::DefaultSplitterPercentages; if(GConfig->GetString(*IniSection, *(SpecificLayoutString + FString::Printf(TEXT(".Percentages%i"), i)), PercentageString, GEditorUserSettingsIni)) { NewPercentage.InitFromString(PercentageString); } SplitterPercentages.Add(NewPercentage); } } SplitterWidget = SNew( SSplitter2x2 ) .TopLeft() [ SAssignNew( ViewportWidgetTL, SLevelViewport ) .ViewportType( LVT_OrthoYZ ) // Side .ParentLayout( AsShared() ) .ParentLevelEditor( ParentLevelEditor ) .ConfigKey( TopLeftKey ) ] .BottomLeft() [ SAssignNew( ViewportWidgetBL, SLevelViewport ) .ViewportType( LVT_Perspective ) // Persp .Realtime( true ) .ParentLayout( AsShared() ) .ParentLevelEditor( ParentLevelEditor ) .ConfigKey( BottomLeftKey ) ] .TopRight() [ SAssignNew( ViewportWidgetTR, SLevelViewport ) .ViewportType( LVT_OrthoXZ ) // Front .ParentLayout( AsShared() ) .ParentLevelEditor( ParentLevelEditor ) .ConfigKey( TopRightKey ) ] .BottomRight() [ SAssignNew( ViewportWidgetBR, SLevelViewport ) .ViewportType( LVT_OrthoXY ) // Top .ParentLayout( AsShared() ) .ParentLevelEditor( ParentLevelEditor ) .ConfigKey( BottomRightKey ) ]; Viewports.Add( ViewportWidgetTL ); Viewports.Add( ViewportWidgetBL ); Viewports.Add( ViewportWidgetTR ); Viewports.Add( ViewportWidgetBR ); // Make newly-created perspective viewports active by default GCurrentLevelEditingViewportClient = &ViewportWidgetBL->GetLevelViewportClient(); if (SplitterPercentages.Num() > 0) { SplitterWidget->SetSplitterPercentages(SplitterPercentages); } InitCommonLayoutFromString(SpecificLayoutString); return SplitterWidget.ToSharedRef(); }
void FStatsMemoryDumpCommand::ProcessMemoryOperations( const TMap<int64, FStatPacketArray>& CombinedHistory ) { // This is only example code, no fully implemented, may sometimes crash. // This code is not optimized. double PreviousSeconds = FPlatformTime::Seconds(); uint64 NumMemoryOperations = 0; // Generate frames TArray<int64> Frames; CombinedHistory.GenerateKeyArray( Frames ); Frames.Sort(); // Raw stats callstack for this stat packet array. TMap<FName, FStackState> StackStates; // All allocation ordered by the sequence tag. // There is an assumption that the sequence tag will not turn-around. //TMap<uint32, FAllocationInfo> SequenceAllocationMap; TArray<FAllocationInfo> SequenceAllocationArray; // Pass 1. // Read all stats messages, parse all memory operations and decode callstacks. const int64 FirstFrame = 0; PreviousSeconds -= NumSecondsBetweenLogs; for( int32 FrameIndex = 0; FrameIndex < Frames.Num(); ++FrameIndex ) { { const double CurrentSeconds = FPlatformTime::Seconds(); if( CurrentSeconds > PreviousSeconds + NumSecondsBetweenLogs ) { UE_LOG( LogStats, Warning, TEXT( "Processing frame %i/%i" ), FrameIndex+1, Frames.Num() ); PreviousSeconds = CurrentSeconds; } } const int64 TargetFrame = Frames[FrameIndex]; const int64 Diff = TargetFrame - FirstFrame; const FStatPacketArray& Frame = CombinedHistory.FindChecked( TargetFrame ); bool bAtLeastOnePacket = false; for( int32 PacketIndex = 0; PacketIndex < Frame.Packets.Num(); PacketIndex++ ) { { const double CurrentSeconds = FPlatformTime::Seconds(); if( CurrentSeconds > PreviousSeconds + NumSecondsBetweenLogs ) { UE_LOG( LogStats, Log, TEXT( "Processing packet %i/%i" ), PacketIndex, Frame.Packets.Num() ); PreviousSeconds = CurrentSeconds; bAtLeastOnePacket = true; } } const FStatPacket& StatPacket = *Frame.Packets[PacketIndex]; const FName& ThreadFName = StatsThreadStats.Threads.FindChecked( StatPacket.ThreadId ); FStackState* StackState = StackStates.Find( ThreadFName ); if( !StackState ) { StackState = &StackStates.Add( ThreadFName ); StackState->Stack.Add( ThreadFName ); StackState->Current = ThreadFName; } const FStatMessagesArray& Data = StatPacket.StatMessages; int32 LastPct = 0; const int32 NumDataElements = Data.Num(); const int32 OnerPercent = FMath::Max( NumDataElements / 100, 1024 ); bool bAtLeastOneMessage = false; for( int32 Index = 0; Index < NumDataElements; Index++ ) { if( Index % OnerPercent ) { const double CurrentSeconds = FPlatformTime::Seconds(); if( CurrentSeconds > PreviousSeconds + NumSecondsBetweenLogs ) { const int32 CurrentPct = int32( 100.0*(Index + 1) / NumDataElements ); UE_LOG( LogStats, Log, TEXT( "Processing %3i%% (%i/%i) stat messages" ), CurrentPct, Index, NumDataElements ); PreviousSeconds = CurrentSeconds; bAtLeastOneMessage = true; } } const FStatMessage& Item = Data[Index]; const EStatOperation::Type Op = Item.NameAndInfo.GetField<EStatOperation>(); const FName RawName = Item.NameAndInfo.GetRawName(); if( Op == EStatOperation::CycleScopeStart || Op == EStatOperation::CycleScopeEnd || Op == EStatOperation::Memory ) { if( Op == EStatOperation::CycleScopeStart ) { StackState->Stack.Add( RawName ); StackState->Current = RawName; } else if( Op == EStatOperation::Memory ) { // Experimental code used only to test the implementation. // First memory operation is Alloc or Free const uint64 EncodedPtr = Item.GetValue_Ptr(); const bool bIsAlloc = (EncodedPtr & (uint64)EMemoryOperation::Alloc) != 0; const bool bIsFree = (EncodedPtr & (uint64)EMemoryOperation::Free) != 0; const uint64 Ptr = EncodedPtr & ~(uint64)EMemoryOperation::Mask; if( bIsAlloc ) { NumMemoryOperations++; // @see FStatsMallocProfilerProxy::TrackAlloc // After alloc ptr message there is always alloc size message and the sequence tag. Index++; const FStatMessage& AllocSizeMessage = Data[Index]; const int64 AllocSize = AllocSizeMessage.GetValue_int64(); // Read operation sequence tag. Index++; const FStatMessage& SequenceTagMessage = Data[Index]; const uint32 SequenceTag = SequenceTagMessage.GetValue_int64(); // Create a callstack. TArray<FName> StatsBasedCallstack; for( const auto& StackName : StackState->Stack ) { StatsBasedCallstack.Add( StackName ); } // Add a new allocation. SequenceAllocationArray.Add( FAllocationInfo( Ptr, AllocSize, StatsBasedCallstack, SequenceTag, EMemoryOperation::Alloc, StackState->bIsBrokenCallstack ) ); } else if( bIsFree ) { NumMemoryOperations++; // Read operation sequence tag. Index++; const FStatMessage& SequenceTagMessage = Data[Index]; const uint32 SequenceTag = SequenceTagMessage.GetValue_int64(); // Create a callstack. /* TArray<FName> StatsBasedCallstack; for( const auto& RawName : StackState->Stack ) { StatsBasedCallstack.Add( RawName ); } */ // Add a new free. SequenceAllocationArray.Add( FAllocationInfo( Ptr, 0, TArray<FName>()/*StatsBasedCallstack*/, SequenceTag, EMemoryOperation::Free, StackState->bIsBrokenCallstack ) ); } else { UE_LOG( LogStats, Warning, TEXT( "Pointer from a memory operation is invalid" ) ); } } else if( Op == EStatOperation::CycleScopeEnd ) { if( StackState->Stack.Num() > 1 ) { const FName ScopeStart = StackState->Stack.Pop(); const FName ScopeEnd = Item.NameAndInfo.GetRawName(); check( ScopeStart == ScopeEnd ); StackState->Current = StackState->Stack.Last(); // The stack should be ok, but it may be partially broken. // This will happen if memory profiling starts in the middle of executing a background thread. StackState->bIsBrokenCallstack = false; } else { const FName ShortName = Item.NameAndInfo.GetShortName(); UE_LOG( LogStats, Warning, TEXT( "Broken cycle scope end %s/%s, current %s" ), *ThreadFName.ToString(), *ShortName.ToString(), *StackState->Current.ToString() ); // The stack is completely broken, only has the thread name and the last cycle scope. // Rollback to the thread node. StackState->bIsBrokenCallstack = true; StackState->Stack.Empty(); StackState->Stack.Add( ThreadFName ); StackState->Current = ThreadFName; } } } } if( bAtLeastOneMessage ) { PreviousSeconds -= NumSecondsBetweenLogs; } } if( bAtLeastOnePacket ) { PreviousSeconds -= NumSecondsBetweenLogs; } } UE_LOG( LogStats, Warning, TEXT( "NumMemoryOperations: %llu" ), NumMemoryOperations ); UE_LOG( LogStats, Warning, TEXT( "SequenceAllocationNum: %i" ), SequenceAllocationArray.Num() ); // Pass 2. /* TMap<uint32,FAllocationInfo> UniqueSeq; TMultiMap<uint32,FAllocationInfo> OriginalAllocs; TMultiMap<uint32,FAllocationInfo> BrokenAllocs; for( const FAllocationInfo& Alloc : SequenceAllocationArray ) { const FAllocationInfo* Found = UniqueSeq.Find(Alloc.SequenceTag); if( !Found ) { UniqueSeq.Add(Alloc.SequenceTag,Alloc); } else { OriginalAllocs.Add(Alloc.SequenceTag, *Found); BrokenAllocs.Add(Alloc.SequenceTag, Alloc); } } */ // Sort all memory operation by the sequence tag, iterate through all operation and generate memory usage. SequenceAllocationArray.Sort( TLess<FAllocationInfo>() ); // Alive allocations. TMap<uint64, FAllocationInfo> AllocationMap; TMultiMap<uint64, FAllocationInfo> FreeWithoutAllocMap; TMultiMap<uint64, FAllocationInfo> DuplicatedAllocMap; int32 NumDuplicatedMemoryOperations = 0; int32 NumFWAMemoryOperations = 0; // FreeWithoutAlloc UE_LOG( LogStats, Warning, TEXT( "Generating memory operations map" ) ); const int32 NumSequenceAllocations = SequenceAllocationArray.Num(); const int32 OnePercent = FMath::Max( NumSequenceAllocations / 100, 1024 ); for( int32 Index = 0; Index < NumSequenceAllocations; Index++ ) { if( Index % OnePercent ) { const double CurrentSeconds = FPlatformTime::Seconds(); if( CurrentSeconds > PreviousSeconds + NumSecondsBetweenLogs ) { const int32 CurrentPct = int32( 100.0*(Index + 1) / NumSequenceAllocations ); UE_LOG( LogStats, Log, TEXT( "Processing allocations %3i%% (%10i/%10i)" ), CurrentPct, Index + 1, NumSequenceAllocations ); PreviousSeconds = CurrentSeconds; } } const FAllocationInfo& Alloc = SequenceAllocationArray[Index]; const EMemoryOperation MemOp = Alloc.Op; const uint64 Ptr = Alloc.Ptr; const int64 Size = Alloc.Size; const uint32 SequenceTag = Alloc.SequenceTag; if( MemOp == EMemoryOperation::Alloc ) { const FAllocationInfo* Found = AllocationMap.Find( Ptr ); if( !Found ) { AllocationMap.Add( Ptr, Alloc ); } else { const FAllocationInfo* FoundAndFreed = FreeWithoutAllocMap.Find( Found->Ptr ); const FAllocationInfo* FoundAndAllocated = FreeWithoutAllocMap.Find( Alloc.Ptr ); #if _DEBUG if( FoundAndFreed ) { const FString FoundAndFreedCallstack = GetCallstack( FoundAndFreed->EncodedCallstack ); } if( FoundAndAllocated ) { const FString FoundAndAllocatedCallstack = GetCallstack( FoundAndAllocated->EncodedCallstack ); } NumDuplicatedMemoryOperations++; const FString FoundCallstack = GetCallstack( Found->EncodedCallstack ); const FString AllocCallstack = GetCallstack( Alloc.EncodedCallstack ); #endif // _DEBUG // Replace pointer. AllocationMap.Add( Ptr, Alloc ); // Store the old pointer. DuplicatedAllocMap.Add( Ptr, *Found ); } } else if( MemOp == EMemoryOperation::Free ) { const FAllocationInfo* Found = AllocationMap.Find( Ptr ); if( Found ) { const bool bIsValid = Alloc.SequenceTag > Found->SequenceTag; if( !bIsValid ) { UE_LOG( LogStats, Warning, TEXT( "InvalidFree Ptr: %llu, Seq: %i/%i" ), Ptr, SequenceTag, Found->SequenceTag ); } AllocationMap.Remove( Ptr ); } else { FreeWithoutAllocMap.Add( Ptr, Alloc ); NumFWAMemoryOperations++; } } } UE_LOG( LogStats, Warning, TEXT( "NumDuplicatedMemoryOperations: %i" ), NumDuplicatedMemoryOperations ); UE_LOG( LogStats, Warning, TEXT( "NumFWAMemoryOperations: %i" ), NumFWAMemoryOperations ); // Dump problematic allocations DuplicatedAllocMap.ValueSort( FAllocationInfoGreater() ); //FreeWithoutAllocMap uint64 TotalDuplicatedMemory = 0; for( const auto& It : DuplicatedAllocMap ) { const FAllocationInfo& Alloc = It.Value; TotalDuplicatedMemory += Alloc.Size; } UE_LOG( LogStats, Warning, TEXT( "Dumping duplicated alloc map" ) ); const float MaxPctDisplayed = 0.80f; uint64 DisplayedSoFar = 0; for( const auto& It : DuplicatedAllocMap ) { const FAllocationInfo& Alloc = It.Value; const FString AllocCallstack = GetCallstack( Alloc.EncodedCallstack ); UE_LOG( LogStats, Log, TEXT( "%lli (%.2f MB) %s" ), Alloc.Size, Alloc.Size / 1024.0f / 1024.0f, *AllocCallstack ); DisplayedSoFar += Alloc.Size; const float CurrentPct = (float)DisplayedSoFar / (float)TotalDuplicatedMemory; if( CurrentPct > MaxPctDisplayed ) { break; } } GenerateMemoryUsageReport( AllocationMap ); }
bool FPerfCounters::Tick(float DeltaTime) { // if we didn't get a socket, don't tick if (Socket == nullptr) { return false; } // accept any connections static const FString PerfCounterRequest = TEXT("FPerfCounters Request"); FSocket* IncomingConnection = Socket->Accept(PerfCounterRequest); if (IncomingConnection) { if (0) { TSharedRef<FInternetAddr> FromAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); IncomingConnection->GetPeerAddress(*FromAddr); UE_LOG(LogPerfCounters, Log, TEXT("New connection from %s"), *FromAddr->ToString(true)); } // make sure this is non-blocking IncomingConnection->SetNonBlocking(true); new (Connections) FPerfConnection(IncomingConnection); } TArray<FPerfConnection> ConnectionsToClose; for (FPerfConnection& Connection : Connections) { FSocket* ExistingSocket = Connection.Connection; if (ExistingSocket && ExistingSocket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::Zero())) { // read any data that's ready // NOTE: this is not a full HTTP implementation, just enough to be usable by curl uint8 Buffer[2 * 1024] = { 0 }; int32 DataLen = 0; if (ExistingSocket->Recv(Buffer, sizeof(Buffer) - 1, DataLen, ESocketReceiveFlags::None)) { FResponse Response; if (ProcessRequest(Buffer, DataLen, Response)) { if (SendAsUtf8(ExistingSocket, Response.Header)) { if (!SendAsUtf8(ExistingSocket, Response.Body)) { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send full HTTP response body")); } } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send HTTP response header: %s"), *Response.Header); } } } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to immediately receive request header")); } ConnectionsToClose.Add(Connection); } else if (Connection.ElapsedTime > 5.0f) { ConnectionsToClose.Add(Connection); } Connection.ElapsedTime += DeltaTime; } for (FPerfConnection& Connection : ConnectionsToClose) { Connections.RemoveSingleSwap(Connection); FSocket* ClosingSocket = Connection.Connection; if (ClosingSocket) { // close the socket (whether we processed or not) ClosingSocket->Close(); ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ClosingSocket); if (0) { UE_LOG(LogPerfCounters, Log, TEXT("Closed connection.")); } } } // keep ticking return true; }
UObject* UFactory::StaticImportObject ( UClass* Class, UObject* InOuter, FName Name, EObjectFlags Flags, bool& bOutOperationCanceled, const TCHAR* Filename, UObject* Context, UFactory* InFactory, const TCHAR* Parms, FFeedbackContext* Warn, int32 MaxImportFileSize ) { check(Class); CurrentFilename = Filename; // Make list of all applicable factories. TArray<UFactory*> Factories; if( InFactory ) { // Use just the specified factory. if (ensureMsgf( !InFactory->SupportedClass || Class->IsChildOf(InFactory->SupportedClass), TEXT("Factory is (%s), SupportedClass is (%s) and Class name is (%s)"), *InFactory->GetName(), (InFactory->SupportedClass)? *InFactory->SupportedClass->GetName() : TEXT("None"), *Class->GetName() )) { Factories.Add( InFactory ); } } else { auto TransientPackage = GetTransientPackage(); // Try all automatic factories, sorted by priority. for( TObjectIterator<UClass> It; It; ++It ) { if( It->IsChildOf( UFactory::StaticClass() ) ) { UFactory* Default = It->GetDefaultObject<UFactory>(); if (Class->IsChildOf(Default->SupportedClass) && Default->ImportPriority >= 0) { Factories.Add(NewObject<UFactory>(TransientPackage, *It)); } } } Factories.Sort([](const UFactory& A, const UFactory& B) -> bool { // First sort so that higher priorities are earlier in the list if( A.ImportPriority > B.ImportPriority ) { return true; } else if( A.ImportPriority < B.ImportPriority ) { return false; } // Then sort so that factories that only create new assets are tried after those that actually import the file data (when they have an equivalent priority) const bool bFactoryAImportsFiles = !A.CanCreateNew(); const bool bFactoryBImportsFiles = !B.CanCreateNew(); if( bFactoryAImportsFiles && !bFactoryBImportsFiles ) { return true; } return false; }); } bool bLoadedFile = false; // Try each factory in turn. for( int32 i=0; i<Factories.Num(); i++ ) { UFactory* Factory = Factories[i]; UObject* Result = NULL; if( Factory->CanCreateNew() ) { UE_LOG(LogFactory, Log, TEXT("FactoryCreateNew: %s with %s (%i %i %s)"), *Class->GetName(), *Factories[i]->GetClass()->GetName(), Factory->bCreateNew, Factory->bText, Filename ); Factory->ParseParms( Parms ); Result = Factory->FactoryCreateNew( Class, InOuter, Name, Flags, NULL, Warn ); } else if( FCString::Stricmp(Filename,TEXT(""))!=0 ) { if( Factory->bText ) { //UE_LOG(LogFactory, Log, TEXT("FactoryCreateText: %s with %s (%i %i %s)"), *Class->GetName(), *Factories(i)->GetClass()->GetName(), Factory->bCreateNew, Factory->bText, Filename ); FString Data; if( FFileHelper::LoadFileToString( Data, Filename ) ) { bLoadedFile = true; const TCHAR* Ptr = *Data; Factory->ParseParms( Parms ); Result = Factory->FactoryCreateText( Class, InOuter, Name, Flags, NULL, *FPaths::GetExtension(Filename), Ptr, Ptr+Data.Len(), Warn ); } } else { UE_LOG(LogFactory, Log, TEXT("FactoryCreateBinary: %s with %s (%i %i %s)"), *Class->GetName(), *Factories[i]->GetClass()->GetName(), Factory->bCreateNew, Factory->bText, Filename ); // Sanity check the file size of the impending import and prompt the user if they wish to continue if the file size is very large const int32 FileSize = IFileManager::Get().FileSize( Filename ); bool bValidFileSize = true; if ( FileSize == INDEX_NONE ) { UE_LOG(LogFactory, Error,TEXT("File '%s' does not exist"), Filename ); bValidFileSize = false; } TArray<uint8> Data; if( bValidFileSize && FFileHelper::LoadFileToArray( Data, Filename ) ) { bLoadedFile = true; Data.Add( 0 ); const uint8* Ptr = &Data[ 0 ]; Factory->ParseParms( Parms ); Result = Factory->FactoryCreateBinary( Class, InOuter, Name, Flags, NULL, *FPaths::GetExtension(Filename), Ptr, Ptr+Data.Num()-1, Warn, bOutOperationCanceled ); } } } if( Result ) { // prevent UTextureCube created from UTextureFactory check(Result->IsA(Class)); Result->MarkPackageDirty(); ULevel::LevelDirtiedEvent.Broadcast(); Result->PostEditChange(); CurrentFilename = TEXT(""); return Result; } } if ( !bLoadedFile && !bOutOperationCanceled ) { Warn->Logf( *FText::Format( NSLOCTEXT( "UnrealEd", "NoFindImport", "Can't find file '{0}' for import" ), FText::FromString( FString(Filename) ) ).ToString() ); } CurrentFilename = TEXT(""); return NULL; }
bool FCollection::CheckoutCollection(FText& OutError) { if ( !ensure(SourceFilename.Len()) ) { OutError = LOCTEXT("Error_Internal", "There was an internal error."); return false; } ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); if ( !ISourceControlModule::Get().IsEnabled() ) { OutError = LOCTEXT("Error_SCCDisabled", "Source control is not enabled. Enable source control in the preferences menu."); return false; } if ( !SourceControlProvider.IsAvailable() ) { OutError = LOCTEXT("Error_SCCNotAvailable", "Source control is currently not available. Check your connection and try again."); return false; } FString AbsoluteFilename = FPaths::ConvertRelativePathToFull(SourceFilename); FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(AbsoluteFilename, EStateCacheUsage::ForceUpdate); bool bSuccessfullyCheckedOut = false; TArray<FString> FilesToBeCheckedOut; FilesToBeCheckedOut.Add(AbsoluteFilename); if (SourceControlState.IsValid() && SourceControlState->IsDeleted()) { // Revert our delete if ( !RevertCollection(OutError) ) { return false; } // Make sure we get a fresh state from the server SourceControlState = SourceControlProvider.GetState(AbsoluteFilename, EStateCacheUsage::ForceUpdate); } // If not at the head revision, sync up if (SourceControlState.IsValid() && !SourceControlState->IsCurrent()) { if ( !SourceControlProvider.Execute(ISourceControlOperation::Create<FSync>(), FilesToBeCheckedOut) ) { // Could not sync up with the head revision OutError = LOCTEXT("Error_SCCSync", "Failed to sync collection to the head revision."); return false; } // Check to see if the file exists at the head revision if ( IFileManager::Get().FileSize(*SourceFilename) < 0 ) { // File was deleted at head... // Just add our changes to an empty list so we can mark it for add FCollection NewCollection; MergeWithCollection(NewCollection); } else { // File found! Load it and merge with our local changes FCollection NewCollection; if ( !NewCollection.LoadFromFile(SourceFilename, false) ) { // Failed to load the head revision file so it isn't safe to delete it OutError = LOCTEXT("Error_SCCBadHead", "Failed to load the collection at the head revision."); return false; } // Loaded the head revision, now merge up so the files are in a consistent state MergeWithCollection(NewCollection); } // Make sure we get a fresh state from the server SourceControlState = SourceControlProvider.GetState(AbsoluteFilename, EStateCacheUsage::ForceUpdate); } if(SourceControlState.IsValid()) { if(SourceControlState->IsAdded() || SourceControlState->IsCheckedOut()) { // Already checked out or opened for add bSuccessfullyCheckedOut = true; } else if(SourceControlState->CanCheckout()) { // In depot and needs to be checked out bSuccessfullyCheckedOut = (SourceControlProvider.Execute(ISourceControlOperation::Create<FCheckOut>(), FilesToBeCheckedOut) == ECommandResult::Succeeded); if (!bSuccessfullyCheckedOut) { OutError = LOCTEXT("Error_SCCCheckout", "Failed to check out collection."); } } else if(!SourceControlState->IsSourceControlled()) { // Not yet in the depot. Add it. bSuccessfullyCheckedOut = (SourceControlProvider.Execute(ISourceControlOperation::Create<FMarkForAdd>(), FilesToBeCheckedOut) == ECommandResult::Succeeded); if (!bSuccessfullyCheckedOut) { OutError = LOCTEXT("Error_SCCAdd", "Failed to add new collection to source control."); } } else if(!SourceControlState->IsCurrent()) { OutError = LOCTEXT("Error_SCCNotCurrent", "Collection is not at head revision after sync."); } else if(SourceControlState->IsCheckedOutOther()) { OutError = LOCTEXT("Error_SCCCheckedOutOther", "Collection is checked out by another user."); } else { OutError = LOCTEXT("Error_SCCUnknown", "Could not determine source control state."); } } else { OutError = LOCTEXT("Error_SCCInvalid", "Source control state is invalid."); } return bSuccessfullyCheckedOut; }
int32 UGridMesher::buildNewMesh(const TArray<float>& vertexRadii, const TArray<FColor>& vertexColors, const TArray<FVector>& vertexNormals, UMaterialInterface* newMeshMaterial, int32 meshToRebuild /*= -1 if we're to build a new mesh*/) { /*void CreateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0, const TArray<FColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents, bool bCreateCollision);*/ bool calcNormals = vertexNormals.Num() == 0; TArray<FVector> Vertices; TArray<int32> Triangles; TArray<FVector> Normals; TArray<FVector2D> UV0; TArray<FProcMeshTangent> Tangents; if (debugTextOutArray.Num() != 0) { for (USceneComponent* debugText : debugTextOutArray) { debugText->DetachFromParent(); debugText->DestroyComponent(); } } debugLineOut->Flush(); for (const FRectGridLocation& gridLoc : myGrid->gridLocationsM) { FVector tilePos = myGrid->getNodeLocationOnSphere(gridLoc); Vertices.Add(tilePos * vertexRadii[gridLoc.tileIndex]); if (calcNormals) { FVector vertexNormal = calculateVertexNormal(gridLoc, vertexRadii); Normals.Add(vertexNormal); } else { Normals.Add(vertexNormals[gridLoc.tileIndex]); } if (renderNodes) { debugLineOut->DrawPoint(tilePos * baseMeshRadius, FLinearColor::Blue, 8, 2); } if (renderNodeIndexes) { UTextRenderComponent* nodeTextId = NewObject<UTextRenderComponent>(this); nodeTextId->RegisterComponent(); nodeTextId->SetRelativeLocation(tilePos * (baseMeshRadius*1.01)); nodeTextId->SetText(FText::FromString(FString::FromInt(gridLoc.tileIndex))); nodeTextId->SetTextRenderColor(FColor::Red); nodeTextId->SetWorldSize(baseMeshRadius / 50.0f); FVector xAxis(1.0, 0.0, 0.0); FRotator textRotator = Normals[gridLoc.tileIndex].Rotation() - xAxis.Rotation(); nodeTextId->AddRelativeRotation(textRotator); nodeTextId->AttachTo(this); debugTextOutArray.Add(nodeTextId); } } for (int32 uLoc = 0; uLoc < myGrid->rectilinearGridM.Num(); ++uLoc) { for (int32 vLoc = 0; vLoc <= myGrid->gridFrequency * 2; ++vLoc) { if (vLoc != myGrid->gridFrequency * 2) { //upperTriangle int32 vertU = uLoc; int32 vertV = vLoc; Triangles.Add(myGrid->rectilinearGridM[vertU][vertV]); ++vertV; Triangles.Add(myGrid->rectilinearGridM[vertU][vertV]); --vertV; myGrid->decrementU(vertU, vertV); Triangles.Add(myGrid->rectilinearGridM[vertU][vertV]); } if (vLoc != 0) { //lowerTriangle int32 vertU = uLoc; int32 vertV = vLoc; Triangles.Add(myGrid->rectilinearGridM[vertU][vertV]); myGrid->decrementU(vertU, vertV); Triangles.Add(myGrid->rectilinearGridM[vertU][vertV]); --vertV; Triangles.Add(myGrid->rectilinearGridM[vertU][vertV]); } } } int32 targetMeshNum = numMeshes; if (meshToRebuild != -1) { targetMeshNum = meshToRebuild; } CreateMeshSection(targetMeshNum, Vertices, Triangles, Normals, UV0, vertexColors, Tangents, false); SetMaterial(targetMeshNum, newMeshMaterial); if (meshToRebuild != -1) { ++numMeshes; } return targetMeshNum; }
int32 UObjectLibrary::LoadBlueprintAssetDataFromPaths(const TArray<FString>& Paths, bool bForceSynchronousScan) { FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")); IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); if (!bHasBlueprintClasses) { return 0; } #if WITH_EDITOR // Cooked data has the asset data already set up const bool bShouldDoSynchronousScan = !bIsGlobalAsyncScanEnvironment || bForceSynchronousScan; if ( bShouldDoSynchronousScan ) { AssetRegistry.ScanPathsSynchronous(Paths); } else { if ( AssetRegistry.IsLoadingAssets() ) { // Keep track of the paths we asked for so once assets are discovered we will refresh the list for (const FString& Path : Paths) { DeferredAssetDataPaths.AddUnique(Path); } } } #endif FARFilter ARFilter; ARFilter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); for (int PathIndex = 0; PathIndex < Paths.Num(); PathIndex++) { ARFilter.PackagePaths.Add(FName(*Paths[PathIndex])); } ARFilter.bRecursivePaths = true; ARFilter.bIncludeOnlyOnDiskAssets = true; /* GetDerivedClassNames doesn't work yet if ( ObjectBaseClass ) { TArray<FName> SearchClassNames; TSet<FName> ExcludedClassNames; TSet<FName> DerivedClassNames; SearchClassNames.Add(ObjectBaseClass->GetFName()); AssetRegistry.GetDerivedClassNames(SearchClassNames, ExcludedClassNames, DerivedClassNames); const FName GeneratedClassName = FName(TEXT("GeneratedClass")); for ( auto DerivedClassIt = DerivedClassNames.CreateConstIterator(); DerivedClassIt; ++DerivedClassIt ) { ARFilter.TagsAndValues.Add(GeneratedClassName, (*DerivedClassIt).ToString()); } }*/ AssetDataList.Empty(); AssetRegistry.GetAssets(ARFilter, AssetDataList); // Filter out any blueprints found whose parent class is not derived from ObjectBaseClass if (ObjectBaseClass) { TSet<FName> DerivedClassNames; TArray<FName> ClassNames; ClassNames.Add(ObjectBaseClass->GetFName()); AssetRegistry.GetDerivedClassNames(ClassNames, TSet<FName>(), DerivedClassNames); for(int32 AssetIdx=AssetDataList.Num() - 1; AssetIdx >= 0; --AssetIdx) { FAssetData& Data = AssetDataList[AssetIdx]; bool bShouldRemove = true; const FString* ParentClassFromData = Data.TagsAndValues.Find("ParentClass"); if (ParentClassFromData && !ParentClassFromData->IsEmpty()) { const FString ClassObjectPath = FPackageName::ExportTextPathToObjectPath(*ParentClassFromData); const FString ClassName = FPackageName::ObjectPathToObjectName(ClassObjectPath); if (DerivedClassNames.Contains(FName(*ClassName))) { // This asset is derived from ObjectBaseClass. Keep it. bShouldRemove = false; } } if ( bShouldRemove ) { AssetDataList.RemoveAt(AssetIdx); } } } return AssetDataList.Num(); }
void USoundCue::PostLoad() { Super::PostLoad(); // Game doesn't care if there are NULL graph nodes #if WITH_EDITOR if (GIsEditor ) { if (SoundCueGraph) { // Deal with SoundNode types being removed - iterate in reverse as nodes may be removed for (int32 idx = SoundCueGraph->Nodes.Num() - 1; idx >= 0; --idx) { USoundCueGraphNode* Node = Cast<USoundCueGraphNode>(SoundCueGraph->Nodes[idx]); if (Node && Node->SoundNode == NULL) { FBlueprintEditorUtils::RemoveNode(NULL, Node, true); } } } else { // we should have a soundcuegraph unless we are contained in a package which is missing editor only data check( GetOutermost()->PackageFlags & PKG_FilterEditorOnly ); } // Always load all sound waves in the editor for (USoundNode* SoundNode : AllNodes) { if (USoundNodeAssetReferencer* AssetReferencerNode = Cast<USoundNodeAssetReferencer>(SoundNode)) { AssetReferencerNode->LoadAsset(); } } } else #endif { TArray<USoundNode*> NodesToEvaluate; NodesToEvaluate.Push(FirstNode); while (NodesToEvaluate.Num() > 0) { if (USoundNode* SoundNode = NodesToEvaluate.Pop(false)) { if (USoundNodeAssetReferencer* AssetReferencerNode = Cast<USoundNodeAssetReferencer>(SoundNode)) { AssetReferencerNode->LoadAsset(); } else if (USoundNodeQualityLevel* QualityLevelNode = Cast<USoundNodeQualityLevel>(SoundNode)) { // Only pick the node connected for current quality, currently don't support changing audio quality on the fly static const int32 CachedQualityLevel = GEngine->GetGameUserSettings()->GetAudioQualityLevel(); if (CachedQualityLevel < QualityLevelNode->ChildNodes.Num()) { NodesToEvaluate.Add(QualityLevelNode->ChildNodes[CachedQualityLevel]); } } else { NodesToEvaluate.Append(SoundNode->ChildNodes); } } } } }
TArray< TSharedRef<FTokenizedMessage> > FCompilerResultsLog::ParseCompilerLogDump(const FString& LogDump) { TArray< TSharedRef<FTokenizedMessage> > Messages; TArray< FString > MessageLines; LogDump.ParseIntoArray(MessageLines, TEXT("\n"), false); // delete any trailing empty lines for (int32 i = MessageLines.Num()-1; i >= 0; --i) { if (!MessageLines[i].IsEmpty()) { if (i < MessageLines.Num() - 1) { MessageLines.RemoveAt(i+1, MessageLines.Num() - (i+1)); } break; } } for (int32 i = 0; i < MessageLines.Num(); ++i) { FString Line = MessageLines[i]; if (Line.EndsWith(TEXT("\r"))) { Line = Line.LeftChop(1); } Line = Line.ConvertTabsToSpaces(4).TrimTrailing(); // handle output line error message if applicable // @todo Handle case where there are parenthesis in path names // @todo Handle errors reported by Clang FString LeftStr, RightStr; FString FullPath, LineNumberString; if (Line.Split(TEXT(")"), &LeftStr, &RightStr, ESearchCase::CaseSensitive) && LeftStr.Split(TEXT("("), &FullPath, &LineNumberString, ESearchCase::CaseSensitive) && LineNumberString.IsNumeric() && (FCString::Strtoi(*LineNumberString, NULL, 10) > 0)) { EMessageSeverity::Type Severity = EMessageSeverity::Error; FString FullPathTrimmed = FullPath; FullPathTrimmed.Trim(); if (FullPathTrimmed.Len() != FullPath.Len()) // check for leading whitespace { Severity = EMessageSeverity::Info; } TSharedRef<FTokenizedMessage> Message = FTokenizedMessage::Create( Severity ); if ( Severity == EMessageSeverity::Info ) // add whitespace now { FString Whitespace = FullPath.Left(FullPath.Len() - FullPathTrimmed.Len()); Message->AddToken( FTextToken::Create( FText::FromString( Whitespace ) ) ); FullPath = FullPathTrimmed; } FString Link = FullPath + TEXT("(") + LineNumberString + TEXT(")"); Message->AddToken( FTextToken::Create( FText::FromString( Link ) )->OnMessageTokenActivated(FOnMessageTokenActivated::CreateStatic(&FCompilerResultsLog::OnGotoError) ) ); Message->AddToken( FTextToken::Create( FText::FromString( RightStr ) ) ); Messages.Add(Message); if (Severity == EMessageSeverity::Error) { FPlatformMisc::LowLevelOutputDebugStringf(TEXT("%s"), *Line); } } else { EMessageSeverity::Type Severity = EMessageSeverity::Info; if (Line.Contains(TEXT("error LNK"), ESearchCase::CaseSensitive)) { Severity = EMessageSeverity::Error; FPlatformMisc::LowLevelOutputDebugStringf(TEXT("%s"), *Line); } TSharedRef<FTokenizedMessage> Message = FTokenizedMessage::Create( Severity ); Message->AddToken( FTextToken::Create( FText::FromString( Line ) ) ); Messages.Add(Message); } } return Messages; }