So you like Textures eh? Texturing Demo in JOGL.

So you’re back, and you’ve been wondering why did Greg leave me high and dry when the time came to actually put textures on the screen. Well something unfortunate happened that has been draining my time… I picked up Bioware’s Knight’s of the Old Republic and everytime I sat down to work on this tutorial, the call of the Jedi order got in the way :slight_smile: But fortunately I’ve reached a logical stopping point and have determined to finish this tutorial and get you folks going so the next game that I?m obsessed with is written in Java!

The first thing we want to do is come up with a class to encapsulate the texture itself. The reason I created this class is two-fold. First, I wanted to have something that I could quickly grab from a cache if I ever needed to refer to a texture or its information. The other reason I created this class is because there was something similar in LWJGL and I wanted to preserve that functionality so that I didn’t have to change too much of my code. The texture class is mostly boilerplate, storing the following properties:


       private String                          name;
      protected int                           width, height;
      protected int                           textureID;

       protected BufferedImage                 bufferedImage;
      protected int                           target;
      protected int                           srcPixelFormat;
      protected int                           dstPixelFormat;
      protected int                           minFilter;
      protected int                           magFilter;
      protected boolean                       wrap;
       protected boolean                       mipmapped;

One thing of importance for you as an OpenGL developer is the textureID. This is the textureID that you will bind to when you want a certain texture to be active. Also of importance is that the texture has a name. The reason I have a name here won?t be immediately obvious to you, but if you?ve ever dealt with a commercial engine or a real game you will quickly come to respect the value of being able to access and manipulate a texture by its name. Your artists will also like the fact that they can name textures (and when we get to the thing on loaders ? materials) and be able to access them in your tools.

There is only one method in this class that doesn?t deal with the actual texture data, and that is the bind method. This method is what you would call when you want to have that texture active (note I?m only talking about texturing in multipass, I will cover multitexture in the next tutorial).


      protected void bind( GL gl )
      {
            gl.glBindTexture( target, textureID );
      }

Cool, so now you have something that effectively wraps a texture. Now we will add some architecture to better handle textures as a whole. The first thing you will want to do is create your textures. You could set up you access methods such that Textures can be created directly, but from an architectural standpoint, that’s not all that great. I have created a class TextureFactory which has several methods for actually creating these Texture objects.

TextureFactory is a singleton and as such there is only ever one instance of the TextureFactory. If you’re not familiar with the Singleton Design Pattern you may want to pick up a book on Design Patterns because it is a very useful and effective pattern and some of my later tutorials will use it and other patterns heavily to reduce the amount of code being written and also to better organize that code in maintainable units.

Anyways, TextureFactory has one method for loading an Image from a file:


protected BufferedImage loadImage( String resourceName ) throws IOException
    {
        logger.debug("Loading resource [" + resourceName + "]");

        BufferedImage bufferedImage = ImageIO.read( new File( resourceName ));

            // Flip Image
            //
            AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
            tx.translate(0, -bufferedImage.getHeight(null));
            AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
            bufferedImage = op.filter(bufferedImage, null);

        return bufferedImage;
    }

You can see here that we are simply using ImageIO to load the texture data in as a BufferedImage. ImageIO is a fairly efficient way to load texture data from an InputStream. The next section of code you see you may not be familiar with. The section that starts with AffineTransform is flipping the image so that the image data is using the same coordinate system as OpenGL.

The next method of merit is the convertImageData method. This method will convert the BufferedImage into a ByteBuffer that we can use. It is important to note that an OpenGL texture is just a collection of bytes just like it is in C/C++. What we need to do is get this ByteBuffer organized in the right format so that when we render the texture we don’t get some gibberish. In a later version of the code you will see some of this section of code change, but I wanted to keep this simple so you could understand what?s going on so that you can be empowered enough to experiment and do cool things on your own.


protected ByteBuffer convertImageData( BufferedImage bufferedImage ) throws TextureFormatException
    {
        ByteBuffer imageBuffer = null;

        switch( bufferedImage.getType() )
        {
            case BufferedImage.TYPE_3BYTE_BGR:
                {
                    byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
                    imageBuffer = ByteBuffer.allocateDirect( data.length );
                    imageBuffer.order(ByteOrder.nativeOrder());
                    imageBuffer.put( data, 0, data.length );
                    break;
                }

            case BufferedImage.TYPE_INT_RGB:
                {
                    int[] data = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
                    imageBuffer.order(ByteOrder.nativeOrder());
                    imageBuffer.asIntBuffer().put(data, 0, data.length);
                    break;
                }

            default:
                throw new TextureFormatException("Unsupported image type " + bufferedImage.getType() );
        }


        return imageBuffer;
    }

Take a look at what’s going on in the case statement. We’re taking a look at the BufferedImages pixelformat and based on what type of format it has, we create the correct ByteBuffer. Finally, if we don’t support that texture format - we throw a meaningful exception so that we can catch it.

Now for the moment you’ve been waiting for, when you finally create that Texture. This is handled in the, wait for it, createTexture method.


      public Texture createTexture(       String name,
                                    String resourceName,
                                    int target,
                                    int srcPixelFormat,
                                    int dstPixelFormat,
                                    int minFilter,
                                    int magFilter,
                                    boolean wrap,
                                    boolean mipmapped ) throws IOException, TextureFormatException
      {
        logger.debug("Creating texture [" + name + "],[" + resourceName + "]");

          Texture texture = new Texture( name, target, srcPixelFormat, dstPixelFormat, minFilter, magFilter, wrap, mipmapped );


        // create the texture ID for this texture
        //
        int textureID = createTextureID();
        texture.setTextureID( textureID );

        // bind this texture
        //
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureID );

        // load the buffered image for this resource - save a copy to we can draw into it later
        //
        BufferedImage bufferedImage = loadImage( resourceName );
        texture.setBufferedImage( bufferedImage );

        // convert that image into a byte buffer of texture data
        //
        ByteBuffer textureBuffer = convertImageData( bufferedImage );

            // set up the texture wrapping mode depending on whether or not
            // this texture is specified for wrapping or not
            //
            int wrapMode = wrap ? GL.GL_REPEAT : GL.GL_CLAMP;

            if ( target == GL.GL_TEXTURE_2D )
            {
                  gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, wrapMode);
                  gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, wrapMode);
                  gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, minFilter);
                  gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, magFilter);
            }

        // create either a series of mipmaps of a single texture image based on what's loaded
        //
        if ( mipmapped )
        {
            glu.gluBuild2DMipmaps( target,
                                   dstPixelFormat,
                                   bufferedImage.getWidth(),
                                   bufferedImage.getHeight(),
                                   srcPixelFormat,
                                   GL.GL_UNSIGNED_BYTE,
                                   textureBuffer );
        }
        else
        {
            gl.glTexImage2D(target,
                          0,
                          dstPixelFormat,
                          bufferedImage.getWidth(),
                          bufferedImage.getHeight(),
                          0,
                          srcPixelFormat,
                          GL.GL_UNSIGNED_BYTE,
                          textureBuffer );
        }

            return texture;
      }

This is a really boring method, except that it does everything you need. This is all OpenGL goodness so I won’t explain too much of what’s going on here except to say that if you have questions - please ask and I’ll update.

Now for the final piece of architecture, the TextureManager. Having a TextureFactory that can create Texture objects is cool and all, but I wanted to be able to manage textures in an easier way. TextureManager contains an instance of the TextureFactory so you can say that it acts as a Façade (those Design Patterns again) for TextureFactory. The only class that you the developer would interact with is the TextureManager. The methods that you?d be using are createTexture() which calls the createTexture of the factory, createManagedTexture() which creates the texture and stores that Texture object , bindTexture() makes the named texture resident, and updateTexture() allows you to update the data that a texture refers to by uploading a new BufferedImage to it.

So that pretty much wraps up the architecture pieces. So how do you use it? We update our init() method to instantiate the TextureManager and create our texture(s).


public void init(GLDrawable drawable)
    {
        this.gl = drawable.getGL();
        this.glu = drawable.getGLU();
        this.glDrawable = drawable;


        this.glDrawable.setGL( new DebugGL(drawable.getGL() ));
        this.textureManager = TextureManager.getInstance( gl, glu );

        gl.glEnable( GL.GL_TEXTURE_2D );
        gl.glShadeModel( GL.GL_SMOOTH );

        try
        {
            textureManager.createManagedTexture("foo", "data/nehe.png", GL.GL_TEXTURE_2D, GL.GL_RGB, GL.GL_RGB, GL.GL_LINEAR, GL.GL_LINEAR, true, false );
        }
        catch( Exception e )
        {
            logger.error("Unable to load texture", e );
        }

        System.out.println("Init GL is " + gl.getClass().getName());
    }

And finally, the update to the display method where the texture is being bound for drawing and the texture being drawn.


public void display(GLDrawable drawable)
    {
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
        gl.glLoadIdentity();

        gl.glColor3f(1.0f, 0.0f, 0.0f );

        textureManager.bindTexture("foo");


        gl.glBegin( GL.GL_TRIANGLES );

            gl.glTexCoord2f( 0.0f, 0.0f );
            gl.glVertex3f( 0.0f, 0.0f, 0.0f );

            gl.glTexCoord2f( 1.0f, 0.0f );
            gl.glVertex3f( 1.0f, 0.0f, 0.0f );

            gl.glTexCoord2f( 1.0f, 1.0f );
            gl.glVertex3f( 1.0f, 1.0f, 0.0f );
        gl.glEnd();
    }

And there you have it. One textured triangle.

Texture.java


import net.java.games.jogl.GL;
import org.apache.log4j.Logger;

import java.awt.image.BufferedImage;

public class Texture
{
      private static Logger                            logger = Logger.getLogger("Texture");

    private String                          name;
      protected int                           width, height;
      protected int                           textureID;

    protected BufferedImage                 bufferedImage;
      protected int                           target;
      protected int                           srcPixelFormat;
      protected int                           dstPixelFormat;
      protected int                           minFilter;
      protected int                           magFilter;
      protected boolean                       wrap;
    protected boolean                       mipmapped;

      public Texture( String name, int target, int srcPixelFormat,
                          int dstPixelFormat, int minFilter, int magFilter,
                    boolean wrap, boolean mipmapped)
      {
            this.name = name;
            this.target = target;
            this.srcPixelFormat = srcPixelFormat;
            this.dstPixelFormat = dstPixelFormat;
            this.minFilter = minFilter;
            this.magFilter = magFilter;
            this.wrap = wrap;
        this.mipmapped = mipmapped;
      }

      public String getName()
      {
            return name;
      }

      public void setName(String name)
      {
            this.name = name;
      }

    public BufferedImage getBufferedImage()
    {
        return bufferedImage;
    }

    public void setBufferedImage(BufferedImage bufferedImage)
    {
        this.bufferedImage = bufferedImage;
    }

      public int getWidth()
      {
            return width;
      }

      public void setWidth(int width)
      {
            this.width = width;
      }

      public int getHeight()
      {
            return height;
      }

      public void setHeight(int height)
      {
            this.height = height;
      }

      public int getTextureID()
      {
            return textureID;
      }

      public void setTextureID(int textureID)
      {
            this.textureID = textureID;
      }

      public int getTarget()
      {
            return target;
      }

      public void setTarget(int target)
      {
            this.target = target;
      }

      public int getSrcPixelFormat()
      {
            return srcPixelFormat;
      }

      public void setSrcPixelFormat(int srcPixelFormat)
      {
            this.srcPixelFormat = srcPixelFormat;
      }

      public int getDstPixelFormat()
      {
            return dstPixelFormat;
      }

      public void setDstPixelFormat(int dstPixelFormat)
      {
            this.dstPixelFormat = dstPixelFormat;
      }

      public int getMinFilter()
      {
            return minFilter;
      }

      public void setMinFilter(int minFilter)
      {
            this.minFilter = minFilter;
      }

      public int getMagFilter()
      {
            return magFilter;
      }

      public void setMagFilter(int magFilter)
      {
            this.magFilter = magFilter;
      }

      public boolean isWrap()
      {
            return wrap;
      }

      public void setWrap(boolean wrap)
      {
            this.wrap = wrap;
      }

    public boolean isMipmapped()
    {
        return mipmapped;
    }

    public void setMipmapped(boolean mipmapped)
    {
        this.mipmapped = mipmapped;
    }

      protected void bind( GL gl )
      {
            gl.glBindTexture( target, textureID );
      }

}

TextureFactory.java


import net.java.games.jogl.GL;
import net.java.games.jogl.GLU;
import org.apache.log4j.Logger;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.AffineTransformOp;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class TextureFactory
{
    private static Logger           logger = Logger.getLogger("TextureFactory");
    private static TextureFactory   instance;


    private GLU                     glu;
    private GL                      gl;

    protected TextureFactory( GL gl, GLU glu )
    {
        this.gl = gl;
        this.glu = glu;
    }

    public static synchronized TextureFactory getFactory( GL gl, GLU glu )
    {
        if ( instance == null )
        {
            instance = new TextureFactory( gl, glu );
        }

        return instance;

    }

    protected BufferedImage loadImage( String resourceName ) throws IOException
    {
        logger.debug("Loading resource [" + resourceName + "]");

        BufferedImage bufferedImage = ImageIO.read( new File( resourceName ));

            // Flip Image
            //
            AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
            tx.translate(0, -bufferedImage.getHeight(null));
            AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
            bufferedImage = op.filter(bufferedImage, null);

        return bufferedImage;
        //return  ImageIO.read( getClass().getClassLoader().getResourceAsStream( resourceName ));
    }

    protected ByteBuffer convertImageData( BufferedImage bufferedImage ) throws TextureFormatException
    {
        ByteBuffer imageBuffer = null;

        switch( bufferedImage.getType() )
        {
            case BufferedImage.TYPE_3BYTE_BGR:
            case BufferedImage.TYPE_CUSTOM:
                {
                    byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
                    imageBuffer = ByteBuffer.allocateDirect( data.length );
                    imageBuffer.order(ByteOrder.nativeOrder());
                    imageBuffer.put( data, 0, data.length );
                    break;
                }

            case BufferedImage.TYPE_INT_RGB:
                {
                    int[] data = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
                    imageBuffer.order(ByteOrder.nativeOrder());
                    imageBuffer.asIntBuffer().put(data, 0, data.length);
                    break;
                }

            default:
                throw new TextureFormatException("Unsupported image type " + bufferedImage.getType() );
        }


        return imageBuffer;
    }

    protected int createTextureID()
    {
        int[] tmp = new int[1];
        gl.glGenTextures(1, tmp);
        return tmp[0];
    }

      public Texture createTexture(       String name,
                                    String resourceName,
                                    int target,
                                    int srcPixelFormat,
                                    int dstPixelFormat,
                                    int minFilter,
                                    int magFilter,
                                    boolean wrap,
                                    boolean mipmapped ) throws IOException, TextureFormatException
      {
        logger.debug("Creating texture [" + name + "],[" + resourceName + "]");

          Texture texture = new Texture( name, target, srcPixelFormat, dstPixelFormat, minFilter, magFilter, wrap, mipmapped );


        // create the texture ID for this texture
        //
        int textureID = createTextureID();
        texture.setTextureID( textureID );

        // bind this texture
        //
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureID );

        // load the buffered image for this resource - save a copy to we can draw into it later
        //
        BufferedImage bufferedImage = loadImage( resourceName );
        texture.setBufferedImage( bufferedImage );

        // convert that image into a byte buffer of texture data
        //
        ByteBuffer textureBuffer = convertImageData( bufferedImage );

            // set up the texture wrapping mode depending on whether or not
            // this texture is specified for wrapping or not
            //
            int wrapMode = wrap ? GL.GL_REPEAT : GL.GL_CLAMP;

            if ( target == GL.GL_TEXTURE_2D )
            {
                  gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, wrapMode);
                  gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, wrapMode);
                  gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, minFilter);
                  gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, magFilter);
            }

        // create either a series of mipmaps of a single texture image based on what's loaded
        //
        if ( mipmapped )
        {
            glu.gluBuild2DMipmaps( target,
                                   dstPixelFormat,
                                   bufferedImage.getWidth(),
                                   bufferedImage.getHeight(),
                                   srcPixelFormat,
                                   GL.GL_UNSIGNED_BYTE,
                                   textureBuffer );
        }
        else
        {
            gl.glTexImage2D(target,
                          0,
                          dstPixelFormat,
                          bufferedImage.getWidth(),
                          bufferedImage.getHeight(),
                          0,
                          srcPixelFormat,
                          GL.GL_UNSIGNED_BYTE,
                          textureBuffer );
        }

            return texture;
      }

    public void updateTexture( Texture texture, BufferedImage bufferedImage ) throws TextureFormatException
    {
        logger.debug("Updating texture [" + texture.getName() + "]");


        // bind this texture
        //
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture.getTextureID() );

        ByteBuffer textureBuffer = convertImageData( bufferedImage );

        // create either a series of mipmaps of a single texture image based on what's loaded
        //
        if ( texture.isMipmapped() )
        {
            glu.gluBuild2DMipmaps( texture.getTarget(),
                                   texture.getDstPixelFormat(),
                                   bufferedImage.getWidth(),
                                   bufferedImage.getHeight(),
                                   texture.getSrcPixelFormat(),
                                   GL.GL_UNSIGNED_BYTE,
                                   textureBuffer );
        }
        else
        {
            gl.glTexImage2D(texture.getTarget(),
                          0,
                          texture.getDstPixelFormat(),
                          bufferedImage.getWidth(),
                          bufferedImage.getHeight(),
                          0,
                          texture.getSrcPixelFormat(),
                          GL.GL_UNSIGNED_BYTE,
                          textureBuffer );
        }
    }

}

TextureFormatException.java


public class TextureFormatException extends Exception
{
    public TextureFormatException()
    {
        super();
    }

    public TextureFormatException( String msg )
    {
        super( msg );
    }
}

TextureManager.java


import net.java.games.jogl.GL;
import net.java.games.jogl.GLU;
import org.apache.log4j.Logger;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class TextureManager
{
      private static Logger                                  logger = Logger.getLogger("TextureManager");

      private GL                                                    gl;
      private GLU                                                    glu;

    private Map                                 textures = new HashMap();
    private TextureFactory                      textureFactory;

    private static TextureManager               instance;

      protected TextureManager( GL gl, GLU glu )
      {
            this.gl = gl;
            this.glu = glu;

        textureFactory = TextureFactory.getFactory( gl, glu );
      }

    public static synchronized TextureManager getInstance( GL gl, GLU glu )
    {
        if ( instance == null )
        {
            instance = new TextureManager( gl, glu );
        }

        return instance;
    }

      public void bindTexture( String name )
      {
            ((Texture)textures.get( name )).bind(gl);
      }

    public void updateTexture( String name, BufferedImage image ) throws TextureFormatException
    {
        textureFactory.updateTexture( (Texture)textures.get( name ), image );
    }

    public void manageTexture( Texture texture )
    {
        logger.debug("Managing texture [" + texture.getName() + "]" );

        textures.put( texture.getName(), texture );
    }

      public Texture createTexture(       String name,
                                    String resourceName,
                                    int target,
                                    int srcPixelFormat,
                                    int dstPixelFormat,
                                    int minFilter,
                                    int magFilter,
                                    boolean wrap,
                                    boolean mipmapped ) throws IOException, TextureFormatException
    {
        return textureFactory.createTexture( name, resourceName, target, srcPixelFormat,
                                      dstPixelFormat, minFilter, magFilter, wrap, mipmapped );
    }

      public Texture createManagedTexture(       String name,
                                            String resourceName,
                                            int target,
                                            int srcPixelFormat,
                                            int dstPixelFormat,
                                            int minFilter,
                                            int magFilter,
                                            boolean wrap,
                                            boolean mipmapped ) throws IOException, TextureFormatException
    {
        Texture texture = textureFactory.createTexture( name, resourceName, target, srcPixelFormat,
                                                        dstPixelFormat, minFilter, magFilter, wrap, mipmapped );

        manageTexture( texture );

        return texture;
    }

}

TestRenderer.java


import com.sojournermobile.engine.texture.TextureManager;
import net.java.games.jogl.*;
import org.apache.log4j.Logger;

public class TestRenderer implements GLEventListener
{
    private static Logger               logger = Logger.getLogger("TestRenderer");
    private GL                          gl;
    private GLU                         glu;
    private GLDrawable                  glDrawable;
    private TextureManager              textureManager;

    public void init(GLDrawable drawable)
    {
        this.gl = drawable.getGL();
        this.glu = drawable.getGLU();
        this.glDrawable = drawable;


        this.glDrawable.setGL( new DebugGL(drawable.getGL() ));
        this.textureManager = TextureManager.getInstance( gl, glu );

        gl.glEnable( GL.GL_TEXTURE_2D );
        gl.glShadeModel( GL.GL_SMOOTH );

        try
        {
            textureManager.createManagedTexture("foo", "data/nehe.png", GL.GL_TEXTURE_2D, GL.GL_RGB, GL.GL_RGB, GL.GL_LINEAR, GL.GL_LINEAR, true, false );
        }
        catch( Exception e )
        {
            logger.error("Unable to load texture", e );
        }

        System.out.println("Init GL is " + gl.getClass().getName());
    }

    public void display(GLDrawable drawable)
    {
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
        gl.glLoadIdentity();

        gl.glColor3f(1.0f, 0.0f, 0.0f );

        textureManager.bindTexture("foo");


        gl.glBegin( GL.GL_TRIANGLES );

            gl.glTexCoord2f( 0.0f, 0.0f );
            gl.glVertex3f( 0.0f, 0.0f, 0.0f );

            gl.glTexCoord2f( 1.0f, 0.0f );
            gl.glVertex3f( 1.0f, 0.0f, 0.0f );

            gl.glTexCoord2f( 1.0f, 1.0f );
            gl.glVertex3f( 1.0f, 1.0f, 0.0f );
        gl.glEnd();
    }

    public void reshape(GLDrawable drawable, int x, int y, int width, int height)
    {
    }

    public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged)
    {
    }

}

This is great ;D

Some feedback, I guess the TextureManager will be used by a lot of opengl (me included :wink: and/or java newbies so maybe it would be a good idea to include some assert’s in the most important methods to catch common misstakes? I guess you guru’s can probably figure out real quick where most misstakes might happen!

will this work with all sort of pixel formats (from the input texture). is there a way of setting the texture fast! as in if i wanted to do a movie texture.

just wondered if i could make a QuickTime texture. i can get a BufferedImage from QuickTime- bit slow mind.

arrrr- i will try it- thanks for your texture code dude. its loads neater then mine :).

[quote]This is great ;D

Some feedback, I guess the TextureManager will be used by a lot of opengl (me included :wink: and/or java newbies so maybe it would be a good idea to include some assert’s in the most important methods to catch common misstakes? I guess you guru’s can probably figure out real quick where most misstakes might happen!
[/quote]
Thanks for your feedback,

You’re right. I will take a look at the best place to add assertions and NPE checks and update this code. The next version of this code will include multitexture unit multitexturing.

[quote]will this work with all sort of pixel formats (from the input texture). is there a way of setting the texture fast! as in if i wanted to do a movie texture.

just wondered if i could make a QuickTime texture. i can get a BufferedImage from QuickTime- bit slow mind.

arrrr- i will try it- thanks for your texture code dude. its loads neater then mine :).
[/quote]
Thanks for your feedback.

It won’t work with all of the pixel formats yet, but I’m working on that right now and within the next few days I should have the bulk of the formats covered as well as an example that would handle animation from a series of textures to do movie stuff. It won’t really touch on using QuickTime movies per say (but you should be able to get the goods from the QuickTime for java classes) since Linux doesn’t support it (QT4J), but at the end of that demo you will be able to make an OpenGL media player pretty easily.

top dude!

YUV would be cool :wink: - get realtime textures from video input then. guess JMF would cover that also. wonder how fast it would be? i use QT4J because it works well with all media formats [also media devices]. but indeed its not a happy Lunix world…

i will play with it today see where i get. JMF is prob better when it comes to crossplatform- wonder how good JMF is on MacOSX mind :wink:

cheers dude - top stuff if we had a all image loader… u the man…

JMF and OSX ??? :slight_smile: Will be funny that at least for the little tidbits we’re supporting, we’ll be more crossplatform than Sun’s own standard API. It has always always surprised me that an engine like JOGL isn’t what all of the Sun GUI infrastructure sits on top of. If it would have been designed that way from the start, Java would already be hardware accelerated and there would have been large games in Java ages ago.

i second that! ;D

Since Sun is working on OpenGL acceleration for Swing on Linux, I wonder why not use JOGL as the binding and ditch the DirectX acceleration on Windows. They will end up sharing more code between implementations and JOGL will get more attention. Not to mention that would pull JOGL into the core JRE.

Actually there are probably a lot of internal Sun policies that would make JOGL in the core more of a drawback… The “core” JOGL certainly wouldn’t change
(as in new features & fixes) as often as what we have now if that were the case.

[quote]TextureFactory.java
[/quote]
Thanks for the starter help. :slight_smile:

The flipping doesn’t work for me. If however I change the filter statement to the following:


  BufferedImage newImage = op.filter(bufferedImage, null);
  return newImage;

it works fine.

One second thought. What’s the meaning of the NIO buffer usage please in the convertImageData method? To cope with different file formats? If, say, I only need PNG files, could I omit it?


byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
gluBuild2DMipmaps(..., byte) or glTexImage2D(..., byte);

This works fine here, however what’s its shortcoming?

Thanks.

well a thing i seem to get errors on within ‘convertImageData’ is this:

BufferedImage.TYPE_INT_RGB:

First i got a NullPointerException eek! then i added the line:

imageBuffer = ByteBuffer.allocateDirect(data.length);

now i get a BufferOverflowException. anyone got any ideas why? its a normal BufferedImage of TYPE_INT_RGB. all is cool… but for this little minx error…

oh i can see some very cool stuff if this worked :wink:

and yep i am using your :

BufferedImage bi = qtt.getQT2BufferedImage();
System.out.println("bi: " + bi);
textureManager.updateTexture(“foo”, bi);

the BufferedImage ‘bi’ prints out:

bi: BufferedImage@1175422: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 128 height = 128 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

your custom buffered image is more indepth. i guess it has to be. but i dont see why we should worry about this bit, but hers a bebug of a simple CUSTOM BufferedImage:

BufferedImage.TYPE_CUSTOM: start: BufferedImage@1081d2e: type = 5 ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@1b3f829 transparency = 1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 128 height = 128 #numDataElements 3 dataOff[0] = 2

As u can see the types are all correct in the Images. So i am stuck at what it could be. any ideas would be helpful.

tip tops

ok i’m in the dark now:

case BufferedImage.TYPE_INT_RGB: {
IntBuffer intBuffer = null;
System.out.println("BufferedImage.TYPE_INT_RGB: start: " +
bufferedImage);
int[] data = ((DataBufferInt)bufferedImage.getRaster().getDataBuffer()).
getData();
System.out.println("BufferedImage.TYPE_INT_RGB: 1: " + data.length);
intBuffer = intBuffer.allocate(data.length);
intBuffer.put(data, 0, data.length);
System.out.println("BufferedImage.TYPE_INT_RGB: 2: " + imageBuffer);
imageBuffer = ByteBuffer.allocateDirect(data.length);
imageBuffer.order(ByteOrder.nativeOrder());
imageBuffer.asIntBuffer().put(intBuffer);
System.out.println("BufferedImage.TYPE_INT_RGB: 3: " + imageBuffer);
System.out.println("BufferedImage.TYPE_INT_RGB: done: " + imageBuffer);
break;
}

output:

BufferedImage.TYPE_INT_RGB: start: BufferedImage@c931fc: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 128 height = 128 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

BufferedImage.TYPE_INT_RGB: 1: 16384

BufferedImage.TYPE_INT_RGB: 2: null

BufferedImage.TYPE_INT_RGB: 3: java.nio.DirectByteBuffer[pos=0 lim=16384 cap=16384]

BufferedImage.TYPE_INT_RGB: done: java.nio.DirectByteBuffer[pos=0 lim=16384 cap=16384]

– real works: java.nio.DirectByteBuffer[pos=0 lim=16384 cap=16384]

An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0xF7844AB
Function=[Unknown.]
Library=(N/A)

NOTE: We are unable to locate the function name symbol for the error
just occurred. Please refer to release documentation for possible
reason and solutions.

Current Java thread:
at net.java.games.jogl.impl.windows.WindowsGLImpl.glTexImage2D(Native Method)
at ant.games.texture.TextureFactory.buildTexture(TextureFactory.java:206)
at ant.games.texture.TextureFactory.createTexture(TextureFactory.java:116)
at ant.games.texture.TextureManager.createManagedTexture(TextureManager.java:100)
at ant.games.texture.RenderCanvas.init(RenderCanvas.java:45)
at net.java.games.jogl.impl.GLDrawableHelper.init(GLDrawableHelper.java:68)
at net.java.games.jogl.GLCanvas$InitAction.run(GLCanvas.java:184)
at net.java.games.jogl.impl.windows.WindowsGLContext.makeCurrent(WindowsGLContext.java:127)
- locked <02FA5320> (a net.java.games.jogl.impl.windows.WindowsOnscreenGLContext)
at net.java.games.jogl.impl.windows.WindowsOnscreenGLContext.makeCurrent(WindowsOnscreenGLContext.java:107)
- locked <02FA5320> (a net.java.games.jogl.impl.windows.WindowsOnscreenGLContext)
at net.java.games.jogl.impl.GLContext.setRenderingThread(GLContext.java:247)
- locked <02FA5320> (a net.java.games.jogl.impl.windows.WindowsOnscreenGLContext)
at net.java.games.jogl.GLCanvas.setRenderingThread(GLCanvas.java:149)
at net.java.games.jogl.Animator$1.run(Animator.java:87)
at java.lang.Thread.run(Thread.java:536)

i dont no… ANYONE?

Yes you could omit it if you don’t use or plan to use other formats.

I need to think about that. You seem to be getting a strangely different behavior than what I’m seeing on Windows or OSX.