LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: cbratton on December 14, 2004, 05:36:32

Title: Trying an Alternative:Question on Displaying Textures
Post by: cbratton on December 14, 2004, 05:36:32
I am writing a Net Meeting clone for java.  I have the entire thing working right now and I have finally declared version 1.0.  I have noticed that the Java2D paint method consumes a lot of CPU usage.  So I thought why not try using an OpenGL library instead.

I need to know how to display a BufferedImage onto one Quad or if that is even possible.

I know that textures have to be a power of two.  Most desktops are going to be in a 4:3 or 16:9 ratio, so this may not work at all, unless someone has ideas.  I was thinking about just taking a 1280x1024 image and placing it on a 1280x1280 texture, then moving the camera over just 1280x1024.  Possible?

The whole idea is to get rid of that Java2D so I can conserve some resources.  :)  This is what I have so far - a mutated version of the FullScreenWindowedTest.  Comments have been removed to save post space...not to ignore their respective owners:

package org.lwjgl.test.opengl;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.glu.GLU;

public class FullScreenWindowedTest
  {
     public static void main ( String[ ] args )
        {
           FullScreenWindowedTest fswTest = new FullScreenWindowedTest( );
           fswTest.execute( );
        }

     private DisplayMode mode;
     private long        startTime = System.currentTimeMillis( );
     private int         texture;

     /**
      * Creates a FullScreenWindowedTest
      */
     public FullScreenWindowedTest ( )
        {
        }

     /**
      * Executes the test
      */
     public void execute ( )
        {
           initialize( );
           mainLoop( );
        }

     /**
      * Retrieves a displaymode, if one such is available
      *
      * @param width Required width
      * @param height Required height
      * @param bpp Minimum required bits per pixel
      * @return
      */
     private DisplayMode findDisplayMode ( int width, int height, int bpp )
        {
           DisplayMode[ ] modes = Display.getAvailableDisplayModes( );
           for ( int i = 0; i < modes.length; i++ )
              {
                 if ( modes[i].getWidth( ) == width && modes[i].getHeight( ) == height && modes[i].getBitsPerPixel( ) >= bpp && modes[i].getFrequency( ) <= 60 )
                    {
                       try
                          {
                             Display.setDisplayMode( modes[i] );
                          }
                       catch ( LWJGLException e )
                          {
                             e.printStackTrace( );
                          }
                       return modes[i];
                    }
              }
           return null;
        }

     /**
      * Initializes OGL
      */
     private void glInit ( )
        {
           // Go into orthographic projection mode.
           GL11.glMatrixMode( GL11.GL_PROJECTION );
           GL11.glLoadIdentity( );
           GLU.gluOrtho2D( 0, mode.getWidth( ), 0, mode.getHeight( ) );
           GL11.glMatrixMode( GL11.GL_MODELVIEW );
           GL11.glLoadIdentity( );
           GL11.glViewport( 0, 0, mode.getWidth( ), mode.getHeight( ) );
           GL11.glHint( GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST );
           GL11.glEnable( GL11.GL_DEPTH_TEST );
           GL11.glDepthFunc( GL11.GL_LEQUAL );
           GL11.glShadeModel( GL11.GL_SMOOTH );
           // enable texture mapping - me
           GL11.glEnable( GL11.GL_TEXTURE_2D );
           //set clear color to black
           GL11.glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
           //sync frame (only works on windows)
           Display.setVSyncEnabled( false );
           System.err.println( "GL_VENDOR: " + GL11.glGetString( GL11.GL_VENDOR ) );
           System.err.println( "GL_RENDERER: " + GL11.glGetString( GL11.GL_RENDERER ) );
           System.err.println( "GL_VERSION: " + GL11.glGetString( GL11.GL_VERSION ) );
           texture = loadTexture( "test.png" );
           System.out.println( texture + "t" );
        }

     /**
      * Initializes the test
      */
     private void initialize ( )
        {
           try
              {
                 //find displaymode
                 mode = findDisplayMode( 800, 600, 32 );
                 // start of in windowed mode
                 Display.create( );
                 glInit( );
              }
           catch ( Exception e )
              {
                 e.printStackTrace( );
              }
        }

     private final int loadTexture ( String path )
        {
           Image image = ( new javax.swing.ImageIcon( path ) ).getImage( );
           // Exctract The Image
           BufferedImage tex = new BufferedImage( image.getWidth( null ), image.getHeight( null ), BufferedImage.TYPE_3BYTE_BGR );
           Graphics2D g = ( Graphics2D ) tex.getGraphics( );
           g.drawImage( image, null, null );
           g.dispose( );
           // Flip Image
           AffineTransform tx = AffineTransform.getScaleInstance( 1, -1 );
           tx.translate( 0, -image.getHeight( null ) );
           AffineTransformOp op = new AffineTransformOp( tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR );
           tex = op.filter( tex, null );
           // Put Image In Memory
           ByteBuffer scratch = ByteBuffer.allocateDirect( 4 * tex.getWidth( ) * tex.getHeight( ) );
           byte data[] = ( byte[ ] ) tex.getRaster( ).getDataElements( 0, 0, tex.getWidth( ), tex.getHeight( ), null );
           scratch.clear( );
           scratch.put( data );
           scratch.rewind( );
           // Create A IntBuffer For Image Address In Memory
           IntBuffer buf = ByteBuffer.allocateDirect( 4 ).order( ByteOrder.nativeOrder( ) ).asIntBuffer( );
           GL11.glGenTextures( buf ); // Create Texture In OpenGL
           GL11.glBindTexture( GL11.GL_TEXTURE_2D, buf.get( 0 ) );
           // Typical Texture Generation Using Data From The Image
           // Linear Filtering
           GL11.glTexParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR );
           // Linear Filtering
           GL11.glTexParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR );
           // Generate The Texture
           GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tex.getWidth( ), tex.getHeight( ), 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, scratch );
           return buf.get( 0 ); // Return Image Address In Memory
        }

     /**
      * Runs the main loop of the "test"
      */
     private void mainLoop ( )
        {
           int fpsCount = 0;
           while ( !Keyboard.isKeyDown( Keyboard.KEY_ESCAPE ) && !Display.isCloseRequested( ) )
              {
                 if ( Display.isVisible( ) )
                    {
                       // check keyboard input
                       processKeyboard( );
                       // render it
                       render( );
                    }
                 else
                    {
                       // no need to render/paint if nothing has changed (ie.
                       // window
                       // dragged over)
                       if ( Display.isDirty( ) )
                          {
                             render( );
                          }
                       // don't waste cpu time, sleep more
                       try
                          {
                             Thread.sleep( 100 );
                          }
                       catch ( InterruptedException inte )
                          {
                          }
                    }
                 // Update window
                 Display.update( );
                 fpsCount++;
                 if ( System.currentTimeMillis( ) - startTime > 1000 )
                    {
                       System.out.println( fpsCount );
                       fpsCount = 0;
                       startTime = System.currentTimeMillis( );
                    }
              }
        }

     /**
      * Processes keyboard input
      */
     private void processKeyboard ( )
        {
           //check for fullscreen key
           if ( Keyboard.isKeyDown( Keyboard.KEY_F ) )
              {
                 try
                    {
                       Display.setFullscreen( true );
                    }
                 catch ( Exception e )
                    {
                       e.printStackTrace( );
                    }
              }
           //check for window key
           if ( Keyboard.isKeyDown( Keyboard.KEY_W ) )
              {
                 try
                    {
                       Display.setFullscreen( false );
                    }
                 catch ( Exception e )
                    {
                       e.printStackTrace( );
                    }
              }
        }

     private void render ( )
        {
           //clear background
           GL11.glClear( GL11.GL_COLOR_BUFFER_BIT );
           // draw white quad
           GL11.glPushMatrix( );
              {
                 // color of quad
                 //GL11.glColor3f( 1.0f, 1.0f, 1.0f );
                 GL11.glBindTexture( GL11.GL_TEXTURE_2D, texture );
                 GL11.glBegin( GL11.GL_QUADS );
                    {
                       // bottom left
                       GL11.glVertex2i( 0, 0 );
                       // bottom right
                       GL11.glVertex2i( 512, 0 );
                       // top right
                       GL11.glVertex2i( 512, 512 );
                       // top left
                       GL11.glVertex2i( 0, 512 );
                    }
                 GL11.glEnd( );
              }
           GL11.glPopMatrix( );
        }
  }
[/code]
Title: Trying an Alternative:Question on Displaying Textures
Post by: CaptainJester on December 14, 2004, 11:27:52
I don't believe 1280x1280 is a legal texture size, since it is not a power of 2.  You can expect most cards to be able to do 512x512.  1024x1024 is not available even a lot, even now.  You can do what you describe in ortho mode.  What you are suggesting however might not look very good.  What you might want to do instead is use a 512x512 image as a texture, set ortho mode to 1024x768 then draw a quad 512x512 centered on the screen using the image as its texture.
Title: Trying an Alternative:Question on Displaying Textures
Post by: princec on December 14, 2004, 12:08:26
You can use ARB_texture_non_power_of_two if it's available to save a bit of RAM.

Cas :)
Title: Trying an Alternative:Question on Displaying Textures
Post by: spasi on December 14, 2004, 12:34:52
ARB_texture_non_power_of_two is available only on 6800s. EXT_texture_rectangle (or NV_texture_rectangle, it's the same thing) should do the job. Both are widely available. 2048 max texture size is also available on most (all?) modern cards.
Title: Trying an Alternative:Question on Displaying Textures
Post by: cbratton on December 15, 2004, 00:55:41
I am more concnered with how to just load one quad onto the screen with a BufferedImage textured onto it.  I could easily resize and reposition the camera node to display what I want.  :)  Thank you for your replies thus far!
Title: Trying an Alternative:Question on Displaying Textures
Post by: napier on December 15, 2004, 20:04:52
Here's a class to use an Image as a texture, I assume it's not much different to use a BufferedImage instead of Image.

   http://potatoland.com/code/gl/GLImage.java

The function  loadImage()  grabs pixels from java Image and prepares them for use as a texture (I'm not sure if the BufferedImage pixel format is different).

You can use the resulting pixelBuffer to create a texture:

   makeTexture(glimg.pixelBuffer, glimg.w, glimg.h);

   ...

   public int makeTexture(ByteBuffer pixels, int w, int h)
   {
       // get a new empty texture
       int textureHandle = allocateTexture();
       // 'select' the new texture by it's handle
       GL11.glBindTexture(GL11.GL_TEXTURE_2D,textureHandle);
       // set texture parameters
       GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
       GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
       GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
       GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
       // Create the texture from pixels
       GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, w, h,
0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
       return textureHandle;
   }


Then the texture can be applied to a quad in ortho mode.