Inagawa's picture

OpenGL not rendering untextured and textured shapes simultaneously

Hello all,

I have a VBO, sometimes I need to draw it with texture and sometimes just a color. I have no success drawing untextured AND textured shapes to the screen simultaneously.

Here is a short SSCCE:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
 
namespace E04w
{
    internal class Renderer
    {
        private readonly Int32 _vertexBufferId;
        private readonly Int32 _textureBufferId;
        private readonly Int32 _indexBufferId;
        private readonly Int32 _colorBufferId;
        private readonly Int32 _normalBufferId;
 
        private readonly Vector2[] _vertices;
        private readonly Vector2[] _textureCoordinates;
        private readonly Byte[] _indices;
        private readonly Vector4[] _colors;
        private readonly Vector3[] _normals;
 
        public Renderer()
        {
            // Create a vertex array
            _vertices = new Vector2[4];
 
            // Set the coordinate data
            _textureCoordinates = new Vector2[4];
            _textureCoordinates[0].X = 0.0f;
            _textureCoordinates[0].Y = 0.0f;
            _textureCoordinates[1].X = 1.0f;
            _textureCoordinates[1].Y = 0.0f;
            _textureCoordinates[2].X = 0.0f;
            _textureCoordinates[2].Y = 1.0f;
            _textureCoordinates[3].X = 1.0f;
            _textureCoordinates[3].Y = 1.0f;
 
            // Set the index data
            _indices = new Byte[6];
            _indices[0] = 0;
            _indices[1] = 1;
            _indices[2] = 3;
            _indices[3] = 3;
            _indices[4] = 2;
            _indices[5] = 0;
 
            // Set the color data
            _colors = new Vector4[4];
            _colors[0] = new Vector4(1.0f, 0.0f, 0.0f, 1.0f);
            _colors[1] = new Vector4(1.0f, 1.0f, 0.0f, 1.0f);
            _colors[2] = new Vector4(0.0f, 1.0f, 0.0f, 1.0f);
            _colors[3] = new Vector4(0.0f, 0.0f, 1.0f, 1.0f);
 
            // Set the normal data
            _normals = new Vector3[4];
            _normals[0] = new Vector3(0.0f, 0.0f, 1.0f);
            _normals[1] = new Vector3(0.0f, 0.0f, 1.0f);
            _normals[2] = new Vector3(0.0f, 0.0f, 1.0f);
            _normals[3] = new Vector3(0.0f, 0.0f, 1.0f);
 
            // Bind the texture array buffer
            GL.GenBuffers(1, out _textureBufferId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, _textureBufferId);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_textureCoordinates.Length * Vector2.SizeInBytes),
                          _textureCoordinates, BufferUsageHint.DynamicDraw);
            GL.TexCoordPointer(2, TexCoordPointerType.Float, 8, IntPtr.Zero);
            GL.EnableClientState(ArrayCap.TextureCoordArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 
            // Bind the normal array buffer
            GL.GenBuffers(1, out _normalBufferId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, _normalBufferId);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_normals.Length * Vector3.SizeInBytes), _normals,
                          BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 
            // Bind the color array buffer
            GL.GenBuffers(1, out _colorBufferId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, _colorBufferId);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_colors.Length * Vector4.SizeInBytes), _colors,
                          BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 
            // Bind vertex array buffer
            GL.GenBuffers(1, out _vertexBufferId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferId);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_vertices.Length * Vector2.SizeInBytes), _vertices,
                          BufferUsageHint.StreamDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 
            // Bind index array buffer
            GL.GenBuffers(1, out _indexBufferId);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBufferId);
            GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(_indices.Length * sizeof(Byte)), _indices,
                          BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
        }
 
        public void DrawQuad(Int32 x, Int32 y, Int32 width, Int32 height)
        {
            UpdateQuadVertices(x, y, width, height);
 
            GL.Disable(EnableCap.Texture2D);
            GL.BindTexture(TextureTarget.Texture2D, 0);
 
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.EnableClientState(ArrayCap.ColorArray);
            GL.EnableClientState(ArrayCap.NormalArray);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferId);
            GL.VertexPointer(2, VertexPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _colorBufferId);
            GL.ColorPointer(4, ColorPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _normalBufferId);
            GL.NormalPointer(NormalPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _textureBufferId);
            GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBufferId);
 
            GL.DrawElements(BeginMode.Triangles, _indices.Length, DrawElementsType.UnsignedByte, 0);
        }
 
        public void DrawQuadTex(Int32 x, Int32 y, Int32 width, Int32 height, Int32 textureId)
        {
            UpdateQuadVertices(x, y, width, height);
 
            GL.Enable(EnableCap.Texture2D);
            GL.BindTexture(TextureTarget.Texture2D, textureId);
 
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.EnableClientState(ArrayCap.ColorArray);
            GL.EnableClientState(ArrayCap.NormalArray);
            GL.EnableClientState(ArrayCap.TextureCoordArray);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferId);
            GL.VertexPointer(2, VertexPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _colorBufferId);
            GL.ColorPointer(4, ColorPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _normalBufferId);
            GL.NormalPointer(NormalPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _textureBufferId);
            GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, IntPtr.Zero);
 
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBufferId);
 
            GL.DrawElements(BeginMode.Triangles, _indices.Length, DrawElementsType.UnsignedByte, 0);
        }
 
        internal void UpdateQuadVertices(Int32 x, Int32 y, Int32 width, Int32 height)
        {
            _vertices[0].X = x;
            _vertices[0].Y = y;
            _vertices[1].X = x + width;
            _vertices[1].Y = y;
            _vertices[2].X = x;
            _vertices[2].Y = y + height;
            _vertices[3].X = x + width;
            _vertices[3].Y = y + height;
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferId);
            GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, (IntPtr)(_vertices.Length * Vector2.SizeInBytes),
                             _vertices);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
 
        public Int32 LoadSimpleTexture()
        {
            Int32 textureObjectId;
 
            GL.GenTextures(1, out textureObjectId);
            GL.BindTexture(TextureTarget.Texture2D, textureObjectId);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter,
                            (Int32)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter,
                            (Int32)TextureMagFilter.Linear);
 
            var bitmap = new Bitmap("simple.png");
            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                                              ImageLockMode.ReadOnly,
                                              System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
                          OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
 
            bitmap.UnlockBits(data);
 
            return textureObjectId;
        }
    }
 
 
    class Program
    {
        static void Main()
        {
            Int32 textureObjectId = 0;
 
            using (var gameWindow = new GameWindow(800, 600))
            {
                var renderer = new Renderer();
                gameWindow.Load += (s, e) =>
                                       {
                                           GL.ClearColor(Color.CornflowerBlue);
                                           GL.Enable(EnableCap.Blend);
                                           GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                                           GL.AlphaFunc(AlphaFunction.Greater, 1.0f);
 
                                           textureObjectId = renderer.LoadSimpleTexture();
 
                                       };
                gameWindow.Resize += (s, e) =>
                                         {
                                             GL.Viewport(0, 0, 800, 600);
                                             GL.MatrixMode(MatrixMode.Projection);
                                             GL.LoadIdentity();
                                             GL.Ortho(0, 800, 600, 0, -1, 1);
                                         };
                gameWindow.RenderFrame += (s, e) =>
                                              {
                                                  GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
                                                  renderer.DrawQuad(0, 0, 128, 128);
                                                  renderer.DrawQuadTex(128, 0, 128, 128, textureObjectId);
 
                                                  renderer.DrawQuad(256, 0, 128, 128);
                                                  renderer.DrawQuadTex(256*128, 0, 128, 128, textureObjectId);
 
                                                  renderer.DrawQuad(512, 0, 128, 128);
                                                  renderer.DrawQuadTex(512+128, 0, 128, 128, textureObjectId);
 
                                                  gameWindow.SwapBuffers();
 
                                                  Thread.Sleep(1000);
                                              };
                gameWindow.Keyboard.KeyDown += (s, e) =>
                                                   {
                                                       if (e.Key == Key.Escape)
                                                       {
                                                           gameWindow.Exit();
                                                       }
                                                   };
 
                gameWindow.Run();
            }
 
        }
    }
}

With the code as above, only the first frame has both shapes and all the subsequent frames have only the shape that gets called first (i.e. if I call DrawQuad and then DrawQuadTex, only untextured quads will be visible in the next frames).

Can anyone tell me what I'm doing wrong? Thanks a lot for any help


Comments

Comment viewing options

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

EnableCap.ColorMaterial -> GL.Color***
EnableCap.Lighting -> GL.Normal***
EnableCap.Texture2D -> GL.TexCoord***

http://www.glprogramming.com/red/chapter05.html

Inagawa's picture

Could you elaborate a bit on that? I have added those EnableCaps to the Load event of GameWindow and the Color, Normal and TexCoord pointers are already set in the example above and the textured quad is still visible only in the first frame. I will read the tutorial, just wanted to ask the obvious things first.

Inagawa's picture

Well, I have looked through the tutorial and I have no idea what that has to do with my problem. It's not as if I cannot see anything, I just don't understand why I'm able to see this:

A screencap of my program

Inertia's picture

You are using "fixed function pipeline" (as opposed to shaders) which uses whatever states you enabled when you call GL.Draw***. Blending, lighting, fog, textures it's all in the Red Book.