Mouse cursor that we load on one monitor may look very small on higher DPI monitors, that is why we should load different sizes of mouse cursors and apply the one that fits best the monitor’s DPI.
Note that in order to simulate different DPIs, we can simply change monitor’s scale in Windows’ display settings (under “Scale and layout”).
Here is a little class that offers basic functionality to solve given problem.
package com.betalord.sgx.core;
import java.awt.Toolkit;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Disposable;
/**
* Class that contains all of the logic to load and set mouse cursor image.
*
* @author Betalord
*/
public class MouseCursor {
/**
* Note: we don't statically load cursor data since we must not do that on Android.
* This is why we load it on {@link MouseCursor#init()}, which should get invoked on desktop only.
*/
public static enum MouseCursorSize {
/** 24x24 pixels */
P24(24),
/** 32x32 pixels */
P32(32),
/** 40x40 pixels */
P40(40),
/** 48x48 pixels */
P48(48),
/** 56x56 pixels */
P56(56),
/** 64x64 pixels */
P64(64);
/** Size in pixels (n x n pixels). Note that cursor image itself is padded to power of two sized image, however the cursor image itself may be smaller. */
private int pixels;
private MouseCursorData data;
MouseCursorSize(int pixels) {
this.pixels = pixels;
}
public int getPixels() {
return pixels;
}
public MouseCursorData getData() {
return data;
}
@Override
public String toString() {
return pixels + " x " + pixels;
}
public static MouseCursorSize getClosest(int pixels) {
MouseCursorSize value = null;
int diff = Integer.MAX_VALUE;
for (MouseCursorSize size : MouseCursorSize.values())
if (Math.abs(pixels-size.pixels) <= diff) {
diff = Math.abs(pixels-size.pixels);
value = size;
}
return value;
}
private MouseCursorData load() {
MouseCursorData data = new MouseCursorData();
// create a 1x1 white pixel texture:
data.pixmap = new Pixmap(Gdx.files.internal("gfx/mouse_" + pixels + ".png"));
TextureData texData = new PixmapTextureData(data.pixmap, Format.RGBA8888, false, false, false);
data.texture = new Texture(texData);
data.drawable = new TextureRegionDrawable(new TextureRegion(data.texture));
return data;
}
}
public static class MouseCursorData implements Disposable {
public Pixmap pixmap;
public Texture texture;
public Drawable drawable;
@Override
public void dispose() {
pixmap.dispose();
texture.dispose();
}
}
/**
* Loads cursors of all sizes and creates textures for them.
* Should be called on desktop only (Android doesn't have mouse and hence does not use mouse cursors).
*/
public static void init() {
for (MouseCursorSize size : MouseCursorSize.values())
size.data = size.load();
}
/**
* Will determine best mouse cursor image size (based on monitor's PPI value).
*/
public static MouseCursorSize determineClosest() {
float ppi = Toolkit.getDefaultToolkit().getScreenResolution();
float start = 96; // PPI value for which we use the smallest cursor, 24x24 pixels
int pixels = Math.round(24 * (ppi/start));
return MouseCursorSize.getClosest(pixels);
}
}