void FHotReloadClassReinstancer::UpdateDefaultProperties() { struct FPropertyToUpdate { UProperty* Property; FName SubobjectName; uint8* OldSerializedValuePtr; uint8* NewValuePtr; int64 OldSerializedSize; }; /** Memory writer archive that supports UObject values the same way as FCDOWriter. */ class FPropertyValueMemoryWriter : public FMemoryWriter { public: FPropertyValueMemoryWriter(TArray<uint8>& OutData) : FMemoryWriter(OutData) {} virtual FArchive& operator<<(class UObject*& InObj) override { FArchive& Ar = *this; if (InObj) { FName ClassName = InObj->GetClass()->GetFName(); FName ObjectName = InObj->GetFName(); Ar << ClassName; Ar << ObjectName; } else { FName UnusedName = NAME_None; Ar << UnusedName; Ar << UnusedName; } return *this; } virtual FArchive& operator<<(FName& InName) override { FArchive& Ar = *this; NAME_INDEX ComparisonIndex = InName.GetComparisonIndex(); NAME_INDEX DisplayIndex = InName.GetDisplayIndex(); int32 Number = InName.GetNumber(); Ar << ComparisonIndex; Ar << DisplayIndex; Ar << Number; return Ar; } virtual FArchive& operator<<(FLazyObjectPtr& LazyObjectPtr) override { FArchive& Ar = *this; auto UniqueID = LazyObjectPtr.GetUniqueID(); Ar << UniqueID; return *this; } virtual FArchive& operator<<(FAssetPtr& AssetPtr) override { FArchive& Ar = *this; auto UniqueID = AssetPtr.GetUniqueID(); Ar << UniqueID; return Ar; } virtual FArchive& operator<<(FStringAssetReference& Value) override { FArchive& Ar = *this; FString Path = Value.ToString(); Ar << Path; if (IsLoading()) { Value.SetPath(MoveTemp(Path)); } return Ar; } }; // Collect default subobjects to update their properties too const int32 DefaultSubobjectArrayCapacity = 16; TArray<UObject*> DefaultSubobjectArray; DefaultSubobjectArray.Empty(DefaultSubobjectArrayCapacity); NewClass->GetDefaultObject()->CollectDefaultSubobjects(DefaultSubobjectArray); TArray<FPropertyToUpdate> PropertiesToUpdate; // Collect all properties that have actually changed for (auto& Pair : ReconstructedCDOProperties.Properties) { auto OldPropertyInfo = OriginalCDOProperties.Properties.Find(Pair.Key); if (OldPropertyInfo) { auto& NewPropertyInfo = Pair.Value; uint8* OldSerializedValuePtr = OriginalCDOProperties.Bytes.GetData() + OldPropertyInfo->SerializedValueOffset; uint8* NewSerializedValuePtr = ReconstructedCDOProperties.Bytes.GetData() + NewPropertyInfo.SerializedValueOffset; if (OldPropertyInfo->SerializedValueSize != NewPropertyInfo.SerializedValueSize || FMemory::Memcmp(OldSerializedValuePtr, NewSerializedValuePtr, OldPropertyInfo->SerializedValueSize) != 0) { // Property value has changed so add it to the list of properties that need updating on instances FPropertyToUpdate PropertyToUpdate; PropertyToUpdate.Property = NewPropertyInfo.Property; PropertyToUpdate.NewValuePtr = nullptr; PropertyToUpdate.SubobjectName = NewPropertyInfo.SubobjectName; if (NewPropertyInfo.Property->GetOuter() == NewClass) { PropertyToUpdate.NewValuePtr = PropertyToUpdate.Property->ContainerPtrToValuePtr<uint8>(NewClass->GetDefaultObject()); } else if (NewPropertyInfo.SubobjectName != NAME_None) { UObject* DefaultSubobjectPtr = FindDefaultSubobject(DefaultSubobjectArray, NewPropertyInfo.SubobjectName); if (DefaultSubobjectPtr && NewPropertyInfo.Property->GetOuter() == DefaultSubobjectPtr->GetClass()) { PropertyToUpdate.NewValuePtr = PropertyToUpdate.Property->ContainerPtrToValuePtr<uint8>(DefaultSubobjectPtr); } } if (PropertyToUpdate.NewValuePtr) { PropertyToUpdate.OldSerializedValuePtr = OldSerializedValuePtr; PropertyToUpdate.OldSerializedSize = OldPropertyInfo->SerializedValueSize; PropertiesToUpdate.Add(PropertyToUpdate); } } } } if (PropertiesToUpdate.Num()) { TArray<uint8> CurrentValueSerializedData; // Update properties on all existing instances of the class for (FObjectIterator It(NewClass); It; ++It) { UObject* ObjectPtr = *It; DefaultSubobjectArray.Empty(DefaultSubobjectArrayCapacity); ObjectPtr->CollectDefaultSubobjects(DefaultSubobjectArray); for (auto& PropertyToUpdate : PropertiesToUpdate) { uint8* InstanceValuePtr = nullptr; if (PropertyToUpdate.SubobjectName == NAME_None) { InstanceValuePtr = PropertyToUpdate.Property->ContainerPtrToValuePtr<uint8>(ObjectPtr); } else { UObject* DefaultSubobjectPtr = FindDefaultSubobject(DefaultSubobjectArray, PropertyToUpdate.SubobjectName); if (DefaultSubobjectPtr && PropertyToUpdate.Property->GetOuter() == DefaultSubobjectPtr->GetClass()) { InstanceValuePtr = PropertyToUpdate.Property->ContainerPtrToValuePtr<uint8>(DefaultSubobjectPtr); } } if (InstanceValuePtr) { // Serialize current value to a byte array as we don't have the previous CDO to compare against, we only have its serialized property data CurrentValueSerializedData.Empty(CurrentValueSerializedData.Num() + CurrentValueSerializedData.GetSlack()); FPropertyValueMemoryWriter CurrentValueWriter(CurrentValueSerializedData); PropertyToUpdate.Property->SerializeItem(CurrentValueWriter, InstanceValuePtr); // Update only when the current value on the instance is identical to the original CDO if (CurrentValueSerializedData.Num() == PropertyToUpdate.OldSerializedSize && FMemory::Memcmp(CurrentValueSerializedData.GetData(), PropertyToUpdate.OldSerializedValuePtr, CurrentValueSerializedData.Num()) == 0) { // Update with the new value PropertyToUpdate.Property->CopyCompleteValue(InstanceValuePtr, PropertyToUpdate.NewValuePtr); } } } } } }
void FAsyncSoundFileImportTask::DoWork() { // Create a new sound file object TScopedPointer<FSoundFile> SoundFileInput = TScopedPointer<FSoundFile>(new FSoundFile()); // Open the file ESoundFileError::Type Error = SoundFileInput->OpenFileForReading(ImportSettings.SoundFilePath); SOUND_IMPORT_CHECK(Error); TSharedPtr<ISoundFileData> SoundFileData; Error = SoundFileInput->GetSoundFileData(SoundFileData); SOUND_IMPORT_CHECK(Error); // Get the input file's description const FSoundFileDescription& InputDescription = SoundFileData->GetDescription(); // Get the input file's channel map const TArray<ESoundFileChannelMap::Type>& InputChannelMap = SoundFileData->GetChannelMap(); // Build a description for the new file FSoundFileDescription NewSoundFileDescription; NewSoundFileDescription.NumChannels = InputDescription.NumChannels; NewSoundFileDescription.NumFrames = InputDescription.NumFrames; NewSoundFileDescription.FormatFlags = ImportSettings.Format; NewSoundFileDescription.SampleRate = ImportSettings.SampleRate; NewSoundFileDescription.NumSections = 0; NewSoundFileDescription.bIsSeekable = 1; // Open it as an empty file for reading and writing ISoundFileInternal* SoundFileInternal = (ISoundFileInternal*)SoundFile.Get(); Error = SoundFileInternal->OpenEmptyFileForImport(NewSoundFileDescription, InputChannelMap); SOUND_IMPORT_CHECK(Error); // Set the original description on the new sound file Error = SoundFileInternal->SetImportFileInfo(InputDescription, ImportSettings.SoundFilePath); SOUND_IMPORT_CHECK(Error); // Set the encoding quality (will only do anything if import target is Ogg-Vorbis) Error = SoundFileInternal->SetEncodingQuality(ImportSettings.EncodingQuality); SOUND_IMPORT_CHECK(Error); // Set the state of the sound file to be loading Error = SoundFileInternal->BeginImport(); SOUND_IMPORT_CHECK(Error); // Create a buffer to do the processing SoundFileCount ProcessBufferSamples = 1024 * NewSoundFileDescription.NumChannels; TArray<double> ProcessBuffer; ProcessBuffer.Init(0.0, ProcessBufferSamples); // Find the max value if we've been told to do peak normalization on import double MaxValue = 0.0; SoundFileCount SamplesRead = 0; bool bPerformPeakNormalization = ImportSettings.bPerformPeakNormalization; if (bPerformPeakNormalization) { Error = SoundFileInput->ReadSamples(ProcessBuffer.GetData(), ProcessBufferSamples, SamplesRead); SOUND_IMPORT_CHECK(Error); while (SamplesRead) { for (SoundFileCount Sample = 0; Sample < SamplesRead; ++Sample) { if (ProcessBuffer[Sample] > FMath::Abs(MaxValue)) { MaxValue = ProcessBuffer[Sample]; } } Error = SoundFileInput->ReadSamples(ProcessBuffer.GetData(), ProcessBufferSamples, SamplesRead); SOUND_IMPORT_CHECK(Error); } // If this happens, it means we have a totally silent file if (MaxValue == 0.0) { bPerformPeakNormalization = false; } // Seek the file back to the beginning SoundFileCount OutOffset; SoundFileInput->SeekFrames(0, ESoundFileSeekMode::FROM_START, OutOffset); } // Now perform the encoding to the target file Error = SoundFileInput->ReadSamples(ProcessBuffer.GetData(), ProcessBufferSamples, SamplesRead); SOUND_IMPORT_CHECK(Error); while (SamplesRead) { SOUND_IMPORT_CHECK(SoundFileInput->GetError()); // Normalize the samples if we're told to if (bPerformPeakNormalization) { for (int32 Sample = 0; Sample < SamplesRead; ++Sample) { ProcessBuffer[Sample] /= MaxValue; } } SoundFileCount SamplesWritten; Error = SoundFileInternal->WriteSamples((const double*)ProcessBuffer.GetData(), SamplesRead, SamplesWritten); SOUND_IMPORT_CHECK(Error); Error = SoundFileInput->ReadSamples(ProcessBuffer.GetData(), ProcessBufferSamples, SamplesRead); SOUND_IMPORT_CHECK(Error); } SoundFileInput->ReleaseSoundFileHandle(); SoundFileInternal->ReleaseSoundFileHandle(); // We're done doing the encoding Error = SoundFileInternal->EndImport(); SOUND_IMPORT_CHECK(Error); }
void FSlateOpenGLTexture::Init( GLenum TexFormat, const TArray<uint8>& TextureData ) { // Create a new OpenGL texture glGenTextures(1, &ShaderResource); CHECK_GL_ERRORS; // Ensure texturing is enabled before setting texture properties #if USE_DEPRECATED_OPENGL_FUNCTIONALITY glEnable(GL_TEXTURE_2D); #endif // USE_DEPRECATED_OPENGL_FUNCTIONALITY glBindTexture(GL_TEXTURE_2D, ShaderResource); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #if USE_DEPRECATED_OPENGL_FUNCTIONALITY glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); #endif // USE_DEPRECATED_OPENGL_FUNCTIONALITY // the raw data is in bgra or bgr const GLint Format = GL_BGRA; // Upload the texture data glTexImage2D( GL_TEXTURE_2D, 0, TexFormat, SizeX, SizeY, 0, Format, GL_UNSIGNED_INT_8_8_8_8_REV, TextureData.GetData() ); bHasPendingResize = false; CHECK_GL_ERRORS; }
bool UDestructibleComponent::DoCustomNavigableGeometryExport(FNavigableGeometryExport& GeomExport) const { #if WITH_APEX if (ApexDestructibleActor == NULL) { return false; } NxDestructibleActor* DestrActor = const_cast<NxDestructibleActor*>(ApexDestructibleActor); const FTransform ComponentToWorldNoScale(ComponentToWorld.GetRotation(), ComponentToWorld.GetTranslation(), FVector(1.f)); TArray<PxShape*> Shapes; Shapes.AddUninitialized(8); PxRigidDynamic** PActorBuffer = NULL; PxU32 PActorCount = 0; if (DestrActor->acquirePhysXActorBuffer(PActorBuffer, PActorCount , NxDestructiblePhysXActorQueryFlags::Static | NxDestructiblePhysXActorQueryFlags::Dormant | NxDestructiblePhysXActorQueryFlags::Dynamic)) { uint32 ShapesExportedCount = 0; while (PActorCount--) { const PxRigidDynamic* PActor = *PActorBuffer++; if (PActor != NULL) { const FTransform PActorGlobalPose = P2UTransform(PActor->getGlobalPose()); const PxU32 ShapesCount = PActor->getNbShapes(); if (ShapesCount > PxU32(Shapes.Num())) { Shapes.AddUninitialized(ShapesCount - Shapes.Num()); } const PxU32 RetrievedShapesCount = PActor->getShapes(Shapes.GetData(), Shapes.Num()); PxShape* const* ShapePtr = Shapes.GetData(); for (PxU32 ShapeIndex = 0; ShapeIndex < RetrievedShapesCount; ++ShapeIndex, ++ShapePtr) { if (*ShapePtr != NULL) { const PxTransform LocalPose = (*ShapePtr)->getLocalPose(); FTransform LocalToWorld = P2UTransform(LocalPose); LocalToWorld.Accumulate(PActorGlobalPose); switch((*ShapePtr)->getGeometryType()) { case PxGeometryType::eCONVEXMESH: { PxConvexMeshGeometry Geometry; if ((*ShapePtr)->getConvexMeshGeometry(Geometry)) { ++ShapesExportedCount; // @todo address Geometry.scale not being used here GeomExport.ExportPxConvexMesh(Geometry.convexMesh, LocalToWorld); } } break; case PxGeometryType::eTRIANGLEMESH: { // @todo address Geometry.scale not being used here PxTriangleMeshGeometry Geometry; if ((*ShapePtr)->getTriangleMeshGeometry(Geometry)) { ++ShapesExportedCount; if ((Geometry.triangleMesh->getTriangleMeshFlags()) & PxTriangleMeshFlag::eHAS_16BIT_TRIANGLE_INDICES) { GeomExport.ExportPxTriMesh16Bit(Geometry.triangleMesh, LocalToWorld); } else { GeomExport.ExportPxTriMesh32Bit(Geometry.triangleMesh, LocalToWorld); } } } default: { UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::DoCustomNavigableGeometryExport(): unhandled PxGeometryType, %d.") , int32((*ShapePtr)->getGeometryType())); } break; } } } } } ApexDestructibleActor->releasePhysXActorBuffer(); INC_DWORD_STAT_BY(STAT_Navigation_DestructiblesShapesExported, ShapesExportedCount); } #endif // WITH_APEX // we don't want a regular geometry export return false; }
/** * Helper function to create an unwrapped 2D image of the cube map ( longitude/latitude ) * This version takes explicitly passed properties of the source object, as the sources have different APIs. * @param TextureResource Source FTextureResource object. * @param AxisDimenion axis length of the cube. * @param SourcePixelFormat pixel format of the source. * @param BitsOUT Raw bits of the 2D image bitmap. * @param SizeXOUT Filled with the X dimension of the output bitmap. * @param SizeYOUT Filled with the Y dimension of the output bitmap. * @return true on success. * @param FormatOUT Filled with the pixel format of the output bitmap. */ bool GenerateLongLatUnwrap(const FTextureResource* TextureResource, const uint32 AxisDimenion, const EPixelFormat SourcePixelFormat, TArray<uint8>& BitsOUT, FIntPoint& SizeOUT, EPixelFormat& FormatOUT) { TRefCountPtr<FBatchedElementParameters> BatchedElementParameters; BatchedElementParameters = new FMipLevelBatchedElementParameters((float)0, true); const FIntPoint LongLatDimensions(AxisDimenion * 2, AxisDimenion); // If the source format is 8 bit per channel or less then select a LDR target format. const EPixelFormat TargetPixelFormat = CalculateImageBytes(1, 1, 0, SourcePixelFormat) <= 4 ? PF_B8G8R8A8 : PF_FloatRGBA; UTextureRenderTarget2D* RenderTargetLongLat = NewObject<UTextureRenderTarget2D>(); check(RenderTargetLongLat); RenderTargetLongLat->AddToRoot(); RenderTargetLongLat->ClearColor = FLinearColor(0.0f, 0.0f, 0.0f, 0.0f); RenderTargetLongLat->InitCustomFormat(LongLatDimensions.X, LongLatDimensions.Y, TargetPixelFormat, false); RenderTargetLongLat->TargetGamma = 0; FRenderTarget* RenderTarget = RenderTargetLongLat->GameThread_GetRenderTargetResource(); FCanvas* Canvas = new FCanvas(RenderTarget, NULL, 0, 0, 0, GMaxRHIFeatureLevel); Canvas->SetRenderTarget_GameThread(RenderTarget); // Clear the render target to black Canvas->Clear(FLinearColor(0, 0, 0, 0)); FCanvasTileItem TileItem(FVector2D(0.0f, 0.0f), TextureResource, FVector2D(LongLatDimensions.X, LongLatDimensions.Y), FLinearColor::White); TileItem.BatchedElementParameters = BatchedElementParameters; TileItem.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem(TileItem); Canvas->Flush_GameThread(); FlushRenderingCommands(); Canvas->SetRenderTarget_GameThread(NULL); FlushRenderingCommands(); int32 ImageBytes = CalculateImageBytes(LongLatDimensions.X, LongLatDimensions.Y, 0, TargetPixelFormat); BitsOUT.AddUninitialized(ImageBytes); bool bReadSuccess = false; switch (TargetPixelFormat) { case PF_B8G8R8A8: bReadSuccess = RenderTarget->ReadPixelsPtr((FColor*)BitsOUT.GetData()); break; case PF_FloatRGBA: { TArray<FFloat16Color> FloatColors; bReadSuccess = RenderTarget->ReadFloat16Pixels(FloatColors); FMemory::Memcpy(BitsOUT.GetData(), FloatColors.GetData(), ImageBytes); } break; } // Clean up. RenderTargetLongLat->RemoveFromRoot(); RenderTargetLongLat = NULL; delete Canvas; SizeOUT = LongLatDimensions; FormatOUT = TargetPixelFormat; if (bReadSuccess == false) { // Reading has failed clear output buffer. BitsOUT.Empty(); } return bReadSuccess; }
//This function requires // #include <string> FString ATitanBotsPlayerController::StringFromBinaryArray(const TArray<uint8>& BinaryArray) { //Create a string from a byte array! std::string cstr(reinterpret_cast<const char*>(BinaryArray.GetData()), BinaryArray.Num()); return FString(cstr.c_str()); }
AssetPath = Blueprint.ObjectPath; break; } } FComponentTypeEntry Entry = { FixedString, AssetPath.ToString(), nullptr }; ComponentTypeList.Add(Entry); FComponentClassComboEntryPtr NewEntry(new FComponentClassComboEntry(BlueprintComponents, FixedString, AssetPath, bIncludeInFilter)); SortedClassList.Add(NewEntry); } } if (SortedClassList.Num() > 0) { Sort(SortedClassList.GetData(), SortedClassList.Num(), SortComboEntry()); FString PreviousHeading; for (int32 ClassIndex = 0; ClassIndex < SortedClassList.Num(); ClassIndex++) { FComponentClassComboEntryPtr& CurrentEntry = SortedClassList[ClassIndex]; const FString& CurrentHeadingText = CurrentEntry->GetHeadingText(); if (CurrentHeadingText != PreviousHeading) { // This avoids a redundant separator being added to the very top of the list if (ClassIndex > 0) { FComponentClassComboEntryPtr NewSeparator(new FComponentClassComboEntry()); ComponentClassList.Add(NewSeparator);
/** * Cook a simple mono or stereo wave */ static void CookSimpleWave(USoundWave* SoundWave, FName FormatName, const IAudioFormat& Format, TArray<uint8>& Output) { FWaveModInfo WaveInfo; TArray<uint8> Input; check(!Output.Num()); bool bWasLocked = false; // check if there is any raw sound data if( SoundWave->RawData.GetBulkDataSize() > 0 ) { // Lock raw wave data. uint8* RawWaveData = ( uint8* )SoundWave->RawData.Lock( LOCK_READ_ONLY ); bWasLocked = true; int32 RawDataSize = SoundWave->RawData.GetBulkDataSize(); // parse the wave data if( !WaveInfo.ReadWaveHeader( RawWaveData, RawDataSize, 0 ) ) { UE_LOG(LogAudioDerivedData, Warning, TEXT( "Only mono or stereo 16 bit waves allowed: %s (%d bytes)" ), *SoundWave->GetFullName(), RawDataSize ); } else { Input.AddUninitialized(WaveInfo.SampleDataSize); FMemory::Memcpy(Input.GetData(), WaveInfo.SampleDataStart, WaveInfo.SampleDataSize); } } if(!Input.Num()) { UE_LOG(LogAudioDerivedData, Warning, TEXT( "Can't cook %s because there is no source compressed or uncompressed PC sound data" ), *SoundWave->GetFullName() ); } else { FSoundQualityInfo QualityInfo = { 0 }; QualityInfo.Quality = SoundWave->CompressionQuality; QualityInfo.NumChannels = *WaveInfo.pChannels; QualityInfo.SampleRate = *WaveInfo.pSamplesPerSec; QualityInfo.SampleDataSize = Input.Num(); QualityInfo.DebugName = SoundWave->GetFullName(); // Cook the data. if(Format.Cook(FormatName, Input, QualityInfo, Output)) { //@todo tighten up the checking for empty results here if (SoundWave->SampleRate != *WaveInfo.pSamplesPerSec) { UE_LOG(LogAudioDerivedData, Warning, TEXT( "Updated SoundWave->SampleRate during cooking %s." ), *SoundWave->GetFullName() ); SoundWave->SampleRate = *WaveInfo.pSamplesPerSec; } if (SoundWave->NumChannels != *WaveInfo.pChannels) { UE_LOG(LogAudioDerivedData, Warning, TEXT( "Updated SoundWave->NumChannels during cooking %s." ), *SoundWave->GetFullName() ); SoundWave->NumChannels = *WaveInfo.pChannels; } if (SoundWave->RawPCMDataSize != Input.Num()) { UE_LOG(LogAudioDerivedData, Warning, TEXT( "Updated SoundWave->RawPCMDataSize during cooking %s." ), *SoundWave->GetFullName() ); SoundWave->RawPCMDataSize = Input.Num(); } if (SoundWave->Duration != ( float )SoundWave->RawPCMDataSize / (SoundWave->SampleRate * sizeof( int16 ) * SoundWave->NumChannels)) { UE_LOG(LogAudioDerivedData, Warning, TEXT( "Updated SoundWave->Duration during cooking %s." ), *SoundWave->GetFullName() ); SoundWave->Duration = ( float )SoundWave->RawPCMDataSize / (SoundWave->SampleRate * sizeof( int16 ) * SoundWave->NumChannels); } } } if (bWasLocked) { SoundWave->RawData.Unlock(); } }
FDataScanResult FDataScannerImpl::ScanData() { // Count running scanners FScopeCounter ScopeCounter(&NumRunningScanners); FStatsCollector::Accumulate(StatCreatedScanners, 1); FStatsCollector::Accumulate(StatRunningScanners, 1); // Init data FRollingHash<WindowSize> RollingHash; FChunkWriter ChunkWriter(FBuildPatchServicesModule::GetCloudDirectory(), StatsCollector); FDataStructure DataStructure(DataStartOffset); TMap<FGuid, FChunkInfo> ChunkInfoLookup; TArray<uint8> ChunkBuffer; TArray<uint8> NewChunkBuffer; uint32 PaddedZeros = 0; ChunkInfoLookup.Reserve(Data.Num() / WindowSize); ChunkBuffer.SetNumUninitialized(WindowSize); NewChunkBuffer.Reserve(WindowSize); // Get a copy of the chunk inventory TMap<uint64, TSet<FGuid>> ChunkInventory = CloudEnumeration->GetChunkInventory(); TMap<FGuid, int64> ChunkFileSizes = CloudEnumeration->GetChunkFileSizes(); TMap<FGuid, FSHAHash> ChunkShaHashes = CloudEnumeration->GetChunkShaHashes(); // Loop over and process all data FGuid MatchedChunk; uint64 TempTimer; uint64 CpuTimer; FStatsCollector::AccumulateTimeBegin(CpuTimer); for (int32 idx = 0; (idx < Data.Num() || PaddedZeros < WindowSize) && !bShouldAbort; ++idx) { // Consume data const uint32 NumDataNeeded = RollingHash.GetNumDataNeeded(); if (NumDataNeeded > 0) { FStatsScopedTimer ConsumeTimer(StatConsumeBytesTime); uint32 NumConsumedBytes = 0; if (idx < Data.Num()) { NumConsumedBytes = FMath::Min<uint32>(NumDataNeeded, Data.Num() - idx); RollingHash.ConsumeBytes(&Data[idx], NumConsumedBytes); idx += NumConsumedBytes - 1; } // Zero Pad? if (NumConsumedBytes < NumDataNeeded) { TArray<uint8> Zeros; Zeros.AddZeroed(NumDataNeeded - NumConsumedBytes); RollingHash.ConsumeBytes(Zeros.GetData(), Zeros.Num()); PaddedZeros = Zeros.Num(); } check(RollingHash.GetNumDataNeeded() == 0); continue; } const uint64 NumDataInWindow = WindowSize - PaddedZeros; const uint64 WindowHash = RollingHash.GetWindowHash(); // Try find match if (FindExistingChunk(ChunkInventory, ChunkShaHashes, WindowHash, RollingHash, MatchedChunk)) { // Push the chunk to the structure DataStructure.PushKnownChunk(MatchedChunk, NumDataInWindow); FChunkInfo& ChunkInfo = ChunkInfoLookup.FindOrAdd(MatchedChunk); ChunkInfo.Hash = WindowHash; ChunkInfo.ShaHash = ChunkShaHashes[MatchedChunk]; ChunkInfo.IsNew = false; FStatsCollector::Accumulate(StatMatchedData, NumDataInWindow); // Clear matched window RollingHash.Clear(); // Decrement idx to include current byte in next window --idx; } else { // Collect unrecognized bytes NewChunkBuffer.Add(RollingHash.GetWindowData().Bottom()); DataStructure.PushUnknownByte(); if (NumDataInWindow == 1) { NewChunkBuffer.AddZeroed(WindowSize - NewChunkBuffer.Num()); } if (NewChunkBuffer.Num() == WindowSize) { const uint64 NewChunkHash = FRollingHash<WindowSize>::GetHashForDataSet(NewChunkBuffer.GetData()); if (FindExistingChunk(ChunkInventory, ChunkShaHashes, NewChunkHash, NewChunkBuffer, MatchedChunk)) { DataStructure.RemapCurrentChunk(MatchedChunk); FChunkInfo& ChunkInfo = ChunkInfoLookup.FindOrAdd(MatchedChunk); ChunkInfo.Hash = NewChunkHash; ChunkInfo.ShaHash = ChunkShaHashes[MatchedChunk]; ChunkInfo.IsNew = false; FStatsCollector::Accumulate(StatMatchedData, WindowSize); } else { FStatsScopedTimer ChunkWriterTimer(StatChunkWriterTime); const FGuid& NewChunkGuid = DataStructure.GetCurrentChunkId(); FStatsCollector::AccumulateTimeEnd(StatCpuTime, CpuTimer); ChunkWriter.QueueChunk(NewChunkBuffer.GetData(), NewChunkGuid, NewChunkHash); FStatsCollector::AccumulateTimeBegin(CpuTimer); FChunkInfo& ChunkInfo = ChunkInfoLookup.FindOrAdd(NewChunkGuid); ChunkInfo.Hash = NewChunkHash; ChunkInfo.IsNew = true; FSHA1::HashBuffer(NewChunkBuffer.GetData(), NewChunkBuffer.Num(), ChunkInfo.ShaHash.Hash); ChunkShaHashes.Add(NewChunkGuid, ChunkInfo.ShaHash); FStatsCollector::Accumulate(StatExtraData, NewChunkBuffer.Num()); } DataStructure.CompleteCurrentChunk(); NewChunkBuffer.Empty(WindowSize); } // Roll byte into window if (idx < Data.Num()) { RollingHash.RollForward(Data[idx]); } else { RollingHash.RollForward(0); ++PaddedZeros; } } } // Collect left-overs if (NewChunkBuffer.Num() > 0) { NewChunkBuffer.AddZeroed(WindowSize - NewChunkBuffer.Num()); const uint64 NewChunkHash = FRollingHash<WindowSize>::GetHashForDataSet(NewChunkBuffer.GetData()); if (FindExistingChunk(ChunkInventory, ChunkShaHashes, NewChunkHash, NewChunkBuffer, MatchedChunk)) { // Setup chunk info for a match DataStructure.RemapCurrentChunk(MatchedChunk); FChunkInfo& ChunkInfo = ChunkInfoLookup.FindOrAdd(MatchedChunk); ChunkInfo.Hash = NewChunkHash; ChunkInfo.ShaHash = ChunkShaHashes[MatchedChunk]; ChunkInfo.IsNew = false; } else { // Save the final chunk if no match FStatsScopedTimer ChunkWriterTimer(StatChunkWriterTime); const FGuid& NewChunkGuid = DataStructure.GetCurrentChunkId(); FStatsCollector::AccumulateTimeEnd(StatCpuTime, CpuTimer); ChunkWriter.QueueChunk(NewChunkBuffer.GetData(), NewChunkGuid, NewChunkHash); FStatsCollector::AccumulateTimeBegin(CpuTimer); FChunkInfo& ChunkInfo = ChunkInfoLookup.FindOrAdd(NewChunkGuid); ChunkInfo.Hash = NewChunkHash; ChunkInfo.IsNew = true; FSHA1::HashBuffer(NewChunkBuffer.GetData(), NewChunkBuffer.Num(), ChunkInfo.ShaHash.Hash); ChunkShaHashes.Add(NewChunkGuid, ChunkInfo.ShaHash); FStatsCollector::Accumulate(StatExtraData, NewChunkBuffer.Num()); } } FStatsCollector::AccumulateTimeEnd(StatCpuTime, CpuTimer); // Wait for the chunk writer to finish, and fill out chunk file sizes FStatsCollector::AccumulateTimeBegin(TempTimer); ChunkWriter.NoMoreChunks(); ChunkWriter.WaitForThread(); ChunkWriter.GetChunkFilesizes(ChunkFileSizes); FStatsCollector::AccumulateTimeEnd(StatChunkWriterTime, TempTimer); // Fill out chunk file sizes FStatsCollector::AccumulateTimeBegin(CpuTimer); for (auto& ChunkInfo : ChunkInfoLookup) { ChunkInfo.Value.ChunkFileSize = ChunkFileSizes[ChunkInfo.Key]; } // Empty data to save RAM Data.Empty(); FStatsCollector::AccumulateTimeEnd(StatCpuTime, CpuTimer); FStatsCollector::Accumulate(StatRunningScanners, -1); bIsComplete = true; return FDataScanResult( MoveTemp(DataStructure.GetFinalDataStructure()), MoveTemp(ChunkInfoLookup)); }
FFeaturePackContentSource::FFeaturePackContentSource(FString InFeaturePackPath, bool bDontRegisterForSearch) { FeaturePackPath = InFeaturePackPath; bPackValid = false; // Create a pak platform file and mount the feature pack file. FPakPlatformFile PakPlatformFile; FString CommandLine; PakPlatformFile.Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT("")); FString MountPoint = "root:/"; PakPlatformFile.Mount(*InFeaturePackPath, 0, *MountPoint); // Gets the manifest file as a JSon string TArray<uint8> ManifestBuffer; if( LoadPakFileToBuffer(PakPlatformFile, FPaths::Combine(*MountPoint, TEXT("manifest.json")), ManifestBuffer) == false ) { RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Cannot find manifest."), *InFeaturePackPath)); Category = EContentSourceCategory::Unknown; return; } FString ManifestString; FFileHelper::BufferToString(ManifestString, ManifestBuffer.GetData(), ManifestBuffer.Num()); // Populate text fields from the manifest. TSharedPtr<FJsonObject> ManifestObject; TSharedRef<TJsonReader<>> ManifestReader = TJsonReaderFactory<>::Create(ManifestString); FJsonSerializer::Deserialize(ManifestReader, ManifestObject); if (ManifestReader->GetErrorMessage().IsEmpty() == false) { RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Failed to parse manifest: %s"), *InFeaturePackPath, *ManifestReader->GetErrorMessage())); Category = EContentSourceCategory::Unknown; return; } TSharedPtr<FString> ManifestObjectErrorMessage; if (TryValidateManifestObject(ManifestObject, ManifestObjectErrorMessage) == false) { RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Manifest object error: %s"), *InFeaturePackPath, **ManifestObjectErrorMessage)); Category = EContentSourceCategory::Unknown; return; } for (TSharedPtr<FJsonValue> NameValue : ManifestObject->GetArrayField("Name")) { TSharedPtr<FJsonObject> LocalizedNameObject = NameValue->AsObject(); LocalizedNames.Add(FLocalizedText( LocalizedNameObject->GetStringField("Language"), FText::FromString(LocalizedNameObject->GetStringField("Text")))); } for (TSharedPtr<FJsonValue> DescriptionValue : ManifestObject->GetArrayField("Description")) { TSharedPtr<FJsonObject> LocalizedDescriptionObject = DescriptionValue->AsObject(); LocalizedDescriptions.Add(FLocalizedText( LocalizedDescriptionObject->GetStringField("Language"), FText::FromString(LocalizedDescriptionObject->GetStringField("Text")))); } // Parse asset types field for (TSharedPtr<FJsonValue> AssetTypesValue : ManifestObject->GetArrayField("AssetTypes")) { TSharedPtr<FJsonObject> LocalizedAssetTypesObject = AssetTypesValue->AsObject(); LocalizedAssetTypesList.Add(FLocalizedText( LocalizedAssetTypesObject->GetStringField("Language"), FText::FromString(LocalizedAssetTypesObject->GetStringField("Text")))); } // Parse asset types field if( ManifestObject->HasField("SearchTags")==true) { for (TSharedPtr<FJsonValue> AssetTypesValue : ManifestObject->GetArrayField("SearchTags")) { TSharedPtr<FJsonObject> LocalizedAssetTypesObject = AssetTypesValue->AsObject(); LocalizedSearchTags.Add(FLocalizedTextArray( LocalizedAssetTypesObject->GetStringField("Language"), LocalizedAssetTypesObject->GetStringField("Text"))); } } // Parse class types field ClassTypes = ManifestObject->GetStringField("ClassTypes"); // Parse initial focus asset if we have one - this is not required if (ManifestObject->HasTypedField<EJson::String>("FocusAsset") == true) { FocusAssetIdent = ManifestObject->GetStringField("FocusAsset"); } // Use the path as the sort key - it will be alphabetical that way SortKey = FeaturePackPath; ManifestObject->TryGetStringField("SortKey", SortKey); FString CategoryString = ManifestObject->GetStringField("Category"); UEnum* Enum = FindObjectChecked<UEnum>(ANY_PACKAGE, TEXT("EContentSourceCategory")); int32 Index = Enum->FindEnumIndex(FName(*CategoryString)); Category = Index != INDEX_NONE ? (EContentSourceCategory)Index : EContentSourceCategory::Unknown; // Load image data FString IconFilename = ManifestObject->GetStringField("Thumbnail"); TSharedPtr<TArray<uint8>> IconImageData = MakeShareable(new TArray<uint8>()); FString ThumbnailFile = FPaths::Combine(*MountPoint, TEXT("Media"), *IconFilename); if( LoadPakFileToBuffer(PakPlatformFile, ThumbnailFile, *IconImageData) == true) { IconData = MakeShareable(new FImageData(IconFilename, IconImageData)); } else { RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Cannot find thumbnail %s."), *InFeaturePackPath, *ThumbnailFile )); } const TArray<TSharedPtr<FJsonValue>> ScreenshotFilenameArray = ManifestObject->GetArrayField("Screenshots"); for (const TSharedPtr<FJsonValue> ScreenshotFilename : ScreenshotFilenameArray) { TSharedPtr<TArray<uint8>> SingleScreenshotData = MakeShareable(new TArray<uint8>); if( LoadPakFileToBuffer(PakPlatformFile, FPaths::Combine(*MountPoint, TEXT("Media"), *ScreenshotFilename->AsString()), *SingleScreenshotData) ) { ScreenshotData.Add(MakeShareable(new FImageData(ScreenshotFilename->AsString(), SingleScreenshotData))); } else { RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Cannot find screenshot %s."), *InFeaturePackPath, *ScreenshotFilename->AsString() )); } } if( bDontRegisterForSearch == false ) { FSuperSearchModule& SuperSearchModule = FModuleManager::LoadModuleChecked< FSuperSearchModule >(TEXT("SuperSearch")); SuperSearchModule.GetActOnSearchTextClicked().AddRaw(this, &FFeaturePackContentSource::HandleActOnSearchText); SuperSearchModule.GetSearchTextChanged().AddRaw(this, &FFeaturePackContentSource::HandleSuperSearchTextChanged); } bPackValid = true; }
/** Build the streamed audio. This function is safe to call from any thread. */ void BuildStreamedAudio() { GetStreamedAudioDerivedDataKeySuffix(SoundWave, AudioFormatName, KeySuffix); DerivedData->Chunks.Empty(); ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); const IAudioFormat* AudioFormat = NULL; if (TPM) { AudioFormat = TPM->FindAudioFormat(AudioFormatName); } if (AudioFormat) { DerivedData->AudioFormat = AudioFormatName; FByteBulkData* CompressedData = SoundWave.GetCompressedData(AudioFormatName); TArray<uint8> CompressedBuffer; CompressedBuffer.Empty(CompressedData->GetBulkDataSize()); CompressedBuffer.AddUninitialized(CompressedData->GetBulkDataSize()); void* BufferData = CompressedBuffer.GetData(); CompressedData->GetCopy(&BufferData, false); TArray<TArray<uint8>> ChunkBuffers; if (AudioFormat->SplitDataForStreaming(CompressedBuffer, ChunkBuffers)) { for (int32 ChunkIndex = 0; ChunkIndex < ChunkBuffers.Num(); ++ChunkIndex) { FStreamedAudioChunk* NewChunk = new(DerivedData->Chunks) FStreamedAudioChunk(); NewChunk->DataSize = ChunkBuffers[ChunkIndex].Num(); NewChunk->BulkData.Lock(LOCK_READ_WRITE); void* NewChunkData = NewChunk->BulkData.Realloc(ChunkBuffers[ChunkIndex].Num()); FMemory::Memcpy(NewChunkData, ChunkBuffers[ChunkIndex].GetData(), ChunkBuffers[ChunkIndex].Num()); NewChunk->BulkData.Unlock(); } } else { // Could not split so copy compressed data into a single chunk FStreamedAudioChunk* NewChunk = new(DerivedData->Chunks) FStreamedAudioChunk(); NewChunk->DataSize = CompressedBuffer.Num(); NewChunk->BulkData.Lock(LOCK_READ_WRITE); void* NewChunkData = NewChunk->BulkData.Realloc(CompressedBuffer.Num()); FMemory::Memcpy(NewChunkData, CompressedBuffer.GetData(), CompressedBuffer.Num()); NewChunk->BulkData.Unlock(); } DerivedData->NumChunks = DerivedData->Chunks.Num(); // Store it in the cache. PutDerivedDataInCache(DerivedData, KeySuffix); } if (DerivedData->Chunks.Num()) { bool bInlineChunks = (CacheFlags & EStreamedAudioCacheFlags::InlineChunks) != 0; bSucceeded = !bInlineChunks || DerivedData->TryInlineChunkData(); } else { UE_LOG(LogAudio, Warning, TEXT("Failed to build %s derived data for %s"), *AudioFormatName.GetPlainNameString(), *SoundWave.GetPathName() ); } }
void UAtmosphericFogComponent::PostLoad() { Super::PostLoad(); if ( !IsTemplate() ) { #if WITH_EDITOR if (TransmittanceTexture_DEPRECATED) { // Copy data from Previous data if (TransmittanceTexture_DEPRECATED->Source.IsValid()) { TArray<uint8> RawData; TArray<FColor> OutData; TransmittanceTexture_DEPRECATED->Source.GetMipData(RawData, 0); // Convert from FFloat16Color to FColor for (int32 i = 0; i < RawData.Num(); i+=sizeof(FFloat16Color)) { FFloat16Color* OriginalColor = (FFloat16Color*)&RawData[i]; FColor TempColor; TempColor.R = FMath::Clamp<uint8>(OriginalColor->R.GetFloat() * 255, 0, 255); TempColor.G = FMath::Clamp<uint8>(OriginalColor->G.GetFloat() * 255, 0, 255); TempColor.B = FMath::Clamp<uint8>(OriginalColor->B.GetFloat() * 255, 0, 255); OutData.Add(TempColor); } int32 TotalByte = OutData.Num() * sizeof(FColor); TransmittanceData.Lock(LOCK_READ_WRITE); FColor* TextureData = (FColor*)TransmittanceData.Realloc(TotalByte); FMemory::Memcpy(TextureData, OutData.GetData(), TotalByte); TransmittanceData.Unlock(); TransmittanceTexture_DEPRECATED = NULL; } } if (IrradianceTexture_DEPRECATED) { if (IrradianceTexture_DEPRECATED->Source.IsValid()) { TArray<uint8> RawData; TArray<FColor> OutData; IrradianceTexture_DEPRECATED->Source.GetMipData(RawData, 0); // Convert from FFloat16Color to FColor for (int32 i = 0; i < RawData.Num(); i+=sizeof(FFloat16Color)) { FFloat16Color* OriginalColor = (FFloat16Color*)&RawData[i]; FColor TempColor; TempColor.R = FMath::Clamp<uint8>(OriginalColor->R.GetFloat() * 255, 0, 255); TempColor.G = FMath::Clamp<uint8>(OriginalColor->G.GetFloat() * 255, 0, 255); TempColor.B = FMath::Clamp<uint8>(OriginalColor->B.GetFloat() * 255, 0, 255); OutData.Add(TempColor); } int32 TotalByte = OutData.Num() * sizeof(FColor); IrradianceData.Lock(LOCK_READ_WRITE); FColor* TextureData = (FColor*)IrradianceData.Realloc(TotalByte); FMemory::Memcpy(TextureData, OutData.GetData(), TotalByte); IrradianceData.Unlock(); IrradianceTexture_DEPRECATED = NULL; } } #endif InitResource(); } }
void FSavedCustomSortSectionInfo::Restore(USkeletalMesh* NewSkelMesh, int32 LODModelIndex, TArray<int32>& UnmatchedSections) { FStaticLODModel& LODModel = NewSkelMesh->GetImportedResource()->LODModels[LODModelIndex]; FSkeletalMeshLODInfo& LODInfo = NewSkelMesh->LODInfo[LODModelIndex]; // Re-order the UnmatchedSections so the old section index from the previous model is tried first int32 PrevSectionIndex = UnmatchedSections.Find(SavedSectionIdx); if( PrevSectionIndex != 0 && PrevSectionIndex != INDEX_NONE ) { Exchange( UnmatchedSections[0], UnmatchedSections[PrevSectionIndex] ); } // Find the strips in the old triangle data. TArray< TArray<uint32> > OldStrips[2]; for( int32 IndexCopy=0; IndexCopy < (SavedSortOption==TRISORT_CustomLeftRight ? 2 : 1); IndexCopy++ ) { const uint32* OldIndices = &SavedIndices[(SavedIndices.Num()>>1)*IndexCopy]; TArray<uint32> OldTriSet; GetConnectedTriangleSets( SavedNumTriangles, OldIndices, OldTriSet ); // Convert to strips int32 PrevTriSet = MAX_int32; for( int32 TriIndex=0;TriIndex<SavedNumTriangles; TriIndex++ ) { if( OldTriSet[TriIndex] != PrevTriSet ) { OldStrips[IndexCopy].AddZeroed(); PrevTriSet = OldTriSet[TriIndex]; } OldStrips[IndexCopy][OldStrips[IndexCopy].Num()-1].Add(OldIndices[TriIndex*3+0]); OldStrips[IndexCopy][OldStrips[IndexCopy].Num()-1].Add(OldIndices[TriIndex*3+1]); OldStrips[IndexCopy][OldStrips[IndexCopy].Num()-1].Add(OldIndices[TriIndex*3+2]); } } bool bFoundMatchingSection = false; // Try all remaining sections to find a match for( int32 UnmatchedSectionsIdx=0; !bFoundMatchingSection && UnmatchedSectionsIdx<UnmatchedSections.Num(); UnmatchedSectionsIdx++ ) { // Section of the new mesh to try int32 SectionIndex = UnmatchedSections[UnmatchedSectionsIdx]; FSkelMeshSection& Section = LODModel.Sections[SectionIndex]; TArray<uint32> Indices; LODModel.MultiSizeIndexContainer.GetIndexBuffer( Indices ); const uint32* NewSectionIndices = Indices.GetData() + Section.BaseIndex; // Build the list of triangle sets in the new mesh's section TArray<uint32> TriSet; GetConnectedTriangleSets( Section.NumTriangles, NewSectionIndices, TriSet ); // Mapping from triangle set number to the array of indices that make up the contiguous strip. TMap<uint32, TArray<uint32> > NewStripsMap; // Go through each triangle and assign it to the appropriate contiguous strip. // This is necessary if the strips in the index buffer are not contiguous. int32 Index=0; for( int32 s=0;s<TriSet.Num();s++ ) { // Store the indices for this triangle in the appropriate contiguous set. TArray<uint32>* ThisStrip = NewStripsMap.Find(TriSet[s]); if( !ThisStrip ) { ThisStrip = &NewStripsMap.Add(TriSet[s],TArray<uint32>()); } // Add the three indices for this triangle. ThisStrip->Add(NewSectionIndices[Index++]); ThisStrip->Add(NewSectionIndices[Index++]); ThisStrip->Add(NewSectionIndices[Index++]); } // Get the new vertices TArray<FSoftSkinVertex> NewVertices; LODModel.GetVertices(NewVertices); // Do the processing once for each copy if the index data for( int32 IndexCopy=0; IndexCopy < (SavedSortOption==TRISORT_CustomLeftRight ? 2 : 1); IndexCopy++ ) { // Copy strips in the new mesh's section into an array. We'll remove items from // here as we match to the old strips, so we need to keep a new copy of it each time. TArray<TArray<uint32> > NewStrips; for( TMap<uint32, TArray<uint32> >::TIterator It(NewStripsMap); It; ++It ) { NewStrips.Add(It.Value()); } // Match up old strips to new int32 NumMismatchedStrips = 0; TArray<TArray<uint32> > NewSortedStrips; // output for( int32 OsIdx=0;OsIdx<OldStrips[IndexCopy].Num();OsIdx++ ) { TArray<uint32>& OldStripIndices = OldStrips[IndexCopy][OsIdx]; int32 MatchingNewStrip = INDEX_NONE; for( int32 NsIdx=0;NsIdx<NewStrips.Num() && MatchingNewStrip==INDEX_NONE;NsIdx++ ) { // Check if we have the same number of triangles in the old and new strips. if( NewStrips[NsIdx].Num() != OldStripIndices.Num() ) { continue; } // Make a copy of the indices, as we'll remove them as we try to match triangles. TArray<uint32> NewStripIndices = NewStrips[NsIdx]; // Check if all the triangles in the new strip closely match those in the old. for( int32 OldTriIdx=0;OldTriIdx<OldStripIndices.Num();OldTriIdx+=3 ) { // Try to find a match for this triangle in the new strip. bool FoundMatch = false; for( int32 NewTriIdx=0;NewTriIdx<NewStripIndices.Num();NewTriIdx+=3 ) { if( (SavedVertices[OldStripIndices[OldTriIdx+0]] - NewVertices[NewStripIndices[NewTriIdx+0]].Position).SizeSquared() < KINDA_SMALL_NUMBER && (SavedVertices[OldStripIndices[OldTriIdx+1]] - NewVertices[NewStripIndices[NewTriIdx+1]].Position).SizeSquared() < KINDA_SMALL_NUMBER && (SavedVertices[OldStripIndices[OldTriIdx+2]] - NewVertices[NewStripIndices[NewTriIdx+2]].Position).SizeSquared() < KINDA_SMALL_NUMBER ) { // Found a triangle match. Remove the triangle from the new list and try to match the next old triangle. NewStripIndices.RemoveAt(NewTriIdx,3); FoundMatch = true; break; } } // If we didn't find a match for this old triangle, the whole strip doesn't match. if( !FoundMatch ) { break; } } if( NewStripIndices.Num() == 0 ) { // strip completely matched MatchingNewStrip = NsIdx; } } if( MatchingNewStrip != INDEX_NONE ) { NewSortedStrips.Add( NewStrips[MatchingNewStrip] ); NewStrips.RemoveAt(MatchingNewStrip); } else { NumMismatchedStrips++; } } if( IndexCopy == 0 ) { if( 100 * NumMismatchedStrips / OldStrips[0].Num() > 50 ) { // If less than 50% of this section's strips match, we assume this is not the correct section. break; } // This section matches! bFoundMatchingSection = true; // Warn the user if we couldn't match things up. if( NumMismatchedStrips ) { UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("RestoreSortingMismatchedStripsForSection", "While restoring \"{0}\" sort order for section {1}, {2} of {3} strips could not be matched to the new data."), FText::FromString(TriangleSortOptionToString((ETriangleSortOption)SavedSortOption)), FText::AsNumber(SavedSectionIdx), FText::AsNumber(NumMismatchedStrips), FText::AsNumber(OldStrips[0].Num()))), FFbxErrors::SkeletalMesh_RestoreSortingMismatchedStrips); } // Restore the settings saved in the LODInfo (used for the UI) FTriangleSortSettings& TriangleSortSettings = LODInfo.TriangleSortSettings[SectionIndex]; TriangleSortSettings.TriangleSorting = SavedSortOption; TriangleSortSettings.CustomLeftRightAxis = SavedCustomLeftRightAxis; TriangleSortSettings.CustomLeftRightBoneName = SavedCustomLeftRightBoneName; // Restore the sorting mode. For TRISORT_CustomLeftRight, this will also make the second copy of the index data. FVector SortCenter; bool bHaveSortCenter = NewSkelMesh->GetSortCenterPoint(SortCenter); LODModel.SortTriangles(SortCenter, bHaveSortCenter, SectionIndex, (ETriangleSortOption)SavedSortOption); } // Append any strips we couldn't match to the end NewSortedStrips += NewStrips; // Export the strips out to the index buffer in order TArray<uint32> Indexes; LODModel.MultiSizeIndexContainer.GetIndexBuffer( Indexes ); uint32* NewIndices = Indexes.GetData() + (Section.BaseIndex + Section.NumTriangles*3*IndexCopy); for( int32 StripIdx=0;StripIdx<NewSortedStrips.Num();StripIdx++ ) { FMemory::Memcpy( NewIndices, &NewSortedStrips[StripIdx][0], NewSortedStrips[StripIdx].Num() * sizeof(uint32) ); // Cache-optimize the triangle order inside the final strip CacheOptimizeSortStrip( NewIndices, NewSortedStrips[StripIdx].Num() ); NewIndices += NewSortedStrips[StripIdx].Num(); } LODModel.MultiSizeIndexContainer.CopyIndexBuffer( Indexes ); } } if( !bFoundMatchingSection ) { UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("FailedRestoreSortingNoSectionMatch", "Unable to restore triangle sort setting \"{0}\" for section number {1} in the old mesh, as a matching section could not be found in the new mesh. The custom sorting information has been lost."), FText::FromString(TriangleSortOptionToString((ETriangleSortOption)SavedSortOption)), FText::AsNumber(SavedSectionIdx))), FFbxErrors::SkeletalMesh_RestoreSortingNoSectionMatch); } }
void FNavigationQueryFilter::SetAllAreaCosts(const TArray<float>& CostArray) { SetAllAreaCosts(CostArray.GetData(), CostArray.Num()); }
FReply FLandscapeEditorDetailCustomization_CopyPaste::OnGizmoImportButtonClicked() { FEdModeLandscape* LandscapeEdMode = GetEditorMode(); if (LandscapeEdMode != NULL) { ALandscapeGizmoActiveActor* Gizmo = LandscapeEdMode->CurrentGizmoActor.Get(); if (Gizmo) { TArray<uint8> Data; FFileHelper::LoadFileToArray(Data, *LandscapeEdMode->UISettings->GizmoHeightmapFilenameString); if (Data.Num() <= 0 || Data.Num() != (LandscapeEdMode->UISettings->GizmoImportSize.X * LandscapeEdMode->UISettings->GizmoImportSize.Y * 2)) { FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "LandscapeImport_BadHeightmapSize", "File size does not match")); return FReply::Handled(); } TArray<ULandscapeLayerInfoObject*> LayerInfos; TArray<TArray<uint8> > LayerDataArrays; TArray<uint8*> LayerDataPtrs; for (int32 LayerIndex = 0; LayerIndex < LandscapeEdMode->UISettings->GizmoImportLayers.Num(); LayerIndex++) { const FGizmoImportLayer& Layer = LandscapeEdMode->UISettings->GizmoImportLayers[LayerIndex]; FString LayerName = Layer.LayerName.Replace(TEXT(" "), TEXT("")); if (LayerName == TEXT("")) { FMessageDialog::Open(EAppMsgType::Ok, FText::Format(NSLOCTEXT("UnrealEd", "LandscapeImport_BadLayerName", "You must enter a name for the layer being imported from {0}."), FText::FromString(Layer.LayerFilename))); return FReply::Handled(); } if (Layer.LayerFilename != TEXT("") && !Layer.bNoImport) { TArray<uint8>* LayerData = new(LayerDataArrays)(TArray<uint8>); FFileHelper::LoadFileToArray(*LayerData, *Layer.LayerFilename); if (LayerData->Num() != (LandscapeEdMode->UISettings->GizmoImportSize.X * LandscapeEdMode->UISettings->GizmoImportSize.Y)) { FMessageDialog::Open(EAppMsgType::Ok, FText::Format(NSLOCTEXT("UnrealEd", "LandscapeImport_BadLayerSize", "Layer {0} file size does not match the heightmap resolution."), FText::FromString(Layer.LayerFilename))); return FReply::Handled(); } LayerInfos.Add(LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetLayerInfoByName(FName(*LayerName))); LayerDataPtrs.Add(&(*LayerData)[0]); } } Gizmo->Import(LandscapeEdMode->UISettings->GizmoImportSize.X, LandscapeEdMode->UISettings->GizmoImportSize.Y, (uint16*)Data.GetData(), LayerInfos, LayerDataPtrs.Num() ? LayerDataPtrs.GetData() : NULL); // Make sure gizmo actor is selected GEditor->SelectNone(false, true); GEditor->SelectActor(Gizmo, true, false, true); } } return FReply::Handled(); }
FString FGenericPlatformHttp::UrlDecode(const FString &EncodedString) { FTCHARToUTF8 Converter(*EncodedString); const UTF8CHAR* UTF8Data = (UTF8CHAR*)Converter.Get(); TArray<ANSICHAR> Data; Data.Reserve(EncodedString.Len()); for (int32 CharIdx = 0; CharIdx < Converter.Length();) { if (UTF8Data[CharIdx] == '%') { int32 Value = 0; if (UTF8Data[CharIdx + 1] == 'u') { if (CharIdx + 6 <= Converter.Length()) { // Treat all %uXXXX as code point Value = FParse::HexDigit(UTF8Data[CharIdx + 2]) << 12; Value += FParse::HexDigit(UTF8Data[CharIdx + 3]) << 8; Value += FParse::HexDigit(UTF8Data[CharIdx + 4]) << 4; Value += FParse::HexDigit(UTF8Data[CharIdx + 5]); CharIdx += 6; ANSICHAR Buffer[8] = { 0 }; ANSICHAR* BufferPtr = Buffer; int32 len = ARRAY_COUNT(Buffer); FTCHARToUTF8_Convert::utf8fromcodepoint(Value, &BufferPtr, &len); Data.Append(Buffer, BufferPtr - Buffer); } else { // Not enough in the buffer for valid decoding, skip it CharIdx++; continue; } } else if(CharIdx + 3 <= Converter.Length()) { // Treat all %XX as straight byte Value = FParse::HexDigit(UTF8Data[CharIdx + 1]) << 4; Value += FParse::HexDigit(UTF8Data[CharIdx + 2]); CharIdx += 3; Data.Add((ANSICHAR)(Value)); } else { // Not enough in the buffer for valid decoding, skip it CharIdx++; continue; } } else { // Non escaped characters Data.Add(UTF8Data[CharIdx]); CharIdx++; } } Data.Add(0); FUTF8ToTCHAR DecodeConvert(Data.GetData()); return DecodeConvert.Get(); }
void UnchunkSkeletalModel(TArray<FSkinnedMeshChunk*>& Chunks, TArray<int32>& PointToOriginalMap, const FSkinnedModelData& SrcModel) { #if WITH_EDITORONLY_DATA const TArray<FSoftSkinVertex>& SrcVertices = SrcModel.Vertices; const TArray<uint32>& SrcIndices = SrcModel.Indices; TArray<uint32> IndexMap; check(Chunks.Num() == 0); check(PointToOriginalMap.Num() == 0); IndexMap.Empty(SrcVertices.Num()); IndexMap.AddUninitialized(SrcVertices.Num()); for (int32 SectionIndex = 0; SectionIndex < SrcModel.Sections.Num(); ++SectionIndex) { const FSkelMeshSection& Section = SrcModel.Sections[SectionIndex]; const TArray<FBoneIndexType>& BoneMap = SrcModel.BoneMaps[SectionIndex]; FSkinnedMeshChunk* DestChunk = Chunks.Num() ? Chunks.Last() : NULL; if (DestChunk == NULL || DestChunk->MaterialIndex != Section.MaterialIndex) { DestChunk = new FSkinnedMeshChunk(); Chunks.Add(DestChunk); DestChunk->MaterialIndex = Section.MaterialIndex; DestChunk->OriginalSectionIndex = SectionIndex; // When starting a new chunk reset the index map. FMemory::Memset(IndexMap.GetData(),0xff,IndexMap.Num()*IndexMap.GetTypeSize()); } int32 NumIndicesThisSection = Section.NumTriangles * 3; for (uint32 SrcIndex = Section.BaseIndex; SrcIndex < Section.BaseIndex + NumIndicesThisSection; ++SrcIndex) { uint32 VertexIndex = SrcIndices[SrcIndex]; uint32 DestVertexIndex = IndexMap[VertexIndex]; if (DestVertexIndex == INDEX_NONE) { FSoftSkinBuildVertex NewVertex; const FSoftSkinVertex& SrcVertex = SrcVertices[VertexIndex]; NewVertex.Position = SrcVertex.Position; NewVertex.TangentX = SrcVertex.TangentX; NewVertex.TangentY = SrcVertex.TangentY; NewVertex.TangentZ = SrcVertex.TangentZ; FMemory::Memcpy(NewVertex.UVs, SrcVertex.UVs, sizeof(FVector2D)*MAX_TEXCOORDS); NewVertex.Color = SrcVertex.Color; for (int32 i = 0; i < MAX_TOTAL_INFLUENCES; ++i) { uint8 BoneIndex = SrcVertex.InfluenceBones[i]; check(BoneMap.IsValidIndex(BoneIndex)); NewVertex.InfluenceBones[i] = BoneMap[BoneIndex]; NewVertex.InfluenceWeights[i] = SrcVertex.InfluenceWeights[i]; } NewVertex.PointWedgeIdx = SrcModel.RawPointIndices.Num() ? SrcModel.RawPointIndices[VertexIndex] : 0; int32 RawVertIndex = SrcModel.MeshToImportVertexMap.Num() ? SrcModel.MeshToImportVertexMap[VertexIndex] : INDEX_NONE; if ((int32)NewVertex.PointWedgeIdx >= PointToOriginalMap.Num()) { PointToOriginalMap.AddZeroed(NewVertex.PointWedgeIdx + 1 - PointToOriginalMap.Num()); } PointToOriginalMap[NewVertex.PointWedgeIdx] = RawVertIndex; DestVertexIndex = AddSkinVertex(DestChunk->Vertices,NewVertex,/*bKeepOverlappingVertices=*/ false); IndexMap[VertexIndex] = DestVertexIndex; } DestChunk->Indices.Add(DestVertexIndex); } } #endif // #if WITH_EDITORONLY_DATA }
/** Get vertex deltas for this animation at a particular time. Must call InitEval before calling this, and pass in State allocated. */ FVertexAnimDelta* UVertexAnimation::GetDeltasAtTime(float Time, int32 LODIndex, FVertexAnimEvalStateBase* State, int32& OutNumDeltas) { FVertexAnimEvalState* VertAnimState = (FVertexAnimEvalState*)State; if(VertAnimState != NULL) { check(VertexAnimData.Num() > 0); TArray<FVector> ImportVertDeltas; ImportVertDeltas.AddUninitialized(NumAnimatedVerts); // If time is before first frame (or only 1 frame) if(Time <= VertexAnimData[0].Time || VertexAnimData.Num() == 1) { FMemory::Memcpy(ImportVertDeltas.GetData(), VertexAnimData[0].Deltas.GetData(), NumAnimatedVerts); } // If time is after last frame else if(Time >= VertexAnimData.Last().Time) { FMemory::Memcpy(ImportVertDeltas.GetData(), VertexAnimData.Last().Deltas.GetData(), NumAnimatedVerts); } // Find frames to interpolate else { int32 AfterFrameIdx = INDEX_NONE; for(int32 FrameIdx=1; FrameIdx<VertexAnimData.Num(); FrameIdx++) { if(Time < VertexAnimData[FrameIdx].Time) { AfterFrameIdx = FrameIdx; break; } } check(AfterFrameIdx != INDEX_NONE); // We ensure above that Time < VertexAnimData.Last().Time // Interpolate between FrameIdx and FrameIdx-1 const FVertexAnimFrame& A = VertexAnimData[AfterFrameIdx-1]; const FVertexAnimFrame& B = VertexAnimData[AfterFrameIdx]; const float Alpha = (Time - A.Time)/(B.Time - A.Time); check(A.Deltas.Num() == NumAnimatedVerts); check(B.Deltas.Num() == NumAnimatedVerts); for(int32 DeltaIdx=0; DeltaIdx<NumAnimatedVerts; DeltaIdx++) { ImportVertDeltas[DeltaIdx] = FMath::Lerp<FVector>(A.Deltas[DeltaIdx], B.Deltas[DeltaIdx], Alpha); } } // So now we have all the position deltas for import verts, need to convert this into FVertexAnimDelta, one for each final vert. OutNumDeltas = BaseSkelMesh->GetImportedResource()->LODModels[0].MeshToImportVertexMap.Num(); for(int32 VertIdx=0; VertIdx<OutNumDeltas; VertIdx++) { int32 ImportIdx = BaseSkelMesh->GetImportedResource()->LODModels[0].MeshToImportVertexMap[VertIdx]; FVertexAnimDelta* Delta = VertAnimState->Deltas + VertIdx; Delta->PositionDelta = ImportVertDeltas[ImportIdx]; Delta->TangentZDelta = FVector::ZeroVector; Delta->SourceIdx = VertIdx; } return VertAnimState->Deltas; } else { return NULL; } }
bool FBuildPatchFileConstructor::InsertFileData(const FChunkPartData& ChunkPart, FArchive& DestinationFile, FSHA1& HashState) { bool bSuccess = false; bool bLogged = false; // Wait for the file data to be available while( IsFileDataAvailable( ChunkPart.Guid ) == false ) { FPlatformProcess::Sleep( 0.1f ); } // Read the file TArray<uint8> FileData; FChunkHeader Header; const FString DataFilename = GetFileDataFilename(ChunkPart.Guid); bSuccess = FFileHelper::LoadFileToArray(FileData, *DataFilename); if (!bSuccess && !bLogged) { bLogged = true; FBuildPatchAnalytics::RecordConstructionError(DataFilename, FPlatformMisc::GetLastError(), TEXT("File Data Missing")); GLog->Logf(TEXT("BuildPatchFileConstructor: ERROR: InsertFileData could not open data file %s"), *DataFilename); } // Decompress data bSuccess = bSuccess && FBuildPatchUtils::UncompressFileDataFile(FileData, &Header); if (!bSuccess && !bLogged) { bLogged = true; FBuildPatchAnalytics::RecordConstructionError(DataFilename, INDEX_NONE, TEXT("File Data Uncompress Fail")); GLog->Logf(TEXT("BuildPatchFileConstructor: ERROR: InsertFileData: could not uncompress %s"), *FPaths::GetCleanFilename(DataFilename)); } // Verify integrity bSuccess = bSuccess && FBuildPatchUtils::VerifyChunkFile(FileData); if (!bSuccess && !bLogged) { bLogged = true; FBuildPatchAnalytics::RecordConstructionError(DataFilename, INDEX_NONE, TEXT("File Data Verify Fail")); GLog->Logf(TEXT("BuildPatchFileConstructor: ERROR: InsertFileData: verification failed for %s"), *FPaths::GetCleanFilename(DataFilename)); } // Check correct GUID bSuccess = bSuccess && (!ChunkPart.Guid.IsValid() || (ChunkPart.Guid == Header.Guid)); if (!bSuccess && !bLogged) { bLogged = true; FBuildPatchAnalytics::RecordConstructionError(DataFilename, INDEX_NONE, TEXT("File Data GUID Mismatch")); GLog->Logf(TEXT("BuildPatchFileConstructor: ERROR: InsertFileData: mismatch GUID for %s"), *FPaths::GetCleanFilename(DataFilename)); } // Continue if all was fine if (bSuccess) { switch (Header.StoredAs) { case FChunkHeader::STORED_RAW: { // Check we are able to get the chunk part const int64 StartOfPartPos = Header.HeaderSize + ChunkPart.Offset; const int64 EndOfPartPos = StartOfPartPos + ChunkPart.Size; bSuccess = EndOfPartPos <= FileData.Num(); if (bSuccess) { HashState.Update(FileData.GetData() + StartOfPartPos, ChunkPart.Size); DestinationFile.Serialize(FileData.GetData() + StartOfPartPos, ChunkPart.Size); } else { FBuildPatchAnalytics::RecordConstructionError(DataFilename, INDEX_NONE, TEXT("File Data Part OOB")); GLog->Logf(TEXT("BuildPatchFileConstructor: ERROR: InsertFileData: part out of bounds for %s"), *FPaths::GetCleanFilename(DataFilename)); } } break; default: FBuildPatchAnalytics::RecordConstructionError(DataFilename, INDEX_NONE, TEXT("File Data Unknown Storage")); GLog->Logf(TEXT("BuildPatchFileConstructor: ERROR: InsertFileData: incorrect storage method %d %s"), Header.StoredAs, *FPaths::GetCleanFilename(DataFilename)); bSuccess = false; break; } } return bSuccess; }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FQuat& Quat, const struct FComponentQueryParams& Params) const { if (GetPhysicsScene() == NULL) { return false; } if (PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } OutHits.Reset(); #if UE_WITH_PHYSICS const FBodyInstance* BodyInstance = PrimComp->GetBodyInstance(); if (!BodyInstance || !BodyInstance->IsValidBodyInstance()) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetReadableName()); return false; } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(PrimComp->IsA(USkeletalMeshComponent::StaticClass())) { UE_LOG(LogCollision, Warning, TEXT("ComponentSweepMulti : SkeletalMeshComponent support only root body (%s) "), *PrimComp->GetReadableName()); } #endif #endif SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepMultiple); bool bHaveBlockingHit = false; #if WITH_PHYSX ExecuteOnPxRigidActorReadOnly(BodyInstance, [&] (const PxRigidActor* PRigidActor) { // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<16>> PShapes; PShapes.AddUninitialized(PRigidActor->getNbShapes()); PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); // calculate the test global pose of the actor const PxQuat PGeomRot = U2PQuat(Quat); const PxTransform PGlobalStartPose = PxTransform(U2PVector(Start), PGeomRot); const PxTransform PGlobalEndPose = PxTransform(U2PVector(End), PGeomRot); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if (PGeom != NULL) { // Calc shape global pose const PxTransform PLocalShape = PShape->getLocalPose(); const PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); const PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation const PxQuat PShapeRot = PGeomRot * PLocalShape.q; if (GeomSweepMulti_PhysX(this, *PGeom, PShapeRot, OutHits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } } } }); #endif //WITH_PHYSX //@TODO: BOX2D: Implement UWorld::ComponentSweepMulti #if WITH_BOX2D // if (b2Body* BodyInstance = PrimComp->BodyInstance.BodyInstancePtr) // { // // } #endif return bHaveBlockingHit; }
bool FFileTests::RunTest( const FString& Parameters ) { // Disabled for now, pending changes to make all platforms consistent. return true; const FString TempFilename = FPaths::EngineSavedDir() / FGuid::NewGuid().ToString(); TArray<uint8> TestData; TArray<uint8> ReadData; uint8 One = 1; FArchive* TestFile = nullptr; // We will test the platform abstraction class, IFileManager IFileManager& FileManager = IFileManager::Get(); // Ensure always starting off without test file existing FileManager.Delete(*TempFilename); check(FileManager.FileExists(*TempFilename) == false); // Check a new file can be created TestData.AddZeroed(64); TestFile = FileManager.CreateFileWriter(*TempFilename, 0); check(TestFile != nullptr); TestFile->Serialize(TestData.GetData(), TestData.Num()); delete TestFile; // Confirm same data check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); if(ReadData != TestData) { return false; } // Using append flag should open the file, and writing data immediatly should append to the end. // We should also be capable of seeking writing. TestData.Add(One); TestData[10] = One; TestFile = FileManager.CreateFileWriter(*TempFilename, EFileWrite::FILEWRITE_Append); check(TestFile != nullptr); TestFile->Serialize(&One, 1); TestFile->Seek(10); TestFile->Serialize(&One, 1); delete TestFile; // Confirm same data check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); if(ReadData != TestData) { return false; } // No flags should clobber existing file TestData.Empty(); TestData.Add(One); TestFile = FileManager.CreateFileWriter(*TempFilename, 0); check(TestFile != nullptr); TestFile->Serialize(&One, 1); delete TestFile; // Confirm same data check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); if(ReadData != TestData) { return false; } // Delete temp file FileManager.Delete(*TempFilename); return true; }
void SResponsiveGridPanel::ComputeDesiredCellSizes(float AvailableWidth, TArray<float>& OutColumns, TArray<float>& OutRows, TArray<float>& OutRowToSlot) const { FMemory::Memzero(OutColumns.GetData(), OutColumns.Num() * sizeof(float)); FMemory::Memzero(OutRows.GetData(), OutRows.Num() * sizeof(float)); int32 ColumnsSoFar = 0; int32 CurrentRow = INDEX_NONE; int32 LastRowParam = INDEX_NONE; for (int32 SlotIndex = 0; SlotIndex < Slots.Num(); ++SlotIndex) { const FSlot& CurSlot = Slots[SlotIndex]; if (CurSlot.GetWidget()->GetVisibility() != EVisibility::Collapsed) { // Find the appropriate column layout for the slot FSlot::FColumnLayout ColumnLayout; ColumnLayout.Span = TotalColumns; ColumnLayout.Offset = 0; for (int32 Index = CurSlot.ColumnLayouts.Num() - 1; Index >= 0; Index--) { if (CurSlot.ColumnLayouts[Index].LayoutSize < AvailableWidth) { ColumnLayout = CurSlot.ColumnLayouts[Index]; break; } } if (ColumnLayout.Span == 0) { continue; } if (CurSlot.RowParam != LastRowParam) { ColumnsSoFar = 0; LastRowParam = CurSlot.RowParam; ++CurrentRow; OutRowToSlot.AddZeroed((CurrentRow + 1) - OutRowToSlot.Num()); OutRowToSlot[CurrentRow] = CurSlot.RowParam; } // The slots want to be as big as its content along with the required padding. const FVector2D SlotDesiredSize = CurSlot.GetWidget()->GetDesiredSize() + CurSlot.SlotPadding.Get().GetDesiredSize(); // If the slot has a (colspan,rowspan) of (1,1) it will only affect that cell. // For larger spans, the slots size will be evenly distributed across all the affected cells. const FVector2D SizeContribution(SlotDesiredSize.X / ColumnLayout.Span, SlotDesiredSize.Y); int32 StartColumnIndex = ColumnsSoFar + ColumnLayout.Offset; int32 EndColumnIndex = StartColumnIndex + ColumnLayout.Span; ColumnsSoFar = FMath::Max(EndColumnIndex, ColumnsSoFar); if (ColumnsSoFar > TotalColumns) { StartColumnIndex = 0; EndColumnIndex = StartColumnIndex + ColumnLayout.Span; ColumnsSoFar = EndColumnIndex - StartColumnIndex; ++CurrentRow; OutRowToSlot.AddZeroed((CurrentRow + 1) - OutRowToSlot.Num()); OutRowToSlot[CurrentRow] = CurSlot.RowParam; } OutColumns.AddZeroed(FMath::Max(0, ColumnsSoFar - OutColumns.Num())); OutRows.AddZeroed((CurrentRow + 1) - OutRows.Num()); // Distribute the size contributions over all the columns and rows that this slot spans DistributeSizeContributions(SizeContribution.X, OutColumns, StartColumnIndex, EndColumnIndex); DistributeSizeContributions(SizeContribution.Y, OutRows, CurrentRow, CurrentRow + 1); } } }
void FEpicSurvey::OnReadFileComplete( bool bSuccess, const FString& DLName ) { if ( bSuccess ) { if ( DLName == SurveyIndexCloudFile.DLName ) { LoadSurveyIndexFile(); } else { int32 FileHeaderIndex = INDEX_NONE; TArray< FCloudFileHeader > FileHeaders; TitleCloud->GetFileList( FileHeaders ); for (int Index = 0; Index < FileHeaders.Num(); Index++) { if ( FileHeaders[ Index ].DLName == DLName ) { FileHeaderIndex = Index; break; } } if ( FileHeaderIndex > INDEX_NONE ) { const FCloudFileHeader FileHeader = FileHeaders[ FileHeaderIndex ]; const FString FileExtension = FPaths::GetExtension( FileHeader.FileName ); if ( FileExtension == TEXT("json") ) { TArray< uint8 > FileContents; TitleCloud->GetFileContents( DLName, FileContents ); FString SurveyJson; FFileHelper::BufferToString( SurveyJson, FileContents.GetData(), FileContents.Num() ); TSharedPtr< FJsonObject > SurveyObject = NULL; TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<TCHAR>::Create( SurveyJson ); if ( FJsonSerializer::Deserialize( Reader, SurveyObject ) ) { TSharedPtr< FSurvey > NewSurvey = FSurvey::Create( SharedThis( this ), SurveyObject.ToSharedRef() ); if ( NewSurvey.IsValid() ) { switch( NewSurvey->GetSurveyType() ) { case ESurveyType::Normal: { auto* Settings = GetDefault<UEditorSettings>(); Surveys.Add( NewSurvey.ToSharedRef() ); const bool IsActiveSurveyInProgress = ActiveSurvey.IsValid() ? Settings->InProgressSurveys.Contains( ActiveSurvey->GetIdentifier() ) : false; if ( !IsActiveSurveyInProgress ) { const bool HasBeenCompleted = Settings->CompletedSurveys.Contains( NewSurvey->GetIdentifier() ); if ( !HasBeenCompleted ) { const bool IsInProgress = Settings->InProgressSurveys.Contains( NewSurvey->GetIdentifier() ); if ( NewSurvey->CanAutoPrompt() ) { SetActiveSurvey( NewSurvey ); } else if ( IsInProgress ) { SetActiveSurvey( NewSurvey ); } } } } break; case ESurveyType::Branch: BranchSurveys.Add( FileHeader.FileName, NewSurvey ); break; } } } else { UE_LOG(LogEpicSurvey, Verbose, TEXT("Parsing JSON survey failed. Filename: %s Message: %s"), *FileHeader.FileName, *Reader->GetErrorMessage()); } } else if ( FileExtension == TEXT("png") ) { TArray< FOnBrushLoaded > MapResults; FilenameToLoadCallbacks.MultiFind( FileHeaders[ FileHeaderIndex ].FileName, MapResults ); if ( MapResults.Num() > 0 ) { TArray< uint8 > FileContents; TitleCloud->GetFileContents( DLName, FileContents ); for (int Index = 0; Index < MapResults.Num(); Index++) { MapResults[ Index ].Execute( LoadRawDataAsBrush( *(FString(TEXT("EpicSurvey.")) + FileHeaders[ FileHeaderIndex ].FileName), FileContents ) ); } FilenameToLoadCallbacks.Remove( FileHeaders[ FileHeaderIndex ].FileName ); } } } } } else { InitializationState = EContentInitializationState::Failure; } }
bool FWebJSScripting::HandleExecuteUObjectMethodMessage(CefRefPtr<CefListValue> MessageArguments) { FGuid ObjectKey; // Message arguments are Name, Value, bGlobal if (MessageArguments->GetSize() != 4 || MessageArguments->GetType(0) != VTYPE_STRING || MessageArguments->GetType(1) != VTYPE_STRING || MessageArguments->GetType(2) != VTYPE_STRING || MessageArguments->GetType(3) != VTYPE_LIST ) { // Wrong message argument types or count return false; } if (!FGuid::Parse(FString(MessageArguments->GetString(0).ToWString().c_str()), ObjectKey)) { // Invalid GUID return false; } // Get the promise callback and use that to report any results from executing this function. FGuid ResultCallbackId; if (!FGuid::Parse(FString(MessageArguments->GetString(2).ToWString().c_str()), ResultCallbackId)) { // Invalid GUID return false; } UObject* Object = GuidToPtr(ObjectKey); if (Object == nullptr) { // Unknown uobject id InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject ID")); return true; } FName MethodName = MessageArguments->GetString(1).ToWString().c_str(); UFunction* Function = Object->FindFunction(MethodName); if (!Function) { InvokeJSErrorResult(ResultCallbackId, TEXT("Unknown UObject Function")); return true; } // Coerce arguments to function arguments. uint16 ParamsSize = Function->ParmsSize; TArray<uint8> Params; UProperty* ReturnParam = nullptr; // Convert cef argument list to a dictionary, so we can use FStructDeserializer to convert it for us CefRefPtr<CefDictionaryValue> NamedArgs = CefDictionaryValue::Create(); { int32 CurrentArg = 0; CefRefPtr<CefListValue> CefArgs = MessageArguments->GetList(3); for ( TFieldIterator<UProperty> It(Function); It; ++It ) { UProperty* Param = *It; if (Param->PropertyFlags & CPF_Parm) { if (Param->PropertyFlags & CPF_ReturnParm) { ReturnParam = Param; } else { CopyContainerValue(NamedArgs, CefArgs, CefString(*Param->GetName()), CurrentArg); CurrentArg++; } } } if (ParamsSize > 0) { // UFunction is a subclass of UStruct, so we can treat the arguments as a struct for deserialization UStruct* TypeInfo = Cast<UStruct>(Function); Params.AddUninitialized(ParamsSize); TypeInfo->InitializeStruct(Params.GetData()); FWebJSStructDeserializerBackend Backend = FWebJSStructDeserializerBackend(SharedThis(this), NamedArgs); FStructDeserializer::Deserialize(Params.GetData(), *TypeInfo, Backend); } } Object->ProcessEvent(Function, Params.GetData()); if ( ReturnParam ) { FWebJSParam Results[1] = {ConvertResult(ReturnParam, Params.GetData())}; InvokeJSFunction(ResultCallbackId, 1, Results, false); } else { InvokeJSFunction(ResultCallbackId, 0, nullptr, false); } return true; }
void FIndirectLightingCache::UpdateBlock(FScene* Scene, FViewInfo* DebugDrawingView, FBlockUpdateInfo& BlockInfo) { const int32 NumSamplesPerBlock = BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize; FSHVectorRGB2 SingleSample; float DirectionalShadowing = 1; FVector SkyBentNormal(0, 0, 1); if (CanIndirectLightingCacheUseVolumeTexture(GetFeatureLevel()) && !BlockInfo.Allocation->bPointSample) { static TArray<float> AccumulatedWeight; AccumulatedWeight.Reset(NumSamplesPerBlock); AccumulatedWeight.AddZeroed(NumSamplesPerBlock); static TArray<FSHVectorRGB2> AccumulatedIncidentRadiance; AccumulatedIncidentRadiance.Reset(NumSamplesPerBlock); AccumulatedIncidentRadiance.AddZeroed(NumSamplesPerBlock); static TArray<FVector> AccumulatedSkyBentNormal; AccumulatedSkyBentNormal.Reset(NumSamplesPerBlock); AccumulatedSkyBentNormal.AddZeroed(NumSamplesPerBlock); // Interpolate SH samples from precomputed lighting samples and accumulate lighting data for an entire block InterpolateBlock(Scene, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance, AccumulatedSkyBentNormal); static TArray<FFloat16Color> Texture0Data; static TArray<FFloat16Color> Texture1Data; static TArray<FFloat16Color> Texture2Data; Texture0Data.Reset(NumSamplesPerBlock); Texture1Data.Reset(NumSamplesPerBlock); Texture2Data.Reset(NumSamplesPerBlock); Texture0Data.AddUninitialized(NumSamplesPerBlock); Texture1Data.AddUninitialized(NumSamplesPerBlock); Texture2Data.AddUninitialized(NumSamplesPerBlock); const int32 FormatSize = GPixelFormats[PF_FloatRGBA].BlockBytes; check(FormatSize == sizeof(FFloat16Color)); // Encode the SH samples into a texture format // Note the single sample is updated even if this is a volume allocation, because translucent materials only use the single sample EncodeBlock(DebugDrawingView, BlockInfo.Block, AccumulatedWeight, AccumulatedIncidentRadiance, AccumulatedSkyBentNormal, Texture0Data, Texture1Data, Texture2Data, SingleSample, SkyBentNormal); // Setup an update region const FUpdateTextureRegion3D UpdateRegion( BlockInfo.Block.MinTexel.X, BlockInfo.Block.MinTexel.Y, BlockInfo.Block.MinTexel.Z, 0, 0, 0, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize, BlockInfo.Block.TexelSize); // Update the volume texture atlas RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture0().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture0Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture1().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture1Data.GetData()); RHIUpdateTexture3D((const FTexture3DRHIRef&)GetTexture2().ShaderResourceTexture, 0, UpdateRegion, BlockInfo.Block.TexelSize * FormatSize, BlockInfo.Block.TexelSize * BlockInfo.Block.TexelSize * FormatSize, (const uint8*)Texture2Data.GetData()); } else { InterpolatePoint(Scene, BlockInfo.Block, DirectionalShadowing, SingleSample, SkyBentNormal); if (GCacheDrawInterpolationPoints != 0 && DebugDrawingView) { FViewElementPDI DebugPDI(DebugDrawingView, NULL); const FVector WorldPosition = BlockInfo.Block.Min; DebugPDI.DrawPoint(WorldPosition, FLinearColor(0, 0, 1), 10, SDPG_World); } } // Record the position that the sample was taken at BlockInfo.Allocation->TargetPosition = BlockInfo.Block.Min + BlockInfo.Block.Size / 2; BlockInfo.Allocation->TargetSamplePacked[0] = FVector4(SingleSample.R.V[0], SingleSample.R.V[1], SingleSample.R.V[2], SingleSample.R.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked[1] = FVector4(SingleSample.G.V[0], SingleSample.G.V[1], SingleSample.G.V[2], SingleSample.G.V[3]) / PI; BlockInfo.Allocation->TargetSamplePacked[2] = FVector4(SingleSample.B.V[0], SingleSample.B.V[1], SingleSample.B.V[2], SingleSample.B.V[3]) / PI; BlockInfo.Allocation->TargetDirectionalShadowing = DirectionalShadowing; const float BentNormalLength = SkyBentNormal.Size(); BlockInfo.Allocation->TargetSkyBentNormal = FVector4(SkyBentNormal / FMath::Max(BentNormalLength, .0001f), BentNormalLength); if (!BlockInfo.Allocation->bHasEverUpdatedSingleSample) { // If this is the first update, also set the interpolated state to match the new target //@todo - detect and handle teleports in the same way BlockInfo.Allocation->SingleSamplePosition = BlockInfo.Allocation->TargetPosition; for (int32 VectorIndex = 0; VectorIndex < ARRAY_COUNT(BlockInfo.Allocation->SingleSamplePacked); VectorIndex++) { BlockInfo.Allocation->SingleSamplePacked[VectorIndex] = BlockInfo.Allocation->TargetSamplePacked[VectorIndex]; } BlockInfo.Allocation->CurrentDirectionalShadowing = BlockInfo.Allocation->TargetDirectionalShadowing; BlockInfo.Allocation->CurrentSkyBentNormal = BlockInfo.Allocation->TargetSkyBentNormal; BlockInfo.Allocation->bHasEverUpdatedSingleSample = true; } BlockInfo.Block.bHasEverBeenUpdated = true; }
/** * 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; // 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.GetData(), physx::NxRenderDataFormat::FLOAT3, sizeof(FVector), NormalBufferIndex, 0, SubmeshVertexCount); if (!bHaveNormals) { FMemory::Memset(Normals.GetData(), 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.GetData(), physx::NxRenderDataFormat::FLOAT3, sizeof(FVector), TangentBufferIndex, 0, SubmeshVertexCount); if (!bHaveTangents) { FMemory::Memset(Tangents.GetData(), 0, SubmeshVertexCount*sizeof(FVector)); // Fill with zeros } // Update bHaveAllNormals and bHaveAllTangents bHaveAllNormals = bHaveAllNormals && bHaveNormals; bHaveAllTangents = bHaveAllTangents && bHaveTangents; // Binormomals const PxI32 BinormalBufferIndex = VBFormat.getBufferIndexFromID(VBFormat.getSemanticID(NxRenderVertexSemantic::BINORMAL)); TArray<FVector> Binormals; Binormals.AddUninitialized(SubmeshVertexCount); bool bHaveBinormals = VB.getBufferData(Binormals.GetData(), 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.GetData(), physx::NxRenderDataFormat::B8G8R8A8, sizeof(FColor), ColorBufferIndex, 0, SubmeshVertexCount); if (!bHaveColors) { FMemory::Memset(Colors.GetData(), 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 Triangle.MatIndex = SubmeshIndex; Triangle.AuxMatIndex = 0; // Per-vertex for (uint32 V = 0; V < 3; ++V) { // Tangent basis Triangle.TangentX[V] = Tangents[SubmeshVertexIndex[V]]; Triangle.TangentY[V] = Binormals[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; } // 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; }
bool FReferenceChainSearch::ProcessObject( UObject* CurrentObject ) { // Make sure that token stream has been assembled at this point as the below code relies on it. if ( !CurrentObject->GetClass()->HasAnyClassFlags(CLASS_TokenStreamAssembled) ) { CurrentObject->GetClass()->AssembleReferenceTokenStream(); check(CurrentObject->GetClass()->HasAnyClassFlags(CLASS_TokenStreamAssembled)); } // Get pointer to token stream and jump to the start. FGCReferenceTokenStream* RESTRICT TokenStream = &CurrentObject->GetClass()->ReferenceTokenStream; uint32 TokenStreamIndex = 0; // Keep track of index to reference info. Used to avoid LHSs. uint32 ReferenceTokenStreamIndex = 0; TArray<FStackEntry> Stack; Stack.AddUninitialized( 128 ); // Create strack entry and initialize sane values. FStackEntry* RESTRICT StackEntry = Stack.GetData(); uint8* StackEntryData = (uint8*) CurrentObject; StackEntry->Data = StackEntryData; StackEntry->Stride = 0; StackEntry->Count = -1; StackEntry->LoopStartIndex = -1; // Keep track of token return count in separate integer as arrays need to fiddle with it. int32 TokenReturnCount = 0; bool bRetVal = false; UProperty* InArrayProp = NULL; ReferenceMap.Add(CurrentObject, TArray<FReferenceChainLink>()); TArray<FReferenceChainLink>* ReferenceList = ReferenceMap.Find(CurrentObject); // Parse the token stream. while( true ) { // Cache current token index as it is the one pointing to the reference info. ReferenceTokenStreamIndex = TokenStreamIndex; // Handle returning from an array of structs, array of structs of arrays of ... (yadda yadda) for( int32 ReturnCount=0; ReturnCount<TokenReturnCount; ReturnCount++ ) { // Make sure there's no stack underflow. check( StackEntry->Count != -1 ); // We pre-decrement as we're already through the loop once at this point. if( --StackEntry->Count > 0 ) { // Point data to next entry. StackEntryData = StackEntry->Data + StackEntry->Stride; StackEntry->Data = StackEntryData; // Jump back to the beginning of the loop. TokenStreamIndex = StackEntry->LoopStartIndex; ReferenceTokenStreamIndex = StackEntry->LoopStartIndex; // We're not done with this token loop so we need to early out instead of backing out further. break; } else { StackEntry--; StackEntryData = StackEntry->Data; InArrayProp = NULL; } } // Instead of reading information about reference from stream and caching it like below we access // the same memory address over and over and over again to avoid a nasty LHS penalty. Not reading // the reference info means we need to manually increment the token index to skip to the next one. TokenStreamIndex++; // Helper to make code more readable and hide the ugliness that is avoiding LHSs from caching. #define REFERENCE_INFO TokenStream->AccessReferenceInfo( ReferenceTokenStreamIndex ) uint32 Offset = REFERENCE_INFO.Offset; // Get the property from token stream UProperty* Prop = Internal::FindPropertyForOffset(CurrentObject->GetClass(), Offset); if (InArrayProp != NULL && Prop == NULL) { Prop = InArrayProp; } if( REFERENCE_INFO.Type == GCRT_Object ) { // We're dealing with an object reference. UObject** ObjectPtr = (UObject**)(StackEntryData + Offset); UObject*& Object = *ObjectPtr; TokenReturnCount = REFERENCE_INFO.ReturnCount; FReferenceChainLink TopRef(ReferenceTokenStreamIndex, InArrayProp != NULL ? EReferenceType::ArrayProperty : EReferenceType::Property, CurrentObject, Prop, Object); AddToReferenceList(ReferenceList, TopRef); } else if( REFERENCE_INFO.Type == GCRT_ArrayObject ) { // We're dealing with an array of object references. TArray<UObject*>& ObjectArray = *((TArray<UObject*>*)(StackEntryData + Offset)); TokenReturnCount = REFERENCE_INFO.ReturnCount; for( int32 ObjectIndex=0; ObjectIndex<ObjectArray.Num(); ObjectIndex++ ) { UObject*& Object = ObjectArray[ObjectIndex]; FReferenceChainLink TopRef(ReferenceTokenStreamIndex, EReferenceType::ArrayProperty, CurrentObject, Prop, Object, ObjectIndex); AddToReferenceList(ReferenceList, TopRef); } } else if( REFERENCE_INFO.Type == GCRT_ArrayStruct ) { InArrayProp = Prop; // We're dealing with a dynamic array of structs. const FScriptArray& Array = *((FScriptArray*)(StackEntryData + Offset)); StackEntry++; StackEntryData = (uint8*) Array.GetData(); StackEntry->Data = StackEntryData; StackEntry->Stride = TokenStream->ReadStride( TokenStreamIndex ); StackEntry->Count = Array.Num(); const FGCSkipInfo SkipInfo = TokenStream->ReadSkipInfo( TokenStreamIndex ); StackEntry->LoopStartIndex = TokenStreamIndex; if( StackEntry->Count == 0 ) { // Skip empty array by jumping to skip index and set return count to the one about to be read in. TokenStreamIndex = SkipInfo.SkipIndex; TokenReturnCount = TokenStream->GetSkipReturnCount( SkipInfo ); } else { // Loop again. check( StackEntry->Data ); TokenReturnCount = 0; } } else if( REFERENCE_INFO.Type == GCRT_PersistentObject ) { // We're dealing with an object reference. UObject** ObjectPtr = (UObject**)(StackEntryData + Offset); UObject*& Object = *ObjectPtr; TokenReturnCount = REFERENCE_INFO.ReturnCount; FReferenceChainLink TopRef(ReferenceTokenStreamIndex, InArrayProp != NULL ? EReferenceType::ArrayProperty : EReferenceType::Property, CurrentObject, Prop, Object); AddToReferenceList(ReferenceList, TopRef); } else if( REFERENCE_INFO.Type == GCRT_FixedArray ) { InArrayProp = Prop; // We're dealing with a fixed size array uint8* PreviousData = StackEntryData; StackEntry++; StackEntryData = PreviousData; StackEntry->Data = PreviousData; StackEntry->Stride = TokenStream->ReadStride( TokenStreamIndex ); StackEntry->Count = TokenStream->ReadCount( TokenStreamIndex ); StackEntry->LoopStartIndex = TokenStreamIndex; TokenReturnCount = 0; } else if( REFERENCE_INFO.Type == GCRT_AddStructReferencedObjects ) { // We're dealing with a function call void const* StructPtr = (void*)(StackEntryData + Offset); TokenReturnCount = REFERENCE_INFO.ReturnCount; UScriptStruct::ICppStructOps::TPointerToAddStructReferencedObjects Func = (UScriptStruct::ICppStructOps::TPointerToAddStructReferencedObjects) TokenStream->ReadPointer( TokenStreamIndex ); FFindReferencerCollector ReferenceCollector(this, EReferenceType::StructARO, (void*)Func, CurrentObject); Func(StructPtr, ReferenceCollector); for (int32 i=0; i < ReferenceCollector.References.Num(); ++i) { AddToReferenceList(ReferenceList, ReferenceCollector.References[i]); } } else if( REFERENCE_INFO.Type == GCRT_AddReferencedObjects ) { // Static AddReferencedObjects function call. void (*AddReferencedObjects)(UObject*, FReferenceCollector&) = (void(*)(UObject*, FReferenceCollector&))TokenStream->ReadPointer( TokenStreamIndex ); TokenReturnCount = REFERENCE_INFO.ReturnCount; FFindReferencerCollector ReferenceCollector(this, EReferenceType::ARO, (void*)AddReferencedObjects, CurrentObject); AddReferencedObjects(CurrentObject, ReferenceCollector); for (int32 i=0; i < ReferenceCollector.References.Num(); ++i) { AddToReferenceList(ReferenceList, ReferenceCollector.References[i]); } } else if( REFERENCE_INFO.Type == GCRT_AddTMapReferencedObjects ) { void* Map = StackEntryData + REFERENCE_INFO.Offset; UMapProperty* MapProperty = (UMapProperty*)TokenStream->ReadPointer( TokenStreamIndex ); TokenReturnCount = REFERENCE_INFO.ReturnCount; FFindReferencerCollector ReferenceCollector(this, EReferenceType::MapProperty, (void*)MapProperty, CurrentObject); FSimpleObjectReferenceCollectorArchive CollectorArchive(CurrentObject, ReferenceCollector); MapProperty->SerializeItem(CollectorArchive, Map, nullptr); for (const FReferenceChainLink& Ref : ReferenceCollector.References) { AddToReferenceList(ReferenceList, Ref); } } else if (REFERENCE_INFO.Type == GCRT_EndOfPointer) { TokenReturnCount = REFERENCE_INFO.ReturnCount; } else if( REFERENCE_INFO.Type == GCRT_EndOfStream ) { // Break out of loop. break; } else { UE_LOG(LogReferenceChain, Fatal,TEXT("Unknown token")); } } check(StackEntry == Stack.GetData()); return bRetVal; }
const bool FChunkWriter::FQueuedChunkWriter::WriteChunkData(const FString& ChunkFilename, FChunkFile* ChunkFile, const FGuid& ChunkGuid) { // Chunks are saved with GUID, so if a file already exists it will never be different. // Skip with return true if already exists if( FPaths::FileExists( ChunkFilename ) ) { const int64 ChunkFilesSize = IFileManager::Get().FileSize(*ChunkFilename); ChunkFileSizesCS.Lock(); ChunkFileSizes.Add(ChunkGuid, ChunkFilesSize); ChunkFileSizesCS.Unlock(); return true; } FArchive* FileOut = IFileManager::Get().CreateFileWriter( *ChunkFilename ); bool bSuccess = FileOut != NULL; if( bSuccess ) { // Setup to handle compression bool bDataIsCompressed = true; uint8* ChunkDataSource = ChunkFile->ChunkData; int32 ChunkDataSourceSize = FBuildPatchData::ChunkDataSize; TArray< uint8 > TempCompressedData; TempCompressedData.Empty( ChunkDataSourceSize ); TempCompressedData.AddUninitialized( ChunkDataSourceSize ); int32 CompressedSize = ChunkDataSourceSize; // Compressed can increase in size, but the function will return as failure in that case // we can allow that to happen since we would not keep larger compressed data anyway. bDataIsCompressed = FCompression::CompressMemory( static_cast< ECompressionFlags >( COMPRESS_ZLIB | COMPRESS_BiasMemory ), TempCompressedData.GetData(), CompressedSize, ChunkFile->ChunkData, FBuildPatchData::ChunkDataSize ); // If compression succeeded, set data vars if( bDataIsCompressed ) { ChunkDataSource = TempCompressedData.GetData(); ChunkDataSourceSize = CompressedSize; } // Setup Header FChunkHeader& Header = ChunkFile->ChunkHeader; *FileOut << Header; Header.HeaderSize = FileOut->Tell(); Header.StoredAs = bDataIsCompressed ? FChunkHeader::STORED_COMPRESSED : FChunkHeader::STORED_RAW; Header.DataSize = ChunkDataSourceSize; Header.HashType = FChunkHeader::HASH_ROLLING; // Write out files FileOut->Seek( 0 ); *FileOut << Header; FileOut->Serialize( ChunkDataSource, ChunkDataSourceSize ); const int64 ChunkFilesSize = FileOut->TotalSize(); FileOut->Close(); ChunkFileSizesCS.Lock(); ChunkFileSizes.Add(ChunkGuid, ChunkFilesSize); ChunkFileSizesCS.Unlock(); bSuccess = !FileOut->GetError(); delete FileOut; } // Log errors if( !bSuccess ) { GLog->Logf( TEXT( "BuildPatchServices: Error: Could not save out generated chunk file %s" ), *ChunkFilename ); } return bSuccess; }
void FSlateOpenGLTexture::UpdateTexture(const TArray<uint8>& Bytes) { UpdateTextureRaw(Bytes.GetData(), FIntRect()); }
void TermGamePhys() { #if WITH_BOX2D FPhysicsIntegration2D::ShutdownPhysics(); #endif #if WITH_PHYSX FPhysxSharedData::Terminate(); // Do nothing if they were never initialized if(GPhysXFoundation == NULL) { return; } if (GPhysCommandHandler != NULL) { GPhysCommandHandler->Flush(); //finish off any remaining commands FCoreUObjectDelegates::PreGarbageCollect.Remove(GPreGarbageCollectDelegateHandle); delete GPhysCommandHandler; GPhysCommandHandler = NULL; } #if WITH_APEX #if WITH_APEX_LEGACY if(GApexModuleLegacy != NULL) { GApexModuleLegacy->release(); GApexModuleLegacy = NULL; } #endif // WITH_APEX_LEGACY if(GApexSDK != NULL) { GApexSDK->release(); GApexSDK = NULL; } #endif // #if WITH_APEX //Remove all scenes still registered if (int32 NumScenes = GPhysXSDK->getNbScenes()) { TArray<PxScene*> PScenes; PScenes.AddUninitialized(NumScenes); GPhysXSDK->getScenes(PScenes.GetData(), sizeof(PxScene*)* NumScenes); for (PxScene* PScene : PScenes) { if (PScene) { PScene->release(); } } } #if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING if(GPhysXCooking != NULL) { GPhysXCooking->release(); GPhysXCooking = NULL; } #endif PxCloseExtensions(); PxCloseVehicleSDK(); if(GPhysXSDK != NULL) { GPhysXSDK->release(); GPhysXSDK = NULL; } // @todo delete FPhysXAllocator // @todo delete FPhysXOutputStream UnloadPhysXModules(); #endif }