static int processBonesAndAnimations(glhckObject *object, const struct aiScene *sc) { unsigned int i, b, numBones = 0, oldNumBones; const struct aiMesh *mesh; glhckObject *child; glhckBone **bones = NULL; glhckSkinBone **skinBones = NULL; /* import bones */ if (!(bones = _glhckCalloc(ASSIMP_BONES_MAX, sizeof(glhckBone*)))) goto fail; if (!(skinBones = _glhckCalloc(ASSIMP_BONES_MAX, sizeof(glhckSkinBone*)))) goto fail; for (i = 0; i != sc->mNumMeshes; ++i) { mesh = sc->mMeshes[i]; /* FIXME: UGLY */ char pointer[16]; snprintf(pointer, sizeof(pointer), "%p", mesh); if (!(child = findObject(object, pointer))) continue; if (mesh->mNumBones) { oldNumBones = numBones; processBones(sc->mRootNode, sc->mRootNode, mesh, bones, skinBones, &numBones); if (numBones) glhckObjectInsertSkinBones(child, skinBones+oldNumBones, numBones-oldNumBones); for (b = oldNumBones; b < numBones; ++b) glhckSkinBoneFree(skinBones[b]); } } /* we don't need skin bones anymore */ NULLDO(_glhckFree, skinBones); /* store all bones in root object */ if (numBones) glhckObjectInsertBones(object, bones, numBones); for (b = 0; b < numBones; ++b) glhckBoneFree(bones[b]); NULLDO(_glhckFree, bones); /* import animations */ if (sc->mNumAnimations && processAnimations(object, sc) != RETURN_OK) goto fail; return RETURN_OK; fail: if (bones) { for (i = 0; i < ASSIMP_BONES_MAX; ++i) if (bones[i]) glhckBoneFree(bones[i]); _glhckFree(bones); } if (skinBones) { for (i = 0; i < ASSIMP_BONES_MAX; ++i) if (skinBones[i]) glhckSkinBoneFree(skinBones[i]); _glhckFree(skinBones); } return RETURN_FAIL; }
/* \brief allocate new camera */ GLHCKAPI glhckCamera* glhckCameraNew(void) { glhckCamera *object; /* allocate camera */ if (!(object = _glhckCalloc(1, sizeof(glhckCamera)))) goto fail; /* increase reference */ object->refCounter++; /* initialize camera's object */ if (!(object->object = glhckObjectNew())) goto fail; /* defaults */ object->view.projectionType = GLHCK_PROJECTION_PERSPECTIVE; object->view.near = 1.0f; object->view.far = 100.0f; object->view.fov = 35.0f; /* reset */ glhckCameraReset(object); /* insert to world */ _glhckWorldInsert(camera, object, glhckCamera*); RET(0, "%p", object); return object; fail: IFDO(_glhckFree, object); RET(0, "%p", NULL); return NULL; }
/* \brief allocate new texture object */ GLHCKAPI glhckTexture* glhckTextureNew(void) { glhckTexture *object; /* allocate texture */ if (!(object = _glhckCalloc(1, sizeof(glhckTexture)))) goto fail; /* increase reference */ object->refCounter++; /* default target type */ object->target = GLHCK_TEXTURE_2D; /* insert to world */ _glhckWorldInsert(texture, object, glhckTexture*); RET(0, "%p", object); return object; fail: IFDO(glhckTextureFree, object); RET(0, "%p", NULL); return NULL; }
/* \brief allocate new skin bone object */ GLHCKAPI glhckSkinBone* glhckSkinBoneNew(void) { glhckSkinBone *object; TRACE(0); /* allocate object */ if (!(object = _glhckCalloc(1, sizeof(glhckSkinBone)))) goto fail; /* increase reference */ object->refCounter++; /* identity matrices */ kmMat4Identity(&object->offsetMatrix); /* insert to world */ _glhckWorldInsert(skinBone, object, glhckSkinBone*); RET(0, "%p", object); return object; fail: RET(0, "%p", NULL); return NULL; }
/* \brief import MikuMikuDance PMD file */ int _glhckImportPMD(_glhckObject *object, const char *file, const glhckImportModelParameters *params, glhckGeometryIndexType itype, glhckGeometryVertexType vtype) { FILE *f; char *texturePath; mmd_data *mmd = NULL; glhckAtlas *atlas = NULL; glhckMaterial *material = NULL; glhckTexture *texture = NULL, **textureList = NULL; glhckImportVertexData *vertexData = NULL; glhckImportIndexData *indices = NULL, *stripIndices = NULL; unsigned int geometryType = GLHCK_TRIANGLE_STRIP; unsigned int i, i2, ix, start, numFaces, numIndices = 0; CALL(0, "%p, %s, %p", object, file, params); if (!(f = fopen(file, "rb"))) goto read_fail; if (!(mmd = mmd_new(f))) goto mmd_no_memory; if (mmd_read_header(mmd) != 0) goto mmd_import_fail; if (mmd_read_vertex_data(mmd) != 0) goto mmd_import_fail; if (mmd_read_index_data(mmd) != 0) goto mmd_import_fail; if (mmd_read_material_data(mmd) != 0) goto mmd_import_fail; /* close file */ NULLDO(fclose, f); if (mmd->header.name) { DEBUG(GLHCK_DBG_CRAP, "%s\n", mmd->header.name); } if (mmd->header.comment) printf("%s\n\n", mmd->header.comment); if (!(vertexData = _glhckCalloc(mmd->num_vertices, sizeof(glhckImportVertexData)))) goto mmd_no_memory; if (!(indices = _glhckMalloc(mmd->num_indices * sizeof(unsigned int)))) goto mmd_no_memory; if (!(textureList = _glhckCalloc(mmd->num_materials, sizeof(_glhckTexture*)))) goto mmd_no_memory; if (!(atlas = glhckAtlasNew())) goto mmd_no_memory; /* add all textures to atlas packer */ for (i = 0; i < mmd->num_materials; ++i) { if (!mmd->materials[i].texture) continue; if (!(texturePath = _glhckImportTexturePath(mmd->materials[i].texture, file))) continue; if ((texture = glhckTextureNewFromFile(texturePath, NULL, NULL))) { glhckAtlasInsertTexture(atlas, texture); glhckTextureFree(texture); textureList[i] = texture; } _glhckFree(texturePath); } for (i = 0; i < mmd->num_materials && !textureList[i]; ++i); if (i >= mmd->num_materials) { /* no textures found */ NULLDO(glhckAtlasFree, atlas); NULLDO(_glhckFree, textureList); } else { /* pack textures */ if (glhckAtlasPack(atlas, GLHCK_RGBA, 1, 0, glhckTextureDefaultParameters()) != RETURN_OK) goto fail; } /* assign data */ for (i = 0, start = 0; i < mmd->num_materials; ++i, start += numFaces) { numFaces = mmd->materials[i].face; for (i2 = start; i2 < start + numFaces; ++i2) { ix = mmd->indices[i2]; /* vertices */ vertexData[ix].vertex.x = mmd->vertices[ix*3+0]; vertexData[ix].vertex.y = mmd->vertices[ix*3+1]; vertexData[ix].vertex.z = mmd->vertices[ix*3+2]; /* normals */ vertexData[ix].normal.x = mmd->normals[ix*3+0]; vertexData[ix].normal.y = mmd->normals[ix*3+1]; vertexData[ix].normal.z = mmd->normals[ix*3+2]; /* texture coords */ vertexData[ix].coord.x = mmd->coords[ix*2+0]; vertexData[ix].coord.y = mmd->coords[ix*2+1] * -1; /* fix coords */ if (vertexData[ix].coord.x < 0.0f) vertexData[ix].coord.x += 1.0f; if (vertexData[ix].coord.y < 0.0f) vertexData[ix].coord.y += 1.0f; /* if there is packed texture */ if (atlas && textureList[i]) { kmVec2 coord; coord.x = vertexData[ix].coord.x; coord.y = vertexData[ix].coord.y; glhckAtlasTransformCoordinates(atlas, textureList[i], &coord, &coord); vertexData[ix].coord.x = coord.x; vertexData[ix].coord.y = coord.y; } indices[i2] = ix; } } if (atlas) { if (!(material = glhckMaterialNew(glhckAtlasGetTexture(atlas)))) goto mmd_no_memory; glhckObjectMaterial(object, material); NULLDO(glhckMaterialFree, material); NULLDO(glhckAtlasFree, atlas); NULLDO(_glhckFree, textureList); } /* triangle strip geometry */ if (!(stripIndices = _glhckTriStrip(indices, mmd->num_indices, &numIndices))) { /* failed, use non stripped geometry */ geometryType = GLHCK_TRIANGLES; numIndices = mmd->num_indices; stripIndices = indices; } else NULLDO(_glhckFree, indices); /* set geometry */ glhckObjectInsertIndices(object, itype, stripIndices, numIndices); glhckObjectInsertVertices(object, vtype, vertexData, mmd->num_vertices); object->geometry->type = geometryType; /* finish */ NULLDO(_glhckFree, vertexData); NULLDO(_glhckFree, stripIndices); NULLDO(mmd_free, mmd); RET(0, "%d", RETURN_OK); return RETURN_OK; read_fail: DEBUG(GLHCK_DBG_ERROR, "Failed to open: %s", file); goto fail; mmd_import_fail: DEBUG(GLHCK_DBG_ERROR, "MMD importing failed."); goto fail; mmd_no_memory: DEBUG(GLHCK_DBG_ERROR, "MMD not enough memory."); fail: IFDO(fclose, f); IFDO(glhckAtlasFree, atlas); IFDO(mmd_free, mmd); IFDO(_glhckFree, textureList); IFDO(_glhckFree, vertexData); IFDO(_glhckFree, indices); IFDO(_glhckFree, stripIndices); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
static int processModel(const char *file, glhckObject *object, glhckObject *current, const struct aiScene *sc, const struct aiNode *nd, glhckGeometryIndexType itype, glhckGeometryVertexType vtype, const glhckImportModelParameters *params) { unsigned int m, f; unsigned int numVertices = 0, numIndices = 0; unsigned int ioffset, voffset; glhckImportIndexData *indices = NULL; glhckImportVertexData *vertexData = NULL; glhckMaterial *material = NULL; glhckTexture **textureList = NULL, *texture = NULL; glhckAtlas *atlas = NULL; const struct aiMesh *mesh; const struct aiFace *face; int canFreeCurrent = 0; int hasTexture = 0; assert(file); assert(object && current); assert(sc && nd); /* combine && atlas loading path */ if (params->flatten) { /* prepare atlas for texture combining */ if (!(atlas = glhckAtlasNew())) goto assimp_no_memory; /* texturelist for offseting coordinates */ if (!(textureList = _glhckCalloc(nd->mNumMeshes, sizeof(_glhckTexture*)))) goto assimp_no_memory; /* gather statistics */ for (m = 0; m != nd->mNumMeshes; ++m) { mesh = sc->mMeshes[nd->mMeshes[m]]; if (!mesh->mVertices) continue; for (f = 0; f != mesh->mNumFaces; ++f) { face = &mesh->mFaces[f]; if (!face) goto fail; numIndices += face->mNumIndices; } numVertices += mesh->mNumVertices; if ((texture = textureFromMaterial(file, sc->mMaterials[mesh->mMaterialIndex]))) { glhckAtlasInsertTexture(atlas, texture); glhckTextureFree(texture); textureList[m] = texture; hasTexture = 1; } } /* allocate vertices */ if (!(vertexData = _glhckCalloc(numVertices, sizeof(glhckImportVertexData)))) goto assimp_no_memory; /* allocate indices */ if (!(indices = _glhckMalloc(numIndices * sizeof(glhckImportIndexData)))) goto assimp_no_memory; /* pack combined textures */ if (hasTexture) { if (glhckAtlasPack(atlas, GLHCK_RGBA, 1, 0, glhckTextureDefaultParameters()) != RETURN_OK) goto fail; } else { NULLDO(glhckAtlasFree, atlas); NULLDO(_glhckFree, textureList); } /* join vertex data */ for (m = 0, ioffset = 0, voffset = 0; m != nd->mNumMeshes; ++m) { mesh = sc->mMeshes[nd->mMeshes[m]]; if (!mesh->mVertices) continue; if (textureList) texture = textureList[m]; else texture = NULL; joinMesh(mesh, voffset, indices+ioffset, vertexData+voffset, atlas, texture); for (f = 0; f != mesh->mNumFaces; ++f) { face = &mesh->mFaces[f]; if (!face) goto fail; ioffset += face->mNumIndices; } voffset += mesh->mNumVertices; } /* create material */ if (hasTexture && !(material = glhckMaterialNew(texture))) goto assimp_no_memory; /* finally build the model */ if (buildModel(current, numIndices, numVertices, indices, vertexData, itype, vtype) == RETURN_OK) { _glhckObjectFile(current, nd->mName.data); if (material) glhckObjectMaterial(current, material); if (!(current = glhckObjectNew())) goto fail; glhckObjectAddChild(object, current); glhckObjectFree(current); canFreeCurrent = 1; } /* free stuff */ IFDO(glhckAtlasFree, atlas); IFDO(glhckMaterialFree, material); IFDO(_glhckFree, textureList); NULLDO(_glhckFree, vertexData); NULLDO(_glhckFree, indices); } else { /* default loading path */ for (m = 0, ioffset = 0, voffset = 0; m != nd->mNumMeshes; ++m) { mesh = sc->mMeshes[nd->mMeshes[m]]; if (!mesh->mVertices) continue; /* gather statistics */ numIndices = 0; for (f = 0; f != mesh->mNumFaces; ++f) { face = &mesh->mFaces[f]; if (!face) goto fail; numIndices += face->mNumIndices; } numVertices = mesh->mNumVertices; // FIXME: create materialFromAssimpMaterial // that returns glhckMaterial with correct stuff /* get texture */ hasTexture = 0; if ((texture = textureFromMaterial(file, sc->mMaterials[mesh->mMaterialIndex]))) hasTexture = 1; /* create material */ if (hasTexture && !(material = glhckMaterialNew(texture))) goto assimp_no_memory; /* allocate vertices */ if (!(vertexData = _glhckCalloc(numVertices, sizeof(glhckImportVertexData)))) goto assimp_no_memory; /* allocate indices */ if (!(indices = _glhckMalloc(numIndices * sizeof(glhckImportIndexData)))) goto assimp_no_memory; /* fill arrays */ joinMesh(mesh, 0, indices, vertexData, NULL, NULL); /* build model */ if (buildModel(current, numIndices, numVertices, indices, vertexData, itype, vtype) == RETURN_OK) { /* FIXME: UGLY */ char pointer[16]; snprintf(pointer, sizeof(pointer), "%p", mesh); _glhckObjectFile(current, pointer); if (material) glhckObjectMaterial(current, material); if (!(current = glhckObjectNew())) goto fail; glhckObjectAddChild(object, current); glhckObjectFree(current); canFreeCurrent = 1; } /* free stuff */ NULLDO(_glhckFree, vertexData); NULLDO(_glhckFree, indices); IFDO(glhckTextureFree, texture); IFDO(glhckMaterialFree, material); } } /* process childrens */ for (m = 0; m != nd->mNumChildren; ++m) { if (processModel(file, object, current, sc, nd->mChildren[m], itype, vtype, params) == RETURN_OK) { if (!(current = glhckObjectNew())) goto fail; glhckObjectAddChild(object, current); glhckObjectFree(current); canFreeCurrent = 1; } } /* we din't do anything to the next * allocated object, so free it */ if (canFreeCurrent) glhckObjectRemoveFromParent(current); return RETURN_OK; assimp_no_memory: DEBUG(GLHCK_DBG_ERROR, "Assimp not enough memory."); fail: IFDO(_glhckFree, vertexData); IFDO(_glhckFree, indices); IFDO(_glhckFree, textureList); IFDO(glhckTextureFree, texture); IFDO(glhckMaterialFree, material); IFDO(glhckAtlasFree, atlas); if (canFreeCurrent) glhckObjectRemoveFromParent(current); return RETURN_FAIL; }
static int processAnimations(glhckObject *object, const struct aiScene *sc) { glhckAnimationVectorKey *vectorKeys; glhckAnimationQuaternionKey *quaternionKeys; unsigned int i, n, k, numAnimations, numNodes; glhckAnimation *animation; glhckAnimationNode *node; const struct aiNodeAnim *assimpNode; const struct aiAnimation *assimpAnimation; glhckAnimation *animations[sc->mNumAnimations]; for (i = 0, numAnimations = 0; i != sc->mNumAnimations; ++i) { assimpAnimation = sc->mAnimations[i]; /* allocate new animation */ if (!(animation = glhckAnimationNew())) continue; /* set animation properties */ glhckAnimationTicksPerSecond(animation, assimpAnimation->mTicksPerSecond); glhckAnimationDuration(animation, assimpAnimation->mDuration); glhckAnimationName(animation, assimpAnimation->mName.data); glhckAnimationNode *nodes[assimpAnimation->mNumChannels]; for (n = 0, numNodes = 0; n != assimpAnimation->mNumChannels; ++n) { assimpNode = assimpAnimation->mChannels[n]; /* allocate new animation node */ if (!(node = glhckAnimationNodeNew())) continue; /* set bone name for this node */ glhckAnimationNodeBoneName(node, assimpNode->mNodeName.data); /* translation keys */ vectorKeys = _glhckCalloc(assimpNode->mNumPositionKeys, sizeof(glhckAnimationVectorKey)); if (!vectorKeys) continue; for (k = 0; k != assimpNode->mNumPositionKeys; ++k) { vectorKeys[k].vector.x = assimpNode->mPositionKeys[k].mValue.x; vectorKeys[k].vector.y = assimpNode->mPositionKeys[k].mValue.y; vectorKeys[k].vector.z = assimpNode->mPositionKeys[k].mValue.z; vectorKeys[k].time = assimpNode->mPositionKeys[k].mTime; } glhckAnimationNodeInsertTranslations(node, vectorKeys, assimpNode->mNumPositionKeys); _glhckFree(vectorKeys); /* scaling keys */ vectorKeys = _glhckCalloc(assimpNode->mNumScalingKeys, sizeof(glhckAnimationVectorKey)); if (!vectorKeys) continue; for (k = 0; k != assimpNode->mNumScalingKeys; ++k) { vectorKeys[k].vector.x = assimpNode->mScalingKeys[k].mValue.x; vectorKeys[k].vector.y = assimpNode->mScalingKeys[k].mValue.y; vectorKeys[k].vector.z = assimpNode->mScalingKeys[k].mValue.z; vectorKeys[k].time = assimpNode->mScalingKeys[k].mTime; } glhckAnimationNodeInsertScalings(node, vectorKeys, assimpNode->mNumScalingKeys); _glhckFree(vectorKeys); /* rotation keys */ quaternionKeys = _glhckCalloc(assimpNode->mNumRotationKeys, sizeof(glhckAnimationQuaternionKey)); if (!quaternionKeys) continue; for (k = 0; k != assimpNode->mNumRotationKeys; ++k) { quaternionKeys[k].quaternion.x = assimpNode->mRotationKeys[k].mValue.x; quaternionKeys[k].quaternion.y = assimpNode->mRotationKeys[k].mValue.y; quaternionKeys[k].quaternion.z = assimpNode->mRotationKeys[k].mValue.z; quaternionKeys[k].quaternion.w = assimpNode->mRotationKeys[k].mValue.w; quaternionKeys[k].time = assimpNode->mRotationKeys[k].mTime; } glhckAnimationNodeInsertRotations(node, quaternionKeys, assimpNode->mNumRotationKeys); _glhckFree(quaternionKeys); /* increase imported nodes count */ nodes[numNodes++] = node; } /* set nodes to animation */ if (numNodes) { glhckAnimationInsertNodes(animation, nodes, numNodes); for (n = 0; n != numNodes; ++n) glhckAnimationNodeFree(nodes[n]); } /* increase imported animations count */ animations[numAnimations++] = animation; } /* insert animations to object */ if (numAnimations) { glhckObjectInsertAnimations(object, animations, numAnimations); #if 0 unsigned int numChildren; glhckObject **children; children = glhckObjectChildren(object, &numChildren); for (i = 0; i != numChildren; ++i) glhckObjectInsertAnimations(children[i], animations, numAnimations); #endif for (i = 0; i != numAnimations; ++i) glhckAnimationFree(animations[i]); } return RETURN_OK; }