#include "assetload_funcs.h" #include #include #include "Assets.h" #include "../files/files.h" #include "../files/engine_paths.h" #include "../coders/png.h" #include "../coders/json.h" #include "../graphics/Shader.h" #include "../graphics/Texture.h" #include "../graphics/ImageData.h" #include "../graphics/Atlas.h" #include "../graphics/Font.h" #include "../graphics/TextureAnimation.h" #include "../frontend/UiDocument.h" #include "../logic/scripting/scripting.h" namespace fs = std::filesystem; bool assetload::texture(Assets* assets, const ResPaths* paths, const std::string filename, const std::string name, std::shared_ptr ) { std::unique_ptr texture( png::load_texture(paths->find(filename).u8string()) ); if (texture == nullptr) { std::cerr << "failed to load texture '" << name << "'" << std::endl; return false; } assets->store(texture.release(), name); return true; } bool assetload::shader(Assets* assets, const ResPaths* paths, const std::string filename, const std::string name, std::shared_ptr ) { fs::path vertexFile = paths->find(filename+".glslv"); fs::path fragmentFile = paths->find(filename+".glslf"); std::string vertexSource = files::read_string(vertexFile); std::string fragmentSource = files::read_string(fragmentFile); Shader* shader = Shader::loadShader( vertexFile.string(), fragmentFile.string(), vertexSource, fragmentSource); if (shader == nullptr) { std::cerr << "failed to load shader '" << name << "'" << std::endl; return false; } assets->store(shader, name); return true; } static bool appendAtlas(AtlasBuilder& atlas, const fs::path& file) { // png is only supported format if (file.extension() != ".png") return false; std::string name = file.stem().string(); // skip duplicates if (atlas.has(name)) { return false; } std::unique_ptr image(png::load_image(file.string())); if (image == nullptr) { std::cerr << "could not to load " << file.string() << std::endl; return false; } image->fixAlphaColor(); atlas.add(name, image.release()); return true; } bool assetload::atlas(Assets* assets, const ResPaths* paths, const std::string directory, const std::string name, std::shared_ptr ) { AtlasBuilder builder; for (const auto& file : paths->listdir(directory)) { if (!appendAtlas(builder, file)) continue; } Atlas* atlas = builder.build(2); assets->store(atlas, name); for (const auto& file : builder.getNames()) { assetload::animation(assets, paths, "textures", file, atlas); } return true; } bool assetload::font(Assets* assets, const ResPaths* paths, const std::string filename, const std::string name, std::shared_ptr ) { std::vector> pages; for (size_t i = 0; i <= 4; i++) { std::string name = filename + "_" + std::to_string(i) + ".png"; name = paths->find(name).string(); std::unique_ptr texture (png::load_texture(name)); if (texture == nullptr) { std::cerr << "failed to load bitmap font '" << name; std::cerr << "' (missing page " << std::to_string(i) << ")"; std::cerr << std::endl; return false; } pages.push_back(std::move(texture)); } int res = pages[0]->height / 16; assets->store(new Font(std::move(pages), res, 4), name); return true; } bool assetload::layout( Assets* assets, const ResPaths* paths, const std::string file, const std::string name, std::shared_ptr config ) { try { LayoutCfg* cfg = reinterpret_cast(config.get()); auto document = UiDocument::read(cfg->env, name, file); assets->store(document.release(), name); return true; } catch (const parsing_error& err) { std::cerr << "failed to parse layout XML '" << file << "'" << std::endl; std::cerr << err.errorLog() << std::endl; return false; } } bool assetload::animation(Assets* assets, const ResPaths* paths, const std::string directory, const std::string name, Atlas* dstAtlas) { std::string animsDir = directory + "/animations"; std::string blocksDir = directory + "/blocks"; for (const auto& folder : paths->listdir(animsDir)) { if (!fs::is_directory(folder)) continue; if (folder.filename().string() != name) continue; if (fs::is_empty(folder)) continue; AtlasBuilder builder; appendAtlas(builder, paths->find(blocksDir + "/" + name + ".png")); std::string animFile = folder.string() + "/animation.json"; std::vector> frameList; if (fs::exists(animFile)) { auto root = files::read_json(animFile); auto frameArr = root->list("frames"); float frameDuration = DEFAULT_FRAME_DURATION; std::string frameName; if (frameArr) { for (size_t i = 0; i < frameArr->size(); i++) { auto currentFrame = frameArr->list(i); frameName = currentFrame->str(0); if (currentFrame->size() > 1) frameDuration = static_cast(currentFrame->integer(1)) / 1000; frameList.emplace_back(frameName, frameDuration); } } } for (const auto& file : paths->listdir(animsDir + "/" + name)) { if (!frameList.empty()) { bool contains = false; for (const auto& elem : frameList) { if (file.stem() == elem.first) { contains = true; break; } } if (!contains) continue; } if (!appendAtlas(builder, file)) continue; } std::unique_ptr srcAtlas (builder.build(2)); Texture* srcTex = srcAtlas->getTexture(); Texture* dstTex = dstAtlas->getTexture(); TextureAnimation animation(srcTex, dstTex); Frame frame; UVRegion region = dstAtlas->get(name); frame.dstPos = glm::ivec2(region.u1 * dstTex->width, region.v1 * dstTex->height); frame.size = glm::ivec2(region.u2 * dstTex->width, region.v2 * dstTex->height) - frame.dstPos; if (frameList.empty()) { for (const auto& elem : builder.getNames()) { region = srcAtlas->get(elem); frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); animation.addFrame(frame); } } else { for (const auto& elem : frameList) { if (!srcAtlas->has(elem.first)) { std::cerr << "Unknown frame name: " << elem.first << std::endl; continue; } region = srcAtlas->get(elem.first); frame.duration = elem.second; frame.srcPos = glm::ivec2(region.u1 * srcTex->width, srcTex->height - region.v2 * srcTex->height); animation.addFrame(frame); } } assets->store(srcAtlas.release(), name + "_animation"); assets->store(animation); return true; } return true; }