2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.gallery3d.glrenderer;
19 import android.graphics.Bitmap;
20 import android.graphics.Rect;
21 import android.graphics.RectF;
22 import android.opengl.GLU;
23 import android.opengl.GLUtils;
24 import android.opengl.Matrix;
25 import android.util.Log;
27 import com.android.gallery3d.common.Utils;
28 import com.android.gallery3d.util.IntArray;
30 import junit.framework.Assert;
32 import java.nio.Buffer;
33 import java.nio.ByteBuffer;
34 import java.nio.ByteOrder;
35 import java.nio.FloatBuffer;
36 import java.util.ArrayList;
38 import javax.microedition.khronos.opengles.GL10;
39 import javax.microedition.khronos.opengles.GL11;
40 import javax.microedition.khronos.opengles.GL11Ext;
41 import javax.microedition.khronos.opengles.GL11ExtensionPack;
43 public class GLES11Canvas implements GLCanvas {
44 @SuppressWarnings("unused")
45 private static final String TAG = "GLCanvasImp";
47 private static final float OPAQUE_ALPHA = 0.95f;
49 private static final int OFFSET_FILL_RECT = 0;
50 private static final int OFFSET_DRAW_LINE = 4;
51 private static final int OFFSET_DRAW_RECT = 6;
52 private static final float[] BOX_COORDINATES = {
53 0, 0, 1, 0, 0, 1, 1, 1, // used for filling a rectangle
54 0, 0, 1, 1, // used for drawing a line
55 0, 0, 0, 1, 1, 1, 1, 0}; // used for drawing the outline of a rectangle
59 private final float mMatrixValues[] = new float[16];
60 private final float mTextureMatrixValues[] = new float[16];
62 // The results of mapPoints are stored in this buffer, and the order is
64 private final float mMapPointsBuffer[] = new float[4];
66 private final float mTextureColor[] = new float[4];
68 private int mBoxCoords;
70 private GLState mGLState;
71 private final ArrayList<RawTexture> mTargetStack = new ArrayList<RawTexture>();
74 private final ArrayList<ConfigState> mRestoreStack = new ArrayList<ConfigState>();
75 private ConfigState mRecycledRestoreAction;
77 private final RectF mDrawTextureSourceRect = new RectF();
78 private final RectF mDrawTextureTargetRect = new RectF();
79 private final float[] mTempMatrix = new float[32];
80 private final IntArray mUnboundTextures = new IntArray();
81 private final IntArray mDeleteBuffers = new IntArray();
82 private int mScreenWidth;
83 private int mScreenHeight;
84 private boolean mBlendEnabled = true;
85 private int mFrameBuffer[] = new int[1];
86 private static float[] sCropRect = new float[4];
88 private RawTexture mTargetTexture;
94 int mCountTextureRect;
97 private static GLId mGLId = new GLES11IdImpl();
99 public GLES11Canvas(GL11 gl) {
101 mGLState = new GLState(gl);
102 // First create an nio buffer, then create a VBO from it.
103 int size = BOX_COORDINATES.length * Float.SIZE / Byte.SIZE;
104 FloatBuffer xyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer();
105 xyBuffer.put(BOX_COORDINATES, 0, BOX_COORDINATES.length).position(0);
107 int[] name = new int[1];
108 mGLId.glGenBuffers(1, name, 0);
109 mBoxCoords = name[0];
111 gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords);
112 gl.glBufferData(GL11.GL_ARRAY_BUFFER, xyBuffer.capacity() * (Float.SIZE / Byte.SIZE),
113 xyBuffer, GL11.GL_STATIC_DRAW);
115 gl.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
116 gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
118 // Enable the texture coordinate array for Texture 1
119 gl.glClientActiveTexture(GL11.GL_TEXTURE1);
120 gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
121 gl.glClientActiveTexture(GL11.GL_TEXTURE0);
122 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
124 // mMatrixValues and mAlpha will be initialized in setSize()
128 public void setSize(int width, int height) {
129 Assert.assertTrue(width >= 0 && height >= 0);
131 if (mTargetTexture == null) {
132 mScreenWidth = width;
133 mScreenHeight = height;
138 gl.glViewport(0, 0, width, height);
139 gl.glMatrixMode(GL11.GL_PROJECTION);
141 GLU.gluOrtho2D(gl, 0, width, 0, height);
143 gl.glMatrixMode(GL11.GL_MODELVIEW);
146 float matrix[] = mMatrixValues;
147 Matrix.setIdentityM(matrix, 0);
148 // to match the graphic coordinate system in android, we flip it vertically.
149 if (mTargetTexture == null) {
150 Matrix.translateM(matrix, 0, 0, height, 0);
151 Matrix.scaleM(matrix, 0, 1, -1, 1);
156 public void setAlpha(float alpha) {
157 Assert.assertTrue(alpha >= 0 && alpha <= 1);
162 public float getAlpha() {
167 public void multiplyAlpha(float alpha) {
168 Assert.assertTrue(alpha >= 0 && alpha <= 1);
172 private static ByteBuffer allocateDirectNativeOrderBuffer(int size) {
173 return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
177 public void drawRect(float x, float y, float width, float height, GLPaint paint) {
180 mGLState.setColorMode(paint.getColor(), mAlpha);
181 mGLState.setLineWidth(paint.getLineWidth());
185 scale(width, height, 1);
187 gl.glLoadMatrixf(mMatrixValues, 0);
188 gl.glDrawArrays(GL11.GL_LINE_LOOP, OFFSET_DRAW_RECT, 4);
195 public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
198 mGLState.setColorMode(paint.getColor(), mAlpha);
199 mGLState.setLineWidth(paint.getLineWidth());
203 scale(x2 - x1, y2 - y1, 1);
205 gl.glLoadMatrixf(mMatrixValues, 0);
206 gl.glDrawArrays(GL11.GL_LINE_STRIP, OFFSET_DRAW_LINE, 2);
213 public void fillRect(float x, float y, float width, float height, int color) {
214 mGLState.setColorMode(color, mAlpha);
219 scale(width, height, 1);
221 gl.glLoadMatrixf(mMatrixValues, 0);
222 gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, 4);
229 public void translate(float x, float y, float z) {
230 Matrix.translateM(mMatrixValues, 0, x, y, z);
233 // This is a faster version of translate(x, y, z) because
234 // (1) we knows z = 0, (2) we inline the Matrix.translateM call,
235 // (3) we unroll the loop
237 public void translate(float x, float y) {
238 float[] m = mMatrixValues;
239 m[12] += m[0] * x + m[4] * y;
240 m[13] += m[1] * x + m[5] * y;
241 m[14] += m[2] * x + m[6] * y;
242 m[15] += m[3] * x + m[7] * y;
246 public void scale(float sx, float sy, float sz) {
247 Matrix.scaleM(mMatrixValues, 0, sx, sy, sz);
251 public void rotate(float angle, float x, float y, float z) {
252 if (angle == 0) return;
253 float[] temp = mTempMatrix;
254 Matrix.setRotateM(temp, 0, angle, x, y, z);
255 Matrix.multiplyMM(temp, 16, mMatrixValues, 0, temp, 0);
256 System.arraycopy(temp, 16, mMatrixValues, 0, 16);
260 public void multiplyMatrix(float matrix[], int offset) {
261 float[] temp = mTempMatrix;
262 Matrix.multiplyMM(temp, 0, mMatrixValues, 0, matrix, offset);
263 System.arraycopy(temp, 0, mMatrixValues, 0, 16);
266 private void textureRect(float x, float y, float width, float height) {
271 scale(width, height, 1);
273 gl.glLoadMatrixf(mMatrixValues, 0);
274 gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, 4);
281 public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
282 int uvBuffer, int indexBuffer, int indexCount) {
283 float alpha = mAlpha;
284 if (!bindTexture(tex)) return;
286 mGLState.setBlendEnabled(mBlendEnabled
287 && (!tex.isOpaque() || alpha < OPAQUE_ALPHA));
288 mGLState.setTextureAlpha(alpha);
290 // Reset the texture matrix. We will set our own texture coordinates
292 setTextureCoords(0, 0, 1, 1);
297 mGL.glLoadMatrixf(mMatrixValues, 0);
299 mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, xyBuffer);
300 mGL.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
302 mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, uvBuffer);
303 mGL.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
305 mGL.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
306 mGL.glDrawElements(GL11.GL_TRIANGLE_STRIP,
307 indexCount, GL11.GL_UNSIGNED_BYTE, 0);
309 mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords);
310 mGL.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
311 mGL.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
317 // Transforms two points by the given matrix m. The result
318 // {x1', y1', x2', y2'} are stored in mMapPointsBuffer and also returned.
319 private float[] mapPoints(float m[], int x1, int y1, int x2, int y2) {
320 float[] r = mMapPointsBuffer;
322 // Multiply m and (x1 y1 0 1) to produce (x3 y3 z3 w3). z3 is unused.
323 float x3 = m[0] * x1 + m[4] * y1 + m[12];
324 float y3 = m[1] * x1 + m[5] * y1 + m[13];
325 float w3 = m[3] * x1 + m[7] * y1 + m[15];
330 float x4 = m[0] * x2 + m[4] * y2 + m[12];
331 float y4 = m[1] * x2 + m[5] * y2 + m[13];
332 float w4 = m[3] * x2 + m[7] * y2 + m[15];
339 private void drawBoundTexture(
340 BasicTexture texture, int x, int y, int width, int height) {
341 // Test whether it has been rotated or flipped, if so, glDrawTexiOES
343 if (isMatrixRotatedOrFlipped(mMatrixValues)) {
344 if (texture.hasBorder()) {
346 1.0f / texture.getTextureWidth(),
347 1.0f / texture.getTextureHeight(),
348 (texture.getWidth() - 1.0f) / texture.getTextureWidth(),
349 (texture.getHeight() - 1.0f) / texture.getTextureHeight());
351 setTextureCoords(0, 0,
352 (float) texture.getWidth() / texture.getTextureWidth(),
353 (float) texture.getHeight() / texture.getTextureHeight());
355 textureRect(x, y, width, height);
357 // draw the rect from bottom-left to top-right
358 float points[] = mapPoints(
359 mMatrixValues, x, y + height, x + width, y);
360 x = (int) (points[0] + 0.5f);
361 y = (int) (points[1] + 0.5f);
362 width = (int) (points[2] + 0.5f) - x;
363 height = (int) (points[3] + 0.5f) - y;
364 if (width > 0 && height > 0) {
365 ((GL11Ext) mGL).glDrawTexiOES(x, y, 0, width, height);
372 public void drawTexture(
373 BasicTexture texture, int x, int y, int width, int height) {
374 drawTexture(texture, x, y, width, height, mAlpha);
377 private void drawTexture(BasicTexture texture,
378 int x, int y, int width, int height, float alpha) {
379 if (width <= 0 || height <= 0) return;
381 mGLState.setBlendEnabled(mBlendEnabled
382 && (!texture.isOpaque() || alpha < OPAQUE_ALPHA));
383 if (!bindTexture(texture)) return;
384 mGLState.setTextureAlpha(alpha);
385 drawBoundTexture(texture, x, y, width, height);
389 public void drawTexture(BasicTexture texture, RectF source, RectF target) {
390 if (target.width() <= 0 || target.height() <= 0) return;
392 // Copy the input to avoid changing it.
393 mDrawTextureSourceRect.set(source);
394 mDrawTextureTargetRect.set(target);
395 source = mDrawTextureSourceRect;
396 target = mDrawTextureTargetRect;
398 mGLState.setBlendEnabled(mBlendEnabled
399 && (!texture.isOpaque() || mAlpha < OPAQUE_ALPHA));
400 if (!bindTexture(texture)) return;
401 convertCoordinate(source, target, texture);
402 setTextureCoords(source);
403 mGLState.setTextureAlpha(mAlpha);
404 textureRect(target.left, target.top, target.width(), target.height());
408 public void drawTexture(BasicTexture texture, float[] mTextureTransform,
409 int x, int y, int w, int h) {
410 mGLState.setBlendEnabled(mBlendEnabled
411 && (!texture.isOpaque() || mAlpha < OPAQUE_ALPHA));
412 if (!bindTexture(texture)) return;
413 setTextureCoords(mTextureTransform);
414 mGLState.setTextureAlpha(mAlpha);
415 textureRect(x, y, w, h);
418 // This function changes the source coordinate to the texture coordinates.
419 // It also clips the source and target coordinates if it is beyond the
420 // bound of the texture.
421 private static void convertCoordinate(RectF source, RectF target,
422 BasicTexture texture) {
424 int width = texture.getWidth();
425 int height = texture.getHeight();
426 int texWidth = texture.getTextureWidth();
427 int texHeight = texture.getTextureHeight();
428 // Convert to texture coordinates
429 source.left /= texWidth;
430 source.right /= texWidth;
431 source.top /= texHeight;
432 source.bottom /= texHeight;
434 // Clip if the rendering range is beyond the bound of the texture.
435 float xBound = (float) width / texWidth;
436 if (source.right > xBound) {
437 target.right = target.left + target.width() *
438 (xBound - source.left) / source.width();
439 source.right = xBound;
441 float yBound = (float) height / texHeight;
442 if (source.bottom > yBound) {
443 target.bottom = target.top + target.height() *
444 (yBound - source.top) / source.height();
445 source.bottom = yBound;
450 public void drawMixed(BasicTexture from,
451 int toColor, float ratio, int x, int y, int w, int h) {
452 drawMixed(from, toColor, ratio, x, y, w, h, mAlpha);
455 private boolean bindTexture(BasicTexture texture) {
456 if (!texture.onBind(this)) return false;
457 int target = texture.getTarget();
458 mGLState.setTextureTarget(target);
459 mGL.glBindTexture(target, texture.getId());
463 private void setTextureColor(float r, float g, float b, float alpha) {
464 float[] color = mTextureColor;
471 private void setMixedColor(int toColor, float ratio, float alpha) {
473 // The formula we want:
474 // alpha * ((1 - ratio) * from + ratio * to)
476 // The formula that GL supports is in the form of:
477 // combo * from + (1 - combo) * to * scale
479 // So, we have combo = alpha * (1 - ratio)
480 // and scale = alpha * ratio / (1 - combo)
482 float combo = alpha * (1 - ratio);
483 float scale = alpha * ratio / (1 - combo);
485 // Specify the interpolation factor via the alpha component of
486 // GL_TEXTURE_ENV_COLORs.
487 // RGB component are get from toColor and will used as SRC1
488 float colorScale = scale * (toColor >>> 24) / (0xff * 0xff);
489 setTextureColor(((toColor >>> 16) & 0xff) * colorScale,
490 ((toColor >>> 8) & 0xff) * colorScale,
491 (toColor & 0xff) * colorScale, combo);
493 gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, mTextureColor, 0);
495 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE);
496 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_ALPHA, GL11.GL_INTERPOLATE);
497 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC1_RGB, GL11.GL_CONSTANT);
498 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND1_RGB, GL11.GL_SRC_COLOR);
499 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC1_ALPHA, GL11.GL_CONSTANT);
500 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND1_ALPHA, GL11.GL_SRC_ALPHA);
502 // Wire up the interpolation factor for RGB.
503 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_RGB, GL11.GL_CONSTANT);
504 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_RGB, GL11.GL_SRC_ALPHA);
506 // Wire up the interpolation factor for alpha.
507 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_SRC2_ALPHA, GL11.GL_CONSTANT);
508 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_OPERAND2_ALPHA, GL11.GL_SRC_ALPHA);
513 public void drawMixed(BasicTexture from, int toColor, float ratio,
514 RectF source, RectF target) {
515 if (target.width() <= 0 || target.height() <= 0) return;
517 if (ratio <= 0.01f) {
518 drawTexture(from, source, target);
520 } else if (ratio >= 1) {
521 fillRect(target.left, target.top, target.width(), target.height(), toColor);
525 float alpha = mAlpha;
527 // Copy the input to avoid changing it.
528 mDrawTextureSourceRect.set(source);
529 mDrawTextureTargetRect.set(target);
530 source = mDrawTextureSourceRect;
531 target = mDrawTextureTargetRect;
533 mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
534 || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));
536 if (!bindTexture(from)) return;
538 // Interpolate the RGB and alpha values between both textures.
539 mGLState.setTexEnvMode(GL11.GL_COMBINE);
540 setMixedColor(toColor, ratio, alpha);
541 convertCoordinate(source, target, from);
542 setTextureCoords(source);
543 textureRect(target.left, target.top, target.width(), target.height());
544 mGLState.setTexEnvMode(GL11.GL_REPLACE);
547 private void drawMixed(BasicTexture from, int toColor,
548 float ratio, int x, int y, int width, int height, float alpha) {
549 // change from 0 to 0.01f to prevent getting divided by zero below
550 if (ratio <= 0.01f) {
551 drawTexture(from, x, y, width, height, alpha);
553 } else if (ratio >= 1) {
554 fillRect(x, y, width, height, toColor);
558 mGLState.setBlendEnabled(mBlendEnabled && (!from.isOpaque()
559 || !Utils.isOpaque(toColor) || alpha < OPAQUE_ALPHA));
562 if (!bindTexture(from)) return;
564 // Interpolate the RGB and alpha values between both textures.
565 mGLState.setTexEnvMode(GL11.GL_COMBINE);
566 setMixedColor(toColor, ratio, alpha);
568 drawBoundTexture(from, x, y, width, height);
569 mGLState.setTexEnvMode(GL11.GL_REPLACE);
572 // TODO: the code only work for 2D should get fixed for 3D or removed
573 private static final int MSKEW_X = 4;
574 private static final int MSKEW_Y = 1;
575 private static final int MSCALE_X = 0;
576 private static final int MSCALE_Y = 5;
578 private static boolean isMatrixRotatedOrFlipped(float matrix[]) {
579 final float eps = 1e-5f;
580 return Math.abs(matrix[MSKEW_X]) > eps
581 || Math.abs(matrix[MSKEW_Y]) > eps
582 || matrix[MSCALE_X] < -eps
583 || matrix[MSCALE_Y] > eps;
586 private static class GLState {
588 private final GL11 mGL;
590 private int mTexEnvMode = GL11.GL_REPLACE;
591 private float mTextureAlpha = 1.0f;
592 private int mTextureTarget = GL11.GL_TEXTURE_2D;
593 private boolean mBlendEnabled = true;
594 private float mLineWidth = 1.0f;
595 private boolean mLineSmooth = false;
597 public GLState(GL11 gl) {
600 // Disable unused state
601 gl.glDisable(GL11.GL_LIGHTING);
603 // Enable used features
604 gl.glEnable(GL11.GL_DITHER);
606 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
607 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
608 gl.glEnable(GL11.GL_TEXTURE_2D);
610 gl.glTexEnvf(GL11.GL_TEXTURE_ENV,
611 GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE);
613 // Set the background color
614 gl.glClearColor(0f, 0f, 0f, 0f);
616 gl.glEnable(GL11.GL_BLEND);
617 gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
619 // We use 565 or 8888 format, so set the alignment to 2 bytes/pixel.
620 gl.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 2);
623 public void setTexEnvMode(int mode) {
624 if (mTexEnvMode == mode) return;
626 mGL.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, mode);
629 public void setLineWidth(float width) {
630 if (mLineWidth == width) return;
632 mGL.glLineWidth(width);
635 public void setTextureAlpha(float alpha) {
636 if (mTextureAlpha == alpha) return;
637 mTextureAlpha = alpha;
638 if (alpha >= OPAQUE_ALPHA) {
639 // The alpha is need for those texture without alpha channel
640 mGL.glColor4f(1, 1, 1, 1);
641 setTexEnvMode(GL11.GL_REPLACE);
643 mGL.glColor4f(alpha, alpha, alpha, alpha);
644 setTexEnvMode(GL11.GL_MODULATE);
648 public void setColorMode(int color, float alpha) {
649 setBlendEnabled(!Utils.isOpaque(color) || alpha < OPAQUE_ALPHA);
651 // Set mTextureAlpha to an invalid value, so that it will reset
652 // again in setTextureAlpha(float) later.
653 mTextureAlpha = -1.0f;
657 float prealpha = (color >>> 24) * alpha * 65535f / 255f / 255f;
659 Math.round(((color >> 16) & 0xFF) * prealpha),
660 Math.round(((color >> 8) & 0xFF) * prealpha),
661 Math.round((color & 0xFF) * prealpha),
662 Math.round(255 * prealpha));
665 // target is a value like GL_TEXTURE_2D. If target = 0, texturing is disabled.
666 public void setTextureTarget(int target) {
667 if (mTextureTarget == target) return;
668 if (mTextureTarget != 0) {
669 mGL.glDisable(mTextureTarget);
671 mTextureTarget = target;
672 if (mTextureTarget != 0) {
673 mGL.glEnable(mTextureTarget);
677 public void setBlendEnabled(boolean enabled) {
678 if (mBlendEnabled == enabled) return;
679 mBlendEnabled = enabled;
681 mGL.glEnable(GL11.GL_BLEND);
683 mGL.glDisable(GL11.GL_BLEND);
689 public void clearBuffer(float[] argb) {
690 if(argb != null && argb.length == 4) {
691 mGL.glClearColor(argb[1], argb[2], argb[3], argb[0]);
693 mGL.glClearColor(0, 0, 0, 1);
695 mGL.glClear(GL10.GL_COLOR_BUFFER_BIT);
699 public void clearBuffer() {
703 private void setTextureCoords(RectF source) {
704 setTextureCoords(source.left, source.top, source.right, source.bottom);
707 private void setTextureCoords(float left, float top,
708 float right, float bottom) {
709 mGL.glMatrixMode(GL11.GL_TEXTURE);
710 mTextureMatrixValues[0] = right - left;
711 mTextureMatrixValues[5] = bottom - top;
712 mTextureMatrixValues[10] = 1;
713 mTextureMatrixValues[12] = left;
714 mTextureMatrixValues[13] = top;
715 mTextureMatrixValues[15] = 1;
716 mGL.glLoadMatrixf(mTextureMatrixValues, 0);
717 mGL.glMatrixMode(GL11.GL_MODELVIEW);
720 private void setTextureCoords(float[] mTextureTransform) {
721 mGL.glMatrixMode(GL11.GL_TEXTURE);
722 mGL.glLoadMatrixf(mTextureTransform, 0);
723 mGL.glMatrixMode(GL11.GL_MODELVIEW);
726 // unloadTexture and deleteBuffer can be called from the finalizer thread,
727 // so we synchronized on the mUnboundTextures object.
729 public boolean unloadTexture(BasicTexture t) {
730 synchronized (mUnboundTextures) {
731 if (!t.isLoaded()) return false;
732 mUnboundTextures.add(t.mId);
738 public void deleteBuffer(int bufferId) {
739 synchronized (mUnboundTextures) {
740 mDeleteBuffers.add(bufferId);
745 public void deleteRecycledResources() {
746 synchronized (mUnboundTextures) {
747 IntArray ids = mUnboundTextures;
748 if (ids.size() > 0) {
749 mGLId.glDeleteTextures(mGL, ids.size(), ids.getInternalArray(), 0);
753 ids = mDeleteBuffers;
754 if (ids.size() > 0) {
755 mGLId.glDeleteBuffers(mGL, ids.size(), ids.getInternalArray(), 0);
767 public void save(int saveFlags) {
768 ConfigState config = obtainRestoreConfig();
770 if ((saveFlags & SAVE_FLAG_ALPHA) != 0) {
771 config.mAlpha = mAlpha;
776 if ((saveFlags & SAVE_FLAG_MATRIX) != 0) {
777 System.arraycopy(mMatrixValues, 0, config.mMatrix, 0, 16);
779 config.mMatrix[0] = Float.NEGATIVE_INFINITY;
782 mRestoreStack.add(config);
786 public void restore() {
787 if (mRestoreStack.isEmpty()) throw new IllegalStateException();
788 ConfigState config = mRestoreStack.remove(mRestoreStack.size() - 1);
789 config.restore(this);
790 freeRestoreConfig(config);
793 private void freeRestoreConfig(ConfigState action) {
794 action.mNextFree = mRecycledRestoreAction;
795 mRecycledRestoreAction = action;
798 private ConfigState obtainRestoreConfig() {
799 if (mRecycledRestoreAction != null) {
800 ConfigState result = mRecycledRestoreAction;
801 mRecycledRestoreAction = result.mNextFree;
804 return new ConfigState();
807 private static class ConfigState {
809 float mMatrix[] = new float[16];
810 ConfigState mNextFree;
812 public void restore(GLES11Canvas canvas) {
813 if (mAlpha >= 0) canvas.setAlpha(mAlpha);
814 if (mMatrix[0] != Float.NEGATIVE_INFINITY) {
815 System.arraycopy(mMatrix, 0, canvas.mMatrixValues, 0, 16);
821 public void dumpStatisticsAndClear() {
822 String line = String.format(
823 "MESH:%d, TEX_OES:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d",
824 mCountDrawMesh, mCountTextureRect, mCountTextureOES,
825 mCountFillRect, mCountDrawLine);
827 mCountTextureRect = 0;
828 mCountTextureOES = 0;
834 private void saveTransform() {
835 System.arraycopy(mMatrixValues, 0, mTempMatrix, 0, 16);
838 private void restoreTransform() {
839 System.arraycopy(mTempMatrix, 0, mMatrixValues, 0, 16);
842 private void setRenderTarget(RawTexture texture) {
843 GL11ExtensionPack gl11ep = (GL11ExtensionPack) mGL;
845 if (mTargetTexture == null && texture != null) {
846 mGLId.glGenBuffers(1, mFrameBuffer, 0);
847 gl11ep.glBindFramebufferOES(
848 GL11ExtensionPack.GL_FRAMEBUFFER_OES, mFrameBuffer[0]);
850 if (mTargetTexture != null && texture == null) {
851 gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);
852 gl11ep.glDeleteFramebuffersOES(1, mFrameBuffer, 0);
855 mTargetTexture = texture;
856 if (texture == null) {
857 setSize(mScreenWidth, mScreenHeight);
859 setSize(texture.getWidth(), texture.getHeight());
861 if (!texture.isLoaded()) texture.prepare(this);
863 gl11ep.glFramebufferTexture2DOES(
864 GL11ExtensionPack.GL_FRAMEBUFFER_OES,
865 GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES,
866 GL11.GL_TEXTURE_2D, texture.getId(), 0);
868 checkFramebufferStatus(gl11ep);
873 public void endRenderTarget() {
874 RawTexture texture = mTargetStack.remove(mTargetStack.size() - 1);
875 setRenderTarget(texture);
876 restore(); // restore matrix and alpha
880 public void beginRenderTarget(RawTexture texture) {
881 save(); // save matrix and alpha
882 mTargetStack.add(mTargetTexture);
883 setRenderTarget(texture);
886 private static void checkFramebufferStatus(GL11ExtensionPack gl11ep) {
887 int status = gl11ep.glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES);
888 if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES) {
891 case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES:
892 msg = "FRAMEBUFFER_FORMATS";
894 case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES:
895 msg = "FRAMEBUFFER_ATTACHMENT";
897 case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES:
898 msg = "FRAMEBUFFER_MISSING_ATTACHMENT";
900 case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES:
901 msg = "FRAMEBUFFER_DRAW_BUFFER";
903 case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES:
904 msg = "FRAMEBUFFER_READ_BUFFER";
906 case GL11ExtensionPack.GL_FRAMEBUFFER_UNSUPPORTED_OES:
907 msg = "FRAMEBUFFER_UNSUPPORTED";
909 case GL11ExtensionPack.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES:
910 msg = "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
913 throw new RuntimeException(msg + ":" + Integer.toHexString(status));
918 public void setTextureParameters(BasicTexture texture) {
919 int width = texture.getWidth();
920 int height = texture.getHeight();
921 // Define a vertically flipped crop rectangle for OES_draw_texture.
922 // The four values in sCropRect are: left, bottom, width, and
923 // height. Negative value of width or height means flip.
925 sCropRect[1] = height;
926 sCropRect[2] = width;
927 sCropRect[3] = -height;
929 // Set texture parameters.
930 int target = texture.getTarget();
931 mGL.glBindTexture(target, texture.getId());
932 mGL.glTexParameterfv(target, GL11Ext.GL_TEXTURE_CROP_RECT_OES, sCropRect, 0);
933 mGL.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE);
934 mGL.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE);
935 mGL.glTexParameterf(target, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
936 mGL.glTexParameterf(target, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
940 public void initializeTextureSize(BasicTexture texture, int format, int type) {
941 int target = texture.getTarget();
942 mGL.glBindTexture(target, texture.getId());
943 int width = texture.getTextureWidth();
944 int height = texture.getTextureHeight();
945 mGL.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
949 public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
950 int target = texture.getTarget();
951 mGL.glBindTexture(target, texture.getId());
952 GLUtils.texImage2D(target, 0, bitmap, 0);
956 public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
957 int format, int type) {
958 int target = texture.getTarget();
959 mGL.glBindTexture(target, texture.getId());
960 GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
964 public int uploadBuffer(FloatBuffer buf) {
965 return uploadBuffer(buf, Float.SIZE / Byte.SIZE);
969 public int uploadBuffer(ByteBuffer buf) {
970 return uploadBuffer(buf, 1);
973 private int uploadBuffer(Buffer buf, int elementSize) {
974 int[] bufferIds = new int[1];
975 mGLId.glGenBuffers(bufferIds.length, bufferIds, 0);
976 int bufferId = bufferIds[0];
977 mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, bufferId);
978 mGL.glBufferData(GL11.GL_ARRAY_BUFFER, buf.capacity() * elementSize, buf,
979 GL11.GL_STATIC_DRAW);
984 public void recoverFromLightCycle() {
985 // This is only required for GLES20
989 public void getBounds(Rect bounds, int x, int y, int width, int height) {
990 // This is only required for GLES20
994 public GLId getGLId() {