1 /* 2 * Copyright (C) 2010 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 17 package com.android.camera.ui; 18 19 import com.android.camera.Util; 20 21 import android.app.Activity; 22 import android.content.Context; 23 import android.graphics.Color; 24 import android.graphics.Matrix; 25 import android.graphics.PixelFormat; 26 import android.opengl.GLSurfaceView; 27 import android.opengl.GLU; 28 import android.os.SystemClock; 29 import android.util.AttributeSet; 30 import android.util.DisplayMetrics; 31 import android.util.Log; 32 import android.view.MotionEvent; 33 import android.view.animation.Animation; 34 import android.view.animation.Transformation; 35 36 import java.nio.ByteBuffer; 37 import java.nio.ByteOrder; 38 import java.util.ArrayList; 39 import java.util.Stack; 40 41 import javax.microedition.khronos.egl.EGLConfig; 42 import javax.microedition.khronos.opengles.GL10; 43 import javax.microedition.khronos.opengles.GL11; 44 import javax.microedition.khronos.opengles.GL11Ext; 45 46 // The root component of all <code>GLView</code>s. The rendering is done in GL 47 // thread while the event handling is done in the main thread. To synchronize 48 // the two threads, the entry points of this package need to synchronize on the 49 // <code>GLRootView</code> instance unless it can be proved that the rendering 50 // thread won't access the same thing as the method. The entry points include: 51 // (1) The public methods of HeadUpDisplay 52 // (2) The public methods of CameraHeadUpDisplay 53 // (3) The overridden methods in GLRootView. 54 public class GLRootView extends GLSurfaceView 55 implements GLSurfaceView.Renderer { 56 private static final String TAG = "GLRootView"; 57 58 private final boolean ENABLE_FPS_TEST = false; 59 private int mFrameCount = 0; 60 private long mFrameCountingStart = 0; 61 62 // We need 16 vertices for a normal nine-patch image (the 4x4 vertices) 63 private static final int VERTEX_BUFFER_SIZE = 16 * 2; 64 65 // We need 22 indices for a normal nine-patch image 66 private static final int INDEX_BUFFER_SIZE = 22; 67 68 private static final int FLAG_INITIALIZED = 1; 69 private static final int FLAG_NEED_LAYOUT = 2; 70 71 private static boolean mTexture2DEnabled; 72 73 private static float sPixelDensity = -1f; 74 75 private GL11 mGL; 76 private GLView mContentView; 77 private DisplayMetrics mDisplayMetrics; 78 79 private final ArrayList<Animation> mAnimations = new ArrayList<Animation>(); 80 81 private final Stack<Transformation> mFreeTransform = 82 new Stack<Transformation>(); 83 84 private final Transformation mTransformation = new Transformation(); 85 private final Stack<Transformation> mTransformStack = 86 new Stack<Transformation>(); 87 88 private float mLastAlpha = mTransformation.getAlpha(); 89 90 private final float mMatrixValues[] = new float[16]; 91 92 private final float mUvBuffer[] = new float[VERTEX_BUFFER_SIZE]; 93 private final float mXyBuffer[] = new float[VERTEX_BUFFER_SIZE]; 94 private final byte mIndexBuffer[] = new byte[INDEX_BUFFER_SIZE]; 95 96 private int mNinePatchX[] = new int[4]; 97 private int mNinePatchY[] = new int[4]; 98 private float mNinePatchU[] = new float[4]; 99 private float mNinePatchV[] = new float[4]; 100 101 private ByteBuffer mXyPointer; 102 private ByteBuffer mUvPointer; 103 private ByteBuffer mIndexPointer; 104 105 private int mFlags = FLAG_NEED_LAYOUT; 106 private long mAnimationTime; 107 108 private CameraEGLConfigChooser mEglConfigChooser = new CameraEGLConfigChooser(); 109 GLRootView(Context context)110 public GLRootView(Context context) { 111 this(context, null); 112 } 113 GLRootView(Context context, AttributeSet attrs)114 public GLRootView(Context context, AttributeSet attrs) { 115 super(context, attrs); 116 initialize(); 117 } 118 registerLaunchedAnimation(Animation animation)119 void registerLaunchedAnimation(Animation animation) { 120 // Register the newly launched animation so that we can set the start 121 // time more precisely. (Usually, it takes much longer for the first 122 // rendering, so we set the animation start time as the time we 123 // complete rendering) 124 mAnimations.add(animation); 125 } 126 currentAnimationTimeMillis()127 public long currentAnimationTimeMillis() { 128 return mAnimationTime; 129 } 130 dpToPixel(Context context, float dp)131 public synchronized static float dpToPixel(Context context, float dp) { 132 if (sPixelDensity < 0) { 133 DisplayMetrics metrics = new DisplayMetrics(); 134 ((Activity) context).getWindowManager() 135 .getDefaultDisplay().getMetrics(metrics); 136 sPixelDensity = metrics.density; 137 } 138 return sPixelDensity * dp; 139 } 140 dpToPixel(Context context, int dp)141 public static int dpToPixel(Context context, int dp) { 142 return (int)(dpToPixel(context, (float) dp) + .5f); 143 } 144 obtainTransformation()145 public Transformation obtainTransformation() { 146 if (!mFreeTransform.isEmpty()) { 147 Transformation t = mFreeTransform.pop(); 148 t.clear(); 149 return t; 150 } 151 return new Transformation(); 152 } 153 freeTransformation(Transformation freeTransformation)154 public void freeTransformation(Transformation freeTransformation) { 155 mFreeTransform.push(freeTransformation); 156 } 157 getTransformation()158 public Transformation getTransformation() { 159 return mTransformation; 160 } 161 pushTransform()162 public Transformation pushTransform() { 163 Transformation trans = obtainTransformation(); 164 trans.set(mTransformation); 165 mTransformStack.push(trans); 166 return mTransformation; 167 } 168 popTransform()169 public void popTransform() { 170 Transformation trans = mTransformStack.pop(); 171 mTransformation.set(trans); 172 freeTransformation(trans); 173 } 174 getEGLConfigChooser()175 public CameraEGLConfigChooser getEGLConfigChooser() { 176 return mEglConfigChooser; 177 } 178 allocateDirectNativeOrderBuffer(int size)179 private static ByteBuffer allocateDirectNativeOrderBuffer(int size) { 180 return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); 181 } 182 initialize()183 private void initialize() { 184 mFlags |= FLAG_INITIALIZED; 185 setEGLConfigChooser(mEglConfigChooser); 186 getHolder().setFormat(PixelFormat.TRANSLUCENT); 187 setZOrderOnTop(true); 188 189 setRenderer(this); 190 191 int size = VERTEX_BUFFER_SIZE * Float.SIZE / Byte.SIZE; 192 mXyPointer = allocateDirectNativeOrderBuffer(size); 193 mUvPointer = allocateDirectNativeOrderBuffer(size); 194 mIndexPointer = allocateDirectNativeOrderBuffer(INDEX_BUFFER_SIZE); 195 } 196 setContentPane(GLView content)197 public void setContentPane(GLView content) { 198 mContentView = content; 199 content.onAttachToRoot(this); 200 201 // no parent for the content pane 202 content.onAddToParent(null); 203 requestLayoutContentPane(); 204 } 205 getContentPane()206 public GLView getContentPane() { 207 return mContentView; 208 } 209 handleLowMemory()210 void handleLowMemory() { 211 //TODO: delete texture from GL 212 } 213 requestLayoutContentPane()214 public synchronized void requestLayoutContentPane() { 215 if (mContentView == null || (mFlags & FLAG_NEED_LAYOUT) != 0) return; 216 217 // "View" system will invoke onLayout() for initialization(bug ?), we 218 // have to ignore it since the GLThread is not ready yet. 219 if ((mFlags & FLAG_INITIALIZED) == 0) return; 220 221 mFlags |= FLAG_NEED_LAYOUT; 222 requestRender(); 223 } 224 layoutContentPane()225 private synchronized void layoutContentPane() { 226 mFlags &= ~FLAG_NEED_LAYOUT; 227 int width = getWidth(); 228 int height = getHeight(); 229 Log.v(TAG, "layout content pane " + width + "x" + height); 230 if (mContentView != null && width != 0 && height != 0) { 231 mContentView.layout(0, 0, width, height); 232 } 233 } 234 235 @Override onLayout( boolean changed, int left, int top, int right, int bottom)236 protected void onLayout( 237 boolean changed, int left, int top, int right, int bottom) { 238 if (changed) requestLayoutContentPane(); 239 } 240 241 /** 242 * Called when the context is created, possibly after automatic destruction. 243 */ 244 // This is a GLSurfaceView.Renderer callback onSurfaceCreated(GL10 gl1, EGLConfig config)245 public void onSurfaceCreated(GL10 gl1, EGLConfig config) { 246 GL11 gl = (GL11) gl1; 247 if (mGL != null) { 248 // The GL Object has changed 249 Log.i(TAG, "GLObject has changed from " + mGL + " to " + gl); 250 } 251 mGL = gl; 252 253 if (!ENABLE_FPS_TEST) { 254 setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 255 } else { 256 setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); 257 } 258 259 // Disable unused state 260 gl.glDisable(GL11.GL_LIGHTING); 261 262 // Enable used features 263 gl.glEnable(GL11.GL_BLEND); 264 gl.glEnable(GL11.GL_SCISSOR_TEST); 265 gl.glEnable(GL11.GL_STENCIL_TEST); 266 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 267 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 268 gl.glEnable(GL11.GL_TEXTURE_2D); 269 mTexture2DEnabled = true; 270 271 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, 272 GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE); 273 274 // Set the background color 275 gl.glClearColor(0f, 0f, 0f, 0f); 276 gl.glClearStencil(0); 277 278 gl.glVertexPointer(2, GL11.GL_FLOAT, 0, mXyPointer); 279 gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, mUvPointer); 280 281 } 282 283 /** 284 * Called when the OpenGL surface is recreated without destroying the 285 * context. 286 */ 287 // This is a GLSurfaceView.Renderer callback onSurfaceChanged(GL10 gl1, int width, int height)288 public void onSurfaceChanged(GL10 gl1, int width, int height) { 289 Log.v(TAG, "onSurfaceChanged: " + width + "x" + height 290 + ", gl10: " + gl1.toString()); 291 GL11 gl = (GL11) gl1; 292 mGL = gl; 293 gl.glViewport(0, 0, width, height); 294 295 gl.glMatrixMode(GL11.GL_PROJECTION); 296 gl.glLoadIdentity(); 297 298 GLU.gluOrtho2D(gl, 0, width, 0, height); 299 Matrix matrix = mTransformation.getMatrix(); 300 matrix.reset(); 301 matrix.preTranslate(0, getHeight()); 302 matrix.preScale(1, -1); 303 } 304 setAlphaValue(float alpha)305 private void setAlphaValue(float alpha) { 306 if (mLastAlpha == alpha) return; 307 308 GL11 gl = mGL; 309 mLastAlpha = alpha; 310 if (alpha >= 0.95f) { 311 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, 312 GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE); 313 } else { 314 gl.glTexEnvf(GL11.GL_TEXTURE_ENV, 315 GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); 316 gl.glColor4f(alpha, alpha, alpha, alpha); 317 } 318 } 319 drawRect(int x, int y, int width, int height)320 public void drawRect(int x, int y, int width, int height) { 321 float matrix[] = mMatrixValues; 322 mTransformation.getMatrix().getValues(matrix); 323 drawRect(x, y, width, height, matrix); 324 } 325 putRectangle(float x, float y, float width, float height, float[] buffer, ByteBuffer pointer)326 private static void putRectangle(float x, float y, 327 float width, float height, float[] buffer, ByteBuffer pointer) { 328 buffer[0] = x; 329 buffer[1] = y; 330 buffer[2] = x + width; 331 buffer[3] = y; 332 buffer[4] = x; 333 buffer[5] = y + height; 334 buffer[6] = x + width; 335 buffer[7] = y + height; 336 pointer.asFloatBuffer().put(buffer, 0, 8).position(0); 337 } 338 drawRect( int x, int y, int width, int height, float matrix[])339 private void drawRect( 340 int x, int y, int width, int height, float matrix[]) { 341 GL11 gl = mGL; 342 gl.glPushMatrix(); 343 gl.glMultMatrixf(toGLMatrix(matrix), 0); 344 putRectangle(x, y, width, height, mXyBuffer, mXyPointer); 345 gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4); 346 gl.glPopMatrix(); 347 } 348 drawNinePatch( NinePatchTexture tex, int x, int y, int width, int height)349 public void drawNinePatch( 350 NinePatchTexture tex, int x, int y, int width, int height) { 351 352 NinePatchChunk chunk = tex.getNinePatchChunk(); 353 354 // The code should be easily extended to handle the general cases by 355 // allocating more space for buffers. But let's just handle the only 356 // use case. 357 if (chunk.mDivX.length != 2 || chunk.mDivY.length != 2) { 358 throw new RuntimeException("unsupported nine patch"); 359 } 360 if (!tex.bind(this, mGL)) { 361 throw new RuntimeException("cannot bind" + tex.toString()); 362 } 363 if (width <= 0 || height <= 0) return ; 364 365 int divX[] = mNinePatchX; 366 int divY[] = mNinePatchY; 367 float divU[] = mNinePatchU; 368 float divV[] = mNinePatchV; 369 370 int nx = stretch(divX, divU, chunk.mDivX, tex.getWidth(), width); 371 int ny = stretch(divY, divV, chunk.mDivY, tex.getHeight(), height); 372 373 setAlphaValue(mTransformation.getAlpha()); 374 Matrix matrix = mTransformation.getMatrix(); 375 matrix.getValues(mMatrixValues); 376 GL11 gl = mGL; 377 gl.glPushMatrix(); 378 gl.glMultMatrixf(toGLMatrix(mMatrixValues), 0); 379 gl.glTranslatef(x, y, 0); 380 drawMesh(divX, divY, divU, divV, nx, ny); 381 gl.glPopMatrix(); 382 } 383 384 /** 385 * Stretches the texture according to the nine-patch rules. It will 386 * linearly distribute the strechy parts defined in the nine-patch chunk to 387 * the target area. 388 * 389 * <pre> 390 * source 391 * /--------------^---------------\ 392 * u0 u1 u2 u3 u4 u5 393 * div ---> |fffff|ssssssss|fff|ssssss|ffff| ---> u 394 * | div0 div1 div2 div3 | 395 * | | / / / / 396 * | | / / / / 397 * | | / / / / 398 * |fffff|ssss|fff|sss|ffff| ---> x 399 * x0 x1 x2 x3 x4 x5 400 * \----------v------------/ 401 * target 402 * 403 * f: fixed segment 404 * s: stretchy segment 405 * </pre> 406 * 407 * @param div the stretch parts defined in nine-patch chunk 408 * @param source the length of the texture 409 * @param target the length on the drawing plan 410 * @param u output, the positions of these dividers in the texture 411 * coordinate 412 * @param x output, the corresponding position of these dividers on the 413 * drawing plan 414 * @return the number of these dividers. 415 */ stretch( int x[], float u[], int div[], int source, int target)416 private int stretch( 417 int x[], float u[], int div[], int source, int target) { 418 int textureSize = Util.nextPowerOf2(source); 419 float textureBound = (source - 0.5f) / textureSize; 420 421 int stretch = 0; 422 for (int i = 0, n = div.length; i < n; i += 2) { 423 stretch += div[i + 1] - div[i]; 424 } 425 426 float remaining = target - source + stretch; 427 428 int lastX = 0; 429 int lastU = 0; 430 431 x[0] = 0; 432 u[0] = 0; 433 for (int i = 0, n = div.length; i < n; i += 2) { 434 // fixed segment 435 x[i + 1] = lastX + (div[i] - lastU); 436 u[i + 1] = Math.min((float) div[i] / textureSize, textureBound); 437 438 // stretchy segment 439 float partU = div[i + 1] - div[i]; 440 int partX = (int)(remaining * partU / stretch + 0.5f); 441 remaining -= partX; 442 stretch -= partU; 443 444 lastX = x[i + 1] + partX; 445 lastU = div[i + 1]; 446 x[i + 2] = lastX; 447 u[i + 2] = Math.min((float) lastU / textureSize, textureBound); 448 } 449 // the last fixed segment 450 x[div.length + 1] = target; 451 u[div.length + 1] = textureBound; 452 453 // remove segments with length 0. 454 int last = 0; 455 for (int i = 1, n = div.length + 2; i < n; ++i) { 456 if (x[last] == x[i]) continue; 457 x[++last] = x[i]; 458 u[last] = u[i]; 459 } 460 return last + 1; 461 } 462 drawMesh( int x[], int y[], float u[], float v[], int nx, int ny)463 private void drawMesh( 464 int x[], int y[], float u[], float v[], int nx, int ny) { 465 /* 466 * Given a 3x3 nine-patch image, the vertex order is defined as the 467 * following graph: 468 * 469 * (0) (1) (2) (3) 470 * | /| /| /| 471 * | / | / | / | 472 * (4) (5) (6) (7) 473 * | \ | \ | \ | 474 * | \| \| \| 475 * (8) (9) (A) (B) 476 * | /| /| /| 477 * | / | / | / | 478 * (C) (D) (E) (F) 479 * 480 * And we draw the triangle strip in the following index order: 481 * 482 * index: 04152637B6A5948C9DAEBF 483 */ 484 int pntCount = 0; 485 float xy[] = mXyBuffer; 486 float uv[] = mUvBuffer; 487 for (int j = 0; j < ny; ++j) { 488 for (int i = 0; i < nx; ++i) { 489 int xIndex = (pntCount++) << 1; 490 int yIndex = xIndex + 1; 491 xy[xIndex] = x[i]; 492 xy[yIndex] = y[j]; 493 uv[xIndex] = u[i]; 494 uv[yIndex] = v[j]; 495 } 496 } 497 mUvPointer.asFloatBuffer().put(uv, 0, pntCount << 1).position(0); 498 mXyPointer.asFloatBuffer().put(xy, 0, pntCount << 1).position(0); 499 500 int idxCount = 1; 501 byte index[] = mIndexBuffer; 502 for (int i = 0, bound = nx * (ny - 1); true;) { 503 // normal direction 504 --idxCount; 505 for (int j = 0; j < nx; ++j, ++i) { 506 index[idxCount++] = (byte) i; 507 index[idxCount++] = (byte) (i + nx); 508 } 509 if (i >= bound) break; 510 511 // reverse direction 512 int sum = i + i + nx - 1; 513 --idxCount; 514 for (int j = 0; j < nx; ++j, ++i) { 515 index[idxCount++] = (byte) (sum - i); 516 index[idxCount++] = (byte) (sum - i + nx); 517 } 518 if (i >= bound) break; 519 } 520 mIndexPointer.put(index, 0, idxCount).position(0); 521 522 mGL.glDrawElements(GL11.GL_TRIANGLE_STRIP, 523 idxCount, GL11.GL_UNSIGNED_BYTE, mIndexPointer); 524 } 525 mapPoints(Matrix matrix, int x1, int y1, int x2, int y2)526 private float[] mapPoints(Matrix matrix, int x1, int y1, int x2, int y2) { 527 float[] point = mXyBuffer; 528 point[0] = x1; point[1] = y1; point[2] = x2; point[3] = y2; 529 matrix.mapPoints(point, 0, point, 0, 4); 530 return point; 531 } 532 clipRect(int x, int y, int width, int height)533 public void clipRect(int x, int y, int width, int height) { 534 float point[] = mapPoints( 535 mTransformation.getMatrix(), x, y + height, x + width, y); 536 537 // mMatrix could be a rotation matrix. In this case, we need to find 538 // the boundaries after rotation. (only handle 90 * n degrees) 539 if (point[0] > point[2]) { 540 x = (int) point[2]; 541 width = (int) point[0] - x; 542 } else { 543 x = (int) point[0]; 544 width = (int) point[2] - x; 545 } 546 if (point[1] > point[3]) { 547 y = (int) point[3]; 548 height = (int) point[1] - y; 549 } else { 550 y = (int) point[1]; 551 height = (int) point[3] - y; 552 } 553 mGL.glScissor(x, y, width, height); 554 } 555 clearClip()556 public void clearClip() { 557 mGL.glScissor(0, 0, getWidth(), getHeight()); 558 } 559 toGLMatrix(float v[])560 private static float[] toGLMatrix(float v[]) { 561 v[15] = v[8]; v[13] = v[5]; v[5] = v[4]; v[4] = v[1]; 562 v[12] = v[2]; v[1] = v[3]; v[3] = v[6]; 563 v[2] = v[6] = v[8] = v[9] = 0; 564 v[10] = 1; 565 return v; 566 } 567 drawColor(int x, int y, int width, int height, int color)568 public void drawColor(int x, int y, int width, int height, int color) { 569 float alpha = mTransformation.getAlpha(); 570 GL11 gl = mGL; 571 if (mTexture2DEnabled) { 572 // Set mLastAlpha to an invalid value, so that it will reset again 573 // in setAlphaValue(float) later. 574 mLastAlpha = -1.0f; 575 gl.glDisable(GL11.GL_TEXTURE_2D); 576 mTexture2DEnabled = false; 577 } 578 alpha /= 256.0f; 579 gl.glColor4f(Color.red(color) * alpha, Color.green(color) * alpha, 580 Color.blue(color) * alpha, Color.alpha(color) * alpha); 581 drawRect(x, y, width, height); 582 } 583 drawTexture( BasicTexture texture, int x, int y, int width, int height)584 public void drawTexture( 585 BasicTexture texture, int x, int y, int width, int height) { 586 drawTexture(texture, x, y, width, height, mTransformation.getAlpha()); 587 } 588 drawTexture(BasicTexture texture, int x, int y, int width, int height, float alpha)589 public void drawTexture(BasicTexture texture, 590 int x, int y, int width, int height, float alpha) { 591 592 if (!mTexture2DEnabled) { 593 mGL.glEnable(GL11.GL_TEXTURE_2D); 594 mTexture2DEnabled = true; 595 } 596 597 if (!texture.bind(this, mGL)) { 598 throw new RuntimeException("cannot bind" + texture.toString()); 599 } 600 if (width <= 0 || height <= 0) return ; 601 602 Matrix matrix = mTransformation.getMatrix(); 603 matrix.getValues(mMatrixValues); 604 605 // Test whether it has been rotated or flipped, if so, glDrawTexiOES 606 // won't work 607 if (isMatrixRotatedOrFlipped(mMatrixValues)) { 608 putRectangle(0, 0, 609 (texture.mWidth - 0.5f) / texture.mTextureWidth, 610 (texture.mHeight - 0.5f) / texture.mTextureHeight, 611 mUvBuffer, mUvPointer); 612 setAlphaValue(alpha); 613 drawRect(x, y, width, height, mMatrixValues); 614 } else { 615 // draw the rect from bottom-left to top-right 616 float points[] = mapPoints(matrix, x, y + height, x + width, y); 617 x = (int) points[0]; 618 y = (int) points[1]; 619 width = (int) points[2] - x; 620 height = (int) points[3] - y; 621 if (width > 0 && height > 0) { 622 setAlphaValue(alpha); 623 ((GL11Ext) mGL).glDrawTexiOES(x, y, 0, width, height); 624 } 625 } 626 } 627 isMatrixRotatedOrFlipped(float matrix[])628 private static boolean isMatrixRotatedOrFlipped(float matrix[]) { 629 return matrix[Matrix.MSKEW_X] != 0 || matrix[Matrix.MSKEW_Y] != 0 630 || matrix[Matrix.MSCALE_X] < 0 || matrix[Matrix.MSCALE_Y] > 0; 631 } 632 onDrawFrame(GL10 gl)633 public synchronized void onDrawFrame(GL10 gl) { 634 if (ENABLE_FPS_TEST) { 635 long now = System.nanoTime(); 636 if (mFrameCountingStart == 0) { 637 mFrameCountingStart = now; 638 } else if ((now - mFrameCountingStart) > 1000000000) { 639 Log.v(TAG, "fps: " + (double) mFrameCount 640 * 1000000000 / (now - mFrameCountingStart)); 641 mFrameCountingStart = now; 642 mFrameCount = 0; 643 } 644 ++mFrameCount; 645 } 646 647 if ((mFlags & FLAG_NEED_LAYOUT) != 0) layoutContentPane(); 648 clearClip(); 649 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_STENCIL_BUFFER_BIT); 650 gl.glEnable(GL11.GL_BLEND); 651 gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); 652 653 mAnimationTime = SystemClock.uptimeMillis(); 654 if (mContentView != null) { 655 mContentView.render(GLRootView.this, (GL11) gl); 656 } 657 long now = SystemClock.uptimeMillis(); 658 for (Animation animation : mAnimations) { 659 animation.setStartTime(now); 660 } 661 mAnimations.clear(); 662 } 663 664 @Override dispatchTouchEvent(MotionEvent event)665 public synchronized boolean dispatchTouchEvent(MotionEvent event) { 666 // If this has been detached from root, we don't need to handle event 667 return mContentView != null 668 ? mContentView.dispatchTouchEvent(event) 669 : false; 670 } 671 getDisplayMetrics()672 public DisplayMetrics getDisplayMetrics() { 673 if (mDisplayMetrics == null) { 674 mDisplayMetrics = new DisplayMetrics(); 675 ((Activity) getContext()).getWindowManager() 676 .getDefaultDisplay().getMetrics(mDisplayMetrics); 677 } 678 return mDisplayMetrics; 679 } 680 copyTexture2D( RawTexture texture, int x, int y, int width, int height)681 public void copyTexture2D( 682 RawTexture texture, int x, int y, int width, int height) 683 throws GLOutOfMemoryException { 684 Matrix matrix = mTransformation.getMatrix(); 685 matrix.getValues(mMatrixValues); 686 687 if (isMatrixRotatedOrFlipped(mMatrixValues)) { 688 throw new IllegalArgumentException("cannot support rotated matrix"); 689 } 690 float points[] = mapPoints(matrix, x, y + height, x + width, y); 691 x = (int) points[0]; 692 y = (int) points[1]; 693 width = (int) points[2] - x; 694 height = (int) points[3] - y; 695 696 GL11 gl = mGL; 697 int newWidth = Util.nextPowerOf2(width); 698 int newHeight = Util.nextPowerOf2(height); 699 int glError = GL11.GL_NO_ERROR; 700 701 gl.glBindTexture(GL11.GL_TEXTURE_2D, texture.getId()); 702 703 int[] cropRect = {0, 0, width, height}; 704 gl.glTexParameteriv(GL11.GL_TEXTURE_2D, 705 GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, 0); 706 gl.glTexParameteri(GL11.GL_TEXTURE_2D, 707 GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); 708 gl.glTexParameteri(GL11.GL_TEXTURE_2D, 709 GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); 710 gl.glTexParameterf(GL11.GL_TEXTURE_2D, 711 GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); 712 gl.glTexParameterf(GL11.GL_TEXTURE_2D, 713 GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); 714 gl.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, 715 GL11.GL_RGBA, x, y, newWidth, newHeight, 0); 716 glError = gl.glGetError(); 717 718 if (glError == GL11.GL_OUT_OF_MEMORY) { 719 throw new GLOutOfMemoryException(); 720 } 721 722 if (glError != GL11.GL_NO_ERROR) { 723 throw new RuntimeException( 724 "Texture copy fail, glError " + glError); 725 } 726 727 texture.setSize(width, height); 728 texture.setTextureSize(newWidth, newHeight); 729 } 730 731 } 732