jodev's picture

Porting C++ tutorial, triangle not showing up

Hi everyone,

I'm taking my first steps in OpenGl using Jason L. McKesson's tutorial (http://www.arcsynthesis.org/gltut/index.html). I'll have to admit that it is all pretty daunting to digest, but in general lines I understand the roles of the shaders and programs that the tutorial uses. I find the actual code conversion from C++ top OpenTK not difficult at all so far. However, I seem to have hit a snag in that my code works except for showing the triangle. The file that I am converting to C#/OpenTK is this one: https://bitbucket.org/alfonse/gltut/src/3ee6f3dd04a7/Tut%2001%20Hello%20... The code that I have converted it to is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
namespace GLTest
{
    class GLWindow : GameWindow
    {
        const string strVertexShader =
            "#version 330\n" +
            "layout(location = 0) in vec4 position;\n" +
            "void main()\n" +
            "{\n" +
            "   gl_Position = position;\n" +
            "}\n";
 
        const string strFragmentShader =
            "#version 330\n" +
            "out vec4 outputColor;\n" +
            "void main()\n" +
            "{\n" +
            "   outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n" +
            "}\n";
 
        private int vao;
        private int positionBufferObject;
        private int theProgram;
        private float[] vertexPositions = 
        {
            0.75f, 0.75f, 0.0f, 1.0f,
            0.75f, -0.75f, 0.0f, 1.0f,
            -0.75f, -0.75f, 0.0f, 1.0f,
        };
 
        static void Main(string[] args)
        {
            using (GLWindow wnd = new GLWindow(800, 600, GraphicsMode.Default, "Learning Modern 3D Graphics Programming"))
            {
                wnd.init();
                wnd.Run();
            }
        }
 
        public GLWindow(int width, int height, GraphicsMode mode, string title)
            : base(width, height, mode, title)
        { }
 
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            base.OnClosing(e);
 
            System.Diagnostics.Debug.WriteLine("Exiting program and releasing OpenGL resources...");
            GL.DeleteProgram(this.theProgram);
        }
 
        protected void init()
        {
            System.Diagnostics.Debug.WriteLine("Initializing OpenGL...");
 
            initializeProgram();
            initializeVertexBuffer();
 
            GL.GenVertexArrays(1, out this.vao);
            GL.BindVertexArray(this.vao);
 
            System.Diagnostics.Debug.WriteLine("Ready, entering the main loop...");
        }
 
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            GL.ClearColor(Color.CornflowerBlue);
            GL.Clear(ClearBufferMask.ColorBufferBit);
 
            GL.UseProgram(this.theProgram);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.positionBufferObject);
            GL.VertexAttribPointer(0, 4, VertexAttribPointerType.Float, false, 0, 0);
            GL.DrawArrays(BeginMode.Triangles, 0, 3);
 
            GL.DisableVertexAttribArray(0);
            GL.UseProgram(0);
 
            this.SwapBuffers();
        }
 
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            GL.Viewport(0, 0, this.Width, this.Height);
        }
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
        }
 
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);
        }
 
        protected void initializeVertexBuffer()
        {
            GL.GenBuffers(1, out this.positionBufferObject);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.positionBufferObject);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertexPositions.Length * sizeof(float)),
                vertexPositions, BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
 
        protected void initializeProgram()
        {
            List<uint> shaderList = new List<uint>();
 
            shaderList.Add(this.CreateShader(ShaderType.VertexShader, strVertexShader));
            shaderList.Add(this.CreateShader(ShaderType.FragmentShader, strFragmentShader));
 
            this.theProgram = this.CreateProgram(shaderList);
 
            foreach (uint shader in shaderList)
                GL.DeleteShader(shader);
        }
 
        protected uint CreateShader(ShaderType eShaderType, string strShaderFile)
        {
            int shader = GL.CreateShader(eShaderType);
            string strFileData = strShaderFile;
 
            GL.ShaderSource(shader, strFileData);
            GL.CompileShader(shader);
 
            int status;
            GL.GetShader(shader, ShaderParameter.CompileStatus, out status);
            if (status == 0)
            {
                int infoLogLength;
                GL.GetShader(shader, ShaderParameter.InfoLogLength, out infoLogLength);
 
                string strInfolog;
                GL.GetShaderInfoLog(shader, out strInfolog);
 
                string strShaderType = null;
                switch (eShaderType)
                {
                    case ShaderType.VertexShader: strShaderType = "vertex"; break;
                    case ShaderType.GeometryShader: strShaderType = "geometry"; break;
                    case ShaderType.FragmentShader: strShaderType = "fragment"; break;
                }
 
                System.Diagnostics.Debug.WriteLine("Compile failure in {0} shader:\n{1}\n", strShaderType, strInfolog);
            }
 
            return (uint)shader;
        }
 
        protected int CreateProgram(List<uint> shaderList)
        {
            int program = GL.CreateProgram();
 
            for (int iLoop = 0; iLoop < shaderList.Count; iLoop++)
                GL.AttachShader((uint)program, shaderList[iLoop]);
 
            GL.LinkProgram(program);
 
            int status;
            GL.GetProgram(program, ProgramParameter.LinkStatus, out status);
            if (status == 0)
            {
                string strInfoLog = GL.GetProgramInfoLog(program);
                System.Diagnostics.Debug.WriteLine("Linker failure: {0}", strInfoLog);
            }
 
            for (int iLoop = 0; iLoop < shaderList.Count; iLoop++)
            {
                GL.DetachShader((uint)program, shaderList[iLoop]);
            }
 
            return program;
        }
    }
}

My apologies for the long piece of code, but I honestly have no clue where I may have messed up. The CreateShader and CreateProgram methods are not reporting any issues and the OnRenderFrame method draws a beautiful cornflowerblue background. But no triangle... I have determined that the 'theProgram' field in the OnRenderFrame method is set (with a value of 3). I have also tried switching around the vertex position, figuring it may have been wound the wrong way.

Any clues as to what I may have missed? Thanks!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
jodev's picture

Okay, so this is a new day and after some extra strong morning coffee I went through the code again line by line and found the problem. I forgot to add GL.EnableVertexAttribArray(0); to the OnRenderFrame method. With that done it all works as expected.