mirror of https://github.com/mosra/magnum.git
6 changed files with 634 additions and 0 deletions
@ -0,0 +1,242 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "AndroidApplication.h" |
||||||
|
|
||||||
|
#include <Corrade/Utility/AndroidStreamBuffer.h> |
||||||
|
#include <Corrade/Utility/Debug.h> |
||||||
|
|
||||||
|
#include "Magnum/Context.h" |
||||||
|
|
||||||
|
#include "Implementation/Egl.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Platform { |
||||||
|
|
||||||
|
/** @todo Delegating constructors when support for GCC 4.6 can be dropped */ |
||||||
|
|
||||||
|
AndroidApplication::AndroidApplication(const Arguments& arguments, const Configuration& configuration): _state(arguments) { |
||||||
|
initialize(); |
||||||
|
createContext(configuration); |
||||||
|
} |
||||||
|
|
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
AndroidApplication::AndroidApplication(const Arguments& arguments): _state(arguments) { |
||||||
|
initialize(); |
||||||
|
createContext(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
AndroidApplication::AndroidApplication(const Arguments& arguments, std::nullptr_t): _state(arguments) { |
||||||
|
initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
AndroidApplication::~AndroidApplication() { |
||||||
|
eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
||||||
|
eglDestroyContext(_display, _context); |
||||||
|
eglDestroySurface(_display, _surface); |
||||||
|
eglTerminate(_display); |
||||||
|
} |
||||||
|
|
||||||
|
struct AndroidApplication::LogOutput { |
||||||
|
LogOutput(); |
||||||
|
|
||||||
|
Utility::AndroidLogStreamBuffer debugBuffer, warningBuffer, errorBuffer; |
||||||
|
std::ostream debugStream, warningStream, errorStream; |
||||||
|
}; |
||||||
|
|
||||||
|
AndroidApplication::LogOutput::LogOutput(): |
||||||
|
debugBuffer(Utility::AndroidLogStreamBuffer::LogPriority::Info, "magnum"), |
||||||
|
warningBuffer(Utility::AndroidLogStreamBuffer::LogPriority::Warning, "magnum"), |
||||||
|
errorBuffer(Utility::AndroidLogStreamBuffer::LogPriority::Error, "magnum"), |
||||||
|
debugStream(&debugBuffer), warningStream(&warningBuffer), errorStream(&errorBuffer) |
||||||
|
{ |
||||||
|
Debug::setOutput(&debugStream); |
||||||
|
Warning::setOutput(&warningStream); |
||||||
|
Error::setOutput(&errorStream); |
||||||
|
} |
||||||
|
|
||||||
|
void AndroidApplication::initialize() { |
||||||
|
/* Redirect debug output to Android log */ |
||||||
|
_logOutput.reset(new LogOutput); |
||||||
|
} |
||||||
|
|
||||||
|
void AndroidApplication::createContext() { createContext({}); } |
||||||
|
|
||||||
|
void AndroidApplication::createContext(const Configuration& configuration) { |
||||||
|
if(!tryCreateContext(configuration)) std::exit(32); |
||||||
|
} |
||||||
|
|
||||||
|
bool AndroidApplication::tryCreateContext(const Configuration& configuration) { |
||||||
|
/* Initialize EGL */ |
||||||
|
_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
||||||
|
if(!eglInitialize(_display, nullptr, nullptr)) { |
||||||
|
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot initialize EGL:" |
||||||
|
<< Implementation::eglErrorString(eglGetError()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/* Choose config */ |
||||||
|
const EGLint configAttributes[] = { |
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
||||||
|
EGL_BLUE_SIZE, 8, |
||||||
|
EGL_GREEN_SIZE, 8, |
||||||
|
EGL_RED_SIZE, 8, |
||||||
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
||||||
|
EGL_NONE |
||||||
|
}; |
||||||
|
EGLint configCount; |
||||||
|
EGLConfig config; |
||||||
|
if(!eglChooseConfig(_display, configAttributes, &config, 1, &configCount)) { |
||||||
|
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot choose EGL config:" |
||||||
|
<< Implementation::eglErrorString(eglGetError()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/* Resize native window and match it to the selected format */ |
||||||
|
EGLint format; |
||||||
|
CORRADE_INTERNAL_ASSERT_OUTPUT(eglGetConfigAttrib(_display, config, EGL_NATIVE_VISUAL_ID, &format)); |
||||||
|
ANativeWindow_setBuffersGeometry(_state->window, |
||||||
|
configuration.size().isZero() ? 0 : configuration.size().x(), |
||||||
|
configuration.size().isZero() ? 0 : configuration.size().y(), format); |
||||||
|
|
||||||
|
/* Create surface and context */ |
||||||
|
if(!(_surface = eglCreateWindowSurface(_display, config, _state->window, nullptr))) { |
||||||
|
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot create EGL window surface:" |
||||||
|
<< Implementation::eglErrorString(eglGetError()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
const EGLint contextAttributes[] = { |
||||||
|
#ifdef MAGNUM_TARGET_GLES2 |
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 2, |
||||||
|
#elif defined(MAGNUM_TARGET_GLES3) |
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 3, |
||||||
|
#else |
||||||
|
#error Android with desktop OpenGL? Wow, that is a new thing. |
||||||
|
#endif |
||||||
|
EGL_NONE |
||||||
|
}; |
||||||
|
if(!(_context = eglCreateContext(_display, config, EGL_NO_CONTEXT, contextAttributes))) { |
||||||
|
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot create EGL context:" |
||||||
|
<< Implementation::eglErrorString(eglGetError()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/* Make the context current */ |
||||||
|
CORRADE_INTERNAL_ASSERT_OUTPUT(eglMakeCurrent(_display, _surface, _surface, _context)); |
||||||
|
|
||||||
|
_c.reset(new Context); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void AndroidApplication::swapBuffers() { |
||||||
|
eglSwapBuffers(_display, _surface); |
||||||
|
} |
||||||
|
|
||||||
|
void AndroidApplication::viewportEvent(const Vector2i&) {} |
||||||
|
|
||||||
|
namespace { |
||||||
|
struct Data { |
||||||
|
Data(std::unique_ptr<AndroidApplication>(*instancer)(const AndroidApplication::Arguments&)): instancer(instancer) {} |
||||||
|
|
||||||
|
std::unique_ptr<AndroidApplication>(*instancer)(const AndroidApplication::Arguments&); |
||||||
|
std::unique_ptr<AndroidApplication> instance; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
void AndroidApplication::commandEvent(android_app* state, int32_t cmd) { |
||||||
|
Data& data = *static_cast<Data*>(state->userData); |
||||||
|
|
||||||
|
switch (cmd) { |
||||||
|
case APP_CMD_SAVE_STATE: |
||||||
|
/** @todo Make use of this */ |
||||||
|
break; |
||||||
|
|
||||||
|
case APP_CMD_INIT_WINDOW: |
||||||
|
/* Create the application */ |
||||||
|
if(!data.instance) { |
||||||
|
data.instance = data.instancer(state); |
||||||
|
data.instance->drawEvent(); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case APP_CMD_TERM_WINDOW: |
||||||
|
/* Destroy the application */ |
||||||
|
data.instance.reset(); |
||||||
|
break; |
||||||
|
|
||||||
|
case APP_CMD_GAINED_FOCUS: |
||||||
|
case APP_CMD_LOST_FOCUS: |
||||||
|
/** @todo Make use of these */ |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::int32_t AndroidApplication::inputEvent(android_app*, AInputEvent*) { |
||||||
|
/** @todo Implement input events */ |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
void AndroidApplication::exec(android_app* state, std::unique_ptr<AndroidApplication>(*instancer)(const Arguments&)) { |
||||||
|
state->onAppCmd = commandEvent; |
||||||
|
state->onInputEvent = inputEvent; |
||||||
|
|
||||||
|
/* Make sure the glue isn't stripped. WHY WHYYY CAN'T THIS BE DONE SOME
|
||||||
|
SANE WAY WHYY */ |
||||||
|
app_dummy(); |
||||||
|
|
||||||
|
/** @todo Make use of saved state */ |
||||||
|
Data data{instancer}; |
||||||
|
state->userData = &data; |
||||||
|
|
||||||
|
for(;;) { |
||||||
|
/* Read all pending events. Block and wait for them only if the app
|
||||||
|
doesn't want to redraw immediately WHY THIS GODDAMN THING DOESNT |
||||||
|
HAVE SOMETHING LIKE WAIT FOR EVENT SO I NEED TO TANGLE THIS TANGLED |
||||||
|
MESS OF HELL */ |
||||||
|
int ident, events; |
||||||
|
android_poll_source* source; |
||||||
|
while((ident = ALooper_pollAll( |
||||||
|
data.instance && (data.instance->_flags & Flag::Redraw) ? 0 : -1, |
||||||
|
nullptr, &events, reinterpret_cast<void**>(&source))) >= 0) |
||||||
|
{ |
||||||
|
/* Process this event OH SIR MAY MY POOR EXISTENCE CALL THIS
|
||||||
|
FUNCTION FOR YOU IF YOU DON'T MIND? */ |
||||||
|
if(source) source->process(state, source); |
||||||
|
|
||||||
|
/* Exit WHY THIS HAS TO BE HANDLED HERE WHILE EVERY OTHER THING
|
||||||
|
IS HANDLED THROUGH CALLBACK GODDAMMIT */ |
||||||
|
if(state->destroyRequested != 0) return; |
||||||
|
} |
||||||
|
|
||||||
|
/* Redraw the app if it wants to be redrawn. Frame limiting is done by
|
||||||
|
Android itself */ |
||||||
|
if(data.instance && (data.instance->_flags & Flag::Redraw)) |
||||||
|
data.instance->drawEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
state->userData = nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
}} |
||||||
@ -0,0 +1,357 @@ |
|||||||
|
#ifndef Magnum_Platform_AndroidApplication_h |
||||||
|
#define Magnum_Platform_AndroidApplication_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief Class @ref Magnum::Platform::AndroidApplication |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <EGL/egl.h> |
||||||
|
#include <android_native_app_glue.h> |
||||||
|
|
||||||
|
#include "Magnum/Magnum.h" |
||||||
|
#include "Magnum/Math/Vector2.h" |
||||||
|
#include "Magnum/Platform/Platform.h" |
||||||
|
|
||||||
|
#ifndef CORRADE_TARGET_ANDROID |
||||||
|
#error This file is available only on Android |
||||||
|
#endif |
||||||
|
|
||||||
|
namespace Magnum { namespace Platform { |
||||||
|
|
||||||
|
/** @nosubgrouping
|
||||||
|
@brief Android application |
||||||
|
|
||||||
|
Application running in Android. |
||||||
|
|
||||||
|
This application library is available only in |
||||||
|
@ref CORRADE_TARGET_ANDROID "Android", see respective sections |
||||||
|
in @ref building-corrade-cross-android "Corrade's" and @ref building-cross-android "Magnum's" |
||||||
|
building documentation. It is built if `WITH_ANDROIDAPPLICATION` is enabled in |
||||||
|
CMake. |
||||||
|
|
||||||
|
## Bootstrap application |
||||||
|
|
||||||
|
Fully contained base application using @ref GlutApplication for desktop build |
||||||
|
and @ref AndroidApplication for Android build along with full Android packaging |
||||||
|
stuff and CMake setup is available in `base-android` branch of |
||||||
|
[Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository,
|
||||||
|
download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-android.tar.gz)
|
||||||
|
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-android.zip) file.
|
||||||
|
After extracting the downloaded archive, you can do the desktop build in the |
||||||
|
same way as with @ref GlutApplication. For the Android build you also |
||||||
|
need to put the contents of toolchains repository from https://github.com/mosra/toolchains
|
||||||
|
in `toolchains/` subdirectory. Don't forget to adapt `ANDROID_NDK_ROOT` in |
||||||
|
`toolchains/generic/Android-*.cmake` to path where NDK is installed. Default is |
||||||
|
`/opt/android-ndk`. Adapt also `ANDROID_SYSROOT` to your preferred API level. |
||||||
|
You might also need to update `ANDROID_TOOLCHAIN_PREFIX` and |
||||||
|
`ANDROID_TOOLCHAIN_ROOT` to fit your system. |
||||||
|
|
||||||
|
First you need to update Android project files with the following command. It |
||||||
|
will create `build.xml` file for Ant and a bunch of other files. You need to |
||||||
|
specify the target for which you will build in the `-t` parameter. List of all |
||||||
|
targets can be obtained by calling `android list target`. |
||||||
|
|
||||||
|
android update project -p . -t "android-19" |
||||||
|
|
||||||
|
Then create build directories for ARM and x86 and run `cmake` and build command |
||||||
|
in them. The toolchains need access to the platform file, so be sure to |
||||||
|
properly set **absolute** path to `toolchains/modules/` directory containing |
||||||
|
`Platform/Android.cmake`. |
||||||
|
|
||||||
|
mkdir build-android-arm && cd build-android-arm |
||||||
|
cmake .. \
|
||||||
|
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Android-ARM.cmake" |
||||||
|
cmake --build . |
||||||
|
|
||||||
|
mkdir build-android-x86 && cd build-android-x86 |
||||||
|
cmake .. \
|
||||||
|
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Android-x86.cmake" |
||||||
|
cmake --build . |
||||||
|
|
||||||
|
The compiled binaries will be put into `lib/armeabi-v7a` and `lib/x86`. You can |
||||||
|
then build the APK package simply by running `ant`. The resulting APK package |
||||||
|
can be then installed directly on the device or emulator using `adb install`. |
||||||
|
|
||||||
|
ant debug |
||||||
|
adb install bin/NativeActivity-debug.apk |
||||||
|
|
||||||
|
## General usage |
||||||
|
|
||||||
|
For CMake you need to copy `FindEGL.cmake` and `FindOpenGLES2.cmake` (or |
||||||
|
`FindOpenGLES3.cmake`) from `modules/` directory in %Magnum source to `modules/` |
||||||
|
dir in your project (so it is able to find EGL and OpenGL ES libraries). |
||||||
|
Request `%AndroidApplication` component, add |
||||||
|
`${MAGNUM_ANDROIDAPPLICATION_INCLUDE_DIRS}` to include path and link to |
||||||
|
`${MAGNUM_ANDROIDAPPLICATION_LIBRARIES}`. If no other application is requested, |
||||||
|
you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` and |
||||||
|
`${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See |
||||||
|
@ref building and @ref cmake for more information. Note that unlike on other |
||||||
|
platforms you need to create *shared library* instead of executable. The |
||||||
|
resulting binary then needs to be copied to `lib/armeabi-v7a` and `lib/x86`, |
||||||
|
you can do that automatically in CMake using the following commands: |
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}") |
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}") |
||||||
|
|
||||||
|
In C++ code you need to implement at least @ref drawEvent() to be able to draw |
||||||
|
on the screen. The subclass must be then made accessible from JNI using |
||||||
|
@ref MAGNUM_ANDROIDAPPLICATION_MAIN() macro. See @ref platform for more |
||||||
|
information. |
||||||
|
@code |
||||||
|
class MyApplication: public Platform::AndroidApplication { |
||||||
|
// implement required methods...
|
||||||
|
}; |
||||||
|
MAGNUM_ANDROIDAPPLICATION_MAIN(MyApplication) |
||||||
|
@endcode |
||||||
|
|
||||||
|
If no other application header is included, this class is also aliased to |
||||||
|
`Platform::Application` and the macro is aliased to `MAGNUM_APPLICATION_MAIN()` |
||||||
|
to simplify porting. |
||||||
|
|
||||||
|
### Android packaging stuff |
||||||
|
|
||||||
|
The application needs at least the `AndroidManifest.xml` with the following |
||||||
|
contents: |
||||||
|
|
||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cz.mosra.magnum.{{application}}" android:versionCode="1" android:versionName="1.0"> |
||||||
|
<uses-sdk android:minSdkVersion="9" /> |
||||||
|
<uses-feature android:glEsVersion="0x00020000" /> |
||||||
|
<application android:label="{{name}}" android:hasCode="false"> |
||||||
|
<activity android:name="android.app.NativeActivity" android:label="{{name}}"> |
||||||
|
<meta-data android:name="android.app.lib_name" android:value="{{application}}" /> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
</application> |
||||||
|
</manifest> |
||||||
|
|
||||||
|
Replace `{{name}}` with the actual application name and `{{application}}` with |
||||||
|
name of the binary file (without extension). If you plan to use OpenGL ES, set |
||||||
|
`android:glEsVersion` to `0x00030000`. |
||||||
|
|
||||||
|
## Redirecting output to Android log buffer |
||||||
|
|
||||||
|
The application by default redirects @ref Corrade::Utility::Debug "Debug", |
||||||
|
@ref Corrade::Utility::Warning "Warning" and @ref Corrade::Utility::Error "Error" |
||||||
|
output to Android log buffer with tag `"magnum"`, which can be then accessed |
||||||
|
through `logcat` utility. See also @ref Corrade::Utility::AndroidLogStreamBuffer |
||||||
|
for more information. |
||||||
|
*/ |
||||||
|
class AndroidApplication { |
||||||
|
public: |
||||||
|
/** @brief Application arguments */ |
||||||
|
typedef android_app* Arguments; |
||||||
|
|
||||||
|
class Configuration; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Execute the application |
||||||
|
* |
||||||
|
* See @ref MAGNUM_ANDROIDAPPLICATION_MAIN() for usage information. |
||||||
|
*/ |
||||||
|
static void exec(android_app* state, std::unique_ptr<AndroidApplication>(*instancer)(const Arguments&)); |
||||||
|
|
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
template<class T> static std::unique_ptr<AndroidApplication> instancer(const Arguments& arguments) { |
||||||
|
return std::unique_ptr<AndroidApplication>{new T{arguments}}; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
/** @copydoc Sdl2Application::Sdl2Application(const Arguments&, const Configuration&) */ |
||||||
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
||||||
|
explicit AndroidApplication(const Arguments& arguments, const Configuration& configuration = Configuration()); |
||||||
|
#else |
||||||
|
/* To avoid "invalid use of incomplete type" */ |
||||||
|
explicit AndroidApplication(const Arguments& arguments, const Configuration& configuration); |
||||||
|
explicit AndroidApplication(const Arguments& arguments); |
||||||
|
#endif |
||||||
|
|
||||||
|
/** @copydoc Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t) */ |
||||||
|
explicit AndroidApplication(const Arguments& arguments, std::nullptr_t); |
||||||
|
|
||||||
|
/** @brief Copying is not allowed */ |
||||||
|
AndroidApplication(const AndroidApplication&) = delete; |
||||||
|
|
||||||
|
/** @brief Moving is not allowed */ |
||||||
|
AndroidApplication(AndroidApplication&&) = delete; |
||||||
|
|
||||||
|
virtual ~AndroidApplication(); |
||||||
|
|
||||||
|
/** @brief Copying is not allowed */ |
||||||
|
AndroidApplication& operator=(const AndroidApplication&) = delete; |
||||||
|
|
||||||
|
/** @brief Moving is not allowed */ |
||||||
|
AndroidApplication& operator=(AndroidApplication&&) = delete; |
||||||
|
|
||||||
|
protected: |
||||||
|
/** @copydoc Sdl2Application::createContext() */ |
||||||
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
||||||
|
void createContext(const Configuration& configuration = Configuration()); |
||||||
|
#else |
||||||
|
/* To avoid "invalid use of incomplete type" */ |
||||||
|
void createContext(const Configuration& configuration); |
||||||
|
void createContext(); |
||||||
|
#endif |
||||||
|
|
||||||
|
/** @copydoc Sdl2Application::tryCreateContext() */ |
||||||
|
bool tryCreateContext(const Configuration& configuration); |
||||||
|
|
||||||
|
/** @{ @name Screen handling */ |
||||||
|
|
||||||
|
/** @copydoc Sdl2Application::swapBuffers() */ |
||||||
|
void swapBuffers(); |
||||||
|
|
||||||
|
/** @copydoc Sdl2Application::redraw() */ |
||||||
|
void redraw() { _flags |= Flag::Redraw; } |
||||||
|
|
||||||
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
||||||
|
protected: |
||||||
|
#else |
||||||
|
private: |
||||||
|
#endif |
||||||
|
/** @copydoc Sdl2Application::viewportEvent() */ |
||||||
|
virtual void viewportEvent(const Vector2i& size); |
||||||
|
|
||||||
|
/** @copydoc Sdl2Application::drawEvent() */ |
||||||
|
virtual void drawEvent() = 0; |
||||||
|
|
||||||
|
/*@}*/ |
||||||
|
|
||||||
|
private: |
||||||
|
struct LogOutput; |
||||||
|
|
||||||
|
enum class Flag: UnsignedByte { |
||||||
|
Redraw = 1 << 1 |
||||||
|
}; |
||||||
|
typedef Containers::EnumSet<Flag, UnsignedByte> Flags; |
||||||
|
|
||||||
|
static void commandEvent(android_app* app, std::int32_t cmd); |
||||||
|
static std::int32_t inputEvent(android_app* app, AInputEvent* event); |
||||||
|
|
||||||
|
void initialize(); |
||||||
|
|
||||||
|
android_app* const _state; |
||||||
|
Flags _flags; |
||||||
|
|
||||||
|
EGLDisplay _display; |
||||||
|
EGLSurface _surface; |
||||||
|
EGLContext _context; |
||||||
|
|
||||||
|
std::unique_ptr<Context> _c; |
||||||
|
std::unique_ptr<LogOutput> _logOutput; |
||||||
|
|
||||||
|
CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) |
||||||
|
}; |
||||||
|
|
||||||
|
CORRADE_ENUMSET_OPERATORS(AndroidApplication::Flags) |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief %Configuration |
||||||
|
|
||||||
|
Double-buffered RGBA canvas with depth and stencil buffers. |
||||||
|
@see @ref AndroidApplication(), @ref createContext(), @ref tryCreateContext() |
||||||
|
*/ |
||||||
|
class AndroidApplication::Configuration { |
||||||
|
public: |
||||||
|
constexpr /*implicit*/ Configuration() {} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set window title |
||||||
|
* @return Reference to self (for method chaining) |
||||||
|
* |
||||||
|
* @note This function does nothing and is included only for |
||||||
|
* compatibility with other toolkits. You need to set the title |
||||||
|
* separately in the XML file. |
||||||
|
*/ |
||||||
|
template<class T> Configuration& setTitle(const T&) { return *this; } |
||||||
|
|
||||||
|
/** @brief Window size */ |
||||||
|
Vector2i size() const { return _size; } |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set window size |
||||||
|
* @return Reference to self (for method chaining) |
||||||
|
* |
||||||
|
* Default is `{0, 0}`, which means that the size of the physical |
||||||
|
* window will be used. If set to different value than the physical |
||||||
|
* size, the surface will be scaled. |
||||||
|
*/ |
||||||
|
Configuration& setSize(const Vector2i& size) { |
||||||
|
_size = size; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set context version |
||||||
|
* |
||||||
|
* @note This function does nothing and is included only for |
||||||
|
* compatibility with other toolkits. @ref Version::GLES200 or |
||||||
|
* @ref Version::GLES300 is used based on engine compile-time |
||||||
|
* settings. |
||||||
|
*/ |
||||||
|
Configuration& setVersion(Version) { return *this; } |
||||||
|
|
||||||
|
private: |
||||||
|
Vector2i _size; |
||||||
|
}; |
||||||
|
|
||||||
|
/** @hideinitializer
|
||||||
|
@brief Entry point for Android applications |
||||||
|
@param className Class name |
||||||
|
|
||||||
|
See @ref Magnum::Platform::AndroidApplication "Platform::AndroidApplication" |
||||||
|
for usage information. This macro abstracts out platform-specific entry point |
||||||
|
code (the classic `main()` function cannot be used in Android). See |
||||||
|
@ref portability-applications for more information. When no other application |
||||||
|
header is included this macro is also aliased to `MAGNUM_APPLICATION_MAIN()`. |
||||||
|
*/ |
||||||
|
#define MAGNUM_ANDROIDAPPLICATION_MAIN(className) \ |
||||||
|
void android_main(android_app* state) { \
|
||||||
|
Magnum::Platform::AndroidApplication::exec(state, \
|
||||||
|
Magnum::Platform::AndroidApplication::instancer<className>); \
|
||||||
|
} |
||||||
|
|
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
#ifndef MAGNUM_APPLICATION_MAIN |
||||||
|
typedef AndroidApplication Application; |
||||||
|
typedef BasicScreen<AndroidApplication> Screen; |
||||||
|
typedef BasicScreenedApplication<AndroidApplication> ScreenedApplication; |
||||||
|
#define MAGNUM_APPLICATION_MAIN(className) MAGNUM_ANDROIDAPPLICATION_MAIN(className) |
||||||
|
#else |
||||||
|
#undef MAGNUM_APPLICATION_MAIN |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
#endif |
||||||
Loading…
Reference in new issue