Exemple #1
0
static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
{
	DerivedMesh *result = CDDM_from_template(mesh->dm,
			mesh->num_verts,
			mesh->num_edges,
			mesh->num_faces);
	MVert *new_verts = CDDM_get_verts(result);
	MEdge *new_edges = CDDM_get_edges(result);
	MFace *new_faces = CDDM_get_faces(result);
	int i;

	for(i = 0; i < mesh->num_verts; ++i) {
		SmoothVert *vert = &mesh->verts[i];
		MVert *newMV = &new_verts[vert->newIndex];

		DM_copy_vert_data(mesh->dm, result,
				vert->oldIndex, vert->newIndex, 1);
		mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV);
	}

	for(i = 0; i < mesh->num_edges; ++i) {
		SmoothEdge *edge = &mesh->edges[i];
		MEdge *newME = &new_edges[edge->newIndex];

		DM_copy_edge_data(mesh->dm, result,
				edge->oldIndex, edge->newIndex, 1);
		mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME);
		newME->v1 = edge->verts[0]->newIndex;
		newME->v2 = edge->verts[1]->newIndex;
	}

	for(i = 0; i < mesh->num_faces; ++i) {
		SmoothFace *face = &mesh->faces[i];
		MFace *newMF = &new_faces[face->newIndex];

		DM_copy_face_data(mesh->dm, result,
				face->oldIndex, face->newIndex, 1);
		mesh->dm->getFace(mesh->dm, face->oldIndex, newMF);

		newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex;
		newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex;
		newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex;

		if(face->edges[3]) {
			newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex;
		} else {
			newMF->v4 = 0;
		}
	}

	return result;
}
Exemple #2
0
static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
{
	unsigned int numverts = dm->getNumVerts ( dm );
	unsigned int numfaces = dm->getNumFaces ( dm );
	MFace *mface = CDDM_get_faces(dm);
	unsigned int i = 0;

	/* Allocate our vertices. */
	clmd->clothObject->numverts = numverts;
	clmd->clothObject->verts = MEM_callocN ( sizeof ( ClothVertex ) * clmd->clothObject->numverts, "clothVertex" );
	if ( clmd->clothObject->verts == NULL )
	{
		cloth_free_modifier ( ob, clmd );
		modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->verts." );
		printf("cloth_free_modifier clmd->clothObject->verts\n");
		return;
	}

	// save face information
	clmd->clothObject->numfaces = numfaces;
	clmd->clothObject->mfaces = MEM_callocN ( sizeof ( MFace ) * clmd->clothObject->numfaces, "clothMFaces" );
	if ( clmd->clothObject->mfaces == NULL )
	{
		cloth_free_modifier ( ob, clmd );
		modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->mfaces." );
		printf("cloth_free_modifier clmd->clothObject->mfaces\n");
		return;
	}
	for ( i = 0; i < numfaces; i++ )
		memcpy ( &clmd->clothObject->mfaces[i], &mface[i], sizeof ( MFace ) );

	/* Free the springs since they can't be correct if the vertices
	* changed.
	*/
	if ( clmd->clothObject->springs != NULL )
		MEM_freeN ( clmd->clothObject->springs );

}
Exemple #3
0
/* read .bobj.gz file into a fluidsimDerivedMesh struct */
static DerivedMesh *fluidsim_read_obj(const char *filename)
{
	int wri = 0,i;
	int gotBytes;
	gzFile gzf;
	int numverts = 0, numfaces = 0;
	DerivedMesh *dm = NULL;
	MFace *mf;
	MVert *mv;
	short *normals, *no_s;
	float no[3];

	// ------------------------------------------------
	// get numverts + numfaces first
	// ------------------------------------------------
	gzf = gzopen(filename, "rb");
	if (!gzf)
	{
		return NULL;
	}

	// read numverts
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	numverts = wri;

	// skip verts
	gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;


	// read number of normals
	if(gotBytes)
		gotBytes = gzread(gzf, &wri, sizeof(wri));

	// skip normals
	gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;

	/* get no. of triangles */
	if(gotBytes)
		gotBytes = gzread(gzf, &wri, sizeof(wri));
	numfaces = wri;

	gzclose( gzf );
	// ------------------------------------------------

	if(!numfaces || !numverts || !gotBytes)
		return NULL;

	gzf = gzopen(filename, "rb");
	if (!gzf)
	{
		return NULL;
	}

	dm = CDDM_new(numverts, 0, numfaces);

	if(!dm)
	{
		gzclose( gzf );
		return NULL;
	}

	// read numverts
	gotBytes = gzread(gzf, &wri, sizeof(wri));

	// read vertex position from file
	mv = CDDM_get_verts(dm);

	for(i=0; i<numverts; i++, mv++)
		gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);

	// should be the same as numverts
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	if(wri != numverts)
	{
		if(dm)
			dm->release(dm);
		gzclose( gzf );
		return NULL;
	}

	normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
	if(!normals)
	{
		if(dm)
			dm->release(dm);
		gzclose( gzf );
		return NULL;
	}

	// read normals from file (but don't save them yet)
	for(i=numverts, no_s= normals; i>0; i--, no_s += 3)
	{
		gotBytes = gzread(gzf, no, sizeof(float) * 3);
		normal_float_to_short_v3(no_s, no);
	}

	/* read no. of triangles */
	gotBytes = gzread(gzf, &wri, sizeof(wri));

	if(wri!=numfaces) {
		printf("Fluidsim: error in reading data from file.\n");
		if(dm)
			dm->release(dm);
		gzclose( gzf );
		MEM_freeN(normals);
		return NULL;
	}

	// read triangles from file
	mf = CDDM_get_faces(dm);
	for(i=numfaces; i>0; i--, mf++)
	{
		int face[3];

		gotBytes = gzread(gzf, face, sizeof(int) * 3);

		// check if 3rd vertex has index 0 (not allowed in blender)
		if(face[2])
		{
			mf->v1 = face[0];
			mf->v2 = face[1];
			mf->v3 = face[2];
		}
		else
		{
			mf->v1 = face[1];
			mf->v2 = face[2];
			mf->v3 = face[0];
		}
		mf->v4 = 0;

		test_index_face(mf, NULL, 0, 3);
	}

	gzclose( gzf );

	CDDM_calc_edges(dm);

	CDDM_apply_vert_normals(dm, (short (*)[3])normals);
	MEM_freeN(normals);

	// CDDM_calc_normals(result);

	return dm;
}
Exemple #4
0
DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
{
	MFace *mface, *mf;
	MEdge *medge, *me;
	MVert *mvert, *mv;
	int *origindex;
	int totface,totedge,totvert,i,bmeshok,len, numTex, numCol;

	BME_Vert *v1=NULL;
	BME_Edge *e=NULL, *oe=NULL;
	BME_Poly *f=NULL;
	
	DerivedMesh *result;
	EdgeHash *edge_hash = BLI_edgehash_new();

	totvert = BLI_countlist(&(bm->verts));
	totedge = 0;
	
	/*we cannot have double edges in a derived mesh!*/
	for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i;
	for(e=bm->edges.first; e; e=e->next){
		oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1);
		if(!oe){
			totedge++;
			BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e);
			e->tflag2 = 1;
		}
		else{
			e->tflag2 = 0;
		}
	}
	
	/*count quads and tris*/
	totface = 0;
	bmeshok = 1;
	for(f=bm->polys.first;f;f=f->next){
		len = BME_cycle_length(f->loopbase);
		if(len == 3 || len == 4) totface++;
	}
	
	/*convert back to mesh*/
	result = CDDM_from_template(dm,totvert,totedge,totface);
	CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
	CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
	CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
	CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
	numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
	numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);


	/*Make Verts*/
	mvert = CDDM_get_verts(result);
	origindex = result->getVertDataArray(result, CD_ORIGINDEX);
	for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){
		VECCOPY(mv->co,v1->co);
		mv->flag = (unsigned char)v1->flag;
		mv->bweight = (char)(255.0*v1->bweight);
		CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i);
		origindex[i] = ORIGINDEX_NONE;
	}
	medge = CDDM_get_edges(result);
	origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
	i=0;
	for(e=bm->edges.first,me=medge;e;e=e->next){
		if(e->tflag2){
			if(e->v1->tflag1 < e->v2->tflag1){
				me->v1 = e->v1->tflag1;
				me->v2 = e->v2->tflag1;
			}
			else{
				me->v1 = e->v2->tflag1;
				me->v2 = e->v1->tflag1;
			}
		
			me->crease = (char)(255.0*e->crease);
			me->bweight = (char)(255.0*e->bweight);
			me->flag = e->flag;
			CustomData_from_bmesh_block(&bm->edata, &result->edgeData, &e->data, i);
			origindex[i] = ORIGINDEX_NONE;
			me++;
			i++;
		}
	}
	if(totface){
		mface = CDDM_get_faces(result);
		origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
		/*make faces*/
		for(i=0,f=bm->polys.first;f;f=f->next){
			mf = &mface[i];
			len = BME_cycle_length(f->loopbase);
			if(len==3 || len==4){
				mf->v1 = f->loopbase->v->tflag1;
				mf->v2 = f->loopbase->next->v->tflag1;
				mf->v3 = f->loopbase->next->next->v->tflag1;
				if(len == 4){
					mf->v4 = f->loopbase->prev->v->tflag1;
				}
				/* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
				if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){
					test_index_face(mf, NULL, i, len);
				}
				mf->mat_nr = (unsigned char)f->mat_nr;
				mf->flag = (unsigned char)f->flag;
				CustomData_from_bmesh_block(&bm->pdata, &result->faceData, &f->data, i);
				BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex);
				origindex[i] = ORIGINDEX_NONE;
				i++;
			}
		}
	}
	BLI_edgehash_free(edge_hash, NULL);
	return result;
}
Exemple #5
0
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
{
	Cloth *cloth = clmd->clothObject;
	ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
	unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
	int i = 0;
	int numverts = dm->getNumVerts ( dm );
	int numedges = dm->getNumEdges ( dm );
	int numfaces = dm->getNumFaces ( dm );
	MEdge *medge = CDDM_get_edges ( dm );
	MFace *mface = CDDM_get_faces ( dm );
	int index2 = 0; // our second vertex index
	LinkNode **edgelist = NULL;
	EdgeHash *edgehash = NULL;
	LinkNode *search = NULL, *search2 = NULL;
	float temp[3];
	
	// error handling
	if ( numedges==0 )
		return 0;

	cloth->springs = NULL;

	edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" );
	
	if(!edgelist)
		return 0;
	
	for ( i = 0; i < numverts; i++ )
	{
		edgelist[i] = NULL;
	}

	if ( cloth->springs )
		MEM_freeN ( cloth->springs );

	// create spring network hash
	edgehash = BLI_edgehash_new();

	// structural springs
	for ( i = 0; i < numedges; i++ )
	{
		spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );

		if ( spring )
		{
			spring->ij = MIN2(medge[i].v1, medge[i].v2);
			spring->kl = MAX2(medge[i].v2, medge[i].v1);
			VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
			spring->restlen =  sqrt ( INPR ( temp, temp ) );
			clmd->sim_parms->avg_spring_len += spring->restlen;
			cloth->verts[spring->ij].avg_spring_len += spring->restlen;
			cloth->verts[spring->kl].avg_spring_len += spring->restlen;
			cloth->verts[spring->ij].spring_count++;
			cloth->verts[spring->kl].spring_count++;
			spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
			spring->flags = 0;
			spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0;
			struct_springs++;
			
			BLI_linklist_prepend ( &cloth->springs, spring );
		}
		else
		{
			cloth_free_errorsprings(cloth, edgehash, edgelist);
			return 0;
		}
	}
	
	if(struct_springs > 0)
		clmd->sim_parms->avg_spring_len /= struct_springs;
	
	for(i = 0; i < numverts; i++)
	{
		cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49 / ((float)cloth->verts[i].spring_count);
	}
	
	// shear springs
	for ( i = 0; i < numfaces; i++ )
	{
		// triangle faces already have shear springs due to structural geometry
		if ( !mface[i].v4 )
			continue; 
		
		spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
		
		if(!spring)
		{
			cloth_free_errorsprings(cloth, edgehash, edgelist);
			return 0;
		}

		spring->ij = MIN2(mface[i].v1, mface[i].v3);
		spring->kl = MAX2(mface[i].v3, mface[i].v1);
		VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
		spring->restlen =  sqrt ( INPR ( temp, temp ) );
		spring->type = CLOTH_SPRING_TYPE_SHEAR;
		spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0;

		BLI_linklist_append ( &edgelist[spring->ij], spring );
		BLI_linklist_append ( &edgelist[spring->kl], spring );
		shear_springs++;

		BLI_linklist_prepend ( &cloth->springs, spring );

		
		// if ( mface[i].v4 ) --> Quad face
		spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
		
		if(!spring)
		{
			cloth_free_errorsprings(cloth, edgehash, edgelist);
			return 0;
		}

		spring->ij = MIN2(mface[i].v2, mface[i].v4);
		spring->kl = MAX2(mface[i].v4, mface[i].v2);
		VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
		spring->restlen =  sqrt ( INPR ( temp, temp ) );
		spring->type = CLOTH_SPRING_TYPE_SHEAR;
		spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0;

		BLI_linklist_append ( &edgelist[spring->ij], spring );
		BLI_linklist_append ( &edgelist[spring->kl], spring );
		shear_springs++;

		BLI_linklist_prepend ( &cloth->springs, spring );
	}
	
	if(numfaces) {
		// bending springs
		search2 = cloth->springs;
		for ( i = struct_springs; i < struct_springs+shear_springs; i++ )
		{
			if ( !search2 )
				break;

			tspring2 = search2->link;
			search = edgelist[tspring2->kl];
			while ( search )
			{
				tspring = search->link;
				index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) );
				
				// check for existing spring
				// check also if startpoint is equal to endpoint
				if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) )
				&& ( index2!=tspring2->ij ) )
				{
					spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
					
					if(!spring)
					{
						cloth_free_errorsprings(cloth, edgehash, edgelist);
						return 0;
					}

					spring->ij = MIN2(tspring2->ij, index2);
					spring->kl = MAX2(tspring2->ij, index2);
					VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
					spring->restlen =  sqrt ( INPR ( temp, temp ) );
					spring->type = CLOTH_SPRING_TYPE_BENDING;
					spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0;
					BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL );
					bend_springs++;

					BLI_linklist_prepend ( &cloth->springs, spring );
				}
				search = search->next;
			}
			search2 = search2->next;
		}
	}
	else if(struct_springs > 2) {
		/* bending springs for hair strands */
		/* The current algorightm only goes through the edges in order of the mesh edges list	*/
		/* and makes springs between the outer vert of edges sharing a vertice. This works just */
		/* fine for hair, but not for user generated string meshes. This could/should be later	*/
		/* extended to work with non-ordered edges so that it can be used for general "rope		*/
		/* dynamics" without the need for the vertices or edges to be ordered through the length*/
		/* of the strands. -jahka */
		search = cloth->springs;
		search2 = search->next;
		while(search && search2)
		{
			tspring = search->link;
			tspring2 = search2->link;

			if(tspring->ij == tspring2->kl) {
				spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
				
				if(!spring)
				{
					cloth_free_errorsprings(cloth, edgehash, edgelist);
					return 0;
				}

				spring->ij = tspring2->ij;
				spring->kl = tspring->kl;
				VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x );
				spring->restlen =  sqrt ( INPR ( temp, temp ) );
				spring->type = CLOTH_SPRING_TYPE_BENDING;
				spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0;
				bend_springs++;

				BLI_linklist_prepend ( &cloth->springs, spring );
			}
			
			search = search->next;
			search2 = search2->next;
		}
	}
	
	/* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */
	for ( i = 0; i < numedges; i++ ) // struct springs
		BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL );
	
	for ( i = 0; i < numfaces; i++ ) // edge springs
	{
		if(mface[i].v4)
		{
			BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL );
			
			BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL );
		}
	}
	
	
	cloth->numsprings = struct_springs + shear_springs + bend_springs;
	
	if ( edgelist )
	{
		for ( i = 0; i < numverts; i++ )
		{
			BLI_linklist_free ( edgelist[i],NULL );
		}
	
		MEM_freeN ( edgelist );
	}
	
	cloth->edgehash = edgehash;
	
	if(G.rt>0)
		printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len);

	return 1;

} /* cloth_build_springs */
Exemple #6
0
/* read .bobj.gz file into a fluidsimDerivedMesh struct */
static DerivedMesh *fluidsim_read_obj(char *filename)
{
	int wri,i,j;
	float wrf;
	int gotBytes;
	gzFile gzf;
	int numverts = 0, numfaces = 0;
	DerivedMesh *dm = NULL;
	MFace *mface;
	MVert *mvert;
	short *normals;
		
	// ------------------------------------------------
	// get numverts + numfaces first
	// ------------------------------------------------
	gzf = gzopen(filename, "rb");
	if (!gzf) 
	{
		return NULL;
	}

	// read numverts
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	numverts = wri;
	
	// skip verts
	for(i=0; i<numverts*3; i++) 
	{	
		gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
	}
	
	// read number of normals
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	
	// skip normals
	for(i=0; i<numverts*3; i++) 
	{	
		gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
	}
	
	/* get no. of triangles */
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	numfaces = wri;
	
	gzclose( gzf );
	// ------------------------------------------------
	
	if(!numfaces || !numverts)
		return NULL;
	
	gzf = gzopen(filename, "rb");
	if (!gzf) 
	{
		return NULL;
	}
	
	dm = CDDM_new(numverts, 0, numfaces);
	
	if(!dm)
	{
		gzclose( gzf );
		return NULL;
	}
	
	// read numverts
	gotBytes = gzread(gzf, &wri, sizeof(wri));

	// read vertex position from file
	mvert = CDDM_get_verts(dm);
	for(i=0; i<numverts; i++) 
	{
		MVert *mv = &mvert[i];
		
		for(j=0; j<3; j++) 
		{
			gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
			mv->co[j] = wrf;
		}
	}

	// should be the same as numverts
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	if(wri != numverts) 
	{
		if(dm)
			dm->release(dm);
		gzclose( gzf );
		return NULL;
	}
	
	normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );	
	if(!normals)
	{
		if(dm)
			dm->release(dm);
		gzclose( gzf );
		return NULL;
	}	
	
	// read normals from file (but don't save them yet)
	for(i=0; i<numverts*3; i++) 
	{ 
		gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
		normals[i] = (short)(wrf*32767.0f);
	}
	
	/* read no. of triangles */
	gotBytes = gzread(gzf, &wri, sizeof(wri));
	
	if(wri!=numfaces)
		printf("Fluidsim: error in reading data from file.\n");
	
	// read triangles from file
	mface = CDDM_get_faces(dm);
	for(i=0; i<numfaces; i++) 
	{
		int face[4];
		MFace *mf = &mface[i];

		gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] )); 
		gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] )); 
		gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] )); 
		face[3] = 0;

		// check if 3rd vertex has index 0 (not allowed in blender)
		if(face[2])
		{
			mf->v1 = face[0];
			mf->v2 = face[1];
			mf->v3 = face[2];
		}
		else
		{
			mf->v1 = face[1];
			mf->v2 = face[2];
			mf->v3 = face[0];
		}
		mf->v4 = face[3];
		
		test_index_face(mf, NULL, 0, 3);
	}
	
	gzclose( gzf );
	
	CDDM_calc_edges(dm);
	
	CDDM_apply_vert_normals(dm, (short (*)[3])normals);
	MEM_freeN(normals);
	
	// CDDM_calc_normals(result);

	return dm;
}