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.gallery3d.ui; 18 19 import android.test.suitebuilder.annotation.SmallTest; 20 import android.util.Log; 21 22 import junit.framework.TestCase; 23 24 import java.util.Arrays; 25 26 import javax.microedition.khronos.opengles.GL10; 27 import javax.microedition.khronos.opengles.GL11; 28 29 @SmallTest 30 public class GLCanvasTest extends TestCase { 31 private static final String TAG = "GLCanvasTest"; 32 33 private static GLPaint newColorPaint(int color) { 34 GLPaint paint = new GLPaint(); 35 paint.setColor(color); 36 return paint; 37 } 38 39 @SmallTest 40 public void testSetSize() { 41 GL11 glStub = new GLStub(); 42 GLCanvas canvas = new GLCanvasImpl(glStub); 43 canvas.setSize(100, 200); 44 canvas.setSize(1000, 100); 45 try { 46 canvas.setSize(-1, 100); 47 fail(); 48 } catch (Throwable ex) { 49 // expected. 50 } 51 } 52 53 @SmallTest 54 public void testClearBuffer() { 55 new ClearBufferTest().run(); 56 } 57 58 private static class ClearBufferTest extends GLMock { 59 void run() { 60 GLCanvas canvas = new GLCanvasImpl(this); 61 assertEquals(0, mGLClearCalled); 62 canvas.clearBuffer(); 63 assertEquals(GL10.GL_COLOR_BUFFER_BIT, mGLClearMask); 64 assertEquals(1, mGLClearCalled); 65 } 66 } 67 68 @SmallTest 69 public void testSetColor() { 70 new SetColorTest().run(); 71 } 72 73 // This test assumes we use pre-multipled alpha blending and should 74 // set the blending function and color correctly. 75 private static class SetColorTest extends GLMock { 76 void run() { 77 int[] testColors = new int[] { 78 0, 0xFFFFFFFF, 0xFF000000, 0x00FFFFFF, 0x80FF8001, 79 0x7F010101, 0xFEFEFDFC, 0x017F8081, 0x027F8081, 0x2ADE4C4D 80 }; 81 82 GLCanvas canvas = new GLCanvasImpl(this); 83 canvas.setSize(400, 300); 84 // Test one color to make sure blend function is set. 85 assertEquals(0, mGLColorCalled); 86 canvas.drawLine(0, 0, 1, 1, newColorPaint(0x7F804020)); 87 assertEquals(1, mGLColorCalled); 88 assertEquals(0x7F402010, mGLColor); 89 assertPremultipliedBlending(this); 90 91 // Test other colors to make sure premultiplication is right 92 for (int c : testColors) { 93 float a = (c >>> 24) / 255f; 94 float r = ((c >> 16) & 0xff) / 255f; 95 float g = ((c >> 8) & 0xff) / 255f; 96 float b = (c & 0xff) / 255f; 97 int pre = makeColor4f(a * r, a * g, a * b, a); 98 99 mGLColorCalled = 0; 100 canvas.drawLine(0, 0, 1, 1, newColorPaint(c)); 101 assertEquals(1, mGLColorCalled); 102 assertEquals(pre, mGLColor); 103 } 104 } 105 } 106 107 @SmallTest 108 public void testSetGetMultiplyAlpha() { 109 GL11 glStub = new GLStub(); 110 GLCanvas canvas = new GLCanvasImpl(glStub); 111 112 canvas.setAlpha(1f); 113 assertEquals(1f, canvas.getAlpha()); 114 115 canvas.setAlpha(0f); 116 assertEquals(0f, canvas.getAlpha()); 117 118 canvas.setAlpha(0.5f); 119 assertEquals(0.5f, canvas.getAlpha()); 120 121 canvas.multiplyAlpha(0.5f); 122 assertEquals(0.25f, canvas.getAlpha()); 123 124 canvas.multiplyAlpha(0f); 125 assertEquals(0f, canvas.getAlpha()); 126 127 try { 128 canvas.setAlpha(-0.01f); 129 fail(); 130 } catch (Throwable ex) { 131 // expected. 132 } 133 134 try { 135 canvas.setAlpha(1.01f); 136 fail(); 137 } catch (Throwable ex) { 138 // expected. 139 } 140 } 141 142 @SmallTest 143 public void testAlpha() { 144 new AlphaTest().run(); 145 } 146 147 private static class AlphaTest extends GLMock { 148 void run() { 149 GLCanvas canvas = new GLCanvasImpl(this); 150 canvas.setSize(400, 300); 151 152 assertEquals(0, mGLColorCalled); 153 canvas.setAlpha(0.48f); 154 canvas.drawLine(0, 0, 1, 1, newColorPaint(0xFF804020)); 155 assertPremultipliedBlending(this); 156 assertEquals(1, mGLColorCalled); 157 assertEquals(0x7A3D1F0F, mGLColor); 158 } 159 } 160 161 @SmallTest 162 public void testDrawLine() { 163 new DrawLineTest().run(); 164 } 165 166 // This test assumes the drawLine() function use glDrawArrays() with 167 // GL_LINE_STRIP mode to draw the line and the input coordinates are used 168 // directly. 169 private static class DrawLineTest extends GLMock { 170 private int mDrawArrayCalled = 0; 171 private final int[] mResult = new int[4]; 172 173 @Override 174 public void glDrawArrays(int mode, int first, int count) { 175 assertNotNull(mGLVertexPointer); 176 assertEquals(GL10.GL_LINE_STRIP, mode); 177 assertEquals(2, count); 178 mGLVertexPointer.bindByteBuffer(); 179 180 double[] coord = new double[4]; 181 mGLVertexPointer.getArrayElement(first, coord); 182 mResult[0] = (int) coord[0]; 183 mResult[1] = (int) coord[1]; 184 mGLVertexPointer.getArrayElement(first + 1, coord); 185 mResult[2] = (int) coord[0]; 186 mResult[3] = (int) coord[1]; 187 mDrawArrayCalled++; 188 } 189 190 void run() { 191 GLCanvas canvas = new GLCanvasImpl(this); 192 canvas.setSize(400, 300); 193 canvas.drawLine(2, 7, 1, 8, newColorPaint(0) /* color */); 194 assertTrue(mGLVertexArrayEnabled); 195 assertEquals(1, mDrawArrayCalled); 196 197 Log.v(TAG, "result = " + Arrays.toString(mResult)); 198 int[] answer = new int[] {2, 7, 1, 8}; 199 for (int i = 0; i < answer.length; i++) { 200 assertEquals(answer[i], mResult[i]); 201 } 202 } 203 } 204 205 @SmallTest 206 public void testFillRect() { 207 new FillRectTest().run(); 208 } 209 210 // This test assumes the drawLine() function use glDrawArrays() with 211 // GL_TRIANGLE_STRIP mode to draw the line and the input coordinates 212 // are used directly. 213 private static class FillRectTest extends GLMock { 214 private int mDrawArrayCalled = 0; 215 private final int[] mResult = new int[8]; 216 217 @Override 218 public void glDrawArrays(int mode, int first, int count) { 219 assertNotNull(mGLVertexPointer); 220 assertEquals(GL10.GL_TRIANGLE_STRIP, mode); 221 assertEquals(4, count); 222 mGLVertexPointer.bindByteBuffer(); 223 224 double[] coord = new double[4]; 225 for (int i = 0; i < 4; i++) { 226 mGLVertexPointer.getArrayElement(first + i, coord); 227 mResult[i * 2 + 0] = (int) coord[0]; 228 mResult[i * 2 + 1] = (int) coord[1]; 229 } 230 231 mDrawArrayCalled++; 232 } 233 234 void run() { 235 GLCanvas canvas = new GLCanvasImpl(this); 236 canvas.setSize(400, 300); 237 canvas.fillRect(2, 7, 1, 8, 0 /* color */); 238 assertTrue(mGLVertexArrayEnabled); 239 assertEquals(1, mDrawArrayCalled); 240 Log.v(TAG, "result = " + Arrays.toString(mResult)); 241 242 // These are the four vertics that should be used. 243 int[] answer = new int[] { 244 2, 7, 245 3, 7, 246 3, 15, 247 2, 15}; 248 int count[] = new int[4]; 249 250 // Count the number of appearances for each vertex. 251 for (int i = 0; i < 4; i++) { 252 for (int j = 0; j < 4; j++) { 253 if (answer[i * 2] == mResult[j * 2] && 254 answer[i * 2 + 1] == mResult[j * 2 + 1]) { 255 count[i]++; 256 } 257 } 258 } 259 260 // Each vertex should appear exactly once. 261 for (int i = 0; i < 4; i++) { 262 assertEquals(1, count[i]); 263 } 264 } 265 } 266 267 @SmallTest 268 public void testTransform() { 269 new TransformTest().run(); 270 } 271 272 // This test assumes glLoadMatrixf is used to load the model view matrix, 273 // and glOrthof is used to load the projection matrix. 274 // 275 // The projection matrix is set to an orthogonal projection which is the 276 // inverse of viewport transform. So the model view matrix maps input 277 // directly to screen coordinates (default no scaling, and the y-axis is 278 // reversed). 279 // 280 // The matrix here are all listed in column major order. 281 // 282 private static class TransformTest extends GLMock { 283 private final float[] mModelViewMatrixUsed = new float[16]; 284 private final float[] mProjectionMatrixUsed = new float[16]; 285 286 @Override 287 public void glDrawArrays(int mode, int first, int count) { 288 copy(mModelViewMatrixUsed, mGLModelViewMatrix); 289 copy(mProjectionMatrixUsed, mGLProjectionMatrix); 290 } 291 292 private void copy(float[] dest, float[] src) { 293 System.arraycopy(src, 0, dest, 0, 16); 294 } 295 296 void run() { 297 GLCanvas canvas = new GLCanvasImpl(this); 298 canvas.setSize(40, 50); 299 int color = 0; 300 301 // Initial matrix 302 canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); 303 assertMatrixEq(new float[] { 304 1, 0, 0, 0, 305 0, -1, 0, 0, 306 0, 0, 1, 0, 307 0, 50, 0, 1 308 }, mModelViewMatrixUsed); 309 310 assertMatrixEq(new float[] { 311 2f / 40, 0, 0, 0, 312 0, 2f / 50, 0, 0, 313 0, 0, -1, 0, 314 -1, -1, 0, 1 315 }, mProjectionMatrixUsed); 316 317 // Translation 318 canvas.translate(3, 4, 5); 319 canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); 320 assertMatrixEq(new float[] { 321 1, 0, 0, 0, 322 0, -1, 0, 0, 323 0, 0, 1, 0, 324 3, 46, 5, 1 325 }, mModelViewMatrixUsed); 326 canvas.save(); 327 328 // Scaling 329 canvas.scale(0.7f, 0.6f, 0.5f); 330 canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); 331 assertMatrixEq(new float[] { 332 0.7f, 0, 0, 0, 333 0, -0.6f, 0, 0, 334 0, 0, 0.5f, 0, 335 3, 46, 5, 1 336 }, mModelViewMatrixUsed); 337 338 // Rotation 339 canvas.rotate(90, 0, 0, 1); 340 canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); 341 assertMatrixEq(new float[] { 342 0, -0.6f, 0, 0, 343 -0.7f, 0, 0, 0, 344 0, 0, 0.5f, 0, 345 3, 46, 5, 1 346 }, mModelViewMatrixUsed); 347 canvas.restore(); 348 349 // After restoring to the point just after translation, 350 // do rotation again. 351 canvas.rotate(180, 1, 0, 0); 352 canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); 353 assertMatrixEq(new float[] { 354 1, 0, 0, 0, 355 0, 1, 0, 0, 356 0, 0, -1, 0, 357 3, 46, 5, 1 358 }, mModelViewMatrixUsed); 359 } 360 } 361 362 @SmallTest 363 public void testGetGLInstance() { 364 GL11 glStub = new GLStub(); 365 GLCanvas canvas = new GLCanvasImpl(glStub); 366 assertSame(glStub, canvas.getGLInstance()); 367 } 368 369 private static void assertPremultipliedBlending(GLMock mock) { 370 assertTrue(mock.mGLBlendFuncCalled > 0); 371 assertTrue(mock.mGLBlendEnabled); 372 assertEquals(GL11.GL_ONE, mock.mGLBlendFuncSFactor); 373 assertEquals(GL11.GL_ONE_MINUS_SRC_ALPHA, mock.mGLBlendFuncDFactor); 374 } 375 376 private static void assertMatrixEq(float[] expected, float[] actual) { 377 try { 378 for (int i = 0; i < 16; i++) { 379 assertFloatEq(expected[i], actual[i]); 380 } 381 } catch (Throwable t) { 382 Log.v(TAG, "expected = " + Arrays.toString(expected) + 383 ", actual = " + Arrays.toString(actual)); 384 fail(); 385 } 386 } 387 388 public static void assertFloatEq(float expected, float actual) { 389 if (Math.abs(actual - expected) > 1e-6) { 390 Log.v(TAG, "expected: " + expected + ", actual: " + actual); 391 fail(); 392 } 393 } 394 } 395