Trying an Alternative:Question on Displaying Textures

Started by cbratton, December 14, 2004, 05:36:32

Previous topic - Next topic

cbratton

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]

CaptainJester

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.
The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities.  We need men and women who can dream of things that never were. - John Fitzgerald Kennedy(35th US President)
8)

princec

You can use ARB_texture_non_power_of_two if it's available to save a bit of RAM.

Cas :)

spasi

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.

cbratton

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!

napier

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.
penGL/Java/LWJGL demos and code: http://potatoland.org/code/gl