Android NDK 開發 —— 從 Assets 文件夾加載圖片並上傳紋理

原文連接: Android NDK 開發 —— 從 Assets 文件夾加載圖片並上傳紋理

在 OpenGL 開發中,咱們要渲染一張圖片,一般先是獲得一張圖片對應的 Bitmap ,而後將該 Bitmap 做爲紋理上傳到 OpenGL 中。在 Android 中有封裝好的 GLUtils 類的 texImage2D 方法供咱們調用。java

public static void texImage2D(int target, int level, int internalformat,
            Bitmap bitmap, int type, int border)

該方法的底層原理實際上也是解析了該 Bitmap ,獲得了 Bitmap 全部的像素數據,相似於 Android NDK 關於 Bitmap 操做的 AndroidBitmap_lockPixels 方法,若是你不太瞭解該方法,能夠參考這篇文章:Android JNI 之 Bitmap 操做android

獲得了全部像素數據以後,實際最終仍是調用了 OpenGL 的 glTexImage2D 來實現紋理上傳。固然,若是能夠直接獲得全部數據,也不須要走解析 Bitmap 這一步了,這種場景最多見的就是把相機做爲輸入了。git

<!--more-->github

接下來咱們會經過 Android NDK 開發中去渲染一張圖片,步驟仍是如上,從圖像解析到紋理上傳,不一樣的是咱們將會解析 Assets 文件夾中的圖片,而不是一張已經保存在手機 SDCard 上的圖片。微信

相比於前者,SDCard 上的圖片已經有了絕對地址了,直接把地址傳到 stb_image 庫就能夠完成解析了(參考以前的文章 []()),而 Assets 文件夾的內容在手機上可沒有絕對地址哦,不信你仔細回想,可曾在看到過 APK 安裝後 Assets 文件夾對應的內容?post

一開始陷入了誤區,想着怎麼去得到文件的絕對地址,看到了 AssetManager 的 AAsset_openFileDescriptor 方法覺得拿到文件描述符就萬事大吉了,結果打印的地址是這樣的 /proc/9941/fd/79 ,這基本的不可用了。spa

換個思路,在 Java 中去加載 Assets 目錄下的圖片:code

InputStream is = getAssets().open(fileName);

經過 AssertManager 的 open 方法直接拿到文件的輸入流了。orm

而在 NDK 開發中一樣的方式是行不通的,這裏要採用另一種方式,但其實意思都差很少的:blog

// NDK 中是 AssetManager
    AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
    // 打開 Asset 文件夾下的文件
    AAsset *pathAsset = AAssetManager_open(mgr, assetPath, AASSET_MODE_UNKNOWN);
    // 獲得文件的長度
    off_t assetLength = AAsset_getLength(pathAsset);
    // 獲得文件對應的 Buffer
    unsigned char *fileData = (unsigned char *) AAsset_getBuffer(pathAsset);
    // stb_image 的方法,從內存中加載圖片
    unsigned char *contnet = stbi_load_from_memory(fileData, assetLength, &w, &h, &n, 0);

NDK 中可拿不到像 Java 那樣的輸入流,可是能夠經過 AssetManager 的 AAsset_getBuffer 或者是 AAsset_read 方法去獲取文件內容。

看到上面那兩個 API 基本就穩了,再配合 stb_image 介紹過的方法,stbi_load_from_memory 從內存中加載圖片的像素數據,最後就是 glTexImage2D 方法實現紋理上傳。

具體的代碼實踐參考項目:

https://github.com/glumes/InstantGLSL

歡迎關注微信公衆號:【紙上淺談】,得到最新文章推送~~~

掃碼關注

相關文章
相關標籤/搜索