Creating BufferedImage's for Textures

I’m struggling to understand how to create a BufferedImage for drawing onto, and then how to use this image as a texture.

I’ve tried looking at Chris Adamson’s ‘Jumping Into JOGL’ article, in which he goes through a number of steps of creating rasters and colour models, etc… From this code I have been able to create a BufferedImage draw onto it, and then draw those pixels to the screen with a glDrawPixels call. All attempts to draw this image to a texture result in a wacky screwed-up looking texture.

I’ve also tried using the code from the jogl version of NeHe tutorial #6, but this code wants to load from a file, rather than create a BufferedImage from scratch, and I’m left with the same problems.

So, if someone could please help me to understand how to create a BufferedImage (with alpha) for drawing on with it’s Graphics object, and then how to apply this image to a texture, that would be a huge help.

Thanks in advance,
Brian.

Digging through this code might help a bit:

http://wiki.java.net/bin/view/Games/TextureLoadingExample

Kev

I’m looking at it now… It’s designed for loading an image from file; I need to create and draw on one in memory. I’ve been banging my head against this for quite a while now–long enough to convince myself I’m not getting anywhere. If someone could please take the time to look into my issues that would be incredibly helpful.

I’ll post my non-working code below. The problems I’m getting are somewhat bizarre. I’ll do my best to describe them:

The texture I’m creating is a red half-alpha background, with a blue circle in the top-left corner.
Drawing pixels to the screen with glDrawPixels works fine.
Drawing pixels to a texture doesn’t work: substituting the same image bytes used to draw to screen into the nehe jogl tutorial results in a garbled texture. the image is mostly black with the circle repeated 3 times. it seems like something is going wrong with the channels. A screenshot of the textured cube is here: http://www.zooid.org/~liminal/joglHelp/nehe6.png

I’ve tried drawing to screen and drawing to a textured quad. What I find is that the image draws properly to the screen the first time, the texture draws entirely black, and then the second time display is called the blue circle in the screen-drawn texture is black too (instead of blue)!

This might be hard to follow, so i’ve made a few more screen shots:
http://www.zooid.org/~liminal/joglHelp/test2before.png
is the screen pixels and the textured quad on first display.
http://www.zooid.org/~liminal/joglHelp/test2after.png
is the screen pixels with the blue now black and the textured quad on the second or third display call.

Here’s the code:


public class JOGLTest2 extends Frame implements GLEventListener {

      public static final Dimension PREFERRED_FRAME_SIZE = new Dimension (450,375);

      int[] textureNames;
      
      BufferedImage img;
      ByteBuffer imgBuf;
      
      private float xrot;                        // X Rotation ( NEW )
      private float yrot;                        // Y Rotation ( NEW )
      private float zrot;                        // Z Rotation ( NEW )

      /**
       * 
       */
      public JOGLTest2() {
//System.out.println("library path: " + System.getProperty("java.library.path"));
            GLCapabilities caps = new GLCapabilities();
            GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(caps);
            canvas.addGLEventListener(this);
            add (canvas, BorderLayout.CENTER);
      }


      /* (non-Javadoc)
       * @see java.awt.Component#getPreferredSize()
       */
      public Dimension getPreferredSize() {
            return PREFERRED_FRAME_SIZE;
      }



      /* (non-Javadoc)
       * @see net.java.games.jogl.GLEventListener#init(net.java.games.jogl.GLDrawable)
       */
      public void init(GLDrawable drawable) {
            GL gl = drawable.getGL();
            gl.glShadeModel(GL.GL_SMOOTH);
            gl.glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
            gl.glColor3f( 0.0f, 0.0f, 0.0f ); 
            gl.glPointSize(4.0f);

            gl.glClearDepth(1.0f);
            gl.glDepthFunc(GL.GL_LEQUAL);
            gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
            gl.glEnable(GL.GL_TEXTURE_2D);


            img = createImage2(256);
            byte[] bytes = JOGLTest.getImageBytes(img);
            imgBuf = ByteBuffer.allocateDirect(bytes.length);
            imgBuf.order(ByteOrder.nativeOrder());
            imgBuf.put(bytes);
            textureNames = new int[1];
            gl.glGenTextures(1, textureNames);
            gl.glBindTexture(GL.GL_TEXTURE_2D, textureNames[0]);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
      }

      /* (non-Javadoc)
       * @see net.java.games.jogl.GLEventListener#reshape(net.java.games.jogl.GLDrawable, int, int, int, int)
       */
      public void reshape(GLDrawable drawable, int x, int y, int width, int height) {
            GL gl = drawable.getGL(); 
            GLU glu = drawable.getGLU(); 
            
            if (height <= 0)
                  height = 1;
            float h = (float) width / (float) height;
            gl.glViewport(0, 0, width, height ); 
            gl.glMatrixMode(GL.GL_PROJECTION);  
            gl.glLoadIdentity();
//            glu.gluOrtho2D(0.0, 450.0, 0.0, 375.0);
            glu.gluPerspective(45.0f, h, 1.0, 20.0);
            gl.glMatrixMode(GL.GL_MODELVIEW);
            gl.glLoadIdentity();
      }

      /* (non-Javadoc)
       * @see net.java.games.jogl.GLEventListener#displayChanged(net.java.games.jogl.GLDrawable, boolean, boolean)
       */
      public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {
            System.out.println ("displayChanged()");
      }
      
      /* (non-Javadoc)
       * @see net.java.games.jogl.GLEventListener#display(net.java.games.jogl.GLDrawable)
       */
      public void display(GLDrawable drawable) {
            GL gl = drawable.getGL();
            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
            gl.glLoadIdentity();                                                      // Reset The View
            gl.glTranslatef(0.0f, 0.0f, -5.0f);
            
            gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
            gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
            gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
            
            
            gl.glDrawPixels(img.getWidth(), img.getHeight(), GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, imgBuf);
            gl.glBindTexture(GL.GL_TEXTURE_2D, textureNames[0]);
            gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, img.getWidth(), img.getHeight(), 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, imgBuf);
            
            gl.glBegin(GL.GL_QUADS);
            // Front Face
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex3f(-1.0f, -1.0f, 1.0f);
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex3f(1.0f, -1.0f, 1.0f);
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex3f(1.0f, 1.0f, 1.0f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex3f(-1.0f, 1.0f, 1.0f);
            gl.glEnd();

            xrot += 0.3f;
            yrot += 0.2f;
            zrot += 0.4f;
      }
      
      public static BufferedImage createImage2(int size) {
            int width = size;
            int height = size;
            
            WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 4, null);
            ComponentColorModel colorModel = 
                  new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 
                                                      new int[] {8,8,8,8}, true, false, 
                                                      ComponentColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE);
            BufferedImage bimg = new BufferedImage(colorModel, raster, false, null);
            
            AffineTransform gt = new AffineTransform();
            gt.translate(0, bimg.getHeight());
            gt.scale(1d, -1d);
            
            Graphics2D g = bimg.createGraphics();
            g.transform(gt);
            
            g.setPaint(new Color(1f, 0f, 0f, 0.5f));
            g.fillRect(0, 0, size, size);
            g.setPaint(Color.BLUE);
            g.fillOval(size/4, size/4, size/4, size/4);
            
            return bimg;
      }

      
      public static void main(String[] args) {
            Frame f = new JOGLTest2();
            f.addWindowListener(new WindowAdapter() {
                  public void windowClosing(WindowEvent e) {
                        System.exit(0);
                  }
            });
            f.pack();
            f.setVisible(true);
      }

}


The code in the Wiki reads an image from a file yes. However, it reads the files and then sticks it in a BufferedImage, which it then converts to a texture.

Assuming you’re creating an image in a BufferedImage in memory you should just be able to reuse the second part of the code.

EDIT:

From the looks of your code you need to move the


gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, img.getWidth(), img.getHeight(), 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, imgBuf); 

into the initalise() since it only wants to be done once.

Kev

Thanks Kev,

I’ve mostly fixed things by changing the blending settings.

Thanks for the teximage2d tip!

Brian.