Repe [T3DU] and Moises Jpelaez updates
This commit is contained in:
@ -13,7 +13,7 @@ class AddParticleToObjectNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
|
||||
if (property0 == 'Scene Active'){
|
||||
var objFrom: Object = inputs[1].get();
|
||||
@ -47,7 +47,7 @@ class AddParticleToObjectNode extends LogicNode {
|
||||
|
||||
var oslot: Int = mobjTo.particleSystems.length-1;
|
||||
var opsys = mobjTo.particleSystems[oslot];
|
||||
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
|
||||
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot]);
|
||||
|
||||
} else {
|
||||
var sceneName: String = inputs[1].get();
|
||||
@ -82,7 +82,7 @@ class AddParticleToObjectNode extends LogicNode {
|
||||
|
||||
var oslot: Int = mobjTo.particleSystems.length-1;
|
||||
var opsys = mobjTo.particleSystems[oslot];
|
||||
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
|
||||
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import iron.object.Object;
|
||||
|
||||
#if lnx_physics
|
||||
import leenkx.trait.physics.PhysicsConstraint;
|
||||
import leenkx.trait.physics.PhysicsConstraint.ConstraintAxis;
|
||||
#if lnx_bullet
|
||||
import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType;
|
||||
#elseif lnx_jolt
|
||||
@ -31,7 +32,6 @@ class AddPhysicsConstraintNode extends LogicNode {
|
||||
if (pivotObject == null || rb1 == null || rb2 == null) return;
|
||||
|
||||
#if lnx_physics
|
||||
|
||||
var disableCollisions: Bool = inputs[4].get();
|
||||
var breakable: Bool = inputs[5].get();
|
||||
var breakingThreshold: Float = inputs[6].get();
|
||||
|
||||
@ -31,7 +31,7 @@ class DrawImageNode extends LogicNode {
|
||||
|
||||
RenderToTexture.g.rotate(angle, x, y);
|
||||
|
||||
if (imgName != lastImgName) {
|
||||
if (imgName != lastImgName || img == null) {
|
||||
// Load new image
|
||||
lastImgName = imgName;
|
||||
iron.data.Data.getImage(imgName, (image: Image) -> {
|
||||
|
||||
107
leenkx/Sources/leenkx/logicnode/DrawImageRenderNode.hx
Normal file
107
leenkx/Sources/leenkx/logicnode/DrawImageRenderNode.hx
Normal file
@ -0,0 +1,107 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import kha.Image;
|
||||
import kha.Color;
|
||||
import leenkx.renderpath.RenderToTexture;
|
||||
|
||||
class DrawImageRenderNode extends LogicNode {
|
||||
var img: Image;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
|
||||
if (from == 1)
|
||||
tree.notifyOnRender(render);
|
||||
else {
|
||||
|
||||
RenderToTexture.ensure2DContext("DrawImageRenderNode");
|
||||
|
||||
final colorVec: Vec4 = inputs[3].get();
|
||||
final anchorH: Int = inputs[4].get();
|
||||
final anchorV: Int = inputs[5].get();
|
||||
final x: Float = inputs[6].get();
|
||||
final y: Float = inputs[7].get();
|
||||
final width: Float = inputs[8].get();
|
||||
final height: Float = inputs[9].get();
|
||||
final sx: Float = inputs[10].get();
|
||||
final sy: Float = inputs[11].get();
|
||||
final swidth: Float = inputs[12].get();
|
||||
final sheight: Float = inputs[13].get();
|
||||
final angle: Float = inputs[14].get();
|
||||
|
||||
final drawx = x - 0.5 * width * anchorH;
|
||||
final drawy = y - 0.5 * height * anchorV;
|
||||
|
||||
RenderToTexture.g.rotate(angle, x, y);
|
||||
|
||||
if (img != null){
|
||||
RenderToTexture.g.color = 0xff000000;
|
||||
RenderToTexture.g.fillRect(drawx, drawy, width, height);
|
||||
RenderToTexture.g.color = RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
|
||||
RenderToTexture.g.drawScaledSubImage(img, sx, sy, swidth, sheight, drawx, drawy, width, height);
|
||||
}
|
||||
|
||||
RenderToTexture.g.rotate(-angle, x, y);
|
||||
|
||||
runOutput(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function render(g: kha.graphics4.Graphics) {
|
||||
|
||||
var camera = inputs[2].get();
|
||||
|
||||
img = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
final sceneCam = iron.Scene.active.camera;
|
||||
final oldRT = camera.renderTarget;
|
||||
|
||||
iron.Scene.active.camera = camera;
|
||||
camera.renderTarget = img;
|
||||
|
||||
camera.renderFrame(g);
|
||||
|
||||
img = camera.renderTarget;
|
||||
|
||||
if (inputs[15].get() || kha.Image.renderTargetsInvertedY()) {
|
||||
|
||||
img = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
img.g2.begin(true, Color.Transparent);
|
||||
|
||||
img.g2.color = Color.White;
|
||||
|
||||
if (kha.Image.renderTargetsInvertedY()) {
|
||||
img.g2.drawScaledImage(camera.renderTarget, 0, iron.App.h(), iron.App.w(), -iron.App.h());
|
||||
} else {
|
||||
img.g2.drawImage(camera.renderTarget, 0, 0);
|
||||
}
|
||||
|
||||
if (inputs[15].get()) {
|
||||
for (f in @:privateAccess iron.App.traitRenders2D) {
|
||||
f(img.g2);
|
||||
}
|
||||
}
|
||||
|
||||
img.g2.end();
|
||||
|
||||
}
|
||||
|
||||
camera.renderTarget = oldRT;
|
||||
iron.Scene.active.camera = sceneCam;
|
||||
|
||||
tree.removeRender(render);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -14,7 +14,7 @@ class DrawSubImageNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
RenderToTexture.ensure2DContext("DrawImageNode");
|
||||
RenderToTexture.ensure2DContext("DrawSubImageNode");
|
||||
|
||||
final imgName: String = inputs[1].get();
|
||||
final colorVec: Vec4 = inputs[2].get();
|
||||
@ -32,12 +32,10 @@ class DrawSubImageNode extends LogicNode {
|
||||
|
||||
final drawx = x - 0.5 * width * anchorH;
|
||||
final drawy = y - 0.5 * height * anchorV;
|
||||
final sdrawx = sx - 0.5 * swidth * anchorH;
|
||||
final sdrawy = sy - 0.5 * sheight * anchorV;
|
||||
|
||||
RenderToTexture.g.rotate(angle, x, y);
|
||||
|
||||
if (imgName != lastImgName) {
|
||||
if (imgName != lastImgName || img == null) {
|
||||
// Load new image
|
||||
lastImgName = imgName;
|
||||
iron.data.Data.getImage(imgName, (image: Image) -> {
|
||||
@ -51,7 +49,7 @@ class DrawSubImageNode extends LogicNode {
|
||||
}
|
||||
|
||||
RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
|
||||
RenderToTexture.g.drawScaledSubImage(img, sdrawx, sdrawy, swidth, sheight, drawx, drawy, width, height);
|
||||
RenderToTexture.g.drawScaledSubImage(img, sx, sy, swidth, sheight, drawx, drawy, width, height);
|
||||
RenderToTexture.g.rotate(-angle, x, y);
|
||||
|
||||
runOutput(0);
|
||||
|
||||
71
leenkx/Sources/leenkx/logicnode/DrawToImageNode.hx
Normal file
71
leenkx/Sources/leenkx/logicnode/DrawToImageNode.hx
Normal file
@ -0,0 +1,71 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import kha.Color;
|
||||
import iron.math.Vec4;
|
||||
import leenkx.renderpath.RenderToTexture;
|
||||
|
||||
class DrawToImageNode extends LogicNode {
|
||||
|
||||
var img: kha.Image = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var file: String = inputs[1].get();
|
||||
var colorVec: Vec4 = inputs[2].get();
|
||||
|
||||
img = kha.Image.createRenderTarget(inputs[3].get(), inputs[4].get(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
RenderToTexture.ensureEmptyRenderTarget("DrawToImageNode");
|
||||
img.g2.begin();
|
||||
RenderToTexture.g = img.g2;
|
||||
RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
|
||||
RenderToTexture.g.fillRect(0, 0, img.width, img.height);
|
||||
runOutput(0);
|
||||
RenderToTexture.g = null;
|
||||
img.g2.end();
|
||||
|
||||
var pixels = img.getPixels();
|
||||
|
||||
var tx = inputs[5].get();
|
||||
var ty = inputs[6].get();
|
||||
var tw = inputs[7].get();
|
||||
var th = inputs[8].get();
|
||||
|
||||
var bo = new haxe.io.BytesOutput();
|
||||
var rgb = haxe.io.Bytes.alloc(tw * th * 4);
|
||||
for (j in ty...ty + th) {
|
||||
for (i in tx...tx + tw) {
|
||||
var l = j * img.width + i;
|
||||
var m = (j - ty) * tw + i - tx;
|
||||
|
||||
//ARGB 0xff
|
||||
rgb.set(m * 4 + 0, pixels.get(l * 4 + 3));
|
||||
rgb.set(m * 4 + 1, pixels.get(l * 4 + 0));
|
||||
rgb.set(m * 4 + 2, pixels.get(l * 4 + 1));
|
||||
rgb.set(m * 4 + 3, pixels.get(l * 4 + 2));
|
||||
}
|
||||
}
|
||||
|
||||
var imgwriter = new iron.format.bmp.Writer(bo);
|
||||
imgwriter.write(iron.format.bmp.Tools.buildFromARGB(tw, th, rgb));
|
||||
|
||||
#if kha_krom
|
||||
Krom.fileSaveBytes(Krom.getFilesLocation() + "/" + file, bo.getBytes().getData());
|
||||
|
||||
#elseif kha_html5
|
||||
var blob = new js.html.Blob([bo.getBytes().getData()], {type: "application"});
|
||||
var url = js.html.URL.createObjectURL(blob);
|
||||
var a = cast(js.Browser.document.createElement("a"), js.html.AnchorElement);
|
||||
a.href = url;
|
||||
a.download = file;
|
||||
a.click();
|
||||
js.html.URL.revokeObjectURL(url);
|
||||
#end
|
||||
}
|
||||
|
||||
}
|
||||
80
leenkx/Sources/leenkx/logicnode/DrawToScreenNode.hx
Normal file
80
leenkx/Sources/leenkx/logicnode/DrawToScreenNode.hx
Normal file
@ -0,0 +1,80 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import kha.Image;
|
||||
import kha.Color;
|
||||
import leenkx.renderpath.RenderToTexture;
|
||||
|
||||
class DrawToScreenNode extends LogicNode {
|
||||
var img: Image;
|
||||
var colorVec: Vec4;
|
||||
var anchorH: Int;
|
||||
var anchorV: Int;
|
||||
var x: Float;
|
||||
var y: Float;
|
||||
var width: Float;
|
||||
var height: Float;
|
||||
var sx: Float;
|
||||
var sy: Float;
|
||||
var swidth: Float;
|
||||
var sheight: Float;
|
||||
var angle: Float;
|
||||
|
||||
var drawx: Float;
|
||||
var drawy: Float;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
|
||||
if (from == 0){
|
||||
|
||||
if (img == null){
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
colorVec = inputs[4].get();
|
||||
anchorH = inputs[5].get();
|
||||
anchorV = inputs[6].get();
|
||||
x = inputs[7].get();
|
||||
y = inputs[8].get();
|
||||
width = inputs[9].get();
|
||||
height = inputs[10].get();
|
||||
sx = inputs[11].get();
|
||||
sy = inputs[12].get();
|
||||
swidth = inputs[13].get();
|
||||
sheight = inputs[14].get();
|
||||
angle = inputs[15].get();
|
||||
|
||||
drawx = x - 0.5 * width * anchorH;
|
||||
drawy = y - 0.5 * height * anchorV;
|
||||
|
||||
RenderToTexture.g.rotate(angle, x, y);
|
||||
RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
|
||||
RenderToTexture.g.drawScaledSubImage(img, sx, sy, swidth, sheight, drawx, drawy, width, height);
|
||||
RenderToTexture.g.rotate(-angle, x, y);
|
||||
|
||||
runOutput(0);
|
||||
|
||||
} else {
|
||||
|
||||
if (img == null)
|
||||
img = kha.Image.createRenderTarget(inputs[2].get(), inputs[3].get(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
RenderToTexture.ensureEmptyRenderTarget("DrawToScreenNode");
|
||||
img.g2.begin(inputs[16].get(), Color.Transparent);
|
||||
RenderToTexture.g = img.g2;
|
||||
runOutput(1);
|
||||
RenderToTexture.g = null;
|
||||
img.g2.end();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
23
leenkx/Sources/leenkx/logicnode/EmitSignalNode.hx
Normal file
23
leenkx/Sources/leenkx/logicnode/EmitSignalNode.hx
Normal file
@ -0,0 +1,23 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import leenkx.system.Signal;
|
||||
|
||||
class EmitSignalNode extends LogicNode {
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var signal: Signal = inputs[1].get();
|
||||
if (signal == null)
|
||||
return;
|
||||
|
||||
var args: Array<Any> = [];
|
||||
for (i in 2...inputs.length) {
|
||||
args.push(inputs[i].get());
|
||||
}
|
||||
|
||||
Reflect.callMethod(signal, Reflect.field(signal, "emit"), args);
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
96
leenkx/Sources/leenkx/logicnode/GetImageColorNode.hx
Normal file
96
leenkx/Sources/leenkx/logicnode/GetImageColorNode.hx
Normal file
@ -0,0 +1,96 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import kha.Color;
|
||||
import kha.Image;
|
||||
|
||||
class GetImageColorNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
var renderTarget: Image = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
renderTarget = Image.createRenderTarget(iron.App.w(), iron.App.h(), kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
|
||||
var i: Int;
|
||||
var j: Int;
|
||||
|
||||
if (property0 == 'Image'){
|
||||
i = inputs[1].get();
|
||||
j = inputs[2].get();
|
||||
} else {
|
||||
i = inputs[0].get();
|
||||
j = inputs[1].get();
|
||||
}
|
||||
|
||||
if (i < 0 || j < 0) return null;
|
||||
|
||||
if (property0 != 'Image')
|
||||
if (i > renderTarget.width || j > renderTarget.height) return null;
|
||||
|
||||
renderTarget.g2.begin(true, Color.Transparent);
|
||||
|
||||
renderTarget.g2.color = Color.White;
|
||||
|
||||
if (property0 == 'Render' || property0 == 'Render&Render2D'){
|
||||
if (leenkx.renderpath.RenderPathCreator.finalTarget != null){
|
||||
var img: Image = iron.RenderPath.active.renderTargets.get("buf").image;
|
||||
renderTarget.g2.drawScaledImage(img, 0, 0, iron.App.w(), iron.App.h());
|
||||
}
|
||||
}
|
||||
|
||||
if (Image.renderTargetsInvertedY()){
|
||||
renderTarget.g2.scale(1, -1);
|
||||
renderTarget.g2.translate(0, renderTarget.height);
|
||||
}
|
||||
|
||||
if (property0 == 'Image'){
|
||||
var img: Image;
|
||||
iron.data.Data.getImage(inputs[0].get(), (image: Image) -> {
|
||||
img = image;
|
||||
});
|
||||
if (img == null || i > img.width || j > img.height){
|
||||
renderTarget.g2.end();
|
||||
return null;
|
||||
} else
|
||||
renderTarget.g2.drawScaledImage(img, 0, 0, img.width, img.height);
|
||||
}
|
||||
|
||||
if (property0.indexOf('2D') > 0)
|
||||
for (f in @:privateAccess iron.App.traitRenders2D)
|
||||
f(renderTarget.g2);
|
||||
|
||||
if (Image.renderTargetsInvertedY()){
|
||||
renderTarget.g2.scale(1, -1);
|
||||
renderTarget.g2.translate(0, renderTarget.height);
|
||||
}
|
||||
|
||||
renderTarget.g2.end();
|
||||
|
||||
var pixels = renderTarget.getPixels();
|
||||
|
||||
var k = j * renderTarget.width + i;
|
||||
|
||||
#if kha_krom
|
||||
var l = k;
|
||||
#elseif kha_html5
|
||||
var l = (renderTarget.height - j) * renderTarget.width + i;
|
||||
#end
|
||||
|
||||
var r = pixels.get(l * 4 + 0)/255;
|
||||
var g = pixels.get(l * 4 + 1)/255;
|
||||
var b = pixels.get(l * 4 + 2)/255;
|
||||
var a = pixels.get(l * 4 + 3)/255;
|
||||
|
||||
var v = new Vec4(r, g, b, a);
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -14,7 +14,7 @@ class GetParticleDataNode extends LogicNode {
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ class GetParticleNode extends LogicNode {
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
|
||||
21
leenkx/Sources/leenkx/logicnode/GetTilesheetFlipNode.hx
Normal file
21
leenkx/Sources/leenkx/logicnode/GetTilesheetFlipNode.hx
Normal file
@ -0,0 +1,21 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
|
||||
class GetTilesheetFlipNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: MeshObject = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
if (object.tilesheet == null) return null;
|
||||
if (from == 0) return object.tilesheet.flipX;
|
||||
if (from == 1) return object.tilesheet.flipY;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -11,13 +11,13 @@ class GetTilesheetStateNode extends LogicNode {
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: MeshObject = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
if (object == null || object.tilesheet == null) return null;
|
||||
|
||||
var tilesheet = object.activeTilesheet;
|
||||
var tilesheet = object.tilesheet;
|
||||
|
||||
return switch (from) {
|
||||
case 0: tilesheet.raw.name;
|
||||
case 1: tilesheet.action.name;
|
||||
case 0: object.name; // Return object name since tilesheet is embedded
|
||||
case 1: tilesheet.action != null ? tilesheet.action.name : null;
|
||||
case 2: tilesheet.getFrameOffset();
|
||||
case 3: tilesheet.frame;
|
||||
case 4: tilesheet.paused;
|
||||
|
||||
24
leenkx/Sources/leenkx/logicnode/GlobalSignalNode.hx
Normal file
24
leenkx/Sources/leenkx/logicnode/GlobalSignalNode.hx
Normal file
@ -0,0 +1,24 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import leenkx.system.Signal;
|
||||
|
||||
class GlobalSignalNode extends LogicNode {
|
||||
public static var signals: Map<String, Signal> = new Map<String, Signal>();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Null<Signal> {
|
||||
var name: String = inputs[0].get();
|
||||
if (name == null || name == "")
|
||||
return null;
|
||||
|
||||
var signal: Signal = signals.get(name);
|
||||
if (signal == null) {
|
||||
signal = new Signal();
|
||||
signals.set(name, signal);
|
||||
}
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,7 @@ class LogicTree extends iron.Trait {
|
||||
if (paused) return;
|
||||
paused = true;
|
||||
|
||||
if (_fixedUpdate != null) for (f in _fixedUpdate) iron.App.removeFixedUpdate(f);
|
||||
if (_update != null) for (f in _update) iron.App.removeUpdate(f);
|
||||
if (_lateUpdate != null) for (f in _lateUpdate) iron.App.removeLateUpdate(f);
|
||||
}
|
||||
@ -41,6 +42,7 @@ class LogicTree extends iron.Trait {
|
||||
if (!paused) return;
|
||||
paused = false;
|
||||
|
||||
if (_fixedUpdate != null) for (f in _fixedUpdate) iron.App.notifyOnFixedUpdate(f);
|
||||
if (_update != null) for (f in _update) iron.App.notifyOnUpdate(f);
|
||||
if (_lateUpdate != null) for (f in _lateUpdate) iron.App.notifyOnLateUpdate(f);
|
||||
}
|
||||
|
||||
@ -11,10 +11,10 @@ class OnContactArrayNode extends LogicNode {
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
||||
tree.notifyOnUpdate(update);
|
||||
tree.notifyOnFixedUpdate(fixedUpdate);
|
||||
}
|
||||
|
||||
function update() {
|
||||
function fixedUpdate() {
|
||||
var object1: Object = inputs[0].get();
|
||||
var objects: Array<Object> = inputs[1].get();
|
||||
|
||||
|
||||
@ -15,10 +15,10 @@ class OnContactNode extends LogicNode {
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
||||
tree.notifyOnUpdate(update);
|
||||
tree.notifyOnFixedUpdate(fixedUpdate);
|
||||
}
|
||||
|
||||
function update() {
|
||||
function fixedUpdate() {
|
||||
var object1: Object = inputs[0].get();
|
||||
var object2: Object = inputs[1].get();
|
||||
|
||||
|
||||
49
leenkx/Sources/leenkx/logicnode/OnSignalNode.hx
Normal file
49
leenkx/Sources/leenkx/logicnode/OnSignalNode.hx
Normal file
@ -0,0 +1,49 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import leenkx.system.Signal;
|
||||
|
||||
class OnSignalNode extends LogicNode {
|
||||
var emittedArgs: Array<Dynamic> = [];
|
||||
var connectedSignal: Signal = null;
|
||||
var callback: haxe.Constraints.Function = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
tree.notifyOnInit(init);
|
||||
tree.notifyOnRemove(onRemove);
|
||||
}
|
||||
|
||||
function init() {
|
||||
var signal: Signal = inputs[0].get();
|
||||
if (signal == null)
|
||||
return;
|
||||
|
||||
connectedSignal = signal;
|
||||
callback = onSignal;
|
||||
signal.connect(callback);
|
||||
}
|
||||
|
||||
function onSignal(...args: Any) {
|
||||
emittedArgs = [];
|
||||
for (arg in args) {
|
||||
emittedArgs.push(arg);
|
||||
}
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Any {
|
||||
var argIndex: Int = from - 1;
|
||||
if (argIndex >= 0 && argIndex < emittedArgs.length) {
|
||||
return emittedArgs[argIndex];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function onRemove() {
|
||||
if (connectedSignal != null && callback != null) {
|
||||
connectedSignal.disconnect(callback);
|
||||
connectedSignal = null;
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,7 @@ import leenkx.trait.physics.PhysicsWorld;
|
||||
|
||||
class OnUpdateNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Update, Late Update, Physics Pre-Update
|
||||
public var property0: String; // Update, Fixed Update, Late Update, Physics Pre-Update
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
@ -13,6 +13,7 @@ class OnUpdateNode extends LogicNode {
|
||||
|
||||
function init() {
|
||||
switch (property0) {
|
||||
case "Fixed Update": tree.notifyOnFixedUpdate(update);
|
||||
case "Late Update": tree.notifyOnLateUpdate(update);
|
||||
#if lnx_physics
|
||||
case "Physics Pre-Update": PhysicsWorld.active.notifyOnPreUpdate(update);
|
||||
|
||||
@ -11,9 +11,9 @@ class PauseTilesheetNode extends LogicNode {
|
||||
override function run(from: Int) {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
|
||||
if (object == null) return;
|
||||
if (object == null || object.tilesheet == null) return;
|
||||
|
||||
object.activeTilesheet.pause();
|
||||
object.tilesheet.pause();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
210
leenkx/Sources/leenkx/logicnode/PlayActionFromNode.hx
Normal file
210
leenkx/Sources/leenkx/logicnode/PlayActionFromNode.hx
Normal file
@ -0,0 +1,210 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Animation;
|
||||
import iron.object.Animation.ActionSampler;
|
||||
import iron.object.Object;
|
||||
import iron.Scene;
|
||||
import kha.arrays.Float32Array;
|
||||
import iron.object.ObjectAnimation;
|
||||
#if lnx_skin
|
||||
import iron.object.BoneAnimation;
|
||||
#end
|
||||
|
||||
class PlayActionFromNode extends LogicNode {
|
||||
|
||||
var animation: Animation;
|
||||
var startFrame: Int;
|
||||
var endFrame: Int = -1;
|
||||
var loop: Bool;
|
||||
var reverse: Bool;
|
||||
var action: String;
|
||||
var actionR: String;
|
||||
var sampler: ActionSampler;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
tree.notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (sampler != null && action == sampler.action) {
|
||||
if (sampler.offset == endFrame-1) {
|
||||
if (loop) sampler.setFrameOffset(startFrame);
|
||||
else {
|
||||
if (!sampler.paused) {
|
||||
sampler.paused = true;
|
||||
runOutput(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
action = inputs[2].get();
|
||||
startFrame = inputs[3].get();
|
||||
endFrame = inputs[4].get();
|
||||
var blendTime: Float = inputs[5].get();
|
||||
var speed: Float = inputs[6].get();
|
||||
loop = inputs[7].get();
|
||||
reverse = inputs[8].get();
|
||||
|
||||
if (object == null) return;
|
||||
animation = object.animation;
|
||||
if (animation == null) animation = object.getBoneAnimation(object.uid);
|
||||
|
||||
if (animation == null) return;
|
||||
|
||||
if (reverse){
|
||||
var isnew = true;
|
||||
actionR = action+'Reverse';
|
||||
|
||||
#if lnx_skin
|
||||
if (animation.isSkinned){
|
||||
for(a in animation.armature.actions)
|
||||
if (a.name == actionR) isnew = false;
|
||||
|
||||
if (isnew){
|
||||
for(a in animation.armature.actions)
|
||||
if(a.name == action){
|
||||
var bones = [];
|
||||
var cn = [];
|
||||
for(bone in a.bones){
|
||||
var v = bone.anim.tracks[0];
|
||||
var len: Int = v.values.length;
|
||||
var val = new Float32Array(len);
|
||||
var l = Std.int(len/16);
|
||||
for(i in 0...l)
|
||||
for(j in 0...16){
|
||||
val[i*16+j] = v.values[(l-i)*16+j-16];
|
||||
}
|
||||
|
||||
if (bone.children != null){
|
||||
var cdn = [];
|
||||
for (child in bone.children)
|
||||
cdn.push(child.name);
|
||||
cn.push(cdn);
|
||||
} else cn.push(null);
|
||||
|
||||
var a: iron.data.SceneFormat.TObj = {
|
||||
type : bone.type,
|
||||
name : bone.name,
|
||||
transform : {
|
||||
values : bone.transform.values
|
||||
},
|
||||
anim : {
|
||||
tracks : [{
|
||||
target : v.target,
|
||||
frames : v.frames,
|
||||
values : val,
|
||||
ref_values : null
|
||||
}]
|
||||
},
|
||||
children : bone.children,
|
||||
data_ref : null
|
||||
}
|
||||
|
||||
if (bone.parent != null){
|
||||
a.parent = bone.parent;
|
||||
}
|
||||
|
||||
bones.push(a);
|
||||
}
|
||||
|
||||
for (i in 0...bones.length){
|
||||
var cd = [];
|
||||
if (cn[i] != null)
|
||||
for (name in cn[i])
|
||||
for (bone in bones)
|
||||
if (bone.name == name)
|
||||
cd.push(bone);
|
||||
bones[i].children = cd;
|
||||
}
|
||||
|
||||
for (i in 0...bones.length){
|
||||
if (bones[i].parent != null)
|
||||
for (bone in bones)
|
||||
if (bone.name == bones[i].parent.name)
|
||||
bones[i].parent = bone;
|
||||
}
|
||||
|
||||
animation.armature.actions.push({
|
||||
name: actionR,
|
||||
bones: bones,
|
||||
mats: null});
|
||||
|
||||
var mats: Array<iron.math.Mat4> = [];
|
||||
for (bone in a.bones) mats.push(iron.math.Mat4.fromFloat32Array(bone.transform.values));
|
||||
|
||||
var castBoneAnim = cast(animation, BoneAnimation);
|
||||
castBoneAnim.data.geom.actions.set(actionR, bones);
|
||||
castBoneAnim.data.geom.mats.set(actionR, mats);
|
||||
|
||||
for(o in iron.Scene.active.raw.objects)
|
||||
if (o.name == object.name) o.bone_actions.push('action_'+o.bone_actions[0].split('_')[1]+'_'+actionR);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#end
|
||||
{
|
||||
|
||||
var oaction = null;
|
||||
var tracks: Array<iron.data.SceneFormat.TTrack> = [];
|
||||
|
||||
var oactions = cast(animation, ObjectAnimation).oactions;
|
||||
|
||||
for (a in oactions)
|
||||
if (a != null && a.objects[0].name == actionR) isnew = false;
|
||||
|
||||
if (isnew){
|
||||
for (a in oactions){
|
||||
if (a != null && a.objects[0].name == action){
|
||||
oaction = a.objects[0];
|
||||
for(b in a.objects[0].anim.tracks){
|
||||
var val: Array<Float> = [];
|
||||
for(c in b.values) val.unshift(c);
|
||||
var vali = new Float32Array(val.length);
|
||||
for(i in 0...val.length) vali[i] = val[i];
|
||||
tracks.push({target: b.target, frames: b.frames, values: vali});
|
||||
}
|
||||
|
||||
oactions.push({
|
||||
objects: [{name: actionR,
|
||||
anim: {begin: oaction.anim.begin, end: oaction.anim.end, tracks: tracks},
|
||||
type: 'object',
|
||||
data_ref: '',
|
||||
transform: null}]});
|
||||
|
||||
for(o in iron.Scene.active.raw.objects)
|
||||
if (o.name == object.name) o.object_actions.push('action_'+actionR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animation.play(reverse ? actionR : action, function() {
|
||||
runOutput(1);
|
||||
}, blendTime, speed, loop);
|
||||
|
||||
// Get the sampler for the played action
|
||||
if (animation.activeActions != null) {
|
||||
for (key in animation.activeActions.keys()) {
|
||||
var s = animation.activeActions.get(key);
|
||||
if (s.action == (reverse ? actionR : action)) {
|
||||
sampler = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sampler != null) {
|
||||
sampler.setFrameOffset(startFrame);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@ package leenkx.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
|
||||
class PlayTilesheetNode extends LogicNode {
|
||||
class PlayTilesheetActionNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
@ -12,9 +12,9 @@ class PlayTilesheetNode extends LogicNode {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
var action: String = inputs[2].get();
|
||||
|
||||
if (object == null) return;
|
||||
if (object == null || object.tilesheet == null) return;
|
||||
|
||||
object.activeTilesheet.play(action, function() {
|
||||
object.tilesheet.play(action, function() {
|
||||
runOutput(1);
|
||||
});
|
||||
|
||||
@ -11,7 +11,7 @@ class RemoveParticleFromObjectNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
var object: Object = inputs[1].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
71
leenkx/Sources/leenkx/logicnode/ReplaceObjectNode.hx
Normal file
71
leenkx/Sources/leenkx/logicnode/ReplaceObjectNode.hx
Normal file
@ -0,0 +1,71 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import leenkx.trait.physics.RigidBody;
|
||||
|
||||
class ReplaceObjectNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var base: Object = inputs[1].get();
|
||||
var replace: Object = inputs[2].get();
|
||||
var invert: Bool = inputs[3].get();
|
||||
var includeScale: Bool = inputs[4].get();
|
||||
|
||||
if (base == null || replace == null) return;
|
||||
|
||||
// Obtener posicion, rotacion y escala global de ambos obj // get position, rotation and global scale of both obj
|
||||
var baseLoc = base.transform.world.getLoc().clone();
|
||||
var replaceLoc = replace.transform.world.getLoc().clone();
|
||||
|
||||
var tmpVec = new Vec4();
|
||||
var baseRot = new Quat();
|
||||
var replaceRot = new Quat();
|
||||
var tmpScale = new Vec4();
|
||||
|
||||
base.transform.world.decompose(tmpVec, baseRot, tmpScale);
|
||||
replace.transform.world.decompose(tmpVec, replaceRot, tmpScale);
|
||||
|
||||
var baseScale = base.transform.scale.clone();
|
||||
var replaceScale = replace.transform.scale.clone();
|
||||
|
||||
if (!invert) {
|
||||
// Intercambiar transformaciones // Swap transformations
|
||||
base.transform.loc.setFrom(replaceLoc);
|
||||
base.transform.rot.setFrom(replaceRot);
|
||||
if (includeScale) base.transform.scale.setFrom(replaceScale);
|
||||
|
||||
replace.transform.loc.setFrom(baseLoc);
|
||||
replace.transform.rot.setFrom(baseRot);
|
||||
if (includeScale) replace.transform.scale.setFrom(baseScale);
|
||||
} else {
|
||||
// Invertir: cada (object) vuelve a su lugar inicial // Invert: each (object) returns to its initial place
|
||||
base.transform.loc.setFrom(baseLoc);
|
||||
base.transform.rot.setFrom(baseRot);
|
||||
if (includeScale) base.transform.scale.setFrom(baseScale);
|
||||
|
||||
replace.transform.loc.setFrom(replaceLoc);
|
||||
replace.transform.rot.setFrom(replaceRot);
|
||||
if (includeScale) replace.transform.scale.setFrom(replaceScale);
|
||||
}
|
||||
|
||||
// Recalcular matrices
|
||||
base.transform.buildMatrix();
|
||||
replace.transform.buildMatrix();
|
||||
|
||||
// Sincronizar RB // Sync RB
|
||||
#if lnx_physics
|
||||
for (obj in [base, replace]) {
|
||||
var rb = obj.getTrait(RigidBody);
|
||||
if (rb != null) rb.syncTransform();
|
||||
}
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
@ -11,9 +11,9 @@ class ResumeTilesheetNode extends LogicNode {
|
||||
override function run(from: Int) {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
|
||||
if (object == null) return;
|
||||
if (object == null || object.tilesheet == null) return;
|
||||
|
||||
object.activeTilesheet.resume();
|
||||
object.tilesheet.resume();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
|
||||
class RetainValueNode extends LogicNode {
|
||||
|
||||
var value: Dynamic = null;
|
||||
@ -9,7 +13,19 @@ class RetainValueNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
value = inputs[1].get();
|
||||
var retainValue = inputs[1].get();
|
||||
|
||||
switch(Type.getClassName(Type.getClass(retainValue))){
|
||||
case "iron.math.Vec4":
|
||||
value = (cast retainValue: Vec4).clone();
|
||||
case "iron.math.Mat4":
|
||||
value = (cast retainValue: Mat4).clone();
|
||||
case "iron.math.Quat":
|
||||
var q: Quat = new Quat();
|
||||
value = q.setFrom((cast retainValue: Quat));
|
||||
default:
|
||||
value = retainValue;
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
|
||||
class SetFirstPersonControllerNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int): Void {
|
||||
// Control de las var de FirstPersonController...
|
||||
// Control FirstPersonController var
|
||||
|
||||
var object: Object = inputs[1].get();
|
||||
|
||||
// Ajustes de la camara. // Camera settings
|
||||
var rotationSpeed: Float = inputs[2].get();
|
||||
var maxPitch: Float = inputs[3].get();
|
||||
var minPitch: Float = inputs[4].get();
|
||||
|
||||
// Ajustes de desplazamiento.. // Move settings
|
||||
var moveSpeed: Float = inputs[5].get();
|
||||
var runSpeed: Float = inputs[6].get();
|
||||
|
||||
|
||||
// var bool to set true/false the trait props (FirstPersonController)
|
||||
var enableJump: Bool = inputs[7].get();
|
||||
var allowAirJump: Bool = inputs[8].get();
|
||||
var canRun: Bool = inputs[9].get();
|
||||
var stamina: Bool = inputs[10].get();
|
||||
var enableFatigue: Bool = inputs[11].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
// Tomar el Trait desde el object (FPController) // Get trait from (object) and assigned to the var (fpController)
|
||||
var fpController: leenkx.trait.FirstPersonController = object.getTrait(leenkx.trait.FirstPersonController);
|
||||
|
||||
if (fpController != null) {
|
||||
|
||||
// Ajustes de la camara // Cam settings
|
||||
fpController.rotationSpeed = rotationSpeed;
|
||||
fpController.maxPitch = maxPitch;
|
||||
fpController.minPitch = minPitch;
|
||||
|
||||
// Ajuste de desplazamiento // Move settings
|
||||
fpController.moveSpeed = moveSpeed;
|
||||
fpController.runSpeed = runSpeed;
|
||||
|
||||
|
||||
// Settings (run, jump, stamina anad fatigue)
|
||||
fpController.enableJump = enableJump;
|
||||
fpController.allowAirJump = allowAirJump;
|
||||
fpController.canRun = canRun;
|
||||
fpController.stamina = stamina;
|
||||
fpController.enableFatigue = enableFatigue;
|
||||
|
||||
} else {
|
||||
// Alert the user if they do not have the trait assigning to the object.
|
||||
trace("ERROR: The object '" + object.name + "' does not have the FirstPersonController script assigning(assign it from (Object->add trait->bundle)).");
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
|
||||
class SetOverheadPersonControllerNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int): Void {
|
||||
// Control de las var de OverheadPersonController...
|
||||
// Control OverheadPersonController var
|
||||
|
||||
var objectTrait: Object = inputs[1].get();
|
||||
|
||||
// Ajustes de la camara. // Camera settings
|
||||
var smoothTrack: Bool = inputs[2].get();
|
||||
var smoothSpeed: Float = inputs[3].get();
|
||||
|
||||
// Ajustes de desplazamiento.. // Move setting
|
||||
var moveSpeed: Float = inputs[4].get();
|
||||
var runSpeed: Float = inputs[5].get();
|
||||
|
||||
|
||||
// var bool to set true/false the trait props (OverheadPersonController)
|
||||
var enableJump: Bool = inputs[6].get();
|
||||
var allowAirJump: Bool = inputs[7].get();
|
||||
var canRun: Bool = inputs[8].get();
|
||||
var stamina: Bool = inputs[9].get();
|
||||
var enableFatigue: Bool = inputs[10].get();
|
||||
|
||||
if (objectTrait == null) return;
|
||||
|
||||
// Tomar el trait del object (ovController). // Get trait from (objectTrait) and assigned to the var (ovController)
|
||||
var ovController: leenkx.trait.OverheadPersonController = objectTrait.getTrait(leenkx.trait.OverheadPersonController);
|
||||
|
||||
if (ovController != null) {
|
||||
|
||||
// Setting smoothCamera
|
||||
ovController.smoothTrack = smoothTrack;
|
||||
ovController.smoothSpeed = smoothSpeed;
|
||||
|
||||
// Setting move
|
||||
ovController.moveSpeed = moveSpeed;
|
||||
ovController.runSpeed = runSpeed;
|
||||
|
||||
|
||||
// Settings (run, jump, stamina anad fatigue)
|
||||
ovController.enableJump = enableJump;
|
||||
ovController.allowAirJump = allowAirJump;
|
||||
ovController.canRun = canRun;
|
||||
ovController.stamina = stamina;
|
||||
ovController.enableFatigue = enableFatigue;
|
||||
|
||||
} else {
|
||||
// Alert the user if they do not have the trait assigning to the object..
|
||||
trace("ERROR: The object '" + objectTrait.name + "' does not have the OverheadPersonController script assigning(assign it from (Object->add trait->bundle)).");
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,7 +11,7 @@ class SetParticleDataNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
var object: Object = inputs[1].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
|
||||
@ -41,7 +41,7 @@ class SetParticleDataNode extends LogicNode {
|
||||
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);
|
||||
@:privateAccess psys.setupGeomGpu(mo.particleChildren != null ? mo.particleChildren[slot] : cast(iron.Scene.active.getChild(@:privateAccess psys.data.raw.instance_object), iron.object.MeshObject));
|
||||
}
|
||||
case 'Auto Start':
|
||||
@:privateAccess psys.r.auto_start = inputs[3].get();
|
||||
|
||||
@ -9,7 +9,7 @@ class SetParticleRenderEmitterNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
var object: Object = inputs[1].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
@ -9,7 +9,7 @@ class SetParticleSpeedNode extends LogicNode {
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
#if lnx_gpu_particles
|
||||
var object: Object = inputs[1].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
var speed: Float = inputs[3].get();
|
||||
|
||||
21
leenkx/Sources/leenkx/logicnode/SetTilesheetActionNode.hx
Normal file
21
leenkx/Sources/leenkx/logicnode/SetTilesheetActionNode.hx
Normal file
@ -0,0 +1,21 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
|
||||
class SetTilesheetActionNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
var action: String = inputs[2].get();
|
||||
|
||||
if (object == null || object.tilesheet == null) return;
|
||||
|
||||
object.setTilesheetAction(action);
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.object.MeshObject;
|
||||
|
||||
class SetActiveTilesheetNode extends LogicNode {
|
||||
class SetTilesheetFlipNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
@ -11,12 +10,13 @@ class SetActiveTilesheetNode extends LogicNode {
|
||||
|
||||
override function run(from: Int) {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
var tilesheet: String = inputs[2].get();
|
||||
var action: String = inputs[3].get();
|
||||
var flipX: Bool = inputs[2].get();
|
||||
var flipY: Bool = inputs[3].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
object.setActiveTilesheet(Scene.active.raw.name, tilesheet, action);
|
||||
if (object.tilesheet == null) return;
|
||||
object.tilesheet.flipX = flipX;
|
||||
object.tilesheet.flipY = flipY;
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
@ -12,9 +12,9 @@ class SetTilesheetFrameNode extends LogicNode {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
var frame: Int = inputs[2].get();
|
||||
|
||||
if (object == null) return;
|
||||
if (object == null || object.tilesheet == null) return;
|
||||
|
||||
object.activeTilesheet.setFrameOffset(frame);
|
||||
object.tilesheet.setFrameOffset(frame);
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
@ -12,9 +12,9 @@ class SetTilesheetPausedNode extends LogicNode {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
var paused: Bool = inputs[2].get();
|
||||
|
||||
if (object == null) return;
|
||||
if (object == null || object.tilesheet == null) return;
|
||||
|
||||
paused ? object.activeTilesheet.pause() : object.activeTilesheet.resume();
|
||||
paused ? object.tilesheet.pause() : object.tilesheet.resume();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
@ -8,5 +8,6 @@ class ShutdownNode extends LogicNode {
|
||||
|
||||
override function run(from: Int) {
|
||||
kha.System.stop();
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
26
leenkx/Sources/leenkx/logicnode/SignalNode.hx
Normal file
26
leenkx/Sources/leenkx/logicnode/SignalNode.hx
Normal file
@ -0,0 +1,26 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import leenkx.system.Signal;
|
||||
import iron.object.Object;
|
||||
|
||||
class SignalNode extends LogicNode {
|
||||
var signal: Signal = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Null<Signal> {
|
||||
var object: Object = inputs[0].get();
|
||||
var property: String = inputs[1].get();
|
||||
|
||||
if (object != null && property != null && property != "") {
|
||||
return Reflect.getProperty(object, property);
|
||||
}
|
||||
|
||||
if (signal == null) {
|
||||
signal = new Signal();
|
||||
}
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.CameraObject;
|
||||
import kha.Color;
|
||||
|
||||
class WriteImageNode extends LogicNode {
|
||||
|
||||
@ -43,6 +44,34 @@ class WriteImageNode extends LogicNode {
|
||||
camera.renderTarget = oldRT;
|
||||
iron.Scene.active.camera = sceneCam;
|
||||
|
||||
if (inputs[9].get()){
|
||||
|
||||
tex = kha.Image.createRenderTarget(inputs[3].get(), inputs[4].get(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
tex.g2.begin(true, Color.Transparent);
|
||||
|
||||
tex.g2.color = Color.White;
|
||||
tex.g2.drawScaledImage(renderTarget, 0, 0, inputs[3].get(), inputs[4].get());
|
||||
|
||||
var scl = inputs[3].get() / iron.App.w();
|
||||
|
||||
if (kha.Image.renderTargetsInvertedY()){
|
||||
tex.g2.scale(scl, -scl);
|
||||
tex.g2.translate(0, inputs[4].get());
|
||||
}
|
||||
else
|
||||
tex.g2.scale(scl, scl);
|
||||
|
||||
for (f in @:privateAccess iron.App.traitRenders2D){
|
||||
f(tex.g2);
|
||||
}
|
||||
|
||||
tex.g2.end();
|
||||
|
||||
}
|
||||
|
||||
var pixels = tex.getPixels();
|
||||
|
||||
for (i in 0...pixels.length){
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package leenkx.network;
|
||||
|
||||
@:enum abstract OpCode(Int) {
|
||||
enum abstract OpCode(Int) {
|
||||
var Continuation = 0x00;
|
||||
var Text = 0x01;
|
||||
var Binary = 0x02;
|
||||
|
||||
@ -6,7 +6,7 @@ import haxe.io.Bytes;
|
||||
typedef BinaryType = js.html.BinaryType;
|
||||
#else
|
||||
|
||||
@:enum abstract BinaryType(String) {
|
||||
enum abstract BinaryType(String) {
|
||||
var ARRAYBUFFER = "arraybuffer";
|
||||
|
||||
@:to public function toString() {
|
||||
|
||||
@ -10,8 +10,6 @@ class Inc {
|
||||
static var path: RenderPath;
|
||||
public static var superSample = 1.0;
|
||||
|
||||
static var pointIndex = 0;
|
||||
static var spotIndex = 0;
|
||||
static var lastFrame = -1;
|
||||
|
||||
#if lnx_shadowmap_atlas
|
||||
@ -41,6 +39,7 @@ class Inc {
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
static var voxel_td1:kha.compute.TextureUnit;
|
||||
static var voxel_te1:kha.compute.TextureUnit;
|
||||
static var voxel_tf1:kha.compute.TextureUnit;
|
||||
static var voxel_cc1:kha.compute.ConstantLocation;
|
||||
#else
|
||||
#if lnx_voxelgi_shadows
|
||||
@ -94,8 +93,34 @@ class Inc {
|
||||
static var voxel_cb4:kha.compute.ConstantLocation;
|
||||
static var voxel_cc4:kha.compute.ConstantLocation;
|
||||
static var voxel_cd4:kha.compute.ConstantLocation;
|
||||
|
||||
static var voxel_sh5:kha.compute.Shader = null;
|
||||
static var voxel_ta5:kha.compute.TextureUnit;
|
||||
static var voxel_te5:kha.compute.TextureUnit;
|
||||
static var voxel_tf5:kha.compute.TextureUnit;
|
||||
static var voxel_tg5:kha.compute.TextureUnit;
|
||||
static var voxel_ca5:kha.compute.ConstantLocation;
|
||||
static var voxel_cb5:kha.compute.ConstantLocation;
|
||||
static var voxel_cc5:kha.compute.ConstantLocation;
|
||||
static var voxel_cd5:kha.compute.ConstantLocation;
|
||||
static var voxel_ce5:kha.compute.ConstantLocation;
|
||||
static var voxel_cf5:kha.compute.ConstantLocation;
|
||||
static var voxel_cg5:kha.compute.ConstantLocation;
|
||||
#if rp_shadowmap
|
||||
static var voxel_tb5:kha.compute.TextureUnit;
|
||||
static var voxel_tc5:kha.compute.TextureUnit;
|
||||
static var voxel_td5:kha.compute.TextureUnit;
|
||||
static var voxel_ch5:kha.compute.ConstantLocation;
|
||||
static var voxel_ci5:kha.compute.ConstantLocation;
|
||||
static var voxel_cj5:kha.compute.ConstantLocation;
|
||||
static var voxel_ck5:kha.compute.ConstantLocation;
|
||||
#if lnx_shadowmap_atlas
|
||||
static var voxel_cl5:kha.compute.ConstantLocation;
|
||||
static var voxel_cm5:kha.compute.ConstantLocation;
|
||||
#end
|
||||
#end //rp_voxels
|
||||
#end
|
||||
#end //rp_voxels == "Voxel GI"
|
||||
#end //rp_voxels != "Off"
|
||||
|
||||
public static function init(_path: RenderPath) {
|
||||
path = _path;
|
||||
@ -440,33 +465,39 @@ class Inc {
|
||||
path.bindTarget(n, n);
|
||||
break;
|
||||
}
|
||||
for (i in 0...pointIndex) {
|
||||
var n = "shadowMapPoint[" + i + "]";
|
||||
path.bindTarget(n, n);
|
||||
var n = "shadowMapPointTransparent[" + i + "]";
|
||||
path.bindTarget(n, n);
|
||||
}
|
||||
for (i in 0...spotIndex) {
|
||||
var n = "shadowMapSpot[" + i + "]";
|
||||
path.bindTarget(n, n);
|
||||
var n = "shadowMapSpotTransparent[" + i + "]";
|
||||
path.bindTarget(n, n);
|
||||
var lightIndex = 0;
|
||||
for (l in iron.Scene.active.lights) {
|
||||
if (iron.object.LightObject.discardLightCulled(l)) continue;
|
||||
|
||||
if (l.data.raw.type == "point") {
|
||||
var n = "shadowMapPoint[" + lightIndex + "]";
|
||||
path.bindTarget(n, n);
|
||||
var n = "shadowMapPointTransparent[" + lightIndex + "]";
|
||||
path.bindTarget(n, n);
|
||||
}
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") {
|
||||
var n = "shadowMapSpot[" + lightIndex + "]";
|
||||
path.bindTarget(n, n);
|
||||
var n = "shadowMapSpotTransparent[" + lightIndex + "]";
|
||||
path.bindTarget(n, n);
|
||||
}
|
||||
lightIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
static function shadowMapName(light: LightObject, transparent: Bool): String {
|
||||
static function shadowMapName(light: LightObject, index: Int, transparent: Bool): String {
|
||||
switch (light.data.raw.type) {
|
||||
case "sun":
|
||||
return transparent ? "shadowMapTransparent" : "shadowMap";
|
||||
case "point":
|
||||
return transparent ? "shadowMapPointTransparent[" + pointIndex + "]" : "shadowMapPoint[" + pointIndex + "]";
|
||||
return transparent ? "shadowMapPointTransparent[" + index + "]" : "shadowMapPoint[" + index + "]";
|
||||
default:
|
||||
return transparent ? "shadowMapSpotTransparent[" + spotIndex + "]" : "shadowMapSpot[" + spotIndex + "]";
|
||||
return transparent ? "shadowMapSpotTransparent[" + index + "]" : "shadowMapSpot[" + index + "]";
|
||||
}
|
||||
}
|
||||
|
||||
static function getShadowMap(l: iron.object.LightObject, transparent: Bool): String {
|
||||
var target = shadowMapName(l, transparent);
|
||||
static function getShadowMap(l: iron.object.LightObject, index: Int, transparent: Bool): String {
|
||||
var target = shadowMapName(l, index, transparent);
|
||||
var rt = path.renderTargets.get(target);
|
||||
// Create shadowmap on the fly
|
||||
if (rt == null) {
|
||||
@ -509,13 +540,12 @@ class Inc {
|
||||
lastFrame = RenderPath.active.frame;
|
||||
#end
|
||||
|
||||
pointIndex = 0;
|
||||
spotIndex = 0;
|
||||
var lightIndex = 0;
|
||||
for (l in iron.Scene.active.lights) {
|
||||
if (!l.visible) continue;
|
||||
|
||||
path.light = l;
|
||||
var shadowmap = Inc.getShadowMap(l, false);
|
||||
var shadowmap = Inc.getShadowMap(l, lightIndex, false);
|
||||
var faces = l.data.raw.shadowmap_cube ? 6 : 1;
|
||||
for (i in 0...faces) {
|
||||
if (faces > 1) path.currentFace = i;
|
||||
@ -527,18 +557,18 @@ class Inc {
|
||||
}
|
||||
path.currentFace = -1;
|
||||
|
||||
if (l.data.raw.type == "point") pointIndex++;
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") spotIndex++;
|
||||
if (!iron.object.LightObject.discardLightCulled(l)) {
|
||||
lightIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
#if rp_shadowmap_transparent
|
||||
pointIndex = 0;
|
||||
spotIndex = 0;
|
||||
lightIndex = 0;
|
||||
for (l in iron.Scene.active.lights) {
|
||||
if (!l.visible) continue;
|
||||
|
||||
path.light = l;
|
||||
var shadowmap_transparent = Inc.getShadowMap(l, true);
|
||||
var shadowmap_transparent = Inc.getShadowMap(l, lightIndex, true);
|
||||
var faces = l.data.raw.shadowmap_cube ? 6 : 1;
|
||||
for (i in 0...faces) {
|
||||
if (faces > 1) path.currentFace = i;
|
||||
@ -550,8 +580,9 @@ class Inc {
|
||||
}
|
||||
path.currentFace = -1;
|
||||
|
||||
if (l.data.raw.type == "point") pointIndex++;
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") spotIndex++;
|
||||
if (!iron.object.LightObject.discardLightCulled(l)) {
|
||||
lightIndex++;
|
||||
}
|
||||
}
|
||||
#end
|
||||
#end // rp_shadowmap
|
||||
@ -606,6 +637,9 @@ class Inc {
|
||||
// Init voxels
|
||||
#if (rp_voxels != 'Off')
|
||||
if (!voxelsCreated) initGI();
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
initGI("voxelsLight");
|
||||
#end
|
||||
#end
|
||||
#end // lnx_config
|
||||
}
|
||||
@ -732,6 +766,12 @@ class Inc {
|
||||
t.height = res * Main.voxelgiClipmapCount;
|
||||
t.depth = res;
|
||||
}
|
||||
else if (t.name == "voxelsLight") {
|
||||
t.format = "RGBA32";
|
||||
t.width = res;
|
||||
t.height = res * Main.voxelgiClipmapCount;
|
||||
t.depth = res;
|
||||
}
|
||||
else {
|
||||
#if (rp_voxels == "Voxel AO")
|
||||
{
|
||||
@ -876,7 +916,8 @@ class Inc {
|
||||
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
voxel_td1 = voxel_sh1.getTextureUnit("voxelsSampler");
|
||||
voxel_te1 = voxel_sh1.getTextureUnit("SDF");
|
||||
voxel_te1 = voxel_sh1.getTextureUnit("voxelsLight");
|
||||
voxel_tf1 = voxel_sh1.getTextureUnit("SDF");
|
||||
voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength");
|
||||
#else
|
||||
#if lnx_voxelgi_shadows
|
||||
@ -949,6 +990,37 @@ class Inc {
|
||||
voxel_cc4 = voxel_sh4.getConstantLocation("eye");
|
||||
voxel_cd4 = voxel_sh4.getConstantLocation("postprocess_resolution");
|
||||
}
|
||||
if (voxel_sh5 == null)
|
||||
{
|
||||
voxel_sh5 = path.getComputeShader("voxel_light");
|
||||
voxel_ta5 = voxel_sh5.getTextureUnit("voxelsLight");
|
||||
voxel_te5 = voxel_sh5.getTextureUnit("voxels");
|
||||
voxel_tf5 = voxel_sh5.getTextureUnit("voxelsSampler");
|
||||
voxel_tg5 = voxel_sh5.getTextureUnit("voxelsSDFSampler");
|
||||
|
||||
voxel_ca5 = voxel_sh5.getConstantLocation("clipmaps");
|
||||
voxel_cb5 = voxel_sh5.getConstantLocation("clipmapLevel");
|
||||
|
||||
voxel_cc5 = voxel_sh5.getConstantLocation("lightPos");
|
||||
voxel_cd5 = voxel_sh5.getConstantLocation("lightColor");
|
||||
voxel_ce5 = voxel_sh5.getConstantLocation("lightType");
|
||||
voxel_cf5 = voxel_sh5.getConstantLocation("lightDir");
|
||||
voxel_cg5 = voxel_sh5.getConstantLocation("spotData");
|
||||
#if rp_shadowmap
|
||||
voxel_tb5 = voxel_sh5.getTextureUnit("shadowMap");
|
||||
voxel_tc5 = voxel_sh5.getTextureUnit("shadowMapSpot");
|
||||
voxel_td5 = voxel_sh5.getTextureUnit("shadowMapPoint");
|
||||
|
||||
voxel_ch5 = voxel_sh5.getConstantLocation("lightShadow");
|
||||
voxel_ci5 = voxel_sh5.getConstantLocation("lightProj");
|
||||
voxel_cj5 = voxel_sh5.getConstantLocation("LVP");
|
||||
voxel_ck5 = voxel_sh5.getConstantLocation("shadowsBias");
|
||||
#if lnx_shadowmap_atlas
|
||||
voxel_cl5 = voxel_sh5.getConstantLocation("index");
|
||||
voxel_cm5 = voxel_sh5.getConstantLocation("pointLightDataArray");
|
||||
#end
|
||||
#end
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
@ -998,7 +1070,8 @@ class Inc {
|
||||
kha.compute.Compute.setTexture(voxel_tc1, rts.get("voxelsOut").image, kha.compute.Access.Write);
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
kha.compute.Compute.setSampledTexture(voxel_td1, rts.get("voxelsOutB").image);
|
||||
kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsSDF").image, kha.compute.Access.Write);
|
||||
kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsLight").image, kha.compute.Access.Read);
|
||||
kha.compute.Compute.setTexture(voxel_tf1, rts.get("voxelsSDF").image, kha.compute.Access.Write);
|
||||
kha.compute.Compute.setFloat(voxel_cc1, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
|
||||
#else
|
||||
#if lnx_voxelgi_shadows
|
||||
@ -1270,6 +1343,7 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
|
||||
}
|
||||
#end
|
||||
|
||||
public static function resolveSpecular() {
|
||||
var rts = path.renderTargets;
|
||||
@ -1334,6 +1408,149 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
|
||||
}
|
||||
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
public static function computeVoxelsLight() {
|
||||
var rts = path.renderTargets;
|
||||
var res = iron.RenderPath.getVoxelRes();
|
||||
var camera = iron.Scene.active.camera;
|
||||
var clipmaps = iron.RenderPath.clipmaps;
|
||||
var clipmap = clipmaps[iron.RenderPath.clipmapLevel];
|
||||
var lights = iron.Scene.active.lights;
|
||||
|
||||
var lightIndex = 0;
|
||||
for (i in 0...lights.length) {
|
||||
var l = lights[i];
|
||||
if (!l.visible) continue;
|
||||
path.light = l;
|
||||
|
||||
kha.compute.Compute.setShader(voxel_sh5);
|
||||
|
||||
kha.compute.Compute.setTexture(voxel_ta5, rts.get("voxelsLight").image, kha.compute.Access.Write);
|
||||
kha.compute.Compute.setTexture(voxel_te5, rts.get("voxels").image, kha.compute.Access.Read);
|
||||
kha.compute.Compute.setSampledTexture(voxel_tf5, rts.get("voxelsOut").image);
|
||||
kha.compute.Compute.setSampledTexture(voxel_tg5, rts.get("voxelsSDF").image);
|
||||
|
||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||
for (i in 0...Main.voxelgiClipmapCount) {
|
||||
fa[i * 10] = clipmaps[i].voxelSize;
|
||||
fa[i * 10 + 1] = clipmaps[i].extents.x;
|
||||
fa[i * 10 + 2] = clipmaps[i].extents.y;
|
||||
fa[i * 10 + 3] = clipmaps[i].extents.z;
|
||||
fa[i * 10 + 4] = clipmaps[i].center.x;
|
||||
fa[i * 10 + 5] = clipmaps[i].center.y;
|
||||
fa[i * 10 + 6] = clipmaps[i].center.z;
|
||||
fa[i * 10 + 7] = clipmaps[i].offset_prev.x;
|
||||
fa[i * 10 + 8] = clipmaps[i].offset_prev.y;
|
||||
fa[i * 10 + 9] = clipmaps[i].offset_prev.z;
|
||||
}
|
||||
|
||||
kha.compute.Compute.setFloats(voxel_ca5, fa);
|
||||
|
||||
kha.compute.Compute.setInt(voxel_cb5, iron.RenderPath.clipmapLevel);
|
||||
|
||||
#if rp_shadowmap
|
||||
if (l.data.raw.type == "sun") {
|
||||
#if lnx_shadowmap_atlas
|
||||
#if lnx_shadowmap_atlas_single_map
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb5, rts.get("shadowMapAtlas").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb5, rts.get("shadowMapAtlasSun").image);
|
||||
#end
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb5, rts.get("shadowMap").image);
|
||||
#end
|
||||
kha.compute.Compute.setInt(voxel_ch5, 1); // lightShadow
|
||||
}
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") {
|
||||
#if lnx_shadowmap_atlas
|
||||
#if lnx_shadowmap_atlas_single_map
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc5, rts.get("shadowMapAtlas").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc5, rts.get("shadowMapAtlasSpot").image);
|
||||
#end
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc5, rts.get("shadowMapSpot[" + lightIndex + "]").image);
|
||||
#end
|
||||
kha.compute.Compute.setInt(voxel_ch5, 2);
|
||||
}
|
||||
else {
|
||||
#if lnx_shadowmap_atlas
|
||||
#if lnx_shadowmap_atlas_single_map
|
||||
kha.compute.Compute.setSampledTexture(voxel_td5, rts.get("shadowMapAtlas").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_td5, rts.get("shadowMapAtlasPoint").image);
|
||||
kha.compute.Compute.setInt(voxel_cl5, i);
|
||||
kha.compute.Compute.setFloats(voxel_cm5, iron.object.LightObject.pointLightsData);
|
||||
#end
|
||||
#else
|
||||
kha.compute.Compute.setSampledCubeMap(voxel_td5, rts.get("shadowMapPoint[" + lightIndex + "]").cubeMap);
|
||||
#end
|
||||
kha.compute.Compute.setInt(voxel_ch5, 3);
|
||||
}
|
||||
|
||||
// lightProj
|
||||
var near = l.data.raw.near_plane;
|
||||
var far = l.data.raw.far_plane;
|
||||
var a:kha.FastFloat = far + near;
|
||||
var b:kha.FastFloat = far - near;
|
||||
var f2:kha.FastFloat = 2.0;
|
||||
var c:kha.FastFloat = f2 * far * near;
|
||||
var vx:kha.FastFloat = a / b;
|
||||
var vy:kha.FastFloat = c / b;
|
||||
kha.compute.Compute.setFloat2(voxel_ci5, vx, vy);
|
||||
// LVP
|
||||
m.setFrom(l.VP);
|
||||
m.multmat(iron.object.Uniforms.biasMat);
|
||||
#if lnx_shadowmap_atlas
|
||||
if (l.data.raw.type == "sun")
|
||||
{
|
||||
// tile matrix
|
||||
m.setIdentity();
|
||||
// scale [0-1] coords to [0-tilescale]
|
||||
m._00 = l.tileScale[0];
|
||||
m._11 = l.tileScale[0];
|
||||
// offset coordinate start from [0, 0] to [tile-start-x, tile-start-y]
|
||||
m._30 = l.tileOffsetX[0];
|
||||
m._31 = l.tileOffsetY[0];
|
||||
m.multmat(m);
|
||||
#if (!kha_opengl)
|
||||
m.setIdentity();
|
||||
m._11 = -1.0;
|
||||
m._31 = 1.0;
|
||||
m.multmat(m);
|
||||
#end
|
||||
}
|
||||
#end
|
||||
kha.compute.Compute.setMatrix(voxel_cj5, m.self);
|
||||
// shadowsBias
|
||||
kha.compute.Compute.setFloat(voxel_ck5, l.data.raw.shadows_bias);
|
||||
#end // rp_shadowmap
|
||||
|
||||
// lightPos
|
||||
kha.compute.Compute.setFloat3(voxel_cc5, l.transform.worldx(), l.transform.worldy(), l.transform.worldz());
|
||||
// lightCol
|
||||
var f = l.data.raw.strength;
|
||||
kha.compute.Compute.setFloat3(voxel_cd5, l.data.raw.color[0] * f, l.data.raw.color[1] * f, l.data.raw.color[2] * f);
|
||||
// lightType
|
||||
kha.compute.Compute.setInt(voxel_ce5, iron.data.LightData.typeToInt(l.data.raw.type));
|
||||
// lightDir
|
||||
var v = l.look();
|
||||
kha.compute.Compute.setFloat3(voxel_cf5, v.x, v.y, v.z);
|
||||
// spotData
|
||||
if (l.data.raw.type == "spot") {
|
||||
var vx = l.data.raw.spot_size;
|
||||
var vy = vx - l.data.raw.spot_blend;
|
||||
kha.compute.Compute.setFloat2(voxel_cg5, vx, vy);
|
||||
}
|
||||
|
||||
kha.compute.Compute.compute(Std.int(res / 8), Std.int(res / 8), Std.int(res / 8));
|
||||
|
||||
if (!iron.object.LightObject.discardLightCulled(l)) {
|
||||
lightIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#end // GI
|
||||
#end // Voxels
|
||||
}
|
||||
|
||||
@ -342,12 +342,6 @@ class Postprocess {
|
||||
v.x = ssao_uniforms[0]; //SSAO Strength
|
||||
v.y = ssao_uniforms[1]; //SSAO Radius
|
||||
v.z = ssao_uniforms[2]; //SSAO Max Steps
|
||||
case "_PPComp13":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
||||
v.y = chromatic_aberration_uniforms[1]; //CA Samples
|
||||
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
|
||||
@ -377,6 +371,12 @@ class Postprocess {
|
||||
v.y = letterbox_uniforms[0][1];
|
||||
v.z = letterbox_uniforms[0][2];
|
||||
v.w = letterbox_uniforms[1][0]; //Size
|
||||
case "_PPComp13":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
||||
v.y = chromatic_aberration_uniforms[1]; //CA Samples
|
||||
v.z = chromatic_aberration_uniforms[2]; //CA Type
|
||||
v.w = chromatic_aberration_uniforms[3]; //On/Off
|
||||
case "_PPComp16":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = sharpen_uniforms[0][0]; //Color
|
||||
|
||||
@ -712,6 +712,7 @@ class RenderPathDeferred {
|
||||
Inc.computeVoxelsTemporal();
|
||||
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
Inc.computeVoxelsLight();
|
||||
Inc.computeVoxelsSDF();
|
||||
#end
|
||||
|
||||
|
||||
@ -448,6 +448,10 @@ class RenderPathForward {
|
||||
|
||||
Inc.computeVoxelsTemporal();
|
||||
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
Inc.computeVoxelsLight();
|
||||
#end
|
||||
|
||||
#if (lnx_voxelgi_shadows || (rp_voxels == "Voxel GI"))
|
||||
Inc.computeVoxelsSDF();
|
||||
#end
|
||||
|
||||
@ -27,7 +27,7 @@ class Signal {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
public function isConnected(callBack: Function):Bool {
|
||||
public function isConnected(callBack: Function): Bool {
|
||||
return callbacks.contains(callBack);
|
||||
}
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ class Starter {
|
||||
#if lnx_patch
|
||||
iron.Scene.getRenderPath = getRenderPath;
|
||||
#end
|
||||
#if lnx_draworder_shader
|
||||
#if lnx_draworder_index
|
||||
iron.RenderPath.active.drawOrder = iron.RenderPath.DrawOrder.Index;
|
||||
#end // else Distance
|
||||
});
|
||||
|
||||
60
leenkx/Sources/leenkx/system/Timer.hx
Normal file
60
leenkx/Sources/leenkx/system/Timer.hx
Normal file
@ -0,0 +1,60 @@
|
||||
package leenkx.system;
|
||||
|
||||
import iron.App;
|
||||
import iron.system.Time;
|
||||
|
||||
class Timer {
|
||||
public var timeout: Signal = new Signal();
|
||||
|
||||
public var oneShot: Bool = true;
|
||||
public var paused: Bool = true;
|
||||
public var timeLeft: Float = 1.0;
|
||||
public var waitTime: Float = 1.0;
|
||||
|
||||
public function new(time: Float = 1.0, oneShot: Bool = true) {
|
||||
this.oneShot = oneShot;
|
||||
this.waitTime = time;
|
||||
this.timeLeft = time;
|
||||
}
|
||||
|
||||
public function start(time: Float = -1.0) {
|
||||
if (isStopped()) App.notifyOnUpdate(update);
|
||||
if (time > 0) {
|
||||
waitTime = time;
|
||||
}
|
||||
timeLeft = waitTime;
|
||||
paused = false;
|
||||
}
|
||||
|
||||
public function pause() {
|
||||
paused = true;
|
||||
}
|
||||
|
||||
public function stop() {
|
||||
if (!isStopped()) App.removeUpdate(update);
|
||||
paused = true;
|
||||
timeLeft = waitTime;
|
||||
}
|
||||
|
||||
public function isStopped(): Bool {
|
||||
return paused && timeLeft == waitTime;
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (paused) return;
|
||||
|
||||
timeLeft -= Time.delta;
|
||||
|
||||
if (timeLeft <= 0) {
|
||||
timeout.emit();
|
||||
|
||||
if (oneShot) {
|
||||
paused = true;
|
||||
timeLeft = waitTime;
|
||||
App.removeUpdate(update);
|
||||
} else {
|
||||
timeLeft += waitTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,11 +86,14 @@ class FirstPersonController extends Trait {
|
||||
|
||||
var zVec = Vec4.zAxis();
|
||||
|
||||
// Control de la rotacion del jugador y la camara con el mouse..
|
||||
// Control player and camera rotation with the mouse.
|
||||
function preUpdate() {
|
||||
if (Input.occupied || body == null) return;
|
||||
var mouse = Input.getMouse();
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
// Blooquear/Desbloquear cursor // lock/unlock cursor
|
||||
if (mouse.started() && !mouse.locked)
|
||||
mouse.lock();
|
||||
else if (kb.started("escape") && mouse.locked)
|
||||
@ -113,6 +116,7 @@ class FirstPersonController extends Trait {
|
||||
return enableFatigue && isFatigueActive;
|
||||
}
|
||||
|
||||
// Comprobar si el jugador esta moviendose y si esta en el suelo // Check if the player is moving and if he is on the ground...
|
||||
function update() {
|
||||
if (body == null) return;
|
||||
var deltaTime:Float = iron.system.Time.delta;
|
||||
@ -132,14 +136,15 @@ class FirstPersonController extends Trait {
|
||||
}
|
||||
#end
|
||||
|
||||
// Dejo establecido el salto para tener en cuenta la (enableFatigue) si es que es false/true....
|
||||
// Dejo establecido el salto para tener en cuenta (isFatigued)
|
||||
// I set the jump to take into account the (isFatigued)
|
||||
if (isGrounded && !isFatigued()) {
|
||||
canJump = true;
|
||||
}
|
||||
// Saltar con estamina
|
||||
// Saltar con estamina // Jump with stamina
|
||||
if (enableJump && kb.started(jumpKey) && canJump) {
|
||||
var jumpPower = jumpForce;
|
||||
// Disminuir el salto al 50% si la (stamina) esta por debajo o en el 20%.
|
||||
// Disminuir el salto al 50% si la (stamina) esta por debajo o en el 20%. // Decrease jump to 50% if stamina is below or at 20%
|
||||
if (stamina) {
|
||||
if (staminaValue <= 0) {
|
||||
jumpPower = 0;
|
||||
@ -158,7 +163,7 @@ class FirstPersonController extends Trait {
|
||||
}
|
||||
}
|
||||
|
||||
// Control de estamina y correr
|
||||
// Control de estamina y correr // Control of stamina and running
|
||||
if (canRun && kb.down(runKey) && isMoving) {
|
||||
if (stamina) {
|
||||
if (staminaValue > 0.0) {
|
||||
@ -175,7 +180,7 @@ class FirstPersonController extends Trait {
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
// (temporizadores aparte)
|
||||
// (temporizadores aparte) (fatigue system timers)
|
||||
if (isRunning) {
|
||||
timeSinceStop = 0.0;
|
||||
fatigueTimer += deltaTime;
|
||||
@ -185,24 +190,25 @@ class FirstPersonController extends Trait {
|
||||
fatigueCooldown += deltaTime;
|
||||
}
|
||||
|
||||
// Evitar correr y saltar al estar fatigado...
|
||||
// Evitar correr y saltar al estar fatigado // Avoid running and jumping when fatigued
|
||||
if (isFatigued()) {
|
||||
isRunning = false;
|
||||
canJump = false;
|
||||
isRunning = false;
|
||||
canJump = false;
|
||||
}
|
||||
|
||||
// Activar fatiga despues de correr continuamente durante cierto umbral
|
||||
// Activate fatigue after running continuously for a certain threshold
|
||||
if (enableFatigue && fatigueTimer >= fatigueThreshold) {
|
||||
isFatigueActive = true;
|
||||
}
|
||||
|
||||
// Eliminar la fatiga despues de recuperarse
|
||||
// Eliminar la fatiga despues de recuperarse // Eliminate fatigue after recovery (fatRecoveryThreshold)
|
||||
if (enableFatigue && isFatigueActive && fatigueCooldown >= fatRecoveryThreshold) {
|
||||
isFatigueActive = false;
|
||||
fatigueTimer = 0.0;
|
||||
}
|
||||
|
||||
// Recuperar estamina si no esta corriendo
|
||||
// Recuperar estamina si no esta corriendo // Recover stamina if you re not running ()
|
||||
if (stamina && !isRunning && staminaValue < staminaBase && !isFatigued()) {
|
||||
if (timeSinceStop >= staRecoverTime) {
|
||||
staminaValue += staRecoverPerSec * deltaTime;
|
||||
@ -210,7 +216,7 @@ class FirstPersonController extends Trait {
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento ejes (local)
|
||||
// Movimiento en ejes locales // Movement on local axies
|
||||
dir.set(0, 0, 0);
|
||||
if (moveForward) dir.add(object.transform.look());
|
||||
if (moveBackward) dir.add(object.transform.look().mult(-1));
|
||||
@ -220,6 +226,7 @@ class FirstPersonController extends Trait {
|
||||
var btvec = body.getLinearVelocity();
|
||||
body.setLinearVelocity(0.0, 0.0, btvec.z - 1.0);
|
||||
|
||||
// Movement speed control (final) (run and fatigued when are true/false)
|
||||
if (isMoving) {
|
||||
var dirN = dir.normalize();
|
||||
var baseSpeed = moveSpeed;
|
||||
|
||||
278
leenkx/Sources/leenkx/trait/OverheadPersonController.hx
Normal file
278
leenkx/Sources/leenkx/trait/OverheadPersonController.hx
Normal file
@ -0,0 +1,278 @@
|
||||
package leenkx.trait;
|
||||
|
||||
import iron.Trait;
|
||||
import iron.math.Vec4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.CameraObject;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
import leenkx.trait.physics.RigidBody;
|
||||
import kha.System;
|
||||
|
||||
class OverheadPersonController extends Trait {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
// Nota: Dejo establecido que el eje (+Y) sera considerada la "cara" del personaje
|
||||
// I established that the axis (+Y) will be considered the "face" of the character.
|
||||
// Camara
|
||||
@prop public var cameraFollow:CameraObject;
|
||||
@prop public var smoothTrack:Bool = false;
|
||||
@prop public var smoothSpeed:Float = 5.0;
|
||||
|
||||
@prop public var enableJump:Bool = true;
|
||||
@prop public var jumpForce:Float = 22.0;
|
||||
@prop public var moveSpeed:Float = 500.0;
|
||||
@prop public var forwardKey:String = "w";
|
||||
@prop public var backwardKey:String = "s";
|
||||
@prop public var leftKey:String = "a";
|
||||
@prop public var rightKey:String = "d";
|
||||
@prop public var jumpKey:String = "space";
|
||||
@prop public var allowAirJump:Bool = false;
|
||||
@prop public var canRun:Bool = true;
|
||||
@prop public var runKey:String = "shift";
|
||||
@prop public var runSpeed:Float = 1000.0;
|
||||
|
||||
// Sistema de estamina
|
||||
@prop public var stamina:Bool = false;
|
||||
@prop public var staminaBase:Float = 75.0;
|
||||
@prop public var staRecoverPerSec:Float = 5.0;
|
||||
@prop public var staDecreasePerSec:Float = 5.0;
|
||||
@prop public var staRecoverTime:Float = 2.0;
|
||||
@prop public var staDecreasePerJump:Float = 5.0;
|
||||
@prop public var enableFatigue:Bool = false;
|
||||
@prop public var fatigueSpeed:Float = 0.5; // the reduction of movement when fatigue is activated... // reduccion de movimiento con la fatiga activada
|
||||
@prop public var fatigueThreshold:Float = 30.0; // Tiempo corriendo sin parar para la activacion // Time running non-stop for activation...
|
||||
@prop public var fatRecoveryThreshold:Float = 7.5; // Tiempo sin correr/saltar para salir de fatiga // Time without running/jumping to get rid of fatigue...
|
||||
|
||||
// Variables privadas
|
||||
var body:RigidBody;
|
||||
|
||||
// var de la camara (camera vars)
|
||||
var initialCameraLoc:Vec4;
|
||||
var initialOffset:Vec4;
|
||||
var currentPos:Vec4;
|
||||
|
||||
var moveForward:Bool = false;
|
||||
var moveBackward:Bool = false;
|
||||
var moveLeft:Bool = false;
|
||||
var moveRight:Bool = false;
|
||||
var isRunning:Bool = false;
|
||||
var canJump:Bool = true;
|
||||
var staminaValue:Float = 0.0;
|
||||
var timeSinceStop:Float = 0.0;
|
||||
var fatigueTimer:Float = 0.0;
|
||||
var fatigueCooldown:Float = 0.0;
|
||||
var isFatigueActive:Bool = false;
|
||||
|
||||
var dir:Vec4 = new Vec4();
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
iron.Scene.active.notifyOnInit(init);
|
||||
}
|
||||
|
||||
// Ajustes para la camara y la rotaicon del "jugador"
|
||||
// Settings for the camera and the "player" rotation
|
||||
|
||||
function init() {
|
||||
body = object.getTrait(RigidBody);
|
||||
|
||||
if (cameraFollow == null) {
|
||||
// Alertar al usuario en caso de no asignar una camara. // Alert the user if a camera is not assigned
|
||||
trace("[OverheadCameraController] a camera was not assigned to 'cameraFollow'.");
|
||||
} else {
|
||||
// Guardar la posicion inicial de la camara // Save the initial position of the camera
|
||||
initialCameraLoc = cameraFollow.transform.loc.clone();
|
||||
// Calcular el offset relativo al jugador // Calculate the offset relative to the player
|
||||
initialOffset = initialCameraLoc.sub(object.transform.loc);
|
||||
currentPos = initialCameraLoc.clone();
|
||||
}
|
||||
|
||||
PhysicsWorld.active.notifyOnPreUpdate(preUpdate);
|
||||
notifyOnUpdate(update);
|
||||
notifyOnRemove(removed);
|
||||
staminaValue = staminaBase;
|
||||
}
|
||||
|
||||
function removed() {
|
||||
PhysicsWorld.active.removePreUpdate(preUpdate);
|
||||
}
|
||||
|
||||
function preUpdate() {
|
||||
if (Input.occupied || body == null) return;
|
||||
var mouse = Input.getMouse();
|
||||
|
||||
var screenW = System.windowWidth();
|
||||
var screenH = System.windowHeight();
|
||||
|
||||
// Posicion relativa del mouse respecto al centro de la pantalla
|
||||
// Relative position of the mouse with respect to the center of the screen
|
||||
var mouseXRel = mouse.x - screenW / 2;
|
||||
var mouseYRel = mouse.y - screenH / 2;
|
||||
|
||||
// Angulo 360° usando atan2 (invertido para corregir direccion) // 360° angle using atan2 (inverted to correct direction)
|
||||
var angleZ = -Math.atan2(mouseXRel, -mouseYRel);
|
||||
object.transform.setRotation(object.transform.rot.x, object.transform.rot.y, angleZ);
|
||||
|
||||
body.syncTransform();
|
||||
|
||||
// Camara siguiendo al jugador (manteniendo offset inicial) // Camera following the player (maintaining initial offset)
|
||||
if (cameraFollow != null) {
|
||||
var playerPos = object.transform.loc;
|
||||
var targetPos = new Vec4(
|
||||
playerPos.x + initialOffset.x,
|
||||
playerPos.y + initialOffset.y,
|
||||
playerPos.z + initialOffset.z,
|
||||
1 // w 1 (posicion absoluta)
|
||||
// used w=1 to indicate that the camera position is an absolute point in the world...
|
||||
);
|
||||
|
||||
// Mover la camara a 'targetPos' de forma gradual o instantanea si 'smoothTrack' es false
|
||||
// Moves the camera to 'targetPos' gradually or instantly if 'smoothTrack' is false
|
||||
if (smoothTrack) {
|
||||
var delta = targetPos.sub(currentPos);
|
||||
var moveStep = delta.mult(smoothSpeed * iron.system.Time.delta);
|
||||
if (moveStep.length() > delta.length()) moveStep = delta;
|
||||
currentPos = currentPos.add(moveStep);
|
||||
cameraFollow.transform.loc.setFrom(currentPos);
|
||||
} else {
|
||||
currentPos = targetPos.clone();
|
||||
cameraFollow.transform.loc.setFrom(currentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isFatigued():Bool {
|
||||
return enableFatigue && isFatigueActive;
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (body == null) return;
|
||||
var deltaTime:Float = iron.system.Time.delta;
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
moveForward = kb.down(forwardKey);
|
||||
moveBackward = kb.down(backwardKey);
|
||||
moveLeft = kb.down(leftKey);
|
||||
moveRight = kb.down(rightKey);
|
||||
var isMoving = moveForward || moveBackward || moveLeft || moveRight;
|
||||
|
||||
var isGrounded:Bool = false;
|
||||
#if lnx_physics
|
||||
var vel = body.getLinearVelocity();
|
||||
if (Math.abs(vel.z) < 0.1) isGrounded = true;
|
||||
#end
|
||||
|
||||
// Dejo establecido el salto para tener en cuenta (isFatigued)
|
||||
// I set the jump to take into account the (isFatigued)
|
||||
if (isGrounded && !isFatigued()) {
|
||||
canJump = true;
|
||||
}
|
||||
// Saltar con estamina // Jump with stamina
|
||||
if (enableJump && kb.started(jumpKey) && canJump) {
|
||||
var jumpPower = jumpForce;
|
||||
// Disminuir el salto al 50% si la (stamina) esta por debajo o en el 20%. // Decrease jump to 50% if stamina is below or at 20%
|
||||
if (stamina) {
|
||||
if (staminaValue <= 0) {
|
||||
jumpPower = 0;
|
||||
} else if (staminaValue <= staminaBase * 0.2) {
|
||||
jumpPower *= 0.5;
|
||||
}
|
||||
|
||||
staminaValue -= staDecreasePerJump;
|
||||
if (staminaValue < 0.0) staminaValue = 0.0;
|
||||
timeSinceStop = 0.0;
|
||||
}
|
||||
|
||||
if (jumpPower > 0) {
|
||||
body.applyImpulse(new Vec4(0, 0, jumpPower));
|
||||
if (!allowAirJump) canJump = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Control de estamina y correr // Control of stamina and running
|
||||
if (canRun && kb.down(runKey) && isMoving) {
|
||||
if (stamina) {
|
||||
if (staminaValue > 0.0) {
|
||||
isRunning = true;
|
||||
staminaValue -= staDecreasePerSec * deltaTime;
|
||||
if (staminaValue < 0.0) staminaValue = 0.0;
|
||||
} else {
|
||||
isRunning = false;
|
||||
}
|
||||
} else {
|
||||
isRunning = true;
|
||||
}
|
||||
} else {
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
// (temporizadores aparte) (fatigue system timers)
|
||||
if (isRunning) {
|
||||
timeSinceStop = 0.0;
|
||||
fatigueTimer += deltaTime;
|
||||
fatigueCooldown = 0.0;
|
||||
} else {
|
||||
timeSinceStop += deltaTime;
|
||||
fatigueCooldown += deltaTime;
|
||||
}
|
||||
|
||||
// Evitar correr y saltar al estar fatigado // Avoid running and jumping when fatigued
|
||||
if (isFatigued()) {
|
||||
isRunning = false;
|
||||
canJump = false;
|
||||
}
|
||||
|
||||
// Activar fatiga despues de correr continuamente durante cierto umbral
|
||||
// Activate fatigue after running continuously for a certain threshold
|
||||
if (enableFatigue && fatigueTimer >= fatigueThreshold) {
|
||||
isFatigueActive = true;
|
||||
}
|
||||
|
||||
// Eliminar la fatiga despues de recuperarse // Eliminate fatigue after recovery (fatRecoveryThreshold)
|
||||
if (enableFatigue && isFatigueActive && fatigueCooldown >= fatRecoveryThreshold) {
|
||||
isFatigueActive = false;
|
||||
fatigueTimer = 0.0;
|
||||
}
|
||||
|
||||
// Recuperar estamina si no esta corriendo // Recover stamina if you re not running ()
|
||||
if (stamina && !isRunning && staminaValue < staminaBase && !isFatigued()) {
|
||||
if (timeSinceStop >= staRecoverTime) {
|
||||
staminaValue += staRecoverPerSec * deltaTime;
|
||||
if (staminaValue > staminaBase) staminaValue = staminaBase;
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento en ejes globales // Movement on global axies
|
||||
dir.set(0,0,0);
|
||||
if (moveForward) dir.add(new Vec4(0, 1, 0, 0));
|
||||
if (moveBackward) dir.add(new Vec4(0,-1, 0, 0));
|
||||
if (moveRight) dir.add(new Vec4(1, 0, 0, 0));
|
||||
if (moveLeft) dir.add(new Vec4(-1,0, 0, 0));
|
||||
|
||||
var btvec = body.getLinearVelocity();
|
||||
body.setLinearVelocity(0.0, 0.0, btvec.z - 1.0);
|
||||
|
||||
// Movement speed control (final) (run and fatigued when are true/false)
|
||||
if (dir.length() > 0) {
|
||||
var dirN = dir.normalize();
|
||||
var baseSpeed = moveSpeed;
|
||||
if (isRunning) baseSpeed = runSpeed;
|
||||
var currentSpeed = isFatigued() ? baseSpeed * fatigueSpeed : baseSpeed;
|
||||
dirN.mult(currentSpeed * deltaTime);
|
||||
body.activate();
|
||||
body.setLinearVelocity(dirN.x, dirN.y, btvec.z - 1.0);
|
||||
}
|
||||
|
||||
body.setAngularFactor(0,0,0);
|
||||
if (cameraFollow != null) cameraFollow.buildMatrix();
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
// Stamina and fatigue system.....
|
||||
@ -6,60 +6,91 @@ import iron.Trait;
|
||||
import iron.object.MeshObject;
|
||||
import iron.data.MeshData;
|
||||
import iron.data.SceneFormat;
|
||||
#if lnx_bullet
|
||||
import leenkx.trait.physics.bullet.RigidBody;
|
||||
#if (lnx_bullet || lnx_oimo)
|
||||
import leenkx.trait.physics.RigidBody;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
#end
|
||||
|
||||
class PhysicsBreak extends Trait {
|
||||
|
||||
#if (!lnx_bullet)
|
||||
#if (!lnx_bullet && !lnx_oimo)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static var physics: PhysicsWorld = null;
|
||||
static var breaker: ConvexBreaker = null;
|
||||
// Track all debris for cleanup on scene change
|
||||
static var allDebris: Array<MeshObject> = [];
|
||||
static var sceneCallbackRegistered = false;
|
||||
|
||||
var breaker: ConvexBreaker;
|
||||
var physics: PhysicsWorld;
|
||||
var body: RigidBody;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
if (breaker == null) breaker = new ConvexBreaker();
|
||||
breaker = new ConvexBreaker();
|
||||
notifyOnInit(init);
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (physics == null) physics = leenkx.trait.physics.PhysicsWorld.active;
|
||||
physics = leenkx.trait.physics.PhysicsWorld.active;
|
||||
if (physics == null) return;
|
||||
|
||||
body = object.getTrait(RigidBody);
|
||||
breaker.initBreakableObject(cast object, body.mass, body.friction, new Vec4(), new Vec4(), true);
|
||||
|
||||
// Register scene removal callback once
|
||||
if (!sceneCallbackRegistered) {
|
||||
sceneCallbackRegistered = true;
|
||||
iron.Scene.active.notifyOnRemove(cleanupAllDebris);
|
||||
}
|
||||
|
||||
notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
static function cleanupAllDebris() {
|
||||
// Make a copy since remove() modifies the array
|
||||
var toRemove = allDebris.copy();
|
||||
for (debris in toRemove) {
|
||||
if (debris != null) debris.remove();
|
||||
}
|
||||
allDebris = [];
|
||||
sceneCallbackRegistered = false;
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (body == null || !body.ready || physics == null) return;
|
||||
|
||||
var ar = physics.getContactPairs(body);
|
||||
if (ar != null) {
|
||||
var maxImpulse = 0.0;
|
||||
var maxImpulse: Float = 0.0;
|
||||
var impactPoint: Vec4 = null;
|
||||
var impactNormal: Vec4 = null;
|
||||
for (p in ar) {
|
||||
if (maxImpulse < p.impulse) {
|
||||
maxImpulse = p.impulse;
|
||||
impactPoint = p.posB;
|
||||
#if lnx_bullet
|
||||
impactNormal = p.normOnB;
|
||||
#elseif lnx_oimo
|
||||
impactNormal = p.nor;
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
#if lnx_bullet
|
||||
var fractureImpulse = 4.0;
|
||||
if (maxImpulse > fractureImpulse) {
|
||||
#elseif lnx_oimo
|
||||
var fractureImpulse = 1.0;
|
||||
#end
|
||||
if (maxImpulse > fractureImpulse && impactPoint != null && impactNormal != null) {
|
||||
var radialIter = 1;
|
||||
var randIter = 1;
|
||||
var debris = breaker.subdivideByImpact(cast object, impactPoint, impactNormal, radialIter, randIter);
|
||||
// var numObjects = debris.length;
|
||||
for (o in debris) {
|
||||
var ud = breaker.userDataMap.get(cast o);
|
||||
if (ud == null) continue;
|
||||
var params: RigidBodyParams = {
|
||||
linearDamping: 0.04,
|
||||
angularDamping: 0.1,
|
||||
@ -72,7 +103,7 @@ class PhysicsBreak extends Trait {
|
||||
angularFactorsZ: 1.0,
|
||||
collisionMargin: 0.04,
|
||||
linearDeactivationThreshold: 0.0,
|
||||
angularDeactivationThrshold: 0.0,
|
||||
angularDeactivationThreshold: 0.0,
|
||||
deactivationTime: 0.0,
|
||||
linearVelocityMin: 0.0,
|
||||
linearVelocityMax: 0.0,
|
||||
@ -89,7 +120,12 @@ class PhysicsBreak extends Trait {
|
||||
if (cast(o, MeshObject).data.geom.positions.values.length < 600) {
|
||||
o.addTrait(new PhysicsBreak());
|
||||
}
|
||||
// Track debris for cleanup on scene change
|
||||
allDebris.push(cast o);
|
||||
}
|
||||
|
||||
// Remove self from update before removing object
|
||||
remove();
|
||||
object.remove();
|
||||
}
|
||||
}
|
||||
@ -485,22 +521,26 @@ class ConvexBreaker {
|
||||
var numObjects = 0;
|
||||
if (numPoints1 > 4) {
|
||||
var data1 = makeMeshData(points1);
|
||||
object1 = new MeshObject(data1, object.materials);
|
||||
object1.transform.loc.setFrom(tempCM1);
|
||||
object1.transform.rot.setFrom(object.transform.rot);
|
||||
object1.transform.buildMatrix();
|
||||
initBreakableObject(object1, newMass, userData.friction, userData.velocity, userData.angularVelocity, 2 * radius1 > minSizeForBreak);
|
||||
numObjects++;
|
||||
if (data1 != null) {
|
||||
object1 = new MeshObject(data1, object.materials);
|
||||
object1.transform.loc.setFrom(tempCM1);
|
||||
object1.transform.rot.setFrom(object.transform.rot);
|
||||
object1.transform.buildMatrix();
|
||||
initBreakableObject(object1, newMass, userData.friction, userData.velocity, userData.angularVelocity, 2 * radius1 > minSizeForBreak);
|
||||
numObjects++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numPoints2 > 4) {
|
||||
var data2 = makeMeshData(points2);
|
||||
object2 = new MeshObject(data2, object.materials);
|
||||
object2.transform.loc.setFrom(tempCM2);
|
||||
object2.transform.rot.setFrom(object.transform.rot);
|
||||
object2.transform.buildMatrix();
|
||||
initBreakableObject(object2, newMass, userData.friction, userData.velocity, userData.angularVelocity, 2 * radius2 > minSizeForBreak);
|
||||
numObjects++;
|
||||
if (data2 != null) {
|
||||
object2 = new MeshObject(data2, object.materials);
|
||||
object2.transform.loc.setFrom(tempCM2);
|
||||
object2.transform.rot.setFrom(object.transform.rot);
|
||||
object2.transform.buildMatrix();
|
||||
initBreakableObject(object2, newMass, userData.friction, userData.velocity, userData.angularVelocity, 2 * radius2 > minSizeForBreak);
|
||||
numObjects++;
|
||||
}
|
||||
}
|
||||
|
||||
output.object1 = object1;
|
||||
@ -510,9 +550,15 @@ class ConvexBreaker {
|
||||
|
||||
static var meshIndex = 0;
|
||||
function makeMeshData(points: Array<Vec4>): MeshData {
|
||||
// Need at least 4 points for a 3D hull
|
||||
if (points.length < 4) return null;
|
||||
|
||||
while (points.length > 50) points.pop();
|
||||
var cm = new ConvexHull(points);
|
||||
|
||||
// Validate hull has enough geometry for a mesh
|
||||
if (cm.vertices.length < 4 || cm.face3s.length < 4) return null;
|
||||
|
||||
var maxdim = 1.0;
|
||||
var pa = new Array<Float>();
|
||||
var na = new Array<Float>();
|
||||
|
||||
@ -271,7 +271,7 @@ class DebugConsole extends Trait {
|
||||
|
||||
if (ui.tab(htab, "Scene")) {
|
||||
|
||||
if (ui.panel(Id.handle({selected: true}), "Outliner: obj.uid_obj.name")) {
|
||||
if (ui.panel(Id.handle({selected: true}), "Outliner: [ obj.uid ] : obj.name")) {
|
||||
ui.indent();
|
||||
ui._y -= ui.ELEMENT_OFFSET();
|
||||
|
||||
@ -282,9 +282,9 @@ class DebugConsole extends Trait {
|
||||
var _y = ui._y;
|
||||
|
||||
if (object.parent.name == 'Root' && object.raw == null)
|
||||
ui.text(object.uid+'_'+object.name+' ('+iron.Scene.active.raw.world_ref+')');
|
||||
ui.text('[ '+object.uid+' ] : '+object.name+' ( '+iron.Scene.active.raw.world_ref+' )');
|
||||
else
|
||||
ui.text(object.uid+'_'+object.name);
|
||||
ui.text('[ '+object.uid+' ] : '+object.name);
|
||||
|
||||
if (object == iron.Scene.active.camera) {
|
||||
var tagWidth = 100;
|
||||
|
||||
@ -3,7 +3,7 @@ package leenkx.trait.physics;
|
||||
#if (!lnx_physics)
|
||||
|
||||
class PhysicsConstraint extends iron.Trait { public function new() { super(); } }
|
||||
@:enum abstract ConstraintAxis(Int) from Int to Int { }
|
||||
enum abstract ConstraintAxis(Int) from Int to Int { }
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@ -3,19 +3,22 @@ package leenkx.trait.physics;
|
||||
#if (!lnx_physics)
|
||||
|
||||
class RigidBody extends iron.Trait { public function new() { super(); } }
|
||||
@:enum abstract Shape(Int) from Int to Int { }
|
||||
enum abstract Shape(Int) from Int to Int { }
|
||||
|
||||
#else
|
||||
|
||||
#if lnx_bullet
|
||||
typedef RigidBody = leenkx.trait.physics.bullet.RigidBody;
|
||||
typedef Shape = leenkx.trait.physics.bullet.RigidBody.Shape;
|
||||
typedef RigidBodyParams = leenkx.trait.physics.bullet.RigidBody.RigidBodyParams;
|
||||
#elseif lnx_jolt
|
||||
typedef RigidBody = leenkx.trait.physics.jolt.RigidBody;
|
||||
typedef Shape = leenkx.trait.physics.jolt.RigidBody.Shape;
|
||||
typedef RigidBodyParams = leenkx.trait.physics.jolt.RigidBody.RigidBodyParams;
|
||||
#else
|
||||
typedef RigidBody = leenkx.trait.physics.oimo.RigidBody;
|
||||
typedef Shape = leenkx.trait.physics.oimo.RigidBody.Shape;
|
||||
typedef RigidBodyParams = leenkx.trait.physics.oimo.RigidBody.RigidBodyParams;
|
||||
#end
|
||||
|
||||
#end
|
||||
|
||||
@ -346,7 +346,7 @@ class KinematicCharacterController extends Trait {
|
||||
}
|
||||
}
|
||||
|
||||
@:enum abstract ControllerShape(Int) from Int to Int {
|
||||
enum abstract ControllerShape(Int) from Int to Int {
|
||||
var Box = 0;
|
||||
var Sphere = 1;
|
||||
var ConvexHull = 2;
|
||||
@ -355,7 +355,7 @@ class KinematicCharacterController extends Trait {
|
||||
var Capsule = 5;
|
||||
}
|
||||
|
||||
@:enum abstract ControllerActivationState(Int) from Int to Int {
|
||||
enum abstract ControllerActivationState(Int) from Int to Int {
|
||||
var Active = 1;
|
||||
var NoDeactivation = 4;
|
||||
var NoSimulation = 5;
|
||||
|
||||
@ -36,24 +36,24 @@ class PhysicsConstraint extends iron.Trait {
|
||||
|
||||
/**
|
||||
* Function to initialize physics constraint trait.
|
||||
*
|
||||
* @param object Pivot object to which this constraint trait will be added. The constraint limits are applied along the local axes of this object. This object need not
|
||||
* be a Rigid Body. Typically an `Empty` object may be used. Moving/rotating/parenting this pivot object has no effect once the constraint trait is added. Removing
|
||||
* the pivot object removes the constraint.
|
||||
*
|
||||
* @param body1 First rigid body to be constrained. This rigid body may be constrained by other constraints.
|
||||
*
|
||||
* @param body2 Second rigid body to be constrained. This rigid body may be constrained by other constraints.
|
||||
*
|
||||
* @param type Type of the constraint.
|
||||
*
|
||||
* @param disableCollisions Disable collisions between constrained objects.
|
||||
*
|
||||
* @param breakingThreshold Break the constraint if stress on this constraint exceeds this value. Set to 0 to make un-breakable.
|
||||
*
|
||||
* @param limits Constraint limits. This may be set before adding the trait to pivot object using the set limits functions.
|
||||
*
|
||||
**/
|
||||
*
|
||||
* @param object Pivot object to which this constraint trait will be added. The constraint limits are applied along the local axes of this object. This object need not
|
||||
* be a Rigid Body. Typically an `Empty` object may be used. Moving/rotating/parenting this pivot object has no effect once the constraint trait is added. Removing
|
||||
* the pivot object removes the constraint.
|
||||
*
|
||||
* @param body1 First rigid body to be constrained. This rigid body may be constrained by other constraints.
|
||||
*
|
||||
* @param body2 Second rigid body to be constrained. This rigid body may be constrained by other constraints.
|
||||
*
|
||||
* @param type Type of the constraint.
|
||||
*
|
||||
* @param disableCollisions Disable collisions between constrained objects.
|
||||
*
|
||||
* @param breakingThreshold Break the constraint if stress on this constraint exceeds this value. Set to 0 to make un-breakable.
|
||||
*
|
||||
* @param limits Constraint limits. This may be set before adding the trait to pivot object using the set limits functions.
|
||||
*
|
||||
**/
|
||||
public function new(body1: Object, body2: Object, type: ConstraintType, disableCollisions: Bool, breakingThreshold: Float, limits: Array<Float> = null) {
|
||||
super();
|
||||
|
||||
@ -335,7 +335,7 @@ class PhysicsConstraint extends iron.Trait {
|
||||
if (breakingThreshold > 0) con.setBreakingImpulseThreshold(breakingThreshold);
|
||||
|
||||
physics.addPhysicsConstraint(this);
|
||||
|
||||
|
||||
id = nextId;
|
||||
nextId++;
|
||||
|
||||
@ -350,11 +350,11 @@ class PhysicsConstraint extends iron.Trait {
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set constraint limits when using Hinge constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object
|
||||
**/
|
||||
* Function to set constraint limits when using Hinge constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object
|
||||
**/
|
||||
public function setHingeConstraintLimits(angLimit: Bool, lowerAngLimit: Float, upperAngLimit: Float) {
|
||||
|
||||
|
||||
angLimit? limits[0] = 1 : limits[0] = 0;
|
||||
|
||||
limits[1] = lowerAngLimit * (Math.PI/ 180);
|
||||
@ -362,11 +362,11 @@ class PhysicsConstraint extends iron.Trait {
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set constraint limits when using Slider constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object
|
||||
**/
|
||||
* Function to set constraint limits when using Slider constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object
|
||||
**/
|
||||
public function setSliderConstraintLimits(linLimit: Bool, lowerLinLimit: Float, upperLinLimit: Float) {
|
||||
|
||||
|
||||
linLimit? limits[0] = 1 : limits[0] = 0;
|
||||
|
||||
limits[1] = lowerLinLimit;
|
||||
@ -374,11 +374,11 @@ class PhysicsConstraint extends iron.Trait {
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set constraint limits when using Piston constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object
|
||||
**/
|
||||
* Function to set constraint limits when using Piston constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object
|
||||
**/
|
||||
public function setPistonConstraintLimits(linLimit: Bool, lowerLinLimit: Float, upperLinLimit: Float, angLimit: Bool, lowerAngLimit: Float, upperAngLimit: Float) {
|
||||
|
||||
|
||||
linLimit? limits[0] = 1 : limits[0] = 0;
|
||||
|
||||
limits[1] = lowerLinLimit;
|
||||
@ -391,9 +391,9 @@ class PhysicsConstraint extends iron.Trait {
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set customized constraint limits when using Generic/ Generic Spring constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object. Multiple constarints may be set by calling this function with different parameters.
|
||||
**/
|
||||
* Function to set customized constraint limits when using Generic/ Generic Spring constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object. Multiple constarints may be set by calling this function with different parameters.
|
||||
**/
|
||||
public function setGenericConstraintLimits(setLimit: Bool = false, lowerLimit: Float = 1.0, upperLimit: Float = -1.0, axis: ConstraintAxis = X, isAngular: Bool = false) {
|
||||
|
||||
var i = 0;
|
||||
@ -401,7 +401,7 @@ class PhysicsConstraint extends iron.Trait {
|
||||
var radian = (Math.PI/ 180);
|
||||
|
||||
switch (axis){
|
||||
case X:
|
||||
case X:
|
||||
i = 0;
|
||||
case Y:
|
||||
i = 3;
|
||||
@ -420,16 +420,16 @@ class PhysicsConstraint extends iron.Trait {
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set customized spring parameters when using Generic/ Generic Spring constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object. Multiple parameters to different axes may be set by calling this function with different parameters.
|
||||
**/
|
||||
* Function to set customized spring parameters when using Generic/ Generic Spring constraint. May be used after initalizing this trait but before adding it
|
||||
* to the pivot object. Multiple parameters to different axes may be set by calling this function with different parameters.
|
||||
**/
|
||||
public function setSpringParams(setSpring: Bool = false, stiffness: Float = 10.0, damping: Float = 0.5, axis: ConstraintAxis = X, isAngular: Bool = false) {
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
|
||||
switch (axis){
|
||||
case X:
|
||||
case X:
|
||||
i = 18;
|
||||
case Y:
|
||||
i = 21;
|
||||
@ -453,10 +453,9 @@ class PhysicsConstraint extends iron.Trait {
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@:enum abstract ConstraintType(Int) from Int to Int {
|
||||
enum abstract ConstraintType(Int) from Int to Int {
|
||||
var Fixed = 0;
|
||||
var Point = 1;
|
||||
var Hinge = 2;
|
||||
@ -467,7 +466,7 @@ class PhysicsConstraint extends iron.Trait {
|
||||
var Motor = 7;
|
||||
}
|
||||
|
||||
@:enum abstract ConstraintAxis(Int) from Int to Int {
|
||||
enum abstract ConstraintAxis(Int) from Int to Int {
|
||||
var X = 0;
|
||||
var Y = 1;
|
||||
var Z = 2;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package leenkx.trait.physics.bullet;
|
||||
|
||||
#if lnx_bullet
|
||||
|
||||
import iron.Trait;
|
||||
import iron.system.Time;
|
||||
import iron.math.Vec4;
|
||||
@ -10,7 +9,6 @@ import iron.math.RayCaster;
|
||||
import leenkx.trait.physics.PhysicsCache;
|
||||
|
||||
class Hit {
|
||||
|
||||
public var rb: RigidBody;
|
||||
public var pos: Vec4;
|
||||
public var normal: Vec4;
|
||||
@ -33,7 +31,6 @@ class ConvexHit {
|
||||
}
|
||||
|
||||
class ContactPair {
|
||||
|
||||
public var a: Int;
|
||||
public var b: Int;
|
||||
public var posA: Vec4;
|
||||
@ -48,7 +45,6 @@ class ContactPair {
|
||||
}
|
||||
|
||||
class PhysicsWorld extends Trait {
|
||||
|
||||
public static var active: PhysicsWorld = null;
|
||||
static var sceneRemoved = false;
|
||||
|
||||
@ -207,6 +203,12 @@ class PhysicsWorld extends Trait {
|
||||
rbMap.set(body.id, body);
|
||||
}
|
||||
|
||||
public function updateRigidBody(body: RigidBody) {
|
||||
if (world != null) world.removeRigidBody(body.body);
|
||||
rbMap.remove(body.id);
|
||||
addRigidBody(body);
|
||||
}
|
||||
|
||||
public function addPhysicsConstraint(constraint: PhysicsConstraint) {
|
||||
world.addConstraint(constraint.con, constraint.disableCollisions);
|
||||
conMap.set(constraint.id, constraint);
|
||||
@ -319,7 +321,7 @@ class PhysicsWorld extends Trait {
|
||||
world.stepSimulation(t, currMaxSteps, Time.fixedStep);
|
||||
updateContacts();
|
||||
|
||||
for (rb in rbMap) @:privateAccess rb.physicsUpdate();
|
||||
for (rb in rbMap) { @:privateAccess try { rb.physicsUpdate(); } catch(e:haxe.Exception) { trace(e.message); } } // HACK: see this recommendation: https://github.com/armory3d/armory/issues/3044#issuecomment-2558199944.
|
||||
|
||||
#if lnx_debug
|
||||
physTime = kha.Scheduler.realTime() - startTime;
|
||||
|
||||
@ -68,6 +68,10 @@ class RigidBody extends iron.Trait {
|
||||
public var onReady: Void->Void = null;
|
||||
public var onContact: Array<RigidBody->Void> = null;
|
||||
public var heightData: haxe.io.Bytes = null;
|
||||
|
||||
// Compound shape children (baked from exporter)
|
||||
var compoundChildren: Array<CompoundChild> = null;
|
||||
|
||||
#if js
|
||||
static var ammoArray: Int = -1;
|
||||
#end
|
||||
@ -92,7 +96,6 @@ class RigidBody extends iron.Trait {
|
||||
|
||||
// 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);
|
||||
@ -131,7 +134,7 @@ class RigidBody extends iron.Trait {
|
||||
angularFactorsZ: 1.0,
|
||||
collisionMargin: 0.0,
|
||||
linearDeactivationThreshold: 0.0,
|
||||
angularDeactivationThrshold: 0.0,
|
||||
angularDeactivationThreshold: 0.0,
|
||||
deactivationTime: 0.0,
|
||||
linearVelocityMin: 0.0,
|
||||
linearVelocityMax: 0.0,
|
||||
@ -160,7 +163,7 @@ class RigidBody extends iron.Trait {
|
||||
this.linearFactors = [params.linearFactorsX, params.linearFactorsY, params.linearFactorsZ];
|
||||
this.angularFactors = [params.angularFactorsX, params.angularFactorsY, params.angularFactorsZ];
|
||||
this.collisionMargin = params.collisionMargin;
|
||||
this.deactivationParams = [params.linearDeactivationThreshold, params.angularDeactivationThrshold, params.deactivationTime];
|
||||
this.deactivationParams = [params.linearDeactivationThreshold, params.angularDeactivationThreshold, params.deactivationTime];
|
||||
// New velocity limiting properties
|
||||
this.linearVelocityMin = params.linearVelocityMin;
|
||||
this.linearVelocityMax = params.linearVelocityMax;
|
||||
@ -180,6 +183,9 @@ class RigidBody extends iron.Trait {
|
||||
this.staticObj = flags.staticObj;
|
||||
this.useDeactivation = flags.useDeactivation;
|
||||
|
||||
// Store compound children data if provided
|
||||
this.compoundChildren = params.compoundChildren;
|
||||
|
||||
notifyOnAdd(init);
|
||||
}
|
||||
|
||||
@ -281,6 +287,25 @@ class RigidBody extends iron.Trait {
|
||||
btshape.setLocalScaling(vec1);
|
||||
#end
|
||||
}
|
||||
else if (shape == Shape.Compound) {
|
||||
// Create compound shape and add all child shapes
|
||||
var compound = new bullet.Bt.CompoundShape(true);
|
||||
if (compoundChildren != null) {
|
||||
for (child in compoundChildren) {
|
||||
var childShape = createChildShape(child);
|
||||
if (childShape != null) {
|
||||
// Set child local transform
|
||||
trans2.setIdentity();
|
||||
vec1.setValue(child.posX, child.posY, child.posZ);
|
||||
trans2.setOrigin(vec1);
|
||||
quat1.setValue(child.rotX, child.rotY, child.rotZ, child.rotW);
|
||||
trans2.setRotation(quat1);
|
||||
compound.addChildShape(trans2, childShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
btshape = compound;
|
||||
}
|
||||
|
||||
trans1.setIdentity();
|
||||
vec1.setX(transform.worldx());
|
||||
@ -313,7 +338,7 @@ class RigidBody extends iron.Trait {
|
||||
bodyColl.setRollingFriction(angularFriction);
|
||||
bodyColl.setRestitution(restitution);
|
||||
|
||||
if ( useDeactivation) {
|
||||
if (useDeactivation) {
|
||||
setDeactivationParams(deactivationParams[0], deactivationParams[1], deactivationParams[2]);
|
||||
}
|
||||
else {
|
||||
@ -382,16 +407,49 @@ class RigidBody extends iron.Trait {
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child collision shape for compound rigidbodies from baked export data.
|
||||
* @param child The compound child data containing shape type and dimensions
|
||||
* @return The created Bullet collision shape, or null if shape type is unsupported
|
||||
*/
|
||||
function createChildShape(child: CompoundChild): bullet.Bt.CollisionShape {
|
||||
var childShapeType: Int = child.shape;
|
||||
|
||||
if (childShapeType == Shape.Box) {
|
||||
vec1.setValue(withMargin(child.dimX / 2), withMargin(child.dimY / 2), withMargin(child.dimZ / 2));
|
||||
return new bullet.Bt.BoxShape(vec1);
|
||||
}
|
||||
else if (childShapeType == Shape.Sphere) {
|
||||
return new bullet.Bt.SphereShape(withMargin(child.dimX / 2));
|
||||
}
|
||||
else if (childShapeType == Shape.Cone) {
|
||||
var coneZ = new bullet.Bt.ConeShapeZ(
|
||||
withMargin(child.dimX / 2), // Radius
|
||||
withMargin(child.dimZ)); // Height
|
||||
return coneZ;
|
||||
}
|
||||
else if (childShapeType == Shape.Cylinder) {
|
||||
vec1.setValue(withMargin(child.dimX / 2), withMargin(child.dimY / 2), withMargin(child.dimZ / 2));
|
||||
var cylZ = new bullet.Bt.CylinderShapeZ(vec1);
|
||||
return cylZ;
|
||||
}
|
||||
else if (childShapeType == Shape.Capsule) {
|
||||
var r = child.dimX / 2;
|
||||
var capsZ = new bullet.Bt.CapsuleShapeZ(
|
||||
withMargin(r), // Radius
|
||||
withMargin(child.dimZ - r * 2)); // Height between 2 sphere centers
|
||||
return capsZ;
|
||||
}
|
||||
else {
|
||||
// Unsupported shape type for compound children (ConvexHull, Mesh, Terrain)
|
||||
trace("Warning: Unsupported compound child shape type: " + childShapeType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (interpolate) {
|
||||
time += Time.delta;
|
||||
|
||||
while (time >= Time.fixedStep) {
|
||||
time -= Time.fixedStep;
|
||||
}
|
||||
|
||||
var t: Float = time / Time.fixedStep;
|
||||
var t: Float = Time.fixedStepInterpolation;
|
||||
t = Helper.clamp(t, 0, 1);
|
||||
|
||||
var tx: Float = prevPos.x() * (1.0 - t) + currentPos.x() * t;
|
||||
@ -402,9 +460,6 @@ class RigidBody extends iron.Trait {
|
||||
|
||||
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) {
|
||||
@ -429,32 +484,30 @@ class RigidBody extends iron.Trait {
|
||||
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;
|
||||
|
||||
prevPos.setValue(currentPos.x(), currentPos.y(), currentPos.z());
|
||||
prevRot.setValue(currentRot.x(), currentRot.y(), currentRot.z(), currentRot.w());
|
||||
|
||||
if (animated) {
|
||||
syncTransform();
|
||||
} 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.clearDelta();
|
||||
// transform.buildMatrix();
|
||||
currentPos.setValue(p.x(), p.y(), p.z());
|
||||
currentRot.setValue(q.x(), q.y(), q.z(), q.w());
|
||||
|
||||
|
||||
#if hl
|
||||
p.delete();
|
||||
q.delete();
|
||||
trans.delete();
|
||||
#end
|
||||
}
|
||||
|
||||
var trans = body.getWorldTransform();
|
||||
var p = trans.getOrigin();
|
||||
var q = trans.getRotation();
|
||||
|
||||
currentPos.setValue(p.x(), p.y(), p.z());
|
||||
currentRot.setValue(q.x(), q.y(), q.z(), q.w());
|
||||
|
||||
#if hl
|
||||
p.delete();
|
||||
q.delete();
|
||||
trans.delete();
|
||||
#end
|
||||
|
||||
if (onContact != null) {
|
||||
var rbs = physics.getContacts(this);
|
||||
if (rbs != null) for (rb in rbs) for (f in onContact) f(rb);
|
||||
@ -533,6 +586,18 @@ class RigidBody extends iron.Trait {
|
||||
bodyColl.activate(false);
|
||||
}
|
||||
|
||||
public function setGroup(group: Int) {
|
||||
if (this.group == group) return;
|
||||
this.group = group;
|
||||
physics.updateRigidBody(this);
|
||||
}
|
||||
|
||||
public function setMask(mask: Int) {
|
||||
if (this.mask == mask) return;
|
||||
this.mask = mask;
|
||||
physics.updateRigidBody(this);
|
||||
}
|
||||
|
||||
public function disableGravity() {
|
||||
vec1.setValue(0, 0, 0);
|
||||
body.setGravity(vec1);
|
||||
@ -817,7 +882,7 @@ class RigidBody extends iron.Trait {
|
||||
}
|
||||
}
|
||||
|
||||
@:enum abstract Shape(Int) from Int to Int {
|
||||
enum abstract Shape(Int) from Int to Int {
|
||||
var Box = 0;
|
||||
var Sphere = 1;
|
||||
var ConvexHull = 2;
|
||||
@ -826,6 +891,7 @@ class RigidBody extends iron.Trait {
|
||||
var Cylinder = 5;
|
||||
var Capsule = 6;
|
||||
var Terrain = 7;
|
||||
var Compound = 8;
|
||||
}
|
||||
|
||||
typedef RigidBodyParams = {
|
||||
@ -840,7 +906,7 @@ typedef RigidBodyParams = {
|
||||
var angularFactorsZ: Float;
|
||||
var collisionMargin: Float;
|
||||
var linearDeactivationThreshold: Float;
|
||||
var angularDeactivationThrshold: Float;
|
||||
var angularDeactivationThreshold: Float;
|
||||
var deactivationTime: Float;
|
||||
var linearVelocityMin: Float;
|
||||
var linearVelocityMax: Float;
|
||||
@ -852,6 +918,21 @@ typedef RigidBodyParams = {
|
||||
var lockRotationX: Bool;
|
||||
var lockRotationY: Bool;
|
||||
var lockRotationZ: Bool;
|
||||
@:optional var compoundChildren: Array<CompoundChild>;
|
||||
}
|
||||
|
||||
typedef CompoundChild = {
|
||||
var shape: Int; // 0=Box, 1=Sphere, 2=ConvexHull, 3=Mesh, 4=Cone, 5=Cylinder, 6=Capsule
|
||||
var posX: Float; // Local position relative to parent
|
||||
var posY: Float;
|
||||
var posZ: Float;
|
||||
var rotX: Float; // Local rotation quaternion
|
||||
var rotY: Float;
|
||||
var rotZ: Float;
|
||||
var rotW: Float;
|
||||
var dimX: Float; // Dimensions
|
||||
var dimY: Float;
|
||||
var dimZ: Float;
|
||||
}
|
||||
|
||||
typedef RigidBodyFlags = {
|
||||
|
||||
@ -297,7 +297,7 @@ class SoftBody extends Trait {
|
||||
vertOffsetX /= numNodes;
|
||||
vertOffsetY /= numNodes;
|
||||
vertOffsetZ /= numNodes;
|
||||
|
||||
|
||||
//Setting the mean position as object local location
|
||||
mo.transform.scale.set(1, 1, 1);
|
||||
mo.transform.loc.set(vertOffsetX, vertOffsetY, vertOffsetZ);
|
||||
@ -343,7 +343,7 @@ class SoftBody extends Trait {
|
||||
var mx = nodePos.x() - vertOffsetX;
|
||||
var my = nodePos.y() - vertOffsetY;
|
||||
var mz = nodePos.z() - vertOffsetZ;
|
||||
|
||||
|
||||
var nx = nodeNor.x();
|
||||
var ny = nodeNor.y();
|
||||
var nz = nodeNor.z();
|
||||
@ -423,7 +423,7 @@ class SoftBody extends Trait {
|
||||
#end
|
||||
}
|
||||
|
||||
@:enum abstract SoftShape(Int) from Int {
|
||||
enum abstract SoftShape(Int) from Int {
|
||||
var Cloth = 0;
|
||||
var Volume = 1;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ class RigidBody extends Trait {
|
||||
angularFactorsZ: 1.0,
|
||||
collisionMargin: 0.0,
|
||||
linearDeactivationThreshold: 0.0,
|
||||
angularDeactivationThrshold: 0.0,
|
||||
angularDeactivationThreshold: 0.0,
|
||||
deactivationTime: 0.0,
|
||||
linearVelocityMin: 0.0,
|
||||
linearVelocityMax: 0.0,
|
||||
@ -152,6 +152,7 @@ class RigidBody extends Trait {
|
||||
return;
|
||||
|
||||
transform = object.transform;
|
||||
transform.buildMatrix();
|
||||
physics = PhysicsWorld.active;
|
||||
|
||||
if (physics == null) {
|
||||
@ -720,7 +721,7 @@ typedef RigidBodyParams = {
|
||||
var angularFactorsZ:Float;
|
||||
var collisionMargin:Float;
|
||||
var linearDeactivationThreshold:Float;
|
||||
var angularDeactivationThrshold:Float;
|
||||
var angularDeactivationThreshold:Float;
|
||||
var deactivationTime:Float;
|
||||
var linearVelocityMin:Float;
|
||||
var linearVelocityMax:Float;
|
||||
|
||||
@ -254,7 +254,7 @@ class Canvas {
|
||||
if (element.editable == null) element.editable = true;
|
||||
|
||||
zui.Ext.textArea(ui, h.nest(element.id), element.alignment, element.editable, getText(canvas, element), true);
|
||||
|
||||
|
||||
//handle does not change
|
||||
if (h.nest(element.id).changed) {
|
||||
var e = element.event;
|
||||
@ -483,7 +483,7 @@ typedef TTranslatedText = {
|
||||
var text: String;
|
||||
}
|
||||
|
||||
@:enum abstract ElementType(Int) from Int to Int {
|
||||
enum abstract ElementType(Int) from Int to Int {
|
||||
var Text = 0;
|
||||
var Image = 1;
|
||||
var Button = 2;
|
||||
@ -507,7 +507,7 @@ typedef TTranslatedText = {
|
||||
var TextArea = 20;
|
||||
}
|
||||
|
||||
@:enum abstract Anchor(Int) from Int to Int {
|
||||
enum abstract Anchor(Int) from Int to Int {
|
||||
var TopLeft = 0;
|
||||
var Top = 1;
|
||||
var TopRight = 2;
|
||||
|
||||
Reference in New Issue
Block a user