/* \brief destroys the current glhck context */ GLHCKAPI void glhckContextTerminate(void) { if (!glhckInitialized()) return; TRACE(0); /* destroy queues */ _glhckFree(GLHCKRD()->objects.queue); _glhckFree(GLHCKRD()->textures.queue); /* destroy world */ glhckMassacreWorld(); /* terminate internal vertex/index types */ _glhckGeometryTerminate(); /* close display */ glhckDisplayClose(); /* terminate allocation tracking */ #ifndef NDEBUG puts("\nExit graph, this should be empty."); glhckMemoryGraph(); _glhckTrackTerminate(); #endif #if !GLHCK_DISABLE_TRACE /* terminate trace system */ _glhckTraceTerminate(); #endif /* finally remove the context */ free(_glhckContext); glhckContextSet(NULL); }
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 helper function for importers. * helps finding texture files. * maybe we could have a _default_ texture for missing files? */ char* _glhckImportTexturePath(const char* odd_texture_path, const char* model_path) { char *textureFile, *modelFolder, *modelPath; char textureInModelFolder[2048]; CALL(0, "%s, %s", odd_texture_path, model_path); /* these are must to check */ if (!odd_texture_path || !odd_texture_path[0]) goto fail; /* lets try first if it contains real path to the texture */ textureFile = (char*)odd_texture_path; /* guess not, lets try basename it */ if (access(textureFile, F_OK) != 0) textureFile = gnu_basename((char*)odd_texture_path); else { RET(0, "%s", textureFile); return _glhckStrdup(textureFile); } /* hrmm, we could not even basename it? * I think we have a invalid path here Watson! */ if (!textureFile) goto fail; /* Sherlock, you are a genius */ /* these are must to check */ if (!model_path || !model_path[0]) goto fail; /* copy original path */ if (!(modelPath = _glhckStrdup(model_path))) goto fail; /* grab the folder where model resides */ modelFolder = dirname(modelPath); /* ok, maybe the texture is in same folder as the model? */ snprintf(textureInModelFolder, sizeof(textureInModelFolder)-1, "%s/%s", modelFolder, textureFile); /* free this */ _glhckFree(modelPath); /* gah, don't give me missing textures damnit!! */ if (access(textureInModelFolder, F_OK) != 0) goto fail; /* return, remember to free */ RET(0, "%s", textureInModelFolder); return _glhckStrdup(textureInModelFolder); fail: RET(0, "%p", NULL); return NULL; }
static void _glhckTriStripReverse(glhckImportIndexData *indices, unsigned int memb) { unsigned int i; glhckImportIndexData *original; if (!(original = _glhckCopy(indices, memb * sizeof(glhckImportIndexData)))) return; for (i = 0; i != memb; ++i) indices[i] = original[memb-1-i]; _glhckFree(original); }
glhckTexture* textureFromMaterial(const char *file, const struct aiMaterial *mtl) { glhckTexture *texture; struct aiString textureName; enum aiTextureMapping textureMapping; enum aiTextureOp op; enum aiTextureMapMode textureMapMode[3] = {0,0,0}; unsigned int uvwIndex, flags; float blend; char *texturePath; glhckTextureParameters params; assert(file && mtl); if (!aiGetMaterialTextureCount(mtl, aiTextureType_DIFFUSE)) return NULL; if (aiGetMaterialTexture(mtl, aiTextureType_DIFFUSE, 0, &textureName, &textureMapping, &uvwIndex, &blend, &op, textureMapMode, &flags) != AI_SUCCESS) return NULL; memcpy(¶ms, glhckTextureDefaultParameters(), sizeof(glhckTextureParameters)); switch (textureMapMode[0]) { case aiTextureMapMode_Clamp: case aiTextureMapMode_Decal: params.wrapR = GLHCK_WRAP_CLAMP_TO_EDGE; params.wrapS = GLHCK_WRAP_CLAMP_TO_EDGE; params.wrapT = GLHCK_WRAP_CLAMP_TO_EDGE; break; case aiTextureMapMode_Mirror: params.wrapR = GLHCK_WRAP_MIRRORED_REPEAT; params.wrapS = GLHCK_WRAP_MIRRORED_REPEAT; params.wrapT = GLHCK_WRAP_MIRRORED_REPEAT; break; default: break; } if (!(texturePath = _glhckImportTexturePath(textureName.data, file))) return NULL; DEBUG(0, "%s", texturePath); texture = glhckTextureNewFromFile(texturePath, NULL, ¶ms); _glhckFree(texturePath); return texture; }
/* \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 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; }