#include "android/android_native_app_glue.h" #include "materialsystem/igamewindow.h" #include "tier0/lib.h" #include "tier0/platform.h" #include "tier1/interface.h" #include "tier1/utlvector.h" #include "volk.h" extern struct android_app *g_android_app; class CAndroidGameWindow: public IGameWindow { public: virtual void Init() override; virtual void Shutdown() override; virtual void Frame( float fDelta ) override; virtual uint32_t GetRenderWidth() override; virtual uint32_t GetRenderHeight() override; virtual bool BRenderSizeUpdated() override; virtual void SetOutputImage( IImage *pImage ) override; virtual IImage *GetOutputImage() override; virtual void SetKeyCallback( KeyCallbackFn fn ) override; virtual void SetAxisCallback( AxisCallbackFn fn ) override; virtual void *CreateVulkanSurface( void *pInstance ) override; virtual void DestroyVulkanSurface( void *pInstance ) override; virtual bool IsValid() override; KeyCallbackFn m_fnKeyCallback = NULL; AxisCallbackFn m_fnAxisCallback = NULL; bool m_bWindowSizeUpdated; uint32_t m_uRenderWidth; uint32_t m_uRenderHeight; bool m_bIsValid = false; private: VkSurfaceKHR m_hSurface = NULL; IImage *m_pOutputImage = NULL; }; void CAndroidGameWindow::Init() { m_uRenderWidth = 1280; m_uRenderHeight = 720; } void CAndroidGameWindow::Shutdown() { } void CAndroidGameWindow::Frame( float fDelta ) { } uint32_t CAndroidGameWindow::GetRenderWidth() { return m_uRenderWidth; } uint32_t CAndroidGameWindow::GetRenderHeight() { return m_uRenderHeight; } bool CAndroidGameWindow::BRenderSizeUpdated() { return m_bWindowSizeUpdated; } void CAndroidGameWindow::SetOutputImage( IImage *pImage ) { m_pOutputImage = pImage; } IImage *CAndroidGameWindow::GetOutputImage() { return m_pOutputImage; } void CAndroidGameWindow::SetKeyCallback( KeyCallbackFn fn ) { m_fnKeyCallback = fn; } void CAndroidGameWindow::SetAxisCallback( AxisCallbackFn fn ) { m_fnAxisCallback = fn; } void *CAndroidGameWindow::CreateVulkanSurface( void *pInstance ) { VkAndroidSurfaceCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; ci.window = g_android_app->window; vkCreateAndroidSurfaceKHR((VkInstance)pInstance, &ci, NULL, &m_hSurface); return m_hSurface; } void CAndroidGameWindow::DestroyVulkanSurface( void *pInstance ) { vkDestroySurfaceKHR((VkInstance)pInstance, m_hSurface, NULL); } bool CAndroidGameWindow::IsValid() { return m_bIsValid; } class CAndroidGameWindowManager: public IGameWindowManager { public: virtual void Init() override; virtual void Frame( float fDelta ) override; virtual void Shutdown() override; virtual IGameWindow *CreateWindow() override; virtual void DestroyWindow( IGameWindow* pWindow ) override; virtual int GetVulkanInstanceExtensionCount() override; virtual const char **GetVulkanInstanceExtensions() override; CAndroidGameWindow m_window; private: }; IGameWindowManager *GameWindowManager() { static CAndroidGameWindowManager mgr; return &mgr; } EXPOSE_INTERFACE_FN(GameWindowManager, IGameWindowManager, GAME_WINDOW_MANAGER_INTERFACE_VERSION) #include "android/log.h" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "funnygame", __VA_ARGS__) static void HandleAndroidEvent(android_app* app, int32_t cmd) { CAndroidGameWindowManager *pMgr = (CAndroidGameWindowManager*)GameWindowManager(); switch (cmd) { case APP_CMD_INIT_WINDOW: pMgr->m_window.m_bIsValid = true; break; default: break; } } void CAndroidGameWindowManager::Init() { g_android_app->onAppCmd = HandleAndroidEvent; while (true) { int events; android_poll_source* source; while (ALooper_pollOnce(0, nullptr, &events, (void**)&source) >= 0) { if (source) source->process(g_android_app, source); } if (m_window.IsValid()) break; } } /* static EInputButton GetKeyButton( Android_Keycode eCode ) { } */ void CAndroidGameWindowManager::Frame( float fDelta ) { m_window.m_bWindowSizeUpdated = false; int events; android_poll_source* source; while (ALooper_pollOnce(0, nullptr, &events, (void**)&source) >= 0) { if (source) source->process(g_android_app, source); } LOGI("%u %u", m_window.m_uRenderWidth, m_window.m_uRenderHeight); uint32_t uNewWidth = ANativeWindow_getWidth(g_android_app->window); uint32_t uNewHeight = ANativeWindow_getHeight(g_android_app->window); if (m_window.m_uRenderWidth != uNewWidth || m_window.m_uRenderHeight != uNewHeight) { m_window.m_bWindowSizeUpdated = true; } m_window.m_uRenderWidth = uNewWidth; m_window.m_uRenderHeight = uNewHeight; } void CAndroidGameWindowManager::Shutdown() { } IGameWindow *CAndroidGameWindowManager::CreateWindow() { return &m_window; } void CAndroidGameWindowManager::DestroyWindow( IGameWindow* pWindow ) { pWindow->Shutdown(); } int CAndroidGameWindowManager::GetVulkanInstanceExtensionCount() { return 2; } static const char *extensions[] = { VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_EXTENSION_NAME, }; const char **CAndroidGameWindowManager::GetVulkanInstanceExtensions() { return extensions; }