More work on the engine.

- Added: Animation Features (Delays/reverse playing/etc)
- Added: Joystick can now work when no window is focused (per window
setting)
- Changed: BitUtil functions to with better names.
This commit is contained in:
Speiger 2024-06-02 00:47:22 +02:00
parent afa3215abd
commit 099eec4fe4
11 changed files with 84 additions and 40 deletions

View File

@ -29,7 +29,6 @@ public class NewInputTest {
manager.addDevices(Mouse.INSTANCE, Keyboard.INSTANCE, Joystick.INSTANCE, FileDrop.INSTANCE);
Window window = manager.builder().title("Testing Engine").build();
window.visible(true);
//TODO implement window close requests
while(!window.shouldClose()) {
GLFW.glfwPollEvents();
window.beginFrame();

View File

@ -1,42 +1,36 @@
package speiger.src.coreengine.math;
import speiger.src.coreengine.math.vector.ints.Vec2i;
public class BitUtil {
public static long toLong(long firstShort, long secondShort) {
return (firstShort << 32) | (secondShort & 0xFFFFFFFFL);
public static long toLong(long key, long value) {
return (key << 32L) | (value & 0xFFFFFFFFL);
}
public static int toFirstInt(long value) {
public static int intKey(long value) {
return (int)((value >> 32) & 0xFFFFFFFFL);
}
public static int toSecondInt(long value) {
return (int)(value & 0xFFFFFFFFL);
public static int intValue(long value) {
return (int)(value & 0xFFFFFFFFL);
}
public static long intAdd(long source, long key, long value) {
return toLong(key + intKey(source), value + intValue(source));
}
public static long addToLong(long value, long x, long z) {
return ((x + toFirstInt(value)) & 0xFFFFFFFFL) << 32 | (((z + toSecondInt(value)) & 0xFFFFFFFFL));
public static int toInt(int key, int value) {
return (key & 0xFFFF) << 16 | (value & 0xFFFF);
}
public static int toInt(int firstShort, int secondShort) {
return (firstShort & 0xFFFF) << 16 | (secondShort & 0xFFFF);
}
public static int toFirstShort(int value) {
public static int shortKey(int value) {
return (short)(value >> 16 & 0xFFFF);
}
public static int toSecondShort(int value) {
public static int shortValue(int value) {
return (short)(value & 0xFFFF);
}
public static int addToInt(int value, int x, int z) {
return ((x + toFirstShort(value)) & 0xFFFF) << 16 | ((z + toSecondShort(value)) & 0xFFFF);
}
public static int addToInt(int value, Vec2i offset) {
return ((offset.x() + toFirstShort(value)) & 0xFFFF) << 16 | ((offset.y() + toSecondShort(value)) & 0xFFFF);
public static int shortAdd(int source, int key, int value) {
return toInt(key + shortKey(source), value + shortValue(source));
}
public static int pack_2_10_10_10_int_rev(float x, float y, float z, float w) {

View File

@ -48,27 +48,27 @@ public class MathUtils {
}
public static byte sign(byte value) {
return value > 0 ? 1 : (value < 0 ? -1 : (byte)0);
return (byte)Integer.signum(value);
}
public static short sign(short value) {
return value > 0 ? 1 : (value < 0 ? -1 : (short)0);
return (short)Integer.signum(value);
}
public static int sign(int value) {
return value > 0 ? 1 : (value < 0 ? -1 : 0);
return Integer.signum(value);
}
public static long sign(long value) {
return value > 0 ? 1 : (value < 0 ? -1 : 0);
return Long.signum(value);
}
public static float sign(float value) {
return value > 0 ? 1F : (value < 0 ? -1F : 0F);
return Math.signum(value);
}
public static double sign(double value) {
return value > 0 ? 1D : (value < 0 ? -1D : 0D);
return Math.signum(value);
}
public static int sub(int key, int value) {

View File

@ -4,7 +4,7 @@ import speiger.src.coreengine.math.vector.ints.Vec2i;
public class ShapeUtil {
public static boolean isInCircle(int position, int radius, int testX, int testZ) {
return isInCircle(BitUtil.toFirstShort(position), BitUtil.toSecondShort(position), radius, testX, testZ);
return isInCircle(BitUtil.shortKey(position), BitUtil.shortValue(position), radius, testX, testZ);
}
public static boolean isInCircle(Vec2i position, int radius, int testX, int testZ) {

View File

@ -6,7 +6,7 @@ import speiger.src.coreengine.math.vector.ints.Vec2i;
public interface I2DCollision extends Iterable<Vec2i>
{
public default boolean isMixedCollision() {return false;}
public default boolean isColliding(int position){return isColliding(BitUtil.toFirstShort(position), BitUtil.toSecondShort(position));}
public default boolean isColliding(int position){return isColliding(BitUtil.shortKey(position), BitUtil.shortValue(position));}
public default boolean isColliding(Vec2i pos){return isColliding(pos.x(), pos.y());}
public boolean isColliding(int x, int y);
}

View File

@ -26,7 +26,7 @@ public class GuiAnimation {
public void apply(GuiComponent owner, float progress) {
for(Entry<Target, IAction> entry : Object2ObjectMaps.fastIterable(actions)) {
IAction action = entry.getValue();
action.apply(entry.getKey(), Math.min(progress, action.duration()));
action.apply(entry.getKey(), owner, Math.min(progress, action.duration()));
}
}

View File

@ -1,8 +1,41 @@
package speiger.src.coreengine.rendering.gui.animation;
import speiger.src.coreengine.rendering.gui.animation.GuiAnimation.Target;
import speiger.src.coreengine.rendering.gui.components.base.GuiComponent;
public interface IAction {
public float duration();
public void apply(Target target, float progress);
public void apply(Target target, GuiComponent component, float progress);
public default IAction withPreDelay(float delay) { return this instanceof PreDelayedAction delayed ? new PreDelayedAction(delayed.action(), delay + delayed.delay()) : new PreDelayedAction(this, delay); }
public default IAction withPostDelay(float delay) { return this instanceof PostDelayedAction delayed ? new PostDelayedAction(delayed.action(), delay + delayed.delay()) : new PostDelayedAction(this, delay); }
public default IAction reverse() { return this instanceof ReversedAction reversed ? reversed.action() : new ReversedAction(this); }
public record PreDelayedAction(IAction action, float delay) implements IAction {
@Override
public float duration() { return delay + action.duration(); }
@Override
public void apply(Target target, GuiComponent component, float progress) {
action.apply(target, component, Math.max(progress - delay, 0F));
}
}
public record PostDelayedAction(IAction action, float delay) implements IAction {
@Override
public float duration() { return action.duration() + delay; }
@Override
public void apply(Target target, GuiComponent component, float progress) {
action.apply(target, component, Math.min(progress, action.duration()));
}
}
public record ReversedAction(IAction action) implements IAction {
@Override
public float duration() { return action.duration(); }
@Override
public void apply(Target target, GuiComponent component, float progress) {
action.apply(target, component, action.duration() - progress);
}
}
}

View File

@ -14,6 +14,8 @@ import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.ints.sets.IntLinkedOpenHashSet;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.longs.collections.LongIterator;
import speiger.src.collections.longs.sets.LongOpenHashSet;
import speiger.src.collections.longs.sets.LongSet;
import speiger.src.coreengine.rendering.input.devices.Joystick.JoyStickData;
import speiger.src.coreengine.rendering.input.devices.Joystick.JoyStickTask;
import speiger.src.coreengine.rendering.input.events.JoystickEvent;
@ -24,6 +26,7 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
public static final Joystick INSTANCE = new Joystick();
WindowManager manager;
IntSet presentJoysticks = new IntLinkedOpenHashSet();
LongSet alwaysProcessInputs = new LongOpenHashSet();
public void init(WindowManager manager, EventBus bus) {
this.manager = manager;
@ -31,7 +34,7 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
manager.addCallback(this::plugin, GLFW::glfwSetJoystickCallback);
for(int i = 0,m=GLFW.GLFW_JOYSTICK_LAST;i<=m;i++) {
if(GLFW.glfwJoystickPresent(i)) {
presentJoysticks.add(i);
plugin(i, GLFW.GLFW_CONNECTED);
}
}
}
@ -39,6 +42,15 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
@Override
public void init(EventBus bus) { throw new UnsupportedOperationException("Use init(WindowManager, EventBus) instead"); }
public void setWindowAlwaysProcessInputs(long windowId, boolean value) {
if(value) alwaysProcessInputs.add(windowId);
else alwaysProcessInputs.remove(windowId);
}
public boolean isWindowAlwaysProcessingInputs(long windowId) {
return alwaysProcessInputs.contains(windowId);
}
private void plugin(int jid, int event) {
if(event == GLFW.GLFW_CONNECTED) presentJoysticks.add(jid);
else presentJoysticks.remove(jid);
@ -51,14 +63,14 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
@Override
public void reset(long windowId) {}
@Override
protected JoyStickData createData(long windowId) { return new JoyStickData(); }
protected JoyStickData createData(long windowId) { return new JoyStickData(presentJoysticks); }
@Override
protected void process(JoyStickTask task) { task.process(this); }
@Override
public void processInput(long windowId) {
super.processInput(windowId);
if(manager.getActiveWindow() != windowId) return;
if(manager.getActiveWindow() != windowId && !alwaysProcessInputs.contains(windowId)) return;
JoyStickData data = get(windowId);
if(data == null) return;
for(IntIterator iter = presentJoysticks.iterator();iter.hasNext();) {
@ -97,6 +109,12 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
public static class JoyStickData {
Int2ObjectMap<ButtonData> data = new Int2ObjectOpenHashMap<>();
public JoyStickData(IntSet knownJoysticks) {
for(IntIterator iter = knownJoysticks.iterator();iter.hasNext();) {
data.put(iter.nextInt(), new ButtonData());
}
}
}
public static class ButtonData {

View File

@ -23,7 +23,7 @@ public class TextureMetadata {
public void applyArguments(int texture) {
for(int i = 0,m=arguments.size();i<m;i++) {
long value = arguments.getLong(i);
GL45.glTextureParameteri(texture, BitUtil.toFirstInt(value), BitUtil.toSecondInt(value));
GL45.glTextureParameteri(texture, BitUtil.intKey(value), BitUtil.intValue(value));
}
}
@ -98,7 +98,7 @@ public class TextureMetadata {
public Builder removeArgument(int id) {
LongList list = metadata.arguments;
for(int i = 0,m=list.size();i<m;i++) {
if(BitUtil.toFirstInt(list.getLong(i)) == id) {
if(BitUtil.intKey(list.getLong(i)) == id) {
list.removeLong(i--);
}
}

View File

@ -66,7 +66,7 @@ public class DynamicTexture extends BaseTexture implements IDynamicTexture {
Thread thread = Thread.currentThread();
for(IntIterator iter = dirtySections.iterator();iter.hasNext() && !thread.isInterrupted();iter.remove()) {
int key = iter.nextInt();
uploadPixels(BitUtil.toFirstShort(key) * 16, BitUtil.toSecondShort(key) * 16);
uploadPixels(BitUtil.shortKey(key) * 16, BitUtil.shortValue(key) * 16);
}
GLStateTracker.instance().unpack_row_length.setDefault();
GLStateTracker.instance().unpack_skip_pixel.setDefault();

View File

@ -171,8 +171,8 @@ public class DynamicTexture extends AbstractTexture implements IDynamicTexture
{
Entry<IntSet> values = iter.next();
int key = values.getIntKey();
int chunkX = BitUtil.toFirstShort(key) * 16;
int chunkZ = BitUtil.toSecondShort(key) * 16;
int chunkX = BitUtil.shortKey(key) * 16;
int chunkZ = BitUtil.shortValue(key) * 16;
int width = 0;
int height = 0;
for(IntIterator subIt = values.getValue().iterator();subIt.hasNext();)