Jump to content
  • Advertisement
Sign in to follow this  
mr_mo

OpenGL Unable to load 2D texture

This topic is 3737 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
// 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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 Corner
Gl.glTexCoord2d(1, 0);
Gl.glVertex2d(256, 1024);

should be

// Lower Rigt Corner
Gl.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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!