#pragma once #include #include #include #include "object.hpp" #include "components.hpp" #include "utility.hpp" #include "render_constants.hpp" template using Pool = std::unordered_map; template class ObjectComponents : Pool... { 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. */ prism::Object add_object(const prism::Object parent = prism::NullObject) { const prism::Object new_index = make_unique_index(); add(new_index).parent = parent; add(new_index); _objects.push_back(new_index); return new_index; } /// Adds a new object but with a manually specified id. prism::Object add_object_by_id(const prism::Object id) { add(id); add(id); _objects.push_back(id); return id; } /// Remove an object. void remove_object(const prism::Object obj) { recurse_remove(obj); } /// Find an object by name. [[nodiscard]] prism::Object find_object(const std::string_view name) const { for(auto& obj : _objects) { if(get(obj).name == name) return obj; } return prism::NullObject; } /// Check whether or not an object exists. [[nodiscard]] bool object_exists(const std::string_view name) const { return find_object(name) != prism::NullObject; } /// Check if the object originated from a prefab. This works even on children of a root prefab object. [[nodiscard]] bool is_object_prefab(const prism::Object obj) const { bool is_prefab = false; check_prefab_parent(obj, is_prefab); return is_prefab; } /// Duplicates an object and all of it's components and data. prism::Object duplicate_object(const prism::Object original_object) { const prism::Object duplicate_object = make_unique_index(); (add_duplicate_component(original_object, duplicate_object), ...); _objects.push_back(duplicate_object); return duplicate_object; } /// Returns all of the children of an object, with optional recursion. [[nodiscard]] std::vector children_of(const prism::Object obj, const bool recursive = false) const { std::vector vec; 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 Component& add(const prism::Object object) { return Pool::emplace(object, Component()).first->second; } /// Returns a component. template Component& get(const prism::Object object) { return Pool::at(object); } /// Returns a component. template Component get(const prism::Object object) const { return Pool::at(object); } /// Checks whether or not an object has a certain component. template [[nodiscard]] bool has(const prism::Object object) const { return Pool::count(object); } /// Removes a component from an object. Is a no-op if the component wasn't attached. template bool remove(const prism::Object object) { if(has(object)) { Pool::erase(object); return true; } else { return false; } } /// Returns all instances of a component. template std::vector> get_all() { std::vector> comps; for(auto it = Pool::begin(); it != Pool::end(); it++) comps.emplace_back(it->first, it->second); return comps; } /// Returns all objects. [[nodiscard]] std::vector get_objects() const { return _objects; } /// Callback function when an object is removed. std::function on_remove; private: prism::Object make_unique_index() { return _last_index++; } void recurse_remove(prism::Object obj) { for(auto& o : children_of(obj)) recurse_remove(o); utility::erase(_objects, obj); on_remove(obj); (remove(obj), ...); } void check_prefab_parent(prism::Object obj, bool& p) const { if(!get(obj).prefab_path.empty()) p = true; if(get(obj).parent != prism::NullObject) check_prefab_parent(get(obj).parent, p); } template void add_duplicate_component(const prism::Object from, const prism::Object to) { if(Pool::count(from)) Pool::emplace(to, Pool::at(from)); } void recurse_children(std::vector& vec, prism::Object obj) const { for(const auto o : _objects) { if(get(o).parent == obj) { vec.push_back(o); recurse_children(vec, o); } } } prism::Object _last_index = 1; std::vector _objects; }; class GFXFramebuffer; class GFXTexture; /// Represents a scene consisting of Objects with varying Components. class Scene : public ObjectComponents { 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 point_light_dirty; std::array spot_light_dirty; int shadow_refresh_timer = 1; int probe_refresh_timer = 1; // environment std::array 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. */ void camera_look_at(Scene& scene, prism::Object cam, prism::float3 pos, prism::float3 target); prism::Object load_object(Scene& scene, const nlohmann::json& obj); nlohmann::json save_object(prism::Object obj);