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