最近在学习ndk加载纹理的例子时,有些收获,写出来与大家共同探讨!
在用ndk开发游戏时,最常见的就是显示图片,在c语言下用opengl贴图,经过实践,已知有4种方法可行!
备注:以下部分内容参考网上代码,具体是哪,忘记了。如有冒犯,敬请谅解!
1. java层生成好纹理,通过jni传递给c层
private Bitmap getBitmap(Context context, int resId) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
return BitmapFactory.decodeResource(context.getResources(), resId, options);
}
Bitmap bitmap = getBitmap(context, R.drawable.ic_1);
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
//textureId = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
GL0JNILib.setTextures(textures);
把textures[0]传递给c层直接绑定纹理
2. java层生成bitmap的图像数据,传递给c
Bitmap bitmap = getBitmap(context, R.drawable.ic_1);
ByteBuffer fcbuffer = ByteBuffer.allocate(bitmap.getHeight() * bitmap.getWidth() * 4);
bitmap.copyPixelsToBuffer(fcbuffer);
fcbuffer.flip();
Log.d(TAG, "bitmap=" + bitmap + "," + fcbuffer);
byte[] data = fcbuffer.array();
3. java层生成bitmap,传递给c,c层获取图片数据
推荐使用这种方式来实现,在C层处理纹理
Bitmap bitmap = getBitmap(context, R.drawable.ic_1);
c层读取图片数据
GLvoid* getBitmapPixels(JNIEnv* env, jobject bitmap)
{
AndroidBitmapInfo info;
int ret;
GLvoid* pixels;
AndroidBitmap_getInfo(env, bitmap, &info);
if(info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
LOGI("Bitmap format is not RGBA_8888!");
return;
}
AndroidBitmap_lockPixels(env, bitmap, &pixels);
// Now you can use the pixel array 'pixels', which is in RGBA format
LOGI("Bitmap format --------------------------");
AndroidBitmap_unlockPixels(env, bitmap);
return pixels;
}
4. 通过libpng,libzip库,在c层直接读取png数据
unsigned char* png_read_zip(const char* filename, int *w, int *h) {
int k; //用于循环
png_bytep * row_pointers;//图片的数据内容
int row,col,pos; //用于改变png像素排列的问题。
unsigned char *rgba;
int width;
int height;
file = zip_fopen(APKArchive, filename, 0);
if (!file) {
LOGI("loadTexture Error opening %s from APK", filename);
return TEXTURE_LOAD_ERROR;
}
//LOGI("loadTexture0");
//header for testing if it is a png
png_byte header[8];
//read the header
zip_fread(file, header, 8);
//test if png
int is_png = !png_sig_cmp(header, 0, 8);
if (!is_png) {
zip_fclose(file);
LOGI("loadTexture Not a png file : %s", filename);
return TEXTURE_LOAD_ERROR;
}
//create png struct
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL);
if (!png_ptr) {
zip_fclose(file);
LOGI("loadTexture Unable to create png struct : %s", filename);
return (TEXTURE_LOAD_ERROR);
}
//create png info struct
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
LOGI("loadTexture Unable to create png info : %s", filename);
zip_fclose(file);
return (TEXTURE_LOAD_ERROR);
}
//create png info struct
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
LOGI("loadTexture Unable to create png end info : %s", filename);
zip_fclose(file);
return (TEXTURE_LOAD_ERROR);
}
//png error stuff, not sure libpng man suggests this.
if (setjmp(png_jmpbuf(png_ptr))) {
zip_fclose(file);
LOGI("loadTexture Error during setjmp : %s", filename);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return (TEXTURE_LOAD_ERROR);
}
//init png reading
//png_init_io(png_ptr, fp);
png_set_read_fn(png_ptr, NULL, png_zip_read);
//let libpng know you already read the first 8 bytes
png_set_sig_bytes(png_ptr, 8);
// read all the info up to the image data
png_read_info(png_ptr, info_ptr);
//variables to pass to get info
int bit_depth, color_type;
png_uint_32 twidth, theight;
// get info about png
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
NULL, NULL, NULL);
//update width and height based on png info
width = twidth;
height = theight;
// Update the png info struct.
png_read_update_info(png_ptr, info_ptr);
//读文件
if (setjmp(png_jmpbuf(png_ptr))){
zip_fclose(file);
return (TEXTURE_LOAD_ERROR);
}
rgba = malloc(width * height * 4);
//使用动态数组 设置长度
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (k = 0; k < height; k++)
row_pointers[k] = NULL;
//通过扫描流里面的每一行将得到的数据赋值给动态数组
for (k=0; k
//row_pointers[k] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
row_pointers[k] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
//由于png他的像素是由 左-右-从顶到底 而贴图需要的像素都是从左-右-底到顶的所以在这里需要把像素内容进行一个从新排列
//读图片
png_read_image(png_ptr, row_pointers);
pos = (width * height * 4) - (4 * width);
for( row = 0; row < height; row++)
{
for( col = 0; col < (4 * width); col += 4)
{
rgba[pos++] = row_pointers[row][col]; // red
rgba[pos++] = row_pointers[row][col + 1]; // green
rgba[pos++] = row_pointers[row][col + 2]; // blue
rgba[pos++] = row_pointers[row][col + 3]; // alpha
}
pos=(pos - (width * 4)*2);
}
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
//LOGI("loadTexture7");
free(row_pointers);
zip_fclose(file);
*w = width;
*h = height;
return rgba;
}