Esempio n. 1
0
static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
{
	DerivedMesh *result;

	GenerateOceanGeometryData gogd;

	int num_verts;
	int num_polys;

	const bool use_threading = omd->resolution > 4;

	gogd.rx = omd->resolution * omd->resolution;
	gogd.ry = omd->resolution * omd->resolution;
	gogd.res_x = gogd.rx * omd->repeat_x;
	gogd.res_y = gogd.ry * omd->repeat_y;

	num_verts = (gogd.res_x + 1) * (gogd.res_y + 1);
	num_polys = gogd.res_x * gogd.res_y;

	gogd.sx = omd->size * omd->spatial_size;
	gogd.sy = omd->size * omd->spatial_size;
	gogd.ox = -gogd.sx / 2.0f;
	gogd.oy = -gogd.sy / 2.0f;

	gogd.sx /= gogd.rx;
	gogd.sy /= gogd.ry;

	result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);

	gogd.mverts = CDDM_get_verts(result);
	gogd.mpolys = CDDM_get_polys(result);
	gogd.mloops = CDDM_get_loops(result);

	gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	/* create vertices */
	BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);

	/* create faces */
	BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);

	CDDM_calc_edges(result);

	/* add uvs */
	if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
		gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
		CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);

		if (gogd.mloopuvs) { /* unlikely to fail */
			gogd.ix = 1.0 / gogd.rx;
			gogd.iy = 1.0 / gogd.ry;

			BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
		}
	}

	result->dirty |= DM_DIRTY_NORMALS;

	return result;
}
Esempio n. 2
0
/* allocate and initialize a DualConOutput */
static void *dualcon_alloc_output(int totvert, int totquad)
{
	DualConOutput *output;

	if (!(output = MEM_callocN(sizeof(DualConOutput),
	                           "DualConOutput")))
	{
		return NULL;
	}
	
	output->dm = CDDM_new(totvert, 0, 0, 4 * totquad, totquad);
	return output;
}
/* Create new external mesh */
static void exporter_InitGeomArrays(ExportMeshData *export_data,
                                    int num_verts, int num_edges,
                                    int num_loops, int num_polys)
{
	DerivedMesh *dm = CDDM_new(num_verts, num_edges, 0,
	                           num_loops, num_polys);
	DerivedMesh *dm_left = export_data->dm_left,
	            *dm_right = export_data->dm_right;

	/* Mask for custom data layers to be merged from operands. */
	CustomDataMask merge_mask = CD_MASK_DERIVEDMESH & ~CD_MASK_ORIGINDEX;

	export_data->dm = dm;
	export_data->mvert = dm->getVertArray(dm);
	export_data->medge = dm->getEdgeArray(dm);
	export_data->mloop = dm->getLoopArray(dm);
	export_data->mpoly = dm->getPolyArray(dm);

	/* Allocate layers for UV layers and vertex colors.
	 * Without this interpolation of those data will not happen.
	 */
	allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops,
	                       CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPCOL));
	allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops,
	                       CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPUV));

	allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops,
	                       CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPCOL));
	allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops,
	                       CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPUV));

	/* Merge custom data layers from operands.
	 *
	 * Will only create custom data layers for all the layers which appears in
	 * the operand. Data for those layers will not be allocated or initialized.
	 */
	CustomData_merge(&dm_left->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys);
	CustomData_merge(&dm_right->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys);

	CustomData_merge(&dm_left->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges);
	CustomData_merge(&dm_right->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges);

	export_data->vert_origindex = dm->getVertDataArray(dm, CD_ORIGINDEX);
	export_data->edge_origindex = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
	export_data->poly_origindex = dm->getPolyDataArray(dm, CD_ORIGINDEX);
	export_data->loop_origindex = dm->getLoopDataArray(dm, CD_ORIGINDEX);
}
Esempio n. 4
0
static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
{
	DerivedMesh *result = NULL;

	if (derivedData->getNumPolys(derivedData) == 0 || dm->getNumPolys(dm) == 0) {
		switch (operation) {
			case eBooleanModifierOp_Intersect:
				result = CDDM_new(0, 0, 0, 0, 0);
				break;

			case eBooleanModifierOp_Union:
				if (derivedData->getNumPolys(derivedData)) result = derivedData;
				else result = CDDM_copy(dm);

				break;

			case eBooleanModifierOp_Difference:
				result = derivedData;
				break;
		}
	}

	return result;
}
Esempio n. 5
0
static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
{
	DerivedMesh *result;

	MVert *mverts;
	MPoly *mpolys;
	MLoop *mloops;
	int *origindex;

	int cdlayer;

	const int rx = omd->resolution * omd->resolution;
	const int ry = omd->resolution * omd->resolution;
	const int res_x = rx * omd->repeat_x;
	const int res_y = ry * omd->repeat_y;

	const int num_verts = (res_x + 1) * (res_y + 1);
	/* const int num_edges = (res_x * res_y * 2) + res_x + res_y; */ /* UNUSED BMESH */
	const int num_faces = res_x * res_y;

	float sx = omd->size * omd->spatial_size;
	float sy = omd->size * omd->spatial_size;
	const float ox = -sx / 2.0f;
	const float oy = -sy / 2.0f;

	float ix, iy;

	int x, y;

	sx /= rx;
	sy /= ry;

	result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);

	mverts = CDDM_get_verts(result);
	mpolys = CDDM_get_polys(result);
	mloops = CDDM_get_loops(result);

	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	/* create vertices */
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
	for (y = 0; y <= res_y; y++) {
		for (x = 0; x <= res_x; x++) {
			const int i = y * (res_x + 1) + x;
			float *co = mverts[i].co;
			co[0] = ox + (x * sx);
			co[1] = oy + (y * sy);
			co[2] = 0;
		}
	}

	/* create faces */
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
	for (y = 0; y < res_y; y++) {
		for (x = 0; x < res_x; x++) {
			const int fi = y * res_x + x;
			const int vi = y * (res_x + 1) + x;
			MPoly *mp = &mpolys[fi];
			MLoop *ml = &mloops[fi * 4];

			ml->v = vi;
			ml++;
			ml->v = vi + 1;
			ml++;
			ml->v = vi + 1 + res_x + 1;
			ml++;
			ml->v = vi + res_x + 1;
			ml++;

			mp->loopstart = fi * 4;
			mp->totloop = 4;

			mp->flag |= ME_SMOOTH;

			/* generated geometry does not map to original faces */
			origindex[fi] = ORIGINDEX_NONE;
		}
	}

	CDDM_calc_edges(result);

	/* add uvs */
	cdlayer = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
	if (cdlayer < MAX_MTFACE) {
		MLoopUV *mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_faces * 4);
		CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_faces);

		if (mloopuvs) { /* unlikely to fail */
			ix = 1.0 / rx;
			iy = 1.0 / ry;
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
			for (y = 0; y < res_y; y++) {
				for (x = 0; x < res_x; x++) {
					const int i = y * res_x + x;
					MLoopUV *luv = &mloopuvs[i * 4];

					luv->uv[0] = x * ix;
					luv->uv[1] = y * iy;
					luv++;

					luv->uv[0] = (x + 1) * ix;
					luv->uv[1] = y * iy;
					luv++;

					luv->uv[0] = (x + 1) * ix;
					luv->uv[1] = (y + 1) * iy;
					luv++;

					luv->uv[0] = x * ix;
					luv->uv[1] = (y + 1) * iy;
					luv++;

				}
			}
		}
	}

	result->dirty |= DM_DIRTY_NORMALS;

	return result;
}
Esempio n. 6
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;
}
Esempio n. 7
0
/* read .bobj.gz file into a fluidsimDerivedMesh struct */
static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example)
{
	int wri = 0, i;
	int gotBytes;
	gzFile gzf;
	int numverts = 0, numfaces = 0;
	DerivedMesh *dm = NULL;
	MPoly *mp;
	MLoop *ml;
	MVert *mv;
	short *normals, *no_s;
	float no[3];

	const short mp_mat_nr = mp_example->mat_nr;
	const char mp_flag =   mp_example->flag;

	// ------------------------------------------------
	// get numverts + numfaces first
	// ------------------------------------------------
	gzf = BLI_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 = BLI_gzopen(filename, "rb");
	if (!gzf) {
		return NULL;
	}

	dm = CDDM_new(numverts, 0, 0, numfaces * 3, 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
	mp = CDDM_get_polys(dm);
	ml = CDDM_get_loops(dm);
	for (i = 0; i < numfaces; i++, mp++, ml += 3) {
		int face[3];

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

		/* initialize from existing face */
		mp->mat_nr = mp_mat_nr;
		mp->flag =   mp_flag;

		mp->loopstart = i * 3;
		mp->totloop = 3;

		ml[0].v = face[0];
		ml[1].v = face[1];
		ml[2].v = face[2];

	}

	gzclose(gzf);

	CDDM_calc_edges(dm);

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

	// CDDM_calc_normals(result);
	return dm;
}
Esempio n. 8
0
/* Iterate over the CSG Output Descriptors and create a new DerivedMesh
   from them */
static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
	CSG_FaceIteratorDescriptor *face_it,
	CSG_VertexIteratorDescriptor *vertex_it,
	float parinv[][4],
	float mapmat[][4],
	Material **mat,
	int *totmat,
	DerivedMesh *dm1,
	Object *ob1,
	DerivedMesh *dm2,
	Object *ob2)
{
	DerivedMesh *result, *orig_dm;
	GHash *material_hash = NULL;
	Mesh *me1= (Mesh*)ob1->data;
	Mesh *me2= (Mesh*)ob2->data;
	int i;

	// create a new DerivedMesh
	result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements);
	CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
					  CD_DEFAULT, face_it->num_elements); 
	CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
					  CD_DEFAULT, face_it->num_elements); 

	// step through the vertex iterators:
	for (i = 0; !vertex_it->Done(vertex_it->it); i++) {
		CSG_IVertex csgvert;
		MVert *mvert = CDDM_get_vert(result, i);

		// retrieve a csg vertex from the boolean module
		vertex_it->Fill(vertex_it->it, &csgvert);
		vertex_it->Step(vertex_it->it);

		// we have to map the vertex coordinates back in the coordinate frame
		// of the resulting object, since it was computed in world space
		mul_v3_m4v3(mvert->co, parinv, csgvert.position);
	}

	// a hash table to remap materials to indices
	if (mat) {
		material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "CSG_mat gh");
		*totmat = 0;
	}

	// step through the face iterators
	for(i = 0; !face_it->Done(face_it->it); i++) {
		Mesh *orig_me;
		Object *orig_ob;
		Material *orig_mat;
		CSG_IFace csgface;
		MFace *mface;
		int orig_index, mat_nr;

		// retrieve a csg face from the boolean module
		face_it->Fill(face_it->it, &csgface);
		face_it->Step(face_it->it);

		// find the original mesh and data
		orig_ob = (csgface.orig_face < dm1->getNumFaces(dm1))? ob1: ob2;
		orig_dm = (csgface.orig_face < dm1->getNumFaces(dm1))? dm1: dm2;
		orig_me = (orig_ob == ob1)? me1: me2;
		orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1);

		// copy all face layers, including mface
		CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1);

		// set mface
		mface = CDDM_get_face(result, i);
		mface->v1 = csgface.vertex_index[0];
		mface->v2 = csgface.vertex_index[1];
		mface->v3 = csgface.vertex_index[2];
		mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0;

		// set material, based on lookup in hash table
		orig_mat= give_current_material(orig_ob, mface->mat_nr+1);

		if (mat && orig_mat) {
			if (!BLI_ghash_haskey(material_hash, orig_mat)) {
				mat[*totmat] = orig_mat;
				mat_nr = mface->mat_nr = (*totmat)++;
				BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr));
			}
			else
				mface->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat));
		}
		else
			mface->mat_nr = 0;

		InterpCSGFace(result, orig_dm, i, orig_index, csgface.vertex_number,
					  (orig_me == me2)? mapmat: NULL);

		test_index_face(mface, &result->faceData, i, csgface.vertex_number);
	}

	if (material_hash)
		BLI_ghash_free(material_hash, NULL, NULL);

	CDDM_calc_edges(result);
	CDDM_calc_normals(result);

	return result;
}
Esempio n. 9
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;
}