From d018adfab772ce6a36c90fd5d5ac1d78ca2210b7 Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Wed, 20 Mar 2024 18:40:47 +0530 Subject: [PATCH] perf improvement - remove unnecessary allocs --- src/DtsObject.hx | 21 +++++---------- src/InstanceManager.hx | 36 ++++++++++++++++---------- src/Marble.hx | 33 ++++++++++++++++++------ src/Radar.hx | 51 +++++++++++++++++++++++++++++-------- src/Util.hx | 22 ++++++++-------- src/octree/IOctreeObject.hx | 4 ++- 6 files changed, 108 insertions(+), 59 deletions(-) diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 6c42a0eb..94b5cc05 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1132,10 +1132,6 @@ class DtsObject extends GameObject { completion = Util.clamp((timeState.timeSinceLoad - doSequenceOnceBeginTime) / sequence.duration, 0, 0.98); } - var quaternions:Array = null; - var translations:Array = null; - var scales:Array = null; - var actualKeyframe = this.sequenceKeyframeOverride.exists(sequence) ? this.sequenceKeyframeOverride.get(sequence) : ((completion * sequence.numKeyFrames) % sequence.numKeyFrames); if (this.lastSequenceKeyframes.get(sequence) == actualKeyframe) continue; @@ -1148,8 +1144,6 @@ class DtsObject extends GameObject { var t = (actualKeyframe - keyframeLow) % 1; if (rot > 0) { - quaternions = []; - for (i in 0...this.dts.nodes.length) { var affected = ((1 << i) & rot) != 0; @@ -1169,7 +1163,8 @@ class DtsObject extends GameObject { quat.slerp(q1, q2, t); quat.normalize(); - this.graphNodes[i].setRotationQuat(quat); + this.graphNodes[i].getRotationQuat().load(quat); + this.graphNodes[i].posChanged = true; propagateDirtyFlags(i); affectedCount++; // quaternions.push(quat); @@ -1178,7 +1173,8 @@ class DtsObject extends GameObject { var quat = new Quat(-rotation.x, rotation.y, rotation.z, -rotation.w); quat.normalize(); quat.conjugate(); - this.graphNodes[i].setRotationQuat(quat); + this.graphNodes[i].getRotationQuat().load(quat); + this.graphNodes[i].posChanged = true; // quaternions.push(quat); } } @@ -1186,8 +1182,6 @@ class DtsObject extends GameObject { affectedCount = 0; if (trans > 0) { - translations = []; - for (i in 0...this.dts.nodes.length) { var affected = ((1 << i) & trans) != 0; @@ -1213,8 +1207,6 @@ class DtsObject extends GameObject { affectedCount = 0; if (scale > 0) { - scales = []; - if (sequence.flags & 1 > 0) { // Uniform scales for (i in 0...this.dts.nodes.length) { var affected = ((1 << i) & scale) != 0; @@ -1433,10 +1425,11 @@ class DtsObject extends GameObject { var spinAnimation = new Quat(); spinAnimation.initRotateAxis(0, 0, -1, timeState.timeSinceLoad * this.ambientSpinFactor); - var orientation = this.getRotationQuat(); + // var orientation = this.getRotationQuat(); // spinAnimation.multiply(orientation, spinAnimation); - this.rootObject.setRotationQuat(spinAnimation); + this.rootObject.getRotationQuat().load(spinAnimation); + this.rootObject.posChanged = true; } for (i in 0...this.colliders.length) { diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index 3514b46b..75eadf7d 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -54,33 +54,42 @@ class InstanceManager { } public function render() { - var renderFrustums = [scene.camera.frustum]; + var renderFrustum = scene.camera.frustum; + var doFrustumCheck = true; // This sucks holy shit - if (MarbleGame.instance.world != null + doFrustumCheck = MarbleGame.instance.world != null && MarbleGame.instance.world.marble != null - && MarbleGame.instance.world.marble.cubemapRenderer != null) - renderFrustums = renderFrustums.concat(MarbleGame.instance.world.marble.cubemapRenderer.getCameraFrustums()); + && MarbleGame.instance.world.marble.cubemapRenderer != null; + // renderFrustums = renderFrustums.concat(MarbleGame.instance.world.marble.cubemapRenderer.getCameraFrustums()); for (meshes in objects) { for (minfo in meshes) { - var visibleinstances = []; + var opaqueinstances = []; + var transparentinstances = []; // Culling if (minfo.meshbatch != null || minfo.transparencymeshbatch != null) { for (inst in minfo.instances) { - var objBounds = @:privateAccess cast(minfo.meshbatch.primitive, Instanced).baseBounds.clone(); - objBounds.transform(inst.emptyObj.getAbsPos()); - for (frustum in renderFrustums) { - if (frustum.hasBounds(objBounds)) { - visibleinstances.push(inst); - break; - } + // for (frustum in renderFrustums) { + // if (frustum.hasBounds(objBounds)) { + if (doFrustumCheck) { + var objBounds = @:privateAccess cast(minfo.meshbatch.primitive, Instanced).baseBounds.clone(); + objBounds.transform(inst.emptyObj.getAbsPos()); + + if (!renderFrustum.hasBounds(objBounds)) + continue; } + if (inst.gameObject.currentOpacity == 1) + opaqueinstances.push(inst); + else if (inst.gameObject.currentOpacity != 0) + transparentinstances.push(inst); + // break; + // } + // } } } // Emit non culled primitives if (minfo.meshbatch != null) { - var opaqueinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity == 1); minfo.meshbatch.begin(opaqueinstances.length); for (instance in opaqueinstances) { // Draw the opaque shit first var dtsShader = minfo.dtsShader; // minfo.meshbatch.material.mainPass.getShader(DtsTexture); @@ -123,7 +132,6 @@ class InstanceManager { } } if (minfo.transparencymeshbatch != null) { - var transparentinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity != 1 && x.gameObject.currentOpacity != 0); // Filter out all zero opacity things too minfo.transparencymeshbatch.begin(transparentinstances.length); for (instance in transparentinstances) { // Non opaque shit var dtsShader = minfo.dtsShader; diff --git a/src/Marble.hx b/src/Marble.hx index b06af672..56839257 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -184,6 +184,25 @@ final blastMaxParticleOptions:ParticleEmitterOptions = { } } +@:publicFields +@:structInit +class MarbleTestMoveFoundContact { + var v:Array; + var n:Vector; +} + +@:publicFields +@:structInit +class MarbleTestMoveResult { + var position:Vector; + var t:Float; + var found:Bool; + var foundContacts:Array; + var lastContactPos:Null; + var lastContactNormal:Null; + var foundMarbles:Array; +} + class Marble extends GameObject { public var camera:CameraController; public var cameraObject:Object; @@ -721,7 +740,7 @@ class Marble extends GameObject { normP.scale(1 + bounce); - velocity.load(velocity.sub(normP.multiply(ourMass))); + velocity.load(velocity.sub(normP.multiply(1 / ourMass))); otherMarble.velocity.load(otherMarble.velocity.add(normP.multiply(1 / theirMass))); contacts[i].velocity.load(otherMarble.velocity); @@ -1063,7 +1082,7 @@ class Marble extends GameObject { } } - function testMove(velocity:Vector, position:Vector, deltaT:Float, radius:Float, testPIs:Bool) { + function testMove(velocity:Vector, position:Vector, deltaT:Float, radius:Float, testPIs:Bool):MarbleTestMoveResult { if (velocity.length() < 0.001) { return { position: position, @@ -1087,7 +1106,7 @@ class Marble extends GameObject { var lastContactPos = new Vector(); - var testTriangles = []; + var testTriangles:Array = []; var finalContacts = []; var foundMarbles = []; @@ -1149,7 +1168,8 @@ class Marble extends GameObject { Math.max(Math.max(sphereRadius.x, sphereRadius.y), sphereRadius.z) * 2); var currentFinalPos = position.add(relVel.multiply(finalT)); // localpos.add(relLocalVel.multiply(finalT)); - var surfaces = obj.bvh == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.bvh.boundingSearch(boundThing); + var surfaces = @:privateAccess obj.grid != null ? @:privateAccess obj.grid.boundingSearch(boundThing) : (obj.bvh == null ? obj.octree.boundingSearch(boundThing) + .map(x -> cast x) : obj.bvh.boundingSearch(boundThing)); for (surf in surfaces) { var surface:CollisionSurface = cast surf; @@ -1399,10 +1419,7 @@ class Marble extends GameObject { }; } - function nudgeToContacts(position:Vector, radius:Float, foundContacts:Array<{ - v:Array, - n:Vector - }>, foundMarbles:Array) { + function nudgeToContacts(position:Vector, radius:Float, foundContacts:Array, foundMarbles:Array) { var it = 0; var concernedContacts = foundContacts; // PathedInteriors have their own nudge logic var prevResolved = 0; diff --git a/src/Radar.hx b/src/Radar.hx index 4b877d44..a7245496 100644 --- a/src/Radar.hx +++ b/src/Radar.hx @@ -24,6 +24,8 @@ class Radar { var time:Float = 0.0; + var _dirty = false; + public function new(level:MarbleWorld, scene2d:Scene) { this.level = level; this.scene2d = scene2d; @@ -35,7 +37,12 @@ class Radar { public function update(dt:Float) { time += dt; + _dirty = true; + } + public function render() { + if (!_dirty) + return; g.clear(); var gemCount = 0; for (gem in level.gems) { @@ -47,6 +54,7 @@ class Radar { if (@:privateAccess level.endPad != null && gemCount == 0) { renderArrow(@:privateAccess level.endPad.getAbsPos().getPosition(), 0xE6E6E6); } + _dirty = false; } public function blink() { @@ -64,8 +72,30 @@ class Radar { g = null; } + inline function planeDistance(plane:h3d.col.Plane, p:Vector) { + return @:privateAccess plane.nx * p.x + @:privateAccess plane.ny * p.y + @:privateAccess plane.nz * p.z - @:privateAccess plane.d; + } + + function frustumHasPoint(frustum:h3d.col.Frustum, p:Vector) { + if (planeDistance(frustum.pleft, p) < 0) + return false; + if (planeDistance(frustum.pright, p) < 0) + return false; + if (planeDistance(frustum.ptop, p) < 0) + return false; + if (planeDistance(frustum.pbottom, p) < 0) + return false; + if (frustum.checkNearFar) { + if (planeDistance(frustum.pnear, p) < 0) + return false; + if (planeDistance(frustum.pfar, p) < 0) + return false; + } + return true; + } + function renderArrow(pos:Vector, color:Int) { - var validProjection = level.scene.camera.frustum.hasPoint(pos.toPoint()); + var validProjection = frustumHasPoint(level.scene.camera.frustum, pos); var projectedPos = level.scene.camera.project(pos.x, pos.y, pos.z, scene2d.width, scene2d.height); var fovX = (level.scene.camera.getFovX() * 0.5) * Math.PI / 180.0; @@ -100,12 +130,13 @@ class Radar { cc2.normalize(); sd.normalize(); - var arrowPos = new Vector(); + var arrowPosY = 0.0; + var arrowPosX = 0.0; if (cc1.y >= sd.y) { if (cc2.y <= sd.y) { - arrowPos.y = scene2d.height * ((sd.x * cc1.y - cc1.x * sd.y) / (sd.y * (cc2.x - cc1.x) - (cc2.y - cc1.y) * sd.x)); + arrowPosY = scene2d.height * ((sd.x * cc1.y - cc1.x * sd.y) / (sd.y * (cc2.x - cc1.x) - (cc2.y - cc1.y) * sd.x)); } else { - arrowPos.y = scene2d.height; + arrowPosY = scene2d.height; } } var r1 = shapeDist.transformed(gravityMat); @@ -139,21 +170,19 @@ class Radar { if (-fovX <= xfPosAngle) { if (fovX >= xfPosAngle) { // the new x is the fraction of where it is but convert it from an angle to tangent - arrowPos.x = scene2d.width * 0.5 + Math.tan(xfPosAngle) * (scene2d.width * 0.5) / Math.tan(fovX); + arrowPosX = scene2d.width * 0.5 + Math.tan(xfPosAngle) * (scene2d.width * 0.5) / Math.tan(fovX); } else { // otherwise snap to edge - arrowPos.x = scene2d.width; + arrowPosX = scene2d.width; } } - var drawPoint = new Vector(); - if (!validProjection) { - drawPoint.load(arrowPos); - } else { + var drawPoint = new Vector(arrowPosX, arrowPosY); + if (validProjection) { drawPoint.load(projectedPos); if (drawPoint.distanceSq(projectedPos) <= 75 * 75) { var distOff = drawPoint.distance(projectedPos); - drawPoint = Util.lerpThreeVectors(projectedPos, arrowPos, distOff / 75); + drawPoint = Util.lerpThreeVectors(projectedPos, new Vector(arrowPosX, arrowPosY), distOff / 75); } } diff --git a/src/Util.hx b/src/Util.hx index 0279be6e..ea17a42a 100644 --- a/src/Util.hx +++ b/src/Util.hx @@ -11,18 +11,18 @@ import h3d.Vector; import src.Settings; class Util { - public static function mat3x3equal(a:Matrix, b:Matrix) { + public static inline function mat3x3equal(a:Matrix, b:Matrix) { return a._11 == b._11 && a._12 == b._12 && a._13 == b._13 && a._21 == b._21 && a._22 == b._22 && a._23 == b._23 && a._31 == b._31 && a._32 == b._32 && a._33 == b._33; } - public static function adjustedMod(a:Float, n:Float) { + public static inline function adjustedMod(a:Float, n:Float) { var r1 = a % n; var r2 = (r1 + n) % n; return r2; } - public static function clamp(value:Float, min:Float, max:Float) { + public static inline function clamp(value:Float, min:Float, max:Float) { if (value < min) return min; if (value > max) @@ -30,11 +30,11 @@ class Util { return value; } - public static function lerp(a:Float, b:Float, t:Float) { + public static inline function lerp(a:Float, b:Float, t:Float) { return a + (b - a) * t; } - public static function catmullRom(t:Float, p0:Float, p1:Float, p2:Float, p3:Float) { + public static inline function catmullRom(t:Float, p0:Float, p1:Float, p2:Float, p3:Float) { var point = t * t * t * ((-1) * p0 + 3 * p1 - 3 * p2 + p3) / 2; point += t * t * (2 * p0 - 5 * p1 + 4 * p2 - p3) / 2; point += t * ((-1) * p0 + p2) / 2; @@ -42,7 +42,7 @@ class Util { return point; } - public static function lerpThreeVectors(v1:Vector, v2:Vector, t:Float) { + public static inline function lerpThreeVectors(v1:Vector, v2:Vector, t:Float) { return new Vector(lerp(v1.x, v2.x, t), lerp(v1.y, v2.y, t), lerp(v1.z, v2.z, t), lerp(v1.w, v2.w, t)); } @@ -342,7 +342,7 @@ class Util { '${(hours > 0 ? (hoursTen > 0 ? '${hoursTen}' : '') +'${hoursOne}' + ':' : '')}${minutesTen}${minutesOne}:${secondsTen}${secondsOne}.${hundredthTen}${hundredthOne}${thousandth}'; } - public static function rightPad(str:String, len:Int, cutOff:Int) { + public static inline function rightPad(str:String, len:Int, cutOff:Int) { str = str.substring(0, len - cutOff); while (str.length < len) str += " "; @@ -420,7 +420,7 @@ class Util { #end } - public static function isSafari() { + public static inline function isSafari() { #if js var reg = ~/^((?!chrome|android).)*safari/; return reg.match(js.Browser.navigator.userAgent); @@ -430,7 +430,7 @@ class Util { #end } - public static function isInFullscreen() { + public static inline function isInFullscreen() { #if js return (js.Browser.window.innerHeight == js.Browser.window.screen.height || (js.Browser.window.screen.orientation.type == js.html.OrientationType.PORTRAIT_PRIMARY @@ -443,7 +443,7 @@ class Util { #end } - public static function toASCII(bytes:haxe.io.Bytes) { + public static inline function toASCII(bytes:haxe.io.Bytes) { var totBytes = new BytesBuffer(); for (i in 0...bytes.length) { var utfbytes = Bytes.ofString(String.fromCharCode(bytes.get(i))); @@ -453,7 +453,7 @@ class Util { return totBytes.getBytes().toString(); } - public static function getPlatform() { + public static inline function getPlatform() { #if js return js.Browser.navigator.platform; #end diff --git a/src/octree/IOctreeObject.hx b/src/octree/IOctreeObject.hx index 479547cb..ec7d1885 100644 --- a/src/octree/IOctreeObject.hx +++ b/src/octree/IOctreeObject.hx @@ -3,7 +3,9 @@ package octree; import h3d.Vector; import h3d.col.Bounds; -typedef RayIntersectionData = { +@:publicFields +@:structInit +class RayIntersectionData { var point:Vector; var normal:Vector; var object:IOctreeObject;