wip: convert from include style to module import style :D
Some checks are pending
continuous-integration/drone/push Build is running
Some checks are pending
continuous-integration/drone/push Build is running
This commit is contained in:
parent
14c2512202
commit
63cb6dfe92
114 changed files with 2228 additions and 1714 deletions
|
|
@ -1,26 +1,37 @@
|
|||
# engine
|
||||
add_subdirectory(./std)
|
||||
add_subdirectory(./bitwise)
|
||||
add_subdirectory(./env)
|
||||
add_subdirectory(./memory)
|
||||
add_subdirectory(./time)
|
||||
add_subdirectory(./logger)
|
||||
add_subdirectory(./debug)
|
||||
add_subdirectory(./math)
|
||||
#
|
||||
add_subdirectory(./asset_baker)
|
||||
add_subdirectory(./assets)
|
||||
#
|
||||
add_subdirectory(./camera)
|
||||
add_subdirectory(./input)
|
||||
# add_subdirectory(./ui)
|
||||
#
|
||||
add_subdirectory(./surface)
|
||||
add_subdirectory(./renderer)
|
||||
add_subdirectory(./ecs)
|
||||
#
|
||||
add_subdirectory(./app)
|
||||
# engine add_subdirectory(./std)
|
||||
|
||||
# apps
|
||||
add_subdirectory(./mirror)
|
||||
add_subdirectory(test)
|
||||
|
||||
add_subdirectory(./logger)
|
||||
|
||||
add_subdirectory(./bitwise)
|
||||
|
||||
add_subdirectory(./env)
|
||||
|
||||
add_subdirectory(./memory)
|
||||
|
||||
add_subdirectory(./time)
|
||||
|
||||
add_subdirectory(./debug)
|
||||
|
||||
add_subdirectory(./math)
|
||||
|
||||
add_subdirectory(./assets)
|
||||
|
||||
add_subdirectory(./asset_baker)
|
||||
|
||||
add_subdirectory(./camera)
|
||||
|
||||
add_subdirectory(./app)
|
||||
add_subdirectory(./ecs)
|
||||
|
||||
add_subdirectory(./surface)
|
||||
|
||||
add_subdirectory(./input)
|
||||
|
||||
# add_subdirectory(./ui)
|
||||
|
||||
# add_subdirectory(./renderer)
|
||||
|
||||
#
|
||||
# add_subdirectory(./mirror)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
add_library_module(app application.cpp)
|
||||
add_library_module(
|
||||
NAME
|
||||
app
|
||||
INTERFACES
|
||||
application.cppm
|
||||
system.cppm
|
||||
SOURCES
|
||||
entrypoint.cpp)
|
||||
|
||||
target_link_libraries(
|
||||
app
|
||||
PUBLIC memory
|
||||
|
|
|
|||
98
modules/app/application.cppm
Normal file
98
modules/app/application.cppm
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
export module app;
|
||||
import app.system;
|
||||
import memory.reference;
|
||||
import memory.scope;
|
||||
import std;
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
/** The main application class.
|
||||
* Think of this like an aggregate of systems, you register systems through this interface.
|
||||
* Then they'll tick every "application frame".
|
||||
*/
|
||||
export class Application
|
||||
{
|
||||
public:
|
||||
Application(const Application &) = delete;
|
||||
|
||||
Application(Application &&) = delete;
|
||||
|
||||
auto operator=(const Application &) -> Application & = delete;
|
||||
|
||||
auto operator=(Application &&) -> Application & = delete;
|
||||
|
||||
virtual ~Application() = default;
|
||||
|
||||
void game_loop();
|
||||
|
||||
void register_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
void unregister_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
protected:
|
||||
Application() = default;
|
||||
|
||||
private:
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_unregistered;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_registered;
|
||||
};
|
||||
|
||||
export extern memory::Scope<class Application> create_application();
|
||||
|
||||
} // namespace lt::app
|
||||
|
||||
module :private;
|
||||
namespace lt::app {
|
||||
|
||||
void Application::game_loop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (auto &system : m_systems)
|
||||
{
|
||||
const auto &last_tick = system->get_last_tick_result();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
|
||||
system->tick(
|
||||
TickInfo {
|
||||
.delta_time = now - last_tick.end_time,
|
||||
.budget = std::chrono::milliseconds { 10 },
|
||||
.start_time = now,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_registered)
|
||||
{
|
||||
m_systems.emplace_back(system)->on_register();
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_unregistered)
|
||||
{
|
||||
m_systems.erase(
|
||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||
m_systems.end()
|
||||
);
|
||||
}
|
||||
|
||||
if (m_systems.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::register_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
void Application::unregister_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems_to_be_unregistered.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
} // namespace lt::app
|
||||
31
modules/app/entrypoint.cpp
Normal file
31
modules/app/entrypoint.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import memory.scope;
|
||||
import logger;
|
||||
import app;
|
||||
import std;
|
||||
|
||||
/** The ultimate entrypoint. */
|
||||
auto main(int argc, char *argv[]) -> std::int32_t
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore = argc;
|
||||
std::ignore = argv;
|
||||
|
||||
auto application = lt::memory::Scope<lt::app::Application> {};
|
||||
application = lt::app::create_application();
|
||||
if (!application)
|
||||
{
|
||||
throw std::runtime_error { "Failed to create application\n" };
|
||||
}
|
||||
|
||||
application->game_loop();
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what(): {}", exp.what());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#include <app/application.hpp>
|
||||
#include <app/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
void Application::game_loop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (auto &system : m_systems)
|
||||
{
|
||||
const auto &last_tick = system->get_last_tick_result();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
|
||||
system->tick(
|
||||
TickInfo {
|
||||
.delta_time = now - last_tick.end_time,
|
||||
.budget = std::chrono::milliseconds { 10 },
|
||||
.start_time = now,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_registered)
|
||||
{
|
||||
m_systems.emplace_back(system)->on_register();
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_unregistered)
|
||||
{
|
||||
m_systems.erase(
|
||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||
m_systems.end()
|
||||
);
|
||||
}
|
||||
|
||||
if (m_systems.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::register_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
void Application::unregister_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems_to_be_unregistered.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
} // namespace lt::app
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
class ISystem;
|
||||
|
||||
extern memory::Scope<class Application> create_application();
|
||||
|
||||
/** The main application class.
|
||||
* Think of this like an aggregate of systems, you register systems through this interface.
|
||||
* Then they'll tick every "application frame".
|
||||
*/
|
||||
class Application
|
||||
{
|
||||
public:
|
||||
Application(const Application &) = delete;
|
||||
|
||||
Application(Application &&) = delete;
|
||||
|
||||
auto operator=(const Application &) -> Application & = delete;
|
||||
|
||||
auto operator=(Application &&) -> Application & = delete;
|
||||
|
||||
virtual ~Application() = default;
|
||||
|
||||
void game_loop();
|
||||
|
||||
void register_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
void unregister_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
protected:
|
||||
Application() = default;
|
||||
|
||||
private:
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_unregistered;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_registered;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::app
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/application.hpp>
|
||||
#include <logger/logger.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
auto main(int argc, char *argv[]) -> int32_t
|
||||
try
|
||||
{
|
||||
std::ignore = argc;
|
||||
std::ignore = argv;
|
||||
|
||||
auto application = lt::memory::Scope<lt::app::Application> {};
|
||||
application = lt::app::create_application();
|
||||
if (!application)
|
||||
{
|
||||
throw std::runtime_error { "Failed to create application\n" };
|
||||
}
|
||||
|
||||
application->game_loop();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what(): {}", exp.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <logger/logger.hpp>
|
||||
export module app.system;
|
||||
import logger;
|
||||
import std;
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
/** Information required to tick a system.
|
||||
* @note May be used across an entire application-frame (consisting of multiple systems ticking)
|
||||
*/
|
||||
struct TickInfo
|
||||
export struct TickInfo
|
||||
{
|
||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ struct TickInfo
|
|||
};
|
||||
|
||||
/** Information about how a system's tick performed */
|
||||
struct TickResult
|
||||
export struct TickResult
|
||||
{
|
||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
|
|
@ -47,10 +46,9 @@ struct TickResult
|
|||
Timepoint_T end_time;
|
||||
};
|
||||
|
||||
|
||||
struct SystemDiagnosis
|
||||
export struct SystemDiagnosis
|
||||
{
|
||||
enum class Severity : uint8_t
|
||||
enum class Severity : std::uint8_t
|
||||
{
|
||||
verbose,
|
||||
info,
|
||||
|
|
@ -66,7 +64,7 @@ struct SystemDiagnosis
|
|||
Severity severity;
|
||||
};
|
||||
|
||||
class SystemStats
|
||||
export class SystemStats
|
||||
{
|
||||
public:
|
||||
void push_diagnosis(SystemDiagnosis &&diagnosis)
|
||||
|
|
@ -85,7 +83,7 @@ private:
|
|||
std::vector<SystemDiagnosis> m_diagnosis;
|
||||
};
|
||||
|
||||
class ISystem
|
||||
export class ISystem
|
||||
{
|
||||
public:
|
||||
ISystem() = default;
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
add_library_module(libasset_baker bakers.cpp)
|
||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug tbb)
|
||||
add_test_module(libasset_baker bakers.test.cpp)
|
||||
add_library_module(NAME libasset_baker INTERFACES bakers.cppm)
|
||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug)
|
||||
|
||||
add_executable_module(asset_baker entrypoint/baker.cpp)
|
||||
add_executable(asset_baker entrypoint.cpp)
|
||||
target_link_libraries(asset_baker PRIVATE libasset_baker)
|
||||
|
|
|
|||
68
modules/asset_baker/bakers.cppm
Normal file
68
modules/asset_baker/bakers.cppm
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
export module bakers;
|
||||
|
||||
import debug.assertions;
|
||||
import assets.metadata;
|
||||
import assets.shader;
|
||||
import logger;
|
||||
import std;
|
||||
|
||||
export void bake_shader(
|
||||
const std::filesystem::path &in_path,
|
||||
const std::filesystem::path &out_path,
|
||||
lt::assets::ShaderAsset::Type type
|
||||
)
|
||||
{
|
||||
using lt::assets::ShaderAsset;
|
||||
using enum lt::assets::ShaderAsset::Type;
|
||||
|
||||
auto glsl_path = in_path.string();
|
||||
auto spv_path = std::format("{}.spv", glsl_path);
|
||||
lt::log::trace(
|
||||
"Compiling {} shader {} -> {}",
|
||||
type == vertex ? "vertex" : "fragment",
|
||||
glsl_path,
|
||||
spv_path
|
||||
);
|
||||
|
||||
// Don't bother linking to shaderc, just invoke the command with a system call.
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
std::system(
|
||||
std::format(
|
||||
"glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
glsl_path,
|
||||
spv_path
|
||||
)
|
||||
.c_str()
|
||||
);
|
||||
|
||||
auto stream = std::ifstream(spv_path, std::ios::binary);
|
||||
lt::debug::ensure(
|
||||
stream.is_open(),
|
||||
"Failed to open compiled {} shader at: {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
spv_path
|
||||
);
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const auto size = stream.tellg();
|
||||
|
||||
auto bytes = std::vector<std::byte>(size);
|
||||
stream.seekg(0, std::ios::beg);
|
||||
stream.read((char *)bytes.data(), size); // NOLINT
|
||||
lt::log::debug("BYTES: {}", bytes.size());
|
||||
stream.close();
|
||||
std::filesystem::remove(spv_path);
|
||||
|
||||
ShaderAsset::pack(
|
||||
out_path,
|
||||
lt::assets::AssetMetadata {
|
||||
.version = lt::assets::current_version,
|
||||
.type = ShaderAsset::asset_type_identifier,
|
||||
},
|
||||
ShaderAsset::Metadata {
|
||||
.type = type,
|
||||
},
|
||||
std::move(bytes)
|
||||
);
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
#include <asset_baker/bakers.hpp>
|
||||
#include <assets/shader.hpp>
|
||||
#include <logger/logger.hpp>
|
||||
import assets.shader;
|
||||
import logger;
|
||||
import bakers;
|
||||
import std;
|
||||
|
||||
auto main(int argc, char *argv[]) -> int32_t
|
||||
|
||||
auto main(int argc, char *argv[]) -> std::int32_t
|
||||
try
|
||||
{
|
||||
if (argc != 2)
|
||||
|
|
@ -31,12 +33,12 @@ try
|
|||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what: {}:", exp.what());
|
||||
|
||||
return EXIT_FAILURE;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include <asset_baker/bakers.hpp>
|
||||
#include <test/test.hpp>
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/shader.hpp>
|
||||
#include <logger/logger.hpp>
|
||||
|
||||
inline void bake_shader(
|
||||
const std::filesystem::path &in_path,
|
||||
|
|
@ -34,7 +32,7 @@ inline void bake_shader(
|
|||
);
|
||||
|
||||
auto stream = std::ifstream(spv_path, std::ios::binary);
|
||||
lt::ensure(
|
||||
lt::debug::ensure(
|
||||
stream.is_open(),
|
||||
"Failed to open compiled {} shader at: {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
add_library_module(assets shader.cpp)
|
||||
|
||||
add_library_module(NAME assets INTERFACES shader.cppm metadata.cppm)
|
||||
target_link_libraries(assets PUBLIC logger lt_debug)
|
||||
|
||||
add_test_module(assets shader.test.cpp)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
#pragma once
|
||||
export module assets.metadata;
|
||||
import std;
|
||||
|
||||
namespace lt::assets {
|
||||
export namespace lt::assets {
|
||||
|
||||
using Type_T = std::array<const char, 16>;
|
||||
|
||||
using Tag_T = uint8_t;
|
||||
using Tag_T = std::uint8_t;
|
||||
|
||||
using Version = uint8_t;
|
||||
using Version = std::uint8_t;
|
||||
|
||||
using Blob = std::vector<std::byte>;
|
||||
|
||||
constexpr auto current_version = Version { 1u };
|
||||
|
||||
enum class CompressionType : uint8_t
|
||||
enum class CompressionType : std::uint8_t
|
||||
{
|
||||
none,
|
||||
lz4,
|
||||
|
|
@ -30,13 +31,13 @@ struct BlobMetadata
|
|||
{
|
||||
Tag_T tag;
|
||||
|
||||
size_t offset;
|
||||
std::size_t offset;
|
||||
|
||||
CompressionType compression_type;
|
||||
|
||||
size_t compressed_size;
|
||||
std::size_t compressed_size;
|
||||
|
||||
size_t uncompressed_size;
|
||||
std::size_t uncompressed_size;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// TO BE DOOO
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/metadata.hpp>
|
||||
|
||||
namespace lt::assets {
|
||||
|
||||
class ShaderAsset
|
||||
{
|
||||
public:
|
||||
static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
|
||||
|
||||
enum class BlobTag : Tag_T
|
||||
{
|
||||
code,
|
||||
};
|
||||
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
vertex,
|
||||
fragment,
|
||||
geometry,
|
||||
compute,
|
||||
};
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
Type type;
|
||||
};
|
||||
|
||||
static void pack(
|
||||
const std::filesystem::path &destination,
|
||||
AssetMetadata asset_metadata,
|
||||
Metadata metadata,
|
||||
Blob code_blob
|
||||
);
|
||||
|
||||
ShaderAsset(const std::filesystem::path &path);
|
||||
|
||||
void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
|
||||
|
||||
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
|
||||
|
||||
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
|
||||
{
|
||||
return m_asset_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_metadata() const -> const Metadata &
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
|
||||
{
|
||||
ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
return m_code_blob_metadata;
|
||||
}
|
||||
|
||||
private:
|
||||
AssetMetadata m_asset_metadata {};
|
||||
|
||||
Metadata m_metadata {};
|
||||
|
||||
BlobMetadata m_code_blob_metadata {};
|
||||
|
||||
mutable std::ifstream m_stream;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
|
|
@ -1,4 +1,80 @@
|
|||
#include <assets/shader.hpp>
|
||||
export module assets.shader;
|
||||
import assets.metadata;
|
||||
import debug.assertions;
|
||||
|
||||
import std;
|
||||
|
||||
export namespace lt::assets {
|
||||
|
||||
class ShaderAsset
|
||||
{
|
||||
public:
|
||||
static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
|
||||
|
||||
enum class BlobTag : Tag_T
|
||||
{
|
||||
code,
|
||||
};
|
||||
|
||||
enum class Type : std::uint8_t
|
||||
{
|
||||
vertex,
|
||||
fragment,
|
||||
geometry,
|
||||
compute,
|
||||
};
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
Type type;
|
||||
};
|
||||
|
||||
static void pack(
|
||||
const std::filesystem::path &destination,
|
||||
AssetMetadata asset_metadata,
|
||||
Metadata metadata,
|
||||
Blob code_blob
|
||||
);
|
||||
|
||||
ShaderAsset(const std::filesystem::path &path);
|
||||
|
||||
void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
|
||||
|
||||
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
|
||||
|
||||
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
|
||||
{
|
||||
return m_asset_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_metadata() const -> const Metadata &
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
|
||||
{
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
return m_code_blob_metadata;
|
||||
}
|
||||
|
||||
private:
|
||||
AssetMetadata m_asset_metadata {};
|
||||
|
||||
Metadata m_metadata {};
|
||||
|
||||
BlobMetadata m_code_blob_metadata {};
|
||||
|
||||
mutable std::ifstream m_stream;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
|
||||
|
||||
namespace lt::assets {
|
||||
|
||||
|
|
@ -14,14 +90,14 @@ constexpr auto total_metadata_size = //
|
|||
|
||||
ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
||||
{
|
||||
ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
|
||||
debug::ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
|
||||
const auto read = [this](auto &field) {
|
||||
m_stream.read(std::bit_cast<char *>(&field), sizeof(field));
|
||||
};
|
||||
|
||||
m_stream.seekg(0, std::ifstream::end);
|
||||
const auto file_size = static_cast<size_t>(m_stream.tellg());
|
||||
ensure(
|
||||
const auto file_size = static_cast<std::size_t>(m_stream.tellg());
|
||||
debug::ensure(
|
||||
file_size > total_metadata_size,
|
||||
"Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
|
||||
path.string(),
|
||||
|
|
@ -39,7 +115,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
read(m_code_blob_metadata.compressed_size);
|
||||
read(m_code_blob_metadata.uncompressed_size);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_asset_metadata.type == asset_type_identifier,
|
||||
"Failed to open shader asset at: {}, incorrect asset type: {} != {}",
|
||||
path.string(),
|
||||
|
|
@ -47,7 +123,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
asset_type_identifier
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_asset_metadata.version == current_version,
|
||||
"Failed to open shader asset at: {}, version mismatch: {} != {}",
|
||||
path.string(),
|
||||
|
|
@ -55,21 +131,21 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
current_version
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
std::to_underlying(m_metadata.type) <= std::to_underlying(Type::compute),
|
||||
"Failed to open shader asset at: {}, invalid shader type: {}",
|
||||
path.string(),
|
||||
std::to_underlying(m_metadata.type)
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_code_blob_metadata.tag == std::to_underlying(BlobTag::code),
|
||||
"Failed to open shader asset at: {}, invalid blob tag: {}",
|
||||
path.string(),
|
||||
m_code_blob_metadata.tag
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_code_blob_metadata.offset + m_code_blob_metadata.compressed_size <= file_size,
|
||||
"Failed to open shader asset at: {}, file smaller than blob: {} > {} + {}",
|
||||
path.string(),
|
||||
|
|
@ -99,7 +175,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
.uncompressed_size = code_blob.size(),
|
||||
};
|
||||
|
||||
ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
|
||||
debug::ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
|
||||
const auto write = [&stream](auto &field) {
|
||||
stream.write(std::bit_cast<char *>(&field), sizeof(field));
|
||||
};
|
||||
|
|
@ -116,14 +192,18 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
|
||||
void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
||||
{
|
||||
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
destination.size() >= m_code_blob_metadata.uncompressed_size,
|
||||
"Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
|
||||
"than the blobl's uncompressed size: {}",
|
||||
std::to_underlying(tag),
|
||||
std::bit_cast<size_t>(destination.data()),
|
||||
std::bit_cast<std::size_t>(destination.data()),
|
||||
destination.size(),
|
||||
m_code_blob_metadata.uncompressed_size
|
||||
);
|
||||
|
|
@ -137,7 +217,11 @@ void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
|||
|
||||
[[nodiscard]] auto ShaderAsset::unpack(BlobTag tag) const -> Blob
|
||||
{
|
||||
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
auto blob = Blob(m_code_blob_metadata.uncompressed_size);
|
||||
unpack_to(tag, blob);
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
#include <assets/shader.hpp>
|
||||
#include <ranges>
|
||||
#include <test/test.hpp>
|
||||
import assets.metadata;
|
||||
import assets.shader;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
|
||||
using ::lt::assets::AssetMetadata;
|
||||
using ::lt::assets::BlobMetadata;
|
||||
|
|
@ -10,6 +12,7 @@ using ::lt::test::expect_eq;
|
|||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
const auto test_data_path = std::filesystem::path { "./data/test_assets" };
|
||||
const auto tmp_path = std::filesystem::path { "/tmp/lt_assets_tests/" };
|
||||
|
|
@ -70,7 +73,7 @@ Suite packing = "shader_pack"_suite = [] {
|
|||
expect_true(stream.is_open());
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const auto file_size = static_cast<size_t>(stream.tellg());
|
||||
const auto file_size = static_cast<std::size_t>(stream.tellg());
|
||||
expect_eq(file_size, expected_size);
|
||||
stream.close();
|
||||
|
||||
|
|
@ -1 +1 @@
|
|||
add_library_module(bitwise)
|
||||
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
export module bitwise;
|
||||
import std;
|
||||
|
||||
namespace lt::bitwise {
|
||||
|
||||
/* bit-wise */
|
||||
constexpr auto bit(uint32_t x) -> uint32_t
|
||||
constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
||||
{
|
||||
return 1u << x;
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
add_library_module(camera)
|
||||
add_library_module(NAME camera INTERFACES components.cppm)
|
||||
|
||||
target_link_libraries(camera INTERFACE math)
|
||||
target_link_libraries(camera PUBLIC math)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/mat4.hpp>
|
||||
export module camera.components;
|
||||
import math.vec4;
|
||||
|
||||
namespace lt::camera::components {
|
||||
|
||||
struct PerspectiveCamera
|
||||
export struct PerspectiveCamera
|
||||
{
|
||||
float vertical_fov {};
|
||||
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
add_library_module(lt_debug instrumentor.cpp)
|
||||
add_library_module(NAME lt_debug INTERFACES instrumentor.cppm assertions.cppm)
|
||||
target_link_libraries(lt_debug PUBLIC logger)
|
||||
target_precompile_headers(lt_debug PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
|
||||
|
|
|
|||
47
modules/debug/assertions.cppm
Normal file
47
modules/debug/assertions.cppm
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
export module debug.assertions;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::debug {
|
||||
|
||||
///////////////////////////////////////
|
||||
// ----------* INTERFACE *--------- //
|
||||
/////////////////////////////////////
|
||||
export template<typename Expression_T, typename... Args_T>
|
||||
struct ensure
|
||||
{
|
||||
ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
);
|
||||
};
|
||||
|
||||
export template<typename Expression_T, typename... Args_T>
|
||||
ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
|
||||
-> ensure<Expression_T, Args_T...>;
|
||||
|
||||
///////////////////////////////////////
|
||||
// * IMPLEMENTATION -- TEMPLATES * //
|
||||
/////////////////////////////////////
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
ensure<Expression_T, Args_T...>::ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location
|
||||
)
|
||||
{
|
||||
if (!static_cast<bool>(expression))
|
||||
{
|
||||
throw std::runtime_error { std::format(
|
||||
"exception: {}\nlocation: {}:{}",
|
||||
std::format(fmt, std::forward<Args_T>(args)...),
|
||||
location.file_name(),
|
||||
location.line()
|
||||
) };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::debug
|
||||
|
|
@ -1,7 +1,83 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <lt_debug/instrumentor.hpp>
|
||||
export module debug.instrumentor;
|
||||
|
||||
namespace lt {
|
||||
import std;
|
||||
import logger;
|
||||
|
||||
namespace lt::debug {
|
||||
|
||||
struct ScopeProfileResult
|
||||
{
|
||||
std::string name;
|
||||
long long start, duration;
|
||||
std::uint32_t threadID;
|
||||
};
|
||||
|
||||
class Instrumentor
|
||||
{
|
||||
public:
|
||||
static auto instance() -> Instrumentor &
|
||||
{
|
||||
static auto instance = Instrumentor {};
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void begin_session(const std::string &outputPath)
|
||||
{
|
||||
instance().begin_session_impl(outputPath);
|
||||
}
|
||||
static void end_session()
|
||||
{
|
||||
instance().end_session_impl();
|
||||
}
|
||||
|
||||
static void submit_scope_profile(const ScopeProfileResult &profileResult)
|
||||
{
|
||||
instance().submit_scope_profile_impl(profileResult);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream m_output_file_stream;
|
||||
|
||||
unsigned int m_current_session_count { 0u };
|
||||
|
||||
Instrumentor() = default;
|
||||
|
||||
void begin_session_impl(const std::string &outputPath);
|
||||
|
||||
void end_session_impl();
|
||||
|
||||
void submit_scope_profile_impl(const ScopeProfileResult &profileResult);
|
||||
};
|
||||
|
||||
class InstrumentorTimer
|
||||
{
|
||||
public:
|
||||
InstrumentorTimer(const std::string &scopeName);
|
||||
|
||||
~InstrumentorTimer();
|
||||
|
||||
private:
|
||||
ScopeProfileResult m_result;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start;
|
||||
};
|
||||
|
||||
} // namespace lt::debug
|
||||
|
||||
/* scope */
|
||||
#define lt_profile_scope(name) lt_profile_scope_no_redifinition(name, __LINE__)
|
||||
#define lt_profile_scope_no_redifinition(name, line) lt_profile_scope_no_redifinition2(name, line)
|
||||
#define lt_profile_scope_no_redifinition2(name, line) InstrumentorTimer timer##line(name)
|
||||
|
||||
/* function */
|
||||
#define LT_PROFILE_FUNCTION lt_profile_scope(__FUNCSIG__)
|
||||
|
||||
/* session */
|
||||
#define lt_profile_begin_session(outputPath) ::lt::Instrumentor::begin_session(outputPath)
|
||||
#define lt_profile_end_session() ::lt::Instrumentor::end_session()
|
||||
|
||||
module :private;
|
||||
using namespace lt::debug;
|
||||
|
||||
void Instrumentor::begin_session_impl(const std::string &outputPath)
|
||||
{
|
||||
|
|
@ -67,5 +143,3 @@ InstrumentorTimer::~InstrumentorTimer()
|
|||
|
||||
Instrumentor::submit_scope_profile(m_result);
|
||||
}
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <lt_debug/assertions.hpp>
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <source_location>
|
||||
|
||||
namespace lt {
|
||||
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
struct ensure
|
||||
{
|
||||
ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
)
|
||||
{
|
||||
if (!static_cast<bool>(expression))
|
||||
{
|
||||
throw std::runtime_error { std::format(
|
||||
"exception: {}\nlocation: {}:{}",
|
||||
std::format(fmt, std::forward<Args_T>(args)...),
|
||||
location.file_name(),
|
||||
location.line()
|
||||
) };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
|
||||
-> ensure<Expression_T, Args_T...>;
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
namespace lt {
|
||||
|
||||
struct ScopeProfileResult
|
||||
{
|
||||
std::string name;
|
||||
long long start, duration;
|
||||
uint32_t threadID;
|
||||
};
|
||||
|
||||
class Instrumentor
|
||||
{
|
||||
public:
|
||||
static auto instance() -> Instrumentor &
|
||||
{
|
||||
static auto instance = Instrumentor {};
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void begin_session(const std::string &outputPath)
|
||||
{
|
||||
instance().begin_session_impl(outputPath);
|
||||
}
|
||||
static void end_session()
|
||||
{
|
||||
instance().end_session_impl();
|
||||
}
|
||||
|
||||
static void submit_scope_profile(const ScopeProfileResult &profileResult)
|
||||
{
|
||||
instance().submit_scope_profile_impl(profileResult);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream m_output_file_stream;
|
||||
|
||||
unsigned int m_current_session_count { 0u };
|
||||
|
||||
Instrumentor() = default;
|
||||
|
||||
void begin_session_impl(const std::string &outputPath);
|
||||
|
||||
void end_session_impl();
|
||||
|
||||
void submit_scope_profile_impl(const ScopeProfileResult &profileResult);
|
||||
};
|
||||
|
||||
class InstrumentorTimer
|
||||
{
|
||||
public:
|
||||
InstrumentorTimer(const std::string &scopeName);
|
||||
|
||||
~InstrumentorTimer();
|
||||
|
||||
private:
|
||||
ScopeProfileResult m_result;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start;
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
|
||||
/* scope */
|
||||
#define lt_profile_scope(name) lt_profile_scope_no_redifinition(name, __LINE__)
|
||||
#define lt_profile_scope_no_redifinition(name, line) lt_profile_scope_no_redifinition2(name, line)
|
||||
#define lt_profile_scope_no_redifinition2(name, line) InstrumentorTimer timer##line(name)
|
||||
|
||||
/* function */
|
||||
#define LT_PROFILE_FUNCTION lt_profile_scope(__FUNCSIG__)
|
||||
|
||||
/* session */
|
||||
#define lt_profile_begin_session(outputPath) ::lt::Instrumentor::begin_session(outputPath)
|
||||
#define lt_profile_end_session() ::lt::Instrumentor::end_session()
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
add_library_module(ecs sparse_set.cpp)
|
||||
add_library_module(NAME ecs INTERFACES sparse_set.cppm registry.cppm
|
||||
entity.cppm)
|
||||
target_link_libraries(ecs PUBLIC logger lt_debug memory)
|
||||
|
||||
add_test_module(ecs sparse_set.test.cpp registry.test.cpp)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
export module ecs.entity;
|
||||
import debug.assertions;
|
||||
import memory.reference;
|
||||
import ecs.registry;
|
||||
import std;
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
/** High-level entity convenience wrapper */
|
||||
class Entity
|
||||
export class Entity
|
||||
{
|
||||
public:
|
||||
Entity(memory::Ref<Registry> registry, EntityId identifier)
|
||||
: m_registry(std::move(registry))
|
||||
, m_identifier(identifier)
|
||||
{
|
||||
ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
|
||||
debug::ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
|
||||
}
|
||||
|
||||
template<typename Component_T>
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/sparse_set.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
export module ecs.registry;
|
||||
import debug.assertions;
|
||||
import ecs.sparse_set;
|
||||
import memory.scope;
|
||||
import std;
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
using EntityId = uint32_t;
|
||||
export using EntityId = std::uint32_t;
|
||||
|
||||
constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
||||
export constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
||||
|
||||
/** A registry of components, the heart of an ECS architecture.
|
||||
*
|
||||
|
|
@ -22,7 +23,7 @@ constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
|||
* @ref https://github.com/skypjack/entt
|
||||
* @ref https://github.com/SanderMertens/flecs
|
||||
*/
|
||||
class Registry
|
||||
export class Registry
|
||||
{
|
||||
public:
|
||||
using UnderlyingSparseSet_T = TypeErasedSparseSet<EntityId>;
|
||||
|
|
@ -189,25 +190,25 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] auto get_entity_count() const -> size_t
|
||||
[[nodiscard]] auto get_entity_count() const -> std::size_t
|
||||
{
|
||||
return static_cast<size_t>(m_entity_count);
|
||||
return static_cast<std::size_t>(m_entity_count);
|
||||
}
|
||||
|
||||
private:
|
||||
using TypeId = size_t;
|
||||
using TypeId = std::size_t;
|
||||
|
||||
static consteval auto hash_cstr(const char *str) -> TypeId
|
||||
{
|
||||
constexpr auto fnv_offset_basis = size_t { 14695981039346656037ull };
|
||||
constexpr auto fnv_prime = size_t { 1099511628211ull };
|
||||
constexpr auto fnv_offset_basis = std::size_t { 14695981039346656037ull };
|
||||
constexpr auto fnv_prime = std::size_t { 1099511628211ull };
|
||||
|
||||
auto hash = fnv_offset_basis;
|
||||
|
||||
for (const auto &ch : std::string_view { str })
|
||||
{
|
||||
hash *= fnv_prime;
|
||||
hash ^= static_cast<uint8_t>(ch);
|
||||
hash ^= static_cast<std::uint8_t>(ch);
|
||||
}
|
||||
|
||||
return hash;
|
||||
|
|
@ -241,7 +242,7 @@ private:
|
|||
|
||||
auto *base_set = m_sparsed_sets[type_id].get();
|
||||
auto *derived_set = dynamic_cast<SparseSet<T, EntityId> *>(base_set);
|
||||
ensure(derived_set, "Failed to downcast to derived set");
|
||||
debug::ensure(derived_set, "Failed to downcast to derived set");
|
||||
|
||||
return *derived_set;
|
||||
}
|
||||
|
|
@ -1,19 +1,17 @@
|
|||
#include <ecs/registry.hpp>
|
||||
#include <ranges>
|
||||
#include <test/expects.hpp>
|
||||
#include <test/test.hpp>
|
||||
import ecs.registry;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
|
||||
using lt::test::Case;
|
||||
using lt::test::expect_unreachable;
|
||||
using lt::test::Suite;
|
||||
|
||||
using lt::test::expect_eq;
|
||||
|
||||
using lt::test::expect_false;
|
||||
using lt::test::expect_true;
|
||||
|
||||
using lt::ecs::EntityId;
|
||||
using lt::ecs::Registry;
|
||||
using ::lt::ecs::EntityId;
|
||||
using ::lt::ecs::Registry;
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::expect_unreachable;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
struct Component
|
||||
{
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
#pragma once
|
||||
export module ecs.sparse_set;
|
||||
import debug.assertions;
|
||||
import std;
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
/**
|
||||
*
|
||||
* @ref https://programmingpraxis.com/2012/03/09/sparse-sets/
|
||||
*/
|
||||
template<typename Identifier_T = uint32_t>
|
||||
export template<typename Identifier_T = std::uint32_t>
|
||||
class TypeErasedSparseSet
|
||||
{
|
||||
public:
|
||||
|
|
@ -25,19 +26,19 @@ public:
|
|||
virtual void remove(Identifier_T identifier) = 0;
|
||||
};
|
||||
|
||||
template<typename Value_T, typename Identifier_T = uint32_t>
|
||||
export template<typename Value_T, typename Identifier_T = std::uint32_t>
|
||||
class SparseSet: public TypeErasedSparseSet<Identifier_T>
|
||||
{
|
||||
public:
|
||||
using Dense_T = std::pair<Identifier_T, Value_T>;
|
||||
|
||||
static constexpr auto max_capacity = size_t { 1'000'000 };
|
||||
static constexpr auto max_capacity = std::size_t { 1'000'000 };
|
||||
|
||||
static constexpr auto null_identifier = std::numeric_limits<Identifier_T>().max();
|
||||
|
||||
explicit SparseSet(size_t initial_capacity = 1)
|
||||
explicit SparseSet(std::size_t initial_capacity = 1)
|
||||
{
|
||||
ensure(
|
||||
debug::ensure(
|
||||
initial_capacity <= max_capacity,
|
||||
"Failed to create SparseSet: capacity too large ({} > {})",
|
||||
initial_capacity,
|
||||
|
|
@ -52,7 +53,10 @@ public:
|
|||
{
|
||||
if (m_sparse.size() < identifier + 1)
|
||||
{
|
||||
auto new_capacity = std::max(static_cast<size_t>(identifier + 1), m_sparse.size() * 2);
|
||||
auto new_capacity = std::max(
|
||||
static_cast<std::size_t>(identifier + 1),
|
||||
m_sparse.size() * 2
|
||||
);
|
||||
new_capacity = std::min(new_capacity, max_capacity);
|
||||
|
||||
// log::debug("Increasing sparse vector size:", m_dead_count);
|
||||
|
|
@ -145,12 +149,12 @@ public:
|
|||
return std::forward<Self_T>(self).m_dense[std::forward<Self_T>(self).m_sparse[identifier]];
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const noexcept -> size_t
|
||||
[[nodiscard]] auto get_size() const noexcept -> std::size_t
|
||||
{
|
||||
return m_alive_count;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_capacity() const noexcept -> size_t
|
||||
[[nodiscard]] auto get_capacity() const noexcept -> std::size_t
|
||||
{
|
||||
return m_sparse.capacity();
|
||||
}
|
||||
|
|
@ -165,9 +169,9 @@ private:
|
|||
|
||||
std::vector<Identifier_T> m_sparse;
|
||||
|
||||
size_t m_alive_count {};
|
||||
std::size_t m_alive_count {};
|
||||
|
||||
size_t m_dead_count {};
|
||||
std::size_t m_dead_count {};
|
||||
};
|
||||
|
||||
} // namespace lt::ecs
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
#include <ecs/sparse_set.hpp>
|
||||
#include <ranges>
|
||||
#include <test/expects.hpp>
|
||||
#include <test/test.hpp>
|
||||
import ecs.sparse_set;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
|
||||
using lt::test::Case;
|
||||
using lt::test::Suite;
|
||||
|
||||
using lt::test::expect_eq;
|
||||
using lt::test::expect_false;
|
||||
using lt::test::expect_ne;
|
||||
using lt::test::expect_throw;
|
||||
using lt::test::expect_true;
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_ne;
|
||||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
using Set = lt::ecs::SparseSet<int>;
|
||||
constexpr auto capacity = 100;
|
||||
2
modules/env/CMakeLists.txt
vendored
2
modules/env/CMakeLists.txt
vendored
|
|
@ -1 +1 @@
|
|||
add_library_module(env)
|
||||
add_library_module(NAME env INTERFACES constants.cppm)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
export module env;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt {
|
||||
|
||||
enum class Platform : uint8_t
|
||||
enum class Platform : std::uint8_t
|
||||
{
|
||||
/** The GNU/Linux platform.
|
||||
* Tested on the following distros: arch-x86_64
|
||||
|
|
@ -24,7 +26,7 @@ enum class Platform : uint8_t
|
|||
};
|
||||
|
||||
/** The compiler that was used for compiling the project. */
|
||||
enum class Compiler : uint8_t
|
||||
enum class Compiler : std::uint8_t
|
||||
{
|
||||
clang,
|
||||
gcc,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
add_library_module(input system.cpp)
|
||||
add_library_module(NAME input INTERFACES system.cpp)
|
||||
target_link_libraries(input PUBLIC surface math logger tbb)
|
||||
|
||||
add_test_module(input system.test.cpp)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::Key {
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
|
|
@ -177,4 +176,21 @@ enum : uint16_t
|
|||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
enum : uint8_t
|
||||
{
|
||||
Button1 = 0,
|
||||
Button2 = 1,
|
||||
Button3 = 2,
|
||||
Button4 = 3,
|
||||
Button5 = 4,
|
||||
Button6 = 5,
|
||||
Button7 = 6,
|
||||
Button8 = 7,
|
||||
|
||||
LButton = Button1,
|
||||
RButton = Button2,
|
||||
MButton = Button3,
|
||||
};
|
||||
|
||||
} // namespace lt::Key
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#pragma once
|
||||
export module input.components;
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::Mouse {
|
||||
|
||||
enum : uint8_t
|
||||
{
|
||||
Button1 = 0,
|
||||
Button2 = 1,
|
||||
Button3 = 2,
|
||||
Button4 = 3,
|
||||
Button5 = 4,
|
||||
Button6 = 5,
|
||||
Button7 = 6,
|
||||
Button8 = 7,
|
||||
|
||||
LButton = Button1,
|
||||
RButton = Button2,
|
||||
MButton = Button3,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
System(memory::Ref<ecs::Registry> registry);
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_event(const surface::SurfaceComponent::Event &event);
|
||||
|
||||
void on_surface_lost_focus();
|
||||
|
||||
void on_key_press(const lt::surface::KeyPressedEvent &event);
|
||||
|
||||
void on_key_release(const lt::surface::KeyReleasedEvent &event);
|
||||
|
||||
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
|
||||
|
||||
void on_button_press(const lt::surface::ButtonPressedEvent &event);
|
||||
|
||||
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::array<bool, 512> m_keys {};
|
||||
|
||||
std::array<bool, 512> m_buttons {};
|
||||
|
||||
math::vec2 m_pointer_position;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::input
|
||||
|
|
@ -1,3 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
System(memory::Ref<ecs::Registry> registry);
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_event(const surface::SurfaceComponent::Event &event);
|
||||
|
||||
void on_surface_lost_focus();
|
||||
|
||||
void on_key_press(const lt::surface::KeyPressedEvent &event);
|
||||
|
||||
void on_key_release(const lt::surface::KeyReleasedEvent &event);
|
||||
|
||||
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
|
||||
|
||||
void on_button_press(const lt::surface::ButtonPressedEvent &event);
|
||||
|
||||
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::array<bool, 512> m_keys {};
|
||||
|
||||
std::array<bool, 512> m_buttons {};
|
||||
|
||||
math::vec2 m_pointer_position;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::input
|
||||
|
||||
|
||||
module :private;
|
||||
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
add_library_module(logger)
|
||||
add_test_module(logger logger.test.cpp)
|
||||
add_library_module(NAME logger INTERFACES logger.cppm)
|
||||
# add_test_module(logger logger.test.cpp)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,11 @@
|
|||
#pragma once
|
||||
export module logger;
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fmt/chrono.h>
|
||||
#include <fmt/format.h>
|
||||
#include <source_location>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
import std;
|
||||
|
||||
namespace lt::log {
|
||||
|
||||
/** Severity of a log message. */
|
||||
enum class Level : uint8_t
|
||||
enum class Level : std::uint8_t
|
||||
{
|
||||
/** Lowest and most vebose log level, for tracing execution paths and events */
|
||||
trace = 0,
|
||||
|
|
@ -87,7 +81,7 @@ template<typename... Args>
|
|||
print(Level, const std::source_location &, std::format_string<Args...>, Args &&...) noexcept
|
||||
-> print<Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] trace
|
||||
{
|
||||
[[maybe_unused]] trace(
|
||||
|
|
@ -100,10 +94,10 @@ struct [[maybe_unused]] trace
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
trace(std::format_string<Args...>, Args &&...) noexcept -> trace<Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] debug
|
||||
{
|
||||
[[maybe_unused]] debug(
|
||||
|
|
@ -116,10 +110,10 @@ struct [[maybe_unused]] debug
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
debug(std::format_string<Args...>, Args &&...) noexcept -> debug<Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] info
|
||||
{
|
||||
[[maybe_unused]] info(
|
||||
|
|
@ -132,10 +126,10 @@ struct [[maybe_unused]] info
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
info(std::format_string<Args...>, Args &&...) noexcept -> info<Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] warn
|
||||
{
|
||||
[[maybe_unused]] warn(
|
||||
|
|
@ -148,10 +142,10 @@ struct [[maybe_unused]] warn
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
warn(std::format_string<Args...>, Args &&...) noexcept -> warn<Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] error
|
||||
{
|
||||
[[maybe_unused]] error(
|
||||
|
|
@ -164,10 +158,10 @@ struct [[maybe_unused]] error
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
error(std::format_string<Args...>, Args &&...) noexcept -> error<Args...>;
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] critical
|
||||
{
|
||||
[[maybe_unused]] critical(
|
||||
|
|
@ -180,7 +174,7 @@ struct [[maybe_unused]] critical
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
export template<typename... Args>
|
||||
critical(std::format_string<Args...>, Args &&...) noexcept -> critical<Args...>;
|
||||
|
||||
} // namespace lt::log
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <test/test.hpp>
|
||||
import logger;
|
||||
import test;
|
||||
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::Suite;
|
||||
|
|
@ -1 +1,11 @@
|
|||
add_library_module(math)
|
||||
add_library_module(
|
||||
NAME
|
||||
math
|
||||
INTERFACES
|
||||
algebra.cppm
|
||||
mat4.cppm
|
||||
trig.cppm
|
||||
vec2.cppm
|
||||
vec3.cppm
|
||||
vec4.cppm
|
||||
components/transform.cppm)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/mat4.hpp>
|
||||
export module math.algebra;
|
||||
import math.mat4;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
export module math.components;
|
||||
|
||||
#include <math/vec3.hpp>
|
||||
import math.vec3;
|
||||
|
||||
namespace lt::math::components {
|
||||
|
||||
struct Transform
|
||||
export struct Transform
|
||||
{
|
||||
math::vec3 translation;
|
||||
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/vec3.hpp>
|
||||
#include <math/vec4.hpp>
|
||||
export module math.mat4;
|
||||
import math.vec3;
|
||||
import math.vec4;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct mat4_impl
|
||||
{
|
||||
using Column_T = vec4_impl<T>;
|
||||
|
|
@ -54,12 +54,12 @@ struct mat4_impl
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) -> Column_T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) -> Column_T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const Column_T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) const -> const Column_T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
|
@ -77,34 +77,34 @@ struct mat4_impl
|
|||
std::array<Column_T, 4> values; // NOLINT
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto translate(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto translate(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto rotate(float value, const vec3_impl<T> &xyz) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto rotate(float value, const vec3_impl<T> &xyz) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto scale(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto scale(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto inverse(const mat4_impl<T> &value) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto inverse(const mat4_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
using mat4 = mat4_impl<float>;
|
||||
export using mat4 = mat4_impl<float>;
|
||||
|
||||
using imat4 = mat4_impl<int32_t>;
|
||||
export using imat4 = mat4_impl<std::int32_t>;
|
||||
|
||||
using umat4 = mat4_impl<uint32_t>;
|
||||
export using umat4 = mat4_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#pragma once
|
||||
export module math.trig;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
export module math.vec2;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct vec2_impl
|
||||
{
|
||||
constexpr vec2_impl(): x(), y()
|
||||
|
|
@ -57,15 +59,15 @@ struct vec2_impl
|
|||
};
|
||||
|
||||
|
||||
using vec2 = vec2_impl<float>;
|
||||
export using vec2 = vec2_impl<float>;
|
||||
|
||||
using ivec2 = vec2_impl<int32_t>;
|
||||
export using ivec2 = vec2_impl<std::int32_t>;
|
||||
|
||||
using uvec2 = vec2_impl<uint32_t>;
|
||||
export using uvec2 = vec2_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
template<typename T>
|
||||
export template<typename T>
|
||||
struct std::formatter<lt::math::vec2_impl<T>>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &context)
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
export module math.vec3;
|
||||
|
||||
#include <cstdint>
|
||||
#include <math/vec2.hpp>
|
||||
import math.vec2;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct vec3_impl
|
||||
{
|
||||
constexpr vec3_impl(): x(), y(), z()
|
||||
|
|
@ -61,11 +61,11 @@ struct vec3_impl
|
|||
T z; // NOLINT
|
||||
};
|
||||
|
||||
using vec3 = vec3_impl<float>;
|
||||
export using vec3 = vec3_impl<float>;
|
||||
|
||||
using ivec3 = vec3_impl<int32_t>;
|
||||
export using ivec3 = vec3_impl<std::int32_t>;
|
||||
|
||||
using uvec3 = vec3_impl<uint32_t>;
|
||||
export using uvec3 = vec3_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
export module math.vec4;
|
||||
import math.vec2;
|
||||
import math.vec3;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct vec4_impl
|
||||
{
|
||||
constexpr vec4_impl(): x(), y(), z(), w()
|
||||
|
|
@ -40,12 +40,12 @@ struct vec4_impl
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) -> T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) -> T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) const -> const T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
|
@ -86,15 +86,15 @@ struct vec4_impl
|
|||
};
|
||||
};
|
||||
|
||||
using vec4 = vec4_impl<float>;
|
||||
export using vec4 = vec4_impl<float>;
|
||||
|
||||
using ivec4 = vec4_impl<int32_t>;
|
||||
export using ivec4 = vec4_impl<std::int32_t>;
|
||||
|
||||
using uvec4 = vec4_impl<uint32_t>;
|
||||
export using uvec4 = vec4_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
template<typename T>
|
||||
export template<typename T>
|
||||
struct std::formatter<lt::math::vec4_impl<T>>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &context)
|
||||
|
|
@ -1 +1,2 @@
|
|||
add_library_module(memory)
|
||||
add_library_module(NAME memory INTERFACES null_on_move.cppm reference.cppm
|
||||
scope.cppm)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#pragma once
|
||||
export module memory.null_on_move;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
/** Holds an `Underlying_T`, assigns it to `null_value` when this object is moved.
|
||||
*
|
||||
* @note For avoiding the need to explicitly implement the move constructor for objects that hold
|
||||
* Vulkan objects. But may server other purposes, hence why I kept the implementation generic.
|
||||
* Vulkan objects. But may serve other purposes, hence why I kept the implementation generic.
|
||||
*/
|
||||
template<typename Underlying_T, Underlying_T null_value = nullptr>
|
||||
class NullOnMove
|
||||
|
|
@ -77,9 +79,9 @@ public:
|
|||
return m_value;
|
||||
}
|
||||
|
||||
operator uint64_t() const
|
||||
operator std::uint64_t() const
|
||||
{
|
||||
return (uint64_t)m_value;
|
||||
return (std::uint64_t)m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get() -> Underlying_T
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
export module memory.reference;
|
||||
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory>
|
||||
import std;
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
|
|
@ -10,21 +9,21 @@ namespace lt::memory {
|
|||
* @note Currently just an alias, might turn into an implementation later.
|
||||
* @ref https://en.cppreference.com/w/cpp/memory/shared_ptr.html
|
||||
*/
|
||||
template<typename t>
|
||||
using Ref = std::shared_ptr<t>;
|
||||
export template<typename T>
|
||||
using Ref = std::shared_ptr<T>;
|
||||
|
||||
/** Allocates memory for an `Underlying_T` and directly constructs it there.
|
||||
*
|
||||
* @return A Ref<Underlying_T> to the constructed object.
|
||||
*/
|
||||
template<typename Underlying_T, typename... Args>
|
||||
export template<typename Underlying_T, typename... Args>
|
||||
constexpr Ref<Underlying_T> create_ref(Args &&...args)
|
||||
{
|
||||
return std::make_shared<Underlying_T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Converts c-style pointer of type `Underlying_T` to a `Ref<Underlying_T>`. */
|
||||
template<typename Underlying_T>
|
||||
export template<typename Underlying_T>
|
||||
constexpr Ref<Underlying_T> make_ref(Underlying_T *raw_pointer)
|
||||
{
|
||||
return Ref<Underlying_T>(raw_pointer);
|
||||
|
|
@ -1,30 +1,29 @@
|
|||
#pragma once
|
||||
export module memory.scope;
|
||||
|
||||
#include <memory/scope.hpp>
|
||||
#include <memory>
|
||||
import std;
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
/** Wrapper around std::unique_ptr.
|
||||
/** @brief Wrapper around std::unique_ptr.
|
||||
*
|
||||
* @note Currently just an alias, might turn into an implementation later.
|
||||
* @ref https://en.cppreference.com/w/cpp/memory/unique_ptr.html
|
||||
*/
|
||||
template<typename t>
|
||||
export template<typename t>
|
||||
using Scope = std::unique_ptr<t>;
|
||||
|
||||
/** Allocates memory for an `Underlying_T` and directly constructs it there.
|
||||
*
|
||||
* @return A Scope<Underlying_T> to the constructed object.
|
||||
*/
|
||||
template<typename Underlying_T, typename... Args>
|
||||
export template<typename Underlying_T, typename... Args>
|
||||
constexpr Scope<Underlying_T> create_scope(Args &&...args)
|
||||
{
|
||||
return std::make_unique<Underlying_T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Converts c-style pointer of type `Underlying_T` to a `Scope<Underlying_T>`. */
|
||||
template<typename Underlying_T>
|
||||
export template<typename Underlying_T>
|
||||
constexpr Scope<Underlying_T> make_scope(Underlying_T *raw_pointer)
|
||||
{
|
||||
return Scope<Underlying_T>(raw_pointer);
|
||||
|
|
@ -6,11 +6,13 @@
|
|||
#include <ecs/entity.hpp>
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <math/components/transform.hpp>
|
||||
#include <math/trig.hpp>
|
||||
#include <math/vec2.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/components/messenger.hpp>
|
||||
#include <renderer/components/sprite.hpp>
|
||||
#include <renderer/system.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/surface.hpp>
|
||||
|
|
@ -30,7 +32,7 @@ void renderer_callback(
|
|||
std::ignore = message_type;
|
||||
std::ignore = user_data;
|
||||
|
||||
log_dbg("RENDERER CALLBACK: {}", data.message);
|
||||
log::debug("RENDERER CALLBACK: {}", data.message);
|
||||
}
|
||||
|
||||
class MirrorSystem: public lt::app::ISystem
|
||||
|
|
@ -145,7 +147,7 @@ public:
|
|||
|
||||
void on_window_close()
|
||||
{
|
||||
log_inf("Window close requested...");
|
||||
log::info("Window close requested...");
|
||||
|
||||
unregister_system(m_input_system);
|
||||
unregister_system(m_surface_system);
|
||||
|
|
@ -227,6 +229,21 @@ public:
|
|||
.user_data = this,
|
||||
} });
|
||||
|
||||
m_sprite_id = m_editor_registry->create_entity();
|
||||
|
||||
m_editor_registry->add(
|
||||
m_sprite_id,
|
||||
renderer::components::Sprite { .color = lt::math::vec3 { 1.0f, 0.0f, 0.0f } }
|
||||
);
|
||||
m_editor_registry->add(
|
||||
m_sprite_id,
|
||||
math::components::Transform {
|
||||
.translation = { -5.0, -5.0, 0.5 },
|
||||
.scale = { 5.0, 5.0, 1.0 },
|
||||
.rotation = {},
|
||||
}
|
||||
);
|
||||
|
||||
m_camera_id = m_editor_registry->create_entity();
|
||||
|
||||
m_editor_registry->add(
|
||||
|
|
@ -268,6 +285,8 @@ private:
|
|||
lt::ecs::EntityId m_window = lt::ecs::null_entity;
|
||||
|
||||
lt::ecs::EntityId m_camera_id = lt::ecs::null_entity;
|
||||
|
||||
lt::ecs::EntityId m_sprite_id = lt::ecs::null_entity;
|
||||
};
|
||||
|
||||
auto app::create_application() -> memory::Scope<app::Application>
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ void AssetBrowserPanel::on_user_interface_update()
|
|||
))
|
||||
{
|
||||
auto serializer = SceneSerializer { m_active_scene };
|
||||
log_inf("Attempting to deserialize: {}", path.string());
|
||||
log::info("Attempting to deserialize: {}", path.string());
|
||||
serializer.deserialize(path.string());
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//
|
||||
#include <logger/logger.hpp>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
#include <renderer/backend/vk/context/surface.hpp>
|
||||
|
|
@ -47,8 +48,8 @@ Device::~Device()
|
|||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_err("Failed to destroy vk device:");
|
||||
log_err("\twhat: {}", exp.what());
|
||||
log::error("Failed to destroy vk device:");
|
||||
log::error("\twhat: {}", exp.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,26 +77,106 @@ void Device::initialize_logical_device()
|
|||
auto extensions = std::vector<const char *> {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
|
||||
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
auto descriptor_indexing_features = m_gpu->get_descriptor_indexing_features();
|
||||
log::debug("");
|
||||
|
||||
log::debug(
|
||||
"shaderInputAttachmentArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderInputAttachmentArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformTexelBufferArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformTexelBufferArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageTexelBufferArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageTexelBufferArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderSampledImageArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageImageArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageImageArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderInputAttachmentArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderInputAttachmentArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformTexelBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformTexelBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageTexelBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageTexelBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUniformBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingUniformBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingSampledImageUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageImageUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageImageUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUniformTexelBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingUniformTexelBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageTexelBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageTexelBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUpdateUnusedWhilePending: {}",
|
||||
descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingPartiallyBound: {}",
|
||||
descriptor_indexing_features.descriptorBindingPartiallyBound
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingVariableDescriptorCount: {}",
|
||||
descriptor_indexing_features.descriptorBindingVariableDescriptorCount
|
||||
);
|
||||
log::debug(" runtimeDescriptorArray: {}", descriptor_indexing_features.runtimeDescriptorArray);
|
||||
const auto dynamic_rendering_features = VkPhysicalDeviceDynamicRenderingFeatures {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
|
||||
.pNext = &descriptor_indexing_features,
|
||||
.dynamicRendering = true,
|
||||
};
|
||||
|
||||
auto device_info = VkDeviceCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = &dynamic_rendering_features,
|
||||
.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size()),
|
||||
.pQueueCreateInfos = queue_infos.data(),
|
||||
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
|
||||
.ppEnabledExtensionNames = extensions.data(),
|
||||
.pEnabledFeatures = &physical_device_features,
|
||||
};
|
||||
|
||||
ensure(
|
||||
!vk_create_device(m_gpu->vk(), &device_info, nullptr, &m_device),
|
||||
"Failed to create logical vulkan device"
|
||||
m_device = m_gpu->create_device(
|
||||
VkDeviceCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = &dynamic_rendering_features,
|
||||
.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size()),
|
||||
.pQueueCreateInfos = queue_infos.data(),
|
||||
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
|
||||
.ppEnabledExtensionNames = extensions.data(),
|
||||
.pEnabledFeatures = &physical_device_features,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -284,13 +365,14 @@ void Device::unmap_memory(VkDeviceMemory memory)
|
|||
}
|
||||
|
||||
[[nodiscard]] auto Device::create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> descriptor_set_layout,
|
||||
std::vector<VkPushConstantRange> push_constant_ranges
|
||||
) const -> VkPipelineLayout
|
||||
{
|
||||
auto info = VkPipelineLayoutCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 0u,
|
||||
.pSetLayouts = nullptr,
|
||||
.setLayoutCount = static_cast<uint32_t>(descriptor_set_layout.size()),
|
||||
.pSetLayouts = descriptor_set_layout.data(),
|
||||
.pushConstantRangeCount = static_cast<uint32_t>(push_constant_ranges.size()),
|
||||
.pPushConstantRanges = push_constant_ranges.data(),
|
||||
};
|
||||
|
|
@ -346,6 +428,21 @@ void Device::unmap_memory(VkDeviceMemory memory)
|
|||
vkc(vk_create_buffer(m_device, &info, nullptr, &buffer));
|
||||
return buffer;
|
||||
}
|
||||
[[nodiscard]] auto Device::create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const
|
||||
-> VkDescriptorPool
|
||||
{
|
||||
auto *pool = VkDescriptorPool {};
|
||||
vkc(vk_create_descriptor_pool(m_device, &info, nullptr, &pool));
|
||||
return pool;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const
|
||||
-> VkDescriptorSetLayout
|
||||
{
|
||||
auto *layout = VkDescriptorSetLayout {};
|
||||
vkc(vk_create_descriptor_set_layout(m_device, &info, nullptr, &layout));
|
||||
return layout;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::allocate_command_buffers(VkCommandBufferAllocateInfo info) const
|
||||
-> std::vector<VkCommandBuffer>
|
||||
|
|
@ -362,11 +459,27 @@ void Device::unmap_memory(VkDeviceMemory memory)
|
|||
return memory;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const
|
||||
-> VkDescriptorSet
|
||||
{
|
||||
auto *descriptor_set = VkDescriptorSet {};
|
||||
vkc(vk_allocate_descriptor_sets(m_device, &info, &descriptor_set));
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
void Device::free_memory(VkDeviceMemory memory) const
|
||||
{
|
||||
vk_free_memory(m_device, memory, nullptr);
|
||||
}
|
||||
|
||||
void Device::free_descriptor_set(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const
|
||||
{
|
||||
vkc(vk_free_descriptor_sets(m_device, descriptor_pool, 1, &descriptor_set));
|
||||
}
|
||||
|
||||
void Device::destroy_swapchain(VkSwapchainKHR swapchain) const
|
||||
{
|
||||
vk_destroy_swapchain_khr(m_device, swapchain, m_allocator);
|
||||
|
|
@ -454,4 +567,14 @@ void Device::destroy_buffer(VkBuffer buffer) const
|
|||
vk_destroy_buffer(m_device, buffer, nullptr);
|
||||
}
|
||||
|
||||
void Device::destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const
|
||||
{
|
||||
vk_destroy_descriptor_set_layout(m_device, layout, nullptr);
|
||||
}
|
||||
|
||||
void Device::destroy_descriptor_pool(VkDescriptorPool pool) const
|
||||
{
|
||||
vk_destroy_descriptor_pool(m_device, pool, nullptr);
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ public:
|
|||
[[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass;
|
||||
|
||||
[[nodiscard]] auto create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> descriptor_set_layout,
|
||||
std::vector<VkPushConstantRange> push_constant_ranges
|
||||
) const -> VkPipelineLayout;
|
||||
|
||||
|
|
@ -133,15 +134,29 @@ public:
|
|||
|
||||
[[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer;
|
||||
|
||||
[[nodiscard]] auto create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const
|
||||
-> VkDescriptorSetLayout;
|
||||
|
||||
[[nodiscard]] auto create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const
|
||||
-> VkDescriptorPool;
|
||||
|
||||
/** allocation functions */
|
||||
[[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory;
|
||||
|
||||
[[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const
|
||||
-> std::vector<VkCommandBuffer>;
|
||||
|
||||
[[nodiscard]] auto allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const
|
||||
-> VkDescriptorSet;
|
||||
|
||||
/** de-allocation functions */
|
||||
void free_memory(VkDeviceMemory memory) const;
|
||||
|
||||
void free_descriptor_set(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const;
|
||||
|
||||
/** destroy functions */
|
||||
void destroy_swapchain(VkSwapchainKHR swapchain) const;
|
||||
|
||||
|
|
@ -173,6 +188,10 @@ public:
|
|||
|
||||
void destroy_buffer(VkBuffer buffer) const;
|
||||
|
||||
void destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const;
|
||||
|
||||
void destroy_descriptor_pool(VkDescriptorPool pool) const;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static auto get_object_type(const T &object) -> VkObjectType
|
||||
|
|
|
|||
|
|
@ -244,10 +244,10 @@ void Instance::initialize_instance()
|
|||
memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
|
||||
|
||||
// log_inf("Available vulkan instance extensions:");
|
||||
// log::info("Available vulkan instance extensions:");
|
||||
for (auto &ext : extensions)
|
||||
{
|
||||
// log_inf("\t{} @ {}", ext.extensionName, ext.specVersion);
|
||||
// log::info("\t{} @ {}", ext.extensionName, ext.specVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +293,7 @@ void Instance::load_global_functions()
|
|||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(nullptr, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan global function: {}", fn_name);
|
||||
// log_trc("Loaded global function: {}", fn_name);
|
||||
// log::trace("Loaded global function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_create_instance, "vkCreateInstance");
|
||||
|
|
@ -307,7 +307,7 @@ void Instance::load_instance_functions()
|
|||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(m_instance, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan instance function: {}", fn_name);
|
||||
// log_trc("Loaded instance function: {}", fn_name);
|
||||
// log::trace("Loaded instance function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_destroy_instance, "vkDestroyInstance");
|
||||
|
|
@ -352,7 +352,7 @@ void Instance::load_device_functions_impl(VkDevice device)
|
|||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_device_proc_address(device, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan device function: {}", fn_name);
|
||||
// log_trc("Loaded device function: {}", fn_name);
|
||||
// log::trace("Loaded device function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_get_device_queue, "vkGetDeviceQueue");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <ranges>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
|
|
@ -95,8 +96,8 @@ Swapchain::~Swapchain()
|
|||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_err("Failed to destroy swapchain:");
|
||||
log_err("\twhat: {}", exp.what());
|
||||
log::error("Failed to destroy swapchain:");
|
||||
log::error("\twhat: {}", exp.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
9
modules/renderer/private/backend/vk/data/descriptors.hpp
Normal file
9
modules/renderer/private/backend/vk/data/descriptors.hpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Descriptors
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <renderer/backend/vk/messenger.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
|
@ -42,8 +43,8 @@ Messenger::Messenger(IInstance *instance, CreateInfo info)
|
|||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_err("Uncaught exception in messenger callback:");
|
||||
log_err("\twhat: {}", exp.what());
|
||||
log::error("Uncaught exception in messenger callback:");
|
||||
log::error("\twhat: {}", exp.what());
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
|
|
|
|||
|
|
@ -12,16 +12,85 @@ Pass::Pass(
|
|||
const lt::assets::ShaderAsset &fragment_shader
|
||||
)
|
||||
: m_device(static_cast<Device *>(device))
|
||||
, m_layout(m_device->create_pipeline_layout(
|
||||
std::vector<VkPushConstantRange> {
|
||||
VkPushConstantRange {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0u,
|
||||
.size = sizeof(FrameConstants),
|
||||
},
|
||||
}
|
||||
))
|
||||
{
|
||||
auto binding = VkDescriptorSetLayoutBinding {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1'000,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
};
|
||||
|
||||
const auto descriptor_binding_flags = VkDescriptorBindingFlagsEXT {
|
||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
|
||||
| VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
|
||||
| VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
|
||||
| VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT,
|
||||
};
|
||||
|
||||
constexpr auto descriptor_count = uint32_t { 1'000 };
|
||||
|
||||
auto descriptor_binding_flags_info = VkDescriptorSetLayoutBindingFlagsCreateInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
|
||||
.bindingCount = 1,
|
||||
.pBindingFlags = &descriptor_binding_flags,
|
||||
};
|
||||
|
||||
|
||||
m_vertices_descriptor_set_layout = m_device->create_descriptor_set_layout(
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.pNext = &descriptor_binding_flags_info,
|
||||
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT,
|
||||
.bindingCount = 1u,
|
||||
.pBindings = &binding,
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
auto pool_size = VkDescriptorPoolSize {
|
||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = descriptor_count,
|
||||
};
|
||||
|
||||
m_descriptor_pool = m_device->create_desscriptor_pool(
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.poolSizeCount = 1u,
|
||||
.pPoolSizes = &pool_size,
|
||||
}
|
||||
);
|
||||
|
||||
auto descriptor_set_variable_descriptor_count_info
|
||||
= VkDescriptorSetVariableDescriptorCountAllocateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
|
||||
.descriptorSetCount = 1u,
|
||||
.pDescriptorCounts = &descriptor_count,
|
||||
};
|
||||
|
||||
m_vertices_descriptor_set = m_device->allocate_descriptor_set(
|
||||
VkDescriptorSetAllocateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.pNext = &descriptor_set_variable_descriptor_count_info,
|
||||
.descriptorPool = m_descriptor_pool,
|
||||
.descriptorSetCount = 1u,
|
||||
.pSetLayouts = &m_vertices_descriptor_set_layout,
|
||||
}
|
||||
);
|
||||
|
||||
m_layout = m_device->create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> {
|
||||
m_vertices_descriptor_set_layout,
|
||||
},
|
||||
|
||||
std::vector<VkPushConstantRange> {
|
||||
VkPushConstantRange {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0u,
|
||||
.size = sizeof(FrameConstants),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
auto *vertex_module = create_module(
|
||||
vertex_shader.unpack(lt::assets::ShaderAsset::BlobTag::code)
|
||||
);
|
||||
|
|
@ -188,6 +257,11 @@ Pass::~Pass()
|
|||
}
|
||||
|
||||
m_device->wait_idle();
|
||||
|
||||
m_device->destroy_descriptor_set_layout(m_vertices_descriptor_set_layout);
|
||||
m_device->free_descriptor_set(m_descriptor_pool, m_vertices_descriptor_set);
|
||||
m_device->destroy_descriptor_pool(m_descriptor_pool);
|
||||
|
||||
m_device->destroy_framebuffers(m_framebuffers);
|
||||
m_device->destroy_pipeline(m_pipeline);
|
||||
// m_device->destroy_pass(m_pass);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ private:
|
|||
VkPipelineLayout m_layout = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<VkFramebuffer> m_framebuffers;
|
||||
|
||||
VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE;
|
||||
|
||||
VkDescriptorSetLayout m_vertices_descriptor_set_layout;
|
||||
|
||||
VkDescriptorSet m_vertices_descriptor_set = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -4,11 +4,30 @@
|
|||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
Renderer::Renderer(IDevice *device, ISwapchain *swapchain, uint32_t max_frames_in_flight)
|
||||
Renderer::Renderer(IGpu *gpu, IDevice *device, ISwapchain *swapchain, uint32_t max_frames_in_flight)
|
||||
: m_device(static_cast<Device *>(device))
|
||||
, m_swapchain(static_cast<Swapchain *>(swapchain))
|
||||
, m_resolution(m_swapchain->get_resolution())
|
||||
, m_max_frames_in_flight(max_frames_in_flight)
|
||||
, m_staging_offset()
|
||||
, m_vertex_buffer(
|
||||
device,
|
||||
gpu,
|
||||
IBuffer::CreateInfo {
|
||||
.usage = IBuffer::Usage::vertex,
|
||||
.size = 1'000'000,
|
||||
.debug_name = "vertex buffer",
|
||||
}
|
||||
)
|
||||
, m_staging_buffer(
|
||||
device,
|
||||
gpu,
|
||||
IBuffer::CreateInfo {
|
||||
.usage = IBuffer::Usage::staging,
|
||||
.size = 1'000'000,
|
||||
.debug_name = "staging buffer",
|
||||
}
|
||||
)
|
||||
{
|
||||
ensure(m_device, "Failed to initialize renderer: null device");
|
||||
ensure(m_swapchain, "Failed to initialize renderer: null swapchain");
|
||||
|
|
@ -17,7 +36,7 @@ Renderer::Renderer(IDevice *device, ISwapchain *swapchain, uint32_t max_frames_i
|
|||
m_pass = memory::create_ref<vk::Pass>(
|
||||
m_device,
|
||||
m_swapchain,
|
||||
assets::ShaderAsset { "./data/test_assets/triangle.vert.asset" },
|
||||
assets::ShaderAsset { "./data/test_assets/sprite.vert.asset" },
|
||||
assets::ShaderAsset { "./data/test_assets/triangle.frag.asset" }
|
||||
);
|
||||
|
||||
|
|
@ -29,6 +48,15 @@ Renderer::Renderer(IDevice *device, ISwapchain *swapchain, uint32_t max_frames_i
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
m_transient_pool = m_device->create_command_pool(
|
||||
VkCommandPoolCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = m_device->get_family_indices()[0],
|
||||
}
|
||||
);
|
||||
|
||||
m_cmds.resize(m_max_frames_in_flight);
|
||||
m_cmds = m_device->allocate_command_buffers(
|
||||
VkCommandBufferAllocateInfo {
|
||||
|
|
@ -73,9 +101,10 @@ Renderer::~Renderer()
|
|||
m_device->destroy_semaphores(m_submit_semaphores);
|
||||
m_device->destroy_fences(m_frame_fences);
|
||||
m_device->destroy_command_pool(m_pool);
|
||||
m_device->destroy_command_pool(m_transient_pool);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Renderer::draw(uint32_t frame_idx) -> DrawResult
|
||||
[[nodiscard]] auto Renderer::frame(uint32_t frame_idx, std::function<void()> submit_scene) -> Result
|
||||
{
|
||||
ensure(
|
||||
frame_idx < m_max_frames_in_flight,
|
||||
|
|
@ -93,13 +122,14 @@ Renderer::~Renderer()
|
|||
auto image_idx = m_device->acquire_image(m_swapchain->vk(), aquire_semaphore);
|
||||
if (!image_idx.has_value())
|
||||
{
|
||||
return {};
|
||||
return Result::invalid_swapchain;
|
||||
}
|
||||
|
||||
m_device->reset_fence(frame_fence);
|
||||
vk_reset_command_buffer(cmd, {});
|
||||
record_cmd(cmd, *image_idx);
|
||||
|
||||
map_buffers(frame_idx);
|
||||
submit_scene();
|
||||
record_cmd(cmd, *image_idx);
|
||||
|
||||
auto wait_stage = VkPipelineStageFlags { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
auto &submit_semaphore = m_submit_semaphores[*image_idx];
|
||||
|
|
@ -130,7 +160,8 @@ Renderer::~Renderer()
|
|||
.pResults = &result,
|
||||
}
|
||||
);
|
||||
return DrawResult::success;
|
||||
|
||||
return Result::success;
|
||||
}
|
||||
|
||||
void Renderer::replace_swapchain(ISwapchain *swapchain)
|
||||
|
|
@ -141,6 +172,39 @@ void Renderer::replace_swapchain(ISwapchain *swapchain)
|
|||
m_pass->replace_swapchain(*swapchain);
|
||||
}
|
||||
|
||||
void Renderer::map_buffers(uint32_t frame_idx)
|
||||
{
|
||||
using components::Sprite;
|
||||
|
||||
m_current_sprite_idx = 0;
|
||||
m_staging_map = m_staging_buffer.map();
|
||||
auto frame_segment_size = m_staging_map.size() / m_max_frames_in_flight;
|
||||
|
||||
m_staging_offset = frame_segment_size * frame_idx;
|
||||
m_staging_map = m_staging_map.subspan(m_staging_offset, frame_segment_size);
|
||||
|
||||
m_sprite_vertex_map = std::span<Sprite::Vertex>(
|
||||
std::bit_cast<Sprite::Vertex *>(m_staging_map.data()),
|
||||
m_staging_map.size() / sizeof(Sprite::Vertex)
|
||||
);
|
||||
}
|
||||
|
||||
void Renderer::flush_buffers(VkCommandBuffer cmd)
|
||||
{
|
||||
m_staging_map = {};
|
||||
m_sprite_vertex_map = {};
|
||||
|
||||
m_staging_buffer.unmap();
|
||||
const auto buffer_copy_info = VkBufferCopy {
|
||||
|
||||
.srcOffset = m_staging_offset,
|
||||
.dstOffset = m_staging_offset,
|
||||
.size = m_current_sprite_idx * sizeof(components::Sprite::Vertex),
|
||||
};
|
||||
|
||||
vk_cmd_copy_buffer(cmd, m_staging_buffer.vk(), m_vertex_buffer.vk(), 1u, &buffer_copy_info);
|
||||
}
|
||||
|
||||
void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
|
||||
{
|
||||
const auto cmd_begin_info = VkCommandBufferBeginInfo {
|
||||
|
|
@ -216,7 +280,10 @@ void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
|
|||
|
||||
};
|
||||
|
||||
vk_reset_command_buffer(cmd, {});
|
||||
vkc(vk_begin_command_buffer(cmd, &cmd_begin_info));
|
||||
flush_buffers(cmd);
|
||||
|
||||
vk_cmd_push_constants(
|
||||
cmd,
|
||||
m_pass->get_layout(),
|
||||
|
|
@ -241,7 +308,7 @@ void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
|
|||
vk_cmd_bind_pipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pass->get_pipeline());
|
||||
vk_cmd_set_viewport(cmd, 0, 1, &viewport);
|
||||
vk_cmd_set_scissors(cmd, 0, 1, &scissor);
|
||||
vk_cmd_draw(cmd, 3, 1, 0, 0);
|
||||
vk_cmd_draw(cmd, m_current_sprite_idx, 1, 0, 0);
|
||||
vk_cmd_end_rendering(cmd);
|
||||
vk_cmd_pipeline_barrier(
|
||||
cmd,
|
||||
|
|
@ -258,8 +325,45 @@ void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
|
|||
vkc(vk_end_command_buffer(cmd));
|
||||
}
|
||||
|
||||
void submit_sprite(const components::Sprite &sprite, const math::components::Transform &transform)
|
||||
void Renderer::submit_sprite(
|
||||
const components::Sprite &sprite,
|
||||
const math::components::Transform &transform
|
||||
)
|
||||
{
|
||||
using components::Sprite;
|
||||
|
||||
const auto &[x, y, z] = transform.translation;
|
||||
const auto &[width, height, _] = transform.scale;
|
||||
|
||||
m_sprite_vertex_map[m_current_sprite_idx++] = components::Sprite::Vertex {
|
||||
.position = { x, y + height, z },
|
||||
.color = sprite.color,
|
||||
};
|
||||
|
||||
m_sprite_vertex_map[m_current_sprite_idx++] = components::Sprite::Vertex {
|
||||
.position = { x + width, y + height, z },
|
||||
.color = sprite.color,
|
||||
};
|
||||
|
||||
m_sprite_vertex_map[m_current_sprite_idx++] = components::Sprite::Vertex {
|
||||
.position = { x + width, y, z },
|
||||
.color = sprite.color,
|
||||
};
|
||||
|
||||
m_sprite_vertex_map[m_current_sprite_idx++] = components::Sprite::Vertex {
|
||||
.position = { x + width, y, z },
|
||||
.color = sprite.color,
|
||||
};
|
||||
|
||||
m_sprite_vertex_map[m_current_sprite_idx++] = components::Sprite::Vertex {
|
||||
.position = { x, y, z },
|
||||
.color = sprite.color,
|
||||
};
|
||||
|
||||
m_sprite_vertex_map[m_current_sprite_idx++] = components::Sprite::Vertex {
|
||||
.position = { x, y + height, z },
|
||||
.color = sprite.color,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -15,7 +15,12 @@ namespace lt::renderer::vk {
|
|||
class Renderer: public IRenderer
|
||||
{
|
||||
public:
|
||||
Renderer(class IDevice *device, class ISwapchain *swapchain, uint32_t max_frames_in_flight);
|
||||
Renderer(
|
||||
class IGpu *gpu,
|
||||
class IDevice *device,
|
||||
class ISwapchain *swapchain,
|
||||
uint32_t max_frames_in_flight
|
||||
);
|
||||
|
||||
~Renderer() override;
|
||||
|
||||
|
|
@ -27,7 +32,8 @@ public:
|
|||
|
||||
auto operator=(const Renderer &) -> Renderer & = delete;
|
||||
|
||||
[[nodiscard]] DrawResult draw(uint32_t frame_idx) override;
|
||||
[[nodiscard]] auto frame(uint32_t frame_idx, std::function<void()> submit_scene)
|
||||
-> Result override;
|
||||
|
||||
void replace_swapchain(ISwapchain *swapchain) override;
|
||||
|
||||
|
|
@ -39,13 +45,15 @@ public:
|
|||
void submit_sprite(
|
||||
const components::Sprite &sprite,
|
||||
const math::components::Transform &transform
|
||||
) override
|
||||
{
|
||||
}
|
||||
) override;
|
||||
|
||||
private:
|
||||
void record_cmd(VkCommandBuffer cmd, uint32_t image_idx);
|
||||
|
||||
void map_buffers(uint32_t frame_idx);
|
||||
|
||||
void flush_buffers(VkCommandBuffer cmd);
|
||||
|
||||
memory::NullOnMove<class Device *> m_device {};
|
||||
|
||||
class Swapchain *m_swapchain {};
|
||||
|
|
@ -54,6 +62,8 @@ private:
|
|||
|
||||
VkCommandPool m_pool = VK_NULL_HANDLE;
|
||||
|
||||
VkCommandPool m_transient_pool = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<VkCommandBuffer> m_cmds;
|
||||
|
||||
std::vector<VkFence> m_frame_fences;
|
||||
|
|
@ -67,6 +77,18 @@ private:
|
|||
uint32_t m_max_frames_in_flight {};
|
||||
|
||||
FrameConstants m_frame_constants;
|
||||
|
||||
Buffer m_vertex_buffer;
|
||||
|
||||
Buffer m_staging_buffer;
|
||||
|
||||
size_t m_staging_offset;
|
||||
|
||||
std::span<std::byte> m_staging_map;
|
||||
|
||||
std::span<components::Sprite::Vertex> m_sprite_vertex_map;
|
||||
|
||||
size_t m_current_sprite_idx;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <renderer/frontend/context/instance.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ class ShaderAsset;
|
|||
|
||||
namespace lt::renderer {
|
||||
|
||||
|
||||
class IPass
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ namespace lt::renderer {
|
|||
|
||||
[[nodiscard]] /* static */ auto IRenderer::create(
|
||||
Api target_api,
|
||||
IGpu *gpu,
|
||||
IDevice *device,
|
||||
ISwapchain *swapchain,
|
||||
uint32_t max_frames_in_flight
|
||||
) -> memory::Scope<IRenderer>
|
||||
{
|
||||
ensure(gpu, "Failed to create renderer::IRenderer: null gpu");
|
||||
ensure(device, "Failed to create renderer::IRenderer: null device");
|
||||
ensure(swapchain, "Failed to create renderer::IRenderer: null swapchain");
|
||||
ensure(
|
||||
|
|
@ -28,7 +30,7 @@ namespace lt::renderer {
|
|||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan:
|
||||
return memory::create_scope<vk::Renderer>(device, swapchain, max_frames_in_flight);
|
||||
return memory::create_scope<vk::Renderer>(gpu, device, swapchain, max_frames_in_flight);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public:
|
|||
|
||||
static constexpr auto frames_in_flight_lower_limit = 1u;
|
||||
|
||||
enum class DrawResult : uint8_t
|
||||
enum class Result : uint8_t
|
||||
{
|
||||
success = 0,
|
||||
invalid_swapchain,
|
||||
|
|
@ -24,6 +24,7 @@ public:
|
|||
|
||||
[[nodiscard]] static auto create(
|
||||
Api target_api,
|
||||
class IGpu *gpu,
|
||||
class IDevice *device,
|
||||
class ISwapchain *swapchain,
|
||||
uint32_t max_frames_in_flight
|
||||
|
|
@ -41,7 +42,7 @@ public:
|
|||
|
||||
auto operator=(const IRenderer &) -> IRenderer & = delete;
|
||||
|
||||
[[nodiscard]] virtual auto draw(uint32_t frame_idx) -> DrawResult = 0;
|
||||
virtual auto frame(uint32_t frame_idx, std::function<void()> submit_scene) -> Result = 0;
|
||||
|
||||
virtual void replace_swapchain(class ISwapchain *swapchain) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Suite raii = "renderer_raii"_suite = [] {
|
|||
auto fixture = FixtureDeviceSwapchain {};
|
||||
ignore = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
fixture.device(),
|
||||
fixture.swapchain(),
|
||||
constants::frames_in_flight
|
||||
|
|
@ -20,6 +21,7 @@ Suite raii = "renderer_raii"_suite = [] {
|
|||
ignore = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
nullptr,
|
||||
fixture.device(),
|
||||
fixture.swapchain(),
|
||||
constants::frames_in_flight
|
||||
);
|
||||
|
|
@ -28,6 +30,17 @@ Suite raii = "renderer_raii"_suite = [] {
|
|||
expect_throw([&] {
|
||||
ignore = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
nullptr,
|
||||
fixture.swapchain(),
|
||||
constants::frames_in_flight
|
||||
);
|
||||
});
|
||||
|
||||
expect_throw([&] {
|
||||
ignore = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
fixture.device(),
|
||||
nullptr,
|
||||
constants::frames_in_flight
|
||||
|
|
@ -37,6 +50,7 @@ Suite raii = "renderer_raii"_suite = [] {
|
|||
expect_throw([&] {
|
||||
ignore = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
fixture.device(),
|
||||
nullptr,
|
||||
lt::renderer::IRenderer::frames_in_flight_upper_limit + 1
|
||||
|
|
@ -46,6 +60,7 @@ Suite raii = "renderer_raii"_suite = [] {
|
|||
expect_throw([&] {
|
||||
ignore = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
fixture.device(),
|
||||
nullptr,
|
||||
lt::renderer::IRenderer::frames_in_flight_lower_limit - 1
|
||||
|
|
@ -55,12 +70,13 @@ Suite raii = "renderer_raii"_suite = [] {
|
|||
};
|
||||
|
||||
Suite draw = "renderer_draw"_suite = [] {
|
||||
using enum lt::renderer::IRenderer::DrawResult;
|
||||
using enum lt::renderer::IRenderer::Result;
|
||||
|
||||
Case { "renderer draw" } = [] {
|
||||
auto fixture = FixtureDeviceSwapchain {};
|
||||
auto renderer = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
fixture.device(),
|
||||
fixture.swapchain(),
|
||||
constants::frames_in_flight
|
||||
|
|
@ -68,7 +84,7 @@ Suite draw = "renderer_draw"_suite = [] {
|
|||
|
||||
for (auto frame_idx : std::views::iota(0u, 30u))
|
||||
{
|
||||
expect_eq(renderer->draw(frame_idx % constants::frames_in_flight), success);
|
||||
expect_eq(renderer->frame(frame_idx % constants::frames_in_flight, [] {}), success);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -76,6 +92,7 @@ Suite draw = "renderer_draw"_suite = [] {
|
|||
auto fixture = FixtureDeviceSwapchain {};
|
||||
auto renderer = lt::renderer::IRenderer::create(
|
||||
constants::api,
|
||||
fixture.gpu(),
|
||||
fixture.device(),
|
||||
fixture.swapchain(),
|
||||
constants::frames_in_flight
|
||||
|
|
@ -83,14 +100,14 @@ Suite draw = "renderer_draw"_suite = [] {
|
|||
|
||||
for (auto frame_idx : std::views::iota(0u, 15u))
|
||||
{
|
||||
expect_eq(renderer->draw(frame_idx % constants::frames_in_flight), success);
|
||||
expect_eq(renderer->frame(frame_idx % constants::frames_in_flight, [] {}), success);
|
||||
}
|
||||
|
||||
fixture.recreate_swapchain();
|
||||
renderer->replace_swapchain(fixture.swapchain());
|
||||
for (auto frame_idx : std::views::iota(0u, 15u))
|
||||
{
|
||||
expect_eq(renderer->draw(frame_idx % constants::frames_in_flight), success);
|
||||
expect_eq(renderer->frame(frame_idx % constants::frames_in_flight, [] {}), success);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ System::System(CreateInfo info)
|
|||
m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
|
||||
m_renderer = { IRenderer::create(
|
||||
m_api,
|
||||
m_gpu.get(),
|
||||
m_device.get(),
|
||||
m_swapchain.get(),
|
||||
info.config.max_frames_in_flight
|
||||
|
|
@ -64,6 +65,18 @@ void System::tick(app::TickInfo tick)
|
|||
{
|
||||
std::ignore = tick;
|
||||
|
||||
handle_surface_resized_events();
|
||||
auto frame_result = m_renderer->frame(m_frame_idx, [this] { submit_scene(); });
|
||||
|
||||
if (frame_result == IRenderer::Result::invalid_swapchain)
|
||||
{
|
||||
recreate_swapchain();
|
||||
}
|
||||
m_frame_idx = (m_frame_idx + 1) % m_max_frames_in_flight;
|
||||
}
|
||||
|
||||
void System::handle_surface_resized_events()
|
||||
{
|
||||
for (const auto &event : m_surface_entity.get<surface::SurfaceComponent>().peek_events())
|
||||
{
|
||||
if (std::holds_alternative<surface::ResizedEvent>(event))
|
||||
|
|
@ -71,9 +84,15 @@ void System::tick(app::TickInfo tick)
|
|||
m_swapchain.reset();
|
||||
m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
|
||||
m_renderer->replace_swapchain(m_swapchain.get());
|
||||
|
||||
// No need to process multiple resize events
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void System::submit_scene()
|
||||
{
|
||||
auto perspective = math::mat4::identity();
|
||||
for (auto [id, camera] : m_registry->view<lt::camera::components::PerspectiveCamera>())
|
||||
{
|
||||
|
|
@ -90,24 +109,20 @@ void System::tick(app::TickInfo tick)
|
|||
}
|
||||
}
|
||||
|
||||
// for each sprite, submit a new "model matrix" + "color" to go into the scene's SSBO
|
||||
m_renderer->set_frame_constants({ .view_projection = perspective });
|
||||
for (auto &[id, sprite, transform] :
|
||||
m_registry->view<components::Sprite, math::components::Transform>())
|
||||
{
|
||||
m_renderer->submit_sprite(sprite, transform);
|
||||
}
|
||||
}
|
||||
|
||||
m_renderer->set_frame_constants({ .view_projection = perspective });
|
||||
if (m_renderer->draw(m_frame_idx) != IRenderer::DrawResult::success)
|
||||
{
|
||||
m_swapchain.reset();
|
||||
m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
|
||||
m_renderer->replace_swapchain(m_swapchain.get());
|
||||
|
||||
std::ignore = m_renderer->draw(m_frame_idx); // drop the frame if failed twice
|
||||
}
|
||||
|
||||
m_frame_idx = (m_frame_idx + 1) % m_max_frames_in_flight;
|
||||
void System::recreate_swapchain()
|
||||
{
|
||||
log::trace("Re-creating swapchaain");
|
||||
m_swapchain.reset();
|
||||
m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
|
||||
m_renderer->replace_swapchain(m_swapchain.get());
|
||||
}
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/frontend/renderer/renderer.hpp>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <logger/logger.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <renderer/components/messenger.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
|
|
@ -170,7 +171,7 @@ private:
|
|||
{
|
||||
// I know this makes the tests too verbose...
|
||||
// but makes it easier to figure out what the problem is when things fail on ci
|
||||
log_trc("vulkan: {}", data.message);
|
||||
lt::log::trace("vulkan: {}", data.message);
|
||||
std::ignore = data;
|
||||
std::ignore = type;
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ private:
|
|||
{
|
||||
// I know this makes the tests too verbose...
|
||||
// but makes it easier to figure out what the problem is when things fail on ci
|
||||
log_trc("vulkan: {}", data.message);
|
||||
lt::log::trace("vulkan: {}", data.message);
|
||||
|
||||
std::ignore = data;
|
||||
std::ignore = type;
|
||||
|
|
|
|||
|
|
@ -69,9 +69,7 @@ struct Sprite
|
|||
}
|
||||
};
|
||||
|
||||
memory::Ref<assets::ShaderAsset> vertex_shader;
|
||||
|
||||
memory::Ref<assets::ShaderAsset> fragment_shader;
|
||||
math::vec3 color;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::components
|
||||
|
|
|
|||
|
|
@ -10,6 +10,16 @@
|
|||
|
||||
namespace lt::renderer {
|
||||
|
||||
/** The main rendering engine.
|
||||
*
|
||||
* Responsible for:
|
||||
* - Creating a rendering backend context (vk/dx/mt)
|
||||
* - Connecting the context to the physical devices (select gpu, create surface, logical device)
|
||||
* - Rendering the scene represented in registry via lt::renderer::components.
|
||||
*
|
||||
* @todo(Light): Add DirectX12 support
|
||||
* @todo(Light): Add Metal support
|
||||
*/
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
|
|
@ -61,6 +71,12 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void handle_surface_resized_events();
|
||||
|
||||
void submit_scene();
|
||||
|
||||
void recreate_swapchain();
|
||||
|
||||
Api m_api;
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
add_library(std INTERFACE)
|
||||
target_precompile_headers(std INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/public/pch.hpp)
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/** @file pch.hpp
|
||||
*
|
||||
* @brief Provides the entire standard library as a precompiled header
|
||||
*/
|
||||
|
||||
#pragma once // NOLINTBEGIN
|
||||
|
||||
//============================================================
|
||||
// C Standard Library Headers (from <c...> family)
|
||||
//============================================================
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cfenv>
|
||||
#include <cfloat>
|
||||
#include <cinttypes>
|
||||
#include <climits>
|
||||
#include <clocale>
|
||||
#include <cmath>
|
||||
#include <csetjmp>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
|
||||
//============================================================
|
||||
// Input/Output and Formatting
|
||||
//============================================================
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
//============================================================
|
||||
// Containers
|
||||
//============================================================
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <flat_map>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
//============================================================
|
||||
// Algorithms and Iterators
|
||||
//============================================================
|
||||
#include <algorithm>
|
||||
#include <execution>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
||||
//============================================================
|
||||
// Strings and Localization
|
||||
//============================================================
|
||||
#include <charconv>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
//============================================================
|
||||
// Memory Management and Smart Pointers
|
||||
//============================================================
|
||||
#include <memory>
|
||||
#include <memory_resource>
|
||||
#include <new>
|
||||
#include <scoped_allocator>
|
||||
|
||||
//============================================================
|
||||
// Utility and Miscellaneous
|
||||
//============================================================
|
||||
#include <any>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <ratio>
|
||||
#include <source_location>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <version>
|
||||
|
||||
//============================================================
|
||||
// Concurrency and Multithreading
|
||||
//============================================================
|
||||
#include <atomic>
|
||||
#include <barrier>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <latch>
|
||||
#include <mutex>
|
||||
#include <semaphore>
|
||||
#include <shared_mutex>
|
||||
#include <stop_token>
|
||||
#include <thread>
|
||||
|
||||
//============================================================
|
||||
// Random Numbers and Numeric Limits
|
||||
//============================================================
|
||||
#include <complex>
|
||||
#include <limits>
|
||||
#include <numbers>
|
||||
#include <random>
|
||||
#include <valarray>
|
||||
|
||||
//============================================================
|
||||
// Regular Expressions
|
||||
//============================================================
|
||||
#include <regex>
|
||||
|
||||
//============================================================
|
||||
// Error Handling and Diagnostics
|
||||
//============================================================
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <exception>
|
||||
#include <source_location>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
//============================================================
|
||||
// C++20/23 Additions
|
||||
//============================================================
|
||||
#include <bit> // C++20 bit operations
|
||||
#include <compare> // C++20 three-way comparison
|
||||
#include <expected> // C++23 std::expected (if supported)
|
||||
#include <format> // C++20 formatting
|
||||
#include <print> // C++23 print functions
|
||||
#include <ranges> // C++20 ranges library
|
||||
#include <span> // C++20 span (repeated intentionally for clarity)
|
||||
// #include <stacktrace> // C++23 stack tracing utilities // Not supported yet
|
||||
#include <syncstream> // C++20 synchronized output streams
|
||||
// NOLINTEND
|
||||
|
|
@ -1,9 +1,29 @@
|
|||
if(NOT WIN32)
|
||||
add_library_module(surface linux/system.cpp)
|
||||
add_library_module(
|
||||
NAME
|
||||
surface
|
||||
INTERFACES
|
||||
system.cppm
|
||||
requests.cppm
|
||||
events.cppm
|
||||
components.cppm
|
||||
SOURCES
|
||||
platform_linux.cpp)
|
||||
target_link_libraries(surface PRIVATE X11)
|
||||
|
||||
else(WIN32)
|
||||
add_library_module(surface windows/system.cpp)
|
||||
add_library_module(
|
||||
NAME
|
||||
surface
|
||||
INTERFACES
|
||||
system.cppm
|
||||
requests.cppm
|
||||
system.cppm
|
||||
requests.cppm
|
||||
events.cppm
|
||||
components.cppm
|
||||
SOURCES
|
||||
platform_windows.cpp)
|
||||
|
||||
endif()
|
||||
|
||||
|
|
@ -13,4 +33,5 @@ target_link_libraries(
|
|||
PRIVATE logger lt_debug time)
|
||||
|
||||
add_test_module(surface system.test.cpp)
|
||||
add_fuzz_module(surface system.fuzz.cpp)
|
||||
|
||||
# add_fuzz_module(surface system.fuzz.cpp)
|
||||
|
|
|
|||
|
|
@ -1,40 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/vec2.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
#include <surface/events/surface.hpp>
|
||||
#include <surface/requests/surface.hpp>
|
||||
#include <variant>
|
||||
|
||||
module;
|
||||
#ifdef LIGHT_PLATFORM_LINUX
|
||||
typedef struct _XDisplay Display;
|
||||
#endif
|
||||
|
||||
export module surface.system:components;
|
||||
import std;
|
||||
import math.vec2;
|
||||
import surface.events;
|
||||
import surface.requests;
|
||||
|
||||
namespace lt::surface {
|
||||
|
||||
/** Represents a platform's surface (eg. a Window).
|
||||
*
|
||||
* @note This is a "system component"
|
||||
*/
|
||||
class SurfaceComponent
|
||||
export class SurfaceComponent
|
||||
{
|
||||
public:
|
||||
friend class System;
|
||||
|
||||
using Event = std::variant<
|
||||
// surface events
|
||||
ClosedEvent,
|
||||
MovedEvent,
|
||||
ResizedEvent,
|
||||
LostFocusEvent,
|
||||
GainFocusEvent,
|
||||
|
||||
// keyboard events
|
||||
KeyPressedEvent,
|
||||
KeyReleasedEvent,
|
||||
|
||||
// mouse events
|
||||
MouseMovedEvent,
|
||||
ButtonPressedEvent,
|
||||
ButtonReleasedEvent>;
|
||||
|
|
@ -49,7 +42,7 @@ public:
|
|||
struct NativeData
|
||||
{
|
||||
Display *display;
|
||||
uint32_t window;
|
||||
std::uint32_t window;
|
||||
unsigned long wm_delete_message;
|
||||
};
|
||||
#endif
|
||||
260
modules/surface/events.cppm
Normal file
260
modules/surface/events.cppm
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
export module surface.events;
|
||||
import math.vec2;
|
||||
import std;
|
||||
|
||||
export namespace lt::surface {
|
||||
|
||||
class KeyPressedEvent
|
||||
{
|
||||
public:
|
||||
KeyPressedEvent(std::uint32_t key): m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> std::uint32_t
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyPressed: {}", m_key);
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint32_t m_key;
|
||||
};
|
||||
|
||||
class KeyRepeatEvent
|
||||
{
|
||||
public:
|
||||
KeyRepeatEvent(std::int32_t key): m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> std::uint32_t
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyRepeated: {}", m_key);
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint32_t m_key;
|
||||
};
|
||||
|
||||
class KeyReleasedEvent
|
||||
{
|
||||
public:
|
||||
KeyReleasedEvent(std::uint32_t key): m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> std::uint32_t
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyReleased: {}", m_key);
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint32_t m_key;
|
||||
};
|
||||
|
||||
class KeySetCharEvent
|
||||
{
|
||||
public:
|
||||
KeySetCharEvent(std::uint32_t character): m_character(character)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_character() const -> std::uint32_t
|
||||
{
|
||||
return m_character;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyCharSet: {}", m_character);
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint32_t m_character;
|
||||
};
|
||||
|
||||
class MouseMovedEvent
|
||||
{
|
||||
public:
|
||||
MouseMovedEvent(float x, float y): m_position(x, y)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_position() const -> const math::vec2 &
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_x() const -> float
|
||||
{
|
||||
return m_position.x;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_y() const -> float
|
||||
{
|
||||
return m_position.y;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("MouseMoved: {}, {}", m_position.x, m_position.y);
|
||||
}
|
||||
|
||||
private:
|
||||
math::vec2 m_position;
|
||||
};
|
||||
|
||||
class WheelScrolledEvent
|
||||
{
|
||||
public:
|
||||
WheelScrolledEvent(float offset): m_offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_offset() const -> float
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "WheelScrolled: " << m_offset;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
float m_offset;
|
||||
};
|
||||
|
||||
class ButtonPressedEvent
|
||||
{
|
||||
public:
|
||||
ButtonPressedEvent(std::int32_t button): m_button(button)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_button() const -> std::int32_t
|
||||
{
|
||||
return m_button;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("ButtonPressed: {}", m_button);
|
||||
}
|
||||
|
||||
private:
|
||||
std::int32_t m_button;
|
||||
};
|
||||
|
||||
class ButtonReleasedEvent
|
||||
{
|
||||
public:
|
||||
ButtonReleasedEvent(std::int32_t button): m_button(button)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_button() const -> std::int32_t
|
||||
{
|
||||
return m_button;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("ButtonReleased: {}", m_button);
|
||||
}
|
||||
|
||||
private:
|
||||
std::int32_t m_button;
|
||||
};
|
||||
|
||||
class ClosedEvent
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto to_string() const -> std::string_view
|
||||
{
|
||||
return "SurfaceClosedEvent";
|
||||
}
|
||||
};
|
||||
|
||||
class MovedEvent
|
||||
{
|
||||
public:
|
||||
MovedEvent(std::int32_t x, std::int32_t y): m_position(x, y)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_position() const -> const math::ivec2 &
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
auto stream = std::stringstream {};
|
||||
stream << "WindwoMoved: " << m_position.x << ", " << m_position.y;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
math::ivec2 m_position;
|
||||
};
|
||||
|
||||
class ResizedEvent
|
||||
{
|
||||
public:
|
||||
ResizedEvent(std::uint32_t width, std::uint32_t height): m_size(width, height)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const -> const math::uvec2 &
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
auto stream = std::stringstream {};
|
||||
stream << "SurfaceResized: " << m_size.x << ", " << m_size.y;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
math::uvec2 m_size;
|
||||
};
|
||||
|
||||
class LostFocusEvent
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto to_string() const -> std::string_view
|
||||
{
|
||||
return "SurfaceLostFocus";
|
||||
}
|
||||
};
|
||||
|
||||
class GainFocusEvent
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto to_string() const -> std::string_view
|
||||
{
|
||||
return "SurfaceGainFocus";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace lt::surface
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
#include <surface/requests/surface.hpp>
|
||||
#include <surface/system.hpp>
|
||||
#include <time/timer.hpp>
|
||||
|
||||
//
|
||||
module;
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/keysymdef.h>
|
||||
|
||||
//
|
||||
module surface.system;
|
||||
import debug.assertions;
|
||||
import memory.reference;
|
||||
import surface.requests;
|
||||
import surface.events;
|
||||
import logger;
|
||||
import ecs.registry;
|
||||
import time;
|
||||
import std;
|
||||
|
||||
namespace lt::surface {
|
||||
|
||||
|
|
@ -51,9 +52,9 @@ constexpr auto all_events_mask = KeyPressMask | //
|
|||
|
||||
System::System(memory::Ref<ecs::Registry> registry): m_registry(std::move(registry))
|
||||
{
|
||||
ensure(m_registry, "Failed to initialize surface system: null registry");
|
||||
debug::ensure(m_registry, "Failed to initialize surface system: null registry");
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_registry->view<SurfaceComponent>().get_size() == 0,
|
||||
"Failed to initialize surface system: registry has surface component(s)"
|
||||
);
|
||||
|
|
@ -116,15 +117,15 @@ try
|
|||
// TODO(Light): refactor "environment" into standalone module
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
auto *display_env = std::getenv("DISPLAY");
|
||||
ensure(display_env != nullptr, "DISPLAY env var not found!");
|
||||
debug::ensure(display_env != nullptr, "DISPLAY env var not found!");
|
||||
|
||||
auto *display = XOpenDisplay(display_env);
|
||||
ensure(display, "Failed to open XDisplay with DISPLAY: {}", display_env);
|
||||
debug::ensure(display, "Failed to open XDisplay with DISPLAY: {}", display_env);
|
||||
|
||||
auto root_window = XDefaultRootWindow(display);
|
||||
|
||||
auto border_width = 0;
|
||||
auto depth = int32_t { CopyFromParent };
|
||||
auto depth = std::int32_t { CopyFromParent };
|
||||
auto window_class = CopyFromParent;
|
||||
auto *visual = (Visual *)CopyFromParent;
|
||||
|
||||
|
|
@ -226,14 +227,14 @@ void System::handle_events(SurfaceComponent &surface)
|
|||
case KeyPress:
|
||||
{
|
||||
queue.emplace_back<KeyPressedEvent>(
|
||||
static_cast<uint32_t>(XLookupKeysym(&event.xkey, 0))
|
||||
static_cast<std::uint32_t>(XLookupKeysym(&event.xkey, 0))
|
||||
);
|
||||
break;
|
||||
}
|
||||
case KeyRelease:
|
||||
{
|
||||
queue.emplace_back<KeyReleasedEvent>(
|
||||
static_cast<uint32_t>(XLookupKeysym(&event.xkey, 0))
|
||||
static_cast<std::uint32_t>(XLookupKeysym(&event.xkey, 0))
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -284,8 +285,8 @@ void System::handle_events(SurfaceComponent &surface)
|
|||
surface.m_resolution.x = new_width;
|
||||
surface.m_resolution.y = new_height;
|
||||
queue.emplace_back<ResizedEvent>(ResizedEvent {
|
||||
static_cast<uint32_t>(new_width),
|
||||
static_cast<uint32_t>(new_height),
|
||||
static_cast<std::uint32_t>(new_width),
|
||||
static_cast<std::uint32_t>(new_height),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +348,12 @@ void System::modify_resolution(SurfaceComponent &surface, const ModifyResolution
|
|||
auto serial = NextRequest(display);
|
||||
|
||||
// request a new window size from the X server
|
||||
XResizeWindow(display, window, static_cast<uint32_t>(width), static_cast<uint32_t>(height));
|
||||
XResizeWindow(
|
||||
display,
|
||||
window,
|
||||
static_cast<std::uint32_t>(width),
|
||||
static_cast<std::uint32_t>(height)
|
||||
);
|
||||
|
||||
// flush output queue and wait for X server to processes the request
|
||||
XSync(display, False);
|
||||
|
|
@ -367,7 +373,7 @@ void System::modify_resolution(SurfaceComponent &surface, const ModifyResolution
|
|||
// the size we asked for). We receive a ConfigureNotify event when
|
||||
// our new size has been set.
|
||||
constexpr auto lifespan = std::chrono::milliseconds { 10 };
|
||||
auto timer = Timer {};
|
||||
auto timer = time::Timer {};
|
||||
auto event = XEvent {};
|
||||
while (!XCheckIfEvent(
|
||||
display,
|
||||
|
|
@ -406,7 +412,7 @@ void System::modify_position(SurfaceComponent &surface, const ModifyPositionRequ
|
|||
// flush output queue and wait for X server to processes the request
|
||||
XSync(display, False);
|
||||
constexpr auto lifespan = std::chrono::milliseconds { 10 };
|
||||
auto timer = Timer {};
|
||||
auto timer = time::Timer {};
|
||||
auto event = XEvent {};
|
||||
while (!XCheckIfEvent(
|
||||
display,
|
||||
|
|
@ -466,25 +472,29 @@ void ensure_component_sanity(const SurfaceComponent &component)
|
|||
{
|
||||
auto [width, height] = component.get_resolution();
|
||||
|
||||
ensure(width != 0u, "Received bad values for surface component: width({}) == 0", width);
|
||||
debug::ensure(width != 0u, "Received bad values for surface component: width({}) == 0", width);
|
||||
|
||||
ensure(height != 0u, "Received bad values for surface component: height({}) == 0", height);
|
||||
debug::ensure(
|
||||
height != 0u,
|
||||
"Received bad values for surface component: height({}) == 0",
|
||||
height
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
width < SurfaceComponent::max_dimension,
|
||||
"Received bad values for surface component: width({}) > max_dimension({})",
|
||||
width,
|
||||
SurfaceComponent::max_dimension
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
height < SurfaceComponent::max_dimension,
|
||||
"Received bad values for surface component: height({}) > max_dimension({})",
|
||||
height,
|
||||
SurfaceComponent::max_dimension
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
component.get_title().size() < SurfaceComponent::max_title_length,
|
||||
"Received bad values for surface component: title.size({}) > max_title_length({})",
|
||||
component.get_title().size(),
|
||||
|
|
@ -1 +0,0 @@
|
|||
1484824981238913982498139812098u24
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
|
||||
namespace lt::surface {
|
||||
|
||||
class KeyPressedEvent
|
||||
{
|
||||
public:
|
||||
KeyPressedEvent(uint32_t key): m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> uint32_t
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyPressed: {}", m_key);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_key;
|
||||
};
|
||||
|
||||
class KeyRepeatEvent
|
||||
{
|
||||
public:
|
||||
KeyRepeatEvent(int key): m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> uint32_t
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyRepeated: {}", m_key);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_key;
|
||||
};
|
||||
|
||||
class KeyReleasedEvent
|
||||
{
|
||||
public:
|
||||
KeyReleasedEvent(uint32_t key): m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> uint32_t
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyReleased: {}", m_key);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_key;
|
||||
};
|
||||
|
||||
class KeySetCharEvent
|
||||
{
|
||||
public:
|
||||
KeySetCharEvent(uint32_t character): m_character(character)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_character() const -> uint32_t
|
||||
{
|
||||
return m_character;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("KeyCharSet: {}", m_character);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_character;
|
||||
};
|
||||
|
||||
} // namespace lt::surface
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/vec2.hpp>
|
||||
|
||||
namespace lt::surface {
|
||||
|
||||
class MouseMovedEvent
|
||||
{
|
||||
public:
|
||||
MouseMovedEvent(float x, float y): m_position(x, y)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_position() const -> const math::vec2 &
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_x() const -> float
|
||||
{
|
||||
return m_position.x;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_y() const -> float
|
||||
{
|
||||
return m_position.y;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("MouseMoved: {}, {}", m_position.x, m_position.y);
|
||||
}
|
||||
|
||||
private:
|
||||
math::vec2 m_position;
|
||||
};
|
||||
|
||||
class WheelScrolledEvent
|
||||
{
|
||||
public:
|
||||
WheelScrolledEvent(float offset): m_offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_offset() const -> float
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "WheelScrolled: " << m_offset;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
float m_offset;
|
||||
};
|
||||
|
||||
class ButtonPressedEvent
|
||||
{
|
||||
public:
|
||||
ButtonPressedEvent(int button): m_button(button)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_button() const -> int
|
||||
{
|
||||
return m_button;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("ButtonPressed: {}", m_button);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_button;
|
||||
};
|
||||
|
||||
class ButtonReleasedEvent
|
||||
{
|
||||
public:
|
||||
ButtonReleasedEvent(int button): m_button(button)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_button() const -> int
|
||||
{
|
||||
return m_button;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
return std::format("ButtonReleased: {}", m_button);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_button;
|
||||
};
|
||||
|
||||
} // namespace lt::surface
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/vec2.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace lt::surface {
|
||||
|
||||
class ClosedEvent
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto to_string() const -> std::string_view
|
||||
{
|
||||
return "SurfaceClosedEvent";
|
||||
}
|
||||
};
|
||||
|
||||
class MovedEvent
|
||||
{
|
||||
public:
|
||||
MovedEvent(int x, int y): m_position(x, y)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_position() const -> const math::ivec2 &
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
auto stream = std::stringstream {};
|
||||
stream << "WindwoMoved: " << m_position.x << ", " << m_position.y;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
math::ivec2 m_position;
|
||||
};
|
||||
|
||||
class ResizedEvent
|
||||
{
|
||||
public:
|
||||
ResizedEvent(unsigned int width, unsigned int height): m_size(width, height)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const -> const math::uvec2 &
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
auto stream = std::stringstream {};
|
||||
stream << "SurfaceResized: " << m_size.x << ", " << m_size.y;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
math::uvec2 m_size;
|
||||
};
|
||||
|
||||
class LostFocusEvent
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto to_string() const -> std::string_view
|
||||
{
|
||||
return "SurfaceLostFocus";
|
||||
}
|
||||
};
|
||||
|
||||
class GainFocusEvent
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto to_string() const -> std::string_view
|
||||
{
|
||||
return "SurfaceGainFocus";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace lt::surface
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
export module surface.requests;
|
||||
import math.vec2;
|
||||
import std;
|
||||
|
||||
#include <math/vec2.hpp>
|
||||
|
||||
namespace lt::surface {
|
||||
export namespace lt::surface {
|
||||
|
||||
struct ModifyTitleRequest
|
||||
{
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <math/vec2.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
export module surface.system;
|
||||
export import :components;
|
||||
import app.system;
|
||||
import ecs.registry;
|
||||
import math.vec2;
|
||||
import surface.requests;
|
||||
import memory.reference;
|
||||
import std;
|
||||
|
||||
namespace lt::surface {
|
||||
|
||||
class System: public app::ISystem
|
||||
export class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] System(memory::Ref<ecs::Registry> registry);
|
||||
|
|
@ -39,26 +40,17 @@ public:
|
|||
private:
|
||||
void on_surface_destruct(ecs::Registry ®istry, ecs::EntityId entity);
|
||||
|
||||
void handle_requests(struct SurfaceComponent &surface);
|
||||
void handle_requests(SurfaceComponent &surface);
|
||||
|
||||
void handle_events(struct SurfaceComponent &surface);
|
||||
void handle_events(SurfaceComponent &surface);
|
||||
|
||||
void modify_title(struct SurfaceComponent &surface, const struct ModifyTitleRequest &request);
|
||||
void modify_title(SurfaceComponent &surface, const ModifyTitleRequest &request);
|
||||
|
||||
void modify_resolution(
|
||||
struct SurfaceComponent &surface,
|
||||
const struct ModifyResolutionRequest &request
|
||||
);
|
||||
void modify_resolution(SurfaceComponent &surface, const ModifyResolutionRequest &request);
|
||||
|
||||
void modify_position(
|
||||
struct SurfaceComponent &surface,
|
||||
const struct ModifyPositionRequest &request
|
||||
);
|
||||
void modify_position(SurfaceComponent &surface, const ModifyPositionRequest &request);
|
||||
|
||||
void modify_visiblity(
|
||||
struct SurfaceComponent &surface,
|
||||
const struct ModifyVisibilityRequest &request
|
||||
);
|
||||
void modify_visiblity(SurfaceComponent &surface, const ModifyVisibilityRequest &request);
|
||||
|
||||
void modify_position(ecs::EntityId surface_entity, const math::ivec2 &new_size);
|
||||
|
||||
|
|
@ -1,24 +1,29 @@
|
|||
#include <ecs/entity.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <ranges>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/requests/surface.hpp>
|
||||
#include <surface/system.hpp>
|
||||
#include <test/test.hpp>
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import surface.system;
|
||||
import surface.events;
|
||||
import surface.requests;
|
||||
import ecs.registry;
|
||||
import memory.scope;
|
||||
import memory.reference;
|
||||
import logger;
|
||||
import math.vec2;
|
||||
import app.system;
|
||||
import std;
|
||||
|
||||
using namespace lt;
|
||||
using std::ignore;
|
||||
using surface::SurfaceComponent;
|
||||
using surface::System;
|
||||
using test::Case;
|
||||
using test::expect_eq;
|
||||
using test::expect_ne;
|
||||
using test::expect_not_nullptr;
|
||||
using test::expect_throw;
|
||||
using test::Suite;
|
||||
|
||||
[[nodiscard]] auto tick_info() -> app::TickInfo
|
||||
using ::std::ignore;
|
||||
using ::lt::surface::SurfaceComponent;
|
||||
using ::lt::surface::System;
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_ne;
|
||||
using ::lt::test::expect_not_nullptr;
|
||||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
[[nodiscard]] auto tick_info() -> lt::app::TickInfo
|
||||
{
|
||||
return {
|
||||
.delta_time = std::chrono::milliseconds { 16 },
|
||||
|
|
@ -43,7 +48,7 @@ struct overloads: Ts...
|
|||
class Fixture
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto registry() -> memory::Ref<ecs::Registry>
|
||||
[[nodiscard]] auto registry() -> lt::memory::Ref<lt::ecs::Registry>
|
||||
{
|
||||
return m_registry;
|
||||
}
|
||||
|
|
@ -78,7 +83,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
memory::Ref<ecs::Registry> m_registry = memory::create_ref<ecs::Registry>();
|
||||
lt::memory::Ref<lt::ecs::Registry> m_registry = lt::memory::create_ref<lt::ecs::Registry>();
|
||||
|
||||
System m_system { m_registry };
|
||||
};
|
||||
|
|
@ -110,7 +115,7 @@ Suite raii = "raii"_suite = [] {
|
|||
|
||||
Case { "post destruct has correct state" } = [] {
|
||||
auto fixture = Fixture {};
|
||||
auto system = memory::create_scope<System>(fixture.registry());
|
||||
auto system = lt::memory::create_scope<System>(fixture.registry());
|
||||
|
||||
fixture.create_component();
|
||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
||||
|
|
@ -185,7 +190,7 @@ Suite registry_events = "registry_events"_suite = [] {
|
|||
|
||||
Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
|
||||
auto fixture = Fixture {};
|
||||
auto system = memory::create_scope<System>(fixture.registry());
|
||||
auto system = lt::memory::create_scope<System>(fixture.registry());
|
||||
|
||||
const auto &component = fixture.create_component();
|
||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
||||
|
|
@ -221,10 +226,10 @@ Suite tick_handles_events = "tick_handles_events"_suite = [] {
|
|||
system.tick(tick_info());
|
||||
expect_eq(surface.peek_events().size(), 0);
|
||||
|
||||
surface.push_event(surface::MovedEvent({}, {}));
|
||||
surface.push_event(lt::surface::MovedEvent({}, {}));
|
||||
expect_eq(surface.peek_events().size(), 1);
|
||||
|
||||
surface.push_event(surface::ButtonPressedEvent({}));
|
||||
surface.push_event(lt::surface::ButtonPressedEvent({}));
|
||||
expect_eq(surface.peek_events().size(), 2);
|
||||
|
||||
system.tick(tick_info());
|
||||
|
|
@ -239,26 +244,26 @@ Suite tick_handles_requests = "tick_handles_requests"_suite = [] {
|
|||
auto &surface = **fixture.create_component();
|
||||
|
||||
constexpr auto title = "ABC";
|
||||
constexpr auto position = math::ivec2 { 50, 50 };
|
||||
constexpr auto resolution = math::uvec2 { 50, 50 };
|
||||
constexpr auto position = lt::math::ivec2 { 50, 50 };
|
||||
constexpr auto resolution = lt::math::uvec2 { 50, 50 };
|
||||
|
||||
expect_eq(surface.peek_requests().size(), 0);
|
||||
|
||||
surface.push_request(surface::ModifyVisibilityRequest(true));
|
||||
surface.push_request(lt::surface::ModifyVisibilityRequest(true));
|
||||
expect_eq(surface.peek_requests().size(), 1);
|
||||
system.tick(tick_info());
|
||||
expect_eq(surface.peek_requests().size(), 0);
|
||||
|
||||
surface.push_request(surface::ModifyTitleRequest(title));
|
||||
surface.push_request(lt::surface::ModifyTitleRequest(title));
|
||||
expect_eq(surface.peek_requests().size(), 1);
|
||||
|
||||
surface.push_request(surface::ModifyResolutionRequest(resolution));
|
||||
surface.push_request(surface::ModifyPositionRequest(position));
|
||||
surface.push_request(lt::surface::ModifyResolutionRequest(resolution));
|
||||
surface.push_request(lt::surface::ModifyPositionRequest(position));
|
||||
expect_eq(surface.peek_requests().size(), 1 + 2);
|
||||
|
||||
surface.push_request(surface::ModifyVisibilityRequest(false));
|
||||
surface.push_request(surface::ModifyVisibilityRequest(true));
|
||||
surface.push_request(surface::ModifyVisibilityRequest(false));
|
||||
surface.push_request(lt::surface::ModifyVisibilityRequest(false));
|
||||
surface.push_request(lt::surface::ModifyVisibilityRequest(true));
|
||||
surface.push_request(lt::surface::ModifyVisibilityRequest(false));
|
||||
expect_eq(surface.peek_requests().size(), 1 + 2 + 3);
|
||||
|
||||
system.tick(tick_info());
|
||||
|
|
@ -268,11 +273,11 @@ Suite tick_handles_requests = "tick_handles_requests"_suite = [] {
|
|||
expect_eq(surface.get_position(), position);
|
||||
expect_eq(surface.get_resolution(), resolution);
|
||||
|
||||
log::debug("EVENT COUNT: {}", surface.peek_events().size());
|
||||
lt::log::debug("EVENT COUNT: {}", surface.peek_events().size());
|
||||
for (const auto &event : surface.peek_events())
|
||||
{
|
||||
const auto visitor = overloads {
|
||||
[&](auto event) { log::debug("event: {}", event.to_string()); },
|
||||
[&](auto event) { lt::log::debug("event: {}", event.to_string()); },
|
||||
};
|
||||
|
||||
std::visit(visitor, event);
|
||||
|
|
@ -1,7 +1,16 @@
|
|||
add_library_module(test test.cpp entrypoint.cpp)
|
||||
add_library_module(fuzz_test test.cpp fuzz.cpp)
|
||||
add_library_module(
|
||||
NAME
|
||||
test
|
||||
INTERFACES
|
||||
test.cppm
|
||||
expects.cppm
|
||||
PRIVATE_INTERFACES
|
||||
registry.cppm
|
||||
SOURCES
|
||||
entrypoint.cpp)
|
||||
# add_library_module(fuzz_test test.cpp fuzz.cpp)
|
||||
|
||||
target_link_libraries(test PUBLIC logger)
|
||||
target_link_libraries(fuzz_test PUBLIC logger)
|
||||
# target_link_libraries(fuzz_test PUBLIC logger)
|
||||
|
||||
add_test_module(test test.test.cpp)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <test/test.hpp>
|
||||
import logger;
|
||||
import test.test;
|
||||
import test.registry;
|
||||
|
||||
import std;
|
||||
|
||||
using namespace ::lt::test;
|
||||
using namespace ::lt::test::details;
|
||||
|
||||
void parse_option(std::string_view argument, Registry::Options &options)
|
||||
{
|
||||
|
|
@ -49,7 +51,7 @@ void print_help()
|
|||
std::println("--help | -h --> ~You just used it! :D");
|
||||
}
|
||||
|
||||
auto main(int32_t argc, char **argv) -> int32_t
|
||||
auto main(std::int32_t argc, char **argv) -> std::int32_t
|
||||
try
|
||||
{
|
||||
auto raw_arguments = std::span<char *>(argv, argc);
|
||||
|
|
@ -81,18 +83,18 @@ try
|
|||
}
|
||||
}
|
||||
|
||||
return static_cast<int32_t>(Registry::run_all(options));
|
||||
return static_cast<std::int32_t>(Registry::run_all(options));
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminated due to uncaught exception:");
|
||||
lt::log::critical("\twhat: {}", exp.what());
|
||||
|
||||
return EXIT_FAILURE;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
lt::log::critical("Terminated due to uncaught non-std exception!");
|
||||
|
||||
return EXIT_FAILURE;
|
||||
return 1;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue