void ImagesExporter::operator()(Material *ma, Object *ob) { int a; for (a = 0; a < MAX_MTEX; a++) { MTex *mtex = ma->mtex[a]; if (mtex && mtex->tex && mtex->tex->ima) { Image *image = mtex->tex->ima; std::string name(id_name(image)); name = translate_id(name); char rel[FILE_MAX]; char abs[FILE_MAX]; char src[FILE_MAX]; char dir[FILE_MAX]; BLI_split_dirfile(mfilename, dir, NULL); BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.main->name, image->name, dir); if (abs[0] != '\0') { // make absolute source path BLI_strncpy(src, image->name, sizeof(src)); BLI_path_abs(src, G.main->name); // make dest directory if it doesn't exist BLI_make_existing_file(abs); if (BLI_copy_fileops(src, abs) != 0) { fprintf(stderr, "Cannot copy image to file's directory. \n"); } } if (find(mImages.begin(), mImages.end(), name) == mImages.end()) { COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name, name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */ img.add(mSW); mImages.push_back(name); } } } }
std::string get_geometry_id(Object *ob) { return translate_id(id_name(ob->data)) + "-mesh"; }
/** Look at documentation of translate_map */ std::string translate_id(const char *idString) { std::string id = std::string(idString); return translate_id(id); }
std::string ControllerExporter::get_controller_id(Key *key, Object *ob) { return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX; }
// 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 SceneExporter::writeNodes(Object *ob, Scene *sce) { // Add associated armature first if available bool armature_exported = false; Object *ob_arm = bc_get_assigned_armature(ob); if (ob_arm != NULL) { armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm); if (armature_exported && bc_is_marked(ob_arm)) { bc_remove_mark(ob_arm); writeNodes(ob_arm, sce); armature_exported = true; } } COLLADASW::Node colladaNode(mSW); colladaNode.setNodeId(translate_id(id_name(ob))); colladaNode.setNodeName(translate_id(id_name(ob))); colladaNode.setType(COLLADASW::Node::NODE); colladaNode.start(); std::list<Object *> child_objects; // list child objects LinkNode *node; for (node=this->export_settings->export_set; node; node=node->next) { // cob - child object Object *cob = (Object *)node->link; if (cob->parent == ob) { switch (cob->type) { case OB_MESH: case OB_CAMERA: case OB_LAMP: case OB_EMPTY: case OB_ARMATURE: if (bc_is_marked(cob)) child_objects.push_back(cob); break; } } } if (ob->type == OB_MESH && armature_exported) // for skinned mesh we write obmat in <bind_shape_matrix> TransformWriter::add_node_transform_identity(colladaNode); else TransformWriter::add_node_transform_ob(colladaNode, ob); // <instance_geometry> if (ob->type == OB_MESH) { bool instance_controller_created = false; if (armature_exported) { instance_controller_created = arm_exporter->add_instance_controller(ob); } if (!instance_controller_created) { COLLADASW::InstanceGeometry instGeom(mSW); instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation))); InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only); instGeom.add(); } } // <instance_controller> else if (ob->type == OB_ARMATURE) { arm_exporter->add_armature_bones(ob, sce, this, child_objects); } // <instance_camera> else if (ob->type == OB_CAMERA) { COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob))); instCam.add(); } // <instance_light> else if (ob->type == OB_LAMP) { COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob))); instLa.add(); } // empty object else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) { GroupObject *go = NULL; Group *gr = ob->dup_group; /* printf("group detected '%s'\n", gr->id.name+2); */ for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) { printf("\t%s\n", go->ob->id.name); } } } if (ob->type == OB_ARMATURE) { colladaNode.end(); } for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) { if (bc_is_marked(*i)) { bc_remove_mark(*i); writeNodes(*i, sce); } } if (ob->type != OB_ARMATURE) { colladaNode.end(); } }
std::string get_material_id(Material *mat) { return translate_id(id_name(mat)) + "-material"; }
std::string get_joint_id(Bone *bone, Object *ob_arm) { return translate_id(/*id_name(ob_arm) + "_" +*/ bone->name); }
void DocumentExporter::exportCurrentScene(Scene *sce) { PointerRNA sceneptr, unit_settings; PropertyRNA *system; /* unused , *scale; */ clear_global_id_map(); COLLADABU::NativeString native_filename = COLLADABU::NativeString(std::string(this->export_settings->filepath), COLLADABU::NativeString::ENCODING_UTF8); COLLADASW::StreamWriter sw(native_filename); fprintf(stdout, "Collada export: %s\n", this->export_settings->filepath); // open <collada> sw.startDocument(); // <asset> COLLADASW::Asset asset(&sw); RNA_id_pointer_create(&(sce->id), &sceneptr); unit_settings = RNA_pointer_get(&sceneptr, "unit_settings"); system = RNA_struct_find_property(&unit_settings, "system"); //scale = RNA_struct_find_property(&unit_settings, "scale_length"); std::string unitname = "meter"; float linearmeasure = RNA_float_get(&unit_settings, "scale_length"); switch (RNA_property_enum_get(&unit_settings, system)) { case USER_UNIT_NONE: case USER_UNIT_METRIC: if (linearmeasure == 0.001f) { unitname = "millimeter"; } else if (linearmeasure == 0.01f) { unitname = "centimeter"; } else if (linearmeasure == 0.1f) { unitname = "decimeter"; } else if (linearmeasure == 1.0f) { unitname = "meter"; } else if (linearmeasure == 1000.0f) { unitname = "kilometer"; } break; case USER_UNIT_IMPERIAL: if (linearmeasure == 0.0254f) { unitname = "inch"; } else if (linearmeasure == 0.3048f) { unitname = "foot"; } else if (linearmeasure == 0.9144f) { unitname = "yard"; } break; default: break; } asset.setUnit(unitname, linearmeasure); asset.setUpAxisType(COLLADASW::Asset::Z_UP); if (U.author[0] != '\0') { asset.getContributor().mAuthor = U.author; } else { asset.getContributor().mAuthor = "Blender User"; } char version_buf[128]; #ifdef WITH_BUILDINFO sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION, build_rev); #else sprintf(version_buf, "Blender %d.%02d.%d", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION); #endif asset.getContributor().mAuthoringTool = version_buf; asset.add(); LinkNode *export_set = this->export_settings->export_set; // <library_cameras> if (bc_has_object_type(export_set, OB_CAMERA)) { CamerasExporter ce(&sw, this->export_settings); ce.exportCameras(sce); } // <library_lights> if (bc_has_object_type(export_set, OB_LAMP)) { LightsExporter le(&sw, this->export_settings); le.exportLights(sce); } // <library_images> ImagesExporter ie(&sw, this->export_settings); ie.exportImages(sce); // <library_effects> EffectsExporter ee(&sw, this->export_settings); ee.exportEffects(sce); // <library_materials> MaterialsExporter me(&sw, this->export_settings); me.exportMaterials(sce); // <library_geometries> if (bc_has_object_type(export_set, OB_MESH)) { GeometryExporter ge(&sw, this->export_settings); ge.exportGeom(sce); } // <library_animations> AnimationExporter ae(&sw, this->export_settings); ae.exportAnimations(sce); // <library_controllers> ArmatureExporter arm_exporter(&sw, this->export_settings); if (bc_has_object_type(export_set, OB_ARMATURE)) { arm_exporter.export_controllers(sce); } // <library_visual_scenes> SceneExporter se(&sw, &arm_exporter, this->export_settings); se.exportScene(sce); // <scene> std::string scene_name(translate_id(id_name(sce))); COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, scene_name)); scene.add(); // close <Collada> sw.endDocument(); }
void SceneExporter::writeNodes(Object *ob, Scene *sce) { // Add associated armature first if available bool armature_exported = false; Object *ob_arm = bc_get_assigned_armature(ob); if (ob_arm != NULL) { armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm); if (armature_exported && bc_is_marked(ob_arm)) { bc_remove_mark(ob_arm); writeNodes(ob_arm, sce); armature_exported = true; } } COLLADASW::Node colladaNode(mSW); colladaNode.setNodeId(translate_id(id_name(ob))); colladaNode.setNodeName(translate_id(id_name(ob))); colladaNode.setType(COLLADASW::Node::NODE); colladaNode.start(); std::list<Object *> child_objects; // list child objects LinkNode *node; for (node=this->export_settings->export_set; node; node=node->next) { // cob - child object Object *cob = (Object *)node->link; if (cob->parent == ob) { switch (cob->type) { case OB_MESH: case OB_CAMERA: case OB_LAMP: case OB_EMPTY: case OB_ARMATURE: if (bc_is_marked(cob)) child_objects.push_back(cob); break; } } } if (ob->type == OB_MESH && armature_exported) // for skinned mesh we write obmat in <bind_shape_matrix> TransformWriter::add_node_transform_identity(colladaNode); else { TransformWriter::add_node_transform_ob(colladaNode, ob, this->transformation_type); } // <instance_geometry> if (ob->type == OB_MESH) { bool instance_controller_created = false; if (armature_exported) { instance_controller_created = arm_exporter->add_instance_controller(ob); } if (!instance_controller_created) { COLLADASW::InstanceGeometry instGeom(mSW); instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation))); instGeom.setName(translate_id(id_name(ob))); InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only); instGeom.add(); } } // <instance_controller> else if (ob->type == OB_ARMATURE) { arm_exporter->add_armature_bones(ob, sce, this, child_objects); } // <instance_camera> else if (ob->type == OB_CAMERA) { COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob))); instCam.add(); } // <instance_light> else if (ob->type == OB_LAMP) { COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob))); instLa.add(); } // empty object else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) { GroupObject *go = NULL; Group *gr = ob->dup_group; /* printf("group detected '%s'\n", gr->id.name + 2); */ for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) { printf("\t%s\n", go->ob->id.name); } } } if (ob->type == OB_ARMATURE) { colladaNode.end(); } if (BLI_listbase_is_empty(&ob->constraints) == false) { bConstraint *con = (bConstraint *) ob->constraints.first; while (con) { std::string con_name(translate_id(con->name)); std::string con_tag = con_name + "_constraint"; printf("%s\n", con_name.c_str()); printf("%s\n\n", con_tag.c_str()); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"type",con->type); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"enforce",con->enforce); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"flag",con->flag); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"headtail",con->headtail); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"own_space",con->ownspace); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error); //not ideal: add the target object name as another parameter. //No real mapping in the .dae //Need support for multiple target objects also. const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { bConstraintTarget *ct; Object *obtar; cti->get_constraint_targets(con, &targets); for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { obtar = ct->tar; std::string tar_id((obtar) ? id_name(obtar) : ""); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"target_id",tar_id); } if (cti->flush_constraint_targets) cti->flush_constraint_targets(con, &targets, 1); } con = con->next; } } for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) { if (bc_is_marked(*i)) { bc_remove_mark(*i); writeNodes(*i, sce); } } if (ob->type != OB_ARMATURE) colladaNode.end(); }
// parent_mat is armature-space void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, SceneExporter *se, std::vector<Object *> &child_objects) { if (can_export(bone)) { std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name); std::string node_name = std::string(bone->name); std::string node_sid = get_joint_sid(bone); COLLADASW::Node node(mSW); node.setType(COLLADASW::Node::JOINT); node.setNodeId(node_id); node.setNodeName(node_name); node.setNodeSid(node_sid); if (this->export_settings.get_use_blender_profile()) { if (!is_export_root(bone)) { if (bone->flag & BONE_CONNECTED) { node.addExtraTechniqueParameter("blender", "connect", true); } } std::string layers = BoneExtended::get_bone_layers(bone->layer); node.addExtraTechniqueParameter("blender", "layer", layers); bArmature *armature = (bArmature *)ob_arm->data; EditBone *ebone = bc_get_edit_bone(armature, bone->name); if (ebone && ebone->roll != 0) { node.addExtraTechniqueParameter("blender", "roll", ebone->roll); } if (bc_is_leaf_bone(bone)) { Vector head, tail; const BCMatrix &global_transform = this->export_settings.get_global_transform(); if (this->export_settings.get_apply_global_orientation()) { bc_add_global_transform(head, bone->arm_head, global_transform); bc_add_global_transform(tail, bone->arm_tail, global_transform); } else { copy_v3_v3(head, bone->arm_head); copy_v3_v3(tail, bone->arm_tail); } node.addExtraTechniqueParameter("blender", "tip_x", tail[0] - head[0]); node.addExtraTechniqueParameter("blender", "tip_y", tail[1] - head[1]); node.addExtraTechniqueParameter("blender", "tip_z", tail[2] - head[2]); } } node.start(); add_bone_transform(ob_arm, bone, node); // Write nodes of childobjects, remove written objects from list std::vector<Object *>::iterator iter = child_objects.begin(); while (iter != child_objects.end()) { Object *ob = *iter; if (ob->partype == PARBONE && STREQ(ob->parsubstr, bone->name)) { float backup_parinv[4][4]; copy_m4_m4(backup_parinv, ob->parentinv); // crude, temporary change to parentinv // so transform gets exported correctly. // Add bone tail- translation... don't know why // bone parenting is against the tail of a bone // and not it's head, seems arbitrary. ob->parentinv[3][1] += bone->length; // OPEN_SIM_COMPATIBILITY // TODO: when such objects are animated as // single matrix the tweak must be applied // to the result. if (export_settings.get_open_sim()) { // tweak objects parentinverse to match compatibility float temp[4][4]; copy_m4_m4(temp, bone->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; mul_m4_m4m4(ob->parentinv, temp, ob->parentinv); } se->writeNode(ob); copy_m4_m4(ob->parentinv, backup_parinv); iter = child_objects.erase(iter); } else iter++; } for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { add_bone_node(child, ob_arm, se, child_objects); } node.end(); } else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { add_bone_node(child, ob_arm, se, child_objects); } } }
std::string AnimationExporter::getAnimationPathId(const FCurve *fcu) { std::string rna_path = std::string(fcu->rna_path); return translate_id(rna_path); }
void ImagesExporter::export_UV_Image(Image *image, bool use_copies) { std::string name(id_name(image)); std::string translated_name(translate_id(name)); bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_name) == mImages.end(); if (not_yet_exported) { ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL); if (!imbuf) { fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name); return; } bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0; ImageFormatData imageFormat; BKE_imbuf_to_image_format(&imageFormat, imbuf); short image_source = image->source; bool is_generated = image_source == IMA_SRC_GENERATED; bool is_packed = image->packedfile != NULL; char export_path[FILE_MAX]; char source_path[FILE_MAX]; char export_dir[FILE_MAX]; char export_file[FILE_MAX]; // Destination folder for exported assets BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir)); if (is_generated || is_dirty || use_copies || is_packed) { // make absolute destination path BLI_strncpy(export_file, name.c_str(), sizeof(export_file)); BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat); BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file); // make dest directory if it doesn't exist BLI_make_existing_file(export_path); } if (is_generated || is_dirty || is_packed) { // This image in its current state only exists in Blender memory. // So we have to export it. The export will keep the image state intact, // so the exported file will not be associated with the image. if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) { fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path); return; } BLI_strncpy(export_path, export_file, sizeof(export_path)); } else { // make absolute source path BLI_strncpy(source_path, image->name, sizeof(source_path)); BLI_path_abs(source_path, G.main->name); BLI_cleanup_path(NULL, source_path); if (use_copies) { // This image is already located on the file system. // But we want to create copies here. // To move images into the same export directory. // Note: If an image is already located in the export folder, // then skip the copy (as it would result in a file copy error). if (BLI_path_cmp(source_path, export_path) != 0) { if (BLI_copy(source_path, export_path) != 0) { fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path); return; } } BLI_strncpy(export_path, export_file, sizeof(export_path)); } else { // Do not make any copies, but use the source path directly as reference // to the original image BLI_strncpy(export_path, source_path, sizeof(export_path)); } } COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */ img.add(mSW); fprintf(stdout, "Collada export: Added image: %s\n", export_file); mImages.push_back(translated_name); BKE_image_release_ibuf(image, imbuf, NULL); } }
void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type) { bool all_uv_layers = !active_uv_only; COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList(); if (export_texture_type == BC_TEXTURE_TYPE_UV) { std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers); std::set<Image *>::iterator uv_images_iter; for (uv_images_iter = uv_images.begin(); uv_images_iter != uv_images.end(); uv_images_iter++) { Image *ima = *uv_images_iter; std::string matid(id_name(ima)); matid = get_material_id_from_id(matid); std::ostringstream ostr; ostr << matid; COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid)); // create <bind_vertex_input> for each uv map Mesh *me = (Mesh *)ob->data; int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE); int map_index = 0; int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1; for (int b = 0; b < totlayer; b++) { if (!active_uv_only || b == active_uv_index) { char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b); im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++)); } } iml.push_back(im); } } else { for (int a = 0; a < ob->totcol; a++) { Material *ma = give_current_material(ob, a + 1); if (ma) { std::string matid(get_material_id(ma)); matid = translate_id(matid); std::ostringstream ostr; ostr << matid; COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid)); // create <bind_vertex_input> for each uv map Mesh *me = (Mesh *)ob->data; int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE); int map_index = 0; int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1; for (int b = 0; b < totlayer; b++) { if (!active_uv_only || b == active_uv_index) { char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b); im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++)); } } iml.push_back(im); } } } }
std::string get_geometry_id(Object *ob, bool use_instantiation) { std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob); return translate_id(geom_name) + "-mesh"; }
std::string get_light_id(Object *ob) { return translate_id(id_name(ob)) + "-light"; }
// 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(); }
std::string get_camera_id(Object *ob) { return translate_id(id_name(ob)) + "-camera"; }
//convert f-curves to animation curves and write void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma) { const char *axis_name = NULL; char anim_id[200]; bool has_tangents = false; bool quatRotation = false; if (!strcmp(transformName, "rotation_quaternion") ) { fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n"); quatRotation = true; return; } //axis names for colors else if (!strcmp(transformName, "color") || !strcmp(transformName, "specular_color") || !strcmp(transformName, "diffuse_color") || (!strcmp(transformName, "alpha"))) { const char *axis_names[] = {"R", "G", "B"}; if (fcu->array_index < 3) axis_name = axis_names[fcu->array_index]; } //axis names for transforms else if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) || (!strcmp(transformName, "rotation_euler")) || (!strcmp(transformName, "rotation_quaternion"))) { const char *axis_names[] = {"X", "Y", "Z"}; if (fcu->array_index < 3) axis_name = axis_names[fcu->array_index]; } else { /* no axis name. single parameter */ axis_name = ""; } std::string ob_name = std::string("null"); //Create anim Id if (ob->type == OB_ARMATURE) { ob_name = getObjectBoneName(ob, fcu); BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s.%s", (char *)translate_id(ob_name).c_str(), transformName, axis_name); } else { if (ma) ob_name = id_name(ob) + "_material"; else ob_name = id_name(ob); BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), fcu->rna_path, axis_name); } openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); // create input source std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name); // create output source std::string output_id; //quat rotations are skipped for now, because of complications with determining axis. if (quatRotation) { float *eul = get_eul_source_for_quat(ob); float *eul_axis = (float *)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values"); for (int i = 0; i < fcu->totvert; i++) { eul_axis[i] = eul[i * 3 + fcu->array_index]; } output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name); MEM_freeN(eul); MEM_freeN(eul_axis); } else { output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name); } // create interpolations source std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents); // handle tangents (if required) std::string intangent_id; std::string outtangent_id; if (has_tangents) { // create in_tangent source intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name); // create out_tangent source outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name); } std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); std::string empty; sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); // this input is required sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); if (has_tangents) { sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id)); sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id)); } addSampler(sampler); std::string target; if (!is_param) target = translate_id(ob_name) + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true); else { if (ob->type == OB_LAMP) target = get_light_id(ob) + "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true); if (ob->type == OB_CAMERA) target = get_camera_id(ob) + "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true); if (ma) target = translate_id(id_name(ma)) + "-effect" + "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true); } addChannel(COLLADABU::URI(empty, sampler_id), target); closeAnimation(); }
std::string get_morph_id(Object *ob) { return translate_id(id_name(ob)) + "-morph"; }
void EffectsExporter::operator()(Material *ma, Object *ob) { // create a list of indices to textures of type TEX_IMAGE std::vector<int> tex_indices; if (this->export_settings->include_material_textures) createTextureIndices(ma, tex_indices); openEffect(translate_id(id_name(ma)) + "-effect"); COLLADASW::EffectProfile ep(mSW); ep.setProfileType(COLLADASW::EffectProfile::COMMON); ep.openProfile(); // set shader type - one of three blinn, phong or lambert if (ma->spec > 0.0f) { if (ma->spec_shader == MA_SPEC_BLINN) { writeBlinn(ep, ma); } else { // \todo figure out handling of all spec+diff shader combos blender has, for now write phong // for now set phong in case spec shader is not blinn writePhong(ep, ma); } } else { if (ma->diff_shader == MA_DIFF_LAMBERT) { writeLambert(ep, ma); } else { // \todo figure out handling of all spec+diff shader combos blender has, for now write phong writePhong(ep, ma); } } // index of refraction if (ma->mode & MA_RAYTRANSP) { ep.setIndexOfRefraction(ma->ang, false, "index_of_refraction"); } else { ep.setIndexOfRefraction(1.0f, false, "index_of_refraction"); } COLLADASW::ColorOrTexture cot; // transparency if (ma->mode & MA_TRANSP) { // Tod: because we are in A_ONE mode transparency is calculated like this: ep.setTransparency(ma->alpha, false, "transparency"); // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f); // ep.setTransparent(cot); } // emission cot = getcol(ma->emit, ma->emit, ma->emit, 1.0f); ep.setEmission(cot, false, "emission"); // diffuse multiplied by diffuse intensity cot = getcol(ma->r * ma->ref, ma->g * ma->ref, ma->b * ma->ref, 1.0f); ep.setDiffuse(cot, false, "diffuse"); // ambient /* ma->ambX is calculated only on render, so lets do it here manually and not rely on ma->ambX. */ if (this->scene->world) cot = getcol(this->scene->world->ambr * ma->amb, this->scene->world->ambg * ma->amb, this->scene->world->ambb * ma->amb, 1.0f); else cot = getcol(ma->amb, ma->amb, ma->amb, 1.0f); ep.setAmbient(cot, false, "ambient"); // reflective, reflectivity if (ma->mode & MA_RAYMIRROR) { cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f); ep.setReflective(cot); ep.setReflectivity(ma->ray_mirror); } // else { // cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); // ep.setReflective(cot); // ep.setReflectivity(ma->spec); // } // specular if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) { cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f); ep.setSpecular(cot, false, "specular"); } // XXX make this more readable if possible // create <sampler> and <surface> for each image COLLADASW::Sampler samplers[MAX_MTEX]; //COLLADASW::Surface surfaces[MAX_MTEX]; //void *samp_surf[MAX_MTEX][2]; void *samp_surf[MAX_MTEX][1]; // image to index to samp_surf map // samp_surf[index] stores 2 pointers, sampler and surface std::map<std::string, int> im_samp_map; unsigned int a, b; for (a = 0, b = 0; a < tex_indices.size(); a++) { MTex *t = ma->mtex[tex_indices[a]]; Image *ima = t->tex->ima; // Image not set for texture if (!ima) continue; std::string key(id_name(ima)); key = translate_id(key); // create only one <sampler>/<surface> pair for each unique image if (im_samp_map.find(key) == im_samp_map.end()) { // //<newparam> <surface> <init_from> // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D, // key + COLLADASW::Surface::SURFACE_SID_SUFFIX); // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM); // sio.setImageReference(key); // surface.setInitOption(sio); // COLLADASW::NewParamSurface surface(mSW); // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D); //<newparam> <sampler> <source> COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); sampler.setImageId(key); // copy values to arrays since they will live longer samplers[a] = sampler; //surfaces[a] = surface; // store pointers so they can be used later when we create <texture>s samp_surf[b][0] = &samplers[a]; //samp_surf[b][1] = &surfaces[a]; im_samp_map[key] = b; b++; } } std::set<Image *> uv_textures; if (ob->type == OB_MESH && ob->totcol && this->export_settings->include_uv_textures) { bool active_uv_only = this->export_settings->active_uv_only; Mesh *me = (Mesh *) ob->data; int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY); BKE_mesh_tessface_ensure(me); for (int i = 0; i < me->pdata.totlayer; i++) { if (!active_uv_only || active_uv_layer == i) { if (me->pdata.layers[i].type == CD_MTEXPOLY) { MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; MFace *mface = me->mface; for (int j = 0; j < me->totpoly; j++, mface++, txface++) { Material *mat = give_current_material(ob, mface->mat_nr + 1); if (mat != ma) continue; Image *ima = txface->tpage; if (ima == NULL) continue; bool not_in_list = uv_textures.find(ima)==uv_textures.end(); if (not_in_list) { std::string name = id_name(ima); std::string key(name); key = translate_id(key); // create only one <sampler>/<surface> pair for each unique image if (im_samp_map.find(key) == im_samp_map.end()) { //<newparam> <sampler> <source> COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); sampler.setImageId(key); samplers[a] = sampler; samp_surf[b][0] = &samplers[a]; im_samp_map[key] = b; b++; a++; uv_textures.insert(ima); } } } } } } } // used as fallback when MTex->uvname is "" (this is pretty common) // it is indeed the correct value to use in that case std::string active_uv(getActiveUVLayerName(ob)); // write textures // XXX very slow for (a = 0; a < tex_indices.size(); a++) { MTex *t = ma->mtex[tex_indices[a]]; Image *ima = t->tex->ima; std::string key(id_name(ima)); key = translate_id(key); int i = im_samp_map[key]; std::string uvname = strlen(t->uvname) ? t->uvname : active_uv; COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i][0]; writeTextures(ep, key, sampler, t, ima, uvname); } std::set<Image *>::iterator uv_t_iter; for (uv_t_iter = uv_textures.begin(); uv_t_iter != uv_textures.end(); uv_t_iter++ ) { Image *ima = *uv_t_iter; std::string key(id_name(ima)); key = translate_id(key); int i = im_samp_map[key]; COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i][0]; ep.setDiffuse(createTexture(ima, active_uv, sampler), false, "diffuse"); } // performs the actual writing ep.addProfileElements(); bool twoSided = false; if (ob->type == OB_MESH && ob->data) { Mesh *me = (Mesh *)ob->data; if (me->flag & ME_TWOSIDED) twoSided = true; } if (twoSided) ep.addExtraTechniqueParameter("GOOGLEEARTH", "double_sided", 1); ep.addExtraTechniques(mSW); ep.closeProfile(); if (twoSided) mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>"); closeEffect(); }
std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob) { return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX; }
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(); }