2020-08-11 12:07:21 -04:00
|
|
|
#pragma once
|
|
|
|
|
2020-09-20 23:31:03 -04:00
|
|
|
#include <unordered_map>
|
|
|
|
#include <nlohmann/json_fwd.hpp>
|
2020-09-23 08:44:14 -04:00
|
|
|
#include <functional>
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
#include "object.hpp"
|
|
|
|
#include "components.hpp"
|
2020-09-20 23:31:03 -04:00
|
|
|
#include "utility.hpp"
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
template<class Component>
|
2022-02-15 11:25:13 -05:00
|
|
|
using Pool = std::unordered_map<prism::Object, Component>;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
template<class... Components>
|
|
|
|
class ObjectComponents : Pool<Components>... {
|
|
|
|
public:
|
|
|
|
/** Adds a new object.
|
|
|
|
@param parent The object to parent the new object to. Default is null.
|
|
|
|
@return The newly created object. Will not be null.
|
|
|
|
*/
|
2022-02-15 11:25:13 -05:00
|
|
|
prism::Object add_object(const prism::Object parent = prism::NullObject) {
|
|
|
|
const prism::Object new_index = make_unique_index();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
add<Data>(new_index).parent = parent;
|
|
|
|
add<Transform>(new_index);
|
|
|
|
|
|
|
|
_objects.push_back(new_index);
|
|
|
|
|
|
|
|
return new_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds a new object but with a manually specified id.
|
2022-02-15 11:25:13 -05:00
|
|
|
prism::Object add_object_by_id(const prism::Object id) {
|
2020-08-11 12:07:21 -04:00
|
|
|
add<Data>(id);
|
|
|
|
add<Transform>(id);
|
|
|
|
|
|
|
|
_objects.push_back(id);
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove an object.
|
2022-02-15 11:25:13 -05:00
|
|
|
void remove_object(const prism::Object obj) {
|
2020-08-11 12:07:21 -04:00
|
|
|
recurse_remove(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Find an object by name.
|
2022-02-21 00:14:47 -05:00
|
|
|
[[nodiscard]] prism::Object find_object(const std::string_view name) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
for(auto& obj : _objects) {
|
|
|
|
if(get<Data>(obj).name == name)
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
return prism::NullObject;
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check whether or not an object exists.
|
2022-02-21 00:14:47 -05:00
|
|
|
[[nodiscard]] bool object_exists(const std::string_view name) const {
|
2022-02-15 11:25:13 -05:00
|
|
|
return find_object(name) != prism::NullObject;
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check if the object originated from a prefab. This works even on children of a root prefab object.
|
2022-02-21 00:14:47 -05:00
|
|
|
[[nodiscard]] bool is_object_prefab(const prism::Object obj) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
bool is_prefab = false;
|
|
|
|
check_prefab_parent(obj, is_prefab);
|
|
|
|
|
|
|
|
return is_prefab;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Duplicates an object and all of it's components and data.
|
2022-02-15 11:25:13 -05:00
|
|
|
prism::Object duplicate_object(const prism::Object original_object) {
|
|
|
|
const prism::Object duplicate_object = make_unique_index();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
(add_duplicate_component<Components>(original_object, duplicate_object), ...);
|
|
|
|
|
|
|
|
_objects.push_back(duplicate_object);
|
|
|
|
|
|
|
|
return duplicate_object;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns all of the children of an object, with optional recursion.
|
2022-02-21 00:14:47 -05:00
|
|
|
[[nodiscard]] std::vector<prism::Object> children_of(const prism::Object obj, const bool recursive = false) const {
|
2022-02-15 11:25:13 -05:00
|
|
|
std::vector<prism::Object> vec;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
if(recursive) {
|
|
|
|
recurse_children(vec, obj);
|
|
|
|
} else {
|
|
|
|
for(auto& o : _objects) {
|
|
|
|
if(get(o).parent == obj)
|
|
|
|
vec.push_back(o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vec;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds a component.
|
|
|
|
template<class Component>
|
2022-02-15 11:25:13 -05:00
|
|
|
Component& add(const prism::Object object) {
|
2020-08-11 12:07:21 -04:00
|
|
|
return Pool<Component>::emplace(object, Component()).first->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a component.
|
|
|
|
template<class Component = Data>
|
2022-02-15 11:25:13 -05:00
|
|
|
Component& get(const prism::Object object) {
|
2020-08-11 12:07:21 -04:00
|
|
|
return Pool<Component>::at(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a component.
|
|
|
|
template<class Component = Data>
|
2022-02-15 11:25:13 -05:00
|
|
|
Component get(const prism::Object object) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
return Pool<Component>::at(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks whether or not an object has a certain component.
|
|
|
|
template<class Component>
|
2022-02-21 00:14:47 -05:00
|
|
|
[[nodiscard]] bool has(const prism::Object object) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
return Pool<Component>::count(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Removes a component from an object. Is a no-op if the component wasn't attached.
|
|
|
|
template<class Component>
|
2022-02-15 11:25:13 -05:00
|
|
|
bool remove(const prism::Object object) {
|
2020-08-11 12:07:21 -04:00
|
|
|
if(has<Component>(object)) {
|
|
|
|
Pool<Component>::erase(object);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns all instances of a component.
|
|
|
|
template<class Component>
|
2022-02-15 11:25:13 -05:00
|
|
|
std::vector<std::tuple<prism::Object, Component&>> get_all() {
|
|
|
|
std::vector<std::tuple<prism::Object, Component&>> comps;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
for(auto it = Pool<Component>::begin(); it != Pool<Component>::end(); it++)
|
|
|
|
comps.emplace_back(it->first, it->second);
|
|
|
|
|
|
|
|
return comps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns all objects.
|
2022-02-21 00:14:47 -05:00
|
|
|
[[nodiscard]] std::vector<prism::Object> get_objects() const {
|
2020-08-11 12:07:21 -04:00
|
|
|
return _objects;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Callback function when an object is removed.
|
2022-02-15 11:25:13 -05:00
|
|
|
std::function<void(prism::Object)> on_remove;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
private:
|
2022-02-15 11:25:13 -05:00
|
|
|
prism::Object make_unique_index() {
|
2020-08-11 12:07:21 -04:00
|
|
|
return _last_index++;
|
|
|
|
}
|
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
void recurse_remove(prism::Object obj) {
|
2020-08-11 12:07:21 -04:00
|
|
|
for(auto& o : children_of(obj))
|
|
|
|
recurse_remove(o);
|
|
|
|
|
|
|
|
utility::erase(_objects, obj);
|
|
|
|
|
|
|
|
on_remove(obj);
|
|
|
|
|
|
|
|
(remove<Components>(obj), ...);
|
|
|
|
}
|
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
void check_prefab_parent(prism::Object obj, bool& p) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
if(!get(obj).prefab_path.empty())
|
|
|
|
p = true;
|
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
if(get(obj).parent != prism::NullObject)
|
2020-08-11 12:07:21 -04:00
|
|
|
check_prefab_parent(get(obj).parent, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class Component>
|
2022-02-15 11:25:13 -05:00
|
|
|
void add_duplicate_component(const prism::Object from, const prism::Object to) {
|
2020-08-11 12:07:21 -04:00
|
|
|
if(Pool<Component>::count(from))
|
|
|
|
Pool<Component>::emplace(to, Pool<Component>::at(from));
|
|
|
|
}
|
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
void recurse_children(std::vector<prism::Object>& vec, prism::Object obj) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
for(const auto o : _objects) {
|
|
|
|
if(get(o).parent == obj) {
|
|
|
|
vec.push_back(o);
|
|
|
|
|
|
|
|
recurse_children(vec, o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
prism::Object _last_index = 1;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
std::vector<prism::Object> _objects;
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
|
|
|
|
2022-03-10 10:21:09 -05:00
|
|
|
const int max_spot_shadows = 4;
|
|
|
|
const int max_point_shadows = 4;
|
|
|
|
const int max_environment_probes = 4;
|
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
class GFXFramebuffer;
|
2020-09-20 23:31:03 -04:00
|
|
|
class GFXTexture;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
/// Represents a scene consisting of Objects with varying Components.
|
2021-09-13 23:10:26 -04:00
|
|
|
class Scene : public ObjectComponents<Data, Transform, Renderable, Light, Camera, Collision, Rigidbody, EnvironmentProbe> {
|
2020-08-11 12:07:21 -04:00
|
|
|
public:
|
|
|
|
/// If loaded from disk, the path to the scene file this originated from.
|
|
|
|
std::string path;
|
|
|
|
|
|
|
|
/// Invalidates the current shadow data for all shadowed lights. This may cause stuttering while the data is regenerated.
|
|
|
|
void reset_shadows() {
|
|
|
|
sun_light_dirty = true;
|
|
|
|
|
|
|
|
for(auto& point_dirty : point_light_dirty)
|
|
|
|
point_dirty = true;
|
|
|
|
|
|
|
|
for(auto& spot_dirty : spot_light_dirty)
|
|
|
|
spot_dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Invalidates the current environment probe data. This may cause stuttering while the data is regenerated.
|
|
|
|
void reset_environment() {
|
|
|
|
for(auto& probe_dirty : environment_dirty)
|
|
|
|
probe_dirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// shadow
|
|
|
|
GFXTexture* depthTexture = nullptr;
|
|
|
|
GFXFramebuffer* framebuffer = nullptr;
|
|
|
|
|
|
|
|
Matrix4x4 lightSpace;
|
|
|
|
Matrix4x4 spotLightSpaces[max_spot_shadows];
|
|
|
|
|
|
|
|
GFXTexture* pointLightArray = nullptr;
|
|
|
|
GFXTexture* spotLightArray = nullptr;
|
|
|
|
|
|
|
|
bool sun_light_dirty = false;
|
|
|
|
std::array<bool, max_point_shadows> point_light_dirty;
|
|
|
|
std::array<bool, max_spot_shadows> spot_light_dirty;
|
2021-04-18 22:14:19 -04:00
|
|
|
|
2021-06-01 12:34:32 -04:00
|
|
|
int shadow_refresh_timer = 1;
|
|
|
|
int probe_refresh_timer = 1;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
// environment
|
|
|
|
std::array<bool, max_environment_probes> environment_dirty;
|
|
|
|
|
|
|
|
GFXTexture *irradianceCubeArray = nullptr, *prefilteredCubeArray = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Positions and rotates a camera to look at a target from a position.
|
|
|
|
@param scene The scene that the camera exists in.
|
|
|
|
@param cam The camera object.
|
|
|
|
@param pos The position the camera will be viewing the target from.
|
|
|
|
@param target The position to be centered in the camera's view.
|
|
|
|
@note Although this is a look at function, it applies no special attribute to the camera and simply changes it's position and rotation.
|
|
|
|
*/
|
2022-02-15 11:25:13 -05:00
|
|
|
void camera_look_at(Scene& scene, prism::Object cam, prism::float3 pos, prism::float3 target);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2022-02-15 11:25:13 -05:00
|
|
|
prism::Object load_object(Scene& scene, const nlohmann::json& obj);
|
|
|
|
nlohmann::json save_object(prism::Object obj);
|