Hi, Im working on a small library for harware and software mouse management as well as cursor animation.
Currently there is no way to pull off the hardware cursor animation without modifying com.jme.input.lwjgl.LWJGLMouseInput. While it is possible to use the already available method that sets unanimated cursor and then change each frame from your java code, whenever you change the hardware cursor on linux, the cursor flickers… So the result of updating individual frame by calling setHardwareCursor(URL file) is the constanly flickering cursor on linux. Such implementation is by no means portable.
In lwjgl there is already a method that handles harware cursor animation correctly on all systems. All that is needed is to bridge to that method from LWJGLMouseInput. Then add the abstract method with the same signature to the MouseInput class and a method that does nothing to the AWTMouseInput class.
I have modified the existing method of setting the unanimated cursor to set animated cursors… all that is needed is to add that method to LWJGLMouseInput.
Here it is:
/**
* This method will set an animated harware cursor.
*
* @param file in this method file is only used as a key for cursor cashing
* @param images the animation frames
* @param delays delays between changing each frame
* @param xHotspot from image left
* @param yHotspot from image bottom
*/
public void setHardwareCursor(URL file,
Image[] images,
int[] delays, int xHotspot, int yHotspot)
{
Mouse.setGrabbed(false);
if (loadedCursors == null) {
loadedCursors = new Hashtable<URL, Cursor>();
}
Cursor cursor = null;
if (loadedCursors.containsKey(file)) {
cursor = loadedCursors.get(file);
}
else {
boolean eightBitAlpha = true;
if ((Cursor.getCapabilities() & Cursor.CURSOR_8_BIT_ALPHA) == 0) {
eightBitAlpha = false;
}
Image image = images[0];
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
IntBuffer imageData = image.getData().asIntBuffer();
int imageSize = imageData.remaining();
IntBuffer cursorData = BufferUtils.createIntBuffer(
imageSize*images.length);
for (int i = 0; i < images.length; i++) {
image = images[i];
imageData = image.getData().asIntBuffer();
for (int y = 0; y < imageHeight; y++) {
for (int x = 0; x < imageWidth; x++) {
int index = y * imageWidth + x;
int pixel = imageData.get(index);
int a = (pixel >> 24) & 0xff;
if (!eightBitAlpha) {
if (a < 0x7f) a = 0x00;
else a = 0xff;
}
int b = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int r = (pixel) & 0xff;
cursorData.put(index + imageSize*i,
(a << 24) | (r << 16) | (g << 8) | b);
}
}
}
if (xHotspot < 0 || yHotspot < 0 || xHotspot >= imageWidth
|| yHotspot >= imageHeight)
{
//Revert to a hotspot position of top-left
xHotspot = 0;
yHotspot = imageHeight - 1;
logger.log(Level.WARNING,
"Hotspot positions are outside image bounds!");
}
IntBuffer delaysData = null;
if (delays != null) {
delaysData = BufferUtils.createIntBuffer(delays.length);
delaysData.put(delays);
delaysData.rewind();
}
try {
cursor = new Cursor(imageWidth, imageHeight,
xHotspot, yHotspot,
images.length, cursorData, delaysData);
} catch (LWJGLException e) {
logger.log(Level.WARNING, "Failed creating native cursor!", e);
}
loadedCursors.put(file, cursor);
}
try {
org.lwjgl.input.Mouse.setNativeCursor(cursor);
} catch (LWJGLException e) {
logger.log(Level.WARNING, "Failed setting native cursor!", e);
}
}
I am constantly testing lots of stuff involving cursor animation, so this method is being run often and is well tested. (If you are concerned about copyright, then originally this method is written by a jme developer and I put any modifications from my part to the public domain, you do not have to mention me). Including this method to LWJGLMouseInput would allow for system-independent hardware cursor animation to be possible. ;)