• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml">
4<head>
5<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
6<meta http-equiv="X-UA-Compatible" content="IE=9"/>
7<meta name="generator" content="Doxygen 1.8.5"/>
8<title>NDK Programmer&#39;s Guide: Teapot</title>
9<link href="tabs.css" rel="stylesheet" type="text/css"/>
10<script type="text/javascript" src="jquery.js"></script>
11<script type="text/javascript" src="dynsections.js"></script>
12<link href="navtree.css" rel="stylesheet" type="text/css"/>
13<script type="text/javascript" src="resize.js"></script>
14<script type="text/javascript" src="navtree.js"></script>
15<script type="text/javascript">
16  $(document).ready(initResizable);
17  $(window).load(resizeHeight);
18</script>
19<link href="doxygen.css" rel="stylesheet" type="text/css" />
20</head>
21<body>
22<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
23<div id="titlearea">
24<table cellspacing="0" cellpadding="0">
25 <tbody>
26 <tr style="height: 56px;">
27  <td style="padding-left: 0.5em;">
28   <div id="projectname">NDK Programmer&#39;s Guide
29   </div>
30  </td>
31 </tr>
32 </tbody>
33</table>
34</div>
35<!-- end header part -->
36<!-- Generated by Doxygen 1.8.5 -->
37</div><!-- top -->
38<div id="side-nav" class="ui-resizable side-nav-resizable">
39  <div id="nav-tree">
40    <div id="nav-tree-contents">
41      <div id="nav-sync" class="sync"></div>
42    </div>
43  </div>
44  <div id="splitbar" style="-moz-user-select:none;"
45       class="ui-resizable-handle">
46  </div>
47</div>
48<script type="text/javascript">
49$(document).ready(function(){initNavTree('md_2__samples_samples-teapot.html','')
50;});
51</script>
52<div id="doc-content">
53<div class="header">
54  <div class="headertitle">
55<div class="title">Teapot </div>  </div>
56</div><!--header-->
57<div class="contents">
58<div class="textblock"><p>This sample uses the OpenGL library to render the
59iconic <a
60href="http://math.hws.edu/bridgeman/courses/324/s06/doc/opengl.html#basic">Utah
61teapot</a>. It particularly showcases the <code>ndk_helper</code> helper class,
62a collection of native helper functions required for implementing games and
63similar applications as native applications. This class provides:</p>
64<ul>
65<li>an abstraction layer that handles certain NDK-specific behaviors (e.g.,
66<code>GLContext</code>).</li>
67<li>some helper functions that are useful but not present in the NDK, itself
68(e.g., tap detection).</li>
69<li>wrappers for JNI calls for certain platform features (e.g., texture
70loading).</li>
71</ul>
72<h3>AndroidManifest.xml</h3>
73<p>The activity declaration here is not <code>NativeActivity</code> itself, but
74a sublass: <code>TeapotNativeActivity</code>.</p>
75<pre class="fragment">    &lt;activity
76android:name="com.sample.teapot.TeapotNativeActivity"
77            android:label="@string/app_name"
78            android:configChanges="orientation|keyboardHidden"&gt;
79</pre><p>The name of the <code>.so</code> file is
80<code>libTeapotNativeActivity.so</code>; the <code>lib</code> and
81<code>.so</code> are stripped off from the value assigned to
82<code>android:value</code>.</p>
83<pre class="fragment">        &lt;meta-data android:name="android.app.lib_name"
84                android:value="TeapotNativeActivity" /&gt;
85</pre><h3><code>Application.mk</code></h3>
86<p>Define the minimum level of Android API Level support.</p>
87<pre class="fragment">APP_PLATFORM := android-9
88</pre><p>Build for all supported architectures.</p>
89<pre class="fragment">APP_ABI := all
90</pre><p>Specify the <a
91href="./md_3__key__topics__libraries__c_p_l_u_s_p_l_u_s-_s_u_p_p_o_r_t.html">C++
92 runtime support library</a> to use. </p>
93<pre class="fragment">APP_STL := stlport_static
94</pre><h3>Java-side implementation: TeapotNativeActivity.java</h3>
95<p>This file handles activity lifecycle events, as well as displaying text on
96the screen.</p>
97<pre class="fragment">// Our popup window, you will call it from your C/C++
98code later
99
100
101void setImmersiveSticky() {
102    View decorView = getWindow().getDecorView();
103    decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
104            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
105            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
106            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
107            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
108            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
109}
110</pre><h3>Native-side implementation: <code>TeapotRenderer.h/.cpp</code></h3>
111<p>This code does the actual rendering of the teapot. It uses
112<code>ndk_helper</code> for matrix calculation, and to reposition the camera
113based on where the user taps:</p>
114<pre class="fragment">ndk_helper::Mat4 mat_projection_;
115ndk_helper::Mat4 mat_view_;
116ndk_helper::Mat4 mat_model_;
117
118
119ndk_helper::TapCamera* camera_;
120</pre><h3>Native-side implementation: <code>TeapotNativeActivity.cpp</code></h3>
121<p>Include <code>ndk_helper</code> in your native source file, and define the
122helper-class name:</p>
123<pre class="fragment">#include "NDKHelper.h"
124
125
126//-------------------------------------------------------------------------
127//Preprocessor
128//-------------------------------------------------------------------------
129#define HELPER_CLASS_NAME "com/sample/helper/NDKHelper" //Class name of helper
130function
131</pre><p>The first use of the <code>ndk_helper</code> class is to handle the
132EGL-related lifecycle, associating EGL context states (created/lost) with
133Android lifecycle events. It enables the application to preserve context
134information so that a destroyed activity can be restored. This is useful, for
135example, when the target machine is rotated (causing an activity to be
136destroyed, then immediately restored in the new orientation), or when the lock
137screen appears.</p>
138<pre class="fragment">ndk_helper::GLContext* gl_context_; // handles
139EGL-related lifecycle.
140</pre><p>Next, <code>ndk_helper</code> provides touch control.</p>
141<pre class="fragment">ndk_helper::DoubletapDetector doubletap_detector_;
142ndk_helper::PinchDetector pinch_detector_;
143ndk_helper::DragDetector drag_detector_;
144ndk_helper::PerfMonitor monitor_;
145</pre><p>And camera control (openGL view frustum).</p>
146<pre class="fragment">ndk_helper::TapCamera tap_camera_;
147</pre><p>As in the native-activity sample, the application prepares to use the
148sensors, using the native APIs provided in the NDK.</p>
149<pre class="fragment">ASensorManager* sensor_manager_;
150const ASensor* accelerometer_sensor_;
151ASensorEventQueue* sensor_event_queue_;
152</pre><p>The following functions are called in response to various Android
153lifecycle events and EGL context state changes, using various functionalities
154provided by <code>ndk_helper</code> via the <code>Engine</code> class.</p>
155<pre class="fragment">void LoadResources();
156void UnloadResources();
157void DrawFrame();
158void TermDisplay();
159void TrimMemory();
160bool IsReady();
161</pre><p>This function calls back to the Java side to update the UI display.</p>
162<pre class="fragment">void Engine::ShowUI()
163{
164    JNIEnv *jni;
165    app_-&gt;activity-&gt;vm-&gt;AttachCurrentThread( &amp;jni, NULL );
166
167
168    //Default class retrieval
169    jclass clazz = jni-&gt;GetObjectClass( app_-&gt;activity-&gt;clazz );
170    jmethodID methodID = jni-&gt;GetMethodID( clazz, "showUI", "()V" );
171    jni-&gt;CallVoidMethod( app_-&gt;activity-&gt;clazz, methodID );
172
173
174    app_-&gt;activity-&gt;vm-&gt;DetachCurrentThread();
175    return;
176}
177</pre><p>And this one calls back to the Java side to draw a text box
178superimposed on the screen rendered on the native side, and showing frame
179count.</p>
180<pre class="fragment">void Engine::UpdateFPS( float fFPS )
181{
182    JNIEnv *jni;
183    app_-&gt;activity-&gt;vm-&gt;AttachCurrentThread( &amp;jni, NULL );
184
185
186    //Default class retrieval
187    jclass clazz = jni-&gt;GetObjectClass( app_-&gt;activity-&gt;clazz );
188    jmethodID methodID = jni-&gt;GetMethodID( clazz, "updateFPS", "(F)V" );
189    jni-&gt;CallVoidMethod( app_-&gt;activity-&gt;clazz, methodID, fFPS );
190
191
192    app_-&gt;activity-&gt;vm-&gt;DetachCurrentThread();
193    return;
194}
195</pre><p>The application gets the system clock and supplies it to the renderer
196for time-based animation based on real-time clock. For example, calculating
197momentum, where speed declines as a function of time.</p>
198<pre class="fragment">renderer_.Update( monitor_.GetCurrentTime() );
199</pre><p>Having earlier been set up to preserve context information, the
200application now checks whether <code>GLcontext</code> is still valid. If not,
201<code>ndk-helper</code> swaps the buffer, reinstantiating the GL context.</p>
202<pre class="fragment">if( EGL_SUCCESS != gl_context_-&gt;Swap() )  // swaps
203buffer.
204</pre><p>The program passes touch-motion events to the gesture detector defined
205in the <code>ndk_helper</code> class. The gesture detector tracks multitouch
206gestures, such as pinch-and-drag, and sends a notification when triggered by
207any of these events.</p>
208<pre class="fragment">if( AInputEvent_getType( event ) ==
209AINPUT_EVENT_TYPE_MOTION )
210{
211    ndk_helper::GESTURE_STATE doubleTapState =
212eng-&gt;doubletap_detector_.Detect( event );
213    ndk_helper::GESTURE_STATE dragState = eng-&gt;drag_detector_.Detect( event
214);
215    ndk_helper::GESTURE_STATE pinchState = eng-&gt;pinch_detector_.Detect(
216event );
217
218
219    //Double tap detector has a priority over other detectors
220    if( doubleTapState == ndk_helper::GESTURE_STATE_ACTION )
221    {
222        //Detect double tap
223        eng-&gt;tap_camera_.Reset( true );
224    }
225    else
226    {
227        //Handle pinch state
228        if( pinchState &amp; ndk_helper::GESTURE_STATE_START )
229        {
230            //Start new pinch
231            ndk_helper::Vec2 v1;
232            ndk_helper::Vec2 v2;
233            eng-&gt;pinch_detector_.GetPointers( v1, v2 );
234</pre><p><code>ndk_helper</code> also provides access to a vector-math library
235(<code>vecmath.h</code>), using it here to transform touch coordinates.</p>
236<pre class="fragment">void Engine::TransformPosition( ndk_helper::Vec2&amp; vec
237) { vec = ndk_helper::Vec2( 2.0f, 2.0f ) * vec / ndk_helper::Vec2(
238gl_context_-&gt;GetScreenWidth(), gl_context_-&gt;GetScreenHeight() )
239
240ndk_helper::Vec2( 1.f, 1.f ); }</li></pre>
241</ul>
242<p><code>HandleCmd()</code> handles commands posted from the
243android_native_app_glue library. For more information about what the messages
244mean, refer to the comments in the <code>android_native_app_glue.h</code> and
245<code>.c</code> source files.</p>
246
247<pre class="fragment">void Engine::HandleCmd( struct android_app* app, int32_t
248cmd ) { Engine* eng = (Engine*) app-&gt;userData; switch( cmd ) { case
249APP_CMD_SAVE_STATE: break; case APP_CMD_INIT_WINDOW: // The window is being
250shown, get it ready. if( app-&gt;window != NULL )</li></pre>
251
252<p><code>ndk_helper</code> posts APP_CMD_INIT_WINDOW when android_app_glue
253receives an <code>onNativeWindowCreated()</code> callback from the system.
254Applications can normally perform window initializations, such as EGL
255initialization. They do this outside of the activity lifecycle, since the
256activity is not yet ready.</p>
257<pre class="fragment">ndk_helper::JNIHelper::Init( state-&gt;activity,
258HELPER_CLASS_NAME );
259
260
261state-&gt;userData = &amp;g_engine;
262state-&gt;onAppCmd = Engine::HandleCmd;
263state-&gt;onInputEvent = Engine::HandleInput; </pre> </div></div><!-- contents
264-->
265</div><!-- doc-content -->
266<!-- start footer part -->
267<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
268  <ul>
269    <li class="footer">Generated on Wed Jun 25 2014 00:51:19 for NDK
270Programmer&#39;s Guide by
271    <a href="http://www.doxygen.org/index.html">
272    <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.5 </li>
273  </ul>
274</div>
275</body>
276</html>
277