/* Crafter.Build Copyright (C) 2025 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include #include #include #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" export module Crafter.Asset:Asset; namespace fs = std::filesystem; struct __attribute__((packed)) Float3 { float x; float y; float z; }; struct __attribute__((packed)) Float2 { float x; float y; }; struct __attribute__((packed)) VertexUV { Float3 position; Float2 uv; }; void SplitString(const std::string& s, const char delimiter, std::vector& tokens) { std::istringstream iss(s); std::string token; while (std::getline(iss, token, delimiter)) { tokens.push_back(token); } } uint32_t ProcessVertex(std::vector& verticies, std::vector positions, std::vector uvs, uint32_t posIndex, uint32_t uvIndex) { Float3 pos = positions[posIndex - 1]; Float2 uv = uvs[uvIndex - 1]; for (uint32_t i = 0; i < verticies.size(); i++) { VertexUV vert = verticies[i]; if (vert.position.x == pos.x && vert.position.y == pos.y && vert.position.z == pos.z && vert.uv.x == uv.x && vert.uv.y == uv.y) { return i; } } verticies.push_back({ pos ,uv }); return verticies.size() - 1; } export namespace Crafter { std::unordered_map(fs::path)>> serializers = { { "PNG:Crafter.Graphics.TextureR8B8G8A8", [](fs::path file) { int x,y,n; unsigned char *imageData = stbi_load(file.generic_string().c_str(),&x, &y, &n, 4); std::uint32_t x2 = x; std::uint32_t y2 = y; std::vector data(sizeof(std::uint32_t)+sizeof(std::uint32_t)+(x*y*4)); memcpy(&data[0], &x2, sizeof(std::uint32_t)); memcpy(&data[sizeof(std::uint32_t)], &y2, sizeof(std::uint32_t)); memcpy(&data[sizeof(std::uint32_t)*2], imageData, x*y*4); return data; } }, { "OBJ:Crafter.Graphics.Mesh", [](fs::path path) { std::ifstream file(path); std::string line; std::vector positions; std::vector indices; while (std::getline(file, line)) { if (line.substr(0, 1) == "v") { std::istringstream iss(line.substr(2)); Float3 pos{0,0,0}; iss >> pos.x >> pos.y >> pos.z; positions.push_back(pos); } else if (line.substr(0, 1) == "f") { std::vector tokens; SplitString(line.substr(2), ' ', tokens); for (size_t i = 0; i < 3; ++i) { indices.push_back(std::stoul(tokens[i])-1); } } } file.close(); std::vector buffer((positions.size()*sizeof(Float3))+(indices.size()*sizeof(std::uint32_t))+sizeof(std::uint32_t)+sizeof(std::uint32_t)); std::uint32_t vertSize = positions.size(); std::uint32_t indexSize = indices.size(); memcpy(&buffer[0], &vertSize, sizeof(std::uint32_t)); memcpy(&buffer[sizeof(std::uint32_t)], &indexSize, sizeof(std::uint32_t)); memcpy(&buffer[sizeof(std::uint32_t)*2], positions.data(), positions.size()*sizeof(Float3)); memcpy(&buffer[positions.size()*sizeof(Float3)+sizeof(std::uint32_t)+sizeof(std::uint32_t)], indices.data(), indices.size()*sizeof(std::uint32_t)); return buffer; } }, { "OBJ:Crafter.Graphics.MeshUV", [](fs::path path) { std::ifstream file(path); std::string line; std::vector positions; std::vector uvs; std::vector verticies; std::vector indicies; while (std::getline(file, line)) { if (line.substr(0, 2) == "vt") { std::istringstream iss(line.substr(3)); Float2 uv{0,0}; iss >> uv.x >> uv.y; uvs.push_back(uv); } else if (line.substr(0, 1) == "v") { std::istringstream iss(line.substr(2)); Float3 pos{0,0,0}; iss >> pos.x >> pos.y >> pos.z; positions.push_back(pos); } else if (line.substr(0, 1) == "f") { std::vector tokens; SplitString(line.substr(2), ' ', tokens); for (size_t i = 0; i < 3; ++i) { size_t slashPos = tokens[i].find('/'); indicies.push_back(ProcessVertex(verticies, positions, uvs, std::stoul(tokens[i].substr(0, slashPos)), std::stoul(tokens[i].substr(slashPos + 1)))); } } } file.close(); std::vector buffer((verticies.size()*sizeof(VertexUV))+(indicies.size()*sizeof(std::uint32_t))+sizeof(std::uint32_t)+sizeof(std::uint32_t)); std::uint32_t vertSize = verticies.size(); std::uint32_t indexSize = indicies.size(); memcpy(&buffer[0], &vertSize, sizeof(std::uint32_t)); memcpy(&buffer[sizeof(std::uint32_t)], &indexSize, sizeof(std::uint32_t)); memcpy(&buffer[sizeof(std::uint32_t)*2], verticies.data(), verticies.size()*sizeof(VertexUV)); memcpy(&buffer[verticies.size()*sizeof(VertexUV)+sizeof(std::uint32_t)+sizeof(std::uint32_t)], indicies.data(), indicies.size()*sizeof(std::uint32_t)); return buffer; } } }; std::unordered_map> extractors = { { "Crafter.Graphics.TextureR8B8G8A8:PNG", [](fs::path dst, const void* data) { stbi_write_png(dst.generic_string().c_str(), reinterpret_cast(data)[0], reinterpret_cast(data)[1], 4, reinterpret_cast(data)+(sizeof(std::uint32_t)*2), reinterpret_cast(data)[0]*4); } } }; class AssetEntry { public: std::string name; std::string type; std::vector data; AssetEntry(); AssetEntry(std::string name, std::string type, std::vector data); AssetEntry(std::string name, std::string type, void* data); }; class Asset { public: std::vector entries; Asset(); Asset(std::vector entries); void LoadFull(fs::path path); void LoadHeaders(fs::path path); void LoadSpecific(fs::path path, std::string entry); void LoadSpecific(fs::path path, std::vector entries); void LoadSpecific(fs::path path, std::uint32_t entry); void LoadSpecific(fs::path path, std::vector entries); void Save(fs::path path); }; }