Graphics API supports both OpenGL and Android 2D rendering targets efficiently through the same interface
// Copyright 2008 and onwards Matthew Burkhart.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; version 3 of the License.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//package android.com.abb;
import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.opengl.GLDebugHelper;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.util.Log;
import android.view.SurfaceHolder;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.TreeMap;
import java.util.Vector;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11; // For EGL_CONTEXT_LOST constant.
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11ExtensionPack;
import junit.framework.Assert;
/** Graphics API designed for ABB. The goal is to support both OpenGL and
* Android 2D rendering targets efficiently through the same interface. */
public class Graphics {
/**
* Public API.
*/
/** Initialize the graphics sub-system letting the rendering back end target
* be automatically chosen from the system configuration. */
public void initialize(SurfaceHolder surface_holder) {
determineBackendType();
Rect surface_frame = surface_holder.getSurfaceFrame();
surfaceChanged(
surface_holder, surface_frame.width(), surface_frame.height());
switch (mBackendType) {
case ANDROID2D:
Log.d("Graphics::Initialize", "Initializing Android2D rendering.");
initializeAndroid2D();
break;
case OPENGL:
Log.d("Graphics::Initialize", "Initializing OpenGL rendering.");
initializeOpenGL();
break;
}
}
public void surfaceChanged(SurfaceHolder surface_holder,
int width, int height) {
mSurfaceHolder = surface_holder;
mSurfaceWidth = width;
mSurfaceHeight = height;
Log.d("Graphics::surfaceChanged",
"Size = " + mSurfaceWidth + "x" + mSurfaceHeight + ".");
switch (mBackendType) {
case ANDROID2D:
break; // Don't care.
case OPENGL:
mGlSurfaceInitialized = false;
break;
}
}
public void destroy() {
switch (mBackendType) {
case ANDROID2D:
break; // Don't care.
case OPENGL:
destroyOpenGL();
break;
}
}
public int getWidth() {
switch (mBackendType) {
case ANDROID2D:
return getWidthAndroid2D();
case OPENGL:
return getWidthOpenGL();
}
return 0;
}
public int getHeight() {
switch (mBackendType) {
case ANDROID2D:
return getHeightAndroid2D();
case OPENGL:
return getHeightOpenGL();
}
return 0;
}
/** Load an image from a bitmap and return its handle. For OpenGL
* compatibility texture dimensions must be powers of 2. Additionally,
* hardware usually limits texture sizes to 1024 pixels. */
public int loadImageFromBitmap(Bitmap bitmap) {
Assert.assertNotNull(
"Null bitmap specified in LoadImageFromBitmap", bitmap);
int bitmap_hash = hashBitmap(bitmap);
Integer cached_image_handle = mImageCache.get(new Integer(bitmap_hash));
if (cached_image_handle != null) {
return cached_image_handle.intValue();
} else {
int image_handle = -1;
switch (mBackendType) {
case ANDROID2D:
image_handle = loadImageFromBitmapAndroid2D(bitmap);
break;
case OPENGL:
image_handle = loadImageFromBitmapOpenGL(bitmap);
break;
}
mImageCache.put(new Integer(bitmap_hash), new Integer(image_handle));
return image_handle;
}
}
public void freeImage(int image_handle) {
switch (mBackendType) {
case ANDROID2D:
freeImageAndroid2D(image_handle);
break;
case OPENGL:
freeImageOpenGL(image_handle);
break;
}
}
public void drawImage(int image_handle, Rect source_rect, RectF dest_rect,
boolean flipped_horizontal, boolean flipped_vertical,
int block_count) {
/* DEBUGGING ONLY
Assert.assertTrue("Invalid image handle in drawImage", image_handle >= 0);
// The drawImageOpenGL implementation has been inlined here for performance
// reasons. TODO: Inline the 2D API implementation here.
Assert.assertEquals(mBackendType, BackendType.OPENGL);
*/
if (image_handle >= mTextureData.size()) {
Log.d("Graphics::drawImage", "Unknown image handle encountered. " +
"Assuming OpenGL context has been lost. Exiting.");
mContextLost = true;
return;
}
if (image_handle != mCurrentTexture) {
mCurrentTexture = image_handle;
mGl.glBindTexture(GL10.GL_TEXTURE_2D, image_handle);
}
// The vertex and texture coordinate arrays have already been initialized.
// All that is left is to set up the texture and model view transformation
// matrices and render. Note that the OpenGL API expects matrices with a
// column-major layout.
TextureData texture_data = mTextureData.get(image_handle);
float texture_width = texture_data.width;
float texture_height = texture_data.height;
mMatrix4x4[1] = mMatrix4x4[2] = mMatrix4x4[4] =
mMatrix4x4[6] = mMatrix4x4[8] = mMatrix4x4[9] = 0.0f;
if (flipped_vertical) {
mMatrix4x4[5] = (source_rect.top - source_rect.bottom) / texture_height;
mMatrix4x4[13] = source_rect.bottom / texture_height;
} else {
mMatrix4x4[5] = (source_rect.bottom - source_rect.top) / texture_height;
mMatrix4x4[13] = source_rect.top / texture_height;
}
if (flipped_horizontal) {
mMatrix4x4[0] = (source_rect.left - source_rect.right) / texture_width;
mMatrix4x4[12] = source_rect.right / texture_width;
} else {
mMatrix4x4[0] = (source_rect.right - source_rect.left) / texture_width;
mMatrix4x4[12] = source_rect.left / texture_width;
}
mGl.glMatrixMode(GL10.GL_TEXTURE);
mGl.glLoadMatrixf(mMatrix4x4, 0);
mMatrix4x4[0] = dest_rect.right - dest_rect.left;
mMatrix4x4[5] = dest_rect.top - dest_rect.bottom;
mMatrix4x4[12] = dest_rect.left;
mMatrix4x4[13] = mSurfaceHeight - dest_rect.top;
mGl.glMatrixMode(GL10.GL_MODELVIEW);
mGl.glLoadMatrixf(mMatrix4x4, 0);
mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 2 * block_count + 2);
}
public void drawImage(int image_handle, Rect source_rect, Matrix dest_matrix,
boolean flipped_horizontal, boolean flipped_vertical,
int block_count) {
/* DEBUGGING ONLY
Assert.assertTrue("Invalid image handle in drawImage", image_handle >= 0);
// The drawImageOpenGL implementation has been inlined here for performance
// reasons. TODO: Inline the 2D API implementation here.
Assert.assertEquals(mBackendType, BackendType.OPENGL);
*/
if (mBackendType == BackendType.ANDROID2D) {
return;
}
if (image_handle >= mTextureData.size()) {
Log.d("Graphics::drawImage", "Unknown image handle encountered. " +
"Assuming OpenGL context has been lost. Exiting.");
mContextLost = true;
return;
}
if (image_handle != mCurrentTexture) {
mCurrentTexture = image_handle;
mGl.glBindTexture(GL10.GL_TEXTURE_2D, image_handle);
}
// The vertex and texture coordinate arrays have already been initialized.
// All that is left is to set up the texture and model view transformation
// matrices and render. Note that the OpenGL API expects matrices with a
// column-major layout.
TextureData texture_data = mTextureData.get(image_handle);
float texture_width = texture_data.width;
float texture_height = texture_data.height;
mMatrix4x4[1] = mMatrix4x4[2] = mMatrix4x4[4] =
mMatrix4x4[6] = mMatrix4x4[8] = mMatrix4x4[9] = 0.0f;
if (flipped_vertical) {
mMatrix4x4[5] = (source_rect.top - source_rect.bottom) / texture_height;
mMatrix4x4[13] = source_rect.bottom / texture_height;
} else {
mMatrix4x4[5] = (source_rect.bottom - source_rect.top) / texture_height;
mMatrix4x4[13] = source_rect.top / texture_height;
}
if (flipped_horizontal) {
mMatrix4x4[0] = (source_rect.left - source_rect.right) / texture_width;
mMatrix4x4[12] = source_rect.right / texture_width;
} else {
mMatrix4x4[0] = (source_rect.right - source_rect.left) / texture_width;
mMatrix4x4[12] = source_rect.left / texture_width;
}
mGl.glMatrixMode(GL10.GL_TEXTURE);
mGl.glLoadMatrixf(mMatrix4x4, 0);
mScreenMatrix.reset();
mScreenMatrix.preTranslate(0.0f, mSurfaceHeight);
mScreenMatrix.preScale(1.0f, -1.0f);
mScreenMatrix.preConcat(dest_matrix);
mScreenMatrix.getValues(mMatrix3x3);
mMatrix4x4[0] = mMatrix3x3[0];
mMatrix4x4[1] = mMatrix3x3[3];
mMatrix4x4[2] = mMatrix3x3[6];
mMatrix4x4[4] = mMatrix3x3[1];
mMatrix4x4[5] = mMatrix3x3[4];
mMatrix4x4[6] = mMatrix3x3[6];
mMatrix4x4[12] = mMatrix3x3[2];
mMatrix4x4[13] = mMatrix3x3[5];
mGl.glMatrixMode(GL10.GL_MODELVIEW);
mGl.glLoadMatrixf(mMatrix4x4, 0);
mGl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 2 * block_count + 2);
}
/**
* Begin the start of the frame drawing operations. All drawing methods must
* be called between a call to beginFrame() and endFrame(). The beginFrame()
* method may return false to indicate a critical error, signaling that the
* graphics system must be restarted.
*/
public boolean beginFrame() {
switch (mBackendType) {
case ANDROID2D:
return beginFrameAndroid2D();
case OPENGL:
return beginFrameOpenGL();
}
return false;
}
public void endFrame() {
switch (mBackendType) {
case ANDROID2D:
endFrameAndroid2D();
break;
case OPENGL:
endFrameOpenGL();
break;
}
}
public boolean hasHardwareAcceleration() {
return mHasHardwareAcceleration;
}
/**
* Private shared methods and state.
*/
private void determineBackendType() {
// Determine which rendering back-end to use based off of the system setup,
// specifically the presence of any rendering hardware. OpenGL appears to be
// faster on both the Emulator and the HTC Dream handset than the Android2D
// back end. The software OpenGL rasterizer is faster than the Android2D
// graphics API so it should be preferred in nearly all situations. However,
// when using either software back-end, pixel fill rate has been
// experimentally been shown to be a bottleneck.
mBackendType = BackendType.OPENGL;
}
/** Determine a (generally) unique hash code from a Bitmap reference. This is
* intended to be used to quickly identify exact images while only examining a
* small subset of the pixels. */
static private int hashBitmap(Bitmap bitmap) {
int hash_result = 0;
hash_result = (hash_result << 7) ^ bitmap.getHeight();
hash_result = (hash_result << 7) ^ bitmap.getWidth();
for (int pixel = 0; pixel < 20; ++pixel) {
int x = (pixel * 50) % bitmap.getWidth();
int y = (pixel * 100) % bitmap.getHeight();
hash_result = (hash_result << 7) ^ bitmap.getPixel(x, y);
}
return hash_result;
}
private enum BackendType { ANDROID2D, OPENGL }
private BackendType mBackendType;
private TreeMap<Integer, Integer> mImageCache = new TreeMap<Integer, Integer>();
private SurfaceHolder mSurfaceHolder;
private int mSurfaceHeight;
private int mSurfaceWidth;
/**
* Private Android 2D backend methods and state.
*/
private void initializeAndroid2D() {
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_HARDWARE);
}
private int loadImageFromBitmapAndroid2D(Bitmap bitmap) {
mImagesAndroid2D.add(bitmap);
return mImagesAndroid2D.size();
}
private void freeImageAndroid2D(int image_handle) {
if (image_handle >= 1) {
mImagesAndroid2D.set(image_handle - 1, null);
}
}
private int getWidthAndroid2D() {
return mSurfaceWidth;
}
private int getHeightAndroid2D() {
return mSurfaceHeight;
}
private boolean beginFrameAndroid2D() {
mCanvasAndroid2D = mSurfaceHolder.lockCanvas(null);
mCanvasAndroid2D.drawRGB(0, 0, 0);
return true;
}
private void endFrameAndroid2D() {
mSurfaceHolder.unlockCanvasAndPost(mCanvasAndroid2D);
}
private void drawImageAndroid2D(int image_handle,
Rect source_rect, RectF dest_rect,
boolean flipped_horizontal,
boolean flipped_vertical) {
Assert.assertTrue("Vertical flipping not yet implemented.",
!flipped_vertical);
if (flipped_horizontal) {
mTransformationAndroid2D.setScale(-1.0f, 1.0f);
mTransformationAndroid2D.postTranslate(
2.0f * dest_rect.left + dest_rect.width(), 0.0f);
} else {
mTransformationAndroid2D.setScale(1.0f, 1.0f);
}
Bitmap bitmap = mImagesAndroid2D.get(image_handle - 1);
mCanvasAndroid2D.setMatrix(mTransformationAndroid2D);
mCanvasAndroid2D.drawBitmap(
bitmap, source_rect, dest_rect, mPaintAndroid2D);
}
private void drawImageAndroid2D(int image_handle,
Rect source_rect, Matrix dest_matrix,
boolean flipped_horizontal,
boolean flipped_vertical) {
Assert.fail("Method not yet implemented.");
}
private Canvas mCanvasAndroid2D;
private ArrayList<Bitmap> mImagesAndroid2D = new ArrayList<Bitmap>();
private Paint mPaintAndroid2D = new Paint();
private Matrix mTransformationAndroid2D = new Matrix();
/**
* Private OpenGL backend methods and state.
*/
private void initializeOpenGL() {
// Note that OpenGL ES documentation may be found at:
// http://java.sun.com/javame/reference/apis/jsr239/javax/microedition
// /khronos/opengles/GL10.html
mEgl = (EGL10)EGLContext.getEGL();
mEglDisplay = mEgl.eglGetDisplay(EGL11.EGL_DEFAULT_DISPLAY);
// We can now initialize EGL for that display.
int[] version = new int[2];
mEgl.eglInitialize(mEglDisplay, version);
Log.d("Graphics::initializeOpenGL",
"Found version: " + version[0] + "." + version[1]);
int attrib_list[] = { // Use default bit depths.
EGL11.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];
mEgl.eglChooseConfig(mEglDisplay, attrib_list, configs, 1, num_config);
mEglConfig = configs[0];
mEglContext = mEgl.eglCreateContext(
mEglDisplay, mEglConfig, EGL11.EGL_NO_CONTEXT, null);
mGl = (GL10)mEglContext.getGL();
final boolean kEnableOpenGLDebugging = false;
if (kEnableOpenGLDebugging) {
int debugging_flags = (GLDebugHelper.CONFIG_LOG_ARGUMENT_NAMES |
GLDebugHelper.CONFIG_CHECK_THREAD |
GLDebugHelper.CONFIG_CHECK_GL_ERROR);
mEgl = (EGL10)GLDebugHelper.wrap(
mEgl, debugging_flags, new PrintWriter(System.out));
mGl = (GL10)GLDebugHelper.wrap(
mGl, debugging_flags, new PrintWriter(System.out));
}
// Create a place holder surface so we can continue with initialization.
// When the framework gives us a real surface / surface dimensions, it will
// be recreated.
initializeOpenGLSurface();
}
/** Create a new rendering surface. This is indented to be called whenever the
* window size changes, for example. */
private void initializeOpenGLSurface() {
Log.d("Graphics::initializeOpenGLSurface", "Freeing old OpenGL surface.");
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
if (mEglSurface != null) {
// Unbind and destroy the old EGL surface, if there is one.
mEgl.eglMakeCurrent(mEglDisplay,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglSurface = null;
}
// Create an EGL surface we can render into.
Log.d("Graphics::initializeOpenGLSurface", "Creating new OpenGL surface.");
mEglSurface = mEgl.eglCreateWindowSurface(
mEglDisplay, mEglConfig, mSurfaceHolder, null);
// Before we can issue GL commands, we need to make sure the context is
// current and bound to a surface.
Log.d("Graphics::initializeOpenGLSurface", "Updating OpenGL context.");
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
initializeOpenGLClientState();
}
private void initializeOpenGLClientState() {
Log.d("Graphics::initializeOpenGLClientState", "Setting up client state.");
String gl_renderer = mGl.glGetString(GL10.GL_RENDERER);
Log.d("Graphics::initializeOpenGLClientState",
"Found renderer: " + gl_renderer);
// Default settings for unknown hardware considerations. We choose to be on
// the save side with respect to performance considerations.
mHasHardwareAcceleration = true;
// Dream / G1.
if (gl_renderer.indexOf("Q3Dimension") != -1) {
mHasHardwareAcceleration = true;
}
// Emulator / Software drivers.
if (gl_renderer.indexOf("PixelFlinger") != -1) {
mHasHardwareAcceleration = false;
}
// Initialize the orthographic projection within our surface. This must
// happen whenever the surface size changes.
mGl.glViewport(0, 0, getWidthOpenGL(), getHeightOpenGL());
mGl.glMatrixMode(GL10.GL_PROJECTION);
mGl.glLoadIdentity();
mGl.glOrthof(0, getWidthOpenGL(), 0, getHeightOpenGL(), -1, 1);
// Since we will only be rendering triangle strips, set up a shared vertex
// and texture coordinate array. The following array lays out 16 quads.
float[] corner_array = { 0, 0, 0, 1, 1, 0, 1, 1,
2, 0, 2, 1,
3, 0, 3, 1,
4, 0, 4, 1,
5, 0, 5, 1,
6, 0, 6, 1,
7, 0, 7, 1,
8, 0, 8, 1,
9, 0, 9, 1,
10, 0, 10, 1,
11, 0, 11, 1,
12, 0, 12, 1,
13, 0, 13, 1,
14, 0, 14, 1,
15, 0, 15, 1,
16, 0, 16, 1, };
ByteBuffer corner_byte_buffer =
ByteBuffer.allocateDirect(4 * corner_array.length);
corner_byte_buffer.order(ByteOrder.nativeOrder());
FloatBuffer corner_float_buffer = corner_byte_buffer.asFloatBuffer();
corner_float_buffer.put(corner_array);
corner_float_buffer.position(0);
mGl.glVertexPointer(2, GL10.GL_FLOAT, 0, corner_float_buffer);
mGl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
mGl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, corner_float_buffer);
mGl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// OpenGL rendering state configuration.
mGl.glEnable(GL10.GL_TEXTURE_2D);
mGl.glDisable(GL10.GL_CULL_FACE);
mGl.glDisable(GL10.GL_DEPTH_TEST);
mGl.glEnable(GL10.GL_BLEND);
mGl.glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
mGl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
mGl.glDisable(GL10.GL_ALPHA_TEST);
}
private void destroyOpenGL() {
Log.d("Graphics::destroyOpenGL", "Destroying open gl.");
if (mEglSurface != null) {
mEgl.eglMakeCurrent(mEglDisplay,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglSurface = null;
}
if (mEglContext != null) {
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEglContext = null;
}
if (mEglDisplay != null) {
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
}
}
public void pushRotationMatrixOpenGL(float angle) {
mGl.glMatrixMode(GL10.GL_MODELVIEW);
mGl.glPushMatrix();
mGl.glTranslatef(mSurfaceWidth / 2.0f, mSurfaceHeight / 2.0f, 0.0f);
mGl.glRotatef(angle, 0, 0, 1);
mGl.glTranslatef(-mSurfaceWidth / 2.0f, -mSurfaceHeight / 2.0f, 0.0f);
}
public void popMatrixOpenGL() {
mGl.glMatrixMode(GL10.GL_MODELVIEW);
mGl.glPopMatrix();
}
private int loadImageFromBitmapOpenGL(Bitmap bitmap) {
// Allocate a texture handle within the OpenGL context.
int[] texture_names = new int[1];
mGl.glGenTextures(1, texture_names, 0);
int texture_name = texture_names[0];
Log.d("Graphics::loadImageFromBitmapOpenGL",
"Allocated texture handle: " + texture_name);
// Bind the pixel data to the texture handle. The Android Bitmap class gives
// us data in an ARGB pixel format, but we must convert this to an RGBA
// pixel format for OpenGL. Additionally, we need to flip the byte ordering.
int[] bitmap_data = new int[bitmap.getWidth() * bitmap.getHeight()];
bitmap.getPixels(bitmap_data, 0, bitmap.getWidth(), 0, 0,
bitmap.getWidth(), bitmap.getHeight());
for (int n = 0; n < bitmap.getWidth() * bitmap.getHeight(); ++n) {
int pixel = bitmap_data[n];
bitmap_data[n] = (((0xFF000000 & pixel)) | // Alpha.
((0x00FF0000 & pixel) >> 16) | // Red.
((0x0000FF00 & pixel)) | // Green.
((0x000000FF & pixel) << 16)); // Blue.
}
IntBuffer bitmap_data_buffer = IntBuffer.wrap(bitmap_data);
mGl.glBindTexture(GL10.GL_TEXTURE_2D, texture_name);
mGl.glTexImage2D(GL10.GL_TEXTURE_2D,
0, // Mipmap level.
GL10.GL_RGBA, // Internal format.
bitmap.getWidth(),
bitmap.getHeight(),
0, // Border.
GL10.GL_RGBA, // Format.
GL10.GL_UNSIGNED_BYTE,
bitmap_data_buffer);
mGl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_NEAREST);
mGl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_NEAREST);
mGl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_REPEAT);
mGl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
// The size must be manually stored for retrieval during the rendering
// process since the texture coordinate scheme under OpenGL is normalized
// where as under the Android2D back end, texture coordinates are absolute.
if (mTextureData.size() <= texture_name) {
mTextureData.setSize(texture_name + 1);
}
TextureData texture_data = new TextureData();
texture_data.width = bitmap.getWidth();
texture_data.height = bitmap.getHeight();
mTextureData.set(texture_name, texture_data);
return texture_name;
}
private void freeImageOpenGL(int image_handle) {
// TODO(burkhart): Implement.
}
private int getWidthOpenGL() {
return mSurfaceWidth;
}
private int getHeightOpenGL() {
return mSurfaceHeight;
}
private boolean beginFrameOpenGL() {
if (!mGlSurfaceInitialized) {
initializeOpenGLSurface();
mGlSurfaceInitialized = true;
}
if (!mGlStateInitialized) {
initializeOpenGLClientState();
mGlStateInitialized = true;
}
mGl.glClear(GL10.GL_COLOR_BUFFER_BIT);
return !mContextLost;
}
private void endFrameOpenGL() {
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
// Always check for EGL_CONTEXT_LOST, which means the context and all
// associated data were lost (For instance because the device went to
// sleep). We need to sleep until we get a new surface.
if (mEgl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
mContextLost = true;
Log.d("Graphics::endFrameBufferOpenGL", "Context Lost.");
}
}
private int mCurrentTexture = -1;
private boolean mContextLost;
private EGL10 mEgl;
private EGLConfig mEglConfig;
private EGLContext mEglContext;
private EGLDisplay mEglDisplay;
private EGLSurface mEglSurface;
private GL10 mGl;
private boolean mGlStateInitialized;
private boolean mGlSurfaceInitialized;
private boolean mHasHardwareAcceleration;
class TextureData {
public int height;
public int width;
}
private Vector<TextureData> mTextureData = new Vector<TextureData>();
// The following matrix definitions are used to avoid any allocations within
// the draw methods.
private Matrix mScreenMatrix = new Matrix();
private float[] mMatrix3x3 = new float[] {
1, 0, 0, 0, 1, 0, 0, 0, 1 };
private float[] mMatrix4x4 = new float[] {
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
}
Related examples in the same category