Dinberg's picture

Two textures

Hello!

I have been fooling around with the example for the heightmap, and decided to try to make a field of magma to surround a textured mountain. I managed to load the texture for the mountain easily, and all went well - but upon trying to add the lava texture, it seems to override the mountains.

At first I thought I was in someway saving the image over the same slot, but I compared the values of 'texture' and 'magma' (see below, these are the ids for each texture) and they displayed 1 and 2 respectively. This is my first foray into 3d, so I'm sure i've made a silly mistake. Any help is much appreciated; below is the significant code.

In the initiation of the window:

Bitmap bmp = new Bitmap("tile.bmp");
            GL.Enable(EnableCap.Texture2D);
            GL.GenTextures(1, out texture);
            GL.BindTexture(TextureTarget.Texture2D, texture);
 
            BitmapData 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, data.Width, data.Height, 0,
                OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
 
            bmp.UnlockBits(data);
 
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
 
            bmp = new Bitmap("magma.bmp");
 
            GL.GenTextures(1, out magma);
            Console.WriteLine("water:" + magma + ", texture:" + texture);
            GL.BindTexture(TextureTarget.Texture2D, magma);
            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, data.Width, data.Height, 0,
                OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
 
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
 
 
            bmp.UnlockBits(data);

Before rendering the landscape:

            GL.Enable(EnableCap.Texture2D);
            GL.BindTexture(TextureTarget.Texture2D, texture);

Before rendering the magma:
          GL.BindTexture(TextureTarget.Texture2D, magma);

Included is a screenie to elaborate ;)

Many thanks!

Inline Images

Comments

Comment viewing options

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

Now, this is a seminal example of a support request!

Nothing seems out of place on first look. Are "magma.bmp" and "tile.bmp" really different textures on disk? (Sounds crazy, but I've fallen for that many times). What happens if you place a call to bmp.Dispose(); just before creating the new Bitmap?

Dinberg's picture

The two textures are definately different - intriguingly, if i comment out the second loading, and set magma = texture, the tiling texture for the mountain comes out perfectly; but then the lava is also covered in the same texture, as would be expected ;)

I'll go test the dispose now ;)

Dinberg's picture

No luck on the bmp.Dispose() I'm afraid - I even tried making a new Bitmap object, 'bmp2', in the hope that it would clear things up.
I've tried another BitmapData object aswell, thinking perhaps the information was somehow readonly on account of the locking. That too, turned up no results.

Thanks so far ;)

Inertia's picture

Add GL.Finish after the teximage call and before unlocking the bitmap to guarantee that OpenGL is done with the image. There's no harm in calling GL.Finish during initialization, just avoid calling it per frame.

If that's of no help, GL.GetError() very likely points towards a solution.

Entropy's picture

Related to Inertia's suggestion, it might be a little less efficient, but you could try declaring a second BitmapData object for the second Bitmap.LockBits() call rather than reusing the first one.

Dinberg's picture

Hmm the error code at several locations through the code returns as 'NoError', and I'm afraid the GL.Finish didn't bring any fruit either.
Entropy: I did try another Bitmap object aswell, but still giving the same result.

Is there an example which uses multiple textures that you know of? I'm going to continue to crack on and see if I can fix this :D

Was I also correct in my assumption that the int returned by GL.GenTextures is a free 'memory slot' on the textures list? That's the gist I got from all the tutorials, in which case I cant see why slots 1 and 2 are loading different textures yet displaying the same one. As I say I'm new to this, so any help is appreciated =)

Many thanks!

Mincus's picture

Are you positive the problem isn't in the render function?
What happens if you swap the magma/texture handles in the render function for example?

Dinberg's picture

Still causing the same issue - if I swap the order both textures are loaded however, its the tile texture that is pasted over the mountain. It's as if it will only display the last texture loaded I think, but I'm pretty stumped!

Thanks for the ideas though, I'll keep trying ;)

Dinberg's picture

I tried to start it over, to see if I could get round the problem that way. Sometimes a fresh start helps :D

I made the following function to return the uint slot of a texture generated from a .bmp file path. However this too causes the same errors - I store the uints for both loaded textures in separate variables, 'magma' and 'dirt', yet the same problems occur on rendering:

        public uint LoadTexture(string path)
        {
            uint texID; //this will store the ID
            Bitmap bmp = new Bitmap(path); //load the bitmap at the given path; not very safe, but its for testing! :P
 
            GL.GenTextures(1, out texID); //find one free 'slot', write this value to texID
            GL.BindTexture(TextureTarget.Texture2D, texID); //Select texID for working on
 
            BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); //Grab the data relating to the image
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
                OpenTK.Graphics.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0); //make a picture out of it, on the active texture slot
 
            bmp.UnlockBits(data); //unlock the bits
            bmp.Dispose(); //dispose of the bitmap object
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); //set relevant magnification and minification filters for distance and close-up.
 
            return texID; //return the texture ID
        }
the Fiddler's picture

Take a look at the source of OpenTK.Utilities, it contains a simple Texture2D and an RgbaTexture2D.

Add a new constructor to the RgbaTexture2D class that reads like this:

        public RgbaTexture2D(Bitmap bmp)
            : base(bmp.Width, bmp.Height)
        {
            WriteRegion(new Rectangle(0, 0, bmp.Width, bmp.Height), new Rectangle(0, 0, Width, Height), 0, bmp);
        }

I'm using this in my project without problems.

Edit: I cannot see any problems in your code, maybe there is something amiss in the rendering side. Trying running a "Find all references" on the two texture handles and check for stray assignments or BindTexture calls.