Partial rewrite of the Collada Module for Blender 2.8

Most important changes are in the Animation exporter and Animation Importer.
There is still some cleaning up to be done. But the Exporter/Importer basically
work within Blender 2.8

Some details:

User Interface:
The interface has been reorganized to look more like the FBX interface.

New options in user interface:

* keep_keyframes:
  When sampling the distance between 2 keyframes is defined by
  the sampling rate. Furthermore the keyframes defined in the
  FCurves are not exported. However when this option is enabled
  then also the defined keyframes will be added to the exported fcurves

* keep_smooth_curves:
  When sampling we do not use FCurves. So we also have no Curve handles
  for smooth exporting. However when this option is enabled, Blender
  does its best to recreate the handles for export. This is a very
  experimental feature and it is know to break when:

  - the exported animated objects have parent inverse matrices
    different from the unit matrix
  - The exported objects have negative scaling

  There may be many other situations when this feature breaks.
  This needs to be further tested. It may be removed later or replaced
  by something less wonky.

BlenderContext:
is a new class that contains the bridge to Blender. It contains
pointers to the current export/import context plus derived values
of Depsgraph, Scene, Main

Reporting:
I reorganized the output on the Blender Console to become more
informative and more readable

Preservation of Item names:
name attributes are now encoded with XML entities. This makes
sure that i can export/import names exactly defined in the tool.
This affects material names, bone names and object names.

Hierarchy export:
* Object and Bone Hierarchies are now exported correctly
  by taking the Blender parent/child hierarchy into account
* Export also not selected intermediate objects

  Problem:
  When we export an Object Hierarchy, then we must export
  all elements of the hierarchy to maintain the transforms. This
  is especially important when exporting animated objects, because the
  animation curves are exported as relative curves based on the
  parent-child hierarchy. If an intermediate animated object is missing
  then the exported animation breaks.

  Solution:
  If the "Selected" Optioon is enabled, then take care
  to also export all objects which are not selected and hidden,
  but which are parents of selected objects.

Node Based Material Importer (wip):
Added basic support for Materials with diffuse color and
diffuse textures. More properties (opacity, emission) need
changes in the used shader.
Note: Materials are all constructed by using the principled BSDF shader.

Animation Exporter:
* Massive optimization of the Animation Bake tool (Animation Sampler).
  Instead of sampling each fcurve separately, i now sample all
  exported fcurves simultaneously. So i avoid many (many!)
  scene updates during animation export.
* Add support for Continuous Acceleration (Fcurve handles)
  This allows us to create smoother FCurves during importing Collada
  Animation curves. Possibly this should become an option ionstead of
  a fixed import feature.
* Add support for sampling curves (to bake animations)
* The animation sampler now can be used for any animation curve.
  Before the sampler only looked at curves which are supported by
  Standard Collada 1.4. However the Collada exporter currently
  ignores all animation curves which are not covered by the 1.4.1
  Collada Standards. There is still some room for improvements
  here (work in progres)

  Known issues:

    * Some exports do currently not work reliably, among those
      are the camera animations, material animations and light animations
      those animations will be added back next (work in progres)

    * Exporting animation curves with keyframes (and tangents)
      sometimes results in odd curves (when parent inverse matrix is involved)
      This needs to be checked in more depth (probably it can not be solved).

    * Export of "all animations in scene" is disabled because the
      Collada Importer can not handle this reliably at the
      moment (work in progres).

* Support for Animation Clip export
  Added one extra level to the exported animations
  such that now all scene animations are enclosed:

  <Animation name="id_name(ob)_Action">
    <Animation>...</Animation>
    ...
  </Animation>

Animation Importer:
* Import of animations for objects with multiple materials
  When importing multiple materials for one object,
  the imported material animation curves have all been
  assigned to the first material in the object.

Error handling (wip):
The Importer was a bit confused as it sometimes ignored fatal
parsing errors and continued to import. I did my best to
unconfuse it, but i believe that this needs to be tested more.

Refactoring:

update : move generation of effect id names into own function
update : adjust importer/exporter for no longer supported HEMI lights
cleanup: Removed no lopnger existing attribute from the exporter presets
cleanup: Removed not needed Context attribute from DocumentExporter
fix    : Avoid duplicate deletion of temporary items
cleanup: fixed indentation and white space issues
update : Make BCAnimation class more self contained
cleanup: Renamed classes, updated comments for better reading
cleanup: Moved static class functions to collada_utils
cleanup: Moved typedefs to more intuitive locations
cleanup: indentation and class method declarations
cleanup: Removed no longer needed methods
update : Moved Classes into separate files
cleanup: Added comments
cleanup: take care of name conventions
...    : many more small changes, not helpful to list them all
This commit is contained in:
Gaia Clary 2018-11-23 15:57:45 +01:00
parent 3bf7c846ee
commit 322cf89a14
51 changed files with 5183 additions and 2454 deletions

View File

@ -10,7 +10,6 @@ op.include_armatures = True
op.include_shapekeys = False
op.deform_bones_only = True
op.active_uv_only = True
op.include_uv_textures = True
op.use_texture_copies = True
op.triangulate = True
op.use_object_instantiation = False

View File

@ -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();
}

View File

@ -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) :
depsgraph(depsgraph),
COLLADASW::LibraryAnimationClips(sw),
export_settings(export_settings),
anim_meta(anim_meta)
{
this->sw = sw;
}
void exportAnimationClips(Scene *sce);
};

View File

@ -0,0 +1,391 @@
/*
* ***** 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 "AnimationCurveCache.h"
extern "C" {
#include "BKE_action.h"
#include "BLI_listbase.h"
}
AnimationCurveCache::AnimationCurveCache(bContext *C):
mContext(C)
{
}
AnimationCurveCache::~AnimationCurveCache()
{
clear_cache();
}
void AnimationCurveCache::clear_cache()
{
}
void AnimationCurveCache::clear_cache(Object *ob)
{
}
void AnimationCurveCache::create_curves(Object *ob)
{
}
void AnimationCurveCache::addObject(Object *ob)
{
cached_objects.push_back(ob);
}
bool AnimationCurveCache::bone_matrix_local_get(Object *ob, Bone *bone, float(&mat)[4][4], 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;
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);
}
}
return true;
}
void AnimationCurveCache::sampleMain(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim)
{
std::map<int, std::vector<SamplePoint>>::iterator frame;
for (frame = sample_frames.begin(); frame != sample_frames.end(); frame++) {
int frame_index = frame->first;
std::vector<SamplePoint> sample_points = frame->second;
bc_update_scene(mContext, scene, frame_index);
for (int spi = 0; spi < sample_points.size(); spi++) {
SamplePoint &point = sample_points[spi];
Object *ob = point.get_object();
float mat[4][4];
if (ob->type == OB_ARMATURE) {
/* For Armatures we need to check if this maybe is a pose sample point*/
Bone *bone = point.get_bone();
if (bone) {
if (bone_matrix_local_get(ob, bone, mat, for_opensim)) {
point.set_matrix(mat);
}
continue;
}
}
/* When this SamplePoint is not for a Bone,
* then we just store the Object local matrix here
*/
BKE_object_matrix_local_get(ob, mat);
point.set_matrix(mat);
}
}
}
/*
* enable fcurves driving a specific bone, disable all the rest
* if bone_name = NULL enable all fcurves
*/
void AnimationCurveCache::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;
}
}
}
/*
* Sample the scene at frames where object fcurves
* have defined keys.
*/
void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim, bool keyframe_at_end)
{
create_sample_frames_from_keyframes();
sampleMain(scene, atm_type, for_opensim);
}
void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, int sampling_rate, bool for_opensim, bool keyframe_at_end)
{
create_sample_frames_generated(scene->r.sfra, scene->r.efra, sampling_rate, keyframe_at_end);
sampleMain(scene, atm_type, for_opensim);
}
std::vector<FCurve *> *AnimationCurveCache::getSampledCurves(Object *ob)
{
std::map<Object *, std::vector<FCurve *>>::iterator fcurves;
fcurves = cached_curves.find(ob);
return (fcurves == cached_curves.end()) ? NULL : &fcurves->second;
}
std::vector<SamplePoint> &AnimationCurveCache::getFrameInfos(int frame_index)
{
std::map<int, std::vector<SamplePoint>>::iterator frames = sample_frames.find(frame_index);
if (frames == sample_frames.end()) {
std::vector<SamplePoint> sample_points;
sample_frames[frame_index] = sample_points;
}
return sample_frames[frame_index];
}
void AnimationCurveCache::add_sample_point(SamplePoint &point)
{
int frame_index = point.get_frame();
std::vector<SamplePoint> &frame_infos = getFrameInfos(frame_index);
frame_infos.push_back(point);
}
/*
* loop over all cached objects
* loop over all fcurves
* record all keyframes
*
* The vector sample_frames finally contains a list of vectors
* where each vector contains a list of SamplePoints which
* need to be processed when evaluating the animation.
*/
void AnimationCurveCache::create_sample_frames_from_keyframes()
{
sample_frames.clear();
for (int i = 0; i < cached_objects.size(); i++) {
Object *ob = cached_objects[i];
bAction *action = bc_getSceneObjectAction(ob);
FCurve *fcu = (FCurve *)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];
int frame_index = int(f);
SamplePoint sample_point(frame_index, ob, fcu, i);
add_sample_point(sample_point);
}
}
}
}
/*
* loop over all cached objects
* loop over active action using a stesize of sampling_rate
* record all frames
*
* The vector sample_frames finally contains a list of vectors
* where each vector contains a list of SamplePoints which
* need to be processed when evaluating the animation.
* Note: The FCurves of the objects will not be used here.
*/
void AnimationCurveCache::create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end)
{
sample_frames.clear();
for (int i = 0; i < cached_objects.size(); i++) {
Object *ob = cached_objects[i];
float f = sfra;
do {
int frame_index = int(f);
SamplePoint sample_point(frame_index, ob);
add_sample_point(sample_point);
/* Depending on the Object type add more sample points here
*/
if (ob && ob->type == OB_ARMATURE) {
LISTBASE_FOREACH(bPoseChannel *, pchan, &ob->pose->chanbase) {
SamplePoint point(frame_index, ob, pchan->bone);
add_sample_point(sample_point);
}
}
if (f == efra)
break;
f += sampling_rate;
if (f > efra)
if (keyframe_at_end)
f = efra; // make sure the last frame is always exported
else
break;
} while (true);
}
}
Matrix::Matrix()
{
unit_m4(matrix);
}
Matrix::Matrix(float (&mat)[4][4])
{
set_matrix(mat);
}
void Matrix::set_matrix(float(&mat)[4][4])
{
copy_m4_m4(matrix, mat);
}
void Matrix::set_matrix(Matrix &mat)
{
copy_m4_m4(matrix, mat.matrix);
}
void Matrix::get_matrix(float(&mat)[4][4])
{
copy_m4_m4(mat, matrix);
}
SamplePoint::SamplePoint(int frame, Object *ob)
{
this->frame = frame;
this->fcu = NULL;
this->ob = ob;
this->pose_bone = NULL;
this->index = -1;
}
SamplePoint::SamplePoint(int frame, Object *ob, FCurve *fcu, int index)
{
this->frame = frame;
this->fcu = fcu;
this->ob = ob;
this->pose_bone = NULL;
this->index = index;
this->path = std::string(fcu->rna_path);
/* Further elaborate on what this Fcurve is doing by checking
* its rna_path
*/
if (ob && ob->type == OB_ARMATURE) {
char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
bPose *pose = ob->pose;
if (boneName) {
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
this->pose_bone = pchan->bone;
}
}
}
SamplePoint::SamplePoint(int frame, Object *ob, Bone *bone)
{
this->frame = frame;
this->fcu = NULL;
this->ob = ob;
this->pose_bone = bone;
this->index = -1;
this->path = "pose.bones[\"" + id_name(bone) + "\"].matrix";
}
Matrix &SamplePoint::get_matrix()
{
return matrix;
}
void SamplePoint::set_matrix(Matrix &mat)
{
this->matrix.set_matrix(mat);
}
void SamplePoint::set_matrix(float(&mat)[4][4])
{
}
Object *SamplePoint::get_object()
{
return this->ob;
}
Bone *SamplePoint::get_bone()
{
return this->pose_bone;
}
FCurve *SamplePoint::get_fcurve()
{
return this->fcu;
}
int SamplePoint::get_frame()
{
return this->frame;
}
int SamplePoint::get_fcurve_index()
{
return this->index;
}
std::string &SamplePoint::get_path()
{
return path;
}

View File

@ -0,0 +1,130 @@
/*
* ***** 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 *****
*/
#ifndef __ANIMATION_CURVE_CACHE_H__
#define __ANIMATION_CURVE_CACHE_H__
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <map>
#include <algorithm> // std::find
#include "exportSettings.h"
#include "collada_utils.h"
extern "C"
{
#include "DNA_object_types.h"
#include "DNA_anim_types.h"
}
class Matrix {
private:
float matrix[4][4];
public:
Matrix();
Matrix(float (&mat)[4][4]);
void set_matrix(float (&mat)[4][4]);
void set_matrix(Matrix &mat);
void get_matrix(float (&mat)[4][4]);
};
class SamplePoint {
private:
Object * ob;
Bone *pose_bone;
FCurve *fcu;
int frame; /* frame in timeline (not sure if we actually should store a float here) */
int index; /* Keyframe index in fcurve (makes sense only when fcu is also set) */
std::string path; /* Do not mixup with rna_path. It is used for different purposes! */
Matrix matrix; /* Local matrix, by default unit matrix, will be set when sampling */
public:
SamplePoint(int frame, Object *ob);
SamplePoint(int frame, Object *ob, FCurve *fcu, int index);
SamplePoint(int frame, Object *ob, Bone *bone);
Object *get_object();
Bone *get_bone();
FCurve *get_fcurve();
int get_frame();
int get_fcurve_index();
Matrix &get_matrix();
std::string &get_path();
void set_matrix(Matrix &matrix);
void set_matrix(float(&mat)[4][4]);
};
class AnimationCurveCache {
private:
void clear_cache(); // remove all sampled FCurves
void clear_cache(Object *ob); //remove sampled FCurves for single object
void create_curves(Object *ob);
std::vector<Object *> cached_objects; // list of objects for caching
std::map<Object *, std::vector<FCurve *>> cached_curves; //map of cached FCurves
std::map<int, std::vector<SamplePoint>> sample_frames; // list of frames where objects need to be sampled
std::vector<SamplePoint> &getFrameInfos(int frame_index);
void add_sample_point(SamplePoint &point);
void enable_fcurves(bAction *act, char *bone_name);
bool bone_matrix_local_get(Object *ob, Bone *bone, float (&mat)[4][4], bool for_opensim);
bContext *mContext;
public:
AnimationCurveCache(bContext *C);
~AnimationCurveCache();
void addObject(Object *obj);
void sampleMain(Scene *scene,
BC_export_transformation_type atm_type,
bool for_opensim);
void sampleScene(Scene *scene,
BC_export_transformation_type atm_type,
bool for_opensim,
bool keyframe_at_end = true); // use keys from FCurves, use timeline boundaries
void sampleScene(Scene *scene,
BC_export_transformation_type atm_type,
int sampling_rate, bool for_opensim,
bool keyframe_at_end = true ); // generate keyframes for frames use timeline boundaries
std::vector<FCurve *> *getSampledCurves(Object *ob);
void create_sample_frames_from_keyframes();
void create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -20,13 +20,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
/** \file AnimationExporter.h
* \ingroup collada
*/
#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"
@ -74,35 +76,40 @@ 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;
Depsgraph *depsgraph;
BlenderContext &blender_context;
COLLADASW::StreamWriter *sw;
public:
AnimationExporter(Depsgraph *depsgraph, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
AnimationExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
blender_context(blender_context),
COLLADASW::LibraryAnimations(sw),
depsgraph(depsgraph),
export_settings(export_settings)
{
this->sw = sw;
}
bool exportAnimations(Main *bmain, Scene *sce);
bool exportAnimations();
// called for each exported object
void operator() (Object *ob);
@ -110,7 +117,6 @@ public:
protected:
const ExportSettings *export_settings;
void export_object_constraint_animation(Object *ob);
void export_morph_animation(Object *ob);
@ -121,8 +127,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);
@ -141,70 +145,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);
COLLADASW::InputSemantic::Semantics semantic,
bool is_rot,
const std::string axis,
bool transform);
void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length);
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);
float* get_eul_source_for_quat(Object *ob );
std::string collada_tangent_from_curve(
COLLADASW::InputSemantic::Semantics semantic,
BCAnimationCurve &curve,
const std::string& anim_id,
const std::string axis_name);
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> &times, std::vector<float> &values, std::string, std::string label, std::string axis_name, bool is_rot);
std::string collada_interpolation_source(const BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name, bool *has_tangents);
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);
void evaluate_anim_with_constraints(Object *ob, float ctime);
/* ===================================== */
/* Currently unused or not (yet?) needed */
/* ===================================== */
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);
bool is_bone_deform_group(Bone * bone);
std::string create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id);
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 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 create_xyz_source(float *v, int tot, const std::string& anim_id);
std::string create_4x4_source(std::vector<float> &times, 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);
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 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

View File

@ -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,7 +244,8 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain, Object *ob, std::vect
}
}
AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
AnimationImporter::AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
mContext(C),
TransformReader(conv), armature_importer(arm), scene(scene) {
}
@ -304,7 +304,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 +724,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 +839,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 +908,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 +932,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 +941,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 +975,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 +1006,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 +1040,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 +1095,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 +1147,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 +1270,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 +1303,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 +1447,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 +1669,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 +1787,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;

View File

@ -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,7 @@ private:
};
public:
AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
~AnimationImporter();
@ -153,7 +154,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 +162,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 +182,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 *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,
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 );

View File

@ -56,39 +56,47 @@ extern "C" {
// 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) {
ArmatureExporter::ArmatureExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
blender_context(blender_context),
COLLADASW::LibraryControllers(sw), export_settings(export_settings)
{
}
// write bone nodes
void ArmatureExporter::add_armature_bones(bContext *C, Depsgraph *depsgraph, 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, depsgraph, 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);
@ -156,12 +164,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, Depsgraph *depsgraph, 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);
@ -201,7 +211,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bo
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)) {
@ -230,8 +240,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bo
mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv);
}
se->writeNodes(C, depsgraph, *i, sce);
se->writeNodes(*i);
copy_m4_m4((*i)->parentinv, backup_parinv);
child_objects.erase(i++);
}
@ -239,13 +248,13 @@ void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bo
}
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
add_bone_node(C, depsgraph, 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, depsgraph, child, ob_arm, sce, se, child_objects);
add_bone_node(child, ob_arm, se, child_objects);
}
}
}

View File

@ -57,21 +57,20 @@ class SceneExporter;
class ArmatureExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
{
public:
ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
ArmatureExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
// write bone nodes
void add_armature_bones(bContext *C, struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se,
std::list<Object *>& child_objects);
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;
const ExportSettings *export_settings;
BlenderContext &blender_context;
#if 0
std::vector<Object *> written_armatures;
@ -85,8 +84,11 @@ private:
// Scene, SceneExporter and the list of child_objects
// are required for writing bone parented objects
void add_bone_node(bContext *C, struct Depsgraph *depsgraph, 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);

View File

@ -0,0 +1,679 @@
/*
* ***** 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];
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -0,0 +1,188 @@
/*
* ***** 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;
}

View File

@ -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

View File

@ -0,0 +1,61 @@
/*
* ***** 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"
BlenderContext::BlenderContext(bContext *C)
{
context = C;
main = CTX_data_main(C);
depsgraph = CTX_data_depsgraph(C);
scene = CTX_data_scene(C);
view_layer = DEG_get_evaluated_view_layer(depsgraph);
}
bContext *BlenderContext::get_context()
{
return context;
}
Depsgraph *BlenderContext::get_depsgraph()
{
return depsgraph;
}
Scene *BlenderContext::get_scene()
{
return scene;
}
ViewLayer *BlenderContext::get_view_layer()
{
return view_layer;
}
Main *BlenderContext::get_main()
{
return main;
}

View File

@ -0,0 +1,56 @@
/*
* ***** 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();
ViewLayer *get_view_layer();
Main *get_main();
};
#endif

View File

@ -49,8 +49,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
@ -68,6 +73,7 @@ set(SRC
MaterialExporter.cpp
MeshImporter.cpp
SkinInfo.cpp
Materials.cpp
SceneExporter.cpp
TransformReader.cpp
TransformWriter.cpp
@ -77,8 +83,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
@ -95,6 +106,7 @@ set(SRC
LightExporter.h
MaterialExporter.h
MeshImporter.h
Materials.h
SkinInfo.h
SceneExporter.h
TransformReader.h

View File

@ -58,7 +58,9 @@ extern "C" {
// 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) {
ControllerExporter::ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
blender_context(blender_context),
COLLADASW::LibraryControllers(sw), export_settings(export_settings) {
}
bool ControllerExporter::is_skinned_mesh(Object *ob)
@ -66,11 +68,12 @@ 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);
@ -103,12 +106,9 @@ bool ControllerExporter::add_instance_controller(Object *ob)
return true;
}
void ControllerExporter::export_controllers(Main *bmain, Depsgraph *depsgraph, Scene *sce)
void ControllerExporter::export_controllers()
{
this->depsgraph = depsgraph;
m_bmain = bmain;
scene = sce;
Scene *sce = blender_context.get_scene();
openLibrary();
GeometryFunctor gf;
@ -203,8 +203,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
}
me = bc_get_mesh_copy(
depsgraph,
scene,
blender_context,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
@ -305,8 +304,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
Mesh *me;
me = bc_get_mesh_copy(
depsgraph,
scene,
blender_context,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
@ -499,6 +497,9 @@ 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(depsgraph, scene, ob_arm);
}
@ -547,6 +548,8 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
// 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(depsgraph, scene, ob_arm);
}

View File

@ -60,20 +60,18 @@ class SceneExporter;
class ControllerExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
{
public:
ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
bool is_skinned_mesh(Object *ob);
bool add_instance_controller(Object *ob);
void export_controllers(Main *bmain, Depsgraph *depsgraph, Scene *sce);
void export_controllers();
void operator()(Object *ob);
private:
Depsgraph *depsgraph;
Main *m_bmain;
Scene *scene;
BlenderContext &blender_context;
UnitConverter converter;
const ExportSettings *export_settings;

View File

@ -151,8 +151,8 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
return data->layers[layer_index].name;
}
DocumentExporter::DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings) :
depsgraph(depsgraph),
DocumentExporter::DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings) :
blender_context(blender_context),
export_settings(export_settings) {
}
@ -180,9 +180,13 @@ 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, Scene *sce)
int DocumentExporter::exportCurrentScene()
{
Main *bmain = CTX_data_main(C);
Main *bmain = blender_context.get_main();
Scene *sce = blender_context.get_scene();
bContext *C = blender_context.get_context();
Depsgraph *depsgraph = blender_context.get_depsgraph(); \
PointerRNA sceneptr, unit_settings;
PropertyRNA *system; /* unused , *scale; */
@ -272,13 +276,13 @@ int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce)
le.exportLights(sce);
}
// <library_images>
ImagesExporter ie(writer, this->export_settings);
ie.exportImages(sce);
// <library_effects>
EffectsExporter ee(writer, this->export_settings);
ee.exportEffects(sce);
EffectsExporter ee(writer, this->export_settings, key_image_map);
ee.exportEffects(C, sce);
// <library_images>
ImagesExporter ie(writer, this->export_settings, key_image_map);
ie.exportImages(sce);
// <library_materials>
MaterialsExporter me(writer, this->export_settings);
@ -286,28 +290,29 @@ int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce)
// <library_geometries>
if (bc_has_object_type(export_set, OB_MESH)) {
GeometryExporter ge(writer, this->export_settings);
ge.exportGeom(bmain, depsgraph, 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, depsgraph, 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(depsgraph, writer, this->export_settings);
ae.exportAnimations(bmain, sce);
AnimationExporter ae(blender_context, writer, this->export_settings);
ae.exportAnimations();
}
se.exportScene(C, depsgraph, sce);
se.exportScene();
// <scene>
std::string scene_name(translate_id(id_name(sce)));

View File

@ -28,24 +28,24 @@
#define __DOCUMENTEXPORTER_H__
#include "collada.h"
#include "collada_utils.h"
#include "BlenderContext.h"
extern "C" {
#include "DNA_customdata_types.h"
}
struct Scene;
class DocumentExporter
{
public:
DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings);
int exportCurrentScene(bContext *C, Scene *sce);
DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings);
int exportCurrentScene();
void exportScenes(const char *filename);
private:
Depsgraph *depsgraph;
BlenderContext &blender_context;
const ExportSettings *export_settings;
KeyImageMap key_image_map;
};
#endif

View File

@ -91,7 +91,7 @@ extern "C" {
#include "collada_internal.h"
#include "collada_utils.h"
#include "materials.h"
/*
* COLLADA Importer limitations:
@ -104,12 +104,12 @@ extern "C" {
DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_settings) :
import_settings(import_settings),
mImportStage(General),
mImportStage(Fetching_Scene_data),
mContext(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(&unit_converter, &armature_importer, CTX_data_scene(C))
anim_importer(C, &unit_converter, &armature_importer, CTX_data_scene(C))
{
}
@ -149,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);
@ -182,7 +180,7 @@ void DocumentImporter::start()
void DocumentImporter::finish()
{
if (mImportStage != General)
if (mImportStage == Fetching_Controller_data)
return;
Main *bmain = CTX_data_main(mContext);
@ -225,12 +223,14 @@ 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);
objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end());
delete objects_done;
}
}
@ -254,7 +254,7 @@ 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 it;
for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
@ -277,7 +277,6 @@ void DocumentImporter::finish()
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
@ -312,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);
@ -403,7 +402,7 @@ 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);
@ -503,9 +502,10 @@ 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) {
@ -700,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.
@ -723,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;
}
@ -743,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);
@ -753,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);
@ -766,136 +766,18 @@ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
return true;
}
void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
{
COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
// TODO: add back texture and extended material parameter support
// blinn
if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
#if 0
ma->spec_shader = MA_SPEC_BLINN;
ma->spec = ef->getShininess().getFloatValue();
#endif
}
// phong
else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
#if 0
ma->spec_shader = MA_SPEC_PHONG;
ma->har = ef->getShininess().getFloatValue();
#endif
}
// lambert
else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
#if 0
ma->diff_shader = MA_DIFF_LAMBERT;
#endif
}
// default - lambert
else {
#if 0
ma->diff_shader = MA_DIFF_LAMBERT;
fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
#endif
}
// reflectivity
ma->metallic = ef->getReflectivity().getFloatValue();
// index of refraction
#if 0
ma->ang = ef->getIndexOfRefraction().getFloatValue();
#endif
COLLADAFW::Color col;
// DIFFUSE
// color
if (ef->getDiffuse().isColor()) {
col = ef->getDiffuse().getColor();
ma->r = col.getRed();
ma->g = col.getGreen();
ma->b = col.getBlue();
}
// texture
else if (ef->getDiffuse().isTexture()) {
#if 0
COLLADAFW::Texture ctex = ef->getDiffuse().getTexture();
#endif
}
// AMBIENT
// color
if (ef->getAmbient().isColor()) {
#if 0
col = ef->getAmbient().getColor();
#endif
}
// texture
else if (ef->getAmbient().isTexture()) {
#if 0
COLLADAFW::Texture ctex = ef->getAmbient().getTexture();
#endif
}
// 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()) {
#if 0
COLLADAFW::Texture ctex = ef->getSpecular().getTexture();
#endif
}
// REFLECTIVE
// color
if (ef->getReflective().isColor()) {
#if 0
col = ef->getReflective().getColor();
#endif
}
// texture
else if (ef->getReflective().isTexture()) {
#if 0
COLLADAFW::Texture ctex = ef->getReflective().getTexture();
#endif
}
// 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()) {
#if 0
COLLADAFW::Texture ctex = ef->getEmission().getTexture();
#endif
}
// TRANSPARENT
// color
if (ef->getOpacity().isColor()) {
#if 0
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) {
...
}
#endif
}
// texture
else if (ef->getOpacity().isTexture()) {
#if 0
COLLADAFW::Texture ctex = ef->getOpacity().getTexture();
#endif
}
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.
@ -903,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();
@ -940,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);
@ -1066,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();
@ -1083,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();
@ -1091,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;
}
@ -1103,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);
@ -1196,12 +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:
{
/* TODO Fix */
// lamp->type = LA_HEMI;
lamp->type = LA_SUN; //TODO needs more thoughts
}
break;
case COLLADAFW::Light::SPOT_LIGHT:
@ -1251,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;
@ -1261,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;
@ -1278,7 +1158,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);

View File

@ -59,8 +59,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);
@ -155,7 +155,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;
@ -172,6 +172,7 @@ private:
std::string import_from_version;
void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type);
};
#endif

View File

@ -49,7 +49,6 @@ extern "C" {
#include "BKE_material.h"
}
// OB_MESH is assumed
static std::string getActiveUVLayerName(Object *ob)
{
Mesh *me = (Mesh *)ob->data;
@ -61,8 +60,12 @@ static std::string getActiveUVLayerName(Object *ob)
return "";
}
EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) {
}
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)
{
@ -82,9 +85,10 @@ bool EffectsExporter::hasEffects(Scene *sce)
return false;
}
void EffectsExporter::exportEffects(Scene *sce)
void EffectsExporter::exportEffects(bContext *C, Scene *sce)
{
if (hasEffects(sce)) {
this->mContext = C;
this->scene = sce;
openLibrary();
MaterialFunctor mf;
@ -94,61 +98,105 @@ void EffectsExporter::exportEffects(Scene *sce)
}
}
void EffectsExporter::writeLambert(COLLADASW::EffectProfile &ep, Material *ma)
void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
{
COLLADASW::ColorOrTexture cot;
ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); //XXX check if BLINN and PHONG can be supported as well
}
void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
{
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::set_specular_color(COLLADASW::EffectProfile &ep, Material *ma)
{
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::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
{
// not yet supported (needs changes in principled shader
}
void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
{
if (!ma->use_nodes) {
return;
}
MaterialNode material = MaterialNode(mContext, ma, key_image_map);
Image *image = material.get_diffuse_image();
if (image == nullptr) {
return;
}
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::create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &material_image_map, std::string &active_uv)
{
KeyImageMap::iterator iter;
for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
Image *image = iter->second;
std::string uid(id_name(image));
std::string key = translate_id(uid);
COLLADASW::Sampler *sampler = new COLLADASW::Sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
sampler->setImageId(key);
ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
}
}
void EffectsExporter::operator()(Material *ma, Object *ob)
{
// TODO: add back texture and extended material parameter support
KeyImageMap material_image_map;
openEffect(translate_id(id_name(ma)) + "-effect");
openEffect(get_effect_id(ma));
COLLADASW::EffectProfile ep(mSW);
ep.setProfileType(COLLADASW::EffectProfile::COMMON);
ep.openProfile();
writeLambert(ep, ma);
set_shader_type(ep, ma);
COLLADASW::ColorOrTexture cot;
// transparency
if (ma->alpha != 1.0f) {
// 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);
}
set_transparency(ep, ma);
set_diffuse_color(ep, ma);
set_specular_color(ep, ma);
set_emission(ep, ma);
// emission
#if 0
cot = getcol(ma->emit, ma->emit, ma->emit, 1.0f);
#endif
// diffuse
cot = getcol(ma->r, ma->g, ma->b, 1.0f);
ep.setDiffuse(cot, false, "diffuse");
// specular
if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f);
ep.setSpecular(cot, false, "specular");
}
// XXX make this more readable if possible
get_images(ma, material_image_map);
std::string active_uv(getActiveUVLayerName(ob));
create_image_samplers(ep, material_image_map, active_uv);
#if 0
// 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];
// image to index to samp_surf map
// samp_surf[index] stores 2 pointers, sampler and surface
std::map<std::string, int> im_samp_map;
unsigned int a, b;
for (a = 0, b = 0; a < tex_indices.size(); a++) {
MTex *t = ma->mtex[tex_indices[a]];
@ -162,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];
@ -189,15 +226,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
b++;
}
}
#endif
// used as fallback when MTex->uvname is "" (this is pretty common)
// it is indeed the correct value to use in that case
std::string active_uv(getActiveUVLayerName(ob));
// write textures
// XXX very slow
#if 0
for (a = 0; a < tex_indices.size(); a++) {
MTex *t = ma->mtex[tex_indices[a]];
Image *ima = t->tex->ima;
@ -210,7 +239,7 @@ 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

View File

@ -42,12 +42,13 @@
#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);
@ -58,7 +59,14 @@ public:
COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a);
private:
void writeLambert(COLLADASW::EffectProfile &ep, Material *ma);
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 writeTextures(COLLADASW::EffectProfile &ep,
std::string &key,
COLLADASW::Sampler *sampler,
@ -68,8 +76,9 @@ private:
bool hasEffects(Scene *sce);
const ExportSettings *export_settings;
KeyImageMap &key_image_map;
Scene *scene;
bContext *mContext;
};
#endif

View File

@ -49,47 +49,66 @@ 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() != COLLADASaxFWL::IError::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;
}

View File

@ -44,6 +44,19 @@ typedef enum BC_export_transformation_type {
} BC_export_transformation_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;
BC_export_mesh_type export_mesh_type;
@ -54,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;
bool include_material_textures;
BC_export_animation_type export_animation_type;
bool use_texture_copies;
bool triangulate;

View File

@ -51,17 +51,17 @@ 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)
GeometryExporter::GeometryExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
blender_context(blender_context),
COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
{
}
void GeometryExporter::exportGeom(Main *bmain, struct Depsgraph *depsgraph, Scene *sce)
void GeometryExporter::exportGeom()
{
Scene *sce = blender_context.get_scene();
openLibrary();
mDepsgraph = depsgraph;
m_bmain = bmain;
mScene = sce;
GeometryFunctor gf;
gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
@ -72,8 +72,7 @@ void GeometryExporter::operator()(Object *ob)
{
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me = bc_get_mesh_copy(
mDepsgraph,
mScene,
blender_context,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
@ -91,6 +90,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);

View File

@ -43,7 +43,7 @@
#include "ExportSettings.h"
#include "collada_utils.h"
#include "BlenderContext.h"
#include "BKE_key.h"
struct Depsgraph;
@ -74,14 +74,10 @@ class GeometryExporter : COLLADASW::LibraryGeometries
Normal n;
struct Depsgraph *mDepsgraph;
Main *m_bmain;
Scene *mScene;
public:
GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
GeometryExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
void exportGeom(Main *bmain, Depsgraph *depsgraph, Scene *sce);
void exportGeom();
void operator()(Object *ob);
@ -125,7 +121,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);

View File

@ -51,7 +51,10 @@ 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)
{
}
@ -59,135 +62,110 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
{
std::string name(id_name(image));
std::string translated_name(translate_id(name));
bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_name) == mImages.end();
if (not_yet_exported) {
ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL);
if (!imbuf) {
fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
return;
}
ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL);
if (!imbuf) {
fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0;
ImageFormatData imageFormat;
BKE_imbuf_to_image_format(&imageFormat, imbuf);
short image_source = image->source;
bool is_generated = image_source == IMA_SRC_GENERATED;
bool is_packed = 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];
// Destination folder for exported assets
BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));
if (is_generated || is_dirty || use_copies || is_packed) {
// make absolute destination path
BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
// make dest directory if it doesn't exist
BLI_make_existing_file(export_path);
}
if (is_generated || is_dirty || is_packed) {
// This image in its current state only exists in Blender memory.
// So we have to export it. The export will keep the image state intact,
// so the exported file will not be associated with the image.
if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
return;
}
BLI_strncpy(export_path, export_file, sizeof(export_path));
}
else {
bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0;
// 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);
ImageFormatData imageFormat;
BKE_imbuf_to_image_format(&imageFormat, imbuf);
if (use_copies) {
short image_source = image->source;
bool is_generated = image_source == IMA_SRC_GENERATED;
bool is_packed = BKE_image_has_packedfile(image);
// 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).
char export_path[FILE_MAX];
char source_path[FILE_MAX];
char export_dir[FILE_MAX];
char export_file[FILE_MAX];
// Destination folder for exported assets
BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));
if (is_generated || is_dirty || use_copies || is_packed) {
// make absolute destination path
BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
// make dest directory if it doesn't exist
BLI_make_existing_file(export_path);
}
if (is_generated || is_dirty || is_packed) {
// This image in its current state only exists in Blender memory.
// So we have to export it. The export will keep the image state intact,
// so the exported file will not be associated with the image.
if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
return;
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 {
// 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);
// Do not make any copies, but use the source path directly as reference
// to the original image
if (use_copies) {
// This image is already located on the file system.
// But we want to create copies here.
// To move images into the same export directory.
// Note: If an image is already located in the export folder,
// then skip the copy (as it would result in a file copy error).
if (BLI_path_cmp(source_path, export_path) != 0) {
if (BLI_copy(source_path, export_path) != 0) {
fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path);
return;
}
}
BLI_strncpy(export_path, export_file, sizeof(export_path));
}
else {
// Do not make any copies, but use the source path directly as reference
// to the original image
BLI_strncpy(export_path, source_path, sizeof(export_path));
}
}
COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
img.add(mSW);
fprintf(stdout, "Collada export: Added image: %s\n", export_file);
mImages.push_back(translated_name);
BKE_image_release_ibuf(image, imbuf, NULL);
}
}
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;
// TODO: find image textures in shader nodes
BLI_strncpy(export_path, source_path, sizeof(export_path));
}
}
return false;
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);
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->include_material_textures) {
mf.forEachMaterialInExportSet<ImagesExporter>(sce, *this, this->export_settings->export_set);
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);
export_UV_Image(image, use_texture_copies);
}
closeLibrary();
}
void ImagesExporter::operator()(Material *ma, Object *ob)
{
// bool use_texture_copies = this->export_settings->use_texture_copies;
// TODO call export_UV_Image for every image in shader nodes
}

View File

@ -40,20 +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_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

View File

@ -89,15 +89,7 @@ void LightsExporter::operator()(Object *ob)
exportBlenderProfile(cla, la);
addLight(cla);
}
// hemi
/* Hemi were removed from 2.8 */
// 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);

View File

@ -68,12 +68,12 @@ bool MaterialsExporter::hasMaterials(Scene *sce)
void MaterialsExporter::operator()(Material *ma, Object *ob)
{
std::string name(id_name(ma));
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);
openMaterial(get_material_id(ma), translate_id(name));
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();
}

View File

@ -44,6 +44,7 @@ extern "C" {
#include "GeometryExporter.h"
#include "collada_internal.h"
#include "ExportSettings.h"
#include "materials.h"
class MaterialsExporter: COLLADASW::LibraryMaterials
{

View File

@ -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),
effect(nullptr),
material(ma),
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),
effect(ef),
material(ma),
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;
}

View File

@ -0,0 +1,83 @@
/*
* ***** 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

View File

@ -599,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) {

View File

@ -34,22 +34,25 @@ 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)
SceneExporter::SceneExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings):
blender_context(blender_context),
COLLADASW::LibraryVisualScenes(sw), arm_exporter(arm), export_settings(export_settings)
{
}
void SceneExporter::exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce)
void SceneExporter::exportScene()
{
ViewLayer *view_layer = blender_context.get_view_layer();
// <library_visual_scenes> <visual_scene>
std::string id_naming = id_name(sce);
openVisualScene(translate_id(id_naming), id_naming);
exportHierarchy(C, depsgraph, sce);
std::string name = id_name(view_layer);
openVisualScene(translate_id(name), encode_xml(name));
exportHierarchy();
closeVisualScene();
closeLibrary();
}
void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sce)
void SceneExporter::exportHierarchy()
{
LinkNode *node;
std::vector<Object *> base_objects;
@ -82,164 +85,157 @@ void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sc
Object *ob = base_objects[index];
if (bc_is_marked(ob)) {
bc_remove_mark(ob);
writeNodes(C, depsgraph, ob, sce);
writeNodes(ob);
}
}
}
void SceneExporter::writeNodes(bContext *C, Depsgraph *depsgraph, Object *ob, Scene *sce)
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(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, depsgraph, 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;
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);
}
// list child objects
LinkNode *node;
for (node=this->export_settings->export_set; node; node=node->next) {
// cob - child object
Object *cob = (Object *)node->link;
if (cob->parent == ob) {
switch (cob->type) {
case OB_MESH:
case OB_CAMERA:
case OB_LAMP:
case OB_EMPTY:
case OB_GPENCIL:
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);
instGeom.add();
// <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_controller>
else if (ob->type == OB_ARMATURE) {
arm_exporter->add_armature_bones(C, depsgraph, 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_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);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_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 (ob->type == OB_ARMATURE) {
colladaNode.end();
}
if (BLI_listbase_is_empty(&ob->constraints) == false) {
bConstraint *con = (bConstraint *) ob->constraints.first;
while (con) {
std::string con_name(translate_id(con->name));
std::string con_tag = con_name + "_constraint";
printf("%s\n", con_name.c_str());
printf("%s\n\n", con_tag.c_str());
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"type",con->type);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"enforce",con->enforce);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"flag",con->flag);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"headtail",con->headtail);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"own_space",con->ownspace);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
//not ideal: add the target object name as another parameter.
//No real mapping in the .dae
//Need support for multiple target objects also.
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
bConstraintTarget *ct;
Object *obtar;
cti->get_constraint_targets(con, &targets);
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
std::string tar_id((obtar) ? id_name(obtar) : "");
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"target_id",tar_id);
// 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;
}
}
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);
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, depsgraph, *i, sce);
}
}
//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) {
if (ob->type != OB_ARMATURE)
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;
}
}
}
writeNodeList(child_objects, ob);
colladaNode.end();
}
}

View File

@ -94,13 +94,15 @@ 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, Depsgraph *depsgraph, Scene *sce);
SceneExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings);
void exportScene();
private:
friend class ArmatureExporter;
void exportHierarchy(bContext *C, struct Depsgraph *depsgraph, Scene *sce);
void writeNodes(bContext *C, struct Depsgraph *depsgraph, Object *ob, Scene *sce);
BlenderContext &blender_context;
void exportHierarchy();
void writeNodeList(std::vector<Object *> &child_objects, Object *parent);
void writeNodes(Object *ob);
ArmatureExporter *arm_exporter;
const ExportSettings *export_settings;

View File

@ -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;

View File

@ -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;
}

View File

@ -45,23 +45,51 @@ extern "C"
#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,
Depsgraph *depsgraph,
Scene *sce,
ExportSettings *export_settings)
{
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
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(view_layer, objectSet, (eObRelationTypes)includeFilter);
@ -80,8 +108,8 @@ int collada_export(bContext *C,
bc_bubble_sort_by_Object_name(export_settings->export_set);
}
DocumentExporter exporter(depsgraph, export_settings);
int status = exporter.exportCurrentScene(C, sce);
DocumentExporter exporter(blender_context, export_settings);
int status = exporter.exportCurrentScene();
BLI_linklist_free(export_settings->export_set, NULL);

View File

@ -52,8 +52,6 @@ int collada_import(struct bContext *C,
ImportSettings *import_settings);
int collada_export(struct bContext *C,
struct Depsgraph *depsgraph,
struct Scene *sce,
ExportSettings *export_settings);
#ifdef __cplusplus

View File

@ -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 {
{'<' , "&lt;" },
{'>' , "&gt;" },
{'"' , "&quot;"},
{'\'', "&apos;"},
{'&' , "&amp;" }
};
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,21 +355,25 @@ std::string get_light_id(Object *ob)
return translate_id(id_name(ob)) + "-light";
}
std::string get_joint_id(Object *ob, Bone *bone)
{
return translate_id(id_name(ob) + "_" + bone->name);
}
std::string get_joint_sid(Bone *bone)
{
return translate_id(bone->name);
}
std::string get_joint_sid(EditBone *bone)
{
return translate_id(bone->name);
}
std::string get_camera_id(Object *ob)
{
return translate_id(id_name(ob)) + "-camera";
}
std::string get_effect_id(Material *mat)
{
return translate_id(id_name(mat)) + "-effect";
}
std::string get_material_id(Material *mat)
{
return translate_id(id_name(mat)) + "-material";

View File

@ -91,19 +91,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_material_id(Material *mat);
extern std::string get_morph_id(Object *ob);
extern std::string get_effect_id(Material *mat);
extern std::string get_material_id(Material *mat);
#endif /* __COLLADA_INTERNAL_H__ */

View File

@ -33,20 +33,29 @@
#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_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"
@ -56,19 +65,27 @@ extern "C" {
#include "BKE_scene.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)
{
@ -92,6 +109,47 @@ 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)
@ -131,15 +189,52 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
return true;
}
Scene *bc_get_scene(bContext *C)
std::vector<bAction *> bc_getSceneActions(const bContext *C, Object *ob, bool all_actions)
{
return CTX_data_scene(C);
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;
}
void bc_update_scene(Main *bmain, Depsgraph *depsgraph, Scene *scene, float ctime)
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(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);
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
ED_update_for_newframe(bmain, depsgraph);
}
Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
@ -161,7 +256,11 @@ Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type
}
Mesh *bc_get_mesh_copy(
Depsgraph *depsgraph, 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)
{
CustomDataMask mask = CD_MASK_MESH;
Mesh *mesh = (Mesh *)ob->data;
@ -181,6 +280,8 @@ Mesh *bc_get_mesh_copy(
}
}
#else
Depsgraph *depsgraph = blender_context.get_depsgraph();
Scene *scene = blender_context.get_scene();
tmpmesh = mesh_get_eval_final(depsgraph, scene, ob, mask);
#endif
}
@ -221,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)) {
@ -236,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)
@ -819,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.
@ -883,8 +1128,11 @@ 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_mat(double mat[4][4], int precision)
@ -906,7 +1154,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];
}
}
}
void bc_copy_m4d_v44(double (&r)[4][4], std::vector<std::vector<double>> &a)
{
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
r[i][j] = a[i][j];
}
}
}
/**
@ -948,3 +1220,203 @@ std::string bc_get_uvlayer_name(Mesh *me, int layer)
}
return "";
}
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;
}
static bNodeTree *prepare_material_nodetree(Material *ma)
{
if (ma->nodetree == NULL) {
ma->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
ma->use_nodes = true;
}
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());
}
node->locx = locx;
node->locy = locy;
node->flag |= NODE_SELECT;
}
return node;
}
bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy)
{
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);
//bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
//return socket;
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 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;
}

View File

@ -31,14 +31,23 @@
#include "COLLADAFWGeometry.h"
#include "COLLADAFWFloatOrDoubleArray.h"
#include "COLLADAFWTypes.h"
#include "COLLADASWEffectProfile.h"
#include "COLLADAFWColorOrTexture.h"
#include <vector>
#include <map>
#include <set>
#include <algorithm>
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"
@ -49,35 +58,95 @@ extern "C" {
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_object.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"
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 Scene *bc_get_scene(bContext *C);
extern Depsgraph *bc_get_depsgraph();
extern void bc_update_scene(Main *bmain, Depsgraph *depsgraph, 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, ViewLayer *view_layer, int type, const char *name);
extern Mesh *bc_get_mesh_copy(
Depsgraph *depsgraph, 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);
@ -91,8 +160,32 @@ 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);
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);
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);
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
@ -110,9 +203,12 @@ 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);
extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
@ -122,6 +218,13 @@ 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_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 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
@ -203,4 +306,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

View File

@ -94,10 +94,13 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int deform_bones_only;
int include_animations;
int sample_animations;
int include_all_actions;
int sampling_rate;
int keep_smooth_curves;
int keep_keyframes;
int include_material_textures;
int export_animation_type;
int use_texture_copies;
int active_uv_only;
@ -112,6 +115,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int keep_bind_info;
int export_count;
int sample_animations;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@ -148,8 +152,12 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys");
include_animations = RNA_boolean_get(op->ptr, "include_animations");
sample_animations = RNA_boolean_get(op->ptr, "sample_animations");
sampling_rate = (sample_animations) ? RNA_int_get(op->ptr, "sampling_rate") : 0;
include_all_actions = RNA_boolean_get(op->ptr, "include_all_actions");
export_animation_type = RNA_enum_get(op->ptr, "export_animation_type_selection");
sample_animations = (export_animation_type == BC_ANIMATION_EXPORT_SAMPLES);
sampling_rate = (sample_animations)? RNA_int_get(op->ptr, "sampling_rate") : 0;
keep_smooth_curves = RNA_boolean_get(op->ptr, "keep_smooth_curves");
keep_keyframes = RNA_boolean_get(op->ptr, "keep_keyframes");
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
@ -172,7 +180,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
/* get editmode results */
ED_object_editmode_load(bmain, CTX_data_edit_object(C));
Scene *scene = CTX_data_scene(C);
//Scene *scene = CTX_data_scene(C);
ExportSettings export_settings;
@ -185,18 +193,36 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_settings.include_armatures = include_armatures != 0;
export_settings.include_shapekeys = include_shapekeys != 0;
export_settings.deform_bones_only = deform_bones_only != 0;
export_settings.include_animations = include_animations;
export_settings.include_animations = include_animations != 0;
export_settings.include_all_actions = include_all_actions != 0;
export_settings.sampling_rate = sampling_rate;
export_settings.keep_keyframes = keep_keyframes != 0 || sampling_rate < 1;
export_settings.active_uv_only = active_uv_only != 0;
export_settings.include_material_textures = include_material_textures != 0;
export_settings.export_animation_type = export_animation_type;
export_settings.use_texture_copies = use_texture_copies != 0;
export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
export_settings.use_blender_profile = use_blender_profile != 0;
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
if (export_animation_type == BC_ANIMATION_EXPORT_SAMPLES) {
export_settings.export_transformation_type = export_transformation_type;
}
else {
// When curves are exported then we can not export as matrix
export_settings.export_transformation_type = BC_TRANSFORMATION_TYPE_TRANSROTLOC;
}
if (export_settings.export_transformation_type == BC_TRANSFORMATION_TYPE_TRANSROTLOC) {
export_settings.keep_smooth_curves = keep_smooth_curves != 0;
}
else {
// Can not export smooth curves when Matrix export is enabled.
export_settings.keep_smooth_curves = false;
}
export_settings.open_sim = open_sim != 0;
export_settings.limit_precision = limit_precision != 0;
export_settings.keep_bind_info = keep_bind_info != 0;
@ -207,8 +233,6 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_count = collada_export(
C,
CTX_data_depsgraph(C),
scene,
&export_settings
);
@ -232,96 +256,134 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayout *box, *row, *col, *split;
bool include_animations = RNA_boolean_get(imfptr, "include_animations");
int ui_section = RNA_enum_get(imfptr, "prop_bc_export_ui_section");
BC_export_animation_type animation_type = RNA_enum_get(imfptr, "export_animation_type_selection");
BC_export_transformation_type transformation_type = RNA_enum_get(imfptr, "export_transformation_type_selection");
bool sampling = animation_type == BC_ANIMATION_EXPORT_SAMPLES;
/* Export Options: */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Export Data Options:"), ICON_MESH_DATA);
uiItemR(row, imfptr, "prop_bc_export_ui_section", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
col = uiLayoutColumn(split, false);
uiItemR(col, imfptr, "apply_modifiers", 0, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiItemR(col, imfptr, "export_mesh_type_selection", 0, "", ICON_NONE);
uiLayoutSetEnabled(col, RNA_boolean_get(imfptr, "apply_modifiers"));
if (ui_section == BC_UI_SECTION_MAIN) {
/* =================== */
/* Export Data options */
/* =================== */
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_children", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_children", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_armatures", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_armatures", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
/* Texture options */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Texture Options:"), ICON_TEXTURE_DATA);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "active_uv_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_texture_copies", 1, NULL, ICON_NONE);
}
else if (ui_section == BC_UI_SECTION_GEOMETRY) {
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Export Data Options:"), ICON_MESH_DATA);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
col = uiLayoutColumn(split, false);
uiItemR(col, imfptr, "apply_modifiers", 0, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiItemR(col, imfptr, "export_mesh_type_selection", 0, "", ICON_NONE);
uiLayoutSetEnabled(col, RNA_boolean_get(imfptr, "apply_modifiers"));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "triangulate", 1, NULL, ICON_NONE);
}
else if (ui_section == BC_UI_SECTION_ARMATURE) {
/* Armature options */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Armature Options:"), ICON_ARMATURE_DATA);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE);
}
else if (ui_section == BC_UI_SECTION_ANIMATION) {
/* ====================== */
/* Animation Data options */
/* ====================== */
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_animations", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "export_animation_type_selection", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
uiLayoutSetEnabled(row, animation_type == BC_ANIMATION_EXPORT_SAMPLES);
row = uiLayoutColumn(box, false);
uiItemR(row, imfptr, "keep_smooth_curves", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, include_animations &&
(transformation_type == BC_TRANSFORMATION_TYPE_TRANSROTLOC || animation_type == BC_ANIMATION_EXPORT_KEYS));
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_animations", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
if (include_animations) {
uiItemR(row, imfptr, "sample_animations", 0, NULL, ICON_NONE);
row = uiLayoutColumn(box, false);
uiItemR(row, imfptr, "sampling_rate", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "sample_animations"));
uiLayoutSetEnabled(row, sampling && include_animations);
row = uiLayoutColumn(box, false);
uiItemR(row, imfptr, "keep_keyframes", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, sampling && include_animations);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_all_actions", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, include_animations);
}
else if (ui_section == BC_UI_SECTION_COLLADA) {
/* Collada options: */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
/* Texture options */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Texture Options:"), ICON_TEXTURE_DATA);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_object_instantiation", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_blender_profile", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "active_uv_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "include_material_textures", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_texture_copies", 1, NULL, ICON_NONE);
/* Armature options */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Armature Options:"), ICON_ARMATURE_DATA);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE);
/* Collada options: */
box = uiLayoutBox(layout);
row = uiLayoutRow(box, false);
uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "triangulate", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_object_instantiation", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_blender_profile", 1, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE);
}
}
static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
@ -357,11 +419,27 @@ void WM_OT_collada_export(wmOperatorType *ot)
};
static const EnumPropertyItem prop_bc_export_transformation_type[] = {
{BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"},
{BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"},
{0, NULL, 0, NULL, NULL}
{ BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations" },
{ BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations" },
{ 0, NULL, 0, NULL, NULL }
};
static const EnumPropertyItem prop_bc_export_animation_type[] = {
{ BC_ANIMATION_EXPORT_SAMPLES, "sample", 0, "Samples", "Export Sampled points guided by sampling rate" },
{ BC_ANIMATION_EXPORT_KEYS, "keys", 0, "Curves", "Export Curves\n Note: guided by curve keys" },
{ 0, NULL, 0, NULL, NULL }
};
static const EnumPropertyItem prop_bc_export_ui_section[] = {
{ BC_UI_SECTION_MAIN, "main", 0, "Main", "Data Export Section" },
{ BC_UI_SECTION_GEOMETRY, "geometry", 0, "Geom", "Geometry Export Section" },
{ BC_UI_SECTION_ARMATURE, "armature", 0, "Arm", "Armature Export Section" },
{ BC_UI_SECTION_ANIMATION, "animation", 0, "Anim", "Animation Export Section" },
{ BC_UI_SECTION_COLLADA, "collada", 0, "Extra", "Collada Export Section" },
{ 0, NULL, 0, NULL, NULL }
};
ot->name = "Export COLLADA";
ot->description = "Save a Collada file";
ot->idname = "WM_OT_collada_export";
@ -379,6 +457,9 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_enum(func, "prop_bc_export_ui_section", prop_bc_export_ui_section, 0,
"Export Section", "Only for User Interface Organisation");
RNA_def_boolean(func,
"apply_modifiers", 0, "Apply Modifiers",
"Apply modifiers to exported mesh (non destructive))");
@ -404,15 +485,25 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_boolean(func, "deform_bones_only", false, "Deform Bones only",
"Only export deforming bones with armatures");
RNA_def_boolean(func, "include_animations", true,
"Include Animations", "Export Animations if available.\nExporting Animations will enforce the decomposition of node transforms\ninto <translation> <rotation> and <scale> components");
RNA_def_boolean(func, "sample_animations", 0,
"Sample Animations", "Auto-generate keyframes with a frame distance set by 'Sampling Rate'.\nWhen disabled, export only the keyframes defined in the animation f-curves (may be less accurate)");
RNA_def_boolean(func, "include_all_actions", true,
"Include all Actions", "Export also unassigned actions.\nThis allows you to export entire animation libraries for your charater(s)");
RNA_def_enum(func, "export_animation_type_selection", prop_bc_export_animation_type, 0,
"Key Type", "Type for exported animations (use sample keys or Curve keys)");
RNA_def_int(func, "sampling_rate", 1, 1, INT_MAX,
"Sampling Rate", "The distance between 2 keyframes. 1 means: Every frame is keyed", 1, INT_MAX);
RNA_def_boolean(func, "keep_smooth_curves", 0,
"Keep Smooth curves", "Export also the curve handles (if available).\nThis does only work when the inverse parent matrix is the Unity matrix\nOtherwise you may end up with odd results\n");
RNA_def_boolean(func, "keep_keyframes", 0,
"Keep Keyframes", "Use existing keyframes as additional sample points.\nThis helps when you want to keep manual tweeks");
RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map",
"Export only the selected UV Map");
@ -497,7 +588,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_ERROR, "Errors found during parsing COLLADA document (see console for details)");
BKE_report(op->reports, RPT_ERROR, "Parsing errors in Document (see Blender Console)");
return OPERATOR_CANCELLED;
}
}