diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index bfef35d8..c2af062d 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -2138,6 +2138,7 @@ Fix many places where entity position being set on vector fetched from getPositi Undo getPosition new alloc to lower memory footprint Work to reduce allocations Prevent mouse event re-allocation every frame +More allocation work diff --git a/src/main/java/electrosphere/client/sim/ClientSimulation.java b/src/main/java/electrosphere/client/sim/ClientSimulation.java index 7adf1679..ae13dc01 100644 --- a/src/main/java/electrosphere/client/sim/ClientSimulation.java +++ b/src/main/java/electrosphere/client/sim/ClientSimulation.java @@ -1,5 +1,7 @@ package electrosphere.client.sim; +import java.util.HashSet; + import org.joml.Vector3d; import electrosphere.client.entity.camera.CameraEntityUtils; @@ -31,6 +33,11 @@ public class ClientSimulation { //used for tracking different in player position between frames (principally for draw cell manager) Vector3d newPlayerCharacterPosition = new Vector3d(); + + /** + * Set for storing entities of a specific tag + */ + private HashSet entityTagSet = new HashSet(); /** * Constructor @@ -71,7 +78,8 @@ public class ClientSimulation { //update actor animations Globals.profiler.beginCpuSample("update actor animations"); - for(Entity currentEntity : Globals.clientState.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE)){ + Globals.clientState.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE, entityTagSet); + for(Entity currentEntity : entityTagSet){ Actor currentActor = EntityUtils.getActor(currentEntity); if(currentActor.getLodLevel() == Actor.LOD_LEVEL_STATIC){ continue; @@ -84,7 +92,8 @@ public class ClientSimulation { // //make items play idle animation Globals.profiler.beginCpuSample("item animations"); - for(Entity item : Globals.clientState.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.ITEM)){ + Globals.clientState.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.ITEM, entityTagSet); + for(Entity item : entityTagSet){ ItemUtils.updateItemActorAnimation(item); } Globals.profiler.endCpuSample(); @@ -114,7 +123,8 @@ public class ClientSimulation { // //sum collidable impulses Globals.profiler.beginCpuSample("collidable logic"); - for(Entity collidable : Globals.clientState.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){ + Globals.clientState.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE, entityTagSet); + for(Entity collidable : entityTagSet){ if(ClientCollidableTree.hasClientCollidableTree(collidable)){ ClientCollidableTree.getClientCollidableTree(collidable).simulate((float)Globals.engineState.timekeeper.getSimFrameTime()); } diff --git a/src/main/java/electrosphere/data/utils/DataFormatUtil.java b/src/main/java/electrosphere/data/utils/DataFormatUtil.java index 37cab40c..1e8796a8 100644 --- a/src/main/java/electrosphere/data/utils/DataFormatUtil.java +++ b/src/main/java/electrosphere/data/utils/DataFormatUtil.java @@ -52,6 +52,23 @@ public class DataFormatUtil { } } + /** + * Gets the vector in vector3d form + * @param values The list of raw float values + * @param tempVec The vec to set the values to + * @return The vector containing those values or an identity vector if no such values exist + */ + public static Vector3d getDoubleListAsVector(List values, Vector3d tempVec){ + if(values == null){ + return tempVec; + } + if(values.size() > 0){ + return tempVec.set(values.get(0),values.get(1),values.get(2)); + } else { + return tempVec; + } + } + /** * Gets a vector as a list of doubles * @param vec The vector diff --git a/src/main/java/electrosphere/entity/scene/Scene.java b/src/main/java/electrosphere/entity/scene/Scene.java index 04a8a309..ffb2f5a3 100644 --- a/src/main/java/electrosphere/entity/scene/Scene.java +++ b/src/main/java/electrosphere/entity/scene/Scene.java @@ -142,6 +142,22 @@ public class Scene { return rVal; } + /** + * Gets all entities registered to a tag + * @param tag The tag + * @param set The pre-existing set to populate + * @return A list of all entities with the tag, or null if no entities have been added to the tag yet + */ + public Set getEntitiesWithTag(String tag, Set set){ + lock.lock(); + set.clear(); + if(tagEntityMap.containsKey(tag)){ + set.addAll(tagEntityMap.get(tag)); + } + lock.unlock(); + return set; + } + /** * Removes an entity from a tag * @param e The entity diff --git a/src/main/java/electrosphere/entity/state/attach/AttachUtils.java b/src/main/java/electrosphere/entity/state/attach/AttachUtils.java index fc240c54..34adbbfc 100644 --- a/src/main/java/electrosphere/entity/state/attach/AttachUtils.java +++ b/src/main/java/electrosphere/entity/state/attach/AttachUtils.java @@ -340,13 +340,44 @@ public class AttachUtils { Vector3d bonePosition, Quaterniond boneRotation, + //parent transforms + Vector3d parentPosition, + Quaterniond parentRotation, + Vector3d parentScale + ){ + return AttachUtils.calculateBoneAttachmentLocalPosition(new Vector3d(), offsetVector, offsetRotation, bonePosition, boneRotation, parentPosition, parentRotation, parentScale); + } + + /** + * Calculates the position of an entity attached to a bone + * @param offsetVector The offset position + * @param offsetRotation The offset rotation + * @param bonePosition The bone's position + * @param boneRotation The bone's rotation + * @param parentPosition The parent's position + * @param parentRotation The parent's rotation + * @param parentScale The parent's scale + * @return The position of the attached/child entity + */ + public static Vector3d calculateBoneAttachmentLocalPosition( + //The vector to store the result in + Vector3d res, + + //optional offsets + Vector3d offsetVector, + Quaterniond offsetRotation, + + //current bone transform + Vector3d bonePosition, + Quaterniond boneRotation, + //parent transforms Vector3d parentPosition, Quaterniond parentRotation, Vector3d parentScale ){ //transform bone space - Vector3d position = new Vector3d(offsetVector); + Vector3d position = res.set(offsetVector); position = position.rotate(new Quaterniond(boneRotation)); position = position.add(bonePosition); position = position.mul(parentScale); diff --git a/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java b/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java index 6f75d674..60ffa86e 100644 --- a/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java +++ b/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java @@ -73,12 +73,12 @@ public class ServerCollidableTree implements BehaviorTree { Impulse[] impulses = collidable.getImpulses(); Vector3d pos = EntityUtils.getPosition(parent); for(int i = 0; i < collidable.getImpulseCount(); i++){ - if(impulses[i].type.matches(Collidable.TYPE_CREATURE)){ + if(impulses[i].type.equals(Collidable.TYPE_CREATURE)){ if(ServerGravityTree.getServerGravityTree(parent)!=null){ ServerGravityTree.getServerGravityTree(parent).start(); } } - if(impulses[i].type.matches(Collidable.TYPE_WORLD_BOUND) || impulses[i].type.matches(Collidable.TYPE_STATIC)){ + if(impulses[i].type.equals(Collidable.TYPE_WORLD_BOUND) || impulses[i].type.equals(Collidable.TYPE_STATIC)){ this.resetGravityFall(); pos.add(impulses[i].getDirection().mul(impulses[i].getForce())); } diff --git a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java index e218ff78..978efcf9 100644 --- a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java +++ b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java @@ -26,6 +26,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.state.attach.AttachUtils; import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState.HitboxShapeType; import electrosphere.logger.LoggerInterface; +import electrosphere.mem.JomlPool; import electrosphere.server.datacell.Realm; import electrosphere.server.entity.poseactor.PoseActor; import electrosphere.util.math.SpatialMathUtils; @@ -457,8 +458,13 @@ public class HitboxCollectionState { private void updateSphereShapePosition(CollisionEngine collisionEngine, String boneName, HitboxState hitboxState, Vector3d bonePosition){ DGeom geom = this.stateGeomMap.get(hitboxState); + //get pooled objects + Vector3d offsetPosition = JomlPool.getD(); + Vector3d parentScale = JomlPool.getD(); + Vector3d finalPos = JomlPool.getD(); + //get offset's transform - Vector3d offsetPosition = DataFormatUtil.getDoubleListAsVector(hitboxState.getHitboxData().getOffset()); + offsetPosition = DataFormatUtil.getDoubleListAsVector(hitboxState.getHitboxData().getOffset(),offsetPosition); Quaterniond offsetRotation = new Quaterniond(); //the bone's transform @@ -471,15 +477,19 @@ public class HitboxCollectionState { //the parent's transform Vector3d parentPosition = EntityUtils.getPosition(parent); Quaterniond parentRotation = EntityUtils.getRotation(parent); - Vector3d parentScale = new Vector3d(); parentScale.set(EntityUtils.getScale(parent)); //calculate - Vector3d hitboxPos = AttachUtils.calculateBoneAttachmentLocalPosition(offsetPosition, offsetRotation, bonePositionD, boneRotation, parentPosition, parentRotation, parentScale); + Vector3d hitboxPos = AttachUtils.calculateBoneAttachmentLocalPosition(finalPos, offsetPosition, offsetRotation, bonePositionD, boneRotation, parentPosition, parentRotation, parentScale); //actually set value PhysicsEntityUtils.setGeometryOffsetPosition(collisionEngine, geom, hitboxPos, new Quaterniond()); + + //release pooled objects + JomlPool.release(offsetPosition); + JomlPool.release(parentScale); + JomlPool.release(finalPos); } /** diff --git a/src/main/java/electrosphere/mem/JomlPool.java b/src/main/java/electrosphere/mem/JomlPool.java index 6a4f603f..8165e673 100644 --- a/src/main/java/electrosphere/mem/JomlPool.java +++ b/src/main/java/electrosphere/mem/JomlPool.java @@ -4,6 +4,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.locks.ReentrantLock; +import org.joml.Matrix4d; import org.joml.Vector3d; import org.joml.Vector3f; @@ -22,6 +23,11 @@ public class JomlPool { */ static List vec3dPool = new LinkedList(); + /** + * Structure to store not-in-use objects + */ + static List mat4dPool = new LinkedList(); + /** * Lock for thread-safeing operations */ @@ -75,6 +81,22 @@ public class JomlPool { return rVal; } + /** + * Gets a Matrix4d from the pool. Allocates if no free one is available. + * @return A Matrix4d + */ + public static Matrix4d getMat(){ + Matrix4d rVal = null; + lock.lock(); + if(mat4dPool.size() > 0){ + rVal = mat4dPool.remove(0); + } else { + rVal = new Matrix4d(); + } + lock.unlock(); + return rVal; + } + /** * Releases a Vector3d back into the pool * @param data The object to release @@ -90,4 +112,17 @@ public class JomlPool { lock.unlock(); } + /** + * Releases a Matrix4d back into the pool + * @param data The object to release + */ + public static void release(Matrix4d data){ + data.identity(); + lock.lock(); + if(JomlPool.mat4dPool.size() < 1000){ + JomlPool.mat4dPool.add(data); + } + lock.unlock(); + } + } diff --git a/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java b/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java index 3056d780..edd32b18 100644 --- a/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java +++ b/src/main/java/electrosphere/renderer/actor/ActorStaticMorph.java @@ -134,6 +134,8 @@ public class ActorStaticMorph { Vector3f offset = new Vector3f(0,0,0); Vector3f scale = new Vector3f(1,1,1); + Matrix4f transform = null; + public Quaternionf getRotation(){ return new Quaternionf().rotateXYZ(yaw, pitch, roll); } @@ -147,9 +149,11 @@ public class ActorStaticMorph { } public Matrix4f getTransform(){ - Matrix4f rVal = new Matrix4f(); - rVal.translationRotateScale(offset, getRotation(), scale); - return rVal; + if(transform == null){ + transform = new Matrix4f(); + } + transform.translationRotateScale(offset, getRotation(), scale); + return transform; } } diff --git a/src/main/java/electrosphere/renderer/anim/AnimNode.java b/src/main/java/electrosphere/renderer/anim/AnimNode.java index f33868f9..f9c131b7 100644 --- a/src/main/java/electrosphere/renderer/anim/AnimNode.java +++ b/src/main/java/electrosphere/renderer/anim/AnimNode.java @@ -25,11 +25,11 @@ public class AnimNode { this.raw_data = raw_data; } - public Matrix4d getTransform(){ - return new Matrix4d(transform); + public void getTransform(Matrix4d loc){ + loc.set(transform); } public void setTransform(Matrix4d transform){ - this.transform = new Matrix4d(transform); + this.transform.set(transform); } } diff --git a/src/main/java/electrosphere/renderer/model/Model.java b/src/main/java/electrosphere/renderer/model/Model.java index 992ce0b1..263f51bb 100644 --- a/src/main/java/electrosphere/renderer/model/Model.java +++ b/src/main/java/electrosphere/renderer/model/Model.java @@ -13,6 +13,7 @@ import electrosphere.renderer.meshgen.MeshLoader; import electrosphere.renderer.anim.AnimNode; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; +import electrosphere.mem.JomlPool; import java.util.ArrayList; import java.util.Collections; @@ -415,9 +416,10 @@ public class Model { * @param staticMorph The static morph to apply */ private void updateNodeTransform(AnimNode n, Map boneRotators, ActorStaticMorph staticMorph){ - Matrix4d currentTransform = n.getTransform().identity(); + Matrix4d poolMat = JomlPool.getMat(); + //grab parent transform if exists if(n.parent != null){ - currentTransform.set(n.parent.getTransform()); + n.parent.getTransform(poolMat); } if(n.is_bone){ // @@ -430,33 +432,33 @@ public class Model { message = message + "bone map key set: " + boneMap.keySet() + "\n"; throw new Error(message); } - currentTransform.mul(target_bone.getDeform()); + poolMat.mul(target_bone.getDeform()); if(boneRotators.containsKey(target_bone.boneID)){ - currentTransform.rotate(boneRotators.get(target_bone.boneID).getRotation()); + poolMat.rotate(boneRotators.get(target_bone.boneID).getRotation()); } // //static morph (changing nose size, eye distance, etc) if(staticMorph != null && staticMorph.getBoneTransforms(n.id) != null){ - currentTransform.mul(staticMorph.getBoneTransforms(n.id).getTransform()); + poolMat.mul(staticMorph.getBoneTransforms(n.id).getTransform()); } // - Matrix4d bone_matrix = currentTransform; - n.setTransform(currentTransform); + n.setTransform(poolMat); // //Calculate final offset from initial bone //https://stackoverflow.com/a/59869381 - bone_matrix.mul(target_bone.getMOffset()); - bone_matrix = globalInverseTransform.mul(bone_matrix, bone_matrix); - target_bone.setFinalTransform(bone_matrix); + poolMat.mul(target_bone.getMOffset()); + poolMat = globalInverseTransform.mul(poolMat, poolMat); + target_bone.setFinalTransform(poolMat); } else { - n.setTransform(currentTransform.mul(electrosphere.util.Utilities.convertAIMatrix(n.raw_data.mTransformation()))); + n.setTransform(poolMat.mul(electrosphere.util.Utilities.convertAIMatrix(n.raw_data.mTransformation()))); } Iterator node_iterator = n.children.iterator(); while(node_iterator.hasNext()){ AnimNode current_node = node_iterator.next(); updateNodeTransform(current_node,boneRotators,staticMorph); } + JomlPool.release(poolMat); } /** diff --git a/src/main/java/electrosphere/renderer/pipelines/FoliagePipeline.java b/src/main/java/electrosphere/renderer/pipelines/FoliagePipeline.java index c516c852..a37a36fb 100644 --- a/src/main/java/electrosphere/renderer/pipelines/FoliagePipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/FoliagePipeline.java @@ -1,5 +1,6 @@ package electrosphere.renderer.pipelines; +import java.util.HashSet; import java.util.Set; import org.joml.Matrix4d; @@ -26,9 +27,14 @@ public class FoliagePipeline implements RenderPipeline { */ static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,8); + /** + * Set for storing entities of a specific tag + */ + private HashSet entityTagSet = new HashSet(); + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { - Set foliageEntities = Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_FOLIAGE_PASS); + Set foliageEntities = Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_FOLIAGE_PASS, entityTagSet); if(foliageEntities != null){ for(Entity foliageEntity : foliageEntities){ Matrix4d modelMatrix = new Matrix4d(); diff --git a/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java b/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java index 87385d1b..4853e155 100644 --- a/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/MainContentPipeline.java @@ -1,5 +1,6 @@ package electrosphere.renderer.pipelines; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -49,6 +50,11 @@ public class MainContentPipeline implements RenderPipeline { */ private int terrainChunks = 0; + /** + * Set for storing entities of a specific tag + */ + private HashSet entityTagSet = new HashSet(); + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("MainContentPipeline.render"); @@ -202,7 +208,8 @@ public class MainContentPipeline implements RenderPipeline { Globals.renderingEngine.getFoliagePipeline().render(openGLState, renderPipelineState); Globals.profiler.endCpuSample(); Globals.profiler.beginCpuSample("MainContentPipeline.render - Solids instanced"); - for(Entity currentEntity : Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED)){ + Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED, entityTagSet); + for(Entity currentEntity : entityTagSet){ Vector3d position = EntityUtils.getPosition(currentEntity); if(MainContentPipeline.shouldDrawSolidPass(currentEntity)){ //fetch actor @@ -266,7 +273,8 @@ public class MainContentPipeline implements RenderPipeline { // Globals.profiler.beginCpuSample("MainContentPipeline.render - Transparents non-instanced"); - for(Entity currentEntity : Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ + Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE, entityTagSet); + for(Entity currentEntity : entityTagSet){ Vector3d position = EntityUtils.getPosition(currentEntity); if(MainContentPipeline.shouldDrawTransparentPass(currentEntity)){ //fetch actor @@ -285,7 +293,8 @@ public class MainContentPipeline implements RenderPipeline { } Globals.profiler.endCpuSample(); Globals.profiler.beginCpuSample("MainContentPipeline.render - Transparents instanced"); - for(Entity currentEntity : Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED)){ + Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED, entityTagSet); + for(Entity currentEntity : entityTagSet){ Vector3d position = EntityUtils.getPosition(currentEntity); if(MainContentPipeline.shouldDrawTransparentPass(currentEntity)){ //fetch actor diff --git a/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java b/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java index 318ede35..4289ff29 100644 --- a/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java +++ b/src/main/java/electrosphere/renderer/target/DrawTargetEvaluator.java @@ -1,5 +1,6 @@ package electrosphere.renderer.target; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -33,6 +34,16 @@ public class DrawTargetEvaluator { * Cutoff after which we draw lower resolution models */ public static final int LOD_LOWER_CUTOFF = 30; + + /** + * Set for storing entities of a specific tag + */ + private static final HashSet drawableSet = new HashSet(); + + /** + * Set for storing entities of a specific tag + */ + private static final HashSet shadowSet = new HashSet(); /** * Evaluates the draw targets @@ -67,8 +78,8 @@ public class DrawTargetEvaluator { Vector3d positionVec = new Vector3d(); //different entity lists - Set drawables = Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE); - Set shadowList = Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_CAST_SHADOW); + Set drawables = Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE, drawableSet); + Set shadowList = Globals.clientState.clientScene.getEntitiesWithTag(EntityTags.DRAW_CAST_SHADOW, shadowSet); for(Entity currentEntity : drawables){ Vector3d position = EntityUtils.getPosition(currentEntity); diff --git a/src/main/java/electrosphere/server/entity/poseactor/PoseModel.java b/src/main/java/electrosphere/server/entity/poseactor/PoseModel.java index b6cfeef9..042e8dc0 100644 --- a/src/main/java/electrosphere/server/entity/poseactor/PoseModel.java +++ b/src/main/java/electrosphere/server/entity/poseactor/PoseModel.java @@ -17,6 +17,7 @@ import org.lwjgl.assimp.AIScene; import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; +import electrosphere.mem.JomlPool; import electrosphere.renderer.actor.ActorBoneRotator; import electrosphere.renderer.actor.ActorStaticMorph; import electrosphere.renderer.anim.AnimChannel; @@ -200,10 +201,10 @@ public class PoseModel { * @param staticMorph The static morph */ private void updateNodeTransform(AnimNode n, Map boneRotators, ActorStaticMorph staticMorph){ + Matrix4d poolMat = JomlPool.getMat(); //grab parent transform if exists - Matrix4d currentTransform = n.getTransform().identity(); if(n.parent != null){ - currentTransform.set(n.parent.getTransform()); + n.parent.getTransform(poolMat); } //if this is a bone, calculate the transform for the bone if(n.is_bone){ @@ -215,23 +216,23 @@ public class PoseModel { message = message + "bone map key set: " + boneMap.keySet() + "\n"; throw new Error(message); } - currentTransform.mul(target_bone.getDeform()); + poolMat.mul(target_bone.getDeform()); if(boneRotators.containsKey(target_bone.boneID)){ - currentTransform.rotate(boneRotators.get(target_bone.boneID).getRotation()); + poolMat.rotate(boneRotators.get(target_bone.boneID).getRotation()); } - n.setTransform(currentTransform); + n.setTransform(poolMat); if(staticMorph != null && staticMorph.getBoneTransforms(n.id) != null){ - currentTransform.mul(staticMorph.getBoneTransforms(n.id).getTransform()); + poolMat.mul(staticMorph.getBoneTransforms(n.id).getTransform()); } // //Calculate final offset from initial bone //https://stackoverflow.com/a/59869381 - currentTransform.mul(target_bone.getMOffset()); - currentTransform = globalInverseTransform.mul(currentTransform, currentTransform); - target_bone.setFinalTransform(currentTransform); + poolMat.mul(target_bone.getMOffset()); + poolMat = globalInverseTransform.mul(poolMat, poolMat); + target_bone.setFinalTransform(poolMat); } else { //not a bone, so use transform directly from data - n.setTransform(currentTransform.mul(electrosphere.util.Utilities.convertAIMatrix(n.raw_data.mTransformation()))); + n.setTransform(poolMat.mul(electrosphere.util.Utilities.convertAIMatrix(n.raw_data.mTransformation()))); } //update all children accordingly Iterator node_iterator = n.children.iterator(); @@ -239,6 +240,7 @@ public class PoseModel { AnimNode current_node = node_iterator.next(); this.updateNodeTransform(current_node,boneRotators,staticMorph); } + JomlPool.release(poolMat); } /**