示例#1
0
文件: assiqe.c 项目: r-lyeh/eve
void calc_bind_pose(void)
{
	// we now (in the single mesh / non-baking case) have our bind pose
	// our invpose is set to the inv_bind_pose matrix
	// compute forward abspose and pose matrices here
	int i;
	for (i = 0; i < numbones; i++) {
		if (bonelist[i].isskin) {
			// skinned and boned, invpose is our reference
			aiInverseMatrix(&bonelist[i].abspose, &bonelist[i].invpose);
			bonelist[i].pose = bonelist[i].abspose;
			if (bonelist[i].parent >= 0) {
				struct aiMatrix4x4 m = bonelist[bonelist[i].parent].invpose;
				aiMultiplyMatrix4(&m, &bonelist[i].pose);
				bonelist[i].pose = m;
			}
		} else {
			// not skinned, so no invpose. pose is our reference
			bonelist[i].pose = bonelist[i].node->mTransformation;
			bonelist[i].abspose = bonelist[i].pose;
			if (bonelist[i].parent >= 0) {
				bonelist[i].abspose = bonelist[bonelist[i].parent].abspose;
				aiMultiplyMatrix4(&bonelist[i].abspose, &bonelist[i].pose);
			}
			aiInverseMatrix(&bonelist[i].invpose, &bonelist[i].abspose);
		}
	}

	// compute translate/rotate/scale
	for (i = 0; i < numbones; i++)
		if (bonelist[i].isbone)
			aiDecomposeMatrix(&bonelist[i].pose, &bonelist[i].scale, &bonelist[i].rotate, &bonelist[i].translate);
}
示例#2
0
文件: assiqe.c 项目: r-lyeh/eve
void fix_pose(void)
{
	int i;

	calc_abs_pose();

	if (dohips) fix_hips(0);

	for (i = 0; i < numbones; i++) {
		if (bonelist[i].isbone) {
			// remove scaling factor in absolute pose
			if (dounscale < 0) {
				struct aiVector3D apos, ascale;
				struct aiQuaternion arot;
				aiDecomposeMatrix(&bonelist[i].abspose, &ascale, &arot, &apos);
				bonelist[i].unscale[0] = ascale.x;
				bonelist[i].unscale[1] = ascale.y;
				bonelist[i].unscale[2] = ascale.z;
				if (KILL(ascale.x) != 1 || KILL(ascale.y) != 1 || KILL(ascale.z) != 1)
					fprintf(stderr, "unscaling %s: %g %g %g\n", bonelist[i].name, ascale.x, ascale.y, ascale.z);
			}
			if (dounscale) {
				float x = bonelist[i].unscale[0];
				float y = bonelist[i].unscale[1];
				float z = bonelist[i].unscale[2];
				if (KILL(x) != 1 || KILL(y) != 1 || KILL(z) != 1) {
					bonelist[i].abspose.a1 /= x; bonelist[i].abspose.b1 /= x; bonelist[i].abspose.c1 /= x;
					bonelist[i].abspose.a2 /= y; bonelist[i].abspose.b2 /= y; bonelist[i].abspose.c2 /= y;
					bonelist[i].abspose.a3 /= z; bonelist[i].abspose.b3 /= z; bonelist[i].abspose.c3 /= z;
				}
			}

			// flip axis in absolute pose
			if (doaxis)
				aiMultiplyMatrix4(&bonelist[i].abspose, &axis_x_to_y);

			// ...and invert so we can recalculate the local poses
			aiInverseMatrix(&bonelist[i].invpose, &bonelist[i].abspose);

			// ...and recalculate the local pose
			bonelist[i].pose = bonelist[i].abspose;
			if (bonelist[i].parent >= 0) {
				struct aiMatrix4x4 m = bonelist[bonelist[i].parent].invpose;
				aiMultiplyMatrix4(&m, &bonelist[i].pose);
				bonelist[i].pose = m;
			}

			// ...and make sure we have it in decomposed form
			aiDecomposeMatrix(&bonelist[i].pose, &bonelist[i].scale, &bonelist[i].rotate, &bonelist[i].translate);
		}
	}

	if (dohips) unfix_hips();
}
示例#3
0
void get_bounding_box_for_node (const struct aiScene *sc,
                                const struct aiNode* nd,
                                struct aiVector3D* min,
                                struct aiVector3D* max,
                                struct aiMatrix4x4* trafo)
{
	struct aiMatrix4x4 prev;
	unsigned int n = 0, t;
    
	prev = *trafo;
	aiMultiplyMatrix4(trafo,&nd->mTransformation);
    
	for (; n < nd->mNumMeshes; ++n) {
		const struct aiMesh* mesh = sc->mMeshes[nd->mMeshes[n]];
		for (t = 0; t < mesh->mNumVertices; ++t) {
            
			struct aiVector3D tmp = mesh->mVertices[t];
			aiTransformVecByMatrix4(&tmp,trafo);
            
			min->x = aisgl_min(min->x,tmp.x);
			min->y = aisgl_min(min->y,tmp.y);
			min->z = aisgl_min(min->z,tmp.z);
            
			max->x = aisgl_max(max->x,tmp.x);
			max->y = aisgl_max(max->y,tmp.y);
			max->z = aisgl_max(max->z,tmp.z);
		}
	}
    
	for (n = 0; n < nd->mNumChildren; ++n) {
		get_bounding_box_for_node(sc, nd->mChildren[n],min,max,trafo);
	}
	*trafo = prev;
}
/*!
*  \brief      Go through the scene nodes and load and transform all meshes them.
*  \author     Sascha Kaden
*  \param[in]  scene
*  \param[in]  node
*  \param[in]  transformation
*  \param[out] vector of meshes
*  \date       2017-05-09
*/
void getMeshes(const aiScene *scene, const aiNode *node, aiMatrix4x4 *trafo, std::vector<Mesh> &meshes, const bool useTrafo) {
    aiMatrix4x4 prevTrafo;

    prevTrafo = *trafo;
    aiMultiplyMatrix4(trafo, &node->mTransformation);

    for (size_t i = 0; i < node->mNumMeshes; ++i) {
        Mesh mesh;
        const aiMesh *aimesh = scene->mMeshes[node->mMeshes[i]];
        for (size_t j = 0; j < aimesh->mNumVertices; ++j) {
            aiVector3D vertex = aimesh->mVertices[j];
            if (useTrafo)
                aiTransformVecByMatrix4(&vertex, trafo);
            mesh.vertices.emplace_back(vertex.x, vertex.y, vertex.z);
        }
        for (size_t j = 0; j < aimesh->mNumFaces; ++j) {
            if (aimesh->mFaces[j].mNumIndices > 2) {
                mesh.faces.emplace_back(aimesh->mFaces[j].mIndices[0], aimesh->mFaces[j].mIndices[1], aimesh->mFaces[j].mIndices[2]);
            } else {
                Logging::warning("Face array is to short", "CadProcessing");
            }
        }
        meshes.push_back(mesh);
    }

    for (size_t i = 0; i < node->mNumChildren; ++i) {
        getMeshes(scene, node->mChildren[i], trafo, meshes);
    }
    *trafo = prevTrafo;
}
//-------------------------------------------
void ofxAssimpModelLoader::getBoundingBoxForNode(const struct aiNode* nd,  struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo)
{
	struct aiMatrix4x4 prev;
	unsigned int n = 0, t;

	prev = *trafo;
	aiMultiplyMatrix4(trafo,&nd->mTransformation);

	for (; n < nd->mNumMeshes; ++n){
		const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
		for (t = 0; t < mesh->mNumVertices; ++t){
        	struct aiVector3D tmp = mesh->mVertices[t];
			aiTransformVecByMatrix4(&tmp,trafo);


			min->x = MIN(min->x,tmp.x);
			min->y = MIN(min->y,tmp.y);
			min->z = MIN(min->z,tmp.z);

			max->x = MAX(max->x,tmp.x);
			max->y = MAX(max->y,tmp.y);
			max->z = MAX(max->z,tmp.z);
		}
	}

	for (n = 0; n < nd->mNumChildren; ++n){
		this->getBoundingBoxForNode(nd->mChildren[n], min, max, trafo);
	}

	*trafo = prev;
}
示例#6
0
void AssimpScene::recursive_getBoundingBox(
	const aiScene *scene, const aiNode* nd,
	aiVector3D & sceneMin, aiVector3D & sceneMax, aiMatrix4x4* sceneMatrix)
{
	aiMatrix4x4 sceneMatrixOriginal = *sceneMatrix;
	aiMultiplyMatrix4(sceneMatrix, & nd->mTransformation);
	for (int n=0; n < nd->mNumMeshes; n++) {
		aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
		for (int t = 0; t < mesh->mNumVertices; t++) {
			aiVector3D vert = mesh->mVertices[t];
			aiTransformVecByMatrix4(&vert, sceneMatrix);
			sceneMin.x = std::min(sceneMin.x, vert.x);
			sceneMin.y = std::min(sceneMin.y, vert.y);
			sceneMin.z = std::min(sceneMin.z, vert.z);

			sceneMax.x = std::max(sceneMax.x, vert.x);
			sceneMax.y = std::max(sceneMax.y, vert.y);
			sceneMax.z = std::max(sceneMax.z, vert.z);

		}
	}
	//std::cout << "AssimpScene SceneMin " << sceneMin.x << " , " << sceneMin.y << " , " << sceneMin.z << std::endl;
	//std::cout << "AssimpScene SceneMax " << sceneMax.x << " , " << sceneMax.y << " , " << sceneMax.z << std::endl;
	for (int n = 0; n < nd->mNumChildren; n++) {
		recursive_getBoundingBox(scene,nd->mChildren[n], sceneMin, sceneMax,sceneMatrix);
	}
	*sceneMatrix = sceneMatrixOriginal;
}
void AssimpSimpleModelLoader::get_bounding_box_for_node (const aiNode* nd, 
	aiVector3D* min, 
	aiVector3D* max, 
	aiMatrix4x4* trafo
){
	aiMatrix4x4 prev;
	unsigned int n = 0, t;

	prev = *trafo;
	aiMultiplyMatrix4(trafo,&nd->mTransformation);

	for (; n < nd->mNumMeshes; ++n) {
		const aiMesh* mesh = this->scene->mMeshes[nd->mMeshes[n]];
		for (t = 0; t < mesh->mNumVertices; ++t) {

			aiVector3D tmp = mesh->mVertices[t];
			aiTransformVecByMatrix4(&tmp,trafo);

			min->x = aisgl_min(min->x,tmp.x);
			min->y = aisgl_min(min->y,tmp.y);
			min->z = aisgl_min(min->z,tmp.z);

			max->x = aisgl_max(max->x,tmp.x);
			max->y = aisgl_max(max->y,tmp.y);
			max->z = aisgl_max(max->z,tmp.z);
		}
	}

	for (n = 0; n < nd->mNumChildren; ++n) {
		get_bounding_box_for_node(nd->mChildren[n],min,max,trafo);
	}
	*trafo = prev;
}
示例#8
0
void Model3D::get_bounding_box_for_node(const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo) {
    struct aiMatrix4x4 prev; // Use struct keyword to show you want struct version of this, not normal typedef?
    unsigned int n = 0, t;

    prev = *trafo;
    aiMultiplyMatrix4(trafo, &nd->mTransformation);

    for (; n < nd->mNumMeshes; ++n) {
        const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
        for (t = 0; t < mesh->mNumVertices; ++t) {
            struct aiVector3D tmp = mesh->mVertices[t];
            aiTransformVecByMatrix4(&tmp, trafo);

            min->x = aisgl_min(min->x,tmp.x);
            min->y = aisgl_min(min->y,tmp.y);
            min->z = aisgl_min(min->z,tmp.z);

            max->x = aisgl_max(max->x,tmp.x);
            max->y = aisgl_max(max->y,tmp.y);
            max->z = aisgl_max(max->z,tmp.z);
        }
    }

    for (n = 0; n < nd->mNumChildren; ++n)
        get_bounding_box_for_node(nd->mChildren[n], min, max, trafo);

    *trafo = prev;
}
示例#9
0
文件: assiqe.c 项目: r-lyeh/eve
// recalculate abspose from local pose matrix
void calc_abs_pose(void)
{
	int i;
	for (i = 0; i < numbones; i++) {
		bonelist[i].abspose = bonelist[i].pose;
		if (bonelist[i].parent >= 0) {
			bonelist[i].abspose = bonelist[bonelist[i].parent].abspose;
			aiMultiplyMatrix4(&bonelist[i].abspose, &bonelist[i].pose);
		}
	}
}
示例#10
0
文件: assiqe.c 项目: r-lyeh/eve
void bake_mesh_skin(const struct aiMesh *mesh)
{
	int i, k, b;
	struct aiMatrix3x3 mat3;
	struct aiMatrix4x4 bonemat[1000], mat;
	struct aiVector3D *outpos, *outnorm;

	if (mesh->mNumBones == 0)
		return;

	outpos = malloc(mesh->mNumVertices * sizeof *outpos);
	outnorm = malloc(mesh->mNumVertices * sizeof *outnorm);
	memset(outpos, 0, mesh->mNumVertices * sizeof *outpos);
	memset(outnorm, 0, mesh->mNumVertices * sizeof *outpos);

	calc_abs_pose();

	for (i = 0; i < mesh->mNumBones; i++) {
		b = find_bone(mesh->mBones[i]->mName.data);
		bonemat[i] = bonelist[b].abspose;
		aiMultiplyMatrix4(&bonemat[i], &mesh->mBones[i]->mOffsetMatrix);
	}

	for (k = 0; k < mesh->mNumBones; k++) {
		struct aiBone *bone = mesh->mBones[k];
		b = find_bone(mesh->mBones[k]->mName.data);
		mat = bonemat[k];
		mat3.a1 = mat.a1; mat3.a2 = mat.a2; mat3.a3 = mat.a3;
		mat3.b1 = mat.b1; mat3.b2 = mat.b2; mat3.b3 = mat.b3;
		mat3.c1 = mat.c1; mat3.c2 = mat.c2; mat3.c3 = mat.c3;
		for (i = 0; i < bone->mNumWeights; i++) {
			struct aiVertexWeight vw = bone->mWeights[i];
			int v = vw.mVertexId;
			float w = vw.mWeight;
			struct aiVector3D srcpos = mesh->mVertices[v];
			struct aiVector3D srcnorm = mesh->mNormals[v];
			aiTransformVecByMatrix4(&srcpos, &mat);
			aiTransformVecByMatrix3(&srcnorm, &mat3);
			outpos[v].x += srcpos.x * w;
			outpos[v].y += srcpos.y * w;
			outpos[v].z += srcpos.z * w;
			outnorm[v].x += srcnorm.x * w;
			outnorm[v].y += srcnorm.y * w;
			outnorm[v].z += srcnorm.z * w;
		}
	}

	memcpy(mesh->mVertices, outpos, mesh->mNumVertices * sizeof *outpos);
	memcpy(mesh->mNormals, outnorm, mesh->mNumVertices * sizeof *outnorm);

	free(outpos);
	free(outnorm);
}
示例#11
0
文件: assiqe.c 项目: r-lyeh/eve
void aiComposeMatrix(struct aiMatrix4x4 *m, struct aiVector3D *scale, struct aiQuaternion *q, struct aiVector3D *pos)
{
	struct aiMatrix4x4 smat;

	aiIdentityMatrix4(m);
	m->a1 = 1.0f - 2.0f * (q->y * q->y + q->z * q->z);
	m->a2 = 2.0f * (q->x * q->y - q->z * q->w);
	m->a3 = 2.0f * (q->x * q->z + q->y * q->w);
	m->b1 = 2.0f * (q->x * q->y + q->z * q->w);
	m->b2 = 1.0f - 2.0f * (q->x * q->x + q->z * q->z);
	m->b3 = 2.0f * (q->y * q->z - q->x * q->w);
	m->c1 = 2.0f * (q->x * q->z - q->y * q->w);
	m->c2 = 2.0f * (q->y * q->z + q->x * q->w);
	m->c3 = 1.0f - 2.0f * (q->x * q->x + q->y * q->y);

	aiIdentityMatrix4(&smat);
	smat.a1 = scale->x;
	smat.b2 = scale->y;
	smat.c3 = scale->z;

	aiMultiplyMatrix4(m, &smat);

	m->a4 = pos->x; m->b4 = pos->y; m->c4 = pos->z;
}
示例#12
0
文件: assiqe.c 项目: r-lyeh/eve
void export_node(FILE *out, const struct aiScene *scene, const struct aiNode *node,
	struct aiMatrix4x4 mat, char *clean_name)
{
	struct aiMatrix3x3 mat3;
	int i, a, k, t;

	aiMultiplyMatrix4(&mat, &node->mTransformation);
	mat3.a1 = mat.a1; mat3.a2 = mat.a2; mat3.a3 = mat.a3;
	mat3.b1 = mat.b1; mat3.b2 = mat.b2; mat3.b3 = mat.b3;
	mat3.c1 = mat.c1; mat3.c2 = mat.c2; mat3.c3 = mat.c3;

	if (!strstr(node->mName.data, "$ColladaAutoName$"))
		clean_name = clean_node_name((char*)node->mName.data);

	if (only_one_node && strcmp(clean_name, only_one_node))
		goto skip_mesh;

	for (i = 0; i < node->mNumMeshes; i++) {
		struct aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
		struct aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];

		if (mesh->mNumBones == 0 && dobone && !dorigid) {
			if (verbose)
				fprintf(stderr, "skipping rigid mesh %d in node %s (no bones)\n", i, clean_name);
			continue;
		}

		fprintf(stderr, "exporting mesh %s[%d]: %d vertices, %d faces\n",
				clean_name, i, mesh->mNumVertices, mesh->mNumFaces);

		fprintf(out, "\n");
		fprintf(out, "mesh \"%s\"\n", clean_name);
		fprintf(out, "material \"%s\"\n", find_material(material));

		struct vb *vb = (struct vb*) malloc(mesh->mNumVertices * sizeof(*vb));
		memset(vb, 0, mesh->mNumVertices * sizeof(*vb));

		// A rigidly animated node -- insert fake blend index/weights
		if (mesh->mNumBones == 0 && dobone) {
			a = find_bone((char*)node->mName.data);
			if (verbose)
				fprintf(stderr, "\trigid bone %d for mesh in node %s (no bones)\n", bonelist[a].number, node->mName.data);
			for (k = 0; k < mesh->mNumVertices; k++) {
				vb[k].b[0] = bonelist[a].number;
				vb[k].w[0] = 1;
				vb[k].n = 1;
			}
		}

		// Assemble blend index/weight array
		for (k = 0; k < mesh->mNumBones; k++) {
			struct aiBone *bone = mesh->mBones[k];
			a = find_bone(bone->mName.data);
			for (t = 0; t < bone->mNumWeights; t++) {
				struct aiVertexWeight *w = mesh->mBones[k]->mWeights + t;
				int idx = w->mVertexId;
				if (vb[idx].n < MAXBLEND) {
					vb[idx].b[vb[idx].n] = bonelist[a].number;
					vb[idx].w[vb[idx].n] = w->mWeight;
					vb[idx].n++;
				}
			}
		}

		for (k = 0; k < mesh->mNumVertices; k++) {
			struct aiVector3D vp = mesh->mVertices[k];
			if (!dobone)
				aiTransformVecByMatrix4(&vp, &mat);
			fprintf(out, "vp %.9g %.9g %.9g\n", vp.x, vp.y, vp.z);
			if (mesh->mNormals) {
				struct aiVector3D vn = mesh->mNormals[k];
				if (!dobone)
					aiTransformVecByMatrix3(&vn, &mat3);
				fprintf(out, "vn %.9g %.9g %.9g\n", vn.x, vn.y, vn.z);
			}

			if (mesh->mTextureCoords[0]) {
				float u = mesh->mTextureCoords[0][k].x;
				float v = 1 - mesh->mTextureCoords[0][k].y;
				fprintf(out, "vt %.9g %.9g\n", u, v);
			}
			for (t = 1; t <= MAX_UVMAP; t++) {
				if (mesh->mTextureCoords[t]) {
					float u = mesh->mTextureCoords[t][k].x;
					float v = 1 - mesh->mTextureCoords[t][k].y;
					fprintf(out, "v%d %.9g %.9g\n", FIRST_UVMAP+t-1, u, v);
				}
			}

			if (mesh->mColors[0]) {
				float r = mesh->mColors[0][k].r; r = floorf(r * 255) / 255;
				float g = mesh->mColors[0][k].g; g = floorf(g * 255) / 255;
				float b = mesh->mColors[0][k].b; b = floorf(b * 255) / 255;
				float a = mesh->mColors[0][k].a; a = floorf(a * 255) / 255;
				fprintf(out, "vc %.9g %.9g %.9g %.9g\n", r, g, b, a);
			}
			for (t = 1; t <= MAX_COL; t++) {
				if (mesh->mColors[t]) {
					float r = mesh->mColors[t][k].r; r = floorf(r * 255) / 255;
					float g = mesh->mColors[t][k].g; g = floorf(g * 255) / 255;
					float b = mesh->mColors[t][k].b; b = floorf(b * 255) / 255;
					float a = mesh->mColors[t][k].a; a = floorf(a * 255) / 255;
					fprintf(out, "v%d %.9g %.9g %.9g %.9g\n", FIRST_COL+t-1, r, g, b, a);
				}
			}

			if (dobone) {
				fprintf(out, "vb");
				for (t = 0; t < vb[k].n; t++) {
					fprintf(out, " %d %.9g", vb[k].b[t], vb[k].w[t]);
				}
				fprintf(out, "\n");
			}
		}

		for (k = 0; k < mesh->mNumFaces; k++) {
			struct aiFace *face = mesh->mFaces + k;
			if (face->mNumIndices == 3) {
				if (doflip)
					fprintf(out, "fm %d %d %d\n", face->mIndices[2], face->mIndices[1], face->mIndices[0]);
				else
					fprintf(out, "fm %d %d %d\n", face->mIndices[0], face->mIndices[1], face->mIndices[2]);
			} else if (face->mNumIndices == 4) {
				if (doflip)
					fprintf(out, "fm %d %d %d %d\n", face->mIndices[3], face->mIndices[2], face->mIndices[1], face->mIndices[0]);
				else
					fprintf(out, "fm %d %d %d %d\n", face->mIndices[0], face->mIndices[1], face->mIndices[2], face->mIndices[3]);
			} else if (face->mNumIndices > 4) {
				fprintf(stderr, "n-gon (%d) in mesh!\n", face->mNumIndices);
				int i1 = face->mIndices[0];
				int i2 = face->mIndices[1];
				for (a = 2; a < face->mNumIndices; a++) {
					int i3 = face->mIndices[a];
					if (doflip)
						fprintf(out, "fm %d %d %d\n", i3, i2, i1);
					else
						fprintf(out, "fm %d %d %d\n", i1, i2, i3);
					i2 = i3;
				}
			} else {
				fprintf(stderr, "skipping point/line primitive\n");
			}
		}

		free(vb);
	}

skip_mesh:

	for (i = 0; i < node->mNumChildren; i++)
		export_node(out, scene, node->mChildren[i], mat, clean_name);
}
示例#13
0
文件: assiqe.c 项目: r-lyeh/eve
int main(int argc, char **argv)
{
	FILE *file;
	const struct aiScene *scene;
	char *p;
	int c;

	char *output = NULL;
	char *input = NULL;
	int onlyanim = 0;
	int onlymesh = 0;

	while ((c = getopt(argc, argv, "AHMPSabflmn:o:rvxsu:")) != -1) {
		switch (c) {
		case 'A': save_all_bones++; break;
		case 'H': dohips = 1; break;
		case 'M': list_all_meshes = 1; break;
		case 'P': list_all_positions = 1; break;
		case 'S': dostatic = 1; break;
		case 'a': onlyanim = 1; break;
		case 'm': onlymesh = 1; break;
		case 'n': only_one_node = optarg++; break;
		case 'b': need_to_bake_skin = 1; break;
		case 'o': output = optarg++; break;
		case 'f': doflip = 0; break;
		case 'r': dorigid = 1; break;
		case 'l': dolowprec = 1; break;
		case 'v': verbose++; break;
		case 'x': doaxis = 1; break;
		case 's': dounscale = 1; break;
		case 'u': untaglist[numuntags++] = optarg++; break;
		default: usage(); break;
		}
	}

	if (optind == argc)
		usage();

	input = argv[optind++];

	p = strrchr(input, '/');
	if (!p) p = strrchr(input, '\\');
	if (!p) p = input; else p++;
	strcpy(basename, p);
	p = strrchr(basename, '.');
	if (p) *p = 0;

	numtags = argc - optind;
	taglist = argv + optind;

	/* Read input file and post process */

	int flags = 0;
	flags |= aiProcess_JoinIdenticalVertices;
	flags |= aiProcess_GenSmoothNormals;
	flags |= aiProcess_GenUVCoords;
	flags |= aiProcess_TransformUVCoords;
	flags |= aiProcess_LimitBoneWeights;
	//flags |= aiProcess_FindInvalidData;
	flags |= aiProcess_ImproveCacheLocality;
	//flags |= aiProcess_RemoveRedundantMaterials;
	//flags |= aiProcess_OptimizeMeshes;

	fprintf(stderr, "loading %s\n", input);
	scene = aiImportFile(input, flags);
	if (!scene) {
		fprintf(stderr, "cannot import '%s': %s\n", input, aiGetErrorString());
		exit(1);
	}

	if (scene->mNumAnimations > 0) doanim = 1;
	if (onlymesh) { domesh = 1; doanim = 0; }
	if (onlyanim) { domesh = 0; doanim = 1; }

	if (getenv("DOANIM")) doanim = 1;

	// Convert to Z-UP coordinate system
	aiMultiplyMatrix4(&scene->mRootNode->mTransformation, &yup_to_zup);

	// Build a list of bones and compute the bind pose matrices.
	if (build_bone_list(scene) > 0)
		dobone = 1;

	if (dostatic) {
		dobone = 0;
		need_to_bake_skin = 0;
	}

	if (list_all_meshes) {
		export_mesh_list(scene);
		return 0;
	}

	if (list_all_positions) {
		export_position_list(scene);
		return 0;
	}

	// Mesh is split with incompatible bind matrices, so pick a new
	// bind pose and deform the mesh to fit.
	if (need_to_bake_skin && !onlyanim) {
		apply_initial_frame(); // ditch original bind pose
		bake_scene_skin(scene);
	}

	/*
	 * Export scene as mesh/skeleton/animation
	 */

	if (output) {
		fprintf(stderr, "saving %s\n", output);
		file = fopen(output, "w");
		if (!file) {
			fprintf(stderr, "cannot open output file: '%s'\n", output);
			exit(1);
		}
	} else {
		file = stdout;
	}

	fprintf(file, "# Inter-Quake Export\n");

	if (dobone) {
		export_bone_list(file);
	}

	if (domesh) {
		struct aiMatrix4x4 identity;
		aiIdentityMatrix4(&identity);
		export_custom_vertexarrays(file, scene);
		export_node(file, scene, scene->mRootNode, identity, "SCENE");
	}

	if (dobone) {
		if (doanim) {
			export_animations(file, scene);
		}
	}

	if (output)
		fclose(file);

	aiReleaseImport(scene);

	return 0;
}