From 0f3be7d51b6dcb5cb67d9e8945067f4ad14a087c Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Fri, 4 Jun 2021 21:50:34 +0530 Subject: [PATCH] Add interior instancing and animated textures --- src/DtsObject.hx | 50 ++++++++++++++++++++++++++++++++- src/InstanceManager.hx | 2 +- src/InteriorObject.hx | 9 ++++++ src/Main.hx | 23 +++++++-------- src/MarbleWorld.hx | 14 ++++++--- src/PathedInterior.hx | 3 +- src/ResourceLoader.hx | 13 +++++++++ src/collision/CollisionWorld.hx | 11 +++++++- src/shapes/SignFinish.hx | 13 +++++++++ 9 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 src/shapes/SignFinish.hx diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 6001d35b..321132d4 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1,5 +1,6 @@ package src; +import sys.io.File; import src.MarbleWorld; import src.GameObject; import collision.CollisionHull; @@ -70,6 +71,7 @@ class DtsObject extends GameObject { var level:MarbleWorld; var materials:Array = []; + var materialInfos:Map> = new Map(); var matNameOverride:Map = new Map(); var sequenceKeyframeOverride:Map = new Map(); @@ -312,9 +314,11 @@ class DtsObject extends GameObject { // TODO USE PBR??? } } else if (Path.extension(fullName) == "ifl") { + var keyframes = parseIfl(fullName); + this.materialInfos.set(material, keyframes); // TODO IFL SHIT } else { - var texture:Texture = ResourceLoader.loader.load(fullName).toImage().toTexture(); + var texture:Texture = ResourceLoader.getTexture(fullName); texture.wrap = Wrap.Repeat; material.texture = texture; // TODO TRANSLUENCY SHIT @@ -344,6 +348,27 @@ class DtsObject extends GameObject { } } + function parseIfl(path:String) { + var text = File.getContent(path); + var lines = text.split('\n'); + var keyframes = []; + for (line in lines) { + if (line.substr(0, 2) == "//") + continue; + if (line == "") + continue; + + var parts = line.split(' '); + var count = parts.length > 1 ? Std.parseInt(parts[1]) : 1; + + for (i in 0...count) { + keyframes.push(parts[0]); + } + } + + return keyframes; + } + function updateNodeTransforms(quaternions:Array = null, translations:Array = null, bitField = 0xffffffff) { for (i in 0...this.graphNodes.length) { var translation = this.dts.defaultTranslations[i]; @@ -671,6 +696,29 @@ class DtsObject extends GameObject { } } + if (!this.isInstanced) { + for (i in 0...this.materials.length) { + var info = this.materialInfos.get(this.materials[i]); + if (info == null) + continue; + + var iflSequence = this.dts.sequences.filter(seq -> seq.iflMatters.length > 0 ? seq.iflMatters[0] > 0 : false); + if (iflSequence.length == 0 || !this.showSequences) + continue; + + var completion = (currentTime + dt) / (iflSequence[0].duration); + var keyframe = Math.floor(completion * info.length) % info.length; + var currentFile = info[keyframe]; + var texture = ResourceLoader.getTexture(this.directoryPath + '/' + currentFile); + + var flags = this.dts.matFlags[i]; + if (flags & 1 > 0 || flags & 2 > 0) + texture.wrap = Wrap.Repeat; + + this.materials[i].texture = texture; + } + } + for (i in 0...this.colliders.length) { var absTform = this.graphNodes[i].getAbsPos().clone(); if (this.colliders[i] != null) diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index ab11cfb6..254ea81e 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -61,7 +61,7 @@ class InstanceManager { var isMesh = obj is Mesh; var minfo:MeshBatchInfo = { instances: [obj], - meshbatch: isMesh ? new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material, scene) : null, + meshbatch: isMesh ? new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material.clone(), scene) : null, mesh: isMesh ? cast obj : null } minfos.push(minfo); diff --git a/src/InteriorObject.hx b/src/InteriorObject.hx index a4682a0c..3618df10 100644 --- a/src/InteriorObject.hx +++ b/src/InteriorObject.hx @@ -1,5 +1,7 @@ package src; +import src.MarbleWorld; +import src.DifBuilder; import h3d.Matrix; import collision.CollisionEntity; import src.GameObject; @@ -7,11 +9,18 @@ import h3d.scene.Object; class InteriorObject extends GameObject { public var collider:CollisionEntity; + public var interiorFile:String; + public var useInstancing = true; public function new() { super(); } + public function init(level:MarbleWorld) { + this.identifier = this.interiorFile; + DifBuilder.loadDif(this.interiorFile, cast this); + } + public override function setTransform(transform:Matrix) { super.setTransform(transform); collider.setTransform(transform); diff --git a/src/Main.hx b/src/Main.hx index bf2b1ebc..0a776690 100644 --- a/src/Main.hx +++ b/src/Main.hx @@ -1,5 +1,6 @@ package; +import shapes.SignFinish; import shapes.Trapdoor; import shapes.AntiGravity; import shapes.SuperJump; @@ -33,13 +34,13 @@ class Main extends hxd.App { override function init() { super.init(); - dtsObj = new Tornado(); - dtsObj.x = 5; + dtsObj = new SignFinish(); + dtsObj.z = 5; world = new MarbleWorld(s3d); var db = new InteriorObject(); - DifBuilder.loadDif("data/interiors/beginner/training_friction.dif", db); + db.interiorFile = "data/interiors/beginner/training_friction.dif"; world.addInterior(db); var tform = db.getTransform(); tform.setPosition(new Vector(0, 0, 7.5)); @@ -86,14 +87,14 @@ class Main extends hxd.App { world.addDtsObject(dtsObj); - for (i in 0...10) { - for (j in 0...10) { - var trapdoor = new Tornado(); - trapdoor.x = i * 2; - trapdoor.y = j * 2; - world.addDtsObject(trapdoor); - } - } + // for (i in 0...10) { + // for (j in 0...10) { + // var trapdoor = new Tornado(); + // trapdoor.x = i * 2; + // trapdoor.y = j * 2; + // world.addDtsObject(trapdoor); + // } + // } // for (surf in db.collider.surfaces) { // var surfmin = new CustomObject(cube, mat, s3d); diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 14cae2b4..7dd6b9cd 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -33,15 +33,22 @@ class MarbleWorld { public function addInterior(obj:InteriorObject) { this.interiors.push(obj); + obj.init(cast this); this.collisionWorld.addEntity(obj.collider); - this.scene.addChild(obj); + if (obj.useInstancing) + this.instanceManager.addObject(obj); + else + this.scene.addChild(obj); } public function addPathedInterior(obj:PathedInterior) { this.pathedInteriors.push(obj); + obj.init(cast this); this.collisionWorld.addMovingEntity(obj.collider); - this.scene.addChild(obj); - obj.init(); + if (obj.useInstancing) + this.instanceManager.addObject(obj); + else + this.scene.addChild(obj); } public function addDtsObject(obj:DtsObject) { @@ -51,7 +58,6 @@ class MarbleWorld { this.instanceManager.addObject(obj); } else this.scene.addChild(obj); - // this.instanceManager.addObject(obj); for (collider in obj.colliders) { if (collider != null) this.collisionWorld.addEntity(collider); diff --git a/src/PathedInterior.hx b/src/PathedInterior.hx index d248c432..ec1b11c4 100644 --- a/src/PathedInterior.hx +++ b/src/PathedInterior.hx @@ -1,5 +1,6 @@ package src; +import src.MarbleWorld; import h3d.Matrix; import h3d.Vector; import src.Util; @@ -37,7 +38,7 @@ class PathedInterior extends InteriorObject { super(); } - public function init() { + public override function init(level:MarbleWorld) { this.computeDuration(); this.reset(); } diff --git a/src/ResourceLoader.hx b/src/ResourceLoader.hx index 96f869f1..737d8e7e 100644 --- a/src/ResourceLoader.hx +++ b/src/ResourceLoader.hx @@ -1,5 +1,6 @@ package src; +import h3d.mat.Texture; import h3d.scene.Object; import sys.FileSystem; import sys.io.File; @@ -15,6 +16,7 @@ class ResourceLoader { public static var loader = new Loader(fileSystem); static var interiorResources:Map = new Map(); static var dtsResources:Map = new Map(); + static var textureCache:Map = new Map(); public static function loadInterior(path:String) { if (interiorResources.exists(path)) @@ -37,6 +39,17 @@ class ResourceLoader { } } + public static function getTexture(path:String) { + if (textureCache.exists(path)) + return textureCache.get(path); + if (fileSystem.exists(path)) { + var tex = loader.load(path).toTexture(); + textureCache.set(path, tex); + return tex; + } + return null; + } + public static function clearInteriorResources() { interiorResources = new Map(); } diff --git a/src/collision/CollisionWorld.hx b/src/collision/CollisionWorld.hx index b298cca4..e8de221a 100644 --- a/src/collision/CollisionWorld.hx +++ b/src/collision/CollisionWorld.hx @@ -21,6 +21,14 @@ class CollisionWorld { var searchdist = (velocity.length() * dt) + radius; var intersections = this.octree.radiusSearch(position, searchdist); + var box = new Bounds(); + box.xMin = position.x - radius; + box.yMin = position.y - radius; + box.zMin = position.z - radius; + box.xMax = position.x + radius; + box.yMax = position.y + radius; + box.zMax = position.z + radius; + var contacts = []; for (obj in intersections) { @@ -31,7 +39,8 @@ class CollisionWorld { for (obj in dynamicEntities) { if (obj != spherecollision) { - contacts = contacts.concat(obj.sphereIntersection(spherecollision, dt)); + if (obj.boundingBox.collide(box)) + contacts = contacts.concat(obj.sphereIntersection(spherecollision, dt)); } } return contacts; diff --git a/src/shapes/SignFinish.hx b/src/shapes/SignFinish.hx new file mode 100644 index 00000000..9a39509d --- /dev/null +++ b/src/shapes/SignFinish.hx @@ -0,0 +1,13 @@ +package shapes; + +import src.DtsObject; + +class SignFinish extends DtsObject { + public function new() { + super(); + this.dtsPath = "data/shapes/signs/finishlinesign.dts"; + this.isCollideable = true; + this.identifier = "SignFinish"; + this.useInstancing = false; + } +}