LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: gregorypierce on January 23, 2006, 04:52:38

Title: SwingLWJGL JPanel Code Drop
Post by: gregorypierce on January 23, 2006, 04:52:38
This is a code drop taken from the sojourner mobile code archives and as such I have only had a chance to strip it down to the point where it compiles and runs. Doing this to get it into LWJGL1.0. All SOJO asks for is a credit.


public class OpenGLJPanelTest extends JFrame
{
   public static Logger logger = Logger.getLogger("OpenGLJPanelTest");

   public OpenGLJPanelTest()
   {
       OpenGLTool panel = new OpenGLTool();

       getContentPane().add( panel );
       panel.setPreferredSize( new Dimension( 640, 480 ) );
   }

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

       try
       {
           OpenGLJPanelTest test = new OpenGLJPanelTest();

           test.pack();
           test.setVisible( true );

           test.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
       }
       catch( Exception e )
       {
           logger.error(e);
       }

   }
}



import org.lwjgl.Sys;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.*;
import org.apache.log4j.Logger;
import org.jdom.Element;

import javax.swing.Timer;
import javax.swing.JPanel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.Graphics;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ByteOrder;

import com.sojournermobile.studio.component.itempanel.ItemPanelWidgetToolIF;


public class OpenGLTool extends JPanel implements ActionListener, ItemPanelWidgetToolIF
{
   public static Logger logger = Logger.getLogger("OpenGLTool");

   static
   {
       Sys.initialize();
   }

   private Timer                       animationTimer = new Timer(10, this); // the timer that controls animation

   private Pbuffer                     pBuffer;  // the native opengl pBuffer that we render the scene into

   private BufferedImage               renderedImage;    // the image that will be rendered to the swing component
   private int[]                       imageData; // the int[] that represents the backing store of our BufferedImage

   private IntBuffer                   intBuffer; // the int buffer that will host the captured opengl data
   private boolean                     isInitialized = false;


   private int                         width; // stored width for our component
   private int                         height; // stored height for our component
   private int                         bitDepth = 32;
   private int                         refreshRate = 60;
   private int                         alphaBits;
   private int                         stencilBits;
   private int                         depthBufferBits;
   private int                         sampleBits;

   private float                       rotation = 0.1f;
   private int                         frameCount = 0;
   private long                        startTime;


   /**
    * Creates a JPanel that can be rendered to by LWJGL. It sets itself to opaque
    * by default so that Swing knows that we will render our entire bounds and therefore
    * doesn't need to do any checks
    */
   public OpenGLTool()
   {
       // this component is responsible for painting its entire bounds
       //
       setOpaque( true );
   }

   public int getBitDepth()
   {
       return bitDepth;
   }

   public void setBitDepth(int bitDepth)
   {
       this.bitDepth = bitDepth;
   }

   public int getAlphaBits()
   {
       return alphaBits;
   }

   public void setAlphaBits(int alphaBits)
   {
       this.alphaBits = alphaBits;
   }

   public int getStencilBits()
   {
       return stencilBits;
   }

   public void setStencilBits(int stencilBits)
   {
       this.stencilBits = stencilBits;
   }

   public int getDepthBufferBits()
   {
       return depthBufferBits;
   }

   public void setDepthBufferBits(int depthBufferBits)
   {
       this.depthBufferBits = depthBufferBits;
   }

   public int getSampleBits()
   {
       return sampleBits;
   }

   public void setSampleBits(int sampleBits)
   {
       this.sampleBits = sampleBits;
   }

   /**

    */
   public void initComponent( int bpp, int freq ) throws Exception
   {
       logger.debug("Creating headless window " + width +"/" + height + "/" + bitDepth);

       DisplayMode[] modes = Display.getAvailableDisplayModes();
       DisplayMode mode = null;
       
       // Make sure that we find the mode that uses our current monitor freq.

       for (int i = 0; i < modes.length; i++)
       {
           if (modes[i].getWidth() == width && modes[i].getHeight() == height
                   && modes[i].getBitsPerPixel() == bpp
                   && (freq == 0 || modes[i].getFrequency() == freq))
           {
               mode = modes[i];
           }
       }
       
       PixelFormat format = new PixelFormat(bitDepth, alphaBits, depthBufferBits, stencilBits, sampleBits);

       try
       {
           Display.setDisplayMode(mode);

           // create a PbUffer that will store the contents of our renderings
           //
           pBuffer = new Pbuffer(width, height, format, null, null);
           pBuffer.makeCurrent();
       }
       catch( Exception e )
       {
           logger.error("Unable to create headless display", e );
       }
   }

   /**
    * override update to avoid clearing
    */
   public void update(Graphics g)
   {
       paint(g);
   }

   public void start()
   {
       logger.debug("Starting animation timer");
       animationTimer.start();
       startTime = System.currentTimeMillis();
   }

   public void stop()
   {
       logger.debug("Stopping animation timer");
       animationTimer.stop();
   }

   /**
    * Instruct the component to paint its entire bounds
    *
    * @param e
    */
   public void actionPerformed(ActionEvent e)
   {
       paintImmediately(0, 0, getWidth(), getHeight());
   }

   public void paintComponent( Graphics g )
   {
       if ( ! isInitialized )
       {
           width = getWidth();
           height = getHeight();

           try
           {
               initComponent( bitDepth, refreshRate );
           }
           catch (Exception e)
           {
               e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
           }

           // create a buffered image that is of the size of this component
           // we will render directly into this buffered image in Swing
           // fashion so we can render our interface in Swing properly and get the
           // image data that is backing this buffered image so we can write directly
           // to the internal data structure with no unnecessary copy
           //
           renderedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
           imageData = ((DataBufferInt)renderedImage.getRaster().getDataBuffer()).getData();

           // create an int buffer to store the captured data from OpenGL
           //
           intBuffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();

           // we're initialized
           //
           isInitialized = true;

           //start the animation thread
           //
           start();
       }
       else
       {
           // do render in opengl
           //
           render();

           // make sure we're done drawing before capturing the frame
           //
           GL11.glFlush();

           // capture the result
           //
           grabGLFrame();

           // draw the result to this component
           //
           g.drawImage(renderedImage, 0, 0, null);

       }

       frameCount ++;

       if ( frameCount % 100 == 0 )
       {
           long currentTime = System.currentTimeMillis();
           long secondTime = ( currentTime - startTime ) / 1000;

           float frameRate = frameCount / secondTime;

           logger.debug("Another 100 frames " + frameRate );

       }
   }


   /**
    * Captures the currently rendered frame to a buffered image so it can be rendered
    * to a Swing component without any repaint issues. Most assuredly will be slower
    * than direct rendering, but will be compliant with Swing
    */
   private void grabGLFrame()
   {
       GL11.glReadPixels(0, 0, width, height, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, intBuffer);

       intBuffer.clear();

       // dump the captured data into the buffered image
       //
       for (int x = height; --x >= 0; )
       {
          intBuffer.get(imageData, x * width, width);
       }

       intBuffer.flip();
   }

       /**
    * <code>getValidDisplayMode</code> returns a <code>DisplayMode</code>
    * object that has the requested width, height and color depth. If there is
    * no mode that supports a requested resolution, null is returned.
    */
   private DisplayMode getValidDisplayMode(int width, int height, int bpp, int freq)
   {
       // get all the modes, and find one that matches our width, height, bpp.
       DisplayMode[] modes;
       try
       {
           modes = Display.getAvailableDisplayModes();
       } catch (LWJGLException e) {
           e.printStackTrace();
           return null;
       }
       // Make sure that we find the mode that uses our current monitor freq.

       for (int i = 0; i < modes.length; i++) {
           if (modes[i].getWidth() == width && modes[i].getHeight() == height
                   && modes[i].getBitsPerPixel() == bpp
                   && (freq == 0 || modes[i].getFrequency() == freq)) {

               return modes[i];
           }
       }

       // none found
       return null;
   }

   private void render()
   {
       GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

       GL11.glRotatef(rotation,0.0f,1.0f,0.0f); // Rotate The Triangle On The Y axis ( NEW )
       GL11.glBegin(GL11.GL_TRIANGLES); // Drawing Using Triangles
       GL11.glVertex3f( 0.0f, 1.0f, 0.0f); // Top
       GL11.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
       GL11.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
       GL11.glEnd();

       rotation += 0.2f;
   }

   public void setData(Element metadata) throws Exception
   {
       //To change body of implemented methods use File | Settings | File Templates.
   }
}
[/code]