mirror of https://github.com/axmolengine/axmol.git
updated cocos2d-x/angle template files to version 0edf96a2f54a43d068244a86aaf9133c1bf71fe5
This commit is contained in:
parent
ce88dbdee4
commit
fdebb373b1
|
@ -112,14 +112,7 @@ void OpenGLES::Initialize()
|
||||||
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
||||||
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
||||||
//
|
//
|
||||||
// Note: On Windows Phone, we #ifdef out the first set of calls to eglPlatformDisplayEXT and eglInitialize.
|
|
||||||
// Windows Phones devices only support D3D11 Feature Level 9_3, but the Windows Phone emulator supports 11_0+.
|
|
||||||
// We use this #ifdef to limit the Phone emulator to Feature Level 9_3, making it behave more like
|
|
||||||
// real Windows Phone devices.
|
|
||||||
// If you wish to test Feature Level 10_0+ in the Windows Phone emulator then you should remove this #ifdef.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
|
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
|
@ -128,9 +121,8 @@ void OpenGLES::Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on Windows Phone, or certain Windows tablets).
|
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -139,7 +131,7 @@ void OpenGLES::Initialize()
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
{
|
{
|
||||||
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU (e.g. on Surface RT).
|
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -188,13 +180,18 @@ void OpenGLES::Reset()
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize)
|
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize, const float* resolutionScale)
|
||||||
{
|
{
|
||||||
if (!panel)
|
if (!panel)
|
||||||
{
|
{
|
||||||
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (renderSurfaceSize != nullptr && resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
throw Exception::CreateException(E_INVALIDARG, L"A size and a scale can't both be specified");
|
||||||
|
}
|
||||||
|
|
||||||
EGLSurface surface = EGL_NO_SURFACE;
|
EGLSurface surface = EGL_NO_SURFACE;
|
||||||
|
|
||||||
const EGLint surfaceAttributes[] =
|
const EGLint surfaceAttributes[] =
|
||||||
|
@ -207,12 +204,18 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
|
|
||||||
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
||||||
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLNativeWindowTypeProperty), panel);
|
surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel);
|
||||||
|
|
||||||
// If a render surface size is specified, add it to the surface creation properties
|
// If a render surface size is specified, add it to the surface creation properties
|
||||||
if (renderSurfaceSize != nullptr)
|
if (renderSurfaceSize != nullptr)
|
||||||
{
|
{
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a resolution scale is specified, add it to the surface creation properties
|
||||||
|
if (resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(*resolutionScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
||||||
|
@ -224,6 +227,12 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height)
|
||||||
|
{
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLES::DestroySurface(const EGLSurface surface)
|
void OpenGLES::DestroySurface(const EGLSurface surface)
|
||||||
{
|
{
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
// OpenGL ES includes
|
// OpenGL ES includes
|
||||||
#include <GLES3/gl3.h>
|
#include <GLES3/gl3.h>
|
||||||
#include <GLES3/gl3ext.h>
|
|
||||||
|
|
||||||
// EGL includes
|
// EGL includes
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
@ -34,7 +33,8 @@ public:
|
||||||
OpenGLES();
|
OpenGLES();
|
||||||
~OpenGLES();
|
~OpenGLES();
|
||||||
|
|
||||||
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize);
|
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize, const float* renderResolutionScale);
|
||||||
|
void GetSurfaceDimensions(const EGLSurface surface, EGLint *width, EGLint *height);
|
||||||
void DestroySurface(const EGLSurface surface);
|
void DestroySurface(const EGLSurface surface);
|
||||||
void MakeCurrent(const EGLSurface surface);
|
void MakeCurrent(const EGLSurface surface);
|
||||||
EGLBoolean SwapBuffers(const EGLSurface surface);
|
EGLBoolean SwapBuffers(const EGLSurface surface);
|
||||||
|
|
|
@ -24,7 +24,6 @@ using namespace cocos2d;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace Concurrency;
|
using namespace Concurrency;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Foundation::Collections;
|
|
||||||
using namespace Windows::Graphics::Display;
|
using namespace Windows::Graphics::Display;
|
||||||
using namespace Windows::System::Threading;
|
using namespace Windows::System::Threading;
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
|
@ -50,8 +49,6 @@ OpenGLESPage::OpenGLESPage() :
|
||||||
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
mOpenGLES(openGLES),
|
mOpenGLES(openGLES),
|
||||||
mRenderSurface(EGL_NO_SURFACE),
|
mRenderSurface(EGL_NO_SURFACE),
|
||||||
mCustomRenderSurfaceSize(0,0),
|
|
||||||
mUseCustomRenderSurfaceSize(false),
|
|
||||||
mCoreInput(nullptr),
|
mCoreInput(nullptr),
|
||||||
mDpi(0.0f),
|
mDpi(0.0f),
|
||||||
mDeviceLost(false),
|
mDeviceLost(false),
|
||||||
|
@ -72,8 +69,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
|
|
||||||
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
||||||
|
|
||||||
swapChainPanel->SizeChanged +=
|
|
||||||
ref new Windows::UI::Xaml::SizeChangedEventHandler(this, &OpenGLESPage::OnSwapChainPanelSizeChanged);
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
|
||||||
|
@ -85,8 +80,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
this->Loaded +=
|
this->Loaded +=
|
||||||
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
||||||
|
|
||||||
mSwapChainPanelSize = { swapChainPanel->RenderSize.Width, swapChainPanel->RenderSize.Height };
|
|
||||||
|
|
||||||
#if _MSC_VER >= 1900
|
#if _MSC_VER >= 1900
|
||||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||||
{
|
{
|
||||||
|
@ -158,6 +151,201 @@ void OpenGLESPage::OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::Rou
|
||||||
mVisible = true;
|
mVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::CreateRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
// The app can configure the the SwapChainPanel which may boost performance.
|
||||||
|
// By default, this template uses the default configuration.
|
||||||
|
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, nullptr);
|
||||||
|
|
||||||
|
// You can configure the SwapChainPanel to render at a lower resolution and be scaled up to
|
||||||
|
// the swapchain panel size. This scaling is often free on mobile hardware.
|
||||||
|
//
|
||||||
|
// One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
|
||||||
|
// Size customRenderSurfaceSize = Size(800, 600);
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, &customRenderSurfaceSize, nullptr);
|
||||||
|
//
|
||||||
|
// Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
|
||||||
|
// e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
|
||||||
|
// float customResolutionScale = 0.5f;
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, &customResolutionScale);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::DestroyRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
}
|
||||||
|
mRenderSurface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::RecoverFromLostDevice()
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
DestroyRenderSurface();
|
||||||
|
mOpenGLES->Reset();
|
||||||
|
CreateRenderSurface();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mDeviceLost = false;
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::TerminateApp()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
mOpenGLES->Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Windows::UI::Xaml::Application::Current->Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StartRenderLoop()
|
||||||
|
{
|
||||||
|
// If the render loop is already running then do not start another thread.
|
||||||
|
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
mDpi = currentDisplayInformation->LogicalDpi;
|
||||||
|
|
||||||
|
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
||||||
|
|
||||||
|
// Create a task for rendering that will be run on a background thread.
|
||||||
|
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
|
||||||
|
GLsizei panelWidth = 0;
|
||||||
|
GLsizei panelHeight = 0;
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
|
||||||
|
if (mRenderer.get() == nullptr)
|
||||||
|
{
|
||||||
|
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderer->Resume();
|
||||||
|
|
||||||
|
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
if (!mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until app is visible again or thread is cancelled
|
||||||
|
while (!mVisible)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Resume();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
||||||
|
|
||||||
|
// Recreate input dispatch
|
||||||
|
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
||||||
|
{
|
||||||
|
CreateInput();
|
||||||
|
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRenderer->AppShouldExit())
|
||||||
|
{
|
||||||
|
// run on main UI thread
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
TerminateApp();
|
||||||
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLBoolean result = GL_FALSE;
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != GL_TRUE)
|
||||||
|
{
|
||||||
|
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
||||||
|
// If the call fails, then we must reinitialize EGL and the GL resources.
|
||||||
|
mRenderer->Pause();
|
||||||
|
mDeviceLost = true;
|
||||||
|
|
||||||
|
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
RecoverFromLostDevice();
|
||||||
|
}, CallbackContext::Any));
|
||||||
|
|
||||||
|
// wait until OpenGL is reset or thread is cancelled
|
||||||
|
while (mDeviceLost)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDeviceLost)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
// restart cocos2d-x
|
||||||
|
mRenderer->DeviceLost();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run task on a dedicated high priority background thread.
|
||||||
|
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StopRenderLoop()
|
||||||
|
{
|
||||||
|
if (mRenderLoopWorker)
|
||||||
|
{
|
||||||
|
mRenderLoopWorker->Cancel();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
mRenderLoopWorker = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
||||||
{
|
{
|
||||||
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
||||||
|
@ -229,7 +417,6 @@ void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e)
|
||||||
|
|
||||||
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
||||||
{
|
{
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mOrientation = sender->CurrentOrientation;
|
mOrientation = sender->CurrentOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,216 +466,3 @@ void OpenGLESPage::OnBackButtonPressed(Object^ sender, BackPressedEventArgs^ arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OpenGLESPage::OnSwapChainPanelSizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
|
||||||
{
|
|
||||||
// Size change events occur outside of the render thread. A lock is required when updating
|
|
||||||
// the swapchainpanel size
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mSwapChainPanelSize = { e->NewSize.Width, e->NewSize.Height };
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::GetSwapChainPanelSize(GLsizei* width, GLsizei* height)
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
// If a custom render surface size is specified, return its size instead of
|
|
||||||
// the swapchain panel size.
|
|
||||||
if (mUseCustomRenderSurfaceSize)
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mCustomRenderSurfaceSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mCustomRenderSurfaceSize.Height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mSwapChainPanelSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mSwapChainPanelSize.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::CreateRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// A Custom render surface size can be specified by uncommenting the following lines.
|
|
||||||
// The render surface will be automatically scaled to fit the entire window. Using a
|
|
||||||
// smaller sized render surface can result in a performance gain.
|
|
||||||
//
|
|
||||||
//mCustomRenderSurfaceSize = Size(800, 600);
|
|
||||||
//mUseCustomRenderSurfaceSize = true;
|
|
||||||
|
|
||||||
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, mUseCustomRenderSurfaceSize ? &mCustomRenderSurfaceSize : nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::DestroyRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
}
|
|
||||||
mRenderSurface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::RecoverFromLostDevice()
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
DestroyRenderSurface();
|
|
||||||
mOpenGLES->Reset();
|
|
||||||
CreateRenderSurface();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mDeviceLost = false;
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::TerminateApp()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
mOpenGLES->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Windows::UI::Xaml::Application::Current->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StartRenderLoop()
|
|
||||||
{
|
|
||||||
// If the render loop is already running then do not start another thread.
|
|
||||||
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
|
||||||
mDpi = currentDisplayInformation->LogicalDpi;
|
|
||||||
|
|
||||||
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
|
||||||
|
|
||||||
// Create a task for rendering that will be run on a background thread.
|
|
||||||
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
|
|
||||||
GLsizei panelWidth = 0;
|
|
||||||
GLsizei panelHeight = 0;
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
|
|
||||||
if (mRenderer.get() == nullptr)
|
|
||||||
{
|
|
||||||
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderer->Resume();
|
|
||||||
|
|
||||||
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
if (!mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until app is visible again or thread is cancelled
|
|
||||||
while (!mVisible)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Resume();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
|
||||||
|
|
||||||
// Recreate input dispatch
|
|
||||||
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
|
||||||
{
|
|
||||||
CreateInput();
|
|
||||||
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRenderer->AppShouldExit())
|
|
||||||
{
|
|
||||||
// run on main UI thread
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]()
|
|
||||||
{
|
|
||||||
TerminateApp();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLBoolean result = GL_FALSE;
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != GL_TRUE)
|
|
||||||
{
|
|
||||||
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
|
||||||
// If the call fails, then we must reinitialize EGL and the GL resources.
|
|
||||||
mRenderer->Pause();
|
|
||||||
mDeviceLost = true;
|
|
||||||
|
|
||||||
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
|
||||||
{
|
|
||||||
RecoverFromLostDevice();
|
|
||||||
}, CallbackContext::Any));
|
|
||||||
|
|
||||||
// wait until OpenGL is reset or thread is cancelled
|
|
||||||
while (mDeviceLost)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mDeviceLost)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
// restart cocos2d-x
|
|
||||||
mRenderer->DeviceLost();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run task on a dedicated high priority background thread.
|
|
||||||
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StopRenderLoop()
|
|
||||||
{
|
|
||||||
if (mRenderLoopWorker)
|
|
||||||
{
|
|
||||||
mRenderLoopWorker->Cancel();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
mRenderLoopWorker = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,11 +41,9 @@ namespace CocosAppWinRT
|
||||||
private:
|
private:
|
||||||
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
||||||
void OnSwapChainPanelSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
|
||||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
||||||
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
||||||
#endif
|
#endif
|
||||||
void GetSwapChainPanelSize(GLsizei* width, GLsizei* height);
|
|
||||||
void CreateRenderSurface();
|
void CreateRenderSurface();
|
||||||
void DestroyRenderSurface();
|
void DestroyRenderSurface();
|
||||||
void RecoverFromLostDevice();
|
void RecoverFromLostDevice();
|
||||||
|
@ -58,12 +56,6 @@ namespace CocosAppWinRT
|
||||||
OpenGLES* mOpenGLES;
|
OpenGLES* mOpenGLES;
|
||||||
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
||||||
|
|
||||||
Windows::Foundation::Size mSwapChainPanelSize;
|
|
||||||
Concurrency::critical_section mSwapChainPanelSizeCriticalSection;
|
|
||||||
|
|
||||||
Windows::Foundation::Size mCustomRenderSurfaceSize;
|
|
||||||
bool mUseCustomRenderSurfaceSize;
|
|
||||||
|
|
||||||
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
||||||
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
||||||
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
||||||
|
|
|
@ -37,7 +37,6 @@ THE SOFTWARE.
|
||||||
#include "GLES2/gl2.h"
|
#include "GLES2/gl2.h"
|
||||||
#include "GLES2/gl2ext.h"
|
#include "GLES2/gl2ext.h"
|
||||||
#include "GLES3/gl3.h"
|
#include "GLES3/gl3.h"
|
||||||
#include "GLES3/gl3ext.h"
|
|
||||||
|
|
||||||
#define glMapBuffer glMapBufferOES
|
#define glMapBuffer glMapBufferOES
|
||||||
|
|
||||||
|
|
|
@ -112,14 +112,7 @@ void OpenGLES::Initialize()
|
||||||
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
||||||
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
||||||
//
|
//
|
||||||
// Note: On Windows Phone, we #ifdef out the first set of calls to eglPlatformDisplayEXT and eglInitialize.
|
|
||||||
// Windows Phones devices only support D3D11 Feature Level 9_3, but the Windows Phone emulator supports 11_0+.
|
|
||||||
// We use this #ifdef to limit the Phone emulator to Feature Level 9_3, making it behave more like
|
|
||||||
// real Windows Phone devices.
|
|
||||||
// If you wish to test Feature Level 10_0+ in the Windows Phone emulator then you should remove this #ifdef.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
|
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
|
@ -128,9 +121,8 @@ void OpenGLES::Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on Windows Phone, or certain Windows tablets).
|
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -139,7 +131,7 @@ void OpenGLES::Initialize()
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
{
|
{
|
||||||
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU (e.g. on Surface RT).
|
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -188,13 +180,18 @@ void OpenGLES::Reset()
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize)
|
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize, const float* resolutionScale)
|
||||||
{
|
{
|
||||||
if (!panel)
|
if (!panel)
|
||||||
{
|
{
|
||||||
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (renderSurfaceSize != nullptr && resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
throw Exception::CreateException(E_INVALIDARG, L"A size and a scale can't both be specified");
|
||||||
|
}
|
||||||
|
|
||||||
EGLSurface surface = EGL_NO_SURFACE;
|
EGLSurface surface = EGL_NO_SURFACE;
|
||||||
|
|
||||||
const EGLint surfaceAttributes[] =
|
const EGLint surfaceAttributes[] =
|
||||||
|
@ -207,12 +204,18 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
|
|
||||||
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
||||||
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLNativeWindowTypeProperty), panel);
|
surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel);
|
||||||
|
|
||||||
// If a render surface size is specified, add it to the surface creation properties
|
// If a render surface size is specified, add it to the surface creation properties
|
||||||
if (renderSurfaceSize != nullptr)
|
if (renderSurfaceSize != nullptr)
|
||||||
{
|
{
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a resolution scale is specified, add it to the surface creation properties
|
||||||
|
if (resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(*resolutionScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
||||||
|
@ -224,6 +227,12 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height)
|
||||||
|
{
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLES::DestroySurface(const EGLSurface surface)
|
void OpenGLES::DestroySurface(const EGLSurface surface)
|
||||||
{
|
{
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
// OpenGL ES includes
|
// OpenGL ES includes
|
||||||
#include <GLES3/gl3.h>
|
#include <GLES3/gl3.h>
|
||||||
#include <GLES3/gl3ext.h>
|
|
||||||
|
|
||||||
// EGL includes
|
// EGL includes
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
@ -34,7 +33,8 @@ public:
|
||||||
OpenGLES();
|
OpenGLES();
|
||||||
~OpenGLES();
|
~OpenGLES();
|
||||||
|
|
||||||
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize);
|
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize, const float* renderResolutionScale);
|
||||||
|
void GetSurfaceDimensions(const EGLSurface surface, EGLint *width, EGLint *height);
|
||||||
void DestroySurface(const EGLSurface surface);
|
void DestroySurface(const EGLSurface surface);
|
||||||
void MakeCurrent(const EGLSurface surface);
|
void MakeCurrent(const EGLSurface surface);
|
||||||
EGLBoolean SwapBuffers(const EGLSurface surface);
|
EGLBoolean SwapBuffers(const EGLSurface surface);
|
||||||
|
|
|
@ -24,7 +24,6 @@ using namespace cocos2d;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace Concurrency;
|
using namespace Concurrency;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Foundation::Collections;
|
|
||||||
using namespace Windows::Graphics::Display;
|
using namespace Windows::Graphics::Display;
|
||||||
using namespace Windows::System::Threading;
|
using namespace Windows::System::Threading;
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
|
@ -50,8 +49,6 @@ OpenGLESPage::OpenGLESPage() :
|
||||||
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
mOpenGLES(openGLES),
|
mOpenGLES(openGLES),
|
||||||
mRenderSurface(EGL_NO_SURFACE),
|
mRenderSurface(EGL_NO_SURFACE),
|
||||||
mCustomRenderSurfaceSize(0,0),
|
|
||||||
mUseCustomRenderSurfaceSize(false),
|
|
||||||
mCoreInput(nullptr),
|
mCoreInput(nullptr),
|
||||||
mDpi(0.0f),
|
mDpi(0.0f),
|
||||||
mDeviceLost(false),
|
mDeviceLost(false),
|
||||||
|
@ -72,8 +69,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
|
|
||||||
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
||||||
|
|
||||||
swapChainPanel->SizeChanged +=
|
|
||||||
ref new Windows::UI::Xaml::SizeChangedEventHandler(this, &OpenGLESPage::OnSwapChainPanelSizeChanged);
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
|
||||||
|
@ -85,8 +80,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
this->Loaded +=
|
this->Loaded +=
|
||||||
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
||||||
|
|
||||||
mSwapChainPanelSize = { swapChainPanel->RenderSize.Width, swapChainPanel->RenderSize.Height };
|
|
||||||
|
|
||||||
#if _MSC_VER >= 1900
|
#if _MSC_VER >= 1900
|
||||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||||
{
|
{
|
||||||
|
@ -158,6 +151,201 @@ void OpenGLESPage::OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::Rou
|
||||||
mVisible = true;
|
mVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::CreateRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
// The app can configure the the SwapChainPanel which may boost performance.
|
||||||
|
// By default, this template uses the default configuration.
|
||||||
|
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, nullptr);
|
||||||
|
|
||||||
|
// You can configure the SwapChainPanel to render at a lower resolution and be scaled up to
|
||||||
|
// the swapchain panel size. This scaling is often free on mobile hardware.
|
||||||
|
//
|
||||||
|
// One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
|
||||||
|
// Size customRenderSurfaceSize = Size(800, 600);
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, &customRenderSurfaceSize, nullptr);
|
||||||
|
//
|
||||||
|
// Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
|
||||||
|
// e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
|
||||||
|
// float customResolutionScale = 0.5f;
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, &customResolutionScale);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::DestroyRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
}
|
||||||
|
mRenderSurface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::RecoverFromLostDevice()
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
DestroyRenderSurface();
|
||||||
|
mOpenGLES->Reset();
|
||||||
|
CreateRenderSurface();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mDeviceLost = false;
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::TerminateApp()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
mOpenGLES->Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Windows::UI::Xaml::Application::Current->Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StartRenderLoop()
|
||||||
|
{
|
||||||
|
// If the render loop is already running then do not start another thread.
|
||||||
|
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
mDpi = currentDisplayInformation->LogicalDpi;
|
||||||
|
|
||||||
|
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
||||||
|
|
||||||
|
// Create a task for rendering that will be run on a background thread.
|
||||||
|
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
|
||||||
|
GLsizei panelWidth = 0;
|
||||||
|
GLsizei panelHeight = 0;
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
|
||||||
|
if (mRenderer.get() == nullptr)
|
||||||
|
{
|
||||||
|
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderer->Resume();
|
||||||
|
|
||||||
|
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
if (!mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until app is visible again or thread is cancelled
|
||||||
|
while (!mVisible)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Resume();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
||||||
|
|
||||||
|
// Recreate input dispatch
|
||||||
|
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
||||||
|
{
|
||||||
|
CreateInput();
|
||||||
|
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRenderer->AppShouldExit())
|
||||||
|
{
|
||||||
|
// run on main UI thread
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
TerminateApp();
|
||||||
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLBoolean result = GL_FALSE;
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != GL_TRUE)
|
||||||
|
{
|
||||||
|
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
||||||
|
// If the call fails, then we must reinitialize EGL and the GL resources.
|
||||||
|
mRenderer->Pause();
|
||||||
|
mDeviceLost = true;
|
||||||
|
|
||||||
|
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
RecoverFromLostDevice();
|
||||||
|
}, CallbackContext::Any));
|
||||||
|
|
||||||
|
// wait until OpenGL is reset or thread is cancelled
|
||||||
|
while (mDeviceLost)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDeviceLost)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
// restart cocos2d-x
|
||||||
|
mRenderer->DeviceLost();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run task on a dedicated high priority background thread.
|
||||||
|
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StopRenderLoop()
|
||||||
|
{
|
||||||
|
if (mRenderLoopWorker)
|
||||||
|
{
|
||||||
|
mRenderLoopWorker->Cancel();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
mRenderLoopWorker = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
||||||
{
|
{
|
||||||
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
||||||
|
@ -229,7 +417,6 @@ void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e)
|
||||||
|
|
||||||
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
||||||
{
|
{
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mOrientation = sender->CurrentOrientation;
|
mOrientation = sender->CurrentOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,216 +466,3 @@ void OpenGLESPage::OnBackButtonPressed(Object^ sender, BackPressedEventArgs^ arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OpenGLESPage::OnSwapChainPanelSizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
|
||||||
{
|
|
||||||
// Size change events occur outside of the render thread. A lock is required when updating
|
|
||||||
// the swapchainpanel size
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mSwapChainPanelSize = { e->NewSize.Width, e->NewSize.Height };
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::GetSwapChainPanelSize(GLsizei* width, GLsizei* height)
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
// If a custom render surface size is specified, return its size instead of
|
|
||||||
// the swapchain panel size.
|
|
||||||
if (mUseCustomRenderSurfaceSize)
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mCustomRenderSurfaceSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mCustomRenderSurfaceSize.Height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mSwapChainPanelSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mSwapChainPanelSize.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::CreateRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// A Custom render surface size can be specified by uncommenting the following lines.
|
|
||||||
// The render surface will be automatically scaled to fit the entire window. Using a
|
|
||||||
// smaller sized render surface can result in a performance gain.
|
|
||||||
//
|
|
||||||
//mCustomRenderSurfaceSize = Size(800, 600);
|
|
||||||
//mUseCustomRenderSurfaceSize = true;
|
|
||||||
|
|
||||||
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, mUseCustomRenderSurfaceSize ? &mCustomRenderSurfaceSize : nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::DestroyRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
}
|
|
||||||
mRenderSurface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::RecoverFromLostDevice()
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
DestroyRenderSurface();
|
|
||||||
mOpenGLES->Reset();
|
|
||||||
CreateRenderSurface();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mDeviceLost = false;
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::TerminateApp()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
mOpenGLES->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Windows::UI::Xaml::Application::Current->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StartRenderLoop()
|
|
||||||
{
|
|
||||||
// If the render loop is already running then do not start another thread.
|
|
||||||
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
|
||||||
mDpi = currentDisplayInformation->LogicalDpi;
|
|
||||||
|
|
||||||
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
|
||||||
|
|
||||||
// Create a task for rendering that will be run on a background thread.
|
|
||||||
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
|
|
||||||
GLsizei panelWidth = 0;
|
|
||||||
GLsizei panelHeight = 0;
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
|
|
||||||
if (mRenderer.get() == nullptr)
|
|
||||||
{
|
|
||||||
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderer->Resume();
|
|
||||||
|
|
||||||
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
if (!mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until app is visible again or thread is cancelled
|
|
||||||
while (!mVisible)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Resume();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
|
||||||
|
|
||||||
// Recreate input dispatch
|
|
||||||
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
|
||||||
{
|
|
||||||
CreateInput();
|
|
||||||
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRenderer->AppShouldExit())
|
|
||||||
{
|
|
||||||
// run on main UI thread
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]()
|
|
||||||
{
|
|
||||||
TerminateApp();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLBoolean result = GL_FALSE;
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != GL_TRUE)
|
|
||||||
{
|
|
||||||
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
|
||||||
// If the call fails, then we must reinitialize EGL and the GL resources.
|
|
||||||
mRenderer->Pause();
|
|
||||||
mDeviceLost = true;
|
|
||||||
|
|
||||||
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
|
||||||
{
|
|
||||||
RecoverFromLostDevice();
|
|
||||||
}, CallbackContext::Any));
|
|
||||||
|
|
||||||
// wait until OpenGL is reset or thread is cancelled
|
|
||||||
while (mDeviceLost)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mDeviceLost)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
// restart cocos2d-x
|
|
||||||
mRenderer->DeviceLost();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run task on a dedicated high priority background thread.
|
|
||||||
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StopRenderLoop()
|
|
||||||
{
|
|
||||||
if (mRenderLoopWorker)
|
|
||||||
{
|
|
||||||
mRenderLoopWorker->Cancel();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
mRenderLoopWorker = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,11 +41,9 @@ namespace CocosAppWinRT
|
||||||
private:
|
private:
|
||||||
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
||||||
void OnSwapChainPanelSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
|
||||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
||||||
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
||||||
#endif
|
#endif
|
||||||
void GetSwapChainPanelSize(GLsizei* width, GLsizei* height);
|
|
||||||
void CreateRenderSurface();
|
void CreateRenderSurface();
|
||||||
void DestroyRenderSurface();
|
void DestroyRenderSurface();
|
||||||
void RecoverFromLostDevice();
|
void RecoverFromLostDevice();
|
||||||
|
@ -58,12 +56,6 @@ namespace CocosAppWinRT
|
||||||
OpenGLES* mOpenGLES;
|
OpenGLES* mOpenGLES;
|
||||||
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
||||||
|
|
||||||
Windows::Foundation::Size mSwapChainPanelSize;
|
|
||||||
Concurrency::critical_section mSwapChainPanelSizeCriticalSection;
|
|
||||||
|
|
||||||
Windows::Foundation::Size mCustomRenderSurfaceSize;
|
|
||||||
bool mUseCustomRenderSurfaceSize;
|
|
||||||
|
|
||||||
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
||||||
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
||||||
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
||||||
|
|
|
@ -112,14 +112,7 @@ void OpenGLES::Initialize()
|
||||||
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
||||||
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
||||||
//
|
//
|
||||||
// Note: On Windows Phone, we #ifdef out the first set of calls to eglPlatformDisplayEXT and eglInitialize.
|
|
||||||
// Windows Phones devices only support D3D11 Feature Level 9_3, but the Windows Phone emulator supports 11_0+.
|
|
||||||
// We use this #ifdef to limit the Phone emulator to Feature Level 9_3, making it behave more like
|
|
||||||
// real Windows Phone devices.
|
|
||||||
// If you wish to test Feature Level 10_0+ in the Windows Phone emulator then you should remove this #ifdef.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
|
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
|
@ -128,9 +121,8 @@ void OpenGLES::Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on Windows Phone, or certain Windows tablets).
|
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -139,7 +131,7 @@ void OpenGLES::Initialize()
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
{
|
{
|
||||||
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU (e.g. on Surface RT).
|
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -188,13 +180,18 @@ void OpenGLES::Reset()
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize)
|
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize, const float* resolutionScale)
|
||||||
{
|
{
|
||||||
if (!panel)
|
if (!panel)
|
||||||
{
|
{
|
||||||
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (renderSurfaceSize != nullptr && resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
throw Exception::CreateException(E_INVALIDARG, L"A size and a scale can't both be specified");
|
||||||
|
}
|
||||||
|
|
||||||
EGLSurface surface = EGL_NO_SURFACE;
|
EGLSurface surface = EGL_NO_SURFACE;
|
||||||
|
|
||||||
const EGLint surfaceAttributes[] =
|
const EGLint surfaceAttributes[] =
|
||||||
|
@ -207,12 +204,18 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
|
|
||||||
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
||||||
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLNativeWindowTypeProperty), panel);
|
surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel);
|
||||||
|
|
||||||
// If a render surface size is specified, add it to the surface creation properties
|
// If a render surface size is specified, add it to the surface creation properties
|
||||||
if (renderSurfaceSize != nullptr)
|
if (renderSurfaceSize != nullptr)
|
||||||
{
|
{
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a resolution scale is specified, add it to the surface creation properties
|
||||||
|
if (resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(*resolutionScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
||||||
|
@ -224,6 +227,12 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height)
|
||||||
|
{
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLES::DestroySurface(const EGLSurface surface)
|
void OpenGLES::DestroySurface(const EGLSurface surface)
|
||||||
{
|
{
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
// OpenGL ES includes
|
// OpenGL ES includes
|
||||||
#include <GLES3/gl3.h>
|
#include <GLES3/gl3.h>
|
||||||
#include <GLES3/gl3ext.h>
|
|
||||||
|
|
||||||
// EGL includes
|
// EGL includes
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
@ -34,7 +33,8 @@ public:
|
||||||
OpenGLES();
|
OpenGLES();
|
||||||
~OpenGLES();
|
~OpenGLES();
|
||||||
|
|
||||||
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize);
|
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize, const float* renderResolutionScale);
|
||||||
|
void GetSurfaceDimensions(const EGLSurface surface, EGLint *width, EGLint *height);
|
||||||
void DestroySurface(const EGLSurface surface);
|
void DestroySurface(const EGLSurface surface);
|
||||||
void MakeCurrent(const EGLSurface surface);
|
void MakeCurrent(const EGLSurface surface);
|
||||||
EGLBoolean SwapBuffers(const EGLSurface surface);
|
EGLBoolean SwapBuffers(const EGLSurface surface);
|
||||||
|
|
|
@ -24,7 +24,6 @@ using namespace cocos2d;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace Concurrency;
|
using namespace Concurrency;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Foundation::Collections;
|
|
||||||
using namespace Windows::Graphics::Display;
|
using namespace Windows::Graphics::Display;
|
||||||
using namespace Windows::System::Threading;
|
using namespace Windows::System::Threading;
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
|
@ -50,8 +49,6 @@ OpenGLESPage::OpenGLESPage() :
|
||||||
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
mOpenGLES(openGLES),
|
mOpenGLES(openGLES),
|
||||||
mRenderSurface(EGL_NO_SURFACE),
|
mRenderSurface(EGL_NO_SURFACE),
|
||||||
mCustomRenderSurfaceSize(0,0),
|
|
||||||
mUseCustomRenderSurfaceSize(false),
|
|
||||||
mCoreInput(nullptr),
|
mCoreInput(nullptr),
|
||||||
mDpi(0.0f),
|
mDpi(0.0f),
|
||||||
mDeviceLost(false),
|
mDeviceLost(false),
|
||||||
|
@ -72,8 +69,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
|
|
||||||
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
||||||
|
|
||||||
swapChainPanel->SizeChanged +=
|
|
||||||
ref new Windows::UI::Xaml::SizeChangedEventHandler(this, &OpenGLESPage::OnSwapChainPanelSizeChanged);
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
|
||||||
|
@ -85,8 +80,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
this->Loaded +=
|
this->Loaded +=
|
||||||
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
||||||
|
|
||||||
mSwapChainPanelSize = { swapChainPanel->RenderSize.Width, swapChainPanel->RenderSize.Height };
|
|
||||||
|
|
||||||
#if _MSC_VER >= 1900
|
#if _MSC_VER >= 1900
|
||||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||||
{
|
{
|
||||||
|
@ -158,6 +151,201 @@ void OpenGLESPage::OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::Rou
|
||||||
mVisible = true;
|
mVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::CreateRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
// The app can configure the the SwapChainPanel which may boost performance.
|
||||||
|
// By default, this template uses the default configuration.
|
||||||
|
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, nullptr);
|
||||||
|
|
||||||
|
// You can configure the SwapChainPanel to render at a lower resolution and be scaled up to
|
||||||
|
// the swapchain panel size. This scaling is often free on mobile hardware.
|
||||||
|
//
|
||||||
|
// One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
|
||||||
|
// Size customRenderSurfaceSize = Size(800, 600);
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, &customRenderSurfaceSize, nullptr);
|
||||||
|
//
|
||||||
|
// Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
|
||||||
|
// e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
|
||||||
|
// float customResolutionScale = 0.5f;
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, &customResolutionScale);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::DestroyRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
}
|
||||||
|
mRenderSurface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::RecoverFromLostDevice()
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
DestroyRenderSurface();
|
||||||
|
mOpenGLES->Reset();
|
||||||
|
CreateRenderSurface();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mDeviceLost = false;
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::TerminateApp()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
mOpenGLES->Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Windows::UI::Xaml::Application::Current->Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StartRenderLoop()
|
||||||
|
{
|
||||||
|
// If the render loop is already running then do not start another thread.
|
||||||
|
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
mDpi = currentDisplayInformation->LogicalDpi;
|
||||||
|
|
||||||
|
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
||||||
|
|
||||||
|
// Create a task for rendering that will be run on a background thread.
|
||||||
|
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
|
||||||
|
GLsizei panelWidth = 0;
|
||||||
|
GLsizei panelHeight = 0;
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
|
||||||
|
if (mRenderer.get() == nullptr)
|
||||||
|
{
|
||||||
|
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderer->Resume();
|
||||||
|
|
||||||
|
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
if (!mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until app is visible again or thread is cancelled
|
||||||
|
while (!mVisible)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Resume();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
||||||
|
|
||||||
|
// Recreate input dispatch
|
||||||
|
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
||||||
|
{
|
||||||
|
CreateInput();
|
||||||
|
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRenderer->AppShouldExit())
|
||||||
|
{
|
||||||
|
// run on main UI thread
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
TerminateApp();
|
||||||
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLBoolean result = GL_FALSE;
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != GL_TRUE)
|
||||||
|
{
|
||||||
|
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
||||||
|
// If the call fails, then we must reinitialize EGL and the GL resources.
|
||||||
|
mRenderer->Pause();
|
||||||
|
mDeviceLost = true;
|
||||||
|
|
||||||
|
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
RecoverFromLostDevice();
|
||||||
|
}, CallbackContext::Any));
|
||||||
|
|
||||||
|
// wait until OpenGL is reset or thread is cancelled
|
||||||
|
while (mDeviceLost)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDeviceLost)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
// restart cocos2d-x
|
||||||
|
mRenderer->DeviceLost();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run task on a dedicated high priority background thread.
|
||||||
|
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StopRenderLoop()
|
||||||
|
{
|
||||||
|
if (mRenderLoopWorker)
|
||||||
|
{
|
||||||
|
mRenderLoopWorker->Cancel();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
mRenderLoopWorker = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
||||||
{
|
{
|
||||||
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
||||||
|
@ -229,7 +417,6 @@ void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e)
|
||||||
|
|
||||||
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
||||||
{
|
{
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mOrientation = sender->CurrentOrientation;
|
mOrientation = sender->CurrentOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,216 +466,3 @@ void OpenGLESPage::OnBackButtonPressed(Object^ sender, BackPressedEventArgs^ arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OpenGLESPage::OnSwapChainPanelSizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
|
||||||
{
|
|
||||||
// Size change events occur outside of the render thread. A lock is required when updating
|
|
||||||
// the swapchainpanel size
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mSwapChainPanelSize = { e->NewSize.Width, e->NewSize.Height };
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::GetSwapChainPanelSize(GLsizei* width, GLsizei* height)
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
// If a custom render surface size is specified, return its size instead of
|
|
||||||
// the swapchain panel size.
|
|
||||||
if (mUseCustomRenderSurfaceSize)
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mCustomRenderSurfaceSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mCustomRenderSurfaceSize.Height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mSwapChainPanelSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mSwapChainPanelSize.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::CreateRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// A Custom render surface size can be specified by uncommenting the following lines.
|
|
||||||
// The render surface will be automatically scaled to fit the entire window. Using a
|
|
||||||
// smaller sized render surface can result in a performance gain.
|
|
||||||
//
|
|
||||||
//mCustomRenderSurfaceSize = Size(800, 600);
|
|
||||||
//mUseCustomRenderSurfaceSize = true;
|
|
||||||
|
|
||||||
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, mUseCustomRenderSurfaceSize ? &mCustomRenderSurfaceSize : nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::DestroyRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
}
|
|
||||||
mRenderSurface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::RecoverFromLostDevice()
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
DestroyRenderSurface();
|
|
||||||
mOpenGLES->Reset();
|
|
||||||
CreateRenderSurface();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mDeviceLost = false;
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::TerminateApp()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
mOpenGLES->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Windows::UI::Xaml::Application::Current->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StartRenderLoop()
|
|
||||||
{
|
|
||||||
// If the render loop is already running then do not start another thread.
|
|
||||||
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
|
||||||
mDpi = currentDisplayInformation->LogicalDpi;
|
|
||||||
|
|
||||||
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
|
||||||
|
|
||||||
// Create a task for rendering that will be run on a background thread.
|
|
||||||
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
|
|
||||||
GLsizei panelWidth = 0;
|
|
||||||
GLsizei panelHeight = 0;
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
|
|
||||||
if (mRenderer.get() == nullptr)
|
|
||||||
{
|
|
||||||
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderer->Resume();
|
|
||||||
|
|
||||||
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
if (!mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until app is visible again or thread is cancelled
|
|
||||||
while (!mVisible)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Resume();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
|
||||||
|
|
||||||
// Recreate input dispatch
|
|
||||||
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
|
||||||
{
|
|
||||||
CreateInput();
|
|
||||||
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRenderer->AppShouldExit())
|
|
||||||
{
|
|
||||||
// run on main UI thread
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]()
|
|
||||||
{
|
|
||||||
TerminateApp();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLBoolean result = GL_FALSE;
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != GL_TRUE)
|
|
||||||
{
|
|
||||||
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
|
||||||
// If the call fails, then we must reinitialize EGL and the GL resources.
|
|
||||||
mRenderer->Pause();
|
|
||||||
mDeviceLost = true;
|
|
||||||
|
|
||||||
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
|
||||||
{
|
|
||||||
RecoverFromLostDevice();
|
|
||||||
}, CallbackContext::Any));
|
|
||||||
|
|
||||||
// wait until OpenGL is reset or thread is cancelled
|
|
||||||
while (mDeviceLost)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mDeviceLost)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
// restart cocos2d-x
|
|
||||||
mRenderer->DeviceLost();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run task on a dedicated high priority background thread.
|
|
||||||
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StopRenderLoop()
|
|
||||||
{
|
|
||||||
if (mRenderLoopWorker)
|
|
||||||
{
|
|
||||||
mRenderLoopWorker->Cancel();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
mRenderLoopWorker = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,11 +41,9 @@ namespace CocosAppWinRT
|
||||||
private:
|
private:
|
||||||
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
||||||
void OnSwapChainPanelSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
|
||||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
||||||
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
||||||
#endif
|
#endif
|
||||||
void GetSwapChainPanelSize(GLsizei* width, GLsizei* height);
|
|
||||||
void CreateRenderSurface();
|
void CreateRenderSurface();
|
||||||
void DestroyRenderSurface();
|
void DestroyRenderSurface();
|
||||||
void RecoverFromLostDevice();
|
void RecoverFromLostDevice();
|
||||||
|
@ -58,12 +56,6 @@ namespace CocosAppWinRT
|
||||||
OpenGLES* mOpenGLES;
|
OpenGLES* mOpenGLES;
|
||||||
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
||||||
|
|
||||||
Windows::Foundation::Size mSwapChainPanelSize;
|
|
||||||
Concurrency::critical_section mSwapChainPanelSizeCriticalSection;
|
|
||||||
|
|
||||||
Windows::Foundation::Size mCustomRenderSurfaceSize;
|
|
||||||
bool mUseCustomRenderSurfaceSize;
|
|
||||||
|
|
||||||
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
||||||
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
||||||
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
||||||
|
|
|
@ -112,14 +112,7 @@ void OpenGLES::Initialize()
|
||||||
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
||||||
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
||||||
//
|
//
|
||||||
// Note: On Windows Phone, we #ifdef out the first set of calls to eglPlatformDisplayEXT and eglInitialize.
|
|
||||||
// Windows Phones devices only support D3D11 Feature Level 9_3, but the Windows Phone emulator supports 11_0+.
|
|
||||||
// We use this #ifdef to limit the Phone emulator to Feature Level 9_3, making it behave more like
|
|
||||||
// real Windows Phone devices.
|
|
||||||
// If you wish to test Feature Level 10_0+ in the Windows Phone emulator then you should remove this #ifdef.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
|
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
|
@ -128,9 +121,8 @@ void OpenGLES::Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on Windows Phone, or certain Windows tablets).
|
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -139,7 +131,7 @@ void OpenGLES::Initialize()
|
||||||
|
|
||||||
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
||||||
{
|
{
|
||||||
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU (e.g. on Surface RT).
|
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
|
||||||
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
||||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
|
@ -188,13 +180,18 @@ void OpenGLES::Reset()
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize)
|
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize, const float* resolutionScale)
|
||||||
{
|
{
|
||||||
if (!panel)
|
if (!panel)
|
||||||
{
|
{
|
||||||
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (renderSurfaceSize != nullptr && resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
throw Exception::CreateException(E_INVALIDARG, L"A size and a scale can't both be specified");
|
||||||
|
}
|
||||||
|
|
||||||
EGLSurface surface = EGL_NO_SURFACE;
|
EGLSurface surface = EGL_NO_SURFACE;
|
||||||
|
|
||||||
const EGLint surfaceAttributes[] =
|
const EGLint surfaceAttributes[] =
|
||||||
|
@ -207,12 +204,18 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
|
|
||||||
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
||||||
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLNativeWindowTypeProperty), panel);
|
surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel);
|
||||||
|
|
||||||
// If a render surface size is specified, add it to the surface creation properties
|
// If a render surface size is specified, add it to the surface creation properties
|
||||||
if (renderSurfaceSize != nullptr)
|
if (renderSurfaceSize != nullptr)
|
||||||
{
|
{
|
||||||
surfaceCreationProperties->Insert(ref new Platform::String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a resolution scale is specified, add it to the surface creation properties
|
||||||
|
if (resolutionScale != nullptr)
|
||||||
|
{
|
||||||
|
surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(*resolutionScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
|
||||||
|
@ -224,6 +227,12 @@ EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurf
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height)
|
||||||
|
{
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
|
||||||
|
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLES::DestroySurface(const EGLSurface surface)
|
void OpenGLES::DestroySurface(const EGLSurface surface)
|
||||||
{
|
{
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
// OpenGL ES includes
|
// OpenGL ES includes
|
||||||
#include <GLES3/gl3.h>
|
#include <GLES3/gl3.h>
|
||||||
#include <GLES3/gl3ext.h>
|
|
||||||
|
|
||||||
// EGL includes
|
// EGL includes
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
@ -34,7 +33,8 @@ public:
|
||||||
OpenGLES();
|
OpenGLES();
|
||||||
~OpenGLES();
|
~OpenGLES();
|
||||||
|
|
||||||
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize);
|
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize, const float* renderResolutionScale);
|
||||||
|
void GetSurfaceDimensions(const EGLSurface surface, EGLint *width, EGLint *height);
|
||||||
void DestroySurface(const EGLSurface surface);
|
void DestroySurface(const EGLSurface surface);
|
||||||
void MakeCurrent(const EGLSurface surface);
|
void MakeCurrent(const EGLSurface surface);
|
||||||
EGLBoolean SwapBuffers(const EGLSurface surface);
|
EGLBoolean SwapBuffers(const EGLSurface surface);
|
||||||
|
|
|
@ -24,7 +24,6 @@ using namespace cocos2d;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace Concurrency;
|
using namespace Concurrency;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Foundation::Collections;
|
|
||||||
using namespace Windows::Graphics::Display;
|
using namespace Windows::Graphics::Display;
|
||||||
using namespace Windows::System::Threading;
|
using namespace Windows::System::Threading;
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
|
@ -50,8 +49,6 @@ OpenGLESPage::OpenGLESPage() :
|
||||||
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
mOpenGLES(openGLES),
|
mOpenGLES(openGLES),
|
||||||
mRenderSurface(EGL_NO_SURFACE),
|
mRenderSurface(EGL_NO_SURFACE),
|
||||||
mCustomRenderSurfaceSize(0,0),
|
|
||||||
mUseCustomRenderSurfaceSize(false),
|
|
||||||
mCoreInput(nullptr),
|
mCoreInput(nullptr),
|
||||||
mDpi(0.0f),
|
mDpi(0.0f),
|
||||||
mDeviceLost(false),
|
mDeviceLost(false),
|
||||||
|
@ -72,8 +69,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
|
|
||||||
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
|
||||||
|
|
||||||
swapChainPanel->SizeChanged +=
|
|
||||||
ref new Windows::UI::Xaml::SizeChangedEventHandler(this, &OpenGLESPage::OnSwapChainPanelSizeChanged);
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
|
||||||
|
@ -85,8 +80,6 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
|
||||||
this->Loaded +=
|
this->Loaded +=
|
||||||
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
|
||||||
|
|
||||||
mSwapChainPanelSize = { swapChainPanel->RenderSize.Width, swapChainPanel->RenderSize.Height };
|
|
||||||
|
|
||||||
#if _MSC_VER >= 1900
|
#if _MSC_VER >= 1900
|
||||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||||
{
|
{
|
||||||
|
@ -158,6 +151,201 @@ void OpenGLESPage::OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::Rou
|
||||||
mVisible = true;
|
mVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::CreateRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
// The app can configure the the SwapChainPanel which may boost performance.
|
||||||
|
// By default, this template uses the default configuration.
|
||||||
|
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, nullptr);
|
||||||
|
|
||||||
|
// You can configure the SwapChainPanel to render at a lower resolution and be scaled up to
|
||||||
|
// the swapchain panel size. This scaling is often free on mobile hardware.
|
||||||
|
//
|
||||||
|
// One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
|
||||||
|
// Size customRenderSurfaceSize = Size(800, 600);
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, &customRenderSurfaceSize, nullptr);
|
||||||
|
//
|
||||||
|
// Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
|
||||||
|
// e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
|
||||||
|
// float customResolutionScale = 0.5f;
|
||||||
|
// mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, &customResolutionScale);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::DestroyRenderSurface()
|
||||||
|
{
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
}
|
||||||
|
mRenderSurface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::RecoverFromLostDevice()
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
DestroyRenderSurface();
|
||||||
|
mOpenGLES->Reset();
|
||||||
|
CreateRenderSurface();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mDeviceLost = false;
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::TerminateApp()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
|
||||||
|
if (mOpenGLES)
|
||||||
|
{
|
||||||
|
mOpenGLES->DestroySurface(mRenderSurface);
|
||||||
|
mOpenGLES->Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Windows::UI::Xaml::Application::Current->Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StartRenderLoop()
|
||||||
|
{
|
||||||
|
// If the render loop is already running then do not start another thread.
|
||||||
|
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
||||||
|
mDpi = currentDisplayInformation->LogicalDpi;
|
||||||
|
|
||||||
|
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
||||||
|
|
||||||
|
// Create a task for rendering that will be run on a background thread.
|
||||||
|
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
|
||||||
|
GLsizei panelWidth = 0;
|
||||||
|
GLsizei panelHeight = 0;
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
|
||||||
|
if (mRenderer.get() == nullptr)
|
||||||
|
{
|
||||||
|
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderer->Resume();
|
||||||
|
|
||||||
|
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
if (!mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until app is visible again or thread is cancelled
|
||||||
|
while (!mVisible)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVisible)
|
||||||
|
{
|
||||||
|
mRenderer->Resume();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||||
|
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
||||||
|
|
||||||
|
// Recreate input dispatch
|
||||||
|
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
||||||
|
{
|
||||||
|
CreateInput();
|
||||||
|
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRenderer->AppShouldExit())
|
||||||
|
{
|
||||||
|
// run on main UI thread
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
TerminateApp();
|
||||||
|
}));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLBoolean result = GL_FALSE;
|
||||||
|
{
|
||||||
|
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
||||||
|
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != GL_TRUE)
|
||||||
|
{
|
||||||
|
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
||||||
|
// If the call fails, then we must reinitialize EGL and the GL resources.
|
||||||
|
mRenderer->Pause();
|
||||||
|
mDeviceLost = true;
|
||||||
|
|
||||||
|
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
||||||
|
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
||||||
|
{
|
||||||
|
RecoverFromLostDevice();
|
||||||
|
}, CallbackContext::Any));
|
||||||
|
|
||||||
|
// wait until OpenGL is reset or thread is cancelled
|
||||||
|
while (mDeviceLost)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mSleepMutex);
|
||||||
|
mSleepCondition.wait(lock);
|
||||||
|
|
||||||
|
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
||||||
|
{
|
||||||
|
return; // thread was cancelled. Exit thread
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDeviceLost)
|
||||||
|
{
|
||||||
|
mOpenGLES->MakeCurrent(mRenderSurface);
|
||||||
|
// restart cocos2d-x
|
||||||
|
mRenderer->DeviceLost();
|
||||||
|
}
|
||||||
|
else // spurious wake up
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run task on a dedicated high priority background thread.
|
||||||
|
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLESPage::StopRenderLoop()
|
||||||
|
{
|
||||||
|
if (mRenderLoopWorker)
|
||||||
|
{
|
||||||
|
mRenderLoopWorker->Cancel();
|
||||||
|
std::unique_lock<std::mutex> locker(mSleepMutex);
|
||||||
|
mSleepCondition.notify_one();
|
||||||
|
mRenderLoopWorker = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
|
||||||
{
|
{
|
||||||
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
|
||||||
|
@ -229,7 +417,6 @@ void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e)
|
||||||
|
|
||||||
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
|
||||||
{
|
{
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mOrientation = sender->CurrentOrientation;
|
mOrientation = sender->CurrentOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,216 +466,3 @@ void OpenGLESPage::OnBackButtonPressed(Object^ sender, BackPressedEventArgs^ arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OpenGLESPage::OnSwapChainPanelSizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
|
||||||
{
|
|
||||||
// Size change events occur outside of the render thread. A lock is required when updating
|
|
||||||
// the swapchainpanel size
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
mSwapChainPanelSize = { e->NewSize.Width, e->NewSize.Height };
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::GetSwapChainPanelSize(GLsizei* width, GLsizei* height)
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection);
|
|
||||||
// If a custom render surface size is specified, return its size instead of
|
|
||||||
// the swapchain panel size.
|
|
||||||
if (mUseCustomRenderSurfaceSize)
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mCustomRenderSurfaceSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mCustomRenderSurfaceSize.Height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*width = static_cast<GLsizei>(mSwapChainPanelSize.Width);
|
|
||||||
*height = static_cast<GLsizei>(mSwapChainPanelSize.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::CreateRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// A Custom render surface size can be specified by uncommenting the following lines.
|
|
||||||
// The render surface will be automatically scaled to fit the entire window. Using a
|
|
||||||
// smaller sized render surface can result in a performance gain.
|
|
||||||
//
|
|
||||||
//mCustomRenderSurfaceSize = Size(800, 600);
|
|
||||||
//mUseCustomRenderSurfaceSize = true;
|
|
||||||
|
|
||||||
mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, mUseCustomRenderSurfaceSize ? &mCustomRenderSurfaceSize : nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::DestroyRenderSurface()
|
|
||||||
{
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
}
|
|
||||||
mRenderSurface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::RecoverFromLostDevice()
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
DestroyRenderSurface();
|
|
||||||
mOpenGLES->Reset();
|
|
||||||
CreateRenderSurface();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mDeviceLost = false;
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::TerminateApp()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
|
|
||||||
if (mOpenGLES)
|
|
||||||
{
|
|
||||||
mOpenGLES->DestroySurface(mRenderSurface);
|
|
||||||
mOpenGLES->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Windows::UI::Xaml::Application::Current->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StartRenderLoop()
|
|
||||||
{
|
|
||||||
// If the render loop is already running then do not start another thread.
|
|
||||||
if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
|
||||||
mDpi = currentDisplayInformation->LogicalDpi;
|
|
||||||
|
|
||||||
auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
|
|
||||||
|
|
||||||
// Create a task for rendering that will be run on a background thread.
|
|
||||||
auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
|
|
||||||
GLsizei panelWidth = 0;
|
|
||||||
GLsizei panelHeight = 0;
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
|
|
||||||
if (mRenderer.get() == nullptr)
|
|
||||||
{
|
|
||||||
mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderer->Resume();
|
|
||||||
|
|
||||||
while (action->Status == Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
if (!mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until app is visible again or thread is cancelled
|
|
||||||
while (!mVisible)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVisible)
|
|
||||||
{
|
|
||||||
mRenderer->Resume();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GetSwapChainPanelSize(&panelWidth, &panelHeight);
|
|
||||||
mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
|
|
||||||
|
|
||||||
// Recreate input dispatch
|
|
||||||
if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
|
|
||||||
{
|
|
||||||
CreateInput();
|
|
||||||
mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRenderer->AppShouldExit())
|
|
||||||
{
|
|
||||||
// run on main UI thread
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]()
|
|
||||||
{
|
|
||||||
TerminateApp();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLBoolean result = GL_FALSE;
|
|
||||||
{
|
|
||||||
critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
|
|
||||||
result = mOpenGLES->SwapBuffers(mRenderSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != GL_TRUE)
|
|
||||||
{
|
|
||||||
// The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
|
|
||||||
// If the call fails, then we must reinitialize EGL and the GL resources.
|
|
||||||
mRenderer->Pause();
|
|
||||||
mDeviceLost = true;
|
|
||||||
|
|
||||||
// XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
|
|
||||||
swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
|
|
||||||
{
|
|
||||||
RecoverFromLostDevice();
|
|
||||||
}, CallbackContext::Any));
|
|
||||||
|
|
||||||
// wait until OpenGL is reset or thread is cancelled
|
|
||||||
while (mDeviceLost)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mSleepMutex);
|
|
||||||
mSleepCondition.wait(lock);
|
|
||||||
|
|
||||||
if (action->Status != Windows::Foundation::AsyncStatus::Started)
|
|
||||||
{
|
|
||||||
return; // thread was cancelled. Exit thread
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mDeviceLost)
|
|
||||||
{
|
|
||||||
mOpenGLES->MakeCurrent(mRenderSurface);
|
|
||||||
// restart cocos2d-x
|
|
||||||
mRenderer->DeviceLost();
|
|
||||||
}
|
|
||||||
else // spurious wake up
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run task on a dedicated high priority background thread.
|
|
||||||
mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLESPage::StopRenderLoop()
|
|
||||||
{
|
|
||||||
if (mRenderLoopWorker)
|
|
||||||
{
|
|
||||||
mRenderLoopWorker->Cancel();
|
|
||||||
std::unique_lock<std::mutex> locker(mSleepMutex);
|
|
||||||
mSleepCondition.notify_one();
|
|
||||||
mRenderLoopWorker = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,11 +41,9 @@ namespace CocosAppWinRT
|
||||||
private:
|
private:
|
||||||
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
void OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
||||||
void OnSwapChainPanelSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
|
||||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
|
||||||
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
|
||||||
#endif
|
#endif
|
||||||
void GetSwapChainPanelSize(GLsizei* width, GLsizei* height);
|
|
||||||
void CreateRenderSurface();
|
void CreateRenderSurface();
|
||||||
void DestroyRenderSurface();
|
void DestroyRenderSurface();
|
||||||
void RecoverFromLostDevice();
|
void RecoverFromLostDevice();
|
||||||
|
@ -58,12 +56,6 @@ namespace CocosAppWinRT
|
||||||
OpenGLES* mOpenGLES;
|
OpenGLES* mOpenGLES;
|
||||||
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
std::shared_ptr<Cocos2dRenderer> mRenderer;
|
||||||
|
|
||||||
Windows::Foundation::Size mSwapChainPanelSize;
|
|
||||||
Concurrency::critical_section mSwapChainPanelSizeCriticalSection;
|
|
||||||
|
|
||||||
Windows::Foundation::Size mCustomRenderSurfaceSize;
|
|
||||||
bool mUseCustomRenderSurfaceSize;
|
|
||||||
|
|
||||||
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
EGLSurface mRenderSurface; // This surface is associated with a swapChainPanel on the page
|
||||||
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
Concurrency::critical_section mRenderSurfaceCriticalSection;
|
||||||
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
Windows::Foundation::IAsyncAction^ mRenderLoopWorker;
|
||||||
|
|
Loading…
Reference in New Issue