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 732 additions and 152 deletions
......@@ -12,61 +12,48 @@
* If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FGGL_GFX_OGL_COMPAT_HPP
#define FGGL_GFX_OGL_COMPAT_HPP
/**
* Legacy/Direct OpenGL calls.
*
* This shouldn't be exposed to the demo app, but the ECS we're using isn't smart enouph to allow us to
* abstract this yet. It's next thing on the list, but this branch is about cleaning up OpenGL not about
* extending our ECS.
*
* Should be removed when the engine has suitable abstractions in place.
*/
#include <functional>
#include <fggl/gfx/ogl/shader.hpp>
#include <fggl/gfx/ogl/renderer.hpp>
//
// Created by webpigeon on 19/11/22.
//
#include <fggl/gfx/common.hpp>
#include <fggl/gfx/camera.hpp>
#ifndef FGGL_ASSETS_PACKED_DIRECT_HPP
#define FGGL_ASSETS_PACKED_DIRECT_HPP
#include <utility>
#include <fggl/input/camera_input.hpp>
#include <fggl/data/heightmap.hpp>
#include "fggl/gfx/phong.hpp"
namespace fggl::gfx {
#include <functional>
#include <map>
//
// fake module support - allows us to still RAII
//
/*struct SceneUtils : ecs3::Module {
#include "fggl/assets/types.hpp"
#include "fggl/util/safety.hpp"
#include "fggl/util/guid.hpp"
#include "fggl/modules/module.hpp"
SceneUtils() = default;
/**
* Raw Checkin.
*
* This is a version of the checkin system where the check-in functions are shown a raw block of memory and its their
* job to parse and load something meaningful from that.
*/
namespace fggl::assets {
[[nodiscard]]
std::string name() const override {
return "gfx::scene";
}
class RawCheckin {
public:
constexpr const static auto service = modules::make_service("fggl::assets::checkin");
using DecodeAndCheckFunc = std::function<void(AssetGUID, MemoryBlock& block)>;
void onLoad(ecs3::ModuleManager &manager, ecs3::TypeRegistry &types) override {
// mesh dependencies
types.make<math::Transform>();
types.make<data::StaticMesh>();
types.make<data::HeightMap>();
void check(AssetID, AssetTypeID, MemoryBlock& block) const;
types.make<gfx::PhongMaterial>();
inline void check(int64_t id, uint64_t type, MemoryBlock& block ) const {
check( AssetID::make(id), AssetTypeID::make(type), block );
}
// camera dependencies
types.make<fggl::gfx::Camera>();
types.make<fggl::input::FreeCamKeys>();
}
inline void setCheckin(AssetTypeID type, DecodeAndCheckFunc func) {
m_check[type] = func;
}
};*/
private:
std::map<AssetTypeID, DecodeAndCheckFunc> m_check;
};
}
#endif
#endif //FGGL_ASSETS_PACKED_DIRECT_HPP
/*
* 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 27/06/22.
//
#ifndef FGGL_ASSETS_PACKED_MODULE_HPP
#define FGGL_ASSETS_PACKED_MODULE_HPP
#include "fggl/modules/module.hpp"
#include "fggl/data/module.hpp"
#include "fggl/assets/loader.hpp"
#include "fggl/assets/packed/adapter.hpp"
#include "fggl/assets/packed/direct.hpp"
namespace fggl::assets {
struct PackedAssets {
constexpr static const char *name = "fggl::assets::packed";
constexpr static const std::array<modules::ServiceName, 2> provides = {
RawCheckin::service,
CheckinAdapted::service
};
constexpr static const std::array<modules::ServiceName, 1> depends = {
data::Storage::service
};
static bool factory(modules::ServiceName name, modules::Services &serviceManager);
};
} // namespace fggl::assets
#endif //FGGL_ASSETS_PACKED_MODULE_HPP
/*
* 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 19/11/22.
//
#ifndef FGGL_ASSETS_PACKED_PACKED_HPP
#define FGGL_ASSETS_PACKED_PACKED_HPP
#include <cstdint>
#include <cstdio>
#include <memory>
#include "fggl/assets/types.hpp"
#include "fggl/assets/packed/direct.hpp"
/**
* Packed file reader.
*
* Read assets stored as sequential [header,data] blocks. This reader does not care about dependencies, it assumes this
* was handled before storage (ie, asset dependencies are assumed to be stored before the asset that relies on them).
* The caller is also responsible for ensuring that assets in other archives are already loaded by the time the system
* assembles the composite assets into something usable.
*
* If either of these constraints are violated, the results are undefined.
*/
namespace fggl::assets {
struct Header {
uint64_t name;
uint64_t type;
std::size_t size;
};
bool read_header(std::FILE* stream, Header* header) {
constexpr auto headerSize = sizeof(Header);
auto readBytes = std::fread(header, headerSize, 1, stream);
return readBytes == headerSize;
}
bool read_data(std::FILE* stream, void* block, std::size_t size) {
auto readBytes = std::fread(block, size, 1, stream);
return readBytes == size;
}
void read_archive(RawCheckin* checkin, std::FILE* stream) {
while ( !std::feof(stream) ) {
Header header;
bool headRead = read_header(stream, &header);
if ( headRead && header.size != 0 ) {
// header has data
void* memBlock = std::malloc( header.size );
bool valid = read_data( stream, memBlock, header.size );
// read the data, check it in
if (valid) {
MemoryBlock block{
.data = (std::byte*)memBlock,
.size = header.size
};
checkin->check(header.name, header.type, block);
}
}
}
}
}
#endif //FGGL_ASSETS_PACKED_PACKED_HPP
......@@ -24,31 +24,83 @@
#include <functional>
#include "fggl/util/safety.hpp"
#include "fggl/util/guid.hpp"
namespace fggl::assets {
using AssetType = util::OpaqueName<std::string_view, struct AssetTag>;
using AssetGUID = std::string;
using AssetPath = std::filesystem::path;
struct Asset {
AssetType m_type;
virtual void release() = 0;
virtual bool active() = 0;
};
using AssetID = util::OpaqueName<uint64_t, struct AssetIDTag>;
template<unsigned L1, unsigned L2>
constexpr AssetID make_asset_id(const char (&pack)[L1], const char (&path)[L2]) {
auto hash = util::hash_fnv1a_64( util::cat( pack, ":", path ).c );
return AssetID::make( hash );
}
template<unsigned L1, unsigned L2, unsigned L3>
constexpr AssetID make_asset_id(const char (&pack)[L1], const char (&path)[L2], const char (&view)[L3]) {
auto hash = util::hash_fnv1a_64( util::cat( pack, ":", path, "[", view, "]").c );
return AssetID::make( hash );
}
AssetID make_asset_id_rt(const std::string &pack, const std::string &path, const std::string &view = "");
AssetID asset_from_user(const std::string &input, const std::string &pack = "core");
using AssetTypeID = util::OpaqueName<uint64_t, struct AssetTypeTag>;
constexpr auto INVALID_ASSET_TYPE = AssetTypeID::make(0);
constexpr AssetTypeID make_asset_type(const char* type) {
return AssetTypeID::make( util::hash_fnv1a_64(type) );
}
struct MemoryBlock {
void *data;
std::byte *data;
std::size_t size;
template<typename T>
T* viewAs(std::size_t offset = 0) {
static_assert( std::is_standard_layout<T>::value );
return (T*)( data[offset] );
}
};
using AssetRefRaw = std::shared_ptr<void>;
template<typename T>
using AssetRef = std::shared_ptr<T>;
struct LoaderContext {
std::string pack;
std::filesystem::path packRoot;
std::filesystem::path assetPath;
inline std::filesystem::path relParent() const {
return std::filesystem::relative( assetPath, packRoot ).parent_path();
}
inline assets::AssetID makeRef(const char* name) const {
return assets::make_asset_id_rt(pack, relParent() / name );
}
};
class Loader;
using AssetData = std::variant<MemoryBlock, AssetPath *, FILE *>;
using Checkin = std::function<AssetRefRaw(Loader* loader, const AssetGUID &, const AssetData &)>;
using Checkin = std::function<AssetRefRaw(Loader* loader, const AssetID &, const LoaderContext &, void* userPtr)>;
}
// formatter
template<> struct fmt::formatter<fggl::assets::AssetID> {
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const fggl::assets::AssetID & guid, FormatContext& ctx) const -> decltype(ctx.out()) {
#ifndef NDEBUG
return fmt::format_to(ctx.out(), "ASSET[{}]", guid_to_string( fggl::util::GUID::make( guid.get() ) ));
#else
return fmt::format_to(ctx.out(), "ASSET[{}]", guid.get());
#endif
}
};
#endif //FGGL_ASSETS_TYPES_HPP
......@@ -16,8 +16,11 @@
#define FGGL_AUDIO_AUDIO_HPP
#include <string>
#include "fggl/data/storage.hpp"
#include "fggl/modules/module.hpp"
#include "fggl/assets/module.hpp"
#include "fggl/assets/packed/module.hpp"
//! backend independent audio interface
namespace fggl::audio {
......@@ -27,14 +30,34 @@ namespace fggl::audio {
*
* If the sampleCount is -1, the clip is invalid.
*/
struct AudioClip {
template<typename T>
struct AudioClip {
int channels = 0;
int sampleRate = 0;
int sampleCount = -1;
short *data = nullptr;
};
T *data = nullptr;
AudioClip() = default;
AudioClip(const AudioClip&) = delete;
inline ~AudioClip() {
std::free(data);
data = nullptr;
}
constexpr modules::ModuleService SERVICE_AUDIO_PLAYBACK = modules::make_service("fggl::audio::AudioService");
[[nodiscard]]
inline int size() const {
return sampleCount * sizeof(T);
}
};
using AudioClipShort = AudioClip<short>;
using AudioClipByte = AudioClip<char>;
constexpr auto ASSET_CLIP_SHORT = assets::make_asset_type("Audio:Clip:Short");
constexpr auto ASSET_CLIP_BYTE = assets::make_asset_type("Audio:Clip:Byte");
constexpr auto SERVICE_AUDIO_PLAYBACK = modules::make_service("fggl::audio::AudioService");
/**
*
......@@ -42,9 +65,10 @@ namespace fggl::audio {
*/
class AudioService {
public:
constexpr static const modules::ModuleService service = SERVICE_AUDIO_PLAYBACK;
virtual void play(const std::string &filename, bool looping = false) = 0;
virtual void play(AudioClip &clip, bool looping = false) = 0;
constexpr static const modules::ServiceName service = SERVICE_AUDIO_PLAYBACK;
virtual void play(const assets::AssetGUID &asset, bool looping = false) = 0;
virtual void play(const AudioClipShort &clip, bool looping = false) = 0;
virtual ~AudioService() = default;
};
......
......@@ -26,31 +26,27 @@ namespace fggl::audio {
class NullAudioService : public AudioService {
public:
NullAudioService() = default;
virtual ~NullAudioService() = default;
~NullAudioService() override = default;
void play(const std::string & /*filename*/, bool /*looping = false*/) override {}
NullAudioService(NullAudioService&) = delete;
NullAudioService(NullAudioService&&) = delete;
NullAudioService& operator=(const NullAudioService&) = delete;
NullAudioService& operator=(NullAudioService&&) = delete;
void play(AudioClip & /*clip*/, bool /*looping = false*/) override {}
void play(const std::string & /*filename*/, bool /*looping = false*/) override;
void play(const AudioClipShort & /*clip*/, bool /*looping = false*/) override;
};
//! A dummy audio module that does nothing
struct NullAudio {
constexpr static const char *name = "fggl::audio::NULL";
constexpr static const std::array<modules::ModuleService, 1> provides = {
constexpr static const std::array<modules::ServiceName, 1> provides = {
SERVICE_AUDIO_PLAYBACK
};
constexpr static const std::array<modules::ModuleService, 0> depends = {};
static const modules::ServiceFactory factory;
constexpr static const std::array<modules::ServiceName, 0> depends = {};
bool factory(modules::ServiceName, modules::Services&);
};
bool null_factory(modules::ModuleService service, modules::Services &services) {
if (service == SERVICE_AUDIO_PLAYBACK) {
services.bind<audio::AudioService, audio::NullAudioService>();
return true;
}
return false;
}
const modules::ServiceFactory NullAudio::factory = null_factory;
} // namespace fggl::audio
......
......@@ -23,6 +23,8 @@
#include <AL/alc.h>
#include "fggl/audio/audio.hpp"
#include "fggl/assets/manager.hpp"
#include "fggl/data/storage.hpp"
#include "fggl/math/types.hpp"
......@@ -30,8 +32,16 @@
#include <iostream>
#include <memory>
//! Audio backed by openal-soft
namespace fggl::audio::openal {
constexpr uint32_t NULL_BUFFER_ID = 0;
assets::AssetRefRaw load_vorbis(assets::Loader* loader, const assets::AssetID &, const assets::LoaderContext &, void* userPtr);
bool load_vorbis_short(std::filesystem::path path, assets::MemoryBlock& block);
assets::AssetTypeID check_vorbis( const std::filesystem::path& path );
enum class AudioType {
MONO_8 = AL_FORMAT_MONO8,
MONO_16 = AL_FORMAT_MONO16,
......@@ -39,7 +49,7 @@ namespace fggl::audio::openal {
STEREO_16 = AL_FORMAT_STEREO16
};
static void checkError(std::string context) {
static void check_error(const std::string& context) {
auto code = alGetError();
if (code == AL_NO_ERROR) {
return;
......@@ -48,25 +58,25 @@ namespace fggl::audio::openal {
// now we check the error message
std::string error = "unknown";
switch (code) {
case ALC_INVALID_DEVICE: error = "Invalid Device";
break;
case ALC_INVALID_CONTEXT: error = "Invalid Context";
break;
case ALC_INVALID_ENUM: error = "Invalid enum";
break;
case ALC_INVALID_VALUE: error = "Invalid value";
break;
case ALC_OUT_OF_MEMORY: error = "Out of memory";
break;
default: error = "unknown error";
case ALC_INVALID_DEVICE: error = "Invalid Device";
break;
case ALC_INVALID_CONTEXT: error = "Invalid Context";
break;
case ALC_INVALID_ENUM: error = "Invalid enum";
break;
case ALC_INVALID_VALUE: error = "Invalid value";
break;
case ALC_OUT_OF_MEMORY: error = "Out of memory";
break;
default: error = "unknown error";
}
std::cerr << "OpenAL error: " << context << ": " << error << std::endl;
debug::error("OpenAL error: context={}, error={}", context, error);
}
class AudioBuffer {
public:
AudioBuffer() : m_buffer(0) {
AudioBuffer() : m_buffer(NULL_BUFFER_ID) {
alGenBuffers(1, &m_buffer);
}
......@@ -74,16 +84,24 @@ namespace fggl::audio::openal {
alDeleteBuffers(1, &m_buffer);
}
AudioBuffer(const AudioBuffer&) = delete;
AudioBuffer(const AudioBuffer&&) = delete;
AudioBuffer& operator=(const AudioBuffer&) = delete;
AudioBuffer& operator=(const AudioBuffer&&) = delete;
inline void setData(AudioType type, void *data, ALsizei size, ALsizei frequency) {
assert( m_buffer != 0 );
assert( data != nullptr );
alBufferData(m_buffer, (ALenum) type, data, size, frequency);
}
inline ALuint value() {
inline ALuint value() const {
return m_buffer;
}
private:
ALuint m_buffer;
ALuint m_buffer = 0;
};
class AudioSource {
......@@ -96,6 +114,11 @@ namespace fggl::audio::openal {
alDeleteSources(1, &m_source);
}
AudioSource(const AudioSource& source) = delete;
AudioSource(const AudioSource&& source) = delete;
AudioSource& operator=(const AudioSource&) = delete;
AudioSource& operator=(AudioSource&&) = delete;
inline void play() {
alSourcePlay(m_source);
}
......@@ -115,21 +138,10 @@ namespace fggl::audio::openal {
inline void play(AudioBuffer &buffer, bool looping) {
alSourcei(m_source, AL_BUFFER, buffer.value());
alSourcei(m_source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
alSourcePlay(m_source);
}
inline void play(AudioClip &clip, bool looping) {
checkError("pre play");
AudioType format = clip.channels == 1 ? AudioType::MONO_8 : AudioType::STEREO_8;
m_splat.setData(format, clip.data, clip.sampleCount, clip.sampleRate);
checkError("saving to buffer");
alSourcei(m_source, AL_BUFFER, m_splat.value());
alSourcei(m_source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
checkError("setting parameters");
play();
}
inline void play(const AudioClipShort &clip, bool looping = false);
inline void velocity(math::vec3 &value) {
alSource3f(m_source, AL_VELOCITY, value.x, value.y, value.z);
......@@ -150,32 +162,33 @@ namespace fggl::audio::openal {
class AudioServiceOAL : public AudioService {
public:
explicit AudioServiceOAL(data::Storage *storage) : m_device(alcOpenDevice(nullptr)), m_storage(storage) {
explicit AudioServiceOAL(assets::AssetManager *assets) : m_device(alcOpenDevice(nullptr)), m_assets(assets) {
if (m_device != nullptr) {
m_context = alcCreateContext(m_device, nullptr);
alcMakeContextCurrent(m_context);
checkError("context setup");
check_error("context setup");
m_defaultSource = std::make_unique<AudioSource>();
checkError("default source setup");
check_error("default source setup");
}
}
~AudioServiceOAL() override {
if (m_device != nullptr) {
alcDestroyContext(m_context);
alcCloseDevice(m_device);
release();
}
}
void play(const std::string &filename, bool looping = false) override;
void play(AudioClip &clip, bool looping = false) override;
void play(const assets::AssetGUID &filename, bool looping = false) override;
void play(const AudioClipShort &clip, bool looping = false) override;
private:
ALCdevice *m_device;
ALCcontext *m_context{nullptr};
std::unique_ptr<AudioSource> m_defaultSource{nullptr};
data::Storage *m_storage = nullptr;
assets::AssetManager* m_assets;
void release();
};
} // namespace fggl::audio::openal
......
......@@ -21,30 +21,31 @@
#include <array>
#include <string>
#include "fggl/assets/module.hpp"
#include "fggl/assets/packed/module.hpp"
#include "fggl/audio/audio.hpp"
#include "fggl/audio/openal/audio.hpp"
namespace fggl::audio {
constexpr auto OGG_VORBIS = assets::AssetType::make("audio/vorbis");
constexpr auto RES_OGG_VORBIS = assets::from_mime("audio/vorbis");
//! an audio module which uses openal(-soft) as a backend.
struct OpenAL {
constexpr static const char *name = "fggl::audio::OpenAL";
constexpr static const std::array<modules::ModuleService, 1> provides = {
constexpr static const std::array<modules::ServiceName, 1> provides = {
SERVICE_AUDIO_PLAYBACK
};
constexpr static const std::array<modules::ModuleService, 1> depends = {
modules::make_service("fggl::data::Storage")
constexpr static const std::array<modules::ServiceName, 2> depends = {
assets::AssetManager::service,
assets::CheckinAdapted::service
};
static bool factory(modules::ModuleService name, modules::Services &serviceManager);
static bool factory(modules::ServiceName name, modules::Services &serviceManager);
};
bool OpenAL::factory(modules::ModuleService service, modules::Services &services) {
if (service == SERVICE_AUDIO_PLAYBACK) {
auto storage = services.get<data::Storage>();
services.bind<audio::AudioService, openal::AudioServiceOAL>(storage);
return true;
}
return false;
}
} // namespace fggl::audio
......
/*
* 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 18/10/22.
//
#ifndef FGGL_DATA_ASSIMP_MODULE_HPP
#define FGGL_DATA_ASSIMP_MODULE_HPP
#include "fggl/modules/module.hpp"
#include "fggl/assets/loader.hpp"
#include "fggl/assets/packed/module.hpp"
#include "fggl/data/texture.hpp"
namespace fggl::data::models {
constexpr auto MODEL_PROVIDER = modules::make_service("fggl::data::Model");
constexpr auto ASSIMP_MODEL = assets::AssetType::make("model::assimp");
constexpr auto MIME_JPG = assets::from_mime("image/jpeg");
constexpr auto MIME_PNG = assets::from_mime("image/png");
constexpr auto MIME_OBJ = assets::from_mime("model/obj");
constexpr auto MIME_FBX = assets::from_mime("model/fbx");
constexpr auto MODEL_MULTI3D = assets::make_asset_type("model/multi3D");
constexpr auto TEXTURE_RGBA = assets::make_asset_type("texture/rgba");
// old-style loaders
assets::AssetRefRaw load_assimp_model(assets::Loader* loader, const assets::AssetID& guid, const assets::LoaderContext& data, void* userPtr);
assets::AssetRefRaw load_assimp_texture(assets::Loader* loader, const assets::AssetID& guid, const assets::LoaderContext& data, void* userPtr);
// new style loaders (textures)
bool load_tex_stb(const std::filesystem::path& filePath, assets::MemoryBlock& block);
assets::AssetTypeID is_tex_stb(const std::filesystem::path& filePath);
// new style loaders (models)
assets::AssetTypeID is_model_assimp(const std::filesystem::path& filePath);
bool extract_requirements(const std::string& packName, const std::filesystem::path& packRoot, assets::ResourceRecord& rr);
struct AssimpModule {
constexpr static const char *name = "fggl::data::Assimp";
constexpr static const std::array<modules::ServiceName, 1> provides = {
MODEL_PROVIDER
};
constexpr static const std::array<modules::ServiceName, 2> depends = {
assets::Loader::service,
assets::CheckinAdapted::service
};
static bool factory(modules::ServiceName service, modules::Services &serviceManager);
};
}
namespace fggl::data {
using AssimpLoader = models::AssimpModule;
}
#endif //FGGL_DATA_ASSIMP_MODULE_HPP
......@@ -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;
......@@ -172,19 +172,6 @@ namespace fggl::data {
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
......@@ -63,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, ...) \
......@@ -103,10 +103,8 @@ namespace fggl::debug {
template<typename ...T>
inline void trace(FmtType fmt, T &&...args) {
#ifdef FGGL_LOG_TRACE
auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
fmt::print(CERR_FMT, level_to_string(Level::trace), fmtStr);
#endif
auto fmtStr = fmt::format(fmt::runtime(fmt), args...);
fmt::print(CERR_FMT, level_to_string(Level::trace), fmtStr);
}
}
......
......@@ -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>();
......
......@@ -24,6 +24,7 @@
#include "fggl/gfx/interfaces.hpp"
//! Classes responsible for interacting with display managers
namespace fggl::display {
class Window {
......@@ -59,7 +60,7 @@ namespace fggl::display {
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,7 +43,7 @@ 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>
......@@ -66,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>
......@@ -75,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 {
......
......@@ -58,7 +58,7 @@ namespace fggl::entity::grid {
}
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(GridPos pos) const {
......@@ -111,32 +111,32 @@ namespace fggl::entity::grid {
void clear() {
WallState noWall;
for (auto x = 0U; x<width; ++x) {
for (auto y=0U; y<height; ++y) {
m_floors.set({x, y}, 0);
m_walls.set({x, y}, 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.get({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.get({x, y}).north);
return m_tiles.m_walls.at(m_walls.get({xPos, yPos}).north);
} else {
return m_tiles.m_walls.at(m_walls.get({x, y}).west);
return m_tiles.m_walls.at(m_walls.get({xPos, yPos}).west);
}
}
inline void setWallAt(uint32_t x, uint32_t y, bool north, uint32_t wall) {
auto& state = m_walls.get({x, y});
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 {
......