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.
prism/engine/core/src/engine.cpp

860 lines
24 KiB
C++
Raw Normal View History

2020-08-11 12:07:21 -04:00
#include "engine.hpp"
#include <nlohmann/json.hpp>
2021-04-19 12:35:52 -04:00
#include <utility>
#include <imgui.h>
2020-08-11 12:07:21 -04:00
2020-09-21 09:37:52 -04:00
#include "scene.hpp"
#include "console.hpp"
2020-08-11 12:07:21 -04:00
#include "log.hpp"
2020-09-21 09:37:52 -04:00
#include "asset.hpp"
2020-08-11 12:07:21 -04:00
#include "json_conversions.hpp"
2020-09-21 09:37:52 -04:00
#include "app.hpp"
2020-08-11 12:07:21 -04:00
#include "assertions.hpp"
2020-09-21 09:37:52 -04:00
#include "renderer.hpp"
#include "gfx.hpp"
2021-04-20 10:37:56 -04:00
#include "imgui_backend.hpp"
2020-09-21 09:37:52 -04:00
#include "debug.hpp"
#include "timer.hpp"
#include "physics.hpp"
#include "input.hpp"
// TODO: remove these in the future
#include "shadowpass.hpp"
#include "scenecapture.hpp"
2020-08-11 12:07:21 -04:00
2021-04-19 12:23:18 -04:00
using prism::engine;
2021-04-19 12:23:18 -04:00
engine::engine(const int argc, char* argv[]) {
log("Prism Engine loading...");
log("starting gfx debug:");
for(auto [t, t_name] : magic_enum::enum_entries<GFXContext>()) {
log("does platform support {}? {}", t_name, platform::supports_context(t));
}
console::register_command("echo", console::argument_format(1), [](const console::arguments& args) {
log(std::get<std::string>(args[0].data));
});
console::register_command("platform_info", console::argument_format(0), [this](const console::arguments&) {
log("Platform: {}", platform::get_name());
log("GFX: {}", gfx->get_name());
2020-09-20 22:37:15 -04:00
});
console::register_variable("rs_exposure", render_options.exposure);
console::register_variable("rs_dof", render_options.enable_depth_of_field);
2020-09-22 22:43:30 -04:00
console::register_variable("rs_dynamic_resolution", render_options.dynamic_resolution);
console::register_variable("rs_render_scale", render_options.render_scale);
console::register_variable("rs_shadow_resolution", render_options.shadow_resolution);
console::register_variable("rs_aa", render_options.enable_aa);
console::register_variable("rs_ibl", render_options.enable_ibl);
console::register_variable("rs_normal_mapping", render_options.enable_normal_mapping);
console::register_variable("rs_normal_shadowing", render_options.enable_normal_shadowing);
console::register_variable("rs_point_shadows", render_options.enable_point_shadows);
console::register_variable("rs_extra_passes", render_options.enable_extra_passes);
console::register_variable("rs_frustum_culling", render_options.enable_frustum_culling);
console::register_command("rebuild_mat", console::argument_format(0), [this](const console::arguments&) {
for(auto material : assetm->get_all<Material>()) {
material->capture_pipeline = nullptr;
material->skinned_pipeline = nullptr;
material->static_pipeline = nullptr;
}
});
console::register_command("quit", console::argument_format(0), [this](const console::arguments&) {
2020-09-22 13:28:08 -04:00
quit();
});
2020-08-11 12:07:21 -04:00
for(int i = 0; i < argc; i++)
2021-04-19 12:35:52 -04:00
command_line_arguments.emplace_back(argv[i]);
2020-08-11 12:07:21 -04:00
input = std::make_unique<input_system>();
physics = std::make_unique<Physics>();
2021-04-20 10:37:56 -04:00
imgui = std::make_unique<prism::imgui_backend>();
2020-08-11 12:07:21 -04:00
assetm = std::make_unique<AssetManager>();
}
2021-04-19 12:35:52 -04:00
engine::~engine() = default;
2020-09-21 09:37:52 -04:00
2021-04-19 12:35:52 -04:00
void engine::set_app(prism::app* p_app) {
Expects(p_app != nullptr);
this->current_app = p_app;
2022-03-04 19:17:07 -05:00
if(platform::supports_feature(PlatformFeature::Windowing) && get_app()->is_multimodal()) {
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}
console::load_cfg(prism::app_domain / "render_options.cfg");
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
prism::app* engine::get_app() const {
return current_app;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::pause() {
paused = true;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::unpause() {
paused = false;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
bool engine::is_paused() const {
return paused;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::quit() {
2021-04-20 12:17:49 -04:00
if(!windows.empty())
windows[0]->quit_requested = true;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
bool engine::is_quitting() const {
2021-04-20 12:17:49 -04:00
if(!windows.empty())
return windows[0]->quit_requested;
return false;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::prepare_quit() {
current_app->prepare_quit();
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:35:52 -04:00
void engine::set_gfx(GFX* p_gfx) {
Expects(p_gfx != nullptr);
prism::log("this gfx has a context of {}", utility::enum_to_string(p_gfx->required_context()));
2021-04-19 12:35:52 -04:00
this->gfx = p_gfx;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
GFX* engine::get_gfx() {
return gfx;
2020-08-11 12:07:21 -04:00
}
prism::input_system* engine::get_input() {
return input.get();
2020-08-11 12:07:21 -04:00
}
prism::renderer* engine::get_renderer() {
return current_renderer.get();
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
Physics* engine::get_physics() {
return physics.get();
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::create_empty_scene() {
2020-08-11 12:07:21 -04:00
auto scene = std::make_unique<Scene>();
setup_scene(*scene);
scenes.push_back(std::move(scene));
current_scene = scenes.back().get();
2020-08-11 12:07:21 -04:00
}
2021-05-12 09:05:56 -04:00
Scene* engine::load_scene(const prism::path& path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
auto file = prism::open_file(path);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load scene from {}!", path.string());
2020-08-11 12:07:21 -04:00
return nullptr;
}
nlohmann::json j;
file->read_as_stream() >> j;
auto scene = std::make_unique<Scene>();
std::map<Object, std::string> parentQueue;
for(auto& obj : j["objects"]) {
if(obj.contains("prefabPath")) {
Object o = add_prefab(*scene, prism::app_domain / obj["prefabPath"].get<std::string_view>());
2020-08-11 12:07:21 -04:00
scene->get(o).name = obj["name"];
auto& transform = scene->get<Transform>(o);
transform.position = obj["position"];
transform.rotation = obj["rotation"];
transform.scale = obj["scale"];
} else {
2021-04-19 12:35:52 -04:00
auto o = load_object(*scene, obj);
2020-08-11 12:07:21 -04:00
if(obj.contains("parent"))
parentQueue[o] = obj["parent"];
}
}
for(auto& [obj, toParent] : parentQueue)
scene->get<Data>(obj).parent = scene->find_object(toParent);
setup_scene(*scene);
scenes.push_back(std::move(scene));
current_scene = scenes.back().get();
path_to_scene[path.string()] = scenes.back().get();
2020-08-11 12:07:21 -04:00
return scenes.back().get();
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::save_scene(const std::string_view path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
nlohmann::json j;
for(auto& obj : current_scene->get_objects()) {
if(!current_scene->get(obj).editor_object)
2020-08-11 12:07:21 -04:00
j["objects"].push_back(save_object(obj));
}
std::ofstream out(path.data());
out << j;
}
2021-04-19 12:23:18 -04:00
AnimationChannel engine::load_animation(nlohmann::json a) {
2020-08-11 12:07:21 -04:00
AnimationChannel animation;
for(auto& kf : a["frames"]) {
PositionKeyFrame keyframe;
keyframe.time = kf["time"];
keyframe.value = kf["value"];
animation.positions.push_back(keyframe);
}
return animation;
}
2021-05-12 09:05:56 -04:00
Animation engine::load_animation(const prism::path& path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
auto file = prism::open_file(path, true);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load animation from {}!", path.string());
2020-08-11 12:07:21 -04:00
return {};
}
Animation anim;
file->read(&anim.duration);
file->read(&anim.ticks_per_second);
unsigned int num_channels;
file->read(&num_channels);
for(unsigned int i = 0; i < num_channels; i++) {
AnimationChannel channel;
file->read_string(channel.id);
unsigned int num_positions;
file->read(&num_positions);
for(unsigned int j = 0; j < num_positions; j++) {
PositionKeyFrame key;
file->read(&key);
channel.positions.push_back(key);
}
unsigned int num_rotations;
file->read(&num_rotations);
for(unsigned int j = 0; j < num_rotations; j++) {
RotationKeyFrame key;
file->read(&key);
channel.rotations.push_back(key);
}
unsigned int num_scales;
file->read(&num_scales);
for(unsigned int j = 0; j < num_scales; j++) {
ScaleKeyFrame key;
file->read(&key);
channel.scales.push_back(key);
}
anim.channels.push_back(channel);
}
return anim;
}
2021-05-12 09:05:56 -04:00
void engine::load_cutscene(const prism::path& path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
cutscene = std::make_unique<Cutscene>();
auto file = prism::open_file(path);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load cutscene from {}!", path.string());
2020-08-11 12:07:21 -04:00
return;
}
nlohmann::json j;
file->read_as_stream() >> j;
for(auto& s : j["shots"]) {
Shot shot;
shot.begin = s["begin"];
shot.length = s["end"];
for(auto& animation : s["animations"]) {
shot.channels.push_back(load_animation(animation));
}
if(path_to_scene.count(s["scene"])) {
shot.scene = path_to_scene[s["scene"]];
2020-08-11 12:07:21 -04:00
// try to find main camera
auto [obj, cam] = shot.scene->get_all<Camera>()[0];
for(auto& anim : shot.channels) {
if(anim.target == NullObject)
anim.target = obj;
}
} else {
load_scene(prism::root_path(path) / s["scene"].get<std::string_view>());
2020-08-11 12:07:21 -04:00
2021-04-19 12:23:18 -04:00
if(get_scene() == nullptr)
create_empty_scene();
2020-08-11 12:07:21 -04:00
2021-04-19 12:23:18 -04:00
auto cameraObj = get_scene()->add_object();
get_scene()->add<Camera>(cameraObj);
2020-08-11 12:07:21 -04:00
for(auto& anim : shot.channels) {
if(anim.target == NullObject)
anim.target = cameraObj;
}
path_to_scene[s["scene"]] = current_scene;
shot.scene = current_scene;
2020-08-11 12:07:21 -04:00
}
cutscene->shots.push_back(shot);
}
}
2021-04-19 12:23:18 -04:00
void engine::save_cutscene(const std::string_view path) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
nlohmann::json j;
2021-04-19 12:23:18 -04:00
for(auto& shot : cutscene->shots) {
2020-08-11 12:07:21 -04:00
nlohmann::json s;
s["begin"] = shot.begin;
s["end"] = shot.length;
2021-10-14 08:51:58 -04:00
for(auto& [scene_path, scene] : path_to_scene) {
2020-08-11 12:07:21 -04:00
if(shot.scene == scene)
2021-10-14 08:51:58 -04:00
s["scene"] = scene_path;
2020-08-11 12:07:21 -04:00
}
j["shots"].push_back(s);
}
2021-02-15 15:06:13 -05:00
std::ofstream out(path.data());
2020-08-11 12:07:21 -04:00
out << j;
}
prism::Object engine::add_prefab(Scene& scene, const prism::path& path, const std::string_view override_name) {
2020-08-11 12:07:21 -04:00
Expects(!path.empty());
auto file = prism::open_file(path);
2020-08-11 12:07:21 -04:00
if(!file.has_value()) {
prism::log("Failed to load prefab from {}!", path.string());
2020-08-11 12:07:21 -04:00
return NullObject;
}
nlohmann::json j;
file->read_as_stream() >> j;
Object root_node = NullObject;
std::map<Object, std::string> parent_queue;
2021-10-14 08:51:58 -04:00
for(const auto& obj : j["objects"]) {
2020-08-11 12:07:21 -04:00
auto o = load_object(scene, obj);
if(obj.contains("parent")) {
parent_queue[o] = obj["parent"];
} else {
root_node = o;
}
}
for(auto& [obj, parent_name] : parent_queue)
scene.get(obj).parent = scene.find_object(parent_name);
if(!override_name.empty() && root_node != NullObject)
scene.get(root_node).name = override_name;
return root_node;
}
2021-04-19 12:23:18 -04:00
void engine::save_prefab(const Object root, const std::string_view path) {
2020-08-11 12:07:21 -04:00
Expects(root != NullObject);
Expects(!path.empty());
nlohmann::json j;
for(auto& obj : current_scene->get_objects()) {
if(!current_scene->get(obj).editor_object)
2020-08-11 12:07:21 -04:00
j["objects"].push_back(save_object(obj));
}
std::ofstream out(path.data());
out << j;
}
void engine::add_window(void* native_handle, const platform::window_ptr window_ptr, const prism::Extent extent) {
2020-08-11 12:07:21 -04:00
Expects(native_handle != nullptr);
auto* window = new Window();
windows.push_back(window);
window->identifier = window_ptr;
if(platform::is_main_window(window_ptr)) {
current_renderer = std::make_unique<prism::renderer>(gfx);
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
2022-03-04 19:17:07 -05:00
main_viewport->PlatformHandle = get_main_window();
}
const auto drawable_extent = platform::get_window_drawable_size(window_ptr);
gfx->initialize_view(native_handle, window_ptr, drawable_extent.width, drawable_extent.height);
window->extent = extent;
window->render_target = current_renderer->allocate_render_target(drawable_extent);
2020-08-11 12:07:21 -04:00
render_ready = true;
}
void engine::remove_window(const platform::window_ptr identifier) {
utility::erase_if(windows, [identifier](Window*& w) {
return w->identifier == identifier;
2020-08-11 12:07:21 -04:00
});
}
void engine::resize(const platform::window_ptr identifier, const prism::Extent extent) {
2020-08-11 12:07:21 -04:00
auto window = get_window(identifier);
if (window == nullptr)
return;
2020-08-11 12:07:21 -04:00
window->extent = extent;
const auto drawable_extent = platform::get_window_drawable_size(identifier);
gfx->recreate_view(identifier, drawable_extent.width, drawable_extent.height);
current_renderer->resize_render_target(*window->render_target, drawable_extent);
imgui->process_resize(identifier);
2020-08-11 12:07:21 -04:00
}
void engine::move(const platform::window_ptr identifier) {
imgui->process_move(identifier);
}
2021-04-19 12:23:18 -04:00
void engine::process_key_down(const unsigned int keyCode) {
2020-08-11 12:07:21 -04:00
Expects(keyCode >= 0);
if(input->is_text_input() && !input->get_allowable_text_button(keyCode))
return;
imgui->process_key_down(keyCode);
2020-08-11 12:07:21 -04:00
if(keyCode == platform::get_keycode(debug_button) && !ImGui::GetIO().WantTextInput)
2020-08-11 12:07:21 -04:00
debug_enabled = !debug_enabled;
if(keyCode == platform::get_keycode(InputButton::C))
console_enabled = !console_enabled;
2022-02-15 09:01:52 -05:00
if(keyCode == platform::get_keycode(InputButton::Backspace))
ui_enabled = !ui_enabled;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::process_key_up(const unsigned int keyCode) {
2020-08-11 12:07:21 -04:00
Expects(keyCode >= 0);
imgui->process_key_up(keyCode);
2020-08-11 12:07:21 -04:00
}
2021-10-14 08:51:58 -04:00
void engine::process_mouse_down(const int button, const prism::Offset) {
imgui->process_mouse_down(button);
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::calculate_bone(Mesh& mesh, const Mesh::Part& part, Bone& bone, const Bone* parent_bone) {
2020-08-11 12:07:21 -04:00
if(part.offset_matrices.empty())
return;
Matrix4x4 parent_matrix;
if(parent_bone != nullptr)
parent_matrix = parent_bone->local_transform;
2021-05-12 09:56:44 -04:00
Matrix4x4 local = prism::translate(Matrix4x4(), bone.position);
2020-08-11 12:07:21 -04:00
local *= matrix_from_quat(bone.rotation);
2021-05-12 09:56:44 -04:00
local = prism::scale(local, bone.scale);
2020-08-11 12:07:21 -04:00
bone.local_transform = parent_matrix * local;
bone.final_transform = mesh.global_inverse_transformation * bone.local_transform * part.offset_matrices[bone.index];
for(auto& b : mesh.bones) {
if(b.parent != nullptr && b.parent->index == bone.index)
calculate_bone(mesh, part, b, &bone);
}
}
2021-04-19 12:23:18 -04:00
void engine::calculate_object(Scene& scene, Object object, const Object parent_object) {
2020-08-11 12:07:21 -04:00
Matrix4x4 parent_matrix;
if(parent_object != NullObject)
parent_matrix = scene.get<Transform>(parent_object).model;
auto& transform = scene.get<Transform>(object);
2021-05-12 09:56:44 -04:00
Matrix4x4 local = prism::translate(Matrix4x4(), transform.position);
2020-08-11 12:07:21 -04:00
local *= matrix_from_quat(transform.rotation);
2021-05-12 09:56:44 -04:00
local = prism::scale(local, transform.scale);
2020-08-11 12:07:21 -04:00
transform.model = parent_matrix * local;
if(scene.has<Renderable>(object)) {
auto& mesh = scene.get<Renderable>(object);
if(mesh.mesh && !mesh.mesh->bones.empty()) {
if(mesh.temp_bone_data.empty())
mesh.temp_bone_data.resize(mesh.mesh->bones.size());
2020-08-11 12:07:21 -04:00
for(auto& part : mesh.mesh->parts) {
if(scene.get(object).parent != NullObject && scene.has<Renderable>(scene.get(object).parent) && !scene.get<Renderable>(scene.get(object).parent).mesh->bones.empty()) {
for(auto [i, ourBone] : utility::enumerate(mesh.mesh->bones)) {
for(auto& theirBone : scene.get<Renderable>(scene.get(object).parent).mesh->bones) {
if(ourBone.name == theirBone.name)
mesh.temp_bone_data[i] = mesh.mesh->global_inverse_transformation * theirBone.local_transform * part.offset_matrices[ourBone.index];
2020-08-11 12:07:21 -04:00
}
}
} else {
calculate_bone(*mesh.mesh.handle, part, *mesh.mesh->root_bone);
for(auto [i, bone] : utility::enumerate(mesh.temp_bone_data))
mesh.temp_bone_data[i] = mesh.mesh->bones[i].final_transform;
2020-08-11 12:07:21 -04:00
}
gfx->copy_buffer(part.bone_batrix_buffer, mesh.temp_bone_data.data(), 0, mesh.temp_bone_data.size() * sizeof(Matrix4x4));
2020-08-11 12:07:21 -04:00
}
}
}
for(auto& child : scene.children_of(object))
calculate_object(scene, child, object);
}
2021-04-19 12:35:52 -04:00
Shot* engine::get_shot(const float time) const {
2021-04-19 12:23:18 -04:00
for(auto& shot : cutscene->shots) {
2020-08-11 12:07:21 -04:00
if(time >= shot.begin && time <= (shot.begin + shot.length))
return &shot;
}
return nullptr;
}
2021-04-19 12:23:18 -04:00
void engine::update_animation_channel(Scene& scene, const AnimationChannel& channel, const float time) {
2020-08-11 12:07:21 -04:00
{
int keyframeIndex = -1;
int i = 0;
for(auto& frame : channel.positions) {
if(time >= frame.time)
keyframeIndex = i;
i++;
}
if(keyframeIndex != -1) {
2021-05-12 09:56:44 -04:00
prism::float3* targetVec = nullptr;
2020-08-11 12:07:21 -04:00
if(channel.bone != nullptr)
targetVec = &channel.bone->position;
if(channel.target != NullObject && scene.has<Data>(channel.target))
targetVec = &scene.get<Transform>(channel.target).position;
auto& startFrame = channel.positions[keyframeIndex];
int endFrameIndex = keyframeIndex + 1;
if(endFrameIndex > channel.positions.size() - 1) {
if(targetVec != nullptr)
*targetVec = startFrame.value;
} else {
auto& endFrame = channel.positions[endFrameIndex];
if(targetVec != nullptr)
*targetVec = lerp(startFrame.value, endFrame.value, (float)(time - startFrame.time) / (float)(endFrame.time - startFrame.time));
}
}
}
{
int keyframeIndex = -1;
int i = 0;
for(auto& frame : channel.rotations) {
if(time >= frame.time)
keyframeIndex = i;
i++;
}
if(keyframeIndex != -1) {
Quaternion* targetVec = nullptr;
if(channel.bone != nullptr)
targetVec = &channel.bone->rotation;
auto& startFrame = channel.rotations[keyframeIndex];
int endFrameIndex = keyframeIndex + 1;
if(endFrameIndex > channel.rotations.size() - 1) {
if(targetVec != nullptr)
*targetVec = startFrame.value;
} else {
auto& endFrame = channel.rotations[endFrameIndex];
if(targetVec != nullptr)
*targetVec = lerp(startFrame.value, endFrame.value, (float)(time - startFrame.time) / (float)(endFrame.time - startFrame.time));
}
}
}
}
2021-04-19 12:23:18 -04:00
void engine::update_cutscene(const float time) {
2020-08-11 12:07:21 -04:00
Shot* currentShot = get_shot(time);
if(currentShot != nullptr) {
current_scene = currentShot->scene;
2020-08-11 12:07:21 -04:00
for(auto& channel : currentShot->channels)
update_animation_channel(*current_scene, channel, time);
2020-08-11 12:07:21 -04:00
} else {
current_scene = nullptr;
2020-08-11 12:07:21 -04:00
}
}
2021-04-19 12:23:18 -04:00
void engine::update_animation(const Animation& anim, const float time) {
2020-08-11 12:07:21 -04:00
for(const auto& channel : anim.channels)
update_animation_channel(*current_scene, channel, time);
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::begin_frame(const float delta_time) {
imgui->begin_frame(delta_time);
2020-08-11 12:07:21 -04:00
2022-02-15 09:01:52 -05:00
if(ui_enabled) {
if (debug_enabled)
draw_debug_ui();
if (console_enabled)
draw_console();
}
if(current_app != nullptr)
current_app->begin_frame();
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::end_frame() {
ImGui::UpdatePlatformWindows();
}
int frame_delay = 0;
const int frame_delay_between_resolution_change = 60;
2021-04-19 12:23:18 -04:00
void engine::update(const float delta_time) {
2020-08-11 12:07:21 -04:00
const float ideal_delta_time = 0.01667f;
if(render_options.dynamic_resolution) {
frame_delay++;
if(frame_delay >= frame_delay_between_resolution_change) {
if(delta_time > ideal_delta_time) {
render_options.render_scale -= 0.1f;
render_options.render_scale = std::fmax(render_options.render_scale, 0.1f);
} else {
render_options.render_scale += 0.1f;
render_options.render_scale = std::fmin(render_options.render_scale, 1.0f);
}
frame_delay = 0;
2020-08-11 12:07:21 -04:00
}
}
for(auto& timer : timers) {
if(!paused || (paused && timer->continue_during_pause))
2020-08-11 12:07:21 -04:00
timer->current_time += delta_time;
if(timer->current_time >= timer->duration) {
timer->callback();
timer->current_time = 0.0f;
if(timer->remove_on_trigger)
timers_to_remove.push_back(timer);
2020-08-11 12:07:21 -04:00
}
}
for(auto& timer : timers_to_remove)
utility::erase(timers, timer);
2020-08-11 12:07:21 -04:00
timers_to_remove.clear();
2020-08-11 12:07:21 -04:00
input->update();
2020-08-11 12:07:21 -04:00
current_app->update(delta_time);
if(cutscene != nullptr && play_cutscene && !paused) {
update_cutscene(current_cutscene_time);
current_cutscene_time += delta_time;
}
if(current_scene != nullptr) {
if(update_physics && !paused)
physics->update(delta_time);
for(auto& target : animation_targets) {
2020-08-11 12:07:21 -04:00
if((target.current_time * target.animation.ticks_per_second) > target.animation.duration) {
if(target.looping) {
target.current_time = 0.0f;
} else {
utility::erase(animation_targets, target);
2020-08-11 12:07:21 -04:00
}
} else {
update_animation(target.animation, target.current_time * target.animation.ticks_per_second);
target.current_time += delta_time * target.animation_speed_modifier;
}
}
update_scene(*current_scene);
2020-08-11 12:07:21 -04:00
}
assetm->perform_cleanup();
}
2021-04-19 12:23:18 -04:00
void engine::update_scene(Scene& scene) {
2020-08-11 12:07:21 -04:00
for(auto& obj : scene.get_objects()) {
if(scene.get(obj).parent == NullObject)
calculate_object(scene, obj);
}
}
void engine::render(const platform::window_ptr index) {
2020-08-11 12:07:21 -04:00
auto window = get_window(index);
if(window == nullptr)
return;
GFXCommandBuffer* commandbuffer = gfx->acquire_command_buffer(true);
if(platform::is_main_window(index)) {
imgui->render();
current_app->render(commandbuffer);
2020-08-11 12:07:21 -04:00
}
if(current_renderer != nullptr)
current_renderer->render(commandbuffer, current_app->wants_no_scene_rendering() ? nullptr : current_scene, *window->render_target, index);
gfx->submit(commandbuffer, index);
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::add_timer(Timer& timer) {
timers.push_back(&timer);
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
Scene* engine::get_scene() {
return current_scene;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
Scene* engine::get_scene(const std::string_view name) {
2020-08-11 12:07:21 -04:00
Expects(!name.empty());
return path_to_scene[name.data()];
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::set_current_scene(Scene* scene) {
current_scene = scene;
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
std::string_view engine::get_scene_path() const {
for(auto& [path, scene] : path_to_scene) {
if(scene == this->current_scene)
2020-08-11 12:07:21 -04:00
return path;
}
return "";
}
2021-04-19 12:23:18 -04:00
void engine::on_remove(Object object) {
2020-08-11 12:07:21 -04:00
Expects(object != NullObject);
physics->remove_object(object);
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::play_animation(Animation animation, Object object, bool looping) {
2020-08-11 12:07:21 -04:00
Expects(object != NullObject);
if(!current_scene->has<Renderable>(object))
2020-08-11 12:07:21 -04:00
return;
AnimationTarget target;
2021-04-19 12:35:52 -04:00
target.animation = std::move(animation);
2020-08-11 12:07:21 -04:00
target.target = object;
target.looping = looping;
for(auto& channel : target.animation.channels) {
for(auto& bone : current_scene->get<Renderable>(object).mesh->bones) {
2020-08-11 12:07:21 -04:00
if(channel.id == bone.name)
channel.bone = &bone;
}
}
animation_targets.push_back(target);
2020-08-11 12:07:21 -04:00
}
2021-04-19 12:23:18 -04:00
void engine::set_animation_speed_modifier(Object target, float modifier) {
for(auto& animation : animation_targets) {
2020-08-11 12:07:21 -04:00
if(animation.target == target)
animation.animation_speed_modifier = modifier;
}
}
2021-04-19 12:23:18 -04:00
void engine::stop_animation(Object target) {
for(auto& animation : animation_targets) {
2020-08-11 12:07:21 -04:00
if(animation.target == target)
utility::erase(animation_targets, animation);
2020-08-11 12:07:21 -04:00
}
}
2021-04-19 12:23:18 -04:00
void engine::setup_scene(Scene& scene) {
physics->reset();
2020-08-11 12:07:21 -04:00
scene.on_remove = [this](Object obj) {
on_remove(obj);
};
get_renderer()->shadow_pass->create_scene_resources(scene);
get_renderer()->scene_capture->create_scene_resources(scene);
scene.reset_shadows();
scene.reset_environment();
}
void prism::engine::process_text_input(const std::string_view string) {
imgui->process_text_input(string);
}