LWJGL - White box instead of texture

Hello,

Just a while ago I got a book for OpenGL which greatly helped me out with getting programming started. But let’s just get to the point.

I got an issue where the texture that I’m trying to load is completely white. I checked on various other people that had the same issue, but none of them helped.
I’ve tried multiple things, such as disabling GL_TEXTURE_2D and enabling it again, making an InputStream method and setting it to the the decoder, and so on.
And just to get it out of the way, I am using TWL’s PNGDecoder to decode the image.

Inside main class:


import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.OpenGLException;

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

public class Ironbolt {
    
    private long last = 0;
    public String screen = "title";
    
    public static int program;
    public static int shader;
    
    private Texture title;
    
    public void initGL(int width, int height, boolean full) {
        System.out.println("Initializing...");
        try {
            System.out.print("Setting display mode " + width + " " + height + " " + full + "\nApplying");
            Display.setDisplayMode(new DisplayMode(width, height));
            System.out.print(".");
            Display.setFullscreen(full);
            System.out.print(".");
            Display.create();
            System.out.println(".");
            System.out.println("Initializing keyboard...");
            Keyboard.create();
            System.out.println("Initializing mouse...");
            Mouse.create();
        } catch (LWJGLException e) {
            System.out.println("LWJGLException: Failed to initialize display");
            System.exit(-1);
        }
        
        Display.setVSyncEnabled(true);
        
        System.out.println("Enabling OpenGL field values...");
        glEnable(GL_TEXTURE_2D);
        
        program = GL20.glCreateProgram();
        shader = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
        GL20.glAttachShader(Ironbolt.program, Ironbolt.shader);
        
        GL20.glUseProgram(program);
        
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        
        glViewport(0, 0, width, height);
        glMatrixMode(GL_MODELVIEW);
        
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, width, height, 0, 1, -1);
        glMatrixMode(GL_MODELVIEW);
        System.out.println("Done");
    }
    
    public void run() {
        initGL(1280, 720, false);
        title = new Texture("title");
        delta();
        while (!Display.isCloseRequested()) {
            glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
            
            switch (screen) {
                case "title":
                    Texture.render(title);
            }
            
            delta();
            
            
            
            Display.update();
        }
        Display.destroy();
        Keyboard.destroy();
        Mouse.destroy();
    }
    
    public int delta() {
        long time = Sys.getTime();
        int delta = (int)(time - last);
        last = time;
        
        return delta;
    }
    
    public static void main(String[] args) {
        Ironbolt game = new Ironbolt();
        game.run();
    }
    
}

Inside texture class:


import de.matthiasmann.twl.utils.PNGDecoder;
import java.io.IOException;
import java.nio.ByteBuffer;

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

public class Texture {
    
    private int id;
    
    private int width;
    private int height;
    
    private int imgWidth;
    private int imgHeight;
    
    private int texWidth;
    private int texHeight;
    
    public Texture(String name) {
        try {
            System.out.println("Initializing decode of texture " + name);
            PNGDecoder decoder = new PNGDecoder(this.getClass().getResourceAsStream("textures/" + name + ".png"));

            ByteBuffer buffer = ByteBuffer.allocateDirect(decoder.getWidth() * decoder.getHeight() * 4);
            System.out.println("Buffer position: " + buffer.position());
            if (buffer.position() != 0) {
                System.out.println("Buffer position not neutrulized, setting to 0");
                buffer.position(0);
            }
            decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);

            System.out.println("Buffer size: " + buffer.capacity());

            System.out.println("Width: " + decoder.getWidth());
            System.out.println("Height: " + decoder.getHeight());
            buffer.flip();

            System.out.println("Done");
            imgWidth = decoder.getWidth();
            imgHeight = decoder.getHeight();
            
            System.out.println("Comparing image with byte buffer...");
            if (imgWidth * imgHeight * 4 != buffer.limit()) throw new ArrayIndexOutOfBoundsException("Buffer size is not equal to image size");
            System.out.println("Byte buffer size is correct");
            
            int i = 1;
            while (i < imgWidth) {
                i = i * 2;
            }
            i = i / 2;
            System.out.println("Texture width power is " + i);
            texWidth = i;
            
            i = 1;
            while (i < imgHeight) {
                i = i * 2;
            }
            i = i / 2;
            System.out.println("Texture height power is " + i);
            texHeight = i;
            
            createTexture(buffer);
            
            System.out.println("Checking texture state for texture " + id);
            if (!glIsTexture(id)) {
                System.out.println("Error, texture " + id + " is not a texture");
            } else {
                System.out.println("Texture state OK. Adding to list...");
            }
            
            System.out.println("Done");
        } catch (IOException e) {
            System.out.println("IOException: Failed to decode image");
        }

    }
    
    private void createTexture(ByteBuffer buffer) {
        System.out.println("Creating texture...");
        id = glGenTextures();
        
        bind();
        
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        
        glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_RGBA8,
                     width, height,
                     0,
                     GL_RGBA, GL_UNSIGNED_BYTE,
                     buffer);
        GL30.glGenerateMipmap(GL_TEXTURE_2D);
        
        System.out.println("Texture created");
    }
    
    public int getTextureWidth() {
        return texWidth;
    }
    
    public int getTextureHeight() {
        return texHeight;
    }
    
    public int getImageWidth() {
        return imgWidth;
    }
    
    public int getImageHeight() {
        return imgHeight;
    }
    
    public int getWidth() {
        return width;
    }
    
    public int getHeight() {
        return height;
    }
    
    public void clear() {
        glDeleteTextures(id);
    }
    
    public void bind() {
        glBindTexture(GL_TEXTURE_2D, id);
    }
    
    public static void render(Texture texture) {
        glEnable(GL_TEXTURE_2D);
        glPushMatrix();
        
        if (glIsTexture(texture.id)) {
            texture.bind();
        } else {
            throw new IllegalArgumentException("The texture method is invalid");
        }
        
        glTranslated(0, 0, 0);
        
        glBegin(GL_QUADS);
        {
            glTexCoord2d(0, 0);
            glVertex2d(0, 0);

            glTexCoord2d(0, texture.getTextureHeight());
            glVertex2d(0, texture.getImageHeight());

            glTexCoord2d(texture.getTextureWidth(), texture.getTextureHeight());
            glVertex2d(texture.getImageWidth(), texture.getImageHeight());

            glTexCoord2d(texture.getTextureWidth(), 0);
            glVertex2d(texture.getImageWidth(), 0);
        }
        glEnd();

        glPopMatrix();
    }
    
}

Anything you spot that is wrong? Since I debugged pretty much everything and it seems fine.

Any help is appriciated.

Don’t know about that PNGDecoder, if it decodes the image to the right format, so I just assume, that the ByteBuffer is filled with the right data.

In your rendering code I see, that you use [icode]texture.getTextureHeight()[/icode], but Texture coordinates go from 0.0 to 1.0 so change your rendering to this:


glBegin(GL_QUADS);
{
    glTexCoord2d(0, 0);
    glVertex2d(0, 0);

    glTexCoord2d(0, 1);
    glVertex2d(0, texture.getImageHeight());

    glTexCoord2d(1, 1);
    glVertex2d(texture.getImageWidth(), texture.getImageHeight());

    glTexCoord2d(1, 0);
    glVertex2d(texture.getImageWidth(), 0);
}
glEnd();

Does that solve your problem? :slight_smile:

Nope, unfortunately nothing happened.
In case this helps, here’s the console after everything is loaded:


debug:
Initializing...
Setting display mode 1280 720 false
Applying...
Initializing keyboard...
Initializing mouse...
Enabling OpenGL field values...
Done
Initializing decode of texture title
Buffer position: 0
Buffer size: 380160
Width: 540
Height: 176
Done
Comparing image with byte buffer...
Byte buffer size is correct
Texture width power is 512
Texture height power is 128
Creating texture...
Texture created
Checking texture state for texture 1
Texture state OK. Adding to list...
Done
BUILD SUCCESSFUL (total time: 2 seconds)

*EDIT:
After deeper examination, I noticed that the byte buffer is empty. Let me see if I can override one of the functions in the PNG decoder to make it return it’s value instead.

Well in that case you could load the picture with [icode]ImageIO[/icode] and put the data into the buffer yourself.
Here’s an example code of how you could load your image :wink:


BufferedImage image = null;
try {
    InputStream in = this.getClass().getResourceAsStream("textures/" + name + ".png");
    image = ImageIO.read(in);
} catch (IOException ex) {
    throw new RuntimeException("Failed to load a texture file!"
        + System.lineSeparator() + ex.getMessage());
}
if (image != null) {
    /* Get width and height of image */
    int width = image.getWidth();
    int height = image.getHeight();

    /* Get pixel data of image */
    int[] pixels = new int[width * height];
    image.getRGB(0, 0, width, height, pixels, 0, width);

    /* Put pixel data into a ByteBuffer */
    ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4);
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            /* Pixel as RGBA: 0xAARRGGBB */
            int pixel = pixels[y * width + x];

            /* Red component 0xAARRGGBB >> 16 = 0x0000AARR */
            buffer.put((byte) ((pixel >> 16) & 0xFF));

            /* Green component 0xAARRGGBB >> 8 = 0x00AARRGG */
            buffer.put((byte) ((pixel >> 8) & 0xFF));

            /* Blue component 0xAARRGGBB >> 0 = 0xAARRGGBB */
            buffer.put((byte) (pixel & 0xFF));

            /* Alpha component 0xAARRGGBB >> 24 = 0x000000AA */
            buffer.put((byte) ((pixel >> 24) & 0xFF));
        }
    }

/* Do not forget to flip the buffer! */
buffer.flip();

} else {
    throw new RuntimeException("File extension not supported!"
        + System.lineSeparator() + "The following file extensions "
        + "are supported: "
        + Arrays.toString(ImageIO.getReaderFileSuffixes()));
}

Tried the code you gave me and unfortunately it didn’t help out.

Could it be because bytes are handled differently in Linux? If the code works for you and you’re running Windows, then it could be the case.
It would also explain why I can’t find a working fix for this issue anywhere.

Are you just making a small engine to run a 2D game? if so you should use @minigame’s ,its very small but gets the job done! (I use it for my game and it is great framework and anything you need he add’s straight away)
https://github.com/two-d/lwjgl_wrapper
Fourm: http://www.javarpg.com/forum/index.php

Right now, I’m starting small. But things usually grow since I rarely start from the beginning (I only restart if I break something I can’t fix). With other words, yes, but not for long.
Apart from that, I don’t think it will work since the code for loading textures look exactly the same as the one I have already.

That shouldn’t make a difference if you are on Linux or another OS, did that code throw an exception?

Just saw that you are creating a vertex shader, does the code work if you comment that part out?
You may also wan’t to try abandoning that legacy OpenGL and start to work with shaders.
I started writing a tutorial some weeks ago for LWJGL3, you could look at it here.
Hope that helps :slight_smile:

The problem is with shaders. You are only attaching the vertex shader, and also you are not compiling the shaders, and you are not linking the program.

Uh, guys?

How did I miss out on this?


            ...System.out.println("Done");
            imgWidth = decoder.getWidth();
            imgHeight = decoder.getHeight();...

            ...glTexImage2D(GL_TEXTURE_2D, 0,
                     GL_RGBA8,
                     width, height,
                     0,
                     GL_RGBA, GL_UNSIGNED_BYTE,
                     buffer);...

If you can’t see it. I bound the size of the texture to imgWidth and imgHeight, NOT width and height.
But what I did was loading up the image size from width and height.

I’m dumb.