
謎面: | 謎底: |
天生癩 | 星 |
地生毛 | 草 |
金脚带 | 『天河』即係『星河』 |
銀香爐 | 月 |
BOOKCARD
『assets讀文檔』, 如果有大量文檔,要逐壹畀文檔路徑蒞讀, 更佳係『assets』 裏邊.
將『文檔』擺係『檔案夾』. 然後遍歷『文檔』.
訪問『assets』檔案夾
AAssetDir * assetDir; |
開啟文檔夾, 『dir』係『assets』 裏邊
assetDir = AAssetManager_openDir(assetManager,dir); |
失敗返回NULL
if(assetDir == NULL) return false; |
遍歷文檔,
while((filename = AAssetDir_getNextFileName(assetDir)) != NULL) { |
組合『assets』『文檔』路徑.
sprintf(path, “%s/%s”, dir, filename); |
閂檔案夾
AAssetDir_close(assetDir); |
『萬事得3』褪車畀矮石碼, 刮花車左前門.
係填灰前需盡量修复明顯凹陷,減小填灰.
平整架餐『橋式修复』.
明顯凹陷填灰平整表層.淺刮痕跳過.
清洁
淺刮痕直接用,郡仕噴灰罐B524.
噴漆
『觸屏坐標』『x,y』坐標轉『正交投影』坐標, 『視錐體解像』寬高, 比例需手機解像寬高比壹致.
計屏幕寬高比
float aspect_ratio = (float)cam->real_width / (float)cam->real_height; |
『視錐體解像』寬高,此時定義『高』800pix
float frustum_width = 800 *aspect_ratio; |
float frustum_height = 800 ; |
『正交投影』代碼
重置視區尺寸, 值係手機解像寬高
::glViewport(0,0,real_width,real_height); |
設定投影矩陣
::glMatrixMode(GL_PROJECTION); |
載入單位矩陣
::glLoadIdentity(); |
正交投影, 游戲坐標原點(0,0,0)為於屏幕中心
glOrthof(frustum_width / 2, frustum_width / 2, -frustum_height / 2, frustum_height / 2, pos.y – 10, far_clip_z); |
設定模型視圖矩陣
::glMatrixMode(GL_MODELVIEW); |
載入單位矩陣
::glLoadIdentity(); |
手指触摸手機屏幕onTouch() 所得坐標需轉游戲世界坐標,正交投影OpenGL游㱆+Z軸指向屏幕深處.
float touch3Dx = (touch2Dx / real_width) * frustum_width ; |
float touch3Dz = (touch2Dy /real_height) * frustum_height ; |
計3D相機位置
touch3Dx = touch3Dx + camPosX; |
touch3Dz = touch3Dz + camPosX; |
游戲坐標原點(0,0,0)為於屏幕中心
touch3Dx = touch3Dx – (frustum_width / 2.0f); |
touch3Dz = touch3Dz – (frustum_height / 2.0f); |
『漢字字庫』同 『ASCII字庫』原理同, 字庫『竪排』, 漢字『32*32』pixel, 『竪』32漢字.
由上至下,由右至左排列.可填1024字符,每色8Bit. 即『索引色』『調色板』.
准備庫位圖
Photoshop轉為『索引色』
止時圖檔『調色板』共有三色『黑』『白』『透明』.
IMAGE-SIZE | 1024*1024 |
FONT-SIZE | 30pt |
FONT | 衡山毛筆フォント |
FONT-PIXEL | 32pixel*32pixel |
影像-模色 | 索引色 |
色盤 | 正確 |
顏色 | 3 |
强制 | 黑白 |
透明 | 勾選 |
『調色板』結构同DirextX唔同, 將flags存alpha『透明值』0~255,0係『透明』,255係『實心』
typedef struct PALETTE_TYP {
BYTE red; BYTE green; BYTE blue; BYTE flags;//alpha } PALETTE,COLOR,* PALETTE_PTR,*COLOR_PTR; |
設置『調色板』顏色
#define INIT_PALETTE(palette,r,g,b,a) {(palette).red=(r); (palette).green=(g); (palette).blue=(b); (palette).flags=(a);} |
黑字『調色板』設置
index | red | green | blue | Alpha |
253 | 0xff | 0xff | 0xff | 0x00 |
255 | 0x00 | 0x00 | 0x00 | 0xFF*0.5f |
白字『調色板』設置
index | red | green | blue | Alpha |
253 | 0x00 | 0x00 | 0x00 | 0x00 |
255 | 0xff | 0xff | 0xff | 0xFF*0.5f |
半透明,激活混合
glEnable(GL_BLEND); |
設混合模式, 渲染時Alpha值混合.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
激活透明测试
glEnable(GL_ALPHA_TEST); |
Alpha=0時, 過濾背影色
glAlphaFunc(GL_GREATER, 0); |
書法家『青柳衡山』揮毫. 登録漢字最多草書字庫. 約萬餘字,公開免費,商業領域冇制限使用.有『TrueType』『OpenType』版. 將『KouzanBrushFontSousyo.ttf』『KouzanSoushoOTF.otf』字庫複製係『C:\Windows\Fonts』
衡山毛筆フォント草書 (揮毫/青柳衡山) |
https://opentype.jp/kouzansousho.htm |
『經倫羅盤』需『漢字庫』, 書法家『青柳衡山』揮亳書寫. 登録萬三漢字.公開免費,商業領域冇制限使用.有『TrueType』『OpenType』版. 將『KouzanMouhituFont.ttf』『KouzanMouhituFontOTF.otf』字庫复制係『C:\Windows\Fonts』
衡山毛筆フォント |
https://opentype.jp/kouzanmouhitufont.htm |
C:\Windows\Fonts |
毛筆體 |
買Google nexus5『壹為神功,貳為弟子』,『壹蒞開發,貳還心愿』.機仔細細窄邊框.當年靚絕Android, 本蒞愛『Android 4』『黑蓋』寄蒞『Android 5』『白蓋』. 韓國LG制造港版,換新電包郵百肆蚊有找.部機吾升級係用吾到, 永遠話連吾到.
Google nexus5 | 簡介 |
屏 | 4.94英寸 |
解像 | 1920*1080 |
電 | 4000mAh |
相機 | 1310萬 |
CPU | 驍龍800 |
RAM | 2GB |
DISK | 32GB |
MODEL | LG-D821港版 |
初台Android手機己采用『單點』触摸, 直至Android2.0(SDK version 5) 先支持『多點』触摸.
static class TounchListener implements OnTouchListener{ |
@Override
public boolean onTouch(View v, MotionEvent event) { |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) |
MultiTouch(v, event); else |
SingleTouch(v, event); |
return false;} |
private static TounchListener Tounch_Listener = new TounchListener() ; |
view.setOnTouchListener(Tounch_Listener); |
MotionEvent.getX() | X軸指右 |
MotionEvent.getY() | Y軸指下 |
MotionEvent.getAction() | |
MotionEvent.ACTION_DOWN | 手指撳屏 |
MotionEvent.ACTION_POINTER_DOWN | 手指撳屏 |
MotionEvent.ACTION_UP | 手指鬆离 |
MotionEvent.ACTION_POINTER_UP | 手指鬆离 |
MotionEvent.ACTION_CANCEL | 手勢鬆 |
MotionEvent.ACTION_MOVE | 移動手指 |
public static int ACTION_UP = 1; | 鬆 |
public static int ACTION_DOWN = 2; | 撳 |
public static int ACTION_DRAGGED = 3; | 拖 |
處理『單點』触摸
static void SingleTouch(View v, MotionEvent event){ |
int action = event.getAction() & MotionEvent.ACTION_MASK; |
if(action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_DOWN) |
Lib.setTouch(ACTION_DOWN,event.getX(),event.getY());else |
if(action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_CANCEL) |
Lib.setTouch(ACTION_UP,event.getX(),event.getY());else |
if(action == MotionEvent.ACTION_MOVE) |
Lib.setTouch(ACTION_DRAGGED,event.getX(),event.getY());} |
處理『多點』触摸
int Pointer_Index = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT; |
MotionEvent.getX(index) | X軸指右 |
MotionEvent.getY(index) | Y軸指下 |
int action = event.getAction() & MotionEvent.ACTION_MASK; |
int Pointer_Index = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT; |
int Pointer_Count = event.getPointerCount(); |
for(int i=0; i< Pointer_Count; ++i) { |
if (action != MotionEvent.ACTION_MOVE && i != Pointer_Index)
continue; |
if(action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_DOWN) |
Lib.setTouch(ACTION_DOWN,event.getX(i),event.getY(i));else |
if(action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_CANCEL) |
Lib.setTouch(ACTION_UP,event.getX(i),event.getY(i));else |
if(action == MotionEvent.ACTION_MOVE) |
Lib.setTouch(ACTION_DRAGGED,event.getX(i),event.getY(i));} |
係C++緩存『触屏』信息Lib.setTouch();
typedef struct TOUCH_STR{ | |
int action; | 触屏類型 |
int x,y; | 触屏坐標 |
}TOUCH,*TOUCH_PTR; |
『触屏座標』轉『熒屏座標』
void TouchToScreen(CAMERA2D_PTR cam,VECTOR2D_PTR touch){ |
touch->x = (touch->x / (float)cam->real_width) * cam->frustum_width * cam->zoom; |
touch->y = (1-touch->y /(float)cam->real_height) * cam->frustum_height * cam->zoom; } |
『Canon PRINT Business』運作需裝『Canon Print Service』,可直接發指今掃描影印『文檔』『圖檔』.
『Mopria Paint』係Android手機平板發影印指令. 如果『Mopria Paint』報『ERROR CODE 853』, 可嘗試『Canon Print Service』,Canon專用Android影印機程式. 同『Mopria Paint』係『外掛程式』後台臺運行, 向Canon發影印指令.
份數 | 1 |
紙張尺碼 | ISO A4 |
色彩 | 黑色/彩色 |
方向 | 縱向/橫向 |
雙面 | 無/長邊/短邊 |
全屏令人沉浸游戲免受干擾. 收埋頂『狀態』『標題』底『導航』.
requestWindowFeature(Window.FEATURE_NO_TITLE); |
Window window = getWindow(); |
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); |
setContentView(R.layout.activity_main); |
<style name=”Theme.Fullscreen” parent=”android:Theme.NoTitleBar.Fullscreen” /> |
<application android:theme=”@style/Theme.Fullscreen” > |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) |
View decorView = window.getDecorView(); |
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN); |
setSystemUiVisibility() | 簡述 |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | 飛底『導航』 |
View.SYSTEM_UI_FLAG_FULLSCREEN | 飛頂『狀態』 |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | 自動恢復『沉㓎模式』 |
View.SYSTEM_UI_FLAG_IMMERSIVE | 『沉㓎模式』 |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { |
WindowManager.LayoutParams param = window.getAttributes(); |
param.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; |
window.setAttributes(param);} |
layoutInDisplayCutoutMode | 簡述 |
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT | 全屏唔延伸至『兔唇 』, 非全屏延伸至『兔唇 』 |
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER | WINDOW唔延伸至『兔唇 』 |
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES | 窻口延伸至『兔唇 』 |
Android 螢幕耗電, 擺低手機螢幕變暗,幷鎖定. 好似你唔惏野會放蚊咁.用『喚醒鎖』WakLock. 保持清醒『螢幕喚醒』.
<uses-permission android:name=”android.permission.WAKE_LOCK” /> |
PowerManager powerManager; |
powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); |
PowerManager.WakeLock wakeLock; |
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, “WAKE LOCK”); |
wakeLock.acquire(); |
wakeLock.release(); |
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); |
係游戲渲染文本,『點陣字體』係遠古技術, 係位圖繪畫ASCII字符, 哎『位圖字符glyph』,標准ASCII字符128,有96拉丁字母可渲染,從32到126.『32』係『吉格』.
位圖每行16字符. 位圖寬高符合2n.位圖『256256』每字符『1616』像素, 位圖『512512』每字符『3232』像素.
定義位圖字符
typedef struct FONT_TYP{ | |
TEXTURE_PTR texture; | 字庫紋理 |
DWORD flag; | 頂點標記 |
TEXTURE_REGION region[96]; | 紋理區域 |
}FONT, * FONT_PTR; |
for(int index = 0; index < 96; ++index){ |
Init_Region_Texture(&font->region[index],font->texture,x,y, width, height); |
x = x + width; |
if(x >= offsetX + width * row){
x = offsetX; y = y + height;} |
渲染位圖字庫
VECTOR2D vertex_array[6 * 1024] ; |
VECTOR2D texCoord_array[6 * 1024] ; |
glEnable(GL_TEXTURE_2D); |
glDisable(GL_NORMALIZE); |
glEnable(GL_ALPHA_TEST); |
glAlphaFunc(GL_GREATER, 0); |
TEXTURE_PTR texture = font->texture;
glBindTexture(GL_TEXTURE_2D, texture->ID); |
glEnableClientState(GL_VERTEX_ARRAY); |
glEnableClientState(GL_TEXTURE_COORD_ARRAY); |
因為OpenGL『2D相機』原點『0,0』係『左下角』, 返䡛Y軸.
y = Font_frustum_height – y – height; |
for(int index = 0; index < length; ++index ){ |
int c = text[index] – ‘ ‘; |
if(c < 0 || c > 96) continue; |
TEXTURE_REGION_PTR region = &font->region[c]; |
Init_VECTOR2D(&vertex_array[0 * 3 + 0], x, y + height);
Init_VECTOR2D(&vertex_array[0 * 3 + 1], x + width, y + height); Init_VECTOR2D(&vertex_array[0 * 3 + 2], x + width, y); Init_VECTOR2D(&vertex_array[1 * 3 + 0], x, y + height); Init_VECTOR2D(&vertex_array[1 * 3 + 1], x + width, y); Init_VECTOR2D(&vertex_array[1 * 3 + 2], x, y); |
Init_VECTOR2D(&texCoord_array[0 * 3 + 0], region->u1, region->v2);
Init_VECTOR2D(&texCoord_array[0 * 3 + 1], region->u2, region->v2); Init_VECTOR2D(&texCoord_array[0 * 3 + 2], region->u2, region->v1); Init_VECTOR2D(&texCoord_array[1 * 3 + 0], region->u1, region->v2); Init_VECTOR2D(&texCoord_array[1 * 3 + 1], region->u2, region->v1); Init_VECTOR2D(&texCoord_array[1 * 3 + 2], region->u1, region->v1); |
glVertexPointer(2, GL_FLOAT, 0, vertex_array); |
glTexCoordPointer(2, GL_FLOAT, 0, texCoord_array); |
glDrawArrays(GL_TRIANGLES, 0, 2 * 3 ); |
if(VH == FONT_HORIZONTAL)
x = x + width; else if(VH == FONT_VERTICAL) y = y + height;} |
glDisable(GL_ALPHA_TEST); |
glPopMatrix(); |
ASCII數字 | 字符 |
0–31 | 控制字元,用于控制印表機等周邊設備 |
32-126 | 鍵盤字符 |
127 | DELETE 命令 |
48-57 | 0-9 |
65-90 | A-Z |
97-122 | a-z |
128-255 | 擴展ASCII,增加特殊符號字符, 歐語字母和圖形符號 |
Photoshop位圖字符glyph | |
Pixel | 32*32 |
Font | Terminal Regular |
Size | 4pt |
mid | |
Aa |
十進制(DEC) | 十六進制(HEX) | ASCII字符 | 簡介 |
0 | 0x00 | 空格NUL(null) | |
1 | 0x01 | 標題開始 SOH(start of headling) | |
2 | 0x02 | 正文開始 STX (start of text) | |
3 | 0x03 | 正文結束 ETX (end of text) | |
4 | 0x04 | 傳輸結束 EOT (end of transmission) | |
5 | 0x05 | 請求 ENQ (enquiry) | |
6 | 0x06 | 收到通知 ACK (acknowledge) | |
7 | 0x07 | 響鈴 BEL (bell) | |
8 | 0x08 | 退格 BS (backspace) | |
9 | 0x09 | 水準跳位字元 HT (horizontal tab) | |
10 | 0x0A | 換行鍵 LF (NL line feed, new line) | |
11 | 0x0B | 垂直跳位字元 VT (vertical tab) | |
12 | 0x0C | 換頁鍵 FF (NP form feed, new page) | |
13 | 0x0D | 回車鍵 CR (carriage return) | |
14 | 0x0E | 不用切換 SO (shift out) | |
15 | 0x0F | 啟用切換 SI (shift in) | |
16 | 0x10 | 資料連結轉義DLE (data link escape) | |
17 | 0x11 | 設備控制1 DC1 (device control 1) | |
18 | 0x12 | 設備控制2 DC2 (device control 2) | |
19 | 0x13 | 設備控制3 DC3 (device control 3) | |
20 | 0x14 | 設備控制4 DC4 (device control 4) | |
21 | 0x15 | 拒絕接收 NAK (negative acknowledge) | |
22 | 0x16 | 同步空閒 SYN (synchronous idle) | |
23 | 0x17 | 傳輸塊結束 ETB (end of trans. block) | |
24 | 0x18 | 取消 CAN (cancel) | |
25 | 0x19 | EM (end of medium) | |
26 | 0x1A | 替補 SUB (substitute) | |
27 | 0x1B | 溢出 ESC (escape) | |
28 | 0x1C | 檔分割符 FS (file separator) | |
29 | 0x1D | 分組符 GS (group separator) | |
30 | 0x1E | 記錄分離符 RS (record separator) | |
31 | 0x1F | 單元分隔符號 US (unit separator) | |
32 | 0x20 | 空格 (space) | |
33 | 0x21 | ! | 嘆號 |
34 | 0x22 | “ | 雙引號 |
35 | 0x23 | # | 井號 |
36 | 0x24 | $ | 美元符 |
37 | 0x25 | % | 百分號 |
38 | 0x26 | & | 和號 |
39 | 0x27 | ‘ | 閉單引號 |
40 | 0x28 | ( | 開括弧 |
41 | 0x29 | ) | 閉括弧 |
42 | 0x2A | * | 星號 |
43 | 0x2B | + | 加號 |
44 | 0x2C | , | 逗號 |
45 | 0x2D | – | 減號/破折號 |
46 | 0x2E | . | 句號 |
47 | 0x2F | / | 斜杠 |
48 | 0x30 | 0 | |
49 | 0x31 | 1 | |
50 | 0x32 | 2 | |
51 | 0x33 | 3 | |
52 | 0x34 | 4 | |
53 | 0x35 | 5 | |
54 | 0x36 | 6 | |
55 | 0x37 | 7 | |
56 | 0x38 | 8 | |
57 | 0x39 | 9 | |
58 | 0x3A | : | 冒號 |
59 | 0x3B | ; | 分號 |
60 | 0x3C | < | 小於 |
61 | 0x3D | = | 等號 |
62 | 0x3E | > | 大於 |
63 | 0x3F | ? | 問號 |
64 | 0x40 | @ | 電子郵件符號 |
65 | 0x41 | A | |
66 | 0x42 | B | |
67 | 0x43 | C | |
68 | 0x44 | D | |
69 | 0x45 | E | |
70 | 0x46 | F | |
71 | 0x47 | G | |
72 | 0x48 | H | |
73 | 0x49 | I | |
74 | 0x4A | J | |
75 | 0x4B | K | |
76 | 0x4C | L | |
77 | 0x4D | M | |
78 | 0x4E | N | |
79 | 0x4F | O | |
80 | 0x50 | P | |
81 | 0x51 | Q | |
82 | 0x52 | R | |
83 | 0x53 | S | |
84 | 0x54 | T | |
85 | 0x55 | U | |
86 | 0x56 | V | |
87 | 0x57 | W | |
88 | 0x58 | X | |
89 | 0x59 | Y | |
90 | 0x5A | Z | |
91 | 0x5B | [ | 開方括號 |
92 | 0x5C | \ | 反斜杠 |
93 | 0x5D | ] | 閉方括號 |
94 | 0x5E | ^ | 脫字元 |
95 | 0x5F | _ | 下劃線 |
96 | 0x60 | ` | 開單引號 |
97 | 0x61 | a | |
98 | 0x62 | b | |
99 | 0x63 | c | |
100 | 0x64 | d | |
101 | 0x65 | e | |
102 | 0x66 | f | |
103 | 0x67 | g | |
104 | 0x68 | h | |
105 | 0x69 | i | |
106 | 0x6A | j | |
107 | 0x6B | k | |
108 | 0x6C | l | |
109 | 0x6D | m | |
110 | 0x6E | n | |
111 | 0x6F | o | |
112 | 0x70 | p | |
113 | 0x71 | q | |
114 | 0x72 | r | |
115 | 0x73 | s | |
116 | 0x74 | t | |
117 | 0x75 | u | |
118 | 0x76 | v | |
119 | 0x77 | w | |
120 | 0x78 | x | |
121 | 0x79 | y | |
122 | 0x7A | z | |
123 | 0x7B | { | 開花括弧 |
124 | 0x7C | | | 垂線 |
125 | 0x7D | } | 閉花括弧 |
126 | 0x7E | ~ | 波浪號 |
127 | 0x7F | 刪除DEL(DELETE) | |
128 | 0x80 | Ç | Ccedil |
129 | 0x81 | ü | uuml |
130 | 0x82 | é | eacute |
131 | 0x83 | â | circ |
132 | 0x84 | ä | auml |
133 | 0x85 | à | agrave |
134 | 0x86 | å | aring |
135 | 0x87 | ç | ccedil |
136 | 0x88 | ê | ecirc |
137 | 0x89 | ë | euml |
138 | 0x8A | è | egrave |
139 | 0x8B | ï | iuml |
140 | 0x8C | î | icirc |
141 | 0x8D | ì | igrave |
142 | 0x8E | Ä | Auml |
143 | 0x8F | Å | ring |
144 | 0x90 | É | Eacute |
145 | 0x91 | æ | aelig |
146 | 0x92 | Æ | AElig |
147 | 0x93 | ô | ocirc |
148 | 0x94 | ö | ouml |
149 | 0x95 | ò | ograve |
150 | 0x96 | û | ucirc |
151 | 0x97 | ù | ugrave |
152 | 0x98 | ÿ | yuml |
153 | 0x99 | Ö | Ouml |
154 | 0x9A | Ü | Uuml |
155 | 0x9B | ¢ | 美分(cent) |
156 | 0x9C | £ | 英磅(pound) |
157 | 0x9D | ¥ | 日元(yen) |
158 | 0x9E | ₧ | |
159 | 0x9F | ƒ | |
160 | 0xA0 | á | aacute |
161 | 0xA1 | í | iacute |
162 | 0xA2 | ó | oacute |
163 | 0xA3 | ú | uacute |
164 | 0xA4 | ñ | ntilde |
165 | 0xA5 | Ñ | Ntilde |
166 | 0xA6 | ª | |
167 | 0xA7 | º | |
168 | 0xA8 | ¿ | |
169 | 0xA9 | ⌐ | |
170 | 0xAA | ¬ | |
171 | 0xAB | ½ | |
172 | 0xAC | ¼ | |
173 | 0xAD | ¡ | |
174 | 0xAE | « | |
175 | 0xAF | » | |
176 | 0xB0 | ░ | |
177 | 0xB1 | ▒ | |
178 | 0xB2 | ▓ | |
179 | 0xB3 | │ | |
180 | 0xB4 | ┤ | |
181 | 0xB5 | ╡ | |
182 | 0xB6 | ╢ | |
183 | 0xB7 | ╖ | |
184 | 0xB8 | ╕ | |
185 | 0xB9 | ╣ | |
186 | 0xBA | ║ | |
187 | 0xBB | ╗ | |
188 | 0xBC | ╝ | |
189 | 0xBD | ╜ | |
190 | 0xBE | ╛ | |
191 | 0xBF | ┐ | |
192 | 0xC0 | └ | |
193 | 0xC1 | ┴ | |
194 | 0xC2 | ┬ | |
195 | 0xC3 | ├ | |
196 | 0xC4 | ─ | |
197 | 0xC5 | ┼ | |
198 | 0xC6 | ╞ | |
199 | 0xC7 | ╟ | |
200 | 0xC8 | ╚ | |
201 | 0xC9 | ╔ | |
202 | 0xCA | ╩ | |
203 | 0xCB | ╦ | |
204 | 0xCC | ╠ | |
205 | 0xCD | ═ | |
206 | 0xCE | ╬ | |
207 | 0xCF | ╧ | |
208 | 0xD0 | ╨ | |
209 | 0xD1 | ╤ | |
210 | 0xD2 | ╥ | |
211 | 0xD3 | ╙ | |
212 | 0xD4 | Ô | |
213 | 0xD5 | ╒ | |
214 | 0xD6 | ╓ | |
215 | 0xD7 | ╫ | |
216 | 0xD8 | ╪ | |
217 | 0xD9 | ┘ | |
218 | 0xDA | ┌ | |
219 | 0xDB | █ | |
220 | 0xDC | ▄ | |
221 | 0xDD | ▌ | |
222 | 0xDE | ▐ | |
223 | 0xDF | ▀ | |
224 | 0xE0 | α | 阿爾法(Alpha) |
225 | 0xE1 | ß | 貝塔(beta) |
226 | 0xE2 | Γ | Gamma |
227 | 0xE3 | π | 圓周率(pi) |
228 | 0xE4 | Σ | sigma |
229 | 0xE5 | σ | sigma |
230 | 0xE6 | µ | mu |
231 | 0xE7 | τ | tau |
232 | 0xE8 | Φ | PHi |
233 | 0xE9 | Θ | Theta |
234 | 0xEA | Ω | 歐米伽(Omega) |
235 | 0xEB | δ | Delta |
236 | 0xEC | ∞ | 無窮 |
237 | 0xED | φ | phi |
238 | 0xEE | ε | epsilon |
239 | 0xEF | ∩ | |
240 | 0xF0 | ≡ | |
241 | 0xF1 | ± | |
242 | 0xF2 | ≥ | |
243 | 0xF3 | ≤ | |
244 | 0xF4 | ⌠ | |
245 | 0xF5 | ⌡ | |
246 | 0xF6 | ÷ | |
247 | 0xF7 | ≈ | |
248 | 0xF8 | ≈ | |
249 | 0xF9 | ∙ | |
250 | 0xFA | · | |
251 | 0xFB | √ | |
252 | 0xFC | ⁿ | |
253 | 0xFD | ² | |
254 | 0xFE | ■ | |
255 | 0xFF | ÿ |
係2D游戲位圖愛蒞做動畫, 要過濾『背景色』, 係Android OpenGL ES用alpha屏蔽『背景色』, 壹法位圖『A分量』Alpha = 0, 貳法黑色定為『背景色』係載入時將『A分量』Alpha = 0. 所以兩法要係『GL_RGBA』模式運運作.
RGBA8888位圖,RGB占24bit, Alpha 值A占8bit, 透明度範圍『0~255』. 『0』通透.『 255』實體.
設Alpha值 | 通透 | 實體 |
glAlphaFunc() | 0.0 | 1.0 |
glAlphaFuncx() | 0 | 255 |
若位圖冇Alpha 值, OpenGL ES 係載入時將Alpha值設1.
BGRA8888/ARGB8888 | Alpha = 0 |
RGB656,RGB888,index | R=0,G=0,B=0, 黑色 |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width , height , 0, GL_RGBA, GL_UNSIGNED_BYTE, image); |
glEnable(GL_ALPHA_TEST); |
glAlphaFunc(GL_GREATER, 0); |
glAlphaFuncx(GL_GREATER, 0); |
OpenGL有『平行投影』同『透視投影』, 2D相機係『平行投影』生成方盒『視體』, 愛蒞剪裁物體, 唔係『視體』內唔『渲染』. 愛蒞『等比例游戲』『平面游戲』
OpenGL『2D相機』原點『0,0』係『左下角』, z軸遠端係負,近端正.
Android『熒屏』原點『0,0』係『左上角』,
glMatrixMode(GL_PROJECTION); |
glLoadIdentity(); |
glViewport(x, y, window_width, window_height); |
glOrthof (left,right,bottom,top,near,far); |
glOrthof (0, frustum_width, 0, frustum_height, 1, -1); |
glOrthof (x- width/2, x+width/x, y-height/2, y+height/2, 1, -1); |
glOrthof() | |
『left, bottom』 | 左下角『0, 0』 |
『right, top』 | 右上角『width, height』 |
near | z軸近端剪裁面 |
far | z軸遠端剪裁面 |
glMatrixMode(GL_MODELVIEW); |
glLoadIdentity(); |
示例
void Projection_Camera2D(CAMERA2D_PTR cam){
// 重置視區尺寸 ::glViewport(0,0,cam->real_width,cam->real_height); // 設爲投影矩陣 ::glMatrixMode(GL_PROJECTION); // 載入單位矩陣 ::glLoadIdentity(); // 正交投影 glOrthof (0, cam->frustum_width, 0, cam->frustum_height, 1, -1); // 設定模型視圖矩陣 ::glMatrixMode(GL_MODELVIEW); // 載入單位矩陣 ::glLoadIdentity(); } |
『JavaVM』指『Java虛擬機』, 壹進程『Process』壹『JavaVM』, 冚辦爛線程『Thread』共用壹『JavaVM』.
係原生代碼獲得『Java虛擬機』, 通過『JNI_OnLoad ()』函式, 載入共享庫『System.loadLibrary(“lib”);』,載入『LIB.SO』 會自動調用『JNI_OnLoad ()』. 將javaVm以全域變量儲存.
緩存JavaVM接口指針
JavaVM javaVm; |
jint JNI_OnLoad (JavaVM* vm, void* reserved){
javaVm = vm; return JNI_VERSION_1_4; } |
加入『jni.h』頭文檔聲明『Java原生接口』
#include <jni.h> |
『JNI』指『Java Native Interface』『Java原生接口』,實現『JavaVM』同『Native』通信.『Java代碼』同『原生代碼』調用.
『JNIEnv』指向當前『線程局部數據』, 『線程局部數據』內含『原生函式指針列表』. 壹線程『thread』壹『JNIEnv』. 唔得跨線程『thread』傳遞彼此獨立,
事因『POSIX線程』唔屬于『JAVA』平臺, 導致『JAVA虛擬機』冇發識別『POSIX線程』, 為咗訪問『JAVA虛擬機』,『POSIX線程』線程先附係『JAVA虛擬機』再行.
if(javaVm->AttachCurrentThread(&env,NULL) == 0) |
if(javaVm->DetachCurrentThread() == 0) |
Android_Studio_NDK_POSIX_Thread
Android Studio NDK-POSIX線程
『Android Studio NDK』生成『C/C++』線程,使用 POSIX線程簡稱『Pthreads』. 儒略歷1995年發布POSIX.1c『標准』『擴展』綫程.為線程定義『創建』『處理』API.『Micrsoft Windows』『Mac OS X』『Linux』冚辬蘭支持POSIX線程.
事因『POSIX線程』唔屬于『JAVA』平臺, 導致『JAVA虛擬機』冇發識別『POSIX線程』, 為咗訪問『JAVA虛擬機』,『POSIX線程』線程先附係『JAVA虛擬機』再行.
#include <pthread.h> // POSIX線程 |
#include <jni.h> |
int pthread_create(pthread_t * thread,
pthread_attr_t const * attr, void *(* start_routine)(void *), void * arg); |
參數 | 簡介 |
thread | 返回新建綫程句柄 |
attr | 指定線程屬性,傅NULL使用默認值. |
start_routine | 指向綫程函式地址, |
args | 線程函式參數 |
0 | 線程啟動 |
Error code | 錯誤碼 |
pthread_t threadID; |
typedef struct OPENGL_TYP{
JNIEnv *env;// JNI AAssetManager * aassetManager;// 資源管理 EGLDisplay display ; EGLSurface surface;// 內核渲染表層 int Width, Height;// 熒屏寬高 }OPENGL,*OPENGL_PTR; |
void * start_rountine (void * args) |
void * run_game(void * param){
while (run == true) { Update_World();// 更新 Draw_World();// 繪畫 } } |
jint JNI_OnLoad (JavaVM* vm, void* reserved){
javaVm = vm; return JNI_VERSION_1_4; } |
if(javaVm->AttachCurrentThread(&env,NULL) == 0) |
if(javaVm->DetachCurrentThread() == 0) |
if( pthread_create(&threadID, NULL, run_game, openGL) == 0)
return true; else return false; |
void * run_game(void * param){
// 將線程附著係JAVA虛擬機, if(javaVm->AttachCurrentThread(&env,NULL) != 0) return NULL; Init_Engine( ); // 初此引擎 Init_World( ); // 初此游戲世界 while (run == true) { Update_World();// 更新 Draw_World();// 繪畫 } Shutdown_World();// 閂游戲世界 Shutdown_Engine(); // 閂引擎 // 係JAVA虛擬機分離綫程 javaVm->DetachCurrentThread(); return NULL; } |
之前係『JAVA Thread』行『ANativeWindow_fromSurface()』冇事,係『C/C++ Thread』行『ANativeWindow_fromSurface()』死機. 暈得壹陣陣.
係『Android OpenGL ES』用『SurfaceView』蒞畀『OpenGL ES』渲染. 之前『SurfaceView』代碼擺係『MainActivity.java』.更佳方法係『SurfaceView』『Runnable』『SurfaceHolder.Callback』封裝成單獨『GameView calss』.以保持代碼『簡潔』同埋『重用』.
『File->New->Java Class』 |
public class GameView extends SurfaceView implements Runnable,SurfaceHolder.Callback{ |
int view_width,view_height;
public SurfaceHolder surfaceHolder; public Surface surface;//用蒞渲染 |
public GameView(Context context) {
super(context); init(context);// 設置渲染 } |
public GameView(Context context, AttributeSet attrs) {
super(context); init(context);// 設置渲染 } |
public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context); init(context);// 設置渲染 } |
public void init(Context context){
this.surfaceHolder = getHolder(); this.surfaceHolder.addCallback(this); this.surface = surfaceHolder.getSurface(); } |
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder){ new Thread(this).start(); } |
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height){ view_width = width; view_height = height; } |
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) { } |
@Override
public void run() { AssetManager assetManager = getContext().getAssets(); Lib.init(assetManager, surface, view_width, view_height); while (true) {// 請求渲染 Lib.update(); } } |
Android Java原生接口(JNI) 令 『Java』 同『C\C++』代碼相互調用. 之前係『MainActivity.java』声明『native』原生代碼接口.
static public native String stringFromJNI(); |
『native-lib.cpp』『C\C++』代碼, 它編譯共享庫『.so』檔
extern “C” JNIEXPORT jstring JNICALL
Java_net_bookcard_compass_MainActivity_stringFromJNI(JNIEnv* env,jobject this) { return env->NewStringUTF(“native-lib”) ; } |
缺點係只能『MainActivity.java』調用, 更佳方發係將原生代碼接口擺係單獨『Java Class』. 并声明為『static』, 可係任意位置調用『C\C++』代碼.
『File』->『New』->『Java Class』 |
static {
System.loadLibrary(“geomanticcompass”); } |
static public native String stringFromJNI(); |
『GPS』全球定位代碼,係『eclipse』移過蒞『Android Studio』, 發現getBestProvider()返回NULL. 源於冇『權限』 , 而『Android 6』後要人手獲得授權, 冇『權限』getBestProvider()永遠返回null. 係程式啟動檢查『權限』, 若冇『權限』提出請求伸請.
string GetBestProvider (Criteria criteria, bool enabledOnly) |
『GPS』定位伸請『權限』
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”/> |
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/> |
『權限』
Manifest.permission.ACCESS_FINE_LOCATION | 高精度定位 |
Manifest.permission.ACCESS_COARSE_LOCATION | 低精度定位 |
檢查『權限』
int coarse = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION); |
int fine = ContextCompat.checkSelfPermission(context,Manifest.permission.ACCESS_FINE_LOCATION); |
返回值判斷係咪獲得『權限』
PackageManager.PERMISSION_GRANTED | 有『權限』 |
PackageManager.PERMISSION_DENIED | 冇『權限』 |
判斷有冇『權限』
if(coarse == PackageManager.PERMISSION_DENIED || fine == PackageManager.PERMISSION_DENIED ) |
請求伸請. context必需係Activity
String permission[] = new String[] { Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION}; |
ActivityCompat.requestPermissions((Activity) context,permission,REQUEST_CODE_GPS); |
GPS權限請求碼
public static int REQUEST_CODE_GPS = 156; |
處理GPS授權回調, 係MainActivity判斷授權
@Override
public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults){ |
requestCode係權限請求碼
if(requestCode == GPS.REQUEST_CODE_GPS) {// 羅盤權限請求碼 |
判斷『權限』係咪獲得
if(grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED) { // 獲得授權 |
再次定位
GPS.UpdatesLocation(); |
交翻畀onRequestPermissionsResult()處理
super.onRequestPermissionsResult(requestCode,permissions,grantResults);
} |
3D游戲基于『透視投影』產生立體效果, 而2D游戲戲用『正交投影』產生平面效果, 生成等比例游戲.
glViewport(0,0,width, height); |
glMatrixMode(GL_PROJECTION); |
glLoadIdentity(); |
gluOrtho( fovy, aspect, zNear, zFar ); |
glMatrixMode(GL_MODELVIEW); |
glLoadIdentity(); |
基於視角『正交投影』
void gluOrtho(double fovy,double aspect,double zNear,double zFar){
double xmin, xmax, ymin, ymax; ymax = zNear * tan(fovy * 3.141592654f / 360.0f); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; glOrthof(xmin, xmax, ymin, ymax, zNear, zFar); } |
Android Studio設置全屏,通過編輯『themes.xml』
『themes.xml』 |
<style name=”Theme.Fullscreen” parent=”android:Theme.NoTitleBar.Fullscreen”> |
編輯『AndroidManifest.xml』
『AndroidManifest.xml』 |
<application android:theme=”@style/Theme.Fullscreen”> |
代碼係『eclipse』移稙過蒞, 『Android Studio』程式閃退. 因『MainActivity』繼承『AppCompatActivity』造成. 改為繼承『Activity』.
public class MainActivity extends Activity |
OpenGL EGL作為平臺冇関 API, 今程序冇視『Linux X Window』『Microsoft Windows』『Mac OS X Quatz』差異.用統壹接口同原生視窗聯接. 跨平臺API更易於移值. 所以OpenGL比DirectX更得人鐘意.
#include <GLES/gl.h> | 標準OpenGL頭文檔 |
#include <GLES/glext.h> | OpenGL實用架餐庫 |
#include <EGL/egl.h> | EGL庫 |
#include <EGL/eglext.h> | EGL架餐庫 |
#include <android/native_window_jni.h> | 原生視窗庫ANativeWindow |
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
EGL_NO_DISPLAY | 0失敗 |
EGLint major,minor;
eglInitialize(display,&major,&minor) ; |
EGL_BAD_DISPLAY | 非有效EGLDisplay |
EGL_NOT_INITALIZED | 未能初始 |
EGLBoolean eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); |
參數 | 簡介 |
EGLDisplay dpy | 『原生視窗』索引 |
EGLint *attrib_list | 指定屬性列表, 以EGL_NONE結屘 |
EGLConfig *configs | 返回配置列表 |
EGLint config_size | 指定配置列表長度 |
EGLint *num_config | 返回配置長度 |
屬性 | 描述 | 值 |
EGL_SURFACE_TYPE | EGL渲染表面類型 | EGL_WINDOW_BIT |
EGL_RENDERABLE_TYPE | OpenGL版本 | EGL_OPENGL_ES_BIT |
EGL_RED_SIZE | 紅色量位 | 8Bit |
EGL_GREEN_SIZE | 綠色量位 | 8Bit |
EGL_BLUE_SIZE | 藍色量位 | 8Bit |
EGL_ALPHA_SIZE | 透明量位 | 8Bit |
EGL_DEPTH_SIZE | 深度量位 | 16Bit |
EGL_NONE | 屬性列表以EGL_NONE結屘 | 0 |
屬性列表
EGLint attrib_array[32]; |
attrib_array[0] = EGL_SURFACE_TYPE; | attrib_array[1] = EGL_WINDOW_BIT; |
attrib_array[2] = EGL_RENDERABLE_TYPE; | attrib_array[3] = EGL_OPENGL_ES_BIT; |
attrib_array[4] = EGL_RED_SIZE; | attrib_array[5] = 8; |
attrib_array[6] = EGL_GREEN_SIZE; | attrib_array[7] = 8, |
attrib_array[8] = EGL_BLUE_SIZE; | attrib_array[9] = 8; |
attrib_array[10] = EGL_ALPHA_SIZE; | attrib_array[11] = 8; |
attrib_array[12] = EGL_DEPTH_SIZE; | attrib_array[13] = 16; |
attrib_array[14] = EGL_NONE; |
EGLint config_number = 32;
EGLConfig config_array[32]; EGLConfig config;// 配置 eglChooseConfig(display,attrib_array,config_array,config_number,&config_number); |
for(int i=0;i<config_number;++i) {
eglGetConfigAttrib(openGL->display, config_array[i],EGL_RED_SIZE, &red); eglGetConfigAttrib(openGL->display, config_array[i],EGL_GREEN_SIZE, &green); eglGetConfigAttrib(openGL->display, config_array[i],EGL_BLUE_SIZE, &blue); eglGetConfigAttrib(openGL->display, config_array[i],EGL_ALPHA_SIZE, &alpha); eglGetConfigAttrib(openGL->display, config_array[i],EGL_DEPTH_SIZE, &depth); if( red == 8 && green == 8 && blue == 8 && alpha == 8 && depth == 16){ openGL->config = config_array[i];// 最佳配置 break; } } |
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); |
參數 | 簡介 |
EGLDisplay dpy | 『原生視窗』索引 |
EGLConfig config | 最佳配置 |
EGLNativeWindowType win | SurfaceView |
const EGLint *attrib_list | 屬性列表 |
視窗屬性 | 描述 | 值 |
EGL_RENDER_BUFFER | 渲染緩存 | EGL_SINGLE_BUFFER『單緩存』EGL_BACK_BUFFER『雙緩存』 |
EGL_NONE | 屬性列表以EGL_NONE結屘 | 0 |
attrib_array[0] = EGL_RENDER_BUFFER; | attrib_array[1] = EGL_BACK_BUFFER; |
attrib_array[2] = EGL_NONE; |
surface_draw = eglCreateWindowSurface(display,config,nativeWindow,attrib_array); |
錯誤碼EGLint error = eglGetError(); | 簡介 |
EGL_BAD_MATCH | 視窗唔匹配EGLConfig唔支持渲染 |
EGL_BAD_CONFIG | 視窗唔匹配EGLConfig系統晤支持 |
EGL_BAD_NATIVE_WINDOW | 原生視窗句柄冇效 |
EGL_BAD_ALLOC | 冇法分配資源 |
eglMakeCurrent(display,surface_draw,surface_draw,context); |
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) |
SurfaceView surfaceView = (SurfaceView)findViewById(R.id.surface_view); |
SurfaceHolder surfaceHolder = surfaceView.getHolder(); |
surfaceHolder.addCallback(this); |
Surface surface = surfaceHolder.getSurface(); |
『Android Studio NDK』提供『EGL』連接『OpenGL』, 『EGL』被設計出來,作爲 OpenGL 和原生窗口系統之間的橋梁『Microsoft Windows』『Mac OS X Quatz』差異.用統壹接口同原生視窗聯接. 跨平臺API更易於移值. 所以OpenGL比DirectX更得人鐘意.
static {
System.loadLibrary(“app”); } |
<android.view.SurfaceView
android:layout_width=”match_parent” android:layout_height=”match_parent” android:id=”@+id/surface_view” /> |
<style name=”FullscreenTheme” parent=”android:Theme.NoTitleBar.Fullscreen” > |
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) { new Thread(this).start();//渲染,啟動線程 Runnable.run() } |
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } |
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) { } |
@Override
public void run() { init( ); while (true) { update(0); } } |
<uses-sdk android:minSdkVersion=”9″ android:targetSdkVersion=”19″ /> |
find_library( OpenGL-lib libGLESv1_CM.so ) |
find_library( OpenEGL-lib libEGL.so ) |
find_library( Android-lib libandroid.so ) |
target_link_libraries(app
${OpenGL-lib} ${OpenEGL-lib} ${Android-lib}) |
#include <GLES/gl.h> | 標準OpenGL頭文檔 |
#include <GLES/glext.h> | OpenGL架餐庫 |
#include <EGL/egl.h> | EGL頭文檔 |
#include <EGL/eglext.h> | EGL架餐庫 |
#include <android/native_window_jni.h> | 原生視窗庫 |
將『OpenGL』移稙過『Andord』. 但OpenGL ES偏偏冇gluPerspective()視錐投影.但有glFrustumf()設定視口.
通過glFrustumf()設置視口, 得到 gluPerspective()視錐投影. |
void gluPerspective(double fovy,double aspect,double zNear,double zFar){
double ymax = zNear * tan(fovy * 3.141592654f / 360.0f); double ymin = -ymax; double xmin = ymin * aspect; double xmax = ymax * aspect; glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); } |
3D相機投影代碼
glViewport(0,0,viewport_width,viewport_height); | 重置視區尺寸 |
glMatrixMode(GL_PROJECTION); | 設定投影矩陣 |
glLoadIdentity(); | 載入單位矩陣 |
gluPerspective(fov,aspect_ratio,near_clip_z,far_clip_z); | 設置視錐體投影 |
glMatrixMode(GL_MODELVIEW); | 設定模型視圖矩陣 |
glLoadIdentity(); | 載入單位矩陣 |
將『風水羅盤』由『Windows』移稙過『Andord』. 係交換緩存畫面『eglSwapBuffers()』返回『EGL_FALSE』, 『eglGetError()』返回『EGL_BAD_SURFACE』.
EGLBoolean ret = eglSwapBuffers(display,surface);
if(ret == EGL_FALSE){ GLint error = eglGetError(); if(error == EGL_BAD_SURFACE){ } } |
係『Windows』有『Winmain()』入口. 可以控制冚個整游戲運作, 係 『Winmain()』 游戲『運行』『渲染』都係主線程行.
而 『Andord』冇『Winmain()』. 游戲『運行』『渲染』要係新線程『Thread()』行. 而『EGLContext』同『EGLSurface』需係同壹線程『Thread()』生成, 唔係『eglSwapBuffers()』投『EGL_BAD_SURFACE』錯誤碼.
知錯係邊就易整, 將egl()程式擺係新線程『Thread()』行,而非『 onSurfaceCreated()』.
新線程『Thread()』 |
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id); |
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); |
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); |
EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); |
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); |
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); |
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); |
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); |
係Android游戲唔將游戲資源擺係『res』而係『assets』, 事因『res』限制層次結構, 而『assets』允許任意檔案資料夾層次結構.位於『assets』檔案只讀唔寫. NDK需android 9版先支持.
係『CMakeLists.txt』添加『libandroid.so』庫
CMakeLists.txt |
find_library( Android-lib libandroid.so ) |
target_link_libraries( geomanticcompass
${OpenGL-lib} ${OpenEGL-lib} ${Android-lib} ${log-lib}) |
係c檔案加入頭檔
#include <android/asset_manager.h> |
#include <android/asset_manager_jni.h> |
『assets』檔通過『AssetManager』訪問
AssetManager assetManager = this.getAssets(); |
係『NDK』『assets』檔通過『AAssetManager』訪問, 『AAssetManager』接口
AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager); |
將『AssetManager』傳過去獲得『AAssetManager』
extern “C”
JNIEXPORT void JNICALL Java_net_bookcard_geomanticcompass_MainActivity_init(JNIEnv *env, jobject thiz, jobject egl_config, jobject asset_manager) { AAssetManager *assetManager= AAssetManager_fromJava(env, asset_manager); } |
public native void init(AssetManager asset_manager); |
init (getAssets()); |
開啟『assets』檔, 冇需畀絕對路徑, 而係畀『assets』相對路俓
AAsset *asset = AAssetManager_open(nativeasset, “name.bmp”, AASSET_MODE_BUFFER); |
檔长度
int size = AAsset_getLength(asset) |
分配記憶體
PBYTE data = (PBYTE)malloc(size); |
讀『assets』檔
AAsset_read(asset, data, size); |
載入分析
Load(data, size); |
释放记忆体
free(data); |
閂『assets』檔
AAsset_close(asset); |
將游戲資源擺係『assets』下,『assets』『res』同位於『app\src\main』之下.
檔案資料夾 | 位置 |
assets | D:\Android\game\app\src\main\assets |
cpp | D:\Android\game\app\src\main\cpp |
java | D:\Android\game\app\src\main\java |
res | D:\Android\game\app\src\main\res |
係游戲每『渲染』1『畫面』呌1『幀』Frame, 影書每秒24格『菲林』24『幀』, Android每秒至高60『幀』.
Android Studio NDK
#include <time.h> |
clock_t clock(void) |
#include <unistd.h> |
long sysconf(int name) |
量度程式耗時
long clockTicks = sysconf(_SC_CLK_TCK);// 時鐘信號
clock_t startTime = clock();//當前時鈡 // 調用程式 clock_t currentTime = clock();//當前時鈡 float seconds = (float)(currentTime – startTime) / (float)clockTicks; |
需要struct結構用蒞計『幀』Frame, 公式加下:
float _fps = Frames * (double)(currentTime – startTime) / (float)clockTicks ; |
『幀』Frame |
typedef struct FPS_TYP {
clock_t startTime;// 啓動時鐘 long clockTicks;// 時鐘信號 float Frames;// 每秒渲染幀數 int n;// 幀計 }FPS,*FPS_PTR; |
計算每秒渲染幀 |
float Get_FPS(FPS_PTR fps){
++fps->n;// 幀加壹 if (fps->n > 100) { fps->Frames = Get_FPS(fps, fps->n); fps->n = 0; } return fps->Frames; } |
float Get_FPS(FPS_PTR fps, int Frames){
clock_t currentTime = clock();// 進程時鈡 double _fps = (double)Frames * (double)(currentTime – fps->startTime) / (float)fps->clockTicks ; fps->startTime = currentTime;// 重置時間 return (float)_fps; } |
Android Studio NDK編譯又蒞失敗, 『ninja: error: unknown target ‘clean’, did you mean ‘ninja -t clean’? 』大意目標唔乾淨.
Build command failed. |
Error while executing process C:\Users\bookc\AppData\Local\Android\Sdk\cmake\3.10.2.4988404\bin\ninja.exe with arguments {-C D:\Android\GeomanticCompass\app\.cxx\RelWithDebInfo\3t474c6q\arm64-v8a clean}
ninja: Entering directory `D:\Android\GeomanticCompass\app\.cxx\RelWithDebInfo\3t474c6q\arm64-v8a’ |
ninja: error: unknown target ‘clean’, did you mean ‘ninja -t clean’? |
gluLookAt() UVN相機模型,設定視點(相機)位置和視綫方向(矩陣運算).
void gluLookAt( GLdouble eyeX,
GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ); |
OpenGL ES冇gluLookAt() , 手工生成『旋轉矩陣』『相機位置』函式
void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, GLfloat upz) { GLfloat m[16];// 旋轉矩陣 GLfloat x[3], y[3], z[3]; GLfloat mag; //生成旋轉矩陣 // Z矢量 z[0] = eyex – centerx; z[1] = eyey – centery; z[2] = eyez – centerz; mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); if (mag) { z[0]/= mag; z[1]/= mag; z[2]/= mag; }
// Y矢量 y[0] = upx; y[1] = upy; y[2] = upz;
// X 矢量 = Y 叉積 Z x[0] = y[1] * z[2] – y[2] * z[1]; x[1] = -y[0] * z[2] + y[2] * z[0]; x[2] = y[0] * z[1] – y[1] * z[0];
// 重新計算 Y = Z 叉積 X y[0] = z[1] * x[2] – z[2] * x[1]; y[1] = -z[0] * x[2] + z[2] * x[0]; y[2] = z[0] * x[1] – z[1] * x[0];
// 叉積給出了平行四邊形的面積,對于非垂直單位長度向量;所以在這裏標準化x,y mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); if (mag) { x[0]/= mag; x[1]/= mag; x[2]/= mag; }
mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); if (mag) { y[0]/= mag; y[1]/= mag; y[2]/= mag; }
#define M(row,col) m[col*4+row] M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; M(0, 3) = 0.0; M(1, 0) = y[0]; M(1, 1) = y[1]; M(1, 2) = y[2]; M(1, 3) = 0.0; M(2, 0) = z[0]; M(2, 1) = z[1]; M(2, 2) = z[2]; M(2, 3) = 0.0; M(3, 0) = 0.0; M(3, 1) = 0.0; M(3, 2) = 0.0; M(3, 3) = 1.0; #undef M glMultMatrixf(m);
// 視點(相機)位置 glTranslatef(-eyex, -eyey, -eyez); } |
近排天口興台電腦成日死機, CrystalDiskInfo睇『TOSHIBA XG3 M.2 MVME SSD』溫度高達73度. 睇中翅片散熱,銅導管,附送『導熱矽㬵片』同『導熱矽㬵脂』相比勝在可重用. 用肆眼鏍絲固定.
計漏咗翅片頂住顯卡,唔得插係 『PCIe 3.016』, 改插 『PCIe 2.04』. 唯壹安慰SSD高溫從74度跌到53度. 降溫20度.
『SUZUKI Gixxer155』唔畀擺係地下車庫. 擺係樓梯底油箱畀人劃交叉, 頭胎畀人用篤窿.擺係露天『好天哂落雨淋』.褸『車罩』冇掟識擺.冇計唯有裝尾箱放『車罩』.
SHAD 尾箱SH39/ SH40. 尺碼再大有可能頂邊箱SH23. SH39比SH40貴因SH39靚仔. 唔介意買SH40仲底.
裝『托架』RACK盡量褪後, 後坐車人闊落. 架餐『六角套筒』, 『十字螺絲批』. 『托架冚蓋』先裝弧面再裝直面.
SHAD TOP CASE SH39 | 39升尾箱 |
SHAD SIDE CASE SH23 | 23升邊箱 |
係NDK調用fprintf ()格式字符函式報錯
fprintf(fp_error,buffer); |
error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security] |
原解fprintf()缺失參數.加入參數0問題消失.
fprintf(fp_error,buffer,0); |
int printf(const char *format [,argument]…); | 熒屏 |
int fprintf(FILE *stream,const char *format [,argument ]…); | 文檔 |
int sprintf(char *buffer,const char *format [,argument] …); | 記憶體 |
format格式 | argument參數 | 簡介 |
c | 字符 | 單個字符 |
C | 字符 | 單個字符 |
d | 整數 | 帶正負符號十進整數 |
i | 整數 | 帶正負符號十進整數 |
o | 整數 | 冇正負符號八進整數 |
u | 整數 | 冇正負符號十進整數 |
x | 整數 | 冇正負符號,細寫十六進整數.abcdef |
X | 整數 | 冇正負符號,大寫十六進整數.ABCDEF |
e | 浮點數 | 帶正負符號十進浮點數,指數版. |
E | 浮點數 | 帶正負符號十進浮點數, 指數版. |
f | 浮點數 | 帶正負符號十進浮點數 |
F | 浮點數 | 帶正負符號十進浮點數 |
g | 浮點數 | 係%e同%f中選 |
G | 浮點數 | 係%e同%f中選 |
a | ||
A | ||
n | ||
s | 字符串 | 直至首個NULL |
S | 字符串 | 直至首個NULL |
z | ||
% | 指定格式 |
樣式 | 輸出/寫入 |
sprintf (text, ” %2d\n”, 3); | 03 |
sprintf (text, “%s\n “, “abcdef”); | abcdef |
Android 所用C/C++庫Bionic API. 即輕量級C/C++庫. 分32位同64位, 32位『time_t』有效期至2038年, 64位『__time64_t』有效期至3000年.
呌『tm』時間結構
struct tm { | 結構時間 |
int tm_sec; | 秒鐘[0~59] |
int tm_min; | 分鐘[0~59] |
int tm_hour; | 時鐘[0~23] |
int tm_mday; | 號[1~31] |
int tm_mon; | 月份[0~11] 需加1 |
int tm_year; | 年份需加1900, 儒略歴 |
int tm_wday; | 禮拜[0~1],禮拜日Sunday=0 |
int tm_yday; | 天[0~365],1月1號=0 |
int tm_isdst; | 夏令時為正, 否 |
long int tm_gmtoff; | 當前時相對UTC往東時差,即東爲正西爲負. |
const char* tm_zone;}; | 時區縮寫 |
係『Win32 API』你需time()/_time64()獲得時間, 再蒞localtime()/_localtime64()根據時區轉爲本地時間『tm』
Win32 API版本 |
char time_text[280];
struct tm temp_str;// 時間結构 __time64_t temp_int;// 時間整数 _time64(&temp_int);// 获取時間 _localtime64_s(&temp_str ,&temp_int);// 根据時區轉為本地時間 sprintf(time_text, “%4d-%02d-%02d %02d:%02d:%02d”, 1900+temp_str.tm_year,1+temp_str.tm_mon, temp_str.tm_mday, temp_str.tm_hour,temp_str.tm_min,temp_str.tm_sec); |
2021-09-09 23:43:08 |
Android Studio NDK 『Bionic API』版本,可用localtime_r()根據時區獲得本地時間『tm』
Bionic API版本 |
char time_text[280];// 時間文本
struct tm temp_str;// 時間結構 time_t temp_int;// 32位時間整數 temp_int = time(0); localtime_r(&temp_int,&temp_str);// 根據時區轉爲本地時間 sprintf(time_text, “%04d-%02d-%02d %02d:%02d:%02d”, 1900+temp_str.tm_year,1+temp_str.tm_mon, temp_str.tm_mday, temp_str.tm_hour,temp_str.tm_min,temp_str.tm_sec); |
2021-09-09 23:43:08 |
新版Android Studio用CMake編譯so庫. 構建『Native C++』工程已自動生成『CMakeLists.txt』同『native-lib.cpp』, 但C/C++代碼係『native-lib.cpp』調用其它『.cpp』程式皆報錯『error: undefined reference』, 皆因冇將C/C++代碼編譯入so庫.
D:/Android/GeomanticCompass/app/src/main/cpp/native-lib.cpp:14: error: undefined reference to ‘IsEven(int)’ |
睇『CMakeLists.txt』文檔
係『add_library()』尾加入『math.cpp』生成鏈接文檔
add_library( geomanticcompass
SHARED native-lib.cpp math.cpp) |
查找日志庫
find_library(log-lib log) |
將目標文檔與庫文檔進行鏈接
target_link_libraries(geomanticcompass math ${log-lib}) |
Android Studio崩潰後重啟弹出『missing essential plugin』缺必須插件,重装Android Studio問題依舊. 缺失插件可能插件崩潰被屏蔽. 係C: 盘搜索 『disabled_plugins.txt』将入面內容冚辦爛刪.
missing essential plugin
org.jietbrains.android Please reinstall Android Studio from scratch |
C:\Users\bookc\AppData\Roaming\Google\AndroidStudio2020.3\disabled_plugins.txt |
Android唔似Window有Winmain()/main()作程式入口. 而Android用Application作程式入口. 比Activity更早調用,也唔會因方向改變重複調用onCreate().
將Application.onCreate()當main()用. 將程式『初此』Init()冚辦爛摆何係度.
class MainApplication extends Application |
<application android:name=”.MainApplication” ></application> |
public class MainApplication extends Application {
// 全局变量,应用程序句柄
private static MainApplication singleton;
//返回应用程序实例
public static MainApplication getInstance() {
return singleton;
}
//创建应用程序时调用
@Override
public final void onCreate(){
Context context;
singleton = this;//
super.onCreate();
context = this.getApplicationContext();
// 初此
}
// 記憶體低
@Override
public final void onLowMemory() {
super.onLowMemory();
}
// 释放憶體低
@Override
public final void onTrimMemory(int level) {
super.onTrimMemory(level);
}
// 改变配置时调用
@Override
public final void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
Android Studio C/ C++編程開發环境由以下組件构成:
Android Studio安装『NDK』同『CMake』
生成C/C++工程
係『native-lib.cpp』下生成C函式
native-lib.cpp |
extern “C” JNIEXPORT jstring JNICALL
Java_net_bookcard_geomanticcompass_Lib_stringFromJNI( JNIEnv* env, jobject /* this */) { std::string hello = “Hello from C++”; return env->NewStringUTF(hello.c_str()); } |
真機調試Android程式
配置『系統變數』
装Android NDK
Android Studio默認安装Android SDK
Android Studio默認安装Java JDK
验証『Java JDK』安装
Android手機『方向切换』『滑出鍵盘』, Android會認為配置改變, 将销毁并重啟程式. 調用activity:onCreate()會大量占用CPU時間. 係游戲造成500ms以上都唔可接受. 編輯『AndroidManifest.xml』係『<activity>』元素『configChanges』属加入『orientation方向切换』同『keyboardHidden滑出鍵盘』『keyboard插入键盘』. 係MainActivity重载onConfigurationChanged ()自己處理, 達置 『方向切换』『滑出鍵盘』冇需再次调周onCreate().
AndroidManifest.xml |
<activity
android:name=”.MainActivity” android:configChanges=”keyboard|keyboardHidden|orientation”> </activity> |
MainActivity |
@Override
public void onConfigurationChanged(Configuration newConfig) { if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {// 横向 } else if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {// 纵向 } if(newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO ) {// 显示键盘 } super.onConfigurationChanged(newConfig); } |
你必須登入才能發表留言。