From 10004d4a421b03f0cdf666b72b4cbadc216030e1 Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Sun, 12 Aug 2012 17:13:07 +0000 Subject: fixed: [#32240] Collada import when nodes share geometry but not material --- source/blender/collada/DocumentImporter.cpp | 4 + source/blender/collada/EffectExporter.cpp | 18 +-- source/blender/collada/GeometryExporter.cpp | 7 +- source/blender/collada/InstanceWriter.cpp | 10 +- source/blender/collada/MaterialExporter.h | 11 +- source/blender/collada/MeshImporter.cpp | 185 ++++++++++++++++++++++++---- source/blender/collada/MeshImporter.h | 19 +-- source/blender/collada/collada_utils.cpp | 5 + source/blender/collada/collada_utils.h | 1 + 9 files changed, 204 insertions(+), 56 deletions(-) diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 7cfce9d2526..60b03a211ba 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -208,6 +208,10 @@ void DocumentImporter::finish() write_node(roots[i], NULL, sce, NULL, false); } } + + + mesh_importer.optimize_material_assignements(); + armature_importer.set_tags_map(this->uid_tags_map); armature_importer.make_armatures(mContext); diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 1eee797b51c..2d9ccc3e3ef 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -35,17 +35,19 @@ #include "DocumentExporter.h" #include "MaterialExporter.h" -#include "DNA_mesh_types.h" -#include "DNA_texture_types.h" -#include "DNA_world_types.h" - -#include "BKE_customdata.h" -#include "BKE_mesh.h" -#include "BKE_material.h" - #include "collada_internal.h" #include "collada_utils.h" +extern "C" { + #include "DNA_mesh_types.h" + #include "DNA_texture_types.h" + #include "DNA_world_types.h" + + #include "BKE_customdata.h" + #include "BKE_mesh.h" + #include "BKE_material.h" +} + // OB_MESH is assumed static std::string getActiveUVLayerName(Object *ob) { diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index d30f9b86a5a..29ffcf53ee9 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -42,12 +42,11 @@ extern "C" { #include "BKE_main.h" #include "BKE_global.h" #include "BKE_library.h" + #include "BKE_customdata.h" + #include "BKE_material.h" + #include "BKE_mesh.h" } - -#include "BKE_customdata.h" -#include "BKE_material.h" -#include "BKE_mesh.h" #include "collada_internal.h" #include "collada_utils.h" diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp index 5908037d782..be45d5295e5 100644 --- a/source/blender/collada/InstanceWriter.cpp +++ b/source/blender/collada/InstanceWriter.cpp @@ -31,13 +31,13 @@ #include "COLLADASWInstanceMaterial.h" -#include "BKE_customdata.h" -#include "BKE_material.h" - -#include "DNA_mesh_types.h" +extern "C" { + #include "BKE_customdata.h" + #include "BKE_material.h" + #include "DNA_mesh_types.h" +} #include "InstanceWriter.h" - #include "collada_internal.h" #include "collada_utils.h" diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h index f65c8849c84..09d10846b53 100644 --- a/source/blender/collada/MaterialExporter.h +++ b/source/blender/collada/MaterialExporter.h @@ -34,11 +34,12 @@ #include "COLLADASWLibraryMaterials.h" #include "COLLADASWStreamWriter.h" -#include "BKE_material.h" - -#include "DNA_material_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" +extern "C" { + #include "BKE_material.h" + #include "DNA_material_types.h" + #include "DNA_object_types.h" + #include "DNA_scene_types.h" +} #include "GeometryExporter.h" #include "collada_internal.h" diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 8ee30f691ee..5593fe993f4 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -39,22 +39,22 @@ #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 "BLI_edgehash.h" - -#include "MEM_guardedalloc.h" + #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 "BLI_edgehash.h" + + #include "MEM_guardedalloc.h" } #include "ArmatureImporter.h" @@ -988,6 +988,139 @@ MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBindi return color_texture; } +/** + * this function checks if both objects have the same + * materials assigned to Object (in the same order) + * returns true if condition matches, otherwise false; + **/ +static bool bc_has_same_material_configuration(Object *ob1, Object *ob2) +{ + if (ob1->totcol != ob2->totcol) return false; // not same number of materials + if (ob1->totcol == 0) return false; // no material at all + + for(int index=0; index < ob1->totcol; index++) { + if (ob1->matbits[index] != ob2->matbits[index]) return false; // shouldn't happen + if (ob1->matbits[index] == 0) return false; // shouldn't happen + if (ob1->mat[index] != ob2->mat[index]) return false; // different material assignment + } + return true; +} + + +/** + * + * Caution here: This code assumes tha all materials are assigned to Object + * and no material is assigned to Data. + * That is true right after the objects have been imported. + * + **/ +static void bc_copy_materials_to_data(Object *ob, Mesh *me) +{ + for (int index = 0; index < ob->totcol; index++) { + ob->matbits[index] = 0; + me->mat[index] = ob->mat[index]; + } +} + +/** + * + * Remove all references to materials from the object + * + **/ +static void bc_remove_materials_from_object(Object *ob, Mesh *me) +{ + for (int index = 0; index < ob->totcol; index++) { + ob->matbits[index] = 0; + ob->mat[index] = NULL; + } +} + +/** + * Returns the list of Users of the given Mesh object. + * Note: This function uses the object user flag to control + * which objects have already been processed. + **/ +std::vector MeshImporter::get_all_users_of(Mesh *reference_mesh) +{ + std::vector mesh_users; + for (std::vector::iterator it = imported_objects.begin(); + it != imported_objects.end(); ++it) + { + Object *ob = (*it); + if (bc_is_marked(ob)) { + bc_remove_mark(ob); + Mesh *me = (Mesh *) ob->data; + if (me == reference_mesh) + mesh_users.push_back(ob); + } + } + return mesh_users; +} + +/** + * + * During import all materials have been assigned to Object. + * Now we iterate over the imported objects and optimize + * the assignements as follows: + * + * for each imported geometry: + * if number of users is 1: + * get the user (object) + * move the materials from Object to Data + * else: + * determine which materials are assigned to the first user + * check if all other users have the same materials in the same order + * if the check is positive: + * Add the materials of the first user to the geometry + * adjust all other users accordingly. + * + **/ +void MeshImporter::optimize_material_assignements() +{ + for (std::vector::iterator it = imported_objects.begin(); + it != imported_objects.end(); ++it) + { + Object *ob = (*it); + Mesh *me = (Mesh *) ob->data; + if (me->id.us==1) { + bc_copy_materials_to_data(ob,me); + bc_remove_materials_from_object(ob,me); + bc_remove_mark(ob); + } + else if (me->id.us > 1) + { + bool can_move = true; + std::vector mesh_users = get_all_users_of(me); + if (mesh_users.size() > 1) + { + Object *ref_ob = mesh_users[0]; + for (int index = 1; index < mesh_users.size(); index++) { + if (!bc_has_same_material_configuration(ref_ob, mesh_users[index])) { + can_move = false; + break; + } + } + if (can_move) { + bc_copy_materials_to_data(ref_ob,me); + for (int index = 0; index < mesh_users.size(); index++) { + Object *object = mesh_users[index]; + bc_remove_materials_from_object(object,me); + bc_remove_mark(object); + } + } + } + } + } +} + +/** + * We do not know in advance which objects will share geometries. + * And we do not know either if the objects which share geometries + * come along with different materials. So we first create the objects + * and assign the materials to Object, then in a later cleanup we decide + * which materials shall be moved to the created geometries. Also see + * optimize_material_assignements() above. + */ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, std::map& uid_material_map, Object *ob, const COLLADAFW::UniqueId *geom_uid, @@ -1003,21 +1136,16 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri fprintf(stderr, "Cannot find material by UID.\n"); return NULL; } - - // different nodes can point to same geometry, but still also specify the same materials - // again. Make sure we don't overwrite them on the next occurrences, so keep list of - // what we already have handled. - std::multimap::iterator it; - it = materials_mapped_to_geom.find(*geom_uid); - while (it != materials_mapped_to_geom.end()) { - if (it->second == ma_uid && it->first == *geom_uid) return NULL; // do nothing if already found - it++; - } + // first time we get geom_uid, ma_uid pair. Save for later check. materials_mapped_to_geom.insert(std::pair(*geom_uid, ma_uid)); Material *ma = uid_material_map[ma_uid]; - assign_material(ob, ma, ob->totcol + 1); + + // Attention! This temporaly assigns material to object on purpose! + // See note above. + ob->actcol=0; + assign_material(ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT); COLLADAFW::TextureCoordinateBindingArray& tex_array = cmaterial.getTextureCoordinateBindingArray(); @@ -1101,9 +1229,12 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta // add object Object *ob = bc_add_object(scene, OB_MESH, name); + bc_set_mark(ob); // used later for material assignement optimization + // store object pointer for ArmatureImporter uid_object_map[*geom_uid] = ob; + imported_objects.push_back(ob); // replace ob->data freeing the old one Mesh *old_mesh = (Mesh *)ob->data; diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h index e4c1aca395a..2cac26d5329 100644 --- a/source/blender/collada/MeshImporter.h +++ b/source/blender/collada/MeshImporter.h @@ -40,6 +40,11 @@ #include "COLLADAFWTypes.h" #include "COLLADAFWUniqueId.h" +#include "ArmatureImporter.h" +#include "collada_utils.h" + +extern "C" { +#include "BLI_edgehash.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -47,11 +52,6 @@ #include "DNA_scene_types.h" #include "DNA_texture_types.h" -#include "ArmatureImporter.h" -#include "collada_utils.h" - -extern "C" { -#include "BLI_edgehash.h" } // only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid @@ -85,6 +85,7 @@ private: std::map uid_mesh_map; // geometry unique id-to-mesh map std::map uid_object_map; // geom uid-to-object + std::vector imported_objects; // list of imported objects // this structure is used to assign material indices to faces // it holds a portion of Mesh faces and corresponds to a DAE primitive list (, , etc.) struct Primitive { @@ -140,7 +141,9 @@ private: void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride); bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count); - + + std::vector get_all_users_of(Mesh *reference_mesh); + public: MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce); @@ -152,7 +155,9 @@ public: MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture, Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, MTex *color_texture); - + + void optimize_material_assignements(); + MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, std::map& uid_material_map, Object *ob, const COLLADAFW::UniqueId *geom_uid, diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 955d699d96c..018d66c6f55 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -230,6 +230,11 @@ void bc_remove_mark(Object *ob) ob->id.flag &= ~LIB_DOIT; } +void bc_set_mark(Object *ob) +{ + ob->id.flag |= LIB_DOIT; +} + // Use bubble sort algorithm for sorting the export set void bc_bubble_sort_by_Object_name(LinkNode *export_set) { diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 5f72581f584..b52115722fe 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -67,6 +67,7 @@ extern bool bc_has_object_type(LinkNode *export_set, short obtype); extern int bc_is_marked(Object *ob); extern void bc_remove_mark(Object *ob); +extern void bc_set_mark(Object *ob); extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int n); extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type); -- cgit v1.2.3