using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using OpenTK.Platform; namespace OpenGL3_TransformFeedback { public partial class Form1 : Form { private int VS_ID; private int FS_ID; private int Program_ID; private int QueryFeedback_ID; private int QueryGenerated_ID; private int VBO_Object; private int VBO_FeedBack; private float[] Triangle_Vertex = new float[] { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f }; #region ShaderSource private string VSsource = @" #version 130 in vec3 position; out vec4 feedback; void main(void) { feedback = vec4(position, 1.0); gl_Position = vec4(position, 1.0); } "; private string FSsource = @" #version 130 in vec4 feedback; out vec4 out_FragColor; void main(void) { out_FragColor = feedback; } "; #endregion Shader public Form1() { InitializeComponent(); InitializeGL(); TransformFeedbackTest(); } private void InitializeGL() { //CGLControl is a CustomGLControl. 480x320 CGLControl.MakeCurrent(); GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); GL.Enable(EnableCap.DepthTest); CreateShaders(VSsource, FSsource, out VS_ID, out FS_ID, out Program_ID); BuildTriangle_VBO(); GL.GenQueries(1, out QueryFeedback_ID); GL.GenQueries(1, out QueryGenerated_ID); GL.GenBuffers(1, out VBO_FeedBack); GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_FeedBack); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(48 * 4 * sizeof(float)), IntPtr.Zero, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.Viewport(0, 0, CGLControl.Width, CGLControl.Height); } private void CreateShaders(string vs, string fs, out int vertexObject, out int fragmentObject, out int program) { int status_code; string info; vertexObject = GL.CreateShader(ShaderType.VertexShader); fragmentObject = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(vertexObject, vs); GL.CompileShader(vertexObject); GL.GetShaderInfoLog(vertexObject, out info); GL.GetShader(vertexObject, ShaderParameter.CompileStatus, out status_code); if (status_code != 1) { throw new ApplicationException(info); } GL.ShaderSource(fragmentObject, fs); GL.CompileShader(fragmentObject); GL.GetShaderInfoLog(fragmentObject, out info); GL.GetShader(fragmentObject, ShaderParameter.CompileStatus, out status_code); if (status_code != 1) { throw new ApplicationException(info); } program = GL.CreateProgram(); GL.AttachShader(program, fragmentObject); GL.AttachShader(program, vertexObject); GL.BindAttribLocation(program, 0, "position"); GL.TransformFeedbackVaryings(program, 1, new string[] { "feedback" }, TransformFeedbackMode.SeparateAttribs); GL.LinkProgram(program); GL.GetProgramInfoLog(program, out info); GL.GetProgram(program, ProgramParameter.LinkStatus, out status_code); if (status_code != 1) { //Error /* Link info --------- error: Varying (named feedback) specified but not present in the program object. */ throw new ApplicationException(info); } GL.UseProgram(program); } private void Form1_Resize(object sender, EventArgs e) { CGLControl.Size = new Size(this.ClientSize.Width, this.ClientSize.Height); GL.Viewport(0, 0, this.ClientSize.Width, this.ClientSize.Height); } private void TransformFeedbackTest() { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.EnableVertexAttribArray(0); { GL.BindBufferBase(BufferTarget.TransformFeedbackBuffer, 0, VBO_FeedBack); GL.Enable(EnableCap.RasterizerDiscard); GL.BeginTransformFeedback(BeginFeedbackMode.Points); GL.BeginQuery(QueryTarget.PrimitivesGenerated, QueryGenerated_ID); GL.BeginQuery(QueryTarget.TransformFeedbackPrimitivesWritten, QueryFeedback_ID); { GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_Object); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, IntPtr.Zero); GL.DrawArrays(BeginMode.Triangles, 0, 3); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } GL.EndQuery(QueryTarget.TransformFeedbackPrimitivesWritten); GL.EndQuery(QueryTarget.PrimitivesGenerated); GL.EndTransformFeedback(); GL.Disable(EnableCap.RasterizerDiscard); int prim_written = -1; int prim_generated = -1; GL.GetQueryObject(QueryFeedback_ID, GetQueryObjectParam.QueryResult, out prim_written); GL.GetQueryObject(QueryGenerated_ID, GetQueryObjectParam.QueryResult, out prim_generated); MessageBox.Show("TransformFeedbackPrimitivesWritten : " + prim_written.ToString() + "\r\nPrimitivesGenerated : " + prim_generated.ToString()); } GL.DisableVertexAttribArray(0); } private void BuildTriangle_VBO() { GL.GenBuffers(1, out VBO_Object); GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_Object); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(Triangle_Vertex.Length * sizeof(float)), Triangle_Vertex, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { GL.DeleteQueries(1, ref QueryFeedback_ID); GL.DeleteQueries(1, ref QueryGenerated_ID); GL.DeleteBuffers(1, ref VBO_FeedBack); GL.DeleteBuffers(1, ref VBO_Object); GL.DeleteProgram(Program_ID); GL.DeleteShader(FS_ID); GL.DeleteShader(VS_ID); } } class CustomGLControl : OpenTK.GLControl { public CustomGLControl() : base(new GraphicsMode(32, 24, 0, 0, 0, 2), 3, 0, GraphicsContextFlags.ForwardCompatible) { } } }