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; using System.Runtime.InteropServices; namespace OpenGL3_TransformFeedback { public partial class Form1 : Form { delegate void glTransformFeedbackVaryings(int program, int count, IntPtr[] varyings, TransformFeedbackMode bufferMode); static glTransformFeedbackVaryings TransformFeedbackVaryings; private int VS_ID; private int GS_ID; private int FS_ID; private int Program_ID; private int PMatLocation; private int MVMatLocation; private int TFActiveLocation; private Matrix4 ProjectionMatrix; private Matrix4 ModelViewMatrix; private int QueryFeedback_ID; private int QueryGenerated_ID; private int[] VBO_FeedBack = new int[2]; private float[] Triangle_Vertex = new float[] { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f }; private int currentTFBuffer = 0; private int prim_written; private int prim_generated; #region ShaderSource private string VSsource = @" #version 150 in vec3 position; out vec4 vPosition; void main(void) { vPosition = vec4(position, 1.0); } "; private string GSsource = @" #version 150 layout(triangles) in; layout(triangle_strip, max_vertices = 12) out; uniform mat4 ProjectionMatrix; uniform mat4 ModelViewMatrix; uniform int TFActive; in Input { vec4 vPosition; } VSout[3]; out vec3 Feedback; void main(void) { if(TFActive == 0) { mat4 PMVMatrix = ProjectionMatrix * ModelViewMatrix; for(int i = 0; i < 3; i++) { gl_Position = PMVMatrix * VSout[i].vPosition; EmitVertex(); } EndPrimitive(); } else { for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { Feedback = (VSout[i].vPosition.xyz + VSout[j].vPosition.xyz) / 2; EmitVertex(); } EndPrimitive(); } Feedback = (VSout[0].vPosition.xyz + VSout[1].vPosition.xyz) / 2; EmitVertex(); Feedback = (VSout[1].vPosition.xyz + VSout[2].vPosition.xyz) / 2; EmitVertex(); Feedback = (VSout[2].vPosition.xyz + VSout[0].vPosition.xyz) / 2; EmitVertex(); EndPrimitive(); } } "; private string FSsource = @" #version 150 out vec4 out_FragColor; void main(void) { out_FragColor = vec4(0.0, 1.0, 0.0, 1.0); } "; #endregion Shader public Form1() { InitializeComponent(); InitializeGL(); } private void InitializeGL() { //CGLControl is a CustomGLControl. 480x320 CGLControl.MakeCurrent(); TransformFeedbackVaryings = (glTransformFeedbackVaryings)Marshal.GetDelegateForFunctionPointer( (OpenTK.Graphics.GraphicsContext.CurrentContext as IGraphicsContextInternal).GetAddress("glTransformFeedbackVaryings"), typeof(glTransformFeedbackVaryings) ); GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); GL.Enable(EnableCap.DepthTest); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); GL.GenBuffers(2, VBO_FeedBack); GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_FeedBack[0]); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(49152 * 3 * sizeof(float)), Triangle_Vertex, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_FeedBack[1]); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(49152 * 3 * sizeof(float)), IntPtr.Zero, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); prim_written = 1; CreateShaders(VSsource, GSsource, FSsource, out VS_ID, out GS_ID, out FS_ID, out Program_ID); PMatLocation = GL.GetUniformLocation(Program_ID, "ProjectionMatrix"); MVMatLocation = GL.GetUniformLocation(Program_ID, "ModelViewMatrix"); TFActiveLocation = GL.GetUniformLocation(Program_ID, "TFActive"); GL.GenQueries(1, out QueryFeedback_ID); GL.GenQueries(1, out QueryGenerated_ID); GL.Viewport(0, 0, CGLControl.Width, CGLControl.Height); ProjectionMatrix = Matrix4.CreatePerspectiveOffCenter(-1.5f, 1.5f, -1.0f, 1.0f, 3.0f, 100.0f); GL.UniformMatrix4(PMatLocation, false, ref ProjectionMatrix); ModelViewMatrix = Matrix4.Identity; } private void CreateShaders(string vs, string gs, string fs, out int vertexObject, out int geometryObject, out int fragmentObject, out int program) { int status_code; string info; vertexObject = GL.CreateShader(ShaderType.VertexShader); geometryObject = GL.CreateShader(ShaderType.GeometryShader); 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(geometryObject, gs); GL.CompileShader(geometryObject); GL.GetShaderInfoLog(geometryObject, out info); GL.GetShader(geometryObject, 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, geometryObject); GL.AttachShader(program, vertexObject); GL.BindAttribLocation(program, 0, "position"); IntPtr varyings = Marshal.StringToHGlobalAnsi("Feedback"); IntPtr[] IPArray_vars = new IntPtr[] { varyings }; TransformFeedbackVaryings(program, 1, IPArray_vars, TransformFeedbackMode.SeparateAttribs); //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) { throw new ApplicationException(info); } GL.UseProgram(program); } private void TransformFeedbackTest() { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); ModelViewMatrix = Matrix4.Identity; ModelViewMatrix = Matrix4.Mult(Matrix4.LookAt(new Vector3(0, 0, 4), new Vector3(0, 0, 0), new Vector3(0, 1, 0)), ModelViewMatrix); GL.UniformMatrix4(MVMatLocation, false, ref ModelViewMatrix); GL.EnableVertexAttribArray(0); { //Draw current vertices GL.Uniform1(TFActiveLocation, 0); GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_FeedBack[currentTFBuffer]); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, IntPtr.Zero); GL.DrawArrays(BeginMode.Triangles, 0, prim_written * 3); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); //TransformFeedback GL.Uniform1(TFActiveLocation, 1); GL.BindBufferBase(BufferTarget.TransformFeedbackBuffer, 0, VBO_FeedBack[1 - currentTFBuffer]); GL.Enable(EnableCap.RasterizerDiscard); GL.BeginTransformFeedback(BeginFeedbackMode.Triangles); GL.BeginQuery(QueryTarget.PrimitivesGenerated, QueryGenerated_ID); GL.BeginQuery(QueryTarget.TransformFeedbackPrimitivesWritten, QueryFeedback_ID); { GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_FeedBack[currentTFBuffer]); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, IntPtr.Zero); GL.DrawArrays(BeginMode.Triangles, 0, prim_written * 3); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } GL.EndQuery(QueryTarget.TransformFeedbackPrimitivesWritten); GL.EndQuery(QueryTarget.PrimitivesGenerated); GL.EndTransformFeedback(); GL.Disable(EnableCap.RasterizerDiscard); GL.GetQueryObject(QueryFeedback_ID, GetQueryObjectParam.QueryResult, out prim_written); GL.GetQueryObject(QueryGenerated_ID, GetQueryObjectParam.QueryResult, out prim_generated); //Reset Vertices if (prim_written != prim_generated) { GL.BindBuffer(BufferTarget.ArrayBuffer, VBO_FeedBack[1 - currentTFBuffer]); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(49152 * 3 * sizeof(float)), Triangle_Vertex, BufferUsageHint.StaticDraw); prim_written = 1; } currentTFBuffer = 1 - currentTFBuffer; } GL.DisableVertexAttribArray(0); CGLControl.SwapBuffers(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { GL.DeleteQueries(1, ref QueryFeedback_ID); GL.DeleteQueries(1, ref QueryGenerated_ID); GL.DeleteBuffers(2, VBO_FeedBack); GL.DeleteProgram(Program_ID); GL.DeleteShader(FS_ID); GL.DeleteShader(VS_ID); } private void btnFeedback_Click(object sender, EventArgs e) { TransformFeedbackTest(); } } class CustomGLControl : OpenTK.GLControl { public CustomGLControl() : base(new GraphicsMode(32, 24, 0, 0, 0, 2), 3, 2, GraphicsContextFlags.ForwardCompatible) { } } }