#include "animationsystem.h" #include #include #include #include "mesh.h" #include "stringutils.h" #include "worldmanager.h" #include "world.h" #include "assetmanager.h" #include "entityparser.h" Cinematic* AnimationSystem::loadCinematic(const std::string& path) { std::ifstream file("data/" + path); if(!file) return nullptr; nlohmann::json json; file >> json; auto cinematic = new Cinematic(); for(auto shotObject : json["shots"]) { Shot* shot = new Shot(); shot->start = shotObject["start"]; shot->end = shotObject["end"]; shot->world = shotObject["world"]; for(auto entityObject : shotObject["entities"]) { CinematicEntity entity; entity.data = entityObject; shot->entities.push_back(entity); } for(auto animationObject : shotObject["animations"]) { auto animation = new Animation(); animation->targetName = animationObject["target"]; animation->targetComponent = animationObject["targetComponent"]; const auto property = animationObject["property"]; if(property == "position") animation->property = AnimationProperty::Position; else if(property == "target") animation->property = AnimationProperty::Target; else if(property == "fov") animation->property = AnimationProperty::FoV; for(auto keyframeObject : animationObject["keyframes"]) { Keyframe keyframe; keyframe.time = keyframeObject["time"]; if(animation->property == AnimationProperty::Position || animation->property == AnimationProperty::Target) { auto tokens = tokenize(keyframeObject["value"]); keyframe.valueVec3[0] = atof(tokens[0].c_str()); keyframe.valueVec3[1] = atof(tokens[1].c_str()); keyframe.valueVec3[2] = atof(tokens[2].c_str()); animation->keyframes.push_back(keyframe); } else if(animation->property == AnimationProperty::FoV) { keyframe.valueInt = keyframeObject["value"]; animation->keyframes.push_back(keyframe); } } shot->animations.push_back(animation); } cinematic->shots.push_back(shot); } preloadShot(cinematic->shots[0]); loadShot(cinematic->shots[0]); return cinematic; } void AnimationSystem::update(Cinematic* cinematic, float deltaTime) { float endTime = 0.0f; for(uint32_t i = 0; i < cinematic->shots.size(); i++) { // load the shot before it happens if((i + 1) <= cinematic->shots.size() && i == (currentShot + 1) && !cinematic->shots[currentShot + 1]->loaded) { preloadShot(cinematic->shots[currentShot + 1]); cinematic->shots[currentShot + 1]->loaded = true; } if(i > currentShot && animationTime > cinematic->shots[i]->start) { unloadShot(cinematic->shots[currentShot]); currentShot = i; loadShot(cinematic->shots[i]); } } for(auto animation : cinematic->shots[currentShot]->animations) { unsigned int frameIndex = 0; for(size_t i = 0; i < animation->keyframes.size(); i++) { if(animationTime < animation->keyframes[i + 1].time) { frameIndex = i; break; } } const auto currentFrame = animation->keyframes[frameIndex]; const auto nextFrame = animation->keyframes[(frameIndex + 1) % animation->keyframes.size()]; const float delta = (animationTime - currentFrame.time) / (nextFrame.time - currentFrame.time); switch(animation->property) { case AnimationProperty::Position: { auto pos = currentFrame.valueVec3 + delta * (nextFrame.valueVec3 - currentFrame.valueVec3); if(animation->targetComponent == "Transform") { TransformComponent* transform = ECS::getComponent(animation->target); transform->position = pos; } } break; case AnimationProperty::Target: { auto pos = currentFrame.valueVec3 + delta * (nextFrame.valueVec3 - currentFrame.valueVec3); if(animation->targetComponent == "Camera") { CameraComponent* camera = ECS::getComponent(animation->target); camera->target = pos; } } break; case AnimationProperty::FoV: { auto pos = currentFrame.valueInt + delta * (nextFrame.valueInt - currentFrame.valueInt); if(animation->targetComponent == "Camera") { CameraComponent* camera = ECS::getComponent(animation->target); camera->fov = pos; } } break; } } animationTime += deltaTime; } void AnimationSystem::preloadShot(Shot* shot) { worldManager.loadWorld(shot->world); for(auto cimEntity : shot->entities) { EntityID entity = parseEntity(cimEntity.data, worldManager.getWorld(shot->world)); for(auto animation : shot->animations) { if(animation->targetName == ECS::getComponent(entity)->name) animation->target = entity; } shot->loadedEntities.push_back(entity); } } void AnimationSystem::loadShot(Shot* shot) { worldManager.switchWorld(shot->world); } void AnimationSystem::unloadShot(Shot* shot) { World* world = worldManager.getCurrentWorld(); for(auto entity : shot->loadedEntities) ECS::destroyEntity(entity); }