Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • gamedev/fggl
  • onuralpsezer/fggl
2 results
Show changes
Showing
with 496 additions and 161 deletions
......@@ -27,10 +27,11 @@ namespace fggl::data {
constexpr math::vec3 ILLEGAL_NORMAL{0.0F, 0.0F, 0.F};
constexpr math::vec3 DEFAULT_COLOUR{1.0F, 1.0F, 1.0F};
struct Vertex {
math::vec3 posititon;
math::vec3 normal;
math::vec3 colour;
math::vec3 normal = ILLEGAL_NORMAL;
math::vec3 colour = DEFAULT_COLOUR;
math::vec2 texPos;
inline static Vertex from_pos(math::vec3 pos) {
......@@ -43,6 +44,22 @@ namespace fggl::data {
}
};
// comparison operators
inline bool operator<(const Vertex &lhs, const Vertex &rhs) {
return std::tie(lhs.posititon, lhs.normal, lhs.colour)
< std::tie(rhs.posititon, rhs.normal, rhs.colour);
}
inline bool operator==(const Vertex &lhs, const Vertex &rhs) {
return lhs.posititon == rhs.posititon
&& lhs.colour == rhs.colour
&& lhs.normal == rhs.normal;
}
inline bool operator!=(const Vertex &lhs, const Vertex &rhs) {
return !(lhs == rhs);
}
struct Vertex2D {
fggl::math::vec2 position;
fggl::math::vec3 colour;
......@@ -64,23 +81,6 @@ namespace fggl::data {
};
// comparison operators
inline bool operator<(const Vertex &lhs, const Vertex &rhs) {
return std::tie(lhs.posititon, lhs.normal, lhs.colour)
< std::tie(rhs.posititon, rhs.normal, rhs.colour);
}
inline bool operator==(const Vertex &lhs, const Vertex &rhs) {
return lhs.posititon == rhs.posititon
&& lhs.colour == rhs.colour
&& lhs.normal == rhs.normal;
}
inline bool operator!=(const Vertex &lhs, const Vertex &rhs) {
return !(lhs == rhs);
}
class Mesh {
public:
using IndexType = unsigned int;
......@@ -134,19 +134,19 @@ namespace fggl::data {
*/
IndexType indexOf(Vertex vert);
inline std::vector<Vertex> &vertexList() {
inline const std::vector<Vertex> &vertexList() const {
return m_verts;
}
inline std::size_t vertexCount() {
inline std::size_t vertexCount() const {
return m_verts.size();
}
inline std::vector<IndexType> &indexList() {
inline const std::vector<IndexType> &indexList() const {
return m_index;
}
inline std::size_t indexCount() {
inline std::size_t indexCount() const {
return m_index.size();
}
......@@ -167,25 +167,11 @@ namespace fggl::data {
data::Mesh mesh;
std::string pipeline;
inline StaticMesh() : mesh(), pipeline() {}
inline StaticMesh() = default;
inline StaticMesh(const data::Mesh &aMesh, std::string aPipeline) :
mesh(aMesh), pipeline(std::move(aPipeline)) {}
};
class Model {
public:
Model() = default;
~Model() = default;
inline void append(const Mesh &mesh) {
m_meshes.push_back(mesh);
}
private:
std::vector<Mesh> m_meshes;
};
}
#endif
......@@ -27,11 +27,11 @@ namespace fggl::data {
struct LocalStorage {
constexpr static const char *name = "fggl::data::Storage";
constexpr static const std::array<modules::ModuleService, 1> provides = {
constexpr static const std::array<modules::ServiceName, 1> provides = {
SERVICE_STORAGE
};
constexpr static const std::array<modules::ModuleService, 0> depends = {};
static bool factory(modules::ModuleService service, modules::Services &serviceManager);
constexpr static const std::array<modules::ServiceName, 0> depends = {};
static bool factory(modules::ServiceName service, modules::Services &serviceManager);
};
} // namespace fggl::data
......
......@@ -16,6 +16,7 @@
#define FGGL_DATA_PROCEDURAL_HPP
#include "model.hpp"
#include "fggl/mesh/mesh.hpp"
namespace fggl::data {
......@@ -28,7 +29,7 @@ namespace fggl::data {
// platonic solids
void make_tetrahedron(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
Mesh make_cube(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
mesh::Mesh3D make_cube(mesh::Mesh3D &mesh, const math::mat4 &offset = OFFSET_NONE);
void make_octahedron(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
void make_icosahedron(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
void make_dodecahedron(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
......@@ -38,13 +39,13 @@ namespace fggl::data {
void make_sphere_iso(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
// level block-out shapes
Mesh make_slope(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
Mesh make_ditch(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
Mesh make_point(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE);
mesh::Mesh3D make_slope(mesh::Mesh3D &mesh, const math::mat4 &offset = OFFSET_NONE);
mesh::Mesh3D make_ditch(mesh::Mesh3D &mesh, const math::mat4 &offset = OFFSET_NONE);
mesh::Mesh3D make_point(mesh::Mesh3D &mesh, const math::mat4 &offset = OFFSET_NONE);
// other useful types people expect
void make_capsule(Mesh &mesh);
void make_sphere(Mesh &mesh, const math::mat4 &offset = OFFSET_NONE, uint32_t stacks = 16U, uint32_t slices = 16U);
void make_sphere(mesh::Mesh3D &mesh, const math::mat4 &offset = OFFSET_NONE, uint32_t stacks = 16U, uint32_t slices = 16U);
}
#endif
\ No newline at end of file
......@@ -35,11 +35,11 @@ namespace fggl::data {
enum StorageType { Data, Config, Cache };
constexpr const modules::ModuleService SERVICE_STORAGE = modules::make_service("fggl::data::Storage");
constexpr const auto SERVICE_STORAGE = modules::make_service("fggl::data::Storage");
class Storage {
public:
constexpr static modules::ModuleService service = SERVICE_STORAGE;
constexpr static auto service = SERVICE_STORAGE;
Storage(fggl::platform::EnginePaths paths) : m_paths(std::move(paths)) {}
......
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 22/10/22.
//
#ifndef FGGL_DATA_TEXTURE_HPP
#define FGGL_DATA_TEXTURE_HPP
#include "fggl/assets/module.hpp"
#include "fggl/math/types.hpp"
namespace fggl::data {
constexpr auto DATA_TEXTURE2D = assets::AssetType::make("gfx::texture");
struct Texture2D {
math::vec2i size;
int channels;
unsigned char* data;
Texture2D() = default;
Texture2D(const Texture2D& other) = delete;
inline ~Texture2D() {
delete data;
}
};
}
#endif //FGGL_DATA_TEXTURE_HPP
......@@ -20,6 +20,8 @@
#define FGGL_DEBUG_IMPL_LOGGING_FMT_HPP
#include <fmt/format.h>
#include <fmt/color.h>
#include <iostream>
#include <string>
#include <string_view>
......@@ -61,7 +63,7 @@ namespace fggl::debug {
template<typename S, typename... Args>
void logf(const char *file, int line, const S &format, Args &&... args) {
vlog(file, line, format, fmt::make_args_checked<Args...>(format, args...));
vlog(file, line, format, fmt::make_format_args(format, args...));
}
#define info_va(format, ...) \
......@@ -78,13 +80,13 @@ namespace fggl::debug {
template<typename ...T>
inline void error(FmtType fmt, T &&...args) {
auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
fmt::print(CERR_FMT, level_to_string(Level::error), fmtStr);
fmt::print(fg(fmt::color::red), CERR_FMT, level_to_string(Level::error), fmtStr);
}
template<typename ...T>
inline void warning(FmtType fmt, T &&...args) {
auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
fmt::print(CERR_FMT, level_to_string(Level::warning), fmtStr);
fmt::print(fg(fmt::color::orange), CERR_FMT, level_to_string(Level::warning), fmtStr);
}
template<typename ...T>
......
......@@ -21,8 +21,12 @@
#include <string_view>
namespace fggl::debug {
std::string demangle(const char* name);
using FmtType = const std::string_view;
enum class Level;
......
......@@ -29,18 +29,18 @@ namespace fggl::display {
struct GLFW {
constexpr static const char *name = "fggl::display::glfw";
constexpr static const std::array<modules::ModuleService, 1> provides = {
constexpr static const std::array<modules::ServiceName, 1> provides = {
WindowService::service
};
constexpr static const std::array<modules::ModuleService, 2> depends = {
constexpr static const std::array<modules::ServiceName, 2> depends = {
fggl::input::Input::service,
fggl::gfx::WindowGraphics::service
};
static bool factory(modules::ModuleService name, modules::Services &serviceManager);
static bool factory(modules::ServiceName name, modules::Services &serviceManager);
};
bool GLFW::factory(modules::ModuleService service, modules::Services &services) {
bool GLFW::factory(modules::ServiceName service, modules::Services &services) {
if (service == WindowService::service) {
auto input = services.get<input::Input>();
auto graphics = services.get<gfx::WindowGraphics>();
......
......@@ -21,8 +21,10 @@
#include "fggl/modules/module.hpp"
#include "fggl/math/types.hpp"
#include "fggl/gfx/interfaces.hpp"
//! Classes responsible for interacting with display managers
namespace fggl::display {
class Window {
......@@ -30,12 +32,6 @@ namespace fggl::display {
virtual ~Window() = default;
virtual void activate() const = 0;
template<typename T, typename ...Args>
void make_graphics(Args... args) {
activate();
m_graphics = std::make_unique<T>(*this, args...);
}
// window-related getters
[[nodiscard]]
virtual math::vec2i frameSize() const = 0;
......@@ -59,12 +55,12 @@ namespace fggl::display {
virtual bool isFullscreen() const = 0;
protected:
std::unique_ptr<gfx::Graphics> m_graphics;
gfx::Graphics* m_graphics;
};
class WindowService {
public:
constexpr static const modules::ModuleService
constexpr static const auto
service = modules::make_service("fggl::display::WindowService");
virtual Window *create() = 0;
......
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 25/03/23.
//
#ifndef FGGL_DS_GRAPH_HPP
#define FGGL_DS_GRAPH_HPP
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
namespace fggl::ds {
template<typename T>
class DirectedGraph {
public:
/**
* Add a single edge to the graph.
*
* If the entry does not already exist, this will create the entry before adding the dependencies to it.
* If the entry already exists, this will append the provided dependencies to its existing list.
*
* @param start the entry which depends something else
* @param end the thing it depends on
*/
inline void addEdge(const T start, const T end) {
m_edges[start].push_back(end);
m_edges[end];
}
/**
* Add a single vertex to the graph.
*/
inline void addVertex(const T vertex) {
m_edges[vertex];
}
/**
* Add a series of dependencies for an entry.
*
* If the entry does not already exist, this will create the entry before adding the dependencies to it.
* If the entry already exists, this will append the provided dependencies to its existing list.
*
* @param name the entry having dependencies added
* @param dependencies the things it depends on
*/
void addEdges(const T name, const std::vector<T> &dependencies) {
auto existing = m_edges.find(name);
if (existing == m_edges.end()) {
m_edges[name] = dependencies;
} else {
existing->second.insert(existing->second.end(), dependencies.begin(), dependencies.end());
}
}
/**
* Clear all currently stored dependencies.
*
* This method will result in the dependency graph being empty, with no known modules.
*/
inline void clear() {
m_edges.clear();
}
inline auto begin() const {
return m_edges.begin();
}
inline auto end() const {
return m_edges.end();
}
bool getOrder(std::stack<T> &stack) {
std::set<T> visited{};
for (const auto &module : m_edges) {
if (!visited.contains(module.first)) {
sortUtil(module.first, visited, stack);
}
}
return true;
}
bool getOrderPartial(T first, std::stack<T> &stack) {
std::set<T> visited{};
sortUtil(first, visited, stack);
return true;
}
bool getOrderRev(std::queue<T> &stack) {
std::set<T> visited{};
for (const auto &module : m_edges) {
if (!visited.contains(module.first)) {
sortUtilRev(module.first, visited, stack);
}
}
return true;
}
bool getOrderPartialRev(T first, std::queue<T>& queue) {
std::set<T> visited{};
sortUtilRev(first, visited, queue);
return true;
}
private:
std::map<T, std::vector<T>> m_edges;
void sortUtil(T idx, std::set<T> &visited, std::stack<T> &stack) {
visited.emplace(idx);
for (auto dep : m_edges.at(idx)) {
if (!visited.contains(dep))
sortUtil(dep, visited, stack);
}
stack.push(idx);
}
void sortUtilRev(T idx, std::set<T> &visited, std::queue<T> &stack) {
visited.emplace(idx);
for (auto dep : m_edges.at(idx)) {
if (!visited.contains(dep))
sortUtilRev(dep, visited, stack);
}
stack.push(idx);
}
};
} // namespace fggl::ds
#endif //FGGL_DS_GRAPH_HPP
......@@ -20,6 +20,8 @@
#define FGGL_ENTITY_ENTITY_HPP
#include <cstdint>
#include <map>
#include <vector>
#include "fggl/debug/logging.hpp"
#include "fggl/vendor/entt.hpp"
......@@ -41,14 +43,15 @@ namespace fggl::entity {
template<typename Component, typename... Args>
inline Component &add(EntityID entity, Args &&... args) {
return m_registry.emplace<Component>(entity, std::forward<Args>(args)...);
return m_registry.get_or_emplace<Component>(entity, std::forward<Args>(args)...);
}
template<typename Component>
Component &get(EntityID entity) {
#ifndef NDEBUG
if (!has<Component>(entity)) {
debug::error("Entity {} has no component of type {}", (uint64_t) entity, typeid(Component).name());
debug::error("Entity {} has no component of type {}", (uint64_t) entity, debug::demangle(typeid(Component).name()));
assert(false && "Entity was missing component - use tryGet or fix definition");
}
#endif
return m_registry.get<Component>(entity);
......@@ -65,8 +68,9 @@ namespace fggl::entity {
}
template<typename Component>
const Component *tryGet(EntityID entity) const {
return m_registry.try_get<Component>(entity);
const Component *tryGet(EntityID entity, const Component* defaultValue = nullptr) const {
auto* comp = m_registry.try_get<Component>(entity);
return comp == nullptr ? defaultValue : comp;
}
template<typename ...Components>
......@@ -74,21 +78,74 @@ namespace fggl::entity {
return m_registry.view<Components...>();
}
EntityID findByName(const std::string& name) const {
auto itr = m_names.find(name);
if ( itr == m_names.end() ){
return INVALID;
}
return m_registry.valid(itr->second) ? itr->second : INVALID;
}
inline void setName(const std::string& name, EntityID eid ) {
if ( eid == INVALID ) {
m_names.erase(name);
} else {
assert(m_registry.valid(eid));
m_names[name] = eid;
}
}
template<typename ...Components>
bool has(EntityID idx) const {
return m_registry.template all_of<Components...>(idx);
}
inline bool exists(EntityID idx) {
bool hasTag(EntityID entity, fggl::util::GUID tag) {
const auto mapItr = m_tags.find( tag );
if ( mapItr == m_tags.end() || !m_registry.valid(entity) ) {
return false;
}
return std::find(mapItr->second.begin(), mapItr->second.end(), entity) != mapItr->second.end();
}
void addTag(const EntityID entity, const fggl::util::GUID tag) {
assert( m_registry.valid(entity) );
auto& tagged = m_tags[ tag ];
tagged.push_back( entity );
}
void removeTag(const EntityID entity, const fggl::util::GUID tag) {
auto mapItr = m_tags.find(tag);
if ( mapItr == m_tags.end() ) {
return;
}
std::remove_if( mapItr->second.begin(), mapItr->second.end(), [entity](auto other) { return other == entity;} );
}
inline std::vector<EntityID> findByTag(const char* tag) {
return findByTag( util::make_guid_rt(tag) );
}
std::vector<EntityID> findByTag(const fggl::util::GUID tag){
auto mapItr = m_tags.find(tag);
if ( mapItr == m_tags.end() ) {
return {};
}
return mapItr->second;
}
inline bool exists(EntityID idx) const {
return m_registry.valid(idx);
}
inline bool alive(EntityID idx) {
inline bool alive(EntityID idx) const {
return m_registry.valid(idx);
}
private:
entt::registry m_registry;
std::map<std::string, EntityID> m_names;
std::map<fggl::util::GUID, std::vector<EntityID>> m_tags;
};
struct Entity {
......
......@@ -23,37 +23,45 @@
#include <vector>
#include "fggl/math/types.hpp"
#include "fggl/assets/types.hpp"
#include "fggl/entity/entity.hpp"
namespace fggl::entity::grid {
using GridPos = math::vec2i;
constexpr auto ASSET_TILESET = assets::AssetType::make("tileset");
template<typename T, uint32_t width, uint32_t height>
struct Grid {
public:
Grid() = default;
inline T& at(math::vec2i pos) {
inline T& get(GridPos pos) {
assert(inBounds(pos));
return m_cells[getCellIndex(pos)];
}
const T& at(math::vec2i pos) const {
const T& get(GridPos pos) const {
assert(inBounds(pos));
return m_cells[getCellIndex(pos)];
}
inline void set(math::vec2i pos, T value) {
inline void set(GridPos pos, T value) {
assert(inBounds(pos));
m_cells[getCellIndex(pos)] = value;
}
inline bool inBounds(math::vec2i pos) const {
inline bool inBounds(GridPos pos) const {
return 0 <= pos.x && pos.x <= size.x &&
0 <= pos.y && pos.y <= size.y;
}
private:
constexpr static math::vec2i size = math::vec2i(width, height);
constexpr static math::vec2i size = math::vec2ui(width, height);
std::array<T, size.x * size.y> m_cells;
inline uint32_t getCellIndex(math::vec2i pos) const {
inline uint32_t getCellIndex(GridPos pos) const {
assert( inBounds(pos));
return pos.y * size.x + pos.x;
}
......@@ -62,16 +70,17 @@ namespace fggl::entity::grid {
struct FloorTile {
constexpr static uint8_t IMPOSSIBLE = 0;
uint8_t moveCost = IMPOSSIBLE;
math::vec3 colour;
math::vec3 colour = gfx::colours::CYAN;
};
struct WallTile {
bool render = false;
math::vec3 colour = gfx::colours::CYAN;
};
struct WallState {
uint32_t wallNorth;
uint32_t wallWest;
uint32_t north = 0;
uint32_t west = 0;
};
struct TileSet {
......@@ -88,51 +97,108 @@ namespace fggl::entity::grid {
template<uint32_t width, uint32_t height>
struct Area2D {
public:
inline explicit Area2D(TileSet& tiles) : m_tiles(tiles) {}
constexpr static std::array<math::vec2i, 4> DIRECTIONS{{ {-1, 0}, {0, -1}, {1, 0}, {0, 1} }};
inline explicit Area2D(TileSet& tiles) : m_tiles(tiles) {
clear();
}
[[nodiscard]]
inline bool inBounds(GridPos pos) const {
return 0 <= pos.x && pos.x <= width
&& 0 <= pos.y && pos.y <= height;
}
void clear() {
WallState noWall;
for (auto xPos = 0U; xPos<width; ++xPos) {
for (auto yPos=0U; yPos<height; ++yPos) {
m_floors.set({xPos, yPos}, 0);
m_walls.set({xPos, yPos}, noWall);
}
}
}
inline FloorTile& floorAt(uint32_t x, uint32_t y) {
return m_tiles.m_floors.at( m_floors.at({x, y}) );
inline FloorTile& floorAt(uint32_t xPos, uint32_t yPos) {
return m_tiles.m_floors.at( m_floors.get({xPos, yPos}) );
}
inline void setFloorAt(uint32_t x, uint32_t y, uint32_t floor) {
m_floors.set({x, y}, floor);
inline void setFloorAt(uint32_t xPos, uint32_t yPos, uint32_t floor) {
m_floors.set({xPos, yPos}, floor);
}
inline WallTile& wallAt(uint32_t x, uint32_t y, bool north) {
inline WallTile& wallAt(uint32_t xPos, uint32_t yPos, bool north) {
if (north) {
return m_tiles.m_walls.at(m_walls.at({x, y}).wallNorth);
return m_tiles.m_walls.at(m_walls.get({xPos, yPos}).north);
} else {
return m_tiles.m_walls.at(m_walls.at({x, y}).wallWest);
return m_tiles.m_walls.at(m_walls.get({xPos, yPos}).west);
}
}
inline void setWallAt(uint32_t x, uint32_t y, uint32_t wall) {
m_walls.set({x, y}, wall);
inline void setWallAt(uint32_t xPos, uint32_t yPos, bool north, uint32_t wall) {
auto& state = m_walls.get({xPos, yPos});
if (north) {
state.north = wall;
} else {
state.west = wall;
}
}
inline bool canMove(math::vec2i pos) const {
return m_tiles.m_floors[m_floors.getCell(pos)] != 0;
inline bool canMove(GridPos pos) const {
if ( !inBounds(pos) ) {
return false;
}
return m_tiles.m_floors[m_floors.get(pos)].moveCost != FloorTile::IMPOSSIBLE;
}
inline bool canMove(math::vec2i pos, math::vec2i dir) const {
inline bool canMove(GridPos pos, math::vec2i dir) const {
return canMove(pos + dir) && !blocked(pos, dir);
}
inline bool blocked(math::vec2i pos, math::vec2i dir) const {
if ( dir.x == -1 || dir.y == -1 ) {
return m_walls.getCell(pos) != 0;
} else {
m_walls.getCell(pos + dir) != 0;
}
inline bool blocked(GridPos pos, math::vec2i dir) const;
EntityManager& entities() {
return m_entities;
}
void neighbours(math::vec2i pos, std::vector<math::vec2i> &neighbours) const;
inline void neighbours(math::vec2i pos, std::vector<math::vec2i> &neighbours) const {
for (auto direction : DIRECTIONS) {
if ( canMove(pos, direction) ) {
auto result = pos + direction;
neighbours.push_back(result);
}
}
}
private:
TileSet& m_tiles;
Grid<uint32_t, width, height> m_floors;
Grid<WallState, width + 1, height + 1> m_walls;
EntityManager m_entities;
};
template<uint32_t width, uint32_t height>
bool Area2D<width, height>::blocked(GridPos pos, math::vec2i dir) const {
auto targetPos = pos;
if ( dir.x == 1 || dir.y == 1 ) {
targetPos = pos + dir;
}
if ( !inBounds(targetPos) ) {
return true;
}
auto& wallObj = m_walls.get(targetPos);
if ( dir.y != 0 ) {
return wallObj.north != 0;
}
if (dir.x != 0) {
return wallObj.west != 0;
}
return true;
}
} // namespace fggl::entity::gridworld
#endif //FGGL_ENTITY_GRIDWORLD_ZONE_HPP
......@@ -31,8 +31,10 @@
namespace fggl::entity {
constexpr auto PROTOTYPE_ASSET = assets::AssetType::make("entity_prototype");
using FactoryFunc = std::function<void(const ComponentSpec &config, EntityManager &, const EntityID &)>;
constexpr auto ENTITY_PROTOTYPE = assets::make_asset_type("entity/prototype");
constexpr auto ENTITY_SCENE = assets::make_asset_type("entity/scene");
using FactoryFunc = std::function<void(const ComponentSpec &config, EntityManager &, const EntityID &, modules::Services &svc)>;
using CustomiseFunc = std::function<void(EntityManager &, const EntityID &)>;
struct FactoryInfo {
......@@ -42,37 +44,47 @@ namespace fggl::entity {
class EntityFactory {
public:
constexpr static const modules::ModuleService service = modules::make_service("fggl::entity:Factory");
constexpr static const modules::ServiceName service = modules::make_service("fggl::entity:Factory");
inline EntityFactory(modules::Services &services) : m_services(services) {}
EntityID create(const EntityType &spec, EntityManager &manager, const CustomiseFunc &customise = nullptr) {
try {
std::vector<CustomiseFunc> finishers;
std::vector<CustomiseFunc> finishers;
// set up the components for the entity
auto entity = setupComponents(spec, manager, finishers);
if (entity == entity::INVALID) {
debug::error("Error attempting to create entity with type {}", std::to_string(spec.get()));
return entity::INVALID;
}
// build the setup
auto entity = setupComponents(spec, manager, finishers);
if ( entity == entity::INVALID ) {
debug::error("EntityFactory: failed to build from prototype {}", std::to_string(spec.get()));
return entity::INVALID;
}
// allow the caller to perform any setup needed
if (customise != nullptr) {
customise(manager, entity);
}
// if requested, allow the user to customize the creation
if ( customise != nullptr ) {
customise(manager, entity);
}
// finally, we run any cleanup/init setups required by the component factories
for (auto &finisher : finishers) {
finisher(manager, entity);
}
// run finishers for components
for ( auto& finisher : finishers ) {
finisher( manager, entity );
}
// use metadata to finalise
processTags(manager, entity, spec);
return entity;
}
void processTags(EntityManager& manager, EntityID id, EntityType spec) {
auto type = m_prototypes.at(spec);
for ( auto& tag : type.tags ) {
manager.addTag(id, tag);
}
}
return entity;
} catch (std::out_of_range &ex) {
#ifndef NDEBUG
debug::log(debug::Level::error,
"EntityFactory: Unknown entity type '{}'",
fggl::util::guidToString(spec));
#endif
return fggl::entity::INVALID;
void log_known_types() const {
debug::debug("dumping known types:");
for(const auto& [k,v] : m_factories) {
debug::debug("\ttype: {}", k);
}
}
......@@ -90,19 +102,34 @@ namespace fggl::entity {
m_factories.erase(configNode);
}
inline FactoryInfo& getInfo(ComponentID comp) {
return m_factories.at(comp);
}
private:
modules::Services m_services;
std::map<ComponentID, FactoryInfo> m_factories;
std::map<EntityType, EntitySpec> m_prototypes;
entity::EntityID setupComponents(EntityType entityType,
EntityManager &manager,
std::vector<CustomiseFunc> &finishers) {
assert(entityType != NO_PARENT && "setup components called with NO_PARENT?!");
auto entity = manager.create();
std::vector<ComponentID> loadedComps;
auto currentType = entityType;
while (currentType != NO_PARENT) {
auto &entitySpec = m_prototypes.at(currentType);
const auto& specEntry = m_prototypes.find( currentType );
if ( specEntry == m_prototypes.end() ) {
debug::warning("Asked to setup {}, for {} but was not a known prototype", specEntry->first, entityType);
return entity::INVALID;
}
auto entitySpec = specEntry->second;
debug::debug("constructing {} for {} ({} comps)", currentType, entityType, entitySpec.components.size());
assert( entitySpec.ordering.size() == entitySpec.components.size() && "ordering incorrect size, bad things happend!" );
for (auto &component : entitySpec.ordering) {
// skip comps loaded by children
......@@ -115,17 +142,14 @@ namespace fggl::entity {
loadedComps.push_back(component);
auto &info = m_factories.at(component);
info.factory(data, manager, entity);
info.factory(data, manager, entity, m_services);
if (info.finalise != nullptr) {
finishers.push_back(info.finalise);
}
} catch (std::out_of_range &ex) {
#ifndef NDEBUG
debug::log(debug::Level::error,
"EntityFactory: Unknown component factory type '{}'",
fggl::util::guidToString(component));
#endif
debug::error( "EntityFactory: Unknown component factory type '{}'", component );
log_known_types();
manager.destroy(entity);
return entity::INVALID;
}
......@@ -149,7 +173,8 @@ namespace fggl::entity {
}
};
assets::AssetRefRaw load_prototype(EntityFactory *factory, const assets::AssetGUID &guid, assets::AssetData data);
assets::AssetRefRaw load_prototype(assets::Loader* loader, const assets::AssetID &guid, const assets::LoaderContext& data, EntityFactory* factory);
assets::AssetRefRaw load_scene(assets::Loader* loader, const assets::AssetID& asset, const assets::LoaderContext& data, void* ptr);
} // namespace fggl::entity
......
......@@ -51,8 +51,14 @@ namespace fggl::entity {
struct EntitySpec {
EntityType parent = NO_PARENT;
std::vector<util::GUID> tags;
std::vector<ComponentID> ordering;
std::map<ComponentID, ComponentSpec> components;
inline void addComp(ComponentID cmp, const ComponentSpec& spec) {
components[cmp] = spec;
ordering.push_back(cmp);
}
};
} // namespace fggl::entity
......
......@@ -22,19 +22,23 @@
#include "fggl/modules/module.hpp"
#include "fggl/assets/loader.hpp"
#include "fggl/assets/packed/adapter.hpp"
#include "fggl/entity/loader/loader.hpp"
namespace fggl::entity {
constexpr auto MIME_SCENE = assets::from_mime("x-fggl/scene");
struct ECS {
constexpr static const char *name = "fggl::entity::ECS";
constexpr static const std::array<modules::ModuleService, 1> provides = {
constexpr static const std::array<modules::ServiceName, 1> provides = {
EntityFactory::service
};
constexpr static const std::array<modules::ModuleService, 1> depends = {
assets::Loader::service
constexpr static const std::array<modules::ServiceName, 2> depends = {
assets::Loader::service,
assets::CheckinAdapted::service
};
static bool factory(modules::ModuleService name, modules::Services &serviceManager);
static bool factory(modules::ServiceName name, modules::Services &serviceManager);
};
void install_component_factories(EntityFactory *factory);
......
......@@ -29,6 +29,7 @@
#include "fggl/audio/null_audio.hpp"
#include "fggl/audio/openal/module.hpp"
//! Root namespace
namespace fggl {
}
......
......@@ -27,6 +27,10 @@ namespace fggl::gfx {
float fov = glm::radians(45.0f);
float nearPlane = 0.1f;
float farPlane = 100.0f;
inline math::mat4 perspective() const {
return glm::perspective(fov, aspectRatio, nearPlane, farPlane);
}
};
inline math::mat4 calc_proj_matrix(const Camera &camera) {
......
......@@ -23,6 +23,7 @@
#include "fggl/entity/entity.hpp"
#include "fggl/modules/module.hpp"
//! Classes responsible for rendering content
namespace fggl::gfx {
struct Bounds {
......@@ -34,7 +35,7 @@ namespace fggl::gfx {
class Graphics {
public:
constexpr static const modules::ModuleService service = modules::make_service("fggl::gfx::Graphics");
constexpr static const auto service = modules::make_service("fggl::gfx::Graphics");
virtual ~Graphics() = default;
virtual void clear() = 0;
......@@ -43,7 +44,7 @@ namespace fggl::gfx {
virtual Bounds canvasBounds() = 0;
virtual void draw2D(const Paint &paint) = 0;
virtual void drawScene(entity::EntityManager &) = 0;
virtual void drawScene(entity::EntityManager &, bool debugMode = false) = 0;
};
} // namespace fggl::gfx
......
......@@ -24,7 +24,6 @@
* FGGL OpenGL 4.x rendering backend.
*/
namespace fggl::gfx {
}
#endif
......@@ -30,21 +30,7 @@
namespace fggl::gfx {
enum GlRenderType {
triangles = GL_TRIANGLES,
triangle_strip = GL_TRIANGLE_STRIP
};
struct GlRenderToken {
constexpr static const char name[] = "RenderToken";
GLuint vao;
GLuint buffs[2];
GLuint idxOffset;
GLsizei idxSize;
GLuint pipeline;
GLuint restartVertex;
GlRenderType renderType = triangles;
};
using GlFunctionLoader = GLADloadproc;
/**
* Class responsible for managing the OpenGL context.
......@@ -55,7 +41,7 @@ namespace fggl::gfx {
*/
class OpenGL4Backend : public Graphics {
public:
explicit OpenGL4Backend(data::Storage *storage, gui::FontLibrary *fonts);
explicit OpenGL4Backend(data::Storage *storage, gui::FontLibrary *fonts, assets::AssetManager *assets, GlFunctionLoader loader);
~OpenGL4Backend() override = default;
// copy bad
......@@ -91,12 +77,12 @@ namespace fggl::gfx {
*
* @param world the world to render
*/
void drawScene(entity::EntityManager &world) override;
void drawScene(entity::EntityManager &world, bool debugMode=false) override;
/**
* Get the 2D canvas bounds.
*
* @return
* @return the canvas bounds
*/
inline Bounds canvasBounds() override {
return m_canvasRenderer->bounds();
......@@ -107,7 +93,7 @@ namespace fggl::gfx {
std::unique_ptr<ogl4::CanvasRenderer> m_canvasRenderer;
std::unique_ptr<ogl4::DebugRenderer> m_debugRenderer;
std::unique_ptr<ShaderCache> m_cache;
GLuint m_canvasPipeline;
std::shared_ptr<ogl::Shader> m_canvasPipeline;
data::Storage *m_storage;
gui::FontLibrary *m_fontLibrary;
};
......