Android projects based on native code Native OpenGL OGRE3D o n Android Native code What is native code C C code Using C C APIs ID: 569675
Download Presentation The PPT/PDF document "3D graphics on" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
3D graphics on Android projects based on native code
Native
OpenGL
, OGRE3D
o
n
AndroidSlide2
Native code?What is native code?C/
C
++
code
Using
C/
C
++
API-s
directly
Why
we
need
it
,
what
should
be
moved
into
native
In
most
situations
native
code
should
be
avoided
Performance
critical
parts
Using
external
cross
platform
APIs
Native
calls
have
a
cost
!Slide3
Native code in an Android projectNeed
separate
SDK:
Android
NDK
Cross
compiling
tools
:
ndk-build
Must be
familiar
with
Java
Native
Interface
(JNI)
Have
to
place
native
code
in
./
jni
folder
Need
special
files
in
./
jni
:
Android.mk
Application.mk
(
optional
)
Have
to
call
ndk-build
before
project
build
Should
load
the
compiled
library
in
Java
code
Use
the
library
through
native
functions
(JNI)Slide4
Java Native Interface I.Allows execution of native
code
from
Java
Native
code
is
compiled
into
a
dynamic
library
Library
should
be
loaded
with
System.loadLibrary
(
String
libraryName
)
Library
is
accesed
through
native
function
calls
Native
functions
does
not
have
definition
,
they
are
implemented
in
the
native
code
:
package
test.jni
;
class
A{
static
{
System.loadLibrary
(”
myLibName
”);}
protected
native
void
myNativeFunc
()
;
protected
void
myFunc
(){
myNativeFunc
();}
}Slide5
Java Native Interface II.Native function declarations
are
special
:
Name
expresses
the
package
and
class
that
declared
it
have
special
input
parameters
Can
be
generated
with
javah
:
javah
test.jni.A
(
A.class
should
be
generated
first
)
javah
output:
#
ifdef
__
cplusplus
extern
"C"
{
#
endif
JNIEXPORT
void
JNICALL
Java_test_
jni
_A_
myNativeFunc
(
JNIEnv
*,
jobject
);
#
ifdef
__
cplusplus
}
#
endifSlide6
Java Native Interface III.Native code should be compiled
into
a
library
Compiled
library
should
be
accessible
by
the
Java
application
in
case
of
Android
it
should
be
packed
into
the
apkSlide7
Android native supportjavah can be used to
generate
native
function
declarations
ndk-build
can
be
used
to
compile
the
native
code
to
a
library
file
Ndk-build
needs
:
Source
files
containing
native
function
definitions
They
are
typically
located
in
./
jni
Android.mk
configuration
file
in
./
jni
This
configuration
file
should
be
properly
filled
After
ndk-build
the
project
can
be
built
as
usual
(
with
NetBeans
for
e.g
.)Slide8
Android.mk simpleLOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := myLibName
LOCAL_SRC_FILES :=
mySourceFile
.
cpp
include $(BUILD_SHARED_LIBRARY)
Name
of
the
library
file
to
be
created
Source
file
in
./
jni
that
contains
native
code
definitionsSlide9
Android.mk advancedLOCAL_PATH := $(call my-dir)include$(CLEAR_VARS)LOCAL_MODULE := OgreJNI
LOCAL_LDLIBS := -
landroid
-
lc
-lm -
ldl
-
llog
-
lEGL
-lGLESv2
LOCAL_LDLIBS += -L./../
MyAPI
/
lib
LOCAL_LDLIBS += -lMyAPILOCAL_STATIC_LIBRARIES := cpufeatures
LOCAL_CFLAGS := -I./../MyAPI/includeLOCAL_CFLAGS += -fexceptions
-frtti -x c++ -D___ANDROID___ -DANDROID -DZZIP_OMIT_CONFIG_HLOCAL_SRC_FILES :=
./MyCode/MainActivity.cppinclude $(BUILD_SHARED_LIBRARY)$(call import-module,android/cpufeatures)
Additional
used
libraries
Additional
library
path
Additional
include path
Source
file
not
in
./
jni
,
Several
source
files
can
be
listedSlide10
NetBeans/Eclipse native supportNetBeans does
not
provide
additional
support
for
native
code
in Android
Eclipse
Right
click
on project – Android Tools – Add native support
jni
folder
,
Android.mk
,
empty
cpp
file created
automatically
Android.mk
refers
to
new
cpp
file
Ndk-build
called
automatically
before
Java
buildSlide11
Pure Native Android Application I.At least
we
need
a
dummy
Java
Activity
to
call
our
native functionsWe also have a built in
„dummy” activityCalls „android_main”
native functionSeparate threadCallbacks
for window and input commandsandroid.app.NativeActivity
android_native_app_glue librarySlide12
Pure Native Android Application II.Android .
mk
LOCAL_STATIC_LIBRARIES :=
android_native_app_glue
…
include $(BUILD_SHARED_LIBRARY
)
…
$(
call import-
module,
android
/
native_app_glue
)
AndroidManifest.xml
<
uses-sdk
android:minSdkVersion="9" /><activity android:name
="android.app.NativeActivity"Slide13
Pure Native Android Application III.Source
file
example
:
void
android
_main
(
struct
android
_
app
*
state
) {
state->onAppCmd = handle_
cmd; state->onInputEvent =
handle_input;
while (1) { // Read all pending events. int ident; int events;
struct
android
_poll_source* source;
while ((ident = ALooper_pollAll(-1, NULL, &events
, (void**)&source)) >= 0) { // Process
this event. if (
source != NULL) { source->process(state, source);
} if (state->
destroyRequested) { return;
} } }}…Slide14
Pure Native Android Application IV.
void
handle
_
cmd
(
struct
android
_
app
*
app
, int32_t
cmd
) {
switch (cmd) {
case APP_CMD_INIT_WINDOW: …}
int32_t handle_input(struct android
_app* app, AInputEvent* event) { if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
float
x =
AMotionEvent
_
getX(event, 0); …
return 1; } return
0;}Slide15
OpenGL in native code I.Move performance critical rendering parts to native code
Keep the window and GUI on the Java side
Some features are easier to access from JavaSlide16
OpenGL in native code II.
We
need
Anctivity
with
a
Surface
View
:
public
class
NativeEglExample
extends
Activity
implements
SurfaceHolder.Callback
{
public
void
onCreate(
Bundle
savedInstanceState) {
super.onCreate
(
savedInstanceState
);
nativeOnCreate
();
setContentView
(
R.layout.main
);
SurfaceView
surfaceView
= (
SurfaceView
)
findViewById
(
R.id.surfaceview
);
surfaceView.getHolder
().
addCallback
(
this
);
}
protected
void
onResume
() {
super.onResume
();
nativeOnResume
();
}
protected
void
onPause
() {
super.onPause
();
nativeOnPause
();
}
protected
void
onStop
() {
super.on
Stop
();
nativeOnStop
();
}
...Slide17
OpenGL in native code III.
…
public
void
surfaceChanged
(
SurfaceHolder
holder
, int
format
,
int
w, int h) {
nativeSetSurface
(
holder.getSurface
());
}
public
void
surfaceCreated
(
SurfaceHolder
holder
) {
}
public
void
surfaceDestroyed
(
SurfaceHolder
holder
) {
nativeSetSurface
(null);
}
public
static
native
void
nativeOnCreate
();
public
static
native
void
nativeOnResume
();
public
static
native
void
nativeOnPause
();
public
static
native
void
nativeOnStop
();
public
static
native
void
nativeSetSurface
(
Surface
surface
);
static
{
System.loadLibrary
("
nativeegl
");
}
}Slide18
OpenGL in native code IV.
Native code:
void JNICALL …_
nativeOnCreate
(
JNIEnv
*
jenv
,
jobject
obj
){
//do your initializations
}
void JNICALL …_
nativeOnResume
(
JNIEnv
*
jenv
,
jobject
obj
){
//do your initializations
//
you can start a
main
loop thread here that calls render()
}
Slide19
OpenGL in native code V.
static
ANativeWindow
*window = 0
;
JNIEXPORT
void JNICALL
…_
nativeSetSurface
(
JNIEnv
*
jenv
,
jobject
obj
,
jobject
surface)
{
if (surface
==
0)
{
ANativeWindow_release
(window);
}
else {
window
= ANativeWindow_fromSurface
(
jenv
, surface);
initializeGLWindow
();
}
return;
}
Slide20
OpenGL in native code VI.
v
oid
initializeGLWindow
()
{
const
EGLint
attribs
[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
EGLDisplay
display;
EGLConfig
config
;
EGLint
numConfigs
;
EGLint
format;
EGLSurface
surface;
EGLContext
context;
EGLint
width;
EGLint
height;
GLfloat
ratio
;
…
Slide21
OpenGL in native code VII.
…
display
=
eglGetDisplay
(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY);
eglInitialize
(display
, 0, 0);
eglChooseConfig
(display
,
attribs
, &
config
, 1, &
numConfigs
);
eglGetConfigAttrib
(display,
config
, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry
(window, 0, 0, format);
surface
=
eglCreateWindowSurface
(display,
config
,
window, 0);
context
=
eglCreateContext
(display,
config
, 0, 0);
eglMakeCurrent
(display
, surface, surface, context);
eglQuerySurface
(display
, surface, EGL_WIDTH, &width);
eglQuerySurface
(display
, surface, EGL_HEIGHT, &height);
glViewport
(0
, 0, width, height);
ratio = (
GLfloat
) width / height;
glMatrixMode
(GL_PROJECTION);
glLoadIdentity
();
glFrustumf
(-ratio, ratio, -1, 1, 1, 10);
//other
GL initialization
}
Slide22
OpenGL in native code VIII.
v
oid render()
{
//regular GL draw calls
glClear
(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT);
glMatrixMode
(GL_MODELVIEW);
glLoadIdentity
();
glTranslatef
(0, 0, -3.0f);
//draw with arrays, no
glBegin
/
glEnd
in GLES
glEnableClientState
(GL_VERTEX_ARRAY);
glEnableClientState
(GL_COLOR_ARRAY);
glFrontFace
(GL_CW);
glVertexPointer
(3, GL_FIXED, 0, vertices);
glColorPointer
(4, GL_FIXED, 0, colors);
glDrawElements
(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
eglSwapBuffers
(_display, _surface
);
}Slide23
OpenGL in native code IX.
void JNICALL …_
nativeOnStop
(
JNIEnv
*
jenv
,
jobject
obj
){
//do
final cleanup
}
void JNICALL …_
nativeOnPause
(
JNIEnv
*
jenv
,
jobject
obj
){
//do your
app state save if necessary
// you can
end your main
thread
here
}Slide24
OpenGL in native code X. (Threads)
Create a thread:
#
include <
pthread.h
>
pthread_t
_
threadId
;
pthread_create
(&_
threadId
, 0,
threadStartCallback
, 0
);Wait thread to terminate:
pthread_join(_threadId, 0);Render thread example:
void* threadStartCallback(void *arg){
while(running) //we can terminate this thread if needed render(); pthread_exit(0); return 0;}Slide25
Pure native OpenGL app I.No Java code is writtenWe use the native app glueandroid_main is called in its separate threadno additional threading needed on the native sideGUI creation and accessing Android features is much harderSlide26
Pure native OpenGL app II.static ANativeWindow *window = 0;void
android
_main(
struct
android
_
app
*
state
)
{
state-
>
onAppCmd
=
handle_cmd; state->
onInputEvent = handle_input; while
(1) { int ident, events
; struct android_poll_source* source; while ((ident = ALooper_pollAll(-1, NULL, &events, (void**)&source)) >= 0) { if
(source != NULL)
{
source-
>process(state, source
); } if (state->
destroyRequested) { return; } } render
(); // same as before }}
void handle_cmd
(struct android_app* app, int32_t cmd) {
switch (cmd) {
case APP_CMD_INIT_WINDOW:
window = state->window; initializeGLWindow() ;//same as before…
}Slide27
Using Ogre on AndroidNow we can use native code in our Android appWhy not use Ogre3D?It is possible …
Still under development (Ogre 1.9)
We have to compile Ogre for Android, instructions:
http://www.ogre3d.org/tikiwiki/CMake%20Quick%20Start%20Guide?tikiversion=Android
We should test if Ogre works on our device
Run the compiled
OgreSampleBrowser
Also available on Google Play (before any build)
In current state (Ogre 1.9 RC1) GLES2 render system is working GLES1 is not
It won’t run on emulator
Min Android 2.3.3Slide28
Ogre3D with Java activity I.Similar to native OpenGL with Java ActivityInitialization, window initialization and rendering is different
Native code
:
static Ogre::Root*
gRoot
= NULL;
void
JNICALL …_
nativeOnCreate
(
JNIEnv
*
jenv
,
jobject
obj
,
jobject
assetManager
){
gRoot
= new Ogre::Root();
gGLESPlugin
= OGRE_NEW GLES2Plugin ();
gRoot
->
installPlugin(
gGLESPlugin
);
gOctreePlugin
= OGRE_NEW
OctreePlugin
();
gRoot
-
>
installPlugin
(
gOctreePlugin
);
//load additional
plugins
(
particlefx
, overlay)
gRoot
-
>
setRenderSystem
(
gRoot
->
getAvailableRenderers
().at(0));
gRoot
-
>
initialise
(false);
//enable loading media files from the
apk
asset folder
assetMgr
=
AAssetManager_fromJava
(
env
,
assetManager
);
if
(
assetMgr
)
{
ArchiveManager
::
getSingleton
().
addArchiveFactory
( new
APKFileSystemArchiveFactory
(
assetMgr
) );
ArchiveManager
::
getSingleton
().
addArchiveFactory
( new
APKZipArchiveFactory
(
assetMgr
) );
}
//
do your
initializations
}Slide29
Ogre3D with Java activity II.
static
ANativeWindow
*window = 0
;
static Ogre::
RenderWindow
*
gRenderWnd
= NULL;
JNIEXPORT
void JNICALL
…_
nativeSetSurface
(
JNIEnv
*
jenv
,
jobject
obj
,
jobject
surface)
{
if (surface
==
0)
{
ANativeWindow_release
(window); }
else {
window
=
ANativeWindow_fromSurface
(
jenv
, surface);
initializeOgreWindow
();
}
return;
}
Slide30
Ogre3D with Java activity III.void initializeOgreWindow
()
{
//create render window based on an existing window
Ogre::
NameValuePairList
opt;
opt["
externalWindowHandle
"] = Ogre::
StringConverter
::
toString
((
int
)
nativeWnd
); AConfiguration* config = AConfiguration_new
(); AConfiguration_fromAssetManager(config, assetMgr);
opt["androidConfig"] = Ogre::StringConverter::toString((int)config); gRenderWnd = Ogre::Root::getSingleton().createRenderWindow("OgreWindow", 0, 0, false, &opt);
ResourceGroupManager
::
getSingleton
().addResourceLocation("/models"
, "APKFileSystem"); ResourceGroupManager::getSingleton().addResourceLocation(
"/material", "APKFileSystem"
); ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
//usual scene graph initialization Ogre::SceneManager* pSceneMgr = gRoot->
createSceneManager(Ogre::ST_GENERIC); Ogre::Camera* pCamera = pSceneMgr->createCamera
("MyCam"); pCamera->
setPosition(100,100,500); pCamera->lookAt(0,0,0); Ogre::Viewport* vp = gRenderWnd->addViewport
(pCamera); vp->setBackgroundColour(Ogre::ColourValue
(1,0,0)); …}Slide31
Ogre3D with Java activity IV.void render()
{
if(
gRenderWnd
!= NULL &&
gRenderWnd
->
isActive
())
{
try
{
gRenderWnd
->
windowMovedOrResized
();
gRoot
->
renderOneFrame
();
}
catch(Ogre::
RenderingAPIException ex) {} }
}Slide32
Ogre3D with Java activity V.Android.mk
LOCAL_PATH
:= $(call my-dir)
include
$(CLEAR_VARS)
LOCAL_MODULE
:=
OgreJNI
LOCAL_LDLIBS :=
-
landroid
-
lc
-lm -
ldl
-
llog
-
lEGL
-lGLESv2
LOCAL_LDLIBS +=
-
L$(OGRE_ANDROID_PATH)/lib
LOCAL_LDLIBS += -L$(OGRE_ANDROID_PATH)/
AndroidDependencies
/lib/armeabi-v7a
LOCAL_LDLIBS += -
lPlugin_OctreeSceneManagerStatic -lRenderSystem_GLES2Static
-lOgreMainStatic
LOCAL_LDLIBS += -lzzip
-lz
-lFreeImage -lfreetype
-lOIS
LOCAL_LDLIBS += -l$(OGRE_ANDROID_PATH)/
systemlibs
/armeabi-v7a/
libsupc
++.a
LOCAL_LDLIBS += -l$(OGRE_ANDROID_PATH)/
systemlibs
/armeabi-v7a/
libstdc
++.a
LOCAL_STATIC_LIBRARIES
:=
cpufeatures
LOCAL_CFLAGS
:= -DGL_GLEXT_PROTOTYPES=1
LOCAL_CFLAGS
+=
-
I$(OGRE_ANDROID_PATH)
OgreMain
/include
LOCAL_CFLAGS +=
-I$(OGRE_ANDROID_PATH)
RenderSystems
/GLES2/include
LOCAL_CFLAGS +=
-I$(OGRE_ANDROID_PATH)
RenderSystems
/GLES2/include/EGL
LOCAL_CFLAGS += -
I$(ANDROID_NDK)/sources/
cpufeatures
LOCAL_CFLAGS +=
-I$(OGRE_ANDROID_PATH)
PlugIns
/
OctreeSceneManager
/include
LOCAL_CFLAGS
+= -
I$(OGRE_ANDROID_PATH)
AndroidDependencies
/include
LOCAL_CFLAGS +=
-I$(OGRE_ANDROID_PATH)
AndroidDependencies
/include/OIS
LOCAL_CFLAGS += -
fexceptions
-
frtti
-x
c++
-D___ANDROID___ -DANDROID -DZZIP_OMIT_CONFIG_H
LOCAL_SRC_FILES
:=
MainActivity.cpp
include
$(BUILD_SHARED_LIBRARY)
$(
call import-
module,android
/
cpufeatures
)Slide33
Using Ogre in pure native app I.
Similar to
pure native OpenGL application
Code:
//
globals
RenderWindow
*
gRenderWindow
= NULL;
Root*
gRoot
= NULL;
static
ANativeWindow
*window =
NULL;Slide34
Using Ogre in pure native app II.
void
android_main
(
struct
android_app
* state) {
app_dummy
();
gRoot
= new Ogre::Root();
gRoot
>installPlugin(OGRE_NEW GLES2Plugin());
gRoot >installPlugin(OGRE_NEW OctreePlugin()); gRoot
>setRenderSystem(root->getAvailableRenderers().at(0)); gRoot
>initialise(false); ArchiveManager::getSingleton().addArchiveFactory( new APKFileSystemArchiveFactory(state->activity->assetManager) ); ArchiveManager
::
getSingleton
().
addArchiveFactory
( new APKZipArchiveFactory(state->activity->assetManager) );
state->onAppCmd = handleCmd; int ident, events;
struct android_poll_source* source; while (true){
while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0){
if (source != NULL) source->process(state, source); if (state->destroyRequested != 0) return; }
if(renderWindow != NULL && renderWindow->isActive()){
gRenderWindow->windowMovedOrResized();
gRoot->renderOneFrame(); } }}Slide35
Using Ogre in pure native app III.
void
handleCmd
(
struct
android_app
* app, int32_t
cmd
){
switch (
cmd
){
case APP_CMD_SAVE_STATE:
break;
case APP_CMD_INIT_WINDOW
:
window = state->window;
initializeOgreWindow
(); //same as above break; case APP_CMD_TERM_WINDOW:
if(gRoot && gRenderWindow) static_cast<AndroidEGLWindow*>(gRenderWindow)->_destroyInternalResources(); break;
}
}Slide36
The End