Repe [T3DU] Update - 31f26d171bba0355ce2a77031e3aad4c64dbc7e9

This commit is contained in:
2026-09-04 10:46:13 -07:00
parent c915312901
commit 0460b9d587
482 changed files with 27797 additions and 3226 deletions

View File

@ -1,31 +1,119 @@
package iron.object;
import iron.data.SceneFormat;
import iron.math.Vec4;
import iron.math.Quat;
class Constraint {
var raw: TConstraint;
var target: Transform = null;
public function new(constr: TConstraint) {
raw = constr;
public function new(constraint: TConstraint) {
raw = constraint;
}
public function apply(transform: Transform) {
if (target == null && raw.target != null) target = Scene.active.getChild(raw.target).transform;
if (target == null && raw.type != "LIMIT_LOCATION" && raw.type != "LIMIT_ROTATION" && raw.type != "LIMIT_SCALE") return;
if (raw.type == "COPY_LOCATION") {
if (raw.use_x) {
transform.world._30 = target.loc.x;
if (raw.use_offset) transform.world._30 += transform.loc.x;
if (raw.use_offset) {
if (raw.use_x) transform.world._30 += target.world._30;
if (raw.use_y) transform.world._31 += target.world._31;
if (raw.use_z) transform.world._32 += target.world._32;
}
if (raw.use_y) {
transform.world._31 = target.loc.y;
if (raw.use_offset) transform.world._31 += transform.loc.y;
else {
if (raw.use_x) transform.world._30 = target.world._30;
if (raw.use_y) transform.world._31 = target.world._31;
if (raw.use_z) transform.world._32 = target.world._32;
}
if (raw.use_z) {
transform.world._32 = target.loc.z;
if (raw.use_offset) transform.world._32 += transform.loc.z;
}
else if (raw.type == "COPY_ROTATION") {
var tq = target.rot;
var mq = transform.rot;
if (raw.use_offset) {
mq.mult(tq);
}
else {
if (raw.use_x) mq.x = tq.x;
if (raw.use_y) mq.y = tq.y;
if (raw.use_z) mq.z = tq.z;
mq.w = tq.w;
}
var loc = new Vec4(transform.world._30, transform.world._31, transform.world._32);
var scale = transform.scale;
transform.world.compose(loc, mq, scale);
}
else if (raw.type == "COPY_SCALE") {
var ts = target.scale;
if (raw.use_offset) {
if (raw.use_x) transform.scale.x *= ts.x;
if (raw.use_y) transform.scale.y *= ts.y;
if (raw.use_z) transform.scale.z *= ts.z;
}
else {
if (raw.use_x) transform.scale.x = ts.x;
if (raw.use_y) transform.scale.y = ts.y;
if (raw.use_z) transform.scale.z = ts.z;
}
var loc = new Vec4(transform.world._30, transform.world._31, transform.world._32);
transform.world.compose(loc, transform.rot, transform.scale);
}
else if (raw.type == "COPY_TRANSFORMS") {
transform.world.setFrom(target.world);
}
else if (raw.type == "LIMIT_LOCATION") {
if (raw.use_min_x && transform.world._30 < raw.min_x) transform.world._30 = raw.min_x;
if (raw.use_max_x && transform.world._30 > raw.max_x) transform.world._30 = raw.max_x;
if (raw.use_min_y && transform.world._31 < raw.min_y) transform.world._31 = raw.min_y;
if (raw.use_max_y && transform.world._31 > raw.max_y) transform.world._31 = raw.max_y;
if (raw.use_min_z && transform.world._32 < raw.min_z) transform.world._32 = raw.min_z;
if (raw.use_max_z && transform.world._32 > raw.max_z) transform.world._32 = raw.max_z;
}
else if (raw.type == "LIMIT_ROTATION") {
var euler = transform.rot.getEuler();
var changed = false;
if (raw.use_limit_x) {
if (euler.x < raw.min_x) { euler.x = raw.min_x; changed = true; }
if (euler.x > raw.max_x) { euler.x = raw.max_x; changed = true; }
}
if (raw.use_limit_y) {
if (euler.y < raw.min_y) { euler.y = raw.min_y; changed = true; }
if (euler.y > raw.max_y) { euler.y = raw.max_y; changed = true; }
}
if (raw.use_limit_z) {
if (euler.z < raw.min_z) { euler.z = raw.min_z; changed = true; }
if (euler.z > raw.max_z) { euler.z = raw.max_z; changed = true; }
}
if (changed) {
transform.rot.fromEuler(euler.x, euler.y, euler.z);
var loc = new Vec4(transform.world._30, transform.world._31, transform.world._32);
transform.world.compose(loc, transform.rot, transform.scale);
}
}
else if (raw.type == "LIMIT_SCALE") {
if (raw.use_min_x && transform.scale.x < raw.min_x) transform.scale.x = raw.min_x;
if (raw.use_max_x && transform.scale.x > raw.max_x) transform.scale.x = raw.max_x;
if (raw.use_min_y && transform.scale.y < raw.min_y) transform.scale.y = raw.min_y;
if (raw.use_max_y && transform.scale.y > raw.max_y) transform.scale.y = raw.max_y;
if (raw.use_min_z && transform.scale.z < raw.min_z) transform.scale.z = raw.min_z;
if (raw.use_max_z && transform.scale.z > raw.max_z) transform.scale.z = raw.max_z;
var loc = new Vec4(transform.world._30, transform.world._31, transform.world._32);
transform.world.compose(loc, transform.rot, transform.scale);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,12 @@ import iron.object.CameraObject;
class LightObject extends Object {
public var data: LightData;
public var color: Vec4;
public var strength: Float;
#if lnx_spot
public var size: Float;
public var blend: Float;
#end
#if rp_shadowmap
#if lnx_shadowmap_atlas
@ -79,6 +85,15 @@ class LightObject extends Object {
super();
this.data = data;
this.color = new Vec4(data.raw.color[0], data.raw.color[1], data.raw.color[2]);
this.strength = data.raw.strength;
#if lnx_spot
if (data.raw.type == "spot"){
this.size = data.raw.spot_size;
this.blend = data.raw.spot_blend;
}
#end
var type = data.raw.type;
var fov = data.raw.fov;
@ -374,7 +389,7 @@ class LightObject extends Object {
// Centralize discarding conditions when iterating over lights
// Important to avoid issues later with "misaligned" data in uniforms (lightsArray, clusterData, LWVPSpotArray)
public inline static function discardLight(light: LightObject) {
return !light.visible || light.data.raw.strength == 0.0 || light.data.raw.type == "sun";
return !light.visible || light.strength == 0.0 || light.data.raw.type == "sun";
}
// Discarding conditions but with culling included
public inline static function discardLightCulled(light: LightObject) {
@ -457,7 +472,7 @@ class LightObject extends Object {
lpos.set(l.transform.worldx(), l.transform.worldy(), l.transform.worldz());
lpos.applymat4(camera.V);
lpos.z *= -1.0;
var radius = getRadius(l.data.raw.strength);
var radius = getRadius(l.strength);
var minX = 0;
var minY = 0;
var minZ = 0;
@ -552,10 +567,10 @@ class LightObject extends Object {
lightsArray[i * 12 + 3] = 0.0; // padding or spot scale x
// light color
var f = l.data.raw.strength;
lightsArray[i * 12 + 4] = l.data.raw.color[0] * f;
lightsArray[i * 12 + 5] = l.data.raw.color[1] * f;
lightsArray[i * 12 + 6] = l.data.raw.color[2] * f;
var f = l.strength;
lightsArray[i * 12 + 4] = l.color.x * f;
lightsArray[i * 12 + 5] = l.color.y * f;
lightsArray[i * 12 + 6] = l.color.z * f;
lightsArray[i * 12 + 7] = 0.0; // padding or spot scale y
// other data
@ -566,13 +581,13 @@ class LightObject extends Object {
#if lnx_spot
if (l.data.raw.type == "spot") {
lightsArray[i * 12 + 9] = l.data.raw.spot_size;
lightsArray[i * 12 + 9] = l.size;
var dir = l.look().normalize();
lightsArraySpot[i * 8 ] = dir.x;
lightsArraySpot[i * 8 + 1] = dir.y;
lightsArraySpot[i * 8 + 2] = dir.z;
lightsArraySpot[i * 8 + 3] = l.data.raw.spot_blend;
lightsArraySpot[i * 8 + 3] = l.blend;
// Premultiply scale with z component
var scale = l.transform.scale;

View File

@ -28,13 +28,15 @@ class MeshObject extends Object {
public var cameraList: Array<String> = null;
public var screenSize = 0.0;
public var frustumCulling = true;
public var tilesheet: Tilesheet = null;
public var activeTilesheet: Tilesheet = null;
public var tilesheets: Array<Tilesheet> = null;
public var skip_context: String = null; // Do not draw this context
public var force_context: String = null; // Draw only this context
static var lastPipeline: PipelineState = null;
#if lnx_morph_target
public var morphTarget: MorphTarget = null;
#end
public var vertexGroups: Map<String, Array<Vec4>> = null;
#if lnx_veloc
public var prevMatrix = Mat4.identity();
@ -50,6 +52,10 @@ class MeshObject extends Object {
public function setData(data: MeshData) {
this.data = data;
if (this.materials != null && this.materials.length > 0)
data.geom.instanceElements = @:privateAccess this.materials[0].shader.contexts[0].instanceElements;
data.refcount++;
#if (!lnx_batch)
@ -87,7 +93,8 @@ class MeshObject extends Object {
particleSystems = null;
}
#end
if (tilesheet != null) tilesheet.remove();
if (activeTilesheet != null) activeTilesheet.remove();
if (tilesheets != null) { for (ts in tilesheets) { ts.remove(); } tilesheets = null; }
if (Scene.active != null) Scene.active.meshes.remove(this);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
@ -126,12 +133,34 @@ class MeshObject extends Object {
#end
public function setupTilesheet(tilesheetData: iron.data.SceneFormat.TTilesheetData) {
tilesheet = new Tilesheet(tilesheetData, this);
activeTilesheet = new Tilesheet(tilesheetData, this);
if (tilesheets == null) tilesheets = new Array<Tilesheet>();
tilesheets.push(activeTilesheet);
}
public function setActiveTilesheet(tilesheetData: iron.data.SceneFormat.TTilesheetData, tilesheetActionRef: String = null) {
var set = false;
if (tilesheets != null) {
for (ts in tilesheets) {
if (ts.raw == tilesheetData) {
if (activeTilesheet != null) activeTilesheet.pause();
activeTilesheet = ts;
if (tilesheetActionRef != null) activeTilesheet.play(tilesheetActionRef);
set = true;
break;
}
}
}
if (!set) {
if (activeTilesheet != null) activeTilesheet.pause();
setupTilesheet(tilesheetData);
if (tilesheetActionRef != null) activeTilesheet.play(tilesheetActionRef);
}
}
public function setTilesheetAction(actionRef: String) {
if (tilesheet != null) {
tilesheet.play(actionRef);
if (activeTilesheet != null) {
activeTilesheet.play(actionRef);
}
}
@ -164,6 +193,7 @@ class MeshObject extends Object {
}
function cullMesh(context: String, camera: CameraObject, light: LightObject): Bool {
var isShadow = context == "shadowmap";
if (camera == null) return false;
if (camera.data.raw.frustum_culling && frustumCulling) {
@ -172,11 +202,12 @@ class MeshObject extends Object {
var radiusScale = data.isSkinned ? 2.0 : 1.0;
#if lnx_gpu_particles
// particleSystems for update, particleOwner for render
if (particleSystems != null || particleOwner != null) radiusScale *= 1000;
if (particleSystems != null && particleSystems.length > 0) return setCulled(isShadow, false);
#end
/*
if (context == "voxel") radiusScale *= 100;
if (data.geom.instanced) radiusScale *= 100;
var isShadow = context == "shadowmap";
if (data.geom.instanced) radiusScale *= 100;*/
if (data.geom.instanced) return setCulled(isShadow, false);
var frustumPlanes = isShadow ? light.frustumPlanes : camera.frustumPlanes;
if (isShadow && light.data.raw.type != "sun") { // Non-sun light bounds intersect camera frustum
@ -191,8 +222,9 @@ class MeshObject extends Object {
}
}
culled = false;
return culled;
//culled = false;
//return culled;
return setCulled(isShadow, false);
}
function skipContext(context: String, mat: MaterialData): Bool {
@ -227,11 +259,6 @@ class MeshObject extends Object {
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
var meshContext = raw != null ? context == "mesh" : false;
// Update tilesheet
if (tilesheet != null && meshContext) {
tilesheet.update();
}
if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
#if lnx_gpu_particles

View File

@ -61,6 +61,25 @@ class MorphTarget {
public inline function setMorphValueDirect(index: Int, value: Float) {
morphWeights.set(index, value);
}
public function getMorphValue(name: String): Float {
var i = morphMap.get(name);
return (i != null) ? morphWeights.get(i) : 0.0;
}
public function hasMorph(name: String): Bool {
return morphMap.exists(name);
}
public function resetWeights() {
for (i in 0...morphWeights.length) {
morphWeights.set(i, 0.0);
}
}
public function getMorphNames(): Array<String> {
return [for (key in morphMap.keys()) key];
}
}
#end

View File

@ -27,7 +27,6 @@ class Object {
public var culled = false; // Object was culled last frame
public var culledMesh = false;
public var culledShadow = false;
public var vertex_groups: Map<String, Array<Vec4>> = null;
public var properties: Map<String, Dynamic> = null;
var isEmpty = false;
@ -95,6 +94,7 @@ class Object {
Removes the game object from the scene.
**/
public function remove() {
Scene.active.removeFromGroups(this);
if (isEmpty && Scene.active != null) Scene.active.empties.remove(this);
if (animation != null) animation.remove();
while (children.length > 0) children[0].remove();
@ -111,16 +111,12 @@ class Object {
@return Object or null
**/
public function getChild(name: String): Object {
if (this.name == name) return this;
else if (this.filename != "") {
if (this.name == name + "_" + this.filename) return this;
}
for (c in children) {
if (c.name == name) return c;
if (c.filename != "" && c.name == name + "_" + c.filename) return c;
var r = c.getChild(name);
if (r != null) return r;
}
return null;
}
@ -145,12 +141,10 @@ class Object {
}
public function getChildOfType<T: Object>(type: Class<T>): T {
if (Std.isOfType(this, type)) return cast this;
else {
for (c in children) {
var r = c.getChildOfType(type);
if (r != null) return r;
}
for (c in children) {
if (Std.isOfType(c, type)) return cast c;
var r = c.getChildOfType(type);
if (r != null) return r;
}
return null;
}

View File

@ -8,6 +8,7 @@ import iron.data.SceneFormat;
import iron.math.Quat;
import iron.math.Vec3;
import iron.math.Vec4;
import iron.object.CurveObject;
import iron.object.MeshObject;
import iron.object.Object;
import iron.system.Time;
@ -19,6 +20,10 @@ import kha.arrays.Uint32Array;
class ParticleSystemCPU {
public var data: ParticleData;
public var speed: FastFloat = 1.0; // Not used yet. Added to go in hand with `ParticleSystemGPU`
public var curveGuides: Array<CurveObject> = [];
public var curveGuideStrength: FastFloat = 1.0;
public var curveGuideSpeed: FastFloat = 1.0;
var paused: Bool = false;
var r: TParticleData;
// Format
@ -37,6 +42,7 @@ class ParticleSystemCPU {
// Velocity
var velocity: Vec3 = new Vec3(0.0, 0.0, 1.0); // object_align_factor: Float32Array
var velocityRandom: FastFloat = 0.0; // factor_random
var normalFactor: FastFloat = 0.0;
// Rotation
var rotation: Bool = false; // use_rotations
@ -114,11 +120,12 @@ class ParticleSystemCPU {
scale = r.particle_size;
scaleRandom = r.size_random;
velocity = new Vec3(r.object_align_factor[0], r.object_align_factor[1], r.object_align_factor[2]).mult(frameRate / baseFrameRate).mult(1 / scale);
velocity = new Vec3(r.object_align_factor[0], r.object_align_factor[1], r.object_align_factor[2]).mult(frameRate / baseFrameRate);
velocityRandom = r.factor_random * (frameRate / baseFrameRate);
normalFactor = r.normal_factor * (frameRate / baseFrameRate);
if (Scene.active.raw.gravity != null) {
gravity = new Vec3(Scene.active.raw.gravity[0], Scene.active.raw.gravity[1], Scene.active.raw.gravity[2]).mult(frameRate / baseFrameRate).mult(1 / scale);
gravity = new Vec3(Scene.active.raw.gravity[0], Scene.active.raw.gravity[1], Scene.active.raw.gravity[2]).mult(frameRate / baseFrameRate);
}
gravityFactor = r.weight_gravity * (frameRate / baseFrameRate);
textureFactor = r.weight_texture;
@ -139,39 +146,36 @@ class ParticleSystemCPU {
scaleElementsCount = getRampElementsLength();
scaleRampSizeFactor = getRampSizeFactor();
switch (type) {
case 0: // Emission
loopAnim = {
tick: function () {
spawnTime += Time.delta * Time.scale;
var expected: Int = Math.floor(spawnTime / spawnRate);
while (spawnedParticles < expected && spawnedParticles < count) {
spawnParticle();
spawnedParticles++;
}
updateParticles();
},
target: null,
props: null,
duration: loop ? lifetimeSeconds : lifetimeSeconds * 2,
done: function () {
if (loop) start();
}
}
Scene.active.notifyOnInit(function () {
if (autoStart) start();
});
case 1: // Hair
Scene.active.notifyOnInit(function () {
for (i in 0...count) spawnParticle();
});
default:
}
Scene.active.notifyOnInit(function () {
for (i in 0...count) addToPool();
switch (type) {
case 0: // Emission
loopAnim = {
tick: function () {
if (paused) return;
spawnTime += Time.delta;
var expected: Int = Math.floor(spawnTime / spawnRate);
while (spawnedParticles < expected && spawnedParticles < count) {
spawnParticle();
spawnedParticles++;
}
updateParticles();
},
target: null,
props: null,
duration: loop ? lifetimeSeconds : lifetimeSeconds * 2,
done: function () {
if (loop) start();
}
}
if (autoStart) start();
case 1: // Hair
for (i in 0...count) spawnParticle();
default:
}
});
});
}
@ -182,14 +186,12 @@ class ParticleSystemCPU {
Tween.to(loopAnim);
}
// TODO
public function pause() {
paused = true;
}
// TODO
public function resume() {
paused = false;
}
public function stop() {
@ -246,6 +248,8 @@ class ParticleSystemCPU {
var scalePos: FastFloat = owner.data.scalePos;
var scalePosParticle: FastFloat = cast(o, MeshObject).data.scalePos;
var normDir: Vec3 = new Vec3();
// TODO: add all properties from Blender's UI
switch (emitFrom) {
case 0: // Vertices
@ -253,6 +257,8 @@ class ParticleSystemCPU {
var i: Int = Std.int(Math.random() * (pa.values.length / pa.size));
var loc: Vec4 = new Vec4(pa.values[i * pa.size] * normFactor, pa.values[i * pa.size + 1] * normFactor, pa.values[i * pa.size + 2] * normFactor, 1);
if (normalFactor != 0.0) normDir = new Vec3(loc.x, loc.y, loc.z).normalize();
if (!localCoords) {
loc.applyQuat(objectRot);
loc.add(objectPos);
@ -274,6 +280,9 @@ class ParticleSystemCPU {
var pos: Vec3 = randomPointInTriangle(v0, v1, v2);
var loc: Vec4 = new Vec4(pos.x, pos.y, pos.z, 1).mult(normFactor);
if (normalFactor != 0.0) normDir = new Vec3(loc.x, loc.y, loc.z).normalize();
if (!localCoords) {
loc.applyQuat(objectRot);
loc.add(objectPos);
@ -285,6 +294,8 @@ class ParticleSystemCPU {
scaleFactorVolume.mult(0.5);
var loc: Vec4 = new Vec4((Math.random() * 2.0 - 1.0) * scaleFactorVolume.x, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z, 1);
if (normalFactor != 0.0) normDir = new Vec3(loc.x, loc.y, loc.z).normalize();
if (!localCoords) {
loc.applyQuat(objectRot);
loc.add(objectPos);
@ -310,7 +321,9 @@ class ParticleSystemCPU {
var randomZ: FastFloat = (Math.random() * 2 / (scale * particleScale) - 1 / (scale * particleScale)) * velocityRandom;
var g: Vec3 = new Vec3();
var rotatedVelocity: Vec4 = new Vec4(velocity.x + randomX, velocity.y + randomY, velocity.z + randomZ, 1);
if (normalFactor != 0.0) normDir = normDir.mult(normalFactor);
var rotatedVelocity: Vec4 = new Vec4(velocity.x + randomX + normDir.x, velocity.y + randomY + normDir.y, velocity.z + randomZ + normDir.z, 1);
if (!localCoords) rotatedVelocity.applyQuat(objectRot);
if (rotation) {
@ -371,7 +384,7 @@ class ParticleSystemCPU {
function updateParticles() {
for (particle => physics in particlePhysics) {
physics.age += Time.delta * Time.scale;
physics.age += Time.delta;
if (physics.age >= physics.lifetime) {
particlePhysics.remove(particle);
@ -379,14 +392,63 @@ class ParticleSystemCPU {
continue;
}
physics.velocity.x += physics.gravity.x * Time.delta * Time.scale;
physics.velocity.y += physics.gravity.y * Time.delta * Time.scale;
physics.velocity.z += physics.gravity.z * Time.delta * Time.scale;
physics.velocity.x += physics.gravity.x * Time.delta;
physics.velocity.y += physics.gravity.y * Time.delta;
physics.velocity.z += physics.gravity.z * Time.delta;
if (curveGuides != null && curveGuides.length > 0) {
var curveVelX: FastFloat = 0.0;
var curveVelY: FastFloat = 0.0;
var curveVelZ: FastFloat = 0.0;
var validCurves: Int = 0;
for (curve in curveGuides) {
if (curve != null && curve.data != null && curve.data.splines != null && curve.splinesLength > 0) {
var t = physics.age / physics.lifetime;
var tangent = curve.getTangent(t, 0);
tangent.w = 0.0;
tangent.applymat4(curve.transform.world);
tangent.normalize();
var curveLen = curve.getLength(0);
var speed = (curveLen / physics.lifetime) * curveGuideSpeed;
var tgtX = tangent.x * speed;
var tgtY = tangent.y * speed;
var tgtZ = tangent.z * speed;
if (localCoords) {
var targetVel = new Vec4(tgtX, tgtY, tgtZ, 0.0);
var invOwnerRot = new Quat(-owner.transform.rot.x, -owner.transform.rot.y, -owner.transform.rot.z, owner.transform.rot.w);
targetVel.applyQuat(invOwnerRot);
tgtX = targetVel.x;
tgtY = targetVel.y;
tgtZ = targetVel.z;
}
curveVelX += tgtX;
curveVelY += tgtY;
curveVelZ += tgtZ;
validCurves++;
}
}
if (validCurves > 0) {
curveVelX /= validCurves;
curveVelY /= validCurves;
curveVelZ /= validCurves;
physics.velocity.x += (curveVelX - physics.velocity.x) * curveGuideStrength;
physics.velocity.y += (curveVelY - physics.velocity.y) * curveGuideStrength;
physics.velocity.z += (curveVelZ - physics.velocity.z) * curveGuideStrength;
}
}
particle.transform.translate(
physics.velocity.x * Time.delta * Time.scale,
physics.velocity.y * Time.delta * Time.scale,
physics.velocity.z * Time.delta * Time.scale
physics.velocity.x * Time.delta,
physics.velocity.y * Time.delta,
physics.velocity.z * Time.delta
);
if (rotation && dynamicRotation && orientationAxis == 3) setVelocityHair(particle, physics.velocity, randQuat, phaseQuat);

View File

@ -141,10 +141,10 @@ class ParticleSystemGPU {
dimx = object.transform.dim.x;
dimy = object.transform.dim.y;
if (object.tilesheet != null) {
tilesx = object.tilesheet.getTilesX();
tilesy = object.tilesheet.getTilesY();
tilesFramerate = object.tilesheet.action.framerate;
if (object.activeTilesheet != null) {
tilesx = object.activeTilesheet.getTilesX();
tilesy = object.activeTilesheet.getTilesY();
tilesFramerate = object.activeTilesheet.action.framerate;
}
// Animate

View File

@ -1,6 +1,7 @@
package iron.object;
import kha.FastFloat;
import kha.Sound;
import kha.audio1.AudioChannel;
import iron.data.Data;
import iron.data.SceneFormat;
@ -13,9 +14,10 @@ class SpeakerObject extends Object {
public var data: TSpeakerData;
public var paused(default, null) = false;
public var sound(default, null): kha.Sound = null;
public var sound(default, null): Sound = null;
public var channels(default, null): Array<AudioChannel> = [];
public var volume(default, null) : FastFloat;
public var sampleRate(default, null) : Int;
public function new(data: TSpeakerData) {
super();
@ -26,28 +28,32 @@ class SpeakerObject extends Object {
if (data.sound == "") return;
Data.getSound(data.sound, function(sound: kha.Sound) {
this.sound = sound;
Data.getSound(data.sound, function(sound: Sound) {
this.sound = cloneSound(sound);
App.notifyOnInit(init);
});
}
function init() {
sampleRate = sound.sampleRate;
if (data.pitch != 1.0)
sound.sampleRate = Std.int(sampleRate * data.pitch);
if (visible && data.play_on_start) play();
}
public function play() {
if (sound == null || data.muted) return;
public function play(): AudioChannel {
if (sound == null || data.muted) return null;
if (paused) {
for (c in channels) c.play();
paused = false;
return;
return null;
}
var channel = Audio.play(sound, data.loop, data.stream);
if (channel != null) {
channels.push(channel);
if (data.attenuation > 0 && channels.length == 1) App.notifyOnUpdate(update);
}
return channel;
}
public function pause() {
@ -65,14 +71,24 @@ class SpeakerObject extends Object {
data.sound = sound;
Data.getSound(sound, function(sound: kha.Sound) {
this.sound = sound;
Data.getSound(sound, function(sound: Sound) {
this.sound = cloneSound(sound);
});
sampleRate = this.sound.sampleRate;
if (data.pitch != 1.0)
this.sound.sampleRate = Std.int(sampleRate * data.pitch);
}
public function setVolume(volume: FastFloat) {
data.volume = volume;
}
public function setPosition(position: Float) {
for (c in channels)
if (position < c.length) c.position = position;
}
function update() {
if (paused) return;
for (c in channels) if (c.finished) channels.remove(c);
@ -103,6 +119,17 @@ class SpeakerObject extends Object {
super.remove();
}
function cloneSound(sound: Sound): Sound {
if (sound == null) return null;
var s = Type.createEmptyInstance(Sound);
s.compressedData = sound.compressedData;
s.uncompressedData = sound.uncompressedData;
s.sampleRate = sound.sampleRate;
s.length = sound.length;
s.channels = sound.channels;
return s;
}
#end
}

View File

@ -1,11 +1,12 @@
package iron.object;
import iron.App;
import iron.Scene;
import iron.data.SceneFormat;
import iron.system.Time;
import haxe.ds.Map;
@:allow(iron.Scene)
class Tilesheet {
public var tileX: Float = 0.0;
@ -14,7 +15,8 @@ class Tilesheet {
public var flipY: Bool = false;
public var paused: Bool = false;
public var frame: Int = 0;
public var actions: Array<TTilesheetAction>;
public var raw: TTilesheetData = null;
public var actions: Array<TTilesheetAction> = null;
public var action: TTilesheetAction = null;
public var ready: Bool = false;
@ -31,8 +33,11 @@ class Tilesheet {
public function new(tilesheetData: TTilesheetData, ownerObject: MeshObject = null) {
owner = ownerObject;
raw = tilesheetData;
actions = tilesheetData.actions;
Scene.active.tilesheets.push(this);
pendingAction = tilesheetData.start_action;
if ((pendingAction == null || pendingAction == "") && actions.length > 0) {
pendingAction = actions[0].name;
@ -262,8 +267,10 @@ class Tilesheet {
}
public function remove() {
Scene.active.tilesheets.remove(this);
ready = false;
action = null;
raw = null;
actions = null;
owner = null;
currentMesh = null;

View File

@ -106,6 +106,7 @@ class Transform {
Rebuild the matrices, if needed.
**/
public function update() {
if (object.constraints != null && object.constraints.length > 0) dirty = true;
if (dirty) buildMatrix();
}
@ -150,12 +151,19 @@ class Transform {
if (boneParent != null) local.multmats(boneParent, local);
if (object.parent != null && !localOnly) {
world.multmats3x4(local, object.parent.transform.world);
// Swap multiplication order for linked objects to keep local transform intact
var swapMult: Bool = object.raw != null && object.parent.raw != null && object.parent.raw.group_ref != null && object.parent.raw.group_ref != "";
var a: Mat4 = swapMult ? object.parent.transform.world : local;
var b: Mat4 = swapMult ? local : object.parent.transform.world;
world.multmats3x4(a, b);
}
else {
world.setFrom(local);
}
// Constraints
if (object.constraints != null) for (c in object.constraints) c.apply(this);
worldUnpack.setFrom(world);
if (scaleWorld != 1.0) {
worldUnpack._00 *= scaleWorld;
@ -172,9 +180,6 @@ class Transform {
worldUnpack._23 *= scaleWorld;
}
// Constraints
if (object.constraints != null) for (c in object.constraints) c.apply(this);
computeDim();
// Update children
@ -265,7 +270,7 @@ class Transform {
}
function computeRadius() {
radius = Math.sqrt(dim.x * dim.x + dim.y * dim.y + dim.z * dim.z);
radius = 0.5 * Math.sqrt(dim.x * dim.x + dim.y * dim.y + dim.z * dim.z);
}
function computeDim() {

View File

@ -428,12 +428,10 @@ class Uniforms {
var v: Vec4 = null;
helpVec.set(0, 0, 0, 0);
switch (c.link) {
#if lnx_debug
case "_input": {
helpVec.set(Input.getMouse().x / iron.App.w(), Input.getMouse().y / iron.App.h(), Input.getMouse().down() ? 1.0 : 0.0, 0.0);
v = helpVec;
}
#end
default:
return false;
}
@ -690,7 +688,7 @@ class Uniforms {
}
case "_hosekSunDirection": {
var w = Scene.active.world;
if (w != null) {
if (w != null && w.raw.sun_direction != null) {
// Clamp Z for night cycle
helpVec.set(w.raw.sun_direction[0],
w.raw.sun_direction[1],
@ -956,6 +954,22 @@ class Uniforms {
}
static function setObjectConstant(g: Graphics, object: Object, location: ConstantLocation, c: TShaderConstant) {
#if lnx_spot
if (c.name == "LWVPSpot") {
var light = getSpot(0);
if (light != null) {
if (object == null) helpMat.setIdentity();
else helpMat.setFrom(object.transform.worldUnpack);
helpMat.multmat(light.VP);
helpMat.multmat(biasMat);
g.setMatrix(location, helpMat.self);
return;
}
}
#end
if (c.link == null) return;
var camera = Scene.active.camera;
@ -1263,17 +1277,17 @@ class Uniforms {
var vy: Null<kha.FastFloat> = null;
switch (c.link) {
case "_tilesheetOffset": {
var ts = cast(object, MeshObject).tilesheet;
var ts = cast(object, MeshObject).activeTilesheet;
vx = ts.tileX;
vy = ts.tileY;
}
case "_tilesheetFlip": {
var ts = cast(object, MeshObject).tilesheet;
var ts = cast(object, MeshObject).activeTilesheet;
vx = ts.flipX ? 1.0 : 0.0;
vy = ts.flipY ? 1.0 : 0.0;
}
case "_tilesheetTiles": {
var ts = cast(object, MeshObject).tilesheet;
var ts = cast(object, MeshObject).activeTilesheet;
vx = ts.getTilesX();
vy = ts.getTilesY();
}