[2D/C#] Getting texturing to mount onto a 50x50 rectangle using glRectf()?

I have been working on a side-scrolling 2D demo that uses glOrtho2D(). On the screen are four rectangles (Box user-datatype) with three shaped as long rectangles (Box1, Box2, Box3), and the player object (PC) is shaped as a red square, all using glRectf(). I decided it’s time to apply a simple 50x50 texture onto the PC object. Everything executes, but the texture doesn’t show up. I know the texture is found due to some testing. How do I mount my texture onto my 50x50 rectangle using glRectf()? I’m assuming my small understanding of texturing is what’s causing the problem. It could be a simple mistake. Please let me know, thanks!

Form1.cs:

  
#region Using Clauses
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using Tao.OpenGl;
using Tao.FreeGlut;
using Tao.OpenAl;
#endregion

namespace Form_Practice
{
    public partial class Form1 : Form
    {
        private static bool[] keys = new bool[256];
        private Tao.Platform.Windows.SimpleOpenGlControl cntrl;
        private System.Timers.Timer timer1; 
        Box PC, Box1, Box2, Box3;
        private const float speed = 0.7f;
        private bool active = true;
        private int[] texture = new int[1];

        public Form1()
        {
            InitializeComponent();
            this.ClientSize = new Size(800, 600);
            cntrl.KeyDown += new KeyEventHandler(cntrl_KeyDown);
            cntrl.KeyUp += new KeyEventHandler(cntrl_KeyUp);
            cntrl.Click += new EventHandler(cntrl_Click);
            this.Activated += new EventHandler(Form1_Activated);
            this.Deactivate += new EventHandler(Form1_Deactivate);
            
            PC = new Box(350, 200, 50, 50, 1.0f, 0.0f, 0.0f);
            Box1 = new Box(50, 50, 550, 50, 0.0f, 1.0f, 0.0f);
            Box2 = new Box(50, 300, 550, 50, 0.0f, 1.0f, 0.0f);
            Box3 = new Box(550, 300, 50, 900, 0.0f, 1.0f, 0.0f);  
        }

        /// <summary>
        /// Window closed, deallocate files here.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e); 
        }

        /// <summary>
        /// Window Deactivated  
        /// </summary> 
        void Form1_Deactivate(object sender, EventArgs e)
        {
            this.active = false;
        }

        /// <summary>
        /// Window Activated
        /// </summary> 
        void Form1_Activated(object sender, EventArgs e)
        {
            this.active = true;
        }
 
        /// <summary>
        /// Submit Button
        /// </summary> 
        private void btnSubmit_Click(object sender, EventArgs e)
        {
        } 

        /// <summary>
        /// OpenGL control clicked for focus
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cntrl_Click(object sender, EventArgs e)
        {
            cntrl.Focus();
        }

        /// <summary>
        /// Key Up on OpenGL Control
        /// </summary> 
        void cntrl_KeyUp(object sender, KeyEventArgs e)
        {
            base.OnKeyDown(e);
            keys[e.KeyValue] = false; 
        }

        /// <summary>
        /// Key Down on OpenGL Control
        /// </summary> 
        void cntrl_KeyDown(object sender, KeyEventArgs e)
        {
            base.OnKeyDown(e);
            keys[e.KeyValue] = true; 
        }    

        /// <summary>
        /// Initializes OpenGL Control
        /// </summary> 
        private void cntrl_Load(object sender, System.EventArgs e)
        {
            if (!LoadGLTextures())
                Application.Exit();

            this.cntrl.InitializeContexts();

            Gl.glEnable(Gl.GL_TEXTURE_2D);
            Gl.glShadeModel(Gl.GL_SMOOTH);
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);

            Reshape(null, null); 
        }

        /// <summary>
        /// Timer1 Elapsed Time
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        { 
            this.cntrl.Invalidate();
        }

        /// <summary>
        /// Loads all OpenGL Textures.
        /// </summary>
        /// <returns></returns>
        public bool LoadGLTextures()
        {
            Bitmap[] textureImage = new Bitmap[1];
            bool status = false;

            textureImage[0] = Utilities.LoadBitmap("NeHe.Lesson06.NeHe.bmp");

            if (textureImage[0] != null)
            {
                status = true;

                Gl.glGenTextures(1, out texture[0]);

                textureImage[0].RotateFlip(RotateFlipType.RotateNoneFlipY);
                Rectangle rectangle = new Rectangle(0, 0, textureImage[0].Width, 
                    textureImage[0].Height);
                BitmapData bitmapData = textureImage[0].LockBits(rectangle,
                    ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]);
                Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB8, textureImage[0].Width,
                    textureImage[0].Height, 0, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);

                if (textureImage[0] != null)
                {
                    textureImage[0].UnlockBits(bitmapData);
                    textureImage[0].Dispose();
                }
            }

            return status;
        }

        /// <summary>
        /// OpenGL Control Reshape
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Reshape(object sender, EventArgs e) 
        { 
            if (cntrl.Height == 0)
                cntrl.Height = 1; 

            Gl.glViewport(0, 0, cntrl.Width, cntrl.Height);

            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();

            Glu.gluOrtho2D(0.0, cntrl.Width, cntrl.Height, 0.0);

            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity(); 
        }

        /// <summary>
        /// OpenGL Control Paint
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void cntrl_Paint(object sender, PaintEventArgs e)
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
            Gl.glLoadIdentity();

            if (!active)
                return;

            GetInput(); 

            Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); 

            Gl.glBegin(Gl.GL_QUADS);

                Gl.glTexCoord2f(0.0f, 0.0f); 
                Gl.glVertex2f(0.0f, 0.0f);
     
                Gl.glTexCoord2f(1.0f, 0.0f); 
                Gl.glVertex2f(1.0f, 0.0f);  

                Gl.glTexCoord2f(1.0f, 1.0f); 
                Gl.glVertex2f(1.0f, 1.0f);
     
                Gl.glTexCoord2f(0.0f, 1.0f); 
                Gl.glVertex2f(0.0f, 1.0f);

            Gl.glEnd();


            PC.Draw();

            Box1.Draw();
            Box2.Draw();
            Box3.Draw(); 

            cntrl.Invalidate();
        }

        /// <summary>
        /// Gets User Input
        /// </summary>
        public void GetInput()
        {
            if (keys[(int)Keys.D])
            {  
                Box1.X -= speed;
                Box2.X -= speed;
                Box3.X -= speed;
            }

            if (keys[(int)Keys.A])
            {  
                Box1.X += speed;
                Box2.X += speed;
                Box3.X += speed;
            }

            
            if (keys[(int)Keys.W])
            { 
                Box1.Y += speed;
                Box2.Y += speed;
                Box3.Y += speed;
            }

            if (keys[(int)Keys.S])
            { 
                Box1.Y -= speed;
                Box2.Y -= speed;
                Box3.Y -= speed;
            } 
        } 
    }
}

Utilities:

#region Using Clauses
using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using Tao.OpenGl;
using Tao.FreeGlut;
#endregion
 
namespace Form_Practice
{
    class Utilities
    {
        /// <summary>
        /// Loads a bitmap file.
        /// </summary>
        /// <param name="filename">The filename of the bitmap.</param>
        /// <returns>Returns a bitmap.</returns>
        public static Bitmap LoadBitmap(string filename)
        {
            if (filename == null &#0124;&#0124; filename == string.Empty)
                return null;

            string filename1 = string.Format("Data{0}{1}", 
                Path.DirectorySeparatorChar, filename);
            string filename2 = string.Format("{0}{1}{0}{1}Data{1}{2}", 
                "..", Path.DirectorySeparatorChar, filename);

            if (!File.Exists(filename) && !File.Exists(filename1) &&
                !File.Exists(filename2))
                return null;

            if (File.Exists(filename))
                return new Bitmap(filename);
            else if (File.Exists(filename1))
                return new Bitmap(filename1);
            else if (File.Exists(filename2))
                return new Bitmap(filename2);

            return null;
        } 
    }
}

Box.cs

#region Using Clauses
using System;
using System.Drawing;
using System.Windows.Forms;
using Tao.OpenGl;
using Tao.FreeGlut;
#endregion
 
namespace Form_Practice
{
    struct Box
    {
        public float X, Y, Width, Height, R, G, B;

        public Box(float x, float y, float width, float height, float r, 
            float g, float b)
        {
            this.X = x;
            this.Y = y;
            this.Width = width;
            this.Height = height;
            this.R = r;
            this.G = g;
            this.B = b;
        }

        public void Draw()
        {
            Gl.glColor3f(R, G, B);
            Gl.glRectf(X, Y, X + Width, Y + Height);
        }
    }
}

If you take a XML frame grab with GLIntercept (http://glintercept.nutty.org/) and post the results here, I can probably help you out.

Also take a look at the gliLog.txt to see if there is any errors.

Side note: I see you are not destroying the textures, but when you do ensure you don’t destroy them in a C# finalizer as this gets run on a seperate thread (which OpenGL is not current to) Use a IDispose type interface (or other method) to destroy them manually when they are no longer necessary. GLIntercept will help you find any leaks.

Just re-read your question, you can’t texture properly with glRectf() (without texture-gen or vertex program) So I suggest you do what you did above with the glBegin(GL_QUADS) and provide the texture coordinates.

Don’t forget to do a Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0); When done texturing. (Prefered way is to use glEnable(GL_TEXTURE_2D) when needed and call glDisable(GL_TEXTURE_2D) when done texturing)

Alright… I tried this but I’m still not seeing the texture on execution. I’m a little confused. GL_TEXTURE_2D is enabled, too. Also, how can I make sure this quad of 0.0’s and 1.0’s equal 50x50 pixels like i could specify for glRectf()? It’s necessary for my sprite map.

I’m suprised that I need to use 1.0’s and 0.0’s as well. With DirectX, that was only necessary if I was in world space (untransformed). With this being a 2D game demo, I would imagine that I’d be working in screen coordinates (transformed). Why does this differ with OpenGL? What’s the benefit? Forgive my OpenGL 101 questions lol.

Thanks…

            Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); 

            Gl.glBegin(Gl.GL_QUADS);

                Gl.glTexCoord2f(0.0f, 0.0f); 
                Gl.glVertex2f(0.0f, 0.0f);
     
                Gl.glTexCoord2f(1.0f, 0.0f); 
                Gl.glVertex2f(1.0f, 0.0f);  

                Gl.glTexCoord2f(1.0f, 1.0f); 
                Gl.glVertex2f(1.0f, 1.0f);
     
                Gl.glTexCoord2f(0.0f, 1.0f); 
                Gl.glVertex2f(0.0f, 1.0f);

            Gl.glEnd();

            Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);  

you do realise that you need a projection for 2D drawing? check out the redbook chapter on viewing and i think there’s something in the wiki about it. anyway it is very simple you just need the right projection to draw in 2d (glOrtho) :slight_smile:

hth

I am using gluOrtho2D() in my Reshape method above. On execution, the reshape method is called before rendering anything to the screen. Need I say, I can see my boxes on the screen (thus gluOrtho2D() did its job). I just don’t see my texture.

And can someone please explain why my textures need world coordinates for a transformed environment?

u just need to set your texcoords. each verttex needs texcoord assigned. opengl cant texture without texcoords so be sure to set them. no need to worry about world coords, just texcoords. like, no texcoords in glRect, so use quads. make any sense? i feel like i’m babbling.

hth

Thank you for wanting to help, although everything you mentioned is already in the code above. Did you look at it? What’s wrong with it is the question.

Unless you know for certain that your card supports RGB8 for the internal format parameter, then I’d suggest trying something different, probably starting with RGBA, or BGRA.

Failing that, try a single channel (greyscale) image, using the alpha, luminance, or chrominance internal formats.

Also, if your colours get swapped, it might be because you provide reversed data (BGR) in the format parameter when using non-reversed data in the internal format parameter - I’m not sure if swizzling is guaranteed…

“a simple 50x50 texture”

This will only work with GL_TEXTURE_2D targets on OpenGL implementations if the extension ARB_texture_non_power_of_two is listed in the extension string (glGetString(GL_EXTENSIONS).
http://www.opengl.org/registry/specs/ARB/texture_non_power_of_two.txt

Or if your OpenGL version is 2.0 because that functionality moved into the core, but if the extension is not advertised there, it’s not hardware accelerated, e.g GeForce 5xxx run that in SW, GeForce 6xxx and can do it HW. There is ARB_texture_rectangle as an alternative, but that needs unnormalized texcoords.

Change your bitmap so that textureImage[0].Width and textureImage[0].Height are power-of-twos.