diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 9e5ffc94..05d301f8 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -2060,6 +2060,7 @@ Code cleanup More tests Move actor masks into dedicated package Actor code cleanup +Refactor animation logic into dedicated actor class diff --git a/src/main/java/electrosphere/client/sim/ClientSimulation.java b/src/main/java/electrosphere/client/sim/ClientSimulation.java index 75347f69..1c1fd5c9 100644 --- a/src/main/java/electrosphere/client/sim/ClientSimulation.java +++ b/src/main/java/electrosphere/client/sim/ClientSimulation.java @@ -76,8 +76,8 @@ public class ClientSimulation { if(currentActor.getLodLevel() == Actor.LOD_LEVEL_STATIC){ continue; } - if(currentActor.isPlayingAnimation()){ - currentActor.incrementAnimationTime((float)Globals.engineState.timekeeper.getSimFrameTime()); + if(currentActor.getAnimationData().isPlayingAnimation()){ + currentActor.getAnimationData().incrementAnimationTime((float)Globals.engineState.timekeeper.getSimFrameTime()); } } Globals.profiler.endCpuSample(); diff --git a/src/main/java/electrosphere/client/ui/components/CharacterCustomizer.java b/src/main/java/electrosphere/client/ui/components/CharacterCustomizer.java index 77b83e3b..77d05144 100644 --- a/src/main/java/electrosphere/client/ui/components/CharacterCustomizer.java +++ b/src/main/java/electrosphere/client/ui/components/CharacterCustomizer.java @@ -97,7 +97,7 @@ public class CharacterCustomizer { sliderName.setMinWidth(200); //add a slider Slider boneSlider = Slider.createSlider((ValueChangeEvent event) -> { - if(characterActor.getStaticMorph() != null){ + if(characterActor.getAnimationData().getStaticMorph() != null){ staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat()); if(attribute.getMirrorBone() != null){ staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat()); @@ -167,7 +167,7 @@ public class CharacterCustomizer { } } //finally set static morph - characterActor.setActorStaticMorph(staticMorph); + characterActor.getAnimationData().setActorStaticMorph(staticMorph); //character create button Div createButtonContainer = Div.createDiv(); diff --git a/src/main/java/electrosphere/client/ui/menu/debug/entity/tabs/ImGuiEntityActorTab.java b/src/main/java/electrosphere/client/ui/menu/debug/entity/tabs/ImGuiEntityActorTab.java index 0db19333..b3d5aa07 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/entity/tabs/ImGuiEntityActorTab.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/entity/tabs/ImGuiEntityActorTab.java @@ -75,7 +75,7 @@ public class ImGuiEntityActorTab { //animation queue if(ImGui.collapsingHeader("Animation Queue")){ - Set animationQueue = actor.getAnimationQueue(); + Set animationQueue = actor.getAnimationData().getAnimationQueue(); for(ActorAnimationMaskEntry mask : animationQueue){ ImGui.text(mask.getAnimationName() + " - " + mask.getPriority()); ImGui.text(mask.getDuration() + " " + mask.getTime()); @@ -84,10 +84,10 @@ public class ImGuiEntityActorTab { //bone values if(ImGui.collapsingHeader("Bone Values")){ - for(Bone bone : actor.getBoneValues()){ + for(Bone bone : actor.getAnimationData().getBoneValues()){ ImGui.text(bone.boneID); - ImGui.text("Position: " + actor.getBonePosition(bone.boneID)); - ImGui.text("Rotation: " + actor.getBoneRotation(bone.boneID)); + ImGui.text("Position: " + actor.getAnimationData().getBonePosition(bone.boneID)); + ImGui.text("Rotation: " + actor.getAnimationData().getBoneRotation(bone.boneID)); ImGui.text(bone.getFinalTransform() + ""); } } @@ -104,7 +104,7 @@ public class ImGuiEntityActorTab { for(Animation animation : model.getAnimations()){ if(ImGui.collapsingHeader(animation.name)){ if(ImGui.button("Play")){ - actor.playAnimation(animation.name, AnimationPriorities.getValue(AnimationPriorities.MODIFIER_MAX)); + actor.getAnimationData().playAnimation(animation.name, AnimationPriorities.getValue(AnimationPriorities.MODIFIER_MAX)); } for(AnimChannel channel : animation.channels){ ImGui.pushID(channel.getNodeID()); @@ -131,7 +131,7 @@ public class ImGuiEntityActorTab { if(ImGui.collapsingHeader("Print Data")){ //print bone values if(ImGui.button("Print current bone values")){ - for(Bone bone : actor.getBoneValues()){ + for(Bone bone : actor.getAnimationData().getBoneValues()){ LoggerInterface.loggerRenderer.DEBUG(bone.boneID); LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform()); } diff --git a/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsInGame.java b/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsInGame.java index 9b8458c1..899fe67f 100644 --- a/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsInGame.java +++ b/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsInGame.java @@ -362,7 +362,7 @@ public class MenuGeneratorsInGame { Entity playerEntity = Globals.clientState.playerEntity; Actor playerActor = EntityUtils.getActor(playerEntity); - ActorStaticMorph staticMorph = playerActor.getStaticMorph(); + ActorStaticMorph staticMorph = playerActor.getAnimationData().getStaticMorph(); CreatureData playeCreatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getType(CreatureUtils.getType(playerEntity)); int offset = 0; for(VisualAttribute attribute : playeCreatureType.getVisualAttributes()){ diff --git a/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java b/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java index 0ab38c40..1f3b62dc 100644 --- a/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java +++ b/src/main/java/electrosphere/entity/btree/StateTransitionUtil.java @@ -138,11 +138,11 @@ public class StateTransitionUtil { // //Play main animation // - if(!actor.isPlayingAnimation() && state.onComplete != null && state.startedAnimation == true){ + if(!actor.getAnimationData().isPlayingAnimation() && state.onComplete != null && state.startedAnimation == true){ //state transition if this isn't set to loop state.onComplete.run(); state.startedAnimation = false; - } else if(!actor.isPlayingAnimation() || !actor.isPlayingAnimation(animation)){ + } else if(!actor.getAnimationData().isPlayingAnimation() || !actor.getAnimationData().isPlayingAnimation(animation)){ // //if it isn't looping, only play on first go around @@ -167,10 +167,10 @@ public class StateTransitionUtil { // //play animation if(animation != null){ - actor.playAnimation(animation,true); + actor.getAnimationData().playAnimation(animation,true); shouldPlayFirstPerson = true; } - actor.incrementAnimationTime(animationOffset); + actor.getAnimationData().incrementAnimationTime(animationOffset); } state.startedAnimation = true; } else if(state.animation == null && state.onComplete != null){ @@ -272,8 +272,8 @@ public class StateTransitionUtil { // //Interrupt main animation // - if(animation != null && actor.isPlayingAnimation() && actor.isPlayingAnimation(animation)){ - actor.interruptAnimation(animation, true); + if(animation != null && actor.getAnimationData().isPlayingAnimation() && actor.getAnimationData().isPlayingAnimation(animation)){ + actor.getAnimationData().interruptAnimation(animation, true); } // diff --git a/src/main/java/electrosphere/entity/state/attach/AttachUtils.java b/src/main/java/electrosphere/entity/state/attach/AttachUtils.java index babff618..14ac4226 100644 --- a/src/main/java/electrosphere/entity/state/attach/AttachUtils.java +++ b/src/main/java/electrosphere/entity/state/attach/AttachUtils.java @@ -208,8 +208,8 @@ public class AttachUtils { child, new Vector3d(offset), new Quaterniond(AttachUtils.getRotationOffset(child)), - new Vector3d(parentActor.getBonePosition(targetBone)), - new Quaterniond(parentActor.getBoneRotation(targetBone)), + new Vector3d(parentActor.getAnimationData().getBonePosition(targetBone)), + new Quaterniond(parentActor.getAnimationData().getBoneRotation(targetBone)), new Vector3d(EntityUtils.getPosition(parent)), new Quaterniond(EntityUtils.getRotation(parent)), new Vector3d(EntityUtils.getScale(parent)) diff --git a/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java b/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java index b1dcc9d3..4935dce5 100644 --- a/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java +++ b/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java @@ -564,11 +564,11 @@ public class ClientAttackTree implements BehaviorTree { Actor actor = EntityUtils.getActor(parent); if(this.currentMove != null && this.currentMove.getHitstun() != null){ String animName = this.currentMove.getAttackState().getAnimation().getNameThirdPerson(); - actor.setFreezeFrames(animName, this.currentMove.getHitstun()); + actor.getAnimationData().setFreezeFrames(animName, this.currentMove.getHitstun()); if(parent == Globals.clientState.playerEntity && !Globals.controlHandler.cameraIsThirdPerson()){ Actor viewmodelActor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); animName = this.currentMove.getAttackState().getAnimation().getNameFirstPerson(); - viewmodelActor.setFreezeFrames(animName, this.currentMove.getHitstun()); + viewmodelActor.getAnimationData().setFreezeFrames(animName, this.currentMove.getHitstun()); } } } diff --git a/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java b/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java index 6b99d548..17d5a2f5 100644 --- a/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java +++ b/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java @@ -402,7 +402,7 @@ public class ServerAttackTree implements BehaviorTree { if(targetBone != null){ Actor parentActor = EntityUtils.getActor(parent); //transform bone space - spawnPosition = new Vector3d(parentActor.getBonePosition(targetBone)); + spawnPosition = new Vector3d(parentActor.getAnimationData().getBonePosition(targetBone)); spawnPosition = spawnPosition.mul(((Vector3f)EntityUtils.getScale(parent))); Quaterniond rotation = EntityUtils.getRotation(parent); spawnPosition = spawnPosition.rotate(new Quaterniond(rotation.x,rotation.y,rotation.z,rotation.w)); @@ -414,7 +414,7 @@ public class ServerAttackTree implements BehaviorTree { // Quaternionf rotation = parentActor.getBoneRotation(targetBone); // EntityUtils.getRotation(currentEntity).set(rotation).normalize(); // Vector3d facingAngle = CreatureUtils.getFacingVector(parent); - arrowRotation = parentActor.getBoneRotation(targetBone); + arrowRotation = parentActor.getAnimationData().getBoneRotation(targetBone); // EntityUtils.getRotation(currentEntity).rotationTo(MathUtils.ORIGIN_VECTORF, new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize(); } Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize(); diff --git a/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java b/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java index 2de9dc04..07e986c3 100644 --- a/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java +++ b/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java @@ -106,11 +106,11 @@ public class FirstPersonTree implements BehaviorTree { if(Globals.clientState.firstPersonEntity != null){ Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); if( - (!actor.isPlayingAnimation() || !actor.isPlayingAnimation(animationName)) && + (!actor.getAnimationData().isPlayingAnimation() || !actor.getAnimationData().isPlayingAnimation(animationName)) && (Globals.assetManager.fetchModel(actor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(actor.getBaseModelPath()).getAnimation(animationName) != null) ){ - actor.playAnimation(animationName,priority); - actor.incrementAnimationTime(offset); + actor.getAnimationData().playAnimation(animationName,priority); + actor.getAnimationData().incrementAnimationTime(offset); } } } @@ -132,11 +132,11 @@ public class FirstPersonTree implements BehaviorTree { if(Globals.clientState.firstPersonEntity != null){ Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); if( - (!actor.isPlayingAnimation() || !actor.isPlayingAnimation(animation.getNameFirstPerson())) && + (!actor.getAnimationData().isPlayingAnimation() || !actor.getAnimationData().isPlayingAnimation(animation.getNameFirstPerson())) && (Globals.assetManager.fetchModel(actor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(actor.getBaseModelPath()).getAnimation(animation.getNameFirstPerson()) != null) ){ - actor.playAnimation(animation, false); - actor.incrementAnimationTime(offset); + actor.getAnimationData().playAnimation(animation, false); + actor.getAnimationData().incrementAnimationTime(offset); } } } @@ -149,10 +149,10 @@ public class FirstPersonTree implements BehaviorTree { if(Globals.clientState.firstPersonEntity != null){ Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); if( - (actor.isPlayingAnimation() || actor.isPlayingAnimation(animation.getNameFirstPerson())) && + (actor.getAnimationData().isPlayingAnimation() || actor.getAnimationData().isPlayingAnimation(animation.getNameFirstPerson())) && (Globals.assetManager.fetchModel(actor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(actor.getBaseModelPath()).getAnimation(animation.getNameFirstPerson()) != null) ){ - actor.interruptAnimation(animation, false); + actor.getAnimationData().interruptAnimation(animation, false); } } } diff --git a/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java b/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java index daaaf143..3769b845 100644 --- a/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java +++ b/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java @@ -361,11 +361,11 @@ public class ClientEquipState implements BehaviorTree { if(point.getEquippedAnimation() != null){ TreeDataAnimation animation = point.getEquippedAnimation(); //play third person - if(thirdPersonActor.isPlayingAnimation() && thirdPersonActor.isPlayingAnimation(animation)){ + if(thirdPersonActor.getAnimationData().isPlayingAnimation() && thirdPersonActor.getAnimationData().isPlayingAnimation(animation)){ if(animation != null){ - thirdPersonActor.interruptAnimation(animation,true); + thirdPersonActor.getAnimationData().interruptAnimation(animation,true); } - thirdPersonActor.incrementAnimationTime(0.0001); + thirdPersonActor.getAnimationData().incrementAnimationTime(0.0001); } //play first person @@ -451,11 +451,11 @@ public class ClientEquipState implements BehaviorTree { if(this.hasEquippedAtPoint(point.getEquipPointId()) && point.getEquippedAnimation() != null){ TreeDataAnimation animation = point.getEquippedAnimation(); //play third person - if(!thirdPersonActor.isPlayingAnimation() || !thirdPersonActor.isPlayingAnimation(animation)){ + if(!thirdPersonActor.getAnimationData().isPlayingAnimation() || !thirdPersonActor.getAnimationData().isPlayingAnimation(animation)){ if(animation != null){ - thirdPersonActor.playAnimation(animation,true); + thirdPersonActor.getAnimationData().playAnimation(animation,true); } - thirdPersonActor.incrementAnimationTime(0.0001); + thirdPersonActor.getAnimationData().incrementAnimationTime(0.0001); } //play first person diff --git a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java index 4c8da02e..ddc717d1 100644 --- a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java +++ b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java @@ -256,11 +256,11 @@ public class ClientToolbarState implements BehaviorTree { if(targetPoint.getEquippedAnimation() != null){ TreeDataAnimation animation = targetPoint.getEquippedAnimation(); //play third person - if(thirdPersonActor.isPlayingAnimation() && thirdPersonActor.isPlayingAnimation(animation)){ + if(thirdPersonActor.getAnimationData().isPlayingAnimation() && thirdPersonActor.getAnimationData().isPlayingAnimation(animation)){ if(animation != null){ - thirdPersonActor.interruptAnimation(animation,true); + thirdPersonActor.getAnimationData().interruptAnimation(animation,true); } - thirdPersonActor.incrementAnimationTime(0.0001); + thirdPersonActor.getAnimationData().incrementAnimationTime(0.0001); } //play first person diff --git a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java index e2ce1ea1..79ece7c3 100644 --- a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java +++ b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java @@ -339,8 +339,8 @@ public class HitboxCollectionState { } PhysicsUtils.setRigidBodyTransform(collisionEngine, entityPosition, new Quaterniond(), body); for(String boneName : this.boneHitboxMap.keySet()){ - if(EntityUtils.getActor(parent).containsBone(boneName)){ - Vector3d bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName); + if(EntityUtils.getActor(parent).getAnimationData().containsBone(boneName)){ + Vector3d bonePosition = EntityUtils.getActor(parent).getAnimationData().getBonePosition(boneName); for(HitboxState state : this.boneHitboxMap.get(boneName)){ DGeom geom = this.stateGeomMap.get(state); HitboxState shapeStatus = this.geomStateMap.get(geom); diff --git a/src/main/java/electrosphere/entity/state/idle/ClientIdleTree.java b/src/main/java/electrosphere/entity/state/idle/ClientIdleTree.java index d54b4be5..fce1ae1f 100644 --- a/src/main/java/electrosphere/entity/state/idle/ClientIdleTree.java +++ b/src/main/java/electrosphere/entity/state/idle/ClientIdleTree.java @@ -78,15 +78,15 @@ public class ClientIdleTree implements BehaviorTree { if(entityActor != null){ if( idleData != null && - (!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(idleData.getAnimation())) && + (!entityActor.getAnimationData().isPlayingAnimation() || !entityActor.getAnimationData().isPlayingAnimation(idleData.getAnimation())) && ( Globals.assetManager.fetchModel(entityActor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(entityActor.getBaseModelPath()).getAnimation(idleData.getAnimation().getNameThirdPerson()) != null ) ){ - entityActor.playAnimation(idleData.getAnimation(),true); - entityActor.incrementAnimationTime(0.0001); + entityActor.getAnimationData().playAnimation(idleData.getAnimation(),true); + entityActor.getAnimationData().incrementAnimationTime(0.0001); } if(idleData != null){ FirstPersonTree.conditionallyPlayAnimation(parent, idleData.getAnimation()); diff --git a/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java b/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java index 8bb2bc00..1af795c9 100644 --- a/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java +++ b/src/main/java/electrosphere/entity/state/movement/fall/ClientFallTree.java @@ -120,7 +120,7 @@ public class ClientFallTree implements BehaviorTree { boolean isPlayingJump = false; Actor entityActor = EntityUtils.getActor(parent); if(entityActor != null && ClientJumpTree.getClientJumpTree(parent) != null){ - isPlayingJump = entityActor.isPlayingAnimation(ClientJumpTree.getClientJumpTree(parent).getJumpData().getAnimationJump()); + isPlayingJump = entityActor.getAnimationData().isPlayingAnimation(ClientJumpTree.getClientJumpTree(parent).getJumpData().getAnimationJump()); } boolean rVal = frameCurrent > ServerFallTree.MIN_FRAMES_BEFORE_ACTIVATION_SCAN && @@ -141,10 +141,10 @@ public class ClientFallTree implements BehaviorTree { Actor entityActor = EntityUtils.getActor(parent); if(entityActor != null){ if( - !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(fallMovementSystem.getLandState().getAnimation().getNameThirdPerson()) + !entityActor.getAnimationData().isPlayingAnimation() || !entityActor.getAnimationData().isPlayingAnimation(fallMovementSystem.getLandState().getAnimation().getNameThirdPerson()) ){ - entityActor.playAnimation(fallMovementSystem.getLandState().getAnimation().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER)); - entityActor.incrementAnimationTime(0.0001); + entityActor.getAnimationData().playAnimation(fallMovementSystem.getLandState().getAnimation().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER)); + entityActor.getAnimationData().incrementAnimationTime(0.0001); } FirstPersonTree.conditionallyPlayAnimation(parent, fallMovementSystem.getLandState().getAnimation()); } diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java index 70fc2b1e..c0edf7e7 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java @@ -309,9 +309,9 @@ public class ClientGroundMovementTree implements BehaviorTree { //play animation String animationToPlay = determineCorrectAnimation(MovementTreeState.STARTUP); if(entityActor != null){ - if(!entityActor.isPlayingAnimation(animationToPlay)){ - entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); - entityActor.incrementAnimationTime(0.0001); + if(!entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){ + entityActor.getAnimationData().playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); + entityActor.getAnimationData().incrementAnimationTime(0.0001); //reset footstep tracking this.playedFootstepFirst = false; this.playedFootstepSecond = false; @@ -319,7 +319,7 @@ public class ClientGroundMovementTree implements BehaviorTree { FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationStartup().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); } //conditionally play footstep audio - this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); + this.playFootstepAudio(0,entityActor.getAnimationData().getAnimationTime(animationToPlay),position); this.updateVelocity(); float velocity = this.getModifiedVelocity(); @@ -347,9 +347,9 @@ public class ClientGroundMovementTree implements BehaviorTree { //play animation String animationToPlay = determineCorrectAnimation(MovementTreeState.MOVE); if(entityActor != null){ - if(!entityActor.isPlayingAnimation(animationToPlay)){ - entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); - entityActor.incrementAnimationTime(0.0001); + if(!entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){ + entityActor.getAnimationData().playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); + entityActor.getAnimationData().incrementAnimationTime(0.0001); //reset footstep tracking this.playedFootstepFirst = false; this.playedFootstepSecond = false; @@ -358,7 +358,7 @@ public class ClientGroundMovementTree implements BehaviorTree { } //conditionally play footstep audio - this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); + this.playFootstepAudio(0,entityActor.getAnimationData().getAnimationTime(animationToPlay),position); this.updateVelocity(); float velocity = this.getModifiedVelocity(); @@ -380,20 +380,20 @@ public class ClientGroundMovementTree implements BehaviorTree { String animationToPlay = determineCorrectAnimation(MovementTreeState.SLOWDOWN); if(entityActor != null){ //play animations - if(!entityActor.isPlayingAnimation(animationToPlay)){ - entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); - entityActor.incrementAnimationTime(0.0001); + if(!entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){ + entityActor.getAnimationData().playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); + entityActor.getAnimationData().incrementAnimationTime(0.0001); //reset footstep tracking this.playedFootstepFirst = false; this.playedFootstepSecond = false; } FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationWindDown().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); - if(entityActor.isPlayingAnimation(determineCorrectAnimation(MovementTreeState.MOVE))){ - entityActor.stopAnimation(determineCorrectAnimation(MovementTreeState.MOVE)); + if(entityActor.getAnimationData().isPlayingAnimation(determineCorrectAnimation(MovementTreeState.MOVE))){ + entityActor.getAnimationData().stopAnimation(determineCorrectAnimation(MovementTreeState.MOVE)); } } //conditionally play footstep audio - this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); + this.playFootstepAudio(0,entityActor.getAnimationData().getAnimationTime(animationToPlay),position); //velocity stuff this.updateVelocity(); @@ -404,8 +404,8 @@ public class ClientGroundMovementTree implements BehaviorTree { state = MovementTreeState.IDLE; if(entityActor != null){ animationToPlay = determineCorrectAnimation(MovementTreeState.SLOWDOWN); - if(entityActor.isPlayingAnimation() && entityActor.isPlayingAnimation(animationToPlay)){ - entityActor.stopAnimation(animationToPlay); + if(entityActor.getAnimationData().isPlayingAnimation() && entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){ + entityActor.getAnimationData().stopAnimation(animationToPlay); } } CreatureUtils.setVelocity(parent, velocity); diff --git a/src/main/java/electrosphere/entity/state/movement/jump/ClientJumpTree.java b/src/main/java/electrosphere/entity/state/movement/jump/ClientJumpTree.java index 5f682f5d..4638c502 100644 --- a/src/main/java/electrosphere/entity/state/movement/jump/ClientJumpTree.java +++ b/src/main/java/electrosphere/entity/state/movement/jump/ClientJumpTree.java @@ -95,9 +95,9 @@ public class ClientJumpTree implements BehaviorTree { switch(state){ case ACTIVE: { if(entityActor != null){ - if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(jumpData.getAnimationJump().getNameThirdPerson())){ - entityActor.playAnimation(jumpData.getAnimationJump().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER)); - entityActor.incrementAnimationTime(0.0001); + if(!entityActor.getAnimationData().isPlayingAnimation() || !entityActor.getAnimationData().isPlayingAnimation(jumpData.getAnimationJump().getNameThirdPerson())){ + entityActor.getAnimationData().playAnimation(jumpData.getAnimationJump().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER)); + entityActor.getAnimationData().incrementAnimationTime(0.0001); } FirstPersonTree.conditionallyPlayAnimation(parent, jumpData.getAnimationJump()); } diff --git a/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java b/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java index 0dc19c04..f464d109 100644 --- a/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java +++ b/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java @@ -42,7 +42,7 @@ public class RotatorTree implements BehaviorTree{ state = RotatorTreeState.INACTIVE; //clear all modifications we've made up to this point for(RotatorHierarchyNode node : nodes){ - entityActor.getBoneRotator(node.getBone()).getRotation().identity(); + entityActor.getAnimationData().getBoneRotator(node.getBone()).getRotation().identity(); } } } @@ -70,7 +70,7 @@ public class RotatorTree implements BehaviorTree{ // currentRotation. } if(followsView){ - ActorBoneRotator currentRotator = entityActor.getBoneRotator(node.getBone()); + ActorBoneRotator currentRotator = entityActor.getAnimationData().getBoneRotator(node.getBone()); //apparently this isn't needed? //not sure I understand the math on this one // Vector3d facingVector = CreatureUtils.getFacingVector(parent); diff --git a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java index b60ce475..b955e917 100644 --- a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java @@ -380,7 +380,7 @@ public class CommonEntityUtils { for(RotatorItem item : system.getRotatorItems()){ //put actor rotator ActorBoneRotator newRotator = new ActorBoneRotator(); - creatureActor.addBoneRotator(item.getBoneName(), newRotator); + creatureActor.getAnimationData().addBoneRotator(item.getBoneName(), newRotator); //construct node for tree RotatorHierarchyNode hierarchyNode = new RotatorHierarchyNode(); hierarchyNode.setBone(item.getBoneName()); @@ -394,7 +394,7 @@ public class CommonEntityUtils { } //bone groups if(rawType.getBoneGroups() != null){ - creatureActor.setBoneGroups(rawType.getBoneGroups()); + creatureActor.getAnimationData().setBoneGroups(rawType.getBoneGroups()); } //grid alignment if(rawType.getGridAlignedData() != null){ diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 47b0c879..55c86383 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -107,7 +107,7 @@ public class CreatureUtils { if(attributeType.getType().equals("bone")){ if(staticMorph == null){ staticMorph = new ActorStaticMorph(); - creatureActor.setActorStaticMorph(staticMorph); + creatureActor.getAnimationData().setActorStaticMorph(staticMorph); } if(attributeType.getPrimaryBone() != null && staticMorph.getBoneTransforms(attributeType.getPrimaryBone()) == null){ staticMorph.initBoneTransforms(attributeType.getPrimaryBone()); @@ -380,7 +380,7 @@ public class CreatureUtils { Actor creatureActor = EntityUtils.getActor(rVal); if(rawType.getBoneGroups() != null){ - creatureActor.setBoneGroups(rawType.getBoneGroups()); + creatureActor.getAnimationData().setBoneGroups(rawType.getBoneGroups()); } return rVal; diff --git a/src/main/java/electrosphere/entity/types/item/ItemUtils.java b/src/main/java/electrosphere/entity/types/item/ItemUtils.java index 0c7eca6e..90746978 100644 --- a/src/main/java/electrosphere/entity/types/item/ItemUtils.java +++ b/src/main/java/electrosphere/entity/types/item/ItemUtils.java @@ -331,9 +331,9 @@ public class ItemUtils { Actor actor = EntityUtils.getActor(item); if(actor != null && item.getData(EntityDataStrings.ANIM_IDLE) != null){ String idleAnim = (String)item.getData(EntityDataStrings.ANIM_IDLE); - if(!actor.isPlayingAnimation(idleAnim)){ - actor.playAnimation(idleAnim,AnimationPriorities.getValue(AnimationPriorities.INTERACTION)); - actor.incrementAnimationTime(0.0001); + if(!actor.getAnimationData().isPlayingAnimation(idleAnim)){ + actor.getAnimationData().playAnimation(idleAnim,AnimationPriorities.getValue(AnimationPriorities.INTERACTION)); + actor.getAnimationData().incrementAnimationTime(0.0001); } } } diff --git a/src/main/java/electrosphere/renderer/actor/Actor.java b/src/main/java/electrosphere/renderer/actor/Actor.java index c6f39de3..ff48adab 100644 --- a/src/main/java/electrosphere/renderer/actor/Actor.java +++ b/src/main/java/electrosphere/renderer/actor/Actor.java @@ -1,34 +1,25 @@ package electrosphere.renderer.actor; -import electrosphere.data.entity.common.treedata.TreeDataAnimation; -import electrosphere.data.entity.creature.bonegroups.BoneGroup; import electrosphere.engine.Globals; -import electrosphere.entity.state.AnimationPriorities; -import electrosphere.logger.LoggerInterface; import electrosphere.mem.JomlPool; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; -import electrosphere.renderer.actor.mask.ActorAnimationMaskEntry; +import electrosphere.renderer.actor.mask.ActorAnimationData; import electrosphere.renderer.actor.mask.ActorMeshMask; import electrosphere.renderer.actor.mask.ActorShaderMask; import electrosphere.renderer.actor.mask.ActorTextureMask; import electrosphere.renderer.actor.mask.ActorUniformMap; import electrosphere.renderer.actor.mask.ActorUniformMap.UniformValue; -import electrosphere.renderer.model.Bone; import electrosphere.renderer.model.Model; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.TreeSet; import org.joml.Matrix4d; -import org.joml.Quaterniond; import org.joml.Sphered; import org.joml.Vector3d; -import org.joml.Vector4d; /** * An actor @@ -43,11 +34,6 @@ import org.joml.Vector4d; */ public class Actor { - /** - * Returned when the current time is requested of an animation that the actor is not playing - */ - public static final int INVALID_ANIMATION = -1; - /** * full-resolution lod level */ @@ -83,11 +69,6 @@ public class Actor { */ private boolean frustumCull = true; - /** - * scales the time that animations are played at - */ - private float animationScalar = 1.0f; - /** * Sets scaling applied at the actor level */ @@ -129,9 +110,9 @@ public class Actor { private String lowResBaseModelPath; /** - * The stack of animations being applied to a given actor + * The animation data for the actor */ - private Set animationQueue = new TreeSet(); + private final ActorAnimationData animationData; /** * Mask for overwriting meshes in a given actor @@ -148,49 +129,10 @@ public class Actor { */ private Map textureMap = null; - /** - * bone rotators - */ - private Map boneRotators = new HashMap(); - - /** - * static morph for this specific actor - */ - private ActorStaticMorph staticMorph; - - /** - * The list of bone groups - */ - private List boneGroups; - /** * A map of mesh -> uniforms to apply to the mesh */ private ActorUniformMap uniformMap = new ActorUniformMap(); - - /** - * Used for caching animation masks that should be removed - */ - private List toRemoveMasks = new LinkedList(); - - - - - // - // - // DATA CACHING - // - // - - /** - * Stores the positions of bones as they are updated - */ - private Map bonePositionMap = new HashMap(); - - /** - * Stores the rotations of bones as they are updated - */ - private Map boneRotationMap = new HashMap(); @@ -208,354 +150,7 @@ public class Actor { */ public Actor(String modelPath){ this.baseModelPath = modelPath; - } - - /** - * Increments the animation time of the actor - * @param deltaTime The amount of time to increment by - */ - public void incrementAnimationTime(double deltaTime){ - toRemoveMasks.clear(); - for(ActorAnimationMaskEntry mask : animationQueue){ - if(mask.getFreezeFrames() > 0){ - mask.setFreezeFrames(mask.getFreezeFrames() - 1); - } else { - mask.setTime(mask.getTime() + deltaTime * animationScalar); - if(mask.getTime() > mask.getDuration()){ - toRemoveMasks.add(mask); - } - } - } - for(ActorAnimationMaskEntry mask : toRemoveMasks){ - animationQueue.remove(mask); - } - } - - /** - * Gets the current time of the given animation that is being played on this actor - * @param animation The animation's name - * @return The time into the animation, -1 if the animation is not being played - */ - public double getAnimationTime(String animation){ - ActorAnimationMaskEntry mask = this.getAnimationMask(animation); - if(mask != null){ - return mask.getTime(); - } - return INVALID_ANIMATION; - } - - /** - * Checks if an animation is being played on any meshes - * @param animationName The animation name - * @return true if the animation is being played on any meshes, false if the provided animation name is null or the animation is not being played on any meshes - */ - public boolean isPlayingAnimation(String animationName){ - if(animationName == null){ - return false; - } - for(ActorAnimationMaskEntry mask : animationQueue){ - if(mask.getAnimationName().equals(animationName)){ - return true; - } - } - return false; - } - - /** - * Checks if an animation is being played on any meshes - * @param animationData The animation data - * @return true if the animation is being played on any meshes, false if the provided animation name is null or the animation is not being played on any meshes - */ - public boolean isPlayingAnimation(TreeDataAnimation animationData){ - if(animationData == null){ - return false; - } - for(ActorAnimationMaskEntry mask : animationQueue){ - if(animationData.getNameFirstPerson() != null && mask.getAnimationName().contains(animationData.getNameFirstPerson())){ - return true; - } - if(animationData.getNameThirdPerson() != null && mask.getAnimationName().contains(animationData.getNameThirdPerson())){ - return true; - } - } - return false; - } - - /** - * Checks if the actor is playing an animation - * @return true if it is playing an animation, false otherwise - */ - public boolean isPlayingAnimation(){ - return animationQueue.size() > 0; - } - - /** - * Stops playing an animation on the actor - * @param animationName The name of the animation - */ - public void stopAnimation(String animationName){ - List toRemove = new LinkedList(); - for(ActorAnimationMaskEntry mask : animationQueue){ - if(mask.getAnimationName().contains(animationName)){ - toRemove.add(mask); - } - } - for(ActorAnimationMaskEntry mask : toRemove){ - animationQueue.remove(mask); - } - } - - /** - * Plays an animation provided as a string with a given priority - * @param animationName The name of the animation - * @param priority The priority of the animation - */ - public void playAnimation(String animationName, int priority){ - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null && model.getAnimation(animationName) != null){ - double length = model.getAnimation(animationName).duration; - ActorAnimationMaskEntry animMask = new ActorAnimationMaskEntry(priority, animationName, 0, length); - for(Bone bone : model.getBones()){ - animMask.addBone(bone.boneID); - } - toRemoveMasks.clear(); - for(ActorAnimationMaskEntry currentMask : animationQueue){ - if(currentMask.getPriority() == animMask.getPriority()){ - toRemoveMasks.add(currentMask); - break; - } - } - for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ - animationQueue.remove(currentMask); - } - animationQueue.add(animMask); - } - } - - /** - * Plays animation data - * @param animation The animation data - * @param isThirdPerson true if is third person, false if is first person - */ - public void playAnimation(TreeDataAnimation animation, boolean isThirdPerson){ - - //Get the animation's name - String animationName = ""; - if(isThirdPerson){ - animationName = animation.getNameThirdPerson(); - } else { - animationName = animation.getNameFirstPerson(); - } - - //Get the animation's priority - int priority = AnimationPriorities.getValue(AnimationPriorities.DEFAULT); - if(animation.getPriority() != null){ - priority = animation.getPriority(); - } - if(animation.getPriorityCategory() != null){ - priority = AnimationPriorities.getValue(animation.getPriorityCategory()); - } - - //Gets the mask - List boneMask = null; - if(animation.getBoneGroups() != null && this.boneGroups != null){ - boneMask = new LinkedList(); - for(String boneGroupName : animation.getBoneGroups()){ - BoneGroup group = null; - - for(BoneGroup currentGroup : this.boneGroups){ - if(currentGroup.getId().equals(boneGroupName)){ - group = currentGroup; - break; - } - } - - if(group != null && isThirdPerson == true && group.getBoneNamesThirdPerson() != null && group.getBoneNamesThirdPerson().size() > 0){ - boneMask.addAll(group.getBoneNamesThirdPerson()); - } - if(group != null && isThirdPerson == false && group.getBoneNamesFirstPerson() != null && group.getBoneNamesFirstPerson().size() > 0){ - boneMask.addAll(group.getBoneNamesFirstPerson()); - } - } - } else if(animation.getBoneGroups() != null && this.boneGroups == null){ - LoggerInterface.loggerRenderer.WARNING( - "Trying to play animation on Actor that uses bone groups, but the Actor's bone group isn't defined!\n" + - "Model path: " + baseModelPath + "\n" + - "Animation name: " + animationName + "\n" - ); - } else if(animation.getBoneGroups() == null){ - Model model = Globals.assetManager.fetchModel(this.baseModelPath); - if(model != null){ - boneMask = new LinkedList(); - for(Bone bone : model.getBones()){ - boneMask.add(bone.boneID); - } - } - } - - - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null && model.getAnimation(animationName) != null){ - - //get data from the actual animation in the model - double length = model.getAnimation(animationName).duration; - - //construct the animation mask - ActorAnimationMaskEntry animMask; - if(boneMask == null){ - animMask = new ActorAnimationMaskEntry( - priority, - animationName, - length - ); - } else { - animMask = new ActorAnimationMaskEntry( - priority, - animationName, - length, - boneMask - ); - } - - //if a mask wasn't defined, apply this mask to all animations - if(boneMask == null){ - for(Bone bone : model.getBones()){ - animMask.addBone(bone.boneID); - } - } - - - //clear existing masks that are lower priority - toRemoveMasks.clear(); - for(ActorAnimationMaskEntry currentMask : animationQueue){ - if(currentMask.getPriority() == animMask.getPriority()){ - toRemoveMasks.add(currentMask); - break; - } - } - for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ - animationQueue.remove(currentMask); - } - animationQueue.add(animMask); - } - } - - /** - * Interrupts an animation, thereby causing it to stop playing - * @param animation The animation to interrupt - */ - public void interruptAnimation(TreeDataAnimation animation, boolean isThirdPerson){ - //Get the animation's name - String animationName = ""; - if(isThirdPerson){ - animationName = animation.getNameThirdPerson(); - } else { - animationName = animation.getNameFirstPerson(); - } - - //Get the animation's priority - int priority = AnimationPriorities.getValue(AnimationPriorities.DEFAULT); - if(animation.getPriority() != null){ - priority = animation.getPriority(); - } - if(animation.getPriorityCategory() != null){ - priority = AnimationPriorities.getValue(animation.getPriorityCategory()); - } - - toRemoveMasks.clear(); - for(ActorAnimationMaskEntry mask : this.animationQueue){ - if(mask.getAnimationName() == animationName && mask.getPriority() == priority){ - toRemoveMasks.add(mask); - } - } - for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ - animationQueue.remove(currentMask); - } - } - - public void playAnimationWithMask(String animationName, int priority, List boneMask){ - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - double length = model.getAnimation(animationName).duration; - ActorAnimationMaskEntry animMask = new ActorAnimationMaskEntry(priority, animationName, 0, length, boneMask); - toRemoveMasks.clear(); - for(ActorAnimationMaskEntry currentMask : animationQueue){ - if(currentMask.getPriority() == animMask.getPriority()){ - toRemoveMasks.add(currentMask); - break; - } - } - for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ - animationQueue.remove(currentMask); - } - animationQueue.add(animMask); - } - } - - /** - * Gets the animation queue - * @return The animation queue - */ - public Set getAnimationQueue(){ - return animationQueue; - } - - /** - * Applies the animation masks in this actor to the provided model - * @param model The model - */ - private void applyAnimationMasks(Model model){ - List bonesUsed = new LinkedList(); - List currentAnimationMask = new LinkedList(); - for(ActorAnimationMaskEntry mask : animationQueue){ - currentAnimationMask.clear(); - for(String currentBone : mask.getBones()){ - if(!bonesUsed.contains(currentBone)){ - bonesUsed.add(currentBone); - currentAnimationMask.add(currentBone); - } - } - model.applyAnimationMask(mask.getAnimationName(), mask.getTime(), currentAnimationMask); - } - } - - /** - * Calculates the node transforms for the actor - * @param model The model that backs the actor - */ - private void calculateNodeTransforms(Model model){ - model.updateNodeTransform(boneRotators,staticMorph); - for(Bone bone : model.getBones()){ - //store position - Matrix4d betweenMat = new Matrix4d(bone.getMOffset()).invert(); - Vector4d result = betweenMat.transform(new Vector4d(0,0,0,1)); - betweenMat.set(bone.getFinalTransform()); - result = betweenMat.transform(result); - this.bonePositionMap.put(bone.boneID,new Vector3d(result.x,result.y,result.z)); - //store rotation - Quaterniond rotation = new Matrix4d(bone.getFinalTransform()).getNormalizedRotation(new Quaterniond()); - this.boneRotationMap.put(bone.boneID,rotation); - } - } - - public void setAnimationScalar(float animationScalar) { - this.animationScalar = animationScalar; - } - - /** - * Gets the animation mask for a given animation - * @param animationName The animation's name - * @return The animation mask if the actor is playing the animation, null otherwise - */ - public ActorAnimationMaskEntry getAnimationMask(String animationName){ - for(ActorAnimationMaskEntry mask : this.getAnimationQueue()){ - if(mask.getAnimationName().equals(animationName)){ - return mask; - } else if(mask.getAnimationName().equalsIgnoreCase(animationName)){ - LoggerInterface.loggerEngine.WARNING("Animation mask failed to find, but there is an animation with a very similar name! " + animationName + " vs " + mask.getAnimationName()); - } - } - return null; + this.animationData = new ActorAnimationData(this); } /** @@ -594,7 +189,7 @@ public class Actor { //frustum cull then draw if(Actor.isWithinFrustumBox(renderPipelineState,model,frustumCull)){ - this.applyAnimationMasks(model); + this.animationData.applyAnimationMasks(model); meshMask.processMeshMaskQueue(); model.setMeshMask(meshMask); model.setTextureMask(textureMap); @@ -603,7 +198,7 @@ public class Actor { model.getShaderMask().put(shaderMask.getMeshName(),shaderMask); } } - this.calculateNodeTransforms(model); + this.animationData.calculateNodeTransforms(model); //apply uniform overrides if(this.uniformMap.getMeshes() != null && this.uniformMap.getMeshes().size() > 0){ for(String meshName : this.uniformMap.getMeshes()){ @@ -635,12 +230,12 @@ public class Actor { this.lodLevel == Actor.LOD_LEVEL_STATIC || //actor doesn't have anything complicated render-wise (animations, custom textures, etc) ( - this.animationQueue.size() == 0 && + this.animationData.isPlayingAnimation() && this.meshMask.getBlockedMeshes().size() == 0 && this.textureMap == null && this.shaderMasks.size() == 0 && this.uniformMap.isEmpty() && - this.staticMorph == null + this.animationData.getStaticMorph() == null ) ; } @@ -657,12 +252,12 @@ public class Actor { public String getStatisDrawStatus(){ String rVal = ""; rVal = rVal + this.isStaticDrawCall() + "\n"; - rVal = rVal + (this.animationQueue.size() == 0) + "\n"; + rVal = rVal + this.animationData.isPlayingAnimation() + "\n"; rVal = rVal + (this.meshMask.getBlockedMeshes().size() == 0) + "\n"; rVal = rVal + (this.textureMap == null) + "\n"; rVal = rVal + (this.shaderMasks.size() == 0) + "\n"; rVal = rVal + this.uniformMap.isEmpty() + "\n"; - rVal = rVal + (this.staticMorph == null) + "\n"; + rVal = rVal + (this.animationData.getStaticMorph() == null) + "\n"; return rVal; } @@ -697,130 +292,6 @@ public class Actor { public String getBaseModelPath(){ return baseModelPath; } - - /** - * Gets the position of a bone in local space - * @param boneName The name of the bone - * @return The vector3d containing the position of the bone, or a vector of (0,0,0) if the model lookup fails - * //TODO: refactor to make failure more transparent (both for model not existing and bone not existing) - */ - public Vector3d getBonePosition(String boneName){ - if(bonePositionMap.containsKey(boneName)){ - return bonePositionMap.get(boneName); - } - Vector3d rVal = new Vector3d(); - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - this.applyAnimationMasks(model); - this.calculateNodeTransforms(model); - Bone currentBone = model.getBoneMap().get(boneName); - if(currentBone != null){ - Matrix4d betweenMat = new Matrix4d(currentBone.getMOffset()).invert(); - Vector4d result = betweenMat.transform(new Vector4d(rVal.x,rVal.y,rVal.z,1)); - betweenMat.set(currentBone.getFinalTransform()); - result = betweenMat.transform(result); - rVal.x = (float)result.x; - rVal.y = (float)result.y; - rVal.z = (float)result.z; - } else { - String message = "Trying to get position of bone that does not exist on model!\n" + - "boneName: " + boneName; - throw new Error(message); - } - } - if(!Double.isFinite(rVal.x)){ - throw new Error("Bone position that is not finite!"); - } - return rVal; - } - - /** - * Gets the rotation of a bone in local space - * @param boneName The name of the bone - * @return The Quaterniond containing the rotation of the bone, or an identity Quaterniond if the lookup fails - */ - public Quaterniond getBoneRotation(String boneName){ - if(boneRotationMap.containsKey(boneName)){ - return boneRotationMap.get(boneName); - } - Quaterniond rVal = new Quaterniond(); - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - this.applyAnimationMasks(model); - this.calculateNodeTransforms(model); - Bone currentBone = model.getBoneMap().get(boneName); - if(currentBone != null){ - Quaterniond rotation = new Matrix4d(currentBone.getFinalTransform()).getNormalizedRotation(new Quaterniond()); - rVal.set(rotation); - } else { - String message = "Trying to get rotation of bone that does not exist on model!\n" + - "boneName: " + boneName; - throw new IllegalArgumentException(message); - } - } - if(!Double.isFinite(rVal.x)){ - throw new IllegalStateException("Bone rotation that is not finite!"); - } - return rVal; - } - - public Matrix4d getBoneTransform(String boneName){ - Matrix4d rVal = new Matrix4d(); - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - applyAnimationMasks(model); - calculateNodeTransforms(model); - Bone currentBone = model.getBoneMap().get(boneName); - if(currentBone != null){ - rVal.set(currentBone.getFinalTransform()); - } else { - throw new IllegalArgumentException("Trying to get rotation of bone that does not exist on model!"); - } - } - if(!Double.isFinite(rVal.m00())){ - throw new IllegalStateException("Bone rotation that is not finite!"); - } - return rVal; - } - - /** - * Gets the list of all bones - * @return the list of all bones - */ - public List getBoneValues(){ - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - applyAnimationMasks(model); - calculateNodeTransforms(model); - return model.getBones(); - } - return null; - } - - /** - * Gets the value of a single bone - * @return the bone - */ - public Bone getBone(String boneName){ - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - return model.getBoneMap().get(boneName); - } - return null; - } - - /** - * Checks if the actor contains a bone - * @param boneName The name of the bone - * @return true if it exists, false otherwise - */ - public boolean containsBone(String boneName){ - Model model = Globals.assetManager.fetchModel(baseModelPath); - if(model != null){ - return model.getBoneMap().containsKey(boneName); - } - return false; - } /** * Checks if the model is loaded for this actor @@ -872,25 +343,6 @@ public class Actor { textureMap.put(textureMask.getMeshName(),textureMask); } - - /** - * Adds a rotator to a bone on this actor - * @param bone The name of the bone - * @param rotator The rotator - */ - public void addBoneRotator(String bone, ActorBoneRotator rotator){ - boneRotators.put(bone, rotator); - } - - /** - * Gets the rotator to apply to a bone - * @param bone The name of the bone - * @return The rotator to apply to that bone if it exists, null otherwise - */ - public ActorBoneRotator getBoneRotator(String bone){ - return boneRotators.get(bone); - } - /** * Sets the value of a uniform on a given mesh within this actor * @param meshName The name of the mesh @@ -900,22 +352,6 @@ public class Actor { public void setUniformOnMesh(String meshName, String uniformName, Object value){ this.uniformMap.setUniform(meshName, uniformName, value); } - - /** - * Sets the static morph for this actor - * @param staticMorph The static morph - */ - public void setActorStaticMorph(ActorStaticMorph staticMorph){ - this.staticMorph = staticMorph; - } - - /** - * Gets the static morph for this actor - * @return The static morph for this actor - */ - public ActorStaticMorph getStaticMorph(){ - return this.staticMorph; - } /** * Sets whether this actor should frustum cull or not @@ -933,31 +369,6 @@ public class Actor { return frustumCull; } - /** - * Sets the bone groups in the actor - * @param boneGroups The bone groups - */ - public void setBoneGroups(List boneGroups){ - this.boneGroups = boneGroups; - } - - /** - * Sets the number of freeze frames for a given animation path if the animation is being played - * @param animationPath The path to the animation - * @param numFrames The number of frames to freeze for - */ - public void setFreezeFrames(String animationPath, int numFrames){ - if(numFrames < 1){ - throw new Error("Num frames less than 1 !" + numFrames); - } - for(ActorAnimationMaskEntry mask : this.animationQueue){ - if(mask.getAnimationName().contains(animationPath)){ - mask.setFreezeFrames(numFrames); - break; - } - } - } - /** @@ -1047,5 +458,13 @@ public class Actor { this.lodLevel = lodLevel; } + /** + * Gets the animation data for the actor + * @return + */ + public ActorAnimationData getAnimationData(){ + return this.animationData; + } + } diff --git a/src/main/java/electrosphere/renderer/actor/ActorUtils.java b/src/main/java/electrosphere/renderer/actor/ActorUtils.java index 67a7eaae..b68fea01 100644 --- a/src/main/java/electrosphere/renderer/actor/ActorUtils.java +++ b/src/main/java/electrosphere/renderer/actor/ActorUtils.java @@ -37,7 +37,7 @@ public class ActorUtils { */ public static ActorStaticMorph getStaticMorph(Entity actorEntity){ Actor entityActor = EntityUtils.getActor(actorEntity); - return entityActor.getStaticMorph(); + return entityActor.getAnimationData().getStaticMorph(); } /** diff --git a/src/main/java/electrosphere/renderer/actor/mask/ActorAnimationData.java b/src/main/java/electrosphere/renderer/actor/mask/ActorAnimationData.java new file mode 100644 index 00000000..883f5716 --- /dev/null +++ b/src/main/java/electrosphere/renderer/actor/mask/ActorAnimationData.java @@ -0,0 +1,642 @@ +package electrosphere.renderer.actor.mask; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.joml.Matrix4d; +import org.joml.Quaterniond; +import org.joml.Vector3d; +import org.joml.Vector4d; + +import electrosphere.data.entity.common.treedata.TreeDataAnimation; +import electrosphere.data.entity.creature.bonegroups.BoneGroup; +import electrosphere.engine.Globals; +import electrosphere.entity.state.AnimationPriorities; +import electrosphere.logger.LoggerInterface; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.actor.ActorBoneRotator; +import electrosphere.renderer.actor.ActorStaticMorph; +import electrosphere.renderer.model.Bone; +import electrosphere.renderer.model.Model; + +/** + * The data about animations for a given actor + */ +public class ActorAnimationData { + + /** + * Returned when the current time is requested of an animation that the actor is not playing + */ + public static final int INVALID_ANIMATION = -1; + + /** + * The parent actor + */ + private final Actor parent; + + /** + * scales the time that animations are played at + */ + private float animationScalar = 1.0f; + + /** + * The stack of animations being applied to a given actor + */ + private Set animationQueue = new TreeSet(); + + /** + * Used for caching animation masks that should be removed + */ + private List toRemoveMasks = new LinkedList(); + + /** + * The list of bone groups + */ + private List boneGroups; + + /** + * static morph for this specific actor + */ + private ActorStaticMorph staticMorph; + + /** + * bone rotators + */ + private Map boneRotators = new HashMap(); + + // + // + // DATA CACHING + // + // + + /** + * Stores the positions of bones as they are updated + */ + private Map bonePositionMap = new HashMap(); + + /** + * Stores the rotations of bones as they are updated + */ + private Map boneRotationMap = new HashMap(); + + + + + + + /** + * Constructor + * @param parent The parent actor + */ + public ActorAnimationData(Actor parent){ + this.parent = parent; + } + + /** + * Increments the animation time of the actor + * @param deltaTime The amount of time to increment by + */ + public void incrementAnimationTime(double deltaTime){ + toRemoveMasks.clear(); + for(ActorAnimationMaskEntry mask : animationQueue){ + if(mask.getFreezeFrames() > 0){ + mask.setFreezeFrames(mask.getFreezeFrames() - 1); + } else { + mask.setTime(mask.getTime() + deltaTime * animationScalar); + if(mask.getTime() > mask.getDuration()){ + toRemoveMasks.add(mask); + } + } + } + for(ActorAnimationMaskEntry mask : toRemoveMasks){ + animationQueue.remove(mask); + } + } + + /** + * Gets the current time of the given animation that is being played on this actor + * @param animation The animation's name + * @return The time into the animation, -1 if the animation is not being played + */ + public double getAnimationTime(String animation){ + ActorAnimationMaskEntry mask = this.getAnimationMask(animation); + if(mask != null){ + return mask.getTime(); + } + return INVALID_ANIMATION; + } + + /** + * Checks if an animation is being played on any meshes + * @param animationName The animation name + * @return true if the animation is being played on any meshes, false if the provided animation name is null or the animation is not being played on any meshes + */ + public boolean isPlayingAnimation(String animationName){ + if(animationName == null){ + return false; + } + for(ActorAnimationMaskEntry mask : animationQueue){ + if(mask.getAnimationName().equals(animationName)){ + return true; + } + } + return false; + } + + /** + * Checks if an animation is being played on any meshes + * @param animationData The animation data + * @return true if the animation is being played on any meshes, false if the provided animation name is null or the animation is not being played on any meshes + */ + public boolean isPlayingAnimation(TreeDataAnimation animationData){ + if(animationData == null){ + return false; + } + for(ActorAnimationMaskEntry mask : animationQueue){ + if(animationData.getNameFirstPerson() != null && mask.getAnimationName().contains(animationData.getNameFirstPerson())){ + return true; + } + if(animationData.getNameThirdPerson() != null && mask.getAnimationName().contains(animationData.getNameThirdPerson())){ + return true; + } + } + return false; + } + + /** + * Checks if the actor is playing an animation + * @return true if it is playing an animation, false otherwise + */ + public boolean isPlayingAnimation(){ + return animationQueue.size() > 0; + } + + /** + * Stops playing an animation on the actor + * @param animationName The name of the animation + */ + public void stopAnimation(String animationName){ + List toRemove = new LinkedList(); + for(ActorAnimationMaskEntry mask : animationQueue){ + if(mask.getAnimationName().contains(animationName)){ + toRemove.add(mask); + } + } + for(ActorAnimationMaskEntry mask : toRemove){ + animationQueue.remove(mask); + } + } + + /** + * Plays an animation provided as a string with a given priority + * @param animationName The name of the animation + * @param priority The priority of the animation + */ + public void playAnimation(String animationName, int priority){ + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null && model.getAnimation(animationName) != null){ + double length = model.getAnimation(animationName).duration; + ActorAnimationMaskEntry animMask = new ActorAnimationMaskEntry(priority, animationName, 0, length); + for(Bone bone : model.getBones()){ + animMask.addBone(bone.boneID); + } + toRemoveMasks.clear(); + for(ActorAnimationMaskEntry currentMask : animationQueue){ + if(currentMask.getPriority() == animMask.getPriority()){ + toRemoveMasks.add(currentMask); + break; + } + } + for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ + animationQueue.remove(currentMask); + } + animationQueue.add(animMask); + } + } + + /** + * Plays animation data + * @param animation The animation data + * @param isThirdPerson true if is third person, false if is first person + */ + public void playAnimation(TreeDataAnimation animation, boolean isThirdPerson){ + + //Get the animation's name + String animationName = ""; + if(isThirdPerson){ + animationName = animation.getNameThirdPerson(); + } else { + animationName = animation.getNameFirstPerson(); + } + + //Get the animation's priority + int priority = AnimationPriorities.getValue(AnimationPriorities.DEFAULT); + if(animation.getPriority() != null){ + priority = animation.getPriority(); + } + if(animation.getPriorityCategory() != null){ + priority = AnimationPriorities.getValue(animation.getPriorityCategory()); + } + + //Gets the mask + List boneMask = null; + if(animation.getBoneGroups() != null && this.boneGroups != null){ + boneMask = new LinkedList(); + for(String boneGroupName : animation.getBoneGroups()){ + BoneGroup group = null; + + for(BoneGroup currentGroup : this.boneGroups){ + if(currentGroup.getId().equals(boneGroupName)){ + group = currentGroup; + break; + } + } + + if(group != null && isThirdPerson == true && group.getBoneNamesThirdPerson() != null && group.getBoneNamesThirdPerson().size() > 0){ + boneMask.addAll(group.getBoneNamesThirdPerson()); + } + if(group != null && isThirdPerson == false && group.getBoneNamesFirstPerson() != null && group.getBoneNamesFirstPerson().size() > 0){ + boneMask.addAll(group.getBoneNamesFirstPerson()); + } + } + } else if(animation.getBoneGroups() != null && this.boneGroups == null){ + LoggerInterface.loggerRenderer.WARNING( + "Trying to play animation on Actor that uses bone groups, but the Actor's bone group isn't defined!\n" + + "Model path: " + parent.getBaseModelPath() + "\n" + + "Animation name: " + animationName + "\n" + ); + } else if(animation.getBoneGroups() == null){ + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + boneMask = new LinkedList(); + for(Bone bone : model.getBones()){ + boneMask.add(bone.boneID); + } + } + } + + + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null && model.getAnimation(animationName) != null){ + + //get data from the actual animation in the model + double length = model.getAnimation(animationName).duration; + + //construct the animation mask + ActorAnimationMaskEntry animMask; + if(boneMask == null){ + animMask = new ActorAnimationMaskEntry( + priority, + animationName, + length + ); + } else { + animMask = new ActorAnimationMaskEntry( + priority, + animationName, + length, + boneMask + ); + } + + //if a mask wasn't defined, apply this mask to all animations + if(boneMask == null){ + for(Bone bone : model.getBones()){ + animMask.addBone(bone.boneID); + } + } + + + //clear existing masks that are lower priority + toRemoveMasks.clear(); + for(ActorAnimationMaskEntry currentMask : animationQueue){ + if(currentMask.getPriority() == animMask.getPriority()){ + toRemoveMasks.add(currentMask); + break; + } + } + for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ + animationQueue.remove(currentMask); + } + animationQueue.add(animMask); + } + } + + /** + * Interrupts an animation, thereby causing it to stop playing + * @param animation The animation to interrupt + */ + public void interruptAnimation(TreeDataAnimation animation, boolean isThirdPerson){ + //Get the animation's name + String animationName = ""; + if(isThirdPerson){ + animationName = animation.getNameThirdPerson(); + } else { + animationName = animation.getNameFirstPerson(); + } + + //Get the animation's priority + int priority = AnimationPriorities.getValue(AnimationPriorities.DEFAULT); + if(animation.getPriority() != null){ + priority = animation.getPriority(); + } + if(animation.getPriorityCategory() != null){ + priority = AnimationPriorities.getValue(animation.getPriorityCategory()); + } + + toRemoveMasks.clear(); + for(ActorAnimationMaskEntry mask : this.animationQueue){ + if(mask.getAnimationName() == animationName && mask.getPriority() == priority){ + toRemoveMasks.add(mask); + } + } + for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ + animationQueue.remove(currentMask); + } + } + + /** + * Plays an animation on a specified set of bones + * @param animationName The name of the animation + * @param priority The priority of the animation + * @param boneMask The set of bones to play the animation on + */ + public void playAnimationWithMask(String animationName, int priority, List boneMask){ + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + double length = model.getAnimation(animationName).duration; + ActorAnimationMaskEntry animMask = new ActorAnimationMaskEntry(priority, animationName, 0, length, boneMask); + toRemoveMasks.clear(); + for(ActorAnimationMaskEntry currentMask : animationQueue){ + if(currentMask.getPriority() == animMask.getPriority()){ + toRemoveMasks.add(currentMask); + break; + } + } + for(ActorAnimationMaskEntry currentMask : toRemoveMasks){ + animationQueue.remove(currentMask); + } + animationQueue.add(animMask); + } + } + + /** + * Gets the animation queue + * @return The animation queue + */ + public Set getAnimationQueue(){ + return animationQueue; + } + + /** + * Applies the animation masks in this actor to the provided model + * @param model The model + */ + public void applyAnimationMasks(Model model){ + List bonesUsed = new LinkedList(); + List currentAnimationMask = new LinkedList(); + for(ActorAnimationMaskEntry mask : animationQueue){ + currentAnimationMask.clear(); + for(String currentBone : mask.getBones()){ + if(!bonesUsed.contains(currentBone)){ + bonesUsed.add(currentBone); + currentAnimationMask.add(currentBone); + } + } + model.applyAnimationMask(mask.getAnimationName(), mask.getTime(), currentAnimationMask); + } + } + + /** + * Calculates the node transforms for the actor + * @param model The model that backs the actor + */ + public void calculateNodeTransforms(Model model){ + model.updateNodeTransform(boneRotators,staticMorph); + for(Bone bone : model.getBones()){ + //store position + Matrix4d betweenMat = new Matrix4d(bone.getMOffset()).invert(); + Vector4d result = betweenMat.transform(new Vector4d(0,0,0,1)); + betweenMat.set(bone.getFinalTransform()); + result = betweenMat.transform(result); + this.bonePositionMap.put(bone.boneID,new Vector3d(result.x,result.y,result.z)); + //store rotation + Quaterniond rotation = new Matrix4d(bone.getFinalTransform()).getNormalizedRotation(new Quaterniond()); + this.boneRotationMap.put(bone.boneID,rotation); + } + } + + public void setAnimationScalar(float animationScalar) { + this.animationScalar = animationScalar; + } + + /** + * Gets the animation mask for a given animation + * @param animationName The animation's name + * @return The animation mask if the actor is playing the animation, null otherwise + */ + public ActorAnimationMaskEntry getAnimationMask(String animationName){ + for(ActorAnimationMaskEntry mask : this.getAnimationQueue()){ + if(mask.getAnimationName().equals(animationName)){ + return mask; + } else if(mask.getAnimationName().equalsIgnoreCase(animationName)){ + LoggerInterface.loggerEngine.WARNING("Animation mask failed to find, but there is an animation with a very similar name! " + animationName + " vs " + mask.getAnimationName()); + } + } + return null; + } + + /** + * Adds a rotator to a bone on this actor + * @param bone The name of the bone + * @param rotator The rotator + */ + public void addBoneRotator(String bone, ActorBoneRotator rotator){ + boneRotators.put(bone, rotator); + } + + /** + * Gets the rotator to apply to a bone + * @param bone The name of the bone + * @return The rotator to apply to that bone if it exists, null otherwise + */ + public ActorBoneRotator getBoneRotator(String bone){ + return boneRotators.get(bone); + } + + /** + * Sets the static morph for this actor + * @param staticMorph The static morph + */ + public void setActorStaticMorph(ActorStaticMorph staticMorph){ + this.staticMorph = staticMorph; + } + + /** + * Gets the static morph for this actor + * @return The static morph for this actor + */ + public ActorStaticMorph getStaticMorph(){ + return this.staticMorph; + } + + /** + * Sets the bone groups in the actor + * @param boneGroups The bone groups + */ + public void setBoneGroups(List boneGroups){ + this.boneGroups = boneGroups; + } + + /** + * Sets the number of freeze frames for a given animation path if the animation is being played + * @param animationPath The path to the animation + * @param numFrames The number of frames to freeze for + */ + public void setFreezeFrames(String animationPath, int numFrames){ + if(numFrames < 1){ + throw new Error("Num frames less than 1 !" + numFrames); + } + for(ActorAnimationMaskEntry mask : this.animationQueue){ + if(mask.getAnimationName().contains(animationPath)){ + mask.setFreezeFrames(numFrames); + break; + } + } + } + + /** + * Gets the position of a bone in local space + * @param boneName The name of the bone + * @return The vector3d containing the position of the bone, or a vector of (0,0,0) if the model lookup fails + * //TODO: refactor to make failure more transparent (both for model not existing and bone not existing) + */ + public Vector3d getBonePosition(String boneName){ + if(bonePositionMap.containsKey(boneName)){ + return bonePositionMap.get(boneName); + } + Vector3d rVal = new Vector3d(); + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + this.applyAnimationMasks(model); + this.calculateNodeTransforms(model); + Bone currentBone = model.getBoneMap().get(boneName); + if(currentBone != null){ + Matrix4d betweenMat = new Matrix4d(currentBone.getMOffset()).invert(); + Vector4d result = betweenMat.transform(new Vector4d(rVal.x,rVal.y,rVal.z,1)); + betweenMat.set(currentBone.getFinalTransform()); + result = betweenMat.transform(result); + rVal.x = (float)result.x; + rVal.y = (float)result.y; + rVal.z = (float)result.z; + } else { + String message = "Trying to get position of bone that does not exist on model!\n" + + "boneName: " + boneName; + throw new Error(message); + } + } + if(!Double.isFinite(rVal.x)){ + throw new Error("Bone position that is not finite!"); + } + return rVal; + } + + /** + * Gets the rotation of a bone in local space + * @param boneName The name of the bone + * @return The Quaterniond containing the rotation of the bone, or an identity Quaterniond if the lookup fails + */ + public Quaterniond getBoneRotation(String boneName){ + if(boneRotationMap.containsKey(boneName)){ + return boneRotationMap.get(boneName); + } + Quaterniond rVal = new Quaterniond(); + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + this.applyAnimationMasks(model); + this.calculateNodeTransforms(model); + Bone currentBone = model.getBoneMap().get(boneName); + if(currentBone != null){ + Quaterniond rotation = new Matrix4d(currentBone.getFinalTransform()).getNormalizedRotation(new Quaterniond()); + rVal.set(rotation); + } else { + String message = "Trying to get rotation of bone that does not exist on model!\n" + + "boneName: " + boneName; + throw new IllegalArgumentException(message); + } + } + if(!Double.isFinite(rVal.x)){ + throw new IllegalStateException("Bone rotation that is not finite!"); + } + return rVal; + } + + /** + * Gets the bone transform for a bone on this actor + * @param boneName The name of the bone + * @return The transform + */ + public Matrix4d getBoneTransform(String boneName){ + Matrix4d rVal = new Matrix4d(); + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + applyAnimationMasks(model); + calculateNodeTransforms(model); + Bone currentBone = model.getBoneMap().get(boneName); + if(currentBone != null){ + rVal.set(currentBone.getFinalTransform()); + } else { + throw new IllegalArgumentException("Trying to get rotation of bone that does not exist on model!"); + } + } + if(!Double.isFinite(rVal.m00())){ + throw new IllegalStateException("Bone rotation that is not finite!"); + } + return rVal; + } + + /** + * Gets the list of all bones + * @return the list of all bones + */ + public List getBoneValues(){ + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + applyAnimationMasks(model); + calculateNodeTransforms(model); + return model.getBones(); + } + return null; + } + + /** + * Gets the value of a single bone + * @return the bone + */ + public Bone getBone(String boneName){ + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + return model.getBoneMap().get(boneName); + } + return null; + } + + /** + * Checks if the actor contains a bone + * @param boneName The name of the bone + * @return true if it exists, false otherwise + */ + public boolean containsBone(String boneName){ + Model model = Globals.assetManager.fetchModel(parent.getBaseModelPath()); + if(model != null){ + return model.getBoneMap().containsKey(boneName); + } + return false; + } + +} diff --git a/src/main/java/electrosphere/renderer/pipelines/debug/DebugBonesPipeline.java b/src/main/java/electrosphere/renderer/pipelines/debug/DebugBonesPipeline.java index 02ee15cc..8a1d2221 100644 --- a/src/main/java/electrosphere/renderer/pipelines/debug/DebugBonesPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/debug/DebugBonesPipeline.java @@ -70,7 +70,7 @@ public class DebugBonesPipeline implements RenderPipeline { Actor targetActor = EntityUtils.getActor(targetEntity); Model boneModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER); boneModel.getMaterials().get(0).setDiffuse(Globals.assetManager.fetchTexture(AssetDataStrings.TEXTURE_DEFAULT)); - for(Bone bone : targetActor.getBoneValues()){ + for(Bone bone : targetActor.getAnimationData().getBoneValues()){ Vector3d bonePos = MathBones.getBoneWorldPosition(targetEntity, bone.boneID); Quaterniond boneRot = MathBones.getBoneWorldRotation(targetEntity, bone.boneID); diff --git a/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java b/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java index 3bbed156..abafbd3e 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java +++ b/src/main/java/electrosphere/renderer/ui/elements/ActorPanel.java @@ -226,12 +226,12 @@ public class ActorPanel extends BufferedStandardDrawableContainerElement impleme Model actorModel = Globals.assetManager.fetchModel(actor.getBaseModelPath()); if(currentAnim != null){ - if((!actor.isPlayingAnimation() || !actor.isPlayingAnimation(currentAnim)) && + if((!actor.getAnimationData().isPlayingAnimation() || !actor.getAnimationData().isPlayingAnimation(currentAnim)) && actorModel != null && actorModel.getAnimation(currentAnim) != null ){ - actor.playAnimation(currentAnim,3); - actor.incrementAnimationTime(0.0001); + actor.getAnimationData().playAnimation(currentAnim,3); + actor.getAnimationData().incrementAnimationTime(0.0001); } } if(!hasOffsetFromBoundingSphere && actorModel != null){ diff --git a/src/main/java/electrosphere/util/math/MathBones.java b/src/main/java/electrosphere/util/math/MathBones.java index 9ff7e3f3..ddac1825 100644 --- a/src/main/java/electrosphere/util/math/MathBones.java +++ b/src/main/java/electrosphere/util/math/MathBones.java @@ -22,7 +22,7 @@ public class MathBones { */ public static Vector3d getBoneWorldPosition(Entity actorEntity, String boneName){ Actor actor = EntityUtils.getActor(actorEntity); - Vector3d localPos = new Vector3d(actor.getBonePosition(boneName)); + Vector3d localPos = new Vector3d(actor.getAnimationData().getBonePosition(boneName)); //transform bone space Vector3d position = new Vector3d(localPos); @@ -41,7 +41,7 @@ public class MathBones { */ public static Quaterniond getBoneWorldRotation(Entity actorEntity, String boneName){ Actor actor = EntityUtils.getActor(actorEntity); - Quaterniond localRot = actor.getBoneRotation(boneName); + Quaterniond localRot = actor.getAnimationData().getBoneRotation(boneName); Vector3d facingAngle = CreatureUtils.getFacingVector(actorEntity); if(facingAngle == null){