void GeometryExporter::createLooseEdgeList(Object *ob,
                                           Mesh   *me,
                                           std::string& geom_id)
{

	MEdge *medges = me->medge;
	int totedges  = me->totedge;
	int edges_in_linelist = 0;
	std::vector<unsigned int> edge_list;
	int index;

	// Find all loose edges in Mesh 
	// and save vertex indices in edge_list
	for (index = 0; index < totedges; index++) 
	{
		MEdge *edge = &medges[index];

		if (edge->flag & ME_LOOSEEDGE)
		{
			edges_in_linelist += 1;
			edge_list.push_back(edge->v1);
			edge_list.push_back(edge->v2);
		}
	}

	if (edges_in_linelist > 0)
	{
		// Create the list of loose edges
		COLLADASW::Lines lines(mSW);

		lines.setCount(edges_in_linelist);


		COLLADASW::InputList &til = lines.getInputList();
			
		// creates <input> in <lines> for vertices 
		COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
		til.push_back(input1);

		lines.prepareToAppendValues();

		for (index = 0; index < edges_in_linelist; index++) 
		{
			lines.appendValues(edge_list[2 * index + 1]);
			lines.appendValues(edge_list[2 * index]);
		}
		lines.finish();
	}

}
void GeometryExporter::operator()(Object *ob)
{
	// XXX don't use DerivedMesh, Mesh instead?

#if 0		
	DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
#endif
	Mesh *me = (Mesh*)ob->data;
	std::string geom_id = get_geometry_id(ob);
	std::string geom_name = id_name(ob->data);
	std::vector<Normal> nor;
	std::vector<Face> norind;

	// Skip if linked geometry was already exported from another reference
	if (exportedGeometry.find(geom_id) != exportedGeometry.end())
		return;
	exportedGeometry.insert(geom_id);

	bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);

	create_normals(nor, norind, me);

	// openMesh(geoId, geoName, meshId)
	openMesh(geom_id, geom_name);
	
	// writes <source> for vertex coords
	createVertsSource(geom_id, me);
	
	// writes <source> for normal coords
	createNormalsSource(geom_id, me, nor);

	bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
	
	// writes <source> for uv coords if mesh has uv coords
	if (has_uvs)
		createTexcoordsSource(geom_id, me);

	if (has_color)
		createVertexColorSource(geom_id, me);

	// <vertices>
	COLLADASW::Vertices verts(mSW);
	verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
	COLLADASW::InputList &input_list = verts.getInputList();
	COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
	input_list.push_back(input);
	verts.add();

	// XXX slow		
	if (ob->totcol) {
		for(int a = 0; a < ob->totcol; a++)	{
			createPolylist(a, has_uvs, has_color, ob, geom_id, norind);
		}
	}
	else {
		createPolylist(0, has_uvs, has_color, ob, geom_id, norind);
	}
	
	closeMesh();
	
	if (me->flag & ME_TWOSIDED) {
		mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
	}
	
	closeGeometry();
	
#if 0
	dm->release(dm);
#endif
}
// powerful because it handles both cases when there is material and when there's not
void GeometryExporter::createPolylist(short material_index,
					bool has_uvs,
					bool has_color,
					Object *ob,
					std::string& geom_id,
					std::vector<Face>& norind)
{
	Mesh *me = (Mesh*)ob->data;
	MFace *mfaces = me->mface;
	int totfaces = me->totface;

	// <vcount>
	int i;
	int faces_in_polylist = 0;
	std::vector<unsigned long> vcount_list;

	// count faces with this material
	for (i = 0; i < totfaces; i++) {
		MFace *f = &mfaces[i];
		
		if (f->mat_nr == material_index) {
			faces_in_polylist++;
			if (f->v4 == 0) {
				vcount_list.push_back(3);
			}
			else {
				vcount_list.push_back(4);
			}
		}
	}

	// no faces using this material
	if (faces_in_polylist == 0) {
		fprintf(stderr, "%s: no faces use material %d\n", id_name(ob).c_str(), material_index);
		return;
	}
		
	Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
	COLLADASW::Polylist polylist(mSW);
		
	// sets count attribute in <polylist>
	polylist.setCount(faces_in_polylist);
		
	// sets material name
	if (ma) {
		std::ostringstream ostr;
		ostr << translate_id(id_name(ma)) << material_index+1;
		polylist.setMaterial(ostr.str());
	}
			
	COLLADASW::InputList &til = polylist.getInputList();
		
	// creates <input> in <polylist> for vertices 
	COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
		
	// creates <input> in <polylist> for normals
	COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
		
	til.push_back(input1);
	til.push_back(input2);
		
	// if mesh has uv coords writes <input> for TEXCOORD
	int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);

	for (i = 0; i < num_layers; i++) {
		// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
		COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
								makeUrl(makeTexcoordSourceId(geom_id, i)),
								2, // offset always 2, this is only until we have optimized UV sets
								i  // set number equals UV map index
								);
		til.push_back(input3);
	}

	if (has_color) {
		COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
		til.push_back(input4);
	}
		
	// sets <vcount>
	polylist.setVCountList(vcount_list);
		
	// performs the actual writing
	polylist.prepareToAppendValues();
		
	// <p>
	int texindex = 0;
	for (i = 0; i < totfaces; i++) {
		MFace *f = &mfaces[i];

		if (f->mat_nr == material_index) {

			unsigned int *v = &f->v1;
			unsigned int *n = &norind[i].v1;
			for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
				polylist.appendValues(v[j]);
				polylist.appendValues(n[j]);

				if (has_uvs)
					polylist.appendValues(texindex + j);

				if (has_color)
					polylist.appendValues(texindex + j);
			}
		}

		texindex += 3;
		if (f->v4 != 0)
			texindex++;
	}
		
	polylist.finish();
}
void GeometryExporter::operator()(Object *ob)
{ 
	// XXX don't use DerivedMesh, Mesh instead?
#if 0		
	DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
#endif

	bool use_instantiation = this->export_settings->use_object_instantiation;
	Mesh *me = bc_get_mesh_copy( mScene, 
					ob,
					this->export_settings->export_mesh_type,
					this->export_settings->apply_modifiers,
					this->export_settings->triangulate);

	Mesh *mesh = (Mesh *) ob->data;
	me->flag = mesh->flag;

	std::string geom_id = get_geometry_id(ob, use_instantiation);
	std::vector<Normal> nor;
	std::vector<BCPolygonNormalsIndices> norind;

	// Skip if linked geometry was already exported from another reference
	if (use_instantiation && 
	    exportedGeometry.find(geom_id) != exportedGeometry.end())
	{
		return;
	}

	std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);

	exportedGeometry.insert(geom_id);

	bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);

	create_normals(nor, norind, me);

	// openMesh(geoId, geoName, meshId)
	openMesh(geom_id, geom_name);
	
	// writes <source> for vertex coords
	createVertsSource(geom_id, me);
	
	// writes <source> for normal coords
	createNormalsSource(geom_id, me, nor);

	bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
	
	// writes <source> for uv coords if mesh has uv coords
	if (has_uvs) {
		createTexcoordsSource(geom_id, me);
	}

	if (has_color) {
		createVertexColorSource(geom_id, me);
	}
	// <vertices>

	COLLADASW::Vertices verts(mSW);
	verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
	COLLADASW::InputList &input_list = verts.getInputList();
	COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
	input_list.push_back(input);
	verts.add();

	createLooseEdgeList(ob, me, geom_id);

	// Only create Polylists if number of faces > 0
	if (me->totface > 0) {
		// XXX slow
		if (ob->totcol) {
			for (int a = 0; a < ob->totcol; a++) {
				createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
			}
		}
		else {
			createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
		}
	}
	
	closeMesh();
	
	if (me->flag & ME_TWOSIDED) {
		mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
	}

	closeGeometry();

	if (this->export_settings->include_shapekeys) {
		Key * key = BKE_key_from_object(ob);
		if (key) {
			KeyBlock * kb = (KeyBlock *)key->block.first;
			//skip the basis
			kb = kb->next;
			for (; kb; kb = kb->next) {
				BKE_keyblock_convert_to_mesh(kb, me);
				export_key_mesh(ob, me, kb);
			}
		}
	}

	BKE_libblock_free_us(G.main, me);

}
// powerful because it handles both cases when there is material and when there's not
void GeometryExporter::createPolylist(short material_index,
                                      bool has_uvs,
                                      bool has_color,
                                      Object *ob,
                                      Mesh *me,
                                      std::string& geom_id,
                                      std::vector<BCPolygonNormalsIndices>& norind)
{

	MPoly *mpolys = me->mpoly;
	MLoop *mloops = me->mloop;
	int totpolys  = me->totpoly;

	// <vcount>
	int i;
	int faces_in_polylist = 0;
	std::vector<unsigned long> vcount_list;

	// count faces with this material
	for (i = 0; i < totpolys; i++) {
		MPoly *p = &mpolys[i];
		
		if (p->mat_nr == material_index) {
			faces_in_polylist++;
			vcount_list.push_back(p->totloop);
		}
	}

	// no faces using this material
	if (faces_in_polylist == 0) {
		fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
		return;
	}
		
	Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
	COLLADASW::Polylist polylist(mSW);
		
	// sets count attribute in <polylist>
	polylist.setCount(faces_in_polylist);
		
	// sets material name
	if (ma) {
		std::string material_id = get_material_id(ma);
		std::ostringstream ostr;
		ostr << translate_id(material_id);
		polylist.setMaterial(ostr.str());
	}
			
	COLLADASW::InputList &til = polylist.getInputList();
		
	// creates <input> in <polylist> for vertices 
	COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
		
	// creates <input> in <polylist> for normals
	COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
		
	til.push_back(input1);
	til.push_back(input2);
		
	// if mesh has uv coords writes <input> for TEXCOORD
	int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
	int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
	for (i = 0; i < num_layers; i++) {
		if (!this->export_settings->active_uv_only || i == active_uv_index) {

			// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
			COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
									makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings->active_uv_only)),
									2, // this is only until we have optimized UV sets
									(this->export_settings->active_uv_only) ? 0 : i  // only_active_uv exported -> we have only one set
									);
			til.push_back(input3);
		}
	}

	int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
	if (totlayer_mcol > 0) {
		int map_index = 0;

		for (int a = 0; a < totlayer_mcol; a++) {
			char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
			COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
			                        makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
			                        (has_uvs) ? 3 : 2,  // all color layers have same index order
			                        map_index           // set number equals color map index
			                        );
			til.push_back(input4);
			map_index++;
		}
	}
		
	// sets <vcount>
	polylist.setVCountList(vcount_list);
		
	// performs the actual writing
	polylist.prepareToAppendValues();
	
	// <p>
	int texindex = 0;
	for (i = 0; i < totpolys; i++) {
		MPoly *p = &mpolys[i];
		int loop_count = p->totloop;

		if (p->mat_nr == material_index) {
			MLoop *l = &mloops[p->loopstart];
			BCPolygonNormalsIndices normal_indices = norind[i];

			for (int j = 0; j < loop_count; j++) {
				polylist.appendValues(l[j].v);
				polylist.appendValues(normal_indices[j]);
				if (has_uvs)
					polylist.appendValues(texindex + j);

				if (has_color)
					polylist.appendValues(texindex + j);
			}
		}

		texindex += loop_count;
	}
		
	polylist.finish();
}
void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
{
	std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
	std::vector<Normal> nor;
	std::vector<BCPolygonNormalsIndices> norind;
	
	if (exportedGeometry.find(geom_id) != exportedGeometry.end())
	{
		return;
	}

	std::string geom_name = kb->name;

	exportedGeometry.insert(geom_id);

	bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);

	create_normals(nor, norind, me);

	// openMesh(geoId, geoName, meshId)
	openMesh(geom_id, geom_name);
	
	// writes <source> for vertex coords
	createVertsSource(geom_id, me);
	
	// writes <source> for normal coords
	createNormalsSource(geom_id, me, nor);

	bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
	
	// writes <source> for uv coords if mesh has uv coords
	if (has_uvs) {
		createTexcoordsSource(geom_id, me);
	}

	if (has_color) {
		createVertexColorSource(geom_id, me);
	}

	// <vertices>

	COLLADASW::Vertices verts(mSW);
	verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
	COLLADASW::InputList &input_list = verts.getInputList();
	COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
	input_list.push_back(input);
	verts.add();

	//createLooseEdgeList(ob, me, geom_id, norind);

	// XXX slow		
	if (ob->totcol) {
		for (int a = 0; a < ob->totcol; a++) {
			createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
		}
	}
	else {
		createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
	}
	
	closeMesh();
	
	if (me->flag & ME_TWOSIDED) {
		mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
	}

	closeGeometry();
}