Bug 292 - gluScaleImage does not scale correctly
Summary: gluScaleImage does not scale correctly
Status: VERIFIED FIXED
Alias: None
Product: Jogl
Classification: JogAmp
Component: core (show other bugs)
Version: 1
Hardware: All all
: P3 normal
Assignee: Sven Gothel
URL:
Depends on:
Blocks:
 
Reported: 2007-04-12 04:00 CEST by Sven Gothel
Modified: 2010-03-24 07:50 CET (History)
0 users

See Also:
Type: DEFECT
SCM Refs:
Workaround: ---


Attachments
Example application showing issue (9.73 KB, text/plain)
2007-04-12 04:03 CEST, Sven Gothel
Details
Example non sqaure image used by example application (2.82 KB, image/jpeg)
2007-04-12 04:03 CEST, Sven Gothel
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sven Gothel 2010-03-24 07:50:23 CET


---- Reported by alang 2007-04-12 04:00:50 ----

Attached is an example application showing that gluScaleImage does not always 
scale correctly. 

Run the application with and without the following JVM command line argument:
 
-Djogl.glu.nojava
 
When the application is ran *with* this command line argument the texture is
displayed correctly. When the application is ran without the texture is not
scaled correctly. 

--------------------------------------------
Attached application: JOGLTexture.java

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.nio.*;
import java.util.*;

import javax.imageio.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;

/**
 * Example JOGL application showing bug when using gluScaleImage. The 
application
 * simply displays a quad with a texture map. Load any non square image, the
 * sample included is 134x57. Run the application with and without the following
 * JVM command line argument:
 * 
 * -Djogl.glu.nojava
 * 
 * When the application is ran *with* this command line argument the texture is
 * displayed correctly. When the application is ran without the texture is not
 * scaled correctly. 
 * 
 * Run environment: 
 * Machine  : Dell Precision M70 laptop
 * OS       : Windows XP SP2
 * Graphics : NVIDIA Quadro FX Go1400
 * Drivers  : lastest from DELL dated: 22/03/2006 ver. 8.4.3.0
 * JVM      : j2sdk1.4.2_10
 * JOGL     : release 1.1.0-rc3 from Feb 14 2007
 * 
 * @author Alan Michael Gay, AVS Inc.
 */
public class JOGLTexture extends Frame implements GLEventListener, ImageConsumer
{
    // Name of example mage file to load
    String nonSquareImageFileName = ".\\non-squareimage.jpg";
    
    //
    // OpenGL variables.
    //
    private GLU glu = new GLU();  
    private int textureName;

    //
    // Workspace variables for consuming image.
    //
    boolean imageComplete = false;    
    private int imageWidth = 0;
    private int imageHeight = 0;
    private byte[] imageBuffer = null;

    public JOGLTexture()
    {
        // Loads the image we are going to use in this example.
        loadImage(nonSquareImageFileName);
        
        // Specify the Frame window title and initial size.
        setTitle("gluScaleImage bug");

        // Create a listener object that will cause the application
        // to exit when the user dismisses the Frame window.
        this.addWindowListener(new WindowAdapter()
        {
            public void windowClosing(WindowEvent e)
            {
                System.exit(0);
            }
        });   

        // Use the default capabilities.
        GLCapabilities capabilities = new GLCapabilities();

        GLCanvas canvas = new GLCanvas(capabilities);
        canvas.addGLEventListener(this);
            
        this.add(canvas);
    }
    
    /**
     * Loads the specified image from file.
     * @param fileName The string filename for the image.
     */
    private void loadImage(String fileName)
    {   
        File input = new File(fileName);
        Image image = null;
        try
        {
            image = ImageIO.read(input);
        }
        catch (Throwable e)
        {
            System.out.println("Failed to load image file: " + e.getMessage());
        }
        
        ImageProducer imageSource = image.getSource();
        imageSource.startProduction(this);
    }
    
    
    /**
     * Gets a new width and height based on a power of 2.
     * @param width The original image width
     * @param height The original image height
     * @return An in array with two values. The zeroth element containing the 
new width and the first
     * element the new height.
     */
    private int[] newImageSize(int width, int height) 
    {        
        int nN=1;
        while((width >> nN)>0) {
            nN++;
        }
        width = (width == (1<<(nN-1))) ? width : (1<<nN);

        nN = 1;
        while((height >> nN)>0) {
            nN++;
        }

        height = (height == (1<<(nN-1))) ? height : (1<<nN);

        int[] newDims = new int[2];
        newDims[0] = width;
        newDims[1] = height;
       
        return newDims;
    }

    /**
     * Gets a new texture name
     * @param gl The gl context to get the name from.
     * @return An int value containing the texture name.
     */
    private int getTextureName(GL gl)
    {
        int[] result = new int[1];
        gl.glGenTextures(1, result, 0);
        return result[0];
    }
    
    /**
     * Loads an image into opengl to be used as a texture.
     * @param gl The gl context into which to load the texture
     * @param width The width of the image.
     * @param height The height of the image.
     * @param texture The image.
     */
    private int loadTexture(GL gl , int width, int height, byte []texture) 
    {
        int nComp  = 4;
        int nAlign = 4;
        
        int textureName =  getTextureName(gl);
        
        int[] newDims = newImageSize(width, height);        
        int[] nOldAlign = new int[1];
        gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, nOldAlign,0);
        gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, nAlign);
        
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureName);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, 
GL.GL_REPEAT);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, 
GL.GL_LINEAR);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, 
GL.GL_LINEAR);
        gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, 
GL.GL_REPEAT);
        
        int nSize = nComp*(int) newDims[0] * newDims[1];
        byte[] newTexture = new byte [nSize];
        
        ByteBuffer bufferIn  = ByteBuffer.wrap(texture);
        ByteBuffer bufferOut = ByteBuffer.wrap(newTexture);        
       
        glu.gluScaleImage(GL.GL_RGBA, width,  height,
                GL.GL_UNSIGNED_BYTE, bufferIn, newDims[0],  newDims[1],
                GL.GL_UNSIGNED_BYTE, bufferOut);
        
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureName);

        ByteBuffer pixelBuffer = ByteBuffer.wrap(newTexture);
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, nComp, newDims[0],  newDims[1],
                0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer);
        
        gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, nOldAlign[0]);
        
        return textureName;
    }
    
    /**
     * Implementation of GLEventListener.display
     * Draws a simple textured quad. 
     */
    public void display(GLAutoDrawable arg0)
    {
        GL gl = arg0.getGL();
        
        Color col = Color.white;
        
        float red   = col.getRed()/255.0f;
        float green = col.getGreen()/255.0f;
        float blue  = col.getBlue()/255.0f;
        
        gl.glColor3f(red, green, blue);
                
        gl.glEnable(GL.GL_TEXTURE_2D);   
        gl.glBindTexture(GL.GL_TEXTURE_2D, textureName);
        
        gl.glBegin(GL.GL_QUADS);
        
        gl.glTexCoord2f(0.0f,1.0f);
        gl.glVertex3f(-1.0f, 1.0f, 0.0f);
 
        gl.glTexCoord2f(1.0f,1.0f);
        gl.glVertex3f(1.0f, 1.0f, 0.0f);
        
        gl.glTexCoord2f(1.0f,0.0f);
        gl.glVertex3f(1.0f, -1.0f, 0.0f);
        
        gl.glTexCoord2f(0.0f,0.0f);
        gl.glVertex3f(-1.0f, -1.0f, 0.0f);
        gl.glEnd();        
    }

    public void init(GLAutoDrawable arg0)
    {
        GL gl = arg0.getGL();
        
        if (imageComplete == false)
            throw new RuntimeException("Image has not been loaded");
        
        // Load the texture to be used when displaying the textured quad.
        textureName = loadTexture(gl, imageWidth, imageHeight, imageBuffer);
    }

    public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int 
arg4)
    {    
    }

    public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2)
    {  
    }

    //
    // Implementation of ImageConsumer
    //

    public synchronized final void imageComplete(int status) {
        imageComplete = true;
    }
    
    public synchronized final void setDimensions(int width, int height)
    {
        imageWidth  = width;
        imageHeight = height;
        imageBuffer = new byte[4*width*height];
    }
    
    public synchronized final void setPixels(int x, int y, int w, int h, 
ColorModel model,
        int[] pixels, int off, int scansize) 
    {

        if (w == 0 || h == 0)
            return;

        int srcRowIndex = off;
        int dstRowIndex = ((imageHeight - 1) - y) * imageWidth + x;
        for (int row = 0; row < h; row++) {
            int srcIndex = srcRowIndex;
            int dstIndex = dstRowIndex;
            for (int col = 0; col < w; col++) {
                int pixel = pixels[srcIndex++];
                
                int color = model.getRGB(pixel);
                
                imageBuffer[dstIndex*4 + 0] = (byte) (color & 0x000000ff);
                imageBuffer[dstIndex*4 + 1] = (byte)((color & 0x0000ff00) >> 
8);                               
                imageBuffer[dstIndex*4 + 2] = (byte)((color & 0x00ff0000) >> 
16);    
                imageBuffer[dstIndex*4 + 3] = (byte) 0xff;              
                
                dstIndex++;
            }
            srcRowIndex += scansize;
            dstRowIndex += imageWidth;
        }
    }

    public synchronized final void setPixels(int x, int y, int w, int h, 
ColorModel model,
        byte[] pixels, int off, int scansize) {
        // ignore this version
    }
    
    public synchronized final void setHints(int hintflags) {}
    public synchronized final void setColorModel(ColorModel model) {}
    public synchronized final void setProperties(Hashtable props) {}
    
    /**
     * The main() method is called when the Java Virtual Machine starts up. It
     * just creates and displays an instance of the application.
     */
    public static void main(String args[])
    {
        JOGLTexture app = new JOGLTexture();
        app.pack();
        app.setSize(300, 300);
        app.setVisible(true);
    }
}



---- Additional Comments From alang 2007-04-12 04:03:13 ----

Created an attachment
Example application showing issue




---- Additional Comments From alang 2007-04-12 04:03:59 ----

Created an attachment
Example non sqaure image used by example application




---- Additional Comments From alang 2007-04-17 13:16:21 ----

none



---- Additional Comments From kbr 2007-04-18 00:33:03 ----

This is being investigated. It isn't necessary to adjust the priority.

If you would like to help figure out what is going on, you can compare the Java
sources for Mipmap.java, Image.java and ScaleImage.java to the relevant C GLU
sources in the OpenGL sample implementation and see if you can find the bug.
This is what we are doing internally.




---- Additional Comments From kbr 2007-04-18 00:33:27 ----

_



---- Additional Comments From kbr 2007-04-18 23:36:09 ----

Conversion scale factors for x and y dimensions were flipped. Also adjusted
Image.fill_image() so code does not assert.

Fix will be present in JOGL nightly builds dated 4/19 and later, and in the
forthcoming 1.1.0-rc4 and 1.1.0 final release.




---- Additional Comments From alang 2007-04-19 08:31:31 ----

Can confirm fix resolves issue for me. Thanks for such a prompt response. 
Regards 
Alan



--- Bug imported by sgothel@jausoft.com 2010-03-24 07:50 EDT  ---

This bug was previously known as _bug_ 292 at https://jogl.dev.java.net/bugs/show_bug.cgi?id=292
Imported an attachment (id=98)
Imported an attachment (id=99)

The original submitter of attachment 98 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 99 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.