From fb15ed80cb120747a60757e265db8f531a5a9b67 Mon Sep 17 00:00:00 2001 From: gered Date: Wed, 27 Apr 2011 16:01:43 -0400 Subject: [PATCH] implemented converting static meshes --- AssimpToMesh/AssimpToMesh.vcxproj | 7 + AssimpToMesh/AssimpToMesh.vcxproj.filters | 21 ++ .../src/assimputils/assimpgeometry.cpp | 69 +++++++ AssimpToMesh/src/assimputils/types.h | 13 ++ AssimpToMesh/src/assimputils/utils.h | 27 +++ AssimpToMesh/src/convert/mesh.h | 20 ++ AssimpToMesh/src/convert/meshmaterial.h | 63 ++++++ AssimpToMesh/src/convert/meshtriangle.h | 12 ++ AssimpToMesh/src/convert/meshutils.cpp | 194 ++++++++++++++++++ AssimpToMesh/src/convert/static.cpp | 68 ++++++ AssimpToMesh/src/convert/submesh.h | 14 ++ 11 files changed, 508 insertions(+) create mode 100644 AssimpToMesh/src/assimputils/assimpgeometry.cpp create mode 100644 AssimpToMesh/src/assimputils/types.h create mode 100644 AssimpToMesh/src/convert/mesh.h create mode 100644 AssimpToMesh/src/convert/meshmaterial.h create mode 100644 AssimpToMesh/src/convert/meshtriangle.h create mode 100644 AssimpToMesh/src/convert/meshutils.cpp create mode 100644 AssimpToMesh/src/convert/submesh.h diff --git a/AssimpToMesh/AssimpToMesh.vcxproj b/AssimpToMesh/AssimpToMesh.vcxproj index 46477b8..2c7977b 100644 --- a/AssimpToMesh/AssimpToMesh.vcxproj +++ b/AssimpToMesh/AssimpToMesh.vcxproj @@ -80,7 +80,9 @@ + + @@ -88,8 +90,13 @@ + + + + + diff --git a/AssimpToMesh/AssimpToMesh.vcxproj.filters b/AssimpToMesh/AssimpToMesh.vcxproj.filters index 9a185ee..7a4b7e3 100644 --- a/AssimpToMesh/AssimpToMesh.vcxproj.filters +++ b/AssimpToMesh/AssimpToMesh.vcxproj.filters @@ -33,6 +33,12 @@ Source Files + + Source Files + + + Source Files + @@ -47,5 +53,20 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/AssimpToMesh/src/assimputils/assimpgeometry.cpp b/AssimpToMesh/src/assimputils/assimpgeometry.cpp new file mode 100644 index 0000000..1d8efbf --- /dev/null +++ b/AssimpToMesh/src/assimputils/assimpgeometry.cpp @@ -0,0 +1,69 @@ +#include "utils.h" + +// determine if a vertex is already contained in the bucket, if so matchingIndex will contain the index of the matching vertex +bool FindVertex(const aiVector3D &vertex, const AssimpVertices &bucket, unsigned int &matchingIndex) +{ + for (unsigned int i = 0; i < bucket.size(); ++i) + { + if (vertex == bucket[i]) + { + matchingIndex = i; + return true; + } + } + + return false; +} + +void CollectVerticesInMesh( + const aiMesh *mesh, + AssimpVertices &verticesBucket, + AssimpVertices &normalsBucket, + AssimpVertices &texCoordsBucket, + AssimpVertexIndices &indexMapping) +{ + indexMapping.resize(mesh->mNumVertices); + + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) + { + unsigned int matchingIndex = 0; + aiVector3D vertex = mesh->mVertices[i]; + + if (!FindVertex(vertex, verticesBucket, matchingIndex)) + { + // vertex isn't in the bucket already, add it, and then record mapping between the mesh vertex index and the bucket vertex index + verticesBucket.push_back(vertex); + matchingIndex = verticesBucket.size() - 1; + + // also copy the normal and tex coord into the appropriate buckets + // TODO: check if mesh has normals and/or tex coords first! + aiVector3D normal = mesh->mNormals[i]; + normalsBucket.push_back(normal); + aiVector3D texCoord = mesh->mTextureCoords[0][i]; + texCoordsBucket.push_back(texCoord); + } + + // stating the obvious so when i come back here and read this, i know instantly + // what the fuck is going on (sad, I know): + // i = index into mesh's separate vertices list + // matchingIndex = index into bucket's vertices list + indexMapping[i] = matchingIndex; + } +} + +void CollectAllMeshVertices( + const aiScene *scene, + AssimpVertices &verticesBucket, + AssimpVertices &normalsBucket, + AssimpVertices &texCoordsBucket, + AssimpVerticesMap &indexMapping) +{ + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) + { + aiMesh *mesh = scene->mMeshes[i]; + AssimpVertexIndices indexes; + CollectVerticesInMesh(mesh, verticesBucket, normalsBucket, texCoordsBucket, indexes); + + indexMapping[i] = indexes; + } +} diff --git a/AssimpToMesh/src/assimputils/types.h b/AssimpToMesh/src/assimputils/types.h new file mode 100644 index 0000000..bc7eb9d --- /dev/null +++ b/AssimpToMesh/src/assimputils/types.h @@ -0,0 +1,13 @@ +#ifndef __ASSIMPUTILS_TYPES_H_INCLUDED__ +#define __ASSIMPUTILS_TYPES_H_INCLUDED__ + +#include +#include +#include + +typedef std::vector AssimpVertices; + +typedef std::vector AssimpVertexIndices; +typedef std::map AssimpVerticesMap; + +#endif diff --git a/AssimpToMesh/src/assimputils/utils.h b/AssimpToMesh/src/assimputils/utils.h index 525ec6c..307f05e 100644 --- a/AssimpToMesh/src/assimputils/utils.h +++ b/AssimpToMesh/src/assimputils/utils.h @@ -4,8 +4,35 @@ #include #include +#include +#include + +#include "types.h" + bool IsSceneAnimated(const aiScene *scene); bool IsSceneSkeletal(const aiScene *scene); bool IsSceneStatic(const aiScene *scene); +/** + * This will go through each mesh in the scene, and store all the vertices it + * finds into one common bucket, building up a mapping as it goes so that, + * we can easily determine what mesh index and vertex index as stored by ASSIMP + * corresponds to what vertex in the common bucket. That is, after this, given: + * + * aiScene *scene = ... + * aiMesh *mesh = scene->mMeshes[meshIndex]; + * unsigned int bucketIndex = mesh->mVertices[3]; + * ... and/or ... + * unsigned int bucketIndex = mesh->mFaces[10]->mIndices[0]; + * aiVector3D vertex = bucket[bucketIndex]; + * + * where "bucketIndex" is the index into one of the bucket lists + */ +void CollectAllMeshVertices( + const aiScene *scene, + AssimpVertices &verticesBucket, + AssimpVertices &normalsBucket, + AssimpVertices &texCoordsBucket, + AssimpVerticesMap &indexMapping); + #endif diff --git a/AssimpToMesh/src/convert/mesh.h b/AssimpToMesh/src/convert/mesh.h new file mode 100644 index 0000000..6778e38 --- /dev/null +++ b/AssimpToMesh/src/convert/mesh.h @@ -0,0 +1,20 @@ +#ifndef __CONVERT_MESH_H_INCLUDED__ +#define __CONVERT_MESH_H_INCLUDED__ + +#include +#include +#include +#include "../assimputils/types.h" +#include "meshmaterial.h" +#include "meshtriangle.h" +#include "submesh.h" + +void WriteMeshHeader(FILE *fp); +void WriteVertices(const AssimpVertices &vertices, FILE *fp); +void WriteNormals(const AssimpVertices &normals, FILE *fp); +void WriteTexCoords(const AssimpVertices &texCoords, FILE *fp); +void WriteMaterials(const std::vector &materials, FILE *fp); +void WriteTriangles(const std::vector &triangles, FILE *fp); +void WriteSubMeshes(const std::vector &subMeshes, FILE *fp); + +#endif diff --git a/AssimpToMesh/src/convert/meshmaterial.h b/AssimpToMesh/src/convert/meshmaterial.h new file mode 100644 index 0000000..7d69c24 --- /dev/null +++ b/AssimpToMesh/src/convert/meshmaterial.h @@ -0,0 +1,63 @@ +#ifndef __CONVERT_MESHMATERIAL_H_INCLUDED__ +#define __CONVERT_MESHMATERIAL_H_INCLUDED__ + +#include +#include + +struct MeshMaterial +{ + MeshMaterial() + { + } + + MeshMaterial(const aiMaterial *source) + { + aiString name; + aiColor3D ambient; + aiColor3D diffuse; + aiColor3D specular; + aiColor3D emissive; + float shininess; + float opacity; + + source->Get(AI_MATKEY_NAME, name); + source->Get(AI_MATKEY_COLOR_AMBIENT, ambient); + source->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); + source->Get(AI_MATKEY_COLOR_SPECULAR, specular); + source->Get(AI_MATKEY_COLOR_EMISSIVE, emissive); + source->Get(AI_MATKEY_SHININESS, shininess); + source->Get(AI_MATKEY_OPACITY, opacity); + + this->name = std::string(name.data, name.length); + + this->ambient[0] = ambient.r; + this->ambient[1] = ambient.g; + this->ambient[2] = ambient.b; + + this->diffuse[0] = diffuse.r; + this->diffuse[1] = diffuse.g; + this->diffuse[2] = diffuse.b; + + this->specular[0] = specular.r; + this->specular[1] = specular.g; + this->specular[2] = specular.b; + + this->emissive[0] = emissive.r; + this->emissive[1] = emissive.g; + this->emissive[2] = emissive.b; + + this->shininess = shininess; + + this->opacity = opacity; + } + + std::string name; + float ambient[3]; + float diffuse[3]; + float specular[3]; + float emissive[3]; + float shininess; + float opacity; +}; + +#endif diff --git a/AssimpToMesh/src/convert/meshtriangle.h b/AssimpToMesh/src/convert/meshtriangle.h new file mode 100644 index 0000000..5c1824c --- /dev/null +++ b/AssimpToMesh/src/convert/meshtriangle.h @@ -0,0 +1,12 @@ +#ifndef __CONVERT_MESHTRIANGLE_H_INCLUDED__ +#define __CONVERT_MESHTRIANGLE_H_INCLUDED__ + +#include + +struct MeshTriangle +{ + uint32_t vertices[3]; + uint32_t subMesh; +}; + +#endif diff --git a/AssimpToMesh/src/convert/meshutils.cpp b/AssimpToMesh/src/convert/meshutils.cpp new file mode 100644 index 0000000..3cfccad --- /dev/null +++ b/AssimpToMesh/src/convert/meshutils.cpp @@ -0,0 +1,194 @@ +#include "mesh.h" + +#include +#include + +void WriteMeshHeader(FILE *fp) +{ + fputs("MESH", fp); + uint8_t version = 1; + fwrite(&version, 1, 1, fp); +} + +void WriteVertices(const AssimpVertices &vertices, FILE *fp) +{ + uint32_t count = vertices.size(); + if (count == 0) + return; + + uint32_t size = + (sizeof(float) * 3) * // x y, z + vertices.size() + + 4; // chunk size + + fputs("VTX", fp); + fwrite(&size, 4, 1, fp); + fwrite(&count, 4, 1, fp); + + for (uint32_t i = 0; i < count; ++i) + { + fwrite(&vertices[i].x, sizeof(float), 1, fp); + fwrite(&vertices[i].y, sizeof(float), 1, fp); + fwrite(&vertices[i].z, sizeof(float), 1, fp); + } +} + +void WriteNormals(const AssimpVertices &normals, FILE *fp) +{ + uint32_t count = normals.size(); + if (count == 0) + return; + + uint32_t size = + (sizeof(float) * 3) * // x y, z + normals.size() + + 4; // chunk size + + fputs("NRL", fp); + fwrite(&size, 4, 1, fp); + fwrite(&count, 4, 1, fp); + + for (uint32_t i = 0; i < count; ++i) + { + fwrite(&normals[i].x, sizeof(float), 1, fp); + fwrite(&normals[i].y, sizeof(float), 1, fp); + fwrite(&normals[i].z, sizeof(float), 1, fp); + } +} + +void WriteTexCoords(const AssimpVertices &texCoords, FILE *fp) +{ + uint32_t count = texCoords.size(); + if (count == 0) + return; + + uint32_t size = + (sizeof(float) * 2) * // u, v + texCoords.size() + + 4; // count + + fputs("TXT", fp); + fwrite(&size, 4, 1, fp); + fwrite(&count, 4, 1, fp); + + for (uint32_t i = 0; i < count; ++i) + { + fwrite(&texCoords[i].x, sizeof(float), 1, fp); + fwrite(&texCoords[i].y, sizeof(float), 1, fp); + } +} + +void WriteMaterials(const std::vector &materials, FILE *fp) +{ + uint32_t count = materials.size(); + if (count == 0) + return; + + uint32_t size = 4 + // count + ( + ( + (sizeof(float) * 3) + // ambient + (sizeof(float) * 3) + // diffuse + (sizeof(float) * 3) + // specular + (sizeof(float) * 3) + // emissive + sizeof(float) + // shininess + sizeof(float) // opacity + ) * count + ); + + // add up all the variable length string sizes for the material names + for (uint32_t i = 0; i < count; ++i) + size += materials[i].name.length() + 1; // include null terminator + + fputs("MTL", fp); + fwrite(&size, 4, 1, fp); + fwrite(&count, 4, 1, fp); + + for (uint32_t i = 0; i < count; ++i) + { + const MeshMaterial *m = &materials[i]; + + fwrite(m->name.c_str(), m->name.length(), 1, fp); + char ch = '\0'; + fwrite(&ch, 1, 1, fp); + + fwrite(&m->ambient[0], sizeof(float), 1, fp); + fwrite(&m->ambient[1], sizeof(float), 1, fp); + fwrite(&m->ambient[2], sizeof(float), 1, fp); + + fwrite(&m->diffuse[0], sizeof(float), 1, fp); + fwrite(&m->diffuse[1], sizeof(float), 1, fp); + fwrite(&m->diffuse[2], sizeof(float), 1, fp); + + fwrite(&m->specular[0], sizeof(float), 1, fp); + fwrite(&m->specular[1], sizeof(float), 1, fp); + fwrite(&m->specular[2], sizeof(float), 1, fp); + + fwrite(&m->emissive[0], sizeof(float), 1, fp); + fwrite(&m->emissive[1], sizeof(float), 1, fp); + fwrite(&m->emissive[2], sizeof(float), 1, fp); + + fwrite(&m->shininess, sizeof(float), 1, fp); + + fwrite(&m->opacity, sizeof(float), 1, fp); + } +} + +void WriteTriangles(const std::vector &triangles, FILE *fp) +{ + uint32_t count = triangles.size(); + if (count == 0) + return; + + uint32_t size = 4; // count + size += + ( + (4 * 3) // vertex indices + + 4 // material index + ) * count; + + fputs("TRI", fp); + fwrite(&size, 4, 1, fp); + fwrite(&count, 4, 1, fp); + + for (uint32_t i = 0; i < count; ++i) + { + const MeshTriangle *t = &triangles[i]; + + fwrite(&t->vertices[0], 4, 1, fp); + fwrite(&t->vertices[1], 4, 1, fp); + fwrite(&t->vertices[2], 4, 1, fp); + + fwrite(&t->subMesh, 4, 1, fp); + } +} + +void WriteSubMeshes(const std::vector &subMeshes, FILE *fp) +{ + uint32_t count = subMeshes.size(); + if (count == 0) + return; + + uint32_t size = 4 + // count + 4 + // material index + 4; // count of triangles + + // add up all the variable length string sizes for the submesh names + for (uint32_t i = 0; i < count; ++i) + size += subMeshes[i].name.length() + 1; // include null terminator + + fputs("GRP", fp); + fwrite(&size, 4, 1, fp); + fwrite(&count, 4, 1, fp); + for (uint32_t i = 0; i < count; ++i) + { + const SubMesh *m = &subMeshes[i]; + + fwrite(m->name.c_str(), m->name.length(), 1, fp); + char c = '\0'; + fwrite(&c, 1, 1, fp); + + fwrite(&m->material, 4, 1, fp); + fwrite(&m->numTriangles, 4, 1, fp); + } +} diff --git a/AssimpToMesh/src/convert/static.cpp b/AssimpToMesh/src/convert/static.cpp index 57c0a64..a014321 100644 --- a/AssimpToMesh/src/convert/static.cpp +++ b/AssimpToMesh/src/convert/static.cpp @@ -1,5 +1,73 @@ #include "convert.h" +#include +#include +#include + +#include "mesh.h" +#include "../assimputils/utils.h" + void ConvertStatic(const std::string &outfile, const aiScene *scene) { + FILE *fp = fopen(outfile.c_str(), "wb"); + if (fp == NULL) + throw std::exception("Error creating output file."); + + WriteMeshHeader(fp); + + // basic mesh info + AssimpVertices vertices; + AssimpVertices normals; + AssimpVertices texCoords; + AssimpVerticesMap vertexIndicesMap; + CollectAllMeshVertices(scene, vertices, normals, texCoords, vertexIndicesMap); + WriteVertices(vertices, fp); + WriteNormals(normals, fp); + WriteTexCoords(texCoords, fp); + + // materials + std::vector materials; + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) + { + MeshMaterial material = MeshMaterial(scene->mMaterials[i]); + materials.push_back(material); + } + WriteMaterials(materials, fp); + + // triangles + std::vector triangles; + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) + { + aiMesh *mesh = scene->mMeshes[i]; + for (unsigned int j = 0; j < mesh->mNumFaces; ++j) + { + aiFace *face = &mesh->mFaces[j]; + + MeshTriangle triangle; + triangle.vertices[0] = vertexIndicesMap[i][face->mIndices[0]]; + triangle.vertices[1] = vertexIndicesMap[i][face->mIndices[1]]; + triangle.vertices[2] = vertexIndicesMap[i][face->mIndices[2]]; + triangle.subMesh = i; + + triangles.push_back(triangle); + } + } + WriteTriangles(triangles, fp); + + // sub meshes + std::vector subMeshes; + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) + { + aiMesh *mesh = scene->mMeshes[i]; + SubMesh subMesh; + + subMesh.name = std::string(mesh->mName.data, mesh->mName.length); + subMesh.material = mesh->mMaterialIndex; + subMesh.numTriangles = mesh->mNumFaces; + + subMeshes.push_back(subMesh); + } + WriteSubMeshes(subMeshes, fp); + + fclose(fp); } diff --git a/AssimpToMesh/src/convert/submesh.h b/AssimpToMesh/src/convert/submesh.h new file mode 100644 index 0000000..d9edc7f --- /dev/null +++ b/AssimpToMesh/src/convert/submesh.h @@ -0,0 +1,14 @@ +#ifndef __CONVERT_SUBMESH_H_INCLUDED__ +#define __CONVERT_SUBMESH_H_INCLUDED__ + +#include +#include + +struct SubMesh +{ + std::string name; + uint32_t material; + uint32_t numTriangles; +}; + +#endif