- Renamed SExposedVideoData::window to SExposedVideoData::Window

- Fontsize in Android example depends now on the dpi. This also adds example code of how to access the Android Java code from c++.


git-svn-id: http://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@4661 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2014-01-13 14:20:31 +00:00
parent 72e924bf0c
commit f2c944ec0f
8 changed files with 191 additions and 22 deletions

View File

@ -0,0 +1,114 @@
#include "android_tools.h"
namespace irr
{
namespace android
{
// Not all DisplayMetrics are available through the NDK.
// So we access the Java classes with the JNI interface.
// You can access other Java classes available in Android in similar ways.
// Function based roughly on the code from here: http://stackoverflow.com/questions/13249164/android-using-jni-from-nativeactivity
bool getDisplayMetrics(android_app* app, SDisplayMetrics & metrics)
{
if (!app || !app->activity || !app->activity->vm )
return false;
JNIEnv* jni = 0;
app->activity->vm->AttachCurrentThread(&jni, NULL);
if (!jni )
return false;
// get all the classes we want to access from the JVM
jclass classNativeActivity = jni->FindClass("android/app/NativeActivity");
jclass classWindowManager = jni->FindClass("android/view/WindowManager");
jclass classDisplay = jni->FindClass("android/view/Display");
jclass classDisplayMetrics = jni->FindClass("android/util/DisplayMetrics");
if (!classNativeActivity || !classWindowManager || !classDisplay || !classDisplayMetrics)
{
app->activity->vm->DetachCurrentThread();
return false;
}
// Get all the methods we want to access from the JVM classes
// Note: You can get the signatures (third parameter of GetMethodID) for all
// functions of a class with the javap tool, like in the following example for class DisplayMetrics:
// javap -s -classpath myandroidpath/adt-bundle-linux-x86_64-20131030/sdk/platforms/android-10/android.jar android/util/DisplayMetrics
jmethodID idNativeActivity_getWindowManager = jni->GetMethodID( classNativeActivity
, "getWindowManager"
, "()Landroid/view/WindowManager;");
jmethodID idWindowManager_getDefaultDisplay = jni->GetMethodID( classWindowManager
, "getDefaultDisplay"
, "()Landroid/view/Display;");
jmethodID idDisplayMetrics_constructor = jni->GetMethodID( classDisplayMetrics
, "<init>"
, "()V");
jmethodID idDisplay_getMetrics = jni->GetMethodID( classDisplay
, "getMetrics"
, "(Landroid/util/DisplayMetrics;)V");
if (!idNativeActivity_getWindowManager || !idWindowManager_getDefaultDisplay || !idDisplayMetrics_constructor
|| !idDisplay_getMetrics)
{
app->activity->vm->DetachCurrentThread();
return false;
}
// In Java the following code would be: getWindowManager().getDefaultDisplay().getMetrics(metrics);
// Note: If you need to call java functions in time-critical places you can split getting the jmethodID's
// and calling the functions into separate functions as you only have to get the jmethodID's once.
jobject windowManager = jni->CallObjectMethod(app->activity->clazz, idNativeActivity_getWindowManager);
if (!windowManager)
{
app->activity->vm->DetachCurrentThread();
return false;
}
jobject display = jni->CallObjectMethod(windowManager, idWindowManager_getDefaultDisplay);
if (!display)
{
app->activity->vm->DetachCurrentThread();
return false;
}
jobject displayMetrics = jni->NewObject( classDisplayMetrics, idDisplayMetrics_constructor);
if (!displayMetrics)
{
app->activity->vm->DetachCurrentThread();
return false;
}
jni->CallVoidMethod(display, idDisplay_getMetrics, displayMetrics);
// access the fields of DisplayMetrics (we ignore the DENSITY constants)
jfieldID idDisplayMetrics_widthPixels = jni->GetFieldID( classDisplayMetrics, "widthPixels", "I");
jfieldID idDisplayMetrics_heightPixels = jni->GetFieldID( classDisplayMetrics, "heightPixels", "I");
jfieldID idDisplayMetrics_density = jni->GetFieldID( classDisplayMetrics, "density", "F");
jfieldID idDisplayMetrics_densityDpi = jni->GetFieldID( classDisplayMetrics, "densityDpi", "I");
jfieldID idDisplayMetrics_scaledDensity = jni->GetFieldID( classDisplayMetrics, "scaledDensity", "F");
jfieldID idDisplayMetrics_xdpi = jni->GetFieldID(classDisplayMetrics, "xdpi", "F");
jfieldID idDisplayMetrics_ydpi = jni->GetFieldID(classDisplayMetrics, "ydpi", "F");
if ( idDisplayMetrics_widthPixels )
metrics.widthPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_widthPixels);
if ( idDisplayMetrics_heightPixels )
metrics.heightPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_heightPixels);
if (idDisplayMetrics_density )
metrics.density = jni->GetFloatField(displayMetrics, idDisplayMetrics_density);
if (idDisplayMetrics_densityDpi)
metrics.densityDpi = jni->GetIntField(displayMetrics, idDisplayMetrics_densityDpi);
if (idDisplayMetrics_scaledDensity)
metrics.scaledDensity = jni->GetFloatField(displayMetrics, idDisplayMetrics_scaledDensity);
if ( idDisplayMetrics_xdpi )
metrics.xdpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_xdpi);
if ( idDisplayMetrics_ydpi )
metrics.ydpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_ydpi);
app->activity->vm->DetachCurrentThread();
return true;
}
} // namespace android
} // namespace irr

View File

@ -0,0 +1,32 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_ANDROID_TOOLS_H__
#define __IRR_ANDROID_TOOLS_H__
#include <irrlicht.h>
#include <android_native_app_glue.h>
namespace irr
{
namespace android
{
struct SDisplayMetrics
{
irr::s32 widthPixels;
irr::s32 heightPixels;
irr::f32 density;
irr::s32 densityDpi;
irr::f32 scaledDensity;
irr::f32 xdpi;
irr::f32 ydpi;
};
// Access SDisplayMetrics
extern bool getDisplayMetrics(android_app* app, SDisplayMetrics & metrics);
}
}
#endif // __IRR_ANDROID_TOOLS_H__

View File

@ -24,7 +24,7 @@ endif
LOCAL_C_INCLUDES := ../../include
LOCAL_SRC_FILES := main.cpp
LOCAL_SRC_FILES := main.cpp android_tools.cpp
LOCAL_LDLIBS := -lEGL -llog -lGLESv1_CM -lGLESv2 -lz -landroid
@ -44,4 +44,6 @@ $(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/Shaders/*.* $(IRRLICHT_PROJECT_P
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/irrlichtlogo3.png $(IRRLICHT_PROJECT_PATH)/assets/media/)
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/sydney.md2 $(IRRLICHT_PROJECT_PATH)/assets/media/)
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/sydney.bmp $(IRRLICHT_PROJECT_PATH)/assets/media/)
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/fonthaettenschweiler.bmp $(IRRLICHT_PROJECT_PATH)/assets/media/)
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/bigfont.png $(IRRLICHT_PROJECT_PATH)/assets/media/)

View File

@ -9,6 +9,7 @@
#ifdef _IRR_ANDROID_PLATFORM_
#include <android_native_app_glue.h>
#include "android_tools.h"
using namespace irr;
using namespace core;
@ -134,8 +135,7 @@ int run ( IrrlichtDevice *device )
{
stringw str = L"FPS: ";
str += (s32)device->getVideoDriver()->getFPS();
stat->setText ( str.c_str() );
// stat->setText ( str.c_str() );
}
}
device->yield(); // probably nicer to the battery
@ -159,15 +159,33 @@ int example_helloworld(android_app* app)
IGUIEnvironment* guienv = device->getGUIEnvironment();
// access to the Android native window
ANativeWindow* nativeWindow = static_cast<ANativeWindow*>(driver->getExposedVideoData().OGLESAndroid.window);
ANativeWindow* nativeWindow = static_cast<ANativeWindow*>(driver->getExposedVideoData().OGLESAndroid.Window);
int32_t windowWidth = ANativeWindow_getWidth(app->window);
int32_t windowHeight = ANativeWindow_getHeight(app->window);
// get display metrics (accessing the Java functions of the JVM directly in this case as there is no NDK function for that yet)
irr::android::SDisplayMetrics displayMetrics;
memset(&displayMetrics, 0, sizeof displayMetrics);
irr::android::getDisplayMetrics(app, displayMetrics);
// Wherever you put your media. But it must be inside the assets folder.
// This example copies the media in the Android.mk makefile.
stringc mediaPath = "media/";
// Set the font-size depending on your device
// dpi=dots per inch. 1 inch = 2.54 cm
// (xdpi and ydpi are typically very similar or identical, but certainly don't have to be)
IGUISkin* skin = guienv->getSkin();
IGUIFont* font = 0;
if ( displayMetrics.xdpi < 100 ) // just guessing some value where fontsize might start to get too small
font = guienv->getFont(mediaPath + "fonthaettenschweiler.bmp");
else
font = guienv->getFont(mediaPath + "bigfont.png");
if (font)
skin->setFont(font);
IGUIStaticText *text = guienv->addStaticText(L"FPS: 25",
rect<s32>(10,15,200,30), false, false, 0, GUI_INFO_FPS );
IGUIStaticText *text = guienv->addStaticText(stringw(displayMetrics.xdpi).c_str(),
rect<s32>(15,15,300,60), false, false, 0, GUI_INFO_FPS );
// add irrlicht logo
IGUIImage * logo = guienv->addImage(driver->getTexture(mediaPath + "irrlichtlogo3.png"),
@ -175,7 +193,9 @@ int example_helloworld(android_app* app)
s32 minLogoWidth = windowWidth/3;
if ( logo && logo->getRelativePosition().getWidth() < minLogoWidth )
{
// scale to make it better visible on high-res devices
// Scale to make it better visible on high-res devices
// We could also work with displayMetrics.widthPixels, but it's generally better to work with the windowWidth which already subtract
// things like a taskbar which your device might have.
logo->setScaleImage(true);
core::rect<s32> logoPos(logo->getRelativePosition());
f32 scale = (f32)minLogoWidth/(f32)logoPos.getWidth();

View File

@ -1,6 +1,6 @@
-----
SETUP
-----
------------
REQUIREMENTS
------------
To use Android you need to have installed:
- Android SDK (from http://developer.android.com)
@ -11,6 +11,10 @@ To use Android you need to have installed:
- A recent version of awk
- On Windows you need to have Cygwin (at least version 1.7) installed
----------------------------
BUILDING Irrlicht & your App
----------------------------
1. Assign your Android SDK path to an ANDROID_HOME environment variable.
2. Add $ANDROID_HOME/tools and $ANDROID_HOME/platform-tools and the Android NDK main folder to your PATH environment variable.
3. Go to: source->Irrlicht->Android and call "ndk-build" or "ndk-build NDEBUG=1"
@ -56,8 +60,11 @@ jni/Application.mk:
res:
A folder with resources which are compiled into your application and can be accessed via ID's.
There is also support for things like different target resolutions.
Unfortunately no direct NDK access to resources at the time of writing this. So you either have
to access them with java-code and copy to c++ somehow or you have to use hacks to read the format
directly (which is done by some apps, but not future-safe and google recommends not doing that).
Please check the official "App Resources" android developer documention, as this is rather complex.
We use it only for the application icons in this example.
assets:
Files in here are distributed with your app. It's acting like a typical file system.
@ -78,9 +85,3 @@ libs:
src:
Created by our makefile because the ant build.xml in the android sdk needs it for some reason. It's empty (so far?).
----------
DEPLOYMENT
----------
When you require EDT_OGLES2 your android:glEsVersion in AndroidManifest.xml should be "0x00020000"
while for EDT_OGLES1 it should be "0x00010000".

View File

@ -96,7 +96,7 @@ struct SExposedVideoData
struct
{
//! The ANativeWindow object.
void* window;
void* Window;
} OGLESAndroid;
};

View File

@ -208,7 +208,7 @@ void CIrrDeviceAndroid::handleAndroidCommand(android_app* app, int32_t cmd)
break;
case APP_CMD_INIT_WINDOW:
os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG);
Device->getExposedVideoData().OGLESAndroid.window = app->window;
Device->getExposedVideoData().OGLESAndroid.Window = app->window;
if (Device->CreationParams.WindowSize.Width == 0 || Device->CreationParams.WindowSize.Height == 0)
{

View File

@ -47,7 +47,7 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters& params, const SE
EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display);
#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EglWindow = (ANativeWindow*)Data.OGLESAndroid.window;
EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
EglDisplay = eglGetDisplay((NativeDisplayType) EGL_DEFAULT_DISPLAY);
#endif
@ -113,7 +113,7 @@ bool CEGLManager::generateSurface()
// this needs an update method instead!
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EglWindow = (ANativeWindow*)Data.OGLESAndroid.window;
EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
#endif
EGLint EglOpenGLBIT = 0;