aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-02-28 23:45:47 +0100
committerdec05eba <dec05eba@protonmail.com>2020-02-28 23:45:47 +0100
commit8b8a84334f234b21945e8433ba3bd7d117ca69d9 (patch)
treec1178f5b06b084f62a8733adc4d17d364a459f7a
Initial commit, it works
-rw-r--r--.gitignore5
-rw-r--r--LICENSE13
-rw-r--r--README.md33
-rw-r--r--project.conf8
-rw-r--r--src/main.cpp114
5 files changed, 173 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..636c6b9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+# Compiled sibs files
+sibs-build/
+compile_commands.json
+tests/sibs-build/
+tests/compile_commands.json
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ab1d20c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2020 dec05eba
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a53393e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
+# Amalgine 3D model file format (.a3d)
+All types are stored in little endian format. Any type with a * is optional.
+|Type |Description |
+|-------|-------------------------------------------------------------------------------------|
+|uint |The magic number, the value will always be 0x036144AF. |
+|uint |Version of the file format. This is backwards compatible but not forwards compatible.|
+|mesh[] |The mesh data. |
+
+mesh:
+|Type |Description |
+|-----------|-------------------------------------------------------------------------------------|
+|uint |The number of vertices, normals and optionally texture coordinates. |
+|vec3f[] |A list of vertices. |
+|vec3f[] |A list of normals. |
+|uint |The number of faces. Each face has 3 indices of type uint. |
+|uint[] |The face indices. |
+|uint |1 if the model has texture coordinates, otherwise 0. |
+|vec3f[]* |A list of texture coordinates. |
+|uint |1 if the model has materials, otherwise 0. |
+|material[3]|The material data. This is a list of [diffuse, specular, ambient] materials. |
+
+vec3f:
+|Type |Description |
+|-----|----------------|
+|float|The x coordiate.|
+|float|The y coordiate.|
+|float|The z coordiate.|
+
+material:
+|Type |Description |
+|------|-------------------------------------------------------------------------|
+|uint |The number of textures. |
+|char[]|The filepath to the texture (relative). This is a null-terminated string.|
diff --git a/project.conf b/project.conf
new file mode 100644
index 0000000..7f989af
--- /dev/null
+++ b/project.conf
@@ -0,0 +1,8 @@
+[package]
+name = "amalgine-model-converter"
+type = "executable"
+version = "0.1.0"
+platforms = ["any"]
+
+[dependencies]
+assimp = "5"
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..a679828
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,114 @@
+#include <assert.h>
+#include <stdio.h>
+
+#include <assimp/Importer.hpp>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/LogStream.hpp>
+
+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 <source> <destination>\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);
+ }
+} \ No newline at end of file