private void WorkerMain() { if (!Initialized) { throw new InvalidOperationException("The OpenGL Library bindings are not initialized."); } if (TargetWindow == null) { CreateMainWindow(WindowTitle); } _systemTimer.Start(); TargetWindow.MakeCurrent(); ViewportSize = new Size(TargetWindow.ClientSize.X, TargetWindow.ClientSize.Y); if (WireframeMode) { WireframeMode = true; // Recall } if (AutoSetViewport) { Gl.Viewport(0, 0, ViewportSize.Width, ViewportSize.Height); } if (VerticalSync) { TargetWindow.SwapInterval = 1; } else { TargetWindow.SwapInterval = 0; } if (AutoEnableCaps.HasFlag(AutoEnableCapabilitiesFlags.Blend)) { Gl.Enable(EnableCap.Blend); } OnContextCreated(); _lastFrameTimeValue = 0; _timeSinceLastFrame = 0; _frameIndex = 0; _currFrameTimerValue = _lastFrameTimeValue; if (Asynchronous) { while (!TargetWindow.IsExiting && !AbortFlag) { AdvanceFrame(); } AbortFlag = true; } }
public void SetUniform(string name, float v1, float?v2 = null, float?v3 = null, float?v4 = null) { if (ActiveShaderProgram == null) { throw new InvalidOperationException("No shader program is loaded. Cannot set uniforms."); } int uniformLocation = Gl.GetUniformLocation(ActiveShaderProgram.ProgramId, name); if (uniformLocation < 0) { throw new KeyNotFoundException(string.Format("The specified uniform '{0}' cannot be found for program '{1}'.", name, ActiveShaderProgram.ProgramId)); } if (v4 != null && v4.HasValue) { Gl.Uniform4(uniformLocation, v1, v2.Value, v3.Value, v4.Value); return; } if (v3 != null && v3.HasValue) { Gl.Uniform3(uniformLocation, v1, v2.Value, v3.Value); return; } if (v2 != null && v2.HasValue) { Gl.Uniform2(uniformLocation, v1, v2.Value); return; } Gl.Uniform1(uniformLocation, v1); return; }
public static void CheckGlErrors(string stage) { ErrorCode code = Gl.GetError(); if (code != ErrorCode.NoError) { throw new Exception(string.Format("OpenGL Draw error on stage {0}: {1}", stage, code.ToString())); } }
protected virtual void Renderer_ContextCreated_Wrap(RenderThread sender) { GlVersion ver = GlVersion.Parse(Gl.GetString(StringName.Version)); ContextCreationEventArgs args = new ContextCreationEventArgs(ver.Api, ver.Version, ver.ToString(), ver.Profile, Gl.GetString(StringName.Vendor)); Gl.GetError(); Renderer_ContextCreated(sender, args); }
public void SelectShader(ShaderProgram program) { if (!FrameStarted) { throw new InvalidOperationException("Cannot select a Shader program when no frame is currently started on the GPU."); } ActiveShaderProgram = program; Gl.UseProgram(program.ProgramId); }
public void Unload() { if (!Compiled) { throw new InvalidOperationException("Cannot unload shader because its not loaded into the GPU."); } Compiled = false; Gl.DeleteProgram(ProgramId); }
protected int LoadTexture(Bitmap data, TextureWrapMode mode) { BitmapData lockedBitmap = data.LockBits(new Rectangle(Point.Empty, data.Size), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); byte[] buffer = new byte[lockedBitmap.Width * lockedBitmap.Height * 4]; for (int i = 0; i < buffer.Length; i += 4) { byte r, g, b, a; a = Marshal.ReadByte(lockedBitmap.Scan0 + i); r = Marshal.ReadByte(lockedBitmap.Scan0 + i + 1); g = Marshal.ReadByte(lockedBitmap.Scan0 + i + 2); b = Marshal.ReadByte(lockedBitmap.Scan0 + i + 3); buffer[i] = r; buffer[i + 1] = g; buffer[i + 2] = b; buffer[i + 3] = a; } data.UnlockBits(lockedBitmap); CheckGlErrors("pre-texture-gen"); int textureId = Gl.GenTexture(); Gl.ActiveTexture(TextureUnit.Texture0); Gl.BindTexture(TextureTarget.Texture2D, textureId); Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)mode); Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)mode); CheckGlErrors("pre-texture-upload"); Gl.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, data.Width, data.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, buffer); CheckGlErrors("post-texture-upload"); if (mode == TextureWrapMode.ClampToBorder) { float[] borderColor = new float[] { 0xff, 0x14, 0x93 }; Gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, borderColor); } CheckGlErrors("ok-texture-gen"); return(textureId); }
protected override void Renderer_DrawPrepare(RenderThread sender, FrameStageControllerEventArgs args) { CheckGlErrors("pre-program"); sender.SelectShader(glyphShader); CheckGlErrors("post-program"); sender.SelectShader(glyphShader); sender.SetUniform("resolution", 0, 0, sender.InternalResolution.Width, sender.InternalResolution.Height); sender.SetUniform("atlasSize", fontAtlas.AtlasTextureSize.Width, fontAtlas.AtlasTextureSize.Height); Gl.Uniform1(Gl.GetUniformLocation(glyphShader.ProgramId, "atlasTexture"), 0); CheckGlErrors("post-uniforms"); }
protected override void Renderer_ContextCreated(RenderThread sender, ContextCreationEventArgs args) { Log.WriteLine("Context created. Using: " + Gl.GetString(StringName.Renderer) + Gl.GetString(StringName.Version)); Log.WriteLine("Renderer_ContextCreated"); Renderer.TargetWindow.Resize += TargetWindow_Resize; // Load Shaders string vertex = File.ReadAllText("./shaders/hello.vert".Replace('/', Path.DirectorySeparatorChar)); string fragment = File.ReadAllText("./shaders/hello.frag".Replace('/', Path.DirectorySeparatorChar)); // Compile shaders Log.WriteLine("Compiling shader 'hello'..."); shader = new ShaderProgram(vertex, fragment); shader.Compile(); Log.WriteLine("Compiled shader index: %@", LogLevel.Message, shader.ProgramId); // Load vertices and indices vertices = new float[] { 0.0f, 0.5f, 0.0f, // top 0.5f, -0.5f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, // bottom left }; // Setup global VAO VAO = Gl.GenVertexArray(); Gl.BindVertexArray(VAO); CheckGlErrors("Renderer_ContextCreated:AfterVAO"); // Setup VBO (vertices) VBO = Gl.GenBuffer(); Gl.BindBuffer(BufferTarget.ArrayBuffer, VBO); int size = (sizeof(float) * vertices.Length); // size must be 36 Gl.BufferData(BufferTarget.ArrayBuffer, size, vertices, BufferUsageHint.StaticDraw); CheckGlErrors("Renderer_ContextCreated:AfterBufferDataVBO"); Gl.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0); CheckGlErrors("Renderer_ContextCreated:AfterVAP_VBO"); Gl.EnableVertexAttribArray(0); CheckGlErrors("Renderer_ContextCreated:AfterVBO"); // Unbind Gl.BindVertexArray(0); CheckGlErrors("Renderer_ContextCreated:End"); }
protected override void Renderer_ContextCreated(RenderThread sender, ContextCreationEventArgs args) { Log.WriteLine("Render context created. Continuing initialization..."); Log.WriteLine("Running on OpenGL: %@", LogLevel.Message, Gl.GetString(StringName.Renderer) + Gl.GetString(StringName.Version)); Renderer.TargetWindow.KeyDown += TargetWindow_KeyDown; Renderer.TargetWindow.KeyUp += TargetWindow_KeyUp; CompileShaders(); LoadTextures(); Gl.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); VAO = Gl.GenVertexArray(); Gl.BindVertexArray(VAO); CheckGlErrors("pre-texture"); Gl.ActiveTexture(TextureUnit.Texture0); Gl.BindTexture(TextureTarget.Texture2D, fontAtlasTexture); CheckGlErrors("post-texture"); VBO = Gl.GenBuffer(); Gl.BindBuffer(BufferTarget.ArrayBuffer, VBO); EBO = Gl.GenBuffer(); Gl.BindBuffer(BufferTarget.ElementArrayBuffer, EBO); CheckGlErrors("pre_va_pointer"); Gl.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 12 * sizeof(float), 0 * sizeof(float)); CheckGlErrors("post-va-pointer-0-set"); Gl.EnableVertexAttribArray(0); CheckGlErrors("post-va-pointer-0-enable"); Gl.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 12 * sizeof(float), 2 * sizeof(float)); Gl.EnableVertexAttribArray(1); CheckGlErrors("post-va-pointer-1"); Gl.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, false, 12 * sizeof(float), 4 * sizeof(float)); Gl.EnableVertexAttribArray(2); CheckGlErrors("post-va-pointer-2"); Gl.VertexAttribPointer(3, 4, VertexAttribPointerType.Float, false, 12 * sizeof(float), 8 * sizeof(float)); Gl.EnableVertexAttribArray(3); }
protected override void Renderer_Draw(RenderThread sender, FrameStageEventArgs args) { Log.WriteLine("Renderer_Draw(%@)", LogLevel.Message, args.CurrentTime.FrameIndex); Gl.BindVertexArray(VAO); CheckGlErrors("Renderer_Draw:BindVAO"); Gl.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); CheckGlErrors("Renderer_Draw:Clear"); Gl.UseProgram(shader.ProgramId); CheckGlErrors("Renderer_Draw:UseProgram"); Gl.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0); CheckGlErrors("Renderer_Draw:DrawElements"); }
protected int LinkShaderProgram(int vertexId, int fragmentId) { int programId = Gl.CreateProgram(); Gl.AttachShader(programId, vertexId); Gl.AttachShader(programId, fragmentId); Gl.LinkProgram(programId); Gl.GetProgram(programId, GetProgramParameterName.LinkStatus, out int success); if (success < 1) { string infoLog = null; Gl.GetProgram(programId, GetProgramParameterName.InfoLogLength, out int loglen); if (loglen > 0) { string log; Gl.GetProgramInfoLog(programId, loglen, out _, out log); infoLog = log; } throw new ShaderException(this, "Program Link failed.", infoLog); } //Gl.ValidateProgram(programId); //Gl.GetProgram(programId, ProgramProperty.ValidateStatus, out success); //if (success < 1) //{ // string infoLog = null; // Gl.GetProgram(programId, ProgramProperty.InfoLogLength, out int loglen); // if (loglen > 0) // { // StringBuilder log = new StringBuilder(loglen); // Gl.GetProgramInfoLog(programId, loglen, out _, log); // infoLog = log.ToString(); // } // throw new ShaderException(this, "Program Validation failed.", infoLog); //} return(programId); }
protected int CompileShaderSource(ShaderType t, string code) { int shaderId = Gl.CreateShader(t); Gl.ShaderSource(shaderId, code); Gl.CompileShader(shaderId); Gl.GetShader(shaderId, ShaderParameter.CompileStatus, out int success); if (success < 1) { string infoLog = null; Gl.GetShader(shaderId, ShaderParameter.InfoLogLength, out int loglen); if (loglen > 0) { string log; Gl.GetShaderInfoLog(shaderId, loglen, out _, out log); infoLog = log; } throw new ShaderException(this, "Shader compilation failed. Type:" + t.ToString(), infoLog); } return(shaderId); }
private void ClearBuffer() { Gl.ClearColor(ClearColor.R / 255.0f, ClearColor.G / 255.0f, ClearColor.B / 255.0f, 0.5f); Gl.Clear(ClearBufferMask.ColorBufferBit); }
private void TargetWindow_Resize(OpenToolkit.Windowing.Common.ResizeEventArgs obj) { Gl.Viewport(0, 0, obj.Width, obj.Height); }
protected void DestroyShader(int shaderId) { Gl.DeleteShader(shaderId); }
protected override void Renderer_Draw(RenderThread sender, FrameStageEventArgs args) { if (!sender.IsMainThread() && !sender.Asynchronous) { throw new InvalidOperationException("Draw operation initiated from secondary thread when supposed to run in Sync mode."); } float cellX = sender.InternalResolution.Width / (float)ConsoleSize.Width; float cellY = sender.InternalResolution.Height / (float)ConsoleSize.Height; List <float> vertices = new List <float>(4096); List <uint> indices = new List <uint>(4096); float[] db = ColorToFloatArray(DefaultBackColor); float[] df = ColorToFloatArray(DefaultForeColor); int vertexCount = 0; for (int xi = 0; xi < ConsoleSize.Width; xi++) { float x = xi * cellX; for (int yi = 0; yi < ConsoleSize.Height; yi++) { RenderGlyph glyphData = GetGlyph(xi, yi); if (ShowCursor && xi == Cursor.X && yi == Cursor.Y && glyphData == null) { int val = (int)((args.CurrentTime.TotalRuntime / 1000.0f) / BlinkInterval); if (val % 2 == 0 || BlinkInterval == 0) { glyphData = new RenderGlyph('_'); } } float y = yi * cellY; Rectangle texRec = Rectangle.Empty; int glyphId = (int)(glyphData?.Glyph ?? ' '); if (fontAtlas.ContainsId(glyphId)) { texRec = fontAtlas.GetPointerById(glyphId).Bounds; } else if (fontAtlas.ContainsId(0x558)) { texRec = fontAtlas.GetPointerById(0x558).Bounds; } else { texRec = fontAtlas.GetPointerById((int)'?').Bounds; } float[] b = glyphData == null || !glyphData.Background.HasValue ? db : ColorToFloatArray(glyphData.Background.Value); float[] f = glyphData == null || !glyphData.Foreground.HasValue ? df : ColorToFloatArray(glyphData.Foreground.Value); int qi = vertexCount; vertices.AddRange(new float[] { // Add vertices x, y, // 0,0 (A) texRec.X, texRec.Y, // Texture X,Y b[0], b[1], b[2], b[3], // Back f[0], f[1], f[2], f[3], // Fore x + cellX, y, // 1,0 (B) texRec.Right, texRec.Y, // Texture X,Y b[0], b[1], b[2], b[3], // Back f[0], f[1], f[2], f[3], // Fore x + cellX, y + cellY, // 1,1 (C) texRec.Right, texRec.Bottom, // Texture X,Y b[0], b[1], b[2], b[3], // Back f[0], f[1], f[2], f[3], // Fore x, y + cellY, //0,1 (D) texRec.X, texRec.Bottom, // Texture X,Y b[0], b[1], b[2], b[3], // Back f[0], f[1], f[2], f[3], // Fore }); indices.AddRange(new uint[] { (uint)(qi + 1), // B (uint)(qi + 3), // D (uint)(qi), // A (uint)(qi + 1), // B (uint)(qi + 2), // C (uint)(qi + 3), // D }); vertexCount += 4; } } Gl.BindVertexArray(VAO); Gl.BindBuffer(BufferTarget.ArrayBuffer, VBO); float[] fvertices = vertices.ToArray(); vertices.Clear(); uint[] iindices = indices.ToArray(); indices.Clear(); CheckGlErrors("pre-vab"); GCHandle buffAddress = GCHandle.Alloc(fvertices, GCHandleType.Pinned); Gl.BufferData(BufferTarget.ArrayBuffer, fvertices.Length * sizeof(float), buffAddress.AddrOfPinnedObject(), BufferUsageHint.StreamDraw); buffAddress.Free(); CheckGlErrors("pre-eab"); buffAddress = GCHandle.Alloc(iindices, GCHandleType.Pinned); Gl.BufferData(BufferTarget.ElementArrayBuffer, iindices.Length * sizeof(float), buffAddress.AddrOfPinnedObject(), BufferUsageHint.StreamDraw); buffAddress.Free(); CheckGlErrors("predraw"); Gl.DrawElements(BeginMode.Triangles, iindices.Length, DrawElementsType.UnsignedInt, 0); CheckGlErrors("final"); Gl.BindVertexArray(0); CheckGlErrors("unbind"); }