視頻教程請關注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440android
如何安裝安卓的開發環境以及怎麼設置ndk的環境變量等在前邊的文章已經有了詳細的講解,在這裏我就再也不說明,若是有不會安裝和設置環境的,請先參考安卓環境搭建的內容。c++
好,假設以及安裝好了ndk,使用純c++開發安卓程序,下邊是詳細的步驟與說明:windows
1.編寫入口函數數組
android_main爲入口函數,和C++中的main函數是同樣的。這裏建立CELLAndroidApp的對象,直接調用main函數。緩存
void android_main(struct android_app* state) { CELLAndroidApp app(state); app.main(0,0); }
說明:其中的 CELLAndroidApp是咱們設計的一個圖形繪製類,稍後將對其作詳細說明app
2.繪製類的實現說明ide
2.1類的成員說明函數
protected: EGLConfig _config; EGLSurface _surface; EGLContext _context; EGLDisplay _display; android_app* _app; int _width; int _height;
部分參數說明:oop
_surface:用於繪製圖形,至關於windows繪圖中的位圖this
_context:能夠看作是opengl對象
_display:用於繪圖的設備上下文,相似於windows繪圖中的dc
2.2 構造函數說明
CELLAndroidApp(android_app* app):_app(app) { _surface = 0; _context = 0; _display = 0; _width = 64; _height = 48; app->userData = this; //用戶數據 app->onAppCmd = handle_cmd; //窗口的建立銷燬等 app->onInputEvent = handle_input; //回調函數 }
值得注意的是,這裏的app中的userData,傳入用戶數據,這裏直接傳入this,onAppCmd傳入的handle_cmd回調函數,onInputEvent傳入的事handle_input回調函數
2.3 類中函數main()說明
virtual void main(int argc,char** argv) { int ident; int events; android_poll_source* source; while (true) { while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) { if (source != NULL) source->process(_app, source); //有觸摸事件,調用input函數,至關於dispatchmessage if (_app->destroyRequested != 0) return; } render(); } }
其中的android_poll_source至關於windows中的消息隊列,用於存放消息,這個函數中模擬了windows中的消息機制。
ALooper_pollAll()函數,用於獲取消息。值得注意的是第一個參數,若是第一個參數傳入0,則不等待,調用後直接返回,相似於windows消息機制中的pickMessage()函數,若是傳入-1,則相似於windows消息機制中的SendMessage()函數。 返回值:若是返回值大於大於等於0表示獲取到數據,若是爲-1則表示失敗,未獲取到數據。
其中發source若是不爲空,則表示有觸摸事件,則調用process()函數,至關於windows中調用dispatchMessage()函數。
最後,調用render()函數,繪製圖形。
2.4 初始化設備函數initDevice()
virtual void initDevice() { const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLint format; EGLint numConfigs; _display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(_display, 0, 0); eglChooseConfig(_display, attribs, &_config, 1, &numConfigs); eglGetConfigAttrib(_display, _config, EGL_NATIVE_VISUAL_ID, &format); ANativeWindow_setBuffersGeometry(_app->window, 0, 0, format); _surface = eglCreateWindowSurface(_display, _config, _app->window, NULL); #if 0 EGLint contextAtt[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE }; _context = eglCreateContext(_display, _config, 0, contextAtt); #else _context = eglCreateContext(_display, _config, 0, 0); #endif if (eglMakeCurrent(_display, _surface, _surface, _context) == EGL_FALSE) { LOGW("Unable to eglMakeCurrent"); return; } eglQuerySurface(_display, _surface, EGL_WIDTH, &_width); eglQuerySurface(_display, _surface, EGL_HEIGHT, &_height); onCreate(); // Initialize GL state. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glEnable(GL_CULL_FACE); glShadeModel(GL_SMOOTH); glDisable(GL_DEPTH_TEST); glViewport(0,0,_width,_height); glOrthof(0,_width,_height,0,-100,100); }
首先須要說明的是attribs數組,改數組中主要存儲了繪製圖形的一些屬性信息,他們是成對出現的,如EGL_SURFACE_TYPE則表示繪製圖形類型, EGL_WINDOW_BIT則表示繪製到窗口上。
eglGetDisplay()函數:表示獲取一個顯示設備
eglInitialize():表示初始化獲取到的顯示設備
eglChooseConfig():繪製屬性的配置
eglGetConfigAttrib():設置繪製格式
ANativeWindow_setBuffersGeometry():將格式應用到窗口
eglCreateWindowSurface():建立繪圖窗口
eglCreateContext():建立opengl的繪圖上下文
eglMakeCurrent():綁定到繪圖設備上下文
eglQuerySurface():獲取圖片的寬度和高度,具體獲取哪個根據最後一個參數肯定
glHint()、glEnable()和glOrthof()等函數則是與繪圖的投影相關的內容,包括初始化、設置模式等內容。
2.5 繪製函數render()
virtual void render() { if(_display == 0) { return; } glClearColor(0,0,0, 1); glClear(GL_COLOR_BUFFER_BIT); glEnableClientState(GL_VERTEX_ARRAY); if(g_arVertex.size() >= 2) { glColor4f(1,1,1,1); glVertexPointer(3,GL_FLOAT,0,&g_arVertex[0]); glDrawArrays(GL_LINE_STRIP,0,g_arVertex.size()); } eglSwapBuffers(_display,_surface); //雙緩存的交換緩衝區 }
render()函數主要用於繪製點,對主要的幾個函數作以下說明:
glClearColor():用於將屏幕清爲黑色
glClear():清空顏色緩衝區
glEnableClientState():啓動定點數組
glVertexPointer():制定定點緩衝區
glDrawArrays():繪製點數組
eglSwapBuffers():相似雙緩存的交換緩衝區
2.6 handle_cmd()函數
static void handle_cmd(android_app* app, int32_t cmd) { CELLAndroidApp* pThis = (CELLAndroidApp*)app->userData; pThis->cmd(app,cmd); }
2.7 handle_input()函數
static void handle_input(android_app* app, AInputEvent* event) { CELLAndroidApp* pThis = (CELLAndroidApp*)app->userData; pThis->input(app,event); }
2.8 input()函數
virtual int input(struct android_app* app, AInputEvent* event) { int32_t evtType = AInputEvent_getType(event); switch(evtType) { case AINPUT_EVENT_TYPE_KEY: break; case AINPUT_EVENT_TYPE_MOTION: { int32_t sourceId = AInputEvent_getSource(event); if(AINPUT_SOURCE_TOUCHSCREEN == sourceId) { int32_t id = AMotionEvent_getAction(event); switch(id) { case AMOTION_EVENT_ACTION_MOVE: { size_t cnt = AMotionEvent_getPointerCount(event); for( int i = 0 ;i < cnt; ++ i ) { float x = AMotionEvent_getX(event,i); float y = AMotionEvent_getY(event,i); float3 pt; pt.x = x; pt.y = y; pt.z = 0; g_arVertex.push_back(pt); } } break; case AMOTION_EVENT_ACTION_DOWN: { size_t cnt = AMotionEvent_getPointerCount(event); for( int i = 0 ;i < cnt; ++ i ) { float x = AMotionEvent_getX(event,i); float y = AMotionEvent_getY(event,i); } } break; case AMOTION_EVENT_ACTION_UP: { size_t cnt = AMotionEvent_getPointerCount(event); for( int i = 0 ;i < cnt; ++ i ) { float x = AMotionEvent_getX(event,i); float y = AMotionEvent_getY(event,i); } } break; } } else if(AINPUT_SOURCE_TRACKBALL == sourceId) { } } break; } return 0; }
該函數主要用於對輸入進行判斷,以肯定是吉鍵盤、鼠標或遙感等,根據具體輸入作相應的操縱,這裏就再也不作過多的說明
AMotionEvent_getPointerCount():若是是多點觸控,則將各個點保存到vector中。
2.9 cmd()函數
virtual int cmd(struct android_app* app, int32_t cmd) { switch(cmd) { case APP_CMD_SAVE_STATE: break; case APP_CMD_INIT_WINDOW: initDevice(); break; case APP_CMD_TERM_WINDOW: shutDownDevice(); break; case APP_CMD_GAINED_FOCUS: break; case APP_CMD_LOST_FOCUS: break; } return 0; }
根據傳入的命令,對窗口作相應的處理。
APP_CMD_INIT_WINDOW:表示初始化窗口
2.10 shutDownDevice()函數
virtual void shutDownDevice() { onDestroy(); if (_display != EGL_NO_DISPLAY) { eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (_context != EGL_NO_CONTEXT) { eglDestroyContext(_display, _context); } if (_surface != EGL_NO_SURFACE) { eglDestroySurface(_display, _surface); } eglTerminate(_display); } _display = EGL_NO_DISPLAY; _context = EGL_NO_CONTEXT; _surface = EGL_NO_SURFACE; }
關閉設備,主要是將與設備相關的綁定清除,釋放綁定。
編寫完上邊的代碼後,編譯程序,將程序導入到模擬器中,最終運行的效果圖以下:
好了,該說的基本都說玩了,下邊附上源碼地址,趕忙去嘗試吧: