Example usage for android.opengl Matrix setIdentityM

List of usage examples for android.opengl Matrix setIdentityM

Introduction

In this page you can find the example usage for android.opengl Matrix setIdentityM.

Prototype

public static void setIdentityM(float[] sm, int smOffset) 

Source Link

Document

Sets matrix m to the identity matrix.

Usage

From source file:Main.java

private static void setPerspectiveM(float[] m, int offset, double fovy, double aspect, double zNear,
        double zFar) {
    Matrix.setIdentityM(m, offset);
    double ymax = zNear * Math.tan(fovy * Math.PI / 360.0);
    double ymin = -ymax;
    double xmin = ymin * aspect;
    double xmax = ymax * aspect;
    Matrix.frustumM(m, offset, (float) xmin, (float) xmax, (float) ymin, (float) ymax, (float) zNear,
            (float) zFar);
}

From source file:Main.java

public static void setPerspectiveM(float[] m, int offset, double fovy, double aspect, double zNear,
        double zFar) {
    Matrix.setIdentityM(m, offset);
    double ymax = zNear * Math.tan(fovy * Math.PI / 360.0);
    double ymin = -ymax;
    double xmin = ymin * aspect;
    double xmax = ymax * aspect;
    Matrix.frustumM(m, offset, (float) xmin, (float) xmax, (float) ymin, (float) ymax, (float) zNear,
            (float) zFar);
}

From source file:Main.java

/**
 * Returns layout transformation matrix that applies an optional mirror effect and compensates
 * for video vs display aspect ratio.//from  w w w. j  ava2 s . c  o  m
 */
public static float[] getLayoutMatrix(boolean mirror, float videoAspectRatio, float displayAspectRatio) {
    float scaleX = 1;
    float scaleY = 1;
    // Scale X or Y dimension so that video and display size have same aspect ratio.
    if (displayAspectRatio > videoAspectRatio) {
        scaleY = videoAspectRatio / displayAspectRatio;
    } else {
        scaleX = displayAspectRatio / videoAspectRatio;
    }
    // Apply optional horizontal flip.
    if (mirror) {
        scaleX *= -1;
    }
    final float matrix[] = new float[16];
    Matrix.setIdentityM(matrix, 0);
    Matrix.scaleM(matrix, 0, scaleX, scaleY, 1);
    adjustOrigin(matrix);
    return matrix;
}

From source file:com.dmitrybrant.android.cardboardmpo.MainActivity.java

@Override
public void onDrawEye(Eye eye) {
    GLES20.glDisable(GLES20.GL_DEPTH_TEST);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    // Apply the eye transformation to the camera.
    Matrix.multiplyMM(view, 0, eye.getEyeView(), 0, camera, 0);

    // TODO: Do something with the head transform (e.g. pan the photo around)
    // For now, just reset the view matrix, so that the photo is in the center at all times.
    Matrix.setIdentityM(view, 0);

    float[] perspective = eye.getPerspective(Z_NEAR, Z_FAR);
    if (eye.getType() == 1) {
        Matrix.multiplyMM(modelView, 0, view, 0, rectLeftEye.getModelMatrix(), 0);
        Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0);
        rectLeftEye.draw(modelViewProjection);
    } else {//w  ww . ja v a  2s  .c  om
        Matrix.multiplyMM(modelView, 0, view, 0, rectRightEye.getModelMatrix(), 0);
        Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0);
        rectRightEye.draw(modelViewProjection);
    }
}

From source file:com.kentdisplays.synccardboarddemo.Page.java

/**
 * Sets up the drawing object data for use in an OpenGL ES context.
 *
 * @param is InputStream to the page to load the path data from.
 *///  w ww  .  j  a v  a 2  s .  co m
public Page(InputStream is, int glProgram, int direction) {

    this.mModel = new float[16];
    this.mGlProgram = glProgram;

    // Calculate the coordinates from the given path.
    ArrayList<Path> paths = pathsFromSamplePageInputStream(is);
    float finalCoords[] = {};
    float finalNormals[] = {};
    float finalColors[] = {};
    mNumberOfPaths = paths.size();
    for (int i = 0; i < mNumberOfPaths; i++) {
        Path path = paths.get(i);
        float x1 = (path.x1 / 13942 * 2) - 1;
        float y1 = (path.y1 / 20280 * 2) - 1;
        float x2 = (path.x2 / 13942 * 2) - 1;
        float y2 = (path.y2 / 20280 * 2) - 1;
        float width = path.width / 3000;
        width = width < 0.013f ? 0.013f : width; // Width should be at least 0.013

        float distance = (float) Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
        float angle = (float) Math.PI / 2 - (float) Math.asin((x2 - x1) / distance);
        float xdiff = (width / 2) * (float) Math.sin(angle);
        float ydiff = (width / 2) * (float) Math.cos(angle);

        float coords[] = { x1 - xdiff, y1 - ydiff, 1.0f, // top left
                x2 - xdiff, y2 - ydiff, 1.0f, // bottom left
                x1 + xdiff, y1 + ydiff, 1.0f, // top right
                x2 - xdiff, y2 - ydiff, 1.0f, // bottom left
                x2 + xdiff, y2 + ydiff, 1.0f, // bottom right
                x1 + xdiff, y1 + ydiff, 1.0f, // top right
        };

        float normals[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                1.0f, 0.0f, 0.0f, 1.0f, };

        float colors[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f, 0.2f, 0.709803922f, 0.898039216f, 1.0f, 0.2f,
                0.709803922f, 0.898039216f, 1.0f, 0.2f, 0.709803922f, 0.898039216f, 1.0f, 0.2f, 0.709803922f,
                0.898039216f, 1.0f, 0.2f, 0.709803922f, 0.898039216f, 1.0f, };

        finalCoords = Floats.concat(finalCoords, coords);
        finalNormals = Floats.concat(finalNormals, normals);
        finalColors = Floats.concat(finalColors, colors);
    }

    ByteBuffer bbVertices = ByteBuffer.allocateDirect(finalCoords.length * 4);
    bbVertices.order(ByteOrder.nativeOrder());
    mPageVertices = bbVertices.asFloatBuffer();
    mPageVertices.put(finalCoords);
    mPageVertices.position(0);

    ByteBuffer bbNormals = ByteBuffer.allocateDirect(finalNormals.length * 4);
    bbNormals.order(ByteOrder.nativeOrder());
    mPageNormals = bbNormals.asFloatBuffer();
    mPageNormals.put(finalNormals);
    mPageNormals.position(0);

    ByteBuffer bbColors = ByteBuffer.allocateDirect(finalColors.length * 4);
    bbColors.order(ByteOrder.nativeOrder());
    mPageColors = bbColors.asFloatBuffer();
    mPageColors.put(finalColors);
    mPageColors.position(0);

    // Correctly place the page in the world.
    Matrix.setIdentityM(mModel, 0);
    switch (direction) {
    case 0:
        Matrix.translateM(mModel, 0, 0, 0, -mDistance); //Front.
        break;
    case 1:
        Matrix.translateM(mModel, 0, -mDistance, 0, 0); // Left.
        Matrix.rotateM(mModel, 0, 90, 0, 1f, 0);
        break;
    case 2:
        Matrix.translateM(mModel, 0, 0, 0, mDistance); // Behind.
        Matrix.rotateM(mModel, 0, 180, 0, 1f, 0);
        break;
    case 3:
        Matrix.translateM(mModel, 0, mDistance, 0, 0); // Right.
        Matrix.rotateM(mModel, 0, 270, 0, 1f, 0);
        break;
    }
}

From source file:com.google.fpl.liquidfunpaint.ParticleRenderer.java

public void onSurfaceChanged(int width, int height) {

    // Set up the transform
    float ratio = (float) height / width;
    Matrix.setIdentityM(mTransformFromTexture, 0);
    Matrix.scaleM(mTransformFromTexture, 0, 1, 1 / ratio, 1);

    Matrix.setIdentityM(mTransformFromWorld, 0);
    Matrix.translateM(mTransformFromWorld, 0, -1, -ratio, 0);
    Matrix.scaleM(mTransformFromWorld, 0, 2f / Renderer.getInstance().sRenderWorldWidth,
            2 * ratio / Renderer.getInstance().sRenderWorldHeight, 1);
}

From source file:com.kentdisplays.synccardboarddemo.MainActivity.java

/**
 * Creates the buffers we use to store information about the 3D world. OpenGL doesn't use Java
 * arrays, but rather needs data in a format it can understand. Hence we use ByteBuffers.
 * @param config The EGL configuration used when creating the surface.
 *///  ww w .j  a va2  s  .  co  m
@Override
public void onSurfaceCreated(EGLConfig config) {
    Log.i(TAG, "onSurfaceCreated");

    // make a floor
    ByteBuffer bbFloorVertices = ByteBuffer.allocateDirect(DATA.FLOOR_COORDS.length * 4);
    bbFloorVertices.order(ByteOrder.nativeOrder());
    mFloorVertices = bbFloorVertices.asFloatBuffer();
    mFloorVertices.put(DATA.FLOOR_COORDS);
    mFloorVertices.position(0);

    ByteBuffer bbFloorNormals = ByteBuffer.allocateDirect(DATA.FLOOR_NORMALS.length * 4);
    bbFloorNormals.order(ByteOrder.nativeOrder());
    mFloorNormals = bbFloorNormals.asFloatBuffer();
    mFloorNormals.put(DATA.FLOOR_NORMALS);
    mFloorNormals.position(0);

    ByteBuffer bbFloorColors = ByteBuffer.allocateDirect(DATA.FLOOR_COLORS.length * 4);
    bbFloorColors.order(ByteOrder.nativeOrder());
    mFloorColors = bbFloorColors.asFloatBuffer();
    mFloorColors.put(DATA.FLOOR_COLORS);
    mFloorColors.position(0);

    int vertexShader = loadGLShader(GLES20.GL_VERTEX_SHADER, R.raw.light_vertex);
    int gridShader = loadGLShader(GLES20.GL_FRAGMENT_SHADER, R.raw.grid_fragment);

    mGlProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(mGlProgram, vertexShader);
    GLES20.glAttachShader(mGlProgram, gridShader);
    GLES20.glLinkProgram(mGlProgram);

    GLES20.glEnable(GLES20.GL_DEPTH_TEST);

    Matrix.setIdentityM(mModelFloor, 0);
    Matrix.translateM(mModelFloor, 0, 0, -mFloorDepth, 0); // Floor appears below user

    // Create the placeholder pages.
    mPages = new Page[4];
    mPages[0] = new Page(getResources().openRawResource(R.raw.boogie_board), mGlProgram, 0);
    mPages[1] = new Page(getResources().openRawResource(R.raw.house), mGlProgram, 1);
    mPages[2] = new Page(getResources().openRawResource(R.raw.placeholder), mGlProgram, 2);
    mPages[3] = new Page(getResources().openRawResource(R.raw.cylinder), mGlProgram, 3);

    checkGLError("onSurfaceCreated");
}

From source file:com.google.vrtoolkit.cardboard.samples.treasurehunt.MainActivity.java

/**
 * Creates the buffers we use to store information about the 3D world.
 *
 * <p>OpenGL doesn't use Java arrays, but rather needs data in a format it can understand.
 * Hence we use ByteBuffers.//  ww w .jav  a 2  s .  co  m
 *
 * @param config The EGL configuration used when creating the surface.
 */
@Override
public void onSurfaceCreated(EGLConfig config) {
    Log.i(TAG, "onSurfaceCreated");
    GLES20.glClearColor(0.1f, 0.1f, 0.1f, 0.5f); // Dark background so text shows up well.

    ByteBuffer bbVertices = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_COORDS.length * 4);
    bbVertices.order(ByteOrder.nativeOrder());
    cubeVertices = bbVertices.asFloatBuffer();
    cubeVertices.put(WorldLayoutData.CUBE_COORDS);
    cubeVertices.position(0);

    ByteBuffer bbColors = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_COLORS.length * 4);
    bbColors.order(ByteOrder.nativeOrder());
    cubeColors = bbColors.asFloatBuffer();
    cubeColors.put(WorldLayoutData.CUBE_COLORS);
    cubeColors.position(0);

    ByteBuffer bbFoundColors = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_FOUND_COLORS.length * 4);
    bbFoundColors.order(ByteOrder.nativeOrder());
    cubeFoundColors = bbFoundColors.asFloatBuffer();
    cubeFoundColors.put(WorldLayoutData.CUBE_FOUND_COLORS);
    cubeFoundColors.position(0);

    ByteBuffer bbNormals = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_NORMALS.length * 4);
    bbNormals.order(ByteOrder.nativeOrder());
    cubeNormals = bbNormals.asFloatBuffer();
    cubeNormals.put(WorldLayoutData.CUBE_NORMALS);
    cubeNormals.position(0);

    ByteBuffer mcbbVertices = ByteBuffer.allocateDirect(WorldLayoutData.MINI_CUBE_COORDS.length * 4);
    mcbbVertices.order(ByteOrder.nativeOrder());
    miniCubeVertices = mcbbVertices.asFloatBuffer();
    miniCubeVertices.put(WorldLayoutData.MINI_CUBE_COORDS);
    miniCubeVertices.position(0);

    ByteBuffer mcbbColors = ByteBuffer.allocateDirect(WorldLayoutData.MINI_CUBE_COLORS.length * 4);
    mcbbColors.order(ByteOrder.nativeOrder());
    miniCubeColors = mcbbColors.asFloatBuffer();
    miniCubeColors.put(WorldLayoutData.MINI_CUBE_COLORS);
    miniCubeColors.position(0);

    ByteBuffer mcbbNormals = ByteBuffer.allocateDirect(WorldLayoutData.CUBE_NORMALS.length * 4);
    mcbbNormals.order(ByteOrder.nativeOrder());
    miniCubeNormals = mcbbNormals.asFloatBuffer();
    miniCubeNormals.put(WorldLayoutData.CUBE_NORMALS);
    miniCubeNormals.position(0);

    // make a floor
    ByteBuffer bbFloorVertices = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_COORDS.length * 4);
    bbFloorVertices.order(ByteOrder.nativeOrder());
    floorVertices = bbFloorVertices.asFloatBuffer();
    floorVertices.put(WorldLayoutData.FLOOR_COORDS);
    floorVertices.position(0);

    ByteBuffer bbFloorNormals = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_NORMALS.length * 4);
    bbFloorNormals.order(ByteOrder.nativeOrder());
    floorNormals = bbFloorNormals.asFloatBuffer();
    floorNormals.put(WorldLayoutData.FLOOR_NORMALS);
    floorNormals.position(0);

    ByteBuffer bbFloorColors = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_COLORS.length * 4);
    bbFloorColors.order(ByteOrder.nativeOrder());
    floorColors = bbFloorColors.asFloatBuffer();
    floorColors.put(WorldLayoutData.FLOOR_COLORS);
    floorColors.position(0);

    int vertexShader = loadGLShader(GLES20.GL_VERTEX_SHADER, R.raw.light_vertex);
    int gridShader = loadGLShader(GLES20.GL_FRAGMENT_SHADER, R.raw.grid_fragment);
    int passthroughShader = loadGLShader(GLES20.GL_FRAGMENT_SHADER, R.raw.passthrough_fragment);

    cubeProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(cubeProgram, vertexShader);
    GLES20.glAttachShader(cubeProgram, passthroughShader);
    GLES20.glLinkProgram(cubeProgram);
    GLES20.glUseProgram(cubeProgram);

    checkGLError("Cube program");

    cubePositionParam = GLES20.glGetAttribLocation(cubeProgram, "a_Position");
    cubeNormalParam = GLES20.glGetAttribLocation(cubeProgram, "a_Normal");
    cubeColorParam = GLES20.glGetAttribLocation(cubeProgram, "a_Color");

    cubeModelParam = GLES20.glGetUniformLocation(cubeProgram, "u_Model");
    cubeModelViewParam = GLES20.glGetUniformLocation(cubeProgram, "u_MVMatrix");
    cubeModelViewProjectionParam = GLES20.glGetUniformLocation(cubeProgram, "u_MVP");
    cubeLightPosParam = GLES20.glGetUniformLocation(cubeProgram, "u_LightPos");

    GLES20.glEnableVertexAttribArray(cubePositionParam);
    GLES20.glEnableVertexAttribArray(cubeNormalParam);
    GLES20.glEnableVertexAttribArray(cubeColorParam);

    checkGLError("Cube program params");

    //Minicube
    miniCubeProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(miniCubeProgram, vertexShader);
    GLES20.glAttachShader(miniCubeProgram, passthroughShader);
    GLES20.glLinkProgram(miniCubeProgram);
    GLES20.glUseProgram(miniCubeProgram);

    checkGLError("Cube program");

    miniCubePositionParam = GLES20.glGetAttribLocation(miniCubeProgram, "a_Position");
    miniCubeNormalParam = GLES20.glGetAttribLocation(miniCubeProgram, "a_Normal");
    miniCubeColorParam = GLES20.glGetAttribLocation(miniCubeProgram, "a_Color");

    miniCubeModelParam = GLES20.glGetUniformLocation(miniCubeProgram, "u_Model");
    miniCubeModelViewParam = GLES20.glGetUniformLocation(miniCubeProgram, "u_MVMatrix");
    miniCubeModelViewProjectionParam = GLES20.glGetUniformLocation(miniCubeProgram, "u_MVP");
    miniCubeLightPosParam = GLES20.glGetUniformLocation(miniCubeProgram, "u_LightPos");

    GLES20.glEnableVertexAttribArray(miniCubePositionParam);
    GLES20.glEnableVertexAttribArray(miniCubeNormalParam);
    GLES20.glEnableVertexAttribArray(miniCubeColorParam);

    checkGLError("Cube program params");

    floorProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(floorProgram, vertexShader);
    GLES20.glAttachShader(floorProgram, gridShader);
    GLES20.glLinkProgram(floorProgram);
    GLES20.glUseProgram(floorProgram);

    checkGLError("Floor program");

    floorModelParam = GLES20.glGetUniformLocation(floorProgram, "u_Model");
    floorModelViewParam = GLES20.glGetUniformLocation(floorProgram, "u_MVMatrix");
    floorModelViewProjectionParam = GLES20.glGetUniformLocation(floorProgram, "u_MVP");
    floorLightPosParam = GLES20.glGetUniformLocation(floorProgram, "u_LightPos");

    floorPositionParam = GLES20.glGetAttribLocation(floorProgram, "a_Position");
    floorNormalParam = GLES20.glGetAttribLocation(floorProgram, "a_Normal");
    floorColorParam = GLES20.glGetAttribLocation(floorProgram, "a_Color");

    GLES20.glEnableVertexAttribArray(floorPositionParam);
    GLES20.glEnableVertexAttribArray(floorNormalParam);
    GLES20.glEnableVertexAttribArray(floorColorParam);

    checkGLError("Floor program params");

    Matrix.setIdentityM(modelFloor, 0);
    Matrix.translateM(modelFloor, 0, 0, -floorDepth, 0); // Floor appears below user.

    // Avoid any delays during start-up due to decoding of sound files.
    new Thread(new Runnable() {
        public void run() {
            // Start spatial audio playback of SOUND_FILE at the model postion. The returned
            //soundId handle is stored and allows for repositioning the sound object whenever
            // the cube position changes.
            cardboardAudioEngine.preloadSoundFile(SOUND_FILE);
            soundId = cardboardAudioEngine.createSoundObject(SOUND_FILE);
            cardboardAudioEngine.setSoundObjectPosition(soundId, modelPosition[0], modelPosition[1],
                    modelPosition[2]);
            cardboardAudioEngine.playSound(soundId, true /* looped playback */);
        }
    }).start();

    updateModelPosition();

    checkGLError("onSurfaceCreated");
}

From source file:com.google.vrtoolkit.cardboard.samples.treasurehunt.MainActivity.java

/**
 * Updates the cube model position.//from ww w.  j av a2 s  .  com
 */
private void updateModelPosition() {
    Matrix.setIdentityM(modelCube, 0);
    Matrix.translateM(modelCube, 0, modelPosition[0], modelPosition[1], modelPosition[2]);

    // Update the sound location to match it with the new cube position.
    if (soundId != CardboardAudioEngine.INVALID_ID) {
        cardboardAudioEngine.setSoundObjectPosition(soundId, modelPosition[0], modelPosition[1],
                modelPosition[2]);
    }
    checkGLError("updateCubePosition");
}

From source file:com.tumblr.cardboard.Tumblr3DActivity.java

/**
 * Creates the buffers we use to store information about the 3D world. OpenGL doesn't use Java
 * arrays, but rather needs data in a format it can understand. Hence we use ByteBuffers.
 *
 * @param config The EGL configuration used when creating the surface.
 *///  ww w . j  a  v  a  2  s. c o m
@Override
public void onSurfaceCreated(EGLConfig config) {
    Log.i(TAG, "onSurfaceCreated");
    GLES20.glClearColor(0.1f, 0.1f, 0.1f, 0.5f); // Dark background so text shows up well

    ByteBuffer bbVertices = ByteBuffer.allocateDirect(WorldLayoutData.RECT_COORDS.length * 4);
    bbVertices.order(ByteOrder.nativeOrder());
    mRectVertices = bbVertices.asFloatBuffer();
    mRectVertices.put(WorldLayoutData.RECT_COORDS);
    mRectVertices.position(0);

    ByteBuffer bbColors = ByteBuffer.allocateDirect(WorldLayoutData.RECT_COLORS.length * 4);
    bbColors.order(ByteOrder.nativeOrder());
    mRectColors = bbColors.asFloatBuffer();
    mRectColors.put(WorldLayoutData.RECT_COLORS);
    mRectColors.position(0);

    ByteBuffer bbFoundColors = ByteBuffer.allocateDirect(WorldLayoutData.RECT_FOUND_COLORS.length * 4);
    bbFoundColors.order(ByteOrder.nativeOrder());
    mRectFoundColors = bbFoundColors.asFloatBuffer();
    mRectFoundColors.put(WorldLayoutData.RECT_FOUND_COLORS);
    mRectFoundColors.position(0);

    ByteBuffer bbNormals = ByteBuffer.allocateDirect(WorldLayoutData.RECT_NORMALS.length * 4);
    bbNormals.order(ByteOrder.nativeOrder());
    mRectNormals = bbNormals.asFloatBuffer();
    mRectNormals.put(WorldLayoutData.RECT_NORMALS);
    mRectNormals.position(0);

    ByteBuffer bbTextureCoordinates = ByteBuffer.allocateDirect(WorldLayoutData.RECT_TEX_COORDS.length * 4);
    bbTextureCoordinates.order(ByteOrder.nativeOrder());
    mRectTexCoords = bbTextureCoordinates.asFloatBuffer();
    mRectTexCoords.put(WorldLayoutData.RECT_TEX_COORDS);
    mRectTexCoords.position(0);

    // make a floor
    ByteBuffer bbFloorVertices = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_COORDS.length * 4);
    bbFloorVertices.order(ByteOrder.nativeOrder());
    mFloorVertices = bbFloorVertices.asFloatBuffer();
    mFloorVertices.put(WorldLayoutData.FLOOR_COORDS);
    mFloorVertices.position(0);

    ByteBuffer bbFloorNormals = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_NORMALS.length * 4);
    bbFloorNormals.order(ByteOrder.nativeOrder());
    mFloorNormals = bbFloorNormals.asFloatBuffer();
    mFloorNormals.put(WorldLayoutData.FLOOR_NORMALS);
    mFloorNormals.position(0);

    ByteBuffer bbFloorColors = ByteBuffer.allocateDirect(WorldLayoutData.FLOOR_COLORS.length * 4);
    bbFloorColors.order(ByteOrder.nativeOrder());
    mFloorColors = bbFloorColors.asFloatBuffer();
    mFloorColors.put(WorldLayoutData.FLOOR_COLORS);
    mFloorColors.position(0);

    int vertexShader = loadGLShader(GLES20.GL_VERTEX_SHADER, R.raw.light_vertex);
    int gridShader = loadGLShader(GLES20.GL_FRAGMENT_SHADER, R.raw.flat_fragment);

    mGlProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(mGlProgram, vertexShader);
    GLES20.glAttachShader(mGlProgram, gridShader);
    GLES20.glLinkProgram(mGlProgram);

    GLES20.glEnable(GLES20.GL_DEPTH_TEST);

    Matrix.setIdentityM(mModelFloor, 0);
    Matrix.translateM(mModelFloor, 0, 0, -FLOOR_DEPTH, 0); // Floor appears below user

    checkGLError("onSurfaceCreated");
}