Newbie question: textures being rendered as white quads

Hi folks,

I’m loading a PNG texture to use as a sprite, using TextureIO and Texture class from JOGL.

Turns out that when I render the sprite, it’s a white quad! Code that renders is the following:

Sprite.java


/**
     * Draw the sprite at the specified location
     *
     * @param x The x location at which to draw this sprite
     * @param y The y location at which to draw this sprite
     */
    public void draw(int x, int y) {
        
        GL gl = Game.getRenderer().getGL();
        
        gl.glPushMatrix();
        
        texture.bind();
        
        gl.glTranslatef(x, y, 0);
        
        gl.glBegin(GL.GL_QUADS); 
        {
            gl.glTexCoord2f(0, 0);
            gl.glVertex2f(0, 0);
            gl.glTexCoord2f(0, texture.getHeight());
            gl.glVertex2f(0, height);
            gl.glTexCoord2f(texture.getWidth(), texture.getHeight());
            gl.glVertex2f(width, height);
            gl.glTexCoord2f(texture.getWidth(), 0);
            gl.glVertex2f(width, 0);
        }
        gl.glEnd();
        
        gl.glPopMatrix();
        
    }

GameRenderer.java, using active rendering:


/**
 * GameRenderer.java
 */

package com.rghartmann.game;

import com.rghartmann.game.state.GameStateManager;
import com.rghartmann.game.state.impl.MainGameState;
import java.awt.*;

import javax.media.opengl.*;
import javax.media.opengl.glu.*;

public final class GameRenderer extends Canvas implements Runnable {
    
    /**
     * Frame skipping control
     */
    private static final int NO_DELAYS_PER_YIELD = 16;
    private static int MAX_FRAME_SKIPS = 5;
    
    /**
     * Top level window and period
     */
    private Game game;
    private long period;
    
    /**
     * Updater and state management
     */
    private Thread updater;
    private volatile boolean running = false;
    private volatile boolean paused = false;
    
    /**
     * OpenGL stuff
     */
    private GLDrawable drawable;
    private GLContext context;
    private GL gl;
    private GLU glu;
    
    /**
     * Window sizing and resizing
     */
    private boolean resized = false;
    private int width;
    private int height;
    
    /**
     *
     */
    public GameRenderer(Game game,
            long period,
            int width,
            int height,
            GraphicsConfiguration config,
            GLCapabilities caps) {
        
        super(config);
        
        this.game = game;
        this.period = period;
        
        this.width = width;
        this.height = height;
        
        drawable = GLDrawableFactory.getFactory().getGLDrawable(this, caps, null);
        context = drawable.createContext(null);
        
    }
    
    public GL getGL() {
        return gl;
    }
    
    public void addNotify() {
        super.addNotify();
        drawable.setRealized(true);
        if (updater == null || !running) {
            updater = new Thread(this);
            updater.start();
        }
    }
    
    public void resumeGame() {  paused = false; }
    
    public void pauseGame() { paused = true; }
    
    public void stopGame() { running = false; }
    
    public void reshape(int w, int h) {
        resized = true;
        if (h == 0) h = 1;
        width = w; height = h;
    }
    
    public void run() {
        
        initRender();
        loop();
        
        context.destroy();
        System.exit(0);
    }
    
    private void makeContentCurrent() {
        try {
            while (context.makeCurrent() == GLContext.CONTEXT_NOT_CURRENT) {
                System.out.println("Context not yet current...");
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private void initRender() {
        
        makeContentCurrent();
        
        gl = context.getGL();
        glu = new GLU();
        
        // Initialize the resource manager
        ResourceManager.getInstance().initialize(gl);
        
        // MainGameState (should be initialized somewhere else)
        GameStateManager.getInstance().addState(new MainGameState(), true);
        
        resizeView();
        
        gl.glClearColor(0.2f, 0.7f, 0.9f, 0.0f);
        
        gl.glMatrixMode(GL.GL_PROJECTION);
        
        gl.glPushMatrix();
        
        gl.glLoadIdentity();
        
        gl.glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
        
        gl.glMatrixMode(GL.GL_MODELVIEW);
        
        gl.glPushMatrix();
        
        gl.glLoadIdentity();
        
        gl.glDisable(GL.GL_DEPTH_TEST);
        
        gl.glEnable(GL.GL_BLEND);
        
        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
        
        context.release();
    }
    
    private void resizeView() {
        
        gl.glMatrixMode(GL.GL_PROJECTION);
        
        gl.glLoadIdentity();
        
        gl.glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
    }
    
    private void loop() {
        
        long before, after, delta, sleep;
        long overSleep = 0L;
        long excess = 0L;
        int noDelays = 0;
        
        before = System.nanoTime();
        running = true;
        while ( running ) {
            
            after = System.nanoTime();
            delta = after - before;
            sleep = (period - delta) - overSleep;
            
            makeContentCurrent();
            
            update(delta);
            render(delta);
            
            drawable.swapBuffers();
            
            if (sleep > 0) {
                try {
                    Thread.sleep(sleep/1000000L);
                } catch(InterruptedException ex){}
                overSleep = (System.nanoTime() - after) - sleep;
            } else {
                excess -= sleep;
                overSleep = 0L;
                if (++noDelays >= NO_DELAYS_PER_YIELD) {
                    Thread.yield();
                    noDelays = 0;
                }
            }
            
            before = System.nanoTime();
            
            // Frame skipping
            int skips = 0;
            while((excess > period) && (skips < MAX_FRAME_SKIPS)) {
                excess -= period;
                update(delta);
                skips++;
            }
            
            context.release();
        }
        
    }
    
    private void update(long delta) {
        
        // update current game state
        if ( !paused ) {
            GameStateManager.getInstance().getCurrent().update(delta);
        }
    }
    
    private void render(long delta) {
        
        if (context.getCurrent() == null) {
            System.out.println("Current context is null");
            System.exit(0);
        }
        
        if (resized) {
            resizeView();
            resized = false;
        }
        
        // clear colour and depth buffers
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        // render current game state
        GameStateManager.getInstance().getCurrent().render(delta);
        
        gl.glFlush();
    }
    
}

The update() and render() methods are in my GameState class. They are empty methods, and all render() does is calling draw(0, 0) on a Sprite instance in that class.

Thanks in advance for any help or critic. References to readings that might help me out are also appreciated =D

Son Of Cain

Take a look at the demos.texture.TestTexture demo, in particular how it chooses the texture coordinates for the quad being used to render the texture. Post again if you need more help.

Should you be calling texture.enable() instead of/as well as texture.bind()?

Edit:
Only because I don’t see a gl.glEnable( GL.GL_TEXTURE_2D ) anywhere…

Hi guys,

I’ve added the glEnable(GL.GL_TEXTURE_2D) line to the initRender method, and it did’nt change anything. Also when using enable() on the texture as well.

I’ve downloaded the demo source code, but I’m at work right now - gotta take a look at it later and see what I’m missing. So far, I just switched my Quad code with the one in the demo, and now, it produces nothing on the screen =/

Thanks for the help!

Son Of Cain

If you create your texture without mipmaps and then enable mipmaps you can end up with untextured geometry.

No, I don’t generate mipmaps for the textures when loading them. My loading code is the following:


private Texture loadTexture(String filename) {
        try {
            
            Texture texture = TextureIO.newTexture(ResourceManager.class.getResourceAsStream(filename), false, null);
            texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
            texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
            return texture;
            
        } catch (GLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return null;
    }

Son Of Cain

Unless you’re using a funky non-PO2 extension, those texture coords should be in the range of [0,1] rather than [0, width] and [0, height].

Thats probably not your actual problem though.

Being the newbie I am, I’ve no clue of what you’re talking about, Orangy ;D

I have toyed with the demo, but couldn’t see any particular reason why my code does not works. Obviously, I’m messing around with OpenGL calls, but I the tutorials I have read also use it in the same way my code does…

I’m lost =/

Standard texture coordinates go from [0.0,1.0]. Non-power of 2 textures go from [0,width or height]. You probably want to call getImageTexCoords() rather than getWidth() and getHeight().

Oh, got PO2 -> Power of 2. Err… English is not my native language =/

I already changed that, as pointed in the demo Ken suggested for me. Thankns for pointing that out, guys, I didn’t know about it.

Still struggling with my code to make it work =D

Nevermind, solved!

After I changed the code for use of TextureCoords, I left a small typo in one of the gl.glVertex2f() calls… :-[

Thanks for the support!