/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java

https://github.com/aizuzi/platform_frameworks_base · Java · 1009 lines · 839 code · 127 blank · 43 comment · 64 complexity · 49fc9ff3be3c7d276098d9c2a4eb8b5f MD5 · raw file

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