Home | History | Annotate | Download | only in html
      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
     59 iconic <a
     60 href="http://math.hws.edu/bridgeman/courses/324/s06/doc/opengl.html#basic">Utah
     61 teapot</a>. It particularly showcases the <code>ndk_helper</code> helper class,
     62 a collection of native helper functions required for implementing games and
     63 similar 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
     70 loading).</li>
     71 </ul>
     72 <h3>AndroidManifest.xml</h3>
     73 <p>The activity declaration here is not <code>NativeActivity</code> itself, but
     74 a sublass: <code>TeapotNativeActivity</code>.</p>
     75 <pre class="fragment">    &lt;activity
     76 android: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
     91 href="./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
     96 the screen.</p>
     97 <pre class="fragment">// Our popup window, you will call it from your C/C++
     98 code later
     99 
    100 
    101 void 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
    113 based on where the user taps:</p>
    114 <pre class="fragment">ndk_helper::Mat4 mat_projection_;
    115 ndk_helper::Mat4 mat_view_;
    116 ndk_helper::Mat4 mat_model_;
    117 
    118 
    119 ndk_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
    122 helper-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
    130 function
    131 </pre><p>The first use of the <code>ndk_helper</code> class is to handle the
    132 EGL-related lifecycle, associating EGL context states (created/lost) with
    133 Android lifecycle events. It enables the application to preserve context
    134 information so that a destroyed activity can be restored. This is useful, for
    135 example, when the target machine is rotated (causing an activity to be
    136 destroyed, then immediately restored in the new orientation), or when the lock
    137 screen appears.</p>
    138 <pre class="fragment">ndk_helper::GLContext* gl_context_; // handles
    139 EGL-related lifecycle.
    140 </pre><p>Next, <code>ndk_helper</code> provides touch control.</p>
    141 <pre class="fragment">ndk_helper::DoubletapDetector doubletap_detector_;
    142 ndk_helper::PinchDetector pinch_detector_;
    143 ndk_helper::DragDetector drag_detector_;
    144 ndk_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
    148 sensors, using the native APIs provided in the NDK.</p>
    149 <pre class="fragment">ASensorManager* sensor_manager_;
    150 const ASensor* accelerometer_sensor_;
    151 ASensorEventQueue* sensor_event_queue_;
    152 </pre><p>The following functions are called in response to various Android
    153 lifecycle events and EGL context state changes, using various functionalities
    154 provided by <code>ndk_helper</code> via the <code>Engine</code> class.</p>
    155 <pre class="fragment">void LoadResources();
    156 void UnloadResources();
    157 void DrawFrame();
    158 void TermDisplay();
    159 void TrimMemory();
    160 bool 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
    178 superimposed on the screen rendered on the native side, and showing frame
    179 count.</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
    196 for time-based animation based on real-time clock. For example, calculating
    197 momentum, 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
    200 application 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
    203 buffer.
    204 </pre><p>The program passes touch-motion events to the gesture detector defined
    205 in the <code>ndk_helper</code> class. The gesture detector tracks multitouch
    206 gestures, such as pinch-and-drag, and sends a notification when triggered by
    207 any of these events.</p>
    208 <pre class="fragment">if( AInputEvent_getType( event ) ==
    209 AINPUT_EVENT_TYPE_MOTION )
    210 {
    211     ndk_helper::GESTURE_STATE doubleTapState =
    212 eng-&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(
    216 event );
    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(
    238 gl_context_-&gt;GetScreenWidth(), gl_context_-&gt;GetScreenHeight() )
    239 
    240 ndk_helper::Vec2( 1.f, 1.f ); }</li></pre>
    241 </ul>
    242 <p><code>HandleCmd()</code> handles commands posted from the
    243 android_native_app_glue library. For more information about what the messages
    244 mean, 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
    248 cmd ) { Engine* eng = (Engine*) app-&gt;userData; switch( cmd ) { case
    249 APP_CMD_SAVE_STATE: break; case APP_CMD_INIT_WINDOW: // The window is being
    250 shown, 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
    253 receives an <code>onNativeWindowCreated()</code> callback from the system.
    254 Applications can normally perform window initializations, such as EGL
    255 initialization. They do this outside of the activity lifecycle, since the
    256 activity is not yet ready.</p>
    257 <pre class="fragment">ndk_helper::JNIHelper::Init( state-&gt;activity,
    258 HELPER_CLASS_NAME );
    259 
    260 
    261 state-&gt;userData = &amp;g_engine;
    262 state-&gt;onAppCmd = Engine::HandleCmd;
    263 state-&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
    270 Programmer&#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