diff --git a/src/DifBuilder.hx b/src/DifBuilder.hx index dadecb44..43827552 100644 --- a/src/DifBuilder.hx +++ b/src/DifBuilder.hx @@ -22,7 +22,7 @@ import dif.math.Point3F; import h3d.prim.BigPrimitive; import dif.Interior; import dif.Dif; -import src.InteriorGeometry; +import src.InteriorObject; class DifBuilderTriangle { public var texture:String; @@ -71,7 +71,7 @@ class DifBuilder { } ]; - public static function loadDif(path:String, itr:InteriorGeometry) { + public static function loadDif(path:String, itr:InteriorObject) { var dif = ResourceLoader.loadInterior(path); var geo = dif.interiors[0]; diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 0c6a76d2..6001d35b 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1,17 +1,14 @@ package src; +import src.MarbleWorld; +import src.GameObject; import collision.CollisionHull; import collision.CollisionSurface; import collision.CollisionEntity; import hxd.FloatBuffer; -import h3d.prim.DynamicPrimitive; -import h3d.scene.Trail; import src.DynamicPolygon; -import h3d.mat.Data.Blend; -import h3d.prim.Cube; import dts.Sequence; import h3d.scene.Mesh; -import h3d.scene.CustomObject; import h3d.prim.Polygon; import h3d.prim.UV; import h3d.Vector; @@ -20,7 +17,6 @@ import dts.Node; import h3d.mat.BlendMode; import h3d.mat.Data.Wrap; import h3d.mat.Texture; -import hxd.res.Loader; import h3d.mat.Material; import h3d.scene.Object; import haxe.io.Path; @@ -66,11 +62,13 @@ typedef SkinMeshData = { } @:publicFields -class DtsObject extends Object { +class DtsObject extends GameObject { var dtsPath:String; var directoryPath:String; var dts:DtsFile; + var level:MarbleWorld; + var materials:Array = []; var matNameOverride:Map = new Map(); @@ -79,10 +77,12 @@ class DtsObject extends Object { var graphNodes:Array = []; + var useInstancing:Bool = true; var isTSStatic:Bool; var isCollideable:Bool; var showSequences:Bool = true; var hasNonVisualSequences:Bool = true; + var isInstanced:Bool = false; var _regenNormals:Bool = false; @@ -97,11 +97,14 @@ class DtsObject extends Object { super(); } - public function init() { + public function init(level:MarbleWorld) { this.dts = ResourceLoader.loadDts(this.dtsPath); this.directoryPath = Path.directory(this.dtsPath); + this.level = level; - this.computeMaterials(); + isInstanced = this.level.instanceManager.isInstanced(this) && useInstancing; + if (!isInstanced) + this.computeMaterials(); var graphNodes = []; var rootNodesIdx = []; @@ -150,55 +153,71 @@ class DtsObject extends Object { if (mesh == null) continue; - var vertices = mesh.vertices.map(v -> new Vector(v.x, v.y, v.z)); - var vertexNormals = mesh.normals.map(v -> new Vector(v.x, v.y, v.z)); + if (!isInstanced) { + var vertices = mesh.vertices.map(v -> new Vector(v.x, v.y, v.z)); + var vertexNormals = mesh.normals.map(v -> new Vector(v.x, v.y, v.z)); - var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals); - for (k in 0...geometry.length) { - if (geometry[k].vertices.length == 0) - continue; + var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals); + for (k in 0...geometry.length) { + if (geometry[k].vertices.length == 0) + continue; - var poly = new Polygon(geometry[k].vertices.map(x -> x.toPoint())); - poly.normals = geometry[k].normals.map(x -> x.toPoint()); - poly.uvs = geometry[k].uvs; + var poly = new Polygon(geometry[k].vertices.map(x -> x.toPoint())); + poly.normals = geometry[k].normals.map(x -> x.toPoint()); + poly.uvs = geometry[k].uvs; - var obj = new Mesh(poly, materials[k], this.graphNodes[i]); + var obj = new Mesh(poly, materials[k], this.graphNodes[i]); + } + } else { + var usedMats = []; + + for (prim in mesh.primitives) { + if (!usedMats.contains(prim.matIndex)) { + usedMats.push(prim.matIndex); + } + } + + for (k in usedMats) { + var obj = new Object(this.graphNodes[i]); + } } } } } - for (i in 0...dts.nodes.length) { - var objects = dts.objects.filter(object -> object.node == i); - var meshSurfaces = []; - var collider = new CollisionHull(); + if (this.isCollideable) { + for (i in 0...dts.nodes.length) { + var objects = dts.objects.filter(object -> object.node == i); + var meshSurfaces = []; + var collider = new CollisionHull(); - for (object in objects) { - var isCollisionObject = dts.names[object.name].substr(0, 3).toLowerCase() == "col"; + for (object in objects) { + var isCollisionObject = dts.names[object.name].substr(0, 3).toLowerCase() == "col"; - if (isCollisionObject) { - for (j in object.firstMesh...(object.firstMesh + object.numMeshes)) { - if (j >= this.dts.meshes.length) - continue; + if (isCollisionObject) { + for (j in object.firstMesh...(object.firstMesh + object.numMeshes)) { + if (j >= this.dts.meshes.length) + continue; - var mesh = this.dts.meshes[j]; - if (mesh == null) - continue; + var mesh = this.dts.meshes[j]; + if (mesh == null) + continue; - var vertices = mesh.vertices.map(v -> new Vector(v.x, v.y, v.z)); - var vertexNormals = mesh.normals.map(v -> new Vector(v.x, v.y, v.z)); + var vertices = mesh.vertices.map(v -> new Vector(v.x, v.y, v.z)); + var vertexNormals = mesh.normals.map(v -> new Vector(v.x, v.y, v.z)); - var surfaces = this.generateCollisionGeometry(mesh, vertices, vertexNormals); - for (surface in surfaces) - collider.addSurface(surface); - meshSurfaces = meshSurfaces.concat(surfaces); + var surfaces = this.generateCollisionGeometry(mesh, vertices, vertexNormals); + for (surface in surfaces) + collider.addSurface(surface); + meshSurfaces = meshSurfaces.concat(surfaces); + } } } + if (meshSurfaces.length != 0) + colliders.push(collider); + else + colliders.push(null); } - if (meshSurfaces.length != 0) - colliders.push(collider); - else - colliders.push(null); } this.updateNodeTransforms(); @@ -209,31 +228,52 @@ class DtsObject extends Object { continue; if (mesh.meshType == 1) { - var vertices = mesh.vertices.map(v -> new Vector(v.x, v.y, v.z)); - var vertexNormals = mesh.normals.map(v -> new Vector(v.x, v.y, v.z)); - - var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals); var skinObj = new Object(); - for (k in 0...geometry.length) { - if (geometry[k].vertices.length == 0) - continue; - var poly = new DynamicPolygon(geometry[k].vertices.map(x -> x.toPoint())); - poly.normals = geometry[k].normals.map(x -> x.toPoint()); - poly.uvs = geometry[k].uvs; + if (!isInstanced) { + var vertices = mesh.vertices.map(v -> new Vector(v.x, v.y, v.z)); + var vertexNormals = mesh.normals.map(v -> new Vector(v.x, v.y, v.z)); + var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals); + for (k in 0...geometry.length) { + if (geometry[k].vertices.length == 0) + continue; - var obj = new Mesh(poly, materials[k], skinObj); - } - skinMeshData = { - meshIndex: i, - vertices: vertices, - normals: vertexNormals, - indices: [], - geometry: skinObj - }; - var idx = geometry.map(x -> x.indices); - for (indexes in idx) { - skinMeshData.indices = skinMeshData.indices.concat(indexes); + var poly = new DynamicPolygon(geometry[k].vertices.map(x -> x.toPoint())); + poly.normals = geometry[k].normals.map(x -> x.toPoint()); + poly.uvs = geometry[k].uvs; + + var obj = new Mesh(poly, materials[k], skinObj); + } + skinMeshData = { + meshIndex: i, + vertices: vertices, + normals: vertexNormals, + indices: [], + geometry: skinObj + }; + var idx = geometry.map(x -> x.indices); + for (indexes in idx) { + skinMeshData.indices = skinMeshData.indices.concat(indexes); + } + } else { + var usedMats = []; + + for (prim in mesh.primitives) { + if (!usedMats.contains(prim.matIndex)) { + usedMats.push(prim.matIndex); + } + } + + for (k in usedMats) { + var obj = new Object(skinObj); + } + skinMeshData = { + meshIndex: i, + vertices: [], + normals: [], + indices: [], + geometry: skinObj + }; } } } @@ -243,6 +283,7 @@ class DtsObject extends Object { for (i in rootNodesIdx) { rootObject.addChild(this.graphNodes[i]); } + if (this.skinMeshData != null) { rootObject.addChild(this.skinMeshData.geometry); } @@ -288,9 +329,9 @@ class DtsObject extends Object { if (flags & 16 > 0) material.blendMode = BlendMode.Sub; - if (this.isTSStatic && !(flags & 64 > 0)) { - // TODO THIS SHIT - } + // if (this.isTSStatic && !(flags & 64 > 0)) { + // // TODO THIS SHIT + // } // ((flags & 32) || environmentMaterial) ? new Materia this.materials.push(material); @@ -322,7 +363,7 @@ class DtsObject extends Object { } function generateCollisionGeometry(dtsMesh:dts.Mesh, vertices:Array, vertexNormals:Array) { - var surfaces = this.materials.map(x -> new CollisionSurface()); + var surfaces = this.dts.matNames.map(x -> new CollisionSurface()); for (surface in surfaces) { surface.points = []; surface.normals = []; @@ -374,7 +415,7 @@ class DtsObject extends Object { } function generateMaterialGeometry(dtsMesh:dts.Mesh, vertices:Array, vertexNormals:Array) { - var materialGeometry:Array = this.materials.map(x -> { + var materialGeometry:Array = this.dts.matNames.map(x -> { vertices: [], normals: [], uvs: [], @@ -541,7 +582,7 @@ class DtsObject extends Object { } } - if (this.skinMeshData != null) { + if (this.skinMeshData != null && !isInstanced) { var info = this.skinMeshData; var mesh = this.dts.meshes[info.meshIndex]; @@ -555,7 +596,7 @@ class DtsObject extends Object { for (i in 0...mesh.nodeIndices.length) { var mat = mesh.initialTransforms[i].clone(); mat.transpose(); - var tform = this.graphNodes[mesh.nodeIndices[i]].getAbsPos().clone(); + var tform = this.graphNodes[mesh.nodeIndices[i]].getRelPos(this).clone(); mat.multiply(mat, tform); boneTransformations.push(mat); diff --git a/src/GameObject.hx b/src/GameObject.hx new file mode 100644 index 00000000..98f7626b --- /dev/null +++ b/src/GameObject.hx @@ -0,0 +1,7 @@ +package src; + +import h3d.scene.Object; + +class GameObject extends Object { + public var identifier:String; +} diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx new file mode 100644 index 00000000..ab11cfb6 --- /dev/null +++ b/src/InstanceManager.hx @@ -0,0 +1,78 @@ +package src; + +import h2d.col.Matrix; +import src.GameObject; +import h3d.scene.Scene; +import h3d.scene.Object; +import h3d.scene.Mesh; +import h3d.scene.MeshBatch; + +typedef MeshBatchInfo = { + var instances:Array; + var meshbatch:MeshBatch; + var mesh:Mesh; +} + +class InstanceManager { + var objects:Map> = new Map(); + var scene:Scene; + + public function new(scene:Scene) { + this.scene = scene; + } + + public function update(dt:Float) { + for (obj => meshes in objects) { + for (minfo in meshes) { + if (minfo.meshbatch != null) { + minfo.meshbatch.begin(minfo.instances.length); + for (instance in minfo.instances) { + var transform = instance.getAbsPos().clone(); + minfo.meshbatch.setTransform(transform); + minfo.meshbatch.emitInstance(); + } + } + } + } + } + + public function addObject(object:GameObject) { + function getAllChildren(object:Object):Array { + var ret = [object]; + for (i in 0...object.numChildren) { + ret = ret.concat(getAllChildren(object.getChildAt(i))); + } + return ret; + } + + if (isInstanced(object)) { + // Add existing instance + var objs = getAllChildren(object); + var minfos = objects.get(object.identifier); + for (i in 0...objs.length) { + minfos[i].instances.push(objs[i]); + } + } else { + // First time appending the thing so bruh + var infos = []; + var objs = getAllChildren(object); + var minfos = []; + for (obj in objs) { + 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, + mesh: isMesh ? cast obj : null + } + minfos.push(minfo); + } + objects.set(object.identifier, minfos); + } + } + + public function isInstanced(object:GameObject) { + if (objects.exists(object.identifier)) + return true; + return false; + } +} diff --git a/src/InteriorGeometry.hx b/src/InteriorObject.hx similarity index 64% rename from src/InteriorGeometry.hx rename to src/InteriorObject.hx index 63fb6ac4..a4682a0c 100644 --- a/src/InteriorGeometry.hx +++ b/src/InteriorObject.hx @@ -2,14 +2,10 @@ package src; import h3d.Matrix; import collision.CollisionEntity; -import dif.math.Point3F; -import h3d.scene.Mesh; -import h3d.col.Bounds; -import h3d.scene.RenderContext; -import h3d.prim.Polygon; +import src.GameObject; import h3d.scene.Object; -class InteriorGeometry extends Object { +class InteriorObject extends GameObject { public var collider:CollisionEntity; public function new() { diff --git a/src/Main.hx b/src/Main.hx index 6c16956b..bf2b1ebc 100644 --- a/src/Main.hx +++ b/src/Main.hx @@ -1,9 +1,15 @@ package; +import shapes.Trapdoor; +import shapes.AntiGravity; +import shapes.SuperJump; +import h3d.prim.Polygon; +import src.ResourceLoader; +import src.GameObject; import shapes.Tornado; import shapes.DuctFan; import dts.DtsFile; -import src.InteriorGeometry; +import src.InteriorObject; import h3d.Quat; import src.PathedInteriorMarker; import src.PathedInterior; @@ -28,10 +34,11 @@ class Main extends hxd.App { super.init(); dtsObj = new Tornado(); + dtsObj.x = 5; world = new MarbleWorld(s3d); - var db = new InteriorGeometry(); + var db = new InteriorObject(); DifBuilder.loadDif("data/interiors/beginner/training_friction.dif", db); world.addInterior(db); var tform = db.getTransform(); @@ -44,10 +51,16 @@ class Main extends hxd.App { // pim.setPosition(new Vector(5, 0, 0)); // pi.setTransform(pim); - // var cube = new Cube(); - // cube.addUVs(); + // var cube = new Polygon([new h3d.col.Point(0, 0, 0), new h3d.col.Point(0, 0, 1), new h3d.col.Point(0, 1, 0)]); // cube.addNormals(); - // var mat = Material.create(); + // cube.addUVs(); + // var tex = ResourceLoader.loader.load("data/interiors/arrow_cool1.jpg").toTexture(); + // var mat = Material.create(tex); + // var mesh = new Mesh(cube, mat); + // var go = new GameObject(); + // go.identifier = "lol"; + // go.addChild(mesh); + // world.instanceManager.addObject(go); // var m1 = new PathedInteriorMarker(); // m1.msToNext = 5; @@ -73,6 +86,15 @@ 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 (surf in db.collider.surfaces) { // var surfmin = new CustomObject(cube, mat, s3d); // var bound = surf.boundingBox; @@ -110,6 +132,7 @@ class Main extends hxd.App { } static function main() { + h3d.mat.PbrMaterialSetup.set(); new Main(); } } diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 1eb600c9..14cae2b4 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1,19 +1,22 @@ package src; +import src.InstanceManager; +import h3d.scene.MeshBatch; import src.DtsObject; import src.PathedInterior; import hxd.Key; import h3d.Vector; -import src.InteriorGeometry; +import src.InteriorObject; import h3d.scene.Scene; import h3d.scene.CustomObject; import collision.CollisionWorld; import src.Marble; class MarbleWorld { - var collisionWorld:CollisionWorld; + public var collisionWorld:CollisionWorld; + public var instanceManager:InstanceManager; - public var interiors:Array = []; + public var interiors:Array = []; public var pathedInteriors:Array = []; public var marbles:Array = []; public var dtsObjects:Array = []; @@ -25,9 +28,10 @@ class MarbleWorld { public function new(scene:Scene) { this.collisionWorld = new CollisionWorld(); this.scene = scene; + this.instanceManager = new InstanceManager(scene); } - public function addInterior(obj:InteriorGeometry) { + public function addInterior(obj:InteriorObject) { this.interiors.push(obj); this.collisionWorld.addEntity(obj.collider); this.scene.addChild(obj); @@ -42,8 +46,12 @@ class MarbleWorld { public function addDtsObject(obj:DtsObject) { this.dtsObjects.push(obj); - this.scene.addChild(obj); - obj.init(); + obj.init(cast this); + if (obj.useInstancing) { + 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); @@ -67,6 +75,7 @@ class MarbleWorld { for (marble in marbles) { marble.update(currentTime, dt, collisionWorld, this.pathedInteriors); } + this.instanceManager.update(dt); currentTime += dt; } } diff --git a/src/PathedInterior.hx b/src/PathedInterior.hx index 3da94c94..d248c432 100644 --- a/src/PathedInterior.hx +++ b/src/PathedInterior.hx @@ -4,7 +4,7 @@ import h3d.Matrix; import h3d.Vector; import src.Util; import src.PathedInteriorMarker; -import src.InteriorGeometry; +import src.InteriorObject; typedef PIState = { var currentTime:Float; @@ -15,7 +15,7 @@ typedef PIState = { var velocity:Vector; } -class PathedInterior extends InteriorGeometry { +class PathedInterior extends InteriorObject { public var markerData:Array = []; public var duration:Float; diff --git a/src/ResourceLoader.hx b/src/ResourceLoader.hx index 98831b31..96f869f1 100644 --- a/src/ResourceLoader.hx +++ b/src/ResourceLoader.hx @@ -1,5 +1,6 @@ package src; +import h3d.scene.Object; import sys.FileSystem; import sys.io.File; import haxe.io.Path; diff --git a/src/shapes/AntiGravity.hx b/src/shapes/AntiGravity.hx new file mode 100644 index 00000000..13f99924 --- /dev/null +++ b/src/shapes/AntiGravity.hx @@ -0,0 +1,13 @@ +package shapes; + +import src.DtsObject; + +class AntiGravity extends DtsObject { + public function new() { + super(); + this.dtsPath = "data/shapes/items/antigravity.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.identifier = "AntiGravity"; + } +} diff --git a/src/shapes/DuctFan.hx b/src/shapes/DuctFan.hx index 3360ff5a..b29f03c3 100644 --- a/src/shapes/DuctFan.hx +++ b/src/shapes/DuctFan.hx @@ -9,6 +9,7 @@ class DuctFan extends ForceObject { this.dtsPath = "data/shapes/hazards/ductfan.dts"; this.isCollideable = true; this.isTSStatic = false; + this.identifier = "DuctFan"; this.forceDatas = [ { forceType: ForceCone, diff --git a/src/shapes/SmallDuctFan.hx b/src/shapes/SmallDuctFan.hx index bfa88a64..ea858a42 100644 --- a/src/shapes/SmallDuctFan.hx +++ b/src/shapes/SmallDuctFan.hx @@ -9,6 +9,7 @@ class SmallDuctFan extends ForceObject { this.dtsPath = "data/shapes/hazards/ductfan.dts"; this.isCollideable = true; this.isTSStatic = false; + this.identifier = "DuctFan"; this.forceDatas = [ { forceType: ForceCone, diff --git a/src/shapes/SuperJump.hx b/src/shapes/SuperJump.hx new file mode 100644 index 00000000..8a872385 --- /dev/null +++ b/src/shapes/SuperJump.hx @@ -0,0 +1,13 @@ +package shapes; + +import src.DtsObject; + +class SuperJump extends DtsObject { + public function new() { + super(); + this.dtsPath = "data/shapes/items/superjump.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.identifier = "SuperJump"; + } +} diff --git a/src/shapes/SuperSpeed.hx b/src/shapes/SuperSpeed.hx new file mode 100644 index 00000000..a35bd419 --- /dev/null +++ b/src/shapes/SuperSpeed.hx @@ -0,0 +1,13 @@ +package shapes; + +import src.DtsObject; + +class SuperSpeed extends DtsObject { + public function new() { + super(); + this.dtsPath = "data/shapes/items/superspeed.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.identifier = "SuperSpeed"; + } +} diff --git a/src/shapes/Tornado.hx b/src/shapes/Tornado.hx index e09bf18c..c9791bb0 100644 --- a/src/shapes/Tornado.hx +++ b/src/shapes/Tornado.hx @@ -9,6 +9,8 @@ class Tornado extends ForceObject { this.dtsPath = "data/shapes/hazards/tornado.dts"; this.isCollideable = true; this.isTSStatic = false; + this.identifier = "Tornado"; + // this.useInstancing = false; this.forceDatas = [ { forceType: ForceSpherical, diff --git a/src/shapes/Trapdoor.hx b/src/shapes/Trapdoor.hx new file mode 100644 index 00000000..c95d0ef3 --- /dev/null +++ b/src/shapes/Trapdoor.hx @@ -0,0 +1,15 @@ +package shapes; + +import src.DtsObject; +import h3d.Vector; +import src.ForceObject; + +class Trapdoor extends DtsObject { + public function new() { + super(); + this.dtsPath = "data/shapes/hazards/trapdoor.dts"; + this.isCollideable = true; + this.isTSStatic = false; + this.identifier = "Trapdoor"; + } +}