/// <summary>
        /// Generate random positions and colors for specified model.
        /// </summary>
        /// <param name="model"></param>
        /// <param name="minPosition">minimum position in model's vertices.</param>
        /// <param name="maxPosition">maximum position in model's vertices.</param>
        public static void Build(this ScientificModel model, Vertex minPosition, Vertex maxPosition)
        {
            if (model == null)
            {
                return;
            }

            Random random = new Random();
            Vertex min = new Vertex(), max = new Vertex();
            bool   isInit = false;

            for (int i = 0; i < model.VertexCount; i++)
            {
                var x = (float)((maxPosition.X - minPosition.X) * random.NextDouble() + minPosition.X);
                var y = (float)((maxPosition.Y - minPosition.Y) * random.NextDouble() + minPosition.Y);
                var z = (float)((maxPosition.Z - minPosition.Z) * random.NextDouble() + minPosition.Z);
                if (!isInit)
                {
                    min    = new Vertex(x, y, z);
                    max    = new Vertex(x, y, z);
                    isInit = true;
                }
                if (x < min.X)
                {
                    min.X = x;
                }
                if (x > max.X)
                {
                    max.X = x;
                }
                if (y < min.Y)
                {
                    min.Y = y;
                }
                if (y > max.Y)
                {
                    max.Y = y;
                }
                if (z < min.Z)
                {
                    min.Z = z;
                }
                if (z > max.Z)
                {
                    max.Z = z;
                }

                model.Positions[i * 3 + 0] = x;
                model.Positions[i * 3 + 1] = y;
                model.Positions[i * 3 + 2] = z;

                model.Colors[i * 3 + 0] = (float)random.NextDouble();
                model.Colors[i * 3 + 1] = (float)random.NextDouble();
                model.Colors[i * 3 + 2] = (float)random.NextDouble();
            }

            model.BoundingBox.Set(min.X, min.Y, min.Z, max.X, max.Y, max.Z);
        }
        unsafe private void GenerateVerticalLines(ColorIndicatorData data)
        {
            int blockCount = data.GetBlockCount();
            //int blockCount = data.BlockCount;
            int             segmentCount  = blockCount + 1;
            ScientificModel verticalLines = new ScientificModel(segmentCount * 2, Enumerations.BeginMode.Lines);

            float[] positions = verticalLines.Positions;
            for (int i = 0; i < segmentCount; i++)
            {
                if (i + 1 != segmentCount)
                {
                    if (data.MaxValue != data.MinValue)
                    {
                        positions[i * 2 * 3 + 0] = barWidth * (i * data.Step / (data.MaxValue - data.MinValue));
                    }
                    else
                    {
                        positions[i * 2 * 3 + 0] = barWidth * 0;
                    }
                }
                else
                {
                    positions[i * 2 * 3 + 0] = barWidth;
                }
                positions[i * 2 * 3 + 1]     = -9;
                positions[i * 2 * 3 + 2]     = 0;
                positions[i * 2 * 3 + 3 + 0] = positions[i * 2 * 3 + 0];
                positions[i * 2 * 3 + 3 + 1] = barHeight;
                positions[i * 2 * 3 + 3 + 2] = 0;
            }
            // move the vertical lines' center to (0, 0, 0)
            for (int i = 0; i < segmentCount * 2; i++)
            {
                positions[i * 3 + 0] -= barWidth / 2;
                positions[i * 3 + 1] -= barHeight / 2;
            }

            float[] colors = verticalLines.Colors;
            for (int i = 0; i < segmentCount * 2; i++)
            {
                colors[i * 3 + 0] = 1;
                colors[i * 3 + 1] = 1;
                colors[i * 3 + 2] = 1;
                //colors[i].red = byte.MaxValue / 2;
                //colors[i].green = byte.MaxValue / 2;
                //colors[i].blue = byte.MaxValue / 2;
            }

            this.verticalLines = verticalLines;
        }
        IPickedGeometry IColorCodedPicking.Pick(uint stageVertexID)
        {
            IColorCodedPicking    element        = this as IColorCodedPicking;
            PickedGeometryColored pickedGeometry = element.TryPick <PickedGeometryColored>(
                this.Model.Mode, stageVertexID, this.Model.Positions);

            if (pickedGeometry == null)
            {
                return(null);
            }

            // Fill primitive's positions and colors. This maybe changes much more than lines above in second dev.
            uint lastVertexID;

            if (element.GetLastVertexIDOfPickedGeometry(stageVertexID, out lastVertexID))
            {
                ScientificModel model = this.Model;

                int vertexCount = pickedGeometry.GeometryType.GetVertexCount();
                if (vertexCount == -1)
                {
                    vertexCount = model.VertexCount;
                }

                float[] geometryColors = new float[vertexCount * 3];

                float[] modelColors = model.Colors;

                uint i = lastVertexID * 3 + 2;
                for (int j = (geometryColors.Length - 1); j >= 0; i--, j--)
                {
                    if (i == uint.MaxValue)// This is when mode is GL_LINE_LOOP.
                    {
                        i = (uint)modelColors.Length - 1;
                    }
                    geometryColors[j] = modelColors[i];
                }

                pickedGeometry.colors = geometryColors;
            }

            return(pickedGeometry);
        }
        /// <summary>
        /// render with Vertex Array(not VAO)
        /// </summary>
        /// <param name="model"></param>
        /// <param name="gl"></param>
        /// <param name="renderMode"></param>
        public static void RenderVertexArray(this ScientificModel model, OpenGL gl, RenderMode renderMode)
        {
            if (model == null)
            {
                return;
            }
            if (model.VertexCount <= 0)
            {
                return;
            }

            // render with Vertex Array(not VAO)
            gl.Enable(OpenGL.GL_POINT_SPRITE_ARB);

            gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY);
            gl.EnableClientState(OpenGL.GL_COLOR_ARRAY);

            var list = new IntPtr[2];

            {
                IntPtr p = Marshal.AllocHGlobal(model.Positions.Length * sizeof(float));
                Marshal.Copy(model.Positions, 0, p, model.Positions.Length);
                gl.VertexPointer(3, OpenGL.GL_FLOAT, 0, p);
                list[0] = p;
            }
            {
                IntPtr p = Marshal.AllocHGlobal(model.Colors.Length * sizeof(float));
                Marshal.Copy(model.Colors, 0, p, model.Colors.Length);
                gl.ColorPointer(3, OpenGL.GL_FLOAT, 0, p);
                list[1] = p;
            }


            gl.DrawArrays((uint)model.Mode, 0, model.VertexCount);

            gl.DisableClientState(OpenGL.GL_VERTEX_ARRAY);
            gl.DisableClientState(OpenGL.GL_COLOR_ARRAY);

            Marshal.FreeHGlobal(list[0]);
            Marshal.FreeHGlobal(list[1]);
        }
        /// <summary>
        /// Render model with legacy opengl(glVertex() ...).
        /// </summary>
        /// <param name="model"></param>
        /// <param name="gl"></param>
        /// <param name="renderMode"></param>
        public static void RenderLegacyOpenGL(this ScientificModel model, OpenGL gl, RenderMode renderMode)
        {
            if (model == null)
            {
                return;
            }
            if (model.VertexCount <= 0)
            {
                return;
            }

            float[] positions = model.Positions;
            float[] colors    = model.Colors;

            gl.Begin(model.Mode);
            for (int i = 0; i < model.VertexCount; i++)
            {
                gl.Color(colors[i * 3], colors[i * 3 + 1], colors[i * 3 + 2]);
                gl.Vertex(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
            }
            gl.End();
        }
        unsafe private void GenerateHorizontalLines()
        {
            int             length          = 4;
            ScientificModel horizontalLines = new ScientificModel(length, Enumerations.BeginMode.Lines);

            float[] positions = horizontalLines.Positions;
            //positions[0].X = 0; positions[0].Y = 0; positions[0].Z = 0;
            //positions[1].X = barWidth; positions[1].Y = 0; positions[1].Z = 0;
            //positions[2].X = 0; positions[2].Y = barHeight; positions[2].Z = 0;
            //positions[3].X = barWidth;
            //positions[3].Y = barHeight;
            //positions[3].Z = 0;
            positions[0 * 3 + 0] = 0; positions[0 * 3 + 1] = 0; positions[0 * 3 + 2] = 0;
            positions[1 * 3 + 0] = barWidth; positions[1 * 3 + 1] = 0; positions[1 * 3 + 2] = 0;
            positions[2 * 3 + 0] = 0; positions[2 * 3 + 1] = barHeight; positions[2 * 3 + 2] = 0;
            positions[3 * 3 + 0] = barWidth;
            positions[3 * 3 + 1] = barHeight;
            positions[3 * 3 + 2] = 0;
            // move the horizontal white lines' center to (0, 0, 0)
            for (int i = 0; i < length; i++)
            {
                positions[i * 3 + 0] -= barWidth / 2;
                positions[i * 3 + 1] -= barHeight / 2;
            }
            float[] colors = horizontalLines.Colors;
            for (int i = 0; i < length; i++)
            {
                colors[i * 3 + 0] = 1;
                colors[i * 3 + 1] = 1;
                colors[i * 3 + 2] = 1;
                //colors[i].red = byte.MaxValue / 2;
                //colors[i].green = byte.MaxValue / 2;
                //colors[i].blue = byte.MaxValue / 2;
            }

            this.horizontalLines = horizontalLines;
        }
        public void Render(OpenGL gl, RenderMode renderMode)
        {
            TryUpdate(this.data);

            ScientificModel rectModel       = this.rectModel;
            ScientificModel verticalLines   = this.verticalLines;
            ScientificModel horizontalLines = this.horizontalLines;


            if (rectModel != null)
            {
                rectModel.RenderLegacyOpenGL(gl, renderMode);
            }

            if (verticalLines != null)
            {
                verticalLines.RenderLegacyOpenGL(gl, renderMode);
            }

            if (horizontalLines != null)
            {
                horizontalLines.RenderLegacyOpenGL(gl, renderMode);
            }
        }
        unsafe private void GenerateRectangles(ColorIndicatorData data)
        {
            int             rectCount = data.ColorPalette.Colors.Length;
            ScientificModel rectModel = new ScientificModel(rectCount * 2, Enumerations.BeginMode.QuadStrip);

            float[] positions = rectModel.Positions;
            for (int i = 0; i < rectCount; i++)
            {
                positions[i * 2 * 3 + 0]     = barWidth * data.ColorPalette.Coords[i];
                positions[i * 2 * 3 + 1]     = 0;
                positions[i * 2 * 3 + 2]     = 0;
                positions[i * 2 * 3 + 3 + 0] = positions[i * 2 * 3];
                positions[i * 2 * 3 + 3 + 1] = barHeight;
                positions[i * 2 * 3 + 3 + 2] = 0;
            }
            // move the rectangles' center to (0, 0, 0)
            for (int i = 0; i < rectCount * 2; i++)
            {
                positions[i * 3 + 0] -= barWidth / 2;
                positions[i * 3 + 1] -= barHeight / 2;
            }

            float[] colors = rectModel.Colors;
            for (int i = 0; i < rectCount; i++)
            {
                GLColor color = data.ColorPalette.Colors[i];
                colors[i * 2 * 3 + 0]     = (color.R);
                colors[i * 2 * 3 + 1]     = (color.G);
                colors[i * 2 * 3 + 2]     = (color.B);
                colors[i * 2 * 3 + 3 + 0] = (color.R);
                colors[i * 2 * 3 + 3 + 1] = (color.G);
                colors[i * 2 * 3 + 3 + 2] = (color.B);
            }

            this.rectModel = rectModel;
        }
 public ScientificModelElement(ScientificModel model, IScientificCamera camera, bool renderModel = true)
 {
     this.Model       = model;
     this.Camera      = camera;
     this.RenderModel = renderModel;
 }
        void IRenderable.Render(OpenGL gl, RenderMode renderMode)
        {
            if (!this.RenderModel)
            {
                return;
            }

            if (!initialised)
            {
                this.Initialise(gl);
            }
            // Update matrices.
            IScientificCamera camera = this.Camera;

            if (camera != null)
            {
                if (camera.CameraType == CameraTypes.Perspecitive)
                {
                    IPerspectiveViewCamera perspective = camera;
                    this.projectionMatrix = perspective.GetProjectionMat4();
                    this.viewMatrix       = perspective.GetViewMat4();
                }
                else if (camera.CameraType == CameraTypes.Ortho)
                {
                    IOrthoViewCamera ortho = camera;
                    this.projectionMatrix = ortho.GetProjectionMat4();
                    this.viewMatrix       = ortho.GetViewMat4();
                }
                else
                {
                    throw new NotImplementedException();
                }
            }

            modelMatrix = glm.scale(mat4.identity(), new vec3(1, 1, this.ZAxisScale));

            //gl.PointSize(3);

            var shader = (renderMode == RenderMode.HitTest) ? pickingShaderProgram : shaderProgram;

            //  Bind the shader, set the matrices.
            shader.Bind(gl);
            shader.SetUniformMatrix4(gl, "projectionMatrix", projectionMatrix.to_array());
            shader.SetUniformMatrix4(gl, "viewMatrix", viewMatrix.to_array());
            shader.SetUniformMatrix4(gl, "modelMatrix", modelMatrix.to_array());
            if (renderMode == RenderMode.HitTest)
            {
                shader.SetUniform1(gl, "pickingBaseID", ((IColorCodedPicking)this).PickingBaseID);
            }

            //  Bind the out vertex array.
            vertexBufferArray.Bind(gl);

            //  Draw the square.
            ScientificModel model = this.Model;

            if (model.First != null && model.Count != null && model.PrimitiveCount > 0)
            {
                gl.MultiDrawArrays((uint)model.Mode, model.First, model.Count, model.PrimitiveCount);
            }
            else
            {
                gl.DrawArrays((uint)this.Model.Mode, 0, this.Model.VertexCount);
            }

            //  Unbind our vertex array and shader.
            vertexBufferArray.Unbind(gl);
            shader.Unbind(gl);
        }