diff options
Diffstat (limited to 'source/blender/collada')
55 files changed, 4778 insertions, 3472 deletions
diff --git a/source/blender/collada/AnimationClipExporter.cpp b/source/blender/collada/AnimationClipExporter.cpp new file mode 100644 index 00000000000..a2c4b388b7e --- /dev/null +++ b/source/blender/collada/AnimationClipExporter.cpp @@ -0,0 +1,55 @@ +/* +* ***** 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, Jan Diederich, Tod Liverseed. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "GeometryExporter.h" +#include "AnimationClipExporter.h" +#include "MaterialExporter.h" + +void AnimationClipExporter::exportAnimationClips(Scene *sce) +{ + openLibrary(); + std::map<std::string, COLLADASW::ColladaAnimationClip *> clips; + + std::vector<std::vector<std::string>>::iterator anim_meta_entry; + for (anim_meta_entry = anim_meta.begin(); anim_meta_entry != anim_meta.end(); ++anim_meta_entry) { + std::vector<std::string> entry = *anim_meta_entry; + std::string action_id = entry[0]; + std::string action_name = entry[1]; + + std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator it = clips.find(action_name); + if (it == clips.end()) + { + COLLADASW::ColladaAnimationClip *clip = new COLLADASW::ColladaAnimationClip(action_name); + clips[action_name] = clip; + } + COLLADASW::ColladaAnimationClip *clip = clips[action_name]; + clip->setInstancedAnimation(action_id); + } + + std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator clips_it; + for (clips_it = clips.begin(); clips_it != clips.end(); clips_it++) { + COLLADASW::ColladaAnimationClip *clip = (COLLADASW::ColladaAnimationClip *)clips_it->second; + addAnimationClip(*clip); + } + + closeLibrary(); +} diff --git a/source/blender/collada/AnimationClipExporter.h b/source/blender/collada/AnimationClipExporter.h new file mode 100644 index 00000000000..8a9394ce88a --- /dev/null +++ b/source/blender/collada/AnimationClipExporter.h @@ -0,0 +1,50 @@ +/* + * ***** 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, Jan Diederich, Tod Liverseed. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "COLLADASWLibraryAnimationClips.h" + + +class AnimationClipExporter:COLLADASW::LibraryAnimationClips { +private: + Depsgraph *depsgraph; + Scene *scene; + COLLADASW::StreamWriter *sw; + const ExportSettings *export_settings; + std::vector<std::vector<std::string>> anim_meta; + +public: + + AnimationClipExporter(Depsgraph *depsgraph , COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, std::vector<std::vector<std::string>> anim_meta) : + COLLADASW::LibraryAnimationClips(sw), + depsgraph(depsgraph), + scene(nullptr), + sw(sw), + export_settings(export_settings), + anim_meta(anim_meta) + {} + + void exportAnimationClips(Scene *sce); +}; diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index e5c54fd9917..69a25ac7a82 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -20,658 +20,344 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file AnimationExporter.cpp + * \ingroup collada + */ + #include "GeometryExporter.h" #include "AnimationExporter.h" +#include "AnimationClipExporter.h" +#include "BCAnimationSampler.h" #include "MaterialExporter.h" +#include "collada_utils.h" -template<class Functor> -void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set) -{ - LinkNode *node; - for (node = export_set; node; node = node->next) { - Object *ob = (Object *)node->link; - f(ob); - } -} +std::string EMPTY_STRING; -bool AnimationExporter::exportAnimations(Main *bmain, Scene *sce) +std::string AnimationExporter::get_axis_name(std::string channel, int id) { - bool has_animations = hasAnimations(sce); - m_bmain = bmain; - if (has_animations) { - this->scene = sce; + static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = { + { "color" ,{ "R", "G", "B" } }, + { "specular_color",{ "R", "G", "B" } }, + { "diffuse_color",{ "R", "G", "B" } }, + { "alpha",{ "R", "G", "B" } }, + { "scale",{ "X", "Y", "Z" } }, + { "location",{ "X", "Y", "Z" } }, + { "rotation_euler",{ "X", "Y", "Z" } } + }; - openLibrary(); + std::map<std::string, std::vector<std::string>>::const_iterator it; + it = BC_COLLADA_AXIS_FROM_TYPE.find(channel); + if (it == BC_COLLADA_AXIS_FROM_TYPE.end()) + return ""; - forEachObjectInExportSet(sce, *this, this->export_settings->export_set); - - closeLibrary(); - } - return has_animations; + const std::vector<std::string> &subchannel = it->second; + if (id >= subchannel.size()) + return ""; + return subchannel[id]; } -bool AnimationExporter::is_flat_line(std::vector<float> &values, int channel_count) +bool AnimationExporter::open_animation_container(bool has_container, Object *ob) { - for (int i = 0; i < values.size(); i += channel_count) { - for (int j = 0; j < channel_count; j++) { - if (!bc_in_range(values[j], values[i+j], 0.000001)) - return false; - } + if (!has_container) { + char anim_id[200]; + sprintf(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str()); + openAnimation(anim_id, encode_xml(id_name(ob))); } return true; } -/* - * This function creates a complete LINEAR Collada <Animation> Entry with all needed - * <source>, <sampler>, and <channel> entries. - * This is is used for creating sampled Transformation Animations for either: - * - * 1-axis animation: - * times contains the time points in seconds from within the timeline - * values contains the data (list of single floats) - * channel_count = 1 - * axis_name = ['X' | 'Y' | 'Z'] - * is_rot indicates if the animation is a rotation - * - * 3-axis animation: - * times contains the time points in seconds from within the timeline - * values contains the data (list of floats where each 3 entries are one vector) - * channel_count = 3 - * axis_name = "" (actually not used) - * is_rot = false (see xxx below) - * - * xxx: - * I tried to create a 3 axis rotation animation - * like for translation or scale. But i could not - * figure out how to setup the channel for this case. - * So for now rotations are exported as 3 separate 1-axis collada animations - * See export_sampled_animation() further down. - */ -void AnimationExporter::create_sampled_animation(int channel_count, - std::vector<float> ×, - std::vector<float> &values, - std::string ob_name, - std::string label, - std::string axis_name, - bool is_rot) -{ - char anim_id[200]; - - if (is_flat_line(values, channel_count)) - return; - - BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), label.c_str(), axis_name.c_str()); - - openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); - /* create input source */ - std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, times, false, anim_id, ""); - - /* create output source */ - std::string output_id; - if (channel_count == 1) - output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, &values[0], values.size(), is_rot, anim_id, axis_name.c_str()); - else if (channel_count == 3) - output_id = create_xyz_source(&values[0], times.size(), anim_id); - else if (channel_count == 16) - output_id = create_4x4_source(times, values, anim_id); - - 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)); - - /* TODO create in/out tangents source (LINEAR) */ - std::string interpolation_id = fake_interpolation_source(times.size(), anim_id, ""); - - /* Create Sampler */ - sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); - addSampler(sampler); - - /* Create channel */ - std::string target = translate_id(ob_name) + "/" + label + axis_name + ((is_rot) ? ".ANGLE" : ""); - addChannel(COLLADABU::URI(empty, sampler_id), target); - - closeAnimation(); - -} - -/* - * Export all animation FCurves of an Object. - * - * Note: This uses the keyframes as sample points, - * and exports "baked keyframes" while keeping the tangent information - * of the FCurves intact. This works for simple cases, but breaks - * especially when negative scales are involved in the animation. - * - * If it is necessary to conserve the Animation precisely then - * use export_sampled_animation_set() instead. - */ -void AnimationExporter::export_keyframed_animation_set(Object *ob) +void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name) { - FCurve *fcu = (FCurve *)ob->adt->action->curves.first; - if (!fcu) { - return; /* object has no animation */ - } - - if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) { + std::vector<std::string> anim_meta_entry; + anim_meta_entry.push_back(translate_id(action_id)); + anim_meta_entry.push_back(action_name); + anim_meta.push_back(anim_meta_entry); - std::vector<float> ctimes; - find_keyframes(ob, ctimes); - if (ctimes.size() > 0) - export_sampled_matrix_animation(ob, ctimes); - } - else { - char *transformName; - while (fcu) { - //for armature animations as objects - if (ob->type == OB_ARMATURE) - transformName = fcu->rna_path; - else - transformName = extract_transform_name(fcu->rna_path); - - if ( - STREQ(transformName, "location") || - STREQ(transformName, "scale") || - (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) || - STREQ(transformName, "rotation_quaternion")) - { - create_keyframed_animation(ob, fcu, transformName, false); - } - fcu = fcu->next; - } - } + openAnimation(translate_id(action_id), action_name); } -/* - * Export the sampled animation of an Object. - * - * Note: This steps over all animation frames (step size is given in export_settings.sample_size) - * and then evaluates the transformation, - * and exports "baked samples" This works always, however currently the interpolation type is set - * to LINEAR for now. (maybe later this can be changed to BEZIER) - * - * Note: If it is necessary to keep the FCurves intact, then use export_keyframed_animation_set() instead. - * However be aware that exporting keyframed animation may modify the animation slightly. - * Also keyframed animation exports tend to break when negative scales are involved. - */ -void AnimationExporter::export_sampled_animation_set(Object *ob) +void AnimationExporter::close_animation_container(bool has_container) { - std::vector<float>ctimes; - find_sampleframes(ob, ctimes); - if (ctimes.size() > 0) { - if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) - export_sampled_matrix_animation(ob, ctimes); - else - export_sampled_transrotloc_animation(ob, ctimes); - } + if (has_container) + closeAnimation(); } -void AnimationExporter::export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes) +bool AnimationExporter::exportAnimations() { - UnitConverter converter; + Scene *sce = blender_context.get_scene(); - std::vector<float> values; + LinkNode &export_set = *this->export_settings->export_set; + bool has_anim_data = bc_has_animations(sce, export_set); + int animation_count = 0; + if (has_anim_data) { - for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime) { - float fmat[4][4]; + BCObjectSet animated_subset; + BCAnimationSampler::get_animated_from_export_set(animated_subset, export_set); + animation_count = animated_subset.size(); + BCAnimationSampler animation_sampler(blender_context, animated_subset); - bc_update_scene(m_bmain, scene, *ctime); - BKE_object_matrix_local_get(ob, fmat); - if (this->export_settings->limit_precision) - bc_sanitize_mat(fmat, 6); + try { + animation_sampler.sample_scene( + export_settings->sampling_rate, + /*keyframe_at_end = */ true, + export_settings->open_sim, + export_settings->keep_keyframes, + export_settings->export_animation_type + ); - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - values.push_back(fmat[i][j]); - } - - std::string ob_name = id_name(ob); + openLibrary(); - create_sampled_animation(16, ctimes, values, ob_name, "transform", "", false); -} + BCObjectSet::iterator it; + for (it = animated_subset.begin(); it != animated_subset.end(); ++it) { + Object *ob = *it; + exportAnimation(ob, animation_sampler); + } + } + catch (std::invalid_argument &iae) + { + fprintf(stderr, "Animation export interrupted"); + fprintf(stderr, "Exception was: %s", iae.what()); + } -void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes) -{ - static int LOC = 0; - static int EULX = 1; - static int EULY = 2; - static int EULZ = 3; - static int SCALE = 4; - - std::vector<float> baked_curves[5]; - - for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) { - float fmat[4][4]; - float floc[3]; - float fquat[4]; - float fsize[3]; - float feul[3]; - - bc_update_scene(m_bmain, scene, *ctime); - BKE_object_matrix_local_get(ob, fmat); - mat4_decompose(floc, fquat, fsize, fmat); - quat_to_eul(feul, fquat); - - baked_curves[LOC].push_back(floc[0]); - baked_curves[LOC].push_back(floc[1]); - baked_curves[LOC].push_back(floc[2]); - - baked_curves[EULX].push_back(feul[0]); - baked_curves[EULY].push_back(feul[1]); - baked_curves[EULZ].push_back(feul[2]); - - baked_curves[SCALE].push_back(fsize[0]); - baked_curves[SCALE].push_back(fsize[1]); - baked_curves[SCALE].push_back(fsize[2]); + closeLibrary(); +#if 0 + /* TODO: If all actions shall be exported, we need to call the + * AnimationClipExporter which will figure out which actions + * need to be exported for which objects + */ + if (this->export_settings->include_all_actions) { + AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta); + ace.exportAnimationClips(sce); + } +#endif } - - std::string ob_name = id_name(ob); - - create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale", "", false); - create_sampled_animation(3, ctimes, baked_curves[LOC], ob_name, "location", "", false); - - /* Not sure how to export rotation as a 3channel animation, - * so separate into 3 single animations for now: - */ - - create_sampled_animation(1, ctimes, baked_curves[EULX], ob_name, "rotation", "X", true); - create_sampled_animation(1, ctimes, baked_curves[EULY], ob_name, "rotation", "Y", true); - create_sampled_animation(1, ctimes, baked_curves[EULZ], ob_name, "rotation", "Z", true); - - fprintf(stdout, "Animation Export: Baked %d frames for %s (sampling rate: %d)\n", - (int)baked_curves[0].size(), - ob->id.name, - this->export_settings->sampling_rate); + return animation_count; } /* called for each exported object */ -void AnimationExporter::operator()(Object *ob) +void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler) { - char *transformName; + bool container_is_open = false; - /* bool isMatAnim = false; */ /* UNUSED */ + //Transform animations (trans, rot, scale) + container_is_open = open_animation_container(container_is_open, ob); - //Export transform animations - if (ob->adt && ob->adt->action) { + /* Now take care of the Object Animations + * Note: For Armatures the skeletal animation has already been exported (see above) + * However Armatures also can have Object animation. + */ + bool export_as_matrix = this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX; + if (export_as_matrix) { + export_matrix_animation(ob, sampler); // export all transform_curves as one single matrix animation + } - if (ob->type == OB_ARMATURE) { - /* Export skeletal animation (if any)*/ - bArmature *arm = (bArmature *)ob->data; - for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) - write_bone_animation_matrix(ob, bone); - } + export_curve_animation_set(ob, sampler, export_as_matrix); - /* Armatures can have object animation and skeletal animation*/ - if (this->export_settings->sampling_rate < 1) { - export_keyframed_animation_set(ob); - } - else { - export_sampled_animation_set(ob); - } - } + if (ob->type == OB_ARMATURE) { - export_object_constraint_animation(ob); +#ifdef WITH_MORPH_ANIMATION + /* TODO: This needs to be handled by extra profiles, postponed for now */ + export_morph_animation(ob); +#endif - //This needs to be handled by extra profiles, so postponed for now - //export_morph_animation(ob); + /* Export skeletal animation (if any) */ + bArmature *arm = (bArmature *)ob->data; + for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next) + export_bone_animations_recursive(ob, root_bone, sampler); + } - //Export Lamp parameter animations - if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) { - FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first); - while (fcu) { - transformName = extract_transform_name(fcu->rna_path); + close_animation_container(container_is_open); +} - if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) || - (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance"))) - { - create_keyframed_animation(ob, fcu, transformName, true); - } - fcu = fcu->next; +/* + * Export all animation FCurves of an Object. + * + * Note: This uses the keyframes as sample points, + * and exports "baked keyframes" while keeping the tangent information + * of the FCurves intact. This works for simple cases, but breaks + * especially when negative scales are involved in the animation. + * And when parent inverse matrices are involved (when exporting + * object hierarchies) + * + */ +void AnimationExporter::export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix) +{ + BCAnimationCurveMap *curves = sampler.get_curves(ob); + + BCAnimationCurveMap::iterator it; + for (it = curves->begin(); it != curves->end(); ++it) { + BCAnimationCurve &curve = *it->second; + if (curve.get_channel_target() == "rotation_quaternion") { + /* + Can not export Quaternion animation in Collada as far as i know) + Maybe automatically convert to euler rotation? + Discard for now. + */ + continue; + } + + if (export_as_matrix && curve.is_transform_curve()) { + /* All Transform curves will be exported within a single matrix animation, + * see export_matrix_animation() + * No need to export the curves here again. + */ + continue; } - } - //Export Camera parameter animations - if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) { - FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first); - while (fcu) { - transformName = extract_transform_name(fcu->rna_path); - - if ((STREQ(transformName, "lens")) || - (STREQ(transformName, "ortho_scale")) || - (STREQ(transformName, "clip_end")) || - (STREQ(transformName, "clip_start"))) - { - create_keyframed_animation(ob, fcu, transformName, true); - } - fcu = fcu->next; + if (!curve.is_animated()) { + continue; } - } - //Export Material parameter animations. - for (int a = 0; a < ob->totcol; a++) { - Material *ma = give_current_material(ob, a + 1); - if (!ma) continue; - if (ma->adt && ma->adt->action) { - /* isMatAnim = true; */ - FCurve *fcu = (FCurve *)ma->adt->action->curves.first; - while (fcu) { - transformName = extract_transform_name(fcu->rna_path); - - if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) || - (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) || - (STREQ(transformName, "ior"))) - { - create_keyframed_animation(ob, fcu, transformName, true, ma); - } - fcu = fcu->next; - } + BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves); + if (mcurve) { + export_curve_animation(ob, *mcurve); + delete mcurve; + } + else { + export_curve_animation(ob, curve); } } } -void AnimationExporter::export_object_constraint_animation(Object *ob) +void AnimationExporter::export_matrix_animation(Object *ob, BCAnimationSampler &sampler) { - std::vector<float> fra; - //Takes frames of target animations - make_anim_frames_from_targets(ob, fra); + std::vector<float> frames; + sampler.get_object_frames(frames, ob); + if (frames.size() > 0) { + BCMatrixSampleMap samples; + bool is_animated = sampler.get_object_samples(samples, ob); + if (is_animated) { + bAction *action = bc_getSceneObjectAction(ob); + std::string name = encode_xml(id_name(ob)); + std::string action_name = (action == NULL) ? name + "-action" : id_name(action); + std::string channel_type = "transform"; + std::string axis = ""; + std::string id = bc_get_action_id(action_name, name, channel_type, axis); - if (fra.size()) - dae_baked_object_animation(fra, ob); -} + std::string target = translate_id(name) + '/' + channel_type; -void AnimationExporter::export_morph_animation(Object *ob) -{ - FCurve *fcu; - char *transformName; - Key *key = BKE_key_from_object(ob); - if (!key) return; - - if (key->adt && key->adt->action) { - fcu = (FCurve *)key->adt->action->curves.first; - - while (fcu) { - transformName = extract_transform_name(fcu->rna_path); - - create_keyframed_animation(ob, fcu, transformName, true); - - fcu = fcu->next; + export_collada_matrix_animation(id, name, target, frames, samples); } } - } -void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames ) +//write bone animations in transform matrix sources +void AnimationExporter::export_bone_animations_recursive(Object *ob, Bone *bone, BCAnimationSampler &sampler) { - ListBase *conlist = get_active_constraints(ob); - if (conlist == NULL) return; - bConstraint *con; - for (con = (bConstraint *)conlist->first; con; con = con->next) { - ListBase targets = {NULL, NULL}; - - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - - if (!validateConstraints(con)) continue; - - if (cti && cti->get_constraint_targets) { - bConstraintTarget *ct; - Object *obtar; - /* get targets - * - constraints should use ct->matrix, not directly accessing values - * - ct->matrix members have not yet been calculated here! - */ - cti->get_constraint_targets(con, &targets); + std::vector<float> frames; + sampler.get_bone_frames(frames, ob, bone); - for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { - obtar = ct->tar; - - if (obtar) - find_keyframes(obtar, frames); - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); + if (frames.size()) { + BCMatrixSampleMap samples; + bool is_animated = sampler.get_bone_samples(samples, ob, bone); + if (is_animated) { + export_bone_animation(ob, bone, frames, samples); } } + + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) + export_bone_animations_recursive(ob, child, sampler); } -//euler sources from quternion sources -float *AnimationExporter::get_eul_source_for_quat(Object *ob) -{ - FCurve *fcu = (FCurve *)ob->adt->action->curves.first; - const int keys = fcu->totvert; - float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values"); - float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values"); - float temp_quat[4]; - float temp_eul[3]; - while (fcu) { - char *transformName = extract_transform_name(fcu->rna_path); - - if (STREQ(transformName, "rotation_quaternion") ) { - for (int i = 0; i < fcu->totvert; i++) { - *(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1]; +/* +* In some special cases the exported Curve needs to be replaced +* by a modified curve (for collada purposes) +* This method checks if a conversion is necessary and if applicable +* returns a pointer to the modified BCAnimationCurve. +* IMPORTANT: the modified curve must be deleted by the caller when no longer needed +* if no conversion is needed this method returns a NULL; +*/ +BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves) +{ + std::string channel_target = curve.get_channel_target(); + BCAnimationCurve *mcurve = NULL; + if (channel_target == "lens") { + + /* Create an xfov curve */ + + BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0); + mcurve = new BCAnimationCurve(key, ob); + + // now tricky part: transform the fcurve + BCValueMap lens_values; + curve.get_value_map(lens_values); + + BCAnimationCurve *sensor_curve = NULL; + BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0); + BCAnimationCurveMap::iterator cit = curves.find(sensor_key); + if (cit != curves.end()) { + sensor_curve = cit->second; + } + + BCValueMap::const_iterator vit; + for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) { + int frame = vit->first; + float lens_value = vit->second; + + float sensor_value; + if (sensor_curve) { + sensor_value = sensor_curve->get_value(frame); + } + else { + sensor_value = ((Camera *)ob->data)->sensor_x; } + float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value)); + mcurve->add_value(value, frame); } - fcu = fcu->next; + mcurve->clean_handles(); // to reset the handles } - - for (int i = 0; i < keys; i++) { - for (int j = 0; j < 4; j++) - temp_quat[j] = quat[(i * 4) + j]; - - quat_to_eul(temp_eul, temp_quat); - - for (int k = 0; k < 3; k++) - eul[i * 3 + k] = temp_eul[k]; - - } - MEM_freeN(quat); - return eul; - -} - -//Get proper name for bones -std::string AnimationExporter::getObjectBoneName(Object *ob, const FCurve *fcu) -{ - //hard-way to derive the bone name from rna_path. Must find more compact method - std::string rna_path = std::string(fcu->rna_path); - - char *boneName = strtok((char *)rna_path.c_str(), "\""); - boneName = strtok(NULL, "\""); - - if (boneName != NULL) - return /*id_name(ob) + "_" +*/ std::string(boneName); - else - return id_name(ob); + return mcurve; } -std::string AnimationExporter::getAnimationPathId(const FCurve *fcu) +void AnimationExporter::export_curve_animation( + Object *ob, + BCAnimationCurve &curve) { - std::string rna_path = std::string(fcu->rna_path); - return translate_id(rna_path); -} - -/* convert f-curves to animation curves and write */ -void AnimationExporter::create_keyframed_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; - - Object *obj = NULL; - - if (STREQ(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 (STREQ(transformName, "color") || - STREQ(transformName, "specular_color") || - STREQ(transformName, "diffuse_color") || - STREQ(transformName, "alpha")) - { - const char *axis_names[] = {"R", "G", "B"}; - if (fcu->array_index < 3) - axis_name = axis_names[fcu->array_index]; - } + std::string channel_target = curve.get_channel_target(); /* - * Note: Handle transformation animations separately (to apply matrix inverse to fcurves) - * We will use the object to evaluate the animation on all keyframes and calculate the - * resulting object matrix. We need this to incorporate the - * effects of the parent inverse matrix (when it contains a rotation component) - * - * TODO: try to combine exported fcurves into 3 channel animations like done - * in export_sampled_animation(). For now each channel is exported as separate <Animation>. + * Some curves can not be exported as is and need some conversion + * For more information see implementation oif get_modified_export_curve() + * note: if mcurve is not NULL then it must be deleted at end of this method; */ - else if ( - STREQ(transformName, "scale") || - STREQ(transformName, "location") || - STREQ(transformName, "rotation_euler")) - { - const char *axis_names[] = {"X", "Y", "Z"}; - if (fcu->array_index < 3) { - axis_name = axis_names[fcu->array_index]; - obj = ob; - } - } - else { - /* no axis name. single parameter */ - axis_name = ""; - } + int channel_index = curve.get_channel_index(); + std::string axis = get_axis_name(channel_target, channel_index); // RGB or XYZ or "" - std::string ob_name = std::string("null"); + std::string action_name; + bAction *action = bc_getSceneObjectAction(ob); + action_name = (action) ? id_name(action) : "constraint_anim"; - /* 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(), - (char *)translate_id(transformName).c_str(), - 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(), - (char *)getAnimationPathId(fcu).c_str(), - 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); + const std::string curve_name = encode_xml(curve.get_animation_name(ob)); + std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, "."); - // create output source - std::string output_id; + std::string collada_target = translate_id(curve_name); - //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]; + if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) { + int material_index = curve.get_subindex(); + Material *ma = give_current_material(ob, material_index + 1); + if (ma) { + collada_target = translate_id(id_name(ma)) + "-effect/common/" + get_collada_sid(curve, axis); } - 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 if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) { - output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id); } else { - output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name, obj); + collada_target += "/" + get_collada_sid(curve, axis); } - // 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; + export_collada_curve_animation(id, curve_name, collada_target, axis, curve); - if (has_tangents) { - // create in_tangent source - intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj); - - // create out_tangent source - outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name, obj); - } - - 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); - //if shape key animation, this is the main problem, how to define the channel targets. - /*target = get_morph_id(ob) + - "/value" +*/ - } - addChannel(COLLADABU::URI(empty, sampler_id), target); - - closeAnimation(); } - - -//write bone animations in transform matrix sources -void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone) +void AnimationExporter::export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples) { - if (!ob_arm->adt) - return; - - //This will only export animations of bones in deform group. - /* if (!is_bone_deform_group(bone)) return; */ + bAction* action = bc_getSceneObjectAction(ob); + std::string bone_name(bone->name); + std::string name = encode_xml(id_name(ob)); + std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix"); + std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform"; - sample_and_write_bone_animation_matrix(ob_arm, bone); - - for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) - write_bone_animation_matrix(ob_arm, child); + export_collada_matrix_animation(id, name, target, frames, samples); } bool AnimationExporter::is_bone_deform_group(Bone *bone) @@ -691,204 +377,86 @@ bool AnimationExporter::is_bone_deform_group(Bone *bone) return false; } -void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone) -{ - bArmature *arm = (bArmature *)ob_arm->data; - int flag = arm->flag; - std::vector<float> fra; - //char prefix[256]; - - //Check if there is a fcurve in the armature for the bone in param - //when baking this check is not needed, solve every bone for every frame. - /*FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first; - - while (fcu) { - std::string bone_name = getObjectBoneName(ob_arm, fcu); - int val = BLI_strcasecmp((char *)bone_name.c_str(), bone->name); - if (val == 0) break; - fcu = fcu->next; - } - if (!(fcu)) return;*/ +void AnimationExporter::export_collada_curve_animation( + std::string id, + std::string name, + std::string collada_target, + std::string axis, + BCAnimationCurve &curve) +{ + BCFrames frames; + BCValues values; + curve.get_frames(frames); + curve.get_values(values); + std::string channel_target = curve.get_channel_target(); - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); - if (!pchan) - return; + fprintf(stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size())); + openAnimation(id, name); + BC_animation_source_type source_type = (curve.is_rotation_curve()) ? BC_SOURCE_TYPE_ANGLE : BC_SOURCE_TYPE_VALUE; + std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis); + std::string output_id = collada_source_from_values(source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis); - if (this->export_settings->sampling_rate < 1) - find_keyframes(ob_arm, fra); + bool has_tangents = false; + std::string interpolation_id; + if (this->export_settings->keep_smooth_curves) + interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents); else - find_sampleframes(ob_arm, fra); + interpolation_id = collada_linear_interpolation_source(frames.size(), id); - if (flag & ARM_RESTPOS) { - arm->flag &= ~ARM_RESTPOS; - BKE_pose_where_is(scene, ob_arm); - } - - if (fra.size()) { - dae_baked_animation(fra, ob_arm, bone); + std::string intangent_id; + std::string outtangent_id; + if (has_tangents) { + intangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis); + outtangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis); } - if (flag & ARM_RESTPOS) - arm->flag = flag; - BKE_pose_where_is(scene, ob_arm); -} - -void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone) -{ - std::string ob_name = id_name(ob_arm); - std::string bone_name = bone->name; - char anim_id[200]; - - if (!fra.size()) - return; - - BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), - (char *)translate_id(bone_name).c_str(), "pose_matrix"); + std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX; - openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); - - // create input source - std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, ""); - - // create output source - std::string output_id; - - output_id = create_4x4_source(fra, ob_arm, bone, anim_id); - - // create interpolations source - std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, ""); - - 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)); - // TODO create in/out tangents source + sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id)); + sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id)); + sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_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_STRING, intangent_id)); + sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(EMPTY_STRING, outtangent_id)); + } addSampler(sampler); - - std::string target = get_joint_id(ob_arm, bone) + "/transform"; - addChannel(COLLADABU::URI(empty, sampler_id), target); + addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target); closeAnimation(); } -void AnimationExporter::dae_baked_object_animation(std::vector<float> &fra, Object *ob) +void AnimationExporter::export_collada_matrix_animation(std::string id, std::string name, std::string target, BCFrames &frames, BCMatrixSampleMap &samples) { - std::string ob_name = id_name(ob); - char anim_id[200]; - - if (!fra.size()) - return; + fprintf(stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size())); - BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s", (char *)translate_id(ob_name).c_str(), - "object_matrix"); + openAnimationWithClip(id, name); - openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); + std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, ""); + std::string output_id = collada_source_from_values(samples, id); + std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id); - // create input source - std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, ""); - - // create output source - std::string output_id; - output_id = create_4x4_source( fra, ob, NULL, anim_id); - - // create interpolations source - std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, ""); - - std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; + std::string sampler_id = std::string(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)); - // TODO create in/out tangents source - // this input is required - sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); - - addSampler(sampler); + sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id)); + sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id)); + sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id)); - std::string target = translate_id(ob_name) + "/transform"; - addChannel(COLLADABU::URI(empty, sampler_id), target); - - closeAnimation(); -} - -// dae_bone_animation -> add_bone_animation -// (blend this into dae_bone_animation) -void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name) -{ - const char *axis_names[] = {"X", "Y", "Z"}; - const char *axis_name = NULL; - char anim_id[200]; - bool is_rot = tm_type == 0; - - if (!fra.size()) - return; - - char rna_path[200]; - BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(), - tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location")); - - if (axis > -1) - axis_name = axis_names[axis]; - - std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false); - - BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), - (char *)translate_id(bone_name).c_str(), (char *)transform_sid.c_str()); - - openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); - - // create input source - std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name); - - // create output source - std::string output_id; - if (axis == -1) - output_id = create_xyz_source(values, fra.size(), anim_id); - else - output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name); - - // create interpolations source - std::string interpolation_id = fake_interpolation_source(fra.size(), 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)); - - // TODO create in/out tangents source - - // this input is required - sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + // Matrix animation has no tangents addSampler(sampler); - - std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid; - addChannel(COLLADABU::URI(empty, sampler_id), target); + addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target); closeAnimation(); } -float AnimationExporter::convert_time(float frame) -{ - return FRA2TIME(frame); -} - -float AnimationExporter::convert_angle(float angle) -{ - return COLLADABU::Math::Utils::radToDegF(angle); -} - std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic) { switch (semantic) { @@ -909,7 +477,10 @@ std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Sem } void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, - COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform) + COLLADASW::InputSemantic::Semantics semantic, + bool is_rot, + const std::string axis, + bool transform) { switch (semantic) { case COLLADASW::InputSemantic::INPUT: @@ -920,7 +491,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa param.push_back("ANGLE"); } else { - if (axis) { + if (axis != "") { param.push_back(axis); } else @@ -944,262 +515,83 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa } } -void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length) +std::string AnimationExporter::collada_tangent_from_curve(COLLADASW::InputSemantic::Semantics semantic, BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name) { - switch (semantic) { - case COLLADASW::InputSemantic::INPUT: - *length = 1; - values[0] = convert_time(bezt->vec[1][0]); - break; - case COLLADASW::InputSemantic::OUTPUT: - *length = 1; - if (is_angle) { - values[0] = RAD2DEGF(bezt->vec[1][1]); - } - else { - values[0] = bezt->vec[1][1]; - } - break; + Scene *scene = blender_context.get_scene(); + std::string channel = curve.get_channel_target(); - case COLLADASW::InputSemantic::IN_TANGENT: - *length = 2; - values[0] = convert_time(bezt->vec[0][0]); - if (bezt->ipo != BEZT_IPO_BEZ) { - // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data - values[0] = 0; - values[1] = 0; - } - else if (is_angle) { - values[1] = RAD2DEGF(bezt->vec[0][1]); - } - else { - values[1] = bezt->vec[0][1]; - } - break; + const std::string source_id = anim_id + get_semantic_suffix(semantic); - case COLLADASW::InputSemantic::OUT_TANGENT: - *length = 2; - values[0] = convert_time(bezt->vec[2][0]); - if (bezt->ipo != BEZT_IPO_BEZ) { - // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data - values[0] = 0; - values[1] = 0; - } - else if (is_angle) { - values[1] = RAD2DEGF(bezt->vec[2][1]); - } - else { - values[1] = bezt->vec[2][1]; - } - break; - default: - *length = 0; - break; - } -} - -// old function to keep compatibility for calls where offset and object are not needed -std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name) -{ - return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL); -} - -void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime) -{ - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); - ListBase *conlist = get_active_constraints(ob); - bConstraint *con; - for (con = (bConstraint *)conlist->first; con; con = con->next) { - ListBase targets = { NULL, NULL }; - - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - - 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; - - if (obtar) { - BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM); - BKE_object_where_is_calc_time(scene, obtar, ctime); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - BKE_object_where_is_calc_time(scene, ob, ctime); -} - -/* - * ob is needed to aply parent inverse information to fcurve. - * TODO: Here we have to step over all keyframes for each object and for each fcurve. - * Instead of processing each fcurve one by one, - * step over the animation from keyframe to keyframe, - * then create adjusted fcurves (and entries) for all affected objects. - * Then we would need to step through the scene only once. - */ -std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob) -{ - std::string source_id = anim_id + get_semantic_suffix(semantic); - - bool is_angle = (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path, "spot_size")); - bool is_euler = strstr(fcu->rna_path, "rotation_euler"); - bool is_translation = strstr(fcu->rna_path, "location"); - bool is_scale = strstr(fcu->rna_path, "scale"); - bool is_tangent = false; - int offset_index = 0; + bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size"); COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fcu->totvert); - - switch (semantic) { - case COLLADASW::InputSemantic::INPUT: - case COLLADASW::InputSemantic::OUTPUT: - source.setAccessorStride(1); - offset_index = 0; - break; - case COLLADASW::InputSemantic::IN_TANGENT: - case COLLADASW::InputSemantic::OUT_TANGENT: - source.setAccessorStride(2); - offset_index = 1; - is_tangent = true; - break; - default: - break; - } + source.setAccessorCount(curve.sample_count()); + source.setAccessorStride(2); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, is_angle, axis_name, false); source.prepareToAppendValues(); - for (unsigned int frame_index = 0; frame_index < fcu->totvert; frame_index++) { - float fixed_val = 0; - if (ob) { - float fmat[4][4]; - float frame = fcu->bezt[frame_index].vec[1][0]; - float ctime = BKE_scene_frame_get_from_ctime(scene, frame); - - evaluate_anim_with_constraints(ob, ctime); // set object transforms to fcurve's i'th keyframe - - BKE_object_matrix_local_get(ob, fmat); - float floc[3]; - float fquat[4]; - float fsize[3]; - mat4_decompose(floc, fquat, fsize, fmat); - - if (is_euler) { - float eul[3]; - quat_to_eul(eul, fquat); - fixed_val = RAD2DEGF(eul[fcu->array_index]); - } - else if (is_translation) { - fixed_val = floc[fcu->array_index]; - } - else if (is_scale) { - fixed_val = fsize[fcu->array_index]; - } - } + const FCurve *fcu = curve.get_fcurve(); + int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2; - float values[3]; // be careful! - float offset = 0; - int length = 0; - get_source_values(&fcu->bezt[frame_index], semantic, is_angle, values, &length); - if (is_tangent) { - float bases[3]; - int len = 0; - get_source_values(&fcu->bezt[frame_index], COLLADASW::InputSemantic::OUTPUT, is_angle, bases, &len); - offset = values[offset_index] - bases[0]; - } + for (int i = 0; i < fcu->totvert; ++i) { + BezTriple &bezt = fcu->bezt[i]; - for (int j = 0; j < length; j++) { - float val; - if (j == offset_index) { - if (ob) { - val = fixed_val + offset; - } - else { - val = values[j] + offset; - } - } else { - val = values[j]; - } - source.appendValues(val); - } - } - - source.finish(); + float sampled_time = bezt.vec[tangent][0]; + float sampled_val = bezt.vec[tangent][1]; - return source_id; -} - -/* - * Similar to create_source_from_fcurve, but adds conversion of lens - * animation data from focal length to FOV. - */ -std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id) -{ - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fcu->totvert); - - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, false, "", false); + if (is_angle) { + sampled_val = RAD2DEGF(sampled_val); + } - source.prepareToAppendValues(); + source.appendValues(FRA2TIME(sampled_time)); + source.appendValues(sampled_val); - for (unsigned int i = 0; i < fcu->totvert; i++) { - float values[3]; // be careful! - int length = 0; - get_source_values(&fcu->bezt[i], semantic, false, values, &length); - for (int j = 0; j < length; j++) - { - float val = RAD2DEGF(focallength_to_fov(values[j], cam->sensor_x)); - source.appendValues(val); - } } - source.finish(); - return source_id; } -/* - * only to get OUTPUT source values ( if rotation and hence the axis is also specified ) - */ -std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name) +std::string AnimationExporter::collada_source_from_values( + BC_animation_source_type source_type, + COLLADASW::InputSemantic::Semantics semantic, + std::vector<float> &values, + const std::string& anim_id, + const std::string axis_name) { + Scene *scene = blender_context.get_scene(); + /* T can be float, int or double */ + + int stride = 1; + int entry_count = values.size() / stride; std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(tot); - source.setAccessorStride(1); + source.setAccessorCount(entry_count); + source.setAccessorStride(stride); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, is_rot, axis_name, false); + add_source_parameters(param, semantic, source_type== BC_SOURCE_TYPE_ANGLE, axis_name, false); source.prepareToAppendValues(); - for (int i = 0; i < tot; i++) { - float val = v[i]; - ////if (semantic == COLLADASW::InputSemantic::INPUT) - // val = convert_time(val); - //else - if (is_rot) + for (int i = 0; i < entry_count; i++) { + float val = values[i]; + switch (source_type) { + case BC_SOURCE_TYPE_TIMEFRAME: + val = FRA2TIME(val); + break; + case BC_SOURCE_TYPE_ANGLE: val = RAD2DEGF(val); + break; + default: break; + } source.appendValues(val); } @@ -1209,39 +601,9 @@ std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic } /* - * only used for sources with INPUT semantic - */ -std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name) -{ - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fra.size()); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, is_rot, axis_name, false); - - source.prepareToAppendValues(); - - std::vector<float>::iterator it; - for (it = fra.begin(); it != fra.end(); it++) { - float val = *it; - //if (semantic == COLLADASW::InputSemantic::INPUT) - val = convert_time(val); - /*else if (is_rot) - val = convert_angle(val);*/ - source.appendValues(val); - } - - source.finish(); - - return source_id; -} - -std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std::vector<float> &values , const std::string &anim_id) + * Create a collada matrix source for a set of samples +*/ +std::string AnimationExporter::collada_source_from_values(BCMatrixSampleMap &samples, const std::string &anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); @@ -1249,180 +611,38 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std COLLADASW::Float4x4Source source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(ctimes.size()); + source.setAccessorCount(samples.size()); source.setAccessorStride(16); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, false, NULL, true); + add_source_parameters(param, semantic, false, "", true); source.prepareToAppendValues(); - std::vector<float>::iterator it; - - for (it = values.begin(); it != values.end(); it+=16) { - float mat[4][4]; - - bc_copy_m4_farray(mat, &*it); - - UnitConverter converter; - double outmat[4][4]; - converter.mat4_to_dae_double(outmat, mat); - - if (this->export_settings->limit_precision) - bc_sanitize_mat(outmat, 6); - - source.appendValues(outmat); + BCMatrixSampleMap::iterator it; + int precision = (this->export_settings->limit_precision) ? 6 : -1; // could be made configurable + for (it = samples.begin(); it != samples.end(); it++) { + const BCMatrix *sample = it->second; + double daemat[4][4]; + sample->get_matrix(daemat, true, precision); + source.appendValues(daemat); } source.finish(); return source_id; } -std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id) -{ - bool is_bone_animation = ob->type == OB_ARMATURE && bone; - - COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::Float4x4Source source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(frames.size()); - source.setAccessorStride(16); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, false, NULL, true); - - source.prepareToAppendValues(); - - bPoseChannel *parchan = NULL; - bPoseChannel *pchan = NULL; - - if (is_bone_animation) { - bPose *pose = ob->pose; - pchan = BKE_pose_channel_find_name(pose, bone->name); - if (!pchan) - return ""; - - parchan = pchan->parent; - - enable_fcurves(ob->adt->action, bone->name); - } - - std::vector<float>::iterator it; - int j = 0; - for (it = frames.begin(); it != frames.end(); it++) { - float mat[4][4], ipar[4][4]; - float frame = *it; - - float ctime = BKE_scene_frame_get_from_ctime(scene, frame); - bc_update_scene(m_bmain, scene, ctime); - if (is_bone_animation) { - if (pchan->flag & POSE_CHAIN) { - enable_fcurves(ob->adt->action, NULL); - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); - BKE_pose_where_is(scene, ob); - } - else { - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); - } - - // compute bone local mat - if (bone->parent) { - invert_m4_m4(ipar, parchan->pose_mat); - mul_m4_m4m4(mat, ipar, pchan->pose_mat); - } - else - copy_m4_m4(mat, pchan->pose_mat); - - /* OPEN_SIM_COMPATIBILITY - * AFAIK animation to second life is via BVH, but no - * reason to not have the collada-animation be correct - */ - if (export_settings->open_sim) { - float temp[4][4]; - copy_m4_m4(temp, bone->arm_mat); - temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - invert_m4(temp); - - mul_m4_m4m4(mat, mat, temp); - - if (bone->parent) { - copy_m4_m4(temp, bone->parent->arm_mat); - temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; - - mul_m4_m4m4(mat, temp, mat); - } - } - - } - else { - copy_m4_m4(mat, ob->obmat); - } - - UnitConverter converter; - - double outmat[4][4]; - converter.mat4_to_dae_double(outmat, mat); - - if (this->export_settings->limit_precision) - bc_sanitize_mat(outmat, 6); - - source.appendValues(outmat); - - j++; - - BIK_release_tree(scene, ob, ctime); - } - - if (ob->adt) { - enable_fcurves(ob->adt->action, NULL); - } - - source.finish(); - - return source_id; -} - - -/* - * only used for sources with OUTPUT semantic ( locations and scale) - */ -std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id) -{ - COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(tot); - source.setAccessorStride(3); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, false, NULL, false); - - source.prepareToAppendValues(); - - for (int i = 0; i < tot; i++) { - source.appendValues(*v, *(v + 1), *(v + 2)); - v += 3; - } - - source.finish(); - - return source_id; -} - -std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents) +std::string AnimationExporter::collada_interpolation_source(const BCAnimationCurve &curve, + const std::string& anim_id, + const std::string axis, + bool *has_tangents) { std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION); COLLADASW::NameSource source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fcu->totvert); + source.setAccessorCount(curve.sample_count()); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); @@ -1432,12 +652,17 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st *has_tangents = false; - for (unsigned int i = 0; i < fcu->totvert; i++) { - if (fcu->bezt[i].ipo == BEZT_IPO_BEZ) { + std::vector<float>frames; + curve.get_frames(frames); + + for (unsigned int i = 0; i < curve.sample_count(); i++) { + float frame = frames[i]; + int ipo = curve.get_interpolation_type(frame); + if (ipo == BEZT_IPO_BEZ) { source.appendValues(BEZIER_NAME); *has_tangents = true; } - else if (fcu->bezt[i].ipo == BEZT_IPO_CONST) { + else if (ipo == BEZT_IPO_CONST) { source.appendValues(STEP_NAME); } else { // BEZT_IPO_LIN @@ -1451,7 +676,7 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st return source_id; } -std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name) +std::string AnimationExporter::collada_linear_interpolation_source(int tot, const std::string& anim_id) { std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION); @@ -1475,474 +700,102 @@ std::string AnimationExporter::fake_interpolation_source(int tot, const std::str return source_id; } -std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) -{ - std::string tm_name; - // when given rna_path, determine tm_type from it - if (rna_path) { - char *name = extract_transform_name(rna_path); - - if (STREQ(name, "color")) - tm_type = 1; - else if (STREQ(name, "spot_size")) - tm_type = 2; - else if (STREQ(name, "spot_blend")) - tm_type = 3; - else if (STREQ(name, "distance")) - tm_type = 4; - else - tm_type = -1; - } - - switch (tm_type) { - case 1: - tm_name = "color"; - break; - case 2: - tm_name = "fall_off_angle"; - break; - case 3: - tm_name = "fall_off_exponent"; - break; - case 4: - tm_name = "blender/blender_dist"; - break; - - default: - tm_name = ""; - break; - } - - if (tm_name.size()) { - if (axis_name[0]) - return tm_name + "." + std::string(axis_name); - else - return tm_name; - } - - return std::string(""); -} - -std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) +const std::string AnimationExporter::get_collada_name(std::string channel_target) const { - std::string tm_name; - // when given rna_path, determine tm_type from it - if (rna_path) { - char *name = extract_transform_name(rna_path); - - if (STREQ(name, "lens")) - tm_type = 0; - else if (STREQ(name, "ortho_scale")) - tm_type = 1; - else if (STREQ(name, "clip_end")) - tm_type = 2; - else if (STREQ(name, "clip_start")) - tm_type = 3; - - else - tm_type = -1; - } - - switch (tm_type) { - case 0: - tm_name = "xfov"; - break; - case 1: - tm_name = "xmag"; - break; - case 2: - tm_name = "zfar"; - break; - case 3: - tm_name = "znear"; - break; - - default: - tm_name = ""; - break; - } - - if (tm_name.size()) { - if (axis_name[0]) - return tm_name + "." + std::string(axis_name); - else - return tm_name; - } - - return std::string(""); + /* + * Translation table to map FCurve animation types to Collada animation. + * Todo: Maybe we can keep the names from the fcurves here instead of + * mapping. However this is what i found in the old code. So keep + * this map for now. + */ + static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = { + { "rotation", "rotation" }, + { "rotation_euler", "rotation" }, + { "rotation_quaternion", "rotation" }, + { "scale", "scale" }, + { "location", "location" }, + + /* Materials */ + { "specular_color", "specular" }, + { "diffuse_color", "diffuse" }, + { "ior", "index_of_refraction" }, + { "specular_hardness", "specular_hardness" }, + { "alpha", "alpha" }, + + /* Lamps */ + { "color", "color" }, + { "fall_off_angle", "falloff_angle" }, + { "spot_size", "falloff_angle" }, + { "fall_off_exponent", "falloff_exponent" }, + { "spot_blend", "falloff_exponent" }, + { "blender/blender_dist", "blender/blender_dist" }, // special blender profile (todo: make this more elegant) + { "distance", "blender/blender_dist" }, // special blender profile (todo: make this more elegant) + + /* Cameras */ + { "lens", "xfov" }, + { "xfov", "xfov" }, + { "xmag", "xmag" }, + { "zfar", "zfar" }, + { "znear", "znear" }, + { "ortho_scale", "xmag" }, + { "clip_end", "zfar" }, + { "clip_start", "znear" } + }; + + std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(channel_target); + if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end()) + return ""; + + std::string tm_name = name_it->second; + return tm_name; } /* * Assign sid of the animated parameter or transform for rotation, * axis name is always appended and the value of append_axis is ignored */ -std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) +std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name) { - std::string tm_name; - bool is_angle = false; - // when given rna_path, determine tm_type from it - if (rna_path) { - char *name = extract_transform_name(rna_path); - - if (STREQ(name, "rotation_euler")) - tm_type = 0; - else if (STREQ(name, "rotation_quaternion")) - tm_type = 1; - else if (STREQ(name, "scale")) - tm_type = 2; - else if (STREQ(name, "location")) - tm_type = 3; - else if (STREQ(name, "specular_hardness")) - tm_type = 4; - else if (STREQ(name, "specular_color")) - tm_type = 5; - else if (STREQ(name, "diffuse_color")) - tm_type = 6; - else if (STREQ(name, "alpha")) - tm_type = 7; - else if (STREQ(name, "ior")) - tm_type = 8; + std::string channel_target = curve.get_channel_target(); + std::string tm_name = get_collada_name(channel_target); - else - tm_type = -1; - } + bool is_angle = curve.is_rotation_curve(); - switch (tm_type) { - case 0: - case 1: - tm_name = "rotation"; - is_angle = true; - break; - case 2: - tm_name = "scale"; - break; - case 3: - tm_name = "location"; - break; - case 4: - tm_name = "shininess"; - break; - case 5: - tm_name = "specular"; - break; - case 6: - tm_name = "diffuse"; - break; - case 7: - tm_name = "transparency"; - break; - case 8: - tm_name = "index_of_refraction"; - break; - - default: - tm_name = ""; - break; - } if (tm_name.size()) { if (is_angle) return tm_name + std::string(axis_name) + ".ANGLE"; else - if (axis_name[0]) - return tm_name + "." + std::string(axis_name); - else - return tm_name; - } - - return std::string(""); -} - -char *AnimationExporter::extract_transform_name(char *rna_path) -{ - char *dot = strrchr(rna_path, '.'); - return dot ? (dot + 1) : rna_path; -} - -/* - * enable fcurves driving a specific bone, disable all the rest - * if bone_name = NULL enable all fcurves - */ -void AnimationExporter::enable_fcurves(bAction *act, char *bone_name) -{ - FCurve *fcu; - char prefix[200]; - - if (bone_name) - BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); - - for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) { - if (bone_name) { - if (STREQLEN(fcu->rna_path, prefix, strlen(prefix))) - fcu->flag &= ~FCURVE_DISABLED; + if (axis_name != "") + return tm_name + "." + std::string(axis_name); else - fcu->flag |= FCURVE_DISABLED; - } - else { - fcu->flag &= ~FCURVE_DISABLED; - } + return tm_name; } -} -bool AnimationExporter::hasAnimations(Scene *sce) -{ - LinkNode *node; - - for (node=this->export_settings->export_set; node; node=node->next) { - Object *ob = (Object *)node->link; - - FCurve *fcu = 0; - //Check for object transform animations - if (ob->adt && ob->adt->action) - fcu = (FCurve *)ob->adt->action->curves.first; - //Check for Lamp parameter animations - else if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) - fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first); - //Check for Camera parameter animations - else if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) - fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first); - - //Check Material Effect parameter animations. - for (int a = 0; a < ob->totcol; a++) { - Material *ma = give_current_material(ob, a + 1); - if (!ma) continue; - if (ma->adt && ma->adt->action) { - fcu = (FCurve *)ma->adt->action->curves.first; - } - } - - //check shape key animation - if (!fcu) { - Key *key = BKE_key_from_object(ob); - if (key && key->adt && key->adt->action) - fcu = (FCurve *)key->adt->action->curves.first; - } - if (fcu) - return true; - } - return false; -} - -//------------------------------- Not used in the new system.-------------------------------------------------------- -void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode) -{ - if (rotmode > 0) - find_keyframes(ob, fra, prefix, "rotation_euler"); - else if (rotmode == ROT_MODE_QUAT) - find_keyframes(ob, fra, prefix, "rotation_quaternion"); - /*else if (rotmode == ROT_MODE_AXISANGLE) - ;*/ + return tm_name; } -/* Take care to always have the first frame and the last frame in the animation - * regardless of the sampling_rate setting - */ -void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra) +#ifdef WITH_MORPH_ANIMATION +/* TODO: This function needs to be implemented similar to the material animation export +So we have to update BCSample for this to work. +*/ +void AnimationExporter::export_morph_animation(Object *ob, BCAnimationSampler &sampler) { - int frame = scene->r.sfra; - do { - float ctime = BKE_scene_frame_get_from_ctime(scene, frame); - fra.push_back(ctime); - if (frame == scene->r.efra) - break; - frame += this->export_settings->sampling_rate; - if (frame > scene->r.efra) - frame = scene->r.efra; // make sure the last frame is always exported - - } while (true); -} - -/* - * find keyframes of all the objects animations - */ -void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra) -{ - if (ob->adt && ob->adt->action) { - FCurve *fcu = (FCurve *)ob->adt->action->curves.first; - - for (; fcu; fcu = fcu->next) { - for (unsigned int i = 0; i < fcu->totvert; i++) { - float f = fcu->bezt[i].vec[1][0]; - if (std::find(fra.begin(), fra.end(), f) == fra.end()) - fra.push_back(f); - } - } - - // keep the keys in ascending order - std::sort(fra.begin(), fra.end()); - } -} - -void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name) -{ - if (ob->adt && ob->adt->action) { - FCurve *fcu = (FCurve *)ob->adt->action->curves.first; - - for (; fcu; fcu = fcu->next) { - if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix))) - continue; - - char *name = extract_transform_name(fcu->rna_path); - if (STREQ(name, tm_name)) { - for (unsigned int i = 0; i < fcu->totvert; i++) { - float f = fcu->bezt[i].vec[1][0]; - if (std::find(fra.begin(), fra.end(), f) == fra.end()) - fra.push_back(f); - } - } - } - - // keep the keys in ascending order - std::sort(fra.begin(), fra.end()); - } -} - -void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone) -{ - if (!ob_arm->adt) - return; - - //write bone animations for 3 transform types - //i=0 --> rotations - //i=1 --> scale - //i=2 --> location - for (int i = 0; i < 3; i++) - sample_and_write_bone_animation(ob_arm, bone, i); - - for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) - write_bone_animation(ob_arm, child); -} - -void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type) -{ - bArmature *arm = (bArmature *)ob_arm->data; - int flag = arm->flag; - std::vector<float> fra; - char prefix[256]; - - BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name); - - bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); - if (!pchan) - return; - //Fill frame array with key frame values framed at \param:transform_type - switch (transform_type) { - case 0: - find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); - break; - case 1: - find_keyframes(ob_arm, fra, prefix, "scale"); - break; - case 2: - find_keyframes(ob_arm, fra, prefix, "location"); - break; - default: - return; - } - - // exit rest position - if (flag & ARM_RESTPOS) { - arm->flag &= ~ARM_RESTPOS; - BKE_pose_where_is(scene, ob_arm); - } - //v array will hold all values which will be exported. - if (fra.size()) { - float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames"); - sample_animation(values, fra, transform_type, bone, ob_arm, pchan); - - if (transform_type == 0) { - // write x, y, z curves separately if it is rotation - float *axisValues = (float *)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames"); - - for (int i = 0; i < 3; i++) { - for (unsigned int j = 0; j < fra.size(); j++) - axisValues[j] = values[j * 3 + i]; - - dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name); - } - MEM_freeN(axisValues); - } - else { - // write xyz at once if it is location or scale - dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name); - } - - MEM_freeN(values); - } - - // restore restpos - if (flag & ARM_RESTPOS) - arm->flag = flag; - BKE_pose_where_is(scene, ob_arm); -} - -void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan) -{ - bPoseChannel *parchan = NULL; - bPose *pose = ob_arm->pose; - - pchan = BKE_pose_channel_find_name(pose, bone->name); - - if (!pchan) - return; - - parchan = pchan->parent; - - enable_fcurves(ob_arm->adt->action, bone->name); - - std::vector<float>::iterator it; - for (it = frames.begin(); it != frames.end(); it++) { - float mat[4][4], ipar[4][4]; + FCurve *fcu; + Key *key = BKE_key_from_object(ob); + if (!key) return; - float ctime = BKE_scene_frame_get_from_ctime(scene, *it); + if (key->adt && key->adt->action) { + fcu = (FCurve *)key->adt->action->curves.first; + while (fcu) { + BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path); - BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM); - BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1); + create_keyframed_animation(ob, fcu, tm_type, true, sampler); - // compute bone local mat - if (bone->parent) { - invert_m4_m4(ipar, parchan->pose_mat); - mul_m4_m4m4(mat, ipar, pchan->pose_mat); - } - else - copy_m4_m4(mat, pchan->pose_mat); - - switch (type) { - case 0: - mat4_to_eul(v, mat); - break; - case 1: - mat4_to_size(v, mat); - break; - case 2: - copy_v3_v3(v, mat[3]); - break; + fcu = fcu->next; } - - v += 3; } - enable_fcurves(ob_arm->adt->action, NULL); -} - -bool AnimationExporter::validateConstraints(bConstraint *con) -{ - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - /* these we can skip completely (invalid constraints...) */ - if (cti == NULL) - return false; - if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) - return false; - - /* these constraints can't be evaluated anyway */ - if (cti->evaluate_constraint == NULL) - return false; - - /* influence == 0 should be ignored */ - if (con->enforce == 0.0f) - return false; - - /* validation passed */ - return true; } +#endif diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h index b6b67847f4e..969669ef11d 100644 --- a/source/blender/collada/AnimationExporter.h +++ b/source/blender/collada/AnimationExporter.h @@ -20,9 +20,15 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __BC_ANIMATION_EXPORTER_H__ +#define __BC_ANIMATION_EXPORTER_H__ + #include <stdlib.h> #include <stdio.h> #include <math.h> + +#include "BCAnimationCurve.h" + extern "C" { #include "DNA_scene_types.h" @@ -42,7 +48,6 @@ extern "C" #include "BLI_listbase.h" #include "BLI_utildefines.h" -#include "BKE_DerivedMesh.h" #include "BKE_fcurve.h" #include "BKE_animsys.h" #include "BKE_scene.h" @@ -71,40 +76,45 @@ extern "C" #include "COLLADASWBaseInputElement.h" #include "EffectExporter.h" - +#include "BCAnimationSampler.h" #include "collada_internal.h" #include "IK_solver.h" #include <vector> +#include <map> #include <algorithm> // std::find +struct Depsgraph; +typedef enum BC_animation_source_type { + BC_SOURCE_TYPE_VALUE, + BC_SOURCE_TYPE_ANGLE, + BC_SOURCE_TYPE_TIMEFRAME +} BC_animation_source_type; class AnimationExporter: COLLADASW::LibraryAnimations { private: - Main *m_bmain; - Scene *scene; + BlenderContext &blender_context; COLLADASW::StreamWriter *sw; + const ExportSettings *export_settings; public: - AnimationExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings): + AnimationExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings): COLLADASW::LibraryAnimations(sw), + blender_context(blender_context), + sw(sw), export_settings(export_settings) - { - this->sw = sw; - } + {} - bool exportAnimations(Main *bmain, Scene *sce); + bool exportAnimations(); // called for each exported object void operator() (Object *ob); protected: - const ExportSettings *export_settings; - void export_object_constraint_animation(Object *ob); @@ -116,8 +126,6 @@ protected: void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type); - bool is_bone_deform_group(Bone * bone); - void sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone); void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pChan); @@ -136,70 +144,123 @@ protected: float convert_angle(float angle); + std::vector<std::vector<std::string>> anim_meta; + + /* Main entry point into Animation export (called for each exported object) */ + void exportAnimation(Object *ob, BCAnimationSampler &sampler); + + /* export animation as separate trans/rot/scale curves */ + void export_curve_animation_set( + Object *ob, + BCAnimationSampler &sampler, + bool export_tm_curves); + + /* export one single curve */ + void export_curve_animation( + Object *ob, + BCAnimationCurve &curve); + + /* export animation as matrix data */ + void export_matrix_animation( + Object *ob, + BCAnimationSampler &sampler); + + /* step through the bone hierarchy */ + void export_bone_animations_recursive( + Object *ob_arm, + Bone *bone, + BCAnimationSampler &sampler); + + /* Export for one bone */ + void export_bone_animation( + Object *ob, + Bone *bone, + BCFrames &frames, + BCMatrixSampleMap &outmats); + + /* call to the low level collada exporter */ + void export_collada_curve_animation( + std::string id, + std::string name, + std::string target, + std::string axis, + BCAnimationCurve &curve); + + /* call to the low level collada exporter */ + void export_collada_matrix_animation( + std::string id, + std::string name, + std::string target, + BCFrames &frames, + BCMatrixSampleMap &outmats); + + BCAnimationCurve *get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves); + + /* Helper functions */ + void openAnimationWithClip(std::string id, std::string name); + bool open_animation_container(bool has_container, Object *ob); + void close_animation_container(bool has_container); + + /* Input and Output sources (single valued) */ + std::string collada_source_from_values( + BC_animation_source_type tm_channel, + COLLADASW::InputSemantic::Semantics semantic, + std::vector<float> &values, + const std::string& anim_id, + const std::string axis_name); + + /* Output sources (matrix data) */ + std::string collada_source_from_values( + BCMatrixSampleMap &samples, + const std::string& anim_id); + + /* Interpolation sources */ + std::string collada_linear_interpolation_source( + int tot, + const std::string& anim_id); + + /* source ID = animation_name + semantic_suffix */ + std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic); void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, - COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform); - - void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length); - - float* get_eul_source_for_quat(Object *ob ); - - bool is_flat_line(std::vector<float> &values, int channel_count); - void export_keyframed_animation_set(Object *ob); - void create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL); - void export_sampled_animation_set(Object *ob); - void export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes); - void export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes); - void create_sampled_animation(int channel_count, std::vector<float> ×, std::vector<float> &values, std::string, std::string label, std::string axis_name, bool is_rot); - - void evaluate_anim_with_constraints(Object *ob, float ctime); + COLLADASW::InputSemantic::Semantics semantic, + bool is_rot, + const std::string axis, + bool transform); - std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name); - std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob); + int get_point_in_curve(BCBezTriple &bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values); + int get_point_in_curve(const BCAnimationCurve &curve, float sample_frame, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values); - std::string create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id); + std::string collada_tangent_from_curve( + COLLADASW::InputSemantic::Semantics semantic, + BCAnimationCurve &curve, + const std::string& anim_id, + const std::string axis_name); - std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name); + std::string collada_interpolation_source(const BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name, bool *has_tangents); - std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name); + std::string get_axis_name(std::string channel, int id); + const std::string get_collada_name(std::string channel_target) const; + std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name); - std::string create_xyz_source(float *v, int tot, const std::string& anim_id); - std::string create_4x4_source(std::vector<float> ×, std::vector<float> &values, const std::string& anim_id); - std::string create_4x4_source(std::vector<float> &frames, Object * ob_arm, Bone *bone, const std::string& anim_id); + /* ===================================== */ + /* Currently unused or not (yet?) needed */ + /* ===================================== */ - std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents); - - std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name); - - // for rotation, axis name is always appended and the value of append_axis is ignored - std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); - std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); - std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); - - void find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name); - void find_keyframes(Object *ob, std::vector<float> &fra); - void find_sampleframes(Object *ob, std::vector<float> &fra); - - - void make_anim_frames_from_targets(Object *ob, std::vector<float> &frames ); - - void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode); - - // enable fcurves driving a specific bone, disable all the rest - // if bone_name = NULL enable all fcurves - void enable_fcurves(bAction *act, char *bone_name); - - bool hasAnimations(Scene *sce); - - char *extract_transform_name(char *rna_path); - - std::string getObjectBoneName(Object *ob, const FCurve * fcu); - std::string getAnimationPathId(const FCurve *fcu); - - void getBakedPoseData(Object *obarm, int startFrame, int endFrame, bool ActionBake, bool ActionBakeFirstFrame); + bool is_bone_deform_group(Bone * bone); - bool validateConstraints(bConstraint *con); +#if 0 + BC_animation_transform_type _get_transform_type(const std::string path); + void get_eul_source_for_quat(std::vector<float> &cache, Object *ob); +#endif +#ifdef WITH_MORPH_ANIMATION + void export_morph_animation( + Object *ob, + BCAnimationSampler &sampler); +#endif }; + +#endif diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 3dda67abbba..a4b14d9d175 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -107,11 +107,9 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve"); fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); - // fcu->rna_path = BLI_strdupn(path, strlen(path)); fcu->array_index = 0; - //fcu->totvert = curve->getKeyCount(); + fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; - // create beztriple for each key for (unsigned int j = 0; j < curve->getKeyCount(); j++) { BezTriple bez; memset(&bez, 0, sizeof(BezTriple)); @@ -120,7 +118,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) // input, output bez.vec[1][0] = bc_get_float_value(input, j) * fps; bez.vec[1][1] = bc_get_float_value(output, j * dim + i); - + bez.h1 = bez.h2 = HD_AUTO; if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER || curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_STEP) @@ -135,14 +133,15 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) // outtangent bez.vec[2][0] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i)) * fps; bez.vec[2][1] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i) + 1); - if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) + if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) { bez.ipo = BEZT_IPO_BEZ; - else + bez.h1 = bez.h2 = HD_AUTO_ANIM; + } + else { bez.ipo = BEZT_IPO_CONST; - //bez.h1 = bez.h2 = HD_AUTO; + } } else { - bez.h1 = bez.h2 = HD_AUTO; bez.ipo = BEZT_IPO_LIN; } // bez.ipo = U.ipo_new; /* use default interpolation mode here... */ @@ -245,10 +244,6 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain, Object *ob, std::vect } } -AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) : - TransformReader(conv), armature_importer(arm), scene(scene) { -} - AnimationImporter::~AnimationImporter() { // free unused FCurves @@ -304,7 +299,6 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim) bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist) { const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId(); - animlist_map[animlist_id] = animlist; #if 0 @@ -725,7 +719,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid } } -void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, +void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) { bool is_joint = node->getType() == COLLADAFW::Node::JOINT; @@ -840,6 +834,7 @@ void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector add_bezt(newcu[i], fra, scale[i - 7]); } } + Main *bmain = CTX_data_main(mContext); verify_adt_action(bmain, (ID *)&ob->id, 1); ListBase *curves = &ob->adt->action->curves; @@ -908,7 +903,7 @@ static ListBase &get_animation_curves(Main *bmain, Material *ma) return act->curves; } -void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, +void AnimationImporter::translate_Animations(COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map, std::multimap<COLLADAFW::UniqueId, Object *>& object_map, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map, @@ -932,6 +927,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, AnimationImporter::AnimMix *animType = get_animation_type(node, FW_object_map); bAction *act; + Main *bmain = CTX_data_main(mContext); if ( (animType->transform) != 0) { /* const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; */ /* UNUSED */ @@ -940,9 +936,11 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, if (is_joint) armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path)); + if (!ob->adt || !ob->adt->action) + act = verify_adt_action(bmain, (ID *)&ob->id, 1); - if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1); - else act = ob->adt->action; + else + act = ob->adt->action; //Get the list of animation curves of the object ListBase *AnimCurves = &(act->curves); @@ -972,11 +970,11 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, for (unsigned int j = 0; j < bindings.getCount(); j++) { animcurves = curve_map[bindings[j].animation]; if (is_matrix) { - apply_matrix_curves(bmain, ob, animcurves, root, node, transform); + apply_matrix_curves(ob, animcurves, root, node, transform); } else { if (is_joint) { - add_bone_animation_sampled(bmain, ob, animcurves, root, node, transform); + add_bone_animation_sampled(ob, animcurves, root, node, transform); } else { //calculate rnapaths and array index of fcurves according to transformation and animation class @@ -1003,9 +1001,10 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, if ((animType->light) != 0) { Lamp *lamp = (Lamp *) ob->data; - - if (!lamp->adt || !lamp->adt->action) act = verify_adt_action(bmain, (ID *)&lamp->id, 1); - else act = lamp->adt->action; + if (!lamp->adt || !lamp->adt->action) + act = verify_adt_action(bmain, (ID *)&lamp->id, 1); + else + act = lamp->adt->action; ListBase *AnimCurves = &(act->curves); const COLLADAFW::InstanceLightPointerArray& nodeLights = node->getInstanceLights(); @@ -1036,6 +1035,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, } if (animType->camera != 0) { + Camera *cam = (Camera *) ob->data; if (!cam->adt || !cam->adt->action) act = verify_adt_action(bmain, (ID *)&cam->id, 1); @@ -1090,6 +1090,12 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, } if (animType->material != 0) { + Material *ma = give_current_material(ob, 1); + if (!ma->adt || !ma->adt->action) + act = verify_adt_action(bmain, (ID *)&ma->id, 1); + else + act = ma->adt->action; + const COLLADAFW::InstanceGeometryPointerArray& nodeGeoms = node->getInstanceGeometries(); for (unsigned int i = 0; i < nodeGeoms.getCount(); i++) { const COLLADAFW::MaterialBindingArray& matBinds = nodeGeoms[i]->getMaterialBindings(); @@ -1136,7 +1142,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, delete animType; } -void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) +void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) { const char *bone_name = bc_get_joint_name(node); char joint_path[200]; @@ -1259,6 +1265,7 @@ void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std: add_bezt(newcu[i], fra, scale[i - 7]); } } + Main *bmain = CTX_data_main(mContext); verify_adt_action(bmain, (ID *)&ob->id, 1); // add curves @@ -1291,7 +1298,7 @@ AnimationImporter::AnimMix *AnimationImporter::get_animation_type(const COLLADAF continue; } else { - types->transform = types->transform | NODE_TRANSFORM; + types->transform = types->transform | BC_NODE_TRANSFORM; break; } } @@ -1435,7 +1442,7 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N // prerequisites: // animlist_map - map animlist id -> animlist // curve_map - map anim id -> curve(s) -Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node *node, +Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Object *>& object_map, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map, COLLADAFW::Transformation::TransformationType tm_type, @@ -1657,7 +1664,7 @@ Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node } #endif } - + Main *bmain = CTX_data_main(mContext); verify_adt_action(bmain, (ID *)&ob->id, 1); ListBase *curves = &ob->adt->action->curves; @@ -1775,24 +1782,24 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float else if (is_translate) dae_translate_to_v3(tm, vec); - for (unsigned int j = 0; j < bindings.getCount(); j++) { - const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j]; + for (unsigned int index = 0; index < bindings.getCount(); index++) { + const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[index]; std::vector<FCurve *>& curves = curve_map[binding.animation]; COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass; char path[100]; switch (type) { case COLLADAFW::Transformation::ROTATE: - BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j); + BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, index); break; case COLLADAFW::Transformation::SCALE: - BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j); + BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, index); break; case COLLADAFW::Transformation::TRANSLATE: - BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j); + BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, index); break; case COLLADAFW::Transformation::MATRIX: - BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j); + BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, index); break; default: break; @@ -1938,7 +1945,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No job->lay = BKE_scene_base_find(scene, job)->lay = 2; mul_v3_fl(job->size, 0.5f); - DAG_id_tag_update(&job->id, OB_RECALC_OB); + DEG_id_tag_update(&job->id, ID_RECALC_TRANSFORM); verify_adt_action((ID *)&job->id, 1); @@ -1959,14 +1966,14 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No if (par_job) { job->parent = par_job; - DAG_id_tag_update(&par_job->id, OB_RECALC_OB); + DEG_id_tag_update(&par_job->id, ID_RECALC_TRANSFORM); job->parsubstr[0] = 0; } BKE_object_where_is_calc(scene, job); // after parenting and layer change - DAG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(CTX_data_main(C)); joint_objects[node->getUniqueId()] = job; } diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h index ff49bc369cf..d6d5ad03a88 100644 --- a/source/blender/collada/AnimationImporter.h +++ b/source/blender/collada/AnimationImporter.h @@ -42,6 +42,7 @@ #include "COLLADAFWInstanceGeometry.h" extern "C" { +#include "BKE_context.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -65,7 +66,7 @@ public: class AnimationImporter : private TransformReader, public AnimationImporterBase { private: - + bContext *mContext; ArmatureImporter *armature_importer; Scene *scene; @@ -124,8 +125,8 @@ private: enum AnimationType { - INANIMATE = 0, - NODE_TRANSFORM = 1, + BC_INANIMATE = 0, + BC_NODE_TRANSFORM = 1 }; struct AnimMix @@ -138,7 +139,11 @@ private: }; public: - AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene); + AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene) : + TransformReader(conv), + mContext(C), + armature_importer(arm), + scene(scene) {} ~AnimationImporter(); @@ -153,7 +158,7 @@ public: virtual void change_eul_to_quat(Object *ob, bAction *act); #endif - void translate_Animations(Main *bmain, COLLADAFW::Node * Node, + void translate_Animations(COLLADAFW::Node * Node, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, std::multimap<COLLADAFW::UniqueId, Object*>& object_map, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map, @@ -161,10 +166,10 @@ public: AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map ); - void apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, + void apply_matrix_curves(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm ); - void add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm); + void add_bone_animation_sampled(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm); void Assign_transform_animations(COLLADAFW::Transformation* transform, const COLLADAFW::AnimationList::AnimationBinding *binding, @@ -181,12 +186,11 @@ public: // prerequisites: // animlist_map - map animlist id -> animlist // curve_map - map anim id -> curve(s) - Object *translate_animation_OLD( - Main *bmain, COLLADAFW::Node *node, - std::map<COLLADAFW::UniqueId, Object*>& object_map, - std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, - COLLADAFW::Transformation::TransformationType tm_type, - Object *par_job = NULL); + Object *translate_animation_OLD(COLLADAFW::Node *node, + std::map<COLLADAFW::UniqueId, Object *>& object_map, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map, + COLLADAFW::Transformation::TransformationType tm_type, + Object *par_job = NULL); void find_frames( std::vector<float>* frames, std::vector<FCurve*>* curves ); void find_frames_old( std::vector<float>* frames, COLLADAFW::Node * node, COLLADAFW::Transformation::TransformationType tm_type ); diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 432ce92b49d..055ffc39e9a 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -39,10 +39,8 @@ #include "BKE_armature.h" extern "C" { -#include "BKE_main.h" -#include "BKE_mesh.h" #include "BKE_global.h" -#include "BKE_library.h" +#include "BKE_mesh.h" } #include "ED_armature.h" @@ -55,42 +53,41 @@ extern "C" { #include "collada_utils.h" -// XXX exporter writes wrong data for shared armatures. A separate -// controller should be written for each armature-mesh binding how do -// we make controller ids then? -ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) { -} - // write bone nodes -void ArmatureExporter::add_armature_bones(bContext *C, Object *ob_arm, Scene *sce, - SceneExporter *se, - std::list<Object *>& child_objects) +void ArmatureExporter::add_armature_bones( + Object *ob_arm, + ViewLayer *view_layer, + SceneExporter *se, + std::vector<Object *>& child_objects) + { - Main *bmain = CTX_data_main(C); // write bone nodes bArmature *armature = (bArmature *)ob_arm->data; bool is_edited = armature->edbo != NULL; - if (!is_edited) + if (!is_edited) { ED_armature_to_edit(armature); + } for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) { // start from root bones - if (!bone->parent) - add_bone_node(C, bone, ob_arm, sce, se, child_objects); + if (!bone->parent) { + add_bone_node(bone, ob_arm, se, child_objects); + } } if (!is_edited) { - ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); } } void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) { - if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) - ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone))); + if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) { + std::string joint_id = translate_id(id_name(ob_arm) + "_" + bone->name); + ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, joint_id)); + } else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { write_bone_URLs(ins, ob_arm, child); @@ -117,10 +114,7 @@ bool ArmatureExporter::add_instance_controller(Object *ob) write_bone_URLs(ins, ob_arm, bone); } - InstanceWriter::add_material_bindings(ins.getBindMaterial(), - ob, - this->export_settings->active_uv_only, - this->export_settings->export_texture_type); + InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only); ins.add(); return true; @@ -161,12 +155,14 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O #endif // parent_mat is armature-space -void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Scene *sce, - SceneExporter *se, - std::list<Object *>& child_objects) +void ArmatureExporter::add_bone_node( + Bone *bone, + Object *ob_arm, + SceneExporter *se, + std::vector<Object *>& child_objects) { if (!(this->export_settings->deform_bones_only && bone->flag & BONE_NO_DEFORM)) { - std::string node_id = get_joint_id(ob_arm, 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); @@ -206,7 +202,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Sc add_bone_transform(ob_arm, bone, node); // Write nodes of childobjects, remove written objects from list - std::list<Object *>::iterator i = child_objects.begin(); + std::vector<Object *>::iterator i = child_objects.begin(); while (i != child_objects.end()) { if ((*i)->partype == PARBONE && STREQ((*i)->parsubstr, bone->name)) { @@ -235,8 +231,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Sc mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv); } - se->writeNodes(C, *i, sce); - + se->writeNodes(*i); copy_m4_m4((*i)->parentinv, backup_parinv); child_objects.erase(i++); } @@ -244,13 +239,13 @@ void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Sc } for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(C, child, ob_arm, sce, se, child_objects); + 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(C, child, ob_arm, sce, se, child_objects); + add_bone_node(child, ob_arm, se, child_objects); } } } @@ -309,7 +304,7 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW: } if (this->export_settings->limit_precision) - bc_sanitize_mat(mat, 6); + bc_sanitize_mat(mat, LIMITTED_PRECISION); TransformWriter::add_node_transform(node, mat, NULL); diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h index 3199703cb20..1a8080ad613 100644 --- a/source/blender/collada/ArmatureExporter.h +++ b/source/blender/collada/ArmatureExporter.h @@ -57,20 +57,26 @@ class SceneExporter; class ArmatureExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter { public: - ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); - // write bone nodes - void add_armature_bones(bContext *C, Object *ob_arm, Scene *sce, SceneExporter *se, - std::list<Object *>& child_objects); + // XXX exporter writes wrong data for shared armatures. A separate + // controller should be written for each armature-mesh binding how do + // we make controller ids then? + ArmatureExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : + COLLADASW::LibraryControllers(sw), + blender_context(blender_context), + export_settings(export_settings) + {} + + void add_armature_bones( + Object *ob_arm, + ViewLayer *view_layer, + SceneExporter *se, + std::vector<Object *>& child_objects); bool add_instance_controller(Object *ob); - //void export_controllers(Scene *sce);*/ - - //void operator()(Object *ob); - private: - UnitConverter converter; + BlenderContext &blender_context; const ExportSettings *export_settings; #if 0 @@ -85,8 +91,11 @@ private: // Scene, SceneExporter and the list of child_objects // are required for writing bone parented objects - void add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se, - std::list<Object *>& child_objects); + void add_bone_node( + Bone *bone, + Object *ob_arm, + SceneExporter *se, + std::vector<Object *>& child_objects); void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node); diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index a96d1e76a99..cfafa5016ec 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -34,7 +34,6 @@ extern "C" { #include "BKE_action.h" -#include "BKE_depsgraph.h" #include "BKE_object.h" #include "BKE_armature.h" #include "BLI_string.h" @@ -42,6 +41,8 @@ extern "C" { #include "ED_armature.h" } +#include "DEG_depsgraph.h" + #include "collada_utils.h" #include "ArmatureImporter.h" @@ -54,10 +55,12 @@ static const char *bc_get_joint_name(T *node) } -ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, const ImportSettings *import_settings) : +ArmatureImporter::ArmatureImporter( + UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings) : TransformReader(conv), m_bmain(bmain), scene(sce), + view_layer(view_layer), unit_converter(conv), import_settings(import_settings), empty(NULL), @@ -169,7 +172,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon } copy_v3_v3(bone->head, mat[3]); - if (bone_is_skinned) + if (bone_is_skinned && this->import_settings->keep_bind_info) { float rest_mat[4][4]; get_node_mat(rest_mat, node, NULL, NULL, NULL); @@ -410,7 +413,7 @@ Object *ArmatureImporter::get_empty_for_leaves() { if (empty) return empty; - empty = bc_add_object(m_bmain, scene, OB_EMPTY, NULL); + empty = bc_add_object(m_bmain, scene, view_layer, OB_EMPTY, NULL); empty->empty_drawtype = OB_EMPTY_SPHERE; return empty; @@ -496,7 +499,7 @@ void ArmatureImporter::create_armature_bones(Main *bmain, std::vector<Object *> ob_arms.push_back(ob_arm); } - DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob_arm->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } } @@ -585,7 +588,7 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin) ob_arm = skin.set_armature(shared); } else { - ob_arm = skin.create_armature(m_bmain, scene); //once for every armature + ob_arm = skin.create_armature(m_bmain, scene, view_layer); //once for every armature } // enter armature edit mode @@ -629,7 +632,7 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin) ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); - DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&ob_arm->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); return ob_arm; } @@ -879,7 +882,7 @@ void ArmatureImporter::make_shape_keys(bContext *C) //insert basis key kb = BKE_keyblock_add_ctime(key, "Basis", false); - BKE_keyblock_convert_from_mesh(source_me, kb); + BKE_keyblock_convert_from_mesh(source_me, key, kb); //insert other shape keys for (int i = 0 ; i < morphTargetIds.getCount() ; i++ ) { @@ -893,7 +896,7 @@ void ArmatureImporter::make_shape_keys(bContext *C) std::string morph_name = *this->mesh_importer->get_geometry_name(me->id.name); kb = BKE_keyblock_add_ctime(key, morph_name.c_str(), false); - BKE_keyblock_convert_from_mesh(me, kb); + BKE_keyblock_convert_from_mesh(me, key, kb); //apply weights weight = morphWeights.getFloatValues()->getData()[i]; diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index a215b186f75..419861554f4 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -64,6 +64,7 @@ class ArmatureImporter : private TransformReader private: Main *m_bmain; Scene *scene; + ViewLayer *view_layer; UnitConverter *unit_converter; const ImportSettings *import_settings; @@ -138,7 +139,8 @@ private: TagsMap uid_tags_map; public: - ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, const ImportSettings *import_settings); + ArmatureImporter( + UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings); ~ArmatureImporter(); void add_root_joint(COLLADAFW::Node *node, Object *parent); diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp new file mode 100644 index 00000000000..74d852ae980 --- /dev/null +++ b/source/blender/collada/BCAnimationCurve.cpp @@ -0,0 +1,678 @@ +/* +* ***** 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. +* +* The Original Code is Copyright (C) 2008 Blender Foundation. +* All rights reserved. +* +* Contributor(s): Blender Foundation +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "BCAnimationCurve.h" + +BCAnimationCurve::BCAnimationCurve() +{ + this->curve_key.set_object_type(BC_ANIMATION_TYPE_OBJECT); + this->fcurve = NULL; + this->curve_is_local_copy = false; +} + +BCAnimationCurve::BCAnimationCurve(const BCAnimationCurve &other) +{ + this->min = other.min; + this->max = other.max; + this->fcurve = other.fcurve; + this->curve_key = other.curve_key; + this->curve_is_local_copy = false; + this->id_ptr = other.id_ptr; + + /* The fcurve of the new instance is a copy and can be modified */ + + get_edit_fcurve(); +} + +BCAnimationCurve::BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu) +{ + this->min = 0; + this->max = 0; + this->curve_key = key; + this->fcurve = fcu; + this->curve_is_local_copy = false; + init_pointer_rna(ob); +} + +BCAnimationCurve::BCAnimationCurve(const BCCurveKey &key, Object *ob) +{ + this->curve_key = key; + this->fcurve = NULL; + this->curve_is_local_copy = false; + init_pointer_rna(ob); +} + +void BCAnimationCurve::init_pointer_rna(Object *ob) +{ + switch (this->curve_key.get_animation_type()) { + case BC_ANIMATION_TYPE_BONE: + { + bArmature *arm = (bArmature *)ob->data; + RNA_id_pointer_create(&arm->id, &id_ptr); + } + break; + case BC_ANIMATION_TYPE_OBJECT: + { + RNA_id_pointer_create(&ob->id, &id_ptr); + } + break; + case BC_ANIMATION_TYPE_MATERIAL: + { + Material *ma = give_current_material(ob, curve_key.get_subindex() + 1); + RNA_id_pointer_create(&ma->id, &id_ptr); + } + break; + case BC_ANIMATION_TYPE_CAMERA: + { + Camera *camera = (Camera *)ob->data; + RNA_id_pointer_create(&camera->id, &id_ptr); + } + break; + case BC_ANIMATION_TYPE_LIGHT: + { + Lamp *lamp = (Lamp *)ob->data; + RNA_id_pointer_create(&lamp->id, &id_ptr); + } + break; + default: + fprintf(stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index()); + break; + } +} + +void BCAnimationCurve::delete_fcurve(FCurve *fcu) +{ + free_fcurve(fcu); +} + +FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path) +{ + FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve"); + fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); + fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); + fcu->array_index = array_index; + return fcu; +} + +void BCAnimationCurve::create_bezt(float frame, float output) +{ + FCurve *fcu = get_edit_fcurve(); + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + bez.vec[1][0] = frame; + bez.vec[1][1] = output; + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS); + calchandles_fcurve(fcu); +} + +BCAnimationCurve::~BCAnimationCurve() +{ + if (curve_is_local_copy && fcurve) { + //fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path); + delete_fcurve(fcurve); + this->fcurve = NULL; + } +} + +const bool BCAnimationCurve::is_of_animation_type(BC_animation_type type) const +{ + return curve_key.get_animation_type() == type; +} + +const std::string BCAnimationCurve::get_channel_target() const +{ + const std::string path = curve_key.get_path(); + return bc_string_after(path, '.'); +} + +const std::string BCAnimationCurve::get_animation_name(Object *ob) const +{ + std::string name; + + switch (curve_key.get_animation_type()) { + case BC_ANIMATION_TYPE_OBJECT: + { + name = id_name(ob); + } + break; + + case BC_ANIMATION_TYPE_BONE: + { + if (fcurve == NULL || fcurve->rna_path == NULL) + name = ""; + else { + const char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones["); + name = (boneName) ? std::string(boneName) : ""; + } + } + break; + + case BC_ANIMATION_TYPE_CAMERA: + { + Camera *camera = (Camera *)ob->data; + name = id_name(ob) + "-" + id_name(camera) + "-camera"; + } + break; + + case BC_ANIMATION_TYPE_LIGHT: + { + Lamp *lamp = (Lamp *)ob->data; + name = id_name(ob) + "-" + id_name(lamp) + "-light"; + } + break; + + case BC_ANIMATION_TYPE_MATERIAL: + { + Material *ma = give_current_material(ob, this->curve_key.get_subindex() + 1); + name = id_name(ob) + "-" + id_name(ma) + "-material"; + } + break; + + default: + { + name = ""; + } + } + + return name; +} + +const int BCAnimationCurve::get_channel_index() const +{ + return curve_key.get_array_index(); +} + +const int BCAnimationCurve::get_subindex() const +{ + return curve_key.get_subindex(); +} + +const std::string BCAnimationCurve::get_rna_path() const +{ + return curve_key.get_path(); +} + +const int BCAnimationCurve::sample_count() const +{ + if (fcurve == NULL) + return 0; + return fcurve->totvert; +} + +const int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const +{ + if (fcurve == NULL) + return -1; + + const int cframe = fcurve->bezt[start_at].vec[1][0]; // inacurate! + + if (fabs(cframe - sample_frame) < 0.00001) + return start_at; + return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at; +} + +const int BCAnimationCurve::closest_index_below(const float sample_frame) const +{ + if (fcurve == NULL) + return -1; + + float lower_frame = sample_frame; + float upper_frame = sample_frame; + int lower_index = 0; + int upper_index = 0; + + for (int fcu_index = 0; fcu_index < fcurve->totvert; ++fcu_index) { + upper_index = fcu_index; + + const int cframe = fcurve->bezt[fcu_index].vec[1][0]; // inacurate! + if (cframe <= sample_frame) { + lower_frame = cframe; + lower_index = fcu_index; + } + if (cframe >= sample_frame) { + upper_frame = cframe; + break; + } + } + + if (lower_index == upper_index) + return lower_index; + + const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame); + return (fraction < 0.5) ? lower_index : upper_index; +} + +const int BCAnimationCurve::get_interpolation_type(float sample_frame) const +{ + const int index = closest_index_below(sample_frame); + if (index < 0) + return BEZT_IPO_BEZ; + return fcurve->bezt[index].ipo; +} + +const FCurve *BCAnimationCurve::get_fcurve() const +{ + return fcurve; +} + +FCurve *BCAnimationCurve::get_edit_fcurve() +{ + if (!curve_is_local_copy) { + const int index = curve_key.get_array_index(); + const std::string &path = curve_key.get_path(); + fcurve = create_fcurve(index, path.c_str()); + + /* Caution here: + Replacing the pointer here is OK only because the original value + of FCurve was a const pointer into Blender territory. We do not + touch that! We use the local copy to prepare data for export. + */ + + curve_is_local_copy = true; + } + return fcurve; +} + +void BCAnimationCurve::clean_handles() +{ + if (fcurve == NULL) + fcurve = get_edit_fcurve(); + + /* Keep old bezt data for copy)*/ + BezTriple *old_bezts = fcurve->bezt; + int totvert = fcurve->totvert; + fcurve->bezt = NULL; + fcurve->totvert = 0; + + for (int i = 0; i < totvert; i++) { + BezTriple *bezt = &old_bezts[i]; + float x = bezt->vec[1][0]; + float y = bezt->vec[1][1]; + insert_vert_fcurve(fcurve, x, y, (eBezTriple_KeyframeType)BEZKEYTYPE(bezt), INSERTKEY_NOFLAGS); + BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1); + lastb->f1 = lastb->f2 = lastb->f3 = 0; + } + + /* now free the memory used by the old BezTriples */ + if (old_bezts) + MEM_freeN(old_bezts); +} + +const bool BCAnimationCurve::is_transform_curve() const +{ + std::string channel_target = this->get_channel_target(); + return ( + is_rotation_curve() || + channel_target == "scale" || + channel_target == "location" + ); +} + +const bool BCAnimationCurve::is_rotation_curve() const +{ + std::string channel_target = this->get_channel_target(); + return ( + channel_target == "rotation" || + channel_target == "rotation_euler" || + channel_target == "rotation_quaternion" + ); +} + +const float BCAnimationCurve::get_value(const float frame) +{ + if (fcurve) { + return evaluate_fcurve(fcurve, frame); + } + return 0; // TODO: handle case where neither sample nor fcu exist +} + +void BCAnimationCurve::update_range(float val) +{ + if (val < min) { + min = val; + } + if (val > max) { + max = val; + } +} + +void BCAnimationCurve::init_range(float val) +{ + min = max = val; +} + +void BCAnimationCurve::adjust_range(const int frame_index) +{ + if (fcurve && fcurve->totvert > 1) { + const float eval = evaluate_fcurve(fcurve, frame_index); + + int first_frame = fcurve->bezt[0].vec[1][0]; + if (first_frame == frame_index) { + init_range(eval); + } + else { + update_range(eval); + } + } +} + +void BCAnimationCurve::add_value(const float val, const int frame_index) +{ + FCurve *fcu = get_edit_fcurve(); + fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + insert_vert_fcurve( + fcu, + frame_index, val, + BEZT_KEYTYPE_KEYFRAME, + INSERTKEY_NOFLAGS); + + if (fcu->totvert == 1) { + init_range(val); + } + else { + update_range(val); + } +} + +bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index) +{ + int array_index = curve_key.get_array_index(); + + /* transformation curves are feeded directly from the transformation matrix + * to resolve parent inverse matrix issues with object hierarchies. + * Maybe this can be unified with the + */ + const std::string channel_target = get_channel_target(); + float val = 0; + /* Pick the value from the sample according to the definition of the FCurve */ + bool good = sample.get_value(channel_target, array_index, &val); + if (good) { + add_value(val, frame_index); + } + return good; +} + +bool BCAnimationCurve::add_value_from_rna(const int frame_index) +{ + PointerRNA ptr; + PropertyRNA *prop; + float value = 0.0f; + int array_index = curve_key.get_array_index(); + const std::string full_path = curve_key.get_full_path(); + + /* get property to read from, and get value as appropriate */ + bool path_resolved = RNA_path_resolve_full(&id_ptr, full_path.c_str(), &ptr, &prop, &array_index); + if (!path_resolved && array_index == 0) { + const std::string rna_path = curve_key.get_path(); + path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index); + } + + if (path_resolved) { + bool is_array = RNA_property_array_check(prop); + if (is_array) { + /* array */ + if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) { + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + value = (float)RNA_property_boolean_get_index(&ptr, prop, array_index); + break; + case PROP_INT: + value = (float)RNA_property_int_get_index(&ptr, prop, array_index); + break; + case PROP_FLOAT: + value = RNA_property_float_get_index(&ptr, prop, array_index); + break; + default: + break; + } + } + else { + fprintf(stderr, "Out of Bounds while reading data for Curve %s\n", curve_key.get_full_path().c_str()); + return false; + } + } + else { + /* not an array */ + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + value = (float)RNA_property_boolean_get(&ptr, prop); + break; + case PROP_INT: + value = (float)RNA_property_int_get(&ptr, prop); + break; + case PROP_FLOAT: + value = RNA_property_float_get(&ptr, prop); + break; + case PROP_ENUM: + value = (float)RNA_property_enum_get(&ptr, prop); + break; + default: + fprintf(stderr, "property type %d not supported for Curve %s\n", RNA_property_type(prop), curve_key.get_full_path().c_str()); + return false; + break; + } + } + } + else { + /* path couldn't be resolved */ + fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str()); + return false; + } + + add_value(value, frame_index); + return true; +} + +void BCAnimationCurve::get_value_map(BCValueMap &value_map) +{ + value_map.clear(); + if (fcurve == NULL) { + return; + } + + for (int i = 0; i < fcurve->totvert; i++) { + const float frame = fcurve->bezt[i].vec[1][0]; + const float val = fcurve->bezt[i].vec[1][1]; + value_map[frame] = val; + } +} + +void BCAnimationCurve::get_frames(BCFrames &frames) const +{ + frames.clear(); + if (fcurve) { + for (int i = 0; i < fcurve->totvert; i++) { + const float val = fcurve->bezt[i].vec[1][0]; + frames.push_back(val); + } + } +} + +void BCAnimationCurve::get_values(BCValues &values) const +{ + values.clear(); + if (fcurve) { + for (int i = 0; i < fcurve->totvert; i++) { + const float val = fcurve->bezt[i].vec[1][1]; + values.push_back(val); + } + } +} + +bool BCAnimationCurve::is_animated() +{ + static float MIN_DISTANCE = 0.00001; + return fabs(max - min) > MIN_DISTANCE; +} + + +bool BCAnimationCurve::is_keyframe(int frame) { + if (this->fcurve == NULL) + return false; + + for (int i = 0; i < fcurve->totvert; ++i) { + const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]); + if (cframe == frame) + return true; + if (cframe > frame) + break; + } + return false; +} + +/* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */ +inline bool operator< (const BCAnimationCurve& lhs, const BCAnimationCurve& rhs) { + std::string lhtgt = lhs.get_channel_target(); + std::string rhtgt = rhs.get_channel_target(); + if (lhtgt == rhtgt) + { + const int lha = lhs.get_channel_index(); + const int rha = rhs.get_channel_index(); + return lha < rha; + } + else + return lhtgt < rhtgt; +} + +BCCurveKey::BCCurveKey() +{ + this->key_type = BC_ANIMATION_TYPE_OBJECT; + this->rna_path = ""; + this->curve_array_index = 0; + this->curve_subindex = -1; +} + +BCCurveKey::BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex) +{ + this->key_type = type; + this->rna_path = path; + this->curve_array_index = array_index; + this->curve_subindex = subindex; +} + +void BCCurveKey::operator=(const BCCurveKey &other) +{ + this->key_type = other.key_type; + this->rna_path = other.rna_path; + this->curve_array_index = other.curve_array_index; + this->curve_subindex = other.curve_subindex; +} + +const std::string BCCurveKey::get_full_path() const +{ + return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']'; +} + +const std::string BCCurveKey::get_path() const +{ + return this->rna_path; +} + +const int BCCurveKey::get_array_index() const +{ + return this->curve_array_index; +} + +const int BCCurveKey::get_subindex() const +{ + return this->curve_subindex; +} + +void BCCurveKey::set_object_type(BC_animation_type object_type) +{ + this->key_type = object_type; +} + +const BC_animation_type BCCurveKey::get_animation_type() const +{ + return this->key_type; +} + +const bool BCCurveKey::operator<(const BCCurveKey &other) const +{ + /* needed for using this class as key in maps and sets */ + if (this->key_type != other.key_type) + return this->key_type < other.key_type; + + if (this->curve_subindex != other.curve_subindex) + return this->curve_subindex < other.curve_subindex; + + if (this->rna_path != other.rna_path) + return this->rna_path < other.rna_path; + + return this->curve_array_index < other.curve_array_index; +} + +BCBezTriple::BCBezTriple(BezTriple &bezt) : + bezt(bezt) {} + +const float BCBezTriple::get_frame() const +{ + return bezt.vec[1][0]; +} + +const float BCBezTriple::get_time(Scene *scene) const +{ + return FRA2TIME(bezt.vec[1][0]); +} + +const float BCBezTriple::get_value() const +{ + return bezt.vec[1][1]; +} + +const float BCBezTriple::get_angle() const +{ + return RAD2DEGF(get_value()); +} + +void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const +{ + get_tangent(scene, point, as_angle, 0); +} + +void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const +{ + get_tangent(scene, point, as_angle, 2); +} + +void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const +{ + point[0] = FRA2TIME(bezt.vec[index][0]); + if (bezt.ipo != BEZT_IPO_BEZ) { + /* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data */ + point[0] = 0; + point[1] = 0; + } + else if (as_angle) { + point[1] = RAD2DEGF(bezt.vec[index][1]); + } + else { + point[1] = bezt.vec[index][1]; + } +} diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h new file mode 100644 index 00000000000..c575c969e0f --- /dev/null +++ b/source/blender/collada/BCAnimationCurve.h @@ -0,0 +1,156 @@ +/* +* ***** 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. +* +* The Original Code is Copyright (C) 2008 Blender Foundation. +* All rights reserved. +* +* Contributor(s): Blender Foundation +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __BC_ANIMATION_CURVE_H__ +#define __BC_ANIMATION_CURVE_H__ + +#include "collada_utils.h" +#include "BCSampleData.h" + +extern "C" +{ +#include "MEM_guardedalloc.h" +#include "BKE_fcurve.h" +#include "BKE_armature.h" +#include "BKE_material.h" +#include "ED_anim_api.h" +#include "ED_keyframing.h" +#include "ED_keyframes_edit.h" +} + +typedef float(TangentPoint)[2]; + +typedef std::set<float> BCFrameSet; +typedef std::vector<float> BCFrames; +typedef std::vector<float> BCValues; +typedef std::vector<float> BCTimes; +typedef std::map<int, float> BCValueMap; + +typedef enum BC_animation_type { + BC_ANIMATION_TYPE_OBJECT, + BC_ANIMATION_TYPE_BONE, + BC_ANIMATION_TYPE_CAMERA, + BC_ANIMATION_TYPE_MATERIAL, + BC_ANIMATION_TYPE_LIGHT +} BC_animation_type; + +class BCCurveKey { +private: + BC_animation_type key_type; + std::string rna_path; + int curve_array_index; + int curve_subindex; /* only needed for materials */ + +public: + + BCCurveKey(); + BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex = -1); + void operator=(const BCCurveKey &other); + const std::string get_full_path() const; + const std::string get_path() const; + const int get_array_index() const; + const int get_subindex() const; + void set_object_type(BC_animation_type object_type); + const BC_animation_type get_animation_type() const; + const bool operator<(const BCCurveKey &other) const; + +}; + +class BCBezTriple { +public: + BezTriple & bezt; + + BCBezTriple(BezTriple &bezt); + const float get_frame() const; + const float get_time(Scene *scene) const; + const float get_value() const; + const float get_angle() const; + void get_in_tangent(Scene *scene, float point[2], bool as_angle) const; + void get_out_tangent(Scene *scene, float point[2], bool as_angle) const; + void get_tangent(Scene *scene, float point[2], bool as_angle, int index) const; + +}; + +class BCAnimationCurve { +private: + BCCurveKey curve_key; + float min = 0; + float max = 0; + + bool curve_is_local_copy = false; + FCurve *fcurve; + PointerRNA id_ptr; + void init_pointer_rna(Object *ob); + void delete_fcurve(FCurve *fcu); + FCurve *create_fcurve(int array_index, const char *rna_path); + void create_bezt(float frame, float output); + void update_range(float val); + void init_range(float val); + +public: + BCAnimationCurve(); + BCAnimationCurve(const BCAnimationCurve &other); + BCAnimationCurve(const BCCurveKey &key, Object *ob); + BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu); + ~BCAnimationCurve(); + + const bool is_of_animation_type(BC_animation_type type) const; + const int get_interpolation_type(float sample_frame) const; + bool is_animated(); + const bool is_transform_curve() const; + const bool is_rotation_curve() const; + bool is_keyframe(int frame); + void adjust_range(int frame); + + const std::string get_animation_name(Object *ob) const; /* xxx: this is collada specific */ + const std::string get_channel_target() const; + const int get_channel_index() const; + const int get_subindex() const; + const std::string get_rna_path() const; + const FCurve *get_fcurve() const; + const int sample_count() const; + + const float get_value(const float frame); + void get_values(BCValues &values) const; + void get_value_map(BCValueMap &value_map); + + void get_frames(BCFrames &frames) const; + + /* Curve edit functions create a copy of the underlaying FCurve */ + FCurve *get_edit_fcurve(); + bool add_value_from_rna(const int frame); + bool add_value_from_matrix(const BCSample &sample, const int frame); + void add_value(const float val, const int frame); + void clean_handles(); + + /* experimental stuff */ + const int closest_index_above(const float sample_frame, const int start_at) const; + const int closest_index_below(const float sample_frame) const; + +}; + +typedef std::map<BCCurveKey, BCAnimationCurve *> BCAnimationCurveMap; + +#endif diff --git a/source/blender/collada/BCAnimationSampler.cpp b/source/blender/collada/BCAnimationSampler.cpp new file mode 100644 index 00000000000..5c0c1b4316d --- /dev/null +++ b/source/blender/collada/BCAnimationSampler.cpp @@ -0,0 +1,645 @@ +/* +* ***** 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. +* +* The Original Code is Copyright (C) 2008 Blender Foundation. +* All rights reserved. +* +* Contributor(s): Blender Foundation +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include <vector> +#include <map> +#include <algorithm> // std::find + +#include "ExportSettings.h" +#include "BCAnimationCurve.h" +#include "BCAnimationSampler.h" +#include "collada_utils.h" + +extern "C" { +#include "BKE_action.h" +#include "BKE_constraint.h" +#include "BKE_key.h" +#include "BKE_main.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BLI_listbase.h" +#include "DNA_anim_types.h" +#include "DNA_scene_types.h" +#include "DNA_key_types.h" +#include "DNA_constraint_types.h" +#include "ED_object.h" +} + +static std::string EMPTY_STRING; +static BCAnimationCurveMap BCEmptyAnimationCurves; + +BCAnimationSampler::BCAnimationSampler(BlenderContext &blender_context, BCObjectSet &object_set): + blender_context(blender_context) +{ + BCObjectSet::iterator it; + for (it = object_set.begin(); it != object_set.end(); ++it) { + Object *ob = *it; + add_object(ob); + } +} + +BCAnimationSampler::~BCAnimationSampler() +{ + BCAnimationObjectMap::iterator it; + for (it = objects.begin(); it != objects.end(); ++it) { + BCAnimation *animation = it->second; + delete animation; + } +} + +void BCAnimationSampler::add_object(Object *ob) +{ + BCAnimation *animation = new BCAnimation(blender_context.get_context(), ob); + objects[ob] = animation; + + initialize_keyframes(animation->frame_set, ob); + initialize_curves(animation->curve_map, ob); +} + +BCAnimationCurveMap *BCAnimationSampler::get_curves(Object *ob) +{ + BCAnimation &animation = *objects[ob]; + if (animation.curve_map.size() == 0) + initialize_curves(animation.curve_map, ob); + return &animation.curve_map; +} + +static void get_sample_frames(BCFrameSet &sample_frames, int sampling_rate, bool keyframe_at_end, Scene *scene) +{ + sample_frames.clear(); + + if (sampling_rate < 1) + return; // no sample frames in this case + + float sfra = scene->r.sfra; + float efra = scene->r.efra; + + int frame_index; + for (frame_index = nearbyint(sfra); frame_index < efra; frame_index += sampling_rate) { + sample_frames.insert(frame_index); + } + + if (frame_index >= efra && keyframe_at_end) + { + sample_frames.insert(efra); + } +} + +static bool is_object_keyframe(Object *ob, int frame_index) +{ + return false; +} + +static void add_keyframes_from(bAction *action, BCFrameSet &frameset) +{ + if (action) { + FCurve *fcu = NULL; + for (fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) { + BezTriple *bezt = fcu->bezt; + for (int i = 0; i < fcu->totvert; bezt++, i++) { + int frame_index = nearbyint(bezt->vec[1][0]); + frameset.insert(frame_index); + } + } + } +} + +void BCAnimationSampler::check_property_is_animated(BCAnimation &animation, float *ref, float *val, std::string data_path, int length) +{ + for (int array_index =0; array_index < length; ++array_index) { + if (!bc_in_range(ref[length], val[length], 0.00001)) { + BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index); + BCAnimationCurveMap::iterator it = animation.curve_map.find(key); + if (it == animation.curve_map.end()) { + animation.curve_map[key] = new BCAnimationCurve(key, animation.get_reference()); + } + } + } +} + +void BCAnimationSampler::update_animation_curves(BCAnimation &animation, BCSample &sample, Object *ob, int frame) +{ + BCAnimationCurveMap::iterator it; + for (it = animation.curve_map.begin(); it != animation.curve_map.end(); ++it) { + BCAnimationCurve *curve = it->second; + if (curve->is_transform_curve()) { + curve->add_value_from_matrix(sample, frame); + } + else { + curve->add_value_from_rna(frame); + } + } +} + +BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim) +{ + BCSample &ob_sample = sample_data.add(ob, frame_index); + + if (ob->type == OB_ARMATURE) { + bPoseChannel *pchan; + for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; + Matrix bmat; + if (bc_bone_matrix_local_get(ob, bone, bmat, for_opensim)) { + ob_sample.add_bone_matrix(bone, bmat); + } + } + } + return ob_sample; +} + +void BCAnimationSampler::sample_scene( + int sampling_rate, + int keyframe_at_end, + bool for_opensim, + bool keep_keyframes, + BC_export_animation_type export_animation_type) +{ + Scene *scene = blender_context.get_scene(); + BCFrameSet scene_sample_frames; + get_sample_frames(scene_sample_frames, sampling_rate, keyframe_at_end, scene); + BCFrameSet::iterator it; + + int startframe = scene->r.sfra; + int endframe = scene->r.efra; + + for (int frame_index = startframe; frame_index <= endframe; ++frame_index) { + /* Loop over all frames and decide for each frame if sampling is necessary */ + bool is_scene_sample_frame = false; + bool needs_update = true; + if (scene_sample_frames.find(frame_index) != scene_sample_frames.end()) { + bc_update_scene(blender_context, frame_index); + needs_update = false; + is_scene_sample_frame = true; + } + + bool needs_sampling = is_scene_sample_frame || keep_keyframes || export_animation_type == BC_ANIMATION_EXPORT_KEYS; + if (!needs_sampling) { + continue; + } + + BCAnimationObjectMap::iterator obit; + for (obit = objects.begin(); obit != objects.end(); ++obit) { + Object *ob = obit->first; + BCAnimation *animation = obit->second; + BCFrameSet &object_keyframes = animation->frame_set; + if (is_scene_sample_frame || object_keyframes.find(frame_index) != object_keyframes.end()) { + + if (needs_update) { + bc_update_scene(blender_context, frame_index); + needs_update = false; + } + + BCSample &sample = sample_object(ob, frame_index, for_opensim); + update_animation_curves(*animation, sample, ob, frame_index); + } + } + } +} + +bool BCAnimationSampler::is_animated_by_constraint(Object *ob, ListBase *conlist, std::set<Object *> &animated_objects) +{ + bConstraint *con; + for (con = (bConstraint *)conlist->first; con; con = con->next) { + ListBase targets = { NULL, NULL }; + + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + + if (!bc_validateConstraints(con)) + continue; + + 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; + if (obtar) { + if (animated_objects.find(obtar) != animated_objects.end()) + return true; + } + } + } + } + return false; +} + +void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_objects, std::set<Object *> &candidates) +{ + bool found_more; + do { + found_more = false; + std::set<Object *>::iterator it; + for (it = candidates.begin(); it != candidates.end(); ++it) { + Object *cob = *it; + ListBase *conlist = get_active_constraints(cob); + if (is_animated_by_constraint(cob, conlist, animated_objects)) { + animated_objects.insert(cob); + candidates.erase(cob); + found_more = true; + break; + } + } + } while (found_more && candidates.size() > 0); +} + +void BCAnimationSampler::get_animated_from_export_set(std::set<Object *> &animated_objects, LinkNode &export_set) +{ + /* + Check if this object is animated. That is: Check if it has its own action, or + + - Check if it has constraints to other objects + - at least one of the other objects is animated as well + */ + + animated_objects.clear(); + std::set<Object *> static_objects; + std::set<Object *> candidates; + + LinkNode *node; + for (node = &export_set; node; node = node->next) { + Object *cob = (Object *)node->link; + if (bc_has_animations(cob)) { + animated_objects.insert(cob); + } + else { + ListBase conlist = cob->constraints; + if (conlist.first) + candidates.insert(cob); + } + } + find_depending_animated(animated_objects, candidates); +} + +void BCAnimationSampler::get_object_frames(BCFrames &frames, Object *ob) +{ + sample_data.get_frames(ob, frames); +} + +void BCAnimationSampler::get_bone_frames(BCFrames &frames, Object *ob, Bone *bone) +{ + sample_data.get_frames(ob, bone, frames); +} + +bool BCAnimationSampler::get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone) +{ + sample_data.get_matrices(ob, bone, samples); + return bc_is_animated(samples); +} + +bool BCAnimationSampler::get_object_samples(BCMatrixSampleMap &samples, Object *ob) +{ + sample_data.get_matrices(ob, samples); + return bc_is_animated(samples); +} + +#if 0 +/* + Add sampled values to FCurve + If no FCurve exists, create a temporary FCurve; + Note: The temporary FCurve will later be removed when the + BCAnimationSampler is removed (by its destructor) + + curve: The curve to whioch the data is added + matrices: The set of matrix values from where the data is taken + animation_type BC_ANIMATION_EXPORT_SAMPLES: Use all matrix data + animation_type BC_ANIMATION_EXPORT_KEYS: Only take data from matrices for keyframes +*/ + +void BCAnimationSampler::add_value_set( + BCAnimationCurve &curve, + BCFrameSampleMap &samples, + BC_export_animation_type animation_type) +{ + int array_index = curve.get_array_index(); + const BC_animation_transform_type tm_type = curve.get_transform_type(); + + BCFrameSampleMap::iterator it; + for (it = samples.begin(); it != samples.end(); ++it) { + const int frame_index = nearbyint(it->first); + if (animation_type == BC_ANIMATION_EXPORT_SAMPLES || curve.is_keyframe(frame_index)) { + + const BCSample *sample = it->second; + float val = 0; + + int subindex = curve.get_subindex(); + bool good; + if (subindex == -1) { + good = sample->get_value(tm_type, array_index, &val); + } + else { + good = sample->get_value(tm_type, array_index, &val, subindex); + } + + if (good) { + curve.add_value(val, frame_index); + } + } + } + curve.remove_unused_keyframes(); + curve.calchandles(); +} +#endif + +void BCAnimationSampler::generate_transform( + Object *ob, + const BCCurveKey &key, + BCAnimationCurveMap &curves) +{ + BCAnimationCurveMap::const_iterator it = curves.find(key); + if (it == curves.end()) { + curves[key] = new BCAnimationCurve(key, ob); + } +} + +void BCAnimationSampler::generate_transforms( + Object *ob, + const std::string prep, + const BC_animation_type type, + BCAnimationCurveMap &curves) +{ + generate_transform(ob, BCCurveKey(type, prep+"location", 0), curves); + generate_transform(ob, BCCurveKey(type, prep+"location", 1), curves); + generate_transform(ob, BCCurveKey(type, prep+"location", 2), curves); + generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 0), curves); + generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 1), curves); + generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 2), curves); + generate_transform(ob, BCCurveKey(type, prep+"scale", 0), curves); + generate_transform(ob, BCCurveKey(type, prep+"scale", 1), curves); + generate_transform(ob, BCCurveKey(type, prep+"scale", 2), curves); +} + +void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves) +{ + std::string prep = "pose.bones[\"" + std::string(bone->name) + "\"]."; + generate_transforms(ob, prep, BC_ANIMATION_TYPE_BONE, curves); + + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) + generate_transforms(ob, child, curves); +} + +/* +* Collect all keyframes from all animation curves related to the object +* The bc_get... functions check for NULL and correct object type +* The add_keyframes_from() function checks for NULL +*/ +void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob) +{ + frameset.clear(); + add_keyframes_from(bc_getSceneObjectAction(ob), frameset); + add_keyframes_from(bc_getSceneCameraAction(ob), frameset); + add_keyframes_from(bc_getSceneLampAction(ob), frameset); + + for (int a = 0; a < ob->totcol; a++) { + Material *ma = give_current_material(ob, a + 1); + add_keyframes_from(bc_getSceneMaterialAction(ma), frameset); + } +} + +void BCAnimationSampler::initialize_curves(BCAnimationCurveMap &curves, Object *ob) +{ + BC_animation_type object_type = BC_ANIMATION_TYPE_OBJECT; + + bAction *action = bc_getSceneObjectAction(ob); + if (action) { + FCurve *fcu = (FCurve *)action->curves.first; + + for (; fcu; fcu = fcu->next) { + object_type = BC_ANIMATION_TYPE_OBJECT; + if (ob->type == OB_ARMATURE) { + char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + if (boneName) { + object_type = BC_ANIMATION_TYPE_BONE; + } + } + + /* Adding action curves on object */ + BCCurveKey key(object_type, fcu->rna_path, fcu->array_index); + curves[key] = new BCAnimationCurve(key, ob, fcu); + } + } + + /* Add missing curves */ + object_type = BC_ANIMATION_TYPE_OBJECT; + generate_transforms(ob, EMPTY_STRING, object_type, curves); + if (ob->type == OB_ARMATURE) { + bArmature *arm = (bArmature *)ob->data; + for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next) + generate_transforms(ob, root_bone, curves); + } + + /* Add curves on Object->data actions */ + action = NULL; + if (ob->type == OB_CAMERA) { + action = bc_getSceneCameraAction(ob); + object_type = BC_ANIMATION_TYPE_CAMERA; + } + else if (ob->type == OB_LAMP) { + action = bc_getSceneLampAction(ob); + object_type = BC_ANIMATION_TYPE_LIGHT; + } + + if (action) { + /* Add lamp action or Camera action */ + FCurve *fcu = (FCurve *)action->curves.first; + for (; fcu; fcu = fcu->next) { + BCCurveKey key(object_type, fcu->rna_path, fcu->array_index); + curves[key] = new BCAnimationCurve(key, ob, fcu); + } + } + + /* Add curves on Object->material actions*/ + object_type = BC_ANIMATION_TYPE_MATERIAL; + for (int a = 0; a < ob->totcol; a++) { + /* Export Material parameter animations. */ + Material *ma = give_current_material(ob, a + 1); + if (ma) { + action = bc_getSceneMaterialAction(ma); + if (action) { + /* isMatAnim = true; */ + FCurve *fcu = (FCurve *)action->curves.first; + for (; fcu; fcu = fcu->next) { + BCCurveKey key(object_type, fcu->rna_path, fcu->array_index, a); + curves[key] = new BCAnimationCurve(key, ob, fcu); + } + } + } + } +} + +/* ==================================================================== */ + +BCSample &BCSampleFrame::add(Object *ob) +{ + BCSample *sample = new BCSample(ob); + sampleMap[ob] = sample; + return *sample; +} + +/* Get the matrix for the given key, returns Unity when the key does not exist */ +const BCSample *BCSampleFrame::get_sample(Object *ob) const +{ + BCSampleMap::const_iterator it = sampleMap.find(ob); + if (it == sampleMap.end()) { + return NULL; + } + return it->second; +} + +const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const +{ + BCSampleMap::const_iterator it = sampleMap.find(ob); + if (it == sampleMap.end()) { + return NULL; + } + BCSample *sample = it->second; + return &sample->get_matrix(); +} + +/* Get the matrix for the given Bone, returns Unity when the Objewct is not sampled */ +const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const +{ + BCSampleMap::const_iterator it = sampleMap.find(ob); + if (it == sampleMap.end()) { + return NULL; + } + + BCSample *sample = it->second; + const BCMatrix *bc_bone = sample->get_matrix(bone); + return bc_bone; +} + +/* Check if the key is in this BCSampleFrame */ +const bool BCSampleFrame::has_sample_for(Object *ob) const +{ + return sampleMap.find(ob) != sampleMap.end(); +} + +/* Check if the Bone is in this BCSampleFrame */ +const bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const +{ + const BCMatrix *bc_bone = get_sample_matrix(ob, bone); + return (bc_bone); +} + +/* ==================================================================== */ + +BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index) +{ + BCSampleFrame &frame = sample_frames[frame_index]; + return frame.add(ob); +} + + +/* ====================================================== */ +/* Below are the getters which we need to export the data */ +/* ====================================================== */ + +/* Return either the BCSampleFrame or NULL if frame does not exist*/ +BCSampleFrame * BCSampleFrameContainer::get_frame(int frame_index) +{ + BCSampleFrameMap::iterator it = sample_frames.find(frame_index); + BCSampleFrame *frame = (it == sample_frames.end()) ? NULL : &it->second; + return frame; +} + +/* Return a list of all frames that need to be sampled */ +const int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const +{ + frames.clear(); // safety; + BCSampleFrameMap::const_iterator it; + for (it = sample_frames.begin(); it != sample_frames.end(); ++it) { + frames.push_back(it->first); + } + return frames.size(); +} + +const int BCSampleFrameContainer::get_frames(Object *ob, BCFrames &frames) const +{ + frames.clear(); // safety; + BCSampleFrameMap::const_iterator it; + for (it = sample_frames.begin(); it != sample_frames.end(); ++it) { + const BCSampleFrame &frame = it->second; + if (frame.has_sample_for(ob)) { + frames.push_back(it->first); + } + } + return frames.size(); +} + +const int BCSampleFrameContainer::get_frames(Object *ob, Bone *bone, BCFrames &frames) const +{ + frames.clear(); // safety; + BCSampleFrameMap::const_iterator it; + for (it = sample_frames.begin(); it != sample_frames.end(); ++it) { + const BCSampleFrame &frame = it->second; + if (frame.has_sample_for(ob, bone)) { + frames.push_back(it->first); + } + } + return frames.size(); +} + +const int BCSampleFrameContainer::get_samples(Object *ob, BCFrameSampleMap &samples) const +{ + samples.clear(); // safety; + BCSampleFrameMap::const_iterator it; + for (it = sample_frames.begin(); it != sample_frames.end(); ++it) { + const BCSampleFrame &frame = it->second; + const BCSample *sample = frame.get_sample(ob); + if (sample) { + samples[it->first] = sample; + } + } + return samples.size(); +} + +const int BCSampleFrameContainer::get_matrices(Object *ob, BCMatrixSampleMap &samples) const +{ + samples.clear(); // safety; + BCSampleFrameMap::const_iterator it; + for (it = sample_frames.begin(); it != sample_frames.end(); ++it) { + const BCSampleFrame &frame = it->second; + const BCMatrix *matrix = frame.get_sample_matrix(ob); + if (matrix) { + samples[it->first] = matrix; + } + } + return samples.size(); +} + +const int BCSampleFrameContainer::get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &samples) const +{ + samples.clear(); // safety; + BCSampleFrameMap::const_iterator it; + for (it = sample_frames.begin(); it != sample_frames.end(); ++it) { + const BCSampleFrame &frame = it->second; + const BCMatrix *sample = frame.get_sample_matrix(ob, bone); + if (sample) { + samples[it->first] = sample; + } + } + return samples.size(); +} diff --git a/source/blender/collada/BCAnimationSampler.h b/source/blender/collada/BCAnimationSampler.h new file mode 100644 index 00000000000..ae0a04a706c --- /dev/null +++ b/source/blender/collada/BCAnimationSampler.h @@ -0,0 +1,205 @@ +/* +* ***** 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. +* +* The Original Code is Copyright (C) 2008 Blender Foundation. +* All rights reserved. +* +* Contributor(s): Blender Foundation +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __BC_ANIMATION_CURVE_CONTAINER_H__ +#define __BC_ANIMATION_CURVE_CONTAINER_H__ + +#include "BCAnimationCurve.h" +#include "BCSampleData.h" +#include "collada_utils.h" + +extern "C" { +#include "BKE_action.h" +#include "BKE_library.h" +#include "BLI_math_rotation.h" +#include "DNA_action_types.h" +} + +/* Collection of animation curves */ +class BCAnimation { +private: + Object *reference = NULL; + bContext *mContext; + + +public: + BCFrameSet frame_set; + BCAnimationCurveMap curve_map; + + BCAnimation(bContext *C, Object *ob): + mContext(C) + { + Main *bmain = CTX_data_main(mContext); + reference = BKE_object_copy(bmain, ob); + } + + ~BCAnimation() + { + BCAnimationCurveMap::iterator it; + for (it = curve_map.begin(); it != curve_map.end(); ++it) { + delete it->second; + } + + if (reference && reference->id.us == 0) + { + Main *bmain = CTX_data_main(mContext); + BKE_libblock_delete(bmain, &reference->id); + } + curve_map.clear(); + } + + Object *get_reference() + { + return reference; + } +}; + +typedef std::map<Object *, BCAnimation *> BCAnimationObjectMap; + +class BCSampleFrame { + + /* + Each frame on the timeline that needs to be sampled will have + one BCSampleFrame where we collect sample information about all objects + that need to be sampled for that frame. + */ + +private: + BCSampleMap sampleMap; + +public: + + ~BCSampleFrame() + { + BCSampleMap::iterator it; + for (it = sampleMap.begin(); it != sampleMap.end(); ++it) { + BCSample *sample = it->second; + delete sample; + } + sampleMap.clear(); + } + + BCSample &add(Object *ob); + + /* Following methods return NULL if object is not in the sampleMap*/ + const BCSample *get_sample(Object *ob) const; + const BCMatrix *get_sample_matrix(Object *ob) const; + const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const; + + const bool has_sample_for(Object *ob) const; + const bool has_sample_for(Object *ob, Bone *bone) const; +}; + +typedef std::map<int, BCSampleFrame> BCSampleFrameMap; + +class BCSampleFrameContainer { + + /* + * The BCSampleFrameContainer stores a map of BCSampleFrame objects + * with the timeline frame as key. + * + * Some details on the purpose: + * An Animation is made of multiple FCurves where each FCurve can + * have multiple keyframes. When we want to export the animation we + * also can decide whether we want to export the keyframes or a set + * of sample frames at equidistant locations (sample period). + * In any case we must resample first need to resample it fully + * to resolve things like: + * + * - animations by constraints + * - animations by drivers + * + * For this purpose we need to step through the entire animation and + * then sample each frame that contains at least one keyFrame or + * sampleFrame. Then for each frame we have to store the transform + * information for all exported objects in a BCSampleframe + * + * The entire set of BCSampleframes is finally collected into + * a BCSampleframneContainer + */ + +private: + BCSampleFrameMap sample_frames; + +public: + + ~BCSampleFrameContainer() + { + } + + BCSample &add(Object *ob, int frame_index); + BCSampleFrame *get_frame(int frame_index); // returns NULL if frame does not exist + + const int get_frames(std::vector<int> &frames) const; + const int get_frames(Object *ob, BCFrames &frames) const; + const int get_frames(Object *ob, Bone *bone, BCFrames &frames) const; + + const int get_samples(Object *ob, BCFrameSampleMap &samples) const; + const int get_matrices(Object *ob, BCMatrixSampleMap &matrices) const; + const int get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &bones) const; +}; + +class BCAnimationSampler { +private: + BlenderContext &blender_context; + BCSampleFrameContainer sample_data; + BCAnimationObjectMap objects; + + void generate_transform(Object *ob, const BCCurveKey &key, BCAnimationCurveMap &curves); + void generate_transforms(Object *ob, const std::string prep, const BC_animation_type type, BCAnimationCurveMap &curves); + void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves); + + void initialize_curves(BCAnimationCurveMap &curves, Object *ob); + void initialize_keyframes(BCFrameSet &frameset, Object *ob); + BCSample &sample_object(Object *ob, int frame_index, bool for_opensim); + void update_animation_curves(BCAnimation &animation, BCSample &sample, Object *ob, int frame_index); + void check_property_is_animated(BCAnimation &animation, float *ref, float *val, std::string data_path, int length); + +public: + BCAnimationSampler(BlenderContext &blender_context, BCObjectSet &animated_subset); + ~BCAnimationSampler(); + + void add_object(Object *ob); + + void sample_scene( + int sampling_rate, + int keyframe_at_end, + bool for_opensim, + bool keep_keyframes, + BC_export_animation_type export_animation_type); + + BCAnimationCurveMap *get_curves(Object *ob); + void get_object_frames(BCFrames &frames, Object *ob); + bool get_object_samples(BCMatrixSampleMap &samples, Object *ob); + void get_bone_frames(BCFrames &frames, Object *ob, Bone *bone); + bool get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone); + + static void get_animated_from_export_set(std::set<Object *> &animated_objects, LinkNode &export_set); + static void find_depending_animated(std::set<Object *> &animated_objects, std::set<Object *> &candidates); + static bool is_animated_by_constraint(Object *ob, ListBase *conlist, std::set<Object *> &animated_objects); + +}; + +#endif diff --git a/source/blender/collada/BCSampleData.cpp b/source/blender/collada/BCSampleData.cpp new file mode 100644 index 00000000000..95898bb5429 --- /dev/null +++ b/source/blender/collada/BCSampleData.cpp @@ -0,0 +1,186 @@ +/* +* ***** 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. +* +* The Original Code is Copyright (C) 2008 Blender Foundation. +* All rights reserved. +* +* Contributor(s): Blender Foundation +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "BCSampleData.h" +#include "collada_utils.h" + +BCSample::BCSample(Object *ob): + obmat(ob) +{} + +BCSample::~BCSample() +{ + BCBoneMatrixMap::iterator it; + for (it = bonemats.begin(); it != bonemats.end(); ++it) { + delete it->second; + } +} + +void BCSample::add_bone_matrix(Bone *bone, Matrix &mat) +{ + BCMatrix *matrix; + BCBoneMatrixMap::const_iterator it = bonemats.find(bone); + if (it != bonemats.end()) { + throw std::invalid_argument("bone " + std::string(bone->name) + " already defined before"); + } + matrix = new BCMatrix(mat); + bonemats[bone] = matrix; +} + +BCMatrix::BCMatrix(Matrix &mat) +{ + set_transform(mat); +} + +BCMatrix::BCMatrix(Object *ob) +{ + set_transform(ob); +} + +void BCMatrix::set_transform(Matrix &mat) +{ + copy_m4_m4(matrix, mat); + mat4_decompose(this->loc, this->q, this->size, mat); + quat_to_eul(this->rot, this->q); +} + +void BCMatrix::set_transform(Object *ob) +{ + Matrix lmat; + + BKE_object_matrix_local_get(ob, lmat); + copy_m4_m4(matrix, lmat); + + mat4_decompose(this->loc, this->q, this->size, lmat); + quat_to_compatible_eul(this->rot, ob->rot, this->q); +} + +const BCMatrix *BCSample::get_matrix(Bone *bone) const +{ + BCBoneMatrixMap::const_iterator it = bonemats.find(bone); + if (it == bonemats.end()) { + return NULL; + } + return it->second; +} + +const BCMatrix &BCSample::get_matrix() const +{ + return obmat; +} + + +/* Get channel value */ +const bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const +{ + if (channel_target == "location") { + *val = obmat.location()[array_index]; + } + else if (channel_target == "scale") { + *val = obmat.scale()[array_index]; + } + else if ( + channel_target == "rotation" || + channel_target == "rotation_euler") { + *val = obmat.rotation()[array_index]; + } + else if (channel_target == "rotation_quat") { + *val = obmat.quat()[array_index]; + } + else { + *val = 0; + return false; + } + + return true; +} + +void BCMatrix::copy(Matrix &out, Matrix &in) +{ + /* destination comes first: */ + memcpy(out, in, sizeof(Matrix)); +} + +void BCMatrix::transpose(Matrix &mat) +{ + transpose_m4(mat); +} + +void BCMatrix::sanitize(Matrix &mat, int precision) +{ + bc_sanitize_mat(mat, precision); +} + +void BCMatrix::unit() +{ + unit_m4(matrix); +} + +/* +We need double here because the OpenCollada API needs it. +precision = -1 indicates to not limit the precision +*/ +void BCMatrix::get_matrix(double(&mat)[4][4], const bool transposed, const int precision) const +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) { + float val = (transposed) ? matrix[j][i] : matrix[i][j]; + if (precision >= 0) + val = floor((val * pow(10, precision) + 0.5)) / pow(10, precision); + mat[i][j] = val; + } +} + +const bool BCMatrix::in_range(const BCMatrix &other, float distance) const +{ + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if (fabs(other.matrix[i][j] - matrix[i][j]) > distance) { + return false; + } + } + } + return true; +} + +float(&BCMatrix::location() const)[3] +{ + return loc; +} + +float(&BCMatrix::rotation() const)[3] +{ + return rot; +} + +float(&BCMatrix::scale() const)[3] +{ + return size; +} + +float(&BCMatrix::quat() const)[4] +{ + return q; +} diff --git a/source/blender/collada/BCSampleData.h b/source/blender/collada/BCSampleData.h new file mode 100644 index 00000000000..a685cb30fa6 --- /dev/null +++ b/source/blender/collada/BCSampleData.h @@ -0,0 +1,102 @@ +/* +* ***** 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. +* +* The Original Code is Copyright (C) 2008 Blender Foundation. +* All rights reserved. +* +* Contributor(s): Blender Foundation +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __BC_SAMPLE_H__ +#define __BC_SAMPLE_H__ + +#include <string> +#include <map> +#include <algorithm> + +extern "C" +{ +#include "BKE_object.h" +#include "BLI_math_rotation.h" +#include "DNA_object_types.h" +#include "DNA_armature_types.h" +#include "DNA_material_types.h" +#include "DNA_lamp_types.h" +#include "DNA_camera_types.h" +} + +typedef float(Matrix)[4][4]; + +class BCMatrix { + +private: + mutable float matrix[4][4]; + mutable float size[3]; + mutable float rot[3]; + mutable float loc[3]; + mutable float q[4]; + + void unit(); + void copy(Matrix &r, Matrix &a); + void set_transform(Object *ob); + void set_transform(Matrix &mat); + +public: + + float(&location() const)[3]; + float(&rotation() const)[3]; + float(&scale() const)[3]; + float(&quat() const)[4]; + + BCMatrix(Matrix &mat); + BCMatrix(Object *ob); + + void get_matrix(double(&mat)[4][4], const bool transposed = false, const int precision = -1) const; + + const bool in_range(const BCMatrix &other, float distance) const; + static void sanitize(Matrix &matrix, int precision); + static void transpose(Matrix &matrix); + +}; + +typedef std::map<Bone *, BCMatrix *> BCBoneMatrixMap; + +class BCSample{ +private: + + BCMatrix obmat; + BCBoneMatrixMap bonemats; /* For Armature animation */ + +public: + BCSample(Object *ob); + ~BCSample(); + + void add_bone_matrix(Bone *bone, Matrix &mat); + + const bool get_value(std::string channel_target, const int array_index, float *val) const; + const BCMatrix &get_matrix() const; + const BCMatrix *get_matrix(Bone *bone) const; // returns NULL if bone is not animated + +}; + +typedef std::map<Object *, BCSample *> BCSampleMap; +typedef std::map<int, const BCSample *> BCFrameSampleMap; +typedef std::map<int, const BCMatrix *> BCMatrixSampleMap; + +#endif diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp new file mode 100644 index 00000000000..2281b3dd529 --- /dev/null +++ b/source/blender/collada/BlenderContext.cpp @@ -0,0 +1,77 @@ +/* + * ***** 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): Gaia Clary, + * + * ***** END GPL LICENSE BLOCK ***** + */ + + /** \file CameraExporter.h + * \ingroup collada + */ + +#include "BlenderContext.h" +#include "BKE_scene.h" + +BlenderContext::BlenderContext(bContext *C) +{ + context = C; + main = CTX_data_main(C); + scene = CTX_data_scene(C); + view_layer = CTX_data_view_layer(C); + depsgraph = nullptr; // create only when needed +} + +bContext *BlenderContext::get_context() +{ + return context; +} + +Depsgraph *BlenderContext::get_depsgraph() +{ + if (!depsgraph) { + depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + } + return depsgraph; +} + +Scene *BlenderContext::get_scene() +{ + return scene; +} + +Scene *BlenderContext::get_evaluated_scene() +{ + Scene *scene_eval = DEG_get_evaluated_scene(get_depsgraph()); + return scene_eval; +} + +Object *BlenderContext::get_evaluated_object(Object *ob) +{ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + return ob_eval; +} + +ViewLayer *BlenderContext::get_view_layer() +{ + return view_layer; +} + +Main *BlenderContext::get_main() +{ + return main; +} diff --git a/source/blender/collada/BlenderContext.h b/source/blender/collada/BlenderContext.h new file mode 100644 index 00000000000..e6157a5a7f2 --- /dev/null +++ b/source/blender/collada/BlenderContext.h @@ -0,0 +1,58 @@ +/* + * ***** 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): Gaia Clary, + * + * ***** END GPL LICENSE BLOCK ***** + */ + + /** \file CameraExporter.h + * \ingroup collada + */ + +#ifndef __BLENDERCONTEXT_H__ +#define __BLENDERCONTEXT_H__ + +extern "C" { +#include "DNA_object_types.h" +#include "BKE_context.h" +#include "BKE_main.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" +} + +class BlenderContext +{ +private: + bContext *context; + Depsgraph *depsgraph; + Scene *scene; + ViewLayer *view_layer; + Main *main; + +public: + BlenderContext(bContext *C); + bContext *get_context(); + Depsgraph *get_depsgraph(); + Scene *get_scene(); + Scene *get_evaluated_scene(); + Object *get_evaluated_object(Object *ob); + ViewLayer *get_view_layer(); + Main *get_main(); +}; + +#endif diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt index fd38998c98c..8c2339497bf 100644 --- a/source/blender/collada/CMakeLists.txt +++ b/source/blender/collada/CMakeLists.txt @@ -44,6 +44,7 @@ set(INC ../blenkernel ../blenlib ../blentranslation + ../depsgraph ../editors/include ../makesdna ../makesrna @@ -62,8 +63,13 @@ set(INC_SYS set(SRC AnimationImporter.cpp AnimationExporter.cpp + AnimationClipExporter.cpp ArmatureExporter.cpp ArmatureImporter.cpp + BlenderContext.cpp + BCAnimationCurve.cpp + BCAnimationSampler.cpp + BCSampleData.cpp CameraExporter.cpp ControllerExporter.cpp DocumentExporter.cpp @@ -81,6 +87,7 @@ set(SRC MaterialExporter.cpp MeshImporter.cpp SkinInfo.cpp + Materials.cpp SceneExporter.cpp TransformReader.cpp TransformWriter.cpp @@ -90,8 +97,13 @@ set(SRC AnimationImporter.h AnimationExporter.h + AnimationClipExporter.h ArmatureExporter.h ArmatureImporter.h + BlenderContext.h + BCAnimationCurve.h + BCAnimationSampler.h + BCSampleData.h CameraExporter.h ControllerExporter.h DocumentExporter.h @@ -108,6 +120,7 @@ set(SRC LightExporter.h MaterialExporter.h MeshImporter.h + Materials.h SkinInfo.h SceneExporter.h TransformReader.h diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp index a5f96123fd4..5ec199f086b 100644 --- a/source/blender/collada/ControllerExporter.cpp +++ b/source/blender/collada/ControllerExporter.cpp @@ -38,11 +38,10 @@ #include "BKE_armature.h" extern "C" { -#include "BKE_main.h" -#include "BKE_mesh.h" #include "BKE_global.h" -#include "BKE_library.h" #include "BKE_idprop.h" +#include "BKE_library.h" +#include "BKE_mesh.h" } #include "ED_armature.h" @@ -56,22 +55,18 @@ extern "C" { #include "collada_utils.h" -// XXX exporter writes wrong data for shared armatures. A separate -// controller should be written for each armature-mesh binding how do -// we make controller ids then? -ControllerExporter::ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) { -} bool ControllerExporter::is_skinned_mesh(Object *ob) { return bc_get_assigned_armature(ob) != NULL; } - void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) { - if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) - ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone))); + if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) { + std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name); + ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, node_id)); + } else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { write_bone_URLs(ins, ob_arm, child); @@ -98,20 +93,15 @@ bool ControllerExporter::add_instance_controller(Object *ob) write_bone_URLs(ins, ob_arm, bone); } - InstanceWriter::add_material_bindings(ins.getBindMaterial(), - ob, - this->export_settings->active_uv_only, - this->export_settings->export_texture_type); + InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only); ins.add(); return true; } -void ControllerExporter::export_controllers(Main *bmain, Scene *sce) +void ControllerExporter::export_controllers() { - m_bmain = bmain; - scene = sce; - + Scene *sce = blender_context.get_scene(); openLibrary(); GeometryFunctor gf; @@ -201,16 +191,17 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) bool use_instantiation = this->export_settings->use_object_instantiation; Mesh *me; + if (((Mesh *)ob->data)->dvert == NULL) { + return; + } + me = bc_get_mesh_copy( - m_bmain, - scene, + blender_context, ob, this->export_settings->export_mesh_type, this->export_settings->apply_modifiers, this->export_settings->triangulate); - if (!me->dvert) return; - std::string controller_name = id_name(ob_arm); std::string controller_id = get_controller_id(ob_arm, ob); @@ -294,7 +285,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints); - BKE_libblock_free_us(m_bmain, me); + BKE_id_free(NULL, me); closeSkin(); closeController(); @@ -306,8 +297,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key) Mesh *me; me = bc_get_mesh_copy( - m_bmain, - scene, + blender_context, ob, this->export_settings->export_mesh_type, this->export_settings->apply_modifiers, @@ -332,8 +322,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key) COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id))); targets.add(); - BKE_libblock_free_us(m_bmain, me); - + BKE_id_free(NULL, me); //support for animations //can also try the base element and param alternative @@ -432,8 +421,13 @@ void ControllerExporter::add_joints_element(ListBase *defbase, void ControllerExporter::add_bind_shape_mat(Object *ob) { double bind_mat[4][4]; + float f_obmat[4][4]; + BKE_object_matrix_local_get(ob, f_obmat); - converter.mat4_to_dae_double(bind_mat, ob->obmat); + //UnitConverter::mat4_to_dae_double(bind_mat, ob->obmat); + UnitConverter::mat4_to_dae_double(bind_mat, f_obmat); + if (this->export_settings->limit_precision) + bc_sanitize_mat(bind_mat, LIMITTED_PRECISION); addBindShapeTransform(bind_mat); } @@ -501,8 +495,11 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas // put armature in rest position if (!(arm->flag & ARM_RESTPOS)) { + Depsgraph *depsgraph = blender_context.get_depsgraph(); + Scene *scene = blender_context.get_scene(); + arm->flag |= ARM_RESTPOS; - BKE_pose_where_is(scene, ob_arm); + BKE_pose_where_is(depsgraph, scene, ob_arm); } for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { @@ -540,17 +537,19 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas mul_m4_m4m4(world, ob_arm->obmat, bind_mat); invert_m4_m4(mat, world); - converter.mat4_to_dae(inv_bind_mat, mat); + UnitConverter::mat4_to_dae(inv_bind_mat, mat); if (this->export_settings->limit_precision) - bc_sanitize_mat(inv_bind_mat, 6); + bc_sanitize_mat(inv_bind_mat, LIMITTED_PRECISION); source.appendValues(inv_bind_mat); } } - // back from rest positon + // back from rest position if (!(flag & ARM_RESTPOS)) { + Depsgraph *depsgraph = blender_context.get_depsgraph(); + Scene *scene = blender_context.get_scene(); arm->flag = flag; - BKE_pose_where_is(scene, ob_arm); + BKE_pose_where_is(depsgraph, scene, ob_arm); } source.finish(); diff --git a/source/blender/collada/ControllerExporter.h b/source/blender/collada/ControllerExporter.h index 2e258c63b6f..309bdbd37f0 100644 --- a/source/blender/collada/ControllerExporter.h +++ b/source/blender/collada/ControllerExporter.h @@ -54,25 +54,31 @@ #include "BKE_key.h" +struct Depsgraph; class SceneExporter; class ControllerExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter { public: - ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); + // XXX exporter writes wrong data for shared armatures. A separate + // controller should be written for each armature-mesh binding how do + // we make controller ids then? + ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : + COLLADASW::LibraryControllers(sw), + blender_context(blender_context), + export_settings(export_settings) { + } bool is_skinned_mesh(Object *ob); bool add_instance_controller(Object *ob); - void export_controllers(Main *bmain, Scene *sce); + void export_controllers(); void operator()(Object *ob); private: - Main *m_bmain; - Scene *scene; - UnitConverter converter; + BlenderContext &blender_context; const ExportSettings *export_settings; #if 0 diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index bf29ec42c42..4d0dd7605f9 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -66,12 +66,11 @@ extern "C" { #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "DNA_image_types.h" #include "DNA_material_types.h" -#include "DNA_texture_types.h" #include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" @@ -86,11 +85,11 @@ extern "C" #include "BLI_listbase.h" #include "BLI_utildefines.h" -#include "BKE_DerivedMesh.h" #include "BKE_action.h" // pose functions #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_blender_version.h" +#include "BKE_customdata.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_image.h" @@ -138,8 +137,7 @@ extern bool bc_has_object_type(LinkNode *export_set, short obtype); char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n) { int layer_index = CustomData_get_layer_index(data, type); - if (layer_index < 0) - return NULL; + if (layer_index < 0) return NULL; return data->layers[layer_index + n].name; } @@ -148,13 +146,14 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); - if (layer_index < 1) - return NULL; + if (layer_index < 0) return NULL; - return bc_CustomData_get_layer_name(data, type, layer_index-1); + return data->layers[layer_index].name; } -DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) { +DocumentExporter::DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings) : + blender_context(blender_context), + export_settings(export_settings) { } static COLLADABU::NativeString make_temp_filepath(const char *name, const char *extension) @@ -181,9 +180,11 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char * // COLLADA allows this through multiple <channel>s in <animation>. // For this to work, we need to know objects that use a certain action. -int DocumentExporter::exportCurrentScene(bContext *C, const EvaluationContext *eval_ctx, Scene *sce) +int DocumentExporter::exportCurrentScene() { - Main *bmain = CTX_data_main(C); + Scene *sce = blender_context.get_scene(); + bContext *C = blender_context.get_context(); + PointerRNA sceneptr, unit_settings; PropertyRNA *system; /* unused , *scale; */ @@ -273,42 +274,43 @@ int DocumentExporter::exportCurrentScene(bContext *C, const EvaluationContext *e le.exportLights(sce); } + // <library_effects> + EffectsExporter ee(writer, this->export_settings, key_image_map); + ee.exportEffects(C, sce); + // <library_images> - ImagesExporter ie(writer, this->export_settings); + ImagesExporter ie(writer, this->export_settings, key_image_map); ie.exportImages(sce); - // <library_effects> - EffectsExporter ee(writer, this->export_settings); - ee.exportEffects(sce); - // <library_materials> MaterialsExporter me(writer, this->export_settings); me.exportMaterials(sce); // <library_geometries> if (bc_has_object_type(export_set, OB_MESH)) { - GeometryExporter ge(writer, this->export_settings); - ge.exportGeom(bmain, sce); + GeometryExporter ge(blender_context, writer, this->export_settings); + ge.exportGeom(); } // <library_controllers> - ArmatureExporter arm_exporter(writer, this->export_settings); - ControllerExporter controller_exporter(writer, this->export_settings); + ArmatureExporter arm_exporter(blender_context, writer, this->export_settings); + ControllerExporter controller_exporter(blender_context, writer, this->export_settings); if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys) { - controller_exporter.export_controllers(bmain, sce); + controller_exporter.export_controllers(); } // <library_visual_scenes> - SceneExporter se(writer, &arm_exporter, this->export_settings); + SceneExporter se(blender_context, writer, &arm_exporter, this->export_settings); if (this->export_settings->include_animations) { // <library_animations> - AnimationExporter ae(writer, this->export_settings); - ae.exportAnimations(bmain, sce); + AnimationExporter ae(blender_context, writer, this->export_settings); + ae.exportAnimations(); } - se.exportScene(C, sce); + + se.exportScene(); // <scene> std::string scene_name(translate_id(id_name(sce))); diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h index 817df3735da..cb55dbc459e 100644 --- a/source/blender/collada/DocumentExporter.h +++ b/source/blender/collada/DocumentExporter.h @@ -28,22 +28,24 @@ #define __DOCUMENTEXPORTER_H__ #include "collada.h" +#include "collada_utils.h" +#include "BlenderContext.h" extern "C" { #include "DNA_customdata_types.h" -#include "BKE_depsgraph.h" -} -struct Scene; +} class DocumentExporter { public: - DocumentExporter(const ExportSettings *export_settings); - int exportCurrentScene(bContext *C, const EvaluationContext *eval_ctx, Scene *sce); + DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings); + int exportCurrentScene(); void exportScenes(const char *filename); private: + BlenderContext &blender_context; const ExportSettings *export_settings; + KeyImageMap key_image_map; }; #endif diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index c3b2108c35b..e59483fa93c 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -57,16 +57,15 @@ extern "C" { #include "BLI_fileops.h" #include "BKE_camera.h" -#include "BKE_main.h" -#include "BKE_lamp.h" -#include "BKE_library.h" -#include "BKE_texture.h" +#include "BKE_collection.h" #include "BKE_fcurve.h" -#include "BKE_depsgraph.h" -#include "BKE_scene.h" #include "BKE_global.h" -#include "BKE_material.h" #include "BKE_image.h" +#include "BKE_layer.h" +#include "BKE_lamp.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BKE_scene.h" #include "BLI_path_util.h" @@ -82,6 +81,9 @@ extern "C" { } +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "ExtraHandler.h" #include "ErrorHandler.h" #include "DocumentImporter.h" @@ -89,7 +91,7 @@ extern "C" { #include "collada_internal.h" #include "collada_utils.h" - +#include "Materials.h" /* * COLLADA Importer limitations: @@ -102,11 +104,12 @@ extern "C" { DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_settings) : import_settings(import_settings), - mImportStage(General), + mImportStage(Fetching_Scene_data), mContext(C), - armature_importer(&unit_converter, &mesh_importer, CTX_data_main(C), CTX_data_scene(C), import_settings), - mesh_importer(&unit_converter, &armature_importer, CTX_data_main(C), CTX_data_scene(C)), - anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) + view_layer(CTX_data_view_layer(mContext)), + armature_importer(&unit_converter, &mesh_importer, CTX_data_main(C), CTX_data_scene(C), view_layer, import_settings), + mesh_importer(&unit_converter, &armature_importer, CTX_data_main(C), CTX_data_scene(C), view_layer), + anim_importer(C, &unit_converter, &armature_importer, CTX_data_scene(C)) { } @@ -130,7 +133,7 @@ bool DocumentImporter::import() loader.registerExtraDataCallbackHandler(ehandler); // deselect all to select new objects - BKE_scene_base_deselect_all(CTX_data_scene(mContext)); + BKE_view_layer_base_deselect_all(view_layer); std::string mFilename = std::string(this->import_settings->filepath); const std::string encodedFilename = bc_url_encode(mFilename); @@ -146,9 +149,7 @@ bool DocumentImporter::import() } /** TODO set up scene graph and such here */ - - mImportStage = Controller; - + mImportStage = Fetching_Controller_data; COLLADASaxFWL::Loader loader2; COLLADAFW::Root root2(&loader2, this); @@ -179,7 +180,7 @@ void DocumentImporter::start() void DocumentImporter::finish() { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return; Main *bmain = CTX_data_main(mContext); @@ -222,6 +223,7 @@ void DocumentImporter::finish() } // Write nodes to scene + fprintf(stderr, "+-- Import Scene --------\n"); const COLLADAFW::NodePointerArray& roots = (*sit)->getRootNodes(); for (unsigned int i = 0; i < roots.getCount(); i++) { std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false); @@ -229,10 +231,6 @@ void DocumentImporter::finish() delete objects_done; } - // update scene - DAG_relations_tag_update(bmain); - WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL); - } @@ -241,7 +239,6 @@ void DocumentImporter::finish() armature_importer.set_tags_map(this->uid_tags_map); armature_importer.make_armatures(mContext, *objects_to_scale); armature_importer.make_shape_keys(mContext); - DAG_relations_tag_update(bmain); #if 0 armature_importer.fix_animation(); @@ -257,35 +254,29 @@ void DocumentImporter::finish() if (libnode_ob.size()) { - fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size()); + fprintf(stderr, "| Cleanup: free %d library nodes\n", (int)libnode_ob.size()); // free all library_nodes - std::vector<Object *>::iterator lit; - for (lit = libnode_ob.begin(); lit != libnode_ob.end(); lit++) { - Object *ob = *lit; - - Base *base = BKE_scene_base_find(sce, ob); - if (base) { - BLI_remlink(&sce->base, base); - BKE_libblock_free_us(bmain, base->object); - if (sce->basact == base) - sce->basact = NULL; - MEM_freeN(base); - } + std::vector<Object *>::iterator it; + for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) { + Object *ob = *it; + BKE_scene_collections_object_remove(bmain, sce, ob, true); } libnode_ob.clear(); - - DAG_relations_tag_update(bmain); } bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units); delete objects_to_scale; + + // update scene + DEG_id_tag_update(&sce->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL); } void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL) { - Main *bmain = CTX_data_main(mContext); // The split in #29246, rootmap must point at actual root when // calculating bones in apply_curves_as_matrix. - actual root is the root node. // This has to do with inverse bind poses being world space @@ -320,7 +311,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW translate_anim_recursive(node, node, parob); } else { - anim_importer.translate_Animations(bmain, node, root_map, object_map, FW_object_map, uid_material_map); + anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map); COLLADAFW::NodePointerArray &children = node->getChildNodes(); for (i = 0; i < children.getCount(); i++) { translate_anim_recursive(children[i], node, NULL); @@ -384,7 +375,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera } Main *bmain = CTX_data_main(mContext); - Object *ob = bc_add_object(bmain, sce, OB_CAMERA, NULL); + Object *ob = bc_add_object(bmain, sce, view_layer, OB_CAMERA, NULL); Camera *cam = uid_camera_map[cam_uid]; Camera *old_cam = (Camera *)ob->data; ob->data = cam; @@ -396,12 +387,12 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce { const COLLADAFW::UniqueId& lamp_uid = lamp->getInstanciatedObjectId(); if (uid_lamp_map.find(lamp_uid) == uid_lamp_map.end()) { - fprintf(stderr, "Couldn't find lamp by UID.\n"); + fprintf(stderr, "Couldn't find light by UID.\n"); return NULL; } Main *bmain = CTX_data_main(mContext); - Object *ob = bc_add_object(bmain, sce, OB_LAMP, NULL); + Object *ob = bc_add_object(bmain, sce, view_layer, OB_LAMP, NULL); Lamp *la = uid_lamp_map[lamp_uid]; Lamp *old_lamp = (Lamp *)ob->data; ob->data = la; @@ -411,12 +402,12 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Node *source_node, COLLADAFW::Node *instance_node, Scene *sce, bool is_library_node) { - fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL); + //fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL); Main *bmain = CTX_data_main(mContext); Object *obn = BKE_object_copy(bmain, source_ob); - DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - BKE_scene_base_add(sce, obn); + DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + BKE_collection_object_add_from(bmain, sce, source_ob, obn); if (instance_node) { anim_importer.read_node_transform(instance_node, obn); @@ -511,15 +502,16 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA std::vector<Object *> *root_objects = new std::vector<Object *>(); fprintf(stderr, - "Writing node id='%s', name='%s'\n", - id.c_str(), - name.c_str()); + "| %s id='%s', name='%s'\n", + is_joint ? "JOINT" : "NODE ", + id.c_str(), + name.c_str() ); if (is_joint) { if (parent_node == NULL && !is_library_node) { // A Joint on root level is a skeleton without root node. // Here we add the armature "on the fly": - par = bc_add_object(bmain, sce, OB_ARMATURE, std::string("Armature").c_str()); + par = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, std::string("Armature").c_str()); objects_done->push_back(par); root_objects->push_back(par); object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par)); @@ -551,8 +543,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA // maybe join multiple <instance_...> meshes into 1, and link object with it? not sure... // <instance_geometry> while (geom_done < geom.getCount()) { - ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map, - material_texture_mapping_map); + ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map); if (ob == NULL) { report_unknown_reference(*node, "instance_mesh"); } @@ -592,7 +583,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA } while (controller_done < controller.getCount()) { COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)controller[controller_done]; - ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map, material_texture_mapping_map); + ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map); if (ob == NULL) { report_unknown_reference(*node, "instance_controller"); } @@ -633,10 +624,10 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) { //Check if Object is armature, by checking if immediate child is a JOINT node. if (is_armature(node)) { - ob = bc_add_object(bmain, sce, OB_ARMATURE, name.c_str()); + ob = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, name.c_str()); } else { - ob = bc_add_object(bmain, sce, OB_EMPTY, NULL); + ob = bc_add_object(bmain, sce, view_layer, OB_EMPTY, NULL); } objects_done->push_back(ob); if (parent_node == NULL) { @@ -709,7 +700,7 @@ finally: */ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; // this method called on post process after writeGeometry, writeMaterial, etc. @@ -732,19 +723,19 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; Scene *sce = CTX_data_scene(mContext); const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes(); + fprintf(stderr, "+-- Read Library nodes ----------\n"); for (unsigned int i = 0; i < nodes.getCount(); i++) { std::vector<Object *> *child_objects; child_objects = write_node(nodes[i], NULL, sce, NULL, true); delete child_objects; } - return true; } @@ -752,7 +743,7 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; return mesh_importer.write_geometry(geom); @@ -762,7 +753,7 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom) * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; Main *bmain = CTX_data_main(mContext); @@ -775,181 +766,18 @@ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat) return true; } -// create mtex, create texture, set texture image -MTex *DocumentImporter::create_texture(COLLADAFW::EffectCommon *ef, COLLADAFW::Texture &ctex, Material *ma, - int i, TexIndexTextureArrayMap &texindex_texarray_map) -{ - COLLADAFW::SamplerPointerArray& samp_array = ef->getSamplerPointerArray(); - COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()]; - - const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage(); - - if (uid_image_map.find(ima_uid) == uid_image_map.end()) { - fprintf(stderr, "Couldn't find an image by UID.\n"); - return NULL; - } - - Main *bmain = CTX_data_main(mContext); - ma->mtex[i] = BKE_texture_mtex_add(); - ma->mtex[i]->texco = TEXCO_UV; - ma->mtex[i]->tex = BKE_texture_add(bmain, "Texture"); - ma->mtex[i]->tex->type = TEX_IMAGE; - ma->mtex[i]->tex->ima = uid_image_map[ima_uid]; - - texindex_texarray_map[ctex.getTextureMapId()].push_back(ma->mtex[i]); - - return ma->mtex[i]; -} void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma) { - COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType(); - - // blinn - if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) { - ma->spec_shader = MA_SPEC_BLINN; - ma->spec = ef->getShininess().getFloatValue(); - } - // phong - else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) { - ma->spec_shader = MA_SPEC_PHONG; - ma->har = ef->getShininess().getFloatValue(); - } - // lambert - else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) { - ma->diff_shader = MA_DIFF_LAMBERT; - } - // default - lambert - else { - ma->diff_shader = MA_DIFF_LAMBERT; - fprintf(stderr, "Current shader type is not supported, default to lambert.\n"); - } - // reflectivity - ma->ray_mirror = ef->getReflectivity().getFloatValue(); - // index of refraction - ma->ang = ef->getIndexOfRefraction().getFloatValue(); - - int i = 0; - COLLADAFW::Color col; - MTex *mtex = NULL; - TexIndexTextureArrayMap texindex_texarray_map; - - // DIFFUSE - // color - if (ef->getDiffuse().isColor()) { - /* too high intensity can create artefacts (fireflies) - So here we take care that intensity is set to 0.8 wherever possible - */ - col = ef->getDiffuse().getColor(); - ma->ref = max_ffff(col.getRed(), col.getGreen(), col.getBlue(), 0.8); - ma->r = col.getRed() / ma->ref; - ma->g = col.getGreen() / ma->ref; - ma->b = col.getBlue() / ma->ref; - } - // texture - else if (ef->getDiffuse().isTexture()) { - COLLADAFW::Texture ctex = ef->getDiffuse().getTexture(); - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) { - mtex->mapto = MAP_COL; - ma->texact = (int)i; - i++; - } - } - // AMBIENT - // color - if (ef->getAmbient().isColor()) { - col = ef->getAmbient().getColor(); - ma->ambr = col.getRed(); - ma->ambg = col.getGreen(); - ma->ambb = col.getBlue(); - } - // texture - else if (ef->getAmbient().isTexture()) { - COLLADAFW::Texture ctex = ef->getAmbient().getTexture(); - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) { - mtex->mapto = MAP_AMB; - i++; - } - } - // SPECULAR - // color - if (ef->getSpecular().isColor()) { - col = ef->getSpecular().getColor(); - ma->specr = col.getRed(); - ma->specg = col.getGreen(); - ma->specb = col.getBlue(); - } - // texture - else if (ef->getSpecular().isTexture()) { - COLLADAFW::Texture ctex = ef->getSpecular().getTexture(); - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) { - mtex->mapto = MAP_SPEC; - i++; - } - } - // REFLECTIVE - // color - if (ef->getReflective().isColor()) { - col = ef->getReflective().getColor(); - ma->mirr = col.getRed(); - ma->mirg = col.getGreen(); - ma->mirb = col.getBlue(); - } - // texture - else if (ef->getReflective().isTexture()) { - COLLADAFW::Texture ctex = ef->getReflective().getTexture(); - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) { - mtex->mapto = MAP_REF; - i++; - } - } - - // EMISSION - // color - if (ef->getEmission().isColor()) { - // XXX there is no emission color in blender - // but I am not sure - } - // texture - else if (ef->getEmission().isTexture()) { - COLLADAFW::Texture ctex = ef->getEmission().getTexture(); - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) { - mtex->mapto = MAP_EMIT; - i++; - } - } - - // TRANSPARENT - // color - if (ef->getOpacity().isColor()) { - col = ef->getTransparent().getColor(); - float alpha = ef->getTransparency().getFloatValue(); - if (col.isValid()) { - alpha *= col.getAlpha(); // Assuming A_ONE opaque mode - } - if (col.isValid() || alpha < 1.0) { - ma->alpha = alpha; - ma->mode |= MA_ZTRANSP | MA_TRANSP; - } - } - // texture - else if (ef->getOpacity().isTexture()) { - COLLADAFW::Texture ctex = ef->getOpacity().getTexture(); - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) { - mtex->mapto = MAP_ALPHA; - i++; - ma->spectra = ma->alpha = 0; - ma->mode |= MA_ZTRANSP | MA_TRANSP; - } - } - - material_texture_mapping_map[ma] = texindex_texarray_map; + MaterialNode matNode = MaterialNode(mContext, ef, ma, uid_image_map); + matNode.set_reflectivity(ef->getReflectivity().getFloatValue()); + matNode.set_ior(ef->getIndexOfRefraction().getFloatValue()); + matNode.set_diffuse(ef->getDiffuse(), "Diffuse"); + matNode.set_ambient(ef->getAmbient(), "Ambient"); + matNode.set_specular(ef->getSpecular(), "Specular"); + matNode.set_reflective(ef->getReflective(), "Reflective"); + matNode.set_emission(ef->getEmission(), "Emission"); + matNode.set_opacity(ef->getOpacity(), "Opacity"); } /** When this method is called, the writer must write the effect. @@ -957,7 +785,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; const COLLADAFW::UniqueId& uid = effect->getUniqueId(); @@ -994,7 +822,7 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect) * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; Main *bmain = CTX_data_main(mContext); @@ -1120,7 +948,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; const std::string& imagepath = image->getImageURI().toNativePath(); @@ -1137,7 +965,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) else { // Maybe imagepath was already absolute ? if (!BLI_exists(imagepath.c_str())) { - fprintf(stderr, "Image not found: %s.\n", imagepath.c_str() ); + fprintf(stderr, "|! Image not found: %s\n", imagepath.c_str() ); return true; } workpath = imagepath.c_str(); @@ -1145,11 +973,11 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) Image *ima = BKE_image_load_exists(CTX_data_main(mContext), workpath); if (!ima) { - fprintf(stderr, "Cannot create image: %s\n", workpath); + fprintf(stderr, "|! Cannot create image: %s\n", workpath); return true; } this->uid_image_map[image->getUniqueId()] = ima; - + fprintf(stderr, "| import Image: %s\n", workpath); return true; } @@ -1157,7 +985,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; Main *bmain = CTX_data_main(mContext); @@ -1177,7 +1005,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) else lamp = (Lamp *)BKE_lamp_add(bmain, (char *)la_id.c_str()); if (!lamp) { - fprintf(stderr, "Cannot create lamp.\n"); + fprintf(stderr, "Cannot create light.\n"); return true; } @@ -1198,7 +1026,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) et->setData("spotsize", &(lamp->spotsize)); lamp->spotsize = DEG2RADF(lamp->spotsize); et->setData("spotblend", &(lamp->spotblend)); - et->setData("halo_intensity", &(lamp->haint)); et->setData("att1", &(lamp->att1)); et->setData("att2", &(lamp->att2)); et->setData("falloff_type", &(lamp->falloff_type)); @@ -1206,38 +1033,12 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) et->setData("clipend", &(lamp->clipend)); et->setData("bias", &(lamp->bias)); et->setData("soft", &(lamp->soft)); - et->setData("compressthresh", &(lamp->compressthresh)); et->setData("bufsize", &(lamp->bufsize)); - et->setData("samp", &(lamp->samp)); et->setData("buffers", &(lamp->buffers)); - et->setData("filtertype", &(lamp->filtertype)); - et->setData("bufflag", &(lamp->bufflag)); - et->setData("buftype", &(lamp->buftype)); - et->setData("ray_samp", &(lamp->ray_samp)); - et->setData("ray_sampy", &(lamp->ray_sampy)); - et->setData("ray_sampz", &(lamp->ray_sampz)); - et->setData("ray_samp_type", &(lamp->ray_samp_type)); et->setData("area_shape", &(lamp->area_shape)); et->setData("area_size", &(lamp->area_size)); et->setData("area_sizey", &(lamp->area_sizey)); et->setData("area_sizez", &(lamp->area_sizez)); - et->setData("adapt_thresh", &(lamp->adapt_thresh)); - et->setData("ray_samp_method", &(lamp->ray_samp_method)); - et->setData("shadhalostep", &(lamp->shadhalostep)); - et->setData("sun_effect_type", &(lamp->shadhalostep)); - et->setData("skyblendtype", &(lamp->skyblendtype)); - et->setData("horizon_brightness", &(lamp->horizon_brightness)); - et->setData("spread", &(lamp->spread)); - et->setData("sun_brightness", &(lamp->sun_brightness)); - et->setData("sun_size", &(lamp->sun_size)); - et->setData("backscattered_light", &(lamp->backscattered_light)); - et->setData("sun_intensity", &(lamp->sun_intensity)); - et->setData("atm_turbidity", &(lamp->atm_turbidity)); - et->setData("atm_extinction_factor", &(lamp->atm_extinction_factor)); - et->setData("atm_distance_factor", &(lamp->atm_distance_factor)); - et->setData("skyblendfac", &(lamp->skyblendfac)); - et->setData("sky_exposure", &(lamp->sky_exposure)); - et->setData("sky_colorspace", &(lamp->sky_colorspace)); } else { float constatt = light->getConstantAttenuation().getValue(); @@ -1277,11 +1078,10 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) lamp->energy = e; lamp->dist = d; - COLLADAFW::Light::LightType type = light->getLightType(); - switch (type) { + switch (light->getLightType()) { case COLLADAFW::Light::AMBIENT_LIGHT: { - lamp->type = LA_HEMI; + lamp->type = LA_SUN; //TODO needs more thoughts } break; case COLLADAFW::Light::SPOT_LIGHT: @@ -1301,7 +1101,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) { /* our sun is very strong, so pick a smaller energy level */ lamp->type = LA_SUN; - lamp->mode |= LA_NO_SPEC; } break; case COLLADAFW::Light::POINT_LIGHT: @@ -1317,7 +1116,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) break; case COLLADAFW::Light::UNDEFINED: { - fprintf(stderr, "Current lamp type is not supported.\n"); + fprintf(stderr, "Current light type is not supported.\n"); lamp->type = LA_LOCAL; } break; @@ -1332,7 +1131,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) // this function is called only for animations that pass COLLADAFW::validate bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; // return true; @@ -1342,7 +1141,7 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim) // called on post-process stage after writeVisualScenes bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; // return true; @@ -1354,7 +1153,7 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat // called on post-process stage after writeVisualScenes bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animationClip) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; return true; @@ -1372,7 +1171,7 @@ bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerDa // this is called on postprocess, before writeVisualScenes bool DocumentImporter::writeController(const COLLADAFW::Controller *controller) { - if (mImportStage != General) + if (mImportStage == Fetching_Controller_data) return true; return armature_importer.write_controller(controller); diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index bdb84dd9104..2f0fd7efceb 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -57,8 +57,8 @@ class DocumentImporter : COLLADAFW::IWriter public: //! Enumeration to denote the stage of import enum ImportStage { - General, //!< First pass to collect all data except controller - Controller, //!< Second pass to collect controller data + Fetching_Scene_data, /* First pass to collect all data except controller */ + Fetching_Controller_data, /* Second pass to collect controller data */ }; /** Constructor */ DocumentImporter(bContext *C, const ImportSettings *import_settings); @@ -75,7 +75,6 @@ public: Object* create_instance_node(Object*, COLLADAFW::Node*, COLLADAFW::Node*, Scene*, bool); void create_constraints(ExtraTags *et, Object *ob); std::vector<Object *> *write_node(COLLADAFW::Node*, COLLADAFW::Node*, Scene*, Object*, bool); - MTex* create_texture(COLLADAFW::EffectCommon*, COLLADAFW::Texture&, Material*, int, TexIndexTextureArrayMap&); void write_profile_COMMON(COLLADAFW::EffectCommon*, Material*); void translate_anim_recursive(COLLADAFW::Node*, COLLADAFW::Node*, Object*); @@ -147,6 +146,7 @@ private: ImportStage mImportStage; bContext *mContext; + ViewLayer *view_layer; UnitConverter unit_converter; ArmatureImporter armature_importer; @@ -158,7 +158,7 @@ private: /** Tags map of unique id as a string and ExtraTags instance. */ TagsMap uid_tags_map; - std::map<COLLADAFW::UniqueId, Image*> uid_image_map; + UidImageMap uid_image_map; std::map<COLLADAFW::UniqueId, Material*> uid_material_map; std::map<COLLADAFW::UniqueId, Material*> uid_effect_map; std::map<COLLADAFW::UniqueId, Camera*> uid_camera_map; @@ -175,6 +175,7 @@ private: std::string import_from_version; void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type); + }; #endif diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index d33ce725e58..f16392cdc1c 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -27,6 +27,7 @@ #include <map> +#include <set> #include "COLLADASWEffectProfile.h" #include "COLLADAFWColorOrTexture.h" @@ -40,24 +41,36 @@ extern "C" { #include "DNA_mesh_types.h" - #include "DNA_texture_types.h" #include "DNA_world_types.h" + #include "BKE_collection.h" #include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_material.h" } -EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) { +static std::string getActiveUVLayerName(Object *ob) +{ + Mesh *me = (Mesh *)ob->data; + + int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); + if (num_layers) + return std::string(bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV)); + + return ""; } +EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) : + COLLADASW::LibraryEffects(sw), + export_settings(export_settings), + key_image_map(key_image_map) +{} + bool EffectsExporter::hasEffects(Scene *sce) { - Base *base = (Base *)sce->base.first; - - while (base) { - Object *ob = base->object; + FOREACH_SCENE_OBJECT_BEGIN(sce, ob) + { int a; for (a = 0; a < ob->totcol; a++) { Material *ma = give_current_material(ob, a + 1); @@ -67,234 +80,123 @@ bool EffectsExporter::hasEffects(Scene *sce) return true; } - base = base->next; } + FOREACH_SCENE_OBJECT_END; return false; } -void EffectsExporter::exportEffects(Scene *sce) +void EffectsExporter::exportEffects(bContext *C, Scene *sce) { - this->scene = sce; - - if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) { - if (hasEffects(sce)) { - MaterialFunctor mf; - openLibrary(); - mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set); - closeLibrary(); - } - } - else { - std::set<Object *> uv_textured_obs = bc_getUVTexturedObjects(sce, !this->export_settings->active_uv_only); - std::set<Image *> uv_images = bc_getUVImages(sce, !this->export_settings->active_uv_only); - if (uv_images.size() > 0) { - openLibrary(); - 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 key(id_name(ima)); - key = translate_id(key); - COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, - key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, - key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); - sampler.setImageId(key); - - openEffect(key + "-effect"); - COLLADASW::EffectProfile ep(mSW); - ep.setProfileType(COLLADASW::EffectProfile::COMMON); - ep.setShaderType(COLLADASW::EffectProfile::PHONG); - ep.setDiffuse(createTexture(ima, key, &sampler), false, "diffuse"); - COLLADASW::ColorOrTexture cot = getcol(0, 0, 0, 1.0f); - ep.setSpecular(cot, false, "specular"); - ep.openProfile(); - ep.addProfileElements(); - ep.addExtraTechniques(mSW); - ep.closeProfile(); - closeEffect(); - } - closeLibrary(); - } + if (hasEffects(sce)) { + this->mContext = C; + this->scene = sce; + openLibrary(); + MaterialFunctor mf; + mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set); + + closeLibrary(); } } -void EffectsExporter::writeBlinn(COLLADASW::EffectProfile &ep, Material *ma) +void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma) { - COLLADASW::ColorOrTexture cot; - ep.setShaderType(COLLADASW::EffectProfile::BLINN); - // shininess - ep.setShininess(ma->har, false, "shininess"); - // specular - cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); - ep.setSpecular(cot, false, "specular"); + ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); //XXX check if BLINN and PHONG can be supported as well } -void EffectsExporter::writeLambert(COLLADASW::EffectProfile &ep, Material *ma) +void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma) { - COLLADASW::ColorOrTexture cot; - ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); + if (ma->alpha == 1.0f) { + return; // have no transparency + } + + // Tod: because we are in A_ONE mode transparency is calculated like this: + COLLADASW::ColorOrTexture cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha); + ep.setTransparent(cot); + ep.setOpaque(COLLADASW::EffectProfile::A_ONE); +} +void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma) +{ + // get diffuse color + COLLADASW::ColorOrTexture cot = bc_get_base_color(ma); + ep.setDiffuse(cot, false, "diffuse"); } -void EffectsExporter::writePhong(COLLADASW::EffectProfile &ep, Material *ma) +void EffectsExporter::set_specular_color(COLLADASW::EffectProfile &ep, Material *ma) { - COLLADASW::ColorOrTexture cot; - ep.setShaderType(COLLADASW::EffectProfile::PHONG); - // shininess - ep.setShininess(ma->har, false, "shininess"); - // specular - cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); + bool use_fallback = ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT; + COLLADASW::ColorOrTexture cot = bc_get_specular_color(ma, use_fallback); ep.setSpecular(cot, false, "specular"); } -void EffectsExporter::writeTextures( - COLLADASW::EffectProfile &ep, - std::string &key, - COLLADASW::Sampler *sampler, - MTex *t, Image *ima, - std::string &uvname ) +void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma) { - // Image not set for texture - if (!ima) return; + // not yet supported (needs changes in principled shader +} - // color - if (t->mapto & MAP_COL) { - ep.setDiffuse(createTexture(ima, uvname, sampler), false, "diffuse"); - } - // ambient - if (t->mapto & MAP_AMB) { - ep.setAmbient(createTexture(ima, uvname, sampler), false, "ambient"); - } - // specular - if (t->mapto & (MAP_SPEC | MAP_COLSPEC)) { - ep.setSpecular(createTexture(ima, uvname, sampler), false, "specular"); - } - // emission - if (t->mapto & MAP_EMIT) { - ep.setEmission(createTexture(ima, uvname, sampler), false, "emission"); - } - // reflective - if (t->mapto & MAP_REF) { - ep.setReflective(createTexture(ima, uvname, sampler)); +void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map) +{ + if (!ma->use_nodes) { + return; } - // alpha - if (t->mapto & MAP_ALPHA) { - ep.setTransparent(createTexture(ima, uvname, sampler)); + + MaterialNode material = MaterialNode(mContext, ma, key_image_map); + Image *image = material.get_diffuse_image(); + if (image == nullptr) { + return; } - // extension: - // Normal map --> Must be stored with <extra> tag as different technique, - // since COLLADA doesn't support normal maps, even in current COLLADA 1.5. - if (t->mapto & MAP_NORM) { - COLLADASW::Texture texture(key); - texture.setTexcoord(uvname); - texture.setSampler(*sampler); - // technique FCOLLADA, with the <bump> tag, is most likely the best understood, - // most widespread de-facto standard. - texture.setProfileName("FCOLLADA"); - texture.setChildElementName("bump"); - ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture)); + + std::string uid(id_name(image)); + std::string key = translate_id(uid); + + if (material_image_map.find(key) == material_image_map.end()) { + material_image_map[key] = image; + key_image_map[key] = image; } } -void EffectsExporter::operator()(Material *ma, Object *ob) +void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &material_image_map, std::string &active_uv) { - // create a list of indices to textures of type TEX_IMAGE - std::vector<int> tex_indices; - createTextureIndices(ma, tex_indices); + KeyImageMap::iterator iter; - openEffect(translate_id(id_name(ma)) + "-effect"); + for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) { - 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); - } - } + Image *image = iter->second; + std::string uid(id_name(image)); + std::string key = translate_id(uid); - // 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::Sampler *sampler = new COLLADASW::Sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, + key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, + key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); - COLLADASW::ColorOrTexture cot; + sampler->setImageId(key); - // transparency - if (ma->mode & MA_TRANSP) { - // Tod: because we are in A_ONE mode transparency is calculated like this: - cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha); - ep.setTransparent(cot); - ep.setOpaque(COLLADASW::EffectProfile::A_ONE); + ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse"); } +} - // 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); +void EffectsExporter::operator()(Material *ma, Object *ob) +{ + KeyImageMap material_image_map; - ep.setAmbient(cot, false, "ambient"); + openEffect(get_effect_id(ma)); - // 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"); - } + COLLADASW::EffectProfile ep(mSW); + ep.setProfileType(COLLADASW::EffectProfile::COMMON); + ep.openProfile(); + set_shader_type(ep, ma); - // XXX make this more readable if possible + COLLADASW::ColorOrTexture cot; - // 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]; + set_transparency(ep, ma); + set_diffuse_color(ep, ma); + set_specular_color(ep, ma); + set_emission(ep, ma); - // image to index to samp_surf map - // samp_surf[index] stores 2 pointers, sampler and surface - std::map<std::string, int> im_samp_map; + get_images(ma, material_image_map); + std::string active_uv(getActiveUVLayerName(ob)); + create_image_samplers(ep, material_image_map, active_uv); +#if 0 unsigned int a, b; for (a = 0, b = 0; a < tex_indices.size(); a++) { MTex *t = ma->mtex[tex_indices[a]]; @@ -308,24 +210,13 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // 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); + 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] = &samplers[a]; @@ -336,12 +227,6 @@ void EffectsExporter::operator()(Material *ma, Object *ob) } } - // 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(bc_get_active_uvlayer_name(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; @@ -354,9 +239,10 @@ void EffectsExporter::operator()(Material *ma, Object *ob) 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]; + COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i]; // possibly uninitialised memory ... writeTextures(ep, key, sampler, t, ima, uvname); } +#endif // performs the actual writing ep.addProfileElements(); @@ -397,20 +283,3 @@ COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, flo COLLADASW::ColorOrTexture cot(color); return cot; } - -//returns the array of mtex indices which have image -//need this for exporting textures -void EffectsExporter::createTextureIndices(Material *ma, std::vector<int> &indices) -{ - indices.clear(); - - for (int a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && - ma->mtex[a]->tex && - ma->mtex[a]->tex->type == TEX_IMAGE && - ma->mtex[a]->texco == TEXCO_UV) - { - indices.push_back(a); - } - } -} diff --git a/source/blender/collada/EffectExporter.h b/source/blender/collada/EffectExporter.h index 278e1ebcfce..462f1548586 100644 --- a/source/blender/collada/EffectExporter.h +++ b/source/blender/collada/EffectExporter.h @@ -42,12 +42,14 @@ #include "DNA_scene_types.h" #include "ExportSettings.h" +#include "collada_utils.h" class EffectsExporter: COLLADASW::LibraryEffects { public: - EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); - void exportEffects(Scene *sce); + EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map); + void exportEffects(bContext *C, Scene *sce); + void operator()(Material *ma, Object *ob); COLLADASW::ColorOrTexture createTexture(Image *ima, @@ -57,12 +59,14 @@ public: COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a); private: - /** Fills the array of mtex indices which have image. Used for exporting images. */ - void createTextureIndices(Material *ma, std::vector<int> &indices); + void set_shader_type(COLLADASW::EffectProfile &ep, Material *ma); + void set_transparency(COLLADASW::EffectProfile &ep, Material *ma); + void set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma); + void set_specular_color(COLLADASW::EffectProfile &ep, Material *ma); + void set_emission(COLLADASW::EffectProfile &ep, Material *ma); + void get_images(Material *ma, KeyImageMap &uid_image_map); + void create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &uid_image_map, std::string &active_uv); - void writeBlinn(COLLADASW::EffectProfile &ep, Material *ma); - void writeLambert(COLLADASW::EffectProfile &ep, Material *ma); - void writePhong(COLLADASW::EffectProfile &ep, Material *ma); void writeTextures(COLLADASW::EffectProfile &ep, std::string &key, COLLADASW::Sampler *sampler, @@ -72,8 +76,9 @@ private: bool hasEffects(Scene *sce); const ExportSettings *export_settings; - + KeyImageMap &key_image_map; Scene *scene; + bContext *mContext; }; #endif diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp index caa73900632..e708cc9fc8c 100644 --- a/source/blender/collada/ErrorHandler.cpp +++ b/source/blender/collada/ErrorHandler.cpp @@ -49,47 +49,67 @@ ErrorHandler::~ErrorHandler() //-------------------------------------------------------------------- bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) { - /* This method must return true when Collada should continue. + /* This method must return false when Collada should continue. * See https://github.com/KhronosGroup/OpenCOLLADA/issues/442 */ - bool isWarning = false; + bool isError = true; + std::string error_context; + std::string error_message; if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) { + error_context = "Schema validation"; + COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error; const GeneratedSaxParser::ParserError& parserError = saxParserError->getError(); + error_message = parserError.getErrorMessage(); - // Workaround to avoid wrong error if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_MIN_OCCURS_UNMATCHED) { if (STREQ(parserError.getElement(), "effect")) { - isWarning = true; + isError = false; } } - if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) { + + else if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) { if (!(STREQ(parserError.getElement(), "extra") && STREQ(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract"))) { - isWarning = true; + isError = false; } } - if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE) { - std::cout << "Couldn't open file" << std::endl; + else if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE) { + isError = true; + error_context = "File access"; } - std::cout << "Schema validation error: " << parserError.getErrorMessage() << std::endl; + else isError = (parserError.getSeverity() != GeneratedSaxParser::ParserError::Severity::SEVERITY_ERROR_NONCRITICAL); + } else if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXFWL) { + error_context = "Sax FWL"; COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error; + error_message = saxFWLError->getErrorMessage(); + /* * Accept non critical errors as warnings (i.e. texture not found) * This makes the importer more graceful, so it now imports what makes sense. */ - isWarning = (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL); - std::cout << "Sax FWL Error: " << saxFWLError->getErrorMessage() << std::endl; + + isError = (saxFWLError->getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL); + } else { - std::cout << "opencollada error: " << error->getFullErrorMessage() << std::endl; + error_context = "OpenCollada"; + error_message = error->getFullErrorMessage(); + isError = true; } - return isWarning; + std::string severity = (isError) ? "Error" : "Warning"; + std::cout << error_context << " (" << severity << "): " << error_message << std::endl; + if (isError) { + std::cout << "The Collada import has been forced to stop." << std::endl; + std::cout << "Please fix the reported error and then try again."; + mError = true; + } + return isError; } diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h index fa6751bef60..3b4397a6093 100644 --- a/source/blender/collada/ExportSettings.h +++ b/source/blender/collada/ExportSettings.h @@ -43,10 +43,19 @@ typedef enum BC_export_transformation_type { BC_TRANSFORMATION_TYPE_TRANSROTLOC } BC_export_transformation_type; -typedef enum BC_export_texture_type { - BC_TEXTURE_TYPE_MAT, - BC_TEXTURE_TYPE_UV -} BC_export_texture_type; + +typedef enum BC_export_animation_type { + BC_ANIMATION_EXPORT_SAMPLES, + BC_ANIMATION_EXPORT_KEYS +} BC_export_animation_type; + +typedef enum BC_ui_export_section { + BC_UI_SECTION_MAIN, + BC_UI_SECTION_GEOMETRY, + BC_UI_SECTION_ARMATURE, + BC_UI_SECTION_ANIMATION, + BC_UI_SECTION_COLLADA +} BC_ui_export_section; typedef struct ExportSettings { bool apply_modifiers; @@ -58,10 +67,13 @@ typedef struct ExportSettings { bool include_shapekeys; bool deform_bones_only; bool include_animations; + bool include_all_actions; int sampling_rate; + bool keep_smooth_curves; + bool keep_keyframes; bool active_uv_only; - BC_export_texture_type export_texture_type; + BC_export_animation_type export_animation_type; bool use_texture_copies; bool triangulate; diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index eb627b5c066..bb69c3fc653 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -40,11 +40,9 @@ extern "C" { #include "BLI_utildefines.h" - #include "BKE_DerivedMesh.h" - #include "BKE_main.h" + #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_library.h" - #include "BKE_customdata.h" #include "BKE_material.h" #include "BKE_mesh.h" } @@ -53,17 +51,11 @@ extern "C" { #include "collada_utils.h" -// TODO: optimize UV sets by making indexed list with duplicates removed -GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings) -{ -} - -void GeometryExporter::exportGeom(Main *bmain, Scene *sce) +void GeometryExporter::exportGeom() { + Scene *sce = blender_context.get_scene(); openLibrary(); - m_bmain = bmain; - mScene = sce; GeometryFunctor gf; gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set); @@ -72,15 +64,9 @@ void GeometryExporter::exportGeom(Main *bmain, Scene *sce) 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( - m_bmain, - mScene, + blender_context, ob, this->export_settings->export_mesh_type, this->export_settings->apply_modifiers, @@ -98,6 +84,7 @@ void GeometryExporter::operator()(Object *ob) } std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob); + geom_name = encode_xml(geom_name); exportedGeometry.insert(geom_id); @@ -114,7 +101,7 @@ void GeometryExporter::operator()(Object *ob) // writes <source> for normal coords createNormalsSource(geom_id, me, nor); - bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); + bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV); // writes <source> for uv coords if mesh has uv coords if (has_uvs) { @@ -138,22 +125,13 @@ void GeometryExporter::operator()(Object *ob) // Only create Polylists if number of faces > 0 if (me->totface > 0) { // XXX slow - std::set<Image *> uv_images = bc_getUVImages(ob, !this->export_settings->active_uv_only); - if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT || uv_images.size() == 0) { - if (ob->totcol) { - for (int a = 0; a < ob->totcol; a++) { - createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind); - } - } - else { - int i = 0; - createPolylist(i, has_uvs, has_color, ob, me, geom_id, norind); + if (ob->totcol) { + for (int a = 0; a < ob->totcol; a++) { + createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind); } } else { - bool all_uv_layers = !this->export_settings->active_uv_only; - std::set<Image *> uv_image_set = bc_getUVImages(ob, all_uv_layers); - createPolylists(uv_image_set, has_uvs, has_color, ob, me, geom_id, norind); + createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind); } } @@ -178,8 +156,7 @@ void GeometryExporter::operator()(Object *ob) } } - BKE_libblock_free_us(m_bmain, me); - + BKE_id_free(NULL, me); } void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) @@ -210,7 +187,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) // writes <source> for normal coords createNormalsSource(geom_id, me, nor); - bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); + bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV); // writes <source> for uv coords if mesh has uv coords if (has_uvs) { @@ -233,15 +210,13 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) //createLooseEdgeList(ob, me, geom_id, norind); // XXX slow - if (ob->totcol && this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) { + if (ob->totcol) { for (int a = 0; a < ob->totcol; a++) { createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind); } } else { - bool all_uv_layers = !this->export_settings->active_uv_only; - std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers); - createPolylists(uv_images, has_uvs, has_color, ob, me, geom_id, norind); + createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind); } closeMesh(); @@ -310,44 +285,7 @@ std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char return result; } -static void prepareToAppendValues(bool is_triangulated, COLLADASW::PrimitivesBase *facelist, std::vector<unsigned long> &vcount_list) -{ - // performs the actual writing - if (is_triangulated) { - ((COLLADASW::Triangles *)facelist)->prepareToAppendValues(); - } - else { - // sets <vcount> - facelist->setVCountList(vcount_list); - ((COLLADASW::Polylist *)facelist)-> prepareToAppendValues(); - } -} - -static void finishList(bool is_triangulated, COLLADASW::PrimitivesBase *facelist) -{ - if (is_triangulated) { - ((COLLADASW::Triangles *)facelist)->finish(); - } - else { - ((COLLADASW::Polylist *)facelist)->finish(); - } -} - -COLLADASW::PrimitivesBase *getFacelist(bool is_triangulated, COLLADASW::StreamWriter *mSW) -{ - COLLADASW::PrimitivesBase *facelist; - - if (is_triangulated) - { - facelist = new COLLADASW::Triangles(mSW); - } - else { - facelist = new COLLADASW::Polylist(mSW); - } - return facelist; -} - -// Export meshes with Materials +// 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, @@ -365,7 +303,7 @@ void GeometryExporter::createPolylist(short material_index, int i; int faces_in_polylist = 0; std::vector<unsigned long> vcount_list; - bool is_triangulated = true; + // count faces with this material for (i = 0; i < totpolys; i++) { MPoly *p = &mpolys[i]; @@ -373,9 +311,6 @@ void GeometryExporter::createPolylist(short material_index, if (p->mat_nr == material_index) { faces_in_polylist++; vcount_list.push_back(p->totloop); - if (p->totloop != 3) { - is_triangulated = false; - } } } @@ -386,21 +321,20 @@ void GeometryExporter::createPolylist(short material_index, } Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL; - COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW); - + COLLADASW::Polylist polylist(mSW); // sets count attribute in <polylist> - facelist->setCount(faces_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); - facelist->setMaterial(ostr.str()); + polylist.setMaterial(ostr.str()); } - COLLADASW::InputList &til = facelist->getInputList(); + COLLADASW::InputList &til = polylist.getInputList(); // creates <input> in <polylist> for vertices COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0); @@ -412,25 +346,18 @@ void GeometryExporter::createPolylist(short material_index, 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; + int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); + int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); for (i = 0; i < num_layers; i++) { - if (!this->export_settings->active_uv_only || i == active_uv_index) { - - std::string uv_name(bc_get_uvlayer_name(me, i)); - std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name; - std::string layer_id = makeTexcoordSourceId( - effective_id, - i, this->export_settings->active_uv_only); + int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, i); + if (!this->export_settings->active_uv_only || layer_index == active_uv_index) { - /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements - For now this is always 2 (This may change sometime/maybe) - */ + // char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i); COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD, - makeUrl(layer_id), - 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 - ); + 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 : layer_index // only_active_uv exported -> we have only one set + ); til.push_back(input3); } } @@ -451,9 +378,11 @@ void GeometryExporter::createPolylist(short material_index, } } + // sets <vcount> + polylist.setVCountList(vcount_list); // performs the actual writing - prepareToAppendValues(is_triangulated, facelist, vcount_list); + polylist.prepareToAppendValues(); // <p> int texindex = 0; @@ -466,202 +395,20 @@ void GeometryExporter::createPolylist(short material_index, BCPolygonNormalsIndices normal_indices = norind[i]; for (int j = 0; j < loop_count; j++) { - facelist->appendValues(l[j].v); - facelist->appendValues(normal_indices[j]); + polylist.appendValues(l[j].v); + polylist.appendValues(normal_indices[j]); if (has_uvs) - facelist->appendValues(texindex + j); + polylist.appendValues(texindex + j); if (has_color) - facelist->appendValues(texindex + j); + polylist.appendValues(texindex + j); } } texindex += loop_count; } - finishList(is_triangulated, facelist); - delete facelist; -} - -void GeometryExporter::createPolylists(std::set<Image *> uv_images, - bool has_uvs, - bool has_color, - Object *ob, - Mesh *me, - std::string& geom_id, - std::vector<BCPolygonNormalsIndices>& norind) -{ - 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 imageid(id_name(ima)); - createPolylist(imageid, has_uvs, - has_color, - ob, - me, - geom_id, - norind); - } - - /* We msut add an additional collector for the case when - * some parts of the object are not textured at all. - * The next call creates a polylist for all untextured polygons - */ - - createPolylist("", has_uvs, - has_color, - ob, - me, - geom_id, - norind); - -} - -/* =========================================================================== - * Export Meshes with UV Textures (export as materials, see also in - * effectExporter and MaterialExporter) - * - * If imageid is the empty string, then collect only untextured polygons - * =========================================================================== */ -void GeometryExporter::createPolylist(std::string imageid, - 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; - MTexPoly *mtpolys = me->mtpoly; - - int totpolys = me->totpoly; - - // <vcount> - int i; - int faces_in_polylist = 0; - std::vector<unsigned long> vcount_list; - bool is_triangulated = true; - // count faces with this material - for (i = 0; i < totpolys; i++) { - MTexPoly *tp = &mtpolys[i]; - MPoly *p = &mpolys[i]; - - std::string tpageid = (mtpolys && tp->tpage) ? id_name(tp->tpage) : ""; - if (tpageid == imageid) { - faces_in_polylist++; - vcount_list.push_back(p->totloop); - if (p->totloop != 3) { - is_triangulated = false; - } - } - } - - // no faces using this imageid - if (faces_in_polylist == 0) { - if (imageid != "") - fprintf(stderr, "%s: Image %s is not used.\n", id_name(ob).c_str(), imageid.c_str()); - return; - } - - COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW); - - // sets count attribute in <polylist> - facelist->setCount(faces_in_polylist); - - if (imageid != "") { - // sets material name - std::string material_id = get_material_id_from_id(imageid); - std::ostringstream ostr; - ostr << translate_id(material_id); - facelist->setMaterial(ostr.str()); - } - COLLADASW::InputList &til = facelist->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) { - - std::string uv_name(bc_get_uvlayer_name(me, i)); - std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name; - std::string layer_id = makeTexcoordSourceId( - effective_id, - i, this->export_settings->active_uv_only); - - /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements - For now this is always 2 (This may change sometime/maybe) - */ - COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD, - makeUrl(layer_id), - 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++; - } - } - - // performs the actual writing - prepareToAppendValues(is_triangulated, facelist, vcount_list); - - // <p> - int texindex = 0; - for (i = 0; i < totpolys; i++) { - MTexPoly *tp = &mtpolys[i]; - MPoly *p = &mpolys[i]; - int loop_count = p->totloop; - std::string tpageid = (mtpolys && tp->tpage) ? id_name(tp->tpage) : ""; - if (tpageid == imageid) { - MLoop *l = &mloops[p->loopstart]; - BCPolygonNormalsIndices normal_indices = norind[i]; - - for (int j = 0; j < loop_count; j++) { - facelist->appendValues(l[j].v); - facelist->appendValues(normal_indices[j]); - if (has_uvs) - facelist->appendValues(texindex + j); - - if (has_color) - facelist->appendValues(texindex + j); - } - } - - texindex += loop_count; - } - - finishList(is_triangulated, facelist); - delete facelist; + polylist.finish(); } // creates <source> for positions @@ -782,13 +529,7 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a); COLLADASW::FloatSourceF source(mSW); - std::string active_uv_name(bc_get_active_uvlayer_name(me)); - std::string effective_id = geom_id; // (active_uv_name == "") ? geom_id : active_uv_name; - std::string layer_id = makeTexcoordSourceId( - effective_id, - a, - this->export_settings->active_uv_only ); - + std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only); source.setId(layer_id); source.setArrayId(layer_id + ARRAY_ID_SUFFIX); diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h index fd9db7b1fd2..bd629946d01 100644 --- a/source/blender/collada/GeometryExporter.h +++ b/source/blender/collada/GeometryExporter.h @@ -43,9 +43,11 @@ #include "ExportSettings.h" #include "collada_utils.h" - +#include "BlenderContext.h" #include "BKE_key.h" +struct Depsgraph; + extern Object *bc_get_highest_selected_ancestor_or_self(Object *ob); class Normal @@ -72,13 +74,16 @@ class GeometryExporter : COLLADASW::LibraryGeometries Normal n; - Main *m_bmain; - Scene *mScene; - public: - GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); - void exportGeom(Main *bmain, Scene *sce); + // TODO: optimize UV sets by making indexed list with duplicates removed + GeometryExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : + COLLADASW::LibraryGeometries(sw), + blender_context(blender_context), + export_settings(export_settings) + {} + + void exportGeom(); void operator()(Object *ob); @@ -86,32 +91,14 @@ public: Mesh *me, std::string& geom_id); - // Create polylists for meshes with Materials + // powerful because it handles both cases when there is material and when there's not void createPolylist(short material_index, - bool has_uvs, - bool has_color, - Object *ob, - Mesh *me, - std::string& geom_id, - std::vector<BCPolygonNormalsIndices>& norind); - - // Create polylists for meshes with UV Textures - void createPolylists(std::set<Image *> uv_images, - bool has_uvs, - bool has_color, - Object *ob, - Mesh *me, - std::string& geom_id, - std::vector<BCPolygonNormalsIndices>& norind); - - // Create polylists for meshes with UV Textures - void createPolylist(std::string imageid, - bool has_uvs, - bool has_color, - Object *ob, - Mesh *me, - std::string& geom_id, - std::vector<BCPolygonNormalsIndices>& norind); + bool has_uvs, + bool has_color, + Object *ob, + Mesh *me, + std::string& geom_id, + std::vector<BCPolygonNormalsIndices>& norind); // creates <source> for positions void createVertsSource(std::string geom_id, Mesh *me); @@ -140,7 +127,7 @@ public: private: std::set<std::string> exportedGeometry; - + BlenderContext &blender_context; const ExportSettings *export_settings; Mesh *get_mesh(Scene *sce, Object *ob, int apply_modifiers); diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index 87f1197e3af..d7ab16f81e7 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -39,9 +39,11 @@ extern "C" { #include "BKE_image.h" #include "BKE_main.h" #include "BKE_mesh.h" + #include "BLI_fileops.h" #include "BLI_path_util.h" #include "BLI_string.h" + #include "IMB_imbuf_types.h" } @@ -49,217 +51,121 @@ extern "C" { #include "MaterialExporter.h" -ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryImages(sw), export_settings(export_settings) +ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) : + COLLADASW::LibraryImages(sw), + export_settings(export_settings), + key_image_map(key_image_map) { } void ImagesExporter::export_UV_Image(Image *image, bool use_copies) { - std::string id(id_name(image)); - std::string translated_id(translate_id(id)); - bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_id) == mImages.end(); + std::string name(id_name(image)); + std::string translated_name(translate_id(name)); - 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; - } + 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; + bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0; - ImageFormatData imageFormat; - BKE_imbuf_to_image_format(&imageFormat, imbuf); + 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 = BKE_image_has_packedfile(image); + short image_source = image->source; + bool is_generated = image_source == IMA_SRC_GENERATED; + bool is_packed = BKE_image_has_packedfile(image); - char export_path[FILE_MAX]; - char source_path[FILE_MAX]; - char export_dir[FILE_MAX]; - char export_file[FILE_MAX]; + 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)); + // 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) { + if (is_generated || is_dirty || use_copies || is_packed) { - // make absolute destination path + // make absolute destination path - BLI_strncpy(export_file, id.c_str(), sizeof(export_file)); - BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat); + 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); + 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); - } + // make dest directory if it doesn't exist + BLI_make_existing_file(export_path); + } - if (is_generated || is_dirty || is_packed) { + 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. + // 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)); + 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; } - else { + 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, BKE_main_blendfile_path_from_global()); - BLI_cleanup_path(NULL, source_path); + // make absolute source path + BLI_strncpy(source_path, image->name, sizeof(source_path)); + BLI_path_abs(source_path, BKE_main_blendfile_path_from_global()); + BLI_cleanup_path(NULL, source_path); - if (use_copies) { + 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). + // 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; - } + 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, export_file, sizeof(export_path)); - BLI_strncpy(export_path, source_path, sizeof(export_path)); - } } + else { - /* set name also to mNameNC. This helps other viewers import files exported from Blender better */ - COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_id, translated_id); - img.add(mSW); - fprintf(stdout, "Collada export: Added image: %s\n", export_file); - mImages.push_back(translated_id); + // Do not make any copies, but use the source path directly as reference + // to the original image - BKE_image_release_ibuf(image, imbuf, NULL); - } -} - -void ImagesExporter::export_UV_Images() -{ - std::set<Image *> uv_textures; - LinkNode *node; - bool use_texture_copies = this->export_settings->use_texture_copies; - bool active_uv_only = this->export_settings->active_uv_only; - - for (node = this->export_settings->export_set; node; node = node->next) { - Object *ob = (Object *)node->link; - if (ob->type == OB_MESH) { - Mesh *me = (Mesh *) ob->data; - BKE_mesh_tessface_ensure(me); - int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY); - for (int i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - if (!active_uv_only || active_uv_layer == i) - { - MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; - for (int j = 0; j < me->totpoly; j++, txface++) { - - Image *ima = txface->tpage; - if (ima == NULL) - continue; - - bool not_in_list = uv_textures.find(ima) == uv_textures.end(); - if (not_in_list) { - uv_textures.insert(ima); - export_UV_Image(ima, use_texture_copies); - } - } - } - } - } + BLI_strncpy(export_path, source_path, sizeof(export_path)); } } -} - -/* ============================================================ - * Check if there are any images to be exported - * Returns true as soon as an object is detected that - * either has an UV Texture assigned, or has a material - * assigned that uses an Image Texture. - * ============================================================ - */ -bool ImagesExporter::hasImages(Scene *sce) -{ - LinkNode *node; - for (node = this->export_settings->export_set; node; node = node->next) { - Object *ob = (Object *)node->link; - - for (int a = 0; a < ob->totcol; a++) { - Material *ma = give_current_material(ob, a + 1); - - // no material, but check all of the slots - if (!ma) continue; - int b; - for (b = 0; b < MAX_MTEX; b++) { - MTex *mtex = ma->mtex[b]; - if (mtex && mtex->tex && mtex->tex->ima) return true; - } + 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); - } - if (ob->type == OB_MESH) { - Mesh *me = (Mesh *) ob->data; - BKE_mesh_tessface_ensure(me); - bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); - if (has_uvs) { - int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - for (int a = 0; a < num_layers; a++) { - MTFace *tface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a); - Image *img = tface->tpage; - if (img) return true; - } - } - } - - } - return false; + BKE_image_release_ibuf(image, imbuf, NULL); } void ImagesExporter::exportImages(Scene *sce) { + bool use_texture_copies = this->export_settings->use_texture_copies; openLibrary(); - MaterialFunctor mf; - if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) { - mf.forEachMaterialInExportSet<ImagesExporter>(sce, *this, this->export_settings->export_set); - } - else { - export_UV_Images(); - } - - closeLibrary(); -} + KeyImageMap::iterator iter; + for (iter = key_image_map.begin(); iter != key_image_map.end(); iter++) { + Image *image = iter->second; + std::string uid(id_name(image)); + std::string key = translate_id(uid); - -void ImagesExporter::operator()(Material *ma, Object *ob) -{ - int a; - bool use_texture_copies = this->export_settings->use_texture_copies; - for (a = 0; a < MAX_MTEX; a++) { - MTex *mtex = ma->mtex[a]; - if (mtex && mtex->tex && mtex->tex->ima) { - Image *image = mtex->tex->ima; - export_UV_Image(image, use_texture_copies); - } + export_UV_Image(image, use_texture_copies); } + + closeLibrary(); } diff --git a/source/blender/collada/ImageExporter.h b/source/blender/collada/ImageExporter.h index 524260891ae..7ce312a52b1 100644 --- a/source/blender/collada/ImageExporter.h +++ b/source/blender/collada/ImageExporter.h @@ -40,21 +40,19 @@ #include "DNA_scene_types.h" #include "ExportSettings.h" +#include "collada_utils.h" class ImagesExporter: COLLADASW::LibraryImages { public: - ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); - + ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map); void exportImages(Scene *sce); - void operator()(Material *ma, Object *ob); -private: - std::vector<std::string> mImages; // contains list of written images, to avoid duplicates - void export_UV_Images(); - void export_UV_Image(Image *image, bool use_texture_copies); - bool hasImages(Scene *sce); +private: const ExportSettings *export_settings; + KeyImageMap &key_image_map; + void export_UV_Image(Image *image, bool use_texture_copies); + }; #endif diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp index 4d846693e50..0c0b1a15653 100644 --- a/source/blender/collada/InstanceWriter.cpp +++ b/source/blender/collada/InstanceWriter.cpp @@ -41,35 +41,30 @@ extern "C" { #include "collada_internal.h" #include "collada_utils.h" -void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type) +void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only) { - bool all_uv_layers = !active_uv_only; - COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList(); + for (int a = 0; a < ob->totcol; a++) { + Material *ma = give_current_material(ob, a + 1); - 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); + COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList(); + + 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 num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); 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++) { + int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); + for (int b = 0; b < num_layers; b++) { if (!active_uv_only || b == active_uv_index) { - char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b); + char *name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, b); im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++)); } } @@ -77,32 +72,4 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia 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); - } - } - } } diff --git a/source/blender/collada/InstanceWriter.h b/source/blender/collada/InstanceWriter.h index a46027325a2..49ddf091b1c 100644 --- a/source/blender/collada/InstanceWriter.h +++ b/source/blender/collada/InstanceWriter.h @@ -31,12 +31,11 @@ #include "COLLADASWBindMaterial.h" #include "DNA_object_types.h" -#include "collada.h" class InstanceWriter { protected: - void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type); + void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only); }; #endif diff --git a/source/blender/collada/LightExporter.cpp b/source/blender/collada/LightExporter.cpp index 02c5438ec47..b1f805bfb87 100644 --- a/source/blender/collada/LightExporter.cpp +++ b/source/blender/collada/LightExporter.cpp @@ -89,14 +89,7 @@ void LightsExporter::operator()(Object *ob) exportBlenderProfile(cla, la); addLight(cla); } - // hemi - else if (la->type == LA_HEMI) { - COLLADASW::AmbientLight cla(mSW, la_id, la_name); - cla.setColor(col, false, "color"); - cla.setConstantAttenuation(constatt); - exportBlenderProfile(cla, la); - addLight(cla); - } + // spot else if (la->type == LA_SPOT) { COLLADASW::SpotLight cla(mSW, la_id, la_name); @@ -149,7 +142,6 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la) cla.addExtraTechniqueParameter("blender", "dist", la->dist, "blender_dist"); cla.addExtraTechniqueParameter("blender", "spotsize", RAD2DEGF(la->spotsize)); cla.addExtraTechniqueParameter("blender", "spotblend", la->spotblend); - cla.addExtraTechniqueParameter("blender", "halo_intensity", la->haint, "blnder_halo_intensity"); cla.addExtraTechniqueParameter("blender", "att1", la->att1); cla.addExtraTechniqueParameter("blender", "att2", la->att2); // \todo figure out how we can have falloff curve supported here @@ -158,38 +150,13 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la) cla.addExtraTechniqueParameter("blender", "clipend", la->clipend); cla.addExtraTechniqueParameter("blender", "bias", la->bias); cla.addExtraTechniqueParameter("blender", "soft", la->soft); - cla.addExtraTechniqueParameter("blender", "compressthresh", la->compressthresh); cla.addExtraTechniqueParameter("blender", "bufsize", la->bufsize); cla.addExtraTechniqueParameter("blender", "samp", la->samp); cla.addExtraTechniqueParameter("blender", "buffers", la->buffers); - cla.addExtraTechniqueParameter("blender", "filtertype", la->filtertype); - cla.addExtraTechniqueParameter("blender", "bufflag", la->bufflag); - cla.addExtraTechniqueParameter("blender", "buftype", la->buftype); - cla.addExtraTechniqueParameter("blender", "ray_samp", la->ray_samp); - cla.addExtraTechniqueParameter("blender", "ray_sampy", la->ray_sampy); - cla.addExtraTechniqueParameter("blender", "ray_sampz", la->ray_sampz); - cla.addExtraTechniqueParameter("blender", "ray_samp_type", la->ray_samp_type); cla.addExtraTechniqueParameter("blender", "area_shape", la->area_shape); cla.addExtraTechniqueParameter("blender", "area_size", la->area_size); cla.addExtraTechniqueParameter("blender", "area_sizey", la->area_sizey); cla.addExtraTechniqueParameter("blender", "area_sizez", la->area_sizez); - cla.addExtraTechniqueParameter("blender", "adapt_thresh", la->adapt_thresh); - cla.addExtraTechniqueParameter("blender", "ray_samp_method", la->ray_samp_method); - cla.addExtraTechniqueParameter("blender", "shadhalostep", la->shadhalostep); - cla.addExtraTechniqueParameter("blender", "sun_effect_type", la->shadhalostep); - cla.addExtraTechniqueParameter("blender", "skyblendtype", la->skyblendtype); - cla.addExtraTechniqueParameter("blender", "horizon_brightness", la->horizon_brightness); - cla.addExtraTechniqueParameter("blender", "spread", la->spread); - cla.addExtraTechniqueParameter("blender", "sun_brightness", la->sun_brightness); - cla.addExtraTechniqueParameter("blender", "sun_size", la->sun_size); - cla.addExtraTechniqueParameter("blender", "backscattered_light", la->backscattered_light); - cla.addExtraTechniqueParameter("blender", "sun_intensity", la->sun_intensity); - cla.addExtraTechniqueParameter("blender", "atm_turbidity", la->atm_turbidity); - cla.addExtraTechniqueParameter("blender", "atm_extinction_factor", la->atm_extinction_factor); - cla.addExtraTechniqueParameter("blender", "atm_distance_factor", la->atm_distance_factor); - cla.addExtraTechniqueParameter("blender", "skyblendfac", la->skyblendfac); - cla.addExtraTechniqueParameter("blender", "sky_exposure", la->sky_exposure); - cla.addExtraTechniqueParameter("blender", "sky_colorspace", la->sky_colorspace); return true; } diff --git a/source/blender/collada/MaterialExporter.cpp b/source/blender/collada/MaterialExporter.cpp index 0c0395f2a21..2fa71817ac8 100644 --- a/source/blender/collada/MaterialExporter.cpp +++ b/source/blender/collada/MaterialExporter.cpp @@ -38,40 +38,14 @@ MaterialsExporter::MaterialsExporter(COLLADASW::StreamWriter *sw, const ExportSe void MaterialsExporter::exportMaterials(Scene *sce) { - if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) - { - if (hasMaterials(sce)) { - openLibrary(); + if (hasMaterials(sce)) { + openLibrary(); - MaterialFunctor mf; - mf.forEachMaterialInExportSet<MaterialsExporter>(sce, *this, this->export_settings->export_set); + MaterialFunctor mf; + mf.forEachMaterialInExportSet<MaterialsExporter>(sce, *this, this->export_settings->export_set); - closeLibrary(); - } - } - - else { - std::set<Image *> uv_images = bc_getUVImages(sce, !this->export_settings->active_uv_only); - if (uv_images.size() > 0) { - openLibrary(); - 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)); - - openMaterial(get_material_id_from_id(matid), translate_id(matid)); - std::string efid = translate_id(matid) + "-effect"; - addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid)); - closeMaterial(); - } - closeLibrary(); - } + closeLibrary(); } - } bool MaterialsExporter::hasMaterials(Scene *sce) @@ -94,12 +68,12 @@ bool MaterialsExporter::hasMaterials(Scene *sce) void MaterialsExporter::operator()(Material *ma, Object *ob) { - std::string name(id_name(ma)); - - openMaterial(get_material_id(ma), translate_id(name)); + std::string mat_name = encode_xml(id_name(ma)); + std::string mat_id = get_material_id(ma); + std::string eff_id = get_effect_id(ma); - std::string efid = translate_id(name) + "-effect"; - addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid)); + openMaterial(mat_id, mat_name); + addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, eff_id)); closeMaterial(); } diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h index e830a433432..171c05fcea7 100644 --- a/source/blender/collada/MaterialExporter.h +++ b/source/blender/collada/MaterialExporter.h @@ -44,6 +44,7 @@ extern "C" { #include "GeometryExporter.h" #include "collada_internal.h" #include "ExportSettings.h" +#include "Materials.h" class MaterialsExporter: COLLADASW::LibraryMaterials { diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp new file mode 100644 index 00000000000..3173c2592c4 --- /dev/null +++ b/source/blender/collada/Materials.cpp @@ -0,0 +1,329 @@ +/* +* ***** 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): Gaia Clary. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "Materials.h" + +MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) : + mContext(C), + material(ma), + effect(nullptr), + key_image_map(&key_image_map) +{ + ntree = prepare_material_nodetree(); + setShaderType(); +} + +MaterialNode::MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map) : + mContext(C), + material(ma), + effect(ef), + uid_image_map(&uid_image_map) +{ + ntree = prepare_material_nodetree(); + setShaderType(); + + std::map<std::string, bNode *> nmap; +#if 0 + nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300); + nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission"); + nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400); + nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200); + nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency"); + nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300); + nmap["out"]->flag &= ~NODE_SELECT; + + add_link(ntree, nmap["emission"], 0, nmap["add"], 0); + add_link(ntree, nmap["main"], 0, nmap["add"], 1); + add_link(ntree, nmap["add"], 0, nmap["mix"], 1); + add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2); + + add_link(ntree, nmap["mix"], 0, nmap["out"], 0); + // experimental, probably not used. + make_group(C, ntree, nmap); +#else + shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, ""); + output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, ""); + add_link(shader_node, 0, output_node, 0); +#endif +} + +void MaterialNode::setShaderType() +{ +#if 0 + COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType(); + // Currently we only support PBR based shaders + // TODO: simulate the effects with PBR + + // blinn + if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) { + ma->spec_shader = MA_SPEC_BLINN; + ma->spec = ef->getShininess().getFloatValue(); + } + // phong + else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) { + ma->spec_shader = MA_SPEC_PHONG; + ma->har = ef->getShininess().getFloatValue(); + } + // lambert + else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) { + ma->diff_shader = MA_DIFF_LAMBERT; + } + // default - lambert + else { + ma->diff_shader = MA_DIFF_LAMBERT; + fprintf(stderr, "Current shader type is not supported, default to lambert.\n"); + } +#endif +} + +bNodeTree *MaterialNode::prepare_material_nodetree() +{ + if (material->nodetree == NULL) { + material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree"); + material->use_nodes = true; + } + return material->nodetree; +} + +bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label) +{ + bNode *node = nodeAddStaticNode(mContext, ntree, node_type); + if (node) { + if (label.length() > 0) { + strcpy(node->label, label.c_str()); + } + node->locx = locx; + node->locy = locy; + node->flag |= NODE_SELECT; + } + node_map[label] = node; + return node; +} + +void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index) +{ + bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index); + bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index); + + nodeAddLink(ntree, from_node, from_socket, to_node, to_socket); +} + +void MaterialNode::set_reflectivity(float val) +{ + material->metallic = val; + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_METALLIC); + *(float *)socket->default_value = val; +} + +void MaterialNode::set_ior(float val) +{ + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_IOR); + *(float *)socket->default_value = val; +} + +void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label) +{ + int locy = -300 * (node_map.size()-2); + if (cot.isColor()) { + COLLADAFW::Color col = cot.getColor(); + material->r = col.getRed(); + material->g = col.getGreen(); + material->b = col.getBlue(); + + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_DIFFUSE); + float *fcol = (float *)socket->default_value; + fcol[0] = col.getRed(); + fcol[1] = col.getGreen(); + fcol[2] = col.getBlue(); + } + else if (cot.isTexture()) { + bNode *texture_node = add_texture_node(cot, -300, locy, label); + if (texture_node != NULL) { + add_link(texture_node, 0, shader_node, 0); + } + } +} + +Image *MaterialNode::get_diffuse_image() +{ + bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED); + if (shader == nullptr) { + return nullptr; + } + + bNodeSocket *in_socket = (bNodeSocket *)BLI_findlink(&shader->inputs, BC_PBR_DIFFUSE); + if (in_socket == nullptr) { + return nullptr; + } + + bNodeLink *link = in_socket->link; + if (link == nullptr) { + return nullptr; + } + + bNode *texture = link->fromnode; + if (texture == nullptr) { + return nullptr; + } + + if (texture->type != SH_NODE_TEX_IMAGE) { + return nullptr; + } + + Image *image = (Image *)texture->id; + return image; + +} + +static bNodeSocket *set_color(bNode *node, COLLADAFW::Color col) +{ + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0); + float *fcol = (float *)socket->default_value; + fcol[0] = col.getRed(); + fcol[1] = col.getGreen(); + fcol[2] = col.getBlue(); + + return socket; +} + +void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label) +{ + int locy = -300 * (node_map.size() - 2); + if (cot.isColor()) { + COLLADAFW::Color col = cot.getColor(); + bNode *node = add_node(SH_NODE_RGB, -300, locy, label); + set_color(node, col); + // TODO: Connect node + } + // texture + else if (cot.isTexture()) { + add_texture_node(cot, -300, locy, label); + // TODO: Connect node + } +} +void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label) +{ + int locy = -300 * (node_map.size() - 2); + if (cot.isColor()) { + COLLADAFW::Color col = cot.getColor(); + bNode *node = add_node(SH_NODE_RGB, -300, locy, label); + set_color(node, col); + // TODO: Connect node + } + // texture + else if (cot.isTexture()) { + add_texture_node(cot, -300, locy, label); + // TODO: Connect node + } +} + +void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot, std::string label) +{ + int locy = -300 * (node_map.size() - 2); + if (cot.isColor()) { + COLLADAFW::Color col = cot.getColor(); + bNode *node = add_node(SH_NODE_RGB, -300, locy, label); + set_color(node, col); + // TODO: Connect node + } + // texture + else if (cot.isTexture()) { + add_texture_node(cot, -300, locy, label); + // TODO: Connect node + } +} + +void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label) +{ + if (effect == nullptr) { + return; + } + + int locy = -300 * (node_map.size() - 2); + if (cot.isColor()) { + COLLADAFW::Color col = effect->getTransparent().getColor(); + float alpha = effect->getTransparency().getFloatValue(); + + if (col.isValid()) { + alpha *= col.getAlpha(); // Assuming A_ONE opaque mode + } + if (col.isValid() || alpha < 1.0) { + // not sure what to do here + } + + bNode *node = add_node(SH_NODE_RGB, -300, locy, label); + set_color(node, col); + // TODO: Connect node + } + // texture + else if (cot.isTexture()) { + add_texture_node(cot, -300, locy, label); + // TODO: Connect node + } +} + +void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot, std::string label) +{ + int locy = -300 * (node_map.size() - 2); + if (cot.isColor()) { + COLLADAFW::Color col = cot.getColor(); + material->specr = col.getRed(); + material->specg = col.getGreen(); + material->specb = col.getBlue(); + + bNode *node = add_node(SH_NODE_RGB, -300, locy, label); + set_color(node, col); + // TODO: Connect node + } + // texture + else if (cot.isTexture()) { + add_texture_node(cot, -300, locy, label); + // TODO: Connect node + } +} + +bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label) +{ + if (effect == nullptr) { + return nullptr; + } + + UidImageMap &image_map = *uid_image_map; + + COLLADAFW::Texture ctex = cot.getTexture(); + + COLLADAFW::SamplerPointerArray& samp_array = effect->getSamplerPointerArray(); + COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()]; + + const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage(); + + if (image_map.find(ima_uid) == image_map.end()) { + fprintf(stderr, "Couldn't find an image by UID.\n"); + return NULL; + } + + Image *ima = image_map[ima_uid]; + bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label); + texture_node->id = &ima->id; + return texture_node; + +} diff --git a/source/blender/collada/Materials.h b/source/blender/collada/Materials.h new file mode 100644 index 00000000000..69f64a6280d --- /dev/null +++ b/source/blender/collada/Materials.h @@ -0,0 +1,84 @@ +/* + * ***** 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 ***** + */ + +#ifndef __MATERIAL_H__ +#define __MATERIAL_H__ + +#include <map> +#include <string> + +extern "C" { +#include "BKE_context.h" +#include "BKE_node.h" +#include "BLI_listbase.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" +} + +#include "collada_utils.h" +#include "COLLADAFWEffectCommon.h" + +typedef enum BC_pbr_inputs { + BC_PBR_DIFFUSE = 0, + BC_PBR_METALLIC = 4, + BC_PBR_IOR = 14 +} BC_pbr_inputs; + +typedef std::map<std::string, bNode *> NodeMap; + +class MaterialNode { + +private: + bContext *mContext; + Material *material; + COLLADAFW::EffectCommon *effect; + UidImageMap *uid_image_map = nullptr; + KeyImageMap *key_image_map = nullptr; + + NodeMap node_map; + bNodeTree *ntree; + + bNode *shader_node; + bNode *output_node; + + bNodeTree *prepare_material_nodetree(); + bNode *add_node(int node_type, int locx, int locy, std::string label); + void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index); + bNode *add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label); + void setShaderType(); + +public: + MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map); + MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map); + void set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label); + Image *get_diffuse_image(); + void set_specular(COLLADAFW::ColorOrTexture &cot, std::string label); + void set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label); + void set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label); + void set_emission(COLLADAFW::ColorOrTexture &cot, std::string label); + void set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label); + void set_reflectivity(float val); + void set_ior(float val); + +}; + +#endif diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 1f24010b04e..4dd3f1cc219 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -43,7 +43,6 @@ extern "C" { #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" @@ -207,11 +206,12 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) } -MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce) : - unitconverter(unitconv), - m_bmain(bmain), - scene(sce), - armature_importer(arm) { +MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer): + unitconverter(unitconv), + m_bmain(bmain), + scene(sce), + view_layer(view_layer), + armature_importer(arm) { } bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count) @@ -476,11 +476,9 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i]; COLLADAFW::String &uvname = info->mName; // Allocate space for UV_data - CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str()); CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str()); } // activate the first uv map - me->mtpoly = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0); me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0); } @@ -601,9 +599,8 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me) COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); - for (int i = 0; i < prim_arr.getCount(); i++) { - - COLLADAFW::MeshPrimitive *mp = prim_arr[i]; + for (int index = 0; index < prim_arr.getCount(); index++) { + COLLADAFW::MeshPrimitive *mp = prim_arr[index]; int type = mp->getPrimitiveType(); if (type == COLLADAFW::MeshPrimitive::LINES) { @@ -881,48 +878,6 @@ std::string *MeshImporter::get_geometry_name(const std::string &mesh_name) 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(); - size_t setindex = ctexture.getSetIndex(); - std::string uvname = ctexture.getSemantic(); - - if (setindex == -1) return NULL; - - const CustomData *data = &me->fdata; - int layer_index = CustomData_get_layer_index(data, CD_MTFACE); - - if (layer_index == -1) return NULL; - - 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; -} - /** * this function checks if both objects have the same * materials assigned to Object (in the same order) @@ -1056,21 +1011,19 @@ void MeshImporter::optimize_material_assignements() * 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<COLLADAFW::UniqueId, Material *>& uid_material_map, - Object *ob, const COLLADAFW::UniqueId *geom_uid, - char *layername, MTFace *texture_face, - std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index) +void MeshImporter::assign_material_to_geom( + COLLADAFW::MaterialBinding cmaterial, + std::map<COLLADAFW::UniqueId, Material *>& uid_material_map, + Object *ob, const COLLADAFW::UniqueId *geom_uid, + short mat_index) { - MTex *color_texture = NULL; - 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; + return; } // first time we get geom_uid, ma_uid pair. Save for later check. @@ -1083,27 +1036,6 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri ob->actcol=0; assign_material(m_bmain, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT); - 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) && - !STREQ(layername, color_texture->uvname)) - { - 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(); @@ -1118,23 +1050,16 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri Primitive& prim = *it; MPoly *mpoly = prim.mpoly; - for (i = 0; i < prim.totpoly; i++, mpoly++) { + for (int i = 0; i < prim.totpoly; i++, mpoly++) { mpoly->mat_nr = mat_index; - // bind texture images to faces - if (texture_face && color_texture) { - 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) + std::map<COLLADAFW::UniqueId, Material *>& uid_material_map) { const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId(); @@ -1164,8 +1089,8 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta const char *name = (id.length()) ? id.c_str() : NULL; // add object - Object *ob = bc_add_object(m_bmain, scene, OB_MESH, name); - bc_set_mark(ob); // used later for material assignement optimization + Object *ob = bc_add_object(m_bmain, scene, view_layer, OB_MESH, name); + bc_set_mark(ob); // used later for material assignment optimization // store object pointer for ArmatureImporter @@ -1182,10 +1107,6 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta id_us_plus(&old_mesh->id); /* Because BKE_mesh_assign_object would have already decreased it... */ BKE_libblock_free_us(m_bmain, old_mesh); - char layername[100]; - layername[0] = '\0'; - MTFace *texture_face = NULL; - COLLADAFW::MaterialBindingArray& mat_array = geom->getMaterialBindings(); @@ -1193,9 +1114,9 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta for (unsigned int i = 0; i < mat_array.getCount(); i++) { if (mat_array[i].getReferencedMaterial().isValid()) { - texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid, - layername, texture_face, - material_texture_mapping_map, i); + assign_material_to_geom( + mat_array[i], uid_material_map, ob, geom_uid, + i); } else { fprintf(stderr, "invalid referenced material for %s\n", mat_array[i].getName().c_str()); diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h index 23926bf1ce5..4583242808b 100644 --- a/source/blender/collada/MeshImporter.h +++ b/source/blender/collada/MeshImporter.h @@ -51,7 +51,6 @@ extern "C" { #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_texture_types.h" } @@ -93,6 +92,8 @@ private: Main *m_bmain; Scene *scene; + ViewLayer *view_layer; + ArmatureImporter *armature_importer; std::map<std::string, std::string> mesh_geom_map; // needed for correct shape key naming @@ -160,29 +161,24 @@ private: public: - MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce); + MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer); virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); - 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<COLLADAFW::UniqueId, Material*>& uid_material_map, - Object *ob, const COLLADAFW::UniqueId *geom_uid, - char *layername, MTFace *texture_face, - std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index); + void assign_material_to_geom( + COLLADAFW::MaterialBinding cmaterial, + std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, + Object *ob, const COLLADAFW::UniqueId *geom_uid, + short mat_index); Object *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); + std::map<COLLADAFW::UniqueId, Material*>& uid_material_map); // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID bool write_geometry(const COLLADAFW::Geometry* geom); diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp index b571b7503d5..3e375b14e44 100644 --- a/source/blender/collada/SceneExporter.cpp +++ b/source/blender/collada/SceneExporter.cpp @@ -26,6 +26,7 @@ extern "C" { #include "BLI_utildefines.h" + #include "BKE_collection.h" #include "BKE_object.h" #include "BLI_listbase.h" } @@ -33,22 +34,19 @@ extern "C" { #include "SceneExporter.h" #include "collada_utils.h" -SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings) - : COLLADASW::LibraryVisualScenes(sw), arm_exporter(arm), export_settings(export_settings) +void SceneExporter::exportScene() { -} + Scene *scene = blender_context.get_scene(); -void SceneExporter::exportScene(bContext *C, Scene *sce) -{ // <library_visual_scenes> <visual_scene> - std::string id_naming = id_name(sce); - openVisualScene(translate_id(id_naming), id_naming); - exportHierarchy(C, sce); + std::string name = id_name(scene); + openVisualScene(translate_id(name), encode_xml(name)); + exportHierarchy(); closeVisualScene(); closeLibrary(); } -void SceneExporter::exportHierarchy(bContext *C, Scene *sce) +void SceneExporter::exportHierarchy() { LinkNode *node; std::vector<Object *> base_objects; @@ -68,6 +66,7 @@ void SceneExporter::exportHierarchy(bContext *C, Scene *sce) case OB_CAMERA: case OB_LAMP: case OB_EMPTY: + case OB_GPENCIL: case OB_ARMATURE: base_objects.push_back(ob); break; @@ -80,165 +79,162 @@ void SceneExporter::exportHierarchy(bContext *C, Scene *sce) Object *ob = base_objects[index]; if (bc_is_marked(ob)) { bc_remove_mark(ob); - writeNodes(C, ob, sce); + writeNodes(ob); } } } +void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *parent) +{ + /* TODO: Handle the case where a parent is not exported + Actually i am not even sure if this can be done at all + in a good way. + I really prefer to enforce the export of hidden + elements in an object hierarchy. When the children of + the hidden elements are exported as well. + */ + for (int i = 0; i < child_objects.size(); ++i) { + Object *child = child_objects[i]; + if (bc_is_marked(child)) { + bc_remove_mark(child); + writeNodes(child); + } + } +} -void SceneExporter::writeNodes(bContext *C, Object *ob, Scene *sce) +void SceneExporter::writeNodes(Object *ob) { + ViewLayer *view_layer = blender_context.get_view_layer(); + + std::vector<Object *> child_objects; + bc_get_children(child_objects, ob, view_layer); + bool can_export = bc_is_in_Export_set(this->export_settings->export_set, ob, view_layer); + // 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); + armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm, view_layer); if (armature_exported && bc_is_marked(ob_arm)) { bc_remove_mark(ob_arm); - writeNodes(C, ob_arm, sce); + writeNodes(ob_arm); 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); + if (can_export) { + COLLADASW::Node colladaNode(mSW); + colladaNode.setNodeId(translate_id(id_name(ob))); + colladaNode.setNodeName(encode_xml(id_name(ob))); + colladaNode.setType(COLLADASW::Node::NODE); - colladaNode.start(); + 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 (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->export_settings->export_transformation_type, + this->export_settings->limit_precision + ); + } - 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; + // <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(encode_xml(id_name(ob))); + InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), + ob, + this->export_settings->active_uv_only); + instGeom.add(); } } - } - - 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->export_settings->export_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); + // <instance_controller> + else if (ob->type == OB_ARMATURE) { + arm_exporter->add_armature_bones(ob, view_layer, this, child_objects); } - 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, - this->export_settings->export_texture_type); - - instGeom.add(); - } - } - - // <instance_controller> - else if (ob->type == OB_ARMATURE) { - arm_exporter->add_armature_bones(C, 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); - } + // <instance_camera> + else if (ob->type == OB_CAMERA) { + COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob))); + instCam.add(); } - } - if (ob->type == OB_ARMATURE) { - colladaNode.end(); - } + // <instance_light> + else if (ob->type == OB_LAMP) { + COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob))); + instLa.add(); + } - 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); + // empty object + else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLICOLLECTION + if ((ob->transflag & OB_DUPLICOLLECTION) == OB_DUPLICOLLECTION && ob->dup_group) { + Collection *collection = ob->dup_group; + /* printf("group detected '%s'\n", group->id.name + 2); */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) + { + printf("\t%s\n", object->id.name); } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } - 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(C, *i, sce); + if (BLI_listbase_is_empty(&ob->constraints) == false) { + bConstraint *con = (bConstraint *)ob->constraints.first; + while (con) { + std::string con_name(encode_xml(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; + } + } } - } - - if (ob->type != OB_ARMATURE) + writeNodeList(child_objects, ob); colladaNode.end(); + } } diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h index 6cf561749de..f6525d5438d 100644 --- a/source/blender/collada/SceneExporter.h +++ b/source/blender/collada/SceneExporter.h @@ -34,7 +34,7 @@ extern "C" { #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "DNA_image_types.h" @@ -48,7 +48,6 @@ extern "C" { #include "DNA_modifier_types.h" #include "DNA_userdef_types.h" -#include "BKE_DerivedMesh.h" #include "BKE_fcurve.h" #include "BKE_animsys.h" #include "BLI_path_util.h" @@ -95,16 +94,26 @@ extern "C" { class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter { public: - SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings); - void exportScene(bContext *C, Scene *sce); + + SceneExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings) : + COLLADASW::LibraryVisualScenes(sw), + blender_context(blender_context), + arm_exporter(arm), + export_settings(export_settings) + {} + + void exportScene(); private: + BlenderContext &blender_context; friend class ArmatureExporter; - void exportHierarchy(bContext *C, Scene *sce); - void writeNodes(bContext *C, Object *ob, Scene *sce); - ArmatureExporter *arm_exporter; const ExportSettings *export_settings; + + void exportHierarchy(); + void writeNodeList(std::vector<Object *> &child_objects, Object *parent); + void writeNodes(Object *ob); + }; #endif diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index b270ac87976..317d39c015b 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -159,9 +159,9 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co) } // called from write_controller -Object *SkinInfo::create_armature(Main *bmain, Scene *scene) +Object *SkinInfo::create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer) { - ob_arm = bc_add_object(bmain, scene, OB_ARMATURE, NULL); + ob_arm = bc_add_object(bmain, scene, view_layer, OB_ARMATURE, NULL); return ob_arm; } @@ -232,7 +232,10 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique amd->object = ob_arm; #if 1 - bc_set_parent(ob, ob_arm, C); + /* XXX Why do we enforce objects to be children of Armatures if they weren't so before ?*/ + if (!BKE_object_is_child_recursive(ob_arm, ob)) { + bc_set_parent(ob, ob_arm, C); + } #else Object workob; ob->parent = ob_arm; @@ -241,10 +244,7 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique BKE_object_workob_calc_parent(scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); - DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA); - - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); #endif copy_m4_m4(ob->obmat, bind_shape_matrix); BKE_object_apply_mat4(ob, ob->obmat, 0, 0); diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h index 500ae3878a6..39808c546b1 100644 --- a/source/blender/collada/SkinInfo.h +++ b/source/blender/collada/SkinInfo.h @@ -99,7 +99,7 @@ public: void set_controller(const COLLADAFW::SkinController* co); // called from write_controller - Object *create_armature(Main *bmain, Scene *scene); + Object *create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer); Object* set_armature(Object *ob_arm); diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp index bf9c34153b7..0c2ea9cb7c4 100644 --- a/source/blender/collada/TransformReader.cpp +++ b/source/blender/collada/TransformReader.cpp @@ -80,8 +80,10 @@ void TransformReader::get_node_mat( dae_scale_to_mat4(tm, cur); break; case COLLADAFW::Transformation::LOOKAT: + fprintf(stderr, "|! LOOKAT transformations are not supported yet.\n"); + break; case COLLADAFW::Transformation::SKEW: - fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n"); + fprintf(stderr, "|! SKEW transformations are not supported yet.\n"); break; } diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index 89653c139f3..4ff9e0af50f 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -26,12 +26,14 @@ */ -#include "BKE_object.h" #include "BLI_math.h" +#include "BLI_sys_types.h" + +#include "BKE_object.h" #include "TransformWriter.h" -void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]) +void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4], bool limit_precision) { float loc[3], rot[3], scale[3]; float local[4][4]; @@ -61,7 +63,11 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], } } -void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, BC_export_transformation_type transformation_type) +void TransformWriter::add_node_transform_ob( + COLLADASW::Node& node, + Object *ob, + BC_export_transformation_type transformation_type, + bool limit_precision) { #if 0 float rot[3], loc[3], scale[3]; @@ -98,17 +104,18 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B add_transform(node, loc, rot, scale); #endif - UnitConverter converter; - double d_obmat[4][4]; - float f_obmat[4][4]; - /* Export the local Matrix (relative to the object parent, be it an object, bone or vertex(-tices)) */ + float f_obmat[4][4]; BKE_object_matrix_local_get(ob, f_obmat); - converter.mat4_to_dae_double(d_obmat, f_obmat); switch (transformation_type) { case BC_TRANSFORMATION_TYPE_MATRIX: { + UnitConverter converter; + double d_obmat[4][4]; + converter.mat4_to_dae_double(d_obmat, f_obmat); + if (limit_precision) + bc_sanitize_mat(d_obmat, LIMITTED_PRECISION); node.addMatrix("transform",d_obmat); break; } @@ -116,6 +123,11 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B { float loc[3], rot[3], scale[3]; bc_decompose(f_obmat, loc, rot, NULL, scale); + if (limit_precision) { + bc_sanitize_v3(loc, LIMITTED_PRECISION); + bc_sanitize_v3(rot, LIMITTED_PRECISION); + bc_sanitize_v3(scale, LIMITTED_PRECISION); + } add_transform(node, loc, rot, scale); break; } diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h index 5bb13d4aac9..2c7fedb9f34 100644 --- a/source/blender/collada/TransformWriter.h +++ b/source/blender/collada/TransformWriter.h @@ -39,9 +39,17 @@ class TransformWriter { protected: - void add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]); - - void add_node_transform_ob(COLLADASW::Node& node, Object *ob, BC_export_transformation_type transformation_type); + void add_node_transform( + COLLADASW::Node& node, + float mat[4][4], + float parent_mat[4][4], + bool limit_precision=false); + + void add_node_transform_ob( + COLLADASW::Node& node, + Object *ob, + BC_export_transformation_type transformation_type, + bool limit_precision = false); void add_node_transform_identity(COLLADASW::Node& node); diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index ecaa7fba08c..c6321a4047e 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -32,34 +32,67 @@ #include "DocumentImporter.h" #include "ExportSettings.h" #include "ImportSettings.h" +#include "collada.h" extern "C" { #include "BKE_scene.h" #include "BKE_context.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" /* make dummy file */ #include "BLI_fileops.h" #include "BLI_linklist.h" + +static void print_import_header(ImportSettings &import_settings) +{ + fprintf(stderr, "+-- Collada Import parameters------\n"); + fprintf(stderr, "| input file : %s\n", import_settings.filepath); + fprintf(stderr, "| use units : %s\n", (import_settings.import_units)?"yes":"no"); + fprintf(stderr, "| autoconnect : %s\n", (import_settings.auto_connect) ? "yes" : "no"); + fprintf(stderr, "+-- Armature Import parameters ----\n"); + fprintf(stderr, "| find bone chains: %s\n", (import_settings.find_chains) ? "yes" : "no"); + fprintf(stderr, "| min chain len : %d\n", import_settings.min_chain_length); + fprintf(stderr, "| fix orientation : %s\n", (import_settings.fix_orientation) ? "yes" : "no"); + fprintf(stderr, "| keep bind info : %s\n", (import_settings.keep_bind_info) ? "yes" : "no"); + +} + +static void print_import_footer(int status) +{ + fprintf(stderr, "+----------------------------------\n"); + fprintf(stderr, "| Collada Import : %s\n", (status)? "OK":"FAIL"); + fprintf(stderr, "+----------------------------------\n"); +} + int collada_import(bContext *C, ImportSettings *import_settings) { + print_import_header(*import_settings); DocumentImporter imp(C, import_settings); - return (imp.import())? 1:0; + int status = imp.import()? 1:0; + print_import_footer(status); + + return status; } int collada_export(bContext *C, - EvaluationContext *eval_ctx, - Scene *sce, ExportSettings *export_settings) { + BlenderContext blender_context(C); + ViewLayer *view_layer = blender_context.get_view_layer(); int includeFilter = OB_REL_NONE; if (export_settings->include_armatures) includeFilter |= OB_REL_MOD_ARMATURE; if (export_settings->include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE; + /* Fetch the complete set of exported objects + * ATTENTION: Invisible objects will not be exported + */ eObjectSet objectSet = (export_settings->selected) ? OB_SET_SELECTED : OB_SET_ALL; - export_settings->export_set = BKE_object_relational_superset(sce, objectSet, (eObRelationTypes)includeFilter); + export_settings->export_set = BKE_object_relational_superset(view_layer, objectSet, (eObRelationTypes)includeFilter); + int export_count = BLI_linklist_count(export_settings->export_set); if (export_count == 0) { @@ -75,8 +108,8 @@ int collada_export(bContext *C, bc_bubble_sort_by_Object_name(export_settings->export_set); } - DocumentExporter exporter(export_settings); - int status = exporter.exportCurrentScene(C, eval_ctx, sce); + DocumentExporter exporter(blender_context, export_settings); + int status = exporter.exportCurrentScene(); BLI_linklist_free(export_settings->export_set, NULL); diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 907c94855f7..7882542ca44 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -36,15 +36,14 @@ extern "C" { #endif -#include "BKE_depsgraph.h" #include "BLI_linklist.h" #include "BLI_path_util.h" #include "RNA_types.h" - -struct EvaluationContext; struct bContext; +struct Depsgraph; struct Scene; +struct ViewLayer; /* * both return 1 on success, 0 on error @@ -53,8 +52,6 @@ int collada_import(struct bContext *C, ImportSettings *import_settings); int collada_export(struct bContext *C, - struct EvaluationContext *eval_ctx, - struct Scene *sce, ExportSettings *export_settings); #ifdef __cplusplus diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp index 14f3e811797..64de0596ac5 100644 --- a/source/blender/collada/collada_internal.cpp +++ b/source/blender/collada/collada_internal.cpp @@ -30,6 +30,7 @@ #include "collada_utils.h" #include "BLI_linklist.h" +#include "ED_armature.h" UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP) { @@ -310,6 +311,33 @@ std::string id_name(void *id) return ((ID *)id)->name + 2; } +std::string encode_xml(std::string xml) +{ + const std::map<char, std::string> escape { + {'<' , "<" }, + {'>' , ">" }, + {'"' , """}, + {'\'', "'"}, + {'&' , "&" } + }; + + std::map<char, std::string>::const_iterator it; + std::string encoded_xml = ""; + + for (unsigned int i = 0; i < xml.size(); i++) { + char c = xml.at(i); + it = escape.find(c); + + if (it == escape.end()) { + encoded_xml += c; + } + else { + encoded_xml += it->second; + } + } + return encoded_xml; +} + std::string get_geometry_id(Object *ob) { return translate_id(id_name(ob->data)) + "-mesh"; @@ -327,12 +355,11 @@ std::string get_light_id(Object *ob) return translate_id(id_name(ob)) + "-light"; } -std::string get_joint_id(Object *ob, Bone *bone) +std::string get_joint_sid(Bone *bone) { - return translate_id(id_name(ob) + "_" + bone->name); + return translate_id(bone->name); } - -std::string get_joint_sid(Bone *bone) +std::string get_joint_sid(EditBone *bone) { return translate_id(bone->name); } @@ -342,15 +369,14 @@ std::string get_camera_id(Object *ob) return translate_id(id_name(ob)) + "-camera"; } -std::string get_material_id(Material *mat) +std::string get_effect_id(Material *mat) { - std::string id = id_name(mat); - return get_material_id_from_id(id); + return translate_id(id_name(mat)) + "-effect"; } -std::string get_material_id_from_id(std::string id) +std::string get_material_id(Material *mat) { - return translate_id(id) + "-material"; + return translate_id(id_name(mat)) + "-material"; } std::string get_morph_id(Object *ob) diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index ff998a94685..f16e3a7cf4a 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -73,11 +73,9 @@ public: // TODO need also for angle conversion, time conversion... - void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in); - - void mat4_to_dae(float out[4][4], float in[4][4]); - - void mat4_to_dae_double(double out[4][4], float in[4][4]); + static void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in); + static void mat4_to_dae(float out[4][4], float in[4][4]); + static void mat4_to_dae_double(double out[4][4], float in[4][4]); float(&get_rotation())[4][4]; float(&get_scale())[4][4]; @@ -91,20 +89,19 @@ extern std::string translate_id(const std::string &id); extern std::string translate_id(const char *idString); extern std::string id_name(void *id); +extern std::string encode_xml(std::string xml); extern std::string get_geometry_id(Object *ob); extern std::string get_geometry_id(Object *ob, bool use_instantiation); extern std::string get_light_id(Object *ob); -extern std::string get_joint_id(Object *ob, Bone *bone); extern std::string get_joint_sid(Bone *bone); extern std::string get_camera_id(Object *ob); +extern std::string get_morph_id(Object *ob); +extern std::string get_effect_id(Material *mat); extern std::string get_material_id(Material *mat); -extern std::string get_material_id_from_id(std::string id); - -extern std::string get_morph_id(Object *ob); #endif /* __COLLADA_INTERNAL_H__ */ diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index b25a35a5452..3716f334d5b 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -33,39 +33,59 @@ #include "COLLADAFWMeshVertexData.h" #include <set> - +#include <string> extern "C" { #include "DNA_modifier_types.h" #include "DNA_customdata_types.h" +#include "DNA_key_types.h" #include "DNA_object_types.h" +#include "DNA_constraint_types.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "DNA_armature_types.h" #include "BLI_math.h" #include "BLI_linklist.h" +#include "BLI_listbase.h" +#include "BKE_action.h" #include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_depsgraph.h" +#include "BKE_constraint.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_node.h" #include "BKE_object.h" #include "BKE_global.h" +#include "BKE_layer.h" +#include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_object.h" #include "BKE_scene.h" -#include "BKE_DerivedMesh.h" -#include "BKE_main.h" #include "ED_armature.h" +#include "ED_screen.h" +#include "ED_node.h" + +#include "MEM_guardedalloc.h" #include "WM_api.h" // XXX hrm, see if we can do without this #include "WM_types.h" #include "bmesh.h" #include "bmesh_tools.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" +#if 0 +#include "NOD_common.h" +#endif } #include "collada_utils.h" #include "ExportSettings.h" +#include "BlenderContext.h" float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index) { @@ -89,11 +109,53 @@ int bc_test_parent_loop(Object *par, Object *ob) return bc_test_parent_loop(par->parent, ob); } +void bc_get_children(std::vector<Object *> &child_set, Object *ob, ViewLayer *view_layer) +{ + Base *base; + for (base = (Base *)view_layer->object_bases.first; base; base = base->next) { + Object *cob = base->object; + if (cob->parent == ob) { + switch (ob->type) { + case OB_MESH: + case OB_CAMERA: + case OB_LAMP: + case OB_EMPTY: + case OB_ARMATURE: + child_set.push_back(cob); + default: break; + } + } + } +} + +bool bc_validateConstraints(bConstraint *con) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + + /* these we can skip completely (invalid constraints...) */ + if (cti == NULL) + return false; + if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) + return false; + + /* these constraints can't be evaluated anyway */ + if (cti->evaluate_constraint == NULL) + return false; + + /* influence == 0 should be ignored */ + if (con->enforce == 0.0f) + return false; + + /* validation passed */ + return true; +} + // a shortened version of parent_set_exec() // if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) { Object workob; + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *sce = CTX_data_scene(C); if (!par || bc_test_parent_loop(par, ob)) @@ -107,7 +169,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) if (is_parent_space) { float mat[4][4]; // calc par->obmat - BKE_object_where_is_calc(sce, par); + BKE_object_where_is_calc(depsgraph, sce, par); // move child obmat into world space mul_m4_m4m4(mat, par->obmat, ob->obmat); @@ -118,74 +180,121 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) BKE_object_apply_mat4(ob, ob->obmat, 0, 0); // compute parentinv - BKE_object_workob_calc_parent(sce, ob, &workob); + BKE_object_workob_calc_parent(depsgraph, sce, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); - DAG_id_tag_update(&par->id, OB_RECALC_OB); - - /** done once after import */ -#if 0 - DAG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); -#endif + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + DEG_id_tag_update(&par->id, ID_RECALC_TRANSFORM); return true; } -EvaluationContext *bc_get_evaluation_context(Main *bmain) +std::vector<bAction *> bc_getSceneActions(const bContext *C, Object *ob, bool all_actions) { - return bmain->eval_ctx; + std::vector<bAction *> actions; + if (all_actions) { + Main *bmain = CTX_data_main(C); + ID *id; + + for (id = (ID *)bmain->action.first; id; id = (ID *)(id->next)) { + bAction *act = (bAction *)id; + /* XXX This currently creates too many actions. + TODO Need to check if the action is compatible to the given object + */ + actions.push_back(act); + } + } + else + { + bAction *action = bc_getSceneObjectAction(ob); + actions.push_back(action); + } + + return actions; +} + +std::string bc_get_action_id(std::string action_name, std::string ob_name, std::string channel_type, std::string axis_name, std::string axis_separator) +{ + std::string result = action_name + "_" + channel_type; + if (ob_name.length() > 0) + result = ob_name + "_" + result; + if (axis_name.length() > 0) + result += axis_separator + axis_name; + return translate_id(result); } -void bc_update_scene(Main *bmain, Scene *scene, float ctime) +void bc_update_scene(BlenderContext &blender_context, float ctime) { + Main *bmain = blender_context.get_main(); + Scene *scene = blender_context.get_scene(); + Depsgraph *depsgraph = blender_context.get_depsgraph(); + + /* + * See remark in physics_fluid.c lines 395...) + * BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay); + */ BKE_scene_frame_set(scene, ctime); - EvaluationContext *ev_context = bc_get_evaluation_context(bmain); - BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay); + ED_update_for_newframe(bmain, depsgraph); } -Object *bc_add_object(Main *bmain, Scene *scene, int type, const char *name) +Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name) { Object *ob = BKE_object_add_only_object(bmain, type, name); ob->data = BKE_object_obdata_add_from_type(bmain, type, name); ob->lay = scene->lay; - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - BKE_scene_base_select(scene, BKE_scene_base_add(scene, ob)); + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, ob); + + Base *base = BKE_view_layer_base_find(view_layer, ob); + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); return ob; } Mesh *bc_get_mesh_copy( - Main *bmain, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate) + BlenderContext &blender_context, + Object *ob, + BC_export_mesh_type export_mesh_type, + bool apply_modifiers, + bool triangulate) { - Mesh *tmpmesh; CustomDataMask mask = CD_MASK_MESH; - Mesh *mesh = (Mesh *)ob->data; - DerivedMesh *dm = NULL; + Mesh *tmpmesh = NULL; if (apply_modifiers) { +#if 0 /* Not supported by new system currently... */ switch (export_mesh_type) { case BC_MESH_TYPE_VIEW: { - dm = mesh_create_derived_view(scene, ob, mask); + dm = mesh_create_derived_view(depsgraph, scene, ob, mask); break; } case BC_MESH_TYPE_RENDER: { - dm = mesh_create_derived_render(scene, ob, mask); + dm = mesh_create_derived_render(depsgraph, scene, ob, mask); break; } } +#else + Depsgraph *depsgraph = blender_context.get_depsgraph(); + Scene *scene_eval = blender_context.get_evaluated_scene(); + Object *ob_eval = blender_context.get_evaluated_object(ob); + tmpmesh = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, mask); +#endif } else { - dm = mesh_create_derived((Mesh *)ob->data, NULL); + tmpmesh = (Mesh *)ob->data; } - tmpmesh = BKE_mesh_add(bmain, "ColladaMesh"); // name is not important here - DM_to_mesh(dm, tmpmesh, ob, CD_MASK_MESH, true); - tmpmesh->flag = mesh->flag; + BKE_id_copy_ex(NULL, &tmpmesh->id, (ID **)&tmpmesh, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); if (triangulate) { bc_triangulate_mesh(tmpmesh); @@ -213,12 +322,14 @@ Object *bc_get_assigned_armature(Object *ob) return ob_arm; } -// Returns the highest selected ancestor -// returns NULL if no ancestor is selected -// IMPORTANT: This function expects that -// all exported objects have set: -// ob->id.tag & LIB_TAG_DOIT +/* +* Returns the highest selected ancestor +* returns NULL if no ancestor is selected +* IMPORTANT: This function expects that all exported objects have set: +* ob->id.tag & LIB_TAG_DOIT +*/ Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob) + { Object *ancestor = ob; while (ob->parent && bc_is_marked(ob->parent)) { @@ -228,16 +339,31 @@ Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *o return ancestor; } - bool bc_is_base_node(LinkNode *export_set, Object *ob) { Object *root = bc_get_highest_selected_ancestor_or_self(export_set, ob); return (root == ob); } -bool bc_is_in_Export_set(LinkNode *export_set, Object *ob) +bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer) { - return (BLI_linklist_index(export_set, ob) != -1); + bool to_export = (BLI_linklist_index(export_set, ob) != -1); + + if (!to_export) + { + /* Mark this object as to_export even if it is not in the + export list, but it contains children to export */ + + std::vector<Object *> children; + bc_get_children(children, ob, view_layer); + for (int i = 0; i < children.size(); i++) { + if (bc_is_in_Export_set(export_set, children[i], view_layer)) { + to_export = true; + break; + } + } + } + return to_export; } bool bc_has_object_type(LinkNode *export_set, short obtype) @@ -317,7 +443,7 @@ bool bc_is_root_bone(Bone *aBone, bool deform_bones_only) int bc_get_active_UVLayer(Object *ob) { Mesh *me = (Mesh *)ob->data; - return CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); + return CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); } std::string bc_url_encode(std::string data) @@ -811,6 +937,133 @@ static bool has_custom_props(Bone *bone, bool enabled, std::string key) } +void bc_enable_fcurves(bAction *act, char *bone_name) +{ + FCurve *fcu; + char prefix[200]; + + if (bone_name) + BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); + + for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) { + if (bone_name) { + if (STREQLEN(fcu->rna_path, prefix, strlen(prefix))) + fcu->flag &= ~FCURVE_DISABLED; + else + fcu->flag |= FCURVE_DISABLED; + } + else { + fcu->flag &= ~FCURVE_DISABLED; + } + } +} + +bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim) +{ + + /* Ok, lets be super cautious and check if the bone exists */ + bPose *pose = ob->pose; + bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name); + if (!pchan) { + return false; + } + + bAction *action = bc_getSceneObjectAction(ob); + bPoseChannel *parchan = pchan->parent; + + bc_enable_fcurves(action, bone->name); + float ipar[4][4]; + + if (bone->parent) { + invert_m4_m4(ipar, parchan->pose_mat); + mul_m4_m4m4(mat, ipar, pchan->pose_mat); + } + else + copy_m4_m4(mat, pchan->pose_mat); + + /* OPEN_SIM_COMPATIBILITY + * AFAIK animation to second life is via BVH, but no + * reason to not have the collada-animation be correct + */ + if (for_opensim) { + float temp[4][4]; + copy_m4_m4(temp, bone->arm_mat); + temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; + invert_m4(temp); + + mul_m4_m4m4(mat, mat, temp); + + if (bone->parent) { + copy_m4_m4(temp, bone->parent->arm_mat); + temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; + + mul_m4_m4m4(mat, temp, mat); + } + } + bc_enable_fcurves(action, NULL); + return true; +} + +bool bc_is_animated(BCMatrixSampleMap &values) +{ + static float MIN_DISTANCE = 0.00001; + + if (values.size() < 2) + return false; // need at least 2 entries to be not flat + + BCMatrixSampleMap::iterator it; + const BCMatrix *refmat = NULL; + for (it = values.begin(); it != values.end(); ++it) { + const BCMatrix *matrix = it->second; + + if (refmat == NULL) { + refmat = matrix; + continue; + } + + if (!matrix->in_range(*refmat, MIN_DISTANCE)) + return true; + } + return false; +} + +bool bc_has_animations(Object *ob) +{ + /* Check for object,lamp and camera transform animations */ + if ((bc_getSceneObjectAction(ob) && bc_getSceneObjectAction(ob)->curves.first) || + (bc_getSceneLampAction(ob) && bc_getSceneLampAction(ob)->curves.first) || + (bc_getSceneCameraAction(ob) && bc_getSceneCameraAction(ob)->curves.first)) + return true; + + //Check Material Effect parameter animations. + for (int a = 0; a < ob->totcol; a++) { + Material *ma = give_current_material(ob, a + 1); + if (!ma) continue; + if (ma->adt && ma->adt->action && ma->adt->action->curves.first) + return true; + } + + Key *key = BKE_key_from_object(ob); + if ((key && key->adt && key->adt->action) && key->adt->action->curves.first) + return true; + + return false; +} + + +bool bc_has_animations(Scene *sce, LinkNode &export_set) +{ + LinkNode *node; + + for (node = &export_set; node; node = node->next) { + Object *ob = (Object *)node->link; + + if (bc_has_animations(ob)) + return true; + } + return false; +} + /** * Check if custom information about bind matrix exists and modify the from_mat * accordingly. @@ -875,8 +1128,20 @@ void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, f void bc_sanitize_mat(float mat[4][4], int precision) { for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - mat[i][j] = double_round(mat[i][j], precision); + for (int j = 0; j < 4; j++) { + double val = (double)mat[i][j]; + val = double_round(val, precision); + mat[i][j] = (float)val; + } +} + +void bc_sanitize_v3(float v[3], int precision) +{ + for (int i = 0; i < 3; i++) { + double val = (double)v[i]; + val = double_round(val, precision); + v[i] = (float)val; + } } void bc_sanitize_mat(double mat[4][4], int precision) @@ -886,6 +1151,13 @@ void bc_sanitize_mat(double mat[4][4], int precision) mat[i][j] = double_round(mat[i][j], precision); } +void bc_sanitize_v3(double v[3], int precision) +{ + for (int i = 0; i < 3; i++) { + v[i] = double_round(v[i], precision); + } +} + void bc_copy_m4_farray(float r[4][4], float *a) { for (int i = 0; i < 4; i++) @@ -898,17 +1170,31 @@ void bc_copy_farray_m4(float *r, float a[4][4]) for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) *r++ = a[i][j]; +} + +void bc_copy_darray_m4d(double *r, double a[4][4]) +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + *r++ = a[i][j]; +} +void bc_copy_v44_m4d(std::vector<std::vector<double>> &r, double(&a)[4][4]) +{ + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + r[i][j] = a[i][j]; + } + } } -/* -* Returns name of Active UV Layer or empty String if no active UV Layer defined. -* Assuming the Object is of type MESH -*/ -std::string bc_get_active_uvlayer_name(Object *ob) +void bc_copy_m4d_v44(double (&r)[4][4], std::vector<std::vector<double>> &a) { - Mesh *me = (Mesh *)ob->data; - return bc_get_active_uvlayer_name(me); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + r[i][j] = a[i][j]; + } + } } /** @@ -916,9 +1202,9 @@ std::string bc_get_active_uvlayer_name(Object *ob) */ std::string bc_get_active_uvlayer_name(Mesh *me) { - int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (num_layers) { - char *layer_name = bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE); + char *layer_name = bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV); if (layer_name) { return std::string(layer_name); } @@ -926,14 +1212,24 @@ std::string bc_get_active_uvlayer_name(Mesh *me) return ""; } -/* +/** + * Returns name of Active UV Layer or empty String if no active UV Layer defined. + * Assuming the Object is of type MESH + */ +std::string bc_get_active_uvlayer_name(Object *ob) +{ + Mesh *me = (Mesh *)ob->data; + return bc_get_active_uvlayer_name(me); +} + +/** * Returns UV Layer name or empty string if layer index is out of range */ std::string bc_get_uvlayer_name(Mesh *me, int layer) { - int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (num_layers && layer < num_layers) { - char *layer_name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, layer); + char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, layer); if (layer_name) { return std::string(layer_name); } @@ -941,124 +1237,202 @@ std::string bc_get_uvlayer_name(Mesh *me, int layer) return ""; } -/********************************************************************** -* -* Return the list of Mesh objects with assigned UVtextures and Images -* Note: We need to create artificaial materials for each of them -* -***********************************************************************/ -std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers) -{ - std::set <Object *> UVObjects; - Base *base = (Base *)sce->base.first; - - while (base) { - Object *ob = base->object; - bool has_uvimage = false; - if (ob->type == OB_MESH) { - Mesh *me = (Mesh *)ob->data; - int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY); - - for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) { - if (all_uv_layers || active_uv_layer == i) - { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; - MPoly *mpoly = me->mpoly; - for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) { - - Image *ima = txface->tpage; - if (ima != NULL) { - has_uvimage = true; - break; - } - } - } - } - } +std::string bc_find_bonename_in_path(std::string path, std::string probe) +{ + std::string result; + char *boneName = BLI_str_quoted_substrN(path.c_str(), probe.c_str()); + if (boneName) { + result = std::string(boneName); + MEM_freeN(boneName); + } + return result; +} - if (has_uvimage) { - UVObjects.insert(ob); - } - } - base = base->next; +static bNodeTree *prepare_material_nodetree(Material *ma) +{ + if (ma->nodetree == NULL) { + ma->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree"); + ma->use_nodes = true; } - return UVObjects; -} - -/********************************************************************** -* -* Return the list of UV Texture images from all exported Mesh Items -* Note: We need to create one artificial material for each Image. -* -***********************************************************************/ -std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers) -{ - std::set <Image *> UVImages; - Base *base = (Base *)sce->base.first; - - while (base) { - Object *ob = base->object; - bool has_uvimage = false; - if (ob->type == OB_MESH) { - Mesh *me = (Mesh *)ob->data; - int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY); - - for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) { - if (all_uv_layers || active_uv_layer == i) - { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; - MPoly *mpoly = me->mpoly; - for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) { - - Image *ima = txface->tpage; - if (ima != NULL) { - if (UVImages.find(ima) == UVImages.end()) - UVImages.insert(ima); - } - } - } - } - } + return ma->nodetree; +} + +bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy, std::string label) +{ + bNode *node = nodeAddStaticNode(C, ntree, node_type); + if (node) { + if (label.length() > 0) { + strcpy(node->label, label.c_str()); } - base = base->next; + node->locx = locx; + node->locy = locy; + node->flag |= NODE_SELECT; } - return UVImages; + return node; } -/********************************************************************** -* -* Return the list of UV Texture images for the given Object -* Note: We need to create one artificial material for each Image. -* -***********************************************************************/ -std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers) + +bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy) { - std::set <Image *> UVImages; + return bc_add_node(C, ntree, node_type, locx, locy, ""); +} + +#if 0 +// experimental, probably not used +static bNodeSocket *bc_group_add_input_socket(bNodeTree *ntree, bNode *to_node, int to_index, std::string label) +{ + bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index); - bool has_uvimage = false; - if (ob->type == OB_MESH) { - Mesh *me = (Mesh *)ob->data; - int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY); + //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); + //return socket; - for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) { - if (all_uv_layers || active_uv_layer == i) - { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; - MPoly *mpoly = me->mpoly; - for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) { - - Image *ima = txface->tpage; - if (ima != NULL) { - if (UVImages.find(ima) == UVImages.end()) - UVImages.insert(ima); - } - } - } + bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); + bNode *inputGroup = ntreeFindType(ntree, NODE_GROUP_INPUT); + node_group_input_verify(ntree, inputGroup, (ID *)ntree); + bNodeSocket *newsock = node_group_input_find_socket(inputGroup, gsock->identifier); + nodeAddLink(ntree, inputGroup, newsock, to_node, to_socket); + strcpy(newsock->name, label.c_str()); + return newsock; +} + +static bNodeSocket *bc_group_add_output_socket(bNodeTree *ntree, bNode *from_node, int from_index, std::string label) +{ + bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index); + + //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket); + //return socket; + + bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, from_node, from_socket); + bNode *outputGroup = ntreeFindType(ntree, NODE_GROUP_OUTPUT); + node_group_output_verify(ntree, outputGroup, (ID *)ntree); + bNodeSocket *newsock = node_group_output_find_socket(outputGroup, gsock->identifier); + nodeAddLink(ntree, from_node, from_socket, outputGroup, newsock); + strcpy(newsock->name, label.c_str()); + return newsock; +} + + +void bc_make_group(bContext *C, bNodeTree *ntree, std::map<std::string, bNode *> nmap) +{ + bNode *gnode = node_group_make_from_selected(C, ntree, "ShaderNodeGroup", "ShaderNodeTree"); + bNodeTree *gtree = (bNodeTree *)gnode->id; + + bc_group_add_input_socket(gtree, nmap["main"], 0, "Diffuse"); + bc_group_add_input_socket(gtree, nmap["emission"], 0, "Emission"); + bc_group_add_input_socket(gtree, nmap["mix"], 0, "Transparency"); + bc_group_add_input_socket(gtree, nmap["emission"], 1, "Emission"); + bc_group_add_input_socket(gtree, nmap["main"], 4, "Metallic"); + bc_group_add_input_socket(gtree, nmap["main"], 5, "Specular"); + + bc_group_add_output_socket(gtree, nmap["mix"], 0, "Shader"); +} +#endif + +static void bc_node_add_link(bNodeTree *ntree, bNode *from_node, int from_index, bNode *to_node, int to_index) +{ + bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index); + bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index); + + nodeAddLink(ntree, from_node, from_socket, to_node, to_socket); +} + +void bc_add_default_shader(bContext *C, Material *ma) +{ + bNodeTree *ntree = prepare_material_nodetree(ma); + std::map<std::string, bNode *> nmap; +#if 0 + nmap["main"] = bc_add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300); + nmap["emission"] = bc_add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission"); + nmap["add"] = bc_add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400); + nmap["transparent"] = bc_add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200); + nmap["mix"] = bc_add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency"); + nmap["out"] = bc_add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300); + nmap["out"]->flag &= ~NODE_SELECT; + + bc_node_add_link(ntree, nmap["emission"], 0, nmap["add"], 0); + bc_node_add_link(ntree, nmap["main"], 0, nmap["add"], 1); + bc_node_add_link(ntree, nmap["add"], 0, nmap["mix"], 1); + bc_node_add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2); + + bc_node_add_link(ntree, nmap["mix"], 0, nmap["out"], 0); + // experimental, probably not used. + bc_make_group(C, ntree, nmap); +#else +nmap["main"] = bc_add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, 0, 300); +nmap["out"] = bc_add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 300, 300); +bc_node_add_link(ntree, nmap["main"], 0, nmap["out"], 0); +#endif +} + +COLLADASW::ColorOrTexture bc_get_base_color(Material *ma) +{ + bNode *master_shader = bc_get_master_shader(ma); + if (master_shader) { + return bc_get_base_color(master_shader); + } + else { + return bc_get_cot(ma->r, ma->g, ma->b, ma->alpha); + } +} + +COLLADASW::ColorOrTexture bc_get_specular_color(Material *ma, bool use_fallback) +{ + bNode *master_shader = bc_get_master_shader(ma); + if (master_shader) { + return bc_get_specular_color(master_shader); + } + else if (use_fallback) { + return bc_get_cot(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f); + } + else { + return bc_get_cot(0.0, 0.0, 0.0, 1.0); // no specular + } +} + +COLLADASW::ColorOrTexture bc_get_base_color(bNode *shader) +{ + bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, "Base Color"); + if (socket) + { + bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value; + float* col = dcol->value; + return bc_get_cot(col[0], col[1], col[2], col[3]); + } + else { + return bc_get_cot(0.8, 0.8, 0.8, 1.0); //default white + } +} + +COLLADASW::ColorOrTexture bc_get_specular_color(bNode *shader) +{ + bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, "Specular"); + if (socket) + { + bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value; + float* col = dcol->value; + return bc_get_cot(col[0], col[1], col[2], col[3]); + } + else { + return bc_get_cot(0.8, 0.8, 0.8, 1.0); //default white + } +} + +bNode *bc_get_master_shader(Material *ma) +{ + bNodeTree *nodetree = ma->nodetree; + if (nodetree) { + for (bNode *node = (bNode *)nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->type == SH_NODE_BSDF_PRINCIPLED) { + return node; } } } - return UVImages; + return NULL; +} + +COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a) +{ + COLLADASW::Color color(r, g, b, a); + COLLADASW::ColorOrTexture cot(color); + return cot; } diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index d1591a34cce..a79085f0282 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -31,6 +31,9 @@ #include "COLLADAFWGeometry.h" #include "COLLADAFWFloatOrDoubleArray.h" #include "COLLADAFWTypes.h" +#include "COLLADASWEffectProfile.h" +#include "COLLADAFWColorOrTexture.h" + #include <vector> #include <map> @@ -39,7 +42,12 @@ extern "C" { #include "DNA_object_types.h" +#include "DNA_anim_types.h" +#include "DNA_constraint_types.h" #include "DNA_mesh_types.h" +#include "DNA_lamp_types.h" +#include "DNA_camera_types.h" + #include "DNA_customdata_types.h" #include "DNA_texture_types.h" #include "DNA_scene_types.h" @@ -50,33 +58,97 @@ extern "C" { #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BKE_main.h" #include "BKE_context.h" #include "BKE_object.h" -#include "BKE_DerivedMesh.h" #include "BKE_scene.h" #include "BKE_idprop.h" +#include "BKE_node.h" } +#include "DEG_depsgraph_query.h" + #include "ImportSettings.h" #include "ExportSettings.h" #include "collada_internal.h" +#include "BCSampleData.h" +#include "BlenderContext.h" +constexpr int LIMITTED_PRECISION = 6; + +struct Depsgraph; + +typedef std::map<COLLADAFW::UniqueId, Image*> UidImageMap; +typedef std::map<std::string, Image*> KeyImageMap; typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex *> > TexIndexTextureArrayMap; +typedef std::set<Object *> BCObjectSet; + +extern void bc_update_scene(BlenderContext &blender_context, float ctime); + +/* Action helpers */ + +std::vector<bAction *> bc_getSceneActions(const bContext *C, Object *ob, bool all_actions); + +/* Action helpers */ + +inline bAction *bc_getSceneObjectAction(Object *ob) +{ + return (ob->adt && ob->adt->action) ? ob->adt->action : NULL; +} + +/* Returns Lamp Action or NULL */ +inline bAction *bc_getSceneLampAction(Object *ob) +{ + if (ob->type != OB_LAMP) + return NULL; + + Lamp *lamp = (Lamp *)ob->data; + return (lamp->adt && lamp->adt->action) ? lamp->adt->action : NULL; +} + +/* Return Camera Action or NULL */ +inline bAction *bc_getSceneCameraAction(Object *ob) +{ + if (ob->type != OB_CAMERA) + return NULL; + + Camera *camera = (Camera *)ob->data; + return (camera->adt && camera->adt->action) ? camera->adt->action : NULL; +} + +/* returns material action or NULL */ +inline bAction *bc_getSceneMaterialAction(Material *ma) +{ + if (ma == NULL) + return NULL; + + return (ma->adt && ma->adt->action) ? ma->adt->action : NULL; +} + +inline void bc_setSceneObjectAction(bAction *action, Object *ob) +{ + if (ob->adt) + ob->adt->action = action; +} + +std::string bc_get_action_id(std::string action_name, std::string ob_name, std::string channel_type, std::string axis_name, std::string axis_separator = "_"); -extern EvaluationContext *bc_get_evaluation_context(Main *bmain); -extern void bc_update_scene(Main *bmain, Scene *scene, float ctime); extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index); extern int bc_test_parent_loop(Object *par, Object *ob); + +extern void bc_get_children(std::vector<Object *> &child_set, Object *ob, ViewLayer *view_layer); +extern bool bc_validateConstraints(bConstraint *con); + extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true); -extern Object *bc_add_object(Main *bmain, Scene *scene, int type, const char *name); +extern Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name); extern Mesh *bc_get_mesh_copy( - Main *bmain, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate); + BlenderContext &blender_context, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate); extern Object *bc_get_assigned_armature(Object *ob); extern Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob); extern bool bc_is_base_node(LinkNode *export_set, Object *ob); -extern bool bc_is_in_Export_set(LinkNode *export_set, Object *ob); +extern bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer); extern bool bc_has_object_type(LinkNode *export_set, short obtype); extern int bc_is_marked(Object *ob); @@ -90,6 +162,30 @@ extern void bc_bubble_sort_by_Object_name(LinkNode *export_set); extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only); extern int bc_get_active_UVLayer(Object *ob); +std::string bc_find_bonename_in_path(std::string path, std::string probe); + +inline std::string bc_string_after(const std::string& s, const char c) +{ + size_t i = s.rfind(c, s.length()); + if (i != std::string::npos) { + return(s.substr(i + 1, s.length() - i)); + } + return(s); +} + +inline bool bc_startswith(std::string const & value, std::string const & starting) +{ + if (starting.size() > value.size()) + return false; + return (value.substr(0, starting.size()) == starting); +} + +inline bool bc_endswith(std::string const & value, std::string const & ending) +{ + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement); extern std::string bc_url_encode(std::string data); extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene); @@ -109,9 +205,14 @@ inline bool bc_in_range(float a, float b, float range) { } void bc_copy_m4_farray(float r[4][4], float *a); void bc_copy_farray_m4(float *r, float a[4][4]); +void bc_copy_darray_m4d(double *r, double a[4][4]); +void bc_copy_m4d_v44(double(&r)[4][4], std::vector<std::vector<double>> &a); +void bc_copy_v44_m4d(std::vector<std::vector<double>> &a, double(&r)[4][4]); -extern void bc_sanitize_mat(float mat[4][4], int precision); -extern void bc_sanitize_mat(double mat[4][4], int precision); +void bc_sanitize_mat(float mat[4][4], int precision); +void bc_sanitize_mat(double mat[4][4], int precision); +void bc_sanitize_v3(double v[3], int precision); +void bc_sanitize_v3(float v[3], int precision); extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key); extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value); @@ -121,15 +222,14 @@ extern float bc_get_property(Bone *bone, std::string key, float def); extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]); extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]); -extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space); +extern void bc_enable_fcurves(bAction *act, char *bone_name); +extern bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim); +extern bool bc_is_animated(BCMatrixSampleMap &values); +extern bool bc_has_animations(Scene *sce, LinkNode &node); +extern bool bc_has_animations(Object *ob); -extern std::string bc_get_active_uvlayer_name(Object *ob); -extern std::string bc_get_active_uvlayer_name(Mesh *me); -extern std::string bc_get_uvlayer_name(Mesh *me, int layer); -extern std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers); -extern std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers); -extern std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers); +extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space); class BCPolygonNormalsIndices { @@ -210,4 +310,12 @@ public: ~BoneExtensionManager(); }; +void bc_add_default_shader(bContext *C, Material *ma); +bNode *bc_get_master_shader(Material *ma); +COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a); +COLLADASW::ColorOrTexture bc_get_base_color(bNode *shader); +COLLADASW::ColorOrTexture bc_get_base_color(Material *ma); +COLLADASW::ColorOrTexture bc_get_specular_color(bNode *shader); +COLLADASW::ColorOrTexture bc_get_specular_color(Material *ma, bool use_fallback); + #endif |