summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/asset_packer.cc185
1 files changed, 185 insertions, 0 deletions
diff --git a/tools/asset_packer.cc b/tools/asset_packer.cc
index 04b74a4..79a6ce6 100644
--- a/tools/asset_packer.cc
+++ b/tools/asset_packer.cc
@@ -5,10 +5,13 @@
#include <cstdio> // for simplicity, use fprintf() for output generation
#include <fstream>
#include <map>
+#include <algorithm> // For std::count
+#include <cstring> // For std::memcpy
#include <regex> // For std::regex
#include <stdexcept> // For std::stof exceptions
#include <string>
#include <vector>
+#include <cmath>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_LINEAR // Don't apply gamma correction, we want raw bytes
@@ -39,6 +42,11 @@ static bool HasImageExtension(const std::string& filename) {
return false;
}
+static bool HasMeshExtension(const std::string& filename) {
+ std::string ext = filename.substr(filename.find_last_of(".") + 1);
+ return ext == "obj";
+}
+
// Helper struct to hold all information about an asset during parsing
struct AssetBuildInfo {
std::string name;
@@ -53,6 +61,22 @@ struct AssetBuildInfo {
std::string func_name_str_name; // ASSET_PROC_FUNC_STR_xxx for procedural
};
+struct Vec3 {
+ float x, y, z;
+ Vec3 operator+(const Vec3& o) const { return {x + o.x, y + o.y, z + o.z}; }
+ Vec3 operator+=(const Vec3& o) { x += o.x; y += o.y; z += o.z; return *this; }
+ Vec3 operator-(const Vec3& o) const { return {x - o.x, y - o.y, z - o.z}; }
+ Vec3 operator*(float s) const { return {x * s, y * s, z * s}; }
+ static Vec3 cross(const Vec3& a, const Vec3& b) {
+ return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
+ }
+ Vec3 normalize() const {
+ float len = std::sqrt(x * x + y * y + z * z);
+ if (len > 1e-6f) return {x / len, y / len, z / len};
+ return {0, 0, 0};
+ }
+};
+
int main(int argc, char* argv[]) {
if (argc != 4) {
fprintf(stderr,
@@ -230,6 +254,7 @@ int main(int argc, char* argv[]) {
std::vector<uint8_t> buffer;
bool is_image = HasImageExtension(info.filename);
+ bool is_mesh = HasMeshExtension(info.filename);
if (is_image) {
int w, h, channels;
@@ -251,6 +276,166 @@ int main(int argc, char* argv[]) {
stbi_image_free(img_data);
printf("Processed image asset %s: %dx%d RGBA\n", info.name.c_str(), w,
h);
+ } else if (is_mesh) {
+ std::ifstream obj_file(full_path);
+ if (!obj_file.is_open()) {
+ fprintf(stderr, "Error: Could not open mesh file: %s\n",
+ full_path.c_str());
+ return 1;
+ }
+
+ std::vector<float> v_pos;
+ std::vector<float> v_norm;
+ std::vector<float> v_uv;
+
+ struct RawFace {
+ int v[3];
+ int vt[3];
+ int vn[3];
+ };
+ std::vector<RawFace> raw_faces;
+
+ struct Vertex {
+ float p[3], n[3], u[2];
+ };
+ std::vector<Vertex> final_vertices;
+ std::vector<uint32_t> final_indices;
+ std::map<std::string, uint32_t> vertex_map;
+
+ std::string obj_line;
+ while (std::getline(obj_file, obj_line)) {
+ if (obj_line.compare(0, 2, "v ") == 0) {
+ float x, y, z;
+ std::sscanf(obj_line.c_str(), "v %f %f %f", &x, &y, &z);
+ v_pos.push_back(x);
+ v_pos.push_back(y);
+ v_pos.push_back(z);
+ } else if (obj_line.compare(0, 3, "vn ") == 0) {
+ float x, y, z;
+ std::sscanf(obj_line.c_str(), "vn %f %f %f", &x, &y, &z);
+ v_norm.push_back(x);
+ v_norm.push_back(y);
+ v_norm.push_back(z);
+ } else if (obj_line.compare(0, 3, "vt ") == 0) {
+ float u, v;
+ std::sscanf(obj_line.c_str(), "vt %f %f", &u, &v);
+ v_uv.push_back(u);
+ v_uv.push_back(v);
+ } else if (obj_line.compare(0, 2, "f ") == 0) {
+ char s1[64], s2[64], s3[64];
+ if (std::sscanf(obj_line.c_str(), "f %s %s %s", s1, s2, s3) == 3) {
+ std::string parts[3] = {s1, s2, s3};
+ RawFace face = {};
+ for (int i = 0; i < 3; ++i) {
+ int v_idx = 0, vt_idx = 0, vn_idx = 0;
+ if (parts[i].find("//") != std::string::npos) {
+ std::sscanf(parts[i].c_str(), "%d//%d", &v_idx, &vn_idx);
+ } else if (std::count(parts[i].begin(), parts[i].end(), '/') ==
+ 2) {
+ std::sscanf(parts[i].c_str(), "%d/%d/%d", &v_idx, &vt_idx,
+ &vn_idx);
+ } else if (std::count(parts[i].begin(), parts[i].end(), '/') ==
+ 1) {
+ std::sscanf(parts[i].c_str(), "%d/%d", &v_idx, &vt_idx);
+ } else {
+ std::sscanf(parts[i].c_str(), "%d", &v_idx);
+ }
+ face.v[i] = v_idx;
+ face.vt[i] = vt_idx;
+ face.vn[i] = vn_idx;
+ }
+ raw_faces.push_back(face);
+ }
+ }
+ }
+
+ // Generate normals if missing
+ if (v_norm.empty() && !v_pos.empty()) {
+ printf("Generating normals for %s...\n", info.name.c_str());
+ std::vector<Vec3> temp_normals(v_pos.size() / 3, {0, 0, 0});
+ for (auto& face : raw_faces) {
+ // Indices are 1-based in OBJ
+ int idx0 = face.v[0] - 1;
+ int idx1 = face.v[1] - 1;
+ int idx2 = face.v[2] - 1;
+
+ if (idx0 >= 0 && idx1 >= 0 && idx2 >= 0) {
+ Vec3 p0 = {v_pos[idx0 * 3], v_pos[idx0 * 3 + 1], v_pos[idx0 * 3 + 2]};
+ Vec3 p1 = {v_pos[idx1 * 3], v_pos[idx1 * 3 + 1], v_pos[idx1 * 3 + 2]};
+ Vec3 p2 = {v_pos[idx2 * 3], v_pos[idx2 * 3 + 1], v_pos[idx2 * 3 + 2]};
+
+ Vec3 normal = Vec3::cross(p1 - p0, p2 - p0).normalize();
+ temp_normals[idx0] += normal;
+ temp_normals[idx1] += normal;
+ temp_normals[idx2] += normal;
+ }
+ }
+
+ for (const auto& n : temp_normals) {
+ Vec3 normalized = n.normalize();
+ v_norm.push_back(normalized.x);
+ v_norm.push_back(normalized.y);
+ v_norm.push_back(normalized.z);
+ }
+
+ // Assign generated normals to faces
+ for (auto& face : raw_faces) {
+ face.vn[0] = face.v[0];
+ face.vn[1] = face.v[1];
+ face.vn[2] = face.v[2];
+ }
+ }
+
+ // Build final vertices
+ for (const auto& face : raw_faces) {
+ for (int i = 0; i < 3; ++i) {
+ // Reconstruct key string for uniqueness check
+ char key_buf[128];
+ std::sprintf(key_buf, "%d/%d/%d", face.v[i], face.vt[i], face.vn[i]);
+ std::string key = key_buf;
+
+ if (vertex_map.find(key) == vertex_map.end()) {
+ vertex_map[key] = (uint32_t)final_vertices.size();
+
+ Vertex v = {};
+ if (face.v[i] > 0) {
+ v.p[0] = v_pos[(face.v[i] - 1) * 3];
+ v.p[1] = v_pos[(face.v[i] - 1) * 3 + 1];
+ v.p[2] = v_pos[(face.v[i] - 1) * 3 + 2];
+ }
+ if (face.vn[i] > 0) {
+ v.n[0] = v_norm[(face.vn[i] - 1) * 3];
+ v.n[1] = v_norm[(face.vn[i] - 1) * 3 + 1];
+ v.n[2] = v_norm[(face.vn[i] - 1) * 3 + 2];
+ }
+ if (face.vt[i] > 0) {
+ v.u[0] = v_uv[(face.vt[i] - 1) * 2];
+ v.u[1] = v_uv[(face.vt[i] - 1) * 2 + 1];
+ }
+ final_vertices.push_back(v);
+ }
+ final_indices.push_back(vertex_map[key]);
+ }
+ }
+
+ // Format: [num_vertices(u32)][Vertex * num_vertices][num_indices(u32)][uint32_t
+ // * num_indices]
+ buffer.resize(sizeof(uint32_t) + final_vertices.size() * sizeof(Vertex) +
+ sizeof(uint32_t) +
+ final_indices.size() * sizeof(uint32_t));
+ uint8_t* out_ptr = buffer.data();
+ *reinterpret_cast<uint32_t*>(out_ptr) = (uint32_t)final_vertices.size();
+ out_ptr += sizeof(uint32_t);
+ std::memcpy(out_ptr, final_vertices.data(),
+ final_vertices.size() * sizeof(Vertex));
+ out_ptr += final_vertices.size() * sizeof(Vertex);
+ *reinterpret_cast<uint32_t*>(out_ptr) = (uint32_t)final_indices.size();
+ out_ptr += sizeof(uint32_t);
+ std::memcpy(out_ptr, final_indices.data(),
+ final_indices.size() * sizeof(uint32_t));
+
+ printf("Processed mesh asset %s: %zu vertices, %zu indices\n",
+ info.name.c_str(), final_vertices.size(), final_indices.size());
} else {
std::ifstream asset_file(full_path, std::ios::binary);
if (!asset_file.is_open()) {