// SPDX-FileCopyrightText: 2021 Jorrit Rouwe // SPDX-License-Identifier: MIT #include #include #include #include #ifdef JPH_PLATFORM_WINDOWS #include #endif // JPH_PLATFORM_WINDOWS #ifdef JPH_PLATFORM_ANDROID #include #include #include #endif // JPH_PLATFORM_ANDROID JPH_SUPPRESS_WARNINGS_STD_BEGIN #include JPH_SUPPRESS_WARNINGS_STD_END using namespace JPH; // Emit everything needed for the main function #define DOCTEST_CONFIG_IMPLEMENT #define DOCTEST_CONFIG_NO_WINDOWS_SEH JPH_SUPPRESS_WARNINGS_STD_BEGIN #include "doctest.h" JPH_SUPPRESS_WARNINGS_STD_END using namespace doctest; // Disable common warnings triggered by Jolt JPH_SUPPRESS_WARNINGS // Callback for traces static void TraceImpl(const char *inFMT, ...) { // Format the message va_list list; va_start(list, inFMT); char buffer[1024]; vsnprintf(buffer, sizeof(buffer), inFMT, list); va_end(list); // Forward to doctest MESSAGE(buffer); } #ifdef JPH_ENABLE_ASSERTS // Callback for asserts static bool AssertFailedImpl(const char *inExpression, const char *inMessage, const char *inFile, uint inLine) { // Format message char buffer[1024]; snprintf(buffer, sizeof(buffer), "%s:%u: (%s) %s", inFile, inLine, inExpression, inMessage != nullptr? inMessage : ""); // Forward to doctest FAIL_CHECK(buffer); // No breakpoint return false; } #endif // JPH_ENABLE_ASSERTS #ifdef JPH_PLATFORM_WINDOWS_UWP JPH_SUPPRESS_WARNING_PUSH JPH_MSVC_SUPPRESS_WARNING(4265) // warning C4265: 'winrt::impl::implements_delegate': class has virtual functions, but its non-trivial destructor is not virtual; instances of this class may not be destructed correctly JPH_MSVC_SUPPRESS_WARNING(4668) // warning C4668: '_MANAGED' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' JPH_MSVC_SUPPRESS_WARNING(4946) // warning C4946: reinterpret_cast used between related classes: 'winrt::impl::abi::type' and 'winrt::impl::abi::type' JPH_MSVC_SUPPRESS_WARNING(5039) // winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception. JPH_MSVC_SUPPRESS_WARNING(5204) // warning C5204: 'winrt::impl::produce_base': class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly JPH_MSVC_SUPPRESS_WARNING(5246) // warning C5246: '_Elems': the initialization of a subobject should be wrapped in braces #include #include #include #include #include #include JPH_SUPPRESS_WARNING_POP using namespace winrt; using namespace Windows; using namespace Windows::ApplicationModel::Core; using namespace Windows::UI; using namespace Windows::UI::Core; using namespace Windows::UI::Composition; struct App : implements { CompositionTarget mTarget { nullptr }; IFrameworkView CreateView() { return *this; } void Initialize(CoreApplicationView const&) { } void Load(hstring const&) { } void Uninitialize() { } void Run() { CoreWindow window = CoreWindow::GetForCurrentThread(); window.Activate(); CoreDispatcher dispatcher = window.Dispatcher(); dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit); } void SetWindow(CoreWindow const& inWindow) { // Register allocation hook RegisterDefaultAllocator(); // Install callbacks Trace = TraceImpl; JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;) #ifdef _DEBUG // Enable leak detection _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif // Enable floating point exceptions FPExceptionsEnable enable_exceptions; JPH_UNUSED(enable_exceptions); // Create a factory Factory::sInstance = new Factory(); // Register physics types RegisterTypes(); // Run the tests int rv = Context().run(); // Destroy the factory delete Factory::sInstance; Factory::sInstance = nullptr; // Color the screen according to the result Compositor compositor; ContainerVisual root = compositor.CreateContainerVisual(); mTarget = compositor.CreateTargetForCurrentView(); mTarget.Root(root); SpriteVisual visual = compositor.CreateSpriteVisual(); visual.Brush(compositor.CreateColorBrush(rv != 0 ? Windows::UI::Color { 0xff, 0xff, 0x00, 0x00 } : Windows::UI::Color { 0xff, 0x00, 0xff, 0x00 })); visual.Size({ inWindow.Bounds().Width, inWindow.Bounds().Height }); visual.Offset({ 0, 0, 0, }); root.Children().InsertAtTop(visual); } }; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { CoreApplication::Run(make()); } #elif !defined(JPH_PLATFORM_ANDROID) // Generic entry point int main(int argc, char** argv) { // Show used instruction sets std::cout << JPH_CPU_ADDRESS_BITS << "-bit build with instructions: "; #ifdef JPH_USE_NEON std::cout << "NEON "; #endif #ifdef JPH_USE_SSE std::cout << "SSE2 "; #endif #ifdef JPH_USE_SSE4_1 std::cout << "SSE4.1 "; #endif #ifdef JPH_USE_SSE4_2 std::cout << "SSE4.2 "; #endif #ifdef JPH_USE_AVX std::cout << "AVX "; #endif #ifdef JPH_USE_AVX2 std::cout << "AVX2 "; #endif #ifdef JPH_USE_AVX512 std::cout << "AVX512 "; #endif #ifdef JPH_USE_F16C std::cout << "F16C "; #endif #ifdef JPH_USE_LZCNT std::cout << "LZCNT "; #endif #ifdef JPH_USE_TZCNT std::cout << "TZCNT "; #endif #ifdef JPH_USE_FMADD std::cout << "FMADD "; #endif #ifdef JPH_CROSS_PLATFORM_DETERMINISTIC std::cout << "(Cross Platform Deterministic)"; #endif std::cout << std::endl; // Register allocation hook RegisterDefaultAllocator(); // Install callbacks Trace = TraceImpl; JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;) #if defined(JPH_PLATFORM_WINDOWS) && defined(_DEBUG) // Enable leak detection _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif // Enable floating point exceptions FPExceptionsEnable enable_exceptions; JPH_UNUSED(enable_exceptions); // Create a factory Factory::sInstance = new Factory(); // Register physics types RegisterTypes(); int rv = Context(argc, argv).run(); // Destroy the factory delete Factory::sInstance; Factory::sInstance = nullptr; return rv; } #else // !JPH_PLATFORM_ANDROID // Reporter that writes logs to the Android log struct LogReporter : public ConsoleReporter { LogReporter(const ContextOptions &inOptions) : ConsoleReporter(inOptions, mStream) { } #define REPORTER_OVERRIDE(func, type, arg) \ void func(type arg) override \ { \ ConsoleReporter::func(arg); \ string str = mStream.str(); \ if (!str.empty()) \ __android_log_write(ANDROID_LOG_INFO, "Jolt", str.c_str()); \ mStream.str(""); \ } REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) REPORTER_OVERRIDE(test_run_end, const TestRunStats &, in) REPORTER_OVERRIDE(test_case_start, const TestCaseData &, in) REPORTER_OVERRIDE(test_case_reenter, const TestCaseData &, in) REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats &, in) REPORTER_OVERRIDE(test_case_exception, const TestCaseException &, in) REPORTER_OVERRIDE(subcase_start, const SubcaseSignature &, in) REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) REPORTER_OVERRIDE(log_assert, const AssertData &, in) REPORTER_OVERRIDE(log_message, const MessageData &, in) REPORTER_OVERRIDE(test_case_skipped, const TestCaseData &, in) private: thread_local static std::ostringstream mStream; }; thread_local std::ostringstream LogReporter::mStream; DOCTEST_REGISTER_REPORTER("android_log", 0, LogReporter); void AndroidInitialize(android_app *inApp) { // Register allocation hook RegisterDefaultAllocator(); // Install callbacks Trace = TraceImpl; JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;) // Enable floating point exceptions FPExceptionsEnable enable_exceptions; JPH_UNUSED(enable_exceptions); // Create a factory Factory::sInstance = new Factory(); // Register physics types RegisterTypes(); // Run all tests Context context; context.addFilter("reporters", "android_log"); int return_value = context.run(); // Color the screen according to the test result JPH::Color color = return_value == 0? JPH::Color::sGreen : JPH::Color::sRed; ANativeWindow_acquire(inApp->window); ANativeWindow_Buffer buffer; ARect bounds; ANativeWindow_lock(inApp->window, &buffer, &bounds); switch (buffer.format) { case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: { uint32 color_u32 = color.GetUInt32(); for (int y = 0; y < buffer.height; ++y) { uint32 *dest = (uint32 *)((uint8 *)buffer.bits + y * buffer.stride * sizeof(uint32)); for (int x = 0; x < buffer.width; ++x) *dest++ = color_u32; } break; } default: // TODO implement break; } ANativeWindow_unlockAndPost(inApp->window); ANativeWindow_release(inApp->window); // Destroy the factory delete Factory::sInstance; Factory::sInstance = nullptr; } // Handle callback from Android void AndroidHandleCommand(android_app *inApp, int32_t inCmd) { switch (inCmd) { case APP_CMD_INIT_WINDOW: AndroidInitialize(inApp); break; } } // Main entry point for android void android_main(struct android_app *ioApp) { ioApp->onAppCmd = AndroidHandleCommand; int events; android_poll_source *source; do { if (ALooper_pollAll(1, nullptr, &events, (void **)&source) >= 0 && source != nullptr) source->process(ioApp, source); } while (ioApp->destroyRequested == 0); } #endif // JPH_PLATFORM_ANDROID