// Copyright Epic Games, Inc. All Rights Reserved. #include "UnitTest.h" #include "LMkDOP.h" #include "Math/LMOctree.h" #include "UnrealLightmass.h" #include "HAL/Runnable.h" #include "HAL/RunnableThread.h" #include "HAL/PlatformTime.h" #include "HAL/PlatformProcess.h" #include "Misc/Guid.h" #include "LightmassScene.h" namespace Lightmass { /** Defines how the light is stored in the scene's light octree. */ struct FTestOctreeSemantics { enum { MaxElementsPerLeaf = 16 }; enum { MinInclusiveElementsPerNode = 7 }; enum { MaxNodeDepth = 12 }; enum { LoosenessDenominator = 16 }; typedef TInlineAllocator ElementAllocator; FORCEINLINE static FBoxCenterAndExtent GetBoundingBox(const float& Element) { return FBoxCenterAndExtent(FVector4f(0), FVector4f(Element)); } FORCEINLINE static bool AreElementsEqual(const float& A,const float& B) { return A == B; } }; class FTestCollisionDataProvider { TkDOPTree& kDOP; FVector4f Vertex; public: FTestCollisionDataProvider(TkDOPTree& InkDOP) : kDOP(InkDOP) , Vertex(0) { } /** * Given an index, returns the position of the vertex * * @param Index the index into the vertices array */ FORCEINLINE const FVector4f& GetVertex(uint16 Index) const { return Vertex; } /** Returns additional information. */ FORCEINLINE int32 GetItemIndex(uint16 MaterialIndex) const { return 0; } /** * Returns the kDOPTree for this mesh */ FORCEINLINE const TkDOPTree& GetkDOPTree(void) const { return kDOP; } /** * Returns the local to world for the component */ FORCEINLINE const FMatrix44f& GetLocalToWorld(void) const { return FMatrix44f::Identity; } /** * Returns the world to local for the component */ FORCEINLINE const FMatrix44f GetWorldToLocal(void) const { return FMatrix44f::Identity; } /** * Returns the local to world transpose adjoint for the component */ FORCEINLINE FMatrix44f GetLocalToWorldTransposeAdjoint(void) const { return FMatrix44f::Identity; } /** * Returns the determinant for the component */ FORCEINLINE float GetDeterminant(void) const { return 0.0f; } }; class FTestRunnable : public FRunnable { bool bStop; public: virtual bool Init(void) { bStop = false; return true; } virtual uint32 Run(void) { for (int32 i = 0; i < 10 && !bStop; i++) { UE_LOG(LogLightmass, Display, TEXT("Thread counter %d"), i); FPlatformProcess::Sleep(1.0f); } UE_LOG(LogLightmass, Display, TEXT("Thread done!!")); return 0; } virtual void Stop(void) { bStop = true; } virtual void Exit(void) { } }; void TestLightmass() { UE_LOG(LogLightmass, Display, TEXT("\n\n")); UE_LOG(LogLightmass, Display, TEXT("===============================================================================================")); UE_LOG(LogLightmass, Display, TEXT("Running \"unit test\". This will take several seconds, and will end with an assertion.")); UE_LOG(LogLightmass, Display, TEXT("This is on purpose, as it's testing the callstack gathering...")); UE_LOG(LogLightmass, Display, TEXT("===============================================================================================")); UE_LOG(LogLightmass, Display, TEXT("\n\n")); void* Buf = FMemory::Malloc(1024); TArray TestArray; TestArray.Add(5); TArray ArrayCopy = TestArray; FVector4f TestVectorA(1, 0, 0, 1); FVector4f TestVectorB(1, 1, 1, 1); FVector4f TestVector = TestVectorA + TestVectorB; FString TestString = FString::Printf(TEXT("Copy has %d, Vector is [%.2f, %.2f, %.2f, %.2f]\n"), ArrayCopy[0], TestVector.X, TestVector.Y, TestVector.Z, TestVector.W); printf("%s", TCHAR_TO_UTF8(*TestString)); FMemory::Free(Buf); struct FAlignTester { uint8 A; FMatrix44f M1; uint8 B; FMatrix44f M2; uint8 C; FVector4f V; }; FAlignTester AlignTest; checkf(((PTRINT)(&FMatrix44f::Identity) & 15) == 0, TEXT("Identity matrix unaligned")); checkf(((PTRINT)(&AlignTest.M1) & 15) == 0, TEXT("First matrix unaligned")); checkf(((PTRINT)(&AlignTest.M2) & 15) == 0, TEXT("Second matrix unaligned")); checkf(((PTRINT)(&AlignTest.V) & 15) == 0, TEXT("Vector unaligned")); FGuid Guid(1, 2, 3, 4); UE_LOG(LogLightmass, Display, TEXT("Guid is %s"), *Guid.ToString()); TMap TestMap; TestMap.Add(FString(TEXT("Five")), 5); TestMap.Add(TEXT("Ten"), 10); UE_LOG(LogLightmass, Display, TEXT("Map[Five] = %d, Map[Ten] = %d"), TestMap.FindRef(TEXT("Five")), TestMap.FindRef(FString(TEXT("Ten")))); FMatrix44f TestMatrix(FVector3f(0, 0, 0.1f), FVector3f(0, 1.0f, 0), FVector3f(0.9f, 0, 0), FVector3f(0, 0, 0)); UE_LOG(LogLightmass, Display, TEXT("Mat=\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]"), TestMatrix.M[0][0], TestMatrix.M[0][1], TestMatrix.M[0][2], TestMatrix.M[0][3], TestMatrix.M[1][0], TestMatrix.M[1][1], TestMatrix.M[1][2], TestMatrix.M[1][3], TestMatrix.M[2][0], TestMatrix.M[2][1], TestMatrix.M[2][2], TestMatrix.M[2][3], TestMatrix.M[3][0], TestMatrix.M[3][1], TestMatrix.M[3][2], TestMatrix.M[3][3] ); TestMatrix = TestMatrix.GetTransposed(); UE_LOG(LogLightmass, Display, TEXT("Transposed Mat=\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]"), TestMatrix.M[0][0], TestMatrix.M[0][1], TestMatrix.M[0][2], TestMatrix.M[0][3], TestMatrix.M[1][0], TestMatrix.M[1][1], TestMatrix.M[1][2], TestMatrix.M[1][3], TestMatrix.M[2][0], TestMatrix.M[2][1], TestMatrix.M[2][2], TestMatrix.M[2][3], TestMatrix.M[3][0], TestMatrix.M[3][1], TestMatrix.M[3][2], TestMatrix.M[3][3] ); TestMatrix = TestMatrix.GetTransposed().InverseFast(); UE_LOG(LogLightmass, Display, TEXT("Inverted Mat=\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]"), TestMatrix.M[0][0], TestMatrix.M[0][1], TestMatrix.M[0][2], TestMatrix.M[0][3], TestMatrix.M[1][0], TestMatrix.M[1][1], TestMatrix.M[1][2], TestMatrix.M[1][3], TestMatrix.M[2][0], TestMatrix.M[2][1], TestMatrix.M[2][2], TestMatrix.M[2][3], TestMatrix.M[3][0], TestMatrix.M[3][1], TestMatrix.M[3][2], TestMatrix.M[3][3] ); UE_LOG(LogLightmass, Display, TEXT("sizeof FDirectionalLight = %d, FLight = %d, FDirectionalLightData = %d"), sizeof(FDirectionalLight), sizeof(FLight), sizeof(FDirectionalLightData)); TOctree TestOctree(FVector4f(0), 10.0f); TestOctree.AddElement(5); // kDOP test TkDOPTree TestkDOP; FTestCollisionDataProvider TestDataProvider(TestkDOP); FHitResult TestResult; FkDOPBuildCollisionTriangle TestTri(0, FVector4f(0,0,0,0), FVector4f(1,1,1,0), FVector4f(2,2,2,0), INDEX_NONE, INDEX_NONE, INDEX_NONE, false, true); TArray > TestTriangles; TestTriangles.Add(TestTri); TestkDOP.Build(TestTriangles); UE_LOG(LogLightmass, Display, TEXT("\nStarting a thread")); FTestRunnable* TestRunnable = new FTestRunnable; // create a thread with the test runnable, and let it auto-delete itself FRunnableThread* TestThread = FRunnableThread::Create(TestRunnable, TEXT("TestRunnable")); double Start = FPlatformTime::Seconds(); UE_LOG(LogLightmass, Display, TEXT("\nWaiting 4 seconds"), Start); FPlatformProcess::Sleep(4.0f); UE_LOG(LogLightmass, Display, TEXT("%.2f seconds have passed, killing thread"), FPlatformTime::Seconds() - Start); // wait for thread to end double KillStart = FPlatformTime::Seconds(); TestRunnable->Stop(); TestThread->WaitForCompletion(); delete TestThread; delete TestRunnable; UE_LOG(LogLightmass, Display, TEXT("It took %.2f seconds to kill the thread [should be < 1 second]"), FPlatformTime::Seconds() - KillStart); UE_LOG(LogLightmass, Display, TEXT("\n\n")); checkf(5 == 2, TEXT("And boom goes the dynamite\n")); } } // namespace