/**
  * Updates the object model matrix and applies scaling.
  *
  * @param modelMatrix A 4x4 model-to-world transformation matrix, stored in column-major order.
  * @param scaleFactor A separate scaling factor to apply before the {@code modelMatrix}.
  * @see android.opengl.Matrix
  */
 public void updateModelMatrix(float[] modelMatrix, float scaleFactor)
 {
     float[] scaleMatrix = new float[16];
     Matrix.SetIdentityM(scaleMatrix, 0);
     scaleMatrix[0]  = scaleFactor;
     scaleMatrix[5]  = scaleFactor;
     scaleMatrix[10] = scaleFactor;
     Matrix.MultiplyMM(mModelMatrix, 0, modelMatrix, 0, scaleMatrix, 0);
 }
        private void DrawLabel(float[] cameraViews, float[] cameraProjection)
        {
            ShaderUtil.CheckGlError(TAG, "Draw label start.");
            Matrix.MultiplyMM(modelViewMatrix, 0, cameraViews, 0, modelMatrix, 0);
            Matrix.MultiplyMM(modelViewProjectionMatrix, 0, cameraProjection, 0, modelViewMatrix, 0);

            float halfWidth  = LABEL_WIDTH / 2.0f;
            float halfHeight = LABEL_HEIGHT / 2.0f;

            float[] vertices =
            {
                -halfWidth, -halfHeight, 1,
                -halfWidth, halfHeight,  1,
                halfWidth,  halfHeight,  1,
                halfWidth,  -halfHeight, 1,
            };

            // The size of each floating point is 4 bits.
            FloatBuffer vetBuffer = ByteBuffer.AllocateDirect(4 * vertices.Length)
                                    .Order(ByteOrder.NativeOrder()).AsFloatBuffer();

            vetBuffer.Rewind();
            for (int i = 0; i < vertices.Length; ++i)
            {
                vetBuffer.Put(vertices[i]);
            }
            vetBuffer.Rewind();

            // The size of each floating point is 4 bits.
            GLES20.GlVertexAttribPointer(glPositionParameter, COORDS_PER_VERTEX, GLES20.GlFloat,
                                         false, 4 * COORDS_PER_VERTEX, vetBuffer);

            // Set the sequence of OpenGL drawing points to generate two triangles that form a plane.
            short[] indices = { 0, 1, 2, 0, 2, 3 };

            // Size of the allocated buffer.
            ShortBuffer idxBuffer = ByteBuffer.AllocateDirect(2 * indices.Length)
                                    .Order(ByteOrder.NativeOrder()).AsShortBuffer();

            idxBuffer.Rewind();
            for (int i = 0; i < indices.Length; ++i)
            {
                idxBuffer.Put(indices[i]);
            }
            idxBuffer.Rewind();

            GLES20.GlUniformMatrix4fv(glModelViewProjectionMatrix, 1, false, modelViewProjectionMatrix, 0);

            GLES20.GlDrawElements(GLES20.GlTriangleStrip, idxBuffer.Limit(), GLES20.GlUnsignedShort, idxBuffer);
            ShaderUtil.CheckGlError(TAG, "Draw label end.");
        }
        /// <summary>
        /// Draw a virtual object at a specific location on a specified plane.
        /// This method is called when WorldRenderManager's OnDrawFrame.
        /// </summary>
        /// <param name="cameraView">The viewMatrix is a 4 * 4 matrix.</param>
        /// <param name="cameraProjection">The ProjectionMatrix is a 4 * 4 matrix.</param>
        /// <param name="lightIntensity">The lighting intensity.</param>
        /// <param name="obj">The virtual object.</param>
        public void OnDrawFrame(float[] cameraView, float[] cameraProjection, float lightIntensity, VirtualObject obj)
        {
            ShaderUtil.CheckGlError(TAG, "onDrawFrame start.");
            mModelMatrixs = obj.GetModelAnchorMatrix();
            Matrix.MultiplyMM(mModelViewMatrixs, 0, cameraView, 0, mModelMatrixs, 0);
            Matrix.MultiplyMM(mModelViewProjectionMatrixs, 0, cameraProjection, 0, mModelViewMatrixs, 0);
            GLES20.GlUseProgram(mGlProgram);
            Matrix.MultiplyMV(mViewLightDirections, 0, mModelViewMatrixs, 0, LIGHT_DIRECTIONS, 0);
            MatrixUtil.NormalizeVec3(mViewLightDirections);

            // Light direction.
            GLES20.GlUniform4f(mLightingParametersUniform,
                               mViewLightDirections[0], mViewLightDirections[1], mViewLightDirections[2], lightIntensity);
            float[] objColors = obj.GetColor();

            GLES20.GlUniform4fv(mColorUniform, 1, objColors, 0);
            GLES20.GlActiveTexture(GLES20.GlTexture0);
            GLES20.GlBindTexture(GLES20.GlTexture2d, mTextures[0]);
            GLES20.GlUniform1i(mTextureUniform, 0);
            GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVertexBufferId);

            // The coordinate dimension of the read virtual object is 3.
            GLES20.GlVertexAttribPointer(
                mPositionAttribute, 3, GLES20.GlFloat, false, 0, 0);

            // The dimension of the normal vector is 3.
            GLES20.GlVertexAttribPointer(
                mNormalAttribute, 3, GLES20.GlFloat, false, 0, mNormalsBaseAddress);

            // The dimension of the texture coordinate is 2.
            GLES20.GlVertexAttribPointer(
                mTexCoordAttribute, 2, GLES20.GlFloat, false, 0, mTexCoordsBaseAddress);
            GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0);
            GLES20.GlUniformMatrix4fv(
                mModelViewUniform, 1, false, mModelViewMatrixs, 0);
            GLES20.GlUniformMatrix4fv(
                mModelViewProjectionUniform, 1, false, mModelViewProjectionMatrixs, 0);
            GLES20.GlEnableVertexAttribArray(mPositionAttribute);
            GLES20.GlEnableVertexAttribArray(mNormalAttribute);
            GLES20.GlEnableVertexAttribArray(mTexCoordAttribute);
            GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mIndexBufferId);
            GLES20.GlDrawElements(GLES20.GlTriangles, mIndexCount, GLES20.GlUnsignedShort, 0);
            GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0);
            GLES20.GlDisableVertexAttribArray(mPositionAttribute);
            GLES20.GlDisableVertexAttribArray(mNormalAttribute);
            GLES20.GlDisableVertexAttribArray(mTexCoordAttribute);
            GLES20.GlBindTexture(GLES20.GlTexture2d, 0);
            ShaderUtil.CheckGlError(TAG, "onDrawFrame end.");
        }
        void Draw(float[] cameraView, float[] cameraPerspective)
        {
            // Build the ModelView and ModelViewProjection matrices
            // for calculating cube position and light.
            Matrix.MultiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0);
            Matrix.MultiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0);

            // Set the position of the plane
            mVertexBuffer.Rewind();
            GLES20.GlVertexAttribPointer(
                mPlaneXZPositionAlphaAttribute, COORDS_PER_VERTEX, GLES20.GlFloat, false,
                BYTES_PER_FLOAT * COORDS_PER_VERTEX, mVertexBuffer);

            // Set the Model and ModelViewProjection matrices in the shader.
            GLES20.GlUniformMatrix4fv(mPlaneModelUniform, 1, false, mModelMatrix, 0);
            GLES20.GlUniformMatrix4fv(
                mPlaneModelViewProjectionUniform, 1, false, mModelViewProjectionMatrix, 0);

            mIndexBuffer.Rewind();
            GLES20.GlDrawElements(GLES20.GlTriangleStrip, mIndexBuffer.Limit(),
                                  GLES20.GlUnsignedShort, mIndexBuffer);
            ShaderUtil.CheckGLError(TAG, "Drawing plane");
        }
        /**
         * Draws the model.
         *
         * @param cameraView  A 4x4 view matrix, in column-major order.
         * @param cameraPerspective  A 4x4 projection matrix, in column-major order.
         * @param lightIntensity  Illumination intensity.  Combined with diffuse and specular material
         *     properties.
         * @see #setBlendMode(BlendMode)
         * @see #updateModelMatrix(float[], float)
         * @see #setMaterialProperties(float, float, float, float)
         * @see android.opengl.Matrix
         */
        public void Draw(float[] cameraView, float[] cameraPerspective, float lightIntensity)
        {
            ShaderUtil.CheckGLError(TAG, "Before draw");

            // Build the ModelView and ModelViewProjection matrices
            // for calculating object position and light.
            Matrix.MultiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0);
            Matrix.MultiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0);

            GLES20.GlUseProgram(mProgram);

            // Set the lighting environment properties.
            Matrix.MultiplyMV(mViewLightDirection, 0, mModelViewMatrix, 0, LIGHT_DIRECTION, 0);
            normalizeVec3(mViewLightDirection);
            GLES20.GlUniform4f(mLightingParametersUniform,
                               mViewLightDirection[0], mViewLightDirection[1], mViewLightDirection[2], lightIntensity);

            // Set the object material properties.
            GLES20.GlUniform4f(mMaterialParametersUniform, mAmbient, mDiffuse, mSpecular,
                               mSpecularPower);

            // Attach the object texture.
            GLES20.GlActiveTexture(GLES20.GlTexture0);
            GLES20.GlBindTexture(GLES20.GlTexture2d, mTextures[0]);
            GLES20.GlUniform1i(mTextureUniform, 0);

            // Set the vertex attributes.
            GLES20.GlBindBuffer(GLES20.GlArrayBuffer, mVertexBufferId);

            GLES20.GlVertexAttribPointer(
                mPositionAttribute, COORDS_PER_VERTEX, GLES20.GlFloat, false, 0, mVerticesBaseAddress);
            GLES20.GlVertexAttribPointer(
                mNormalAttribute, 3, GLES20.GlFloat, false, 0, mNormalsBaseAddress);
            GLES20.GlVertexAttribPointer(
                mTexCoordAttribute, 2, GLES20.GlFloat, false, 0, mTexCoordsBaseAddress);

            GLES20.GlBindBuffer(GLES20.GlArrayBuffer, 0);

            // Set the ModelViewProjection matrix in the shader.
            GLES20.GlUniformMatrix4fv(
                mModelViewUniform, 1, false, mModelViewMatrix, 0);
            GLES20.GlUniformMatrix4fv(
                mModelViewProjectionUniform, 1, false, mModelViewProjectionMatrix, 0);

            // Enable vertex arrays
            GLES20.GlEnableVertexAttribArray(mPositionAttribute);
            GLES20.GlEnableVertexAttribArray(mNormalAttribute);
            GLES20.GlEnableVertexAttribArray(mTexCoordAttribute);

            if (mBlendMode != BlendMode.Null)
            {
                GLES20.GlDepthMask(false);
                GLES20.GlEnable(GLES20.GlBlend);
                switch (mBlendMode)
                {
                case BlendMode.Shadow:
                    // Multiplicative blending function for Shadow.
                    GLES20.GlBlendFunc(GLES20.GlZero, GLES20.GlOneMinusSrcAlpha);
                    break;

                case BlendMode.Grid:
                    // Grid, additive blending function.
                    GLES20.GlBlendFunc(GLES20.GlSrcAlpha, GLES20.GlOneMinusSrcAlpha);
                    break;
                }
            }

            GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, mIndexBufferId);
            GLES20.GlDrawElements(GLES20.GlTriangles, mIndexCount, GLES20.GlUnsignedShort, 0);
            GLES20.GlBindBuffer(GLES20.GlElementArrayBuffer, 0);

            if (mBlendMode != BlendMode.Null)
            {
                GLES20.GlDisable(GLES20.GlBlend);
                GLES20.GlDepthMask(true);
            }

            // Disable vertex arrays
            GLES20.GlDisableVertexAttribArray(mPositionAttribute);
            GLES20.GlDisableVertexAttribArray(mNormalAttribute);
            GLES20.GlDisableVertexAttribArray(mTexCoordAttribute);

            GLES20.GlBindTexture(GLES20.GlTexture2d, 0);

            ShaderUtil.CheckGLError(TAG, "After draw");
        }
        /// <summary>
        /// Check whether the virtual object is clicked.
        /// </summary>
        /// <param name="cameraView">The viewMatrix 4 * 4.</param>
        /// <param name="cameraPerspective">The ProjectionMatrix 4 * 4.</param>
        /// <param name="obj">The virtual object data.</param>
        /// <param name="mEvent">The gesture event.</param>
        /// <returns>Return the click result for determining whether the input virtual object is clicked</returns>
        public bool HitTest(float[] cameraView, float[] cameraPerspective, VirtualObject obj, MotionEvent mEvent)
        {
            mModelMatrixs = obj.GetModelAnchorMatrix();
            Matrix.MultiplyMM(mModelViewMatrixs, 0, cameraView, 0, mModelMatrixs, 0);
            Matrix.MultiplyMM(mModelViewProjectionMatrixs, 0, cameraPerspective, 0, mModelViewMatrixs, 0);
            // Calculate the coordinates of the smallest bounding box in the coordinate system of the device screen.
            float[] screenPos = CalculateScreenPos(mBoundingBoxs[0], mBoundingBoxs[1], mBoundingBoxs[2]);

            // Record the largest bounding rectangle of an object (minX/minY/maxX/maxY).
            float[] boundarys = new float[4];
            boundarys[0] = screenPos[0];
            boundarys[1] = screenPos[0];
            boundarys[2] = screenPos[1];
            boundarys[3] = screenPos[1];
            // Determine whether a screen position corresponding to (maxX, maxY, maxZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 3, 4, 5 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }
            // Determine whether a screen position corresponding to (minX, minY, maxZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 0, 1, 5 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }

            // Determine whether a screen position corresponding to (minX, maxY, minZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 0, 4, 2 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }

            // Determine whether a screen position corresponding to (minX, maxY, maxZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 0, 4, 5 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }
            // Determine whether a screen position corresponding to (maxX, minY, minZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 3, 1, 2 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }

            // Determine whether a screen position corresponding to (maxX, minY, maxZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 3, 1, 5 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }

            // Determine whether a screen position corresponding to (maxX, maxY, maxZ) is clicked.
            boundarys = FindMaximum(boundarys, new int[] { 3, 4, 2 });
            if (((mEvent.GetX() > boundarys[0]) && (mEvent.GetX() < boundarys[1])) &&
                ((mEvent.GetY() > boundarys[2]) && (mEvent.GetY() < boundarys[3])))
            {
                return(true);
            }

            return(false);
        }