Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View 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
}

View 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;
}
}

View 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
}

View 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
}
}

View 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;
}
}

View 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();
}
}

View 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;
}