コード例 #1
0
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);
					}
				}
			}
		}
	}
}
コード例 #2
0
	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);
	}
コード例 #3
0
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;
}
コード例 #4
0
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;
}
コード例 #5
0
	/**
	* 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;
	}
コード例 #6
0
//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());
}
コード例 #7
0
					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);
コード例 #8
0
/**
 * 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();
	}
}
コード例 #9
0
	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));
	}
コード例 #10
0
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;
}
コード例 #11
0
	/** 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()
				);
		}
	}
コード例 #12
0
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();
    }
}
コード例 #13
0
ファイル: SkeletalMeshImport.cpp プロジェクト: johndpope/UE4
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);
	}
}
コード例 #14
0
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();
}
コード例 #16
0
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();
}
コード例 #17
0
	void UnchunkSkeletalModel(TArray<FSkinnedMeshChunk*>& Chunks, TArray<int32>& PointToOriginalMap, const FSkinnedModelData& SrcModel)
	{
	#if WITH_EDITORONLY_DATA
		const TArray<FSoftSkinVertex>& SrcVertices = SrcModel.Vertices;
		const TArray<uint32>& SrcIndices = SrcModel.Indices;
		TArray<uint32> IndexMap;

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

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

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

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

			int32 NumIndicesThisSection = Section.NumTriangles * 3;
			for (uint32 SrcIndex = Section.BaseIndex; SrcIndex < Section.BaseIndex + NumIndicesThisSection; ++SrcIndex)
			{
				uint32 VertexIndex = SrcIndices[SrcIndex];
				uint32 DestVertexIndex = IndexMap[VertexIndex];
				if (DestVertexIndex == INDEX_NONE)
				{
					FSoftSkinBuildVertex NewVertex;
					const FSoftSkinVertex& SrcVertex = SrcVertices[VertexIndex];
					NewVertex.Position = SrcVertex.Position;
					NewVertex.TangentX = SrcVertex.TangentX;
					NewVertex.TangentY = SrcVertex.TangentY;
					NewVertex.TangentZ = SrcVertex.TangentZ;
					FMemory::Memcpy(NewVertex.UVs, SrcVertex.UVs, sizeof(FVector2D)*MAX_TEXCOORDS);
					NewVertex.Color = SrcVertex.Color;
					for (int32 i = 0; i < MAX_TOTAL_INFLUENCES; ++i)
					{
						uint8 BoneIndex = SrcVertex.InfluenceBones[i];
						check(BoneMap.IsValidIndex(BoneIndex));
						NewVertex.InfluenceBones[i] = BoneMap[BoneIndex];
						NewVertex.InfluenceWeights[i] = SrcVertex.InfluenceWeights[i];
					}
					NewVertex.PointWedgeIdx = SrcModel.RawPointIndices.Num() ? SrcModel.RawPointIndices[VertexIndex] : 0;
					int32 RawVertIndex = SrcModel.MeshToImportVertexMap.Num() ? SrcModel.MeshToImportVertexMap[VertexIndex] : INDEX_NONE;
					if ((int32)NewVertex.PointWedgeIdx >= PointToOriginalMap.Num())
					{
						PointToOriginalMap.AddZeroed(NewVertex.PointWedgeIdx + 1 - PointToOriginalMap.Num());
					}
					PointToOriginalMap[NewVertex.PointWedgeIdx] = RawVertIndex;				
					DestVertexIndex = AddSkinVertex(DestChunk->Vertices,NewVertex,/*bKeepOverlappingVertices=*/ false);
					IndexMap[VertexIndex] = DestVertexIndex;
				}
				DestChunk->Indices.Add(DestVertexIndex);
			}
		}
	#endif // #if WITH_EDITORONLY_DATA
	}
コード例 #18
0
/** 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;
	}
}
コード例 #19
0
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;
}
コード例 #20
0
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;
}
コード例 #21
0
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;
}
コード例 #22
0
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);
		}
	}
}
コード例 #23
0
ファイル: EpicSurvey.cpp プロジェクト: aovi/UnrealEngine4
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;
	}
}
コード例 #24
0
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;
}
コード例 #25
0
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;
}
コード例 #26
0
/**
 * 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;
}
コード例 #27
0
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;
}
コード例 #28
0
ファイル: BuildPatchChunk.cpp プロジェクト: johndpope/UE4
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;
}
コード例 #29
0
void FSlateOpenGLTexture::UpdateTexture(const TArray<uint8>& Bytes)
{
	UpdateTextureRaw(Bytes.GetData(), FIntRect());
}
コード例 #30
0
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
}