Example #1
0
 internal static void UniformMatrix(GraphicsLibrary gl, int uniform, Matrix4x4 matrix)
 {
     unsafe
     {
         var t = stackalloc float[16];
         t[0]  = matrix.M11; t[1] = matrix.M12; t[2] = matrix.M13; t[3] = matrix.M14;
         t[4]  = matrix.M21; t[5] = matrix.M22; t[6] = matrix.M23; t[7] = matrix.M24;
         t[8]  = matrix.M31; t[9] = matrix.M32; t[10] = matrix.M33; t[11] = matrix.M34;
         t[12] = matrix.M41; t[13] = matrix.M42; t[14] = matrix.M43; t[15] = matrix.M44;
         gl.UniformMatrix4fv(uniform, 1, Boolean.False, t);
     }
 }
Example #2
0
 private static unsafe string GetShaderHeader(GraphicsLibrary gl)
 {
     if (shaderHeader == null)
     {
         string?s = Marshal.PtrToStringAnsi(new IntPtr(gl.GetString(StringParameter.ShadingLanguageVersion)));
         if (s != null && s.StartsWith("4."))
         {
             shaderHeader = "#version 4" + s.Substring(2, 2) + " core\n";
         }
         else
         {
             shaderHeader = "#version 300 es\nprecision mediump float;\n";
         }
     }
     return(shaderHeader);
 }
Example #3
0
        internal static unsafe uint LoadShader(GraphicsLibrary gl, ShaderType type, string source)
        {
            var shader    = gl.CreateShader(type);
            var header    = GetShaderHeader(gl);
            var byteCount = Encoding.UTF8.GetMaxByteCount(header.Length);

            byteCount += Encoding.UTF8.GetMaxByteCount(source.Length);
            if (byteCount + 1 > byteBuffer.Length)
            {
                byteBuffer = new byte[byteCount + 1];
            }
            byteCount             = Encoding.UTF8.GetBytes(header, 0, header.Length, byteBuffer, 0);
            byteCount            += Encoding.UTF8.GetBytes(source, 0, source.Length, byteBuffer, byteCount);
            byteBuffer[byteCount] = 0;
            fixed(byte *p = byteBuffer)
            {
                byte *t = p;

                gl.ShaderSource(shader, 1, &t, null);
            }

            gl.CompileShader(shader);
            int len;

            gl.GetShaderiv(shader, ShaderParameter.InfoLogLength, &len);
            if (len > 1)
            {
                var buffer = new byte[len];
                fixed(byte *p = buffer)
                {
                    gl.GetShaderInfoLog(shader, len, &len, p);
                    Console.WriteLine("Shader Compiler message: " + Marshal.PtrToStringAnsi(new IntPtr(p)));
                }
            }
            int cs;

            gl.GetShaderiv(shader, ShaderParameter.CompileStatus, &cs);
            if (cs == 0)
            {
                gl.DeleteShader(shader);
                throw new Exception("Shader compilation error");
            }
            return(shader);
        }
Example #4
0
        internal static unsafe void LinkProgram(GraphicsLibrary gl, uint program)
        {
            gl.LinkProgram(program);
            int ls;

            gl.GetProgramiv(program, ProgramParameter.LinkStatus, &ls);
            if (ls == 0)
            {
                int len;
                gl.GetProgramiv(program, ProgramParameter.InfoLogLength, &len);
                if (len > 1)
                {
                    var buffer = new byte[len];
                    fixed(byte *p = buffer)
                    {
                        gl.GetProgramInfoLog(program, len, &len, p);
                        Console.WriteLine("Shader link message: " + Marshal.PtrToStringAnsi(new IntPtr(p)));
                    }
                }
                gl.DeleteProgram(program);
                throw new Exception("Link error");
            }
        }
Example #5
0
        internal static void TexImage2D(GraphicsLibrary gl, RasterImage image, TextureTarget2D target, int level)
        {
            TexturePixelFormat textureFormat;
            PixelFormat        format;

            if (image.Format == RasterImageFormat.TrueColor)
            {
                textureFormat = TexturePixelFormat.Rgb8;
                format        = PixelFormat.Rgb;
            }
            else
            {
                textureFormat = TexturePixelFormat.Rgba8;
                format        = PixelFormat.Rgba;
            }
            unsafe
            {
                fixed(byte *p = image.Data)
                {
                    var(width, height) = image.Size;
                    gl.TexImage2D(target, level, textureFormat, width, height, 0, format, PixelType.UnsignedByte, new IntPtr(p));
                }
            }
        }
        internal unsafe void Launch()
        {
            Console.WriteLine("Draw Texture...");

            var image      = new RasterImage();
            var namePrefix = typeof(DrawTextureLauncher).Namespace + ".Resources.";

            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(namePrefix + "kitten.bmp"))
            {
                image.LoadBmp(stream ?? throw new InvalidOperationException());
            }

            using var windowServer     = new WindowServer();
            using var renderingContext = new RenderingContext();
            using var window           = windowServer.CreateWindow(renderingContext);

            window.BorderStyle             = WindowBorderStyle.Sizable;
            renderingContext.CurrentWindow = window;
            window.MinimumSize             = (400, 300);
            window.MaximumSize             = (600, 500);
            window.Size    = (450, 350);
            window.Opacity = 0.8;

            var gl = new GraphicsLibrary(renderingContext);

            gl.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);

            var program      = gl.CreateProgram();
            var vertexShader = OpenGLHelper.LoadShader(gl, ShaderType.Vertex, @"
                    in vec2 position;
                    in vec3 color;
                    in vec2 texCoord;
                    out vec3 fColor;
                    out vec2 fTexCoord;
                    void main() {
                        gl_Position = vec4(position, 0.0, 1.0);
                        fColor = color;
                        fTexCoord = texCoord;
                    }
                ");

            gl.AttachShader(program, vertexShader);
            var fragmentShader = OpenGLHelper.LoadShader(gl, ShaderType.Fragment, @"
                    in vec3 fColor;
                    in vec2 fTexCoord;
                    out vec4 outColor;
                    uniform sampler2D tex;
                    void main() {
                        outColor = texture(tex, fTexCoord) * vec4(fColor, 1.0);
                    }
                ");

            gl.AttachShader(program, fragmentShader);

            var position = 0u;

            OpenGLHelper.BindAttribLocation(gl, program, position, "position");
            var color = 1u;

            OpenGLHelper.BindAttribLocation(gl, program, color, "color");
            var texCoord = 2u;

            OpenGLHelper.BindAttribLocation(gl, program, texCoord, "texCoord");

            OpenGLHelper.LinkProgram(gl, program);

            uint h;

            gl.GenVertexArrays(1, &h);
            uint vertexArray = h;

            gl.BindVertexArray(vertexArray);

            float[] vertices = new float[] {
                -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,     // Top-left
                0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,      // Top-right
                0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,     // Bottom-right
                -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f     // Bottom-left
            };
            gl.GenBuffers(1, &h);
            uint vertexBuffer = h;

            gl.BindBuffer(BufferTarget.Array, vertexBuffer);
            OpenGLHelper.BufferData(gl, BufferTarget.Array, vertices, BufferUsage.StaticDraw);

            var elements = new ushort[] {
                0, 1, 2,
                2, 3, 0
            };

            gl.GenBuffers(1, &h);
            uint elementBuffer = h;

            gl.BindBuffer(BufferTarget.ElementArray, elementBuffer);
            OpenGLHelper.BufferData(gl, BufferTarget.ElementArray, elements, BufferUsage.StaticDraw);

            gl.UseProgram(program);
            var stride = sizeof(float) * 7;

            gl.EnableVertexAttribArray(position);
            gl.VertexAttribPointer(position, 2, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero);
            gl.EnableVertexAttribArray(color);
            gl.VertexAttribPointer(color, 3, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero + 2 * sizeof(float));
            gl.EnableVertexAttribArray(texCoord);
            gl.VertexAttribPointer(texCoord, 2, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero + 5 * sizeof(float));

            gl.GenTextures(1, &h);
            var texture = h;

            gl.ActiveTexture(TextureUnit.Texture0);
            gl.BindTexture(TextureTarget.Texture2d, texture);
            OpenGLHelper.TexImage2D(gl, image, TextureTarget2D.Texture2d, 0);

            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureWrapS, (int)TextureParameterValue.ClampToEdge);
            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureWrapT, (int)TextureParameterValue.ClampToEdge);
            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureMinFilter, (int)TextureParameterValue.Linear);
            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureMagFilter, (int)TextureParameterValue.Linear);

            var tex = OpenGLHelper.GetUniformLocation(gl, program, "tex");

            gl.Uniform1i(tex, 0);

            window.Closed += (sender, e) => {
                uint t = texture;
                gl.DeleteTextures(1, &t);
                gl.DeleteProgram(program);
                gl.DeleteShader(vertexShader);
                gl.DeleteShader(fragmentShader);
                t = vertexBuffer;
                gl.DeleteBuffers(1, &t);
                t = elementBuffer;
                gl.DeleteBuffers(1, &t);
                t = vertexArray;
                gl.DeleteVertexArrays(1, &t);
            };

            void draw()
            {
                var(width, height) = window.ViewportSize;
                gl.Viewport(0, 0, (int)width, (int)height);
                gl.Clear(Buffers.Color);
                gl.DrawElements(DrawMode.Triangles, 6, DrawIndexType.UnsignedShort, IntPtr.Zero);
                renderingContext.SwapBuffers(window);
            }

            window.Resize += (sender, e) => draw();

            window.Visible = true;
            while (windowServer.Windows.Count > 0)
            {
                draw();

                windowServer.ProcessEvents(0.02);
            }

            Console.WriteLine("Draw Texture done.");
        }
Example #7
0
        internal void Launch()
        {
            Console.WriteLine("Terrain...");
            Console.WriteLine("  Press Esc to exit.");
            Console.WriteLine("  Press W, Q, S, D, Space to move.");

            using var windowServer     = new WindowServer();
            using var renderingContext = new RenderingContext { Settings = new RenderingSettings { Samples = 4 } };

            using var window   = windowServer.CreateWindow(renderingContext);
            window.Title       = "Terrain";
            window.BorderStyle = WindowBorderStyle.Sizable;

            const double WindowWidth  = 1024;
            const double WindowHeight = 768;

            window.Size = (WindowWidth, WindowHeight);

            renderingContext.CurrentWindow = window;
            var gl = new GraphicsLibrary(renderingContext);

            gl.ClearColor(0, 0, 0, 1);
            using (var scene = new Scene(gl))
            {
                var imageLength = 16 * 16 * 3;
                var buffer      = new byte[imageLength * 3];
                var image       = new RasterImage();
                var namePrefix  = typeof(TerrainLauncher).Namespace + ".Resources.";
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(namePrefix + "grass.png"))
                {
                    image.LoadPng(stream ?? throw new InvalidOperationException());
                }
                Array.Copy(image.Data, 0, buffer, 0, imageLength);
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(namePrefix + "grass_side.png"))
                {
                    image.LoadPng(stream ?? throw new InvalidOperationException());
                }
                Array.Copy(image.Data, 0, buffer, imageLength, imageLength);
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(namePrefix + "dirt.png"))
                {
                    image.LoadPng(stream ?? throw new InvalidOperationException());
                }
                Array.Copy(image.Data, 0, buffer, imageLength * 2, imageLength);
                scene.AddTextureMap(buffer, 3);

                var viewportSize = window.ViewportSize;
                scene.SetViewport(0, 0, (int)viewportSize.width, (int)viewportSize.height);

                (double x, double y)previousPoint = (-1d, -1d);
                window.MouseMove += (sender, e) =>
                {
                    if (previousPoint.x != -1d || previousPoint.y != -1d)
                    {
                        scene.Rotate((float)(e.Position.x - previousPoint.x), (float)(e.Position.y - previousPoint.y));
                    }
                    previousPoint = e.Position;
                };


                void draw()
                {
                    scene.Render();
                    renderingContext.SwapBuffers(window);
                }

                window.Resize += (sender, e) =>
                {
                    var(width, height) = window.ViewportSize;
                    scene.SetViewport(0, 0, (int)width, (int)height);
                    draw();
                };

                window.FramebufferResize += (sender, e) =>
                {
                    var(width, height) = window.ViewportSize;
                    scene.SetViewport(0, 0, (int)width, (int)height);
                };

                window.Closed += (sender, e) =>
                {
                    scene.Dispose();
                };

                var stopWatch = new Stopwatch();
                stopWatch.Start();
                var lastTime  = stopWatch.ElapsedMilliseconds / 1e3f;
                var deltaTime = 0.0f;

                window.FreeLookMouse = true;
                //renderingContext.SyncWithVerticalBlank(window, false);
                Console.WriteLine("Press 'Esc' to quit.");
                window.Visible = true;
                while (windowServer.Windows.Count > 0)
                {
                    var currentTime = stopWatch.ElapsedMilliseconds / 1e3f;
                    deltaTime = currentTime - lastTime;
                    lastTime  = currentTime;

                    if (window.IsKeyPressed(Keycode.W))
                    {
                        scene.MoveForward(deltaTime);
                    }
                    if (window.IsKeyPressed(Keycode.S))
                    {
                        scene.MoveBackward(deltaTime);
                    }
                    if (window.IsKeyPressed(Keycode.A))
                    {
                        scene.MoveLeft(deltaTime);
                    }
                    if (window.IsKeyPressed(Keycode.D))
                    {
                        scene.MoveRight(deltaTime);
                    }
                    if (window.IsKeyPressed(Keycode.Space))
                    {
                        scene.MoveUp(deltaTime);
                    }
                    if (window.IsKeyPressed(Keycode.Escape))
                    {
                        window.Close();
                        windowServer.ProcessEvents(0.0);
                        break;
                    }

                    draw();

                    windowServer.ProcessEvents(0.0);
                }
                stopWatch.Stop();
            }
            Console.WriteLine("Terrain done.");
        }
        internal unsafe void Launch()
        {
            Console.WriteLine("Rotate Cube...");

            var image      = new RasterImage();
            var namePrefix = typeof(DrawTextureLauncher).Namespace + ".Resources.";

            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(namePrefix + "kitten.png"))
            {
                image.LoadPng(stream ?? throw new InvalidOperationException());
            }

            using var windowServer     = new WindowServer();
            using var renderingContext = new RenderingContext();
            using var window           = windowServer.CreateWindow(renderingContext);

            window.BorderStyle             = WindowBorderStyle.Sizable;
            window.Title                   = "Rotate Cube...";
            renderingContext.CurrentWindow = window;

            var gl = new GraphicsLibrary(renderingContext);

            gl.ClearColor(0, 0, 0, 1);

            var program      = gl.CreateProgram();
            var vertexShader = OpenGLHelper.LoadShader(gl, ShaderType.Vertex, @"
                    in vec3 position;
                    in vec3 color;
                    in vec2 texCoord;
                    out vec3 fColor;
                    out vec2 fTexCoord;
                    uniform mat4 model;
                    uniform mat4 view;
                    uniform mat4 proj;
                    void main() {
                        gl_Position = proj * view * model * vec4(position, 1.0);
                        fColor = color;
                        fTexCoord = texCoord;
                    }
                ");

            gl.AttachShader(program, vertexShader);
            var fragmentShader = OpenGLHelper.LoadShader(gl, ShaderType.Fragment, @"
                    in vec3 fColor;
                    in vec2 fTexCoord;
                    out vec4 outColor;
                    uniform sampler2D tex;
                    void main() {
                        outColor = texture(tex, fTexCoord) * vec4(fColor, 1.0);
                    }
                ");

            gl.AttachShader(program, fragmentShader);

            var position = 0u;

            OpenGLHelper.BindAttribLocation(gl, program, position, "position");
            var color = 1u;

            OpenGLHelper.BindAttribLocation(gl, program, color, "color");
            var texCoord = 2u;

            OpenGLHelper.BindAttribLocation(gl, program, texCoord, "texCoord");

            OpenGLHelper.LinkProgram(gl, program);

            uint h;

            gl.GenVertexArrays(1, &h);
            uint vertexArray = h;

            gl.BindVertexArray(vertexArray);

            var vertices = new float[] {
                -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,

                -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,

                -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,

                0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,

                -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,

                -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
                0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
                0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
                -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
                -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
            };

            gl.GenBuffers(1, &h);
            uint vertexBuffer = h;

            gl.BindBuffer(BufferTarget.Array, vertexBuffer);
            OpenGLHelper.BufferData(gl, BufferTarget.Array, vertices, BufferUsage.StaticDraw);

            var stride = sizeof(float) * 8;

            gl.EnableVertexAttribArray(position);
            gl.VertexAttribPointer(position, 3, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero);
            gl.EnableVertexAttribArray(color);
            gl.VertexAttribPointer(color, 3, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero + 3 * sizeof(float));
            gl.EnableVertexAttribArray(texCoord);
            gl.VertexAttribPointer(texCoord, 2, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero + 6 * sizeof(float));

            gl.GenTextures(1, &h);
            var texture = h;

            gl.ActiveTexture(TextureUnit.Texture0);
            gl.BindTexture(TextureTarget.Texture2d, texture);
            OpenGLHelper.TexImage2D(gl, image, TextureTarget2D.Texture2d, 0);

            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureWrapS, (int)TextureParameterValue.ClampToEdge);
            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureWrapT, (int)TextureParameterValue.ClampToEdge);
            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureMinFilter, (int)TextureParameterValue.Linear);
            gl.TexParameteri(TextureTarget.Texture2d, TextureParameteri.TextureMagFilter, (int)TextureParameterValue.Linear);

            gl.UseProgram(program);

            var tex = OpenGLHelper.GetUniformLocation(gl, program, "tex");

            gl.Uniform1i(tex, 0);

            var view  = OpenGLHelper.GetUniformLocation(gl, program, "view");
            var proj  = OpenGLHelper.GetUniformLocation(gl, program, "proj");
            var model = OpenGLHelper.GetUniformLocation(gl, program, "model");

            var mat = Matrix4x4.CreateLookAt(new Vector3(1.5f, 1.5f, 1.5f), new Vector3(0f, 0f, 0f), new Vector3(0f, 0f, 1f));

            OpenGLHelper.UniformMatrix(gl, view, mat);

            mat = Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.PI / 4), 1.3f, 1f, 10f);
            OpenGLHelper.UniformMatrix(gl, proj, mat);

            var viewportSize = window.ViewportSize;
            var windowSize   = window.Size;

            renderingContext.CurrentWindow = null;


            bool  done     = false;
            float angle    = 0f;
            var   drawLock = new object();

            void draw()
            {
                var stopWatch = new Stopwatch();

                stopWatch.Start();
                var lastTime  = stopWatch.ElapsedMilliseconds / 1e3f;
                var deltaTime = 0.0f;

                //renderingContext.SyncWithVerticalBlank(window, false);
                renderingContext.CurrentWindow = window;
                while (!done)
                {
                    var currentTime = stopWatch.ElapsedMilliseconds / 1e3f;
                    deltaTime = currentTime - lastTime;
                    lastTime  = currentTime;

                    gl.Viewport(0, 0, (int)viewportSize.width, (int)viewportSize.height);
                    gl.UseProgram(program);
                    angle += deltaTime;
                    mat    = Matrix4x4.CreateFromAxisAngle(new Vector3(0f, 0f, 1f), angle);
                    OpenGLHelper.UniformMatrix(gl, model, mat);

                    gl.Enable(Capability.DepthTest);
                    gl.Clear(Buffers.Color | Buffers.Depth);
                    gl.BindVertexArray(vertexArray);
                    gl.BindBuffer(BufferTarget.Array, vertexBuffer);
                    gl.ActiveTexture(TextureUnit.Texture0);
                    gl.BindTexture(TextureTarget.Texture2d, texture);
                    gl.DrawArrays(DrawMode.Triangles, 0, 36);
                    gl.Disable(Capability.DepthTest);

                    renderingContext.SwapBuffers(window);
                    lock (drawLock)
                    {
                        Monitor.Wait(drawLock, 15);
                    }
                }
                renderingContext.CurrentWindow = null;
            }

            var drawThread = new Thread(draw);

            window.Closed += (sender, e) => {
                done = true;
                drawThread.Join();
                renderingContext.CurrentWindow = window;
                uint t = texture;
                gl.DeleteTextures(1, &t);
                gl.DeleteProgram(program);
                gl.DeleteShader(vertexShader);
                gl.DeleteShader(fragmentShader);
                t = vertexBuffer;
                gl.DeleteBuffers(1, &t);
                t = vertexArray;
                gl.DeleteVertexArrays(1, &t);
            };

            window.Resize += (sender, e) =>
            {
                viewportSize = window.ViewportSize;
                windowSize   = window.Size;
                lock (drawLock)
                {
                    Monitor.Pulse(drawLock);
                }
            };

            window.FramebufferResize += (sender, e) =>
            {
                viewportSize = window.ViewportSize;
                lock (drawLock)
                {
                    Monitor.Pulse(drawLock);
                }
            };

            drawThread.Start();

            window.Visible = true;
            while (windowServer.Windows.Count > 0)
            {
                windowServer.ProcessEvents(-1);
            }

            Console.WriteLine("Rotate Cube done.");
        }
        internal unsafe void Launch()
        {
            Console.WriteLine("Draw Polygon...");

            using var windowServer     = new WindowServer();
            using var renderingContext = new RenderingContext();
            using var window           = windowServer.CreateWindow(renderingContext);

            renderingContext.CurrentWindow = window;

            var gl = new GraphicsLibrary(renderingContext);

            gl.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            Console.WriteLine("  GL VERSION: " + Marshal.PtrToStringAnsi(new IntPtr(gl.GetString(StringParameter.Version))));
            Console.WriteLine("GLSL VERSION: " + Marshal.PtrToStringAnsi(new IntPtr(gl.GetString(StringParameter.ShadingLanguageVersion))));
            Console.WriteLine("   GL VENDOR: " + Marshal.PtrToStringAnsi(new IntPtr(gl.GetString(StringParameter.Vendor))));
            Console.WriteLine(" GL RENDERER: " + Marshal.PtrToStringAnsi(new IntPtr(gl.GetString(StringParameter.Renderer))));

            var program      = gl.CreateProgram();
            var vertexShader = OpenGLHelper.LoadShader(gl, ShaderType.Vertex, @"
                        layout(location = 0) in vec2 vPosition;
                        layout(location = 1) in vec3 vColor;
                        out vec3 fColor;
                        void main() {
                            gl_Position = vec4(vPosition, 0.0, 1.0);
                            fColor = vColor;
                        }
                    ");

            gl.AttachShader(program, vertexShader);
            var fragmentShader = OpenGLHelper.LoadShader(gl, ShaderType.Fragment, @"
                        in vec3 fColor;
                        out vec4 outColor;
                        void main() {
                            outColor = vec4(fColor, 1.0);
                        }
                    ");

            gl.AttachShader(program, fragmentShader);

            const uint position = 0u;
            const uint color    = 1u;

            OpenGLHelper.LinkProgram(gl, program);

            uint h;

            gl.GenVertexArrays(1, &h);
            uint vertexArray = h;

            gl.BindVertexArray(vertexArray);
            gl.EnableVertexAttribArray(color);
            gl.EnableVertexAttribArray(position);

            var vertices = new float[] {
                -0.5f, 0.5f,         // Top-left
                0.5f, 0.5f,          // Top-right
                0.5f, -0.5f,         // Bottom-right
                -0.5f, -0.5f,        // Bottom-left
            };

            gl.GenBuffers(1, &h);
            uint vertexBuffer1 = h;

            gl.BindBuffer(BufferTarget.Array, vertexBuffer1);
            OpenGLHelper.BufferData(gl, BufferTarget.Array, vertices, BufferUsage.StaticDraw);

            var stride = sizeof(float) * 2;

            gl.VertexAttribPointer(position, 2, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero);

            vertices = new float[] {
                1.0f, 0.0f, 0.0f,         // Top-left
                0.0f, 1.0f, 0.0f,         // Top-right
                0.0f, 0.0f, 1.0f,         // Bottom-right
                1.0f, 1.0f, 1.0f,         // Bottom-left
            };

            gl.GenBuffers(1, &h);
            uint vertexBuffer2 = h;

            gl.BindBuffer(BufferTarget.Array, vertexBuffer2);
            OpenGLHelper.BufferData(gl, BufferTarget.Array, vertices, BufferUsage.StaticDraw);

            stride = sizeof(float) * 3;
            gl.VertexAttribPointer(color, 3, AttributeElementType.Float, Boolean.False, stride, IntPtr.Zero);

            var elements = new byte[] {
                0, 1, 2,
                2, 3, 0
            };

            gl.GenBuffers(1, &h);
            uint elementBuffer = h;

            gl.BindBuffer(BufferTarget.ElementArray, elementBuffer);
            OpenGLHelper.BufferData(gl, BufferTarget.ElementArray, elements, BufferUsage.StaticDraw);

            gl.UseProgram(program);

            window.Closed += (sender, e) =>
            {
                gl.DeleteProgram(program);
                gl.DeleteShader(vertexShader);
                gl.DeleteShader(fragmentShader);
                uint t = vertexBuffer1;
                gl.DeleteBuffers(1, &t);
                t = vertexBuffer2;
                gl.DeleteBuffers(1, &t);
                t = elementBuffer;
                gl.DeleteBuffers(1, &t);
                t = vertexArray;
                gl.DeleteVertexArrays(1, &t);
            };

            window.Visible = true;
            while (windowServer.Windows.Count > 0)
            {
                gl.Clear(Buffers.Color);
                gl.DrawElements(DrawMode.Triangles, 6, DrawIndexType.UnsignedByte, IntPtr.Zero);
                renderingContext.SwapBuffers(window);

                windowServer.ProcessEvents(0.02);
            }

            Console.WriteLine("Draw Polygon done.");
        }