Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/collada/MeshImporter.cpp')
-rw-r--r--source/blender/collada/MeshImporter.cpp912
1 files changed, 912 insertions, 0 deletions
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
new file mode 100644
index 00000000000..be7abc3ec4e
--- /dev/null
+++ b/source/blender/collada/MeshImporter.cpp
@@ -0,0 +1,912 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <algorithm>
+
+#if !defined(WIN32) || defined(FREE_WINDOWS)
+#include <iostream>
+#endif
+
+#include "COLLADAFWMeshPrimitive.h"
+#include "COLLADAFWMeshVertexData.h"
+#include "COLLADAFWPolygons.h"
+
+extern "C" {
+#include "BKE_blender.h"
+#include "BKE_customdata.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+}
+
+#include "ArmatureImporter.h"
+#include "MeshImporter.h"
+#include "collada_utils.h"
+
+// works for COLLADAFW::Node, COLLADAFW::Geometry
+template<class T>
+static const char *bc_get_dae_name(T *node)
+{
+ const std::string& name = node->getName();
+ return name.size() ? name.c_str() : node->getOriginalId().c_str();
+}
+
+static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type)
+{
+ switch (type) {
+ case COLLADAFW::MeshPrimitive::LINES:
+ return "LINES";
+ case COLLADAFW::MeshPrimitive::LINE_STRIPS:
+ return "LINESTRIPS";
+ case COLLADAFW::MeshPrimitive::POLYGONS:
+ return "POLYGONS";
+ case COLLADAFW::MeshPrimitive::POLYLIST:
+ return "POLYLIST";
+ case COLLADAFW::MeshPrimitive::TRIANGLES:
+ return "TRIANGLES";
+ case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
+ return "TRIANGLE_FANS";
+ case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
+ return "TRIANGLE_FANS";
+ case COLLADAFW::MeshPrimitive::POINTS:
+ return "POINTS";
+ case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
+ return "UNDEFINED_PRIMITIVE_TYPE";
+ }
+ return "UNKNOWN";
+}
+
+static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type)
+{
+ switch (type) {
+ case COLLADAFW::Geometry::GEO_TYPE_MESH:
+ return "MESH";
+ case COLLADAFW::Geometry::GEO_TYPE_SPLINE:
+ return "SPLINE";
+ case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH:
+ return "CONVEX_MESH";
+ case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN:
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata)
+{}
+
+#ifdef COLLADA_DEBUG
+void WVDataWrapper::print()
+{
+ fprintf(stderr, "UVs:\n");
+ switch(mVData->getType()) {
+ case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+ {
+ COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
+ if (values->getCount()) {
+ for (int i = 0; i < values->getCount(); i += 2) {
+ fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i+1]);
+ }
+ }
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+ {
+ COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
+ if (values->getCount()) {
+ for (int i = 0; i < values->getCount(); i += 2) {
+ fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i+1]);
+ }
+ }
+ }
+ break;
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+void UVDataWrapper::getUV(int uv_index[2], float *uv)
+{
+ switch(mVData->getType()) {
+ case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+ {
+ COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues();
+ if (values->empty()) return;
+ uv[0] = (*values)[uv_index[0]];
+ uv[1] = (*values)[uv_index[1]];
+
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+ {
+ COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues();
+ if (values->empty()) return;
+ uv[0] = (float)(*values)[uv_index[0]];
+ uv[1] = (float)(*values)[uv_index[1]];
+
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
+ default:
+ fprintf(stderr, "MeshImporter.getUV(): unknown data type\n");
+ }
+}
+
+void MeshImporter::set_face_indices(MFace *mface, unsigned int *indices, bool quad)
+{
+ mface->v1 = indices[0];
+ mface->v2 = indices[1];
+ mface->v3 = indices[2];
+ if (quad) mface->v4 = indices[3];
+ else mface->v4 = 0;
+#ifdef COLLADA_DEBUG
+ // fprintf(stderr, "%u, %u, %u \n", indices[0], indices[1], indices[2]);
+#endif
+}
+
+// not used anymore, test_index_face from blenkernel is better
+#if 0
+// change face indices order so that v4 is not 0
+void MeshImporter::rotate_face_indices(MFace *mface) {
+ mface->v4 = mface->v1;
+ mface->v1 = mface->v2;
+ mface->v2 = mface->v3;
+ mface->v3 = 0;
+}
+#endif
+
+void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+ COLLADAFW::IndexList& index_list, unsigned int *tris_indices)
+{
+ int uv_indices[4][2];
+
+ // per face vertex indices, this means for quad we have 4 indices, not 8
+ COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+
+ // make indices into FloatOrDoubleArray
+ for (int i = 0; i < 3; i++) {
+ int uv_index = indices[tris_indices[i]];
+ uv_indices[i][0] = uv_index * 2;
+ uv_indices[i][1] = uv_index * 2 + 1;
+ }
+
+ uvs.getUV(uv_indices[0], mtface->uv[0]);
+ uvs.getUV(uv_indices[1], mtface->uv[1]);
+ uvs.getUV(uv_indices[2], mtface->uv[2]);
+}
+
+void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
+ COLLADAFW::IndexList& index_list, int index, bool quad)
+{
+ int uv_indices[4][2];
+
+ // per face vertex indices, this means for quad we have 4 indices, not 8
+ COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+
+ // make indices into FloatOrDoubleArray
+ for (int i = 0; i < (quad ? 4 : 3); i++) {
+ int uv_index = indices[index + i];
+ uv_indices[i][0] = uv_index * 2;
+ uv_indices[i][1] = uv_index * 2 + 1;
+ }
+
+ uvs.getUV(uv_indices[0], mtface->uv[0]);
+ uvs.getUV(uv_indices[1], mtface->uv[1]);
+ uvs.getUV(uv_indices[2], mtface->uv[2]);
+
+ if (quad) uvs.getUV(uv_indices[3], mtface->uv[3]);
+
+#ifdef COLLADA_DEBUG
+ /*if (quad) {
+ fprintf(stderr, "face uv:\n"
+ "((%d, %d), (%d, %d), (%d, %d), (%d, %d))\n"
+ "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
+
+ uv_indices[0][0], uv_indices[0][1],
+ uv_indices[1][0], uv_indices[1][1],
+ uv_indices[2][0], uv_indices[2][1],
+ uv_indices[3][0], uv_indices[3][1],
+
+ mtface->uv[0][0], mtface->uv[0][1],
+ mtface->uv[1][0], mtface->uv[1][1],
+ mtface->uv[2][0], mtface->uv[2][1],
+ mtface->uv[3][0], mtface->uv[3][1]);
+ }
+ else {
+ fprintf(stderr, "face uv:\n"
+ "((%d, %d), (%d, %d), (%d, %d))\n"
+ "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
+
+ uv_indices[0][0], uv_indices[0][1],
+ uv_indices[1][0], uv_indices[1][1],
+ uv_indices[2][0], uv_indices[2][1],
+
+ mtface->uv[0][0], mtface->uv[0][1],
+ mtface->uv[1][0], mtface->uv[1][1],
+ mtface->uv[2][0], mtface->uv[2][1]);
+ }*/
+#endif
+}
+
+#ifdef COLLADA_DEBUG
+void MeshImporter::print_index_list(COLLADAFW::IndexList& index_list)
+{
+ fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str());
+ for (int i = 0; i < index_list.getIndicesCount(); i += 2) {
+ fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1));
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
+{
+ COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+
+ const char *name = bc_get_dae_name(mesh);
+
+ for (unsigned i = 0; i < prim_arr.getCount(); i++) {
+
+ COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+ COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType();
+
+ const char *type_str = bc_primTypeToStr(type);
+
+ // OpenCollada passes POLYGONS type for <polylist>
+ if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
+
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+ COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray();
+
+ for(unsigned int j = 0; j < vca.getCount(); j++){
+ int count = vca[j];
+ if (count < 3) {
+ fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
+ type_str, name);
+ return false;
+ }
+ }
+
+ }
+ else if(type != COLLADAFW::MeshPrimitive::TRIANGLES) {
+ fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
+ return false;
+ }
+ }
+
+ if (mesh->getPositions().empty()) {
+ fprintf(stderr, "Mesh %s has no vertices.\n", name);
+ return false;
+ }
+
+ return true;
+}
+
+void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
+{
+ // vertices
+ me->totvert = mesh->getPositions().getFloatValues()->getCount() / 3;
+ me->mvert = (MVert*)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+
+ COLLADAFW::MeshVertexData& pos = mesh->getPositions();
+ MVert *mvert;
+ int i;
+
+ for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
+ get_vector(mvert->co, pos, i);
+ }
+}
+
+int MeshImporter::triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri)
+{
+ ListBase dispbase;
+ DispList *dl;
+ float *vert;
+ int i = 0;
+
+ dispbase.first = dispbase.last = NULL;
+
+ dl = (DispList*)MEM_callocN(sizeof(DispList), "poly disp");
+ dl->nr = totvert;
+ dl->type = DL_POLY;
+ dl->parts = 1;
+ dl->verts = vert = (float*)MEM_callocN(totvert * 3 * sizeof(float), "poly verts");
+ dl->index = (int*)MEM_callocN(sizeof(int) * 3 * totvert, "dl index");
+
+ BLI_addtail(&dispbase, dl);
+
+ for (i = 0; i < totvert; i++) {
+ copy_v3_v3(vert, verts[indices[i]].co);
+ vert += 3;
+ }
+
+ filldisplist(&dispbase, &dispbase, 0);
+
+ int tottri = 0;
+ dl= (DispList*)dispbase.first;
+
+ if (dl->type == DL_INDEX3) {
+ tottri = dl->parts;
+
+ int *index = dl->index;
+ for (i= 0; i < tottri; i++) {
+ int t[3]= {*index, *(index + 1), *(index + 2)};
+
+ std::sort(t, t + 3);
+
+ tri.push_back(t[0]);
+ tri.push_back(t[1]);
+ tri.push_back(t[2]);
+
+ index += 3;
+ }
+ }
+
+ freedisplist(&dispbase);
+
+ return tottri;
+}
+
+int MeshImporter::count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
+{
+ COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+ unsigned int i;
+ int tottri = 0;
+
+ for (i = 0; i < prim_arr.getCount(); i++) {
+
+ COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+ int type = mp->getPrimitiveType();
+ size_t prim_totface = mp->getFaceCount();
+ unsigned int *indices = mp->getPositionIndices().getData();
+
+ if (type == COLLADAFW::MeshPrimitive::POLYLIST ||
+ type == COLLADAFW::MeshPrimitive::POLYGONS) {
+
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+ COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
+
+ for (unsigned int j = 0; j < prim_totface; j++) {
+ int vcount = vcounta[j];
+
+ if (vcount > 4) {
+ std::vector<unsigned int> tri;
+
+ // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?!
+ tottri += triangulate_poly(indices, vcount, me->mvert, tri);
+ }
+
+ indices += vcount;
+ }
+ }
+ }
+ return tottri;
+}
+
+// TODO: import uv set names
+void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris)
+{
+ unsigned int i;
+
+ // allocate faces
+ me->totface = mesh->getFacesCount() + new_tris;
+ me->mface = (MFace*)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+
+ // allocate UV layers
+ unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount();
+
+ for (i = 0; i < totuvset; i++) {
+ if (mesh->getUVCoords().getLength(i) == 0) {
+ totuvset = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < totuvset; i++) {
+ COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i];
+ CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str());
+ //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
+ }
+
+ // activate the first uv layer
+ if (totuvset) me->mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0);
+
+ UVDataWrapper uvs(mesh->getUVCoords());
+
+#ifdef COLLADA_DEBUG
+ // uvs.print();
+#endif
+
+ MFace *mface = me->mface;
+
+ MaterialIdPrimitiveArrayMap mat_prim_map;
+
+ int face_index = 0;
+
+ COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
+
+ bool has_normals = mesh->hasNormals();
+ COLLADAFW::MeshVertexData& nor = mesh->getNormals();
+
+ for (i = 0; i < prim_arr.getCount(); i++) {
+
+ COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+
+ // faces
+ size_t prim_totface = mp->getFaceCount();
+ unsigned int *indices = mp->getPositionIndices().getData();
+ unsigned int *nind = mp->getNormalIndices().getData();
+ unsigned int j, k;
+ int type = mp->getPrimitiveType();
+ int index = 0;
+
+ // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive
+ Primitive prim = {mface, 0};
+ COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray();
+
+#ifdef COLLADA_DEBUG
+ /*
+ fprintf(stderr, "Primitive %d:\n", i);
+ for (int j = 0; j < totuvset; j++) {
+ print_index_list(*index_list_array[j]);
+ }
+ */
+#endif
+
+ if (type == COLLADAFW::MeshPrimitive::TRIANGLES) {
+ for (j = 0; j < prim_totface; j++){
+
+ set_face_indices(mface, indices, false);
+ indices += 3;
+
+#if 0
+ for (k = 0; k < totuvset; k++) {
+ if (!index_list_array.empty() && index_list_array[k]) {
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+ set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false);
+ }
+ }
+#else
+ for (k = 0; k < index_list_array.getCount(); k++) {
+ int uvset_index = index_list_array[k]->getSetIndex();
+
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+ set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false);
+ }
+#endif
+
+ test_index_face(mface, &me->fdata, face_index, 3);
+
+ if (has_normals) {
+ if (!flat_face(nind, nor, 3))
+ mface->flag |= ME_SMOOTH;
+
+ nind += 3;
+ }
+
+ index += 3;
+ mface++;
+ face_index++;
+ prim.totface++;
+ }
+ }
+ else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp;
+ COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
+
+ for (j = 0; j < prim_totface; j++) {
+
+ // face
+ int vcount = vcounta[j];
+ if (vcount == 3 || vcount == 4) {
+
+ set_face_indices(mface, indices, vcount == 4);
+
+ // set mtface for each uv set
+ // it is assumed that all primitives have equal number of UV sets
+
+#if 0
+ for (k = 0; k < totuvset; k++) {
+ if (!index_list_array.empty() && index_list_array[k]) {
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
+ set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0);
+ }
+ }
+#else
+ for (k = 0; k < index_list_array.getCount(); k++) {
+ int uvset_index = index_list_array[k]->getSetIndex();
+
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+ set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, mface->v4 != 0);
+ }
+#endif
+
+ test_index_face(mface, &me->fdata, face_index, vcount);
+
+ if (has_normals) {
+ if (!flat_face(nind, nor, vcount))
+ mface->flag |= ME_SMOOTH;
+
+ nind += vcount;
+ }
+
+ mface++;
+ face_index++;
+ prim.totface++;
+
+ }
+ else {
+ std::vector<unsigned int> tri;
+
+ triangulate_poly(indices, vcount, me->mvert, tri);
+
+ for (k = 0; k < tri.size() / 3; k++) {
+ int v = k * 3;
+ unsigned int uv_indices[3] = {
+ index + tri[v],
+ index + tri[v + 1],
+ index + tri[v + 2]
+ };
+ unsigned int tri_indices[3] = {
+ indices[tri[v]],
+ indices[tri[v + 1]],
+ indices[tri[v + 2]]
+ };
+
+ set_face_indices(mface, tri_indices, false);
+
+#if 0
+ for (unsigned int l = 0; l < totuvset; l++) {
+ if (!index_list_array.empty() && index_list_array[l]) {
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l);
+ set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices);
+ }
+ }
+#else
+ for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
+ int uvset_index = index_list_array[l]->getSetIndex();
+
+ // get mtface by face index and uv set index
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
+ set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices);
+ }
+#endif
+
+
+ test_index_face(mface, &me->fdata, face_index, 3);
+
+ if (has_normals) {
+ unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]};
+
+ if (!flat_face(ntri, nor, 3))
+ mface->flag |= ME_SMOOTH;
+ }
+
+ mface++;
+ face_index++;
+ prim.totface++;
+ }
+
+ if (has_normals)
+ nind += vcount;
+ }
+
+ index += vcount;
+ indices += vcount;
+ }
+ }
+
+ mat_prim_map[mp->getMaterialId()].push_back(prim);
+ }
+
+ geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map;
+}
+
+void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i)
+{
+ i *= 3;
+
+ switch(arr.getType()) {
+ case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
+ {
+ COLLADAFW::ArrayPrimitiveType<float>* values = arr.getFloatValues();
+ if (values->empty()) return;
+
+ v[0] = (*values)[i++];
+ v[1] = (*values)[i++];
+ v[2] = (*values)[i];
+ }
+ break;
+ case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
+ {
+ COLLADAFW::ArrayPrimitiveType<double>* values = arr.getDoubleValues();
+ if (values->empty()) return;
+
+ v[0] = (float)(*values)[i++];
+ v[1] = (float)(*values)[i++];
+ v[2] = (float)(*values)[i];
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
+{
+ float a[3], b[3];
+
+ get_vector(a, nor, *nind);
+ normalize_v3(a);
+
+ nind++;
+
+ for (int i = 1; i < count; i++, nind++) {
+ get_vector(b, nor, *nind);
+ normalize_v3(b);
+
+ float dp = dot_v3v3(a, b);
+
+ if (dp < 0.99999f || dp > 1.00001f)
+ return false;
+ }
+
+ return true;
+}
+
+MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {}
+
+Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid)
+{
+ if (uid_object_map.find(geom_uid) != uid_object_map.end())
+ return uid_object_map[geom_uid];
+ return NULL;
+}
+
+MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
+ Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
+ MTex *color_texture)
+{
+ const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId();
+ const size_t setindex = ctexture.getSetIndex();
+ std::string uvname = ctexture.getSemantic();
+
+ const CustomData *data = &me->fdata;
+ int layer_index = CustomData_get_layer_index(data, CD_MTFACE);
+ CustomDataLayer *cdl = &data->layers[layer_index+setindex];
+
+ /* set uvname to bind_vertex_input semantic */
+ BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name));
+
+ if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) {
+
+ fprintf(stderr, "Cannot find texture array by texture index.\n");
+ return color_texture;
+ }
+
+ std::vector<MTex*> textures = texindex_texarray_map[texture_index];
+
+ std::vector<MTex*>::iterator it;
+
+ for (it = textures.begin(); it != textures.end(); it++) {
+
+ MTex *texture = *it;
+
+ if (texture) {
+ BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname));
+ if (texture->mapto == MAP_COL) color_texture = texture;
+ }
+ }
+ return color_texture;
+}
+
+MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ Object *ob, const COLLADAFW::UniqueId *geom_uid,
+ MTex **color_texture, char *layername, MTFace *texture_face,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index)
+{
+ Mesh *me = (Mesh*)ob->data;
+ const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
+
+ // do we know this material?
+ if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
+
+ fprintf(stderr, "Cannot find material by UID.\n");
+ return NULL;
+ }
+
+ Material *ma = uid_material_map[ma_uid];
+ assign_material(ob, ma, ob->totcol + 1);
+
+ COLLADAFW::TextureCoordinateBindingArray& tex_array =
+ cmaterial.getTextureCoordinateBindingArray();
+ TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma];
+ unsigned int i;
+ // loop through <bind_vertex_inputs>
+ for (i = 0; i < tex_array.getCount(); i++) {
+
+ *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
+ *color_texture);
+ }
+
+ // set texture face
+ if (*color_texture &&
+ strlen((*color_texture)->uvname) &&
+ strcmp(layername, (*color_texture)->uvname) != 0) {
+
+ texture_face = (MTFace*)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
+ (*color_texture)->uvname);
+ strcpy(layername, (*color_texture)->uvname);
+ }
+
+ MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
+ COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
+
+ // assign material indices to mesh faces
+ if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
+
+ std::vector<Primitive>& prims = mat_prim_map[mat_id];
+
+ std::vector<Primitive>::iterator it;
+
+ for (it = prims.begin(); it != prims.end(); it++) {
+ Primitive& prim = *it;
+ i = 0;
+ while (i++ < prim.totface) {
+ prim.mface->mat_nr = mat_index;
+ prim.mface++;
+ // bind texture images to faces
+ if (texture_face && (*color_texture)) {
+ texture_face->mode = TF_TEX;
+ texture_face->tpage = (Image*)(*color_texture)->tex->ima;
+ texture_face++;
+ }
+ }
+ }
+ }
+
+ return texture_face;
+}
+
+
+Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
+ bool isController,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map)
+{
+ const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
+
+ // check if node instanciates controller or geometry
+ if (isController) {
+
+ geom_uid = armature_importer->get_geometry_uid(*geom_uid);
+
+ if (!geom_uid) {
+ fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
+ return NULL;
+ }
+ }
+ else {
+
+ if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
+ // this could happen if a mesh was not created
+ // (e.g. if it contains unsupported geometry)
+ fprintf(stderr, "Couldn't find a mesh by UID.\n");
+ return NULL;
+ }
+ }
+ if (!uid_mesh_map[*geom_uid]) return NULL;
+
+ Object *ob = add_object(scene, OB_MESH);
+
+ // store object pointer for ArmatureImporter
+ uid_object_map[*geom_uid] = ob;
+
+ // name Object
+ const std::string& id = node->getOriginalId();
+ if (id.length())
+ rename_id(&ob->id, (char*)id.c_str());
+
+ // replace ob->data freeing the old one
+ Mesh *old_mesh = (Mesh*)ob->data;
+
+ set_mesh(ob, uid_mesh_map[*geom_uid]);
+
+ if (old_mesh->id.us == 0) free_libblock(&G.main->mesh, old_mesh);
+
+ char layername[100];
+ MTFace *texture_face = NULL;
+ MTex *color_texture = NULL;
+
+ COLLADAFW::MaterialBindingArray& mat_array =
+ geom->getMaterialBindings();
+
+ // loop through geom's materials
+ for (unsigned int i = 0; i < mat_array.getCount(); i++) {
+
+ texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
+ &color_texture, layername, texture_face,
+ material_texture_mapping_map, i);
+ }
+
+ return ob;
+}
+
+// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
+bool MeshImporter::write_geometry(const COLLADAFW::Geometry* geom)
+{
+ // TODO: import also uvs, normals
+ // XXX what to do with normal indices?
+ // XXX num_normals may be != num verts, then what to do?
+
+ // check geometry->getType() first
+ if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
+ // TODO: report warning
+ fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
+ return true;
+ }
+
+ COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh*)geom;
+
+ if (!is_nice_mesh(mesh)) {
+ fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh));
+ return true;
+ }
+
+ const std::string& str_geom_id = mesh->getOriginalId();
+ Mesh *me = add_mesh((char*)str_geom_id.c_str());
+
+ // store the Mesh pointer to link it later with an Object
+ this->uid_mesh_map[mesh->getUniqueId()] = me;
+
+ int new_tris = 0;
+
+ read_vertices(mesh, me);
+
+ new_tris = count_new_tris(mesh, me);
+
+ read_faces(mesh, me, new_tris);
+
+ make_edges(me, 0);
+
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+ return true;
+}