using System; using System.Collections.Generic; using System.Diagnostics; using Quik; using Quik.VertexGenerator; using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; using OpenTK.Windowing.Common; using OpenTK.Windowing.Desktop; using OpenTK.Windowing.GraphicsLibraryFramework; using Quik.FreeType; using Quik.OpenTK; using Quik.Typography; using Quik.Controls; namespace QuikTestApplication { public class Program { public const string vertex = @"#version 140 uniform mat4 matrix; in vec2 position; in vec2 texcoord; in vec4 color; out vec2 ftexcoord; out vec4 fcolor; void main() { fcolor = color; ftexcoord = texcoord; gl_Position = matrix * vec4(position.xy, 0, 1); } "; public const string fragment = @"#version 140 in vec2 ftexcoord; in vec4 fcolor; out vec4 outcolor; uniform sampler2D texture0; uniform vec2 texture0offset; void main() { outcolor = fcolor * texture(texture0, ftexcoord + texture0offset); } "; public static void Main(string[] args) { NativeWindowSettings windowSettings = NativeWindowSettings.Default; windowSettings.NumberOfSamples = 4; NativeWindow window = new NativeWindow(windowSettings); window.Context.MakeCurrent(); GL.LoadBindings(new GLFWBindingsContext()); FreeTypeFontManager fontManager = new FreeTypeFontManager(); QuikContext context = new QuikContext(new OpenGLTextureManager(), fontManager); QuikVertexGenerator gen = new QuikVertexGenerator(context); RootControl root = new RootControl(context); Button button = new Button() { Bounds = new QuikRectangle(120, 60, 20, 20), Text = "button", Padding = 8, NormalStroke = new QuikStrokeStyle(new QuikColor(0xccccccff), 4f), HoverStroke = new QuikStrokeStyle(new QuikColor(0x1010ccff), 4f), ActiveStroke = new QuikStrokeStyle(new QuikColor(0x999999ff), 4f), }; button.Clicked += (sender, args) => { if (!args.Buttons.HasFlag(Quik.MouseButton.Primary)) return; Button xbutton = (Button)sender; if (xbutton.Text == "button") { xbutton.Text = "le button"; } else { xbutton.Text = "button"; } }; root.MouseEnter += (_,_) => Console.WriteLine("enter"); root.MouseLeave += (_,_) => Console.WriteLine("leave"); root.MouseMove += (_,_) => Console.WriteLine("move"); root.MouseDown += (_,_) => Console.WriteLine("down"); root.MouseUp += (_,_) => Console.WriteLine("up"); root.Add(button); GL.Enable(EnableCap.Multisample); int sp; { int vs, fs; sp = GL.CreateProgram(); vs = GL.CreateShader(ShaderType.VertexShader); fs = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(vs, vertex); GL.CompileShader(vs); GL.ShaderSource(fs, fragment); GL.CompileShader(fs); GL.AttachShader(sp, vs); GL.AttachShader(sp, fs); GL.LinkProgram(sp); GL.UseProgram(sp); } new GL30Driver(); int vbo, ebo, vao; vbo = GL.GenBuffer(); ebo = GL.GenBuffer(); vao = GL.GenVertexArray(); GL.BindVertexArray(vao); GL.BindBuffer(BufferTarget.ArrayBuffer, vbo); GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo); int loc; GL.VertexAttribPointer( loc = GL.GetAttribLocation(sp, "position"), 2, VertexAttribPointerType.Float, false, QuikVertex.Stride, QuikVertex.PositionOffset); GL.EnableVertexAttribArray(loc); GL.VertexAttribPointer( loc = GL.GetAttribLocation(sp, "texcoord"), 2, VertexAttribPointerType.Float, false, QuikVertex.Stride, QuikVertex.TextureCoordinatesOffset); GL.EnableVertexAttribArray(loc); GL.VertexAttribPointer( loc = GL.GetAttribLocation(sp, "color"), 4, VertexAttribPointerType.UnsignedByte, true, QuikVertex.Stride, QuikVertex.ColorOffset); GL.EnableVertexAttribArray(loc); loc = GL.GetUniformLocation(sp, "matrix"); int offsetLoc = GL.GetUniformLocation(sp, "texture0offset"); QuikStrokeStyle strokeBorder = new QuikStrokeStyle() { Color = new QuikColor(0xaaaaaaff), Width = 8 }; QuikStrokeStyle strokeNoBorder = new QuikStrokeStyle() { Color = new QuikColor(0xaaaaaaff), Width = 0 }; QuikFillStyle fill = new QuikFillStyle() { Color = new QuikColor(0xeeeeeeff) }; QuikFillStyle magenta = new QuikFillStyle { Color = new QuikColor(0xff00ffff) }; int whiteTexture = GL.GenTexture(); uint[] whitePixel = {0xFFFFFFFF}; GL.BindTexture(TextureTarget.Texture2D, whiteTexture); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, 1, 1, 0, PixelFormat.Rgba, PixelType.UnsignedByte, whitePixel); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); context.DefaultFont = context.FontManager.GetFont(new QuikFontStyle("Arial", 16, QuikFontType.Normal)); const string testString = "The quick brown fox jumps over the lazy dog. " + "Sphinx of black quartz judge my vow. " + "Have some japanese for fun: これが読めるかな?"; var para = new HorizontalParagraph(); para.ConsumeText(context.DefaultFont, testString); var typeset = new TypesetGroup(); para.Typeset(typeset, 200); window.Context.SwapInterval = 0; Stopwatch stopwatch = Stopwatch.StartNew(); float lastMs = stopwatch.ElapsedMilliseconds; int frames = 0; for (;!window.IsExiting;) { NativeWindow.ProcessWindowEvents(false); window.ProcessEvents(0.0f); window.TryGetCurrentMonitorDpi(out float dpi, out _); if (window.IsFocused) { var mouseState = window.MouseState; QuikVec2 postion = new QuikVec2(mouseState.Position.X, window.ClientSize.Y - mouseState.Position.Y) * (dpi/72f); Quik.MouseButton buttons = (mouseState.IsButtonDown(OpenTK.Windowing.GraphicsLibraryFramework.MouseButton.Button1) ? Quik.MouseButton.Primary : 0) | (mouseState.IsButtonDown(OpenTK.Windowing.GraphicsLibraryFramework.MouseButton.Button2) ? Quik.MouseButton.Secondary : 0) | (mouseState.IsButtonDown(OpenTK.Windowing.GraphicsLibraryFramework.MouseButton.Button3) ? Quik.MouseButton.Tertiary : 0); root.NotifyMouse(new Quik.MouseState(postion, buttons)); } root.Bounds = new QuikRectangle( window.ClientSize.X, window.ClientSize.Y, 0, 0); root.NotifyUpdate(); GL.Viewport(0, 0, window.Size.X, window.Size.Y); GL.ClearColor(1,1,1,1); GL.Clear(ClearBufferMask.ColorBufferBit); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); Matrix4 matrix = Matrix4.CreateOrthographicOffCenter( 0, (float)window.Size.X*dpi/72f, 0, (float)window.Size.Y*dpi/72f, 1, -1); GL.UniformMatrix4(loc, false, ref matrix); context.Draw.Commands.Enqueue( new QuikCommandRectangle(new QuikRectangle(120, 60, 20, 20)) { CornerRadius = 0, FillStyle = fill, StrokeStyle = strokeNoBorder }); context.Draw.Commands.Enqueue( new QuikCommandRectangle(new QuikRectangle(240, 60, 140, 20)) { CornerRadius = 4, FillStyle = fill, StrokeStyle = strokeNoBorder }); context.Draw.Commands.Enqueue( new QuikCommandRectangle(new QuikRectangle(360, 60, 260, 20)) { CornerRadius = 15, FillStyle = fill, StrokeStyle = strokeNoBorder }); context.Draw.Commands.Enqueue( new QuikCommandRectangle(new QuikRectangle(120, 120, 20, 80)) { CornerRadius = 0, FillStyle = fill, StrokeStyle = strokeBorder }); context.Draw.Commands.Enqueue( new QuikCommandRectangle(new QuikRectangle(240, 120, 140, 80)) { CornerRadius = 4, FillStyle = fill, StrokeStyle = strokeBorder }); context.Draw.Commands.Enqueue( new QuikCommandRectangle(new QuikRectangle(360, 120, 260, 80)) { CornerRadius = 15, FillStyle = fill, StrokeStyle = strokeBorder }); // context.Draw.PutText("これが読めるかな?", new QuikVec2(25,30)); root.NotifyPaint(context.Draw); context.Draw.Commands.Enqueue(new QuikCommandEmitText(typeset, new QuikVec2(200, 200))); QuikCommand command; while (context.Draw.Commands.TryDequeue(out command)) { gen.ConsumeCommand(command); } GL.BufferData(BufferTarget.ArrayBuffer, gen.VertexCount * QuikVertex.Stride, ref gen.VertexBuffer[0], BufferUsageHint.StreamDraw); GL.BufferData(BufferTarget.ElementArrayBuffer, gen.ElementCount * 2, ref gen.ElementBuffer[0], BufferUsageHint.StreamDraw); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); foreach (QuikDrawCall call in gen.DrawCalls) { GL.BindTexture( TextureTarget.Texture2D, call.Texture == null ? whiteTexture : (call.Texture as OpenGLTexture).TextureId); if (call.Texture != null) GL.Uniform2(offsetLoc, 0.5f / call.Texture.Width, 0.5f / call.Texture.Height); GL.DrawElements(BeginMode.Triangles, call.Count, DrawElementsType.UnsignedShort, call.Offset); } GL.Disable(EnableCap.Blend); int callCount = gen.DrawCalls.Count; gen.Clear(); System.Threading.Thread.Sleep(1); window.Context.SwapBuffers(); frames++; float ms = stopwatch.ElapsedMilliseconds; if (ms - lastMs > 1000) { Console.WriteLine("Frames: {0}", frames*(ms - lastMs)/1000); frames = 0; lastMs = ms; Console.WriteLine("Vertex Usage: {0} ; Element Usage: {1} Calls: {2}", gen.VertexUsage, gen.ElementUsage, callCount); } } } public class TextFontManager : IQuikFontManager { public QuikContext Context { get; set; } private TestFont _font; public void Clear() { } public QuikFont GetFont(QuikFontStyle fontStyle) { if (_font is null) { _font = new TestFont(Context); } return _font; } } } }