LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: gregorypierce on January 21, 2005, 05:00:07

Title: Binding LWJGL and Swing/AWT (easily)
Post by: gregorypierce on January 21, 2005, 05:00:07
So I've gone ahead and taken a stab at binding these two together. The process is really trivial once you have the framebuffer that you want to draw to the screen. Since we're not binding this to an image (and we don't really need to in this case), we can dump the raw pixels from glReadPixels into the graphics draw call.

The following code compiles but I haven't begun testing it and it has a glaring error in that it doesn't make a call to LWJGL for rendering the scene or anything but that's a small issue. Just wanted to post this so people can start to chime in if they want. I expect to have a complete adapter class done and ready to go into CVS by the end of the weekend so we can get past the "no Swing/AWT" functionality problem :)

Code: [Select]

import org.apache.log4j.*;

import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.opengl.GL11;
import org.lwjgl.BufferUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.nio.ByteBuffer;

public class LWJGLAdapter extends JComponent implements ComponentListener
{
    public static Logger logger = Logger.getLogger("LWJGLAdapter");

    private Pbuffer                     pbuffer;
    private ByteBuffer                  glFrameBuffer;

    public LWJGLAdapter()
    {
        try
        {
            // create an OpenGL LWJGL PBuffer
            //
            pbuffer = new Pbuffer( getWidth(), getHeight(), new PixelFormat(), null, null );

            // make the PBuffer current
            //
            pbuffer.makeCurrent();

            // create a frame buffer to hold the frame from LWJGL
            //
            glFrameBuffer = BufferUtils.createByteBuffer( getWidth() * getHeight() * 3 );

        }
        catch( Exception e )
        {
            logger.error("Adpater error ", e );
        }
    }

    protected void paintComponent( Graphics g )
    {
        // read the contents of the pbuffer into the frame buffer
        //
        GL11.glReadPixels(0, 0, getWidth(), getHeight(), GL11.GL_RGB, GL11.GL_BYTE, glFrameBuffer );

        // use the components paint command to draw the framebuffer
        //
        g.drawBytes( glFrameBuffer.array(), 0, 0, 0, 0 );
    }

    /**
     * Invoked when the component's size changes.
     */
    public void componentResized(ComponentEvent event)
    {
        // recreate the pbuffer for the new component size
        try
        {
            pbuffer = new Pbuffer( getWidth(), getHeight(), new PixelFormat(), null, null );
            pbuffer.makeCurrent();
            glFrameBuffer = BufferUtils.createByteBuffer( getWidth() * getHeight() * 3);
        }
        catch( Exception e )
        {
            logger.error("Unable to recreate the OpenGL components after the component resized", e );
        }
    }

    /**
     * Invoked when the component's position changes.
     */
    public void componentMoved(ComponentEvent e)
    {

    }

    /**
     * Invoked when the component has been made visible.
     */
    public void componentShown(ComponentEvent event)
    {
        try
        {
            // just in case we've broken some textures or in case some other GL thing became current
            // while we were hidden
            pbuffer.makeCurrent();
        }
        catch( Exception e )
        {
            logger.error("Unable to make the pbuffer current after component shown", e);
        }
    }

    /**
     * Invoked when the component has been made invisible.
     */
    public void componentHidden(ComponentEvent e)
    {

    }
}
Title: Binding LWJGL and Swing/AWT (easily)
Post by: princec on January 21, 2005, 11:15:31
Er, Gregory, Graphics.drawBytes draws a string. You're going to have to do something funky with Images whether you like it or not :/

Cas :)
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Matzon on January 21, 2005, 14:29:34
ROFL
Title: Binding LWJGL and Swing/AWT (easily)
Post by: gregorypierce on January 21, 2005, 16:35:34
Yes, I am going to draw a string that represents the frame - don't question my weird science!

 :D
Title: Binding LWJGL and Swing/AWT (easily)
Post by: spasi on January 21, 2005, 16:35:58
I just saw this

http://www.javagaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=jogl;action=display;num=1106324571;start=0#0

and felt kind of sorry...

I really would like to see a fully working AWT/SWT/whatever binding to LWJGL, so that we can bury JOGL once and for all. I can't believe how many are wasting time with it.
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Chman on January 21, 2005, 18:01:18
The jME team (it was renanse I think) has already made it... And it works well ! (except that you can't use PBuffers).

You could take a look at the code... it could be helpful.

Chman
Title: Binding LWJGL and Swing/AWT (easily)
Post by: princec on January 21, 2005, 18:21:38
Oooh! So jME has an AWT  "LWJGLComponent" does it? That I could bung in, say, an Applet?

Cas :)
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Chman on January 21, 2005, 18:45:39
It might work in an applet :P
JME use a thing called Headless Rendering and it uses a lot of JME specific thingies. About the core part, it simply use a rendering to texture process and draw the images on a Canvas or JCanvas...

The only problem is that you need a video card that can make a fast render to texture.

Chman
Title: Binding LWJGL and Swing/AWT (easily)
Post by: princec on January 21, 2005, 19:24:54
Ahh, no good. That's what Gregory's trying to do, and it's not really going to be fast enough. I need GL rendering direct to a backbuffer context.

Cas :)
Title: Binding LWJGL and Swing/AWT (easily)
Post by: gregorypierce on January 21, 2005, 19:59:11
If you're rendering directly to the backbuffer you're a heavyweight component and you might as well just use a native window.
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Chman on January 21, 2005, 21:28:55
Quote from: "princec"
Ahh, no good. That's what Gregory's trying to do, and it's not really going to be fast enough. I need GL rendering direct to a backbuffer context.

Cas :)


Not so slow :)
Here I get about 100 fps... With 10 or 10000 cubes I get the same number of fps, rendering the scene is as fast as rendering it to screen, it's just the render-to-texture process that slow the thing up...

I'm currently running on an ATI 9800Pro@XT.

I've run some JME + Swing test on a Geforce 4 MX and it runs pretty well :)

I think this method could be a "wait for" a true rendering to an AWT/Swing canvas...

Chman
Title: Binding LWJGL and Swing/AWT (easily)
Post by: gregorypierce on January 21, 2005, 21:40:10
Yeah. Its slower than a native render but its not THAT slow. It is more than usable. Its just the conversion of the framebuffer into something that can be painted in a bufferedimage takes a tad of time.

No biggie though. Its either that or have only native windows :)
Title: Round 2
Post by: gregorypierce on January 21, 2005, 22:44:45
Code: [Select]

import org.apache.log4j.*;

import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.opengl.GL11;
import org.lwjgl.BufferUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

public class LWJGLAdapter extends JComponent implements ComponentListener
{
    public static Logger logger = Logger.getLogger("LWJGLAdapter");

    private Pbuffer                     pbuffer;
    private IntBuffer                   glFrameBuffer;
    private BufferedImage               bufferedImage;
    private RenderingThread             renderingThread;

    class RenderingThread extends Thread
    {
        private int             frameRate = 30;
        private int             sleepTime;


        public RenderingThread()
        {
            this.sleepTime = (int)(1000/frameRate);
        }

        public RenderingThread( int frameRate )
        {
            this.frameRate = frameRate;
            this.sleepTime = (int)(1000/frameRate);
        }

        public void run()
        {
            try
            {
                sleep( sleepTime );
                repaint();
            }
            catch( Exception e )
            {
                logger.error("Failed to repaint screen due to exception ", e );
            }
        }

        public int getFrameRate()
        {
            return frameRate;
        }

        public void setFrameRate(int frameRate)
        {
            this.frameRate = frameRate;
        }
    }

    public LWJGLAdapter()
    {
        try
        {
            // create an OpenGL LWJGL PBuffer
            //
            pbuffer = new Pbuffer( getWidth(), getHeight(), new PixelFormat(), null, null );

            // make the PBuffer current
            //
            pbuffer.makeCurrent();

            // create a frame buffer to hold the frame from LWJGL
            //
            glFrameBuffer = BufferUtils.createByteBuffer( getWidth() * getHeight() * 4 ).asIntBuffer();

            // create a buffered image that will hold the frame buffer contents
            //
            bufferedImage = new BufferedImage( getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB );

            renderingThread = new RenderingThread( 60 );

            // everything should be ready to render before this call is made. The component should have bee
            // added and packed so that it has a valid width() and height()
            //
            renderingThread.start();
        }
        catch( Exception e )
        {
            logger.error("Adpater error ", e );
        }
    }

    public int getFrameRate()
    {
        return renderingThread.getFrameRate();
    }

    public void setFrameRate(int frameRate)
    {
        renderingThread.setFrameRate( frameRate );
    }

    protected void paintComponent( Graphics g )
    {
        // read the contents of the pbuffer into the frame buffer
        //
        GL11.glReadPixels(0, 0, getWidth(), getHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, glFrameBuffer );

        // dump the contents of the frame buffer into the buffered image - there should be a faster way to do
        // this with the writable raster which should give us direct access
        //
        bufferedImage.setRGB( 0, 0, getWidth(), getHeight(), glFrameBuffer.array(), 0, getWidth() );

        // use the components paint command to draw the framebuffer
        //
        g.drawImage( bufferedImage, 0, 0, getWidth(), getHeight(), getBackground(), null );
    }

    /**
     * Invoked when the component's size changes.
     */
    public void componentResized(ComponentEvent event)
    {
        // recreate the pbuffer for the new component size
        try
        {
            pbuffer = new Pbuffer( getWidth(), getHeight(), new PixelFormat(), null, null );
            pbuffer.makeCurrent();
            glFrameBuffer = BufferUtils.createByteBuffer( getWidth() * getHeight() * 4).asIntBuffer();
        }
        catch( Exception e )
        {
            logger.error("Unable to recreate the OpenGL components after the component resized", e );
        }
    }

    /**
     * Invoked when the component's position changes.
     */
    public void componentMoved(ComponentEvent e)
    {

    }

    /**
     * Invoked when the component has been made visible.
     */
    public void componentShown(ComponentEvent event)
    {
        try
        {
            // just in case we've broken some textures or in case some other GL thing became current
            // while we were hidden
            pbuffer.makeCurrent();
        }
        catch( Exception e )
        {
            logger.error("Unable to make the pbuffer current after component shown", e);
        }
    }

    /**
     * Invoked when the component has been made invisible.
     */
    public void componentHidden(ComponentEvent e)
    {

    }
}

Title: Just about done....
Post by: gregorypierce on January 23, 2005, 23:03:11
I've been working with Cas a lot today and he's been very helpful getting me through the more interesting parts of converting the byte[] into something that we can actually draw.

Quote

/*
 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
 */
package com.sojournermobile.client;


import org.apache.log4j.*;

import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.opengl.GL11;
import org.lwjgl.BufferUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ByteOrder;

public class TestPBuffer extends JComponent
{
    public static Logger logger = Logger.getLogger("TestPBuffer");

    private Pbuffer                     pbuffer;
    private ByteBuffer                  glFrameBuffer;
    private byte[]                      frameBytes;
    private BufferedImage               bufferedImage;
    private RenderingThread             renderingThread;
    private boolean                     isRenderable = false;
    private WritableRaster              writableRaster;

    private int                         width;
    private int                         height;

    class RenderingThread extends Thread
    {
        private int             frameRate = 5;
        private int             sleepTime;


        public RenderingThread()
        {
            this.sleepTime = (int)(1000/frameRate);
        }

        public RenderingThread( int frameRate )
        {
            this.frameRate = frameRate;
            this.sleepTime = (int)(1000/frameRate);
        }

        public void run()
        {
            try
            {
                sleep( sleepTime );
                repaint();
            }
            catch( Exception e )
            {
                logger.error("Failed to repaint screen due to exception ", e );
            }
        }

        public int getFrameRate()
        {
            return frameRate;
        }

        public void setFrameRate(int frameRate)
        {
            this.frameRate = frameRate;
        }
    }

    public TestPBuffer( int width, int height )
    {
        this.width = width;
        this.height = height;
        try
        {
            // create an OpenGL LWJGL PBuffer
            //
            pbuffer = new Pbuffer( width, height, new PixelFormat(), null, null );

            // make the PBuffer current
            //
            pbuffer.makeCurrent();

            // create a buffered image that will hold the frame buffer contents
            //
            ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
            writableRaster = colorModel.createCompatibleWritableRaster( width, height );
            bufferedImage =  new BufferedImage(colorModel, writableRaster, false, null);

            renderingThread = new RenderingThread();

            isRenderable = true;

        }
        catch( Exception e )
        {
            logger.error("Adpater error ", e );
        }
    }

    public void start()
    {
        if ( isRenderable )
        {
            // everything should be ready to render before this call is made. The component should have been
            // added and packed so that it has a valid width() and height()
            //
            renderingThread.start();
        }
    }

    public int getFrameRate()
    {
        return renderingThread.getFrameRate();
    }

    public void setFrameRate(int frameRate)
    {
        renderingThread.setFrameRate( frameRate );
    }

    protected void paintComponent( Graphics g )
    {
        g.setColor( Color.BLACK );
        g.fillRect(0, 0, width, height);
       
       
        try
        {
            pbuffer.makeCurrent();
        }
        catch( Exception e ){}

        if ( glFrameBuffer == null )
        {
            // create a frame buffer to hold the frame from LWJGL
            //
            glFrameBuffer = BufferUtils.createByteBuffer( width * height * 4 );
        }

        renderScene();

        GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, glFrameBuffer );

        glFrameBuffer.get( ((DataBufferByte)writableRaster.getDataBuffer()).getData() );
        glFrameBuffer.rewind();


        // draw the image
        g.drawImage( bufferedImage, 0, 0, width, height, getBackground(), null );
    }

    public void renderScene()
    {
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);          // Clear The Screen And The Depth Buffer
    }

    /**
     * Invoked when the component's size changes.
     */
    public void componentResized(ComponentEvent event)
    {
        // recreate the pbuffer for the new component size
        try
        {
            //pbuffer = new Pbuffer( getWidth(), getHeight(), new PixelFormat(), null, null );
            //pbuffer.makeCurrent();
            //glFrameBuffer = BufferUtils.createByteBuffer( getWidth() * getHeight() * 3);
        }
        catch( Exception e )
        {
            logger.error("Unable to recreate the OpenGL components after the component resized", e );
        }
    }

    /**
     * Invoked when the component's position changes.
     */
    public void componentMoved(ComponentEvent e)
    {

    }

    /**
     * Invoked when the component has been made visible.
     */
    public void componentShown(ComponentEvent event)
    {
        try
        {
            // just in case we've broken some textures or in case some other GL thing became current
            // while we were hidden
            pbuffer.makeCurrent();
        }
        catch( Exception e )
        {
            logger.error("Unable to make the pbuffer current after component shown", e);
        }
    }

    /**
     * Invoked when the component has been made invisible.
     */
    public void componentHidden(ComponentEvent e)
    {

    }

    public static void main( String[] args )
    {
        BasicConfigurator.configure();

        try
        {
            JFrame frame = new JFrame();
            frame.setSize( 640, 480 );
            TestPBuffer client = new TestPBuffer(640,480);

            frame.getContentPane().add( client );
            //frame.pack();
            frame.show();

            frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );

            client.start();
        }
        catch( Exception e )
        {
            logger.error("Error building the client ", e );
        }
    }
}




I expect the next code update will be the final and we'll have something that will allow Swing and actually browser compatibility.
Title: Just about done....
Post by: gregorypierce on January 23, 2005, 23:05:00
I've been working with Cas a lot today and he's been very helpful getting me through the more interesting parts of converting the byte[] into something that we can actually draw.

Code: [Select]

/*
 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
 */
package com.sojournermobile.client;


import org.apache.log4j.*;

import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.opengl.GL11;
import org.lwjgl.BufferUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ByteOrder;

public class TestPBuffer extends JComponent
{
    public static Logger logger = Logger.getLogger("TestPBuffer");

    private Pbuffer                     pbuffer;
    private ByteBuffer                  glFrameBuffer;
    private byte[]                      frameBytes;
    private BufferedImage               bufferedImage;
    private RenderingThread             renderingThread;
    private boolean                     isRenderable = false;
    private WritableRaster              writableRaster;

    private int                         width;
    private int                         height;

    class RenderingThread extends Thread
    {
        private int             frameRate = 5;
        private int             sleepTime;


        public RenderingThread()
        {
            this.sleepTime = (int)(1000/frameRate);
        }

        public RenderingThread( int frameRate )
        {
            this.frameRate = frameRate;
            this.sleepTime = (int)(1000/frameRate);
        }

        public void run()
        {
            try
            {
                sleep( sleepTime );
                repaint();
            }
            catch( Exception e )
            {
                logger.error("Failed to repaint screen due to exception ", e );
            }
        }

        public int getFrameRate()
        {
            return frameRate;
        }

        public void setFrameRate(int frameRate)
        {
            this.frameRate = frameRate;
        }
    }

    public TestPBuffer( int width, int height )
    {
        this.width = width;
        this.height = height;
        try
        {
            // create an OpenGL LWJGL PBuffer
            //
            pbuffer = new Pbuffer( width, height, new PixelFormat(), null, null );

            // make the PBuffer current
            //
            pbuffer.makeCurrent();

            // create a buffered image that will hold the frame buffer contents
            //
            ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
            writableRaster = colorModel.createCompatibleWritableRaster( width, height );
            bufferedImage =  new BufferedImage(colorModel, writableRaster, false, null);

            renderingThread = new RenderingThread();

            isRenderable = true;

        }
        catch( Exception e )
        {
            logger.error("Adpater error ", e );
        }
    }

    public void start()
    {
        if ( isRenderable )
        {
            // everything should be ready to render before this call is made. The component should have been
            // added and packed so that it has a valid width() and height()
            //
            renderingThread.start();
        }
    }

    public int getFrameRate()
    {
        return renderingThread.getFrameRate();
    }

    public void setFrameRate(int frameRate)
    {
        renderingThread.setFrameRate( frameRate );
    }

    protected void paintComponent( Graphics g )
    {
        g.setColor( Color.BLACK );
        g.fillRect(0, 0, width, height);
       
       
        try
        {
            pbuffer.makeCurrent();
        }
        catch( Exception e ){}

        if ( glFrameBuffer == null )
        {
            // create a frame buffer to hold the frame from LWJGL
            //
            glFrameBuffer = BufferUtils.createByteBuffer( width * height * 4 );
        }

        renderScene();

        GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, glFrameBuffer );

        glFrameBuffer.get( ((DataBufferByte)writableRaster.getDataBuffer()).getData() );
        glFrameBuffer.rewind();


        // draw the image
        g.drawImage( bufferedImage, 0, 0, width, height, getBackground(), null );
    }

    public void renderScene()
    {
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);          // Clear The Screen And The Depth Buffer
    }

    /**
     * Invoked when the component's size changes.
     */
    public void componentResized(ComponentEvent event)
    {
        // recreate the pbuffer for the new component size
        try
        {
            //pbuffer = new Pbuffer( getWidth(), getHeight(), new PixelFormat(), null, null );
            //pbuffer.makeCurrent();
            //glFrameBuffer = BufferUtils.createByteBuffer( getWidth() * getHeight() * 3);
        }
        catch( Exception e )
        {
            logger.error("Unable to recreate the OpenGL components after the component resized", e );
        }
    }

    /**
     * Invoked when the component's position changes.
     */
    public void componentMoved(ComponentEvent e)
    {

    }

    /**
     * Invoked when the component has been made visible.
     */
    public void componentShown(ComponentEvent event)
    {
        try
        {
            // just in case we've broken some textures or in case some other GL thing became current
            // while we were hidden
            pbuffer.makeCurrent();
        }
        catch( Exception e )
        {
            logger.error("Unable to make the pbuffer current after component shown", e);
        }
    }

    /**
     * Invoked when the component has been made invisible.
     */
    public void componentHidden(ComponentEvent e)
    {

    }

    public static void main( String[] args )
    {
        BasicConfigurator.configure();

        try
        {
            JFrame frame = new JFrame();
            frame.setSize( 640, 480 );
            TestPBuffer client = new TestPBuffer(640,480);

            frame.getContentPane().add( client );
            //frame.pack();
            frame.show();

            frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );

            client.start();
        }
        catch( Exception e )
        {
            logger.error("Error building the client ", e );
        }
    }
}




I expect the next code update will be the final and we'll have something that will allow Swing and actually browser compatibility.
Title: Re: Just about done....
Post by: markush on January 31, 2005, 09:28:27
Quote from: "gregorypierce"
I expect the next code update will be the final and we'll have something that will allow Swing and actually browser compatibility.


Any news on this?
I'd like to switch from JoGL to lwjgl, but without swing integration I can't...
Title: Binding LWJGL and Swing/AWT (easily)
Post by: gregorypierce on January 31, 2005, 20:10:54
Its coming. Got distracted by a couple of OSX bugs that needed fixin. Done this week for certain :)
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Mattbooth on March 02, 2005, 12:00:28
Did this get finished?

I'd like to import aLWJGL windown into some swing components if possible?

Cheers
Title: Binding LWJGL and Swing/AWT (easily)
Post by: princec on March 02, 2005, 12:06:26
We've got AWT integration now if that'll do you. Should work perfectly well if you use it carefully.

Cas :)
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Mattbooth on March 02, 2005, 14:13:39
Hi cas

Is there a link somwhere mate?
Title: Binding LWJGL and Swing/AWT (easily)
Post by: princec on March 02, 2005, 18:47:44
It's currently just in the CVS, but a release is imminent.

Cas :)
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Mattbooth on March 03, 2005, 11:17:14
But i'm guessing not in the next week or so when i could do with it  :shock:

How do you get it out of the CVS?  (probable dumb question i know)

Thanks
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Skippy0 on March 03, 2005, 15:18:03
I would strongly advice not to use BufferedImage.setRGB(), instead
use MemoryImageSource.newPixels(...) backed by a int[].

Just check setRGB() and what an endless sequence of conversions
are done. It's just dead-slow.

Code: [Select]


// init

int width = 256;
int height = 512;
int pixels = width * height;
int bytesPerPixel = 3; // RGB

ByteBuffer frameData = BufferUtils.createByteBuffer(pixels*bytesPerPixel);
byte[] pixBytes = new byte[pixels*bytesPerPixel];
int[] pix = new int[pixels];
MemoryImageSource sourceImage = new MemoryImageSource(width, height, pix, 0, width);
sourceImage.setAnimated(true);
Image image = createImage(sourceImage);

// every frame

GL.read....(frameData);
frameData.rewind();
frameData.get(pixBytes, 0, pixBytes.length);

for(int i=0, j=0; i<pix.length; i++)
{
    int c = 0xFF << 24;
    c |= (pixBytes[j++] & 0xFF) << 16;
    c |= (pixBytes[j++] & 0xFF) << 8;
    c |= (pixBytes[j++] & 0xFF) << 0;
   pix[i] = c;
}

imageSouce.newPixels();

g.drawImage(image, 0, 0, null);


Cannot use the IntBuffer as we read only 24bits per pixel.

What are your opinions?
Title: Binding LWJGL and Swing/AWT (easily)
Post by: Mattbooth on March 03, 2005, 16:11:45
Does anyone have some simple example like drawing a cube using the awt code coz i cant make head nor tails of it.....
Title: Binding LWJGL and Swing/AWT (easily)
Post by: renanse on March 15, 2005, 17:34:06
In jME we don't use setRGB either, we create our BufferedImage and then directly access the DataBuffer of the Raster...  which can be manipulated as an array of ints...

Code: [Select]
int[] ibuf = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();

Our data is grabbed from an IntBuffer that is populated from the GL thread (throttled though to only grab every X ms) using:
Code: [Select]
   public void grabScreenContents(IntBuffer buff, int x, int y, int w, int h) {
        GL11.glReadPixels(x, y, w, h, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE,
                        buff);
    }


Then it's a simple matter to copy from the IntBuffer to the int array backing the BufferedImage:
Code: [Select]
buf.clear(); // Note: clear() resets marks and positions,
//       but not data in buffer.
//Grab pixel information and set it to the BufferedImage info.
for (int x = height; --x >= 0; ) {
buf.get(ibuf, x * width, width);
}


You go on to draw the image as normal.

The copying portions of this code are extremely fast, the slow part is just glReadPixels, which we throttle to only happen a certain number of times per second...  There's no real reason to do it any faster than screen refresh rate for example.

That all said, I'm anxious to see .96 lwjgl with it's direct integration into AWT (or so I've heard.)
Title: Update?
Post by: jjones7947 on May 19, 2005, 18:01:34
greg wrote:
Quote

I expect the next code update will be the final and we'll have something that will allow Swing and actually browser compatibility.


Did this ever go anywhere?
Jim
Title: Binding LWJGL and Swing/AWT (easily)
Post by: princec on May 19, 2005, 20:10:14
AWTGLCanvas does everything nicely now. Try it out. Just remember it's a heavyweight component.

Cas :)
Title: AWTGLCanvas
Post by: rainforest on October 19, 2005, 19:00:31
Dear Cas

Please give me the location of the download.

rainforest.