原文连接: 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
欢迎关注微信公众号:【纸上浅谈】,得到最新文章推送~~~