diff options
Diffstat (limited to 'examples/obj_sticher')
-rw-r--r-- | examples/obj_sticher/obj_sticher.cc | 110 | ||||
-rw-r--r-- | examples/obj_sticher/obj_writer.cc | 176 | ||||
-rw-r--r-- | examples/obj_sticher/obj_writer.h | 9 | ||||
-rw-r--r-- | examples/obj_sticher/premake4.lua | 38 |
4 files changed, 333 insertions, 0 deletions
diff --git a/examples/obj_sticher/obj_sticher.cc b/examples/obj_sticher/obj_sticher.cc new file mode 100644 index 0000000..f59fee4 --- /dev/null +++ b/examples/obj_sticher/obj_sticher.cc @@ -0,0 +1,110 @@ +// +// Stiches multiple .obj files into one .obj. +// +#include "../../tiny_obj_loader.h" +#include "obj_writer.h" + +#include <cassert> +#include <iostream> +#include <cstdlib> +#include <cstdio> + +typedef std::vector<tinyobj::shape_t> Shape; +typedef std::vector<tinyobj::material_t> Material; + +void +StichObjs( + std::vector<tinyobj::shape_t>& out_shape, + std::vector<tinyobj::material_t>& out_material, + const std::vector<Shape>& shapes, + const std::vector<Material>& materials) +{ + int numShapes = 0; + for (size_t i = 0; i < shapes.size(); i++) { + numShapes += (int)shapes[i].size(); + } + + printf("Total # of shapes = %d\n", numShapes); + int materialIdOffset = 0; + + size_t face_offset = 0; + for (size_t i = 0; i < shapes.size(); i++) { + + for (size_t k = 0; k < shapes[i].size(); k++) { + + std::string new_name = shapes[i][k].name; + // Add suffix + char buf[1024]; + sprintf(buf, "_%04d", (int)i); + new_name += std::string(buf); + + printf("shape[%ld][%ld].name = %s\n", i, k, shapes[i][k].name.c_str()); + assert((shapes[i][k].mesh.indices.size() % 3) == 0); + assert((shapes[i][k].mesh.positions.size() % 3) == 0); + + tinyobj::shape_t new_shape = shapes[i][k]; + // Add offset. + for (size_t f = 0; f < new_shape.mesh.material_ids.size(); f++) { + new_shape.mesh.material_ids[f] += materialIdOffset; + } + + new_shape.name = new_name; + printf("shape[%ld][%ld].new_name = %s\n", i, k, new_shape.name.c_str()); + + out_shape.push_back(new_shape); + } + + materialIdOffset += materials[i].size(); + } + + for (size_t i = 0; i < materials.size(); i++) { + for (size_t k = 0; k < materials[i].size(); k++) { + out_material.push_back(materials[i][k]); + } + } + +} + +int +main( + int argc, + char **argv) +{ + if (argc < 3) { + printf("Usage: obj_sticher input0.obj input1.obj ... output.obj\n"); + exit(1); + } + + int num_objfiles = argc - 2; + std::string out_filename = std::string(argv[argc-1]); // last element + + std::vector<Shape> shapes; + std::vector<Material> materials; + shapes.resize(num_objfiles); + materials.resize(num_objfiles); + + for (int i = 0; i < num_objfiles; i++) { + std::cout << "Loading " << argv[i+1] << " ... " << std::flush; + + std::string err; + bool ret = tinyobj::LoadObj(shapes[i], materials[i], err, argv[i+1]); + if (!err.empty()) { + std::cerr << err << std::endl; + } + if (!ret) { + exit(1); + } + + std::cout << "DONE." << std::endl; + } + + std::vector<tinyobj::shape_t> out_shape; + std::vector<tinyobj::material_t> out_material; + StichObjs(out_shape, out_material, shapes, materials); + + bool coordTransform = true; + bool ret = WriteObj(out_filename, out_shape, out_material, coordTransform); + assert(ret); + + return 0; +} diff --git a/examples/obj_sticher/obj_writer.cc b/examples/obj_sticher/obj_writer.cc new file mode 100644 index 0000000..2c8bd7b --- /dev/null +++ b/examples/obj_sticher/obj_writer.cc @@ -0,0 +1,176 @@ +// +// Simple wavefront .obj writer +// +#include "obj_writer.h" +#include <cstdio> + +static std::string GetFileBasename(const std::string& FileName) +{ + if(FileName.find_last_of(".") != std::string::npos) + return FileName.substr(0, FileName.find_last_of(".")); + return ""; +} + +bool WriteMat(const std::string& filename, const std::vector<tinyobj::material_t>& materials) { + FILE* fp = fopen(filename.c_str(), "w"); + if (!fp) { + fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str()); + return false; + } + + for (size_t i = 0; i < materials.size(); i++) { + + tinyobj::material_t mat = materials[i]; + + fprintf(fp, "newmtl %s\n", mat.name.c_str()); + fprintf(fp, "Ka %f %f %f\n", mat.ambient[0], mat.ambient[1], mat.ambient[2]); + fprintf(fp, "Kd %f %f %f\n", mat.diffuse[0], mat.diffuse[1], mat.diffuse[2]); + fprintf(fp, "Ks %f %f %f\n", mat.specular[0], mat.specular[1], mat.specular[2]); + fprintf(fp, "Kt %f %f %f\n", mat.transmittance[0], mat.specular[1], mat.specular[2]); + fprintf(fp, "Ke %f %f %f\n", mat.emission[0], mat.emission[1], mat.emission[2]); + fprintf(fp, "Ns %f\n", mat.shininess); + fprintf(fp, "Ni %f\n", mat.ior); + // @todo { texture } + } + + fclose(fp); + + return true; +} + +bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform) { + FILE* fp = fopen(filename.c_str(), "w"); + if (!fp) { + fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str()); + return false; + } + + std::string basename = GetFileBasename(filename); + std::string material_filename = basename + ".mtl"; + + int v_offset = 0; + int vn_offset = 0; + int vt_offset = 0; + int prev_material_id = -1; + + fprintf(fp, "mtllib %s\n", material_filename.c_str()); + + for (size_t i = 0; i < shapes.size(); i++) { + + bool has_vn = false; + bool has_vt = false; + + if (shapes[i].name.empty()) { + fprintf(fp, "g Unknown\n"); + } else { + fprintf(fp, "g %s\n", shapes[i].name.c_str()); + } + + //if (!shapes[i].material.name.empty()) { + // fprintf(fp, "usemtl %s\n", shapes[i].material.name.c_str()); + //} + + // facevarying vtx + for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { + for (int j = 0; j < 3; j++) { + int idx = shapes[i].mesh.indices[3*k+j]; + if (coordTransform) { + fprintf(fp, "v %f %f %f\n", + shapes[i].mesh.positions[3*idx+0], + shapes[i].mesh.positions[3*idx+2], + -shapes[i].mesh.positions[3*idx+1]); + } else { + fprintf(fp, "v %f %f %f\n", + shapes[i].mesh.positions[3*idx+0], + shapes[i].mesh.positions[3*idx+1], + shapes[i].mesh.positions[3*idx+2]); + } + } + } + + // facevarying normal + if (shapes[i].mesh.normals.size() > 0) { + for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { + for (int j = 0; j < 3; j++) { + int idx = shapes[i].mesh.indices[3*k+j]; + if (coordTransform) { + fprintf(fp, "vn %f %f %f\n", + shapes[i].mesh.normals[3*idx+0], + shapes[i].mesh.normals[3*idx+2], + -shapes[i].mesh.normals[3*idx+1]); + } else { + fprintf(fp, "vn %f %f %f\n", + shapes[i].mesh.normals[3*idx+0], + shapes[i].mesh.normals[3*idx+1], + shapes[i].mesh.normals[3*idx+2]); + } + } + } + } + if (shapes[i].mesh.normals.size() > 0) has_vn = true; + + // facevarying texcoord + if (shapes[i].mesh.texcoords.size() > 0) { + for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { + for (int j = 0; j < 3; j++) { + int idx = shapes[i].mesh.indices[3*k+j]; + fprintf(fp, "vt %f %f\n", + shapes[i].mesh.texcoords[2*idx+0], + shapes[i].mesh.texcoords[2*idx+1]); + } + } + } + if (shapes[i].mesh.texcoords.size() > 0) has_vt = true; + + // face + for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { + + // Face index is 1-base. + //int v0 = shapes[i].mesh.indices[3*k+0] + 1 + v_offset; + //int v1 = shapes[i].mesh.indices[3*k+1] + 1 + v_offset; + //int v2 = shapes[i].mesh.indices[3*k+2] + 1 + v_offset; + int v0 = (3*k + 0) + 1 + v_offset; + int v1 = (3*k + 1) + 1 + v_offset; + int v2 = (3*k + 2) + 1 + v_offset; + + int vt0 = (3*k + 0) + 1 + vt_offset; + int vt1 = (3*k + 1) + 1 + vt_offset; + int vt2 = (3*k + 2) + 1 + vt_offset; + + int material_id = shapes[i].mesh.material_ids[k]; + if (material_id != prev_material_id) { + std::string material_name = materials[material_id].name; + fprintf(fp, "usemtl %s\n", material_name.c_str()); + prev_material_id = material_id; + } + + if (has_vn && has_vt) { + fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", + v0, vt0, v0, v1, vt1, v1, v2, vt2, v2); + } else if (has_vn && !has_vt) { + fprintf(fp, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2); + } else if (!has_vn && has_vt) { + fprintf(fp, "f %d/%d %d/%d %d/%d\n", v0, v0, v1, v1, v2, v2); + } else { + fprintf(fp, "f %d %d %d\n", v0, v1, v2); + } + + } + + v_offset += shapes[i].mesh.indices.size(); + //vn_offset += shapes[i].mesh.normals.size() / 3; + vt_offset += shapes[i].mesh.texcoords.size() / 2; + + } + + fclose(fp); + + // + // Write material file + // + bool ret = WriteMat(material_filename, materials); + + return ret; +} + + diff --git a/examples/obj_sticher/obj_writer.h b/examples/obj_sticher/obj_writer.h new file mode 100644 index 0000000..bb367b6 --- /dev/null +++ b/examples/obj_sticher/obj_writer.h @@ -0,0 +1,9 @@ +#ifndef __OBJ_WRITER_H__ +#define __OBJ_WRITER_H__ + +#include "../../tiny_obj_loader.h" + +extern bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform = false); + + +#endif // __OBJ_WRITER_H__ diff --git a/examples/obj_sticher/premake4.lua b/examples/obj_sticher/premake4.lua new file mode 100644 index 0000000..9c2deb6 --- /dev/null +++ b/examples/obj_sticher/premake4.lua @@ -0,0 +1,38 @@ +lib_sources = { + "../../tiny_obj_loader.cc" +} + +sources = { + "obj_sticher.cc", + "obj_writer.cc", + } + +-- premake4.lua +solution "ObjStickerSolution" + configurations { "Release", "Debug" } + + if (os.is("windows")) then + platforms { "x32", "x64" } + else + platforms { "native", "x32", "x64" } + end + + includedirs { + "../../" + } + + -- A project defines one build target + project "obj_sticher" + kind "ConsoleApp" + language "C++" + files { lib_sources, sources } + + configuration "Debug" + defines { "DEBUG" } -- -DDEBUG + flags { "Symbols" } + targetname "obj_sticher_debug" + + configuration "Release" + -- defines { "NDEBUG" } -- -NDEBUG + flags { "Symbols", "Optimize" } + targetname "obj_sticher" |