fkj's picture

Using multiple textures

The texture examples I've seen only shows how to use a single texture (to keep it simple obviously), but I'm trying to use two textures, and am having a problem. I use the following code to load a texture (I believe there is nothing special about this code):

        Bitmap bitmap = new Bitmap( path );
 
        BitmapData data = bitmap.LockBits(
          new System.Drawing.Rectangle( 0, 0, bitmap.Width, bitmap.Height ),
          System.Drawing.Imaging.ImageLockMode.ReadOnly,
          System.Drawing.Imaging.PixelFormat.Format32bppRgb
        );
 
        int textureId = GL.GenTexture();
 
        GL.TexImage2D(
          TextureTarget.Texture2D,
          0,
          PixelInternalFormat.Rgba,
          data.Width, data.Height,
          0,
          OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
          PixelType.UnsignedByte,
          data.Scan0
        );
 
        bitmap.UnlockBits( data );

Loading two textures I get textureId's 1 and 2. This is done once in the start of the program (...OnLoad...).

I then use only the first texture on some quads (GL.BindTexture( 1 ) etc.).

It all works fine but for one thing, it always uses the last texture loaded! If I only load the first texture it looks fine, but it's like it always uses the last texture nomatter what id I try to use. Note that BindTexture() is never called using 2 anywhere in the code, and GetError() returns no error on neither TexImage2D or BindTexture. Both textures works fine if only one texture is loaded.

What am I missing? Do I have to do something extra to make two textures available?

(using: OpenTK 1.1 (by Subversion), my driver supports only OpenGL 2.1)


Comments

Comment viewing options

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

Hello everyone,

I'm having the same problem as the original poster. I've done a lot of reading on this forum, as well as finding a quite helpful post on StackOverflow, but I am still stuck after several days trying to figure this out on my own. I'm hoping the helpful people in this forum can help me out.

Like the OP, I'm trying to pass two textures to my fragment shader. And like the OP, only the second texture seems to get loaded. I've taken the code straight from the OpenTK sample browser -- the rotating cube. I want to draw a texture on the side of the cube and tint it pink. This works just fine:

        string fragmentShaderSource = @"
 
#version 150
uniform sampler2D MyTexture;
uniform sampler2D MyTexture2;
 
void main(void)
 
 
gl_FragColor = texture2D( MyTexture, gl_TexCoord[0].st );  
gl_FragColor[1] = gl_FragColor[1] * 0.90;
}"
            ;

Then I try to add a second texture. Ideally I'd like to see MyTexture populated with the first texture, and MyTexture2 populated with the second texture).

        protected override void OnLoad(EventArgs e)
        {
 
            CreateShaders();
            base.OnLoad(e);
 
            GL.ClearColor(0.0f, 0.4f, 0.0f, 0.0f);
            GL.Enable(EnableCap.DepthTest);
            GL.Enable(EnableCap.Texture2D);
            GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
 
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.GenTextures(0, out texture);
            GL.BindTexture(TextureTarget.Texture2D, texture); 
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture"), texture);
 
 
            GL.ActiveTexture(TextureUnit.Texture1);
            GL.GenTextures(1, out texture1);
//            GL.BindTexture(TextureTarget.Texture2D, texture1); 
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture2"), texture1);
 
            BitmapData data1 = bitmap1.LockBits(new System.Drawing.Rectangle(0, 0, bitmap1.Width, bitmap1.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            BitmapData data2 = bitmap2.LockBits(new System.Drawing.Rectangle(0, 0, bitmap2.Width, bitmap2.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data1.Width, data1.Height, 0,
            OpenTK.Graphics.OpenGL.
            PixelFormat.Bgra, PixelType.UnsignedByte, data1.Scan0);
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data2.Width, data2.Height, 0,
            OpenTK.Graphics.OpenGL.
            PixelFormat.Bgra, PixelType.UnsignedByte, data2.Scan0);
 
            bitmap1.UnlockBits(data1);
            bitmap2.UnlockBits(data2);
 
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            modelviewMatrix = Matrix4.LookAt(0, 4, 7, 0, 0, 0, 0, 1, 0);
 
            rotationviewMatrix = Matrix4.CreateRotationX((float)Math.PI / 100);// *Matrix4.CreateRotationX((float)Math.PI / 10000);
 
        }

If you run the code as-is, the cube shows the texture on each face of the cube tinted pink. It's the same texture whether you reference MyTexture or MyTexture2 in the fragment shader.

When I uncomment the line

//            GL.BindTexture(TextureTarget.Texture2D, texture1); 

Then the sides of the cube become black. Same problem as the OP.

I'm sure I'm doing something stupid here, but I'm quite stuck. I can't figure out how to get the second texture to be passed to my program!

Here's the source code in full. It's almost identical to the OpenTK example browser code for the simple cube example. This should compile as-is if you have two files on your drive at

        Bitmap bitmap1 = new Bitmap(@"C:\temp\pic1.bmp");
        Bitmap bitmap2 = new Bitmap(@"C:\temp\pic2.bmp");

Here is the full source. Any help would be really appreciated! Thank you!

// Released to the public domain. Use, modify and relicense at will.
 
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
 
namespace StarterKit
{
 
    class Game : GameWindow
    {
 
        private Matrix4 modelviewMatrix, projectionMatrix;
 
        private Matrix4 rotationviewMatrix;
 
        int fragmentShaderHandle, shaderProgramHandle, texture, texture1;
 
        const float rotation_speed = 18.0f;
 
        float angle;
 
        Bitmap bitmap1 = new Bitmap(@"C:\temp\pic1.bmp");
        Bitmap bitmap2 = new Bitmap(@"C:\temp\pic2.bmp");
 
        string fragmentShaderSource = @"
 
#version 150
uniform sampler2D MyTexture;
uniform sampler2D MyTexture2;
 
void main(void)
 
 
gl_FragColor = texture2D( MyTexture, gl_TexCoord[0].st );  
gl_FragColor[1] = gl_FragColor[1] * 0.90;
}"
            ;
 
        void CreateShaders()
        {
 
            fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);
            GL.CompileShader(fragmentShaderHandle);
            Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle));
 
            // Create program
            shaderProgramHandle = GL.CreateProgram();
            GL.AttachShader(shaderProgramHandle, fragmentShaderHandle);
            GL.LinkProgram(shaderProgramHandle);
            Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle));
 
            GL.UseProgram(shaderProgramHandle);
 
 
            float aspectRatio = ClientSize.Width / (float)(ClientSize.Height);
            Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspectRatio, 1, 100, out projectionMatrix);
        }
 
        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game() : base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample")
        {
            VSync = VSyncMode.On;
        }
 
        /// <summary>Load resources here.</summary>
        /// <param name="e">Not used.</param>
        protected override void OnLoad(EventArgs e)
        {
 
            CreateShaders();
            base.OnLoad(e);
 
            GL.ClearColor(0.0f, 0.4f, 0.0f, 0.0f);
            GL.Enable(EnableCap.DepthTest);
            GL.Enable(EnableCap.Texture2D);
            GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
 
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.GenTextures(0, out texture);
            GL.BindTexture(TextureTarget.Texture2D, texture); 
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture"), texture);
 
 
            GL.ActiveTexture(TextureUnit.Texture1);
            GL.GenTextures(1, out texture1);
//            GL.BindTexture(TextureTarget.Texture2D, texture1); 
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture2"), texture1);
 
            BitmapData data1 = bitmap1.LockBits(new System.Drawing.Rectangle(0, 0, bitmap1.Width, bitmap1.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            BitmapData data2 = bitmap2.LockBits(new System.Drawing.Rectangle(0, 0, bitmap2.Width, bitmap2.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data1.Width, data1.Height, 0,
            OpenTK.Graphics.OpenGL.
            PixelFormat.Bgra, PixelType.UnsignedByte, data1.Scan0);
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data2.Width, data2.Height, 0,
            OpenTK.Graphics.OpenGL.
            PixelFormat.Bgra, PixelType.UnsignedByte, data2.Scan0);
 
            bitmap1.UnlockBits(data1);
            bitmap2.UnlockBits(data2);
 
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            modelviewMatrix = Matrix4.LookAt(0, 4, 7, 0, 0, 0, 0, 1, 0);
 
            rotationviewMatrix = Matrix4.CreateRotationX((float)Math.PI / 100);// *Matrix4.CreateRotationX((float)Math.PI / 10000);
 
        }
 
        /// <summary>
        /// Called when your window is resized. Set your viewport here. It is also
        /// a good place to set up your projection matrix (which probably changes
        /// along when the aspect ratio of your window).
        /// </summary>
        /// <param name="e">Not used.</param>
 
        protected override void OnResize(EventArgs e)
        {
 
            base.OnResize(e);
            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
            projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projectionMatrix);
 
        }
 
        /// <summary>
        /// Called when it is time to setup the next frame. Add you game logic here.
        /// </summary>
        /// <param name="e">Contains timing information for framerate independent logic.</param>
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
            if (Keyboard[Key.Escape])
                Exit();
        }
 
        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
 
            base.OnRenderFrame(e);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture"), texture);
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture2"), texture1);
 
            angle += rotation_speed * (float)e.Time;
 
            float translateby = (float)Math.Sin(DateTime.Now.Second) * 0.05f;
 
            rotationviewMatrix = Matrix4.CreateTranslation(0f, 0f, translateby);
 
            // modelview = modelview * rotation;
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelviewMatrix);
            GL.Rotate(angle, 0.0f, 1.0f, 0.0f);
            DrawCube();
            SwapBuffers();
        }
 
 
 
        private void DrawCube()
        {
 
            GL.BindTexture(TextureTarget.Texture2D, texture);
            GL.Begin(BeginMode.Quads);
 
            GL.Color3(Color.Silver);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
 
            GL.Color3(Color.Honeydew);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, -1.0f, 1.0f);
 
            GL.Color3(Color.Goldenrod);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
 
 
            GL.Color3(Color.DodgerBlue);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, 1.0f, 1.0f);
 
            GL.Color3(Color.Purple);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
 
            GL.Color3(Color.ForestGreen);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 1.0f);
 
            GL.End();
 
        }
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
 
        [STAThread]
        static void Main()
        {
            // The 'using' idiom guarantees proper resource cleanup.
            // We request 30 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
                game.Run(30.0);
            }
        }
    }
}
ZTK's picture

Okay after some more digging and poking around I was able to solve it. I'm going to post what I did here in case others are confused:
Problem was that I had to do each texure's entire code path one at a time. So I changed the function to this:

        protected override void OnLoad(EventArgs e)
        {
 
            CreateShaders();
            base.OnLoad(e);
 
            GL.ClearColor(0.0f, 0.4f, 0.0f, 0.0f);
            GL.Enable(EnableCap.DepthTest);
            GL.Enable(EnableCap.Texture2D);
            GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
 
            // load texture 1
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.GenTextures(0, out texture);
            GL.BindTexture(TextureTarget.Texture2D, texture);
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture"), texture);
 
            BitmapData data1 = bitmap1.LockBits(new System.Drawing.Rectangle(0, 0, bitmap2.Width, bitmap2.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data1.Width, data1.Height, 0,
            OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data1.Scan0);
 
            bitmap1.UnlockBits(data1);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
 
            // load texture 2
            GL.ActiveTexture(TextureUnit.Texture1);
            GL.GenTextures(1, out texture1);
            GL.BindTexture(TextureTarget.Texture2D, texture1);
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture2"), texture1);
 
            BitmapData data2 = bitmap2.LockBits(new System.Drawing.Rectangle(0, 0, bitmap2.Width, bitmap2.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data2.Width, data2.Height, 0,
            OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data2.Scan0);
 
            bitmap2.UnlockBits(data2);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
 
            modelviewMatrix = Matrix4.LookAt(0, 4, 7, 0, 0, 0, 0, 1, 0);
 
            rotationviewMatrix = Matrix4.CreateRotationX((float)Math.PI / 100);// *Matrix4.CreateRotationX((float)Math.PI / 10000);
 
        }

This works. I can change the reference to MyTexture to MyTexture2 in the fragment shader and it shows the second texture.

ZTK's picture

Okay, so I was *still* wrong. It turns out that my fundamental error was this

GL.ActiveTexture(TextureUnit.Texture0);

Instead, multiple textures should be loaded at Texture1!

GL.ActiveTexture(TextureUnit.Texture1);

Here is the code for my sample program, which loads 4 textures on each face of a cube (so a quad has multiple textures). The shader tints each texture to "prove" that it went through the shader. I'm embarassed to say this took me multiple days to figure out so I'm posting here hoping someone will get help from this. This seems to be a common enough problem

// Released to the public domain. Use, modify and relicense at will.
 
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
 
namespace StarterKit
{
 
    class Game : GameWindow
    {
        private Matrix4 modelviewMatrix, projectionMatrix;
        private Matrix4 rotationviewMatrix;
 
        int fragmentShaderHandle, shaderProgramHandle, texture1, texture2, texture3, texture4;
 
        const float rotation_speed = 18.0f;
 
        float angle;
 
        Bitmap bitmap1 = new Bitmap(@"..\..\img\pic1.bmp");
        Bitmap bitmap2 = new Bitmap(@"..\..\img\pic2.bmp");
        Bitmap bitmap3 = new Bitmap(@"..\..\img\pic3.bmp");
        Bitmap bitmap4 = new Bitmap(@"..\..\img\pic4.bmp");
 
        string fragmentShaderSource = @"
 
#version 150
uniform sampler2D MyTexture1;
uniform sampler2D MyTexture2;
uniform sampler2D MyTexture3;
uniform sampler2D MyTexture4;
 
void main(void)
{
 if (gl_TexCoord[0].s < 0.25){
  gl_FragColor = texture2D( MyTexture1, gl_TexCoord[0].st );  
  gl_FragColor[1] = gl_FragColor[1] * 0.90;
 }
else if (gl_TexCoord[0].s < 0.5) {
  gl_FragColor = texture2D( MyTexture2, gl_TexCoord[0].st );  
  gl_FragColor[0] = gl_FragColor[0] * 0.90;
 }
else if (gl_TexCoord[0].s < 0.75) {
  gl_FragColor = texture2D( MyTexture3, gl_TexCoord[0].st );  
  gl_FragColor[2] = gl_FragColor[2] * 0.90;
 }
else {
  gl_FragColor = texture2D( MyTexture4, gl_TexCoord[0].st );  
 }
}"
            ;
 
        void CreateShaders()
        {
 
            fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);
            GL.CompileShader(fragmentShaderHandle);
            Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle));
 
            // Create program
            shaderProgramHandle = GL.CreateProgram();
            GL.AttachShader(shaderProgramHandle, fragmentShaderHandle);
            GL.LinkProgram(shaderProgramHandle);
            Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle));
 
            GL.UseProgram(shaderProgramHandle);
 
 
            float aspectRatio = ClientSize.Width / (float)(ClientSize.Height);
            Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspectRatio, 1, 100, out projectionMatrix);
        }
 
        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game()
            : base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample")
        {
            VSync = VSyncMode.On;
        }
 
        /// <summary>Load resources here.</summary>
        /// <param name="e">Not used.</param>
        protected override void OnLoad(EventArgs e)
        {
            CreateShaders();
            base.OnLoad(e);
 
            GL.ClearColor(0.0f, 0.4f, 0.0f, 0.0f);
            GL.Enable(EnableCap.DepthTest);
            GL.Enable(EnableCap.Texture2D);
            GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
 
            CreateAndBindTexture(out texture1, bitmap1, TextureUnit.Texture1, "MyTexture1");
            CreateAndBindTexture(out texture2, bitmap2, TextureUnit.Texture2, "MyTexture2");
            CreateAndBindTexture(out texture3, bitmap3, TextureUnit.Texture3, "MyTexture3");
            CreateAndBindTexture(out texture4, bitmap4, TextureUnit.Texture4, "MyTexture4");
 
 
            modelviewMatrix = Matrix4.LookAt(0, 4, 7, 0, 0, 0, 0, 1, 0);
 
            rotationviewMatrix = Matrix4.CreateRotationX((float)Math.PI / 100);// *Matrix4.CreateRotationX((float)Math.PI / 10000);
        }
 
        private void CreateAndBindTexture(out int texture, Bitmap bitmap, TextureUnit textureUnit, string UniformName)
        {
            // load texture 
            GL.ActiveTexture(textureUnit);
            GL.GenTextures(1, out texture);
            GL.BindTexture(TextureTarget.Texture2D, texture);
            GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, UniformName), texture);
 
            BitmapData data = bitmap.LockBits(new System.Drawing.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);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
        }
 
        /// <summary>
        /// Called when your window is resized. Set your viewport here. It is also
        /// a good place to set up your projection matrix (which probably changes
        /// along when the aspect ratio of your window).
        /// </summary>
        /// <param name="e">Not used.</param>
 
        protected override void OnResize(EventArgs e)
        {
 
            base.OnResize(e);
            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
            projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projectionMatrix);
 
        }
 
        /// <summary>
        /// Called when it is time to setup the next frame. Add you game logic here.
        /// </summary>
        /// <param name="e">Contains timing information for framerate independent logic.</param>
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
            if (Keyboard[Key.Escape])
                Exit();
        }
 
        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
 
            base.OnRenderFrame(e);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            angle += rotation_speed * (float)e.Time;
            float translateby = (float)Math.Sin(DateTime.Now.Second) * 0.05f;
            rotationviewMatrix = Matrix4.CreateTranslation(0f, 0f, translateby);
 
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelviewMatrix);
            GL.Rotate(angle, 0.0f, 1.0f, 0.0f);
            DrawCube();
            SwapBuffers();
        }
 
 
 
        private void DrawCube()
        {
            GL.Begin(BeginMode.Quads);
 
            GL.Color3(Color.Silver);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
 
            GL.Color3(Color.Honeydew);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, -1.0f, 1.0f);
 
            GL.Color3(Color.Goldenrod);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
 
 
            GL.Color3(Color.DodgerBlue);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, 1.0f, 1.0f);
 
            GL.Color3(Color.Purple);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
 
            GL.Color3(Color.ForestGreen);
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 1.0f);
 
            GL.End();
 
        }
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
 
        [STAThread]
        static void Main()
        {
            // The 'using' idiom guarantees proper resource cleanup.
            // We request 30 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
                game.Run(30.0);
            }
        }
    }
}
ZTK's picture

this seems to be a common point of confusion, so I've created a blog post on this

http://www.opentk.com/node/2559

I think something lik ethis should be added as an example to the example browser, since many people seem to get caught up on this!

jjxtra's picture

Anytime you bind a texture you MUST set the texture state BEFORE a Begin call, like so:

GL.BindTexture(TextureTarget.Texture2D, texture.TextureId);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.Begin(BeginMode.Quads);