390 lines
14 KiB
C++
390 lines
14 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
#include "tests/config.h"
|
|
#include <xdk.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <windows.h>
|
|
//#define US_ENABLE_XB1_UI
|
|
#if defined(US_ENABLE_XB1_UI)
|
|
#include <d3d11_x.h>
|
|
#endif
|
|
#include <../private/ubiservices/core/debug/assert.h>
|
|
#include "ubiservices/core/log/log.h"
|
|
#include <agile.h>
|
|
|
|
int mainXboxOne(int argc, US_NS::tchar** argv); // Forward declaration
|
|
|
|
// Application - implements the required functionality for a application
|
|
ref class ApplicationView sealed : public Windows::ApplicationModel::Core::IFrameworkView
|
|
{
|
|
Platform::String^ m_arguments;
|
|
|
|
// http://stackoverflow.com/questions/236129/splitting-a-string-in-c
|
|
static std::vector<std::wstring>& split(const std::wstring& s, US_NS::wchar delim, std::vector<std::wstring>& elems)
|
|
{
|
|
std::wstringstream ss(s);
|
|
std::wstring item;
|
|
|
|
while (std::getline(ss, item, delim))
|
|
{
|
|
elems.push_back(item);
|
|
}
|
|
|
|
return elems;
|
|
}
|
|
|
|
// http://stackoverflow.com/questions/236129/splitting-a-string-in-c
|
|
static std::vector<std::wstring> split(const std::wstring& s, US_NS::wchar delim)
|
|
{
|
|
std::vector<std::wstring> elems;
|
|
split(s, delim, elems);
|
|
return elems;
|
|
}
|
|
|
|
static DWORD __stdcall objectThreadProc(void* param)
|
|
{
|
|
ApplicationView^ thisInstance = reinterpret_cast<ApplicationView^>(param);
|
|
Platform::String^ argumentsExt = "DummyExecutableName " + thisInstance->m_arguments;
|
|
|
|
std::vector<std::wstring> argumentsV = split(std::wstring(argumentsExt->Data()), _T(' '));
|
|
|
|
bool gettingOutputlog = false;
|
|
US_NS::tchar* arguments[20];
|
|
|
|
for (US_NS::uint32 index = 0; index < argumentsV.size() && index < sizeof(arguments)/sizeof(arguments[0]) && !gettingOutputlog; index++)
|
|
{
|
|
gettingOutputlog = (argumentsV[index] == L"GETLOGS");
|
|
arguments[index] = const_cast<US_NS::tchar*>(argumentsV[index].c_str());
|
|
}
|
|
|
|
mainXboxOne(gettingOutputlog ? 0 : static_cast<int>(argumentsV.size()), arguments);
|
|
|
|
m_done = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(US_ENABLE_XB1_UI)
|
|
Microsoft::WRL::ComPtr<ID3D11DeviceX> m_d3dDevice;
|
|
Microsoft::WRL::ComPtr<ID3D11DeviceContextX> m_d3dContext;
|
|
//Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
|
|
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
|
|
|
|
inline void ThrowIfFailed(HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
// Set a breakpoint on this line to catch DirectX API errors
|
|
throw Platform::Exception::CreateException(hr);
|
|
}
|
|
}
|
|
|
|
void CreateDevice()
|
|
{
|
|
assert(!(m_window == nullptr));
|
|
|
|
// Create the DX11 API device object, and get a corresponding context.
|
|
Microsoft::WRL::ComPtr<ID3D11DeviceX> device;
|
|
Microsoft::WRL::ComPtr<ID3D11DeviceContextX> context;
|
|
|
|
D3D11X_CREATE_DEVICE_PARAMETERS params;
|
|
ZeroMemory(¶ms, sizeof(D3D11X_CREATE_DEVICE_PARAMETERS));
|
|
params.Flags = D3D11_CREATE_DEVICE_DEBUG;
|
|
params.Version = D3D11_SDK_VERSION;
|
|
|
|
ThrowIfFailed(D3D11XCreateDeviceX(¶ms, &device, &context)); // d3d11_x.lib
|
|
|
|
// Get the DirectX11.1 device by QI off the DirectX11 one.
|
|
ThrowIfFailed(device.As(&m_d3dDevice));
|
|
|
|
// And get the corresponding device context in the same way.
|
|
ThrowIfFailed(context.As(&m_d3dContext));
|
|
|
|
// First, retrieve the underlying DXGI Device from the D3D Device
|
|
Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice;
|
|
ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
|
|
|
|
// Identify the physical adapter (GPU or card) this device is running on.
|
|
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter;
|
|
ThrowIfFailed(dxgiDevice->GetAdapter(&dxgiAdapter));
|
|
|
|
// And obtain the factory object that created it.
|
|
Microsoft::WRL::ComPtr<IDXGIFactory2> dxgiFactory;
|
|
ThrowIfFailed(dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), &dxgiFactory));
|
|
|
|
// Create a descriptor for the swap chain.
|
|
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
|
|
swapChainDesc.Width = 1920;
|
|
swapChainDesc.Height = 1080;
|
|
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
swapChainDesc.BufferCount = 2;
|
|
swapChainDesc.Stereo = false;
|
|
swapChainDesc.SampleDesc.Count = 1;
|
|
swapChainDesc.SampleDesc.Quality = 0;
|
|
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
|
|
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
|
swapChainDesc.Flags = 0;
|
|
|
|
// Create a SwapChain from a CoreWindow.
|
|
ThrowIfFailed(dxgiFactory->CreateSwapChainForCoreWindow(
|
|
m_d3dDevice.Get(), reinterpret_cast<IUnknown*>(m_window.Get()), &swapChainDesc, nullptr, &m_swapChain));
|
|
}
|
|
#endif
|
|
public:
|
|
ApplicationView()
|
|
: m_thread(NULL)
|
|
{
|
|
m_done = false;
|
|
}
|
|
|
|
// IFrameworkView Methods
|
|
|
|
// Called by the system. Perform application initialization here, hooking application wide events, etc.
|
|
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView)
|
|
{
|
|
using Windows::ApplicationModel::Activation::IActivatedEventArgs;
|
|
using Windows::ApplicationModel::Core::CoreApplicationView;
|
|
using Windows::Foundation::TypedEventHandler;
|
|
|
|
applicationView->Activated +=
|
|
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &ApplicationView::OnViewActivated);
|
|
|
|
// The following event handlers are not required for tests except that
|
|
// it demonstrates that the main program can subscribe to events while
|
|
// the SDK do the same showing that both receives the same events...
|
|
#define US_ENABLE_MAIN_EVENS_LOGS
|
|
#if defined(US_ENABLE_MAIN_EVENS_LOGS)
|
|
Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged +=
|
|
ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ApplicationView::OnResourceAvailabilityChanged);
|
|
|
|
Windows::ApplicationModel::Core::CoreApplication::Suspending +=
|
|
ref new Windows::Foundation::EventHandler<Windows::ApplicationModel::SuspendingEventArgs^>(this, &ApplicationView::OnSuspending);
|
|
|
|
Windows::ApplicationModel::Core::CoreApplication::Resuming +=
|
|
ref new Windows::Foundation::EventHandler<Platform::Object^>(this, &ApplicationView::OnResuming);
|
|
#endif
|
|
}
|
|
|
|
// Called when we are provided a window.
|
|
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window)
|
|
{
|
|
m_window = window;
|
|
#if defined(US_ENABLE_XB1_UI)
|
|
CreateDevice();
|
|
#endif
|
|
|
|
window->Activate(); // Calling it or not does not make any difference.
|
|
}
|
|
|
|
virtual void Load(Platform::String^ entryPoint)
|
|
{
|
|
//m_game = ref new Game();
|
|
//m_game->Initialize(CoreWindow::GetForCurrentThread());
|
|
}
|
|
|
|
// Called by the system after initialization is complete. This implements the traditional game loop
|
|
virtual void Run()
|
|
{
|
|
for (; !m_done;)
|
|
{
|
|
// ProcessEvents will throw if the process is exiting, allowing us to
|
|
// break out of the loop. This will be cleaned up when we get proper
|
|
// process lifetime management online in a future release.
|
|
Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(
|
|
Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
|
|
|
|
//m_game->Tick();
|
|
#if defined(US_ENABLE_XB1_UI)
|
|
m_swapChain->Present(1, 0);
|
|
#endif
|
|
}
|
|
|
|
m_window->Close();
|
|
|
|
//Windows::ApplicationModel::Core::CoreApplication::Exit(); // Not required anymore?
|
|
}
|
|
|
|
#if defined(US_ENABLE_XB1_UI) // Code is missing for attaching these handlers to the event sources...
|
|
virtual void Suspend(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args)
|
|
{
|
|
m_d3dContext->Suspend(0);
|
|
}
|
|
|
|
virtual void Resume(Platform::Object^ sender, Platform::Object^ args)
|
|
{
|
|
m_d3dContext->Resume();
|
|
}
|
|
#endif
|
|
|
|
virtual void Uninitialize()
|
|
{
|
|
US_VERIFY(CloseHandle(m_thread) != FALSE); // Calling it or not does not make any difference.
|
|
|
|
// Exiting explicitly here avoid the appmodel.dll thread to raise an
|
|
// unhandled exception (access violation reading...).
|
|
exit(0);
|
|
}
|
|
|
|
protected:
|
|
// Event Handlers
|
|
|
|
// Called when the application is activated. For now, there is just one activation kind - Launch.
|
|
void OnViewActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args)
|
|
{
|
|
if (args->Kind == Windows::ApplicationModel::Activation::ActivationKind::Launch)
|
|
{
|
|
#if defined(US_ENABLE_MAIN_EVENS_LOGS)
|
|
using Windows::Foundation::TypedEventHandler;
|
|
|
|
US_ASSERT(Windows::UI::Core::CoreWindow::GetForCurrentThread() == applicationView->CoreWindow, "Information");
|
|
|
|
applicationView->CoreWindow->Activated +=
|
|
ref new TypedEventHandler<Windows::UI::Core::CoreWindow^, Windows::UI::Core::WindowActivatedEventArgs^>(this, &ApplicationView::OnActivated);
|
|
|
|
applicationView->CoreWindow->VisibilityChanged +=
|
|
ref new TypedEventHandler<Windows::UI::Core::CoreWindow^, Windows::UI::Core::VisibilityChangedEventArgs^>(this, &ApplicationView::OnVisibilityChanged);
|
|
|
|
US_NS::Log::print("[ MAIN!!!! ] ApplicationView OnViewActivated where Kind is Launch\n");
|
|
#endif
|
|
auto launchArgs = (Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^)args;
|
|
m_arguments = launchArgs->Arguments;
|
|
}
|
|
#if defined(US_ENABLE_MAIN_EVENS_LOGS)
|
|
else
|
|
{
|
|
US_NS::Log::print("[ MAIN!!!! ] ApplicationView OnViewActivated where Kind is %d\n", args->Kind);
|
|
}
|
|
#endif
|
|
|
|
Windows::UI::Core::CoreWindow::GetForCurrentThread()->Activate();
|
|
|
|
m_thread = reinterpret_cast<HANDLE>(CreateThread(NULL,
|
|
(64*1024), //ObjectThreadRootPlatform::s_threadStackSize,
|
|
reinterpret_cast<LPTHREAD_START_ROUTINE>(objectThreadProc),
|
|
reinterpret_cast<LPVOID>(this),
|
|
0,
|
|
reinterpret_cast<unsigned long*>(&m_threadId)));
|
|
}
|
|
|
|
#if defined(US_ENABLE_MAIN_EVENS_LOGS)
|
|
void OnActivated(Windows::UI::Core::CoreWindow^ applicationView, Windows::UI::Core::WindowActivatedEventArgs^ args)
|
|
{
|
|
static bool once = false;
|
|
|
|
switch (args->WindowActivationState)
|
|
{
|
|
case Windows::UI::Core::CoreWindowActivationState::CodeActivated:
|
|
case Windows::UI::Core::CoreWindowActivationState::PointerActivated:
|
|
US_NS::Log::print("[ MAIN!!!! ] OnActivated where WindowActivationState is CodeActivated/PointerActivated\n");
|
|
if (once)
|
|
{
|
|
//US_NS::PlatformHelper::changeState(US_NS::PlatformHelper::Foreground);
|
|
}
|
|
break;
|
|
case Windows::UI::Core::CoreWindowActivationState::Deactivated:
|
|
US_NS::Log::print("[ MAIN!!!! ] OnActivated where WindowActivationState is Deactivated\n");
|
|
if (once)
|
|
{
|
|
//US_NS::PlatformHelper::changeState(US_NS::PlatformHelper::Background);
|
|
}
|
|
break;
|
|
default:
|
|
US_ASSERT(false, "Invalid enumeration value");
|
|
break;
|
|
}
|
|
|
|
once = true;
|
|
}
|
|
|
|
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ applicationView, Windows::UI::Core::VisibilityChangedEventArgs^ args)
|
|
{
|
|
static bool once = false;
|
|
US_NS::Log::print("[ MAIN!!!! ] OnVisibilityChanged to %s\n", args->Visible ? "Visible" : "Invisible");
|
|
if (once)
|
|
{
|
|
//US_NS::PlatformHelper::changeState(args->Visible ? US_NS::PlatformHelper::Foreground : US_NS::PlatformHelper::Background);
|
|
}
|
|
once = true;
|
|
}
|
|
|
|
void OnResourceAvailabilityChanged(Platform::Object^ sender, Platform::Object^ args)
|
|
{
|
|
US_UNUSED(sender);
|
|
US_UNUSED(args);
|
|
switch (Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability)
|
|
{
|
|
case Windows::ApplicationModel::Core::ResourceAvailability::Full:
|
|
US_NS::Log::print("[ MAIN!!!! ] ResourceAvailability::Full\n");
|
|
break;
|
|
case Windows::ApplicationModel::Core::ResourceAvailability::Constrained:
|
|
US_NS::Log::print("[ MAIN!!!! ] ResourceAvailability::Constrained\n");
|
|
break;
|
|
case Windows::ApplicationModel::Core::ResourceAvailability::FullWithExtendedSystemReserve:
|
|
US_NS::Log::print("[ MAIN!!!! ] ResourceAvailability::FullWithExtendedSystemReserve\n");
|
|
break;
|
|
default:
|
|
US_ASSERT(false, "Invalid enumeration value");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args)
|
|
{
|
|
//auto test = args->SuspendingOperation->GetDeferral();
|
|
|
|
US_UNUSED(sender);
|
|
US_UNUSED(args);
|
|
US_NS::Log::print("[ MAIN!!!! ] OnSuspending!\n");
|
|
}
|
|
|
|
void OnResuming(Platform::Object^ sender, Platform::Object^ args)
|
|
{
|
|
US_UNUSED(sender);
|
|
US_UNUSED(args);
|
|
US_NS::Log::print("[ MAIN!!!! ] OnResuming!\n");
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
friend Windows::UI::Core::CoreWindow^ getCoreWindow();
|
|
static Platform::Agile<Windows::UI::Core::CoreWindow> m_window; // (proof of concept)
|
|
|
|
static bool m_done;
|
|
HANDLE m_thread;
|
|
unsigned long* m_threadId;
|
|
};
|
|
|
|
Platform::Agile<Windows::UI::Core::CoreWindow> ApplicationView::m_window;
|
|
|
|
Windows::UI::Core::CoreWindow^ getCoreWindow()
|
|
{
|
|
return ApplicationView::m_window.Get();
|
|
}
|
|
|
|
// Creates the Application instance and pass it back to the system
|
|
ref class ApplicationViewSource : Windows::ApplicationModel::Core::IFrameworkViewSource
|
|
{
|
|
public:
|
|
// Implements an IFrameworkView factory.
|
|
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView()
|
|
{
|
|
return ref new ApplicationView();
|
|
}
|
|
};
|
|
|
|
bool ApplicationView::m_done;
|
|
|
|
// Application entry point
|
|
//[Platform::MTAThread] // Does not make any difference?
|
|
int main(Platform::Array<Platform::String^>^ args)
|
|
{
|
|
auto applicationViewSource = ref new ApplicationViewSource();
|
|
Windows::ApplicationModel::Core::CoreApplication::Run(applicationViewSource);
|
|
return 0;
|
|
}
|
|
|