Redesign resources system: centralized id-based resource registry

This commit is contained in:
Nikita Lisitsa 2022-03-07 00:05:40 +03:00
parent 2c0001be28
commit 75e6db45f1
9 changed files with 183 additions and 10 deletions

View file

@ -164,7 +164,7 @@ namespace psemek::gfx
text_mesh.setup<geom::point<float, 3>, gfx::normalized<color_rgba>, geom::point<std::uint16_t, 2>>();
texture_mesh.setup<geom::point<float, 3>, gfx::normalized<geom::point<std::uint16_t, 2>>>();
font_texture.load(gfx::read_png_monochrome(io::memory_istream{resource::font_9x12_png}));
font_texture.load(gfx::read_png_monochrome(io::memory_istream{resource::font_9x12_png.data}));
font_texture.bind();
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_SWIZZLE_G, gl::RED);

6
libs/rs/CMakeLists.txt Normal file
View file

@ -0,0 +1,6 @@
file(GLOB_RECURSE PSEMEK_IO_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "include/*.hpp")
file(GLOB_RECURSE PSEMEK_IO_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "source/*.cpp")
psemek_add_library(psemek-rs ${PSEMEK_IO_HEADERS} ${PSEMEK_IO_SOURCES})
target_include_directories(psemek-rs PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(psemek-rs PRIVATE psemek-util)

View file

@ -0,0 +1,40 @@
#pragma once
#include <psemek/rs/resource.hpp>
#include <stdexcept>
namespace psemek::rs
{
struct unknown_id_error
: std::runtime_error
{
unknown_id_error(rs::id id);
rs::id id() const { return id_; }
private:
rs::id id_;
};
struct unknown_name_error
: std::runtime_error
{
unknown_name_error(std::string_view name);
std::string_view name() const { return name_; }
private:
std::string_view name_;
};
resource const * find(id id);
resource const * find(std::string_view name);
resource const & get(id id);
resource const & get(std::string_view name);
id add(std::string_view name, std::string_view data);
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <cstdint>
#include <string_view>
namespace psemek::rs
{
using id = std::uint32_t;
struct resource
{
rs::id id;
std::string_view name;
std::string_view data;
};
}

106
libs/rs/source/registry.cpp Normal file
View file

@ -0,0 +1,106 @@
#include <psemek/rs/registry.hpp>
#include <psemek/util/to_string.hpp>
#include <map>
#include <unordered_map>
#include <mutex>
#include <atomic>
#include <optional>
namespace psemek::rs
{
namespace
{
auto & resources_mutex()
{
static std::mutex instance;
return instance;
}
auto & resources()
{
static std::map<id, resource> instance;
return instance;
}
auto & name_map_mutex()
{
static std::mutex instance;
return instance;
}
auto & name_map()
{
static std::unordered_map<std::string_view, id> instance;
return instance;
}
std::atomic<id> next_id{0};
}
unknown_id_error::unknown_id_error(rs::id id)
: std::runtime_error(util::to_string("unknown resource id: ", id))
, id_(id)
{}
unknown_name_error::unknown_name_error(std::string_view name)
: std::runtime_error(util::to_string("unknown resource name: ", name))
{}
resource const * find(id id)
{
std::lock_guard lock{resources_mutex()};
auto it = resources().find(id);
if (it == resources().end())
return nullptr;
return &(it->second);
}
resource const * find(std::string_view name)
{
rs::id id;
{
std::lock_guard lock{name_map_mutex()};
auto it = name_map().find(name);
if (it == name_map().end())
return nullptr;
id = it->second;
}
return find(id);
}
resource const & get(id id)
{
auto result = find(id);
if (!result)
throw unknown_id_error{id};
return *result;
}
resource const & get(std::string_view name)
{
auto result = find(name);
if (!result)
throw unknown_name_error{name};
return *result;
}
id add(std::string_view name, std::string_view data)
{
auto id = next_id.fetch_add(1);
{
std::lock_guard lock{name_map_mutex()};
name_map()[name] = id;
}
{
std::lock_guard lock{resources_mutex()};
resources()[id] = {id, name, data};
}
return id;
}
}

View file

@ -718,7 +718,7 @@ namespace psemek::ui
default_element_factory::impl::impl()
{
cross_red_16x16 = std::make_shared<gfx::texture_2d>(gfx::texture_2d::from_pixmap(gfx::read_png(io::memory_istream{resources::cross_red_16x16_png})));
cross_red_16x16 = std::make_shared<gfx::texture_2d>(gfx::texture_2d::from_pixmap(gfx::read_png(io::memory_istream{resources::cross_red_16x16_png.data})));
cross_red_16x16->nearest_filter();
}

View file

@ -18,7 +18,7 @@ namespace psemek::ui
std::string_view name = "default_monospace_9x12";
geom::vector<int, 2> size{9, 12};
gfx::texture_2d atlas = gfx::texture_2d::from_pixmap(gfx::read_png_monochrome(io::memory_istream{gfx::resource::font_9x12_png}));
gfx::texture_2d atlas = gfx::texture_2d::from_pixmap(gfx::read_png_monochrome(io::memory_istream{gfx::resource::font_9x12_png.data}));
atlas.nearest_filter();
atlas.clamp();
gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_G, gl::RED);
@ -49,7 +49,7 @@ namespace psemek::ui
std::string_view name = "default_9x12";
geom::vector<int, 2> size{9, 12};
gfx::texture_2d atlas = gfx::texture_2d::from_pixmap(gfx::read_png_monochrome(io::memory_istream{gfx::resource::font_9x12_png}));
gfx::texture_2d atlas = gfx::texture_2d::from_pixmap(gfx::read_png_monochrome(io::memory_istream{gfx::resource::font_9x12_png.data}));
atlas.nearest_filter();
atlas.clamp();
gl::TexParameteri(atlas.target, gl::TEXTURE_SWIZZLE_G, gl::RED);
@ -58,7 +58,7 @@ namespace psemek::ui
std::unordered_map<char32_t, kerned_font::glyph_data> glyphs;
{
std::istringstream is{std::string(ui::resources::font_9x12_glyphs_txt)};
std::istringstream is{std::string(ui::resources::font_9x12_glyphs_txt.data)};
std::string line;
while (std::getline(is, line))

View file

@ -7,6 +7,8 @@ function(psemek_add_resources_impl MODE TARGET)
endif()
endif()
target_link_libraries(${TARGET} ${MODE} psemek-rs)
get_target_property(OUT_DIR ${TARGET} BINARY_DIR)
get_target_property(INPUT_DIR ${TARGET} SOURCE_DIR)

View file

@ -13,7 +13,8 @@ int main(int argc, char * argv[])
return EXIT_FAILURE;
}
std::string name = argv[2];
std::string fullname = argv[2];
std::string name = fullname;
std::string ns;
std::size_t const last_slash = name.find_last_of('/');
@ -43,7 +44,7 @@ int main(int argc, char * argv[])
output_header
<< "#pragma once\n"
<< "\n"
<< "#include <string_view>\n"
<< "#include <psemek/rs/resource.hpp>\n"
<< "\n";
if (!ns.empty()) output_header
@ -51,7 +52,7 @@ int main(int argc, char * argv[])
<< "{\n"
<< "\n";
output_header << tab << "extern std::string_view " << name << ";\n";
output_header << tab << "extern ::psemek::rs::resource const & " << name << ";\n";
if (!ns.empty()) output_header
<< "\n"
@ -62,7 +63,7 @@ int main(int argc, char * argv[])
std::ofstream output_source{argv[4]};
output_source
<< "#include <string_view>\n"
<< "#include <psemek/rs/registry.hpp>\n"
<< "\n";
output_source << "alignas(16) static const char data[" << input_data.size() << "] = {\n";
@ -94,7 +95,7 @@ int main(int argc, char * argv[])
<< "{\n"
<< "\n";
output_source << tab << "std::string_view " << name << "{data, sizeof(data)};\n";
output_source << tab << "::psemek::rs::resource const & " << name << " = ::psemek::rs::get(::psemek::rs::add(\"" << fullname << "\", {data, sizeof(data)}));\n";
if (!ns.empty()) output_source
<< "\n"