X攻略

X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略

X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略
X攻略

畀馬仔收購『twitter』後改名『x』.注册吾使填hk電話冧靶, 衹要gmail郵箱.

  1. 撳『使用Google帳戶繼續』
  2. 選揀gmail郵箱登記帳戶
  3. 『言語』揀漢字.
  4. 填『牛一』
  5. 填『使用者名稱』, 填域名『.』替换『_』. 例『bookcard_net』
  6. 允許x存取聯絡人.

 

Facebook攻略

Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略
Facebook攻略

注册『Facebook』要HK電話冧靶.可能區域限制係『google play』下載吾到『facebook.apk』,可用下面URL地址下載後.

https://apkcombo.app/tw/facebook/com.facebook.katana/download/apk

用USB磁碟复制入手機『DOWNLOAD』資料夾.係USB磁碟係装到app.

/storage/emulated/0/download
  1. 撳『Create new account』
  2. 撳『立即開始』
  3. 填『姓氏』『名字』
  4. 填『牛一』
  5. 揀『男女』
  6. 填『手機號碼』,HK電話冧靶.
  7. 設定密碼, 字母+數字6位.
  8. 儲存登入資料
  9. 同意Facebook條款政策.
  10. 自動確認手機gmail帳戶.
  11. 上傳大頭相.
  12. 開啟聯络人穩人.

Google Pixel5

Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5
Google Pixel5

為左張3HK電話咭,祗有買部『Google Pixel5』.鋪頭話係官翻機,冇黑色得番綠色.部機擺得耐冇曬電,係大陸WIFI連線受限,實際可上網.

用『Google Pixel』手機要張『流動數據』『收發短信』『接打電話』叁合壹HK電話卡.手機要更新GOOGLE PLAY等程式先用得. 部機得128GB驚慢,實際運行流畅. 等有銀諗買『Google Pixel8 Pro 1TB』.首先HK電話罧靶, 愛蒞注冊Gmail郵箱.

  1. 注冊Gmail郵箱
  2. Instagram攻略
  3. WhatsApp攻略
  4. Facebook攻略

Instagram攻略

Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略
Instagram攻略

装『Instagram』要『WhatsApp』收驗証碼. 且佢保安系統, 係新機登入要填舊舊機驗証碼, 登出舊機. 如果舊機跌左就大鑊.

  1. 撳『建立新帳戶』
  2. 填8位HK電話冧靶.
  3. 係『WhatsApp』收6位數代碼.
  4. 設定密碼, 英文+數字+字符, 6位以上.
  5. 儲存登入資料
  6. 填牛一
  7. 填名
  8. 建立用戶名稱. 大部畀人登記,試下用域名.
  9. 同意instagram條款同政策.
  10. 輸入確認碼.係『WhatsApp』收6位數代碼.
  11. 新增大頭貼.

 

後續, 冇過两日收到警告, 第日畀人停用,提出申訴後第日帳戶恢复,可能係『Instagram』判斷你係真人.

 

 

 

WhatsApp攻略

WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略
WhatsApp攻略

注册『WhatsApp』,要HK電話冧靶, SIM咭可『收短信』同埋『上網』流動數據.

  1. 係『Google Play』下載『WhatsApp』.
  2. 輸入手機冧靶『+852 8888 8888』, 填錯隔機粒鐘先重發.
  3. 等收短訊,6位驗證代碼.
  4. 允許存取『聯絡人』『相片』『媒體』『google帳戶』權限.
  5. 填名.
  6. 上轉頭像.
  7. 設定->帳户->雙重認證. 設6位數字pin碼.
  8. 設定->帳户->電郵地址. 用翻『Google帳户』.

 

 

Android Studio-Gradle連缐超時

Android Studio-Gradle連缐超時
Android Studio-Gradle連缐超時

随著『Android studio』更新版本,『Gradle』需升級.

  1. 『File』->『project Structure』
  2. 『Gradle version』揀新版本
  3. 撳右下角『Apply』自動下載.點知彈出『Connection timed out:』連缐超時.
  4. 编輯『Project\gradle\wrapper\gradle-wrapper.properties』
  5. 『distributionUrl』係『Gradle』升級包下載路徑.
https://services.gradle.org/distributions/gradle-8.2.1-bin.zip
  1. 『zipStorePath』係升級包擺放點『wrapper/dists』
  2. 下載後將『gradle-8.2.1-bin.zip』擺係.
C:\Users\admin\.gradle\wrapper\dists\gradle-8.2.1-bin\5hap6b9n41hkg4jeh2au2pllh\gradle-8.2.1-bin.zip

 

 

 

Connection timed out: no further information. If you are behind an HTTP proxy, please configure the proxy settings either in IDE or Gradle.

 

Android studio-gradle版本異常

Android studio-gradle版本異常
Android studio-gradle版本異常

Android studio近日彈出gradle版本晤兼容.修改工程配置. 如果唔得重裝『Android Studio』.

  1. 撳『HELP』->『ABOUT』. 『Android Studio版本』确定『Gradle插件版本』
Android Studio版本 Android Gradle Plugin Version插件版本
Hedgehog | 2023.1.1 3.2~8.2
Giraffe | 2022.3.1 3.2~8.1
Flamingo | 2022.2.1 3.2~8.0
Electric Eel | 2022.1.1 3.2~7.4
Dolphin | 2021.3.1 3.2~7.3
  1. 撳『File』->『project Structure』
  2. 『Gradle version』揀版本
Android Gradle Plugin Version插件版本 Gradle Version
8.1 8.0
8.0 8.0
7.4 7.5
7.4 7.4
7.2 7.3.3
7.1 7.2
7.0 7.0
4.2.0+ 6.7.1
  1. 撳右下角『Apply』自動下載.
The project is using an incompatible version (AGP 8.1.0) of the Android Gradle plugin. Latest supported version is AGP 8.0.0

 

Android Studio-ZLIB壓縮同解壓

Android Studio-ZLIB壓縮同解壓
Android Studio-ZLIB壓縮同解壓

ZLIB』開源『壓縮』同『解壓』程式庫, 支持『DEFLATE』冇損壓縮算法,佢混合『LZ77算法』同『霍夫曼編碼』.

『DEFLATE』壓縮算法冇專利權.畀人大量應用係『網络』『圖檔』『文檔』『影片』.

.PNG/ Libpng 圖檔解壓
.ZIP 壓縮檔
.tar 壓縮檔
.gz 壓縮檔
HTTP 壓縮傅送
FFmpeg 影片解壓

下载『ZLIB

http://www.zlib.net/
http://www.zlib.net/zlib-1.2.13.tar.gz

『Android studio』內置『ZLIB』, 唔使下載.但要係『CMakeLists.txt』增添『zlib』庫.

CMakeLists.txt文檔  
find_library( z-lib z ) 搜索zlib
target_link_libraries( ${z-lib} ) 連接zlib

包含『ZLIB』頭文檔

#include <zlib.h> Zlib-api
#include <zconf.h>  

『z_stream』壓縮同解壓皆需此結构體

z_stream stream; zlib流結构體
stream.zalloc = Z_NULL; NULL用默認記憶體分配函数
stream.zfree  = Z_NULL; NULL用默認記憶體释放函数
stream.opaque = Z_NULL;  
stream.next_in  = (Bytef*)sour; 蒞源
stream.avail_in = (uInt)sour_length; 蒞源長
stream.next_out = dest; 輸出
stream.avail_out = (uInt)*dest_length; 輸出長

ZLIB』壓縮分叁步

壓縮  
deflateInit(&stream, level) 分配記憶體,level壓縮等級
deflate(&stream, flush); 壓縮數據, flush設0
deflateEnd(&stream); 释放記憶體

 

int deflateInit2( deflateInit()加强版
z_streamp strm, zlib流結构體
int  level, level壓縮等級0~9.

0:速度快,唔壓縮.

9:速度慢,壓縮率高.

int  method, 壓縮算法僅支緩Z_DEFLATED
int  windowBits, 處理RAW DEFLATE手法.
int  memLevel, 指定記憶體分配MAX_MEM_LEVEL
int  strategy)); 壓縮策略,僅影響壓縮比.默認Z_DEFAULT_STRATEGY

 

level 壓縮等級
#define Z_NO_COMPRESSION         0 唔壓縮
#define Z_BEST_SPEED             1 高速,低壓縮率
#define Z_BEST_COMPRESSION       9 高壓縮率, 慢速
#define Z_DEFAULT_COMPRESSION  (-1) 默認壓縮

 

windowBits 處理RAW DEFLATE手法.
8~15: 純deflate壓縮
-8~-15: zlib頭 + deflate + zlib尾
> 16: Gzip頭+ deflate + Gzip尾

 

method 壓縮算法
#define Z_DEFLATED   8 DEFLATE冇損壓縮

 

memLevel 記憶體分配
MemLevel=1 最小記憶體,速度慢壓縮比低
MemLevel=9

#define MAX_MEM_LEVEL 9

最大記憶體,最佳速度
MemLevel=8 默認值

 

strategy 壓縮算法設定
#define Z_FILTERED            1 僅FILTERED生成數據
#define Z_HUFFMAN_ONLY        2 僅霍夫曼編碼
#define Z_RLE                 3 匹配長度=1
#define Z_FIXED               4 禁霍夫曼編碼
#define Z_DEFAULT_STRATEGY    0 默認壓縮設定

ZLIB』解壓分叁步

解壓  
inflateInit(&stream) 分配記憶體
inflate(&stream, Z_NO_FLUSH); 解压數據
inflateEnd(stream); 释放記憶體

 

返回碼  
#define Z_OK            0  
#define Z_STREAM_END    1 結束
#define Z_NEED_DICT     2 愛密碼
#define Z_ERRNO        (-1)  
#define Z_STREAM_ERROR (-2)  
#define Z_DATA_ERROR   (-3) 加密數據損壞壞,或缺失.
#define Z_MEM_ERROR    (-4) 唔够記憶體
#define Z_BUF_ERROR    (-5) 唔够緩存
#define Z_VERSION_ERROR (-6)  

 

解壓示例

int Uncompress(PBYTE dest,int * dest_length,PBYTE sour,int sour_length)

{

z_stream stream;

int ret;

stream.zalloc = (alloc_func)0;

stream.zfree  = (free_func)0;

stream.opaque = (voidpf)0;

stream.next_in  = (Bytef*)sour;

stream.avail_in = (uInt)sour_length;

stream.next_out = dest;

stream.avail_out = (uInt)*dest_length;

MAX_MEM_LEVEL

ret = inflateInit2(&stream, 16+MAX_WBITS);

if (ret != Z_OK)

return ret;

 

ret = inflate(&stream, Z_NO_FLUSH);// 解压

*dest_length = stream.total_out;

inflateEnd(&stream);

return ret;

}

 

壓缩示例

bool Compress(PBYTE dest,int * dest_length,PBYTE sour,int sour_length, int level)

{

int ret, flush;

int sour_offset,dest_offset;

int have;

z_stream stream;

BYTE in[ZIP_CHUNK];

BYTE out[ZIP_CHUNK];

 

stream.zalloc = Z_NULL;// 内存分配函数

stream.zfree  = Z_NULL;// 内存释放函数

stream.opaque = Z_NULL;

stream.next_in  = (Bytef*)sour;

stream.avail_in = (uInt)sour_length;

stream.next_out = dest;

stream.avail_out = (uInt)*dest_length;

 

ret = deflateInit(&stream, level);// 内存分配

if (ret != Z_OK)

return false;

 

ret = deflate(&stream, flush);  // 进行压缩

*dest_length = stream.total_out;

 

deflateEnd(&stream);// 释放内存

return ret;

}

Android studio-『C/C++ Language Support』

Android studio-『C/C++ Language Support』
Android studio-『C/C++ Language Support』

『Android studio』死機後,點唔開『.CPP/.C』文檔. 連落斷點都.發視『C/C++ Language Support』畀ANDROID禁用Disabled.

  1. 撳『File』->『Settings』
  2. 撳『Settings』->『Plugins』
  3. 撳『Installed』->『C/C++ Language Support』
  4. 撳『Enabled』著 C++插件

Android studio-Image Asset自動生成背景透明圖檔

Android studio-Image Asset自動生成背景透明圖檔
Android studio-Image Asset自動生成背景透明圖檔
Android studio-Image Asset自動生成背景透明圖檔
Android studio-Image Asset自動生成背景透明圖檔

『Android studio』內置架餐『Image Asset』. 畀幅圖檔佢,『Image Asset』帮你自動生成各式圖檔.

揀『Launcher Icons(Legacy only)』冚辦闌圖檔背景透明.

『Android 8.0』及以上,程式圖檔强制背景色,揀『Launcher Icons(Adaptive and Legacy)』.

Android 8.0及以上 圖檔背景白色 Launcher Icons(Adaptive and Legacy)
Android 7.1及以下 圖檔背景透明 Launcher Icons(Legacy only)
  1. 揀『Project』->『app』
  2. 撳『File』->『New』->『Image Asset』
  3. 設置『Asset Studio』
Configure Image Asset Android 8.0(API 26) 及以上
Icon type Launcher Icons(Adaptive and Legacy)
Name ic_launcher
Layer name ic_launcher_foreground
Asset type Image
path 『.png』背景透明圖檔
Trim 修剪勾yes
Resize 100%
Asset type 勾Color
Color 0xFFFFFF

 

Configure Image Asset Android 7.1以下
Icon type Launcher Icons(Legacy only)
Name ic_launcher
Asset type 勾Image
Path 『.png』背景透明圖檔
Trim 修剪勾yes
Padding 0%
Background 背景0xFFFFFF
Scaling Crop/ Shrink to fit自适应宽度
Shape 揀None
Effect 勾None

 

 

資料夾 Size(px)
mipmap-xxxhdpi 192*192
mipmap-xxhdpi 144*144
mipmap-xhdpi 96*96
mipmap-hdpi 72*72
mipmap-mdpi 48*48

 

Android Studio-Cannot load settings from file『misc.xml』

Android Studio-Cannot load settings from file『misc.xml』
Android Studio-Cannot load settings from file『misc.xml』

Android Studio係右下角彈出警示,『Cannot load settings from file』冇法載入『misc.xml』,事實係文檔損毁.內容大致如下.粘貼後諸存.

『misc.xml』文檔
<?xml version=”1.0″ encoding=”UTF-8″?>

<project version=”4″>

<component name=”ProjectRootManager” version=”2″ languageLevel=”JDK_17″ default=”true” project-jdk-name=”Android Studio default JDK” project-jdk-type=”JavaSDK”>

<output url=”file://$PROJECT_DIR$/build/classes” />

</component>

<component name=”ProjectType”>

<option name=”id” value=”Android” />

</component>

</project>

 

Load settings
Cannot load settings from file
“D:\ANDROID\GeomanticCompass\.idea\misc.xml”;illegal character(NULL,Unicode 0) encountered: not valid in any content at[row,col{unknown-source}]:[1,2] Please correct the file content

 

Android Studio丟失鍵盤映射『Missing keymap』

Android Studio丟失鍵盤映射『Missing keymap』
Android Studio丟失鍵盤映射『Missing keymap』

『Android Studio』冇拉拉丟失鍵盤映射『Missing keymap』『Cannot find keymap “Windows Proper Redo” 』.

重新設鍵盤映射.

  1. 撳『File』->『Settings』
  2. 撳『Keymap』->『Eclipse』
  3. 撳『Apply』
Missing keymap
Cannot find keymap “Windows Proper Redo”
Search for Windows Proper Redo Keymap plugin

 

Android studio冇法執行Clang-Tidy:事因稳吾到或冇法執行clazy-standalone.

Android studio冇法執行Clang-Tidy:事因稳吾到或冇法執行clazy-standalone
Android studio冇法執行Clang-Tidy:事因稳吾到或冇法執行clazy-standalone

『Android studio』冇法執行『Clang-Tidy』:事因稳吾到或冇法執行『clazy-standalone』.

Unable to execute Clang-Tidy: clazy-standalone is not found or cannot be executed

事因『Android Studio吾支持『clazy』

  1. 撳『File->Settings』
  2. 撳『Editor->Inspections->C/C++->Static Analysis Tools->』
  3. 禁用『Clazy』

TrueNAS®FTP

TrueNAS®FTP
TrueNAS®FTP
TrueNAS®FTP
TrueNAS®FTP
TrueNAS®FTP
TrueNAS®FTP
TrueNAS®FTP
TrueNAS®FTP

TureNAS-內建支援FTP,即使出到街也可係『手機』同『NAS』傳蒞傳去.

ftp://username:password@truenas/
  1. 登入後臺
  2. 創建戶口User , 作為FTP『名稱』『密碼』
  3. 撳『System Settings』->『Services』
  4. 使能『FTP』->『Runing』
  5. 勾『FTP』->『Start Automatically』
  6. 撳『FTP』->『Configure』
  7. 撳『Advanced Options』
  8. 『File Permissions』同『Directory Permissions』
  9. 『Read』『Write』『Execute』權冚辦闌勾.
  10. 撳『save』

 

Windows10

  1. 撳『Win+E』鍵『檔案總管』
  2. 填『ftp://truenas/』或『ftp://username:password@truenas/』連FTP
  3. 『Username』填FTP『名稱』
  4. 『password』填FTP『密碼』
  5. 勾『儲存密碼』
  6. 撳『登入』

 

Android

  1. 『檔案瀏覽器』->『新增FTP伺服器』
  2. 『SERVER』填『168.1.X』
  3. 『PORT』填『21』
  4. 『模式』勾『被動』
  5. 『Username』填FTP『名稱』
  6. 『password』填FTP『密碼』
  7. 撳『ENTER』

 

Android Studio-CXX5202

Android Studio-CXX5202
Android Studio-CXX5202

Android Studio冇端端彈出[CXX5202] 錯誤碼,android程式僅僅支持32BIT/x86庫. 而Google Play自2019年8月1日起, 要支持64Bit庫,

  1. 下載最新Android SDK , 撳Tools->Android SDK.
  2. 下載API 21以上版本Android SDK
  3. 編輯『xml』
  4. 更改編譯SDK版本『android:targetSdkVersion=”31″』
<uses-sdk android:minSdkVersion=”9″ android:targetSdkVersion=”31″ />

 

[CXX5202] This app only has 32-bit [armeabi-v7a,x86] native libraries. Beginning August 1, 2019 Google Play store requires that all apps that include native libraries must provide 64-bit versions. For more information, visit https://g.co/64-bit-requirement

 

Android Studio NDK-時間

Android Studio NDK-時間
Android Studio NDK-時間

『西曆』 即『儒略曆』, 電腦內置硬件時鐘,得以存儲時間.

  1. 首先取『格林威治標准時鐘』GMT.
time_t _time;
time(&_time);
  1. 『格林威治標准時鐘』轉『本地時鐘』, 据時區調整時鐘.
tm * _tm;
_tm =  localtime(&_time);

tm將『本地時鐘』分解為『年』『月』『日』『時』『分』『秒』『禮拜』.

struct tm{ 簡述
int tm_year; 1900 + 年
int tm_mon; 月 0~11
int tm_mday; 日 1~31
int tm_hour; 時 0~23
int tm_min 分 Minute 0~59
int tm_sec; 秒 second 0~60, 60為潤秒,天文曆校准.
int tm_wday; 禮拜, 0=禮拜日,1=禮拜壹,2=禮拜貳,3=禮拜三,4=禮拜肆,5=禮拜伍,6=禮拜陸
int tm_yday; 年日,(0~365),壹月壹=0,拾貳月參拾=365
int tm_isdst;

}

夏令时  Daylight saving time,

DST=0冇夏令时,

DST>0有夏令时,

DST<0夏令时冇效

 

i-gota USB2.0 micro 5pin專業級高速傅輸線

i-gota USB2.0 micro 5pin專業級高速傅輸線
i-gota USB2.0 micro 5pin專業級高速傅輸線
i-gota USB2.0 micro 5pin專業級高速傅輸線
i-gota USB2.0 micro 5pin專業級高速傅輸線

Android Studio 調試APP要係Android舊機測試, 舊機采用micro USB口, 廉价USB 線叉唔入電,調試連線唔認機.

功欲善其事,必先利器,靚USB線先可事半功倍.

昶興電子出品,『超高密度編織網遮蔽層』+『鋁箔防護層』+『抗干擾磁環』

Android Studio-Touch模拟『單擊』『雙擊』

Android Studio-Touch模拟『單擊』『雙擊』
Android Studio-Touch模拟『單擊』『雙擊』

Android触摸Touch 手指触摸荧屏傳遞『鬆UP』『撳DOWN』『拖DRAGGED』基礎信息, 要模拟『單擊』『雙擊』, 首先定義信息指令.

#define TOUCH_CLICK          4 單擊
#define TOUCH_DOUBLECLICK   5 雙擊

定義『單擊』『雙擊』時間間隔. 约摸0.1秒即触發單擊,

#define TOUCH_TIME_CLICK  0.5f 單擊 500毫秒
#define TOUCH_TIME_DOUBLECLICK  0.5f 雙擊 500毫秒

定義冚域變量,記录『撳up』『單擊click』触發時間.

double touch_time_down; 撳-进程時鐘
double touch_time_click; 單擊-进程時鐘

获得進程時鐘信号

clock_t clock(void);  

每秒時鐘計時单位

#define CLOCKS_PER_SEC 1000000 時鐘单位

計進程時間,單位『秒』

『進程時間=時鐘信号/时鐘单位』

double currTime = clock() / CLOCKS_PER_SEC ;

當接收『鬆UP』指令.

if(action == TOUCH_UP){//鬆

判斷两次單擊小於0.5秒触發雙擊

if((currTime – touch_time_click) < TOUCH_TIME_DOUBLECLICK )  {
touch->action[finger] = TOUCH_DOUBLECLICK; //細過500ms 雙擊
        touch_time_click = currTime;   }

判斷『鬆UP』『撳DOWN』小於0.5秒触發單擊

else if((currTime – touch_time_down) < TOUCH_TIME_CLICK ) {// 細過500ms
       touch->action[finger] = TOUCH_CLICK; //單擊
         touch_time_click = currTime;        }}

記录『撳DOWN』

    if(action == TOUCH_DOWN)
touch_time_down = currTime;//撳-进程時間

 

Android Studio NDK-Debg APP装apk程式失敗

Android Studio NDK-Debg APP装apk程式失敗
Android Studio NDK-Debg APP装apk程式失敗

係『LGE Nexus 5』行Debg,報『The application could not be installed: INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES』簽名衝突未能裝APK程式.

事因先前重装『Android Studio』, ADB Debug簽名改變造成.手動卸載舊版搞掂.

07/12 20:16:23: Launching ‘app’ on LGE Nexus 5.
Installation did not succeed.
The application could not be installed: INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES
List of apks:

[0] ‘D:\ANDROID\GeomanticCompass\app\build\intermediates\apk\debug\app-debug.apk’

Installation failed due to: ‘Failed to commit install session 1496268207 with command pm install-commit 1496268207. Error: INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: New package has a different signature: net.bookcard.geomanticcompass’
Retry
Failed to launch an application on all devices

 

游戲輵-紋理邊缘白色毛剌

游戲輵-紋理邊缘白色毛剌
游戲輵-紋理邊缘白色毛剌
游戲輵-紋理邊缘白色毛剌
游戲輵-紋理邊缘白色毛剌

『紋理』『背景色』指『透明色』,PHOTOSHOP『透明色』默認係『白』. 係OpengGL貼圖邊缘產生白色毛剌, 如果『透明色』改為『黑』, OpengGL貼圖邊缘產生黑色邊框.

  1. Photoshop開啟『.PSD』圖檔.
  2. 清除『背景色』
  3. 『影像』->『模式』->『索引色』
  4. 『要合併可圖層並放棄隱藏圖層嗎?』撳『確定』.
『索引色』  
色盤 局部(最適化)
顏色 256
强制
透明 勾選
邊緣調合
混色
  1. 『影像』->『模式』->『色彩表』
  2. 『色彩表』最屘『透明色』改為『黑』.
  3. 導出圖檔

Android Studio-C/C++代碼超出(500kB)限制代碼解析失效

Android Studio-C/C++代碼超出(500kB)限制代碼解析失效
Android Studio-C/C++代碼超出(500kB)限制代碼解析失效

重装Android Studio後,舊時C/C++代碼超出(500kB)限制.代碼解析失效.

File size(698.07kB) exceeds configured limit for C/C++ (500kB).Code insight features are not available.

撳『Change the maximun file length』更改限制長度. 係右上角

Maximun File Length
Enter the new maximun length for C/C++ files in characters

 

Android Studio-裝CMake

Android Studio-裝CMake
Android Studio-裝CMake
Android Studio-裝CMake
Android Studio-裝CMake

重装Android Studio後Build, 彈出CMake ERROR, 事源CMake未裝

[CXX1300] CMake ‘3.10.2’ was not found in SDK, PATH, or by cmake.dir property.
[CXX1301] – CMake ‘3.18.1’ found in SDK did not satisfy requested version.
  1. 著『Android Studio』
  2. 撳『Tools』->『SDK Manager』
  3. 撳『Android SDK』->『SDK Tools』
  4. 勾『Show Package Details』顯示包裹詳情
  5. 勾『CMake』下冚辦爛版本號.
  6. 撳『Apply』

 

紋理拼圖

紋理拼圖
紋理拼圖

2D游戲動画幀, 由多幅關鍵幀(keyFrame) 組成. 逐幀渲染產生動画卡通.『幀動画』亦哎呌『紋理』texture. 将多幅『幀動画』存放係單壹紋理.OpenGL可提高渲染速度, 係显存記憶體1MB年代可能冇用. 事因渲染皆係電脑記憶體運作.

係显存記憶體大幅增長, OpenGL渲染係显存記憶體完成. 减小『紋理』載入量, 單壹紋理存放多幅『幀動画』,可提高渲染速度.

係3D游戲亦可用相同技術提飛渲染效率.

void zoom_textcoord_model3D(TEXTURE_PTR texture,int index,int size,VECTOR2D_PTR dest,VECTOR2D_PTR sour,int count,int flag)

 

texture 紋理
index 關鍵幀索引
size 關鍵幀寬高解像
dest 纹理隊列
sour 原始纹理隊列
count 纹理頂點量

計單元格

int cell = texture->width / size;

計索引

int  i  = index % cell;// 橫索引
int  j  = index / cell;// 行索引

計缩放率0.0f < zoom < 1.0f

float    zoom    = (float)size / (float)texture->width;

計『幀』偏移.

float offsetX = (float)zoom * (float)i;
float offsetY = (float)zoom * (float)j;

遍歴UV紋理頂㸃

    for (int p = 0; p < count; ++p){

缩細後移動

dest[p].u = sour[p].u * zoom + offsetX ;
dest[p].v = sour[p].v * zoom + offsetY;

纹理返转

if (flag & MODEL3D_TEXTURE_FLIP)

dest[p].v = 1 – (sour[p].v * zoom + offsetY);}

 

SKYBOX天幕

天幕SKYBOX
天幕SKYBOX
天幕SKYBOX
天幕SKYBOX

『天幕SKYBOX』指巨立方體, 係內籠貼天幕紋理,『天幕紋理』可能係『地平線』『室內』『宇宙』. 『天幕SKYBOX』原㸃與3D相機位置重合. 係遠睇時正确.

由陸幅紋理『顶』『底』『前』『後』『左』『右』組成. 以前『天幕SKYBOX』紋理分陸幅位圖存檔.

陸幅位圖存係單壹『紋理』效率更高. 将『紋理』平分拾陸等分. 足够擺两組『天幕』紋理. 『日頭』『晚黑』各壹. 似上圖咁.

紋理索引:0~15 『日頭』 『晚黑』
顶up 0 8
底dn 1 9
前ft 7 15
后bk 5 13
左lt 6 14
右rt 4 12

定義『天幕SKYBOX』

typedef struct SKYBOX_TYP {
VECTOR3D  pos; 位置
VECTOR3D  rot; 旋轉
TEXTURE_PTR texture; 天幕纹理
float     size; 天幕大细
//TEXTURE_REGION region[16]; 纹理区域
VECTOR3D  vertex_array[36]   ; 天幕顶点
VECTOR2D  texCoord_array[36] ; 天幕紋理
}SKYBOX, *SKYBOX_PTR;

手エ构建『天幕SKYBOX』立方體『3D頂㸃』同『UV紋理』. 正方形以两三角形組成. 紋理左上角[u0, v0], 紋理右下角[u1,v1].天幕大细『size』.

天『UV紋理』 『xyz頂㸃』
texCoord[0]=[u1, v1] vertex_array[0]=[-size, size, -size]
texCoord[1]=[u0, v1] vertex_array[1]=[size, size, -size]
texCoord[2]=[u0, v0] vertex_array[2]=[size, size, size]
texCoord[3]=[u1, v1] vertex_array[3]=[-size, size, -size]
texCoord[4]=[u0, v0] vertex_array[4]=[size, size, size]
texCoord[5]=[u1, v0] vertex_array[5]=[-size, size, size]

 

地『UV紋理』 『xyz頂㸃』
texCoord[6]=[u1, v1] vertex_array[6]=[size, -size, -size]
texCoord[7]=[u0, v1] vertex_array[7]=[-size, -size, -size]
texCoord[8]=[u0, v0] vertex_array[8]=[-size, -size, size]
texCoord[9]=[u1, v1] vertex_array[9]=[size, -size, -size]
texCoord[10]=[u0, v0] vertex_array[10]=[-size, -size, size]
texCoord[11]=[u1, v0] vertex_array[11]=[size, -size, size]

 

前『UV紋理』 『xyz頂㸃』
texCoord[12]=[u0, v0] vertex_array[12]=[-size, -size, -size]
texCoord[13]=[u1, v0] vertex_array[13]=[size, -size, -size]
texCoord[14]=[u1, v1] vertex_array[14]=[size, size, -size]
texCoord[15]=[u0, v0] vertex_array[15]=[-size, -size, -size]
texCoord[16]=[u1, v1] vertex_array[16]=[size, size, -size]
texCoord[17]=[u0, v1] vertex_array[17]=[-size, size, -size]

 

后『UV紋理』 『xyz頂㸃』
texCoord[18]=[u0, v0] vertex_array[18]=[size, -size, size]
texCoord[19]=[u1, v0] vertex_array[19]=[-size, -size, size]
texCoord[20]=[u1, v1] vertex_array[20]=[-size, size, size]
texCoord[21]=[u0, v0] vertex_array[21]=[size, -size, size]
texCoord[22]=[u1, v1] vertex_array[22]=[-size, size, size]
texCoord[23]=[u0, v1] vertex_array[23]=[size, size, size]

 

右『UV紋理』 『xyz頂㸃』
texCoord[24]=[u1, v0] vertex_array[24]=[size, -size, size]
texCoord[25]=[u1, v1] vertex_array[25]=[size, size, size]
texCoord[26]=[u0, v1] vertex_array[26]=[size, size, -size]
texCoord[27]=[u1, v0] vertex_array[27]=[size, -size, size]
texCoord[28]=[u0, v1] vertex_array[28]=[size, size, -size]
texCoord[29]=[u0, v0] vertex_array[29]=[size, -size, -size]

 

左『UV紋理』 『xyz頂㸃』
texCoord[30]=[u1, v0] vertex_array[30]=[-size, -size, -size]
texCoord[31]=[u1, v1] vertex_array[31]=[-size, size, -size]
texCoord[32]=[u0, v1] vertex_array[32]=[-size, size, size]
texCoord[33]=[u1, v0] vertex_array[33]=[-size, -size, -size]
texCoord[34]=[u0, v1] vertex_array[34]=[-size, size, size]
texCoord[35]=[u0, v0] vertex_array[35]=[-size, -size, size]

 

Android Studio-Gradle版本

Android Studio-Gradle版本
Android Studio-Gradle版本

同Android Studio更新Android SDK後,  最低支持Gradle版本7.3.3, 當前版本7.0.2

Minimum supported Gradle version is 7.3.3. Current version is 7.0.2.
Please fix the project’s Gradle settings.

Gradle Settings.

撳『Android Gradle Plugin can be upgraded』更新Gradle

Upgrade Android Gradle Plungin from version 7.0.2 to 7.2.0

下載Gradle7.3.3

Gradle: Download gradle-7.3.3-bin.zip

 

Android两指縮放

Android两指縮放
Android两指縮放

之前做Android 游戲皆单㸃触摸, 諗住係風水羅盤實現两指縮放.

触摸分叁動作『鬆』『撳』『拖』.

動作 注释
#define TOUCH_UP      1
#define TOUCH_DOWN    2
#define TOUCH_DRAGGED 3

雙手拾指, 除非用埋脚指

#define MAX_FINGER    10 拾指

定義TOUCH結构, 用蒞存拾指『方位』同『動作』

TOUCH結构 注释
typedef struct TOUCH_STR{
    int count; 手指量, 最多10指
    int action[MAX_FINGER]; 動作
    int x[MAX_FINGER]; X座標
    int y[MAX_FINGER]; Y座標
}TOUCH,*TOUCH_PTR;

用栈stack蒞存触摸,

#define MAX_TOUCH     32 棧高32
TOUCH touch_array[MAX_TOUCH] ; 触摸棧
int   touch_count; 棧頂

棧頂加壹, 每次存触摸『方位』同『動作』前調用

int Add_Touch(){

TOUCH_PTR touch;

int index;

if(touch_count >= MAX_TOUCH)

return touch_count;

index = touch_count;

++touch_count;// 棧頂加壹

touch = &touch_array[index];

touch->count = 0;

return touch_count;

}

棧頂减壹, 讀『方位』同『動作』後調用

int Sub_Touch(){

if(touch_count <= 0)

return touch_count;

–touch_count;

return touch_count;

}

存触摸『方位』同『動作』, finger係手指索引

bool Set_Touch(int finger,int action,float x,float y){

int index;

TOUCH_PTR touch;

index = touch_count-1; // 棧頂

touch = &touch_array[index];

if(touch->count < finger + 1)

touch->count = finger + 1;

touch->action[finger] = action;

touch->x[finger] = x ;

touch->y[finger] = y ;

return true;

}

讀触摸, 『方位』同『動作』, finger係手指索引

bool Get_Touch(int finger,int * action,int * x,int * y){

TOUCH_PTR  touch;

int index;

if(touch_count == 0)

return false;

index = touch_count – 1;

touch = &touch_array[index];

*action = touch->action[finger];

*x = touch->x[finger];

*y = touch->y[finger];

return true;

}

計两指(x0,y0)(x1,y1)縮放時中心位(cx,cy)

float cx = (x0 – x1)/2 + x1;
float cy = (y0 – y1)/2 + y1;

2D触摸坐标转屏幕坐标

VECTOR2D touchPoint2D; 2D触摸點(x,y)
VECTOR3D touchPoint3D; 3D触摸點(x,y,z)

触摸坐标转3D世界坐标

Init_VECTOR2D(&touchPoint2D, cx, cy);
TouchToWorld(camera3D, &touchPoint2D, &touchPoint3D);

計两指距,

Init_VECTOR2D(&v0,x0,y0);
Init_VECTOR2D(&v1,x1,y1);
Sub_VECTOR2D(&vdiff,&v0,&v1);
length = Length_VECTOR2D(&vdiff);

指距拉開放大, 两指行埋縮細. 通過移3D相機實現縮放.

if(_length > length ) y = Camera3D.pos.y + 2; 縮細
if(_length < length ) y = Camera3D.pos.y – 2; 放大

 

Android-360度旋轉羅盤

Android-360度旋轉羅盤
Android-360度旋轉羅盤

自首台Android手機面世, 已標配熒幕觸摸. 旋轉羅盤以天池為原㸃分肆象限.

  1. 係觸屏拖動得到兩觸摸坐標, (x0,y0) 觸摸點. (_x0,_y0) 上壹觸摸點.
  2. 将(x0,y0) 同(_x0,_y0) 歸壹, 即長為壹,方位唔變.
  3. 㸃(x0,y0) ,(_x0,_y0) 同天池原㸃(0,0). 形成『等腰三角』, 腰長壹.
  4. 計㸃(x0,y0) ,(_x0,_y0) 距离, 得到『等腰三角』 底長『length』
  5. 『等腰三角』由两『直角三角』組成
  6. 計『直角三角』原㸃夹角
sin(a)= 對邊/斜邊
a = asinf(對邊/斜邊)
  1. 『旋轉角』= asinf((length / 2) / 1) * 2
angle = RAD_TO_DEG( asinf((length / 2.0f) / 1.0f) ) * 2.0f;
  1. 判轉向
笛卡兒坐標 象限
if( v0.y > 0 && v0.x > _v0.x) length = -length; 逆轉
if( v0.y < 0 && v0.x < _v0.x)length = -length; 逆轉
  1. 旋轉Y軸
rot.y = (int)(rot.y + angle) % 360;

 

 

Android Studio-『app:externalNativeBuildCleanDebug FAILED』

Android Studio-『app:externalNativeBuildCleanDebug FAILED』
Android Studio-『app:externalNativeBuildCleanDebug FAILED』

琴日Android Studio係Build果陣,Win10冇端端死機, 重啟後『Clean Project』『Rebuild Project』皆現『app:externalNativeBuildCleanDebug FAILED』

> Task :app:externalNativeBuildCleanDebug FAILED

Execution failed for task ‘:app:externalNativeBuildCleanDebug’.

> com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $

 

* Try:

Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output. Run with –scan to get full insights.

Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $

問題明显,係寫入時果陣死機. 破壞文档数据, 解决方案係刪『build』資料夾, 再撳『Rebuild Project』 等『Androd studio』重建『build』即可

1.刪『App』->『build』資料夾
2.撳『build』->『Rebuild Project』

 

Android Studio NDK-assets遍歷文檔

謎語之摸蒞又冇烈
謎語之摸蒞又冇烈

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);

 

Android Studio NDK-OpenGL ES 觸屏坐標轉游㱆坐標

Android Studio NDK-OpenGL ES 觸屏坐標轉游㱆坐標
Android Studio NDK-OpenGL ES 觸屏坐標轉游㱆坐標

觸屏坐標』『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);

 

Android Studio NDK-OpenGL ES 漢字位圖字庫

Android Studio NDK-OpenGL ES 漢字位圖字庫
Android Studio NDK-OpenGL ES 漢字位圖字庫

『漢字字庫』同 『ASCII字庫』原理同, 字庫『竪排』, 漢字『32*32』pixel, 『竪』32漢字.

由上至下,由右至左排列.可填1024字符,每色8Bit. 即『索引色』『調色板』.

准備庫位圖

  1. 白紙黑字,
  2. 白色係透明色. 黑色係變換色.

Photoshop轉為『索引色』

  1. 『影像』->『模色』->『索引色』
  2. 『色盤』揀『正確』.
  3. 『顏色』量3
  4. 『强制』揀『黑白』
  5. 『透明』勾選
  6. 存為『.pcx』或『.bmp』

止時圖檔『調色板』共有三色『黑』『白』『透明』.

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);

 

Google nexus5 32GB

Google nexus5 32GB
Google nexus5 32GB
Google nexus5 32GB
Google nexus5 32GB
Google nexus5 32GB
Google nexus5 32GB
Google nexus5 32GB
Google nexus5 32GB

買Google nexus5『壹為神功,貳為弟子』,『壹蒞開發,貳還心愿』.機仔細細窄邊框.當年靚絕Android, 本蒞愛『Android 4』『黑蓋』寄蒞『Android 5』『白蓋』. 韓國LG制造港版,換新電包郵百肆蚊有找.部機吾升級係用吾到, 永遠話連吾到.

  1. 先升android 5.1, 再升5.11 吾停甘升, 最後升至android 6.01
  2. 去下載『google play 商店』, 擺係download安裝.
  3. 再升google play 服務.
  4. 孻屘升gmail郵箱, 登入google帳號.
Google nexus5 簡介
4.94英寸
解像 1920*1080
4000mAh
相機 1310萬
CPU 驍龍800
RAM 2GB
DISK 32GB
MODEL LG-D821港版

 

Android Studio NDK-触摸onTouch()

Android Studio NDK-触摸onTouch()
Android Studio NDK-触摸onTouch()

初台Android手機己采用『單點』触摸, 直至Android2.0(SDK version 5) 先支持『多點』触摸.

  1. Android觸摸監聽『OnTouchListener』 監聽 『触屏』事件.
static class TounchListener implements OnTouchListener{
  1. 通過『onTouch()』獲取『触屏』信息.
@Override

public boolean onTouch(View v, MotionEvent event) {

  1. 0(ÉCLAIR)(API 5) 先支持多點触摸
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR)
  1. 處理『多點』触摸
MultiTouch(v, event); else
  1. 處理『單點』触摸
SingleTouch(v, event);
  1. 返回false, 繼續處理觸摸事件.
return false;}

 

  1. 生成觸摸監聽
private static TounchListener Tounch_Listener  = new TounchListener() ;
  1. 為OpenGL View注冊触摸监听,
view.setOnTouchListener(Tounch_Listener);
  1. 通過OnTouch()(View v, MotionEvent event) 獲取『触屏』坐標 . 『触屏』原點(0,0) 係左上角, 單位象素
MotionEvent.getX() X軸指右
MotionEvent.getY() Y軸指下
  1. 獲取『触屏』事件類型 . MotionEvent.getAction()
MotionEvent.getAction()  
MotionEvent.ACTION_DOWN 手指撳屏
MotionEvent.ACTION_POINTER_DOWN 手指撳屏
MotionEvent.ACTION_UP 手指鬆离
MotionEvent.ACTION_POINTER_UP 手指鬆离
MotionEvent.ACTION_CANCEL 手勢鬆
MotionEvent.ACTION_MOVE 移動手指
  1. 『触屏』類型簡化為『撳』『鬆』『拖』三類
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){
  1. 提取『触屏』事件類型
int action = event.getAction() & MotionEvent.ACTION_MASK;
  1. 處理『撳』類型
if(action == MotionEvent.ACTION_DOWN ||

action == MotionEvent.ACTION_POINTER_DOWN)

        Lib.setTouch(ACTION_DOWN,event.getX(),event.getY());else
  1. 處理『撳』類型
if(action == MotionEvent.ACTION_UP ||

action == MotionEvent.ACTION_POINTER_UP ||

action == MotionEvent.ACTION_CANCEL)

        Lib.setTouch(ACTION_UP,event.getX(),event.getY());else
  1. 處理『拖』類型
if(action == MotionEvent.ACTION_MOVE)
Lib.setTouch(ACTION_DRAGGED,event.getX(),event.getY());}

 

 

處理『多點』触摸

  1. 處理多手指触摸, 提取触摸事件索引
int Pointer_Index = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT;
  1. 通過触摸事件索引,『触屏』原點(0,0) 係左上角, 單位象素
MotionEvent.getX(index) X軸指右
MotionEvent.getY(index) Y軸指下
  1. 提取『触屏』事件類型
int action = event.getAction() & MotionEvent.ACTION_MASK;
  1. 處理多手指触摸, 提取触摸事件索引
int Pointer_Index = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT;
  1. 提取觸摸事件量
int Pointer_Count = event.getPointerCount();
  1. 遍歷冚觸摸事件
for(int i=0; i< Pointer_Count; ++i)        {
  1. 跳過冇關觸摸事件
if (action != MotionEvent.ACTION_MOVE && i != Pointer_Index)

continue;

  1. 處理『撳』類型
if(action == MotionEvent.ACTION_DOWN ||

action == MotionEvent.ACTION_POINTER_DOWN)

        Lib.setTouch(ACTION_DOWN,event.getX(i),event.getY(i));else
  1. 處理『撳』類型
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
  1. 處理『拖』類型
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 Service』

Canon Print Service
Canon Print Service
Canon Print Service
Canon Print Service

Mopria Paint』係Android手機平板發影印指令. 如果『Mopria Paint』報『ERROR CODE 853』, 可嘗試『Canon Print Service』,Canon專用Android影印機程式. 同『Mopria Paint』係『外掛程式』後台臺運行, 向Canon發影印指令.

  1. 係其它程式『文檔』『網頁』『影像』
  2. 撳『更多』『分享』
  3. 撳『Canon』.
  4. 自動跳入『影印設定』
  5. 揀『MF745C/746C(192.168.1.6)』
份數 1
紙張尺碼 ISO A4
色彩 黑色/彩色
方向 縱向/橫向
雙面 無/長邊/短邊
  1. 撳『影印』

Android Studio 全屏CUTOUT MODE

Android Studio 全屏CUTOUT MODE
Android Studio 全屏CUTOUT MODE

全屏令人沉浸游戲免受干擾. 收埋頂『狀態』『標題』底『導航』.

  1. 舊時全屏係『Activity:onCreate()』飛『標題』
 requestWindowFeature(Window.FEATURE_NO_TITLE);
  1. 飛『狀態』
Window window =  getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
  1. 上述代碼需係『填充布局』前執行
setContentView(R.layout.activity_main);
  1. 亦可用『全屏样式』係『xml』
<style  name=”Theme.Fullscreen”  parent=”android:Theme.NoTitleBar.Fullscreen” />
  1. 係<application>或<activity>加『全屏样式』
<application android:theme=”@style/Theme.Fullscreen” >
  1. 因Android『導航』由硬件鍵變成『觸摸屏』軟件鍵, 要飛底『導航』飛頂『狀態』. 即『沉㓎模式』要係4 Kit Kat(API 19).
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
  1. 係『Activity:onCreate()』執行『setSystemUiVisibility()』設置沉浸模式
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);

  1. 設置沉浸模式
setSystemUiVisibility() 簡述
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 飛底『導航』
View.SYSTEM_UI_FLAG_FULLSCREEN 飛頂『狀態』
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 自動恢復『沉㓎模式』
View.SYSTEM_UI_FLAG_IMMERSIVE 『沉㓎模式』
  1. 隨『全面屏』追求係手機頭『鑿窿』裝『相機』. 導置『全面屏』變『兔唇屏 』.即『CUTOUT MODE』要係Androd 9.0 Pie(API 28) 受支持.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
  1. 同係設布局『LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES』
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 螢幕喚醒

Android 螢幕喚醒Android 螢幕耗電, 擺低手機螢幕變暗,幷鎖定. 好似你唔惏野會放蚊咁.用『喚醒鎖』WakLock. 保持清醒『螢幕喚醒』.

  1. 先係『xml』添加權限
<uses-permission android:name=”android.permission.WAKE_LOCK” />
  1. 係『onCreate()』獲得電源管理『PowerManager』
PowerManager powerManager;
powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
  1. 生成『WakLock』喚醒鎖. 『FULL_WAKE_LOCK』螢幕保持著燈.CPU全速運行.
PowerManager.WakeLock wakeLock;
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, “WAKE LOCK”);
  1. 係『onResume()』啟用『WakLock』喚醒鎖, 手機保持喚醒態,
wakeLock.acquire();
  1. 係『onPause()』釋放喚醒鎖
wakeLock.release();

 

 

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

 

Android Studio NDK-OpenGL ES 點陣字體

Android Studio NDK-OpenGL ES 點陣字體
Android Studio NDK-OpenGL ES 點陣字體

係游戲渲染文本,『點陣字體』係遠古技術, 係位圖繪畫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;
  1. 拉丁字母
    for(int index = 0; index < 96; ++index){
  1. 生成ASCII字符UV 紋理坐標,『width, height』字符寬高,
Init_Region_Texture(&font->region[index],font->texture,x,y, width, height);
  1. 移動X坐標
x = x + width;
  1. 換行
if(x >= offsetX + width * row){

x = offsetX;

y = y + height;}

 

渲染位圖字庫

  1. 2D頂點座標數組
VECTOR2D  vertex_array[6 * 1024]   ;
  1. UV紋理座標數組
VECTOR2D  texCoord_array[6 * 1024] ;
  1. 啟用2D紋理映射
glEnable(GL_TEXTURE_2D);
  1. 禁用法線
glDisable(GL_NORMALIZE);
  1. 啓用透明測試
glEnable(GL_ALPHA_TEST);
  1. 指定透明色
    glAlphaFunc(GL_GREATER, 0);
  1. 綁定紋理
TEXTURE_PTR texture = font->texture;

glBindTexture(GL_TEXTURE_2D, texture->ID);

  1. 啟用頂點座標數組
glEnableClientState(GL_VERTEX_ARRAY);
  1. 啟用紋理座標數組
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

因為OpenGL『2D相機』原點『0,0』係『左下角』, 返䡛Y軸.

y = Font_frustum_height – y – height;
  1. 逐字渲染『ASCII碼』
for(int index = 0; index < length; ++index ){
  1. 『ASCII碼』轉『紋理索引』, 首ASCII碼係『吉格』,
int c = text[index] – ‘ ‘;
  1. 可渲染拉丁字母96, 『紋理索引』小於0大於96皆唔渲染.
if(c < 0 || c > 96)  continue;
  1. 得到紋理坐標
TEXTURE_REGION_PTR      region = &font->region[c];
  1. 計算2D頂點坐標, 雙『三角形』.
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);

  1. 計算UV紋理坐標, 雙『三角形』.
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);

  1. 指定頂點數組
glVertexPointer(2, GL_FLOAT, 0, vertex_array);
  1. 指定紋理座標
glTexCoordPointer(2, GL_FLOAT, 0, texCoord_array);
  1. 繪畫頂點數組,雙『三角形』.
glDrawArrays(GL_TRIANGLES, 0, 2 * 3 );
  1. 移動下壹渲染位, 分『橫排』同『縱排』
if(VH == FONT_HORIZONTAL)

x = x + width;

else

if(VH == FONT_VERTICAL)

y = y + height;}

  1. 禁用透明測試
glDisable(GL_ALPHA_TEST);
  1. 當前矩陣堆棧出棧
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 ÿ

 

Android Studio NDK-OpenGL ES 透明glAlphaFunc()

Android Studio NDK-OpenGL ES 透明glAlphaFunc()
Android Studio NDK-OpenGL ES 透明glAlphaFunc()

係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, 黑色
  1.  載入纹理圖形卡『RAM』, 設GL_RGBA模式
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width , height , 0, GL_RGBA, GL_UNSIGNED_BYTE,  image);
  1. 啓用透明測試
glEnable(GL_ALPHA_TEST);
  1. 設Alpha值過濾透明色
glAlphaFunc(GL_GREATER, 0);
glAlphaFuncx(GL_GREATER, 0);

 

Android Studio NDK-OpenGL ES-2D相機

Android Studio NDK-OpenGL ES-2D相機
Android Studio NDK-OpenGL ES-2D相機

OpenGL有『平行投影』同『透視投影』, 2D相機係『平行投影』生成方盒『視體』, 愛蒞剪裁物體, 唔係『視體』內唔『渲染』. 愛蒞『等比例游戲』『平面游戲』

OpenGL『2D相機』原點『0,0』係『左下角』, z軸遠端係負,近端正.

Android『熒屏』原點『0,0』係『左上角』,

  1. 首先指定『矩陣堆棧』為『投影矩陣堆棧』
glMatrixMode(GL_PROJECTION);
  1. 清除殘留矩陣并載入『單位矩陣』,.
glLoadIdentity();
  1. 重置視區尺寸,『視區』變換係『投影』變換之後,『x,y』左下角『0,0』. 『width,height』同視窗尺寸相應『熒屏像素』, 除非想係視窗一部分區域繪畫, 可設較定較細『視區』.
glViewport(x, y, window_width, window_height);
  1. 『平行投影』定方盒『視體』愛蒞剪裁物體, 而唔係3D相機錐形.『left, bottom』指左下角『0, 0』,『right, top』指右上角『width, height』. 熒屏尺寸設『800,600』或『640,480』. 游戲世界尺寸設『80,60』或『64,48』. OpenGL會自動放大與視區相配.『near, far』z軸剪裁面『1, -1』
glOrthof (left,right,bottom,top,near,far);
glOrthof (0, frustum_width, 0, frustum_height, 1, -1);
  1. 指定『視體』中心『x, y』.移動2D相機
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軸遠端剪裁面
  1. 恢復『矩陣堆棧』為『視圖矩陣堆棧』
glMatrixMode(GL_MODELVIEW);
  1. 載入『單位矩陣』,清除殘留矩陣
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();

}

 

Android Studio NDK-獲取JavaVM

Android Studio NDK-獲取JavaVM
Android Studio NDK-獲取JavaVM

『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虛擬機』再行.

  1. 將線程附著係JAVA虛擬機,獲得屬於本線程JNIEnv接口. 返回『零』成功,非『零』為錯誤碼
    if(javaVm->AttachCurrentThread(&env,NULL) == 0)
  1. 係JAVA虛擬機分離綫程.返回『零』成功,非『零』為錯誤碼
    if(javaVm->DetachCurrentThread() == 0)

 

Android Studio NDK-POSIX線程

Android Studio NDK-POSIX線程
Android Studio NDK-POSIX線程

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虛擬機』再行.

  1. 係『NDK』原生代碼用POSIX線程, 加入『h』頭文檔聲明『POSIX Thread APIs』, 係『Android』實現係『Bionic API』庫
#include <pthread.h> // POSIX線程
#include <jni.h>
  1. 用pthread_create()創建線程
int pthread_create(pthread_t * thread,

pthread_attr_t const * attr,

void *(* start_routine)(void *),

void * arg);

  1. 參數
參數 簡介
thread 返回新建綫程句柄
attr 指定線程屬性,傅NULL使用默認值.
start_routine 指向綫程函式地址,
args 線程函式參數
  1. 返回值
0 線程啟動
Error code 錯誤碼
  1. 線程句柄
pthread_t      threadID;
  1. 線程函式參數,要全域變量,若傳多參數要『struct』蒞封裝.
typedef struct OPENGL_TYP{

JNIEnv *env;//   JNI

AAssetManager * aassetManager;// 資源管理

EGLDisplay display ;

EGLSurface surface;// 內核渲染表層

int Width, Height;// 熒屏寬高

}OPENGL,*OPENGL_PTR;

  1. 綫程函式樣板
void * start_rountine (void * args)
  1. 游戲運行綫程實例
void * run_game(void * param){

while (run == true)    {

Update_World();// 更新

Draw_World();// 繪畫

}

}

  1. 緩存JavaVM接口指針
jint JNI_OnLoad (JavaVM* vm, void* reserved){

javaVm = vm;

return JNI_VERSION_1_4;

}

  1. 將線程附著係JAVA虛擬機,獲得屬於本線程JNIEnv接口. 返回『零』成功,非『零』為錯誤碼
    if(javaVm->AttachCurrentThread(&env,NULL) == 0)
  1. 係JAVA虛擬機分離綫程.返回『零』成功,非『零』為錯誤碼
    if(javaVm->DetachCurrentThread() == 0)
  1. 啟動線程
 if( pthread_create(&threadID,  NULL, run_game, openGL) == 0)

return true;

else

return false;

  1. 游戲運行綫程
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 Java 線程Thread()

Android Java 線程Thread()
Android Java 線程Thread()
  1. 係『Java』啟動線程
new Thread(this).start();
  1. 係『Java class』 加入『implements Runnable』愛蒞行線程代碼,
public class GameView extends SurfaceView implements   Runnable {}
  1. 運行線程代碼
@Override

public void run() {

while (true) {

//  Thread Code

}

}

 

Android Studio NDK-OpenGL ES封裝SurfaceView

Android Studio NDK-OpenGL ES封裝SurfaceView
Android Studio NDK-OpenGL ES封裝SurfaceView

係『Android OpenGL ES』用『SurfaceView』蒞畀『OpenGL ES』渲染. 之前『SurfaceView』代碼擺係『MainActivity.java』.更佳方法係『SurfaceView』『Runnable』『SurfaceHolder.Callback』封裝成單獨『GameView calss』.以保持代碼『簡潔』同埋『重用』.

  1. 新建『java』
『File->New->Java Class』
  1. 封裝『Runnable』『Callback』
public class GameView extends SurfaceView implements Runnable,SurfaceHolder.Callback{
  1. 『SurfaceView』變量
int view_width,view_height;

public SurfaceHolder surfaceHolder;

public Surface surface;//用蒞渲染

  1. 構造函數
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);// 設置渲染

}

  1. 初此渲染设置
public void init(Context context){

this.surfaceHolder = getHolder();

this.surfaceHolder.addCallback(this);

this.surface = surfaceHolder.getSurface();

}

  1. 創建表層,啟動渲染線程 run()
@Override

public void surfaceCreated(SurfaceHolder surfaceHolder){

new Thread(this).start();

}

  1. 表層改變, 當手機方向改變触發, 係游戲要禁止旋轉方向.
 @Override

public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height){

view_width = width;

view_height = height;

}

  1. 表層銷毀
@Override

public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

}

  1. 游戲運算渲染線程
@Override

public void run() {

AssetManager assetManager = getContext().getAssets();

Lib.init(assetManager, surface, view_width, view_height);

while (true) {// 請求渲染

Lib.update();

}

}

 

Android Studio NDK-Java原生接口(JNI)

Android Studio NDK-Java原生接口(JNI)
Android Studio NDK-Java原生接口(JNI)

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++』代碼.

  1. 新建『Class』
『File』->『New』->『Java Class』
  1. 新『Java Class』填『java』
  2. 載入共享庫”geomanticcompass.so”
static {

System.loadLibrary(“geomanticcompass”);

}

  1. 声明『native』原生『static』代碼接口.
static public native String stringFromJNI();

 

Android LocationManager.getBestProvider()返回NULL

Android LocationManager.getBestProvider()返回NULL
Android LocationManager.getBestProvider()返回NULL

『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);

}

 

 

Android Studio代碼提示失效

Android Studio代碼提示失效
Android Studio代碼提示失效

編寫『Android』高效歸功於『Android Studio』代碼提示, 近排『Android Studio』冇咗提示, 令『import』冇發自動填寫,源於啟用『Power Save Mode』造成提示失效. 要啟用『代碼提示』禁用『Power Save Mode』.

『File』->『Power Save Mode』

 

Android Studio NDK-OpenGL ES 『正交投影』

Android Studio NDK-OpenGL ES 『正交投影』
Android Studio NDK-OpenGL ES 『正交投影』

3D游戲基于『透視投影』產生立體效果, 而2D游戲戲用『正交投影』產生平面效果, 生成等比例游戲.

  1. 指定視區像素尺碼, 『x』 『y』視區左下角,『width』 『height』視區寬高
glViewport(0,0,width, height);
  1. 設定『矩陣堆栈』為『投影矩陣堆栈』
glMatrixMode(GL_PROJECTION);
  1. 載入單位矩陣, 清除『堆栈』残留『矩陣』,以此唔受先前變换運算影响.
glLoadIdentity();
  1. 『正交投影』運算, Y軸視角『fovy』,Z軸視角『aspect』, 『zNear』近裁剪面距离约摸箱機方向Y軸加 『zFar』远裁剪面距离設較大数值.
gluOrtho( fovy, aspect, zNear, zFar );
  1. 設定『矩陣堆栈』為『模型視圖矩陣堆栈』
glMatrixMode(GL_MODELVIEW);
  1. 載入單位矩陣
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 展現『Structure』

Android Studio 展現『Structure』
Android Studio 展現『Structure』

係『VC6』有『struct』同『Function』检索下拉窗口,可迅速定位代碼. 令工作事半工倍.

係『Android Studio』『struct』同『Function』检索視窗默認收埋.

  1. 撳『View』->『Tool Windows』->『Structure』展現『Structure』視窗
  2. 撳『Alt+7』展現『Structure』視窗
  3. 撳『Show Options Menu』->『Move To』->『Right Top』置於右上角

 

Android Fullscreen 全屏樣式

Android Fullscreen 全屏樣式
Android Fullscreen 全屏樣式

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

 

Android Studio NDK-OpenGL ES/EGL渲染

Android Studio NDK-OpenGL ES/EGL渲染
Android Studio NDK-OpenGL ES/EGL渲染

OpenGL EGL作為平臺冇関 API, 今程序冇視『Linux X Window』『Microsoft Windows』『Mac OS X Quatz』差異.用統壹接口同原生視窗聯接. 跨平臺API更易於移值. 所以OpenGL比DirectX更得人鐘意.

  1. 使用NDK
  2. 編譯OpenGL ES
  3. 布局OpenGL ES
  4. 先加入頭文檔
#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
  1. 冚辦爛EGL程式首先調用『eglGetDisplay()』, 得到『EGLDisplay』等同『原生視窗』, 『EGLDisplay』係整數索引.
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  1. 索引大於零即成功, 因為等於零失敗.
EGL_NO_DISPLAY 0失敗
  1. 初始EGL程式, 幷獲得『major』主版號 , 『minor』副版號
EGLint major,minor;

eglInitialize(display,&major,&minor)  ;

  1. 失敗返回EGL_FALSE, 查錯誤碼eglGetError()
EGL_BAD_DISPLAY 非有效EGLDisplay
EGL_NOT_INITALIZED 未能初始
  1. 穩『surface』渲染配置
EGLBoolean eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
  1. EglChooseConfig()函式參數
參數 簡介
EGLDisplay dpy 『原生視窗』索引
EGLint *attrib_list 指定屬性列表, 以EGL_NONE結屘
EGLConfig *configs 返回配置列表
EGLint config_size 指定配置列表長度
EGLint *num_config 返回配置長度
  1. 『EGLConfig』屬性
屬性 描述
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];
  1. 設定『EGLConfig』屬性
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;  
  1. 據 attrib_array 返回最隹配置config
EGLint    config_number = 32;

EGLConfig config_array[32];

EGLConfig  config;// 配置

eglChooseConfig(display,attrib_array,config_array,config_number,&config_number);

  1. 匹配最佳配置
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;

}

}

  1. 生成渲染視窗
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
  1. eglCreateWindowSurface()函式參數
參數 簡介
EGLDisplay dpy 『原生視窗』索引
EGLConfig config 最佳配置
EGLNativeWindowType win SurfaceView
const EGLint *attrib_list 屬性列表
  1. 渲染視窗屬性
視窗屬性 描述
EGL_RENDER_BUFFER 渲染緩存 EGL_SINGLE_BUFFER『單緩存』EGL_BACK_BUFFER『雙緩存』
EGL_NONE 屬性列表以EGL_NONE結屘 0
  1. 屬性
attrib_array[0] = EGL_RENDER_BUFFER; attrib_array[1] = EGL_BACK_BUFFER;
attrib_array[2] = EGL_NONE;  
  1. 生成渲染視窗
surface_draw = eglCreateWindowSurface(display,config,nativeWindow,attrib_array);
  1. 獲得錯誤碼
錯誤碼EGLint error = eglGetError(); 簡介
EGL_BAD_MATCH 視窗唔匹配EGLConfig唔支持渲染
EGL_BAD_CONFIG 視窗唔匹配EGLConfig系統晤支持
EGL_BAD_NATIVE_WINDOW 原生視窗句柄冇效
EGL_BAD_ALLOC 冇法分配資源
  1. 關聯描述表, 将『EGLContext』『EGLSurface』與當前線程關聯, 『EGL』同『OpenGL』代碼需擺同壹綫程. 唔系eglSwapBuffers()返回
eglMakeCurrent(display,surface_draw,surface_draw,context);
  1. 『Native』層用『ANativeWindow 』蒞渲染.通過『Surface』得到『ANativeWindow』.
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface)
  1. Android 『java』層用『SurfaceView』蒞渲染, 提取『Surface』畀『Native』
SurfaceView surfaceView = (SurfaceView)findViewById(R.id.surface_view);
SurfaceHolder     surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
Surface             surface = surfaceHolder.getSurface();

Android Studio NDK-OpenGL ES布局

Android Studio NDK-OpenGL ES布局
Android Studio NDK-OpenGL ES布局

『Android Studio NDK』提供『EGL』連接『OpenGL』, 『EGL』被設計出來,作爲 OpenGL 和原生窗口系統之間的橋梁『Microsoft Windows』『Mac OS X Quatz』差異.用統壹接口同原生視窗聯接. 跨平臺API更易於移值. 所以OpenGL比DirectX更得人鐘意.

  1. 使用NDK
  2. 編譯OpenGL ES
  3. 載入共享庫”app.so”,『app』系你庫名.
static {

System.loadLibrary(“app”);

}

  1. 首先修改布局『xml』添加『SurfaceView』,而非『GLSurfaceView』.
 <android.view.SurfaceView

android:layout_width=”match_parent”

android:layout_height=”match_parent”

android:id=”@+id/surface_view” />

  1. 係『xml』添加『全屏樣式』
<style  name=”FullscreenTheme”  parent=”android:Theme.NoTitleBar.Fullscreen”  >
  1. 係『java』加『android.view.SurfaceHolder.Callback』用蒞行『SurfaceView』『創建』『改變』『銷毀』
        @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) {

}

  1. 係『java』加『Runnable』用蒞行OpenGL 渲染線程, 『EGL』同『OpenGL』代碼需擺同壹綫程. 唔系eglSwapBuffers()返回EGL_BAD_SURFACE.
    @Override

public void run() {

init( );

while (true) {

update(0);

}

}

  1. 係『xml』為Google Play加版本過濾
<uses-sdk        android:minSdkVersion=”9″       android:targetSdkVersion=”19″ />
  1. 係『txt』穩庫文檔
find_library( OpenGL-lib libGLESv1_CM.so  )
find_library( OpenEGL-lib libEGL.so )
find_library( Android-lib libandroid.so )
  1. 係『txt』連連接庫文檔
target_link_libraries(app

${OpenGL-lib}

${OpenEGL-lib}

${Android-lib})

  1. 加入頭文檔
#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> 原生視窗庫

 

Android Studio NDK-OpenGL ES-3D相機gluPerspective()

Android Studio NDK-OpenGL ES-3D相機gluPerspective()
Android Studio NDK-OpenGL ES-3D相機gluPerspective()

將『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(); 載入單位矩陣

 

Android Studio NDK-OpenGL-交換緩存畫面eglSwapBuffers()返回EGL_BAD_SURFACE

Android Studio NDK-OpenGL-交换緩存画面eglSwapBuffers()返回EGL_BAD_SURFACE
Android Studio NDK-OpenGL-交换緩存画面eglSwapBuffers()返回EGL_BAD_SURFACE

將『風水羅盤』由『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 Studio NDK- assets訪問讀

Android Studio NDK- assets讀係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

 

 

Android Studio NDK-Frames幀

Android Studio NDK-Frames幀
Android Studio NDK-Frames幀

係游戲每『渲染』1『畫面』呌1『幀』Frame,  影書每秒24格『菲林』24『幀』, Android每秒至高60『幀』.

Android Studio NDK

  1. 通過clock()獲得進程時鐘 度量時間整數值.
  2. 通過sysconf(_SC_CLK_TCK) 獲得時鐘信號, 每秒時鐘單元值, 係Linux此值為100
  3. 計算秒 float seconds= (float)clock() / (float)sysconf(_SC_CLK_TCK);
#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-編譯目標唔乾淨

Android Studio NDK-編譯目標唔乾淨
Android Studio NDK-編譯目標唔乾淨

Android Studio NDK編譯又蒞失敗, 『ninja: error: unknown target ‘clean’, did you mean ‘ninja -t clean’? 』大意目標唔乾淨.

  1. 撳『Win+E』進入NDK工程檔䅁夾.
  2. 進入『\app\.cxx\RelWithDebInfo\3t474c6q\』,數字檔䅁夾隨機生成
  3. 進入『arm64-v8a』『armeabi-v7a』『x86』『x86_64』檔䅁夾, 『冚辦爛』刪『子檔䅁』『子文檔』.
  4. 『arm64-v8a』『armeabi-v7a』『x86』『x86_64』保留唔刪
  5. 再蒞編譯掂
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’?

 

Android Studio NDK-OpenGL ES替換gluLookAt()

OpenGL ES替換gluLookAt()
OpenGL ES替換gluLookAt()

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);

}

 

Android Studio NDK编译OpenGL ES

Android Studio NDK编译OpenGL ES
Android Studio NDK编译OpenGL ES

係Android Studio NDK编译OpenGL ES, 需鏈接『libGLESv1_CM.so』庫, 編輯『CMakeLists.txt』.

首先稳『libGLESv1_CM.so』庫

find_library( OpenGL-lib libGLESv1_CM.so )

鏈接『libGLESv1_CM.so』庫

target_link_libraries(  geomanticcompass

${OpenGL-lib}

${log-lib})

 

Android Studio NDK-fprintf()格式字符

Android Studio NDK-fprintf()格式字符
Android Studio NDK-fprintf()格式字符

係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 Studio NDK 日期時間

Android Studio NDK 日期時間
Android Studio NDK 日期時間

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 NDK編譯錯誤 error undefined reference

Android Studio NDK編譯錯誤 error undefined reference
Android Studio NDK編譯錯誤 error undefined reference

新版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缺失插件 missing essential plugin
Android Studio缺失插件 missing essential plugin

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程式入口Application

Android程式入口Application
Android程式入口Application

Android唔似Window有Winmain()/main()作程式入口. 而Android用Application作程式入口. 比Activity更早調用,也唔會因方向改變重複調用onCreate().

將Application.onCreate()當main()用. 將程式『初此』Init()冚辦爛摆何係度.

 

  1. 生永MainApplication继承Application 覆盖onCreate()
class MainApplication extends Application
  1. 配置『xml』
<application android:name=”.MainApplication” ></application>
  1. 係onCreate()『初此』Init()程式

 

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++編程-使用NDK

Android Studio C/ C++編程-使用NDK
Android Studio C/ C++編程-使用NDK

Android Studio C/ C++編程開發环境由以下組件构成:

  1. 装『Android Studio
  2. Android SDK(Software Development Kit) 軟件開發包, Android Studio 己含
  3. Android NDK(Native Development Kit) 原生開發包, Android Studio 己含
  4. Java JDK(Java Development Kit) Android Studio 己包含Java開發包.
  5. CMake构建工具,编译原生库
  6. LLDB調試工具,调试原生代码
  7. 生成C/C++項目
  8. 係『native-lib.cpp』下生成C函式

 

Android Studio安装『NDK』同『CMake』

  1. 撳『Tools』 -> 『SDK Manager』
  2. 撳『Appearance & Behavior』-> 『System Settings』->『Android SDK』
  3. 撳『SDK Tools』
  4. 勾『NDK(Side by side)』
  5. 勾『CMake』
  6. 撳『Apply』下載

 

生成C/C++工程

  1. 啟用Android Studio
  2. 撳『Projects』->『New Project』
  3. 『Templates』撳『Phone and Tablet』手機同平板
  4. 撳『Native C++』
  5. 『Name』指『程式名』填『經倫羅盤/Geomantic Compass』
  6. 『Package name』指『包名』,將网站『域名』倒置加『.程式名』『domain.name』 确保唯壹性,如『net.bookcard.GeomanticCompass』
  7. 『Language』指編程言, 默認『Kotlin』選『Java』.
  8. 『Save location』指工程存檔路徑,只可係ASCII碼,如『D:\Android\GeomanticCompass』
  9. 『Minimum SDK』允許運行Android平臺, 選最細SDK版本,获得盡量多設备支持.
  10. 『Use legacy android support libraries』用旧版android支持库.
  11. 撳『Next』
  12. 『C++ Standard』选择C++ 标准,默認『Toolchain Default』用『 CMake』 设置.
  13. 撳『Finish』自動构建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());

}

  1. 『extern “C”』声明C程式
  2. 『JNIEXPORT』
  3. 『jstring』程式返回類型
  4. 『JNICALL』参数压桟順序
  5. 函式名以『文檔夾路徑』組成,『Java_package_function』區分大細寫.
  6. 函式『Java』開頭, 因位於『Java』根文檔夾
  7. 函式『net_bookcard_geomanticcompass』包名文檔夾
  8. 函式『Lib』指java 文件Lib calss
  9. 函式『stringFromJNI』指函式名
  10. 参數『JNIEnv* env』調用Java函式
  11. 『jobject』
  12. 最後先係函式参數

 

真機調試Android程式

  1. 手機用USB線同电脑相連
  2. 『Build』->『Make Projects』生成工程
  3. 『Run』->『Debug ‘app’』 調試工程

 

 

 

 

配置『系統變數』

  1. 撳『Win+Pause Break』
  2. 撳『變更設定』開啟『系統內容』
  3. 撳『進階』->『環境變數』
  4. 『系統變數』->『新增』
  5. 『變數名稱』
  6. 『變數值』

 

装Android NDK

  1. 撳『File』-> 『Project Structure』或『Ctrl+Alt+Shift+S』
  2. 撳『SDK Location』
  3. 『Android NDK location』撳『Download』下載『Android NDK』
  4. 『Android NDK location』『C:\Users\user\AppData\Local\Android\Sdk\ndk\23.0.7599858』

 

Android Studio默認安装Android SDK

  1. 撳『File』->『New Project Settings』->『Project Structure』
  2. 撳『SDK Location』
  3. 『Android SDK location』『C:\Users\user\AppData\Local\Android\Sdk』

 

Android Studio默認安装Java JDK

  1. 撳『File』->『Project Structure』
  2. 撳『SDK Location』
  3. 『JDK Location』 『C:\Program Files\Android\Android Studio\jre』
  4. 設定『環境變數』

 

 

验証『Java JDK』安装

  1. 開啟命令輸入模式『EXE』
  2. 輸入『java -version』执行
  3. 安装成功則显示JDK版本号

Android Studio設定字體尺碼

Android Studio設定字體尺碼
Android Studio設定字體尺碼

Android Studio默認字體細睇代碼耗神, 而Android Studio唔支持滑輪字體尺碼. 你需要手動設定.

Android Studio設定字體尺碼

  1. 撳『File』->『Settings』或者撳『Ctrl+Alt+S』啟動『Settings』
  2. 撳『Edit』->『Font』
  3. 設定『Size』值默認12, 放大壹倍設
  4. 撳『Apply』应用設定.

Android禁程式頻繁调用onCreate

Android禁程式頻繁调用onCreate
Android禁程式頻繁调用onCreate

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);

}

 

Android程式强制安装SD卡

Android程式强制安装SD卡
Android程式强制安装SD卡

Android程式默認装係内部存储,因佢有极快讀寫速度, 係Android2.2 後可强制装係SD卡, 但SD讀寫慢, 可能會影响程式表現. 編輯AndroidManifest.xml係manifest添installLocation属. 預設装係外部存储 preferExternal.

AndroidManifest.xml
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”

package=”net.bookcard.GeomanticCompass”

android:installLocation=”preferExternal”>

</manifest>

 

Android Studio安装指南

Android Studio安装指南
Android Studio安装指南
初建Android 工程Hello World
初建Android 工程Hello World
真機調試Android程式
真機調試Android程式

装Android Studio可簡化搭建開發环境過程. 且集成『Open JDK』同『Android SDK』

Android Studio安装指南

  1. 下載android Studio『https://developer.android.com/studio』『android-studio-2020.3.1.24-windows.exe
  2. Android Studio 安装路径『C:\Program Files\Android\Android Studio』
  3. 『Install Type』勾『Custom』自定.
  4. 自Android Studio2.2已集成『Open JDK』,『Select Default JDK Location』安装檔案夾『C:\Program Files\Android\Android Studio\jre』
  5. 界面主题『Select UI Theme』有Darcula同Light揀. 白底黑字更適宜睇文本
  6. 『SDK Components Setup』勾『Android SDK』『API:Android 』
  7. 『Downloading Components』安装完成.

 

SDK Manager装Android SDK 組件

  1. 啟動『Android Studio』
  2. 『Settings for New Projects』
  3. 『Appearance & Behavior->System Settings->Android SDK->SDK Tools』

 

初建Android 工程Hello World

  1. 啟動『Android Studio』
  2. 撳『Projects->New Project』
  3. 撳『Phone and Tablet』手機同平板
  4. 『模板』撳『Empty Activity』.
  5. 『Name』指『程式名』填『風水羅盤』
  6. 『Package name』指『包名』,將网站『域名』倒置加『.程式名』『domain.name』 确保唯壹性,如『net.bookcard.GeomanticCompass』
  7. 『Language』指編程言, 默認『Kotlin』選『Java』.
  8. 『Save location』指工程存檔路徑,只可係ASCII碼,如『D:\Android\GeomanticCompass』
  9. 『Minimum SDK』允許運行Android平臺, 選最細SDK版本,获得越多運行設备支持.
  10. 『Use legacy android support libraries』用旧版android支持库.
  11. 撳『Finish』

 

激活手機/平板開發模式

  1. 撳『設定』->『我的裝置』->『全部参數』.
  2. 連續撳『版本』, 直至提示进入『開發人員模式』.
  3. 撳『設定』->『更多設定』->『開發者選項』.
  4. 激活『開啟開發人員選項』
  5. 激活『USB調試』
  6. 激活『USB安装』
  7. 激活『USB調試(安全設定)』

 

真機調試Android程式

  1. 手機用USB線同电脑相連
  2. 『Run』->『Debug ‘app’』

 

手機WIFI影印程式Mopria Paint

手機WIFI影印程式Mopria Paint 手機WIFI影印程式Mopria Paint 手機WIFI影印程式Mopria Paint近日台Canon影印機MF746Cx條USB過機線斷左.其實現在Canon已支持網絡影印.無需再透過電腦影印.

Canon影印機設定WIFI

  1. 『首頁』->『功能表』->『參數選擇』->『網絡』
  2. 設定『網絡』要填寫ID與PIN碼,默認7654321
系統管理器ID: 7654321
系統管理器PIN: 7654321
  1. 『網絡』->『無線區域網絡設定』->『SSID設定』->『選擇存取點』
  2. 選擇WIFI后撳『下一步』
  3. 鍵入『密碼』撳『套用』
  4. WIFI自動連線

 

裝Mopria Paint影印程式

  1. android手機裝Mopria Paint
  2. 『手機』與『影印機』需連同一WIFI網絡.勿手機連4G網絡而『影印機』連5G網絡.否則 Mopria Paint穩唔到『影印機』
  3. WI-FI顯示Canon MF745C/746C

 

Mopria Paint支持三種影印方法

  1. 撳『影印機』『更多』『分享』
  2. 撳『影印機』或『Mopria Print』自動跳入『Mopria Paint』
  3. 影印設定
影印機 Canon MF745C/746C
份數 1
紙張大小 ISO A4
色彩 黑色/彩色
方向 縱向/橫向
雙面 無/長邊/短邊
  1. 撳『影印機』圖示影印.

Android掌機HANDHELD GAME STATION設置WIFI

Android掌機HANDHELD GAME STATION設置WIFI Android掌機HANDHELD GAME STATION設置WIFI新購買Android掌機需連接其自帶『游戲商店』下載游戲.在此之前需要連接WIFI.

  1. 長按HOME鍵進入『系統設置』
  2. 『掌機設定』->『Wi-Fi』按A鍵進入
  3. 『Wi-Fi狀態』按左右鍵『開啓』
  4. 『鏈接Wi-Fi網絡』按A鍵進入
  5. 按上下鍵選擇按A將連接.
  6. 輸入密碼登入網絡
  7. 按D鍵登出.

Android掌機HANDHELD GAME  STATION

Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION Android掌機HANDHELD GAME STATION

HANDHEL_GAME_STATION

Android掌機HANDHELD GAME STATION

多年前曾買過部PSP.後借給一女仔後再無返過我手.無意中在網絡睇到Android游戲掌機HANDHELD GAME STATION.可能太多人購買.2019年12月29號落單,直到2020年1月2號先發貨,順豐隔日送達.通過Android模擬器支持掌機游戲.但居然『無法安裝』PSP游戲.可能是類別錯誤設爲PPSSPP有関.只能等『游戲商店』更新修復.

您無法安裝此游戲,因爲此游戲不支持您的設備

通過USB接口充電但無送USB叉機.且邊玩邊叉電較慢.且按鍵好硬.因類雜牌游戲掌機.儅不在生成時其『游戲商店』亦不再營運.强烈建議先將全部游戲下載.

硬件 簡述
CPU 1.3GMHz 四核
GPU MAIL-400
記憶躰 雙通道512MB
TF插卡 128GB-MicroSD
WIFI 2.4G在綫下載游戲與更新系統.未支持5G網絡
電池 鋰電4000mAH
屏幕 3.5英寸IPS高清硬屏
藍牙 4.0無綫手制
HDMI接口 支持
硬體版本 GBX2000_MB_VD
固體版本 GBX2000V1開發版

 

硬件按鍵 簡述
搖杆 街機
方向鍵 焦點切換
HOME鍵 短按退出儅前界面

主界面模式長按進入系統設置.

SELECT鍵 街機投幣
START鍵 開啓游戲
+/-鍵 調節喇叭音量
START鍵+音量鍵 調節屏幕亮度
X鍵 進入游戲商店
A鍵 OK
B鍵 CANCEL
D鍵 退出
電源鍵 長按關機

短按休眠

 

模擬器 簡述
FC 任天堂/紅白機
SFC 超級任天堂
N64 任天堂64
DC  
WS/WSC 萬代
MA/ME  
FBA 街機
PS Play Station游戲無發保存
PSP Play Station Portable『游戲商店』無法下載
MD 世嘉
GBA Game Boy Advance
GB/GBC Game Boy /Game Boy Color
PCE PC Engine

 

 

Android刷機之晶晨燒錄工具USB Burning Tool

Android刷機之晶晨燒錄工具USB Burning Tool
Android刷機之允許計算機關閉這個設備以節約電源
Android刷機之晶晨燒錄工具USB Burning Tool
Android刷機之安裝驅動
Android刷機之晶晨燒錄工具USB Burning Tool

Android系統通病是越用越慢.近日對台『雜牌古董』Android重寫系統,過程尚算順利. 使用『晶晨燒錄工具』USB Burning Tool進行線擦並把其過程記錄

  1. 你需要一台WinXP
  2. 安裝『晶晨燒錄工具』USB Burning Tool此軟件專門用來寫機
  3. 『固件包』壓縮為ZIP文檔.一定要下載相對應機型與板本
  4. 確保USB接口不被其它設備佔用『設備管理器/通用串行總線控制器/USB Root Hub/屬性/電源管理』.取消勾選『允許計算機關閉這個設備以節約電源』禁用.
  5. 對所有『USB Root Hub』重複第三步
  6. 打開『晶晨燒錄工具』USB Burning tool目錄啟動exe
  7. 『文件->導入升級文件』載入『固件包』
  8. 插USB線連接Android與USB線要質量好
  9. 關閉Android系統,按住HOME鍵不放.然後再按Power鍵不放.等待3秒再鬆開HOME鍵與Power鍵.進入Recovery模式
  10. 此時你可能要安裝驅動.指定驅動路徑如:『USB-Burning-tool\AmlogicusbBurningdriver\xp\WorldCup_Device.inf』.只有安裝驅動『USB Burning Tool』才可認到設備
  11. 若已安裝驅動『USB Burning Tool』則會發現設備.點擊『開始』對Android進行升級
  12. 對Android寫入『固件』大約要十分鐘.當進度達100%時升級成功. 點擊『停止』拔出USB線
  13. 若勾選『擦除舊系統後重啟並燒錄』Android會重啟.然後重做第9步.
  14. 若寫入失敗或wait,先按『複位』Reset鍵.若無則跳過.然後從第9步開始重新寫入固件

Android遊戲之跟隨相機

Android遊戲之跟隨相機

『跟隨相機』與『歐拉相機』喂一區別在於屬性設置不同.跟隨相機常將它固定在移動物體上.它需要以下屬性:

3D空間位置position

向上向量.相當於在相機上貼上一個向上箭頭up

視點向量即相機視口朝向目標lookAt

遠裁剪面far

近裁剪面near

『視場』即視口角度fieldOfView

視口縱橫比aspectRatio

再移動相機時你需要分被相機『位置』與『視點』.『跟隨相機』生成代碼:

設定相機視口,寬與高為屏幕分辨率

gl.glViewport(0,0,width,height);

設置相機矩陣,將當前堆棧設為投影矩陣

gl.glMatrixMode(GL10.GL_PROJECTION);

棧頂載入單位矩陣

gl.glLoadIdentity();

設置透視投影矩陣.定義視錐體參數.『視口角度』『視口縱橫比』『遠近裁剪面』

GLU.gluPerspective(gl, fieldOfView, aspectRation, near, far);

將當前堆棧設為模型視圖矩陣

gl.glMatrixMode(GL10.GL_MODELVIEW);

棧頂載入單位矩陣

gl.glLoadIdentity();

生成方位矩陣,好處在於能防止出現弄反位置或角度

GLU.gluLookAt(gl, position.x,position.y,position.z,

lookAt.x, lookAt.y, lookAt.z,

up.x, up.y, up.z);

Android遊戲之第一人稱相機(歐拉相機)

Android遊戲之第一人稱相機(歐拉相機)

歐拉相機即第一稱射擊遊戲中時用相機.你需要定義以下屬性

『視場』即視口角度fieldOfView

視口縱橫比aspectRatio

遠裁剪面far

近裁剪面near

3D空間位置position

繞y軸旋轉角yaw

繞x軸旋轉角pitch.角度值-90~+90度之間.這類似於頭部傾斜角.若超過這角度則造成骨折.

 

設定歐拉相機視口,寬與高為屏幕分辨率

gl.glViewport(0,0,width,height);

設置歐拉相機矩陣.首先將當前堆棧設為投影矩陣

gl.glMatrixMode(GL10.GL_PROJECTION);

棧頂載入單位矩陣

gl.glLoadIdentity();

設置投影矩陣.你需定義要視錐體

GLU.gluPerspective(gl, fieldOfView, aspectRatio, near, far);

設為模型視圖矩陣

gl.glMatrixMode(GL10.GL_MODELVIEW);

棧頂載入單位矩陣

gl.glLoadIdentity();

繞x軸旋轉角度

gl.glRotatef(-pitch,1,0,0);

繞Y軸旋轉角度

gl.glRotatef(-yaw,0,1,0);

移動相機,相機位於原點且鏡頭指向z軸負方向

gl.glTranslatef(-position.x,-position.y,-position.z);

 

獲取相機方向

相機未旋轉時指向z軸負向

float[] inVec = {0,0,-1,1};

float[] outVec = {0,0,0,0};

設置單位矩陣

float[] matrix = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};

Matrix.setIdentityM(matrix,0);

繞x軸俯仰

Matrix.rotateM(matrix, 0, yaw,0,1,0);

繞Y軸旋轉

Matrix.rotateM(matrix, 0, pitch,1,0,0);

將矩陣和向量相乘的單位方向向量

Matrix.multiplyMV(outVec, 0, matrix, 0, inVec, 0);

direcion.set(outVec[0],outVec[1],outVec[2]);

 

 

Android遊戲之紋理鏈Mipmap

Android遊戲之紋理鏈Mipmap

當相機遠離模型時,模型也會變小.其紋理渲染採樣時會顆粒狀失真.解決失真問題關鍵在於讓屏幕中體積較小物體或遠離視點時.使用低分辯率『紋理Texture』圖像.稱值為紋理鏈.首先獲取紋理尺寸.然後創建比小分辨率紋理圖,把分辨率縮小一半.重複這一過程直到分辨率為1.為了在OpenGL ES使用紋理鏈,需要執行以下兩步

  1. 將縮小係數過濾器設置為GL_XXX_MIPMAP_XXX這裡設置為如果不使用MIPMAP.只會使用首個紋理
  2. 通過縮小紋理創建圖鏈.並將圖片上傳提交給OpenGL ES.作為當前圖層.圖層從0開此,0圖層為原始圖層,然後上傳圖層.然後將其寬度與高除以2不斷創建縮小圖層並上傳.回收位圖.直到寬與高等於零.最後一張紋理1*1像素.則退出循環.並且紋理鏈只能綁定單一紋理
  3. 對於3D模形使用紋理鏈mipmap,而在2D材質無需應用
  4. 若啟用mipmap所繪製物較小.性能提升較明顯.因為GPU只需從小圖片中提取紋理元素
  5. 若啟用mipmap紋理鏈會比沒有使用多佔用33%記憶體.但可換來視角效果提升.特別對遠景物體可修正粒狀失真.
  6. mipmap紋理鏈僅對正方形紋理有效.並且僅在OpenGL ES 1.x獲得支持.

 

紋理位圖載入與綁定.在其基礎加入紋理鏈代碼

GL10 gl = GRAPHICS.gl;

生成空的紋理對象,並獲取id

gl.glGenTextures(1, ids,0);

int id = ids[0];

讀取紋理圖

Bitmap  bitmap = BITMAP.Read(file_name);

綁定紋理ID

gl.glBindTexture(GL10.GL_TEXTURE_2D, id);

設置紋理屬性,紋理過濾器,指定縮小倍數過濾器

gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);

指定放大倍數過濾器

gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

獲取紋理寬度與高度

int    width = bitmap.getWidth();

int    height = bitmap.getHeight();

原始圖層索引為0

int level = 0;

while(true) {

上傳紋理

GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);

圖層索引號加一

++level;

計算縮小一半紋理位圖寬與高

int newWidth = bitmap.getWidth()/2;

int newHeight = bitmap.getHeight()/2;

寬與高等於零時跳出循環

if(newWidth == 0)

break;

創建縮小一半紋理位圖

Bitmap  newBitmap = Bitmap.createBitmap(newWidth,newHeight,bitmap.getConfig());

Canvas canvas = new Canvas(newBitmap);

canvas.drawBitmap(bitmap,

new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()),

new Rect(0,0,newWidth,newHeight),

null);

回收位圖資源

bitmap.recycle();

bitmap = newBitmap;

}

取消邦定紋理ID

gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);

回收位圖資源

bitmap.recycle();

 

Android遊戲之射燈

Android遊戲之射燈

射燈是OpenGL ES中燈光中最耗GPU資源燈光.但其3D效果十分逼真.睇上圖.射燈有多個參數需指定.『位置』『照射方向』『照射角度』小於180度、『衰減指數』小於零,若設為0則亮度不衰減,實制『衰減值』與遊戲3D空間尺寸有關.這裡設為0.01.以及三個光照顏色『環境色』『漫反射色』『鏡面反射色』

public class LightSpot {

private float[] ambient  = {1.0f, 1.0f, 1.0f, 1.0f};// 射燈-環境色

private float[] diffuse  = {1.0f, 1.0f, 1.0f, 1.0f};// 射燈-漫反射色

private float[] specular = {0.0f, 0.0f, 0.0f, 1.0f};// 射燈-高光顏色

private float[] position = {0.0f, 3.0f, 0.0f, 1.0f};// 射燈-位置

private float[] direction = {0.0f, -1.0f, 0.0f, 0.0f};// 射燈-方向

private float  cutoff    = 45;// 射燈-角度範圍,缺省為180.0

private float  exponent  = 0.01f;// 衰減指數,缺省為0.0f

int     id = 0;// 光照ID

// 射燈ID 輸入:GL10.GL_LIGHT0至GL10.GL_LIGHT7

LightSpot(int ID){

this.id = ID;

}

//設置射燈方向,轉換為方向向量.最後w分量設0,代表方向

public void setDirection(float x,float y,float z){

direction[0] = x – position[0];

direction[1] = y – position[1];

direction[2] = z – position[2];

direction[3] = 0;

}

// 設定射燈位置.w分量設為1代表位置向量

public void setPosition(float x,float y,float z){

position[0] = x;

position[1] = y;

position[2] = z;

position[3] = 1;

}

// 設定射燈顏色

public void setColor(float r,float g,float b){

ambient[0] = r;

ambient[1] = g;

ambient[2] = b;

ambient[3] = 1;

}

//使能射燈

public void enable(){

GL10 gl = GRAPHICS.gl;

gl.glEnable(id);//使能

gl.glLightfv(id,GL10.GL_AMBIENT, ambient, 0);// 射燈-環境色

gl.glLightfv(id,GL10.GL_DIFFUSE, diffuse, 0);// 射燈-漫反射色

gl.glLightfv(id,GL10.GL_SPECULAR, specular, 0);// 射燈-高光顏色

gl.glLightfv(id,GL10.GL_POSITION, position, 0);// 位置

gl.glLightfv(id,GL10.GL_SPOT_DIRECTION, direction, 0);// 方向

gl.glLightf(id,GL10.GL_SPOT_CUTOFF,cutoff); //  角度範圍

gl.glLightf(id,GL10.GL_SPOT_EXPONENT,exponent);// 衰減指數

}

// 屏蔽射燈

public void disable(){

GL10 gl = GRAPHICS.gl;

gl.glDisable(id);

}

}

Android遊戲之材質

Android遊戲之材質

物體都由特定材質構成.材質決定照射在物體上光返射方式並會改變反射光顏色.材質為多邊形設置材質屬性用於光照計算,它是全域性影響所有繪製多邊形,直到它在次調用.OpenGL ES中需要為每種材質指定『環境色』『漫反射色』『鏡面反射色』RGBA顏色值.此材質吸收光.只有『光源顏色』與『材質顏色』最小值運算(RGB值)得到『反射光顏色』

材質顏色 光源顏色 反射光顏色『最小值運算』
(0,1,0) (1,1,1) (0,1,0)
(0,1,0) (1,0,0) (0,0,0)
(0,0,1) (1,1,1) (0,0,1)

材質類代碼

public class Material {

private float[] ambient  = {1.0f, 1.0f, 1.0f, 1.0f};// 材質-環境色

private float[] diffuse  = {1.0f, 1.0f, 1.0f,  1.0f};// 材質-漫反射色

private float[] specular = {1.0f, 1.0f, 1.0f, 1.0f};// 材質-鏡面顏色

//設置材質環境色

public void setAmbient(float r,float g,float b){

ambient[0]=r;

ambient[1]=g;

ambient[2]=b;

ambient[3]=1;

}

// 設置材質漫反射色

public void setDiffuse(float r,float g,float b){

diffuse[0]=r;

diffuse[1]=g;

diffuse[2]=b;

diffuse[3]=1;

}

// 設置材質鏡面反射色

public void setSpecular(float r,float g,float b){

specular[0]=r;

specular[1]=g;

specular[2]=b;

specular[3]=1;

}

//使能材質

public void enable(){

GL10 gl = GRAPHICS.gl;

gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_AMBIENT,  ambient, 0);// 環境色

gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_DIFFUSE,  diffuse, 0);//  漫反射色

gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_SPECULAR, specular,0);//  鏡面反射色

}

}

Android遊戲之定向光

Android遊戲之定向光

定向光具有方向但沒有位置.首先在3D空間定義一個點,而『方向』表示為該點指向『原點』向量之方向.若在3D空間右則射過來定向光

public class LightDirectional {

private float[] ambient  = {1.0f, 1.0f, 1.0f, 1.0f};// 點光-環境色

private float[] diffuse  = {1.0f, 1.0f, 1.0f, 1.0f};// 點光-漫反射色

private float[] specular = {0.0f, 0.0f, 0.0f, 1.0f};// 點光-高光顏色
private float[] direction = {0, 0, -1, 0};// 定向光-方向

int id = 0;//  燈光ID

構造定向光.燈光id:GL10.GL_LIGHT0至GL10.GL_LIGHT7

public LightDirectional(int ID){

this.id = ID;//  燈光ID

}

設置方向,將位置轉換為方向.將w分量設0,代表方向

public void setDirection(float x,float y,float z){

direction[0] = -x;

direction[1] = -y;

direction[2] = -z;

direction[3] = 0;

}

設置定向光顏色

public void setColor(float r,float g,float b){

ambient[0] = r;

ambient[1] = g;

ambient[2] = b;

ambient[3] = 1;

}

使能設置頂向光顏色環境色、漫反射色、高光顏色、位置.最後一個參數是數組索引

public void enable(){

GL10 gl = GRAPHICS.gl;

gl.glEnable(id);//使能

gl.glLightfv(id,GL10.GL_AMBIENT, ambient, 0);

gl.glLightfv(id,GL10.GL_DIFFUSE, diffuse, 0);

gl.glLightfv(id,GL10.GL_SPECULAR, specular, 0);

gl.glLightfv(id,GL10.GL_POSITION, direction, 0);

}

定向光屏蔽

public void disable(GL10 gl){

gl.glDisable(id);

}

}

Android遊戲之點光

Android遊戲之點光

點光(燈光)特點是有固定3D位置.首先你需要啟用0號燈光

gl.glEnable(GL10.GL_LIGHT0);

設定燈光顏色,燈光索引為0,最後一個參數是顏色數組偏移量.

float[] ambient = {1.0f, 1.0f, 1.0f, 1.0f};// 點光-環境色

float[] diffuse  = {1.0f, 1.0f, 1.0f, 1.0f};// 點光-漫反射色

float[] specular = {0.0f, 0.0f, 0.0f, 1.0f};// 點光-高亮顏色

gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_AMBIENT, ambient, 0);

gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_DIFFUSE, diffuse, 0);

gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_SPECULAR, specular, 0);

設定燈光位置,設定3D空間xyz座標,第四個元素必須設置為1,即光源有位置.

float[] position = {0, 0, 0, 1};// 點光-位置

gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_POSITION, position, 0);

完成渲染後關閉燈光

gl.glDisable(GL10.GL_LIGHT0);

燈光類代碼

public class LightPoint {

private float[] ambient  = {1.0f, 1.0f, 1.0f, 1.0f};// 點光-環境色

private float[] diffuse  = {1.0f, 1.0f, 1.0f, 1.0f};// 點光-漫反射色

private float[] specular = {0.0f, 0.0f, 0.0f, 1.0f};// 點光-高亮顏色

private float[] position = {0, 0, 0, 1};// 燈光位置

int id = 0;//  燈光ID

構造點光(燈泡) 燈光ID輸入:GL10.GL_LIGHT0至GL10.GL_LIGHT7

public LightPoint(int ID ){

this.id = ID;//  燈光ID

}

設定點光(燈泡)位置

public void setPosition(float x,float y,float z){

position[0] = x;

position[1] = y;

position[2] = z;

position[3] = 1;

}

設定點光(燈泡)顏色

public void setColor(float r,float g,float b){

ambient[0] = r;

ambient[1] = g;

ambient[2] = b;

ambient[3] = 1;

}

使能點光(燈泡)

public void enable(){

GL10 gl = GRAPHICS.gl;

gl.glEnable(id);//使能

gl.glLightfv(id,GL10.GL_AMBIENT, ambient, 0);

gl.glLightfv(id,GL10.GL_DIFFUSE, diffuse, 0);

gl.glLightfv(id,GL10.GL_SPECULAR, specular, 0);

gl.glLightfv(id,GL10.GL_POSITION, position, 0);

}

屏蔽點光(燈泡)

public void disable(){

GL10 gl = GRAPHICS.gl;

gl.glDisable(id);

}

}

Android遊戲之環境光

Android遊戲之環境光

環境光是一種特殊光.它沒有位置和方向.它只會均勻照射3D空間中所有物體.在OpenGL ES中啟用全域環境光.

啟用光照

gl.glEnable(GL10.GL_LIGHTING);

環境光純白色,色域範圍為0~1浮點數.影射對應0~255整數

float[] color = {1.0f,1.0f,1.0f,1f};// 環境光浮點數組

設定環境光最後參數color偏移量通常設為0

gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, color, 0);

全域環境光代碼

public class LightAmbient {

static private float[] color = {1.0f,1.0f,1.0f,1f};// 環境光

//設定環境光

static public void setColor(float r,float g,float b ){

color[0] = r;

color[1] = g;

color[2] = b;

color[3] = 1;

}

//使能環境光

static public void enable(){

GL10 gl = GRAPHICS.gl;

gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, color, 0);

}

}

Android遊戲之光照

Android遊戲之光照

光照系統它可以令3D遊戲更加逼真.要模擬光照需要光源發射光線.和被光照照射物.最後需要一台相機捕足光源發射光以及被物體反射光.光照會改變觀察者對被觀察者物體顏色感受.取卻於以下幾個因素

  1. 光源類型
  2. 光源顏色和強度
  3. 光源相對於被照射物體位置和方向
  4. 被照射物材質和紋理

被照射物體反射光強度取決於光照射到至物體平面時光與物體平面夾角.光與其所照射平面越接近垂直,物體表面反射光強度越大

一旦光照射到平面它會以兩種方式反射.鏡面反射會物體上表現出強光效果.物體鏡面反射效果取決於材質.

漫反射:大部分反射光線會因為物體不規則表面而隨機地發散開來,具有光滑表面

鏡面反射:光照射到光滑鏡面後返射回來,具有粗糙不平整表面是不可能形成

而光照射到表面時反射光顏色還取決於光源和材質顏色.

OpenGL ES可以創建出四種不同光源

環境光源:環境光本身非光源,而是由所在環境中其它光源發出光反射在周圍得到.這些環境光混合形成照明效果.環境光無方向並且被環境光照射所有物體都有共同亮度.

點光源:點光源在空間中有固定位置,並且向個方向照射.如燈泡

定向光源:定向光需要一個方向並延伸至無限遠.如太陽是標準定向光源

投射光源:在3D空間中有固定位置.並且有個照射方向.並且具有錐形照射區域.如街燈就是標準投射光.但很耗GPU資源.

OpenGL ES允許指定光顏色與強度,使用RGBA指定顏色

環境光色:被照射無體整體受到光色.物體將會接受這種顏色照射.並且與光源位置和方向無關.

漫反射色:物體反射時受到光色.背著光源另一面不會被照射到

鏡面反射色:鏡面反射色僅僅影響面向觀察者和光源面

投射色:僅影響錐型照射物

啟用光照,一旦開啟光照系統將被應用於所有渲染.你還需要指定光源與材質以及頂點法線確定最後光照效果

GL10.glEnable(GL10.GL_LIGHTING);

渲染完成必需關閉光照.否則影響之後GUI渲染.

GL10.glDisable(GL10.GL_LIGHTING);

OpenGL ES允許每個場景中最多使用8個光源,外加一個全域光源.光源ID從GL10.GL_LIGHT0至GL10.GL_LIGHT7

光源0使能並將其應用所有渲染物

GL10.glEnable(GL10.GL_LIGHT0);

若想單獨禁用某光源

GL10.glDisable(GL10.GL_LIGHT0);

光源實現代碼
環境光
定向光
燈光
射燈
材質

 

 

Android遊戲之矩陣和變換

Android遊戲之矩陣和變換

OpenGL ES矩陣提供以下運算能力

  1. 『矩陣』可將『頂點』移動glTranslatef()
  2. 『矩陣』縮放『頂點』,即將『頂點』個座標分量剩以縮放值glScalef()
  3. 『矩陣』可令『頂點』繞某軸旋轉glRotatef()
  4. 『頂點』剩以『單位矩陣』相當於剩 glLoadIdentity()
  5. 兩個『矩陣』相剩得到新『矩陣』剩以某個頂點.相當於兩『矩陣』剩以頂點後再相剩glMultMatrixf()

OpenGL ES提供有三種『矩陣』

投影矩陣:建立視錐體形狀和尺寸.它決定投影類型和睇到範圍

模型視圖矩陣:在模型空間中用該矩陣變換3D模型.並將其在3D空間中移動

紋理矩陣:用於動態操縱紋理矩陣

設置當前矩陣為『投影矩陣』

GL10.glMatrixMode(GL10.GL_PROJECTION);

在棧頂載入單位據陣

GL10.glLoadIdentity();

然後剩以正交投影矩陣

GL10.glOrthof(-1,1,-1,1, 1, -1);

設置當前矩陣『模型視圖矩陣』

GL10.glMatrixMode(GL10.GL_PROJECTION);

在棧頂載入單位據陣

GL10.glLoadIdentity();

3D空間中平移

GL10.glTranslatef(x,y,z);

繞Y軸旋轉

GL10.glRoate(angle,0,1,0);

將當前棧頂拷貝並壓入棧頂

GL10.glPushMatrix();

矩陣棧頂出棧

GL10.glPopMatrix();

Android遊戲之透明混合

Android遊戲之透明混合

OpenGL要啟用混合,要將每個頂點顏色ALPHA分量置設為0.5f.這樣模型後方對象都能透過模型睇到

1.       OpenGL ES 將在『深度緩存Z-Buffer』和『幀緩存』中渲染模型

2.       OpenGL ES結合z-buffer啟用混合時.必需確保所有透面對象跟據其距離照相機遠近按升序排序.並且從後往線渲染對象.所有非透明必須在透明對象之前被渲染,而非透明對象不需要經過排序

啟用混合:

1.       啟用深度檢測(Z軸緩存)一定要調用glEnable(GL_DEPTH_TEST);.保證光照正確繪製和模形前後正確繪製

2.       啟用混合gl.glEnable(GL10.GL_BLEND);

3.       設定混合方程式gl.glBlendFunc(GL10.GL_SRC_ALPHA,GL10.GL_ONE_MINUS_SRC_ALPHA);

4.       設定模型透明度gl.glColor4f(1.0f, 1.0f, 1.0f,0.5f);

5.       完成渲染後禁用混合glDisable(GL_BLEND);

當需要在OpenGL ES中啟用混合.需要按以下方式渲染

1.       首先渲染所有不透明對象

2.       將所有透明對象按照其與相機距離運近排序(由遠及近)

3.       渲染排好序透明對象(由遠及近)

混合係數

簡介

GL_ZERO

將顏色設為{0,0,0,0}

GL_ONE

不改變當前顏色(r,g,b,a)*(1,1,1,1)

GL_SRC_COLOR

目標與來源相乘dest (r,g,b,a)* sour (r,g,b,a)

GL_DST_COLOR

來源與目標相乘sour (r,g,b,a)* dest (r,g,b,a)

GL_ONE_MINUS_SRC_COLOR

(r,g,b,a)*((1,1,1,1)- sour(r,g,b,a))

GL_ONE_MINUS_DST_COLOR

(r,g,b,a)*((1,1,1,1)- dest(r,g,b,a))

GL_SRC_ALPHA

(r,g,b,a) * sour(alpha)

GL_DST_ALPHA

(r,g,b,a) * dest(alpha)

GL_ONE_MINUS_SRC_ALPHA

(r,g,b,a) * (1- sour(alpha))

GL_ONE_MINUS_DST_ALPHA

(r,g,b,a) * (1- dest(alpha))

GL_SRC_ALPHA_SATURATE

(r,g,b,a) *MIN (sour(alpha),1-dest(alpha))

 

Android遊戲之z-buffer

Android遊戲之z-buffer

OpenGL中『幀緩存』用於儲存屏幕每個像素.而z-buffer『深度緩存』則儲存像素『深度值』.『深度值』為3D空間中對應點與相機『近裁剪面』距離.

OpenGL ES將z-buffer『深度緩存』為每個像素寫入深度值.OpenGL ES會初此『深度緩存』每個深度值為無窮大(大數).

gl.glEnable(GL10.GL_DEPTH_TEST);

每當渲染像素時將像素深度值和『深度緩存』深度值進行比較.如果深度值更小則表示它接近於『近裁剪面』則更新『幀緩存』像素與『深度緩存』深度值.這一過程稱為『深度測試』.如果未能通過『深度測試』則像素與深度值均不寫入『幀緩存』與『深度測試』

每幀渲染時『幀緩存』與『深度緩存』均需清零.否則上一幀數據會被保留下來

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

在渲染所有3D場景後需關閉『深度測試』.因為渲染2D圖形UI元素無Z軸座標.更無需深度測試.渲染順序由代碼繪製順序決定.

gl.glDisable(GL10.GL_DEPTH_TEST);

Android遊戲之透視投影

Android遊戲之透視投影

2D遊戲使用『正交投影』這意味著模型與視點距離無論多遠,其屏幕尺寸大小總為一至.而3D遊戲則使用『透視投影』模型離視點越近其屏幕尺寸越大.而模型離視點越遠其屏幕尺寸越細.

在『正交投影』就像置身於『矩形盒』.而『透視投影』就像切掉『金字塔』頂部,頂部為『近裁剪面』底部為『遠裁剪面』.而另外四面則分別為『左裁剪面』『右裁剪面』『頂裁剪面』『底裁剪面』

透視錐體由四個參數組成

1.『近裁剪面』與相機矩離

2.『遠裁剪面』與相機矩離

3.視口縱橫比,即視口『近裁剪面』寬高比

4.『視場』指定視錐體寬,也就是它所容納場景

桌面OpenGL帶有GLU輔助函式庫.而Android系統也含有GLU庫.設置投影矩陣

GLU.gluPerspective(GL10 gl,float fieldOfView,float aspectRatio,float near,flat far);

該函式將『透視投影矩陣』與當前矩陣相乘.

gl:為GL10實例

fieldOfView:視場角度,人眼視場角大約67度.加減此值可調整橫向視察範圍

aspectRatio:視口縱橫比,此值為一浮點數

near:遠裁剪面與相機距離

far:近裁剪面與相機距離

『透視投影』代碼

GL10 gl = GRAPHICS.GetGL();

清屏

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

設定視口

gl.glViewport(0,0, GRAPHICS.GetWidth(),GRAPHICS.GetHeight());

設定當前矩陣為投影矩陣

gl.glMatrixMode(GL10.GL_PROJECTION);

載入單位矩陣

gl.glLoadIdentity();

設置投視投影

GLU.gluPerspective(gl, fieldOfView, aspectRatio, near, far);

設定當前矩陣為模型視圖矩陣

gl.glMatrixMode(GL10.GL_MODELVIEW);

載入單位矩陣

gl.glLoadIdentity();

 

 

 

 

Android遊戲之3D頂點索引

Android遊戲之3D頂點索引

在進入豐富多彩3D世界中需要定以『視錐體』和『精靈頂點』.3D空間中頂點需有xyz座標.並且使用『透視投影』.距離相機越遠,物體越小.離相機較近對象覆蓋較進隊象.3D頂點包含『位置(xyz)』『顏色(rgba)』『法線(x,y,z)』並且完成3D頂點『模型』渲染

public class VERTICES3D {

擁有頂點顏色

boolean hasColor = false;

擁有紋理坐標

boolean hasTexCoord =false;

擁有法線

boolean hasNormal = false;

每個頂點所占空間

int vertex_size = 0;

最大頂點量

int vertex_max = 0;

最大索引量

int index_max = 0;

頂點數組

IntBuffer vertex_array = null;

索引數組

ShortBuffer index_array = null;

頂點緩存

int[] vertex_Buffer;

構造函式分配頂點記憶體,vertex_max為最大頂點量,index_max為最大索引量

VERTICES3D(int vertex_max,int index_max,boolean hasColor,boolean hasTexCoord,boolean hasNormal){

ByteBuffer buffer = null;

this.vertex_max    = vertex_max;

this.index_max     = index_max;

this.hasColor  = hasColor;//  是否擁有頂點顏色

this.hasTexCoord = hasTexCoord;// 是否擁有紋理坐標

this.hasNormal = hasNormal;// 是否擁有法線

計算每頂點所占大小.顏色(rgbs)占4單元.紋理座標(uv)占2單元.3D座標(xyz)占3單元.每個整數占4字節

this.vertex_size = (3 + (hasColor ? 4 : 0) + (hasTexCoord ? 2 : 0) + (hasNormal ? 3: 0)) * 4;

vertex_Buffer = new int[vertex_max * vertex_size / 4];

因為OpenGL ES是以C API結口提供.無法直接使用JAVA數組.因此你需要C數組系統堆棧記憶體.而非JAVA虛擬機記憶體.需要 FloatBuffer分配頂點記憶體.vertex_max為最大頂點量.

buffer = ByteBuffer.allocateDirect(vertex_size * vertex_max);

將『網絡字節』改為『主機字節』或稱為『CPU字節』

buffer.order(ByteOrder.nativeOrder());

獲取頂點整數數組

vertex_array = buffer.asIntBuffer();

每索引占兩BYTE.即OpenGL ES每次最多渲染65536個頂點.

if(index_max > 0){

每個短整形占兩個字節.index_max為最大索引量

buffer = ByteBuffer.allocateDirect(index_max * Short.SIZE/8);

將『網絡字節』改為『主機字節』

buffer.order(ByteOrder.nativeOrder());

獲取頂點短整數數組

index_array = buffer.asShortBuffer();

}

}

將頂點提交給OpenGL數組並觸發

public void setVertices(float[] vertices,int offset,int count){

清空緩存.設定當前位置

vertex_array.clear();

int len = offset + count;

for(int i=offset, j=0; i < len; i++, j++)

vertex_Buffer[j] = Float.floatToRawIntBits(vertices[i]);

寫入數據.移動當前位置

vertex_array.put(vertex_Buffer, 0, count);

觸發

vertex_array.flip();

}

將頂點索引提交給OpenGL數組

public void setIndices(short[] indices,int offset,int count) {

清空緩存.設定當前位置

index_array.clear();

寫入數據.移動當前位置

index_array.put(indices, offset, count);

觸發

index_array.flip();

}

 

獲取索引量

public int getNumIndices(){

return index_array.limit();

}

獲取頂點量

public int getNumVertices(){

return    vertex_array.limit() / (vertex_size/4);

}

綁定頂點數據

public void Bind(){

GL10 gl = GRAPHICS.gl;

啟用頂點數組

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

設置當前寫入位置0

vertex_array.position(0);

設置頂點指針,每個頂點包含xyz分量

gl.glVertexPointer(3, GL10.GL_FLOAT, vertex_size, vertex_array);

擁有頂點顏色

if(hasColor == true) {

啟用頂點顏色數組

gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

設置當前寫入位置3

vertex_array.position(3);

設置顏色指針,RGBA四分量

gl.glColorPointer(4, GL10.GL_FLOAT, vertex_size, vertex_array);

}

擁有紋理坐標

if(hasTexCoord == true){

啟用紋理坐標

gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

設置當前寫入位置

vertex_array.position(hasColor?7:3);

設置紋理坐標指針UV分量

gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertex_size, vertex_array);

}

擁有法線

if (hasNormal = true) {

啟用法線

gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);

int offset = 3;

if (hasColor)

offset += 4;

if (hasTexCoord)

offset += 2;

設置當前寫入位置

vertex_array.position(offset);

設置法線指針,xyz分量

gl.glNormalPointer(GL10.GL_FLOAT, vertex_size, vertex_array);

}

}

取消綁定數據

public void Unbind(){

GL10 gl = GRAPHICS.gl;

關閉頂點紋理數組

if(hasColor)

gl.glDisableClientState(GL10.GL_COLOR_ARRAY );

關閉頂點顏色數組

if(hasTexCoord)

gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

關閉法線數組

if (hasNormal)

gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);

}

繪畫3D模型.需要先綁3D頂點

public void Draw(int mode,int offset,int count){

GL10 gl = GRAPHICS.gl;

繪畫頂點

if(index_array != null) {// 繪畫

index_array.position(offset);

gl.glDrawElements(mode, count, GL10.GL_UNSIGNED_SHORT, index_array);

}

else {

gl.glDrawArrays(mode, offset, count);

}

}

}

Android遊戲之3D矢量

Android遊戲之3D矢量

與『2D矢量』相比『3D矢量』僅是在x,y軸座標加上z軸座標.還有『點積』和『叉積』運算.與繞軸旋轉算法. 無左計算向量角度函式.

public class VECTOR3D {

3D浮點數座標

public float x,y,z;

角度轉弧度

public static float DEGREES_TO_RADIANS = ((1.0f/180.0f)* (float)Math.PI);

弧度轉角度

public static float RADIANS_TO_DEGREES = ((1.0f/(float)Math.PI)*180.0f);

用於繞軸旋轉

private static final float[] matrix = new float[16];

private static final float[] inVec = new float[16];

private static final float[] outVec = new float[16];

購造函式並設定x,y,z

public VECTOR3D(float x, float y,float z){

this.x = x;

this.y = y;

this.z = z;

}

拷貝3D矢量

public VECTOR3D Copy(){

VECTOR3D v;

v=new VECTOR3D(x,y,z);

return v;

}

重設3D矢量數值

public VECTOR3D set(VECTOR3D v){

this.x = v.x;

this.y = v.y;

this.z = v.z;

return this;

}

3D矢量加法運算

public VECTOR3D add(VECTOR3D v){

this.x = this.x + v.x;

this.y = this.y + v.y;

this.z = this.z + v.z;

return this;

}

3D矢量減法運算

public VECTOR3D sub(VECTOR3D v){

this.x = this.x – v.x;

this.y = this.y – v.y;

this.z = this.z – v.z;

return this;

}

3D矢量乘法(即縮放)

public VECTOR3D mul(float scalar){

this.x = this.x * scalar;

this.y = this.y * scalar;

this.z = this.z * scalar;

return this;

}

計算3D矢量長度

public float Len(){

float len;

len = (float) Math.sqrt(x*x+y*y+z*z);

return len;

}

3D矢量單位化,長度為1

public VECTOR3D normer(){

float len;

len = Len();

if(len != 0){

x = x / len;

y = y / len;

z = z / len;

}

return this;

}

繞某軸旋轉,先定義3D矢量,然後設置矩陣為零,然後用rotateM()旋轉,在乘以3D向量

public VECTOR3D rotate(float angle,float axisX,float axisY,float axisZ){

inVec[0] = x;

inVec[1] = y;

inVec[2] = z;

inVec[4] = 1;

Matrix.setIdentityM(matrix, 0);

Matrix.rotateM(outVec,0, angle, axisX, axisY, axisZ);// 選轉

Matrix.multiplyMV(outVec, 0, matrix, 0, inVec, 0);

x = outVec[0];

y = outVec[1];

z = outVec[2];

return this;

}

計算兩3D矢量之間距離

public float Dist(VECTOR3D v){

float distX = this.x – v.x;

float distY = this.y – v.y;

float distZ = this.z – v.z;

float dist = (float)Math.sqrt(distX*distX + distY*distY + distZ*distZ);

return dist;

}

計算兩個3D矢量之間距離平方

public float DistSquared(VECTOR3D v){

float distX = this.x – v.x;

float distY = this.y – v.y;

float distZ = this.z – v.z;

float dist = distX*distX + distY*distY + distZ*distZ;

return dist;

}

計算兩個3D向量叉積,叉積是一個向量,它與va和vb垂直.

void cross(VECTOR3D va, VECTOR3D vb){

x =  ( (va.y * vb.z) – (va.z * vb.y) );

y = -( (va.x * vb.z) – (va.z * vb.x) );

z =  ( (va.x * vb.y) – (va.y * vb.x) );

}

計算3D向量點積.返回值為浮點數

float dot(VECTOR3D v){

return( (x * v.x) + (y * v.y) + (z * v.z) );

}

3D向量取反數

VECTOR3D inverse(){

this.x = -this.x ;

this.y = -this.y ;

this.z = -this.z ;

return this;

}

}

 

Android遊戲之精靈動畫

Android遊戲之精靈動畫

遊戲動畫由關鍵幀(keyframe)組成.將它地依次連續渲染產生運動效果.上圖每幀尺寸64*64像素一共四幀.為產生動畫效果需每隔若干毫秒渲染一幀.當渲染到最後一幀時可選擇重新播放或停止播放.通常要實現『行走』『跳躍』『攻擊』『倒下』需要定義動畫結構

public class ANIMATION {

保存紋理圖檔只能關鍵幀位置.並且其順序與動畫回放順序相同

public REGION[] frames = null;

保存每幀間隔時間,用於確定每幀切換時間.

public float     duration;

動畫播放模式,分為『循環播放』與『單次播放』

public static final int LOOPING = 0;

public static final int NONLOOPING = 1;

構建動畫輸入『每幀間隔』與每幀『紋理區域』

ANIMATION(float duration,REGION … frames){

this.duration = duration;

this.frames = frames;

}

輸入時間提取關鍵幀.播放模式是單次或循環,基於『狀態時間』除以『每幀間隔』計算幀索引.

public REGION GetKeyFrame(float stateTime,int mode){

int index = (int)(stateTime/duration);

if(mode == NONLOOPING)// 單次播放

index = Math.min(frames.length-1, index);

else

index = index % frames.length;

return frames[index];

}

Android遊戲之點陣字體

Android遊戲之點陣字體

在遊戲中渲染字符,數字.在這裡介紹『點陣字體』技術.每個子圖表示單個字符如0~9.如上圖.『點陣字體』遊戲中渲染文本已非常古老.它通常包含ASCII碼字符圖像.此圖像程為『圖像字符』(glyph).ASCII字符集有128個字符.但只有95個可打印字符.索引號從32到126個.為節約空間『點陣字體』只包含可打印字符.95個字符每行16個字符分6行.ASCII只適用於存儲和顯示標準『拉丁字母』.但已滿足大部分單機遊戲.首先創建96個紋理區域.每區域映射到『點陣字體』中某圖像字符.

public REGION[] array = new REGION[96];

因為ASCII頭32個字符非打印字符無在『圖像字符』中渲染.首字符是空格只要講String轉為char字符減去空格

c = text.charAt(i) – ‘ ‘;

即可獲得紋理區域數組索引.要注意索引值必需在0~95之間否則會越界訪問.

region = array[c];

渲染ASCII文本.這裡簡單起見字體只時用『固定寬度』.但現代文本渲染字體寬度是非固定.可為每個字符設定不同字寬.

BATCHER.Draw(x, y, width, height, region);

上圖我使用Photoshop生成『圖像字符』.但其實有專門免費工具Codehead’s Bitmap Font Generator簡稱CBFG.可從www.codehead.co.uk/cbfg/下載

Android遊戲之半透明混合處理

Android遊戲之半透明混合處理

2D遊戲紋理渲染必須將『背景色』去除.JPEG格式不支持存儲像素點alpha值.將透明色alpha值設為零.需使用PNG格式.若紋理圖像沒有alpha通道時OpenGL ES自動將alpha設為1.但混合開銷很大而目前手機上GPU都不能對大量像素禁行混合.所以在需要時才啟用Blend『混合』.在OpenGL ES中啟動半透明混合處理
gl.glEnable(GL10.GL_BLEND);
設定『來源色』和『目標色』組合方程.
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
啟用2D紋理渲染
gl.glEnable(GL10.GL_TEXTURE_2D);
渲染三角形

禁用2D紋理渲染
gl.glDisable(GL10.GL_TEXTURE_2D);
結束渲染後禁用混合
gl.glDisable(GL10. GL_BLEND);

Android遊戲之入口『屏幕』

Android遊戲之入口『屏幕』

遊戲主選單 『屏幕』通常有 『圖標』『選單 』.所要做是『觸摸』選單 時切換『屏幕』.計算出選單 項『矩形區域』與觸碰點重疊時切換『屏幕』在這裡設定四個選單 項.你需要繪畫『文本紋理』寬高相等並是2倍數.背景色設為透明色.並且保存為『.PNG』. 『文本紋理』好在於研發時用英文文本之後再漢化.

你需定義『2D相機』屏幕原點在左下角、VECTOR2D『點』把觸碰座標轉換屏幕座標、渲染『圖標』區域.定義四個按鈕『新遊戲』『繼續遊戲』『高分榜』『遊戲設定』每當更新屏幕update()對四個選單 區域進行overlap()『矩形碰撞測試』.而渲染『屏幕』時則先渲染『背景』後渲染『選單』

選單項 簡介
NEW 啟動新遊戲
PLAY 繼續遊戲按扭
Highscores 高分排名榜
Settings 遊戲設定

public class ScreenMain  extends SCREEN{

private CAMERA2D camera;

private VECTOR2D  touchPoint;

private    RECT2D Bounds_Logo;

private    RECT2D Bounds_New;

private    RECT2D Bounds_Play;

private   RECT2D Bounds_Highscores;

private   RECT2D Bounds_Settings;

購造入口屏幕

public ScreenMain(){

camera = new CAMERA2D(320, 480);// 相機

Bounds_Logo = new RECT2D(WORLD.PIXEL_WIDTH/2, WORLD.PIXEL_HEIGHT/2 + 160 , 256, 128);

Bounds_New = new RECT2D(WORLD.PIXEL_WIDTH/2, WORLD.PIXEL_HEIGHT/2 + 64,  128, 32);

Bounds_Play = new RECT2D(WORLD.PIXEL_WIDTH/2, WORLD.PIXEL_HEIGHT/2 + 32,  128, 32);

Bounds_Highscores = new RECT2D(WORLD.PIXEL_WIDTH/2, WORLD.PIXEL_HEIGHT/2 , 256, 32);

Bounds_Settings = new RECT2D(WORLD.PIXEL_WIDTH/2, WORLD.PIXEL_HEIGHT/2 – 32,  256, 32);

touchPoint        = new VECTOR2D();// 觸碰點

}

更新屏幕都觸碰座標

@Override

public void update(float deltaTime){

for(int i = 0; i < TOUCH.Point_Count; i++){

int action = TOUCH.Point_Action[i];

if(action != TOUCH.ACTION_UP)

continue;

float x = TOUCH.Point_X[i];

float y = TOUCH.Point_Y[i];

touchPoint.set(x, y);

camera.TouchToWorld(touchPoint);//觸摸坐標轉世界坐標

if(Bounds_New.overlap(touchPoint)){// 新遊戲按扭

TOUCH.clear();// 清空

SOUND.Play(ASSETS.sound_click);// 點擊

GAME.setScreen(GAME.getGameScreen());// 遊戲按扭

return;

}

else

if(Bounds_Play.overlap(touchPoint)){// 遊戲按扭

SOUND.Play(ASSETS.sound_click);// 點擊

GAME.setScreen(GAME.getGameScreen());// 遊戲按扭

TOUCH.clear();// 清空

break;

}

else

if(Bounds_Highscores.overlap(touchPoint) ){// 高分按扭

SOUND.Play(ASSETS.sound_click);// 點擊

GAME.setCurrentScreen(GAME.getScoreScreen());

TOUCH.clear();// 清空

break;

}

else

if(Bounds_Settings.overlap(touchPoint)){// 設定按鈕

SOUND.Play(ASSETS.sound_click);// 點擊

GAME.setScreen(GAME.getSettingsScreen());

TOUCH.clear();// 清空

break;

}

}

TOUCH.clear();// 清空

}

渲染屏幕

@Override

public void present(float deltaTime){

GL10            gl   = GRAPHICS.gl;

GLSurfaceView view   = GRAPHICS.gl_View;

gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

camera.SetViewportAndMatrices();

gl.glEnable(GL10.GL_TEXTURE_2D);

BATCHER.Begin(ASSETS.texture_background);

BATCHER.Draw(WORLD.PIXEL_WIDTH/2,WORLD.PIXEL_HEIGHT/2, WORLD.PIXEL_WIDTH, WORLD.PIXEL_HEIGHT, ASSETS.region_background);// 渲染背景

BATCHER.End();

// 設為透明

gl.glEnable(GL10.GL_BLEND);

gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

BATCHER.Begin(ASSETS.texture_text);

BATCHER.Draw(Bounds_Logo,  ASSETS.region_logo);// 圖標按扭

BATCHER.Draw(Bounds_New,  ASSETS.region_new);// 圖標按扭

BATCHER.Draw(Bounds_Play,  ASSETS.region_play);// 主選單

BATCHER.Draw(Bounds_Highscores,ASSETS.region_highscores);// 高分按扭

BATCHER.Draw(Bounds_Settings, ASSETS.region_settings);// 設定按扭

BATCHER.End();

gl.glDisable(GL10.GL_TEXTURE_2D);// 禁用

}

暫停保存設置

@Override

public void pause(){

}

恢復

@Override

public void resume(){

}

清除/銷毀

@Override

public void dispose(){

}

返回鍵

@Override

public boolean back(){

SOUND.Shutdown();

MUSIC.Shutdown();

return  true;

}

}

 

 

Android遊戲之GLSurfaceView

Android遊戲之GLSurfaceView

遊戲設計中通常『更新』『渲染』放在同一線程中.在Windows可以在主線程將『消息驅動』改為『實時驅動』.把『更新』『渲染』放在主線程中.而Android卻無法做到這點.但提供GLSurfaceView可建立獨立線程在背後實現『更新』『渲染』.你需要實現監聽接口GLSurfaceView.Renderer.並註冊到GLSurfaceView中.監聽接口需要分別重寫『創建』『調整大細』『渲染』.GLSurfaceView.Renderer可獲得GL10.通過它方可訪問OpenGL ES API.而GL10中10代表OpenGL ES 1.0標準.可以將GLSurfaceView封裝成獨立控件.從而在layout『佈局』中嵌入.

public class RenderView extends GLSurfaceView implements GLSurfaceView.Renderer {

每當Activity恢復或啟動創建. EGLConfig設置Surface顏色與深度

public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig);

當view尺寸發生改變時調用,傳入寬與高

public void onSurfaceChanged(GL10 gl10, int width, int height);

調用『渲染』『更新』完成幀繪製.但每秒不超過60幀.

public void onDrawFrame(GL10 gl10);

令外還需重寫『恢復』『暫停』

『恢復』重啟渲染線程,在Activity恢復顯示時在Activity.onResume()中調用

public void onResume();

『暫停』退出渲染線程,當Activity進入後臺時在Activity.onPause()中調用

public void onPause();

}

編輯layout『佈局』文檔main.xml添加

<net.bookcard.aa.RenderView

android:id=”@+id/render_view”

android:layout_width=”fill_parent”

android:layout_height=”fill_parent” />

定義view狀態

public static final int       STATE_INIT       = 0;// 初此

public static final int  STATE_RUN       = 1;// 運行

public static final int  STATE_PAUSED    = 2;// 暫停

public static final int  STATE_FINISHED  = 3;// 結束

public static final int  STATE_IDLE       = 4;// 閒置

int view_width,view_height;// 寬與高

int state = STATE_INIT;// 初此狀態

long    startTime ;// 啟動時間

創建Surface獲取屏幕

public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig){

SCREEN  screen = GAME.getCurrentScreen();// 當前屏幕

if(state == STATE_INIT) {// 初此

Init(gl, this);

screen = GAME.getMainScreen();

GAME.setCurrentScreen(screen);

}

else {//  重新載入資源

ASSETS.reload();

}

screen = GAME.getCurrentScreen();

state = STATE_RUN;// 運行

startTime = System.nanoTime();// 獲取啟動時間

}

大小發生改變

public void onSurfaceChanged(GL10 gl, int width, int height){

this.view_width = width;// 寬

this.view_height = height;// 高

}

更新並渲染.System.nanoTime()返回納秒, 1000000000納秒=1秒.通過兩次時間測量計算間隔時間

public void onDrawFrame(GL10 gl){

SCREEN screen = GAME.getCurrentScreen();

if(state == STATE_RUN){// 運行

float deltaTime = (System.nanoTime()-startTime) / 1000000000.0f;

startTime = System.nanoTime();// 獲取當前時間

screen.update(deltaTime);// 更新

screen.present(deltaTime);// 渲染

}

else

if(state == STATE_PAUSED) {// 暫停

screen.pause();

}

else

if(state == STATE_FINISHED) {// 結束

screen.pause();

screen.dispose();

}

}

恢復渲染在Activity.onResume()中調用

public void onResume(){

super.onResume();

MUSIC.Resume();

}

暫停渲染在Activity.onPause()中調用

public void onPause(){

state = STATE_PAUSED;// 暫停

super.onPause();

MUSIC.Pause();

}

初此遊戲系統個部件

void Init(GL10 gl, GLSurfaceView view){

GRAPHICS.Init(gl,view);

SYSTEM.Init(context);// 系統

FileIO.Init(context);// 文件讀寫

BITMAP.Init(context);// 位圖

SOUND.Init(context,100);// 聲音

MUSIC.Init(context,100);// 音樂

TOUCH.Init(this);// 觸摸模塊

GAME.Init();//  屏幕切換系統

BATCHER.Init(1500);// 精靈批處理

ASSETS.load();// 資源

}