Unable to load 2D texture

Started by
12 comments, last by mr_mo 15 years, 9 months ago
Hi all, I have a code I put together from Nehe texture tutorial and glEnable2D and glDisable2D code snippets to try and learn how to do 2D in OpenGL. The problem is, for some reason, I keep getting just the Quad(white rect) and no texture. Here is the code(in C# but similar to C++): Initialize

        protected virtual void Initialize()
        {
            InitEvents();
            // Texture
            textureName = "011-PortTown01.png";
            // Set the Frames per second.
            Events.Fps = 60;
            // Sets Window icon and title
            this.SetWindowAttributes();
            // Creates SDL.NET Surface to hold an OpenGL scene
            screen = Video.SetVideoMode(width, height, true, true, false, true);
            // Reset The Current Viewport
            Gl.glViewport(0, 0, width, height);
            // Load Textures
            LoadTextures();
            // Render Screen
            RenderScreen();
        }



LoadTexture

        /// <summary>
        /// Load Textures
        /// </summary>
        private void LoadTextures()
        {
            // Load Bitmap
            Bitmap textureImage = new Bitmap(textureName);
            // Check For Errors, If Bitmap's Not Found, Quit
            if (textureImage != null)
            {
                // Create The Texture
                Gl.glGenTextures(1,out texture);
                textureImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
                // Flip The Bitmap Along The Y-Axis
                // Rectangle For Locking The Bitmap In Memory
                Rectangle rectangle =
                    new Rectangle(0, 0, textureImage.Width, textureImage.Height);
                // Get The Bitmap's Pixel Data From The Locked Bitmap
                BitmapData bitmapData =
                    textureImage.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                // Typical Texture Generation Using Data From The Bitmap
                Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);
                Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB8, textureImage.Width, textureImage.Height, 0, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);
                // Fix image for resoulution
                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);
                Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
                Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
                // If Texture Exists
                if (textureImage != null)
                {
                    // Unlock The Pixel Data From Memory
                    textureImage.UnlockBits(bitmapData);
                    // Dispose The Bitmap
                    textureImage.Dispose();
                }

            }
        }




Render

        /// <summary>
        /// Render the screen.
        /// </summary>
        protected virtual void RenderScreen()
        {
            Gl.glEnable(Gl.GL_TEXTURE_2D);
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            Gl.glLoadIdentity();
            // Enable 2D
            Enable2D();
            // Create Texture
            Gl.glGenTextures(1, out texture);
            // Enable GL
            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_REPLACE);
            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_BLEND);
            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_MODULATE);
            Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);
            // Begin GL
            Gl.glBegin(Gl.GL_QUADS);
            // Upper Left Corner
            Gl.glTexCoord2d(0, 1024);
            Gl.glVertex2d(0, 0);
            // Lower Left Corner
            Gl.glTexCoord2d(0, 0);
            Gl.glVertex2d(0, 1024);
            // Upper Right Corner
            Gl.glTexCoord2d(256, 1024);
            Gl.glVertex2d(256, 0);
            // Lower Rigt Corner
            Gl.glTexCoord2d(256, 0);
            Gl.glVertex2d(256, 1024);
            // End
            Gl.glEnd();
            // Disable 2D
            Disable2D();
        }

Enable/Disable 2D Rendering

       /// <summary>
        /// Enables 2D Mode
        /// </summary>
        void Enable2D()
        {
            int[] vPort = new int[4];
            Gl.glGetIntegerv(Gl.GL_VIEWPORT, vPort);

            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glPushMatrix();
            Gl.glLoadIdentity();
            
            Gl.glOrtho(vPort[0], vPort[2], vPort[3], vPort[1], -1, 1);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glPushMatrix();
            Gl.glLoadIdentity();
        }
        /// <summary>
        /// Disables 2D Mode
        /// </summary>
        void Disable2D()
        {
            Gl.glMatrixMode(Gl.GL_PROJECTION);

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



That's all I have and I'm not sure what I'm doing wrong here.. [Edited by - mr_mo on June 26, 2008 12:44:40 PM]
Advertisement
First of all, do you realize that you can't load .png files when you call

Bitmap textureImage = new Bitmap(textureName);

Unless you are calling your texture loading lib Bitmap for all types?
// Begin GL
Gl.glBegin(Gl.GL_QUADS);
// Upper Left Corner
//Gl.glTexCoord2f(.25F, .125F);
//Gl.glVertex(0.0F, 30.0F, 0.0F);
Gl.glTexCoord2d(0, 1024);
Gl.glVertex2d(0, 0);
// End
Gl.glEnd();

texture coordinates are from 0 to 1. Did you really mean 1024 (repeated textures 1023 times)??

You only have on vertex being drawn for a quad that needs 4 vertcies?

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Thank you for your replies :).

Quote:Original post by MARS_999
First of all, do you realize that you can't load .png files when you call

Bitmap textureImage = new Bitmap(textureName);

Unless you are calling your texture loading lib Bitmap for all types?


I'm pretty sure it loads it. Its a .Net class(GDI+) and on top of that, I used it to paint on a form several times. Also, I've checked during debug mode to see if it loaded the pixels.

Quote:// Begin GL
Gl.glBegin(Gl.GL_QUADS);
// Upper Left Corner
//Gl.glTexCoord2f(.25F, .125F);
//Gl.glVertex(0.0F, 30.0F, 0.0F);
Gl.glTexCoord2d(0, 1024);
Gl.glVertex2d(0, 0);
// End
Gl.glEnd();

texture coordinates are from 0 to 1. Did you really mean 1024 (repeated textures 1023 times)??

You only have on vertex being drawn for a quad that needs 4 vertcies?


No, its seems i somehow deleted rest of the code >.<. My apologies. I've deleted the 3 other coordinates and didn't notice i guess. However, it didn't work with the other 3 corners.

Does Gl.glTexCoord2d(0, 1024) really load the texture 1023 times? The size of the image is (256,1024). So, I was under the impression that it positioned the lower left corner(x,y). I've read that texture coordinates must mirror vertex coordinates and so upper becomes lower and left becomes right, is this right?

I've updated my original post with correct code. I'm sorry for the confusion.
Quote:Original post by mr_mo
Quote:// Begin GL
Gl.glBegin(Gl.GL_QUADS);
// Upper Left Corner
//Gl.glTexCoord2f(.25F, .125F);
//Gl.glVertex(0.0F, 30.0F, 0.0F);
Gl.glTexCoord2d(0, 1024);
Gl.glVertex2d(0, 0);
// End
Gl.glEnd();

texture coordinates are from 0 to 1. Did you really mean 1024 (repeated textures 1023 times)??

You only have on vertex being drawn for a quad that needs 4 vertcies?


<snip>
I've read that texture coordinates must mirror vertex coordinates and so upper becomes lower and left becomes right, is this right?

No? They don't have to, and normally don't if you're trying to see your picture right-side-up. They can, but I don't think you want them to. You may be confusing this with window coordinates (in Windows) and OpenGL's coordinate systems, but that's only on the y axis.

Quote:I've updated my original post with correct code. I'm sorry for the confusion.

You don't seem to have fixed what dpadam450 pointed out - you really only want to use texture coordinates 0.0 and 1.0. These are the lower and upper values for either edge of your texture, OpenGL could (at this point) care less about what exact texels you want to see, it cares about what fraction of the texture you want to see. Normally, OpenGL will generate mipmaps for you, which throws the idea of "give me texel 'x,y'" right out the window. Instead, you want to say "give me region 'x/width,y/height' of my texture," which will apply the appropriate part of the texture to your primitive. As you can see, this number will usually be in the range 0..1 for values of x and y within the texture. However, specifying a larger number can have different effects. Depending on how you have things set up, it will either repeat the texture, or clamp the value to the edge of the texture. In the latter case, you'll end up with one tiny version of your texture in one corner (lower left if you haven't applied any transformations) with bands extending up and to the right containing the contents of the upper and right edges of the texture, respectively. Once you have it loading correctly, try changing the necessary parameters:
              Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP);    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP);
and you'll see what I mean.

Also, you don't want to call Gl.glGenTextures(1, out texture); every frame, just once when you're loading the texture. It makes space for a new texture object, so you're just leaving the one you already loaded in memory somewhere, and causing texture to point to a newly created empty blob of nothing.

So, for now, change to this and see if it works:
/// <summary>        /// Render the screen.        /// </summary>        protected virtual void RenderScreen()        {            Gl.glEnable(Gl.GL_TEXTURE_2D);            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);            Gl.glLoadIdentity();            // Enable 2D            Enable2D();            // Create Texture            // Note: this doesn't create a texture, just reserves space for one.              // since you never come back and create one, you're applying a blank texture.            // Gl.glGenTextures(1, out texture);            // Enable GL            // Note: these are for testing, I guess?  You don't need them here, especially since the first overrides the first two....            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_REPLACE);            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_BLEND);            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_MODULATE);            Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);            // Begin GL            Gl.glBegin(Gl.GL_QUADS);            // Upper Left Corner - (actually lower left, you seem to have flipped everything in Y)            Gl.glTexCoord2d(0, 0);            Gl.glVertex2d(0, 0);            // Upper Right Corner - (again, actually lower right)            Gl.glTexCoord2d(1, 0);            Gl.glVertex2d(256, 0);            // Lower Left Corner            // Does this winding produce a proper quad?  I've never tried drawing a quad out of order before...            // Usually, the ordering of vertices for a quad is to just trace around the perimeter counter-clockwise (in OpenGL)            // i.e. ll, lr, ur, ul            Gl.glTexCoord2d(0, 1);            Gl.glVertex2d(0, 1024);            // Lower Rigt Corner            Gl.glTexCoord2d(1, 0);            Gl.glVertex2d(256, 1024);            // End            Gl.glEnd();            // Disable 2D            Disable2D();        }

If it still doesn't work, try swapping the last two vertex/texcoord pairs to have the indicated winding. If it still doesn't work, post back! [smile]
Oh sorry, I didn't mean I corrected the code, just re-added the parts that were deleted.

So, I added the code you gave me, didn't work. Below is what I ended up with:

        protected virtual void RenderScreen()        {            // Enable GL            Gl.glEnable(Gl.GL_TEXTURE_2D);            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);            Gl.glLoadIdentity();            // Enable 2D            Enable2D();            // Add Texture            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_REPLACE);            Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);            // Begin GL            Gl.glBegin(Gl.GL_QUADS);            // i.e. ll, lr, ur, ul            // Lower Left Corner            Gl.glTexCoord2d(0, 1);            Gl.glVertex2d(0, 1024);            // Lower Rigt Corner            Gl.glTexCoord2d(1, 0);            Gl.glVertex2d(256, 1024);            // Upper Right Corner            Gl.glTexCoord2d(1, 0);            Gl.glVertex2d(256, 0);            // Upper Left Corner            Gl.glTexCoord2d(0, 0);            Gl.glVertex2d(0, 0);            // End            Gl.glEnd();            // Disable 2D            Disable2D();        }


Oh, and thanks for the heads up on the order of things. I knew there was a specific order, but I couldn't figure out what it was.
Quote:Original post by mr_mo
Oh sorry, I didn't mean I corrected the code, just re-added the parts that were deleted.

So, I added the code you gave me, didn't work.
By "didn't work," I assume you mean you got the same white quad?

Quote:Below is what I ended up with:

My fault on this one, I made a typo -
// Lower Rigt CornerGl.glTexCoord2d(1, 0);Gl.glVertex2d(256, 1024);should be // Lower Rigt CornerGl.glTexCoord2d(1, 1);Gl.glVertex2d(256, 1024);

I think I know now why you thought texcoords and vertices should be "mirrored" - because they should be in most cases! But not mirrored as in "flipped," mirrored as in "the same." So, when your x coord is at its max (256), so should the s (or u, depending on nomenclature) texcoord (1). So, wherever you have a 256 or 1024, use 1 for the texcoord.

This shouldn't fix it, though, unless you got more than just a white square. This mistake would have caused a wonky texture to be applied...

The next step is to include error checking. I'm not sure what needs to be done to get it to C# land, but the basic idea is to use glGetError after any important calls, and make sure you haven't broken something without knowing it.

Edit:
My mistake, there is no error. I added Check error between begin and end, so it gave the Invalid operation.

So there is no error and the problem(white quad, not tex) still persists. I added CheckError(Gl.glGetError()), which cases the error type, after everyline that uses OpenGL .


[Edited by - mr_mo on June 26, 2008 6:24:26 PM]
Allright, two more things to try. First, and easier, use a power of 2 x power of 2 (64x64, 512x512, etc.) texture. Second, tell GL to build mipmaps for you with gluBuild2DMipmaps instead of glTexImage2D. Then you'll want to use GL_LINEAR_MIPMAP_LINEAR as your minification filter.

Crossing fingers.
Don't use gluBuild2DMipmaps if your card supports GPU(hardware acclerated mipmap creation) use this instead, as long as its a POT texture, unless your Gfx has NPOT support.

glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, textureImage.Width, textureImage.Height, 0, GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);


BTW what hardware are you on, are you sure your card or drivers are current? GL_BGR isn't supported on GL versions less than 1.2 or 1.3? Can't remember which one...

One last thing just for dumb luck try making that texture image as a .bmp not a .png

This topic is closed to new replies.

Advertisement