OpenGLESPage.xaml.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * cocos2d-x http://www.cocos2d-x.org
  3. *
  4. * Copyright (c) 2010-2014 - cocos2d-x community
  5. *
  6. * Portions Copyright (c) Microsoft Open Technologies, Inc.
  7. * All Rights Reserved
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and limitations under the License.
  17. */
  18. #include "App.xaml.h"
  19. #include "OpenGLESPage.xaml.h"
  20. using namespace CocosAppWinRT;
  21. using namespace cocos2d;
  22. using namespace Platform;
  23. using namespace Concurrency;
  24. using namespace Windows::Foundation;
  25. using namespace Windows::Graphics::Display;
  26. using namespace Windows::System::Threading;
  27. using namespace Windows::UI::Core;
  28. using namespace Windows::UI::Input;
  29. using namespace Windows::UI::Xaml;
  30. using namespace Windows::UI::Xaml::Controls;
  31. using namespace Windows::UI::Xaml::Controls::Primitives;
  32. using namespace Windows::UI::Xaml::Data;
  33. using namespace Windows::UI::Xaml::Input;
  34. using namespace Windows::UI::Xaml::Media;
  35. using namespace Windows::UI::Xaml::Navigation;
  36. #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
  37. using namespace Windows::Phone::UI::Input;
  38. #endif
  39. OpenGLESPage::OpenGLESPage() :
  40. OpenGLESPage(nullptr)
  41. {
  42. }
  43. OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) :
  44. mOpenGLES(openGLES),
  45. mRenderSurface(EGL_NO_SURFACE),
  46. mCoreInput(nullptr),
  47. mDpi(0.0f),
  48. mDeviceLost(false),
  49. mCursorVisible(true),
  50. mVisible(false),
  51. mOrientation(DisplayOrientations::Landscape)
  52. {
  53. InitializeComponent();
  54. Windows::UI::Core::CoreWindow^ window = Windows::UI::Xaml::Window::Current->CoreWindow;
  55. window->VisibilityChanged +=
  56. ref new Windows::Foundation::TypedEventHandler<Windows::UI::Core::CoreWindow^, Windows::UI::Core::VisibilityChangedEventArgs^>(this, &OpenGLESPage::OnVisibilityChanged);
  57. window->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &OpenGLESPage::OnKeyPressed);
  58. window->KeyUp += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &OpenGLESPage::OnKeyReleased);
  59. window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &OpenGLESPage::OnCharacterReceived);
  60. DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
  61. currentDisplayInformation->OrientationChanged +=
  62. ref new TypedEventHandler<DisplayInformation^, Object^>(this, &OpenGLESPage::OnOrientationChanged);
  63. mOrientation = currentDisplayInformation->CurrentOrientation;
  64. this->Loaded +=
  65. ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
  66. #if _MSC_VER >= 1900
  67. if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
  68. {
  69. Windows::UI::ViewManagement::StatusBar::GetForCurrentView()->HideAsync();
  70. }
  71. if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
  72. {
  73. HardwareButtons::BackPressed += ref new EventHandler<BackPressedEventArgs^>(this, &OpenGLESPage::OnBackButtonPressed);
  74. }
  75. #else
  76. #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
  77. Windows::UI::ViewManagement::StatusBar::GetForCurrentView()->HideAsync();
  78. HardwareButtons::BackPressed += ref new EventHandler<BackPressedEventArgs^>(this, &OpenGLESPage::OnBackButtonPressed);
  79. #else
  80. // Disable all pointer visual feedback for better performance when touching.
  81. // This is not supported on Windows Phone applications.
  82. auto pointerVisualizationSettings = Windows::UI::Input::PointerVisualizationSettings::GetForCurrentView();
  83. pointerVisualizationSettings->IsContactFeedbackEnabled = false;
  84. pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;
  85. #endif
  86. #endif
  87. CreateInput();
  88. }
  89. void OpenGLESPage::CreateInput()
  90. {
  91. // Register our SwapChainPanel to get independent input pointer events
  92. auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction ^)
  93. {
  94. // The CoreIndependentInputSource will raise pointer events for the specified device types on whichever thread it's created on.
  95. mCoreInput = swapChainPanel->CreateCoreIndependentInputSource(
  96. Windows::UI::Core::CoreInputDeviceTypes::Mouse |
  97. Windows::UI::Core::CoreInputDeviceTypes::Touch |
  98. Windows::UI::Core::CoreInputDeviceTypes::Pen
  99. );
  100. // Register for pointer events, which will be raised on the background thread.
  101. mCoreInput->PointerPressed += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerPressed);
  102. mCoreInput->PointerMoved += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerMoved);
  103. mCoreInput->PointerReleased += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerReleased);
  104. mCoreInput->PointerWheelChanged += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerWheelChanged);
  105. if (GLViewImpl::sharedOpenGLView() && !GLViewImpl::sharedOpenGLView()->isCursorVisible())
  106. {
  107. mCoreInput->PointerCursor = nullptr;
  108. }
  109. // Begin processing input messages as they're delivered.
  110. mCoreInput->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
  111. });
  112. // Run task on a dedicated high priority background thread.
  113. mInputLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced);
  114. }
  115. OpenGLESPage::~OpenGLESPage()
  116. {
  117. StopRenderLoop();
  118. DestroyRenderSurface();
  119. }
  120. void OpenGLESPage::OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
  121. {
  122. // The SwapChainPanel has been created and arranged in the page layout, so EGL can be initialized.
  123. CreateRenderSurface();
  124. StartRenderLoop();
  125. mVisible = true;
  126. }
  127. void OpenGLESPage::CreateRenderSurface()
  128. {
  129. if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE)
  130. {
  131. // The app can configure the SwapChainPanel which may boost performance.
  132. // By default, this template uses the default configuration.
  133. mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, nullptr);
  134. // You can configure the SwapChainPanel to render at a lower resolution and be scaled up to
  135. // the swapchain panel size. This scaling is often free on mobile hardware.
  136. //
  137. // One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
  138. // Size customRenderSurfaceSize = Size(800, 600);
  139. // mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, &customRenderSurfaceSize, nullptr);
  140. //
  141. // Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
  142. // e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
  143. // float customResolutionScale = 0.5f;
  144. // mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel, nullptr, &customResolutionScale);
  145. //
  146. }
  147. }
  148. void OpenGLESPage::DestroyRenderSurface()
  149. {
  150. if (mOpenGLES)
  151. {
  152. mOpenGLES->DestroySurface(mRenderSurface);
  153. }
  154. mRenderSurface = EGL_NO_SURFACE;
  155. }
  156. void OpenGLESPage::RecoverFromLostDevice()
  157. {
  158. critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
  159. DestroyRenderSurface();
  160. mOpenGLES->Reset();
  161. CreateRenderSurface();
  162. std::unique_lock<std::mutex> locker(mSleepMutex);
  163. mDeviceLost = false;
  164. mSleepCondition.notify_one();
  165. }
  166. void OpenGLESPage::TerminateApp()
  167. {
  168. {
  169. critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
  170. if (mOpenGLES)
  171. {
  172. mOpenGLES->DestroySurface(mRenderSurface);
  173. mOpenGLES->Cleanup();
  174. }
  175. }
  176. Windows::UI::Xaml::Application::Current->Exit();
  177. }
  178. void OpenGLESPage::StartRenderLoop()
  179. {
  180. // If the render loop is already running then do not start another thread.
  181. if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started)
  182. {
  183. return;
  184. }
  185. DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
  186. mDpi = currentDisplayInformation->LogicalDpi;
  187. auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher;
  188. // Create a task for rendering that will be run on a background thread.
  189. auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action)
  190. {
  191. mOpenGLES->MakeCurrent(mRenderSurface);
  192. GLsizei panelWidth = 0;
  193. GLsizei panelHeight = 0;
  194. mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
  195. if (mRenderer.get() == nullptr)
  196. {
  197. mRenderer = std::make_shared<Cocos2dRenderer>(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel);
  198. }
  199. mRenderer->Resume();
  200. while (action->Status == Windows::Foundation::AsyncStatus::Started)
  201. {
  202. if (!mVisible)
  203. {
  204. mRenderer->Pause();
  205. }
  206. // wait until app is visible again or thread is cancelled
  207. while (!mVisible)
  208. {
  209. std::unique_lock<std::mutex> lock(mSleepMutex);
  210. mSleepCondition.wait(lock);
  211. if (action->Status != Windows::Foundation::AsyncStatus::Started)
  212. {
  213. return; // thread was cancelled. Exit thread
  214. }
  215. if (mVisible)
  216. {
  217. mRenderer->Resume();
  218. }
  219. else // spurious wake up
  220. {
  221. continue;
  222. }
  223. }
  224. mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
  225. mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation);
  226. // Recreate input dispatch
  227. if (GLViewImpl::sharedOpenGLView() && mCursorVisible != GLViewImpl::sharedOpenGLView()->isCursorVisible())
  228. {
  229. CreateInput();
  230. mCursorVisible = GLViewImpl::sharedOpenGLView()->isCursorVisible();
  231. }
  232. if (mRenderer->AppShouldExit())
  233. {
  234. // run on main UI thread
  235. swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
  236. {
  237. TerminateApp();
  238. }));
  239. return;
  240. }
  241. EGLBoolean result = GL_FALSE;
  242. {
  243. critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
  244. result = mOpenGLES->SwapBuffers(mRenderSurface);
  245. }
  246. if (result != GL_TRUE)
  247. {
  248. // The call to eglSwapBuffers was not be successful (i.e. due to Device Lost)
  249. // If the call fails, then we must reinitialize EGL and the GL resources.
  250. mRenderer->Pause();
  251. mDeviceLost = true;
  252. // XAML objects like the SwapChainPanel must only be manipulated on the UI thread.
  253. swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
  254. {
  255. RecoverFromLostDevice();
  256. }, CallbackContext::Any));
  257. // wait until OpenGL is reset or thread is cancelled
  258. while (mDeviceLost)
  259. {
  260. std::unique_lock<std::mutex> lock(mSleepMutex);
  261. mSleepCondition.wait(lock);
  262. if (action->Status != Windows::Foundation::AsyncStatus::Started)
  263. {
  264. return; // thread was cancelled. Exit thread
  265. }
  266. if (!mDeviceLost)
  267. {
  268. mOpenGLES->MakeCurrent(mRenderSurface);
  269. // restart cocos2d-x
  270. mRenderer->DeviceLost();
  271. }
  272. else // spurious wake up
  273. {
  274. continue;
  275. }
  276. }
  277. }
  278. }
  279. });
  280. // Run task on a dedicated high priority background thread.
  281. mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, Windows::System::Threading::WorkItemPriority::High, Windows::System::Threading::WorkItemOptions::TimeSliced);
  282. }
  283. void OpenGLESPage::StopRenderLoop()
  284. {
  285. if (mRenderLoopWorker)
  286. {
  287. mRenderLoopWorker->Cancel();
  288. std::unique_lock<std::mutex> locker(mSleepMutex);
  289. mSleepCondition.notify_one();
  290. mRenderLoopWorker = nullptr;
  291. }
  292. }
  293. void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e)
  294. {
  295. bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
  296. if (mRenderer)
  297. {
  298. mRenderer->QueuePointerEvent(isMouseEvent ? PointerEventType::MousePressed : PointerEventType::PointerPressed, e);
  299. }
  300. }
  301. void OpenGLESPage::OnPointerMoved(Object^ sender, PointerEventArgs^ e)
  302. {
  303. bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
  304. if (mRenderer)
  305. {
  306. mRenderer->QueuePointerEvent(isMouseEvent ? PointerEventType::MouseMoved : PointerEventType::PointerMoved, e);
  307. }
  308. }
  309. void OpenGLESPage::OnPointerReleased(Object^ sender, PointerEventArgs^ e)
  310. {
  311. bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
  312. if (mRenderer)
  313. {
  314. mRenderer->QueuePointerEvent(isMouseEvent ? PointerEventType::MouseReleased : PointerEventType::PointerReleased, e);
  315. }
  316. }
  317. void OpenGLESPage::OnPointerWheelChanged(Object^ sender, PointerEventArgs^ e)
  318. {
  319. bool isMouseEvent = e->CurrentPoint->PointerDevice->PointerDeviceType == Windows::Devices::Input::PointerDeviceType::Mouse;
  320. if (mRenderer && isMouseEvent)
  321. {
  322. mRenderer->QueuePointerEvent(PointerEventType::MouseWheelChanged, e);
  323. }
  324. }
  325. void OpenGLESPage::OnKeyPressed(CoreWindow^ sender, KeyEventArgs^ e)
  326. {
  327. //log("OpenGLESPage::OnKeyPressed %d", e->VirtualKey);
  328. if (mRenderer)
  329. {
  330. mRenderer->QueueKeyboardEvent(WinRTKeyboardEventType::KeyPressed, e);
  331. }
  332. }
  333. void OpenGLESPage::OnCharacterReceived(CoreWindow^ sender, CharacterReceivedEventArgs^ e)
  334. {
  335. #if 0
  336. if (!e->KeyStatus.WasKeyDown)
  337. {
  338. log("OpenGLESPage::OnCharacterReceived %d", e->KeyCode);
  339. }
  340. #endif
  341. }
  342. void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e)
  343. {
  344. //log("OpenGLESPage::OnKeyReleased %d", e->VirtualKey);
  345. if (mRenderer)
  346. {
  347. mRenderer->QueueKeyboardEvent(WinRTKeyboardEventType::KeyReleased, e);
  348. }
  349. }
  350. void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
  351. {
  352. mOrientation = sender->CurrentOrientation;
  353. }
  354. void OpenGLESPage::SetVisibility(bool isVisible)
  355. {
  356. if (isVisible && mRenderSurface != EGL_NO_SURFACE)
  357. {
  358. if (!mVisible)
  359. {
  360. std::unique_lock<std::mutex> locker(mSleepMutex);
  361. mVisible = true;
  362. mSleepCondition.notify_one();
  363. }
  364. }
  365. else
  366. {
  367. mVisible = false;
  368. }
  369. }
  370. void OpenGLESPage::OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args)
  371. {
  372. if (args->Visible && mRenderSurface != EGL_NO_SURFACE)
  373. {
  374. SetVisibility(true);
  375. }
  376. else
  377. {
  378. SetVisibility(false);
  379. }
  380. }
  381. #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || _MSC_VER >= 1900
  382. /*
  383. We set args->Handled = true to prevent the app from quitting when the back button is pressed.
  384. This is because this back button event happens on the XAML UI thread and not the cocos2d-x UI thread.
  385. We need to give the game developer a chance to decide to exit the app depending on where they
  386. are in their game. They can receive the back button event by listening for the
  387. EventKeyboard::KeyCode::KEY_ESCAPE event.
  388. The default behavior is to exit the app if the EventKeyboard::KeyCode::KEY_ESCAPE event
  389. is not handled by the game.
  390. */
  391. void OpenGLESPage::OnBackButtonPressed(Object^ sender, BackPressedEventArgs^ args)
  392. {
  393. if (mRenderer)
  394. {
  395. mRenderer->QueueBackButtonEvent();
  396. args->Handled = true;
  397. }
  398. }
  399. #endif