Friday, July 13, 2012

Open Asset Import Library (AssImp) is great!

I can only recommend you to try it out, it has a very simple and well structured API and supports many different formats, including COLLADA.
You don't even need to compile the whole thing, just download the package from sourceforge, add the include path and dynamically link to the provided DLL (you will only need to import aiImportFile, aiReleaseImport and some of the material getter functions).
I use AssImp in my little converter tool to translate COLLADA files to a custom binary format.

Here is a small snippet to dump simple meshes (separate binary files for vertex attributes and indices):

(some helper code first)
class ExportFile {
    FILE* f;
    ExportFile(const char* filename) { f = fopen(filename, "wb"); }
    ~ExportFile() { fclose(f); }
    inline void writeU32(uint32 value) { fwrite(&value, 1, sizeof(uint32), f); }
    inline void write(void* data, size_t length) { fwrite(data, 1, length, f); }
 // etc.

void writeArray(const char* filename, unsigned int count, size_t stride, void* data)
    ExportFile f(filename);
    f.write(data, count*stride);
Here's the export function:
void exportMesh(aiMesh* mesh)
    std::string meshName = meshNodeNames[mesh];

 // vertex arrays
    writeArray((meshName + std::string(".vtx")).c_str(), mesh->mNumVertices,
               sizeof(aiVector3D), mesh->mVertices);
    writeArray((meshName + std::string(".nrm")).c_str(), mesh->mNumVertices, 
                sizeof(aiVector3D), mesh->mNormals);

    if (mesh->mTangents) {
        writeArray((meshName + std::string(".tan")).c_str(), mesh->mNumVertices, 
                   sizeof(aiVector3D), mesh->mTangents);
    // texcoords
    char uvFilename[256];
    int numUVs = 0;
    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
        if (mesh->mTextureCoords[i]) {
            unsigned int numComps = mesh->mNumUVComponents[i];
            aiVector3D* uvw_array = mesh->mTextureCoords[i];
            float* tex = new float[numComps * mesh->mNumVertices];

            for (unsigned int v=0; v < mesh->mNumVertices; v++) {
                if (numComps >= 1) tex[v*numComps+0] = uvw_array[v].x;
                if (numComps >= 2) tex[v*numComps+1] = uvw_array[v].y;
                if (numComps >= 3) tex[v*numComps+2] = uvw_array[v].z;

            sprintf(uvFilename, "%s.uv%d", meshName.c_str(), i);
            writeArray(uvFilename, mesh->mNumVertices, sizeof(float)*numComps, tex);

            delete[] tex;

    // indices
    size_t idxCount = mesh->mNumFaces*3;
    assert(idxCount <= 65536);

    uint16* indices = new uint16[idxCount];
    for (unsigned int i=0; i < mesh->mNumFaces; i++) {
        assert(mesh->mFaces[i].mNumIndices == 3);
        indices[i*3+0] = mesh->mFaces[i].mIndices[0];
        indices[i*3+1] = mesh->mFaces[i].mIndices[1];
        indices[i*3+2] = mesh->mFaces[i].mIndices[2];
    writeArray((meshName + std::string(".idx")).c_str(), idxCount, sizeof(uint16), indices);

    delete[] indices;