forked from LeenkxTeam/LNXSDK
merge upstream
This commit is contained in:
@ -12,6 +12,7 @@ class App {
|
||||
static var traitInits: Array<Void->Void> = [];
|
||||
static var traitUpdates: Array<Void->Void> = [];
|
||||
static var traitLateUpdates: Array<Void->Void> = [];
|
||||
static var traitFixedUpdates: Array<Void->Void> = [];
|
||||
static var traitRenders: Array<kha.graphics4.Graphics->Void> = [];
|
||||
static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
|
||||
public static var framebuffer: kha.Framebuffer;
|
||||
@ -23,6 +24,8 @@ class App {
|
||||
public static var renderPathTime: Float;
|
||||
public static var endFrameCallbacks: Array<Void->Void> = [];
|
||||
#end
|
||||
static var last = 0.0;
|
||||
static var time = 0.0;
|
||||
static var lastw = -1;
|
||||
static var lasth = -1;
|
||||
public static var onResize: Void->Void = null;
|
||||
@ -34,13 +37,14 @@ class App {
|
||||
function new(done: Void->Void) {
|
||||
done();
|
||||
kha.System.notifyOnFrames(render);
|
||||
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta);
|
||||
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.step);
|
||||
}
|
||||
|
||||
public static function reset() {
|
||||
traitInits = [];
|
||||
traitUpdates = [];
|
||||
traitLateUpdates = [];
|
||||
traitFixedUpdates = [];
|
||||
traitRenders = [];
|
||||
traitRenders2D = [];
|
||||
if (onResets != null) for (f in onResets) f();
|
||||
@ -48,6 +52,8 @@ class App {
|
||||
|
||||
static function update() {
|
||||
if (Scene.active == null || !Scene.active.ready) return;
|
||||
|
||||
iron.system.Time.update();
|
||||
if (pauseUpdates) return;
|
||||
|
||||
#if lnx_debug
|
||||
@ -56,6 +62,14 @@ class App {
|
||||
|
||||
Scene.active.updateFrame();
|
||||
|
||||
|
||||
time += iron.system.Time.delta;
|
||||
|
||||
while (time >= iron.system.Time.fixedStep) {
|
||||
for (f in traitFixedUpdates) f();
|
||||
time -= iron.system.Time.fixedStep;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var l = traitUpdates.length;
|
||||
while (i < l) {
|
||||
@ -106,7 +120,7 @@ class App {
|
||||
var frame = frames[0];
|
||||
framebuffer = frame;
|
||||
|
||||
iron.system.Time.update();
|
||||
iron.system.Time.render();
|
||||
|
||||
if (Scene.active == null || !Scene.active.ready) {
|
||||
render2D(frame);
|
||||
@ -172,6 +186,14 @@ class App {
|
||||
traitLateUpdates.remove(f);
|
||||
}
|
||||
|
||||
public static function notifyOnFixedUpdate(f: Void->Void) {
|
||||
traitFixedUpdates.push(f);
|
||||
}
|
||||
|
||||
public static function removeFixedUpdate(f: Void->Void) {
|
||||
traitFixedUpdates.remove(f);
|
||||
}
|
||||
|
||||
public static function notifyOnRender(f: kha.graphics4.Graphics->Void) {
|
||||
traitRenders.push(f);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ class Trait {
|
||||
var _remove: Array<Void->Void> = null;
|
||||
var _update: Array<Void->Void> = null;
|
||||
var _lateUpdate: Array<Void->Void> = null;
|
||||
var _fixedUpdate: Array<Void->Void> = null;
|
||||
var _render: Array<kha.graphics4.Graphics->Void> = null;
|
||||
var _render2D: Array<kha.graphics2.Graphics->Void> = null;
|
||||
|
||||
@ -87,6 +88,23 @@ class Trait {
|
||||
App.removeLateUpdate(f);
|
||||
}
|
||||
|
||||
/**
|
||||
Add fixed game logic handler.
|
||||
**/
|
||||
public function notifyOnFixedUpdate(f: Void->Void) {
|
||||
if (_fixedUpdate == null) _fixedUpdate = [];
|
||||
_fixedUpdate.push(f);
|
||||
App.notifyOnFixedUpdate(f);
|
||||
}
|
||||
|
||||
/**
|
||||
Remove fixed game logic handler.
|
||||
**/
|
||||
public function removeFixedUpdate(f: Void->Void) {
|
||||
_fixedUpdate.remove(f);
|
||||
App.removeFixedUpdate(f);
|
||||
}
|
||||
|
||||
/**
|
||||
Add render handler.
|
||||
**/
|
||||
|
@ -392,6 +392,8 @@ typedef TParticleData = {
|
||||
#end
|
||||
public var name: String;
|
||||
public var type: Int; // 0 - Emitter, Hair
|
||||
public var auto_start: Bool;
|
||||
public var is_unique: Bool;
|
||||
public var loop: Bool;
|
||||
public var count: Int;
|
||||
public var frame_start: FastFloat;
|
||||
|
@ -159,9 +159,17 @@ class Animation {
|
||||
if(markerEvents.get(sampler) != null){
|
||||
for (i in 0...anim.marker_frames.length) {
|
||||
if (frameIndex == anim.marker_frames[i]) {
|
||||
var marketAct = markerEvents.get(sampler);
|
||||
var ar = marketAct.get(anim.marker_names[i]);
|
||||
var markerAct = markerEvents.get(sampler);
|
||||
var ar = markerAct.get(anim.marker_names[i]);
|
||||
if (ar != null) for (f in ar) f();
|
||||
} else {
|
||||
for (j in 0...(frameIndex - lastFrameIndex)) {
|
||||
if (lastFrameIndex + j + 1 == anim.marker_frames[i]) {
|
||||
var markerAct = markerEvents.get(sampler);
|
||||
var ar = markerAct.get(anim.marker_names[i]);
|
||||
if (ar != null) for (f in ar) f();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastFrameIndex = frameIndex;
|
||||
|
@ -172,6 +172,10 @@ class Object {
|
||||
for (f in t._init) App.removeInit(f);
|
||||
t._init = null;
|
||||
}
|
||||
if (t._fixedUpdate != null) {
|
||||
for (f in t._fixedUpdate) App.removeFixedUpdate(f);
|
||||
t._fixedUpdate = null;
|
||||
}
|
||||
if (t._update != null) {
|
||||
for (f in t._update) App.removeUpdate(f);
|
||||
t._update = null;
|
||||
|
@ -2,6 +2,7 @@ package iron.object;
|
||||
|
||||
#if lnx_particles
|
||||
|
||||
import kha.FastFloat;
|
||||
import kha.graphics4.Usage;
|
||||
import kha.arrays.Float32Array;
|
||||
import iron.data.Data;
|
||||
@ -16,39 +17,45 @@ import iron.math.Vec4;
|
||||
class ParticleSystem {
|
||||
public var data: ParticleData;
|
||||
public var speed = 1.0;
|
||||
var currentSpeed = 0.0;
|
||||
var particles: Array<Particle>;
|
||||
var ready: Bool;
|
||||
public var frameRate = 24;
|
||||
public var lifetime = 0.0;
|
||||
public var animtime = 0.0;
|
||||
public var time = 0.0;
|
||||
public var spawnRate = 0.0;
|
||||
var frameRate = 24;
|
||||
var lifetime = 0.0;
|
||||
var looptime = 0.0;
|
||||
var animtime = 0.0;
|
||||
var time = 0.0;
|
||||
var spawnRate = 0.0;
|
||||
var seed = 0;
|
||||
|
||||
public var r: TParticleData;
|
||||
public var gx: Float;
|
||||
public var gy: Float;
|
||||
public var gz: Float;
|
||||
public var alignx: Float;
|
||||
public var aligny: Float;
|
||||
public var alignz: Float;
|
||||
var r: TParticleData;
|
||||
var gx: Float;
|
||||
var gy: Float;
|
||||
var gz: Float;
|
||||
var alignx: Float;
|
||||
var aligny: Float;
|
||||
var alignz: Float;
|
||||
var dimx: Float;
|
||||
var dimy: Float;
|
||||
var tilesx: Int;
|
||||
var tilesy: Int;
|
||||
var tilesFramerate: Int;
|
||||
|
||||
public var count = 0;
|
||||
public var lap = 0;
|
||||
public var lapTime = 0.0;
|
||||
var count = 0;
|
||||
var lap = 0;
|
||||
var lapTime = 0.0;
|
||||
var m = Mat4.identity();
|
||||
|
||||
var ownerLoc = new Vec4();
|
||||
var ownerRot = new Quat();
|
||||
var ownerScl = new Vec4();
|
||||
|
||||
var random = 0.0;
|
||||
|
||||
public function new(sceneName: String, pref: TParticleReference) {
|
||||
seed = pref.seed;
|
||||
currentSpeed = speed;
|
||||
speed = 0;
|
||||
particles = [];
|
||||
ready = false;
|
||||
|
||||
@ -65,33 +72,61 @@ class ParticleSystem {
|
||||
gy = 0;
|
||||
gz = -9.81 * r.weight_gravity;
|
||||
}
|
||||
alignx = r.object_align_factor[0] / 2;
|
||||
aligny = r.object_align_factor[1] / 2;
|
||||
alignz = r.object_align_factor[2] / 2;
|
||||
alignx = r.object_align_factor[0];
|
||||
aligny = r.object_align_factor[1];
|
||||
alignz = r.object_align_factor[2];
|
||||
looptime = (r.frame_end - r.frame_start) / frameRate;
|
||||
lifetime = r.lifetime / frameRate;
|
||||
animtime = (r.frame_end - r.frame_start) / frameRate;
|
||||
animtime = r.loop ? looptime : looptime + lifetime;
|
||||
spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
|
||||
|
||||
for (i in 0...r.count) {
|
||||
var particle = new Particle(i);
|
||||
particle.sr = 1 - Math.random() * r.size_random;
|
||||
particles.push(particle);
|
||||
particles.push(new Particle(i));
|
||||
}
|
||||
|
||||
ready = true;
|
||||
if (r.auto_start){
|
||||
start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function start() {
|
||||
if (r.is_unique) random = Math.random();
|
||||
lifetime = r.lifetime / frameRate;
|
||||
time = 0;
|
||||
lap = 0;
|
||||
lapTime = 0;
|
||||
speed = currentSpeed;
|
||||
}
|
||||
|
||||
public function pause() {
|
||||
lifetime = 0;
|
||||
speed = 0;
|
||||
}
|
||||
|
||||
public function resume() {
|
||||
lifetime = r.lifetime / frameRate;
|
||||
speed = currentSpeed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: interrupt smoothly
|
||||
public function stop() {
|
||||
end();
|
||||
}
|
||||
|
||||
function end() {
|
||||
lifetime = 0;
|
||||
speed = 0;
|
||||
lap = 0;
|
||||
}
|
||||
|
||||
public function update(object: MeshObject, owner: MeshObject) {
|
||||
if (!ready || object == null || speed == 0.0) return;
|
||||
if (iron.App.pauseUpdates) return;
|
||||
|
||||
var prevLap = lap;
|
||||
|
||||
// Copy owner world transform but discard scale
|
||||
owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
|
||||
@ -115,17 +150,21 @@ class ParticleSystem {
|
||||
}
|
||||
|
||||
// Animate
|
||||
time += Time.delta * speed;
|
||||
time += Time.renderDelta * speed; // realDelta to renderDelta
|
||||
lap = Std.int(time / animtime);
|
||||
lapTime = time - lap * animtime;
|
||||
count = Std.int(lapTime / spawnRate);
|
||||
|
||||
if (lap > prevLap && !r.loop) {
|
||||
end();
|
||||
}
|
||||
|
||||
updateGpu(object, owner);
|
||||
}
|
||||
|
||||
public function getData(): Mat4 {
|
||||
var hair = r.type == 1;
|
||||
m._00 = r.loop ? animtime : -animtime;
|
||||
m._00 = animtime;
|
||||
m._01 = hair ? 1 / particles.length : spawnRate;
|
||||
m._02 = hair ? 1 : lifetime;
|
||||
m._03 = particles.length;
|
||||
@ -133,9 +172,9 @@ class ParticleSystem {
|
||||
m._11 = hair ? 0 : aligny;
|
||||
m._12 = hair ? 0 : alignz;
|
||||
m._13 = hair ? 0 : r.factor_random;
|
||||
m._20 = hair ? 0 : gx * r.mass;
|
||||
m._21 = hair ? 0 : gy * r.mass;
|
||||
m._22 = hair ? 0 : gz * r.mass;
|
||||
m._20 = hair ? 0 : gx;
|
||||
m._21 = hair ? 0 : gy;
|
||||
m._22 = hair ? 0 : gz;
|
||||
m._23 = hair ? 0 : r.lifetime_random;
|
||||
m._30 = tilesx;
|
||||
m._31 = tilesy;
|
||||
@ -144,13 +183,25 @@ class ParticleSystem {
|
||||
return m;
|
||||
}
|
||||
|
||||
public function getSizeRandom(): FastFloat {
|
||||
return r.size_random;
|
||||
}
|
||||
|
||||
public function getRandom(): FastFloat {
|
||||
return random;
|
||||
}
|
||||
|
||||
public function getSize(): FastFloat {
|
||||
return r.particle_size;
|
||||
}
|
||||
|
||||
function updateGpu(object: MeshObject, owner: MeshObject) {
|
||||
if (!object.data.geom.instanced) setupGeomGpu(object, owner);
|
||||
// GPU particles transform is attached to owner object
|
||||
}
|
||||
|
||||
public function setupGeomGpu(object: MeshObject, owner: MeshObject) {
|
||||
var instancedData = new Float32Array(particles.length * 6);
|
||||
function setupGeomGpu(object: MeshObject, owner: MeshObject) {
|
||||
var instancedData = new Float32Array(particles.length * 3);
|
||||
var i = 0;
|
||||
|
||||
var normFactor = 1 / 32767; // pa.values are not normalized
|
||||
@ -169,10 +220,6 @@ class ParticleSystem {
|
||||
instancedData.set(i, pa.values[j * pa.size ] * normFactor * scaleFactor.x); i++;
|
||||
instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
|
||||
instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
|
||||
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
}
|
||||
|
||||
case 1: // Face
|
||||
@ -196,10 +243,6 @@ class ParticleSystem {
|
||||
instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
|
||||
instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
|
||||
instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
|
||||
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
}
|
||||
|
||||
case 2: // Volume
|
||||
@ -210,13 +253,9 @@ class ParticleSystem {
|
||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
|
||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
|
||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
|
||||
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
}
|
||||
}
|
||||
object.data.geom.setupInstanced(instancedData, 3, Usage.StaticUsage);
|
||||
object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage);
|
||||
}
|
||||
|
||||
function fhash(n: Int): Float {
|
||||
@ -255,10 +294,11 @@ class ParticleSystem {
|
||||
|
||||
class Particle {
|
||||
public var i: Int;
|
||||
public var px = 0.0;
|
||||
public var py = 0.0;
|
||||
public var pz = 0.0;
|
||||
public var sr = 1.0; // Size random
|
||||
|
||||
public var x = 0.0;
|
||||
public var y = 0.0;
|
||||
public var z = 0.0;
|
||||
|
||||
public var cameraDistance: Float;
|
||||
|
||||
public function new(i: Int) {
|
||||
|
@ -80,7 +80,7 @@ class Tilesheet {
|
||||
function update() {
|
||||
if (!ready || paused || action.start >= action.end) return;
|
||||
|
||||
time += Time.realDelta;
|
||||
time += Time.renderDelta;
|
||||
|
||||
var frameTime = 1 / raw.framerate;
|
||||
var framesToAdvance = 0;
|
||||
|
@ -1113,6 +1113,26 @@ class Uniforms {
|
||||
case "_texUnpack": {
|
||||
f = texUnpack != null ? texUnpack : 1.0;
|
||||
}
|
||||
#if lnx_particles
|
||||
case "_particleSizeRandom": {
|
||||
var mo = cast(object, MeshObject);
|
||||
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
|
||||
f = mo.particleOwner.particleSystems[mo.particleIndex].getSizeRandom();
|
||||
}
|
||||
}
|
||||
case "_particleRandom": {
|
||||
var mo = cast(object, MeshObject);
|
||||
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
|
||||
f = mo.particleOwner.particleSystems[mo.particleIndex].getRandom();
|
||||
}
|
||||
}
|
||||
case "_particleSize": {
|
||||
var mo = cast(object, MeshObject);
|
||||
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
|
||||
f = mo.particleOwner.particleSystems[mo.particleIndex].getSize();
|
||||
}
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
if (f == null && externalFloatLinks != null) {
|
||||
|
@ -1,37 +1,58 @@
|
||||
package iron.system;
|
||||
|
||||
class Time {
|
||||
|
||||
public static var scale = 1.0;
|
||||
|
||||
static var frequency: Null<Int> = null;
|
||||
static function initFrequency() {
|
||||
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
|
||||
}
|
||||
|
||||
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 _fixedStep: Null<Float>;
|
||||
public static var fixedStep(get, never): Float;
|
||||
static function get_fixedStep(): Float {
|
||||
return _fixedStep;
|
||||
}
|
||||
|
||||
public static function initFixedStep(value: Float = 1 / 60) {
|
||||
_fixedStep = value;
|
||||
}
|
||||
|
||||
static var last = 0.0;
|
||||
public static var realDelta = 0.0;
|
||||
static var lastTime = 0.0;
|
||||
static var _delta = 0.0;
|
||||
public static var delta(get, never): Float;
|
||||
static function get_delta(): Float {
|
||||
return _delta;
|
||||
}
|
||||
|
||||
static var lastRenderTime = 0.0;
|
||||
static var _renderDelta = 0.0;
|
||||
public static var renderDelta(get, never): Float;
|
||||
static function get_renderDelta(): Float {
|
||||
return _renderDelta;
|
||||
}
|
||||
|
||||
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() {
|
||||
_delta = realTime() - lastTime;
|
||||
lastTime = realTime();
|
||||
}
|
||||
|
||||
public static function update() {
|
||||
realDelta = realTime() - last;
|
||||
last = realTime();
|
||||
public static function render() {
|
||||
_renderDelta = realTime() - lastRenderTime;
|
||||
lastRenderTime = realTime();
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class Config {
|
||||
var path = iron.data.Data.dataPath + "config.lnx";
|
||||
var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
|
||||
#if kha_krom
|
||||
if (iron.data.Data.dataPath == '') path = Krom.getFilesLocation() + "/config.lnx";
|
||||
Krom.fileSaveBytes(path, bytes.getData());
|
||||
#elseif kha_kore
|
||||
sys.io.File.saveBytes(path, bytes);
|
||||
@ -47,6 +48,7 @@ typedef TConfig = {
|
||||
@:optional var rp_ssr: Null<Bool>;
|
||||
@:optional var rp_ssrefr: Null<Bool>;
|
||||
@:optional var rp_bloom: Null<Bool>;
|
||||
@:optional var rp_chromatic_aberration: Null<Bool>;
|
||||
@:optional var rp_motionblur: Null<Bool>;
|
||||
@:optional var rp_gi: Null<Bool>; // voxelao
|
||||
@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling
|
||||
|
@ -1,99 +1,99 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.data.SceneFormat.TSceneFormat;
|
||||
import iron.data.Data;
|
||||
import iron.object.Object;
|
||||
|
||||
class AddParticleToObjectNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
|
||||
if (property0 == 'Scene Active'){
|
||||
var objFrom: Object = inputs[1].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
var objTo: Object = inputs[3].get();
|
||||
|
||||
if (objFrom == null || objTo == null) return;
|
||||
|
||||
var mobjFrom = cast(objFrom, iron.object.MeshObject);
|
||||
|
||||
var psys = mobjFrom.particleSystems != null ? mobjFrom.particleSystems[slot] :
|
||||
mobjFrom.particleOwner != null && mobjFrom.particleOwner.particleSystems != null ? mobjFrom.particleOwner.particleSystems[slot] : null;
|
||||
|
||||
if (psys == null) return;
|
||||
|
||||
var mobjTo = cast(objTo, iron.object.MeshObject);
|
||||
|
||||
mobjTo.setupParticleSystem(iron.Scene.active.raw.name, {name: 'LnxPS', seed: 0, particle: psys.r.name});
|
||||
|
||||
mobjTo.render_emitter = inputs[4].get();
|
||||
|
||||
iron.Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
|
||||
if (o != null) {
|
||||
var c: iron.object.MeshObject = cast o;
|
||||
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
|
||||
mobjTo.particleChildren.push(c);
|
||||
c.particleOwner = mobjTo;
|
||||
c.particleIndex = mobjTo.particleChildren.length - 1;
|
||||
}
|
||||
});
|
||||
|
||||
var oslot: Int = mobjTo.particleSystems.length-1;
|
||||
var opsys = mobjTo.particleSystems[oslot];
|
||||
opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
|
||||
|
||||
} else {
|
||||
var sceneName: String = inputs[1].get();
|
||||
var objectName: String = inputs[2].get();
|
||||
var slot: Int = inputs[3].get();
|
||||
|
||||
var mobjTo: Object = inputs[4].get();
|
||||
var mobjTo = cast(mobjTo, iron.object.MeshObject);
|
||||
|
||||
#if lnx_json
|
||||
sceneName += ".json";
|
||||
#elseif lnx_compress
|
||||
sceneName += ".lz4";
|
||||
#end
|
||||
|
||||
Data.getSceneRaw(sceneName, (rawScene: TSceneFormat) -> {
|
||||
|
||||
for (obj in rawScene.objects) {
|
||||
if (obj.name == objectName) {
|
||||
mobjTo.setupParticleSystem(sceneName, obj.particle_refs[slot]);
|
||||
mobjTo.render_emitter = inputs[5].get();
|
||||
|
||||
iron.Scene.active.spawnObject(rawScene.particle_datas[slot].instance_object, null, function(o: Object) {
|
||||
if (o != null) {
|
||||
var c: iron.object.MeshObject = cast o;
|
||||
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
|
||||
mobjTo.particleChildren.push(c);
|
||||
c.particleOwner = mobjTo;
|
||||
c.particleIndex = mobjTo.particleChildren.length - 1;
|
||||
}
|
||||
}, true, rawScene);
|
||||
|
||||
var oslot: Int = mobjTo.particleSystems.length-1;
|
||||
var opsys = mobjTo.particleSystems[oslot];
|
||||
opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.data.SceneFormat.TSceneFormat;
|
||||
import iron.data.Data;
|
||||
import iron.object.Object;
|
||||
|
||||
class AddParticleToObjectNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
|
||||
if (property0 == 'Scene Active'){
|
||||
var objFrom: Object = inputs[1].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
var objTo: Object = inputs[3].get();
|
||||
|
||||
if (objFrom == null || objTo == null) return;
|
||||
|
||||
var mobjFrom = cast(objFrom, iron.object.MeshObject);
|
||||
|
||||
var psys = mobjFrom.particleSystems != null ? mobjFrom.particleSystems[slot] :
|
||||
mobjFrom.particleOwner != null && mobjFrom.particleOwner.particleSystems != null ? mobjFrom.particleOwner.particleSystems[slot] : null;
|
||||
|
||||
if (psys == null) return;
|
||||
|
||||
var mobjTo = cast(objTo, iron.object.MeshObject);
|
||||
|
||||
mobjTo.setupParticleSystem(iron.Scene.active.raw.name, {name: 'LnxPS', seed: 0, particle: @:privateAccess psys.r.name});
|
||||
|
||||
mobjTo.render_emitter = inputs[4].get();
|
||||
|
||||
iron.Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
|
||||
if (o != null) {
|
||||
var c: iron.object.MeshObject = cast o;
|
||||
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
|
||||
mobjTo.particleChildren.push(c);
|
||||
c.particleOwner = mobjTo;
|
||||
c.particleIndex = mobjTo.particleChildren.length - 1;
|
||||
}
|
||||
});
|
||||
|
||||
var oslot: Int = mobjTo.particleSystems.length-1;
|
||||
var opsys = mobjTo.particleSystems[oslot];
|
||||
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
|
||||
|
||||
} else {
|
||||
var sceneName: String = inputs[1].get();
|
||||
var objectName: String = inputs[2].get();
|
||||
var slot: Int = inputs[3].get();
|
||||
|
||||
var mobjTo: Object = inputs[4].get();
|
||||
var mobjTo = cast(mobjTo, iron.object.MeshObject);
|
||||
|
||||
#if lnx_json
|
||||
sceneName += ".json";
|
||||
#elseif lnx_compress
|
||||
sceneName += ".lz4";
|
||||
#end
|
||||
|
||||
Data.getSceneRaw(sceneName, (rawScene: TSceneFormat) -> {
|
||||
|
||||
for (obj in rawScene.objects) {
|
||||
if (obj.name == objectName) {
|
||||
mobjTo.setupParticleSystem(sceneName, obj.particle_refs[slot]);
|
||||
mobjTo.render_emitter = inputs[5].get();
|
||||
|
||||
iron.Scene.active.spawnObject(rawScene.particle_datas[slot].instance_object, null, function(o: Object) {
|
||||
if (o != null) {
|
||||
var c: iron.object.MeshObject = cast o;
|
||||
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
|
||||
mobjTo.particleChildren.push(c);
|
||||
c.particleOwner = mobjTo;
|
||||
c.particleIndex = mobjTo.particleChildren.length - 1;
|
||||
}
|
||||
}, true, rawScene);
|
||||
|
||||
var oslot: Int = mobjTo.particleSystems.length-1;
|
||||
var opsys = mobjTo.particleSystems[oslot];
|
||||
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
16
leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx
Normal file
16
leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx
Normal file
@ -0,0 +1,16 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class AutoExposureGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.auto_exposure_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.auto_exposure_uniforms[1];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
}
|
15
leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx
Normal file
15
leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx
Normal file
@ -0,0 +1,15 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class AutoExposureSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.auto_exposure_uniforms[0] = inputs[1].get();
|
||||
leenkx.renderpath.Postprocess.auto_exposure_uniforms[1] = inputs[2].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
@ -1,26 +1,49 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class CameraSetNode extends LogicNode {
|
||||
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();//Camera: Shutter time
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();//Camera: ISO
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();//Camera: Exposure Compensation
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();//Fisheye Distortion
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();//DoF Distance
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();//DoF Focal Length mm
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();//DoF F-Stop
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();//Tonemapping Method
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();//Distort
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[12].get();//Film Grain
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[13].get();//Sharpen
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[14].get();//Vignette
|
||||
|
||||
switch (property0) {
|
||||
case 'F-stop':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
|
||||
case 'Shutter Time':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[1].get();//Camera: Shutter time
|
||||
case 'ISO':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[1].get();//Camera: ISO
|
||||
case 'Exposure Compensation':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[1].get();//Camera: Exposure Compensation
|
||||
case 'Fisheye Distortion':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[1].get();//Fisheye Distortion
|
||||
case 'Auto Focus':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[1].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
||||
case 'DoF Distance':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[1].get();//DoF Distance
|
||||
case 'DoF Length':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[1].get();//DoF Focal Length mm
|
||||
case 'DoF F-Stop':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[1].get();//DoF F-Stop
|
||||
case 'Tonemapping':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[1].get();//Tonemapping Method
|
||||
case 'Distort':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[1].get();//Distort
|
||||
case 'Film Grain':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[1].get();//Film Grain
|
||||
case 'Sharpen':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[1].get();//Sharpen
|
||||
case 'Vignette':
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[1].get();//Vignette
|
||||
case 'Exposure':
|
||||
leenkx.renderpath.Postprocess.exposure_uniforms[0] = inputs[1].get();//Exposure
|
||||
default:
|
||||
null;
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ class ChromaticAberrationGetNode extends LogicNode {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
|
||||
case 2: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ class ChromaticAberrationSetNode extends LogicNode {
|
||||
|
||||
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get();
|
||||
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ class GetFPSNode extends LogicNode {
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (from == 0) {
|
||||
var fps = Math.round(1 / iron.system.Time.realDelta);
|
||||
var fps = Math.round(1 / iron.system.Time.renderDelta);
|
||||
if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,66 +1,72 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetParticleDataNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
var slot: Int = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
#if lnx_particles
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
|
||||
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
|
||||
|
||||
if (psys == null) return null;
|
||||
|
||||
return switch (from) {
|
||||
case 0:
|
||||
psys.r.name;
|
||||
case 1:
|
||||
psys.r.particle_size;
|
||||
case 2:
|
||||
psys.r.frame_start;
|
||||
case 3:
|
||||
psys.r.frame_end;
|
||||
case 4:
|
||||
psys.lifetime;
|
||||
case 5:
|
||||
psys.r.lifetime;
|
||||
case 6:
|
||||
psys.r.emit_from;
|
||||
case 7:
|
||||
new iron.math.Vec3(psys.alignx*2, psys.aligny*2, psys.alignz*2);
|
||||
case 8:
|
||||
psys.r.factor_random;
|
||||
case 9:
|
||||
new iron.math.Vec3(psys.gx, psys.gy, psys.gz);
|
||||
case 10:
|
||||
psys.r.weight_gravity;
|
||||
case 11:
|
||||
psys.speed;
|
||||
case 12:
|
||||
psys.time;
|
||||
case 13:
|
||||
psys.lap;
|
||||
case 14:
|
||||
psys.lapTime;
|
||||
case 15:
|
||||
psys.count;
|
||||
default:
|
||||
null;
|
||||
}
|
||||
#end
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetParticleDataNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
var slot: Int = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
#if lnx_particles
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
|
||||
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
|
||||
|
||||
if (psys == null) return null;
|
||||
|
||||
return switch (from) {
|
||||
case 0:
|
||||
@:privateAccess psys.r.name;
|
||||
case 1:
|
||||
@:privateAccess psys.r.particle_size;
|
||||
case 2:
|
||||
@:privateAccess psys.r.frame_start;
|
||||
case 3:
|
||||
@:privateAccess psys.r.frame_end;
|
||||
case 4:
|
||||
@:privateAccess psys.lifetime;
|
||||
case 5:
|
||||
@:privateAccess psys.r.lifetime;
|
||||
case 6:
|
||||
@:privateAccess psys.r.emit_from;
|
||||
case 7:
|
||||
@:privateAccess psys.r.auto_start;
|
||||
case 8:
|
||||
@:privateAccess psys.r.is_unique;
|
||||
case 9:
|
||||
@:privateAccess psys.r.loop;
|
||||
case 10:
|
||||
new iron.math.Vec3(@:privateAccess psys.alignx, @:privateAccess psys.aligny, @:privateAccess psys.alignz);
|
||||
case 11:
|
||||
@:privateAccess psys.r.factor_random;
|
||||
case 12:
|
||||
new iron.math.Vec3(@:privateAccess psys.gx, @:privateAccess psys.gy, @:privateAccess psys.gz);
|
||||
case 13:
|
||||
@:privateAccess psys.r.weight_gravity;
|
||||
case 14:
|
||||
psys.speed;
|
||||
case 15:
|
||||
@:privateAccess psys.time;
|
||||
case 16:
|
||||
@:privateAccess psys.lap;
|
||||
case 17:
|
||||
@:privateAccess psys.lapTime;
|
||||
case 18:
|
||||
@:privateAccess psys.count;
|
||||
default:
|
||||
null;
|
||||
}
|
||||
#end
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +1,38 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetParticleNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
#if lnx_particles
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
switch (from) {
|
||||
case 0:
|
||||
var names: Array<String> = [];
|
||||
if (mo.particleSystems != null)
|
||||
for (psys in mo.particleSystems)
|
||||
names.push(psys.r.name);
|
||||
return names;
|
||||
case 1:
|
||||
return mo.particleSystems != null ? mo.particleSystems.length : 0;
|
||||
case 2:
|
||||
return mo.render_emitter;
|
||||
default:
|
||||
null;
|
||||
}
|
||||
#end
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetParticleNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
#if lnx_particles
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
switch (from) {
|
||||
case 0:
|
||||
var names: Array<String> = [];
|
||||
if (mo.particleSystems != null)
|
||||
for (psys in mo.particleSystems)
|
||||
names.push(@:privateAccess psys.r.name);
|
||||
return names;
|
||||
case 1:
|
||||
return mo.particleSystems != null ? mo.particleSystems.length : 0;
|
||||
case 2:
|
||||
return mo.render_emitter;
|
||||
default:
|
||||
null;
|
||||
}
|
||||
#end
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +1,64 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class RemoveParticleFromObjectNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
var object: Object = inputs[1].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
if (mo.particleSystems == null) return;
|
||||
|
||||
if (property0 == 'All'){
|
||||
mo.particleSystems = null;
|
||||
for (c in mo.particleChildren) c.remove();
|
||||
mo.particleChildren = null;
|
||||
mo.particleOwner = null;
|
||||
mo.render_emitter = true;
|
||||
}
|
||||
else {
|
||||
|
||||
var slot: Int = -1;
|
||||
if (property0 == 'Name'){
|
||||
var name: String = inputs[2].get();
|
||||
for (i => psys in mo.particleSystems){
|
||||
if (psys.r.name == name){ slot = i; break; }
|
||||
}
|
||||
}
|
||||
else slot = inputs[2].get();
|
||||
|
||||
if (mo.particleSystems.length > slot){
|
||||
for (i in slot+1...mo.particleSystems.length){
|
||||
var mi = cast(mo.particleChildren[i], iron.object.MeshObject);
|
||||
mi.particleIndex = mi.particleIndex - 1;
|
||||
}
|
||||
mo.particleSystems.splice(slot, 1);
|
||||
mo.particleChildren[slot].remove();
|
||||
mo.particleChildren.splice(slot, 1);
|
||||
}
|
||||
|
||||
if (slot == 0){
|
||||
mo.particleSystems = null;
|
||||
mo.particleChildren = null;
|
||||
mo.particleOwner = null;
|
||||
mo.render_emitter = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class RemoveParticleFromObjectNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
var object: Object = inputs[1].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
if (mo.particleSystems == null) return;
|
||||
|
||||
if (property0 == 'All'){
|
||||
mo.particleSystems = null;
|
||||
for (c in mo.particleChildren) c.remove();
|
||||
mo.particleChildren = null;
|
||||
mo.particleOwner = null;
|
||||
mo.render_emitter = true;
|
||||
}
|
||||
else {
|
||||
|
||||
var slot: Int = -1;
|
||||
if (property0 == 'Name'){
|
||||
var name: String = inputs[2].get();
|
||||
for (i => psys in mo.particleSystems){
|
||||
if (@:privateAccess psys.r.name == name){ slot = i; break; }
|
||||
}
|
||||
}
|
||||
else slot = inputs[2].get();
|
||||
|
||||
if (mo.particleSystems.length > slot){
|
||||
for (i in slot+1...mo.particleSystems.length){
|
||||
var mi = cast(mo.particleChildren[i], iron.object.MeshObject);
|
||||
mi.particleIndex = mi.particleIndex - 1;
|
||||
}
|
||||
mo.particleSystems.splice(slot, 1);
|
||||
mo.particleChildren[slot].remove();
|
||||
mo.particleChildren.splice(slot, 1);
|
||||
}
|
||||
|
||||
if (slot == 0){
|
||||
mo.particleSystems = null;
|
||||
mo.particleChildren = null;
|
||||
mo.particleOwner = null;
|
||||
mo.render_emitter = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ class RpConfigNode extends LogicNode {
|
||||
on ? leenkx.data.Config.raw.rp_ssrefr = true : leenkx.data.Config.raw.rp_ssrefr = false;
|
||||
case "Bloom":
|
||||
on ? leenkx.data.Config.raw.rp_bloom = true : leenkx.data.Config.raw.rp_bloom = false;
|
||||
case "CA":
|
||||
on ? leenkx.data.Config.raw.rp_chromatic_aberration = true : leenkx.data.Config.raw.rp_chromatic_aberration = false;
|
||||
case "GI":
|
||||
on ? leenkx.data.Config.raw.rp_gi = true : leenkx.data.Config.raw.rp_gi = false;
|
||||
case "Motion Blur":
|
||||
|
@ -1,75 +1,81 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class SetParticleDataNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
var object: Object = inputs[1].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
|
||||
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null; if (psys == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case 'Particle Size':
|
||||
psys.r.particle_size = inputs[3].get();
|
||||
case 'Frame Start':
|
||||
psys.r.frame_start = inputs[3].get();
|
||||
psys.animtime = (psys.r.frame_end - psys.r.frame_start) / psys.frameRate;
|
||||
psys.spawnRate = ((psys.r.frame_end - psys.r.frame_start) / psys.count) / psys.frameRate;
|
||||
case 'Frame End':
|
||||
psys.r.frame_end = inputs[3].get();
|
||||
psys.animtime = (psys.r.frame_end - psys.r.frame_start) / psys.frameRate;
|
||||
psys.spawnRate = ((psys.r.frame_end - psys.r.frame_start) / psys.count) / psys.frameRate;
|
||||
case 'Lifetime':
|
||||
psys.lifetime = inputs[3].get() / psys.frameRate;
|
||||
case 'Lifetime Random':
|
||||
psys.r.lifetime_random = inputs[3].get();
|
||||
case 'Emit From':
|
||||
var emit_from: Int = inputs[3].get();
|
||||
if (emit_from == 0 || emit_from == 1 || emit_from == 2) {
|
||||
psys.r.emit_from = emit_from;
|
||||
psys.setupGeomGpu(mo.particleChildren != null ? mo.particleChildren[slot] : cast(iron.Scene.active.getChild(psys.data.raw.instance_object), iron.object.MeshObject), mo);
|
||||
}
|
||||
case 'Velocity':
|
||||
var vel: iron.math.Vec3 = inputs[3].get();
|
||||
psys.alignx = vel.x / 2;
|
||||
psys.aligny = vel.y / 2;
|
||||
psys.alignz = vel.z / 2;
|
||||
case 'Velocity Random':
|
||||
psys.r.factor_random = inputs[3].get();
|
||||
case 'Weight Gravity':
|
||||
psys.r.weight_gravity = inputs[3].get();
|
||||
if (iron.Scene.active.raw.gravity != null) {
|
||||
psys.gx = iron.Scene.active.raw.gravity[0] * psys.r.weight_gravity;
|
||||
psys.gy = iron.Scene.active.raw.gravity[1] * psys.r.weight_gravity;
|
||||
psys.gz = iron.Scene.active.raw.gravity[2] * psys.r.weight_gravity;
|
||||
}
|
||||
else {
|
||||
psys.gx = 0;
|
||||
psys.gy = 0;
|
||||
psys.gz = -9.81 * psys.r.weight_gravity;
|
||||
}
|
||||
case 'Speed':
|
||||
psys.speed = inputs[3].get();
|
||||
default:
|
||||
null;
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class SetParticleDataNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
var object: Object = inputs[1].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
|
||||
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null; if (psys == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case 'Particle Size':
|
||||
@:privateAccess psys.r.particle_size = inputs[3].get();
|
||||
case 'Frame Start':
|
||||
@:privateAccess psys.r.frame_start = inputs[3].get();
|
||||
@:privateAccess psys.animtime = (@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.frameRate;
|
||||
@:privateAccess psys.spawnRate = ((@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.count) / @:privateAccess psys.frameRate;
|
||||
case 'Frame End':
|
||||
@:privateAccess psys.r.frame_end = inputs[3].get();
|
||||
@:privateAccess psys.animtime = (@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.frameRate;
|
||||
@:privateAccess psys.spawnRate = ((@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.count) / @:privateAccess psys.frameRate;
|
||||
case 'Lifetime':
|
||||
@:privateAccess psys.lifetime = inputs[3].get() / @:privateAccess psys.frameRate;
|
||||
case 'Lifetime Random':
|
||||
@:privateAccess psys.r.lifetime_random = inputs[3].get();
|
||||
case 'Emit From':
|
||||
var emit_from: Int = inputs[3].get();
|
||||
if (emit_from == 0 || emit_from == 1 || emit_from == 2) {
|
||||
@:privateAccess psys.r.emit_from = emit_from;
|
||||
@:privateAccess psys.setupGeomGpu(mo.particleChildren != null ? mo.particleChildren[slot] : cast(iron.Scene.active.getChild(@:privateAccess psys.data.raw.instance_object), iron.object.MeshObject), mo);
|
||||
}
|
||||
case 'Auto Start':
|
||||
@:privateAccess psys.r.auto_start = inputs[3].get();
|
||||
case 'Is Unique':
|
||||
@:privateAccess psys.r.is_unique = inputs[3].get();
|
||||
case 'Loop':
|
||||
@:privateAccess psys.r.loop = inputs[3].get();
|
||||
case 'Velocity':
|
||||
var vel: iron.math.Vec3 = inputs[3].get();
|
||||
@:privateAccess psys.alignx = vel.x;
|
||||
@:privateAccess psys.aligny = vel.y;
|
||||
@:privateAccess psys.alignz = vel.z;
|
||||
case 'Velocity Random':
|
||||
psys.r.factor_random = inputs[3].get();
|
||||
case 'Weight Gravity':
|
||||
psys.r.weight_gravity = inputs[3].get();
|
||||
if (iron.Scene.active.raw.gravity != null) {
|
||||
@:privateAccess psys.gx = iron.Scene.active.raw.gravity[0] * @:privateAccess psys.r.weight_gravity;
|
||||
@:privateAccess psys.gy = iron.Scene.active.raw.gravity[1] * @:privateAccess psys.r.weight_gravity;
|
||||
@:privateAccess psys.gz = iron.Scene.active.raw.gravity[2] * @:privateAccess psys.r.weight_gravity;
|
||||
}
|
||||
else {
|
||||
@:privateAccess psys.gx = 0;
|
||||
@:privateAccess psys.gy = 0;
|
||||
@:privateAccess psys.gz = -9.81 * @:privateAccess psys.r.weight_gravity;
|
||||
}
|
||||
case 'Speed':
|
||||
psys.speed = inputs[3].get();
|
||||
default:
|
||||
null;
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
17
leenkx/Sources/leenkx/logicnode/SharpenGetNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/SharpenGetNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class SharpenGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.sharpen_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.sharpen_uniforms[1][0];
|
||||
case 2: leenkx.renderpath.Postprocess.camera_uniforms[12];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
}
|
18
leenkx/Sources/leenkx/logicnode/SharpenSetNode.hx
Normal file
18
leenkx/Sources/leenkx/logicnode/SharpenSetNode.hx
Normal file
@ -0,0 +1,18 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class SharpenSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[0][0] = inputs[1].get().x;
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[0][1] = inputs[1].get().y;
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[0][2] = inputs[1].get().z;
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[1][0] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
17
leenkx/Sources/leenkx/logicnode/VolumetricFogGetNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/VolumetricFogGetNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricFogGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.volumetric_fog_uniforms[1][0];
|
||||
case 2: leenkx.renderpath.Postprocess.volumetric_fog_uniforms[2][0];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
}
|
18
leenkx/Sources/leenkx/logicnode/VolumetricFogSetNode.hx
Normal file
18
leenkx/Sources/leenkx/logicnode/VolumetricFogSetNode.hx
Normal file
@ -0,0 +1,18 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricFogSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0][0] = inputs[1].get().x;
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0][1] = inputs[1].get().y;
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0][2] = inputs[1].get().z;
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[1][0] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[2][0] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
17
leenkx/Sources/leenkx/logicnode/VolumetricLightGetNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/VolumetricLightGetNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricLightGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.volumetric_light_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.volumetric_light_uniforms[1][0];
|
||||
case 2: leenkx.renderpath.Postprocess.volumetric_light_uniforms[2][0];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
}
|
18
leenkx/Sources/leenkx/logicnode/VolumetricLightSetNode.hx
Normal file
18
leenkx/Sources/leenkx/logicnode/VolumetricLightSetNode.hx
Normal file
@ -0,0 +1,18 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricLightSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[0][0] = inputs[1].get().x;
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[0][1] = inputs[1].get().y;
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[0][2] = inputs[1].get().z;
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[1][0] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[2][0] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
@ -527,22 +527,29 @@ class Inc {
|
||||
public static function applyConfig() {
|
||||
#if lnx_config
|
||||
var config = leenkx.data.Config.raw;
|
||||
|
||||
#if rp_chromatic_aberration
|
||||
Postprocess.chromatic_aberration_uniforms[3] = config.rp_chromatic_aberration == true ? 1 : 0;
|
||||
#end
|
||||
|
||||
// Resize shadow map
|
||||
var l = path.light;
|
||||
if (l.data.raw.type == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cascade;
|
||||
var rt = path.renderTargets.get("shadowMap");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMap");
|
||||
if (l != null){
|
||||
if (l.data.raw.type == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cascade;
|
||||
var rt = path.renderTargets.get("shadowMap");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMap");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (l.data.raw.shadowmap_size != config.rp_shadowmap_cube) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cube;
|
||||
var rt = path.renderTargets.get("shadowMapCube");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMapCube");
|
||||
else if (l.data.raw.shadowmap_size != config.rp_shadowmap_cube) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cube;
|
||||
var rt = path.renderTargets.get("shadowMapCube");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMapCube");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (superSample != config.rp_supersample) {
|
||||
|
@ -54,10 +54,15 @@ class Postprocess {
|
||||
0, //9: Tonemapping Method
|
||||
2.0, //10: Distort
|
||||
2.0, //11: Film Grain
|
||||
0.25, //12: Sharpen
|
||||
0.25, //12: Sharpen Strength
|
||||
0.7 //13: Vignette
|
||||
];
|
||||
|
||||
public static var sharpen_uniforms = [
|
||||
[0.0, 0.0, 0.0], //0: Sharpen Color
|
||||
[2.5] //1: Sharpen Size
|
||||
];
|
||||
|
||||
public static var tonemapper_uniforms = [
|
||||
1.0, //0: Slope
|
||||
1.0, //1: Toe
|
||||
@ -102,7 +107,30 @@ class Postprocess {
|
||||
|
||||
public static var chromatic_aberration_uniforms = [
|
||||
2.0, //0: Strength
|
||||
32 //1: Samples
|
||||
32, //1: Samples
|
||||
0, //2: Type
|
||||
1 //3: On/Off
|
||||
];
|
||||
|
||||
public static var exposure_uniforms = [
|
||||
1 //0: Exposure
|
||||
];
|
||||
|
||||
public static var auto_exposure_uniforms = [
|
||||
1, //0: Auto Exposure Strength
|
||||
1 //1: Auto Exposure Speed
|
||||
];
|
||||
|
||||
public static var volumetric_light_uniforms = [
|
||||
[1.0, 1.0, 1.0], //0: Volumetric Light Air Color
|
||||
[1.0], //1: Volumetric Light Air Turbidity
|
||||
[20.0] //2: Volumetric Light Steps
|
||||
];
|
||||
|
||||
public static var volumetric_fog_uniforms = [
|
||||
[0.5, 0.6, 0.7], //0: Volumetric Fog Color
|
||||
[0.25], //1: Volumetric Fog Amount A
|
||||
[50.0] //2: Volumetric Fog Amount B
|
||||
];
|
||||
|
||||
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
@ -284,6 +312,11 @@ class Postprocess {
|
||||
v.x = lenstexture_uniforms[2]; //Lum min
|
||||
v.y = lenstexture_uniforms[3]; //Lum max
|
||||
v.z = lenstexture_uniforms[4]; //Expo
|
||||
case "_PPComp8":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = exposure_uniforms[0]; //Exposure
|
||||
v.y = auto_exposure_uniforms[0]; //Auto Exposure Strength
|
||||
v.z = auto_exposure_uniforms[1]; //Auto Exposure Speed
|
||||
case "_PPComp9":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssr_uniforms[0]; //Step
|
||||
@ -297,8 +330,8 @@ class Postprocess {
|
||||
case "_PPComp11":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = bloom_uniforms[2]; // Bloom Strength
|
||||
v.y = 0; // Unused
|
||||
v.z = 0; // Unused
|
||||
v.y = volumetric_light_uniforms[2][0]; //Volumetric Light Steps
|
||||
v.z = volumetric_fog_uniforms[2][0]; //Volumetric Fog Amount B
|
||||
case "_PPComp12":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssao_uniforms[0]; //SSAO Strength
|
||||
@ -308,7 +341,8 @@ class Postprocess {
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
||||
v.y = chromatic_aberration_uniforms[1]; //CA Samples
|
||||
v.z = 0;
|
||||
v.z = chromatic_aberration_uniforms[2]; //CA Type
|
||||
v.w = chromatic_aberration_uniforms[3]; //On/Off
|
||||
case "_PPComp14":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = camera_uniforms[10]; //Distort
|
||||
@ -338,6 +372,24 @@ class Postprocess {
|
||||
v.y = letterbox_uniforms[0][1];
|
||||
v.z = letterbox_uniforms[0][2];
|
||||
v.w = letterbox_uniforms[1][0]; //Size
|
||||
case "_PPComp16":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = sharpen_uniforms[0][0]; //Color
|
||||
v.y = sharpen_uniforms[0][1];
|
||||
v.z = sharpen_uniforms[0][2];
|
||||
v.w = sharpen_uniforms[1][0]; //Size
|
||||
case "_PPComp17":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = volumetric_light_uniforms[0][0]; //Air Color
|
||||
v.y = volumetric_light_uniforms[0][1];
|
||||
v.z = volumetric_light_uniforms[0][2];
|
||||
v.w = volumetric_light_uniforms[1][0]; //Air Turbidity
|
||||
case "_PPComp18":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = volumetric_fog_uniforms[0][0]; //Color
|
||||
v.y = volumetric_fog_uniforms[0][1];
|
||||
v.z = volumetric_fog_uniforms[0][2];
|
||||
v.w = volumetric_fog_uniforms[1][0]; //Amount A
|
||||
}
|
||||
|
||||
return v;
|
||||
|
@ -101,7 +101,7 @@ class PhysicsWorld extends Trait {
|
||||
|
||||
|
||||
|
||||
public function new(timeScale = 1.0, maxSteps = 10, solverIterations = 10, debugDrawMode: DebugDrawMode = NoDebug) {
|
||||
public function new(timeScale = 1.0, maxSteps = 10, solverIterations = 10, fixedStep = 1 / 60, debugDrawMode: DebugDrawMode = NoDebug) {
|
||||
super();
|
||||
|
||||
if (nullvec) {
|
||||
@ -120,6 +120,7 @@ class PhysicsWorld extends Trait {
|
||||
this.timeScale = timeScale;
|
||||
this.maxSteps = maxSteps;
|
||||
this.solverIterations = solverIterations;
|
||||
Time.initFixedStep(fixedStep);
|
||||
|
||||
// First scene
|
||||
if (active == null) {
|
||||
@ -136,10 +137,10 @@ class PhysicsWorld extends Trait {
|
||||
conMap = new Map();
|
||||
active = this;
|
||||
|
||||
// Ensure physics are updated first in the lateUpdate list
|
||||
_lateUpdate = [lateUpdate];
|
||||
@:privateAccess iron.App.traitLateUpdates.insert(0, lateUpdate);
|
||||
|
||||
// Ensure physics are updated first in the fixedUpdate list
|
||||
_fixedUpdate = [fixedUpdate];
|
||||
@:privateAccess iron.App.traitFixedUpdates.insert(0, fixedUpdate);
|
||||
|
||||
setDebugDrawMode(debugDrawMode);
|
||||
|
||||
iron.Scene.active.notifyOnRemove(function() {
|
||||
@ -298,8 +299,8 @@ class PhysicsWorld extends Trait {
|
||||
return rb;
|
||||
}
|
||||
|
||||
function lateUpdate() {
|
||||
var t = Time.delta * timeScale;
|
||||
function fixedUpdate() {
|
||||
var t = Time.fixedStep * timeScale * Time.scale;
|
||||
if (t == 0.0) return; // Simulation paused
|
||||
|
||||
#if lnx_debug
|
||||
@ -308,13 +309,10 @@ class PhysicsWorld extends Trait {
|
||||
|
||||
if (preUpdates != null) for (f in preUpdates) f();
|
||||
|
||||
//Bullet physics fixed timescale
|
||||
var fixedTime = 1.0 / 60;
|
||||
|
||||
//This condition must be satisfied to not loose time
|
||||
var currMaxSteps = t < (fixedTime * maxSteps) ? maxSteps : 1;
|
||||
var currMaxSteps = t < (Time.fixedStep * maxSteps) ? maxSteps : 1;
|
||||
|
||||
world.stepSimulation(t, currMaxSteps, fixedTime);
|
||||
world.stepSimulation(t, currMaxSteps, Time.fixedStep);
|
||||
updateContacts();
|
||||
|
||||
for (rb in rbMap) @:privateAccess rb.physicsUpdate();
|
||||
|
@ -2,11 +2,13 @@ package leenkx.trait.physics.bullet;
|
||||
|
||||
#if lnx_bullet
|
||||
|
||||
import leenkx.math.Helper;
|
||||
import iron.data.MeshData;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.object.Transform;
|
||||
import iron.object.MeshObject;
|
||||
import iron.data.MeshData;
|
||||
import iron.system.Time;
|
||||
|
||||
/**
|
||||
RigidBody is used to allow objects to interact with Physics in your game including collisions and gravity.
|
||||
@ -76,6 +78,14 @@ class RigidBody extends iron.Trait {
|
||||
static var triangleMeshCache = new Map<MeshData, bullet.Bt.TriangleMesh>();
|
||||
static var usersCache = new Map<MeshData, Int>();
|
||||
|
||||
// Interpolation
|
||||
var interpolate: Bool = false;
|
||||
var time: Float = 0.0;
|
||||
var currentPos: bullet.Bt.Vector3 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
var prevPos: bullet.Bt.Vector3 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
var currentRot: bullet.Bt.Quaternion = new bullet.Bt.Quaternion(0, 0, 0, 1);
|
||||
var prevRot: bullet.Bt.Quaternion = new bullet.Bt.Quaternion(0, 0, 0, 1);
|
||||
|
||||
public function new(shape = Shape.Box, mass = 1.0, friction = 0.5, restitution = 0.0, group = 1, mask = 1,
|
||||
params: RigidBodyParams = null, flags: RigidBodyFlags = null) {
|
||||
super();
|
||||
@ -85,7 +95,7 @@ class RigidBody extends iron.Trait {
|
||||
vec1 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
vec2 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
vec3 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
quat1 = new bullet.Bt.Quaternion(0, 0, 0, 0);
|
||||
quat1 = new bullet.Bt.Quaternion(0, 0, 0, 1);
|
||||
trans1 = new bullet.Bt.Transform();
|
||||
trans2 = new bullet.Bt.Transform();
|
||||
}
|
||||
@ -117,6 +127,7 @@ class RigidBody extends iron.Trait {
|
||||
animated: false,
|
||||
trigger: false,
|
||||
ccd: false,
|
||||
interpolate: false,
|
||||
staticObj: false,
|
||||
useDeactivation: true
|
||||
};
|
||||
@ -131,6 +142,7 @@ class RigidBody extends iron.Trait {
|
||||
this.animated = flags.animated;
|
||||
this.trigger = flags.trigger;
|
||||
this.ccd = flags.ccd;
|
||||
this.interpolate = flags.interpolate;
|
||||
this.staticObj = flags.staticObj;
|
||||
this.useDeactivation = flags.useDeactivation;
|
||||
|
||||
@ -153,6 +165,7 @@ class RigidBody extends iron.Trait {
|
||||
if (!Std.isOfType(object, MeshObject)) return; // No mesh data
|
||||
|
||||
transform = object.transform;
|
||||
transform.buildMatrix();
|
||||
physics = leenkx.trait.physics.PhysicsWorld.active;
|
||||
|
||||
if (shape == Shape.Box) {
|
||||
@ -244,6 +257,9 @@ class RigidBody extends iron.Trait {
|
||||
quat1.setValue(quat.x, quat.y, quat.z, quat.w);
|
||||
trans1.setRotation(quat1);
|
||||
|
||||
currentPos.setValue(vec1.x(), vec1.y(), vec1.z());
|
||||
currentRot.setValue(quat.x, quat.y, quat.z, quat.w);
|
||||
|
||||
var centerOfMassOffset = trans2;
|
||||
centerOfMassOffset.setIdentity();
|
||||
motionState = new bullet.Bt.DefaultMotionState(trans1, centerOfMassOffset);
|
||||
@ -307,7 +323,8 @@ class RigidBody extends iron.Trait {
|
||||
|
||||
physics.addRigidBody(this);
|
||||
notifyOnRemove(removeFromWorld);
|
||||
|
||||
if (!animated) notifyOnUpdate(update);
|
||||
|
||||
if (onReady != null) onReady();
|
||||
|
||||
#if js
|
||||
@ -317,26 +334,71 @@ class RigidBody extends iron.Trait {
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
function update() {
|
||||
if (interpolate) {
|
||||
time += Time.delta;
|
||||
|
||||
while (time >= Time.fixedStep) {
|
||||
time -= Time.fixedStep;
|
||||
}
|
||||
|
||||
var t: Float = time / Time.fixedStep;
|
||||
t = Helper.clamp(t, 0, 1);
|
||||
|
||||
var tx: Float = prevPos.x() * (1.0 - t) + currentPos.x() * t;
|
||||
var ty: Float = prevPos.y() * (1.0 - t) + currentPos.y() * t;
|
||||
var tz: Float = prevPos.z() * (1.0 - t) + currentPos.z() * t;
|
||||
|
||||
var tRot: bullet.Bt.Quaternion = nlerp(prevRot, currentRot, t);
|
||||
|
||||
transform.loc.set(tx, ty, tz, 1.0);
|
||||
transform.rot.set(tRot.x(), tRot.y(), tRot.z(), tRot.w());
|
||||
} else {
|
||||
transform.loc.set(currentPos.x(), currentPos.y(), currentPos.z(), 1.0);
|
||||
transform.rot.set(currentRot.x(), currentRot.y(), currentRot.z(), currentRot.w());
|
||||
}
|
||||
|
||||
if (object.parent != null) {
|
||||
var ptransform = object.parent.transform;
|
||||
transform.loc.x -= ptransform.worldx();
|
||||
transform.loc.y -= ptransform.worldy();
|
||||
transform.loc.z -= ptransform.worldz();
|
||||
}
|
||||
|
||||
transform.buildMatrix();
|
||||
}
|
||||
|
||||
function nlerp(q1: bullet.Bt.Quaternion, q2: bullet.Bt.Quaternion, t: Float): bullet.Bt.Quaternion {
|
||||
var dot = q1.x() * q2.x() + q1.y() * q2.y() + q1.z() * q2.z() + q1.w() * q2.w();
|
||||
var _q2 = dot < 0 ? new bullet.Bt.Quaternion(-q2.x(), -q2.y(), -q2.z(), -q2.w()) : q2;
|
||||
|
||||
var x = q1.x() * (1.0 - t) + _q2.x() * t;
|
||||
var y = q1.y() * (1.0 - t) + _q2.y() * t;
|
||||
var z = q1.z() * (1.0 - t) + _q2.z() * t;
|
||||
var w = q1.w() * (1.0 - t) + _q2.w() * t;
|
||||
|
||||
var len = Math.sqrt(x * x + y * y + z * z + w * w);
|
||||
return new bullet.Bt.Quaternion(x / len, y / len, z / len, w / len);
|
||||
}
|
||||
|
||||
function physicsUpdate() {
|
||||
if (!ready) return;
|
||||
if (animated) {
|
||||
syncTransform();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (interpolate) {
|
||||
prevPos.setValue(currentPos.x(), currentPos.y(), currentPos.z());
|
||||
prevRot.setValue(currentRot.x(), currentRot.y(), currentRot.z(), currentRot.w());
|
||||
}
|
||||
var trans = body.getWorldTransform();
|
||||
var p = trans.getOrigin();
|
||||
var q = trans.getRotation();
|
||||
|
||||
transform.loc.set(p.x(), p.y(), p.z());
|
||||
transform.rot.set(q.x(), q.y(), q.z(), q.w());
|
||||
if (object.parent != null) {
|
||||
var ptransform = object.parent.transform;
|
||||
transform.loc.x -= ptransform.worldx();
|
||||
transform.loc.y -= ptransform.worldy();
|
||||
transform.loc.z -= ptransform.worldz();
|
||||
}
|
||||
transform.clearDelta();
|
||||
transform.buildMatrix();
|
||||
// transform.buildMatrix();
|
||||
currentPos.setValue(p.x(), p.y(), p.z());
|
||||
currentRot.setValue(q.x(), q.y(), q.z(), q.w());
|
||||
|
||||
|
||||
#if hl
|
||||
p.delete();
|
||||
@ -689,6 +751,7 @@ typedef RigidBodyFlags = {
|
||||
var animated: Bool;
|
||||
var trigger: Bool;
|
||||
var ccd: Bool;
|
||||
var interpolate: Bool;
|
||||
var staticObj: Bool;
|
||||
var useDeactivation: Bool;
|
||||
}
|
||||
|
Reference in New Issue
Block a user