1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 package com.android.gallery3d.glrenderer; 17 18 import android.graphics.Bitmap; 19 import android.graphics.Rect; 20 import android.graphics.RectF; 21 import android.opengl.GLES20; 22 import android.opengl.GLUtils; 23 import android.opengl.Matrix; 24 import android.util.Log; 25 26 import java.nio.Buffer; 27 import java.nio.ByteBuffer; 28 import java.nio.ByteOrder; 29 import java.nio.FloatBuffer; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 33 public class GLES20Canvas implements GLCanvas { 34 // ************** Constants ********************** 35 private static final String TAG = GLES20Canvas.class.getSimpleName(); 36 private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE; 37 private static final float OPAQUE_ALPHA = 0.95f; 38 39 private static final int COORDS_PER_VERTEX = 2; 40 private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE; 41 42 private static final int COUNT_FILL_VERTEX = 4; 43 private static final int COUNT_LINE_VERTEX = 2; 44 private static final int COUNT_RECT_VERTEX = 4; 45 private static final int OFFSET_FILL_RECT = 0; 46 private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX; 47 private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX; 48 49 private static final float[] BOX_COORDINATES = { 50 0, 0, // Fill rectangle 51 1, 0, 52 0, 1, 53 1, 1, 54 0, 0, // Draw line 55 1, 1, 56 0, 0, // Draw rectangle outline 57 0, 1, 58 1, 1, 59 1, 0, 60 }; 61 62 private static final float[] BOUNDS_COORDINATES = { 63 0, 0, 0, 1, 64 1, 1, 0, 1, 65 }; 66 67 private static final String POSITION_ATTRIBUTE = "aPosition"; 68 private static final String COLOR_UNIFORM = "uColor"; 69 private static final String MATRIX_UNIFORM = "uMatrix"; 70 private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix"; 71 private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler"; 72 private static final String ALPHA_UNIFORM = "uAlpha"; 73 private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate"; 74 75 private static final String DRAW_VERTEX_SHADER = "" 76 + "uniform mat4 " + MATRIX_UNIFORM + ";\n" 77 + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" 78 + "void main() {\n" 79 + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" 80 + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n" 81 + "}\n"; 82 83 private static final String DRAW_FRAGMENT_SHADER = "" 84 + "precision mediump float;\n" 85 + "uniform vec4 " + COLOR_UNIFORM + ";\n" 86 + "void main() {\n" 87 + " gl_FragColor = " + COLOR_UNIFORM + ";\n" 88 + "}\n"; 89 90 private static final String TEXTURE_VERTEX_SHADER = "" 91 + "uniform mat4 " + MATRIX_UNIFORM + ";\n" 92 + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n" 93 + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" 94 + "varying vec2 vTextureCoord;\n" 95 + "void main() {\n" 96 + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" 97 + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n" 98 + " vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n" 99 + "}\n"; 100 101 private static final String MESH_VERTEX_SHADER = "" 102 + "uniform mat4 " + MATRIX_UNIFORM + ";\n" 103 + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n" 104 + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n" 105 + "varying vec2 vTextureCoord;\n" 106 + "void main() {\n" 107 + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n" 108 + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n" 109 + " vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n" 110 + "}\n"; 111 112 private static final String TEXTURE_FRAGMENT_SHADER = "" 113 + "precision mediump float;\n" 114 + "varying vec2 vTextureCoord;\n" 115 + "uniform float " + ALPHA_UNIFORM + ";\n" 116 + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n" 117 + "void main() {\n" 118 + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n" 119 + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n" 120 + "}\n"; 121 122 private static final String OES_TEXTURE_FRAGMENT_SHADER = "" 123 + "#extension GL_OES_EGL_image_external : require\n" 124 + "precision mediump float;\n" 125 + "varying vec2 vTextureCoord;\n" 126 + "uniform float " + ALPHA_UNIFORM + ";\n" 127 + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n" 128 + "void main() {\n" 129 + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n" 130 + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n" 131 + "}\n"; 132 133 private static final int INITIAL_RESTORE_STATE_SIZE = 8; 134 private static final int MATRIX_SIZE = 16; 135 136 // Keep track of restore state 137 private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE]; 138 private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE]; 139 private IntArray mSaveFlags = new IntArray(); 140 141 private int mCurrentAlphaIndex = 0; 142 private int mCurrentMatrixIndex = 0; 143 144 // Viewport size 145 private int mWidth; 146 private int mHeight; 147 148 // Projection matrix 149 private float[] mProjectionMatrix = new float[MATRIX_SIZE]; 150 151 // Screen size for when we aren't bound to a texture 152 private int mScreenWidth; 153 private int mScreenHeight; 154 155 // GL programs 156 private int mDrawProgram; 157 private int mTextureProgram; 158 private int mOesTextureProgram; 159 private int mMeshProgram; 160 161 // GL buffer containing BOX_COORDINATES 162 private int mBoxCoordinates; 163 164 // Handle indices -- common 165 private static final int INDEX_POSITION = 0; 166 private static final int INDEX_MATRIX = 1; 167 168 // Handle indices -- draw 169 private static final int INDEX_COLOR = 2; 170 171 // Handle indices -- texture 172 private static final int INDEX_TEXTURE_MATRIX = 2; 173 private static final int INDEX_TEXTURE_SAMPLER = 3; 174 private static final int INDEX_ALPHA = 4; 175 176 // Handle indices -- mesh 177 private static final int INDEX_TEXTURE_COORD = 2; 178 179 private abstract static class ShaderParameter { 180 public int handle; 181 protected final String mName; 182 ShaderParameter(String name)183 public ShaderParameter(String name) { 184 mName = name; 185 } 186 loadHandle(int program)187 public abstract void loadHandle(int program); 188 } 189 190 private static class UniformShaderParameter extends ShaderParameter { UniformShaderParameter(String name)191 public UniformShaderParameter(String name) { 192 super(name); 193 } 194 195 @Override loadHandle(int program)196 public void loadHandle(int program) { 197 handle = GLES20.glGetUniformLocation(program, mName); 198 checkError(); 199 } 200 } 201 202 private static class AttributeShaderParameter extends ShaderParameter { AttributeShaderParameter(String name)203 public AttributeShaderParameter(String name) { 204 super(name); 205 } 206 207 @Override loadHandle(int program)208 public void loadHandle(int program) { 209 handle = GLES20.glGetAttribLocation(program, mName); 210 checkError(); 211 } 212 } 213 214 ShaderParameter[] mDrawParameters = { 215 new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION 216 new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX 217 new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR 218 }; 219 ShaderParameter[] mTextureParameters = { 220 new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION 221 new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX 222 new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX 223 new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER 224 new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA 225 }; 226 ShaderParameter[] mOesTextureParameters = { 227 new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION 228 new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX 229 new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX 230 new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER 231 new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA 232 }; 233 ShaderParameter[] mMeshParameters = { 234 new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION 235 new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX 236 new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD 237 new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER 238 new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA 239 }; 240 241 private final IntArray mUnboundTextures = new IntArray(); 242 private final IntArray mDeleteBuffers = new IntArray(); 243 244 // Keep track of statistics for debugging 245 private int mCountDrawMesh = 0; 246 private int mCountTextureRect = 0; 247 private int mCountFillRect = 0; 248 private int mCountDrawLine = 0; 249 250 // Buffer for framebuffer IDs -- we keep track so we can switch the attached 251 // texture. 252 private int[] mFrameBuffer = new int[1]; 253 254 // Bound textures. 255 private ArrayList<RawTexture> mTargetTextures = new ArrayList<RawTexture>(); 256 257 // Temporary variables used within calculations 258 private final float[] mTempMatrix = new float[32]; 259 private final float[] mTempColor = new float[4]; 260 private final RectF mTempSourceRect = new RectF(); 261 private final RectF mTempTargetRect = new RectF(); 262 private final float[] mTempTextureMatrix = new float[MATRIX_SIZE]; 263 private final int[] mTempIntArray = new int[1]; 264 265 private static final GLId mGLId = new GLES20IdImpl(); 266 GLES20Canvas()267 public GLES20Canvas() { 268 Matrix.setIdentityM(mTempTextureMatrix, 0); 269 Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex); 270 mAlphas[mCurrentAlphaIndex] = 1f; 271 mTargetTextures.add(null); 272 273 FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES); 274 mBoxCoordinates = uploadBuffer(boxBuffer); 275 276 int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER); 277 int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER); 278 int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER); 279 int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER); 280 int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER); 281 int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, 282 OES_TEXTURE_FRAGMENT_SHADER); 283 284 mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters); 285 mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader, 286 mTextureParameters); 287 mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader, 288 mOesTextureParameters); 289 mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters); 290 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); 291 checkError(); 292 } 293 createBuffer(float[] values)294 private static FloatBuffer createBuffer(float[] values) { 295 // First create an nio buffer, then create a VBO from it. 296 int size = values.length * FLOAT_SIZE; 297 FloatBuffer buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()) 298 .asFloatBuffer(); 299 buffer.put(values, 0, values.length).position(0); 300 return buffer; 301 } 302 assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params)303 private int assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params) { 304 int program = GLES20.glCreateProgram(); 305 checkError(); 306 if (program == 0) { 307 throw new RuntimeException("Cannot create GL program: " + GLES20.glGetError()); 308 } 309 GLES20.glAttachShader(program, vertexShader); 310 checkError(); 311 GLES20.glAttachShader(program, fragmentShader); 312 checkError(); 313 GLES20.glLinkProgram(program); 314 checkError(); 315 int[] mLinkStatus = mTempIntArray; 316 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, mLinkStatus, 0); 317 if (mLinkStatus[0] != GLES20.GL_TRUE) { 318 Log.e(TAG, "Could not link program: "); 319 Log.e(TAG, GLES20.glGetProgramInfoLog(program)); 320 GLES20.glDeleteProgram(program); 321 program = 0; 322 } 323 for (int i = 0; i < params.length; i++) { 324 params[i].loadHandle(program); 325 } 326 return program; 327 } 328 loadShader(int type, String shaderCode)329 private static int loadShader(int type, String shaderCode) { 330 // create a vertex shader type (GLES20.GL_VERTEX_SHADER) 331 // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) 332 int shader = GLES20.glCreateShader(type); 333 334 // add the source code to the shader and compile it 335 GLES20.glShaderSource(shader, shaderCode); 336 checkError(); 337 GLES20.glCompileShader(shader); 338 checkError(); 339 340 return shader; 341 } 342 343 @Override setSize(int width, int height)344 public void setSize(int width, int height) { 345 mWidth = width; 346 mHeight = height; 347 GLES20.glViewport(0, 0, mWidth, mHeight); 348 checkError(); 349 Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex); 350 Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1); 351 if (getTargetTexture() == null) { 352 mScreenWidth = width; 353 mScreenHeight = height; 354 Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0); 355 Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1); 356 } 357 } 358 359 @Override clearBuffer()360 public void clearBuffer() { 361 GLES20.glClearColor(0f, 0f, 0f, 1f); 362 checkError(); 363 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 364 checkError(); 365 } 366 367 @Override clearBuffer(float[] argb)368 public void clearBuffer(float[] argb) { 369 GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]); 370 checkError(); 371 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 372 checkError(); 373 } 374 375 @Override getAlpha()376 public float getAlpha() { 377 return mAlphas[mCurrentAlphaIndex]; 378 } 379 380 @Override setAlpha(float alpha)381 public void setAlpha(float alpha) { 382 mAlphas[mCurrentAlphaIndex] = alpha; 383 } 384 385 @Override multiplyAlpha(float alpha)386 public void multiplyAlpha(float alpha) { 387 setAlpha(getAlpha() * alpha); 388 } 389 390 @Override translate(float x, float y, float z)391 public void translate(float x, float y, float z) { 392 Matrix.translateM(mMatrices, mCurrentMatrixIndex, x, y, z); 393 } 394 395 // This is a faster version of translate(x, y, z) because 396 // (1) we knows z = 0, (2) we inline the Matrix.translateM call, 397 // (3) we unroll the loop 398 @Override translate(float x, float y)399 public void translate(float x, float y) { 400 int index = mCurrentMatrixIndex; 401 float[] m = mMatrices; 402 m[index + 12] += m[index + 0] * x + m[index + 4] * y; 403 m[index + 13] += m[index + 1] * x + m[index + 5] * y; 404 m[index + 14] += m[index + 2] * x + m[index + 6] * y; 405 m[index + 15] += m[index + 3] * x + m[index + 7] * y; 406 } 407 408 @Override scale(float sx, float sy, float sz)409 public void scale(float sx, float sy, float sz) { 410 Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz); 411 } 412 413 @Override rotate(float angle, float x, float y, float z)414 public void rotate(float angle, float x, float y, float z) { 415 if (angle == 0f) { 416 return; 417 } 418 float[] temp = mTempMatrix; 419 Matrix.setRotateM(temp, 0, angle, x, y, z); 420 float[] matrix = mMatrices; 421 int index = mCurrentMatrixIndex; 422 Matrix.multiplyMM(temp, MATRIX_SIZE, matrix, index, temp, 0); 423 System.arraycopy(temp, MATRIX_SIZE, matrix, index, MATRIX_SIZE); 424 } 425 426 @Override multiplyMatrix(float[] matrix, int offset)427 public void multiplyMatrix(float[] matrix, int offset) { 428 float[] temp = mTempMatrix; 429 float[] currentMatrix = mMatrices; 430 int index = mCurrentMatrixIndex; 431 Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset); 432 System.arraycopy(temp, 0, currentMatrix, index, 16); 433 } 434 435 @Override save()436 public void save() { 437 save(SAVE_FLAG_ALL); 438 } 439 440 @Override save(int saveFlags)441 public void save(int saveFlags) { 442 boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA; 443 if (saveAlpha) { 444 float currentAlpha = getAlpha(); 445 mCurrentAlphaIndex++; 446 if (mAlphas.length <= mCurrentAlphaIndex) { 447 mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2); 448 } 449 mAlphas[mCurrentAlphaIndex] = currentAlpha; 450 } 451 boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX; 452 if (saveMatrix) { 453 int currentIndex = mCurrentMatrixIndex; 454 mCurrentMatrixIndex += MATRIX_SIZE; 455 if (mMatrices.length <= mCurrentMatrixIndex) { 456 mMatrices = Arrays.copyOf(mMatrices, mMatrices.length * 2); 457 } 458 System.arraycopy(mMatrices, currentIndex, mMatrices, mCurrentMatrixIndex, MATRIX_SIZE); 459 } 460 mSaveFlags.add(saveFlags); 461 } 462 463 @Override restore()464 public void restore() { 465 int restoreFlags = mSaveFlags.removeLast(); 466 boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA; 467 if (restoreAlpha) { 468 mCurrentAlphaIndex--; 469 } 470 boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX; 471 if (restoreMatrix) { 472 mCurrentMatrixIndex -= MATRIX_SIZE; 473 } 474 } 475 476 @Override drawLine(float x1, float y1, float x2, float y2, GLPaint paint)477 public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) { 478 draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1, 479 paint); 480 mCountDrawLine++; 481 } 482 483 @Override drawRect(float x, float y, float width, float height, GLPaint paint)484 public void drawRect(float x, float y, float width, float height, GLPaint paint) { 485 draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint); 486 mCountDrawLine++; 487 } 488 draw(int type, int offset, int count, float x, float y, float width, float height, GLPaint paint)489 private void draw(int type, int offset, int count, float x, float y, float width, float height, 490 GLPaint paint) { 491 draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth()); 492 } 493 draw(int type, int offset, int count, float x, float y, float width, float height, int color, float lineWidth)494 private void draw(int type, int offset, int count, float x, float y, float width, float height, 495 int color, float lineWidth) { 496 prepareDraw(offset, color, lineWidth); 497 draw(mDrawParameters, type, count, x, y, width, height); 498 } 499 prepareDraw(int offset, int color, float lineWidth)500 private void prepareDraw(int offset, int color, float lineWidth) { 501 GLES20.glUseProgram(mDrawProgram); 502 checkError(); 503 if (lineWidth > 0) { 504 GLES20.glLineWidth(lineWidth); 505 checkError(); 506 } 507 float[] colorArray = getColor(color); 508 boolean blendingEnabled = (colorArray[3] < 1f); 509 enableBlending(blendingEnabled); 510 if (blendingEnabled) { 511 GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]); 512 checkError(); 513 } 514 515 GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0); 516 setPosition(mDrawParameters, offset); 517 checkError(); 518 } 519 getColor(int color)520 private float[] getColor(int color) { 521 float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha(); 522 float red = ((color >>> 16) & 0xFF) / 255f * alpha; 523 float green = ((color >>> 8) & 0xFF) / 255f * alpha; 524 float blue = (color & 0xFF) / 255f * alpha; 525 mTempColor[0] = red; 526 mTempColor[1] = green; 527 mTempColor[2] = blue; 528 mTempColor[3] = alpha; 529 return mTempColor; 530 } 531 enableBlending(boolean enableBlending)532 private void enableBlending(boolean enableBlending) { 533 if (enableBlending) { 534 GLES20.glEnable(GLES20.GL_BLEND); 535 checkError(); 536 } else { 537 GLES20.glDisable(GLES20.GL_BLEND); 538 checkError(); 539 } 540 } 541 setPosition(ShaderParameter[] params, int offset)542 private void setPosition(ShaderParameter[] params, int offset) { 543 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates); 544 checkError(); 545 GLES20.glVertexAttribPointer(params[INDEX_POSITION].handle, COORDS_PER_VERTEX, 546 GLES20.GL_FLOAT, false, VERTEX_STRIDE, offset * VERTEX_STRIDE); 547 checkError(); 548 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 549 checkError(); 550 } 551 draw(ShaderParameter[] params, int type, int count, float x, float y, float width, float height)552 private void draw(ShaderParameter[] params, int type, int count, float x, float y, float width, 553 float height) { 554 setMatrix(params, x, y, width, height); 555 int positionHandle = params[INDEX_POSITION].handle; 556 GLES20.glEnableVertexAttribArray(positionHandle); 557 checkError(); 558 GLES20.glDrawArrays(type, 0, count); 559 checkError(); 560 GLES20.glDisableVertexAttribArray(positionHandle); 561 checkError(); 562 } 563 setMatrix(ShaderParameter[] params, float x, float y, float width, float height)564 private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height) { 565 Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f); 566 Matrix.scaleM(mTempMatrix, 0, width, height, 1f); 567 Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0); 568 GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, mTempMatrix, MATRIX_SIZE); 569 checkError(); 570 } 571 572 @Override fillRect(float x, float y, float width, float height, int color)573 public void fillRect(float x, float y, float width, float height, int color) { 574 draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height, 575 color, 0f); 576 mCountFillRect++; 577 } 578 579 @Override drawTexture(BasicTexture texture, int x, int y, int width, int height)580 public void drawTexture(BasicTexture texture, int x, int y, int width, int height) { 581 if (width <= 0 || height <= 0) { 582 return; 583 } 584 copyTextureCoordinates(texture, mTempSourceRect); 585 mTempTargetRect.set(x, y, x + width, y + height); 586 convertCoordinate(mTempSourceRect, mTempTargetRect, texture); 587 drawTextureRect(texture, mTempSourceRect, mTempTargetRect); 588 } 589 copyTextureCoordinates(BasicTexture texture, RectF outRect)590 private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) { 591 int left = 0; 592 int top = 0; 593 int right = texture.getWidth(); 594 int bottom = texture.getHeight(); 595 if (texture.hasBorder()) { 596 left = 1; 597 top = 1; 598 right -= 1; 599 bottom -= 1; 600 } 601 outRect.set(left, top, right, bottom); 602 } 603 604 @Override drawTexture(BasicTexture texture, RectF source, RectF target)605 public void drawTexture(BasicTexture texture, RectF source, RectF target) { 606 if (target.width() <= 0 || target.height() <= 0) { 607 return; 608 } 609 mTempSourceRect.set(source); 610 mTempTargetRect.set(target); 611 612 convertCoordinate(mTempSourceRect, mTempTargetRect, texture); 613 drawTextureRect(texture, mTempSourceRect, mTempTargetRect); 614 } 615 616 @Override drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w, int h)617 public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w, 618 int h) { 619 if (w <= 0 || h <= 0) { 620 return; 621 } 622 mTempTargetRect.set(x, y, x + w, y + h); 623 drawTextureRect(texture, textureTransform, mTempTargetRect); 624 } 625 drawTextureRect(BasicTexture texture, RectF source, RectF target)626 private void drawTextureRect(BasicTexture texture, RectF source, RectF target) { 627 setTextureMatrix(source); 628 drawTextureRect(texture, mTempTextureMatrix, target); 629 } 630 setTextureMatrix(RectF source)631 private void setTextureMatrix(RectF source) { 632 mTempTextureMatrix[0] = source.width(); 633 mTempTextureMatrix[5] = source.height(); 634 mTempTextureMatrix[12] = source.left; 635 mTempTextureMatrix[13] = source.top; 636 } 637 638 // This function changes the source coordinate to the texture coordinates. 639 // It also clips the source and target coordinates if it is beyond the 640 // bound of the texture. convertCoordinate(RectF source, RectF target, BasicTexture texture)641 private static void convertCoordinate(RectF source, RectF target, BasicTexture texture) { 642 int width = texture.getWidth(); 643 int height = texture.getHeight(); 644 int texWidth = texture.getTextureWidth(); 645 int texHeight = texture.getTextureHeight(); 646 // Convert to texture coordinates 647 source.left /= texWidth; 648 source.right /= texWidth; 649 source.top /= texHeight; 650 source.bottom /= texHeight; 651 652 // Clip if the rendering range is beyond the bound of the texture. 653 float xBound = (float) width / texWidth; 654 if (source.right > xBound) { 655 target.right = target.left + target.width() * (xBound - source.left) / source.width(); 656 source.right = xBound; 657 } 658 float yBound = (float) height / texHeight; 659 if (source.bottom > yBound) { 660 target.bottom = target.top + target.height() * (yBound - source.top) / source.height(); 661 source.bottom = yBound; 662 } 663 } 664 drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target)665 private void drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target) { 666 ShaderParameter[] params = prepareTexture(texture); 667 setPosition(params, OFFSET_FILL_RECT); 668 GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0); 669 checkError(); 670 if (texture.isFlippedVertically()) { 671 save(SAVE_FLAG_MATRIX); 672 translate(0, target.centerY()); 673 scale(1, -1, 1); 674 translate(0, -target.centerY()); 675 } 676 draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top, 677 target.width(), target.height()); 678 if (texture.isFlippedVertically()) { 679 restore(); 680 } 681 mCountTextureRect++; 682 } 683 prepareTexture(BasicTexture texture)684 private ShaderParameter[] prepareTexture(BasicTexture texture) { 685 ShaderParameter[] params; 686 int program; 687 if (texture.getTarget() == GLES20.GL_TEXTURE_2D) { 688 params = mTextureParameters; 689 program = mTextureProgram; 690 } else { 691 params = mOesTextureParameters; 692 program = mOesTextureProgram; 693 } 694 prepareTexture(texture, program, params); 695 return params; 696 } 697 prepareTexture(BasicTexture texture, int program, ShaderParameter[] params)698 private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) { 699 deleteRecycledResources(); 700 GLES20.glUseProgram(program); 701 checkError(); 702 enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA); 703 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 704 checkError(); 705 texture.onBind(this); 706 GLES20.glBindTexture(texture.getTarget(), texture.getId()); 707 checkError(); 708 GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0); 709 checkError(); 710 GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha()); 711 checkError(); 712 } 713 714 @Override drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer, int indexBuffer, int indexCount)715 public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer, 716 int indexBuffer, int indexCount) { 717 prepareTexture(texture, mMeshProgram, mMeshParameters); 718 719 GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 720 checkError(); 721 722 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer); 723 checkError(); 724 int positionHandle = mMeshParameters[INDEX_POSITION].handle; 725 GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 726 VERTEX_STRIDE, 0); 727 checkError(); 728 729 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer); 730 checkError(); 731 int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle; 732 GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, 733 false, VERTEX_STRIDE, 0); 734 checkError(); 735 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 736 checkError(); 737 738 GLES20.glEnableVertexAttribArray(positionHandle); 739 checkError(); 740 GLES20.glEnableVertexAttribArray(texCoordHandle); 741 checkError(); 742 743 setMatrix(mMeshParameters, x, y, 1, 1); 744 GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0); 745 checkError(); 746 747 GLES20.glDisableVertexAttribArray(positionHandle); 748 checkError(); 749 GLES20.glDisableVertexAttribArray(texCoordHandle); 750 checkError(); 751 GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); 752 checkError(); 753 mCountDrawMesh++; 754 } 755 756 @Override drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h)757 public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) { 758 copyTextureCoordinates(texture, mTempSourceRect); 759 mTempTargetRect.set(x, y, x + w, y + h); 760 drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect); 761 } 762 763 @Override drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target)764 public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) { 765 if (target.width() <= 0 || target.height() <= 0) { 766 return; 767 } 768 save(SAVE_FLAG_ALPHA); 769 770 float currentAlpha = getAlpha(); 771 float cappedRatio = Math.min(1f, Math.max(0f, ratio)); 772 773 float textureAlpha = (1f - cappedRatio) * currentAlpha; 774 setAlpha(textureAlpha); 775 drawTexture(texture, source, target); 776 777 float colorAlpha = cappedRatio * currentAlpha; 778 setAlpha(colorAlpha); 779 fillRect(target.left, target.top, target.width(), target.height(), toColor); 780 781 restore(); 782 } 783 784 @Override unloadTexture(BasicTexture texture)785 public boolean unloadTexture(BasicTexture texture) { 786 boolean unload = texture.isLoaded(); 787 if (unload) { 788 synchronized (mUnboundTextures) { 789 mUnboundTextures.add(texture.getId()); 790 } 791 } 792 return unload; 793 } 794 795 @Override deleteBuffer(int bufferId)796 public void deleteBuffer(int bufferId) { 797 synchronized (mUnboundTextures) { 798 mDeleteBuffers.add(bufferId); 799 } 800 } 801 802 @Override deleteRecycledResources()803 public void deleteRecycledResources() { 804 synchronized (mUnboundTextures) { 805 IntArray ids = mUnboundTextures; 806 if (mUnboundTextures.size() > 0) { 807 mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0); 808 ids.clear(); 809 } 810 811 ids = mDeleteBuffers; 812 if (ids.size() > 0) { 813 mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0); 814 ids.clear(); 815 } 816 } 817 } 818 819 @Override dumpStatisticsAndClear()820 public void dumpStatisticsAndClear() { 821 String line = String.format("MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh, 822 mCountTextureRect, mCountFillRect, mCountDrawLine); 823 mCountDrawMesh = 0; 824 mCountTextureRect = 0; 825 mCountFillRect = 0; 826 mCountDrawLine = 0; 827 Log.d(TAG, line); 828 } 829 830 @Override endRenderTarget()831 public void endRenderTarget() { 832 RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1); 833 RawTexture texture = getTargetTexture(); 834 setRenderTarget(oldTexture, texture); 835 restore(); // restore matrix and alpha 836 } 837 838 @Override beginRenderTarget(RawTexture texture)839 public void beginRenderTarget(RawTexture texture) { 840 save(); // save matrix and alpha and blending 841 RawTexture oldTexture = getTargetTexture(); 842 mTargetTextures.add(texture); 843 setRenderTarget(oldTexture, texture); 844 } 845 getTargetTexture()846 private RawTexture getTargetTexture() { 847 return mTargetTextures.get(mTargetTextures.size() - 1); 848 } 849 setRenderTarget(BasicTexture oldTexture, RawTexture texture)850 private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) { 851 if (oldTexture == null && texture != null) { 852 GLES20.glGenFramebuffers(1, mFrameBuffer, 0); 853 checkError(); 854 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]); 855 checkError(); 856 } else if (oldTexture != null && texture == null) { 857 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); 858 checkError(); 859 GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0); 860 checkError(); 861 } 862 863 if (texture == null) { 864 setSize(mScreenWidth, mScreenHeight); 865 } else { 866 setSize(texture.getWidth(), texture.getHeight()); 867 868 if (!texture.isLoaded()) { 869 texture.prepare(this); 870 } 871 872 GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, 873 texture.getTarget(), texture.getId(), 0); 874 checkError(); 875 876 checkFramebufferStatus(); 877 } 878 } 879 checkFramebufferStatus()880 private static void checkFramebufferStatus() { 881 int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); 882 if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { 883 String msg = ""; 884 switch (status) { 885 case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 886 msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; 887 break; 888 case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: 889 msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; 890 break; 891 case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 892 msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; 893 break; 894 case GLES20.GL_FRAMEBUFFER_UNSUPPORTED: 895 msg = "GL_FRAMEBUFFER_UNSUPPORTED"; 896 break; 897 } 898 throw new RuntimeException(msg + ":" + Integer.toHexString(status)); 899 } 900 } 901 902 @Override setTextureParameters(BasicTexture texture)903 public void setTextureParameters(BasicTexture texture) { 904 int target = texture.getTarget(); 905 GLES20.glBindTexture(target, texture.getId()); 906 checkError(); 907 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 908 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 909 GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); 910 GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 911 } 912 913 @Override initializeTextureSize(BasicTexture texture, int format, int type)914 public void initializeTextureSize(BasicTexture texture, int format, int type) { 915 int target = texture.getTarget(); 916 GLES20.glBindTexture(target, texture.getId()); 917 checkError(); 918 int width = texture.getTextureWidth(); 919 int height = texture.getTextureHeight(); 920 GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null); 921 } 922 923 @Override initializeTexture(BasicTexture texture, Bitmap bitmap)924 public void initializeTexture(BasicTexture texture, Bitmap bitmap) { 925 int target = texture.getTarget(); 926 GLES20.glBindTexture(target, texture.getId()); 927 checkError(); 928 GLUtils.texImage2D(target, 0, bitmap, 0); 929 } 930 931 @Override texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap, int format, int type)932 public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap, 933 int format, int type) { 934 int target = texture.getTarget(); 935 GLES20.glBindTexture(target, texture.getId()); 936 checkError(); 937 GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type); 938 } 939 940 @Override uploadBuffer(FloatBuffer buf)941 public int uploadBuffer(FloatBuffer buf) { 942 return uploadBuffer(buf, FLOAT_SIZE); 943 } 944 945 @Override uploadBuffer(ByteBuffer buf)946 public int uploadBuffer(ByteBuffer buf) { 947 return uploadBuffer(buf, 1); 948 } 949 uploadBuffer(Buffer buffer, int elementSize)950 private int uploadBuffer(Buffer buffer, int elementSize) { 951 mGLId.glGenBuffers(1, mTempIntArray, 0); 952 checkError(); 953 int bufferId = mTempIntArray[0]; 954 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId); 955 checkError(); 956 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * elementSize, buffer, 957 GLES20.GL_STATIC_DRAW); 958 checkError(); 959 return bufferId; 960 } 961 checkError()962 public static void checkError() { 963 int error = GLES20.glGetError(); 964 if (error != 0) { 965 Throwable t = new Throwable(); 966 Log.e(TAG, "GL error: " + error, t); 967 } 968 } 969 970 @SuppressWarnings("unused") printMatrix(String message, float[] m, int offset)971 private static void printMatrix(String message, float[] m, int offset) { 972 StringBuilder b = new StringBuilder(message); 973 for (int i = 0; i < MATRIX_SIZE; i++) { 974 b.append(' '); 975 if (i % 4 == 0) { 976 b.append('\n'); 977 } 978 b.append(m[offset + i]); 979 } 980 Log.v(TAG, b.toString()); 981 } 982 983 @Override recoverFromLightCycle()984 public void recoverFromLightCycle() { 985 GLES20.glViewport(0, 0, mWidth, mHeight); 986 GLES20.glDisable(GLES20.GL_DEPTH_TEST); 987 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); 988 checkError(); 989 } 990 991 @Override getBounds(Rect bounds, int x, int y, int width, int height)992 public void getBounds(Rect bounds, int x, int y, int width, int height) { 993 Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f); 994 Matrix.scaleM(mTempMatrix, 0, width, height, 1f); 995 Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0); 996 Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4); 997 bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]); 998 bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]); 999 bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]); 1000 bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]); 1001 bounds.sort(); 1002 } 1003 1004 @Override getGLId()1005 public GLId getGLId() { 1006 return mGLId; 1007 } 1008 } 1009