Question

Lately I have been trying to learn/use OpenGL 3+. I have looked through tutorials and examples but I've run into a wall trying to get textures and 2D projection to work without problems.

The goal for now is to have a function which can draw a textured quad to the screen with it's position specified by pixels (not [-1,1]).

For readability and testing I made a new barebones program with the knowledge I currently have, and it exhibits nearly the same problems. Help would be appreciated since i'm starting to go bald over this :(..

The current code shows a garbled texture instead of the image itself (texture is 128x128px).

enter image description here

[Program.cs]

namespace OpenGLTester
{
    static class Program
    {
        public static GameWindow window;
        public static String programDirectory = Directory.GetCurrentDirectory();
        public static int testTexture;
        public static int uniform_fragment_texture;
        public static int shaderProgram;

        [STAThread]
        static void Main()
        {
            window = new GameWindow(1024, 768, new GraphicsMode(new ColorFormat(8, 8, 8, 8), 0, 8), "OpenGLTester", GameWindowFlags.Default, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Default);
            GL.Viewport(new Size(1024,768));

            shaderProgram = GL.CreateProgram();
            int vertexShader = GL.CreateShader(ShaderType.VertexShader);
            int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);

            GL.ShaderSource(vertexShader, File.ReadAllText(programDirectory + @"\vertex.vert"));
            GL.ShaderSource(fragmentShader, File.ReadAllText(programDirectory + @"\fragment.frag"));

            GL.CompileShader(vertexShader);
            GL.CompileShader(fragmentShader);

            GL.AttachShader(shaderProgram, vertexShader);
            GL.AttachShader(shaderProgram, fragmentShader);
            GL.LinkProgram(shaderProgram);

            if (GL.GetError() != ErrorCode.NoError) { System.Diagnostics.Debugger.Break(); }

            Console.WriteLine(GL.GetProgramInfoLog(shaderProgram));

            GL.UseProgram(shaderProgram);

            Matrix4 projectionMatrix = Matrix4.CreateOrthographic(1024, 768, 0, 1);

            GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "vertex_projection"), false, ref projectionMatrix);

            uniform_fragment_texture = GL.GetUniformLocation(shaderProgram, "fragment_texture");

            testTexture = loadTexture(programDirectory + @"\test.png");

            GL.Disable(EnableCap.DepthTest);
            GL.Disable(EnableCap.Lighting);
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);

            window.UpdateFrame += window_UpdateFrame;
            window.RenderFrame += window_RenderFrame;
            window.Resize += window_Resize;

            window.TargetRenderFrequency = 60;
            window.Run();
        }

        static void window_Resize(object sender, EventArgs e)
        {
            //Don't allow resizing for now.
            window.Size = new Size(1024, 768);
        }

        static void window_UpdateFrame(object sender, FrameEventArgs e)
        {
            ErrorCode currentError = GL.GetError();
            if (currentError != ErrorCode.NoError)
            {
                Console.WriteLine(Enum.GetName(typeof(ErrorCode), currentError));
                System.Diagnostics.Debugger.Break();
            }
        }

        static void window_RenderFrame(object sender, FrameEventArgs e)
        {
            GL.ClearColor(0, 0, 0, 0);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);

            //test texture is 128x128pixels.
            drawTexRect(100, 228, 100, 228, testTexture);

            window.SwapBuffers();
        }

        static int loadTexture(String filePath)
        {
            GL.Enable(EnableCap.Texture2D);
            int id = GL.GenTexture();

            GL.ActiveTexture(TextureUnit.Texture0);
            GL.BindTexture(TextureTarget.Texture2D, id);

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 0);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

            Bitmap bmp = new Bitmap(filePath);
            BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
                OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, bmp_data.Scan0);

            bmp.UnlockBits(bmp_data);
            bmp.Dispose();

            return id;
        }

        static void drawTexRect(float top, float bottom, float left, float right, int texture)
        {
            //topLeft,bottomLeft,bottomRight,topRight

            float[] vertices = new float[] {
               left, top, 0, 0,
               left, bottom, 0, 1,
               right, bottom, 1, 1,
               right, top, 1, 0,
            };

            int buffer = GL.GenBuffer();

            GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
            GL.BufferData<float>(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);

            //vec2 - screen position
            GL.EnableVertexAttribArray(0);
            GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4, 0);

            //vec2 - texture coordinates
            GL.EnableVertexAttribArray(1);
            GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4, 2 * sizeof(float));

            GL.Enable(EnableCap.Texture2D);
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.BindTexture(TextureTarget.Texture2D, texture);
            GL.Uniform1(uniform_fragment_texture, 0);

            GL.DrawArrays(PrimitiveType.Quads, 0, 4);
            GL.DeleteBuffer(buffer);
        }
    }
}

[vertex.vert]

#version 330

in vec2 vertex_position;
in vec2 vertex_texturePosition;

uniform mat4 vertex_projection;

out vec2 fragment_texturePosition;

void main()
{
    gl_Position = vec4(vertex_position,0.0,1.0) * vertex_projection;

    fragment_texturePosition = vertex_texturePosition;
}

[fragment.frag]

#version 330

in vec2 fragment_texturePosition;

uniform sampler2D fragment_texture;

out vec4 output_color;

void main()
{
    output_color = texture(fragment_texture,fragment_texturePosition);
}

After changes suggested by @j-p one problem remains:

enter image description here

After texture position change suggested by @j-p:

The projection is also wrong given the position i expect it to be 100 px from the left and 100 px from the top, don't see how i can fix this..

Was it helpful?

Solution

The stride parameter is in byte:

GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);

//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));

Also,the corresponding opengl pixel format for windows argb bitmap is BGRA. (link)

GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,**OpenTK.Graphics.OpenGL.PixelFormat.Bgra**, PixelType.UnsignedByte, data.Scan0);

And finally, your texture coordinates should be adjusted as follow:

        float[] vertices = new float[] {
           left, top, 0, 1,
           left, bottom, 0, 0,
           right, bottom, 1, 0,
           right, top, 1, 1
        };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top