diff --git a/res/textures/blocks/bazalt.png b/res/content/base/textures/blocks/bazalt.png similarity index 100% rename from res/textures/blocks/bazalt.png rename to res/content/base/textures/blocks/bazalt.png diff --git a/res/textures/blocks/blue_lamp.png b/res/content/base/textures/blocks/blue_lamp.png similarity index 100% rename from res/textures/blocks/blue_lamp.png rename to res/content/base/textures/blocks/blue_lamp.png diff --git a/res/textures/blocks/brick.png b/res/content/base/textures/blocks/brick.png similarity index 100% rename from res/textures/blocks/brick.png rename to res/content/base/textures/blocks/brick.png diff --git a/res/textures/blocks/dirt.png b/res/content/base/textures/blocks/dirt.png similarity index 100% rename from res/textures/blocks/dirt.png rename to res/content/base/textures/blocks/dirt.png diff --git a/res/textures/blocks/flower.png b/res/content/base/textures/blocks/flower.png similarity index 100% rename from res/textures/blocks/flower.png rename to res/content/base/textures/blocks/flower.png diff --git a/res/textures/blocks/glass.png b/res/content/base/textures/blocks/glass.png similarity index 100% rename from res/textures/blocks/glass.png rename to res/content/base/textures/blocks/glass.png diff --git a/res/textures/blocks/grass.png b/res/content/base/textures/blocks/grass.png similarity index 100% rename from res/textures/blocks/grass.png rename to res/content/base/textures/blocks/grass.png diff --git a/res/textures/blocks/grass_side.png b/res/content/base/textures/blocks/grass_side.png similarity index 100% rename from res/textures/blocks/grass_side.png rename to res/content/base/textures/blocks/grass_side.png diff --git a/res/textures/blocks/grass_top.png b/res/content/base/textures/blocks/grass_top.png similarity index 100% rename from res/textures/blocks/grass_top.png rename to res/content/base/textures/blocks/grass_top.png diff --git a/res/textures/blocks/green_lamp.png b/res/content/base/textures/blocks/green_lamp.png similarity index 100% rename from res/textures/blocks/green_lamp.png rename to res/content/base/textures/blocks/green_lamp.png diff --git a/res/textures/blocks/lamp.png b/res/content/base/textures/blocks/lamp.png similarity index 100% rename from res/textures/blocks/lamp.png rename to res/content/base/textures/blocks/lamp.png diff --git a/res/textures/blocks/leaves.png b/res/content/base/textures/blocks/leaves.png similarity index 100% rename from res/textures/blocks/leaves.png rename to res/content/base/textures/blocks/leaves.png diff --git a/res/textures/blocks/lightbulb.png b/res/content/base/textures/blocks/lightbulb.png similarity index 100% rename from res/textures/blocks/lightbulb.png rename to res/content/base/textures/blocks/lightbulb.png diff --git a/res/textures/blocks/metal.png b/res/content/base/textures/blocks/metal.png similarity index 100% rename from res/textures/blocks/metal.png rename to res/content/base/textures/blocks/metal.png diff --git a/res/textures/blocks/pane.png b/res/content/base/textures/blocks/pane.png similarity index 100% rename from res/textures/blocks/pane.png rename to res/content/base/textures/blocks/pane.png diff --git a/res/textures/blocks/pane_side.png b/res/content/base/textures/blocks/pane_side.png similarity index 100% rename from res/textures/blocks/pane_side.png rename to res/content/base/textures/blocks/pane_side.png diff --git a/res/textures/blocks/pane_side_2.png b/res/content/base/textures/blocks/pane_side_2.png similarity index 100% rename from res/textures/blocks/pane_side_2.png rename to res/content/base/textures/blocks/pane_side_2.png diff --git a/res/textures/blocks/pipe_hole.png b/res/content/base/textures/blocks/pipe_hole.png similarity index 100% rename from res/textures/blocks/pipe_hole.png rename to res/content/base/textures/blocks/pipe_hole.png diff --git a/res/textures/blocks/pipe_side.png b/res/content/base/textures/blocks/pipe_side.png similarity index 100% rename from res/textures/blocks/pipe_side.png rename to res/content/base/textures/blocks/pipe_side.png diff --git a/res/textures/blocks/planks.png b/res/content/base/textures/blocks/planks.png similarity index 100% rename from res/textures/blocks/planks.png rename to res/content/base/textures/blocks/planks.png diff --git a/res/textures/blocks/red_lamp.png b/res/content/base/textures/blocks/red_lamp.png similarity index 100% rename from res/textures/blocks/red_lamp.png rename to res/content/base/textures/blocks/red_lamp.png diff --git a/res/textures/blocks/rust.png b/res/content/base/textures/blocks/rust.png similarity index 100% rename from res/textures/blocks/rust.png rename to res/content/base/textures/blocks/rust.png diff --git a/res/textures/blocks/sand.png b/res/content/base/textures/blocks/sand.png similarity index 100% rename from res/textures/blocks/sand.png rename to res/content/base/textures/blocks/sand.png diff --git a/res/textures/blocks/stone.png b/res/content/base/textures/blocks/stone.png similarity index 100% rename from res/textures/blocks/stone.png rename to res/content/base/textures/blocks/stone.png diff --git a/res/textures/blocks/torch_bottom.png b/res/content/base/textures/blocks/torch_bottom.png similarity index 100% rename from res/textures/blocks/torch_bottom.png rename to res/content/base/textures/blocks/torch_bottom.png diff --git a/res/textures/blocks/torch_side.png b/res/content/base/textures/blocks/torch_side.png similarity index 100% rename from res/textures/blocks/torch_side.png rename to res/content/base/textures/blocks/torch_side.png diff --git a/res/textures/blocks/torch_top.png b/res/content/base/textures/blocks/torch_top.png similarity index 100% rename from res/textures/blocks/torch_top.png rename to res/content/base/textures/blocks/torch_top.png diff --git a/res/textures/blocks/wallpaper_s.png b/res/content/base/textures/blocks/wallpaper_s.png similarity index 100% rename from res/textures/blocks/wallpaper_s.png rename to res/content/base/textures/blocks/wallpaper_s.png diff --git a/res/textures/blocks/water.png b/res/content/base/textures/blocks/water.png similarity index 100% rename from res/textures/blocks/water.png rename to res/content/base/textures/blocks/water.png diff --git a/res/textures/blocks/wood.png b/res/content/base/textures/blocks/wood.png similarity index 100% rename from res/textures/blocks/wood.png rename to res/content/base/textures/blocks/wood.png diff --git a/res/textures/blocks/wood_top.png b/res/content/base/textures/blocks/wood_top.png similarity index 100% rename from res/textures/blocks/wood_top.png rename to res/content/base/textures/blocks/wood_top.png diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 98fe994d..dd255dac 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -7,19 +7,20 @@ #include #include "../constants.h" +#include "../files/engine_paths.h" using std::filesystem::path; using std::unique_ptr; -AssetsLoader::AssetsLoader(Assets* assets, path resdir) - : assets(assets), resdir(resdir) { +AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths) + : assets(assets), paths(paths) { } void AssetsLoader::addLoader(int tag, aloader_func func) { loaders[tag] = func; } -void AssetsLoader::add(int tag, const path filename, const std::string alias) { +void AssetsLoader::add(int tag, const std::string filename, const std::string alias) { entries.push(aloader_entry{ tag, filename, alias }); } @@ -37,7 +38,7 @@ bool AssetsLoader::loadNext() { return false; } aloader_func loader = found->second; - bool status = loader(assets, entry.filename, entry.alias); + bool status = loader(assets, paths, entry.filename, entry.alias); entries.pop(); return status; } @@ -50,20 +51,19 @@ void AssetsLoader::createDefaults(AssetsLoader& loader) { } void AssetsLoader::addDefaults(AssetsLoader& loader) { - path resdir = loader.getDirectory(); - loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/main"), "main"); - loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/lines"), "lines"); - loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/ui"), "ui"); - loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/ui3d"), "ui3d"); - loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/background"), "background"); - loader.add(ASSET_SHADER, resdir/path(SHADERS_FOLDER"/skybox_gen"), "skybox_gen"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); - loader.add(ASSET_ATLAS, resdir/path(TEXTURES_FOLDER"/blocks"), "blocks"); - loader.add(ASSET_TEXTURE, resdir/path(TEXTURES_FOLDER"/menubg.png"), "menubg"); + loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/blocks", "blocks"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/menubg.png", "menubg"); - loader.add(ASSET_FONT, resdir/path(FONTS_FOLDER"/font"), "normal"); + loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal"); } -path AssetsLoader::getDirectory() const { - return resdir; +const ResPaths* AssetsLoader::getPaths() const { + return paths; } \ No newline at end of file diff --git a/src/assets/AssetsLoader.h b/src/assets/AssetsLoader.h index 43e3bdca..9a731780 100644 --- a/src/assets/AssetsLoader.h +++ b/src/assets/AssetsLoader.h @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -12,13 +11,14 @@ const short ASSET_SHADER = 2; const short ASSET_FONT = 3; const short ASSET_ATLAS = 4; +class ResPaths; class Assets; -typedef std::function aloader_func; +typedef std::function aloader_func; struct aloader_entry { int tag; - const std::filesystem::path filename; + const std::string filename; const std::string alias; }; @@ -26,11 +26,11 @@ class AssetsLoader { Assets* assets; std::map loaders; std::queue entries; - std::filesystem::path resdir; + const ResPaths* paths; public: - AssetsLoader(Assets* assets, std::filesystem::path resdir); + AssetsLoader(Assets* assets, const ResPaths* paths); void addLoader(int tag, aloader_func func); - void add(int tag, const std::filesystem::path filename, const std::string alias); + void add(int tag, const std::string filename, const std::string alias); bool hasNext() const; bool loadNext(); @@ -38,7 +38,7 @@ public: static void createDefaults(AssetsLoader& loader); static void addDefaults(AssetsLoader& loader); - std::filesystem::path getDirectory() const; + const ResPaths* getPaths() const; }; #endif // ASSETS_ASSETS_LOADER_H diff --git a/src/assets/asset_loaders.cpp b/src/assets/asset_loaders.cpp index 19f69c02..ca93828b 100644 --- a/src/assets/asset_loaders.cpp +++ b/src/assets/asset_loaders.cpp @@ -1,8 +1,10 @@ #include "asset_loaders.h" #include +#include #include "Assets.h" #include "../files/files.h" +#include "../files/engine_paths.h" #include "../coders/png.h" #include "../graphics/Shader.h" #include "../graphics/Texture.h" @@ -18,9 +20,10 @@ using std::filesystem::path; namespace fs = std::filesystem; bool assetload::texture(Assets* assets, - const path filename, + const ResPaths* paths, + const string filename, const string name) { - Texture* texture = png::load_texture(filename.string()); + Texture* texture = png::load_texture(paths->find(filename).string()); if (texture == nullptr) { std::cerr << "failed to load texture '" << name << "'" << std::endl; return false; @@ -30,10 +33,11 @@ bool assetload::texture(Assets* assets, } bool assetload::shader(Assets* assets, - const path filename, - const string name) { - path vertexFile = path(filename.string()+".glslv"); - path fragmentFile = path(filename.string()+".glslf"); + const ResPaths* paths, + const string filename, + const string name) { + path vertexFile = paths->find(filename+".glslv"); + path fragmentFile = paths->find(filename+".glslf"); string vertexSource = files::read_string(vertexFile); string fragmentSource = files::read_string(fragmentFile); @@ -49,13 +53,16 @@ bool assetload::shader(Assets* assets, } bool assetload::atlas(Assets* assets, - const path directory, - const string name) { + const ResPaths* paths, + const string directory, + const string name) { AtlasBuilder builder; - for (const auto& entry : fs::directory_iterator(directory)) { - path file = entry.path(); + for (const auto& file : paths->listdir(directory)) { if (file.extension() == ".png") { string name = file.stem().string(); + if (builder.has(name)) { + continue; // skip duplicates + } std::unique_ptr image (png::load_image(file.string())); image->fixAlphaColor(); builder.add(name, image.release()); @@ -67,11 +74,13 @@ bool assetload::atlas(Assets* assets, } bool assetload::font(Assets* assets, - const path filename, - const string name) { + const ResPaths* paths, + const string filename, + const string name) { vector pages; for (size_t i = 0; i <= 4; i++) { - string name = filename.string() + "_" + std::to_string(i) + ".png"; + string name = filename + "_" + std::to_string(i) + ".png"; + name = paths->find(name).string(); Texture* texture = png::load_texture(name); if (texture == nullptr) { std::cerr << "failed to load bitmap font '" << name; diff --git a/src/assets/asset_loaders.h b/src/assets/asset_loaders.h index 408e0047..bcfec06e 100644 --- a/src/assets/asset_loaders.h +++ b/src/assets/asset_loaders.h @@ -2,23 +2,27 @@ #define ASSETS_ASSET_LOADERS_H_ #include -#include +class ResPaths; class Assets; namespace assetload { bool texture(Assets* assets, - const std::filesystem::path filename, + const ResPaths* paths, + const std::string filename, const std::string name); bool shader(Assets* assets, - const std::filesystem::path filename, - const std::string name); - bool atlas(Assets* assets, - const std::filesystem::path directory, + const ResPaths* paths, + const std::string filename, const std::string name); + bool atlas(Assets* assets, + const ResPaths* paths, + const std::string directory, + const std::string name); bool font(Assets* assets, - const std::filesystem::path filename, - const std::string name); + const ResPaths* paths, + const std::string filename, + const std::string name); } #endif // ASSETS_ASSET_LOADERS_H_ \ No newline at end of file diff --git a/src/coders/GLSLExtension.cpp b/src/coders/GLSLExtension.cpp index df8e217b..fe62dd07 100644 --- a/src/coders/GLSLExtension.cpp +++ b/src/coders/GLSLExtension.cpp @@ -5,25 +5,22 @@ #include "../util/stringutil.h" #include "../typedefs.h" #include "../files/files.h" +#include "../files/engine_paths.h" using std::string; using std::filesystem::path; namespace fs = std::filesystem; -path GLSLExtension::getHeaderPath(string name) { - return libFolder/path(name+".glsl"); -} - -void GLSLExtension::setLibFolder(path folder) { - this->libFolder = folder; -} - void GLSLExtension::setVersion(string version) { this->version = version; } +void GLSLExtension::setPaths(const ResPaths* paths) { + this->paths = paths; +} + void GLSLExtension::loadHeader(string name) { - path file = getHeaderPath(name); + path file = paths->find("shaders/lib/"+name+".glsl"); string source = files::read_string(file); addHeader(name, source); } @@ -117,7 +114,6 @@ const string GLSLExtension::process(const path file, const string& source) { "expected '#include ' syntax"); } string name = line.substr(1, line.length()-2); - path hfile = getHeaderPath(name); if (!hasHeader(name)) { loadHeader(name); } diff --git a/src/coders/GLSLExtension.h b/src/coders/GLSLExtension.h index 74eb1ff8..2b6a2bc1 100644 --- a/src/coders/GLSLExtension.h +++ b/src/coders/GLSLExtension.h @@ -2,19 +2,21 @@ #define CODERS_GLSL_EXTESION_H_ #include +#include #include #include +class ResPaths; + class GLSLExtension { std::unordered_map headers; std::unordered_map defines; - std::filesystem::path libFolder; std::string version = "330 core"; + const ResPaths* paths = nullptr; void loadHeader(std::string name); - std::filesystem::path getHeaderPath(std::string name); public: - void setLibFolder(std::filesystem::path folder); + void setPaths(const ResPaths* paths); void setVersion(std::string version); void define(std::string name, std::string value); @@ -30,4 +32,4 @@ public: const std::string process(const std::filesystem::path file, const std::string& source); }; -#endif // CODERS_GLSL_EXTESION_H_ \ No newline at end of file +#endif // CODERS_GLSL_EXTESION_H_ diff --git a/src/engine.cpp b/src/engine.cpp index f4369c10..b0d75ba2 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -52,29 +52,8 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths) auto resdir = paths->getResources(); contentPacks.push_back({"base", resdir/path("content/base")}); - { - ContentBuilder contentBuilder; - setup_definitions(&contentBuilder); - for (auto& pack : contentPacks) { - ContentLoader loader(pack.folder); - loader.load(&contentBuilder); - } - content.reset(contentBuilder.build()); - } - Shader::preprocessor->setLibFolder(paths->getResources()/path("shaders/lib")); + loadContent(); - assets = new Assets(); - std::cout << "-- loading assets" << std::endl; - AssetsLoader loader(assets, paths->getResources()); - AssetsLoader::createDefaults(loader); - AssetsLoader::addDefaults(loader); - while (loader.hasNext()) { - if (!loader.loadNext()) { - delete assets; - Window::terminate(); - throw initialize_error("could not to initialize assets"); - } - } Audio::initialize(); gui = new GUI(); if (settings.ui.language == "auto") { @@ -120,7 +99,7 @@ void Engine::mainloop() { gui->act(delta); screen->update(delta); screen->draw(delta); - gui->draw(&batch, assets); + gui->draw(&batch, assets.get()); Window::swapInterval(settings.display.swapInterval); Window::swapBuffers(); @@ -135,7 +114,7 @@ Engine::~Engine() { Audio::finalize(); std::cout << "-- shutting down" << std::endl; - delete assets; + assets.reset(); Window::terminate(); std::cout << "-- engine finished" << std::endl; } @@ -149,7 +128,7 @@ EngineSettings& Engine::getSettings() { } Assets* Engine::getAssets() { - return assets; + return assets.get(); } void Engine::setScreen(shared_ptr screen) { @@ -173,3 +152,33 @@ void Engine::setLanguage(string locale) { langs::setup(paths->getResources(), locale, contentPacks); menus::create_menus(this, gui->getMenu()); } + +void Engine::loadContent() { + auto resdir = paths->getResources(); + ContentBuilder contentBuilder; + setup_definitions(&contentBuilder); + + vector resRoots; + for (auto& pack : contentPacks) { + ContentLoader loader(pack.folder); + loader.load(&contentBuilder); + resRoots.push_back(pack.folder); + } + content.reset(contentBuilder.build()); + resPaths.reset(new ResPaths(resdir, resRoots)); + + Shader::preprocessor->setPaths(resPaths.get()); + + assets.reset(new Assets()); + std::cout << "-- loading assets" << std::endl; + AssetsLoader loader(assets.get(), resPaths.get()); + AssetsLoader::createDefaults(loader); + AssetsLoader::addDefaults(loader); + while (loader.hasNext()) { + if (!loader.loadNext()) { + assets.reset(); + Window::terminate(); + throw initialize_error("could not to initialize assets"); + } + } +} diff --git a/src/engine.h b/src/engine.h index b2f9d199..cc544bf1 100644 --- a/src/engine.h +++ b/src/engine.h @@ -8,13 +8,15 @@ #include "typedefs.h" #include "settings.h" +#include "assets/Assets.h" #include "content/Content.h" #include "content/ContentPack.h" +#include "files/engine_paths.h" -class Assets; class Level; class Screen; class EnginePaths; +class ResPaths; namespace gui { class GUI; @@ -26,12 +28,13 @@ public: }; class Engine { - Assets* assets; + std::unique_ptr assets = nullptr; std::shared_ptr screen = nullptr; std::vector contentPacks; EngineSettings& settings; std::unique_ptr content = nullptr; EnginePaths* paths; + std::unique_ptr resPaths = nullptr; uint64_t frame = 0; double lastTime = 0.0; @@ -54,6 +57,7 @@ public: const Content* getContent() const; std::vector& getContentPacks(); void setLanguage(std::string locale); + void loadContent(); }; #endif // SRC_ENGINE_H_ \ No newline at end of file diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index e5769491..6ff65b22 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -8,6 +8,7 @@ namespace fs = std::filesystem; using std::string; +using std::vector; using fs::path; path EnginePaths::getUserfiles() const { @@ -56,3 +57,38 @@ void EnginePaths::setUserfiles(path folder) { void EnginePaths::setResources(path folder) { this->resources = folder; } + +ResPaths::ResPaths(path mainRoot, vector roots) + : mainRoot(mainRoot), roots(roots) { +} + +path ResPaths::find(const string& filename) const { + for (auto& root : roots) { + path file = root / path(filename); + if (fs::exists(file)) { + return file; + } + } + return mainRoot / path(filename); +} + +vector ResPaths::listdir(const string& folderName) const { + vector entries; + for (auto& root : roots) { + path folder = root / path(folderName); + if (!fs::is_directory(folder)) + continue; + for (const auto& entry : fs::directory_iterator(folder)) { + entries.push_back(entry.path()); + } + } + { + path folder = mainRoot / path(folderName); + if (!fs::is_directory(folder)) + return entries; + for (const auto& entry : fs::directory_iterator(folder)) { + entries.push_back(entry.path()); + } + } + return entries; +} diff --git a/src/files/engine_paths.h b/src/files/engine_paths.h index e9095258..62f02b38 100644 --- a/src/files/engine_paths.h +++ b/src/files/engine_paths.h @@ -2,6 +2,7 @@ #define FILES_ENGINE_PATHS_H_ #include +#include #include class EnginePaths { @@ -19,4 +20,15 @@ public: void setResources(std::filesystem::path folder); }; +class ResPaths { + std::filesystem::path mainRoot; + std::vector roots; +public: + ResPaths(std::filesystem::path mainRoot, + std::vector roots); + + std::filesystem::path find(const std::string& filename) const; + std::vector listdir(const std::string& folder) const; +}; + #endif // FILES_ENGINE_PATHS_H_ \ No newline at end of file diff --git a/src/graphics/Atlas.cpp b/src/graphics/Atlas.cpp index a49bbeaa..b4a0077b 100644 --- a/src/graphics/Atlas.cpp +++ b/src/graphics/Atlas.cpp @@ -41,15 +41,20 @@ ImageData* Atlas::getImage() const { void AtlasBuilder::add(string name, ImageData* image) { entries.push_back(atlasentry{name, shared_ptr(image)}); + names.insert(name); +} + +bool AtlasBuilder::has(string name) const { + return names.find(name) != names.end(); } Atlas* AtlasBuilder::build(uint extrusion, uint maxResolution) { unique_ptr sizes (new uint[entries.size() * 2]); - for (uint i = 0; i < entries.size(); i++) { - auto& entry = entries[i]; + uint index = 0; + for (auto& entry : entries) { auto image = entry.image; - sizes[i*2] = image->getWidth(); - sizes[i*2+1] = image->getHeight(); + sizes[index++] = image->getWidth(); + sizes[index++] = image->getHeight(); } LMPacker packer(sizes.get(), entries.size()*2); sizes.reset(nullptr); diff --git a/src/graphics/Atlas.h b/src/graphics/Atlas.h index 28168cef..110caa79 100644 --- a/src/graphics/Atlas.h +++ b/src/graphics/Atlas.h @@ -1,6 +1,7 @@ #ifndef GRAPHICS_ATLAS_H_ #define GRAPHICS_ATLAS_H_ +#include #include #include #include @@ -33,10 +34,12 @@ struct atlasentry { }; class AtlasBuilder { - std::vector entries; + std::vector entries; + std::set names; public: AtlasBuilder() {} void add(std::string name, ImageData* image); + bool has(std::string name) const; Atlas* build(uint extrusion, uint maxResolution=8192); };