Home | History | Annotate | Download | only in ui
      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