टीपॉट का नमूना, एनडीके के तहत samples/Teapot/
डायरेक्ट्री में मौजूद होता है
इंस्टॉलेशन की रूट डायरेक्ट्री से मेल खाना चाहिए. यह नमूना ऐतिहासिक ज़ेहन को रेंडर करने के लिए OpenGL लाइब्रेरी का इस्तेमाल करता है
यूटा
टीपॉट. खास तौर पर, यह ndk_helper
हेल्पर क्लास को दिखाता है,
गेम को लागू करने के लिए ज़रूरी नेटिव हेल्पर फ़ंक्शन का कलेक्शन और
नेटिव ऐप्लिकेशन की तरह मिलते-जुलते ऐप्लिकेशन. इस क्लास में ये सुविधाएं मिलती हैं:
- एक ऐब्स्ट्रैक्ट लेयर,
GLContext
, जो एनडीके से जुड़ी कुछ खास गतिविधियों को हैंडल करती है. - ऐसे हेल्पर फ़ंक्शन जो मददगार हैं, लेकिन एनडीके (एनडीके) में मौजूद नहीं हैं. जैसे, टैप डिटेक्शन.
- टेक्सचर लोडिंग जैसी प्लैटफ़ॉर्म सुविधाओं के लिए, JNI कॉल के लिए रैपर.
AndroidManifest.xml
यहां गतिविधि का एलान NativeActivity
नहीं है, बल्कि
इसकी सब-क्लास: TeapotNativeActivity
.
<activity android:name="com.sample.teapot.TeapotNativeActivity" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden">
इसलिए, बिल्ड सिस्टम में शेयर की गई जो फ़ाइल बनाई जाती है उसका नाम
libTeapotNativeActivity.so
. बिल्ड सिस्टम, lib
प्रीफ़िक्स और .so
को जोड़ता है
एक्सटेंशन; इनमें से कोई भी उस वैल्यू का हिस्सा नहीं होता जिसे मेनिफ़ेस्ट मूल रूप से असाइन करता है
android:value
.
<meta-data android:name="android.app.lib_name" android:value="TeapotNativeActivity" />
ऐप्लिकेशन.एमके
NativeActivity
फ़्रेमवर्क क्लास का इस्तेमाल करने वाले ऐप्लिकेशन को
Android 9 से कम एपीआई लेवल, जिसने इस क्लास को लॉन्च किया. इस बारे में ज़्यादा जानकारी पाने के लिए
NativeActivity
क्लास, देखें
स्थानीय गतिविधियां और ऐप्लिकेशन.
APP_PLATFORM := android-9
अगली लाइन, बिल्ड सिस्टम को इसके साथ काम करने वाले सभी आर्किटेक्चर के लिए बनाने के बारे में बताती है.
APP_ABI := all
इसके बाद, फ़ाइल बिल्ड सिस्टम को बताती है इस्तेमाल करने के लिए, C++ रनटाइम सहायता लाइब्रेरी.
APP_STL := stlport_static
Java-साइड लागू करना
TeapotNativeActivity
फ़ाइल, teapots/classic-teapot/src/com/sample/teapot
में GitHub पर NDK रेपो रूट डायरेक्ट्री में मौजूद है. यह, गतिविधि के लाइफ़साइकल इवेंट को मैनेज करता है और ShowUI()
फ़ंक्शन वाली स्क्रीन पर टेक्स्ट दिखाने के लिए, पॉप-अप विंडो बनाता है. साथ ही, updateFPS()
फ़ंक्शन की मदद से, फ़्रेम रेट को डाइनैमिक तौर पर अपडेट करता है. यहां दिया गया कोड आपको दिलचस्प लग सकता है, क्योंकि यह ऐप्लिकेशन की गतिविधि को फ़ुल स्क्रीन, इमर्सिव, और सिस्टम नेविगेशन बार के बिना तैयार करता है. इससे टीपॉट के रेंडर किए गए फ़्रेम दिखाने के लिए पूरी स्क्रीन का इस्तेमाल किया जा सकता है:
Kotlin
fun setImmersiveSticky() { window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE ) }
Java
void setImmersiveSticky() { View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); }
नेटिव-साइड लागू करना
इस सेक्शन में, C++ में लागू किए गए Teaपॉट ऐप्लिकेशन के बारे में जानकारी दी गई है.
टीपॉटरेंडरर.एच
ये फ़ंक्शन कॉल टीपॉट की असल रेंडरिंग करते हैं. यह
मैट्रिक्स कैलकुलेशन और कैमरे की जगह बदलने के लिए ndk_helper
टैप किया जाता है.
ndk_helper::Mat4 mat_projection_; ndk_helper::Mat4 mat_view_; ndk_helper::Mat4 mat_model_; ndk_helper::TapCamera* camera_;
टी-पॉटनेटिव एक्टिविटी.सीपीपी
इन लाइनों में, नेटिव सोर्स फ़ाइल में ndk_helper
शामिल है और
हेल्पर क्लास का नाम.
#include "NDKHelper.h" //------------------------------------------------------------------------- //Preprocessor //------------------------------------------------------------------------- #define HELPER_CLASS_NAME "com/sample/helper/NDKHelper" //Class name of helper function
ndk_helper
क्लास का पहला इस्तेमाल
ईजीएल से जुड़ा लाइफ़साइकल, ईजीएल के कॉन्टेक्स्ट की स्थितियों (बनाए गए/खोए हुए) को इनके साथ जोड़ना
Android लाइफ़साइकल इवेंट. ndk_helper
क्लास, ऐप्लिकेशन को कॉन्टेक्स्ट सुरक्षित रखने में मदद करती है
जानकारी दें, ताकि सिस्टम खत्म हो चुकी गतिविधि को पहले जैसा कर सके. यह क्षमता उन लोगों के लिए काम की है
उदाहरण के लिए, जब टारगेट मशीन को घुमाया जाता है (जिसकी वजह से कोई गतिविधि होती है
खत्म हो जाता है, फिर तुरंत नए ओरिएंटेशन में बहाल हो जाता है) या जब लॉक
स्क्रीन दिखाई देती है.
ndk_helper::GLContext* gl_context_; // handles EGL-related lifecycle.
इसके बाद, ndk_helper
आपको टच कंट्रोल की सुविधा देता है.
ndk_helper::DoubletapDetector doubletap_detector_; ndk_helper::PinchDetector pinch_detector_; ndk_helper::DragDetector drag_detector_; ndk_helper::PerfMonitor monitor_;
इसमें कैमरा कंट्रोल (openGL व्यू फ़्रस्टम) भी मिलता है.
ndk_helper::TapCamera tap_camera_;
इसके बाद, ऐप्लिकेशन, डिवाइस के सेंसर का इस्तेमाल करता है. इसके लिए, वह एनडीके में दिए गए नेटिव एपीआई का इस्तेमाल करता है.
ASensorManager* sensor_manager_; const ASensor* accelerometer_sensor_; ASensorEventQueue* sensor_event_queue_;
यह ऐप्लिकेशन, अलग-अलग Android ऐप्लिकेशन के लिए इन फ़ंक्शन को कॉल करता है
अलग-अलग फ़ंक्शन का इस्तेमाल करके, लाइफ़साइकल इवेंट और ईजीएल कॉन्टेक्स्ट की स्थिति में बदलाव
ndk_helper
ने Engine
क्लास के ज़रिए उपलब्ध कराया.
void LoadResources(); void UnloadResources(); void DrawFrame(); void TermDisplay(); void TrimMemory(); bool IsReady();
इसके बाद, नीचे दिया गया फ़ंक्शन यूज़र इंटरफ़ेस (यूआई) डिसप्ले को अपडेट करने के लिए फिर से Java का इस्तेमाल करता है.
void Engine::ShowUI() { JNIEnv *jni; app_->activity->vm->AttachCurrentThread( &jni, NULL ); //Default class retrieval jclass clazz = jni->GetObjectClass( app_->activity->clazz ); jmethodID methodID = jni->GetMethodID( clazz, "showUI", "()V" ); jni->CallVoidMethod( app_->activity->clazz, methodID ); app_->activity->vm->DetachCurrentThread(); return; }
इसके बाद, यह फ़ंक्शन एक टेक्स्ट बॉक्स बनाने के लिए Java की तरफ़ वापस कॉल करता है नेटिव साइड में रेंडर की गई स्क्रीन पर सुपरइंपोज़्ड और फ़्रेम दिखा रहा है संख्या.
void Engine::UpdateFPS( float fFPS ) { JNIEnv *jni; app_->activity->vm->AttachCurrentThread( &jni, NULL ); //Default class retrieval jclass clazz = jni->GetObjectClass( app_->activity->clazz ); jmethodID methodID = jni->GetMethodID( clazz, "updateFPS", "(F)V" ); jni->CallVoidMethod( app_->activity->clazz, methodID, fFPS ); app_->activity->vm->DetachCurrentThread(); return; }
ऐप्लिकेशन, सिस्टम की घड़ी लाता है और उसे रेंडरर को उपलब्ध कराता है का इस्तेमाल करें. इस जानकारी का इस्तेमाल, उदाहरण के लिए, संवेग की गणना करते हैं, जहां समय के फलन के रूप में गति घटती है.
renderer_.Update( monitor_.GetCurrentTime() );
ऐप्लिकेशन अब GLcontext::Swap()
फ़ंक्शन के ज़रिए दिखाने के लिए, रेंडर किए गए फ़्रेम को फ़्रंट बफ़र में फ़्लिप कर देता है; यह फ़्लिपिंग की प्रोसेस के दौरान होने वाली संभावित गड़बड़ियों को भी हैंडल करता है.
if( EGL_SUCCESS != gl_context_->Swap() ) // swaps buffer.
प्रोग्राम, टच-मोशन इवेंट को जेस्चर डिटेक्टर के पास करता है
ndk_helper
क्लास में जेस्चर डिटेक्टर मल्टीटच को ट्रैक करता है
जेस्चर, जैसे कि पिंच करके खींचें और छोड़ें. साथ ही, अपने-आप ट्रिगर होने पर सूचना भेजता है
का इस्तेमाल किया जा सकता है.
if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION ) { ndk_helper::GESTURE_STATE doubleTapState = eng->doubletap_detector_.Detect( event ); ndk_helper::GESTURE_STATE dragState = eng->drag_detector_.Detect( event ); ndk_helper::GESTURE_STATE pinchState = eng->pinch_detector_.Detect( event ); //Double tap detector has a priority over other detectors if( doubleTapState == ndk_helper::GESTURE_STATE_ACTION ) { //Detect double tap eng->tap_camera_.Reset( true ); } else { //Handle drag state if( dragState & ndk_helper::GESTURE_STATE_START ) { //Otherwise, start dragging ndk_helper::Vec2 v; eng->drag_detector_.GetPointer( v ); eng->TransformPosition( v ); eng->tap_camera_.BeginDrag( v ); } // ...else other possible drag states... //Handle pinch state if( pinchState & ndk_helper::GESTURE_STATE_START ) { //Start new pinch ndk_helper::Vec2 v1; ndk_helper::Vec2 v2; eng->pinch_detector_.GetPointers( v1, v2 ); eng->TransformPosition( v1 ); eng->TransformPosition( v2 ); eng->tap_camera_.BeginPinch( v1, v2 ); } // ...else other possible pinch states... } return 1; }
ndk_helper
क्लास, वेक्टर-मैथ लाइब्रेरी का ऐक्सेस भी देती है
(vecmath.h
), टच निर्देशांकों को बदलने के लिए यहां इसका इस्तेमाल कर रहे हैं.
void Engine::TransformPosition( ndk_helper::Vec2& vec ) { vec = ndk_helper::Vec2( 2.0f, 2.0f ) * vec / ndk_helper::Vec2( gl_context_->GetScreenWidth(), gl_context_->GetScreenHeight() ) - ndk_helper::Vec2( 1.f, 1.f ); }
यह HandleCmd()
तरीका,
android_native_app_glue लाइब्रेरी में उपलब्ध है. मैसेज के बारे में ज़्यादा जानकारी पाने के लिए
इसका मतलब है, android_native_app_glue.h
में टिप्पणियां देखें और
.c
सोर्स फ़ाइलें.
void Engine::HandleCmd( struct android_app* app, int32_t cmd ) { Engine* eng = (Engine*) app->userData; switch( cmd ) { case APP_CMD_SAVE_STATE: break; case APP_CMD_INIT_WINDOW: // The window is being shown, get it ready. if( app->window != NULL ) { eng->InitDisplay(); eng->DrawFrame(); } break; case APP_CMD_TERM_WINDOW: // The window is being hidden or closed, clean it up. eng->TermDisplay(); eng->has_focus_ = false; break; case APP_CMD_STOP: break; case APP_CMD_GAINED_FOCUS: eng->ResumeSensors(); //Start animation eng->has_focus_ = true; break; case APP_CMD_LOST_FOCUS: eng->SuspendSensors(); // Also stop animating. eng->has_focus_ = false; eng->DrawFrame(); break; case APP_CMD_LOW_MEMORY: //Free up GL resources eng->TrimMemory(); break; } }
ndk_helper
कक्षा, android_app_glue
होने पर APP_CMD_INIT_WINDOW
पोस्ट करती है
सिस्टम से onNativeWindowCreated()
कॉलबैक मिलता है.
ऐप्लिकेशन आम तौर पर विंडो शुरू कर सकते हैं, जैसे कि EGL
शुरू करना. वे ऐसा गतिविधि लाइफ़साइकल के बाहर करते हैं, क्योंकि
गतिविधि अभी तक तैयार नहीं है.
//Init helper functions ndk_helper::JNIHelper::Init( state->activity, HELPER_CLASS_NAME ); state->userData = &g_engine; state->onAppCmd = Engine::HandleCmd; state->onInputEvent = Engine::HandleInput;