From 4338402e29d2c448c24f4efe6a788adb84f81785 Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Mon, 16 Mar 2015 13:36:36 +0100 Subject: [PATCH] OpenGL indirect drawing for ui quad (shader and vao) --- GOLib.csproj | 5 + src/GraphicObjects/Scroller.cs | 52 ------- src/OpenGL/QuadVAO.cs | 45 ++++++ src/OpenGL/Shader.cs | 237 ++++++++++++++++++++++++++++++++ src/OpenGL/TexturedShader.cs | 65 +++++++++ src/OpenGL/VertexArrayObject.cs | 94 +++++++++++++ src/OpenTKGameWindow.cs | 136 +++++++----------- 7 files changed, 494 insertions(+), 140 deletions(-) create mode 100644 src/OpenGL/QuadVAO.cs create mode 100644 src/OpenGL/Shader.cs create mode 100644 src/OpenGL/TexturedShader.cs create mode 100644 src/OpenGL/VertexArrayObject.cs diff --git a/GOLib.csproj b/GOLib.csproj index 5ca2686e..1d36e410 100644 --- a/GOLib.csproj +++ b/GOLib.csproj @@ -81,6 +81,10 @@ + + + + @@ -113,6 +117,7 @@ + diff --git a/src/GraphicObjects/Scroller.cs b/src/GraphicObjects/Scroller.cs index c896f3b4..b24eb784 100644 --- a/src/GraphicObjects/Scroller.cs +++ b/src/GraphicObjects/Scroller.cs @@ -163,57 +163,5 @@ namespace go ctx.Restore(); } - -// -// public override void Paint(ref Cairo.Context ctx, Rectangles clip = null) -// { -// if (!Visible)//check if necessary?? -// return; -// -// ctx.Save(); -// -// Rectangle tmp; -// tmp = Parent.ContextCoordinates(Slot); -//// ctx.Rectangle(tmp); -//// ctx.Clip(); -// -//// if (clip != null) -//// clip.clip(ctx); -// -// if (bmp == null) -// UpdateGraphic (); -// -// -// -// int stride = 4 * Slot.Width; -// using (ImageSurface source = new ImageSurface(bmp, Format.Argb32, tmp.Width, tmp.Height, stride)) { -// ctx.SetSourceSurface (source, tmp.X, tmp.Y); -// ctx.Paint (); -// } -// -// -// //clip to client zone -//// ctx.Rectangle(Parent.ContextCoordinates(ClientRectangle + Slot.Position)); -//// ctx.Clip(); -// -// //ctx.Translate (scrollX, scrollY); -// -// if (clip != null) -// clip.Srcoll (this); -//// -//// //clip.stroke (ctx, Color.Green); -//// -////// if (scrollY < 0) -////// Debug.WriteLine (".."); -//// } -// -// -// -// if (child != null) -// child.Paint(ref ctx, clip); -// -// ctx.Restore(); -// } - } } diff --git a/src/OpenGL/QuadVAO.cs b/src/OpenGL/QuadVAO.cs new file mode 100644 index 00000000..374f2f71 --- /dev/null +++ b/src/OpenGL/QuadVAO.cs @@ -0,0 +1,45 @@ +using System; +using OpenTK; + +namespace go +{ + public class QuadVAO : VertexArrayObject + { + public QuadVAO (float x, float y, float width, float height):base( + new Vector2[] { + new Vector2 (x, y), + new Vector2 (x, y + height), + new Vector2 (x + width, y), + new Vector2 (x + width, y + height) + }, + new Vector2[] { + new Vector2 (0, 1), + new Vector2 (0, 0), + new Vector2 (1, 1), + new Vector2 (1, 0) + }, + new int[] { 0, 1, 2, 3 }) + { + + } + public QuadVAO (float x, float y, float width, float height, + float texX, float texY, float texW, float texH):base( + new Vector2[] { + new Vector2 (x, y), + new Vector2 (x, y + height), + new Vector2 (x + width, y), + new Vector2 (x + width, y + height) + }, + new Vector2[] { + new Vector2 (texX, texY+texH), + new Vector2 (texX, texY), + new Vector2 (texX+texW, texY+texH), + new Vector2 (texX+texW, texY) + }, + new int[] { 0, 1, 2, 3 }) + { + + } + } +} + diff --git a/src/OpenGL/Shader.cs b/src/OpenGL/Shader.cs new file mode 100644 index 00000000..cb8fe99c --- /dev/null +++ b/src/OpenGL/Shader.cs @@ -0,0 +1,237 @@ +using System; +using OpenTK.Graphics.OpenGL; +using System.Diagnostics; +using OpenTK; + +namespace go.GLBackend +{ + public class Shader : IDisposable + { + #region CTOR + public Shader () + { + Compile (); + } + #endregion + + + #region Sources + protected string _vertSource = @" + #version 130 + + precision highp float; + + uniform mat4 projection_matrix; + uniform mat4 modelview_matrix; + + in vec2 in_position; + + void main(void) + { + gl_Position = projection_matrix * modelview_matrix * vec4(in_position,0, 1); + }"; + + protected string _fragSource = @" + #version 130 + precision highp float; + + uniform vec4 color; + uniform bool stencilTest; + uniform sampler2D stencil; + uniform vec2 resolution; + + out vec4 out_frag_color; + + void main(void) + { + if (stencilTest) + { + vec2 uv = gl_FragCoord.xy/resolution; + vec4 s = texture( stencil, uv); + if (s.r == 0.0) + discard; + } + out_frag_color = color; + }"; + string _geomSource = ""; + #endregion + + #region Private and protected fields + protected int vsId, fsId, gsId, pgmId, savedPgmId = 0, + modelviewMatrixLocation, + projectionMatrixLocation, + colorLocation,stencilTestLocation,resolutionLocation; + + Matrix4 projectionMatrix, + modelviewMatrix; + #endregion + + + #region Public properties + public virtual string vertSource + { + get { return _vertSource;} + set { _vertSource = value; } + } + public virtual string fragSource + { + get { return _fragSource;} + set { _fragSource = value; } + } + public virtual string geomSource + { + get { return _geomSource; } + set { _geomSource = value; } + } + + public Matrix4 ProjectionMatrix{ + set { + projectionMatrix = value; + GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix); + } + } + public Matrix4 ModelViewMatrix { + set { + modelviewMatrix = value; + GL.UniformMatrix4 (modelviewMatrixLocation, false, ref modelviewMatrix); + } + } + + public Vector4 Color { + set {GL.Uniform4 (colorLocation, value);} + } + + public bool StencilTest { + set { + if (value) + GL.Uniform1 (stencilTestLocation, 1); + else + GL.Uniform1 (stencilTestLocation, 0); + } + } + + public Vector2 Resolution { + set { GL.Uniform2 (resolutionLocation, value); } + } + + #endregion + + #region Public functions + public virtual void Compile() + { + Dispose (); + + pgmId = GL.CreateProgram(); + + if (!string.IsNullOrEmpty(vertSource)) + { + vsId = GL.CreateShader(ShaderType.VertexShader); + compileShader(vsId, vertSource); + } + if (!string.IsNullOrEmpty(fragSource)) + { + fsId = GL.CreateShader(ShaderType.FragmentShader); + compileShader(fsId, fragSource); + + } + if (!string.IsNullOrEmpty(geomSource)) + { + gsId = GL.CreateShader(ShaderType.GeometryShader); + compileShader(gsId,geomSource); + } + + if (vsId != 0) + GL.AttachShader(pgmId, vsId); + if (fsId != 0) + GL.AttachShader(pgmId, fsId); + if (gsId != 0) + GL.AttachShader(pgmId, gsId); + + BindVertexAttributes (); + + GL.LinkProgram(pgmId); + GL.ValidateProgram(pgmId); + + string info; + GL.GetProgramInfoLog(pgmId, out info); + Debug.WriteLine(info); + + Enable (); + + GetUniformLocations (); + BindSamplesSlots (); + + Disable (); + } + protected virtual void BindVertexAttributes() + { + GL.BindAttribLocation(pgmId, 0, "in_position"); + } + protected virtual void GetUniformLocations() + { + projectionMatrixLocation = GL.GetUniformLocation(pgmId, "projection_matrix"); + modelviewMatrixLocation = GL.GetUniformLocation(pgmId, "modelview_matrix"); + colorLocation = GL.GetUniformLocation (pgmId, "color"); + stencilTestLocation = GL.GetUniformLocation (pgmId, "stencilTest"); + resolutionLocation = GL.GetUniformLocation (pgmId, "resolution"); + } + protected virtual void BindSamplesSlots(){ + GL.Uniform1(GL.GetUniformLocation (pgmId, "stencil"),0); + } + + public virtual void Enable(){ + GL.GetInteger (GetPName.CurrentProgram, out savedPgmId); + GL.UseProgram (pgmId); + } + public virtual void Disable(){ + GL.UseProgram (savedPgmId); + } + public static void Enable(Shader s) + { + if (s == null) + return; + s.Enable (); + } + public static void Disable(Shader s) + { + if (s == null) + return; + s.Disable (); + } + #endregion + + void compileShader(int shader, string source) + { + GL.ShaderSource(shader, source); + GL.CompileShader(shader); + + string info; + GL.GetShaderInfoLog(shader, out info); + Debug.WriteLine(info); + + int compileResult; + GL.GetShader(shader, ShaderParameter.CompileStatus, out compileResult); + if (compileResult != 1) + { + Debug.WriteLine("Compile Error!"); + Debug.WriteLine(source); + } + } + + #region IDisposable implementation + public void Dispose () + { + if (GL.IsProgram (pgmId)) + GL.DeleteProgram (pgmId); + + if (GL.IsShader (vsId)) + GL.DeleteShader (vsId); + if (GL.IsShader (fsId)) + GL.DeleteShader (fsId); + if (GL.IsShader (gsId)) + GL.DeleteShader (gsId); + } + #endregion + } +} + diff --git a/src/OpenGL/TexturedShader.cs b/src/OpenGL/TexturedShader.cs new file mode 100644 index 00000000..a410b16e --- /dev/null +++ b/src/OpenGL/TexturedShader.cs @@ -0,0 +1,65 @@ +using System; +using OpenTK.Graphics.OpenGL; + +namespace go.GLBackend +{ + public class TexturedShader : Shader + { + public TexturedShader () + { + vertSource = @" + #version 130 + + precision highp float; + + uniform mat4 projection_matrix; + uniform mat4 modelview_matrix; + + in vec2 in_position; + in vec2 in_tex; + out vec2 texCoord; + + + void main(void) + { + texCoord = in_tex; + gl_Position = projection_matrix * modelview_matrix * vec4(in_position,0, 1); + }"; + + fragSource = @" + #version 130 + precision highp float; + + uniform vec4 color; + uniform sampler2D tex; + uniform sampler2D stencil; + + in vec2 texCoord; + out vec4 out_frag_color; + + void main(void) + { +// vec4 s = texture( stencil, texCoord); +// if (s.r == 0) +// discard; + vec4 t = texture( tex, texCoord); + out_frag_color = t; + }"; + + Compile (); + + } + + protected override void BindVertexAttributes () + { + base.BindVertexAttributes (); + GL.BindAttribLocation(pgmId, 1, "in_tex"); + } + protected override void BindSamplesSlots () + { + GL.Uniform1(GL.GetUniformLocation (pgmId, "tex"),0); + GL.Uniform1(GL.GetUniformLocation (pgmId, "stencil"),1); + } + } +} + diff --git a/src/OpenGL/VertexArrayObject.cs b/src/OpenGL/VertexArrayObject.cs new file mode 100644 index 00000000..9b75af29 --- /dev/null +++ b/src/OpenGL/VertexArrayObject.cs @@ -0,0 +1,94 @@ +using System; +using OpenTK; +using OpenTK.Graphics.OpenGL; + +namespace go +{ + public class VertexArrayObject : IDisposable + { + public int vaoHandle, + positionVboHandle, + texVboHandle, + eboHandle; + + Vector2[] positionVboData; + public int[] indicesVboData; + Vector2[] texVboData; + + public VertexArrayObject (Vector2[] _positions, Vector2[] _texCoord, int[] _indices) + { + positionVboData = _positions; + texVboData = _texCoord; + indicesVboData = _indices; + + CreateVBOs (); + CreateVAOs (); + } + + void deleteVAOs() + { + GL.DeleteBuffer (positionVboHandle); + GL.DeleteBuffer (texVboHandle); + GL.DeleteBuffer (eboHandle); + GL.DeleteVertexArray (vaoHandle); + } + + void CreateVBOs() + { + positionVboHandle = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle); + GL.BufferData(BufferTarget.ArrayBuffer, + new IntPtr(positionVboData.Length * Vector2.SizeInBytes), + positionVboData, BufferUsageHint.StaticDraw); + + texVboHandle = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, texVboHandle); + GL.BufferData(BufferTarget.ArrayBuffer, + new IntPtr(texVboData.Length * Vector2.SizeInBytes), + texVboData, BufferUsageHint.StaticDraw); + // + eboHandle = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); + GL.BufferData(BufferTarget.ElementArrayBuffer, + new IntPtr(sizeof(uint) * indicesVboData.Length), + indicesVboData, BufferUsageHint.StaticDraw); + + GL.BindBuffer(BufferTarget.ArrayBuffer, 0); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); + } + + void CreateVAOs() + { + vaoHandle = GL.GenVertexArray(); + GL.BindVertexArray(vaoHandle); + + GL.EnableVertexAttribArray(0); + GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle); + GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, true, Vector2.SizeInBytes, 0); + + GL.EnableVertexAttribArray(1); + GL.BindBuffer(BufferTarget.ArrayBuffer, texVboHandle); + GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, true, Vector2.SizeInBytes, 0); + + GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); + + GL.BindVertexArray(0); + } + + public void Render(PrimitiveType _primitiveType){ + GL.BindVertexArray(vaoHandle); + GL.DrawElements(_primitiveType, indicesVboData.Length, + DrawElementsType.UnsignedInt, IntPtr.Zero); + GL.BindVertexArray (0); + } + + + #region IDisposable implementation + public void Dispose () + { + deleteVAOs (); + } + #endregion + } +} + diff --git a/src/OpenTKGameWindow.cs b/src/OpenTKGameWindow.cs index e4186dbd..df9cc903 100755 --- a/src/OpenTKGameWindow.cs +++ b/src/OpenTKGameWindow.cs @@ -31,7 +31,11 @@ namespace go // DisplayDevice.Default, // 3,0,OpenTK.Graphics.GraphicsContextFlags.Default) public OpenTKGameWindow(int _width, int _height, string _title="golib") - : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 8), _title) + : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 0), + _title,GameWindowFlags.Default,DisplayDevice.Default, + 3,2,OpenTK.Graphics.GraphicsContextFlags.Debug|OpenTK.Graphics.GraphicsContextFlags.ForwardCompatible) +// public OpenTKGameWindow(int _width, int _height, string _title="golib") +// : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 8), _title) { VSync = VSyncMode.On; } @@ -89,13 +93,32 @@ namespace go #endregion #region graphic contexte + bool recreateContext = true; + Context ctx; Surface surf; byte[] bmp; int texID; - int dispList; + + QuadVAO uiQuad; + go.GLBackend.Shader shader; + Matrix4 projectionMatrix, + modelviewMatrix; + Rectangle dirtyZone = Rectangle.Empty; + void createContext() + { + createOpenGLSurface (); + if (uiQuad != null) + uiQuad.Dispose (); + uiQuad = new QuadVAO (0, 0, ClientRectangle.Width, ClientRectangle.Height,0,1,1,-1); + projectionMatrix = Matrix4.CreateOrthographicOffCenter + (0, ClientRectangle.Width, ClientRectangle.Height, 0, 0, 1); + modelviewMatrix = Matrix4.Identity; + redrawClip.AddRectangle (ClientRectangle); + recreateContext = false; + } void createOpenGLSurface() { currentWindow = this; @@ -103,10 +126,6 @@ namespace go int stride = 4 * ClientRectangle.Width; int bmpSize = Math.Abs (stride) * ClientRectangle.Height; bmp = new byte[bmpSize]; - //bmp = Enumerable.Repeat((byte)0, bmpSize).ToArray(); - - if (dispList > 0) - GL.DeleteLists (dispList, 1); //create texture if (texID > 0) @@ -126,78 +145,22 @@ namespace go } void OpenGLDraw() { + shader.Enable (); + shader.ProjectionMatrix = projectionMatrix; + shader.ModelViewMatrix = modelviewMatrix; + shader.Color = new Vector4(1f,1f,1f,1f); //if (dirtyZone != Rectangle.Empty) { - GL.BindTexture (TextureTarget.Texture2D, texID); - GL.TexSubImage2D (TextureTarget.Texture2D, 0, - 0, 0, ClientRectangle.Width, ClientRectangle.Height, + GL.ActiveTexture (TextureUnit.Texture0); + GL.BindTexture (TextureTarget.Texture2D, texID); + GL.TexSubImage2D (TextureTarget.Texture2D, 0, + 0, 0, ClientRectangle.Width, ClientRectangle.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmp); -// GL.TexSubImage2D (TextureTarget.Texture2D, 0, -// dirtyZone.X, dirtyZone.Y, ClientRectangle.Width, dirtyZone.Height, -// OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmp); - // dirtyZone = Rectangle.Empty; -// if (dispList > 0) -// GL.DeleteLists (dispList, 1); - //surf.WriteToPng (@"/home/jp/test.png"); - //} - -// if (dispList > 0) { -// GL.CallList (dispList); -// return; -// } -// -// dispList = GL.GenLists (1); -// GL.NewList (dispList, ListMode.CompileAndExecute); -// { - GL.Viewport(0, 0, ClientRectangle.Width, ClientRectangle.Height); - GL.PushAttrib (AttribMask.EnableBit); - GL.Color4 (Color.White); - GL.ActiveTexture (TextureUnit.Texture0); - GL.BindTexture (TextureTarget.Texture2D, texID); - GL.Enable (EnableCap.Texture2D); - - GL.MatrixMode (MatrixMode.Modelview); - - GL.PushMatrix (); - GL.LoadIdentity (); - - GL.MatrixMode (MatrixMode.Projection); - - GL.PushMatrix (); - GL.LoadIdentity (); - - Matrix4 ortho2D = Matrix4.CreateOrthographicOffCenter - (ClientRectangle.Left, ClientRectangle.Right, ClientRectangle.Bottom, ClientRectangle.Top, 0, 1); - GL.LoadMatrix (ref ortho2D); - - GL.Disable (EnableCap.Lighting); - GL.Enable (EnableCap.AlphaTest); - GL.AlphaFunc (AlphaFunction.Greater, 0.0f); - GL.Enable (EnableCap.Blend); - GL.BlendFunc (BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); - - GL.Begin (PrimitiveType.Quads); - { - GL.TexCoord2 (0, 0); - GL.Vertex2 (ClientRectangle.Left, ClientRectangle.Top); - GL.TexCoord2 (0, 1); - GL.Vertex2 (ClientRectangle.Left, ClientRectangle.Bottom); - GL.TexCoord2 (1, 1); - GL.Vertex2 (ClientRectangle.Right, ClientRectangle.Bottom); - GL.TexCoord2 (1, 0); - GL.Vertex2 (ClientRectangle.Right, ClientRectangle.Top); - } - GL.End (); - - GL.PopMatrix (); - - GL.MatrixMode (MatrixMode.Modelview); - GL.PopMatrix (); - GL.PopAttrib (); + uiQuad.Render (PrimitiveType.TriangleStrip); -// } -// GL.EndList (); + GL.BindTexture(TextureTarget.Texture2D, 0); + shader.Disable (); } #endregion @@ -312,11 +275,8 @@ namespace go protected override void OnRenderFrame(FrameEventArgs e) { base.OnRenderFrame(e); - if (recreateContext) { - createOpenGLSurface (); - redrawClip.AddRectangle (ClientRectangle); - recreateContext = false; - } + if (recreateContext) + createContext (); OpenGLDraw (); } protected override void OnLoad(EventArgs e) @@ -337,19 +297,19 @@ namespace go Console.WriteLine("GLSL version: " + GL.GetString (StringName.ShadingLanguageVersion)); Console.WriteLine("*************************************\n"); - createOpenGLSurface (); - } - protected override void OnUnload(EventArgs e) - { - if (dispList > 0) - GL.DeleteLists (dispList, 1); + int matl = GL.GetInteger (GetPName.MaxArrayTextureLayers); + int mts = GL.GetInteger (GetPName.MaxTextureSize); + shader = new go.GLBackend.TexturedShader (); + } + protected override void OnUnload(EventArgs e) + { if (texID > 0) GL.DeleteTexture (texID); //ctx.Dispose (); - surf.Dispose (); - } - bool recreateContext=true; - protected override void OnResize(EventArgs e) + //surf.Dispose (); + } + + protected override void OnResize(EventArgs e) { base.OnResize (e); recreateContext = true; -- 2.47.3