191 lines
6.5 KiB
C++
191 lines
6.5 KiB
C++
|
#include "animationsystem.h"
|
||
|
|
||
|
#include <fstream>
|
||
|
#include <sstream>
|
||
|
#include <iostream>
|
||
|
#include <json.hpp>
|
||
|
|
||
|
#include "mesh.h"
|
||
|
#include "stringutils.h"
|
||
|
#include "worldmanager.h"
|
||
|
#include "world.h"
|
||
|
#include "assetmanager.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 meshObject : shotObject["meshes"]) {
|
||
|
CinematicMesh mesh;
|
||
|
mesh.name = meshObject["name"];
|
||
|
mesh.modelPath = meshObject["path"];
|
||
|
mesh.materialPath = meshObject["material"];
|
||
|
|
||
|
shot->meshes.push_back(mesh);
|
||
|
}
|
||
|
|
||
|
for(auto animationObject : shotObject["animations"]) {
|
||
|
auto animation = new Animation();
|
||
|
animation->targetName = animationObject["target"];
|
||
|
|
||
|
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->target == nullptr)
|
||
|
worldManager.getCurrentWorld()->camera.position = pos;
|
||
|
else {
|
||
|
animation->target->position = pos;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case AnimationProperty::Target:
|
||
|
{
|
||
|
auto pos = currentFrame.valueVec3 + delta * (nextFrame.valueVec3 - currentFrame.valueVec3);
|
||
|
|
||
|
worldManager.getCurrentWorld()->camera.target = pos;
|
||
|
}
|
||
|
break;
|
||
|
case AnimationProperty::FoV:
|
||
|
{
|
||
|
auto pos = currentFrame.valueInt + delta * (nextFrame.valueInt - currentFrame.valueInt);
|
||
|
worldManager.getCurrentWorld()->camera.fov = pos;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
animationTime += deltaTime;
|
||
|
}
|
||
|
|
||
|
void AnimationSystem::preloadShot(Shot* shot) {
|
||
|
std::cout << "preloading shot..." << std::endl;
|
||
|
|
||
|
worldManager.loadWorld(shot->world);
|
||
|
|
||
|
for(auto cimMesh : shot->meshes) {
|
||
|
Mesh* mesh = assetManager.loadMesh(cimMesh.modelPath);
|
||
|
mesh->name = cimMesh.name;
|
||
|
mesh->material = assetManager.loadMaterial(cimMesh.materialPath);
|
||
|
mesh->tag = "cinematic";
|
||
|
|
||
|
for(auto animation : shot->animations) {
|
||
|
if(animation->targetName == mesh->name)
|
||
|
animation->target = mesh;
|
||
|
}
|
||
|
|
||
|
shot->loadedMeshes.push_back(mesh);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AnimationSystem::loadShot(Shot* shot) {
|
||
|
std::cout << "loading shot..." << std::endl;
|
||
|
|
||
|
worldManager.switchWorld(shot->world);
|
||
|
|
||
|
for(auto mesh : shot->loadedMeshes)
|
||
|
worldManager.getCurrentWorld()->meshes.push_back(mesh);
|
||
|
}
|
||
|
|
||
|
void AnimationSystem::unloadShot(Shot* shot) {
|
||
|
std::cout << "unloading shot..." << std::endl;
|
||
|
|
||
|
World* world = worldManager.getCurrentWorld();
|
||
|
|
||
|
for(auto mesh : world->meshes) {
|
||
|
if(mesh->tag == "cinematic") {
|
||
|
//renderer->destroyMaterialBuffers(mesh->material);
|
||
|
delete mesh->material;
|
||
|
|
||
|
//renderer->destroyMeshBuffers(mesh);
|
||
|
delete mesh;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
world->meshes.erase(std::remove_if(world->meshes.begin(),
|
||
|
world->meshes.end(),
|
||
|
[](Mesh* m){return m->tag == "cinematic";}),
|
||
|
world->meshes.end());
|
||
|
}
|