Finished Joystick Support
This commit is contained in:
		
							parent
							
								
									618ccc1cc2
								
							
						
					
					
						commit
						52fcac6fe9
					
				@ -19,7 +19,7 @@ public class NewInputTest {
 | 
			
		||||
		Joystick.INSTANCE.init(bus);
 | 
			
		||||
		ButtonData data = new ButtonData();
 | 
			
		||||
		while(true) {
 | 
			
		||||
			Joystick.INSTANCE.handleJoystick(GLFW.GLFW_JOYSTICK_1, data);
 | 
			
		||||
			Joystick.INSTANCE.handleJoystick(0, GLFW.GLFW_JOYSTICK_1, data);
 | 
			
		||||
			try {
 | 
			
		||||
				Thread.sleep(100);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ public abstract class AbstractDevice<T, E> implements InputDevice {
 | 
			
		||||
	protected abstract void process(E task);
 | 
			
		||||
	
 | 
			
		||||
	protected boolean pushEvent(Event event) {
 | 
			
		||||
		if(bus == null) return true;
 | 
			
		||||
		bus.post(event);
 | 
			
		||||
		return event.isCancelable() && event.isCanceled();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -5,26 +5,30 @@ import java.nio.FloatBuffer;
 | 
			
		||||
import java.util.BitSet;
 | 
			
		||||
 | 
			
		||||
import org.lwjgl.glfw.GLFW;
 | 
			
		||||
import org.lwjgl.system.Callback;
 | 
			
		||||
 | 
			
		||||
import speiger.src.collections.floats.lists.FloatArrayList;
 | 
			
		||||
import speiger.src.collections.floats.lists.FloatList;
 | 
			
		||||
import speiger.src.collections.ints.collections.IntIterator;
 | 
			
		||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
 | 
			
		||||
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.coreengine.rendering.input.devices.Joystick.JoyStickData;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.devices.Joystick.JoyStickTask;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.events.JoystickEvent;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.window.WindowManager;
 | 
			
		||||
import speiger.src.coreengine.utils.eventbus.EventBus;
 | 
			
		||||
 | 
			
		||||
public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
 | 
			
		||||
	public static final Joystick INSTANCE = new Joystick();
 | 
			
		||||
	WindowManager manager;
 | 
			
		||||
	IntSet presentJoysticks = new IntLinkedOpenHashSet();
 | 
			
		||||
	Callback callback;
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public void init(EventBus bus) {
 | 
			
		||||
	public void init(WindowManager manager, EventBus bus) {
 | 
			
		||||
		this.manager = manager;
 | 
			
		||||
		super.init(bus);
 | 
			
		||||
		callback = GLFW.glfwSetJoystickCallback(this::plugin);
 | 
			
		||||
		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);
 | 
			
		||||
@ -32,9 +36,8 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void destroy() {
 | 
			
		||||
		callback.free();
 | 
			
		||||
	}
 | 
			
		||||
	@Override
 | 
			
		||||
	public void init(EventBus bus) { throw new UnsupportedOperationException("Use init(WindowManager, EventBus) instead"); }
 | 
			
		||||
	
 | 
			
		||||
	private void plugin(int jid, int event) {
 | 
			
		||||
		if(event == GLFW.GLFW_CONNECTED) presentJoysticks.add(jid);
 | 
			
		||||
@ -55,28 +58,45 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
 | 
			
		||||
	@Override
 | 
			
		||||
	public void processInput(long windowId) {
 | 
			
		||||
		super.processInput(windowId);
 | 
			
		||||
		if(manager.getActiveWindow() != windowId) return;		
 | 
			
		||||
		JoyStickData data = get(windowId);
 | 
			
		||||
		if(data == null) return;
 | 
			
		||||
		for(IntIterator iter = presentJoysticks.iterator();iter.hasNext();) {
 | 
			
		||||
			int jid = iter.nextInt();
 | 
			
		||||
			ButtonData buttons = data.data.get(jid);
 | 
			
		||||
			if(buttons == null) continue;
 | 
			
		||||
			handleJoystick(windowId, jid, buttons);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void handleJoystick(int jid, ButtonData data) {
 | 
			
		||||
	public void handleJoystick(long window, int jid, ButtonData data) {
 | 
			
		||||
		ByteBuffer buttons = GLFW.glfwGetJoystickButtons(jid);
 | 
			
		||||
		for(int i = 0;buttons.hasRemaining();i++) {
 | 
			
		||||
			data.buttons.set(i, buttons.get() == GLFW.GLFW_PRESS);
 | 
			
		||||
			boolean state = buttons.get() == GLFW.GLFW_PRESS;
 | 
			
		||||
			if(data.buttons.get(i) != state) {
 | 
			
		||||
				data.buttons.set(i, state);
 | 
			
		||||
				pushEvent(new JoystickEvent.Button(window, jid, i, state));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		FloatBuffer axis = GLFW.glfwGetJoystickAxes(jid);
 | 
			
		||||
		for(int i = 0;axis.hasRemaining();i++) {
 | 
			
		||||
			float state = axis.get();
 | 
			
		||||
			if(i >= data.axis.size()) data.axis.add(state);
 | 
			
		||||
			else data.axis.set(i, state);
 | 
			
		||||
			boolean negative = state < 0F;
 | 
			
		||||
			boolean max = state < -0.95F || state > 0.95F;
 | 
			
		||||
			boolean min = state < -0.5F || state > 0.5F;
 | 
			
		||||
			data.axisState.set(i*3, state < 0);
 | 
			
		||||
			boolean min = (state < -0.5F || state > 0.5F) && !max;
 | 
			
		||||
			if(data.axisState.get(i*3) != negative || data.axisState.get(i*3+1) != max || data.axisState.get(i*3+2) != min) {
 | 
			
		||||
				data.axisState.set(i*3, negative);
 | 
			
		||||
				data.axisState.set(i*3+1, max);
 | 
			
		||||
			data.axisState.set(i*3+2, !max && min);				
 | 
			
		||||
				data.axisState.set(i*3+2, min);
 | 
			
		||||
				pushEvent(new JoystickEvent.Axis(window, jid, i, state, negative, min, max));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static class JoyStickData {
 | 
			
		||||
		
 | 
			
		||||
		Int2ObjectMap<ButtonData> data = new Int2ObjectOpenHashMap<>();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static class ButtonData {
 | 
			
		||||
@ -92,7 +112,10 @@ public class Joystick extends AbstractDevice<JoyStickData, JoyStickTask> {
 | 
			
		||||
	public record Plugin(long window, int jid, int event) implements JoyStickTask {
 | 
			
		||||
		@Override
 | 
			
		||||
		public void process(Joystick stick) {
 | 
			
		||||
			
 | 
			
		||||
			JoyStickData data = stick.get(window);
 | 
			
		||||
			if(event == GLFW.GLFW_CONNECTED) data.data.put(jid, new ButtonData());
 | 
			
		||||
			else if(event == GLFW.GLFW_DISCONNECTED) data.data.remove(jid);
 | 
			
		||||
			stick.pushEvent(new JoystickEvent.Connected(window, jid, event == GLFW.GLFW_CONNECTED));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,65 @@
 | 
			
		||||
package speiger.src.coreengine.rendering.input.events;
 | 
			
		||||
 | 
			
		||||
import speiger.src.coreengine.utils.eventbus.Event;
 | 
			
		||||
 | 
			
		||||
public class JoystickEvent extends Event {
 | 
			
		||||
	final long window;
 | 
			
		||||
	final int jid;
 | 
			
		||||
	
 | 
			
		||||
	public JoystickEvent(long window, int jid) {
 | 
			
		||||
		this.window = window;
 | 
			
		||||
		this.jid = jid;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public long window() { return window; }
 | 
			
		||||
	public int jid() { return jid; }
 | 
			
		||||
	
 | 
			
		||||
	public static class Connected extends JoystickEvent {
 | 
			
		||||
		boolean connected;
 | 
			
		||||
 | 
			
		||||
		public Connected(long window, int jid, boolean connected) {
 | 
			
		||||
			super(window, jid);
 | 
			
		||||
			this.connected = connected;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		public boolean connected() { return connected; }
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static class Button extends JoystickEvent {
 | 
			
		||||
		final int button;
 | 
			
		||||
		final boolean press;
 | 
			
		||||
		
 | 
			
		||||
		public Button(long window, int jid, int button, boolean press) {
 | 
			
		||||
			super(window, jid);
 | 
			
		||||
			this.button = button;
 | 
			
		||||
			this.press = press;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		public int button() { return button; }
 | 
			
		||||
		public boolean press() { return press; }
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static class Axis extends JoystickEvent {
 | 
			
		||||
		int axis;
 | 
			
		||||
		float value;
 | 
			
		||||
		boolean negative;
 | 
			
		||||
		boolean halfPress;
 | 
			
		||||
		boolean fullPress;
 | 
			
		||||
		
 | 
			
		||||
		public Axis(long window, int jid, int axis, float value, boolean negative, boolean halfPress, boolean fullPress) {
 | 
			
		||||
			super(window, jid);
 | 
			
		||||
			this.axis = axis;
 | 
			
		||||
			this.value = value;
 | 
			
		||||
			this.negative = negative;
 | 
			
		||||
			this.halfPress = halfPress;
 | 
			
		||||
			this.fullPress = fullPress;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		public int axis() { return axis; }
 | 
			
		||||
		public float value() { return value; }
 | 
			
		||||
		public float absoluteValue() { return Math.abs(value); }
 | 
			
		||||
		public boolean negative() { return negative; }
 | 
			
		||||
		public boolean halfPress() { return halfPress; }
 | 
			
		||||
		public boolean fullPress() { return fullPress; }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -11,7 +11,6 @@ import speiger.src.collections.objects.lists.ObjectArrayList;
 | 
			
		||||
import speiger.src.coreengine.math.vector.ints.Vec4i;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.window.WindowCallback.SimpleReloadFunction;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder;
 | 
			
		||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
 | 
			
		||||
import speiger.src.coreengine.utils.collections.FlagHolder;
 | 
			
		||||
@ -156,7 +155,6 @@ public class Window {
 | 
			
		||||
		callbacks.clear();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public <T extends CallbackI> WindowCallback addSimpleCallback(T listener, SimpleReloadFunction<T> function) { return addCallback(listener, function); }
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public <T extends CallbackI> WindowCallback addCallback(T listener, ReloadFunction<T> function) {
 | 
			
		||||
		WindowCallback callback = new WindowCallback(listener, (ReloadFunction<CallbackI>)function);
 | 
			
		||||
 | 
			
		||||
@ -6,23 +6,26 @@ import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
import org.lwjgl.glfw.GLFW;
 | 
			
		||||
import org.lwjgl.system.Callback;
 | 
			
		||||
import org.lwjgl.system.CallbackI;
 | 
			
		||||
 | 
			
		||||
import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap;
 | 
			
		||||
import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
 | 
			
		||||
import speiger.src.collections.objects.lists.ObjectArrayList;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.devices.InputDevice;
 | 
			
		||||
import speiger.src.coreengine.rendering.input.window.WindowCallback.SimpleReloadFunction;
 | 
			
		||||
 | 
			
		||||
public class WindowManager {
 | 
			
		||||
	Long2ObjectMap<Monitor> monitors;
 | 
			
		||||
	Long2ObjectMap<Window> windows = new Long2ObjectConcurrentOpenHashMap<>();
 | 
			
		||||
	Window activeWindow;
 | 
			
		||||
	Window primaryWindow;
 | 
			
		||||
	List<WindowCallback> callbacks = new ObjectArrayList<>();
 | 
			
		||||
	Callback monitorTracker;
 | 
			
		||||
	List<InputDevice> devices = new ObjectArrayList<>();
 | 
			
		||||
	
 | 
			
		||||
	public void initialize() {
 | 
			
		||||
		monitors = Monitor.createMonitors();
 | 
			
		||||
		monitorTracker = GLFW.glfwSetMonitorCallback(this::onMonitorChanged);
 | 
			
		||||
		addCallback(this::onMonitorChanged, GLFW::glfwSetMonitorCallback);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private void onMonitorChanged(long monitor, int event) {
 | 
			
		||||
@ -33,23 +36,28 @@ public class WindowManager {
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public WindowBuilder builder() { return new WindowBuilder(this); }
 | 
			
		||||
	private Window create(WindowBuilder builder) { return new Window(builder); }
 | 
			
		||||
	
 | 
			
		||||
	private Window create(WindowBuilder builder) {
 | 
			
		||||
		return new Window(builder);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void addDevice(InputDevice device) {
 | 
			
		||||
		devices.add(device);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void addDevice(InputDevice device) { devices.add(device); }
 | 
			
		||||
	public void removeDevice(InputDevice device) { devices.remove(device); }
 | 
			
		||||
	public void processDevices(long windowId) {
 | 
			
		||||
		for(int i = 0,m=devices.size();i<m;i++) {
 | 
			
		||||
			devices.get(i).processInput(windowId);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void removeDevice(InputDevice device) {
 | 
			
		||||
		devices.remove(device);
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public <T extends CallbackI> WindowCallback addCallback(T listener, SimpleReloadFunction<T> function) {
 | 
			
		||||
		WindowCallback callback = new WindowCallback(listener, (SimpleReloadFunction<CallbackI>)function);
 | 
			
		||||
		callbacks.add(callback);
 | 
			
		||||
		callback.load(0L);
 | 
			
		||||
		return callback;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void removeCallback(WindowCallback callback) {
 | 
			
		||||
		if(callbacks.remove(callback)) {
 | 
			
		||||
			callback.destroy();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void addWindow(Window window) {
 | 
			
		||||
@ -67,8 +75,21 @@ public class WindowManager {
 | 
			
		||||
		else if(activeWindow == window) activeWindow = null;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void destroy() {
 | 
			
		||||
		callbacks.forEach(WindowCallback::destroy);
 | 
			
		||||
		callbacks.clear();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public long getActiveWindow() {
 | 
			
		||||
		return activeWindow == null ? 0L : activeWindow.id();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public long getPrimaryWindow() {
 | 
			
		||||
		return primaryWindow == null ? 0 : primaryWindow.id;
 | 
			
		||||
		return primaryWindow == null ? 0 : primaryWindow.id();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public Window getWindow(long window) {
 | 
			
		||||
		return windows.get(window);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public Monitor getMonitor(long id) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user