Browse Source

Platform: initial version of AndroidApplication.

No input events yet.
pull/51/head
Vladimír Vondruš 12 years ago
parent
commit
cb8eecce51
  1. 4
      CMakeLists.txt
  2. 1
      doc/building.dox
  3. 11
      modules/FindMagnum.cmake
  4. 242
      src/Magnum/Platform/AndroidApplication.cpp
  5. 357
      src/Magnum/Platform/AndroidApplication.h
  6. 19
      src/Magnum/Platform/CMakeLists.txt

4
CMakeLists.txt

@ -54,6 +54,10 @@ if(CORRADE_TARGET_NACL)
option(WITH_NACLAPPLICATION "Build NaClApplication library" OFF)
cmake_dependent_option(WITH_WINDOWLESSNACLAPPLICATION "Build WindowlessNaClApplication library" OFF "NOT WITH_MAGNUMINFO" ON)
# Android-specific application libraries
elseif(CORRADE_TARGET_ANDROID)
option(WITH_ANDROIDAPPLICATION "Build AndroidApplication library" OFF)
# X11, GLX and EGL-specific application libraries
elseif(CORRADE_TARGET_UNIX AND NOT APPLE)
option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF)

1
doc/building.dox

@ -185,6 +185,7 @@ None of the @ref Platform "application libraries" is built by default (and you
need at least one). Choose the one which suits your requirements and your
platform best:
- `WITH_ANDROIDAPPLICATION` - @ref Platform::AndroidApplication "AndroidApplication"
- `WITH_GLUTAPPLICATION` - @ref Platform::GlutApplication "GlutApplication"
- `WITH_GLXAPPLICATION` - @ref Platform::GlxApplication "GlxApplication"
- `WITH_NACLAPPLICATION` - @ref Platform::NaClApplication "NaClApplication"

11
modules/FindMagnum.cmake

@ -253,6 +253,17 @@ foreach(component ${Magnum_FIND_COMPONENTS})
if(${component} MATCHES .+Application)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/Platform)
# Android application dependencies
if(${component} STREQUAL AndroidApplication)
find_package(EGL)
if(EGL_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES android ${EGL_LIBRARY} ${_WINDOWCONTEXT_MAGNUM_LIBRARIES_DEPENDENCY})
set(_MAGNUM_${_COMPONENT}_INCLUDE_DIRS ${ANDROID_NATIVE_APP_GLUE_INCLUDE_DIR})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
endif()
# GLUT application dependencies
if(${component} STREQUAL GlutApplication)
find_package(GLUT)

242
src/Magnum/Platform/AndroidApplication.cpp

@ -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;
}
}}

357
src/Magnum/Platform/AndroidApplication.h

@ -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

19
src/Magnum/Platform/CMakeLists.txt

@ -32,6 +32,25 @@ set(Platform_HEADERS
install(FILES ${Platform_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
# Android application
if(WITH_ANDROIDAPPLICATION)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL Android)
message(FATAL_ERROR "AndroidApplication is available only when targeting Android. Set WITH_ANDROIDAPPLICATION to OFF to skip building it.")
endif()
include_directories(${ANDROID_NATIVE_APP_GLUE_INCLUDE_DIR})
add_library(MagnumAndroidApplication STATIC
AndroidApplication.cpp
Implementation/Egl.cpp
${ANDROID_NATIVE_APP_GLUE_SRC})
install(FILES AndroidApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumAndroidApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
# GLUT application
if(WITH_GLUTAPPLICATION)
find_package(GLUT)

Loading…
Cancel
Save