[SOLVED] Texture problem in LWJGL

Hello everyone,
I have a problem in my LWJGL project - binding textures doesn’t seem to work for me, I only see a white plane without the texture. I really have no idea why, the texture is 256x256, I have textures enabled and the loaded image has data.
Here’s the code:
Engine class

package main;

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

import java.nio.ByteBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

public class Engine {
	
	final String TITLE = "IcyEngine2D";
	boolean vsync = false;
	final boolean ESC_ON = true;
	int W = 640;
	int H = 480;
	final int W_DEFAULT = 640;
	final int H_DEFAULT = 480;
	int fps = 60;
	Texture tex = new Texture();
	
	//initialize
	public void init(){
		glMatrixMode(GL_PROJECTION);
		glOrtho(0, W_DEFAULT, H_DEFAULT, 0, 1, -1);
		glMatrixMode(GL_MODELVIEW);
		
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glEnable(GL_TEXTURE_2D);
		tex.loadImage("res/textures/Image.png");
		tex.bind();
	}
	
	//game loop -------------------------------------------
	public void input(){
		if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) && ESC_ON) exit(false);
	}
	
	public void logic(){
		
	}
	
	public void render(){
		glClear(GL_COLOR_BUFFER_BIT);
		glLoadIdentity();
		tex.bind();
		glTranslatef(200, 200, 0);
		glBegin(GL_QUADS);
		glTexCoord2f(1.0f, 0);
		glVertex2f(100, -100);
		glTexCoord2f(0, 0);
		glVertex2f(-100, -100);
		glTexCoord2f(0, 1.0f);
		glVertex2f(-100, 100);
		glTexCoord2f(1.0f, 1.0f);
		glVertex2f(100, 100);
		glEnd();
	}
	//-----------------------------------------------------
	
	//clean up and exit
	public void exit(boolean error){
		Display.destroy();
		System.exit(error ? 1 : 0);
	}
	
	public static void main(String[] args) {
		new Natives().load();
		new Engine();
	}
	
	public Engine(){
		initDisplay();
		init();
		while(!Display.isCloseRequested())
		loop();
		exit(false);
	}
	
	public void loop(){
		input();
		logic();
		render();
		Display.update();
		Display.sync(fps);
	}
	
	public void initDisplay(){
		try {
			Display.setDisplayMode(new DisplayMode(W, H));
			Display.setTitle(TITLE);
			loadIcon("res/textures/Icon.png");
			Display.create();
			Display.setVSyncEnabled(vsync);
		} catch (LWJGLException e) {
			e.printStackTrace();
			exit(true);
		}
	}
	
	public void throwError(){
		String e = checkError();
		if(e != "no errors")throw new Error(e);
	}
	
	public String checkError(){
		int e = glGetError();
		switch (e) {
		case GL_NO_ERROR: return "no errors";
		case GL_INVALID_ENUM: return "invalid enum";
		case GL_INVALID_VALUE: return "invalid value";
		case GL_INVALID_OPERATION: return "invalid operation";
		case GL_STACK_OVERFLOW: return "stack overflow";
		case GL_STACK_UNDERFLOW: return "stack underflow";
		case GL_OUT_OF_MEMORY: return "out of memory";
		default: return "unknown";
		}
	}
	
	public void loadIcon(String path){
		Texture tex = new Texture();
		tex.loadImage(path);
		ByteBuffer buffer = BufferUtils.createByteBuffer(tex.size * tex.size * 4);
		for(int y = 0; y < tex.size; y++){
			for(int x = 0; x < tex.size; x++){
            	int pixel = tex.data[x][y];
                buffer.put((byte) ((pixel >> 16) & 0xFF));
                buffer.put((byte) ((pixel >> 8) & 0xFF));
                buffer.put((byte) (pixel & 0xFF));
                buffer.put((byte) ((pixel >> 24) & 0xFF));
			}
		}
		buffer.flip();
		ByteBuffer[] b = {buffer};
		Display.setIcon(b);
	}
	
}

Texture class

package main;

import static org.lwjgl.opengl.GL11.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.imageio.ImageIO;

import org.lwjgl.BufferUtils;

public class Texture {
	int size = 0;
	int[][] data = new int[size][size];
	int texID = -1;
	
	public void loadImage(String path){
		try {
			BufferedImage img = ImageIO.read(new File(path));
			size = Math.max(img.getWidth(), img.getHeight());
			data = new int[size][size];
			for (int y = 0; y < size; y++) {
				for (int x = 0; x < size; x++) {
					if(x < img.getWidth() && y < img.getHeight())
						data[x][y] = img.getRGB(x, y);
					else data[x][y] = 0;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void bind(){
		if(texID == -1){
			ByteBuffer buffer = BufferUtils.createByteBuffer(size * size * 4);
			buffer.order(ByteOrder.nativeOrder());
			for(int y = 0; y < size; y++){
				for(int x = 0; x < size; x++){
	            	int pixel = data[x][y];
	                buffer.put((byte) ((pixel >> 16) & 0xFF));
	                buffer.put((byte) ((pixel >> 8) & 0xFF));
	                buffer.put((byte) (pixel & 0xFF));
	                buffer.put((byte) ((pixel >> 24) & 0xFF));
				}
			}
			buffer.flip();
			texID = glGenTextures();
			glBindTexture(GL_TEXTURE_2D, texID);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		}else{
			glBindTexture(GL_TEXTURE_2D, texID);
		}
	}
	
}

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

These are state that is stored in the currently bound texture. You need to call them for each texture when creating them (after binding them). Otherwise your textures default to the GL_LINEAR_MIPMAP_LINEAR min filtering, and since you haven’t generated or uploaded any mipmaps your texture is considered incomplete.

That fixes it, thanks a lot :slight_smile: