mirror of
https://github.com/minetest/irrlicht.git
synced 2025-06-28 06:20:21 +02:00
Merging r5975 through r6036 from trunk to ogl-es branch.
GLES drivers adapted, but only did make compile-tests. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6038 dfc29bdd-3216-0410-991c-e03cc46cb475
This commit is contained in:
21
examples/01.HelloWorld_Android/AndroidManifest.xml
Executable file
21
examples/01.HelloWorld_Android/AndroidManifest.xml
Executable file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.irrlicht.example"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<uses-sdk android:minSdkVersion="10"/>
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
|
||||
<application android:icon="@drawable/irr_icon" android:label="HelloWorldMobile" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:debuggable="true">
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
android:label="HelloWorldMobile"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:clearTaskOnLaunch="true">
|
||||
<meta-data android:name="android.app.lib_name" android:value="HelloWorldMobile" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
184
examples/01.HelloWorld_Android/android_tools.cpp
Normal file
184
examples/01.HelloWorld_Android/android_tools.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "android_tools.h"
|
||||
#include <android/log.h> // for the occasional debugging, style: __android_log_print(ANDROID_LOG_VERBOSE, "Irrlicht", "%s\n", "We do log");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void setSoftInputVisibility(android_app* app, bool visible)
|
||||
{
|
||||
// NOTE: Unfortunately ANativeActivity_showSoftInput from the NDK does not work and Google does not care.
|
||||
// This is based on the solution from @Ratamovic from here: http://stackoverflow.com/questions/5864790/how-to-show-the-soft-keyboard-on-native-activity
|
||||
|
||||
if (!app || !app->activity || !app->activity->vm )
|
||||
return;
|
||||
|
||||
JNIEnv* jni = 0;
|
||||
app->activity->vm->AttachCurrentThread(&jni, NULL);
|
||||
if (!jni )
|
||||
return;
|
||||
|
||||
// get all the classes we want to access from the JVM (could be cached)
|
||||
jclass classNativeActivity = jni->FindClass("android/app/NativeActivity");
|
||||
jclass classInputMethodManager = jni->FindClass("android/view/inputmethod/InputMethodManager");
|
||||
jclass classWindow = jni->FindClass("android/view/Window");
|
||||
jclass classView = jni->FindClass("android/view/View");
|
||||
|
||||
if (classNativeActivity && classInputMethodManager && classWindow)
|
||||
{
|
||||
// Get all the methods we want to access from the JVM classes (could be cached)
|
||||
jmethodID mid_getSystemService = jni->GetMethodID(classNativeActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
|
||||
jmethodID mid_showSoftInput = jni->GetMethodID(classInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z");
|
||||
|
||||
jmethodID mid_hideSoftInput = jni->GetMethodID(classInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
|
||||
jmethodID mid_getWindow = jni->GetMethodID(classNativeActivity, "getWindow", "()Landroid/view/Window;");
|
||||
jmethodID mid_getWindowToken = jni->GetMethodID(classView, "getWindowToken", "()Landroid/os/IBinder;");
|
||||
jmethodID mid_getDecorView = jni->GetMethodID(classWindow, "getDecorView", "()Landroid/view/View;");
|
||||
|
||||
if ( mid_getSystemService && mid_showSoftInput && mid_hideSoftInput && mid_getWindow && mid_getDecorView && mid_getWindowToken )
|
||||
{
|
||||
jstring paramInput = jni->NewStringUTF("input_method");
|
||||
jobject objInputMethodManager = jni->CallObjectMethod(app->activity->clazz, mid_getSystemService, paramInput);
|
||||
jni->DeleteLocalRef(paramInput);
|
||||
|
||||
jobject objWindow = jni->CallObjectMethod(app->activity->clazz, mid_getWindow);
|
||||
|
||||
if ( visible && objInputMethodManager && objWindow)
|
||||
{
|
||||
jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView);
|
||||
if ( objDecorView )
|
||||
{
|
||||
int showFlags = 0;
|
||||
jni->CallBooleanMethod(objInputMethodManager, mid_showSoftInput, objDecorView, showFlags);
|
||||
}
|
||||
}
|
||||
else if ( !visible && objInputMethodManager && objWindow )
|
||||
{
|
||||
jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView);
|
||||
if ( objDecorView )
|
||||
{
|
||||
jobject objBinder = jni->CallObjectMethod(objDecorView, mid_getWindowToken);
|
||||
if ( objBinder )
|
||||
{
|
||||
int hideFlags = 0;
|
||||
jni->CallBooleanMethod(objInputMethodManager, mid_hideSoftInput, objBinder, hideFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app->activity->vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace irr
|
33
examples/01.HelloWorld_Android/android_tools.h
Normal file
33
examples/01.HelloWorld_Android/android_tools.h
Normal file
@ -0,0 +1,33 @@
|
||||
// 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);
|
||||
|
||||
extern void setSoftInputVisibility(android_app* app, bool visible);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __IRR_ANDROID_TOOLS_H__
|
17
examples/01.HelloWorld_Android/build.xml
Executable file
17
examples/01.HelloWorld_Android/build.xml
Executable file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="HelloWorldMobile" default="help">
|
||||
<property file="local.properties" />
|
||||
<property file="ant.properties" />
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
<loadproperties srcFile="project.properties" />
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
50
examples/01.HelloWorld_Android/jni/Android.mk
Executable file
50
examples/01.HelloWorld_Android/jni/Android.mk
Executable file
@ -0,0 +1,50 @@
|
||||
LOCAL_PATH := $(call my-dir)/..
|
||||
IRRLICHT_PROJECT_PATH := $(LOCAL_PATH)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Irrlicht
|
||||
LOCAL_SRC_FILES := $(IRRLICHT_PROJECT_PATH)/../../lib/Android/libIrrlicht.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := HelloWorldMobile
|
||||
|
||||
LOCAL_CFLAGS := -pipe -fno-exceptions -fno-rtti -fstrict-aliasing
|
||||
|
||||
ifndef NDEBUG
|
||||
LOCAL_CFLAGS += -g -D_DEBUG
|
||||
else
|
||||
LOCAL_CFLAGS += -fexpensive-optimizations -O3
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
LOCAL_CFLAGS += -fno-stack-protector
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES := ../../include
|
||||
|
||||
LOCAL_SRC_FILES := main.cpp android_tools.cpp
|
||||
|
||||
LOCAL_LDLIBS := -lEGL -llog -lGLESv1_CM -lGLESv2 -lz -landroid
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := Irrlicht android_native_app_glue
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
$(call import-module,android/native_app_glue)
|
||||
|
||||
# copy Irrlicht data to assets
|
||||
|
||||
$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/assets)
|
||||
$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/assets/media)
|
||||
$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/assets/media/Shaders)
|
||||
$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/src)
|
||||
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/Shaders/*.* $(IRRLICHT_PROJECT_PATH)/assets/media/Shaders/)
|
||||
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/irrlichtlogo3.png $(IRRLICHT_PROJECT_PATH)/assets/media/)
|
||||
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/dwarf.x $(IRRLICHT_PROJECT_PATH)/assets/media/)
|
||||
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/dwarf.jpg $(IRRLICHT_PROJECT_PATH)/assets/media/)
|
||||
$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/axe.jpg $(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/)
|
||||
|
2
examples/01.HelloWorld_Android/jni/Application.mk
Executable file
2
examples/01.HelloWorld_Android/jni/Application.mk
Executable file
@ -0,0 +1,2 @@
|
||||
APP_PLATFORM := android-10
|
||||
APP_MODULES := HelloWorldMobile
|
387
examples/01.HelloWorld_Android/main.cpp
Normal file
387
examples/01.HelloWorld_Android/main.cpp
Normal file
@ -0,0 +1,387 @@
|
||||
/** Example 027 Helloworld_Android
|
||||
This example shows a simple application for Android.
|
||||
*/
|
||||
|
||||
#include <irrlicht.h>
|
||||
|
||||
#ifdef _IRR_ANDROID_PLATFORM_
|
||||
|
||||
#include <android_native_app_glue.h>
|
||||
#include "android_tools.h"
|
||||
#include "android/window.h"
|
||||
|
||||
using namespace irr;
|
||||
using namespace core;
|
||||
using namespace scene;
|
||||
using namespace video;
|
||||
using namespace io;
|
||||
using namespace gui;
|
||||
|
||||
|
||||
enum GUI_IDS
|
||||
{
|
||||
GUI_INFO_FPS,
|
||||
GUI_IRR_LOGO,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Android is using multitouch events.
|
||||
We allow users to move around the Irrlicht logo as example of how to use those.
|
||||
*/
|
||||
class MyEventReceiver : public IEventReceiver
|
||||
{
|
||||
public:
|
||||
MyEventReceiver(android_app* app )
|
||||
: Device(0), AndroidApp(app), SpriteToMove(0), TouchID(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void Init(IrrlichtDevice *device)
|
||||
{
|
||||
Device = device;
|
||||
}
|
||||
|
||||
virtual bool OnEvent(const SEvent& event)
|
||||
{
|
||||
if (event.EventType == EET_TOUCH_INPUT_EVENT)
|
||||
{
|
||||
/*
|
||||
For now we fake mouse-events. Touch-events will be handled inside Irrlicht in the future, but until
|
||||
that is implemented you can use this workaround to get a GUI which works at least for simple elements like
|
||||
buttons. That workaround does ignore multi-touch events - if you need several buttons pressed at the same
|
||||
time you have to handle that yourself.
|
||||
*/
|
||||
SEvent fakeMouseEvent;
|
||||
fakeMouseEvent.EventType = EET_MOUSE_INPUT_EVENT;
|
||||
fakeMouseEvent.MouseInput.X = event.TouchInput.X;
|
||||
fakeMouseEvent.MouseInput.Y = event.TouchInput.Y;
|
||||
fakeMouseEvent.MouseInput.Shift = false;
|
||||
fakeMouseEvent.MouseInput.Control = false;
|
||||
fakeMouseEvent.MouseInput.ButtonStates = 0;
|
||||
fakeMouseEvent.MouseInput.Event = EMIE_COUNT;
|
||||
|
||||
switch (event.TouchInput.Event)
|
||||
{
|
||||
case ETIE_PRESSED_DOWN:
|
||||
{
|
||||
// We only work with the first for now.force opengl error
|
||||
if ( TouchID == -1 )
|
||||
{
|
||||
fakeMouseEvent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
|
||||
|
||||
if (Device)
|
||||
{
|
||||
position2d<s32> touchPoint(event.TouchInput.X, event.TouchInput.Y);
|
||||
IGUIElement * logo = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId ( GUI_IRR_LOGO );
|
||||
if ( logo && logo->isPointInside (touchPoint) )
|
||||
{
|
||||
TouchID = event.TouchInput.ID;
|
||||
SpriteToMove = logo;
|
||||
SpriteStartRect = SpriteToMove->getRelativePosition();
|
||||
TouchStartPos = touchPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ETIE_MOVED:
|
||||
if ( TouchID == event.TouchInput.ID )
|
||||
{
|
||||
fakeMouseEvent.MouseInput.Event = EMIE_MOUSE_MOVED;
|
||||
fakeMouseEvent.MouseInput.ButtonStates = EMBSM_LEFT;
|
||||
|
||||
if ( SpriteToMove && TouchID == event.TouchInput.ID )
|
||||
{
|
||||
|
||||
position2d<s32> touchPoint(event.TouchInput.X, event.TouchInput.Y);
|
||||
MoveSprite(touchPoint);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ETIE_LEFT_UP:
|
||||
if ( TouchID == event.TouchInput.ID )
|
||||
{
|
||||
fakeMouseEvent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
|
||||
|
||||
if ( SpriteToMove )
|
||||
{
|
||||
TouchID = -1;
|
||||
position2d<s32> touchPoint(event.TouchInput.X, event.TouchInput.Y);
|
||||
MoveSprite(touchPoint);
|
||||
SpriteToMove = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( fakeMouseEvent.MouseInput.Event != EMIE_COUNT && Device )
|
||||
{
|
||||
Device->postEventFromUser(fakeMouseEvent);
|
||||
}
|
||||
}
|
||||
else if ( event.EventType == EET_GUI_EVENT )
|
||||
{
|
||||
/*
|
||||
Show and hide the soft input keyboard when an edit-box get's the focus.
|
||||
*/
|
||||
switch(event.GUIEvent.EventType)
|
||||
{
|
||||
case EGET_EDITBOX_ENTER:
|
||||
if ( event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX )
|
||||
{
|
||||
if( Device->getGUIEnvironment() )
|
||||
Device->getGUIEnvironment()->setFocus(NULL);
|
||||
android::setSoftInputVisibility(AndroidApp, false);
|
||||
}
|
||||
break;
|
||||
case EGET_ELEMENT_FOCUS_LOST:
|
||||
if ( event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX )
|
||||
{
|
||||
/* Unfortunatly this only works on some android devices.
|
||||
On other devices Android passes through touch-input events when the virtual keyboard is clicked while blocking those events in areas where the keyboard isn't.
|
||||
Very likely an Android bug as it only happens in certain cases (like Android Lollipop with landscape mode on MotoG, but also some reports from other devices).
|
||||
Or maybe Irrlicht still does something wrong.
|
||||
Can't figure it out so far - so be warned - with landscape mode you might be better off writing your own keyboard.
|
||||
*/
|
||||
android::setSoftInputVisibility(AndroidApp, false);
|
||||
}
|
||||
break;
|
||||
case EGET_ELEMENT_FOCUSED:
|
||||
if ( event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX )
|
||||
{
|
||||
android::setSoftInputVisibility(AndroidApp, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MoveSprite(const irr::core::position2d<irr::s32> &touchPos)
|
||||
{
|
||||
irr::core::position2d<irr::s32> move(touchPos-TouchStartPos);
|
||||
SpriteToMove->setRelativePosition(SpriteStartRect.UpperLeftCorner + move);
|
||||
}
|
||||
|
||||
private:
|
||||
IrrlichtDevice * Device;
|
||||
android_app* AndroidApp;
|
||||
gui::IGUIElement * SpriteToMove;
|
||||
core::rect<s32> SpriteStartRect;
|
||||
core::position2d<irr::s32> TouchStartPos;
|
||||
s32 TouchID;
|
||||
};
|
||||
|
||||
/* Mainloop.
|
||||
*/
|
||||
void mainloop( IrrlichtDevice *device, IGUIStaticText * infoText )
|
||||
{
|
||||
u32 loop = 0; // loop is reset when the app is destroyed unlike runCounter
|
||||
static u32 runCounter = 0; // static's seem to survive even an app-destroy message (not sure if that's guaranteed).
|
||||
while(device->run())
|
||||
{
|
||||
/*
|
||||
The window seems to be always active in this setup.
|
||||
That's because when it's not active Android will stop the code from running.
|
||||
*/
|
||||
if (device->isWindowActive())
|
||||
{
|
||||
/*
|
||||
Show FPS and some counters to show which parts of an app run
|
||||
in different app-lifecycle states.
|
||||
*/
|
||||
if ( infoText )
|
||||
{
|
||||
stringw str = L"FPS:";
|
||||
str += (s32)device->getVideoDriver()->getFPS();
|
||||
str += L" r:";
|
||||
str += runCounter;
|
||||
str += L" l:";
|
||||
str += loop;
|
||||
infoText->setText ( str.c_str() );
|
||||
}
|
||||
|
||||
device->getVideoDriver()->beginScene(true, true, SColor(0,100,100,100));
|
||||
device->getSceneManager()->drawAll();
|
||||
device->getGUIEnvironment()->drawAll();
|
||||
device->getVideoDriver()->endScene ();
|
||||
}
|
||||
device->yield(); // probably nicer to the battery
|
||||
++runCounter;
|
||||
++loop;
|
||||
}
|
||||
}
|
||||
|
||||
/* Main application code. */
|
||||
void android_main(android_app* app)
|
||||
{
|
||||
// Make sure glue isn't stripped.
|
||||
app_dummy();
|
||||
|
||||
/*
|
||||
The receiver can already receive system events while createDeviceEx is called.
|
||||
So we create it first.
|
||||
*/
|
||||
MyEventReceiver receiver(app);
|
||||
|
||||
/*
|
||||
Create the device.
|
||||
You have currently the choice between 2 drivers:
|
||||
EDT_OGLES1 is basically a opengl fixed function pipeline.
|
||||
EDT_OGLES2 is a shader pipeline. Irrlicht comes with shaders to simulate
|
||||
typical fixed function materials. For this to work the
|
||||
corresponding shaders from the Irrlicht media/Shaders folder are
|
||||
copied to the application assets folder (done in the Makefile).
|
||||
*/
|
||||
SIrrlichtCreationParameters param;
|
||||
// param.DriverType = EDT_OGLES1; // android:glEsVersion in AndroidManifest.xml should be "0x00010000" (requesting 0x00020000 will also guarantee that ES1 works)
|
||||
param.DriverType = EDT_OGLES2; // android:glEsVersion in AndroidManifest.xml should be "0x00020000"
|
||||
param.WindowSize = dimension2d<u32>(300,300); // using 0,0 it will automatically set it to the maximal size
|
||||
param.PrivateData = app;
|
||||
param.Bits = 24;
|
||||
param.ZBufferBits = 16;
|
||||
param.AntiAlias = 0;
|
||||
param. EventReceiver = &receiver;
|
||||
|
||||
/* Logging is written to a file. So your application should disable all logging when you distribute your
|
||||
application or it can fill up that file over time.
|
||||
*/
|
||||
#ifndef _DEBUG
|
||||
param.LoggingLevel = ELL_NONE;
|
||||
#endif
|
||||
|
||||
IrrlichtDevice *device = createDeviceEx(param);
|
||||
if (device == 0)
|
||||
return;
|
||||
|
||||
receiver.Init(device);
|
||||
|
||||
// ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FULLSCREEN, 0);
|
||||
|
||||
IVideoDriver* driver = device->getVideoDriver();
|
||||
ISceneManager* smgr = device->getSceneManager();
|
||||
IGUIEnvironment* guienv = device->getGUIEnvironment();
|
||||
ILogger* logger = device->getLogger();
|
||||
IFileSystem * fs = device->getFileSystem();
|
||||
|
||||
/* Access to the Android native window. You often need this when accessing NDK functions like we are doing here.
|
||||
Note that windowWidth/windowHeight have already subtracted things like the taskbar which your device might have,
|
||||
so you get the real size of your render-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. We are accessing the Java functions of the JVM directly in this case as there is no NDK function for that yet.
|
||||
Checkout android_tools.cpp if you want to know how that is done. */
|
||||
irr::android::SDisplayMetrics displayMetrics;
|
||||
memset(&displayMetrics, 0, sizeof displayMetrics);
|
||||
irr::android::getDisplayMetrics(app, displayMetrics);
|
||||
|
||||
/* For troubleshooting you can use the Irrlicht logger.
|
||||
The Irrlicht logging messages are send to the Android logging system using the tag "Irrlicht".
|
||||
They stay in a file there, so you can check them even after running your app.
|
||||
You can watch them with the command: "adb logcat Irrlicht:V DEBUG:V *:S"
|
||||
This means Irrlicht _V_erbose, debug messages verbose (p.E callstack on crashes) and all other messages _S_ilent.
|
||||
Clean the logging file with: "adb logcat -c".
|
||||
See http://developer.android.com/tools/debugging/debugging-log.html for more advanced log options.
|
||||
*/
|
||||
char strDisplay[1000];
|
||||
sprintf(strDisplay, "Window size:(%d/%d)\nDisplay size:(%d/%d)", windowWidth, windowHeight, displayMetrics.widthPixels, displayMetrics.heightPixels);
|
||||
logger->log(strDisplay);
|
||||
|
||||
core::dimension2d<s32> dim(driver->getScreenSize());
|
||||
sprintf(strDisplay, "getScreenSize:(%d/%d)", dim.Width, dim.Height);
|
||||
logger->log(strDisplay);
|
||||
|
||||
|
||||
/* Your media must be somewhere inside the assets folder. The assets folder is the root for the file system.
|
||||
This example copies the media in the Android.mk makefile. */
|
||||
stringc mediaPath = "media/";
|
||||
|
||||
// The Android assets file-system does not know which sub-directories it has (blame google).
|
||||
// So we have to add all sub-directories in assets manually. Otherwise we could still open the files,
|
||||
// but existFile checks will fail (which are for example needed by getFont).
|
||||
for ( u32 i=0; i < fs->getFileArchiveCount(); ++i )
|
||||
{
|
||||
IFileArchive* archive = fs->getFileArchive(i);
|
||||
if ( archive->getType() == EFAT_ANDROID_ASSET )
|
||||
{
|
||||
archive->addDirectoryToFileList(mediaPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the font-size depending on your device.
|
||||
dpi=dots per inch. 1 inch = 2.54 cm. */
|
||||
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);
|
||||
|
||||
// A field to show some text. Comment out stat->setText in run() if you want to see the dpi instead of the fps.
|
||||
IGUIStaticText *text = guienv->addStaticText(stringw(displayMetrics.xdpi).c_str(),
|
||||
rect<s32>(5,5,635,35), false, false, 0, GUI_INFO_FPS );
|
||||
guienv->addEditBox( L"", rect<s32>(5,40,475,80));
|
||||
|
||||
// add irrlicht logo
|
||||
IGUIImage * logo = guienv->addImage(driver->getTexture(mediaPath + "irrlichtlogo3.png"),
|
||||
core::position2d<s32>(5,85), true, 0, GUI_IRR_LOGO);
|
||||
s32 minLogoWidth = windowWidth/3;
|
||||
if ( logo && logo->getRelativePosition().getWidth() < minLogoWidth )
|
||||
{
|
||||
/* Scale to make it better visible on high-res devices (we could also work with dpi here).
|
||||
*/
|
||||
logo->setScaleImage(true);
|
||||
core::rect<s32> logoPos(logo->getRelativePosition());
|
||||
f32 scale = (f32)minLogoWidth/(f32)logoPos.getWidth();
|
||||
logoPos.LowerRightCorner.X = logoPos.UpperLeftCorner.X + minLogoWidth;
|
||||
logoPos.LowerRightCorner.Y = logoPos.UpperLeftCorner.Y + (s32)((f32)logoPos.getHeight()*scale);
|
||||
logo->setRelativePosition(logoPos);
|
||||
}
|
||||
|
||||
/*
|
||||
Add a 3d model. Note that you might need to add light when using other models.
|
||||
A copy of the model and it's textures must be inside the assets folder to be installed to Android.
|
||||
In this example we do copy it to the assets folder in the Makefile jni/Android.mk
|
||||
*/
|
||||
IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "dwarf.x");
|
||||
if (!mesh)
|
||||
{
|
||||
device->closeDevice();
|
||||
device->drop();
|
||||
return;
|
||||
}
|
||||
smgr->addAnimatedMeshSceneNode( mesh );
|
||||
|
||||
|
||||
/*
|
||||
To look at the mesh, we place a camera.
|
||||
*/
|
||||
smgr->addCameraSceneNode(0, vector3df(15,40,-90), vector3df(0,30,0));
|
||||
|
||||
/*
|
||||
Mainloop. Applications usually never quit themself in Android. The OS is responsible for that.
|
||||
*/
|
||||
mainloop(device, text);
|
||||
|
||||
/* Cleanup */
|
||||
device->setEventReceiver(0);
|
||||
device->closeDevice();
|
||||
device->drop();
|
||||
}
|
||||
|
||||
#endif // defined(_IRR_ANDROID_PLATFORM_)
|
||||
|
||||
/*
|
||||
**/
|
1
examples/01.HelloWorld_Android/project.properties
Executable file
1
examples/01.HelloWorld_Android/project.properties
Executable file
@ -0,0 +1 @@
|
||||
target = android-10
|
95
examples/01.HelloWorld_Android/readme.txt
Normal file
95
examples/01.HelloWorld_Android/readme.txt
Normal file
@ -0,0 +1,95 @@
|
||||
------------
|
||||
REQUIREMENTS
|
||||
------------
|
||||
|
||||
To use Android you need to have installed:
|
||||
- Android SDK (from http://developer.android.com)
|
||||
- Android NDK (from http://developer.android.com)
|
||||
- ant (a build tool commonly used for Java)
|
||||
- A Java jdk (for example openjdk-6-jdk)
|
||||
- GNU Make 3.81 or later
|
||||
- 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"
|
||||
4. Go to: examples/01.HelloWorld_Android and call "ndk-build" or "ndk-build NDEBUG=1"
|
||||
5. Call "ant debug" to create package
|
||||
6. Connect device to PC (with USB debugging mode ON) or turn on emulator.
|
||||
7. Call "adb -d install bin/HelloWorldMobile-debug.apk" (if you use emulator please add "-e" parameter instead of "-d") to install package on your device/emulator.
|
||||
|
||||
Troubleshooting:
|
||||
|
||||
Error: Unable to resolve project target 'android-10'
|
||||
Solution: Run "android sdk" in sdk/tools and install API 10.
|
||||
Alternatively you can probably (not yet tested) set another APP_PLATFORM
|
||||
in the Application.mk's for the project and for Irrlicht. In this case you
|
||||
should likely also change the android:minSdkVersion in the AndroidManifest.xml
|
||||
|
||||
-----
|
||||
FILES
|
||||
-----
|
||||
|
||||
AndroidManifest.xml:
|
||||
Every Android application needs one of those to describe the needs of the application.
|
||||
Must have exactly this name.
|
||||
See http://developer.android.com/guide/topics/manifest/manifest-intro.html
|
||||
|
||||
build.xml:
|
||||
Ant build file to create the final package.
|
||||
You might want to create a new one as described in the Android documentation:
|
||||
http://developer.android.com/tools/projects/projects-cmdline.html
|
||||
That will then also update project.properties.
|
||||
|
||||
project.properties
|
||||
Contains the build target (and maybe other project properties). Must exist.
|
||||
|
||||
jni:
|
||||
A folder by this name must exist below the folder where you have build.xml.
|
||||
Usually it contains the native (c/c++) source files, but in our case we put
|
||||
the source-files one level higher (with LOCAL_PATH in Android.mk).
|
||||
|
||||
jni/Android.mk:
|
||||
The Makefile for the project.
|
||||
Source-files in the project are added to LOCAL_SRC_FILES
|
||||
In the Irrlicht example it also copies the assets, but you can
|
||||
also already create your project assets in the right place.
|
||||
|
||||
jni/Application.mk:
|
||||
Optional file which for example restricts which modules are installed and
|
||||
where you can set specific target architectures.
|
||||
More info about this can be found in the ndk docs.
|
||||
|
||||
res:
|
||||
A folder with resources which districuted with your application and can be accessed via ID's.
|
||||
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 read-only file system.
|
||||
|
||||
assets/media/Shaders:
|
||||
Shader code needed by the OGLES2 driver to simulate a fixed function pipeline.
|
||||
In the example this code is automatically copied within the Android.mk makefile.
|
||||
The path where the shaders are searched is set in the IRR_OGLES2_SHADER_PATH define in IrrCompileConfig.h
|
||||
The names are hardcoded so they have to be identical to those found in media/Shaders.
|
||||
You can rewrite the shaders, but ensure to add some working shaders files by those names.
|
||||
The OGLES1 driver doesn't need those files.
|
||||
|
||||
obj:
|
||||
All object and library files mentioned in the Android.mk are put in here before linking.
|
||||
|
||||
libs:
|
||||
Contains the binaries of your application after compilation. The application itself is a lib(probably because native code can't run directly but only as lib).
|
||||
|
||||
src:
|
||||
The src folder is needed when you have Java sources and should only contain .java and .aidl files.
|
||||
Although the examples doesn't use Java the makefile creates this folder as the ant build.xml in the android sdk needs it.
|
BIN
examples/01.HelloWorld_Android/res/drawable-hdpi/irr_icon.png
Executable file
BIN
examples/01.HelloWorld_Android/res/drawable-hdpi/irr_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
BIN
examples/01.HelloWorld_Android/res/drawable-ldpi/irr_icon.png
Executable file
BIN
examples/01.HelloWorld_Android/res/drawable-ldpi/irr_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
examples/01.HelloWorld_Android/res/drawable-mdpi/irr_icon.png
Executable file
BIN
examples/01.HelloWorld_Android/res/drawable-mdpi/irr_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
BIN
examples/01.HelloWorld_Android/res/drawable-xhdpi/irr_icon.png
Executable file
BIN
examples/01.HelloWorld_Android/res/drawable-xhdpi/irr_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user