forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
38
leenkx/Sources/iron/system/Audio.hx
Normal file
38
leenkx/Sources/iron/system/Audio.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package iron.system;
|
||||
|
||||
import kha.audio1.AudioChannel;
|
||||
|
||||
/**
|
||||
Audio playback. This class wraps around `kha.audio1.Audio`.
|
||||
**/
|
||||
class Audio {
|
||||
|
||||
#if lnx_audio
|
||||
|
||||
public function new() {}
|
||||
|
||||
/**
|
||||
Plays the given sound.
|
||||
|
||||
If `stream` is `true` and the sound has compressed data, it is streamed
|
||||
from disk instead of being fully loaded into memory. This is useful for
|
||||
longer sounds such as background music.
|
||||
|
||||
This function returns `null` if:
|
||||
|
||||
- there is no unoccupied audio channel available for playback.
|
||||
- the sound has compressed data only but `stream` is `false`. In this
|
||||
case, call `kha.Sound.uncompress()` first.
|
||||
**/
|
||||
public static function play(sound: kha.Sound, loop = false, stream = false): Null<AudioChannel> {
|
||||
if (stream && sound.compressedData != null) {
|
||||
return kha.audio1.Audio.stream(sound, loop);
|
||||
}
|
||||
else if (sound.uncompressedData != null) {
|
||||
return kha.audio1.Audio.play(sound, loop);
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
782
leenkx/Sources/iron/system/Input.hx
Normal file
782
leenkx/Sources/iron/system/Input.hx
Normal file
@ -0,0 +1,782 @@
|
||||
package iron.system;
|
||||
|
||||
import kha.input.KeyCode;
|
||||
|
||||
class Input {
|
||||
|
||||
public static var occupied = false;
|
||||
static var mouse: Mouse = null;
|
||||
static var pen: Pen = null;
|
||||
static var keyboard: Keyboard = null;
|
||||
static var gamepads: Array<Gamepad> = [];
|
||||
static var sensor: Sensor = null;
|
||||
static var registered = false;
|
||||
public static var virtualButtons: Map<String, VirtualButton> = null; // Button name
|
||||
|
||||
public static function reset() {
|
||||
occupied = false;
|
||||
if (mouse != null) mouse.reset();
|
||||
if (pen != null) pen.reset();
|
||||
if (keyboard != null) keyboard.reset();
|
||||
for (gamepad in gamepads) gamepad.reset();
|
||||
}
|
||||
|
||||
public static function endFrame() {
|
||||
if (mouse != null) mouse.endFrame();
|
||||
if (pen != null) pen.endFrame();
|
||||
if (keyboard != null) keyboard.endFrame();
|
||||
for (gamepad in gamepads) gamepad.endFrame();
|
||||
|
||||
if (virtualButtons != null) {
|
||||
for (vb in virtualButtons) vb.started = vb.released = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getMouse(): Mouse {
|
||||
if (!registered) register();
|
||||
if (mouse == null) mouse = new Mouse();
|
||||
return mouse;
|
||||
}
|
||||
|
||||
public static function getPen(): Pen {
|
||||
if (!registered) register();
|
||||
if (pen == null) pen = new Pen();
|
||||
return pen;
|
||||
}
|
||||
|
||||
public static function getSurface(): Surface {
|
||||
if (!registered) register();
|
||||
// Map to mouse for now..
|
||||
return getMouse();
|
||||
}
|
||||
|
||||
/**
|
||||
Get the Keyboard object. If it is not registered yet then register a new Keyboard.
|
||||
**/
|
||||
public static function getKeyboard(): Keyboard {
|
||||
if (!registered) register();
|
||||
if (keyboard == null) keyboard = new Keyboard();
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
public static function getGamepad(i = 0): Gamepad {
|
||||
if (i >= 4) return null;
|
||||
if (!registered) register();
|
||||
while (gamepads.length <= i) gamepads.push(new Gamepad(gamepads.length));
|
||||
return gamepads[i].connected ? gamepads[i] : null;
|
||||
}
|
||||
|
||||
public static function getSensor(): Sensor {
|
||||
if (!registered) register();
|
||||
if (sensor == null) sensor = new Sensor();
|
||||
return sensor;
|
||||
}
|
||||
|
||||
public static function getVirtualButton(virtual: String): VirtualButton {
|
||||
if (!registered) register();
|
||||
if (virtualButtons == null) return null;
|
||||
return virtualButtons.get(virtual);
|
||||
}
|
||||
|
||||
static inline function register() {
|
||||
registered = true;
|
||||
App.notifyOnEndFrame(endFrame);
|
||||
App.notifyOnReset(reset);
|
||||
// Reset mouse delta on foreground
|
||||
kha.System.notifyOnApplicationState(function() { getMouse().reset(); }, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
class VirtualButton {
|
||||
public var started = false;
|
||||
public var released = false;
|
||||
public var down = false;
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
class VirtualInput {
|
||||
var virtualButtons: Map<String, VirtualButton> = null; // Button id
|
||||
|
||||
public function setVirtual(virtual: String, button: String) {
|
||||
if (Input.virtualButtons == null) Input.virtualButtons = new Map<String, VirtualButton>();
|
||||
|
||||
var vb = Input.virtualButtons.get(virtual);
|
||||
if (vb == null) {
|
||||
vb = new VirtualButton();
|
||||
Input.virtualButtons.set(virtual, vb);
|
||||
}
|
||||
|
||||
if (virtualButtons == null) virtualButtons = new Map<String, VirtualButton>();
|
||||
virtualButtons.set(button, vb);
|
||||
}
|
||||
|
||||
function downVirtual(button: String) {
|
||||
if (virtualButtons != null) {
|
||||
var vb = virtualButtons.get(button);
|
||||
if (vb != null) {
|
||||
vb.down = true;
|
||||
vb.started = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function upVirtual(button: String) {
|
||||
if (virtualButtons != null) {
|
||||
var vb = virtualButtons.get(button);
|
||||
if (vb != null) {
|
||||
vb.down = false;
|
||||
vb.released = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef Surface = Mouse;
|
||||
|
||||
class Mouse extends VirtualInput {
|
||||
|
||||
public static var buttons = ["left", "right", "middle", "side1", "side2"];
|
||||
var buttonsDown = [false, false, false, false, false];
|
||||
var buttonsStarted = [false, false, false, false, false];
|
||||
var buttonsReleased = [false, false, false, false, false];
|
||||
|
||||
public var x(default, null) = 0.0;
|
||||
public var y(default, null) = 0.0;
|
||||
public var viewX(get, null) = 0.0;
|
||||
public var viewY(get, null) = 0.0;
|
||||
public var moved(default, null) = false;
|
||||
public var movementX(default, null) = 0.0;
|
||||
public var movementY(default, null) = 0.0;
|
||||
public var wheelDelta(default, null) = 0;
|
||||
public var locked(default, null) = false;
|
||||
public var hidden(default, null) = false;
|
||||
public var lastX = -1.0;
|
||||
public var lastY = -1.0;
|
||||
|
||||
public function new() {
|
||||
kha.input.Mouse.get().notify(downListener, upListener, moveListener, wheelListener);
|
||||
#if (kha_android || kha_ios)
|
||||
if (kha.input.Surface.get() != null) kha.input.Surface.get().notify(onTouchDown, onTouchUp, onTouchMove);
|
||||
#end
|
||||
}
|
||||
|
||||
public function endFrame() {
|
||||
buttonsStarted[0] = buttonsStarted[1] = buttonsStarted[2] = buttonsStarted[3] = buttonsStarted[4] = false;
|
||||
buttonsReleased[0] = buttonsReleased[1] = buttonsReleased[2] = buttonsReleased[3] = buttonsReleased[4] = false;
|
||||
moved = false;
|
||||
movementX = 0;
|
||||
movementY = 0;
|
||||
wheelDelta = 0;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
buttonsDown[0] = buttonsDown[1] = buttonsDown[2] = buttonsDown[3] = buttonsDown[4] = false;
|
||||
endFrame();
|
||||
}
|
||||
|
||||
function buttonIndex(button: String): Int {
|
||||
for (i in 0...buttons.length) if (buttons[i] == button) return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function down(button = "left"): Bool {
|
||||
return buttonsDown[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function started(button = "left"): Bool {
|
||||
return buttonsStarted[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function released(button = "left"): Bool {
|
||||
return buttonsReleased[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function lock() {
|
||||
if (kha.input.Mouse.get().canLock()) {
|
||||
kha.input.Mouse.get().lock();
|
||||
locked = true;
|
||||
hidden = true;
|
||||
}
|
||||
}
|
||||
public function unlock() {
|
||||
if (kha.input.Mouse.get().canLock()) {
|
||||
kha.input.Mouse.get().unlock();
|
||||
locked = false;
|
||||
hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function hide() {
|
||||
kha.input.Mouse.get().hideSystemCursor();
|
||||
hidden = true;
|
||||
}
|
||||
|
||||
public function show() {
|
||||
kha.input.Mouse.get().showSystemCursor();
|
||||
hidden = false;
|
||||
}
|
||||
|
||||
function downListener(index: Int, x: Int, y: Int) {
|
||||
if (Input.getPen().inUse) return;
|
||||
|
||||
buttonsDown[index] = true;
|
||||
buttonsStarted[index] = true;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
#if (kha_android || kha_ios || kha_webgl) // For movement delta using touch
|
||||
if (index == 0) {
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
#end
|
||||
|
||||
downVirtual(buttons[index]);
|
||||
}
|
||||
|
||||
function upListener(index: Int, x: Int, y: Int) {
|
||||
if (Input.getPen().inUse) return;
|
||||
|
||||
buttonsDown[index] = false;
|
||||
buttonsReleased[index] = true;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
upVirtual(buttons[index]);
|
||||
}
|
||||
|
||||
function moveListener(x: Int, y: Int, movementX: Int, movementY: Int) {
|
||||
if (lastX == -1.0 && lastY == -1.0) { // First frame init
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
if (locked) {
|
||||
// Can be called multiple times per frame
|
||||
this.movementX += movementX;
|
||||
this.movementY += movementY;
|
||||
}
|
||||
else {
|
||||
this.movementX += x - lastX;
|
||||
this.movementY += y - lastY;
|
||||
}
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
moved = true;
|
||||
}
|
||||
|
||||
function wheelListener(delta: Int) {
|
||||
wheelDelta = delta;
|
||||
}
|
||||
|
||||
#if (kha_android || kha_ios)
|
||||
public function onTouchDown(index: Int, x: Int, y: Int) {
|
||||
if (index == 1) { // Two fingers down - right mouse button
|
||||
buttonsDown[0] = false;
|
||||
downListener(1, Std.int(this.x), Std.int(this.y));
|
||||
pinchStarted = true;
|
||||
pinchTotal = 0.0;
|
||||
pinchDistance = 0.0;
|
||||
}
|
||||
else if (index == 2) { // Three fingers down - middle mouse button
|
||||
buttonsDown[1] = false;
|
||||
downListener(2, Std.int(this.x), Std.int(this.y));
|
||||
}
|
||||
}
|
||||
|
||||
public function onTouchUp(index: Int, x: Int, y: Int) {
|
||||
if (index == 1) upListener(1, Std.int(this.x), Std.int(this.y));
|
||||
else if (index == 2) upListener(2, Std.int(this.x), Std.int(this.y));
|
||||
}
|
||||
|
||||
var pinchDistance = 0.0;
|
||||
var pinchTotal = 0.0;
|
||||
var pinchStarted = false;
|
||||
|
||||
public function onTouchMove(index: Int, x: Int, y: Int) {
|
||||
// Pinch to zoom - mouse wheel
|
||||
if (index == 1) {
|
||||
var lastDistance = pinchDistance;
|
||||
var dx = this.x - x;
|
||||
var dy = this.y - y;
|
||||
pinchDistance = Math.sqrt(dx * dx + dy * dy);
|
||||
pinchTotal += lastDistance != 0 ? lastDistance - pinchDistance : 0;
|
||||
if (!pinchStarted) {
|
||||
wheelDelta = Std.int(pinchTotal / 10);
|
||||
if (wheelDelta != 0) {
|
||||
pinchTotal = 0.0;
|
||||
}
|
||||
}
|
||||
pinchStarted = false;
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
inline function get_viewX(): Float {
|
||||
return x - iron.App.x();
|
||||
}
|
||||
|
||||
inline function get_viewY(): Float {
|
||||
return y - iron.App.y();
|
||||
}
|
||||
}
|
||||
|
||||
class Pen extends VirtualInput {
|
||||
|
||||
static var buttons = ["tip"];
|
||||
var buttonsDown = [false];
|
||||
var buttonsStarted = [false];
|
||||
var buttonsReleased = [false];
|
||||
|
||||
public var x(default, null) = 0.0;
|
||||
public var y(default, null) = 0.0;
|
||||
public var viewX(get, null) = 0.0;
|
||||
public var viewY(get, null) = 0.0;
|
||||
public var moved(default, null) = false;
|
||||
public var movementX(default, null) = 0.0;
|
||||
public var movementY(default, null) = 0.0;
|
||||
public var pressure(default, null) = 0.0;
|
||||
public var connected = false;
|
||||
public var inUse = false;
|
||||
var lastX = -1.0;
|
||||
var lastY = -1.0;
|
||||
|
||||
public function new() {
|
||||
var pen = kha.input.Pen.get();
|
||||
if (pen != null) pen.notify(downListener, upListener, moveListener);
|
||||
}
|
||||
|
||||
public function endFrame() {
|
||||
buttonsStarted[0] = false;
|
||||
buttonsReleased[0] = false;
|
||||
moved = false;
|
||||
movementX = 0;
|
||||
movementY = 0;
|
||||
inUse = false;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
buttonsDown[0] = false;
|
||||
endFrame();
|
||||
}
|
||||
|
||||
function buttonIndex(button: String): Int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function down(button = "tip"): Bool {
|
||||
return buttonsDown[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function started(button = "tip"): Bool {
|
||||
return buttonsStarted[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function released(button = "tip"): Bool {
|
||||
return buttonsReleased[buttonIndex(button)];
|
||||
}
|
||||
|
||||
function downListener(x: Int, y: Int, pressure: Float) {
|
||||
buttonsDown[0] = true;
|
||||
buttonsStarted[0] = true;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.pressure = pressure;
|
||||
|
||||
#if (!kha_android && !kha_ios)
|
||||
@:privateAccess Input.getMouse().downListener(0, x, y);
|
||||
#end
|
||||
}
|
||||
|
||||
function upListener(x: Int, y: Int, pressure: Float) {
|
||||
#if (!kha_android && !kha_ios)
|
||||
if (buttonsStarted[0]) { buttonsStarted[0] = false; inUse = true; return; }
|
||||
#end
|
||||
|
||||
buttonsDown[0] = false;
|
||||
buttonsReleased[0] = true;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.pressure = pressure;
|
||||
|
||||
#if (!kha_android && !kha_ios)
|
||||
@:privateAccess Input.getMouse().upListener(0, x, y);
|
||||
inUse = true; // On pen release, additional mouse down & up events are fired at once - filter those out
|
||||
#end
|
||||
}
|
||||
|
||||
function moveListener(x: Int, y: Int, pressure: Float) {
|
||||
if (lastX == -1.0 && lastY == -1.0) { // First frame init
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
this.movementX = x - lastX;
|
||||
this.movementY = y - lastY;
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
moved = true;
|
||||
this.pressure = pressure;
|
||||
connected = true;
|
||||
}
|
||||
|
||||
inline function get_viewX(): Float {
|
||||
return x - iron.App.x();
|
||||
}
|
||||
|
||||
inline function get_viewY(): Float {
|
||||
return y - iron.App.y();
|
||||
}
|
||||
}
|
||||
|
||||
class Keyboard extends VirtualInput {
|
||||
|
||||
public static var keys = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "space", "backspace", "tab", "enter", "shift", "control", "alt", "capslock", "win", "escape", "delete", "up", "down", "left", "right", "back", ",", ".", ":", ";", "<", "=", ">", "?", "!", '"', "#", "$", "%", "&", "_", "(", ")", "*", "|", "{", "}", "[", "]", "~", "`", "/", "\\", "@", "+", "-", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12"];
|
||||
var keysDown = new Map<String, Bool>();
|
||||
var keysStarted = new Map<String, Bool>();
|
||||
var keysReleased = new Map<String, Bool>();
|
||||
var keysFrame: Array<String> = [];
|
||||
var repeatKey = false;
|
||||
var repeatTime = 0.0;
|
||||
|
||||
public function new() {
|
||||
reset();
|
||||
kha.input.Keyboard.get().notify(downListener, upListener, pressListener);
|
||||
}
|
||||
|
||||
public function endFrame() {
|
||||
if (keysFrame.length > 0) {
|
||||
for (s in keysFrame) {
|
||||
keysStarted.set(s, false);
|
||||
keysReleased.set(s, false);
|
||||
}
|
||||
keysFrame.splice(0, keysFrame.length);
|
||||
}
|
||||
|
||||
if (kha.Scheduler.time() - repeatTime > 0.05) {
|
||||
repeatTime = kha.Scheduler.time();
|
||||
repeatKey = true;
|
||||
}
|
||||
else repeatKey = false;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
// Use Map for now..
|
||||
for (s in keys) {
|
||||
keysDown.set(s, false);
|
||||
keysStarted.set(s, false);
|
||||
keysReleased.set(s, false);
|
||||
}
|
||||
endFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
Check if a key is currently pressed.
|
||||
@param key A String representing the physical keyboard key to check.
|
||||
@return Bool. Returns true or false depending on the keyboard state.
|
||||
**/
|
||||
public function down(key: String): Bool {
|
||||
return keysDown.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
Check if a key has started being pressed down. Will only be run once until the key is released and pressed again.
|
||||
@param key A String representing the physical keyboard key to check.
|
||||
@return Bool. Returns true or false depending on the keyboard state.
|
||||
**/
|
||||
public function started(key: String): Bool {
|
||||
return keysStarted.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
Check if a key has been released from being pressed down. Will only be run once until the key is pressed again and release again.
|
||||
@param key A String representing the physical keyboard key to check.
|
||||
@return Bool. Returns true or false depending on the keyboard state.
|
||||
**/
|
||||
public function released(key: String): Bool {
|
||||
return keysReleased.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
Check every repeat period if a key is currently pressed.
|
||||
@param key A String representing the physical keyboard key to check.
|
||||
@return Bool. Returns true or false depending on the keyboard state.
|
||||
**/
|
||||
public function repeat(key: String): Bool {
|
||||
return keysStarted.get(key) || (repeatKey && keysDown.get(key));
|
||||
}
|
||||
|
||||
public static function keyCode(key: KeyCode): String {
|
||||
return switch(key) {
|
||||
case KeyCode.Space: "space";
|
||||
case KeyCode.Backspace: "backspace";
|
||||
case KeyCode.Tab: "tab";
|
||||
case KeyCode.Return: "enter";
|
||||
case KeyCode.Shift: "shift";
|
||||
case KeyCode.Control: "control";
|
||||
#if kha_darwin
|
||||
case KeyCode.Meta: "control";
|
||||
#end
|
||||
case KeyCode.Alt: "alt";
|
||||
case KeyCode.CapsLock: "capslock";
|
||||
case KeyCode.Win: "win";
|
||||
case KeyCode.Escape: "escape";
|
||||
case KeyCode.Delete: "delete";
|
||||
case KeyCode.Up: "up";
|
||||
case KeyCode.Down: "down";
|
||||
case KeyCode.Left: "left";
|
||||
case KeyCode.Right: "right";
|
||||
case KeyCode.Back: "back";
|
||||
case KeyCode.Comma: ",";
|
||||
case KeyCode.Period: ".";
|
||||
case KeyCode.Colon: ":";
|
||||
case KeyCode.Semicolon: ";";
|
||||
case KeyCode.LessThan: "<";
|
||||
case KeyCode.Equals: "=";
|
||||
case KeyCode.GreaterThan: ">";
|
||||
case KeyCode.QuestionMark: "?";
|
||||
case KeyCode.Exclamation: "!";
|
||||
case KeyCode.DoubleQuote: '"';
|
||||
case KeyCode.Hash: "#";
|
||||
case KeyCode.Dollar: "$";
|
||||
case KeyCode.Percent: "%";
|
||||
case KeyCode.Ampersand: "&";
|
||||
case KeyCode.Underscore: "_";
|
||||
case KeyCode.OpenParen: "(";
|
||||
case KeyCode.CloseParen: ")";
|
||||
case KeyCode.Asterisk: "*";
|
||||
case KeyCode.Pipe: "|";
|
||||
case KeyCode.OpenCurlyBracket: "{";
|
||||
case KeyCode.CloseCurlyBracket: "}";
|
||||
case KeyCode.OpenBracket: "[";
|
||||
case KeyCode.CloseBracket: "]";
|
||||
case KeyCode.Tilde: "~";
|
||||
case KeyCode.BackQuote: "`";
|
||||
case KeyCode.Slash: "/";
|
||||
case KeyCode.BackSlash: "\\";
|
||||
case KeyCode.At: "@";
|
||||
case KeyCode.Add: "+";
|
||||
case KeyCode.Plus: "+";
|
||||
case KeyCode.Subtract: "-";
|
||||
case KeyCode.HyphenMinus: "-";
|
||||
case KeyCode.Multiply: "*";
|
||||
case KeyCode.Divide: "/";
|
||||
case KeyCode.Decimal: ".";
|
||||
case KeyCode.Zero: "0";
|
||||
case KeyCode.Numpad0: "0";
|
||||
case KeyCode.One: "1";
|
||||
case KeyCode.Numpad1: "1";
|
||||
case KeyCode.Two: "2";
|
||||
case KeyCode.Numpad2: "2";
|
||||
case KeyCode.Three: "3";
|
||||
case KeyCode.Numpad3: "3";
|
||||
case KeyCode.Four: "4";
|
||||
case KeyCode.Numpad4: "4";
|
||||
case KeyCode.Five: "5";
|
||||
case KeyCode.Numpad5: "5";
|
||||
case KeyCode.Six: "6";
|
||||
case KeyCode.Numpad6: "6";
|
||||
case KeyCode.Seven: "7";
|
||||
case KeyCode.Numpad7: "7";
|
||||
case KeyCode.Eight: "8";
|
||||
case KeyCode.Numpad8: "8";
|
||||
case KeyCode.Nine: "9";
|
||||
case KeyCode.Numpad9: "9";
|
||||
case KeyCode.F1: "f1";
|
||||
case KeyCode.F2: "f2";
|
||||
case KeyCode.F3: "f3";
|
||||
case KeyCode.F4: "f4";
|
||||
case KeyCode.F5: "f5";
|
||||
case KeyCode.F6: "f6";
|
||||
case KeyCode.F7: "f7";
|
||||
case KeyCode.F8: "f8";
|
||||
case KeyCode.F9: "f9";
|
||||
case KeyCode.F10: "f10";
|
||||
case KeyCode.F11: "f11";
|
||||
case KeyCode.F12: "f12";
|
||||
default: String.fromCharCode(cast key).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
function downListener(code: KeyCode) {
|
||||
var s = keyCode(code);
|
||||
keysFrame.push(s);
|
||||
keysStarted.set(s, true);
|
||||
keysDown.set(s, true);
|
||||
repeatTime = kha.Scheduler.time() + 0.4;
|
||||
|
||||
#if kha_android_rmb // Detect right mouse button on Android..
|
||||
if (code == KeyCode.Back) {
|
||||
var m = Input.getMouse();
|
||||
@:privateAccess if (!m.buttonsDown[1]) m.downListener(1, Std.int(m.x), Std.int(m.y));
|
||||
}
|
||||
#end
|
||||
|
||||
downVirtual(s);
|
||||
}
|
||||
|
||||
function upListener(code: KeyCode) {
|
||||
var s = keyCode(code);
|
||||
keysFrame.push(s);
|
||||
keysReleased.set(s, true);
|
||||
keysDown.set(s, false);
|
||||
|
||||
#if kha_android_rmb
|
||||
if (code == KeyCode.Back) {
|
||||
var m = Input.getMouse();
|
||||
@:privateAccess m.upListener(1, Std.int(m.x), Std.int(m.y));
|
||||
}
|
||||
#end
|
||||
|
||||
upVirtual(s);
|
||||
}
|
||||
|
||||
function pressListener(char: String) {}
|
||||
}
|
||||
|
||||
class GamepadStick {
|
||||
public var x = 0.0;
|
||||
public var y = 0.0;
|
||||
public var lastX = 0.0;
|
||||
public var lastY = 0.0;
|
||||
public var moved = false;
|
||||
public var movementX = 0.0;
|
||||
public var movementY = 0.0;
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
class Gamepad extends VirtualInput {
|
||||
|
||||
public static var buttonsPS = ["cross", "circle", "square", "triangle", "l1", "r1", "l2", "r2", "share", "options", "l3", "r3", "up", "down", "left", "right", "home", "touchpad"];
|
||||
public static var buttonsXBOX = ["a", "b", "x", "y", "l1", "r1", "l2", "r2", "share", "options", "l3", "r3", "up", "down", "left", "right", "home", "touchpad"];
|
||||
public static var buttons = buttonsPS;
|
||||
|
||||
public var id(get, never): String;
|
||||
inline function get_id() return kha.input.Gamepad.get(num).id;
|
||||
|
||||
var buttonsDown: Array<Float> = []; // Intensity 0 - 1
|
||||
var buttonsStarted: Array<Bool> = [];
|
||||
var buttonsReleased: Array<Bool> = [];
|
||||
|
||||
var buttonsFrame: Array<Int> = [];
|
||||
|
||||
public var leftStick = new GamepadStick();
|
||||
public var rightStick = new GamepadStick();
|
||||
|
||||
public var connected = false;
|
||||
var num = 0;
|
||||
|
||||
public function new(i: Int, virtual = false) {
|
||||
for (s in buttons) {
|
||||
buttonsDown.push(0.0);
|
||||
buttonsStarted.push(false);
|
||||
buttonsReleased.push(false);
|
||||
}
|
||||
num = i;
|
||||
reset();
|
||||
virtual ? connected = true : connect();
|
||||
}
|
||||
|
||||
var connects = 0;
|
||||
function connect() {
|
||||
var gamepad = kha.input.Gamepad.get(num);
|
||||
if (gamepad == null) {
|
||||
// if (connects < 10) leenkx.system.Tween.timer(1, connect);
|
||||
// connects++;
|
||||
return;
|
||||
}
|
||||
connected = true;
|
||||
gamepad.notify(axisListener, buttonListener);
|
||||
}
|
||||
|
||||
public function endFrame() {
|
||||
if (buttonsFrame.length > 0) {
|
||||
for (i in buttonsFrame) {
|
||||
buttonsStarted[i] = false;
|
||||
buttonsReleased[i] = false;
|
||||
}
|
||||
buttonsFrame.splice(0, buttonsFrame.length);
|
||||
}
|
||||
leftStick.moved = false;
|
||||
leftStick.movementX = 0;
|
||||
leftStick.movementY = 0;
|
||||
rightStick.moved = false;
|
||||
rightStick.movementX = 0;
|
||||
rightStick.movementY = 0;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
for (i in 0...buttonsDown.length) {
|
||||
buttonsDown[i] = 0.0;
|
||||
buttonsStarted[i] = false;
|
||||
buttonsReleased[i] = false;
|
||||
}
|
||||
endFrame();
|
||||
}
|
||||
|
||||
public static function keyCode(button: Int): String {
|
||||
return buttons[button];
|
||||
}
|
||||
|
||||
function buttonIndex(button: String): Int {
|
||||
for (i in 0...buttons.length) if (buttons[i] == button) return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function down(button: String): Float {
|
||||
return buttonsDown[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function started(button: String): Bool {
|
||||
return buttonsStarted[buttonIndex(button)];
|
||||
}
|
||||
|
||||
public function released(button: String): Bool {
|
||||
return buttonsReleased[buttonIndex(button)];
|
||||
}
|
||||
|
||||
function axisListener(axis: Int, value: Float) {
|
||||
var stick = axis <= 1 ? leftStick : rightStick;
|
||||
|
||||
if (axis == 0 || axis == 2) { // X
|
||||
stick.lastX = stick.x;
|
||||
stick.x = value;
|
||||
stick.movementX = stick.x - stick.lastX;
|
||||
}
|
||||
else if (axis == 1 || axis == 3) { // Y
|
||||
stick.lastY = stick.y;
|
||||
stick.y = value;
|
||||
stick.movementY = stick.y - stick.lastY;
|
||||
}
|
||||
stick.moved = true;
|
||||
}
|
||||
|
||||
function buttonListener(button: Int, value: Float) {
|
||||
buttonsFrame.push(button);
|
||||
|
||||
buttonsDown[button] = value;
|
||||
if (value > 0) buttonsStarted[button] = true; // Will trigger L2/R2 multiple times..
|
||||
else buttonsReleased[button] = true;
|
||||
|
||||
if (value == 0.0) upVirtual(buttons[button]);
|
||||
else if (value == 1.0) downVirtual(buttons[button]);
|
||||
}
|
||||
}
|
||||
|
||||
class Sensor {
|
||||
|
||||
public var x = 0.0;
|
||||
public var y = 0.0;
|
||||
public var z = 0.0;
|
||||
|
||||
public function new() {
|
||||
kha.input.Sensor.get(kha.input.SensorType.Accelerometer).notify(listener);
|
||||
}
|
||||
|
||||
function listener(x: Float, y: Float, z: Float) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
239
leenkx/Sources/iron/system/LnxPack.hx
Normal file
239
leenkx/Sources/iron/system/LnxPack.hx
Normal file
@ -0,0 +1,239 @@
|
||||
// Msgpack parser with typed arrays
|
||||
// Based on https://github.com/aaulia/msgpack-haxe
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
package iron.system;
|
||||
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.BytesInput;
|
||||
import haxe.io.BytesOutput;
|
||||
import haxe.io.Eof;
|
||||
import iron.data.SceneFormat;
|
||||
#if (!macro)
|
||||
import kha.arrays.Float32Array;
|
||||
import kha.arrays.Uint32Array;
|
||||
import kha.arrays.Int16Array;
|
||||
#end
|
||||
|
||||
class LnxPack {
|
||||
|
||||
public static inline function decode<T>(b: Bytes): T {
|
||||
var i = new BytesInput(b);
|
||||
i.bigEndian = false;
|
||||
return read(i);
|
||||
}
|
||||
|
||||
static function read(i: BytesInput, key = "", parentKey = ""): Any {
|
||||
try {
|
||||
var b = i.readByte();
|
||||
switch (b) {
|
||||
case 0xc0: return null;
|
||||
case 0xc2: return false;
|
||||
case 0xc3: return true;
|
||||
case 0xc4: return i.read(i.readByte());
|
||||
case 0xc5: return i.read(i.readUInt16());
|
||||
case 0xc6: return i.read(i.readInt32());
|
||||
case 0xca: return i.readFloat();
|
||||
case 0xcc: return i.readByte();
|
||||
case 0xcd: return i.readUInt16();
|
||||
case 0xce: return i.readInt32();
|
||||
case 0xd0: return i.readInt8();
|
||||
case 0xd1: return i.readInt16();
|
||||
case 0xd2: return i.readInt32();
|
||||
// case 0xd3: return Int64.make(i.readInt32(), i.readInt32());
|
||||
case 0xd9: return i.readString(i.readByte());
|
||||
case 0xda: return i.readString(i.readUInt16());
|
||||
case 0xdb: return i.readString(i.readInt32());
|
||||
case 0xdc: return readArray(i, i.readUInt16(), key, parentKey);
|
||||
case 0xdd: return readArray(i, i.readInt32(), key, parentKey);
|
||||
case 0xde: return readMap(i, i.readUInt16(), key, parentKey);
|
||||
case 0xdf: return readMap(i, i.readInt32(), key, parentKey);
|
||||
|
||||
default: {
|
||||
if (b < 0x80) return b; // positive fix num
|
||||
else if (b < 0x90) return readMap(i, (0xf & b), key, parentKey); // fix map
|
||||
else if (b < 0xa0) return readArray(i, (0xf & b), key, parentKey); // fix array
|
||||
else if (b < 0xc0) return i.readString(0x1f & b); // fix string
|
||||
else if (b > 0xdf) return 0xffffff00 | b; // negative fix num
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e: Eof) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
static function readArray(i: BytesInput, length: Int, key = "", parentKey = ""): Any {
|
||||
var b = i.readByte();
|
||||
i.position--;
|
||||
|
||||
if (b == 0xca) { // Typed float32
|
||||
i.position++;
|
||||
var a = new Float32Array(length);
|
||||
for (x in 0...length) a[x] = i.readFloat();
|
||||
return a;
|
||||
}
|
||||
else if (b == 0xd2) { // Typed int32
|
||||
i.position++;
|
||||
var a = new Uint32Array(length);
|
||||
for (x in 0...length) a[x] = i.readInt32();
|
||||
return a;
|
||||
}
|
||||
else if (b == 0xd1) { // Typed int16
|
||||
i.position++;
|
||||
var a = new Int16Array(length);
|
||||
for (x in 0...length) a[x] = i.readInt16();
|
||||
return a;
|
||||
}
|
||||
else { // Dynamic type-value
|
||||
var a: Array<Dynamic> = [];
|
||||
for (x in 0...length) a.push(read(i, key, parentKey));
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
static function readMap(i: BytesInput, length: Int, key = "", parentKey = ""): Any {
|
||||
#if js
|
||||
var out = {};
|
||||
#else
|
||||
var out = Type.createEmptyInstance(getClass(key, parentKey));
|
||||
#end
|
||||
for (n in 0...length) {
|
||||
var k = Std.string(read(i));
|
||||
var v = read(i, k, key);
|
||||
Reflect.setField(out, k, v);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#if (!js)
|
||||
static function getClass(key: String, parentKey: String): Class<Dynamic> {
|
||||
return switch (key) {
|
||||
case "": TSceneFormat;
|
||||
case "mesh_datas": TMeshData;
|
||||
case "light_datas": TLightData;
|
||||
case "probe_datas": TProbeData;
|
||||
case "probe": TProbeData;
|
||||
case "camera_datas": TCameraData;
|
||||
case "material_datas": TMaterialData;
|
||||
case "particle_datas": TParticleData;
|
||||
case "shader_datas": TShaderData;
|
||||
case "speaker_datas": TSpeakerData;
|
||||
case "world_datas": TWorldData;
|
||||
case "terrain_datas": TTerrainData;
|
||||
case "tilesheet_datas": TTilesheetData;
|
||||
case "objects": TObj;
|
||||
case "children": TObj;
|
||||
case "groups": TGroup;
|
||||
case "traits": TTrait;
|
||||
case "properties": TProperty;
|
||||
case "vertex_arrays": TVertexArray;
|
||||
case "index_arrays": TIndexArray;
|
||||
case "skin": TSkin;
|
||||
case "transform": TTransform;
|
||||
case "constraints": TConstraint;
|
||||
case "contexts": parentKey == "material_datas" ? TMaterialContext : TShaderContext;
|
||||
case "override_context": TShaderOverride;
|
||||
case "bind_constants": TBindConstant;
|
||||
case "bind_textures": TBindTexture;
|
||||
case "vertex_elements": TVertexElement;
|
||||
case "constants": TShaderConstant;
|
||||
case "texture_units": TTextureUnit;
|
||||
case "actions": TTilesheetAction;
|
||||
case "particle_refs": TParticleReference;
|
||||
case "lods": TLod;
|
||||
case "anim": TAnimation;
|
||||
case "tracks": TTrack;
|
||||
case "morph_target": TMorphTarget;
|
||||
case _: TSceneFormat;
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if (!macro && armorcore)
|
||||
|
||||
public static inline function encode(d: Dynamic): Bytes {
|
||||
var o = new BytesOutput();
|
||||
o.bigEndian = false;
|
||||
write(o, d);
|
||||
return o.getBytes();
|
||||
}
|
||||
|
||||
static function write(o: BytesOutput, d: Dynamic) {
|
||||
switch (Type.typeof(d)) {
|
||||
case TNull: o.writeByte(0xc0);
|
||||
case TBool: o.writeByte(d ? 0xc3 : 0xc2);
|
||||
case TInt: { o.writeByte(0xd2); o.writeInt32(d); }
|
||||
case TFloat: { o.writeByte(0xca); o.writeFloat(d); }
|
||||
case TClass(c): {
|
||||
switch (Type.getClassName(c)) {
|
||||
case "String": {
|
||||
o.writeByte(0xdb);
|
||||
var b = Bytes.ofString(d);
|
||||
o.writeInt32(b.length);
|
||||
o.writeFullBytes(b, 0, b.length);
|
||||
}
|
||||
case "Array", null: { // kha.arrays give null
|
||||
o.writeByte(0xdd);
|
||||
o.writeInt32(d.length);
|
||||
var isInt16 = Std.isOfType(d, #if js js.lib.Int16Array #else Int16ArrayPrivate #end);
|
||||
var isInt = Std.isOfType(d[0], Int) && !Std.isOfType(d, #if js js.lib.Float32Array #else Float32ArrayPrivate #end);
|
||||
var isFloat = Std.isOfType(d[0], Float);
|
||||
|
||||
if (isInt16) { // Int16Array
|
||||
o.writeByte(0xd1);
|
||||
for (i in 0...d.length) o.writeInt16(d[i]);
|
||||
}
|
||||
else if (isFloat && !isInt) { // Float32Array
|
||||
o.writeByte(0xca);
|
||||
for (i in 0...d.length) o.writeFloat(d[i]);
|
||||
}
|
||||
else if (isInt) { // Uint32Array
|
||||
o.writeByte(0xd2);
|
||||
for (i in 0...d.length) o.writeInt32(d[i]);
|
||||
}
|
||||
else for (i in 0...d.length) write(o, d[i]); // Array
|
||||
}
|
||||
case "haxe.io.Bytes": {
|
||||
o.writeByte(0xc6);
|
||||
o.writeInt32(d.length);
|
||||
o.writeFullBytes(d, 0, d.length);
|
||||
}
|
||||
default: writeObject(o, d);
|
||||
}
|
||||
}
|
||||
case TObject: writeObject(o, d);
|
||||
default: {}
|
||||
}
|
||||
}
|
||||
|
||||
static function writeObject(o: BytesOutput, d: Dynamic) {
|
||||
var f = Reflect.fields(d);
|
||||
o.writeByte(0xdf);
|
||||
o.writeInt32(f.length);
|
||||
for (k in f) {
|
||||
o.writeByte(0xdb);
|
||||
var b = Bytes.ofString(k);
|
||||
o.writeInt32(b.length);
|
||||
o.writeFullBytes(b, 0, b.length);
|
||||
write(o, Reflect.field(d, k));
|
||||
}
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
261
leenkx/Sources/iron/system/Lz4.hx
Normal file
261
leenkx/Sources/iron/system/Lz4.hx
Normal file
@ -0,0 +1,261 @@
|
||||
// Based on https://github.com/gorhill/lz4-wasm
|
||||
// BSD 2-Clause License
|
||||
// Copyright (c) 2018, Raymond Hill
|
||||
// All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
package iron.system;
|
||||
|
||||
import haxe.io.Bytes;
|
||||
#if macro
|
||||
import haxe.io.Int32Array;
|
||||
typedef Uint8Array = haxe.io.UInt8Array;
|
||||
#else
|
||||
import kha.arrays.Int32Array;
|
||||
import kha.arrays.Uint8Array;
|
||||
#end
|
||||
|
||||
class Lz4 {
|
||||
|
||||
static var hashTable: Int32Array = null;
|
||||
|
||||
static inline function encodeBound(size: Int): Int {
|
||||
return untyped size > 0x7e000000 ? 0 : size + (size / 255 | 0) + 16;
|
||||
}
|
||||
|
||||
public static function encode(b: Bytes): Bytes {
|
||||
#if armorcore
|
||||
var iBuf = new Uint8Array(cast b.getData());
|
||||
|
||||
#else
|
||||
var iBuf: Uint8Array = new Uint8Array(b.length);
|
||||
for (i in 0...b.length) iBuf[i] = b.get(i);
|
||||
#end
|
||||
|
||||
var iLen = iBuf.length;
|
||||
if (iLen >= 0x7e000000) {
|
||||
trace("LZ4 range error");
|
||||
return null;
|
||||
}
|
||||
|
||||
// "The last match must start at least 12 bytes before end of block"
|
||||
var lastMatchPos = iLen - 12;
|
||||
|
||||
// "The last 5 bytes are always literals"
|
||||
var lastLiteralPos = iLen - 5;
|
||||
|
||||
if (hashTable == null) hashTable = new Int32Array(65536);
|
||||
for (i in 0...hashTable.length) {
|
||||
hashTable[i] = -65536;
|
||||
}
|
||||
|
||||
var oLen = encodeBound(iLen);
|
||||
var oBuf = new Uint8Array(oLen);
|
||||
var iPos = 0;
|
||||
var oPos = 0;
|
||||
var anchorPos = 0;
|
||||
|
||||
// Sequence-finding loop
|
||||
while (true) {
|
||||
var refPos = 0;
|
||||
var mOffset = 0;
|
||||
var sequence = iBuf[iPos] << 8 | iBuf[iPos + 1] << 16 | iBuf[iPos + 2] << 24;
|
||||
|
||||
// Match-finding loop
|
||||
while (iPos <= lastMatchPos) {
|
||||
sequence = sequence >>> 8 | iBuf[iPos + 3] << 24;
|
||||
var hash = (sequence * 0x9e37 & 0xffff) + (sequence * 0x79b1 >>> 16) & 0xffff;
|
||||
refPos = hashTable[hash];
|
||||
hashTable[hash] = iPos;
|
||||
mOffset = iPos - refPos;
|
||||
if (mOffset < 65536 &&
|
||||
iBuf[refPos + 0] == ((sequence ) & 0xff) &&
|
||||
iBuf[refPos + 1] == ((sequence >>> 8) & 0xff) &&
|
||||
iBuf[refPos + 2] == ((sequence >>> 16) & 0xff) &&
|
||||
iBuf[refPos + 3] == ((sequence >>> 24) & 0xff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
iPos += 1;
|
||||
}
|
||||
|
||||
// No match found
|
||||
if (iPos > lastMatchPos) break;
|
||||
|
||||
// Match found
|
||||
var lLen = iPos - anchorPos;
|
||||
var mLen = iPos;
|
||||
iPos += 4; refPos += 4;
|
||||
while (iPos < lastLiteralPos && iBuf[iPos] == iBuf[refPos]) {
|
||||
iPos += 1; refPos += 1;
|
||||
}
|
||||
mLen = iPos - mLen;
|
||||
var token = mLen < 19 ? mLen - 4 : 15;
|
||||
|
||||
// Write token, length of literals if needed
|
||||
if (lLen >= 15) {
|
||||
oBuf[oPos++] = 0xf0 | token;
|
||||
var l = lLen - 15;
|
||||
while (l >= 255) {
|
||||
oBuf[oPos++] = 255;
|
||||
l -= 255;
|
||||
}
|
||||
oBuf[oPos++] = l;
|
||||
}
|
||||
else {
|
||||
oBuf[oPos++] = (lLen << 4) | token;
|
||||
}
|
||||
|
||||
// Write literals
|
||||
while (lLen-- > 0) {
|
||||
oBuf[oPos++] = iBuf[anchorPos++];
|
||||
}
|
||||
|
||||
if (mLen == 0) break;
|
||||
|
||||
// Write offset of match
|
||||
oBuf[oPos + 0] = mOffset;
|
||||
oBuf[oPos + 1] = mOffset >>> 8;
|
||||
oPos += 2;
|
||||
|
||||
// Write length of match if needed
|
||||
if (mLen >= 19) {
|
||||
var l = mLen - 19;
|
||||
while (l >= 255) {
|
||||
oBuf[oPos++] = 255;
|
||||
l -= 255;
|
||||
}
|
||||
oBuf[oPos++] = l;
|
||||
}
|
||||
|
||||
anchorPos = iPos;
|
||||
}
|
||||
|
||||
// Last sequence is literals only
|
||||
var lLen = iLen - anchorPos;
|
||||
if (lLen >= 15) {
|
||||
oBuf[oPos++] = 0xf0;
|
||||
var l = lLen - 15;
|
||||
while (l >= 255) {
|
||||
oBuf[oPos++] = 255;
|
||||
l -= 255;
|
||||
}
|
||||
oBuf[oPos++] = l;
|
||||
}
|
||||
else {
|
||||
oBuf[oPos++] = lLen << 4;
|
||||
}
|
||||
while (lLen-- > 0) {
|
||||
oBuf[oPos++] = iBuf[anchorPos++];
|
||||
}
|
||||
|
||||
#if js
|
||||
return Bytes.ofData(untyped oBuf.buffer.slice(0, oPos));
|
||||
|
||||
#elseif hl
|
||||
return oBuf.getData().toBytes(oPos);
|
||||
|
||||
#else
|
||||
var bOut = Bytes.alloc(oPos);
|
||||
for (i in 0...oPos) {
|
||||
bOut.set(i, oBuf[i]);
|
||||
}
|
||||
return bOut;
|
||||
#end
|
||||
}
|
||||
|
||||
public static function decode(b: Bytes, oLen: Int): Bytes {
|
||||
#if armorcore
|
||||
var iBuf = new Uint8Array(cast b.getData());
|
||||
|
||||
#else
|
||||
var iBuf: Uint8Array = new Uint8Array(b.length);
|
||||
for (i in 0...b.length) iBuf[i] = b.get(i);
|
||||
#end
|
||||
|
||||
var iLen = iBuf.length;
|
||||
var oBuf = new Uint8Array(oLen);
|
||||
var iPos = 0;
|
||||
var oPos = 0;
|
||||
|
||||
while (iPos < iLen) {
|
||||
var token = iBuf[iPos++];
|
||||
|
||||
// Literals
|
||||
var clen = token >>> 4;
|
||||
|
||||
// Length of literals
|
||||
if (clen != 0) {
|
||||
if (clen == 15) {
|
||||
var l = 0;
|
||||
while (true) {
|
||||
l = iBuf[iPos++];
|
||||
if (l != 255) break;
|
||||
clen += 255;
|
||||
}
|
||||
clen += l;
|
||||
}
|
||||
|
||||
// Copy literals
|
||||
var end = iPos + clen;
|
||||
while (iPos < end) {
|
||||
oBuf[oPos++] = iBuf[iPos++];
|
||||
}
|
||||
if (iPos == iLen) break;
|
||||
}
|
||||
|
||||
// Match
|
||||
var mOffset = iBuf[iPos + 0] | (iBuf[iPos + 1] << 8);
|
||||
if (mOffset == 0 || mOffset > oPos) return null;
|
||||
iPos += 2;
|
||||
|
||||
// Length of match
|
||||
clen = (token & 0x0f) + 4;
|
||||
if (clen == 19) {
|
||||
var l = 0;
|
||||
while (true) {
|
||||
l = iBuf[iPos++];
|
||||
if (l != 255) break;
|
||||
clen += 255;
|
||||
}
|
||||
clen += l;
|
||||
}
|
||||
|
||||
// Copy match
|
||||
var mPos = oPos - mOffset;
|
||||
var end = oPos + clen;
|
||||
while (oPos < end) {
|
||||
oBuf[oPos++] = oBuf[mPos++];
|
||||
}
|
||||
}
|
||||
|
||||
#if js
|
||||
return Bytes.ofData(untyped oBuf.buffer);
|
||||
|
||||
#elseif hl
|
||||
return oBuf.getData().toBytes(oBuf.length);
|
||||
|
||||
#else
|
||||
var bOut = Bytes.alloc(oLen);
|
||||
for (i in 0...oLen) {
|
||||
bOut.set(i, oBuf[i]);
|
||||
}
|
||||
return bOut;
|
||||
#end
|
||||
}
|
||||
}
|
38
leenkx/Sources/iron/system/Storage.hx
Normal file
38
leenkx/Sources/iron/system/Storage.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package iron.system;
|
||||
|
||||
import kha.StorageFile;
|
||||
|
||||
class Storage {
|
||||
|
||||
static var file: StorageFile = null;
|
||||
public static var data(get, set): Dynamic;
|
||||
static var _data: Dynamic = null;
|
||||
|
||||
static function init() {
|
||||
file = kha.Storage.defaultFile();
|
||||
if (file != null) {
|
||||
_data = file.readObject();
|
||||
if (_data == null) _data = {};
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public static function save() {
|
||||
if (file != null) {
|
||||
file.writeObject(_data);
|
||||
}
|
||||
}
|
||||
|
||||
public static function clear() {
|
||||
_data = {};
|
||||
}
|
||||
|
||||
public static function set_data(d: Dynamic): Dynamic {
|
||||
return _data = d;
|
||||
}
|
||||
|
||||
public static function get_data(): Dynamic {
|
||||
if (file == null) init();
|
||||
return _data;
|
||||
}
|
||||
}
|
37
leenkx/Sources/iron/system/Time.hx
Normal file
37
leenkx/Sources/iron/system/Time.hx
Normal file
@ -0,0 +1,37 @@
|
||||
package iron.system;
|
||||
|
||||
class Time {
|
||||
|
||||
public static var step(get, never): Float;
|
||||
static function get_step(): Float {
|
||||
if (frequency == null) initFrequency();
|
||||
return 1 / frequency;
|
||||
}
|
||||
|
||||
public static var scale = 1.0;
|
||||
public static var delta(get, never): Float;
|
||||
static function get_delta(): Float {
|
||||
if (frequency == null) initFrequency();
|
||||
return (1 / frequency) * scale;
|
||||
}
|
||||
|
||||
static var last = 0.0;
|
||||
public static var realDelta = 0.0;
|
||||
public static inline function time(): Float {
|
||||
return kha.Scheduler.time();
|
||||
}
|
||||
public static inline function realTime(): Float {
|
||||
return kha.Scheduler.realTime();
|
||||
}
|
||||
|
||||
static var frequency: Null<Int> = null;
|
||||
|
||||
static function initFrequency() {
|
||||
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
|
||||
}
|
||||
|
||||
public static function update() {
|
||||
realDelta = realTime() - last;
|
||||
last = realTime();
|
||||
}
|
||||
}
|
290
leenkx/Sources/iron/system/Tween.hx
Normal file
290
leenkx/Sources/iron/system/Tween.hx
Normal file
@ -0,0 +1,290 @@
|
||||
package iron.system;
|
||||
|
||||
class Tween {
|
||||
|
||||
static inline var DEFAULT_OVERSHOOT: Float = 1.70158;
|
||||
|
||||
static var eases: Array<Float->Float> = [
|
||||
easeLinear,
|
||||
easeSineIn, easeSineOut, easeSineInOut,
|
||||
easeQuadIn, easeQuadOut, easeQuadInOut,
|
||||
easeCubicIn, easeCubicOut, easeCubicInOut,
|
||||
easeQuartIn, easeQuartOut, easeQuartInOut,
|
||||
easeQuintIn, easeQuintOut, easeQuintInOut,
|
||||
easeExpoIn, easeExpoOut, easeExpoInOut,
|
||||
easeCircIn, easeCircOut, easeCircInOut,
|
||||
easeBackIn, easeBackOut, easeBackInOut,
|
||||
easeBounceIn, easeBounceOut, easeBounceInOut,
|
||||
easeElasticIn, easeElasticOut, easeElasticInOut
|
||||
];
|
||||
|
||||
static var anims: Array<TAnim> = [];
|
||||
|
||||
static var registered = false;
|
||||
static inline function register() {
|
||||
registered = true;
|
||||
App.notifyOnUpdate(update);
|
||||
App.notifyOnReset(function() { App.notifyOnUpdate(update); reset(); });
|
||||
}
|
||||
|
||||
public static function to(anim: TAnim): TAnim {
|
||||
if (!registered) register();
|
||||
anim._time = 0;
|
||||
anim.isPlaying = (anim.delay != null && anim.delay > 0.0) ? false : true;
|
||||
|
||||
if (anim.ease == null) anim.ease = Ease.Linear;
|
||||
|
||||
if (anim.target != null && anim.props != null) {
|
||||
|
||||
anim._comps = []; anim._x = []; anim._y = []; anim._z = []; anim._w = []; anim._normalize = [];
|
||||
for (p in Reflect.fields(anim.props)) {
|
||||
var val: Dynamic = Reflect.getProperty(anim.target, p);
|
||||
if (Std.isOfType(val, iron.math.Vec4) || Std.isOfType(val, iron.math.Quat)) {
|
||||
anim._comps.push(4);
|
||||
anim._x.push(val.x);
|
||||
anim._y.push(val.y);
|
||||
anim._z.push(val.z);
|
||||
anim._w.push(val.w);
|
||||
anim._normalize.push(Std.isOfType(val, iron.math.Quat));
|
||||
}
|
||||
else {
|
||||
anim._comps.push(1);
|
||||
anim._x.push(val);
|
||||
anim._y.push(0);
|
||||
anim._z.push(0);
|
||||
anim._w.push(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anims.push(anim);
|
||||
return anim;
|
||||
}
|
||||
|
||||
public static function timer(delay: Float, done: Void->Void): TAnim {
|
||||
return to({ target: null, props: null, duration: 0, delay: delay, done: done });
|
||||
}
|
||||
|
||||
public static function stop(anim: TAnim) {
|
||||
anim.isPlaying = false;
|
||||
anims.remove(anim);
|
||||
}
|
||||
|
||||
public static function reset() {
|
||||
anims = [];
|
||||
}
|
||||
|
||||
public static function update() {
|
||||
var d = Time.delta;
|
||||
var i = anims.length;
|
||||
while (i-- > 0 && anims.length > 0) {
|
||||
var a = anims[i];
|
||||
|
||||
if (a.delay > 0) { // Delay
|
||||
a.delay -= d;
|
||||
if (a.delay > 0) continue;
|
||||
}
|
||||
|
||||
a._time += d;
|
||||
a.isPlaying = a._time < a.duration;
|
||||
|
||||
if (a.target != null) {
|
||||
|
||||
if (Std.isOfType(a.target, iron.object.Transform)) a.target.dirty = true;
|
||||
|
||||
// Way too much Reflect trickery..
|
||||
var ps = Reflect.fields(a.props);
|
||||
for (i in 0...ps.length) {
|
||||
var p = ps[i];
|
||||
var k = a._time / a.duration;
|
||||
if (k > 1) k = 1;
|
||||
|
||||
if (a._comps[i] == 1) {
|
||||
var fromVal: Float = a._x[i];
|
||||
var toVal: Float = Reflect.getProperty(a.props, p);
|
||||
var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k);
|
||||
Reflect.setProperty(a.target, p, val);
|
||||
}
|
||||
else { // _comps[i] == 4
|
||||
var obj = Reflect.getProperty(a.props, p);
|
||||
var toX: Float = Reflect.getProperty(obj, "x");
|
||||
var toY: Float = Reflect.getProperty(obj, "y");
|
||||
var toZ: Float = Reflect.getProperty(obj, "z");
|
||||
var toW: Float = Reflect.getProperty(obj, "w");
|
||||
if (a._normalize[i]) {
|
||||
var qdot = (a._x[i] * toX) + (a._y[i] * toY) + (a._z[i] * toZ) + (a._w[i] * toW);
|
||||
if (qdot < 0.0) {
|
||||
toX = -toX; toY = -toY; toZ = -toZ; toW = -toW;
|
||||
}
|
||||
}
|
||||
var x: Float = a._x[i] + (toX - a._x[i]) * eases[a.ease](k);
|
||||
var y: Float = a._y[i] + (toY - a._y[i]) * eases[a.ease](k);
|
||||
var z: Float = a._z[i] + (toZ - a._z[i]) * eases[a.ease](k);
|
||||
var w: Float = a._w[i] + (toW - a._w[i]) * eases[a.ease](k);
|
||||
if (a._normalize[i]) {
|
||||
var l = Math.sqrt(x * x + y * y + z * z + w * w);
|
||||
if (l > 0.0) {
|
||||
l = 1.0 / l;
|
||||
x *= l; y *= l; z *= l; w *= l;
|
||||
}
|
||||
}
|
||||
var t = Reflect.getProperty(a.target, p);
|
||||
Reflect.setProperty(t, "x", x);
|
||||
Reflect.setProperty(t, "y", y);
|
||||
Reflect.setProperty(t, "z", z);
|
||||
Reflect.setProperty(t, "w", w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a.isPlaying) {
|
||||
if (a.tick != null) a.tick();
|
||||
}
|
||||
else {
|
||||
anims.splice(i, 1);
|
||||
i--;
|
||||
a.isPlaying = false;
|
||||
if (a.done != null) a.done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function easeLinear(k: Float): Float { return k; }
|
||||
public static function easeSineIn(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return 1 - Math.cos(k * Math.PI / 2); } }
|
||||
public static function easeSineOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return Math.sin(k * (Math.PI * 0.5)); } }
|
||||
public static function easeSineInOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return -0.5 * (Math.cos(Math.PI * k) - 1); } }
|
||||
public static function easeQuadIn(k: Float): Float { return k * k; }
|
||||
public static function easeQuadOut(k: Float): Float { return -k * (k - 2); }
|
||||
public static function easeQuadInOut(k: Float): Float { return (k < 0.5) ? 2 * k * k : -2 * ((k -= 1) * k) + 1; }
|
||||
public static function easeCubicIn(k: Float): Float { return k * k * k; }
|
||||
public static function easeCubicOut(k: Float): Float { return (k = k - 1) * k * k + 1; }
|
||||
public static function easeCubicInOut(k: Float): Float { return ((k *= 2) < 1) ? 0.5 * k * k * k : 0.5 * ((k -= 2) * k * k + 2); }
|
||||
public static function easeQuartIn(k: Float): Float { return (k *= k) * k; }
|
||||
public static function easeQuartOut(k: Float): Float { return 1 - (k = (k = k - 1) * k) * k; }
|
||||
public static function easeQuartInOut(k: Float): Float { return ((k *= 2) < 1) ? 0.5 * (k *= k) * k : -0.5 * ((k = (k -= 2) * k) * k - 2); }
|
||||
public static function easeQuintIn(k: Float): Float { return k * (k *= k) * k; }
|
||||
public static function easeQuintOut(k: Float): Float { return (k = k - 1) * (k *= k) * k + 1; }
|
||||
public static function easeQuintInOut(k: Float): Float { return ((k *= 2) < 1) ? 0.5 * k * (k *= k) * k : 0.5 * (k -= 2) * (k *= k) * k + 1; }
|
||||
public static function easeExpoIn(k: Float): Float { return k == 0 ? 0 : Math.pow(2, 10 * (k - 1)); }
|
||||
public static function easeExpoOut(k: Float): Float { return k == 1 ? 1 : (1 - Math.pow(2, -10 * k)); }
|
||||
public static function easeExpoInOut(k: Float): Float { if (k == 0) { return 0; } if (k == 1) { return 1; } if ((k /= 1 / 2.0) < 1.0) { return 0.5 * Math.pow(2, 10 * (k - 1)); } return 0.5 * (2 - Math.pow(2, -10 * --k)); }
|
||||
public static function easeCircIn(k: Float): Float { return -(Math.sqrt(1 - k * k) - 1); }
|
||||
public static function easeCircOut(k: Float): Float { return Math.sqrt(1 - (k - 1) * (k - 1)); }
|
||||
public static function easeCircInOut(k: Float): Float { return k <= .5 ? (Math.sqrt(1 - k * k * 4) - 1) / -2 : (Math.sqrt(1 - (k * 2 - 2) * (k * 2 - 2)) + 1) / 2; }
|
||||
public static function easeBackIn(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return k * k * ((DEFAULT_OVERSHOOT + 1) * k - DEFAULT_OVERSHOOT); } }
|
||||
public static function easeBackOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return ((k = k - 1) * k * ((DEFAULT_OVERSHOOT + 1) * k + DEFAULT_OVERSHOOT) + 1); } }
|
||||
public static function easeBackInOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else if ((k *= 2) < 1) { return (0.5 * (k * k * (((DEFAULT_OVERSHOOT * 1.525) + 1) * k - DEFAULT_OVERSHOOT * 1.525))); } else { return (0.5 * ((k -= 2) * k * (((DEFAULT_OVERSHOOT * 1.525) + 1) * k + DEFAULT_OVERSHOOT * 1.525) + 2)); } }
|
||||
public static function easeBounceIn(k: Float): Float { return 1 - easeBounceOut(1 - k); }
|
||||
public static function easeBounceOut(k: Float): Float { return if (k < (1 / 2.75)) { 7.5625 * k * k; } else if (k < (2 / 2.75)) { 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; } else if (k < (2.5 / 2.75)) { 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } }
|
||||
public static function easeBounceInOut(k: Float): Float { return (k < 0.5) ? easeBounceIn(k * 2) * 0.5 : easeBounceOut(k * 2 - 1) * 0.5 + 0.5; }
|
||||
|
||||
public static function easeElasticIn(k: Float): Float {
|
||||
var s: Null<Float> = null;
|
||||
var a = 0.1, p = 0.4;
|
||||
if (k == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k == 1) {
|
||||
return 1;
|
||||
}
|
||||
if (a < 1) {
|
||||
a = 1;
|
||||
s = p / 4;
|
||||
}
|
||||
else {
|
||||
s = p * Math.asin(1 / a) / (2 * Math.PI);
|
||||
}
|
||||
return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
|
||||
}
|
||||
|
||||
public static function easeElasticOut(k: Float): Float {
|
||||
var s: Null<Float> = null;
|
||||
var a = 0.1, p = 0.4;
|
||||
if (k == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k == 1) {
|
||||
return 1;
|
||||
}
|
||||
if (a < 1) {
|
||||
a = 1;
|
||||
s = p / 4;
|
||||
}
|
||||
else {
|
||||
s = p * Math.asin(1 / a) / (2 * Math.PI);
|
||||
}
|
||||
return (a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1);
|
||||
}
|
||||
|
||||
public static function easeElasticInOut(k: Float): Float {
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if (k == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (k == 1) {
|
||||
return 1;
|
||||
}
|
||||
if (a != 0 || a < 1) {
|
||||
a = 1;
|
||||
s = p / 4;
|
||||
}
|
||||
else {
|
||||
s = p * Math.asin(1 / a) / (2 * Math.PI);
|
||||
}
|
||||
if ((k *= 2) < 1) return - 0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
|
||||
return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
typedef TAnim = {
|
||||
var target: Dynamic;
|
||||
var props: Dynamic;
|
||||
var duration: Float;
|
||||
@:optional var isPlaying: Null<Bool>;
|
||||
@:optional var done: Void->Void;
|
||||
@:optional var tick: Void->Void;
|
||||
@:optional var delay: Null<Float>;
|
||||
@:optional var ease: Null<Ease>;
|
||||
// Internal
|
||||
@:optional var _time: Null<Float>;
|
||||
@:optional var _comps: Array<Int>;
|
||||
@:optional var _x: Array<Float>;
|
||||
@:optional var _y: Array<Float>;
|
||||
@:optional var _z: Array<Float>;
|
||||
@:optional var _w: Array<Float>;
|
||||
@:optional var _normalize: Array<Bool>;
|
||||
}
|
||||
|
||||
@:enum abstract Ease(Int) from Int to Int {
|
||||
var Linear = 0;
|
||||
var SineIn = 1;
|
||||
var SineOut = 2;
|
||||
var SineInOut = 3;
|
||||
var QuadIn = 4;
|
||||
var QuadOut = 5;
|
||||
var QuadInOut = 6;
|
||||
var CubicIn = 7;
|
||||
var CubicOut = 8;
|
||||
var CubicInOut = 9;
|
||||
var QuartIn = 10;
|
||||
var QuartOut = 11;
|
||||
var QuartInOut = 12;
|
||||
var QuintIn = 13;
|
||||
var QuintOut = 14;
|
||||
var QuintInOut = 15;
|
||||
var ExpoIn = 16;
|
||||
var ExpoOut = 17;
|
||||
var ExpoInOut = 18;
|
||||
var CircIn = 19;
|
||||
var CircOut = 20;
|
||||
var CircInOut = 21;
|
||||
var BackIn = 22;
|
||||
var BackOut = 23;
|
||||
var BackInOut = 24;
|
||||
var BounceIn = 25;
|
||||
var BounceOut = 26;
|
||||
var BounceInOut = 27;
|
||||
var ElasticIn = 28;
|
||||
var ElasticOut = 29;
|
||||
var ElasticInOut = 30;
|
||||
}
|
Reference in New Issue
Block a user