Axoren
Axoren

Reputation: 643

Textured Quad issue in Java OpenGL

First, I'll start with my code because I've identified which block is causing the issue.

// init
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_TEXTURE_2D);

// BEGINNING OF OFFENDING CODE

BufferedImage image = ImageIO.read(new File("res/button.png"));
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
IntBuffer buffer = BufferUtils.createIntBuffer(pixels.length);
for (int pixel : pixels)
    buffer.put(pixel);
buffer.flip();

int button = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, button);
//Setup wrap mode
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);

// END OF OFFENDING CODE

This is what things are supposed to look like without the textured quad.

This is how things are supposed to look before the button.

This is what happens when I render with the offending code (with the textured quad).

What I'm getting

This is what happens when I render with the offending code (without the textured quad).

What I get when I comment out the code for the button

For reference, this is the texture

What the button should look like


I can't seem to figure out which GL11 call is affecting the rest of the Display and why it would be affecting the rest of the display. From what I understand, all of the calls that follow GL11.glBindTexture are limited to the bound texture, aren't they?


Edit: Additional Rendering Code

private static void renderQuad(int x, int y, int width, int height) {
    GL11.glPushMatrix();
    GL11.glBegin(GL11.GL_QUADS);
        GL11.glVertex2f(x, y);
        GL11.glVertex2f(x + width, y);
        GL11.glVertex2f(x + width, y + height);
        GL11.glVertex2f(x, y + height);
    GL11.glEnd();
    GL11.glPopMatrix();
}

The method used for the red quads.

GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glColor3f(0.5f,0.5f,1.0f);
renderQuad(0, 0, 800, 600);

// render action bar
GL11.glColor3f(0.2f,0.2f,1.0f);
renderQuad(0, 0, 800, 200);

GL11.glColor3f(1.0f,0.0f,0.0f);
renderQuad(50, 50, 100, 60);

renderQuad(200, 50, 100, 60);

// render textured quad
GL11.glPushMatrix();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, button);
GL11.glBegin(GL11.GL_QUADS);
    GL11.glTexCoord2d(0.0,1.0); 
    GL11.glVertex2f(x, y);
    GL11.glTexCoord2d(1.0,1.0); 
    GL11.glVertex2f(x + width, y);
    GL11.glTexCoord2d(1.0,0.0); 
    GL11.glVertex2f(x + width, y + height);
    GL11.glTexCoord2d(0.0,0.0); 
    GL11.glVertex2f(x, y + height);
GL11.glEnd();
GL11.glPopMatrix();

Upvotes: 0

Views: 129

Answers (1)

SDLeffler
SDLeffler

Reputation: 585

First of all, I think there's a problem with your texture loading. I believe the order of the bytes is reversed or something similar, which is why you get the red on black. Here's a working load-texture-from-BufferedImage example taken from my own code:

     BufferedImage image = ImageIO.read(new File("<file path>.png"));
     int[] pixels = new int[image.getWidth() * image.getHeight()];
     image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());

     ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4);

     for(int y = 0; y < image.getHeight(); y++){
         for(int x = 0; x < image.getWidth(); x++){
             int pixel = pixels[y * image.getWidth() + x];
             buffer.put((byte) ((pixel >> 16) & 0xFF));     // Red component
             buffer.put((byte) ((pixel >> 8) & 0xFF));      // Green component
             buffer.put((byte) (pixel & 0xFF));               // Blue component
             buffer.put((byte) ((pixel >> 24) & 0xFF));    // Alpha component. Only for RGBA
         }
     }

     buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS

     // You now have a ByteBuffer filled with the color data of each pixel.
     // Now just create a texture ID and bind it. Then you can load it using 
     // whatever OpenGL method you want, for example:

     int textureID = GL11.glGenTextures(); //Generate texture ID
     GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID

     //Setup wrap mode
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);

     //Setup texture scaling filtering
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
     GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);

     //Send texel data to OpenGL
     GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);

Now, to the actual rendering problem:

For OpenGL, GL_TEXTURE_2D must be enabled or disabled depending on whether or not the polygon you are drawing is textured. If you do not supply texture coordinates for each vertex, then the last texture coords call still holds and is used for each vertex. So, you'll get a quad using one pixel's worth of texture. This is what's causing the black quads - it's taking from one pixel from a corner of your improperly loaded texture. So, your fixed rendering code:

GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

GL11.glDisable(GL11.GL_TEXTURE_2D);

GL11.glColor3f(0.5f,0.5f,1.0f);
renderQuad(0, 0, 800, 600);

// render action bar
GL11.glColor3f(0.2f,0.2f,1.0f);
renderQuad(0, 0, 800, 200);

GL11.glColor3f(1.0f,0.0f,0.0f);
renderQuad(50, 50, 100, 60);

renderQuad(200, 50, 100, 60);

GL11.glEnable(GL11.GL_TEXTURE_2D);

// render textured quad
GL11.glColor3f(1.0f, 1.0f, 1.0f);
GL11.glPushMatrix();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, button);
GL11.glBegin(GL11.GL_QUADS);
    GL11.glTexCoord2d(0.0,1.0); 
    GL11.glVertex2f(x, y);
    GL11.glTexCoord2d(1.0,1.0); 
    GL11.glVertex2f(x + width, y);
    GL11.glTexCoord2d(1.0,0.0); 
    GL11.glVertex2f(x + width, y + height);
    GL11.glTexCoord2d(0.0,0.0); 
    GL11.glVertex2f(x, y + height);
GL11.glEnd();
GL11.glPopMatrix();

On a side note, you can use simply glEnable() instead of GL11.glEnable() if you do:

import static org.lwjgl.opengl.GL11.*;

instead of simply

import org.lwjgl.opengl.GL11;

Upvotes: 1

Related Questions