用Android OpenGL画Bitmap的方法
Haiyong Lei
用OpenGL API画BITMAP,BITMAP的W、H须为2的倍数,比如32、64、512。注意代码里的Vertices和Texture的坐标顺序。
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class MainActivity extends AppCompatActivity {
Bitmap bitmap = null;
class BitmapRender implements Renderer {
/* the border of bitmap
V3 ------ V4
| |
| |
| |
V1 ------ V2
*/
float borderVerticesCoord[] = {
// x, y, z
-1.0f, -1.0f, 0.0f, // V1 - left bottom
1.0f, -1.0f, 0.0f, // V2 - right bottom
-1.0f, 1.0f, 0.0f, // V3 - left top
1.0f, 1.0f, 0.0f, // V4 - right top
};
float bitmapTextureCoord[] = {
// x, y
0.0f, 1.0f, // V3 - left top
1.0f, 1.0f, // V4 - right top
0.0f, 0.0f, // V1 - left bottom
1.0f, 0.0f, // V2 - right bottom
};
FloatBuffer borderVerticesBuffer = null;
FloatBuffer bitmapTextureBuffer = null;
int bitmapTextureHandle = -1;
private void loadBitmapTexture(GL10 gl) {
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
bitmapTextureHandle = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, bitmapTextureHandle);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
//gl.glTexParameterf(GL10.GL_TEXTURE_2D,
// GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
//gl.glTexParameterf(GL10.GL_TEXTURE_2D,
// GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
}
private void deleteBitmapTexture(GL10 gl) {
int[] textures = new int[1];
textures[0] = bitmapTextureHandle;
gl.glDeleteTextures(1, textures, 0);
}
private void buildBitmapTextureBuffer() {
ByteBuffer tb = ByteBuffer.allocateDirect(bitmapTextureCoord.length * 4); tb.order(ByteOrder.nativeOrder());
bitmapTextureBuffer = tb.asFloatBuffer();
bitmapTextureBuffer.put(bitmapTextureCoord);
bitmapTextureBuffer.position(0);
}
private void buildBorderVertexBuffer() {
ByteBuffer vb = ByteBuffer.allocateDirect(borderVerticesCoord.length * 4); vb.order(ByteOrder.nativeOrder());
borderVerticesBuffer = vb.asFloatBuffer();
borderVerticesBuffer.put(borderVerticesCoord);
borderVerticesBuffer.position(0);
}
private void drawBitmap(GL10 gl) {
gl.glBindTexture(GL10.GL_TEXTURE_2D, bitmapTextureHandle);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
if (borderVerticesBuffer == null)
buildBorderVertexBuffer();
if (bitmapTextureBuffer == null)
buildBitmapTextureBuffer();
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, borderVerticesBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, bitmapTextureBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, borderVerticesCoord.length / 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glEnable(GL10.GL_TEXTURE_2D);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glClearColor(0, 0, 0, 1);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
if (bitmapTextureHandle == -1)
loadBitmapTexture(gl);
drawBitmap(gl);
}
}
GLSurfaceView glSurfaceView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lotus);
glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // need by emulator glSurfaceView.setRenderer(new BitmapRender());
setContentView(glSurfaceView);
}
@Override
public void onPause() {
glSurfaceView.onPause();
super.onPause();
}
@Override
public void onResume() {
super.onResume();
glSurfaceView.onResume();
}
}