Setting the Cursor

Started by CodeBunny, November 04, 2010, 21:44:26

Previous topic - Next topic

CodeBunny

I've tried to set the cursor using BufferedImage, and I run into serious problems with how the image is drawn.

I do the following:

Load a BufferedImage via ImageIO.read(url).
Paint that BufferedImage onto one with the data type BufferedImage.TYPE_INT_ARGB_PRE (don't know if this is necessary, thought that it would help stabilize the method for all image types compatible with BufferedImage).
Create a cursor using an IntBuffer obtained from the image via
IntBuffer.wrap(((DataBufferInt) image.getData().getDataBuffer()).getData());


I get a cursor of the right dimensions and all, but the image data is extremely messed up - patches of it have the wrong color, other patches have the wrong transparency.

I think the problem might be that my computer only supports one bit transparency for the cursor, but the returned intbuffer holds data for a full byte of alpha data, and that causes the problem somehow. Is this right? If so, how can I fix it?

wondersonic

Hi,
what is the format of the image? PNG?

Regards,
WS
S.

CodeBunny

Yeah. I use a 24 x 33 png image.


Matthias

You could also use TWL's PNGDecoder (also available as separate JAR): http://www.javagaming.org/index.php/topic,22435.0.html - it is faster and easier to use.

CodeBunny

Isn't that limited to just PNG images? I'm trying to create a method that will support as many image types as possible - PNG, bitmap, GIF, JPEG (though granted jpeg would be a bad choice for cursor format), etc. The simplest way to do that, code wise, seems to be to use Java2D's native methods for reading images, then dealing with the single format that results.

CodeBunny

Does anyone know how to set the cursor with Java2D methods? I'm running into a bit of a wall here and could use some help.

jediTofu

Perhaps the width and height of the cursor needs to be in powers of 2?
cool story, bro

CodeBunny

I just tried that and it didn't change anything... good idea, though.

This is really bugging me - has anyone gotten this to work? I believe bobjob said this was how he did it, and I tried to base the method on what he recommended...

Matthias

TWL contains code to change the cursor - and it seems to work on every system :) You can take a look at the code.

CodeBunny

One question: It's called "PNGDecoder." Doesn't that mean it works only for PNG images?

Matthias


jediTofu

This works perfectly for me for both PNG and BMP files.  In order to get PNG's to work with varying alpha values, I had to take a percentage of each red, green, and blue value based off of the alpha value.  This uses Slick-Util, but Slick-Util uses ImageIO anyway.  You should be able to figure out how to change this for your Buffered Images.

   Texture tex = TextureLoader.getTexture("BMP",new FileInputStream("test.bmp"));
    int byteCount = 3; //Set this to 4 for PNG, TGA, etc.
    int trueWidth = tex.getImageWidth() * byteCount; //For speed

    int[] array = new int[tex.getImageWidth() * tex.getImageHeight()];
    //If you call getTextureData() continuously in the loop, it's very slow.
    byte[] data = tex.getTextureData();

    for(int y = 0; y < tex.getImageHeight(); y++) {
      for(int x = 0; x < tex.getImageWidth(); x++) {
        int i = y * trueWidth + x * byteCount;

        //Without using "& 0xFF," there were some bad color problems.
        //This is due to conversion from byte to int (a byte is -128 to 127,
        //and we want 0 to 255).
        int r = data[i]     & 0xFF;
        int g = data[i + 1] & 0xFF;
        int b = data[i + 2] & 0xFF;
        int a = 0xFF;

        if(byteCount == 4) {
          a = data[i + 3] & 0xFF;

          if(a > 0) {
            double ap = a / 255.0; //alpha percentage
            r = (int)Math.round(r * ap);
            g = (int)Math.round(g * ap);
            b = (int)Math.round(b * ap);
            a = 0xFF;
          }
        }

        array[y * tex.getImageWidth() + x] =
          (a << 24) |
          (r << 16) |
          (g <<  8) |
          (b);
      }
    }

    Cursor cursor = new Cursor(tex.getImageWidth(),tex.getImageHeight(),0,
      tex.getImageHeight() - 1,1,IntBuffer.wrap(array),null);
    Mouse.setNativeCursor(cursor);



EDIT:  For a Targa (TGA) file with transparency, use a byteCount of 4; for a Targa file without transparency, use a byteCount of 3.  Slick-Util does not support Targa files that use RLE compression... ::)
cool story, bro

jediTofu

For a white background you could do the inverse of above...

You could just set a programmer-adjustable tolerance.  If alpha is below 50% (255 * 0.50), then set it to 0x00, else set it to 0xFF.  This is probably the best way, and just let the programmer know not to use varying degrees of alpha.
cool story, bro

CodeBunny

Thanks for the example.

One question - if you try to supply an intbuffer that holds data for translucent images, and the computer only supports 1-bit alpha cursors, does it simply convert the image, or does it mess up the cursor?