#include #include #include #include #include #include #include static void usage(); static void file_write_error_check(FILE *file, const void *data, size_t size); static void file_write_uint_error_check(FILE *file, unsigned int value); static void process_node(const aiScene *scene, const aiNode *node, FILE *output_file); int main(int argc, char **argv) { if(argc != 3) usage(); const char *source_filepath = argv[1]; const char *destination_filepath = argv[2]; Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE; Assimp::DefaultLogger::create("", severity, aiDefaultLogStream_STDERR); Assimp::Importer importer; const aiScene *scene = importer.ReadFile(source_filepath, aiProcessPreset_TargetRealtime_Quality | aiProcess_Triangulate | aiProcess_FlipUVs); if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { fprintf(stderr, "Failed to load file: %s, reason: %s\n", source_filepath, importer.GetErrorString()); exit(2); } FILE *destination_file = fopen(destination_filepath, "wb"); if(!destination_file) { perror(destination_filepath); exit(3); } file_write_uint_error_check(destination_file, 0x036144AF); // magic number file_write_uint_error_check(destination_file, 0x00000001); // version process_node(scene, scene->mRootNode, destination_file); fclose(destination_file); Assimp::DefaultLogger::kill(); return 0; } void usage() { fprintf(stderr, "usage: amalgine-model-converter \n"); exit(1); } void file_write_error_check(FILE *file, const void *data, size_t size) { if(fwrite(data, 1, size, file) != size) { fprintf(stderr, "Error: failed to write %ld bytes to output file, error: %s\n", size, strerror(errno)); exit(4); } } void file_write_uint_error_check(FILE *file, unsigned int value) { const size_t size = sizeof(value); if(fwrite(&value, 1, size, file) != size) { fprintf(stderr, "Error: failed to write %ld bytes to output file, error: %s\n", size, strerror(errno)); exit(4); } } static void process_mesh(const aiScene *scene, const aiMesh *mesh, FILE *output_file) { file_write_uint_error_check(output_file, mesh->mNumVertices); file_write_error_check(output_file, &mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D)); file_write_error_check(output_file, &mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D)); file_write_uint_error_check(output_file, mesh->mNumFaces); for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { // Should always be 3 since the file was loaded with aiProcess_Triangulate file_write_error_check(output_file, mesh->mFaces[i].mIndices, 3 * sizeof(unsigned int)); } file_write_uint_error_check(output_file, mesh->mTextureCoords[0] ? 1 : 0); if(mesh->mTextureCoords[0]) file_write_error_check(output_file, &mesh->mTextureCoords[0], mesh->mNumVertices * sizeof(aiVector3D)); file_write_uint_error_check(output_file, mesh->mMaterialIndex < scene->mNumMaterials); if(mesh->mMaterialIndex < scene->mNumMaterials) { const unsigned int num_texture_types = 3; const aiTextureType texture_types[num_texture_types] = { aiTextureType_DIFFUSE, aiTextureType_SPECULAR, aiTextureType_AMBIENT }; const aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; for(unsigned int i = 0; i < num_texture_types; ++i) { unsigned int num_textures_for_type = material->GetTextureCount(texture_types[i]); file_write_uint_error_check(output_file, num_textures_for_type); for(unsigned int j = 0; j < num_textures_for_type; ++j) { aiString str; if(material->GetTexture(texture_types[i], j, &str) == aiReturn_SUCCESS) file_write_error_check(output_file, str.data, str.length + 1); // +1 to include null-terminate character else file_write_error_check(output_file, "\0", 1); } } } } void process_node(const aiScene *scene, const aiNode *node, FILE *output_file) { for(unsigned int i = 0; i < node->mNumMeshes; ++i) { const aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; process_mesh(scene, mesh, output_file); } for(unsigned int i = 0; i < node->mNumChildren; ++i) { process_node(scene, node->mChildren[i], output_file); } }