Archived
1
Fork 0
This repository has been archived on 2025-04-12. You can view files and clone it, but cannot push or open issues or pull requests.
graph/src/main.cpp

405 lines
12 KiB
C++
Raw Normal View History

2018-09-26 17:51:22 -04:00
#include <SDL.h>
2018-09-29 21:03:06 -04:00
#include <SDL_vulkan.h>
2018-10-01 21:02:27 -04:00
#include <iostream>
#include <fstream>
#include <sstream>
#include <json.hpp>
2018-10-16 08:49:25 -04:00
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
2018-11-05 20:51:23 -05:00
#include <imgui.h>
2018-10-16 08:49:25 -04:00
#include "renderer.h"
2018-09-29 21:03:06 -04:00
#include "platform.h"
2018-10-16 08:49:25 -04:00
#include "world.h"
#include "mesh.h"
2018-10-18 21:46:48 -04:00
#include "light.h"
2018-10-25 08:57:36 -04:00
#include "camera.h"
2018-10-30 21:13:36 -04:00
#include "cinematic.h"
2018-11-06 09:08:55 -05:00
#include "material.h"
2018-11-08 12:51:32 -05:00
#include "config.h"
2018-09-29 21:03:06 -04:00
SDL_Window* window = nullptr;
2018-10-30 21:13:36 -04:00
Renderer* renderer = nullptr;
2018-09-29 21:03:06 -04:00
std::vector<const char*> platform::getRequiredExtensions() {
uint32_t count = 0;
SDL_Vulkan_GetInstanceExtensions(window, &count, nullptr);
2018-10-16 08:49:25 -04:00
2018-09-29 21:03:06 -04:00
std::vector<const char*> names(count);
SDL_Vulkan_GetInstanceExtensions(window, &count, names.data());
2018-10-16 08:49:25 -04:00
2018-09-29 21:03:06 -04:00
return names;
}
2018-09-26 17:51:22 -04:00
uint32_t platform::getTime() {
return SDL_GetTicks();
}
int windowX = SDL_WINDOWPOS_CENTERED;
int windowY = SDL_WINDOWPOS_CENTERED;
int windowWidth = 640;
int windowHeight = 480;
2018-10-17 17:11:26 -04:00
int windowFullscreen = 0;
2018-11-08 12:51:32 -05:00
std::string currentGraphicsPreset = "Medium";
GraphicsConfig graphicsConfig;
int toInt(const std::string &str) {
std::stringstream ss(str);
int num;
if((ss >> num).fail())
return -1;
2018-10-26 20:56:06 -04:00
return num;
}
2018-11-08 12:51:32 -05:00
void loadGraphicsConfig() {
Config config;
if(!config.load("data/graphics_presets.cfg"))
return;
2018-11-08 12:51:32 -05:00
graphicsConfig.shadowResolution = toInt(config.get(currentGraphicsPreset.c_str(), "shadowResolution"));
graphicsConfig.dofDownscale = toInt(config.get(currentGraphicsPreset.c_str(), "dofDownscale"));
}
2018-11-08 12:51:32 -05:00
void readConfig() {
Config config;
if(!config.load("user.cfg"))
return;
2018-11-08 12:51:32 -05:00
windowX = toInt(config.get("Window", "x"));
windowY = toInt(config.get("Window", "y"));
windowWidth = toInt(config.get("Window", "width"));
windowHeight = toInt(config.get("Window", "height"));
windowFullscreen = toInt(config.get("Window", "fullscreen"));
currentGraphicsPreset = config.get("Graphics", "preset");
2018-11-08 13:27:24 -05:00
graphicsConfig.vsync = toInt(config.get("Graphics", "vsync"));
2018-11-08 12:51:32 -05:00
loadGraphicsConfig();
}
void writeConfig() {
Config config;
2018-11-08 12:51:32 -05:00
config.set("Window", "x", std::to_string(windowX));
config.set("Window", "y", std::to_string(windowY));
config.set("Window", "width", std::to_string(windowWidth));
config.set("Window", "height", std::to_string(windowHeight));
config.set("Window", "fullscreen", std::to_string(windowFullscreen));
2018-11-08 12:51:32 -05:00
config.set("Graphics", "preset", currentGraphicsPreset);
2018-11-08 13:27:24 -05:00
config.set("Graphics", "vsync", std::to_string(graphicsConfig.vsync));
2018-11-08 12:51:32 -05:00
config.save("user.cfg");
}
2018-10-30 21:13:36 -04:00
Mesh* loadMesh(const char* path) {
2018-10-16 08:49:25 -04:00
Assimp::Importer importer;
2018-10-30 21:13:36 -04:00
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate);
2018-10-16 08:49:25 -04:00
Mesh* mesh = new Mesh();
2018-11-03 07:24:32 -04:00
unsigned int indexOffset = 0;
for(unsigned mi = 0; mi < scene->mNumMeshes; mi++) {
aiMesh* m = scene->mMeshes[mi];
2018-11-03 07:24:32 -04:00
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);
2018-11-06 09:08:55 -05:00
vertex.uv = glm::vec2(m->mTextureCoords[0][i].x, m->mTextureCoords[0][i].y);
2018-11-03 07:24:32 -04:00
mesh->vertices.push_back(vertex);
}
2018-10-16 08:49:25 -04:00
2018-11-03 07:24:32 -04:00
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]);
}
2018-11-03 07:24:32 -04:00
indexOffset += m->mNumVertices;
2018-10-16 08:49:25 -04:00
}
renderer->fillMeshBuffers(mesh);
2018-10-30 21:13:36 -04:00
return mesh;
}
std::vector<std::string> tokenize(const std::string& str) {
size_t lastPos = str.find_first_not_of(',', 0);
size_t pos = str.find_first_of(',', lastPos);
std::vector<std::string> tokens;
while(pos != std::string::npos || lastPos != std::string::npos) {
tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(',', pos);
pos = str.find_first_of(',', lastPos);
}
return tokens;
}
Cinematic* loadCinematic(const char* path) {
std::ifstream file(path);
if(!file)
return nullptr;
nlohmann::json json;
file >> json;
2018-11-03 20:36:05 -04:00
auto cinematic = new Cinematic();
2018-10-30 21:13:36 -04:00
for(auto shotObject : json["shots"]) {
Shot* shot = new Shot();
shot->start = shotObject["start"];
shot->end = shotObject["end"];
for(auto meshObject : shotObject["meshes"]) {
Mesh* mesh = loadMesh(meshObject["path"].get<std::string>().c_str());
mesh->name = meshObject["name"];
shot->meshes.push_back(mesh);
}
for(auto animationObject : shotObject["animations"]) {
2018-11-03 20:36:05 -04:00
auto animation = new Animation();
2018-10-30 21:13:36 -04:00
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;
for(auto keyframeObject : animationObject["keyframes"]) {
Keyframe keyframe;
keyframe.time = keyframeObject["time"];
auto tokens = tokenize(keyframeObject["value"]);
keyframe.value[0] = atof(tokens[0].c_str());
keyframe.value[1] = atof(tokens[1].c_str());
keyframe.value[2] = atof(tokens[2].c_str());
animation->keyframes.push_back(keyframe);
}
shot->animations.push_back(animation);
}
cinematic->shots.push_back(shot);
}
return cinematic;
}
Cinematic* cinematic = nullptr;
int main(int argc, char* argv[]) {
readConfig();
bool cinematicMode = false;
if(argc > 2 && strcmp(argv[1], "--cinematic") == 0)
cinematicMode = true;
window = SDL_CreateWindow("Graph",
windowX,
windowY,
windowWidth,
windowHeight,
SDL_WINDOW_VULKAN |
SDL_WINDOW_RESIZABLE);
if(window == nullptr)
return -1;
SDL_SetWindowFullscreen(window, windowFullscreen == 1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
2018-11-05 20:51:23 -05:00
ImGui::CreateContext();
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
auto& io = ImGui::GetIO();
io.DisplaySize = ImVec2(windowWidth, windowHeight);
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
ImGui::StyleColorsDark();
2018-11-06 09:08:55 -05:00
2018-11-08 12:51:32 -05:00
renderer = new Renderer(graphicsConfig);
2018-10-30 21:13:36 -04:00
VkSurfaceKHR surface = nullptr;
SDL_Vulkan_CreateSurface(window, renderer->getInstance(), &surface);
RenderTarget* target = renderer->createSurfaceRenderTarget(surface);
2018-11-06 09:08:55 -05:00
2018-10-16 08:49:25 -04:00
World world;
2018-10-26 20:56:06 -04:00
auto light = new Light();
2018-11-07 05:27:00 -05:00
light->type = LightType::Directional;
2018-11-08 08:57:41 -05:00
light->position = glm::vec3(66, 56, 25);
2018-10-18 21:46:48 -04:00
world.lights.push_back(light);
2018-10-16 08:49:25 -04:00
2018-10-25 08:57:36 -04:00
Camera camera;
2018-11-03 07:24:32 -04:00
camera.position = {5.0, 5.0, 5.0};
2018-10-25 08:57:36 -04:00
2018-10-30 21:13:36 -04:00
if(cinematicMode)
cinematic = loadCinematic(argv[2]);
2018-11-06 09:08:55 -05:00
else {
Material* material = new Material();
material->albedoTexturePath = "data/tile.jpg";
renderer->fillMaterialBuffers(material);
Mesh* mesh = loadMesh("data/scene.obj");
mesh->material = material;
world.meshes.push_back(mesh);
}
2018-10-30 21:13:36 -04:00
2018-11-05 20:51:23 -05:00
float currentTime = 0.0f, lastTime = 0.0f, animationTime = 0.0f;
2018-10-30 21:13:36 -04:00
Shot* currentShot = nullptr;
2018-09-26 17:51:22 -04:00
bool running = true;
2018-11-06 09:08:55 -05:00
while(running) {
2018-09-26 17:51:22 -04:00
SDL_Event event = {};
2018-10-26 20:56:06 -04:00
while(SDL_PollEvent(&event) > 0) {
2018-09-26 17:51:22 -04:00
if(event.type == SDL_QUIT)
running = false;
2018-10-16 08:49:25 -04:00
2018-10-01 21:02:27 -04:00
if(event.type == SDL_WINDOWEVENT) {
2018-11-05 20:51:23 -05:00
if(event.window.event == SDL_WINDOWEVENT_RESIZED) {
io.DisplaySize = ImVec2(event.window.data1, event.window.data2);
2018-11-06 09:08:55 -05:00
2018-10-01 21:02:27 -04:00
target = renderer->createSurfaceRenderTarget(surface, target);
2018-11-05 20:51:23 -05:00
}
2018-10-01 21:02:27 -04:00
}
2018-10-17 17:11:26 -04:00
if(event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_F11) {
if(windowFullscreen == 1) {
SDL_SetWindowFullscreen(window, 0);
windowFullscreen = 0;
} else {
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
windowFullscreen = 1;
}
2018-10-17 17:11:26 -04:00
target = renderer->createSurfaceRenderTarget(surface, target);
}
2018-11-03 07:24:32 -04:00
if(event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_F7) {
2018-10-30 21:13:36 -04:00
renderer->takeScreenshot("screenshot.ppm", target);
2018-10-24 21:13:55 -04:00
}
2018-09-26 17:51:22 -04:00
}
2018-10-16 08:49:25 -04:00
2018-10-30 21:13:36 -04:00
if(cinematicMode) {
float endTime = 0.0f;
for(auto shot : cinematic->shots) {
if(shot->end > endTime)
endTime = shot->end;
2018-11-05 20:51:23 -05:00
if(animationTime >= shot->start && animationTime < shot->end && currentShot != shot) {
2018-10-30 21:13:36 -04:00
if(currentShot != nullptr) {
world.meshes.clear();
}
for(auto mesh : shot->meshes)
world.meshes.push_back(mesh);
currentShot = shot;
}
}
// we have reached the end of the cinematic
2018-11-05 20:51:23 -05:00
if(animationTime >= endTime) {
2018-10-30 21:13:36 -04:00
currentShot = nullptr;
world.meshes.clear();
}
if(currentShot != nullptr) {
for(auto animation : currentShot->animations) {
unsigned int frameIndex = 0;
for(size_t i = 0; i < animation->keyframes.size(); i++) {
2018-11-05 20:51:23 -05:00
if(animationTime < animation->keyframes[i + 1].time) {
2018-10-30 21:13:36 -04:00
frameIndex = i;
break;
}
}
const auto currentFrame = animation->keyframes[frameIndex];
const auto nextFrame = animation->keyframes[(frameIndex + 1) % animation->keyframes.size()];
2018-11-05 20:51:23 -05:00
const float delta = (animationTime - currentFrame.time) / (nextFrame.time - currentFrame.time);
2018-10-30 21:13:36 -04:00
glm::vec3 pos = currentFrame.value + delta * (nextFrame.value - currentFrame.value);
if(animation->target != nullptr)
animation->target->position = pos;
else
camera.position = pos;
}
}
}
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
currentTime = SDL_GetTicks() / 1000.0f;
const float deltaTime = currentTime - lastTime;
lastTime = currentTime;
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
ImGui::NewFrame();
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
io.DeltaTime = deltaTime;
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
int mouseX = 0, mouseY = 0;
const Uint32 mouseButtons = SDL_GetMouseState(&mouseX, &mouseY);
io.MouseDown[0] = (mouseButtons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
io.MouseDown[1] = (mouseButtons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = (mouseButtons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
2018-11-05 21:06:12 -05:00
2018-11-08 08:57:41 -05:00
ImGui::DragFloat3("Light Position", &world.lights[0]->position[0]);
ImGui::DragFloat3("Camera Position", &camera.position[0], 0.1f);
ImGui::DragFloat3("Target", &camera.target[0], 0.1f);
2018-11-05 21:06:12 -05:00
ImGui::DragFloat("Aperture", &camera.aperture, 0.01f, 0.0f, 1.0f);
ImGui::DragFloat("Focus Distance", &camera.focusDistance);
ImGui::Text("dpack[2] = %f", (100 - camera.focusDistance) / 100.0f);
2018-11-06 09:08:55 -05:00
2018-11-05 20:51:23 -05:00
ImGui::Render();
2018-10-25 08:57:36 -04:00
renderer->render(world, camera, target);
2018-11-06 09:08:55 -05:00
2018-10-30 21:13:36 -04:00
if(cinematicMode) {
2018-11-05 20:51:23 -05:00
animationTime += deltaTime;
2018-10-16 08:49:25 -04:00
2018-10-30 21:13:36 -04:00
static int frameNum = 0;
std::string screenshotName = "frame" + std::to_string(frameNum) + ".ppm";
frameNum++;
2018-10-30 21:13:36 -04:00
renderer->takeScreenshot(screenshotName.c_str(), target);
}
}
if(cinematic == nullptr) {
2018-11-06 09:08:55 -05:00
renderer->destroyMaterialBuffers(world.meshes[0]->material);
delete world.meshes[0]->material;
2018-10-30 21:13:36 -04:00
renderer->destroyMeshBuffers(world.meshes[0]);
delete world.meshes[0];
}
delete light;
2018-09-29 21:03:06 -04:00
renderer->destroyRenderTarget(target);
2018-10-16 08:49:25 -04:00
2018-10-01 21:02:27 -04:00
vkDestroySurfaceKHR(renderer->getInstance(), surface, nullptr);
2018-10-16 08:49:25 -04:00
delete renderer;
2018-10-16 08:49:25 -04:00
writeConfig();
SDL_DestroyWindow(window);
2018-10-16 08:49:25 -04:00
2018-09-26 17:51:22 -04:00
return 0;
}