refactor animation logic into dedicated class
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-05-29 15:48:57 -04:00
parent 4f663a322c
commit f7d8072122
27 changed files with 745 additions and 683 deletions

View File

@ -2060,6 +2060,7 @@ Code cleanup
More tests More tests
Move actor masks into dedicated package Move actor masks into dedicated package
Actor code cleanup Actor code cleanup
Refactor animation logic into dedicated actor class

View File

@ -76,8 +76,8 @@ public class ClientSimulation {
if(currentActor.getLodLevel() == Actor.LOD_LEVEL_STATIC){ if(currentActor.getLodLevel() == Actor.LOD_LEVEL_STATIC){
continue; continue;
} }
if(currentActor.isPlayingAnimation()){ if(currentActor.getAnimationData().isPlayingAnimation()){
currentActor.incrementAnimationTime((float)Globals.engineState.timekeeper.getSimFrameTime()); currentActor.getAnimationData().incrementAnimationTime((float)Globals.engineState.timekeeper.getSimFrameTime());
} }
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();

View File

@ -97,7 +97,7 @@ public class CharacterCustomizer {
sliderName.setMinWidth(200); sliderName.setMinWidth(200);
//add a slider //add a slider
Slider boneSlider = Slider.createSlider((ValueChangeEvent event) -> { Slider boneSlider = Slider.createSlider((ValueChangeEvent event) -> {
if(characterActor.getStaticMorph() != null){ if(characterActor.getAnimationData().getStaticMorph() != null){
staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat()); staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat());
if(attribute.getMirrorBone() != null){ if(attribute.getMirrorBone() != null){
staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat()); staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat());
@ -167,7 +167,7 @@ public class CharacterCustomizer {
} }
} }
//finally set static morph //finally set static morph
characterActor.setActorStaticMorph(staticMorph); characterActor.getAnimationData().setActorStaticMorph(staticMorph);
//character create button //character create button
Div createButtonContainer = Div.createDiv(); Div createButtonContainer = Div.createDiv();

View File

@ -75,7 +75,7 @@ public class ImGuiEntityActorTab {
//animation queue //animation queue
if(ImGui.collapsingHeader("Animation Queue")){ if(ImGui.collapsingHeader("Animation Queue")){
Set<ActorAnimationMaskEntry> animationQueue = actor.getAnimationQueue(); Set<ActorAnimationMaskEntry> animationQueue = actor.getAnimationData().getAnimationQueue();
for(ActorAnimationMaskEntry mask : animationQueue){ for(ActorAnimationMaskEntry mask : animationQueue){
ImGui.text(mask.getAnimationName() + " - " + mask.getPriority()); ImGui.text(mask.getAnimationName() + " - " + mask.getPriority());
ImGui.text(mask.getDuration() + " " + mask.getTime()); ImGui.text(mask.getDuration() + " " + mask.getTime());
@ -84,10 +84,10 @@ public class ImGuiEntityActorTab {
//bone values //bone values
if(ImGui.collapsingHeader("Bone Values")){ if(ImGui.collapsingHeader("Bone Values")){
for(Bone bone : actor.getBoneValues()){ for(Bone bone : actor.getAnimationData().getBoneValues()){
ImGui.text(bone.boneID); ImGui.text(bone.boneID);
ImGui.text("Position: " + actor.getBonePosition(bone.boneID)); ImGui.text("Position: " + actor.getAnimationData().getBonePosition(bone.boneID));
ImGui.text("Rotation: " + actor.getBoneRotation(bone.boneID)); ImGui.text("Rotation: " + actor.getAnimationData().getBoneRotation(bone.boneID));
ImGui.text(bone.getFinalTransform() + ""); ImGui.text(bone.getFinalTransform() + "");
} }
} }
@ -104,7 +104,7 @@ public class ImGuiEntityActorTab {
for(Animation animation : model.getAnimations()){ for(Animation animation : model.getAnimations()){
if(ImGui.collapsingHeader(animation.name)){ if(ImGui.collapsingHeader(animation.name)){
if(ImGui.button("Play")){ 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){ for(AnimChannel channel : animation.channels){
ImGui.pushID(channel.getNodeID()); ImGui.pushID(channel.getNodeID());
@ -131,7 +131,7 @@ public class ImGuiEntityActorTab {
if(ImGui.collapsingHeader("Print Data")){ if(ImGui.collapsingHeader("Print Data")){
//print bone values //print bone values
if(ImGui.button("Print current 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.boneID);
LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform()); LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform());
} }

View File

@ -362,7 +362,7 @@ public class MenuGeneratorsInGame {
Entity playerEntity = Globals.clientState.playerEntity; Entity playerEntity = Globals.clientState.playerEntity;
Actor playerActor = EntityUtils.getActor(playerEntity); Actor playerActor = EntityUtils.getActor(playerEntity);
ActorStaticMorph staticMorph = playerActor.getStaticMorph(); ActorStaticMorph staticMorph = playerActor.getAnimationData().getStaticMorph();
CreatureData playeCreatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getType(CreatureUtils.getType(playerEntity)); CreatureData playeCreatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getType(CreatureUtils.getType(playerEntity));
int offset = 0; int offset = 0;
for(VisualAttribute attribute : playeCreatureType.getVisualAttributes()){ for(VisualAttribute attribute : playeCreatureType.getVisualAttributes()){

View File

@ -138,11 +138,11 @@ public class StateTransitionUtil {
// //
//Play main animation //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 transition if this isn't set to loop
state.onComplete.run(); state.onComplete.run();
state.startedAnimation = false; 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 //if it isn't looping, only play on first go around
@ -167,10 +167,10 @@ public class StateTransitionUtil {
// //
//play animation //play animation
if(animation != null){ if(animation != null){
actor.playAnimation(animation,true); actor.getAnimationData().playAnimation(animation,true);
shouldPlayFirstPerson = true; shouldPlayFirstPerson = true;
} }
actor.incrementAnimationTime(animationOffset); actor.getAnimationData().incrementAnimationTime(animationOffset);
} }
state.startedAnimation = true; state.startedAnimation = true;
} else if(state.animation == null && state.onComplete != null){ } else if(state.animation == null && state.onComplete != null){
@ -272,8 +272,8 @@ public class StateTransitionUtil {
// //
//Interrupt main animation //Interrupt main animation
// //
if(animation != null && actor.isPlayingAnimation() && actor.isPlayingAnimation(animation)){ if(animation != null && actor.getAnimationData().isPlayingAnimation() && actor.getAnimationData().isPlayingAnimation(animation)){
actor.interruptAnimation(animation, true); actor.getAnimationData().interruptAnimation(animation, true);
} }
// //

View File

@ -208,8 +208,8 @@ public class AttachUtils {
child, child,
new Vector3d(offset), new Vector3d(offset),
new Quaterniond(AttachUtils.getRotationOffset(child)), new Quaterniond(AttachUtils.getRotationOffset(child)),
new Vector3d(parentActor.getBonePosition(targetBone)), new Vector3d(parentActor.getAnimationData().getBonePosition(targetBone)),
new Quaterniond(parentActor.getBoneRotation(targetBone)), new Quaterniond(parentActor.getAnimationData().getBoneRotation(targetBone)),
new Vector3d(EntityUtils.getPosition(parent)), new Vector3d(EntityUtils.getPosition(parent)),
new Quaterniond(EntityUtils.getRotation(parent)), new Quaterniond(EntityUtils.getRotation(parent)),
new Vector3d(EntityUtils.getScale(parent)) new Vector3d(EntityUtils.getScale(parent))

View File

@ -564,11 +564,11 @@ public class ClientAttackTree implements BehaviorTree {
Actor actor = EntityUtils.getActor(parent); Actor actor = EntityUtils.getActor(parent);
if(this.currentMove != null && this.currentMove.getHitstun() != null){ if(this.currentMove != null && this.currentMove.getHitstun() != null){
String animName = this.currentMove.getAttackState().getAnimation().getNameThirdPerson(); 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()){ if(parent == Globals.clientState.playerEntity && !Globals.controlHandler.cameraIsThirdPerson()){
Actor viewmodelActor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); Actor viewmodelActor = EntityUtils.getActor(Globals.clientState.firstPersonEntity);
animName = this.currentMove.getAttackState().getAnimation().getNameFirstPerson(); animName = this.currentMove.getAttackState().getAnimation().getNameFirstPerson();
viewmodelActor.setFreezeFrames(animName, this.currentMove.getHitstun()); viewmodelActor.getAnimationData().setFreezeFrames(animName, this.currentMove.getHitstun());
} }
} }
} }

View File

@ -402,7 +402,7 @@ public class ServerAttackTree implements BehaviorTree {
if(targetBone != null){ if(targetBone != null){
Actor parentActor = EntityUtils.getActor(parent); Actor parentActor = EntityUtils.getActor(parent);
//transform bone space //transform bone space
spawnPosition = new Vector3d(parentActor.getBonePosition(targetBone)); spawnPosition = new Vector3d(parentActor.getAnimationData().getBonePosition(targetBone));
spawnPosition = spawnPosition.mul(((Vector3f)EntityUtils.getScale(parent))); spawnPosition = spawnPosition.mul(((Vector3f)EntityUtils.getScale(parent)));
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
spawnPosition = spawnPosition.rotate(new Quaterniond(rotation.x,rotation.y,rotation.z,rotation.w)); 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); // Quaternionf rotation = parentActor.getBoneRotation(targetBone);
// EntityUtils.getRotation(currentEntity).set(rotation).normalize(); // EntityUtils.getRotation(currentEntity).set(rotation).normalize();
// Vector3d facingAngle = CreatureUtils.getFacingVector(parent); // 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(); // 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(); Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize();

View File

@ -106,11 +106,11 @@ public class FirstPersonTree implements BehaviorTree {
if(Globals.clientState.firstPersonEntity != null){ if(Globals.clientState.firstPersonEntity != null){
Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity);
if( 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) (Globals.assetManager.fetchModel(actor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(actor.getBaseModelPath()).getAnimation(animationName) != null)
){ ){
actor.playAnimation(animationName,priority); actor.getAnimationData().playAnimation(animationName,priority);
actor.incrementAnimationTime(offset); actor.getAnimationData().incrementAnimationTime(offset);
} }
} }
} }
@ -132,11 +132,11 @@ public class FirstPersonTree implements BehaviorTree {
if(Globals.clientState.firstPersonEntity != null){ if(Globals.clientState.firstPersonEntity != null){
Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity);
if( 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) (Globals.assetManager.fetchModel(actor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(actor.getBaseModelPath()).getAnimation(animation.getNameFirstPerson()) != null)
){ ){
actor.playAnimation(animation, false); actor.getAnimationData().playAnimation(animation, false);
actor.incrementAnimationTime(offset); actor.getAnimationData().incrementAnimationTime(offset);
} }
} }
} }
@ -149,10 +149,10 @@ public class FirstPersonTree implements BehaviorTree {
if(Globals.clientState.firstPersonEntity != null){ if(Globals.clientState.firstPersonEntity != null){
Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity); Actor actor = EntityUtils.getActor(Globals.clientState.firstPersonEntity);
if( 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) (Globals.assetManager.fetchModel(actor.getBaseModelPath()) != null && Globals.assetManager.fetchModel(actor.getBaseModelPath()).getAnimation(animation.getNameFirstPerson()) != null)
){ ){
actor.interruptAnimation(animation, false); actor.getAnimationData().interruptAnimation(animation, false);
} }
} }
} }

View File

@ -361,11 +361,11 @@ public class ClientEquipState implements BehaviorTree {
if(point.getEquippedAnimation() != null){ if(point.getEquippedAnimation() != null){
TreeDataAnimation animation = point.getEquippedAnimation(); TreeDataAnimation animation = point.getEquippedAnimation();
//play third person //play third person
if(thirdPersonActor.isPlayingAnimation() && thirdPersonActor.isPlayingAnimation(animation)){ if(thirdPersonActor.getAnimationData().isPlayingAnimation() && thirdPersonActor.getAnimationData().isPlayingAnimation(animation)){
if(animation != null){ if(animation != null){
thirdPersonActor.interruptAnimation(animation,true); thirdPersonActor.getAnimationData().interruptAnimation(animation,true);
} }
thirdPersonActor.incrementAnimationTime(0.0001); thirdPersonActor.getAnimationData().incrementAnimationTime(0.0001);
} }
//play first person //play first person
@ -451,11 +451,11 @@ public class ClientEquipState implements BehaviorTree {
if(this.hasEquippedAtPoint(point.getEquipPointId()) && point.getEquippedAnimation() != null){ if(this.hasEquippedAtPoint(point.getEquipPointId()) && point.getEquippedAnimation() != null){
TreeDataAnimation animation = point.getEquippedAnimation(); TreeDataAnimation animation = point.getEquippedAnimation();
//play third person //play third person
if(!thirdPersonActor.isPlayingAnimation() || !thirdPersonActor.isPlayingAnimation(animation)){ if(!thirdPersonActor.getAnimationData().isPlayingAnimation() || !thirdPersonActor.getAnimationData().isPlayingAnimation(animation)){
if(animation != null){ if(animation != null){
thirdPersonActor.playAnimation(animation,true); thirdPersonActor.getAnimationData().playAnimation(animation,true);
} }
thirdPersonActor.incrementAnimationTime(0.0001); thirdPersonActor.getAnimationData().incrementAnimationTime(0.0001);
} }
//play first person //play first person

View File

@ -256,11 +256,11 @@ public class ClientToolbarState implements BehaviorTree {
if(targetPoint.getEquippedAnimation() != null){ if(targetPoint.getEquippedAnimation() != null){
TreeDataAnimation animation = targetPoint.getEquippedAnimation(); TreeDataAnimation animation = targetPoint.getEquippedAnimation();
//play third person //play third person
if(thirdPersonActor.isPlayingAnimation() && thirdPersonActor.isPlayingAnimation(animation)){ if(thirdPersonActor.getAnimationData().isPlayingAnimation() && thirdPersonActor.getAnimationData().isPlayingAnimation(animation)){
if(animation != null){ if(animation != null){
thirdPersonActor.interruptAnimation(animation,true); thirdPersonActor.getAnimationData().interruptAnimation(animation,true);
} }
thirdPersonActor.incrementAnimationTime(0.0001); thirdPersonActor.getAnimationData().incrementAnimationTime(0.0001);
} }
//play first person //play first person

View File

@ -339,8 +339,8 @@ public class HitboxCollectionState {
} }
PhysicsUtils.setRigidBodyTransform(collisionEngine, entityPosition, new Quaterniond(), body); PhysicsUtils.setRigidBodyTransform(collisionEngine, entityPosition, new Quaterniond(), body);
for(String boneName : this.boneHitboxMap.keySet()){ for(String boneName : this.boneHitboxMap.keySet()){
if(EntityUtils.getActor(parent).containsBone(boneName)){ if(EntityUtils.getActor(parent).getAnimationData().containsBone(boneName)){
Vector3d bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName); Vector3d bonePosition = EntityUtils.getActor(parent).getAnimationData().getBonePosition(boneName);
for(HitboxState state : this.boneHitboxMap.get(boneName)){ for(HitboxState state : this.boneHitboxMap.get(boneName)){
DGeom geom = this.stateGeomMap.get(state); DGeom geom = this.stateGeomMap.get(state);
HitboxState shapeStatus = this.geomStateMap.get(geom); HitboxState shapeStatus = this.geomStateMap.get(geom);

View File

@ -78,15 +78,15 @@ public class ClientIdleTree implements BehaviorTree {
if(entityActor != null){ if(entityActor != null){
if( if(
idleData != null && 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()) != null &&
Globals.assetManager.fetchModel(entityActor.getBaseModelPath()).getAnimation(idleData.getAnimation().getNameThirdPerson()) != null Globals.assetManager.fetchModel(entityActor.getBaseModelPath()).getAnimation(idleData.getAnimation().getNameThirdPerson()) != null
) )
){ ){
entityActor.playAnimation(idleData.getAnimation(),true); entityActor.getAnimationData().playAnimation(idleData.getAnimation(),true);
entityActor.incrementAnimationTime(0.0001); entityActor.getAnimationData().incrementAnimationTime(0.0001);
} }
if(idleData != null){ if(idleData != null){
FirstPersonTree.conditionallyPlayAnimation(parent, idleData.getAnimation()); FirstPersonTree.conditionallyPlayAnimation(parent, idleData.getAnimation());

View File

@ -120,7 +120,7 @@ public class ClientFallTree implements BehaviorTree {
boolean isPlayingJump = false; boolean isPlayingJump = false;
Actor entityActor = EntityUtils.getActor(parent); Actor entityActor = EntityUtils.getActor(parent);
if(entityActor != null && ClientJumpTree.getClientJumpTree(parent) != null){ 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 = boolean rVal =
frameCurrent > ServerFallTree.MIN_FRAMES_BEFORE_ACTIVATION_SCAN && frameCurrent > ServerFallTree.MIN_FRAMES_BEFORE_ACTIVATION_SCAN &&
@ -141,10 +141,10 @@ public class ClientFallTree implements BehaviorTree {
Actor entityActor = EntityUtils.getActor(parent); Actor entityActor = EntityUtils.getActor(parent);
if(entityActor != null){ if(entityActor != null){
if( 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.getAnimationData().playAnimation(fallMovementSystem.getLandState().getAnimation().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER));
entityActor.incrementAnimationTime(0.0001); entityActor.getAnimationData().incrementAnimationTime(0.0001);
} }
FirstPersonTree.conditionallyPlayAnimation(parent, fallMovementSystem.getLandState().getAnimation()); FirstPersonTree.conditionallyPlayAnimation(parent, fallMovementSystem.getLandState().getAnimation());
} }

View File

@ -309,9 +309,9 @@ public class ClientGroundMovementTree implements BehaviorTree {
//play animation //play animation
String animationToPlay = determineCorrectAnimation(MovementTreeState.STARTUP); String animationToPlay = determineCorrectAnimation(MovementTreeState.STARTUP);
if(entityActor != null){ if(entityActor != null){
if(!entityActor.isPlayingAnimation(animationToPlay)){ if(!entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){
entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); entityActor.getAnimationData().playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT));
entityActor.incrementAnimationTime(0.0001); entityActor.getAnimationData().incrementAnimationTime(0.0001);
//reset footstep tracking //reset footstep tracking
this.playedFootstepFirst = false; this.playedFootstepFirst = false;
this.playedFootstepSecond = false; this.playedFootstepSecond = false;
@ -319,7 +319,7 @@ public class ClientGroundMovementTree implements BehaviorTree {
FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationStartup().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationStartup().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT));
} }
//conditionally play footstep audio //conditionally play footstep audio
this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); this.playFootstepAudio(0,entityActor.getAnimationData().getAnimationTime(animationToPlay),position);
this.updateVelocity(); this.updateVelocity();
float velocity = this.getModifiedVelocity(); float velocity = this.getModifiedVelocity();
@ -347,9 +347,9 @@ public class ClientGroundMovementTree implements BehaviorTree {
//play animation //play animation
String animationToPlay = determineCorrectAnimation(MovementTreeState.MOVE); String animationToPlay = determineCorrectAnimation(MovementTreeState.MOVE);
if(entityActor != null){ if(entityActor != null){
if(!entityActor.isPlayingAnimation(animationToPlay)){ if(!entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){
entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); entityActor.getAnimationData().playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT));
entityActor.incrementAnimationTime(0.0001); entityActor.getAnimationData().incrementAnimationTime(0.0001);
//reset footstep tracking //reset footstep tracking
this.playedFootstepFirst = false; this.playedFootstepFirst = false;
this.playedFootstepSecond = false; this.playedFootstepSecond = false;
@ -358,7 +358,7 @@ public class ClientGroundMovementTree implements BehaviorTree {
} }
//conditionally play footstep audio //conditionally play footstep audio
this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); this.playFootstepAudio(0,entityActor.getAnimationData().getAnimationTime(animationToPlay),position);
this.updateVelocity(); this.updateVelocity();
float velocity = this.getModifiedVelocity(); float velocity = this.getModifiedVelocity();
@ -380,20 +380,20 @@ public class ClientGroundMovementTree implements BehaviorTree {
String animationToPlay = determineCorrectAnimation(MovementTreeState.SLOWDOWN); String animationToPlay = determineCorrectAnimation(MovementTreeState.SLOWDOWN);
if(entityActor != null){ if(entityActor != null){
//play animations //play animations
if(!entityActor.isPlayingAnimation(animationToPlay)){ if(!entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){
entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); entityActor.getAnimationData().playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT));
entityActor.incrementAnimationTime(0.0001); entityActor.getAnimationData().incrementAnimationTime(0.0001);
//reset footstep tracking //reset footstep tracking
this.playedFootstepFirst = false; this.playedFootstepFirst = false;
this.playedFootstepSecond = false; this.playedFootstepSecond = false;
} }
FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationWindDown().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationWindDown().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT));
if(entityActor.isPlayingAnimation(determineCorrectAnimation(MovementTreeState.MOVE))){ if(entityActor.getAnimationData().isPlayingAnimation(determineCorrectAnimation(MovementTreeState.MOVE))){
entityActor.stopAnimation(determineCorrectAnimation(MovementTreeState.MOVE)); entityActor.getAnimationData().stopAnimation(determineCorrectAnimation(MovementTreeState.MOVE));
} }
} }
//conditionally play footstep audio //conditionally play footstep audio
this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); this.playFootstepAudio(0,entityActor.getAnimationData().getAnimationTime(animationToPlay),position);
//velocity stuff //velocity stuff
this.updateVelocity(); this.updateVelocity();
@ -404,8 +404,8 @@ public class ClientGroundMovementTree implements BehaviorTree {
state = MovementTreeState.IDLE; state = MovementTreeState.IDLE;
if(entityActor != null){ if(entityActor != null){
animationToPlay = determineCorrectAnimation(MovementTreeState.SLOWDOWN); animationToPlay = determineCorrectAnimation(MovementTreeState.SLOWDOWN);
if(entityActor.isPlayingAnimation() && entityActor.isPlayingAnimation(animationToPlay)){ if(entityActor.getAnimationData().isPlayingAnimation() && entityActor.getAnimationData().isPlayingAnimation(animationToPlay)){
entityActor.stopAnimation(animationToPlay); entityActor.getAnimationData().stopAnimation(animationToPlay);
} }
} }
CreatureUtils.setVelocity(parent, velocity); CreatureUtils.setVelocity(parent, velocity);

View File

@ -95,9 +95,9 @@ public class ClientJumpTree implements BehaviorTree {
switch(state){ switch(state){
case ACTIVE: { case ACTIVE: {
if(entityActor != null){ if(entityActor != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(jumpData.getAnimationJump().getNameThirdPerson())){ if(!entityActor.getAnimationData().isPlayingAnimation() || !entityActor.getAnimationData().isPlayingAnimation(jumpData.getAnimationJump().getNameThirdPerson())){
entityActor.playAnimation(jumpData.getAnimationJump().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER)); entityActor.getAnimationData().playAnimation(jumpData.getAnimationJump().getNameThirdPerson(),AnimationPriorities.getValue(AnimationPriorities.MOVEMENT_MODIFIER));
entityActor.incrementAnimationTime(0.0001); entityActor.getAnimationData().incrementAnimationTime(0.0001);
} }
FirstPersonTree.conditionallyPlayAnimation(parent, jumpData.getAnimationJump()); FirstPersonTree.conditionallyPlayAnimation(parent, jumpData.getAnimationJump());
} }

View File

@ -42,7 +42,7 @@ public class RotatorTree implements BehaviorTree{
state = RotatorTreeState.INACTIVE; state = RotatorTreeState.INACTIVE;
//clear all modifications we've made up to this point //clear all modifications we've made up to this point
for(RotatorHierarchyNode node : nodes){ 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. // currentRotation.
} }
if(followsView){ if(followsView){
ActorBoneRotator currentRotator = entityActor.getBoneRotator(node.getBone()); ActorBoneRotator currentRotator = entityActor.getAnimationData().getBoneRotator(node.getBone());
//apparently this isn't needed? //apparently this isn't needed?
//not sure I understand the math on this one //not sure I understand the math on this one
// Vector3d facingVector = CreatureUtils.getFacingVector(parent); // Vector3d facingVector = CreatureUtils.getFacingVector(parent);

View File

@ -380,7 +380,7 @@ public class CommonEntityUtils {
for(RotatorItem item : system.getRotatorItems()){ for(RotatorItem item : system.getRotatorItems()){
//put actor rotator //put actor rotator
ActorBoneRotator newRotator = new ActorBoneRotator(); ActorBoneRotator newRotator = new ActorBoneRotator();
creatureActor.addBoneRotator(item.getBoneName(), newRotator); creatureActor.getAnimationData().addBoneRotator(item.getBoneName(), newRotator);
//construct node for tree //construct node for tree
RotatorHierarchyNode hierarchyNode = new RotatorHierarchyNode(); RotatorHierarchyNode hierarchyNode = new RotatorHierarchyNode();
hierarchyNode.setBone(item.getBoneName()); hierarchyNode.setBone(item.getBoneName());
@ -394,7 +394,7 @@ public class CommonEntityUtils {
} }
//bone groups //bone groups
if(rawType.getBoneGroups() != null){ if(rawType.getBoneGroups() != null){
creatureActor.setBoneGroups(rawType.getBoneGroups()); creatureActor.getAnimationData().setBoneGroups(rawType.getBoneGroups());
} }
//grid alignment //grid alignment
if(rawType.getGridAlignedData() != null){ if(rawType.getGridAlignedData() != null){

View File

@ -107,7 +107,7 @@ public class CreatureUtils {
if(attributeType.getType().equals("bone")){ if(attributeType.getType().equals("bone")){
if(staticMorph == null){ if(staticMorph == null){
staticMorph = new ActorStaticMorph(); staticMorph = new ActorStaticMorph();
creatureActor.setActorStaticMorph(staticMorph); creatureActor.getAnimationData().setActorStaticMorph(staticMorph);
} }
if(attributeType.getPrimaryBone() != null && staticMorph.getBoneTransforms(attributeType.getPrimaryBone()) == null){ if(attributeType.getPrimaryBone() != null && staticMorph.getBoneTransforms(attributeType.getPrimaryBone()) == null){
staticMorph.initBoneTransforms(attributeType.getPrimaryBone()); staticMorph.initBoneTransforms(attributeType.getPrimaryBone());
@ -380,7 +380,7 @@ public class CreatureUtils {
Actor creatureActor = EntityUtils.getActor(rVal); Actor creatureActor = EntityUtils.getActor(rVal);
if(rawType.getBoneGroups() != null){ if(rawType.getBoneGroups() != null){
creatureActor.setBoneGroups(rawType.getBoneGroups()); creatureActor.getAnimationData().setBoneGroups(rawType.getBoneGroups());
} }
return rVal; return rVal;

View File

@ -331,9 +331,9 @@ public class ItemUtils {
Actor actor = EntityUtils.getActor(item); Actor actor = EntityUtils.getActor(item);
if(actor != null && item.getData(EntityDataStrings.ANIM_IDLE) != null){ if(actor != null && item.getData(EntityDataStrings.ANIM_IDLE) != null){
String idleAnim = (String)item.getData(EntityDataStrings.ANIM_IDLE); String idleAnim = (String)item.getData(EntityDataStrings.ANIM_IDLE);
if(!actor.isPlayingAnimation(idleAnim)){ if(!actor.getAnimationData().isPlayingAnimation(idleAnim)){
actor.playAnimation(idleAnim,AnimationPriorities.getValue(AnimationPriorities.INTERACTION)); actor.getAnimationData().playAnimation(idleAnim,AnimationPriorities.getValue(AnimationPriorities.INTERACTION));
actor.incrementAnimationTime(0.0001); actor.getAnimationData().incrementAnimationTime(0.0001);
} }
} }
} }

View File

@ -1,34 +1,25 @@
package electrosphere.renderer.actor; package electrosphere.renderer.actor;
import electrosphere.data.entity.common.treedata.TreeDataAnimation;
import electrosphere.data.entity.creature.bonegroups.BoneGroup;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.state.AnimationPriorities;
import electrosphere.logger.LoggerInterface;
import electrosphere.mem.JomlPool; import electrosphere.mem.JomlPool;
import electrosphere.renderer.OpenGLState; import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState; 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.ActorMeshMask;
import electrosphere.renderer.actor.mask.ActorShaderMask; import electrosphere.renderer.actor.mask.ActorShaderMask;
import electrosphere.renderer.actor.mask.ActorTextureMask; import electrosphere.renderer.actor.mask.ActorTextureMask;
import electrosphere.renderer.actor.mask.ActorUniformMap; import electrosphere.renderer.actor.mask.ActorUniformMap;
import electrosphere.renderer.actor.mask.ActorUniformMap.UniformValue; import electrosphere.renderer.actor.mask.ActorUniformMap.UniformValue;
import electrosphere.renderer.model.Bone;
import electrosphere.renderer.model.Model; import electrosphere.renderer.model.Model;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.joml.Matrix4d; import org.joml.Matrix4d;
import org.joml.Quaterniond;
import org.joml.Sphered; import org.joml.Sphered;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector4d;
/** /**
* An actor * An actor
@ -43,11 +34,6 @@ import org.joml.Vector4d;
*/ */
public class Actor { 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 * full-resolution lod level
*/ */
@ -83,11 +69,6 @@ public class Actor {
*/ */
private boolean frustumCull = true; private boolean frustumCull = true;
/**
* scales the time that animations are played at
*/
private float animationScalar = 1.0f;
/** /**
* Sets scaling applied at the actor level * Sets scaling applied at the actor level
*/ */
@ -129,9 +110,9 @@ public class Actor {
private String lowResBaseModelPath; private String lowResBaseModelPath;
/** /**
* The stack of animations being applied to a given actor * The animation data for the actor
*/ */
private Set<ActorAnimationMaskEntry> animationQueue = new TreeSet<ActorAnimationMaskEntry>(); private final ActorAnimationData animationData;
/** /**
* Mask for overwriting meshes in a given actor * Mask for overwriting meshes in a given actor
@ -148,50 +129,11 @@ public class Actor {
*/ */
private Map<String,ActorTextureMask> textureMap = null; private Map<String,ActorTextureMask> textureMap = null;
/**
* bone rotators
*/
private Map<String,ActorBoneRotator> boneRotators = new HashMap<String,ActorBoneRotator>();
/**
* static morph for this specific actor
*/
private ActorStaticMorph staticMorph;
/**
* The list of bone groups
*/
private List<BoneGroup> boneGroups;
/** /**
* A map of mesh -> uniforms to apply to the mesh * A map of mesh -> uniforms to apply to the mesh
*/ */
private ActorUniformMap uniformMap = new ActorUniformMap(); private ActorUniformMap uniformMap = new ActorUniformMap();
/**
* Used for caching animation masks that should be removed
*/
private List<ActorAnimationMaskEntry> toRemoveMasks = new LinkedList<ActorAnimationMaskEntry>();
//
//
// DATA CACHING
//
//
/**
* Stores the positions of bones as they are updated
*/
private Map<String,Vector3d> bonePositionMap = new HashMap<String,Vector3d>();
/**
* Stores the rotations of bones as they are updated
*/
private Map<String,Quaterniond> boneRotationMap = new HashMap<String,Quaterniond>();
@ -208,354 +150,7 @@ public class Actor {
*/ */
public Actor(String modelPath){ public Actor(String modelPath){
this.baseModelPath = modelPath; this.baseModelPath = modelPath;
} this.animationData = new ActorAnimationData(this);
/**
* 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<ActorAnimationMaskEntry> toRemove = new LinkedList<ActorAnimationMaskEntry>();
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<String> boneMask = null;
if(animation.getBoneGroups() != null && this.boneGroups != null){
boneMask = new LinkedList<String>();
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<String>();
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<String> 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<ActorAnimationMaskEntry> getAnimationQueue(){
return animationQueue;
}
/**
* Applies the animation masks in this actor to the provided model
* @param model The model
*/
private void applyAnimationMasks(Model model){
List<String> bonesUsed = new LinkedList<String>();
List<String> currentAnimationMask = new LinkedList<String>();
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;
} }
/** /**
@ -594,7 +189,7 @@ public class Actor {
//frustum cull then draw //frustum cull then draw
if(Actor.isWithinFrustumBox(renderPipelineState,model,frustumCull)){ if(Actor.isWithinFrustumBox(renderPipelineState,model,frustumCull)){
this.applyAnimationMasks(model); this.animationData.applyAnimationMasks(model);
meshMask.processMeshMaskQueue(); meshMask.processMeshMaskQueue();
model.setMeshMask(meshMask); model.setMeshMask(meshMask);
model.setTextureMask(textureMap); model.setTextureMask(textureMap);
@ -603,7 +198,7 @@ public class Actor {
model.getShaderMask().put(shaderMask.getMeshName(),shaderMask); model.getShaderMask().put(shaderMask.getMeshName(),shaderMask);
} }
} }
this.calculateNodeTransforms(model); this.animationData.calculateNodeTransforms(model);
//apply uniform overrides //apply uniform overrides
if(this.uniformMap.getMeshes() != null && this.uniformMap.getMeshes().size() > 0){ if(this.uniformMap.getMeshes() != null && this.uniformMap.getMeshes().size() > 0){
for(String meshName : this.uniformMap.getMeshes()){ for(String meshName : this.uniformMap.getMeshes()){
@ -635,12 +230,12 @@ public class Actor {
this.lodLevel == Actor.LOD_LEVEL_STATIC || this.lodLevel == Actor.LOD_LEVEL_STATIC ||
//actor doesn't have anything complicated render-wise (animations, custom textures, etc) //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.meshMask.getBlockedMeshes().size() == 0 &&
this.textureMap == null && this.textureMap == null &&
this.shaderMasks.size() == 0 && this.shaderMasks.size() == 0 &&
this.uniformMap.isEmpty() && this.uniformMap.isEmpty() &&
this.staticMorph == null this.animationData.getStaticMorph() == null
) )
; ;
} }
@ -657,12 +252,12 @@ public class Actor {
public String getStatisDrawStatus(){ public String getStatisDrawStatus(){
String rVal = ""; String rVal = "";
rVal = rVal + this.isStaticDrawCall() + "\n"; 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.meshMask.getBlockedMeshes().size() == 0) + "\n";
rVal = rVal + (this.textureMap == null) + "\n"; rVal = rVal + (this.textureMap == null) + "\n";
rVal = rVal + (this.shaderMasks.size() == 0) + "\n"; rVal = rVal + (this.shaderMasks.size() == 0) + "\n";
rVal = rVal + this.uniformMap.isEmpty() + "\n"; rVal = rVal + this.uniformMap.isEmpty() + "\n";
rVal = rVal + (this.staticMorph == null) + "\n"; rVal = rVal + (this.animationData.getStaticMorph() == null) + "\n";
return rVal; return rVal;
} }
@ -698,130 +293,6 @@ public class Actor {
return baseModelPath; 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<Bone> 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 * Checks if the model is loaded for this actor
* @return true if it is loaded, false otherwise * @return true if it is loaded, false otherwise
@ -872,25 +343,6 @@ public class Actor {
textureMap.put(textureMask.getMeshName(),textureMask); 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 * Sets the value of a uniform on a given mesh within this actor
* @param meshName The name of the mesh * @param meshName The name of the mesh
@ -901,22 +353,6 @@ public class Actor {
this.uniformMap.setUniform(meshName, uniformName, 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 * Sets whether this actor should frustum cull or not
* @param frustumCull true to frustum cull, false to skip frustum culling * @param frustumCull true to frustum cull, false to skip frustum culling
@ -933,31 +369,6 @@ public class Actor {
return frustumCull; return frustumCull;
} }
/**
* Sets the bone groups in the actor
* @param boneGroups The bone groups
*/
public void setBoneGroups(List<BoneGroup> 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; this.lodLevel = lodLevel;
} }
/**
* Gets the animation data for the actor
* @return
*/
public ActorAnimationData getAnimationData(){
return this.animationData;
}
} }

View File

@ -37,7 +37,7 @@ public class ActorUtils {
*/ */
public static ActorStaticMorph getStaticMorph(Entity actorEntity){ public static ActorStaticMorph getStaticMorph(Entity actorEntity){
Actor entityActor = EntityUtils.getActor(actorEntity); Actor entityActor = EntityUtils.getActor(actorEntity);
return entityActor.getStaticMorph(); return entityActor.getAnimationData().getStaticMorph();
} }
/** /**

View File

@ -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<ActorAnimationMaskEntry> animationQueue = new TreeSet<ActorAnimationMaskEntry>();
/**
* Used for caching animation masks that should be removed
*/
private List<ActorAnimationMaskEntry> toRemoveMasks = new LinkedList<ActorAnimationMaskEntry>();
/**
* The list of bone groups
*/
private List<BoneGroup> boneGroups;
/**
* static morph for this specific actor
*/
private ActorStaticMorph staticMorph;
/**
* bone rotators
*/
private Map<String,ActorBoneRotator> boneRotators = new HashMap<String,ActorBoneRotator>();
//
//
// DATA CACHING
//
//
/**
* Stores the positions of bones as they are updated
*/
private Map<String,Vector3d> bonePositionMap = new HashMap<String,Vector3d>();
/**
* Stores the rotations of bones as they are updated
*/
private Map<String,Quaterniond> boneRotationMap = new HashMap<String,Quaterniond>();
/**
* 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<ActorAnimationMaskEntry> toRemove = new LinkedList<ActorAnimationMaskEntry>();
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<String> boneMask = null;
if(animation.getBoneGroups() != null && this.boneGroups != null){
boneMask = new LinkedList<String>();
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<String>();
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<String> 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<ActorAnimationMaskEntry> getAnimationQueue(){
return animationQueue;
}
/**
* Applies the animation masks in this actor to the provided model
* @param model The model
*/
public void applyAnimationMasks(Model model){
List<String> bonesUsed = new LinkedList<String>();
List<String> currentAnimationMask = new LinkedList<String>();
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<BoneGroup> 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<Bone> 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;
}
}

View File

@ -70,7 +70,7 @@ public class DebugBonesPipeline implements RenderPipeline {
Actor targetActor = EntityUtils.getActor(targetEntity); Actor targetActor = EntityUtils.getActor(targetEntity);
Model boneModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER); Model boneModel = Globals.assetManager.fetchModel(AssetDataStrings.UNITCYLINDER);
boneModel.getMaterials().get(0).setDiffuse(Globals.assetManager.fetchTexture(AssetDataStrings.TEXTURE_DEFAULT)); 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); Vector3d bonePos = MathBones.getBoneWorldPosition(targetEntity, bone.boneID);
Quaterniond boneRot = MathBones.getBoneWorldRotation(targetEntity, bone.boneID); Quaterniond boneRot = MathBones.getBoneWorldRotation(targetEntity, bone.boneID);

View File

@ -226,12 +226,12 @@ public class ActorPanel extends BufferedStandardDrawableContainerElement impleme
Model actorModel = Globals.assetManager.fetchModel(actor.getBaseModelPath()); Model actorModel = Globals.assetManager.fetchModel(actor.getBaseModelPath());
if(currentAnim != null){ if(currentAnim != null){
if((!actor.isPlayingAnimation() || !actor.isPlayingAnimation(currentAnim)) && if((!actor.getAnimationData().isPlayingAnimation() || !actor.getAnimationData().isPlayingAnimation(currentAnim)) &&
actorModel != null && actorModel != null &&
actorModel.getAnimation(currentAnim) != null actorModel.getAnimation(currentAnim) != null
){ ){
actor.playAnimation(currentAnim,3); actor.getAnimationData().playAnimation(currentAnim,3);
actor.incrementAnimationTime(0.0001); actor.getAnimationData().incrementAnimationTime(0.0001);
} }
} }
if(!hasOffsetFromBoundingSphere && actorModel != null){ if(!hasOffsetFromBoundingSphere && actorModel != null){

View File

@ -22,7 +22,7 @@ public class MathBones {
*/ */
public static Vector3d getBoneWorldPosition(Entity actorEntity, String boneName){ public static Vector3d getBoneWorldPosition(Entity actorEntity, String boneName){
Actor actor = EntityUtils.getActor(actorEntity); Actor actor = EntityUtils.getActor(actorEntity);
Vector3d localPos = new Vector3d(actor.getBonePosition(boneName)); Vector3d localPos = new Vector3d(actor.getAnimationData().getBonePosition(boneName));
//transform bone space //transform bone space
Vector3d position = new Vector3d(localPos); Vector3d position = new Vector3d(localPos);
@ -41,7 +41,7 @@ public class MathBones {
*/ */
public static Quaterniond getBoneWorldRotation(Entity actorEntity, String boneName){ public static Quaterniond getBoneWorldRotation(Entity actorEntity, String boneName){
Actor actor = EntityUtils.getActor(actorEntity); Actor actor = EntityUtils.getActor(actorEntity);
Quaterniond localRot = actor.getBoneRotation(boneName); Quaterniond localRot = actor.getAnimationData().getBoneRotation(boneName);
Vector3d facingAngle = CreatureUtils.getFacingVector(actorEntity); Vector3d facingAngle = CreatureUtils.getFacingVector(actorEntity);
if(facingAngle == null){ if(facingAngle == null){