Add support for multiple worlds in a single cinematic
This commit is contained in:
parent
c7d87e9a9f
commit
d91c7d7221
12 changed files with 425 additions and 267 deletions
|
@ -53,7 +53,10 @@ set(GRAPH_SRC
|
||||||
src/skypass.cpp
|
src/skypass.cpp
|
||||||
src/shadowpass.cpp
|
src/shadowpass.cpp
|
||||||
src/config.cpp
|
src/config.cpp
|
||||||
src/stringutils.cpp)
|
src/stringutils.cpp
|
||||||
|
src/animationsystem.cpp
|
||||||
|
src/worldmanager.cpp
|
||||||
|
src/assetmanager.cpp)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
set(GRAPH_SRC
|
set(GRAPH_SRC
|
||||||
|
@ -109,4 +112,5 @@ add_data(Graph
|
||||||
data/tile.jpg
|
data/tile.jpg
|
||||||
data/graphics_presets.cfg
|
data/graphics_presets.cfg
|
||||||
data/test.world
|
data/test.world
|
||||||
data/test.material)
|
data/test.material
|
||||||
|
data/empty.world)
|
||||||
|
|
11
data/empty.world
Normal file
11
data/empty.world
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"meshes": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"lights": [
|
||||||
|
{
|
||||||
|
"position": "66,56,25",
|
||||||
|
"type": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -70,7 +70,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"world": "test.world",
|
"world": "empty.world",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
"end": 10,
|
"end": 10,
|
||||||
"meshes": [
|
"meshes": [
|
||||||
|
|
20
include/animationsystem.h
Normal file
20
include/animationsystem.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "cinematic.h"
|
||||||
|
|
||||||
|
class AnimationSystem {
|
||||||
|
public:
|
||||||
|
Cinematic* loadCinematic(const std::string& path);
|
||||||
|
|
||||||
|
void update(Cinematic* cinematic, float deltaTime);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void preloadShot(Shot* shot);
|
||||||
|
void loadShot(Shot* shot);
|
||||||
|
void unloadShot(Shot* shot);
|
||||||
|
|
||||||
|
float animationTime = 0.0f;
|
||||||
|
int currentShot = 0;
|
||||||
|
};
|
22
include/assetmanager.h
Normal file
22
include/assetmanager.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Mesh;
|
||||||
|
struct Material;
|
||||||
|
class Renderer;
|
||||||
|
|
||||||
|
class AssetManager {
|
||||||
|
public:
|
||||||
|
void setRenderer(Renderer* r) {
|
||||||
|
renderer = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh* loadMesh(const std::string& path);
|
||||||
|
Material* loadMaterial(const std::string& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Renderer* renderer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline AssetManager assetManager;
|
|
@ -19,15 +19,24 @@ enum class AnimationProperty {
|
||||||
|
|
||||||
struct Animation {
|
struct Animation {
|
||||||
Mesh* target = nullptr;
|
Mesh* target = nullptr;
|
||||||
|
std::string targetName;
|
||||||
AnimationProperty property = AnimationProperty::Position;
|
AnimationProperty property = AnimationProperty::Position;
|
||||||
|
|
||||||
std::vector<Keyframe> keyframes;
|
std::vector<Keyframe> keyframes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CinematicMesh {
|
||||||
|
std::string name, modelPath, materialPath;
|
||||||
|
};
|
||||||
|
|
||||||
struct Shot {
|
struct Shot {
|
||||||
int start = 0, end = 0;
|
int start = 0, end = 0;
|
||||||
|
bool loaded = false;
|
||||||
|
|
||||||
std::vector<Mesh*> meshes;
|
std::string world;
|
||||||
|
|
||||||
|
std::vector<CinematicMesh> meshes;
|
||||||
|
std::vector<Mesh*> loadedMeshes;
|
||||||
std::vector<Animation*> animations;
|
std::vector<Animation*> animations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "camera.h"
|
||||||
|
|
||||||
class Mesh;
|
class Mesh;
|
||||||
class Light;
|
class Light;
|
||||||
|
|
||||||
|
@ -9,4 +11,6 @@ class World {
|
||||||
public:
|
public:
|
||||||
std::vector<Mesh*> meshes;
|
std::vector<Mesh*> meshes;
|
||||||
std::vector<Light*> lights;
|
std::vector<Light*> lights;
|
||||||
|
|
||||||
|
Camera camera;
|
||||||
};
|
};
|
||||||
|
|
23
include/worldmanager.h
Normal file
23
include/worldmanager.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
struct World;
|
||||||
|
|
||||||
|
class WorldManager {
|
||||||
|
public:
|
||||||
|
void loadWorld(const std::string& path);
|
||||||
|
|
||||||
|
void switchWorld(const std::string& path);
|
||||||
|
|
||||||
|
World* getCurrentWorld() {
|
||||||
|
return currentWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, World*> loadedWorlds;
|
||||||
|
World* currentWorld = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline WorldManager worldManager;
|
190
src/animationsystem.cpp
Normal file
190
src/animationsystem.cpp
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
#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());
|
||||||
|
}
|
61
src/assetmanager.cpp
Normal file
61
src/assetmanager.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include "assetmanager.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <json.hpp>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/postprocess.h>
|
||||||
|
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "material.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
Mesh* AssetManager::loadMesh(const std::string& path) {
|
||||||
|
std::string fixedPath = "data/" + path;
|
||||||
|
|
||||||
|
Assimp::Importer importer;
|
||||||
|
const aiScene* scene = importer.ReadFile(fixedPath.c_str(), aiProcess_Triangulate);
|
||||||
|
|
||||||
|
Mesh* mesh = new Mesh();
|
||||||
|
|
||||||
|
unsigned int indexOffset = 0;
|
||||||
|
for(unsigned mi = 0; mi < scene->mNumMeshes; mi++) {
|
||||||
|
aiMesh* m = scene->mMeshes[mi];
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < m->mNumVertices; i++) {
|
||||||
|
Vertex vertex;
|
||||||
|
vertex.position = glm::vec3(m->mVertices[i].x, m->mVertices[i].y, m->mVertices[i].z);
|
||||||
|
vertex.normal = glm::vec3(m->mNormals[i].x, m->mNormals[i].y, m->mNormals[i].z);
|
||||||
|
vertex.uv = glm::vec2(m->mTextureCoords[0][i].x, m->mTextureCoords[0][i].y);
|
||||||
|
|
||||||
|
mesh->vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < m->mNumFaces; i++) {
|
||||||
|
aiFace face = m->mFaces[i];
|
||||||
|
for(unsigned int j = 0; j < face.mNumIndices; j++)
|
||||||
|
mesh->indices.push_back(indexOffset + face.mIndices[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
indexOffset += m->mNumVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer->fillMeshBuffers(mesh);
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material* AssetManager::loadMaterial(const std::string& path) {
|
||||||
|
std::ifstream file("data/" + path);
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
file >> json;
|
||||||
|
|
||||||
|
Material* material = new Material();
|
||||||
|
material->albedoTexturePath = "data/" + json["albedoTexture"].get<std::string>();
|
||||||
|
|
||||||
|
renderer->fillMaterialBuffers(material);
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
286
src/main.cpp
286
src/main.cpp
|
@ -5,9 +5,6 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
#include <assimp/Importer.hpp>
|
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/postprocess.h>
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
@ -19,10 +16,12 @@
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
#include "light.h"
|
#include "light.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "cinematic.h"
|
#include "animationsystem.h"
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "stringutils.h"
|
#include "stringutils.h"
|
||||||
|
#include "worldmanager.h"
|
||||||
|
#include "assetmanager.h"
|
||||||
|
|
||||||
SDL_Window* window = nullptr;
|
SDL_Window* window = nullptr;
|
||||||
Renderer* renderer = nullptr;
|
Renderer* renderer = nullptr;
|
||||||
|
@ -49,8 +48,6 @@ int windowFullscreen = 0;
|
||||||
std::string currentGraphicsPreset = "Medium";
|
std::string currentGraphicsPreset = "Medium";
|
||||||
GraphicsConfig graphicsConfig;
|
GraphicsConfig graphicsConfig;
|
||||||
|
|
||||||
World* world = nullptr;
|
|
||||||
|
|
||||||
int toInt(const std::string &str) {
|
int toInt(const std::string &str) {
|
||||||
std::stringstream ss(str);
|
std::stringstream ss(str);
|
||||||
|
|
||||||
|
@ -105,161 +102,6 @@ void writeConfig() {
|
||||||
config.save("user.cfg");
|
config.save("user.cfg");
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh* loadMesh(const std::string& path) {
|
|
||||||
std::string fixedPath = "data/" + path;
|
|
||||||
|
|
||||||
Assimp::Importer importer;
|
|
||||||
const aiScene* scene = importer.ReadFile(fixedPath.c_str(), aiProcess_Triangulate);
|
|
||||||
|
|
||||||
Mesh* mesh = new Mesh();
|
|
||||||
|
|
||||||
unsigned int indexOffset = 0;
|
|
||||||
for(unsigned mi = 0; mi < scene->mNumMeshes; mi++) {
|
|
||||||
aiMesh* m = scene->mMeshes[mi];
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < m->mNumVertices; i++) {
|
|
||||||
Vertex vertex;
|
|
||||||
vertex.position = glm::vec3(m->mVertices[i].x, m->mVertices[i].y, m->mVertices[i].z);
|
|
||||||
vertex.normal = glm::vec3(m->mNormals[i].x, m->mNormals[i].y, m->mNormals[i].z);
|
|
||||||
vertex.uv = glm::vec2(m->mTextureCoords[0][i].x, m->mTextureCoords[0][i].y);
|
|
||||||
|
|
||||||
mesh->vertices.push_back(vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < m->mNumFaces; i++) {
|
|
||||||
aiFace face = m->mFaces[i];
|
|
||||||
for(unsigned int j = 0; j < face.mNumIndices; j++)
|
|
||||||
mesh->indices.push_back(indexOffset + face.mIndices[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
indexOffset += m->mNumVertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer->fillMeshBuffers(mesh);
|
|
||||||
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
Material* loadMaterial(const std::string& path) {
|
|
||||||
std::ifstream file("data/" + path);
|
|
||||||
|
|
||||||
nlohmann::json json;
|
|
||||||
file >> json;
|
|
||||||
|
|
||||||
Material* material = new Material();
|
|
||||||
material->albedoTexturePath = "data/" + json["albedoTexture"].get<std::string>();
|
|
||||||
|
|
||||||
renderer->fillMaterialBuffers(material);
|
|
||||||
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
World* loadWorld(const std::string& path) {
|
|
||||||
std::ifstream file("data/" + path);
|
|
||||||
|
|
||||||
nlohmann::json json;
|
|
||||||
file >> json;
|
|
||||||
|
|
||||||
World* world = new World();
|
|
||||||
|
|
||||||
for(auto meshObject : json["meshes"]) {
|
|
||||||
Mesh* mesh = loadMesh(meshObject["path"]);
|
|
||||||
mesh->material = loadMaterial(meshObject["material"]);
|
|
||||||
|
|
||||||
auto tokens = tokenize(meshObject["position"]);
|
|
||||||
|
|
||||||
mesh->position[0] = atof(tokens[0].c_str());
|
|
||||||
mesh->position[1] = atof(tokens[1].c_str());
|
|
||||||
mesh->position[2] = atof(tokens[2].c_str());
|
|
||||||
|
|
||||||
world->meshes.push_back(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto lightObject : json["lights"]) {
|
|
||||||
Light* light = new Light();
|
|
||||||
|
|
||||||
auto tokens = tokenize(lightObject["position"]);
|
|
||||||
|
|
||||||
light->position[0] = atof(tokens[0].c_str());
|
|
||||||
light->position[1] = atof(tokens[1].c_str());
|
|
||||||
light->position[2] = atof(tokens[2].c_str());
|
|
||||||
|
|
||||||
world->lights.push_back(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cinematic* 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"];
|
|
||||||
|
|
||||||
// TODO: concurrent worlds not implemented, we just load the first one
|
|
||||||
if(world == nullptr)
|
|
||||||
world = loadWorld(shotObject["world"]);
|
|
||||||
|
|
||||||
for(auto meshObject : shotObject["meshes"]) {
|
|
||||||
Mesh* mesh = loadMesh(meshObject["path"]);
|
|
||||||
mesh->name = meshObject["name"];
|
|
||||||
mesh->material = loadMaterial(meshObject["material"]);
|
|
||||||
mesh->tag = "cinematic";
|
|
||||||
|
|
||||||
shot->meshes.push_back(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto animationObject : shotObject["animations"]) {
|
|
||||||
auto animation = new Animation();
|
|
||||||
for(auto mesh : shot->meshes) {
|
|
||||||
if(mesh->name == animationObject["target"])
|
|
||||||
animation->target = mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cinematic;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cinematic* cinematic = nullptr;
|
Cinematic* cinematic = nullptr;
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
@ -301,17 +143,18 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
RenderTarget* target = renderer->createSurfaceRenderTarget(surface);
|
RenderTarget* target = renderer->createSurfaceRenderTarget(surface);
|
||||||
|
|
||||||
|
assetManager.setRenderer(renderer);
|
||||||
|
|
||||||
|
AnimationSystem* animationSystem = new AnimationSystem();
|
||||||
|
|
||||||
if(cinematicMode)
|
if(cinematicMode)
|
||||||
cinematic = loadCinematic(argv[2]);
|
cinematic = animationSystem->loadCinematic(argv[2]);
|
||||||
else {
|
else {
|
||||||
world = loadWorld("test.world");
|
worldManager.loadWorld("test.world");
|
||||||
|
worldManager.switchWorld("test.world");
|
||||||
}
|
}
|
||||||
|
|
||||||
Camera camera;
|
float currentTime = 0.0f, lastTime = 0.0f;
|
||||||
camera.position = {5.0, 5.0, 5.0};
|
|
||||||
|
|
||||||
float currentTime = 0.0f, lastTime = 0.0f, animationTime = 0.0f;
|
|
||||||
Shot* currentShot = nullptr;
|
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while(running) {
|
while(running) {
|
||||||
|
@ -347,93 +190,13 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cinematicMode) {
|
|
||||||
float endTime = 0.0f;
|
|
||||||
for(auto shot : cinematic->shots) {
|
|
||||||
if(shot->end > endTime)
|
|
||||||
endTime = shot->end;
|
|
||||||
|
|
||||||
if(animationTime >= shot->start && animationTime < shot->end && currentShot != shot) {
|
|
||||||
if(currentShot != nullptr) {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto mesh : shot->meshes)
|
|
||||||
world->meshes.push_back(mesh);
|
|
||||||
|
|
||||||
currentShot = shot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we have reached the end of the cinematic
|
|
||||||
if(animationTime >= endTime) {
|
|
||||||
currentShot = nullptr;
|
|
||||||
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(currentShot != nullptr) {
|
|
||||||
for(auto animation : 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)
|
|
||||||
camera.position = pos;
|
|
||||||
else {
|
|
||||||
animation->target->position = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AnimationProperty::Target:
|
|
||||||
{
|
|
||||||
auto pos = currentFrame.valueVec3 + delta * (nextFrame.valueVec3 - currentFrame.valueVec3);
|
|
||||||
|
|
||||||
camera.target = pos;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AnimationProperty::FoV:
|
|
||||||
{
|
|
||||||
auto pos = currentFrame.valueInt + delta * (nextFrame.valueInt - currentFrame.valueInt);
|
|
||||||
camera.fov = pos;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTime = SDL_GetTicks() / 1000.0f;
|
currentTime = SDL_GetTicks() / 1000.0f;
|
||||||
const float deltaTime = currentTime - lastTime;
|
const float deltaTime = currentTime - lastTime;
|
||||||
lastTime = currentTime;
|
lastTime = currentTime;
|
||||||
|
|
||||||
|
if(cinematicMode)
|
||||||
|
animationSystem->update(cinematic, deltaTime);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
@ -448,20 +211,17 @@ int main(int argc, char* argv[]) {
|
||||||
if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)
|
if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)
|
||||||
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
||||||
|
|
||||||
ImGui::DragFloat3("Light Position", &world->lights[0]->position[0]);
|
ImGui::DragFloat3("Light Position", &worldManager.getCurrentWorld()->lights[0]->position[0]);
|
||||||
ImGui::DragFloat3("Camera Position", &camera.position[0], 0.1f);
|
ImGui::DragFloat3("Camera Position", &worldManager.getCurrentWorld()->camera.position[0], 0.1f);
|
||||||
ImGui::DragFloat3("Target", &camera.target[0], 0.1f);
|
ImGui::DragFloat3("Target", &worldManager.getCurrentWorld()->camera.target[0], 0.1f);
|
||||||
ImGui::DragFloat("Aperture", &camera.aperture, 0.01f, 0.0f, 1.0f);
|
ImGui::DragFloat("Aperture", &worldManager.getCurrentWorld()->camera.aperture, 0.01f, 0.0f, 1.0f);
|
||||||
ImGui::DragFloat("Focus Distance", &camera.focusDistance);
|
ImGui::DragFloat("Focus Distance", &worldManager.getCurrentWorld()->camera.focusDistance);
|
||||||
ImGui::Text("dpack[2] = %f", (100 - camera.focusDistance) / 100.0f);
|
ImGui::Text("dpack[2] = %f", (100 - worldManager.getCurrentWorld()->camera.focusDistance) / 100.0f);
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
renderer->render(*world, camera, target);
|
renderer->render(*worldManager.getCurrentWorld(), worldManager.getCurrentWorld()->camera, target);
|
||||||
|
|
||||||
if(cinematicMode)
|
|
||||||
animationTime += deltaTime;
|
|
||||||
|
|
||||||
if(record) {
|
if(record) {
|
||||||
static int frameNum = 0;
|
static int frameNum = 0;
|
||||||
|
@ -472,7 +232,7 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto mesh : world->meshes) {
|
/*for(auto mesh : world->meshes) {
|
||||||
renderer->destroyMaterialBuffers(mesh->material);
|
renderer->destroyMaterialBuffers(mesh->material);
|
||||||
delete mesh->material;
|
delete mesh->material;
|
||||||
|
|
||||||
|
@ -484,7 +244,7 @@ int main(int argc, char* argv[]) {
|
||||||
delete light;
|
delete light;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete world;
|
delete world;*/
|
||||||
|
|
||||||
renderer->destroyRenderTarget(target);
|
renderer->destroyRenderTarget(target);
|
||||||
|
|
||||||
|
|
54
src/worldmanager.cpp
Normal file
54
src/worldmanager.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include "worldmanager.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
|
#include "stringutils.h"
|
||||||
|
#include "world.h"
|
||||||
|
#include "assetmanager.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "light.h"
|
||||||
|
|
||||||
|
void WorldManager::loadWorld(const std::string& path) {
|
||||||
|
std::ifstream file("data/" + path);
|
||||||
|
if(!file)
|
||||||
|
std::cout << "failed to load " << path << std::endl;
|
||||||
|
|
||||||
|
nlohmann::json json;
|
||||||
|
file >> json;
|
||||||
|
|
||||||
|
World* world = new World();
|
||||||
|
|
||||||
|
for(auto meshObject : json["meshes"]) {
|
||||||
|
Mesh* mesh = assetManager.loadMesh(meshObject["path"]);
|
||||||
|
mesh->material = assetManager.loadMaterial(meshObject["material"]);
|
||||||
|
|
||||||
|
auto tokens = tokenize(meshObject["position"]);
|
||||||
|
|
||||||
|
mesh->position[0] = atof(tokens[0].c_str());
|
||||||
|
mesh->position[1] = atof(tokens[1].c_str());
|
||||||
|
mesh->position[2] = atof(tokens[2].c_str());
|
||||||
|
|
||||||
|
world->meshes.push_back(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto lightObject : json["lights"]) {
|
||||||
|
Light* light = new Light();
|
||||||
|
|
||||||
|
auto tokens = tokenize(lightObject["position"]);
|
||||||
|
|
||||||
|
light->position[0] = atof(tokens[0].c_str());
|
||||||
|
light->position[1] = atof(tokens[1].c_str());
|
||||||
|
light->position[2] = atof(tokens[2].c_str());
|
||||||
|
|
||||||
|
world->lights.push_back(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedWorlds[path] = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldManager::switchWorld(const std::string& path) {
|
||||||
|
currentWorld = loadedWorlds[path];
|
||||||
|
}
|
Reference in a new issue