86
94
#include "COLLADASWSurfaceInitOption.h"
87
95
#include "COLLADASWSampler.h"
88
96
#include "COLLADASWScene.h"
89
//#include "COLLADASWSurface.h"
90
97
#include "COLLADASWTechnique.h"
91
98
#include "COLLADASWTexture.h"
92
99
#include "COLLADASWLibraryMaterials.h"
93
100
#include "COLLADASWBindMaterial.h"
94
#include "COLLADASWLibraryCameras.h"
95
#include "COLLADASWLibraryLights.h"
96
101
#include "COLLADASWInstanceCamera.h"
97
102
#include "COLLADASWInstanceLight.h"
98
#include "COLLADASWCameraOptic.h"
99
103
#include "COLLADASWConstants.h"
100
104
#include "COLLADASWLibraryControllers.h"
101
105
#include "COLLADASWInstanceController.h"
106
#include "COLLADASWInstanceNode.h"
102
107
#include "COLLADASWBaseInputElement.h"
104
109
#include "collada_internal.h"
105
110
#include "DocumentExporter.h"
111
#include "ExportSettings.h"
113
// can probably go after refactor is complete
114
#include "InstanceWriter.h"
115
#include "TransformWriter.h"
117
#include "SceneExporter.h"
118
#include "ArmatureExporter.h"
119
#include "AnimationExporter.h"
120
#include "CameraExporter.h"
121
#include "EffectExporter.h"
122
#include "GeometryExporter.h"
123
#include "ImageExporter.h"
124
#include "LightExporter.h"
125
#include "MaterialExporter.h"
107
127
#include <vector>
108
128
#include <algorithm> // std::find
110
// arithb.c now has QuatToAxisAngle too
112
// This function assumes that quat is normalized.
113
// The following document was used as reference:
114
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
115
void quat_to_axis_angle( float *axis, float *angle,float *q)
117
// quat to axis angle
118
*angle = 2 * acos(q[0]);
119
float divisor = sqrt(1 - q[0] * q[0]);
121
// test to avoid divide by zero, divisor is always positive
122
if (divisor < 0.001f ) {
128
axis[0] = q[1] / divisor;
129
axis[1] = q[2] / divisor;
130
axis[2] = q[3] / divisor;
135
char *CustomData_get_layer_name(const struct CustomData *data, int type, int n)
130
char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
137
132
int layer_index = CustomData_get_layer_index(data, type);
138
if(layer_index < 0) return NULL;
133
if (layer_index < 0) return NULL;
140
135
return data->layers[layer_index+n].name;
143
char *CustomData_get_active_layer_name(const CustomData *data, int type)
138
char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
145
140
/* get the layer index of the active layer of type */
146
141
int layer_index = CustomData_get_active_layer_index(data, type);
147
if(layer_index < 0) return NULL;
142
if (layer_index < 0) return NULL;
149
144
return data->layers[layer_index].name;
154
Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
155
included. Look at the IDREF XSD declaration for more.
156
Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars,
157
like special chars (e.g. micro sign), umlauts and so on.
158
The COLLADA spec also allows additional chars for member access ('.'), these
159
must obviously be removed too, otherwise they would be heavily misinterpreted.
161
const unsigned char translate_map[256] = {
162
95, 95, 95, 95, 95, 95, 95, 95,
163
95, 95, 95, 95, 95, 95, 95, 95,
164
95, 95, 95, 95, 95, 95, 95, 95,
165
95, 95, 95, 95, 95, 95, 95, 95,
166
95, 95, 95, 95, 95, 95, 95, 95,
167
95, 95, 95, 95, 95, 45, 95, 95,
168
48, 49, 50, 51, 52, 53, 54, 55,
169
56, 57, 95, 95, 95, 95, 95, 95,
170
95, 65, 66, 67, 68, 69, 70, 71,
171
72, 73, 74, 75, 76, 77, 78, 79,
172
80, 81, 82, 83, 84, 85, 86, 87,
173
88, 89, 90, 95, 95, 95, 95, 95,
174
95, 97, 98, 99, 100, 101, 102, 103,
175
104, 105, 106, 107, 108, 109, 110, 111,
176
112, 113, 114, 115, 116, 117, 118, 119,
177
120, 121, 122, 95, 95, 95, 95, 95,
178
95, 95, 95, 95, 95, 95, 95, 95,
179
95, 95, 95, 95, 95, 95, 95, 95,
180
95, 95, 95, 95, 95, 95, 95, 95,
181
95, 95, 95, 95, 95, 95, 95, 95,
182
95, 95, 95, 95, 95, 95, 95, 95,
183
95, 95, 95, 95, 95, 95, 95, 95,
184
95, 95, 95, 95, 95, 95, 95, 183,
185
95, 95, 95, 95, 95, 95, 95, 95,
186
192, 193, 194, 195, 196, 197, 198, 199,
187
200, 201, 202, 203, 204, 205, 206, 207,
188
208, 209, 210, 211, 212, 213, 214, 95,
189
216, 217, 218, 219, 220, 221, 222, 223,
190
224, 225, 226, 227, 228, 229, 230, 231,
191
232, 233, 234, 235, 236, 237, 238, 239,
192
240, 241, 242, 243, 244, 245, 246, 95,
193
248, 249, 250, 251, 252, 253, 254, 255};
195
/** Look at documentation of translate_map */
196
static std::string translate_id(const std::string &id)
198
std::string id_translated = id;
199
for (unsigned int i=0; i < id_translated.size(); i++)
201
id_translated[i] = translate_map[(unsigned int)id_translated[i]];
203
return id_translated;
206
static std::string id_name(void *id)
208
return ((ID*)id)->name + 2;
211
static std::string get_geometry_id(Object *ob)
213
return translate_id(id_name(ob)) + "-mesh";
216
static std::string get_light_id(Object *ob)
218
return translate_id(id_name(ob)) + "-light";
221
static std::string get_camera_id(Object *ob)
223
return translate_id(id_name(ob)) + "-camera";
226
std::string get_joint_id(Bone *bone, Object *ob_arm)
228
return translate_id(id_name(ob_arm) + "_" + bone->name);
233
Utilities to avoid code duplication.
234
Definition can take some time to understand, but they should be useful.
238
// void operator()(Object* ob)
239
template<class Functor>
240
void forEachMeshObjectInScene(Scene *sce, Functor &f)
243
Base *base= (Base*) sce->base.first;
245
Object *ob = base->object;
247
if (ob->type == OB_MESH && ob->data) {
255
template<class Functor>
256
void forEachObjectInScene(Scene *sce, Functor &f)
258
Base *base= (Base*) sce->base.first;
260
Object *ob = base->object;
268
template<class Functor>
269
void forEachCameraObjectInScene(Scene *sce, Functor &f)
271
Base *base= (Base*) sce->base.first;
273
Object *ob = base->object;
275
if (ob->type == OB_CAMERA && ob->data) {
282
template<class Functor>
283
void forEachLampObjectInScene(Scene *sce, Functor &f)
285
Base *base= (Base*) sce->base.first;
287
Object *ob = base->object;
289
if (ob->type == OB_LAMP && ob->data) {
296
// used in forEachMaterialInScene
297
template <class MaterialFunctor>
298
class ForEachMaterialFunctor
300
std::vector<std::string> mMat; // contains list of material names, to avoid duplicate calling of f
303
ForEachMaterialFunctor(MaterialFunctor *f) : f(f) { }
304
void operator ()(Object *ob)
307
for(a = 0; a < ob->totcol; a++) {
309
Material *ma = give_current_material(ob, a+1);
313
std::string translated_id = translate_id(id_name(ma));
314
if (find(mMat.begin(), mMat.end(), translated_id) == mMat.end()) {
317
mMat.push_back(translated_id);
323
// calls f for each unique material linked to each object in sce
325
// void operator()(Material* ma)
326
template<class Functor>
327
void forEachMaterialInScene(Scene *sce, Functor &f)
329
ForEachMaterialFunctor<Functor> matfunc(&f);
330
forEachMeshObjectInScene(sce, matfunc);
333
// OB_MESH is assumed
334
std::string getActiveUVLayerName(Object *ob)
336
Mesh *me = (Mesh*)ob->data;
338
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
340
return std::string(CustomData_get_active_layer_name(&me->fdata, CD_MTFACE));
345
// TODO: optimize UV sets by making indexed list with duplicates removed
346
class GeometryExporter : COLLADASW::LibraryGeometries
350
unsigned int v1, v2, v3, v4;
361
GeometryExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryGeometries(sw) {}
363
void exportGeom(Scene *sce)
368
forEachMeshObjectInScene(sce, *this);
373
void operator()(Object *ob)
375
// XXX don't use DerivedMesh, Mesh instead?
378
DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
380
Mesh *me = (Mesh*)ob->data;
381
std::string geom_id = get_geometry_id(ob);
382
std::vector<Normal> nor;
383
std::vector<Face> norind;
385
bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
387
create_normals(nor, norind, me);
389
// openMesh(geoId, geoName, meshId)
392
// writes <source> for vertex coords
393
createVertsSource(geom_id, me);
395
// writes <source> for normal coords
396
createNormalsSource(geom_id, me, nor);
398
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
400
// writes <source> for uv coords if mesh has uv coords
402
createTexcoordsSource(geom_id, me);
405
createVertexColorSource(geom_id, me);
408
COLLADASW::Vertices verts(mSW);
409
verts.setId(getIdBySemantics(geom_id, COLLADASW::VERTEX));
410
COLLADASW::InputList &input_list = verts.getInputList();
411
COLLADASW::Input input(COLLADASW::POSITION, getUrlBySemantics(geom_id, COLLADASW::POSITION));
412
input_list.push_back(input);
417
for(int a = 0; a < ob->totcol; a++) {
418
// account for NULL materials, this should not normally happen?
419
Material *ma = give_current_material(ob, a + 1);
420
createPolylist(ma != NULL, a, has_uvs, has_color, ob, geom_id, norind);
424
createPolylist(false, 0, has_uvs, has_color, ob, geom_id, norind);
435
// powerful because it handles both cases when there is material and when there's not
436
void createPolylist(bool has_material,
441
std::string& geom_id,
442
std::vector<Face>& norind)
444
Mesh *me = (Mesh*)ob->data;
445
MFace *mfaces = me->mface;
446
int totfaces = me->totface;
450
int faces_in_polylist = 0;
451
std::vector<unsigned long> vcount_list;
453
// count faces with this material
454
for (i = 0; i < totfaces; i++) {
455
MFace *f = &mfaces[i];
457
if ((has_material && f->mat_nr == material_index) || !has_material) {
460
vcount_list.push_back(3);
463
vcount_list.push_back(4);
468
// no faces using this material
469
if (faces_in_polylist == 0) {
473
Material *ma = has_material ? give_current_material(ob, material_index + 1) : NULL;
474
COLLADASW::Polylist polylist(mSW);
476
// sets count attribute in <polylist>
477
polylist.setCount(faces_in_polylist);
479
// sets material name
481
polylist.setMaterial(translate_id(id_name(ma)));
484
COLLADASW::InputList &til = polylist.getInputList();
486
// creates <input> in <polylist> for vertices
487
COLLADASW::Input input1(COLLADASW::VERTEX, getUrlBySemantics(geom_id, COLLADASW::VERTEX), 0);
489
// creates <input> in <polylist> for normals
490
COLLADASW::Input input2(COLLADASW::NORMAL, getUrlBySemantics(geom_id, COLLADASW::NORMAL), 1);
492
til.push_back(input1);
493
til.push_back(input2);
495
// if mesh has uv coords writes <input> for TEXCOORD
496
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
498
for (i = 0; i < num_layers; i++) {
499
// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
500
COLLADASW::Input input3(COLLADASW::TEXCOORD,
501
makeUrl(makeTexcoordSourceId(geom_id, i)),
502
2, // offset always 2, this is only until we have optimized UV sets
503
i // set number equals UV layer index
505
til.push_back(input3);
509
COLLADASW::Input input4(COLLADASW::COLOR, getUrlBySemantics(geom_id, COLLADASW::COLOR), has_uvs ? 3 : 2);
510
til.push_back(input4);
514
polylist.setVCountList(vcount_list);
516
// performs the actual writing
517
polylist.prepareToAppendValues();
521
for (i = 0; i < totfaces; i++) {
522
MFace *f = &mfaces[i];
524
if ((has_material && f->mat_nr == material_index) || !has_material) {
526
unsigned int *v = &f->v1;
527
unsigned int *n = &norind[i].v1;
528
for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
529
polylist.appendValues(v[j]);
530
polylist.appendValues(n[j]);
533
polylist.appendValues(texindex + j);
536
polylist.appendValues(texindex + j);
548
// creates <source> for positions
549
void createVertsSource(std::string geom_id, Mesh *me)
552
int totverts = dm->getNumVerts(dm);
553
MVert *verts = dm->getVertArray(dm);
555
int totverts = me->totvert;
556
MVert *verts = me->mvert;
558
COLLADASW::FloatSourceF source(mSW);
559
source.setId(getIdBySemantics(geom_id, COLLADASW::POSITION));
560
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::POSITION) +
562
source.setAccessorCount(totverts);
563
source.setAccessorStride(3);
564
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
565
param.push_back("X");
566
param.push_back("Y");
567
param.push_back("Z");
568
/*main function, it creates <source id = "">, <float_array id = ""
570
source.prepareToAppendValues();
571
//appends data to <float_array>
573
for (i = 0; i < totverts; i++) {
574
source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
581
void createVertexColorSource(std::string geom_id, Mesh *me)
583
if (!CustomData_has_layer(&me->fdata, CD_MCOL))
587
int totcolor = 0, i, j;
589
for (i = 0, f = me->mface; i < me->totface; i++, f++)
590
totcolor += f->v4 ? 4 : 3;
592
COLLADASW::FloatSourceF source(mSW);
593
source.setId(getIdBySemantics(geom_id, COLLADASW::COLOR));
594
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::COLOR) + ARRAY_ID_SUFFIX);
595
source.setAccessorCount(totcolor);
596
source.setAccessorStride(3);
598
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
599
param.push_back("R");
600
param.push_back("G");
601
param.push_back("B");
603
source.prepareToAppendValues();
605
int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
607
MCol *mcol = (MCol*)me->fdata.layers[index].data;
610
for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++)
611
for (j = 0; j < (f->v4 ? 4 : 3); j++)
612
source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f);
617
std::string makeTexcoordSourceId(std::string& geom_id, int layer_index)
620
sprintf(suffix, "-%d", layer_index);
621
return getIdBySemantics(geom_id, COLLADASW::TEXCOORD) + suffix;
624
//creates <source> for texcoords
625
void createTexcoordsSource(std::string geom_id, Mesh *me)
628
int totfaces = dm->getNumFaces(dm);
629
MFace *mfaces = dm->getFaceArray(dm);
631
int totfaces = me->totface;
632
MFace *mfaces = me->mface;
638
for (i = 0; i < totfaces; i++) {
639
MFace *f = &mfaces[i];
648
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
650
// write <source> for each layer
651
// each <source> will get id like meshName + "map-channel-1"
652
for (int a = 0; a < num_layers; a++) {
653
MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
654
// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
656
COLLADASW::FloatSourceF source(mSW);
657
std::string layer_id = makeTexcoordSourceId(geom_id, a);
658
source.setId(layer_id);
659
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
661
source.setAccessorCount(totuv);
662
source.setAccessorStride(2);
663
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
664
param.push_back("S");
665
param.push_back("T");
667
source.prepareToAppendValues();
669
for (i = 0; i < totfaces; i++) {
670
MFace *f = &mfaces[i];
672
for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
673
source.appendValues(tface[i].uv[j][0],
683
//creates <source> for normals
684
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
687
int totverts = dm->getNumVerts(dm);
688
MVert *verts = dm->getVertArray(dm);
691
COLLADASW::FloatSourceF source(mSW);
692
source.setId(getIdBySemantics(geom_id, COLLADASW::NORMAL));
693
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::NORMAL) +
695
source.setAccessorCount(nor.size());
696
source.setAccessorStride(3);
697
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
698
param.push_back("X");
699
param.push_back("Y");
700
param.push_back("Z");
702
source.prepareToAppendValues();
704
std::vector<Normal>::iterator it;
705
for (it = nor.begin(); it != nor.end(); it++) {
707
source.appendValues(n.x, n.y, n.z);
713
void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
716
MVert *vert = me->mvert;
717
std::map<unsigned int, unsigned int> nshar;
719
for (i = 0; i < me->totface; i++) {
720
MFace *fa = &me->mface[i];
722
unsigned int *nn = &f.v1;
723
unsigned int *vv = &fa->v1;
725
memset(&f, 0, sizeof(f));
726
v = fa->v4 == 0 ? 3 : 4;
728
if (!(fa->flag & ME_SMOOTH)) {
731
normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
733
normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
737
for (j = 0; j < v; j++) {
738
if (fa->flag & ME_SMOOTH) {
739
if (nshar.find(*vv) != nshar.end())
743
vert[*vv].no[0]/32767.0,
744
vert[*vv].no[1]/32767.0,
745
vert[*vv].no[2]/32767.0
748
*nn = nor.size() - 1;
754
*nn = nor.size() - 1;
763
std::string getIdBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") {
764
return geom_id + getSuffixBySemantic(type) + other_suffix;
768
COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") {
770
std::string id(getIdBySemantics(geom_id, type, other_suffix));
771
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
775
COLLADASW::URI makeUrl(std::string id)
777
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
781
/* int getTriCount(MFace *faces, int totface) {
784
for (i = 0; i < totface; i++) {
786
if (faces[i].v4 != 0)
796
class TransformWriter : protected TransformBase
799
void add_node_transform(COLLADASW::Node& node, float mat[][4], float parent_mat[][4])
801
float loc[3], rot[3], scale[3];
806
invert_m4_m4(invpar, parent_mat);
807
mul_m4_m4m4(local, mat, invpar);
810
copy_m4_m4(local, mat);
813
TransformBase::decompose(local, loc, rot, NULL, scale);
815
add_transform(node, loc, rot, scale);
818
void add_node_transform_ob(COLLADASW::Node& node, Object *ob)
820
float rot[3], loc[3], scale[3];
823
float C[4][4], tmat[4][4], imat[4][4], mat[4][4];
825
// factor out scale from obmat
827
copy_v3_v3(scale, ob->size);
829
ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
830
object_to_mat4(ob, C);
831
copy_v3_v3(ob->size, scale);
833
mul_serie_m4(tmat, ob->parent->obmat, ob->parentinv, C, NULL, NULL, NULL, NULL, NULL);
835
// calculate local mat
837
invert_m4_m4(imat, ob->parent->obmat);
838
mul_m4_m4m4(mat, tmat, imat);
842
mat4_to_eul(rot, mat);
843
copy_v3_v3(loc, mat[3]);
846
copy_v3_v3(loc, ob->loc);
847
copy_v3_v3(rot, ob->rot);
848
copy_v3_v3(scale, ob->size);
851
add_transform(node, loc, rot, scale);
854
void add_node_transform_identity(COLLADASW::Node& node)
856
float loc[] = {0.0f, 0.0f, 0.0f}, scale[] = {1.0f, 1.0f, 1.0f}, rot[] = {0.0f, 0.0f, 0.0f};
857
add_transform(node, loc, rot, scale);
861
void add_transform(COLLADASW::Node& node, float loc[3], float rot[3], float scale[3])
863
node.addTranslate("location", loc[0], loc[1], loc[2]);
864
node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2]));
865
node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1]));
866
node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0]));
867
node.addScale("scale", scale[0], scale[1], scale[2]);
874
void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob)
876
for(int a = 0; a < ob->totcol; a++) {
877
Material *ma = give_current_material(ob, a+1);
879
COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
882
std::string matid(id_name(ma));
883
matid = translate_id(matid);
884
COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
886
// create <bind_vertex_input> for each uv layer
887
Mesh *me = (Mesh*)ob->data;
888
int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
890
for (int b = 0; b < totlayer; b++) {
891
char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
892
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b));
901
// XXX exporter writes wrong data for shared armatures. A separate
902
// controller should be written for each armature-mesh binding how do
903
// we make controller ids then?
904
class ArmatureExporter: public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
910
ArmatureExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryControllers(sw) {}
913
void add_armature_bones(Object *ob_arm, Scene *sce)
916
bArmature *arm = (bArmature*)ob_arm->data;
917
for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
918
// start from root bones
920
add_bone_node(bone, ob_arm);
924
bool is_skinned_mesh(Object *ob)
926
return get_assigned_armature(ob) != NULL;
929
void add_instance_controller(Object *ob)
931
Object *ob_arm = get_assigned_armature(ob);
932
bArmature *arm = (bArmature*)ob_arm->data;
934
const std::string& controller_id = get_controller_id(ob_arm, ob);
936
COLLADASW::InstanceController ins(mSW);
937
ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
939
// write root bone URLs
941
for (bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
943
ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
946
InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob);
951
void export_controllers(Scene *sce)
957
forEachMeshObjectInScene(sce, *this);
962
void operator()(Object *ob)
964
Object *ob_arm = get_assigned_armature(ob);
966
if (ob_arm /*&& !already_written(ob_arm)*/)
967
export_controller(ob, ob_arm);
972
UnitConverter converter;
975
std::vector<Object*> written_armatures;
977
bool already_written(Object *ob_arm)
979
return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end();
982
void wrote(Object *ob_arm)
984
written_armatures.push_back(ob_arm);
987
void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce)
991
Base *base= (Base*) sce->base.first;
993
Object *ob = base->object;
995
if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
996
objects.push_back(ob);
1004
Object *get_assigned_armature(Object *ob)
1006
Object *ob_arm = NULL;
1008
if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
1009
ob_arm = ob->parent;
1012
ModifierData *mod = (ModifierData*)ob->modifiers.first;
1014
if (mod->type == eModifierType_Armature) {
1015
ob_arm = ((ArmatureModifierData*)mod)->object;
1025
std::string get_joint_sid(Bone *bone, Object *ob_arm)
1027
return get_joint_id(bone, ob_arm);
1030
// parent_mat is armature-space
1031
void add_bone_node(Bone *bone, Object *ob_arm)
1033
std::string node_id = get_joint_id(bone, ob_arm);
1034
std::string node_name = std::string(bone->name);
1035
std::string node_sid = get_joint_sid(bone, ob_arm);
1037
COLLADASW::Node node(mSW);
1039
node.setType(COLLADASW::Node::JOINT);
1040
node.setNodeId(node_id);
1041
node.setNodeName(node_name);
1042
node.setNodeSid(node_sid);
1046
add_bone_transform(ob_arm, bone, node);
1048
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
1049
add_bone_node(child, ob_arm);
1055
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
1057
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
1062
// get bone-space matrix from armature-space
1063
bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name);
1066
invert_m4_m4(invpar, parchan->pose_mat);
1067
mul_m4_m4m4(mat, pchan->pose_mat, invpar);
1070
// get world-space from armature-space
1071
mul_m4_m4m4(mat, pchan->pose_mat, ob_arm->obmat);
1074
TransformWriter::add_node_transform(node, mat, NULL);
1077
std::string get_controller_id(Object *ob_arm, Object *ob)
1079
return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX;
1082
// ob should be of type OB_MESH
1083
// both args are required
1084
void export_controller(Object* ob, Object *ob_arm)
1087
// joint inverse bind matrices
1091
// joint names: ob -> vertex group names
1092
// vertex group weights: me->dvert -> groups -> index, weight
1097
typedef struct MDeformVert {
1098
struct MDeformWeight *dw;
1100
int flag; // flag only in use for weightpaint now
1103
typedef struct MDeformWeight {
1109
Mesh *me = (Mesh*)ob->data;
1110
if (!me->dvert) return;
1112
std::string controller_name = id_name(ob_arm);
1113
std::string controller_id = get_controller_id(ob_arm, ob);
1115
openSkin(controller_id, controller_name,
1116
COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
1118
add_bind_shape_mat(ob);
1120
std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
1121
std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id);
1122
std::string weights_source_id = add_weights_source(me, controller_id);
1124
add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
1125
add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase);
1131
void add_joints_element(ListBase *defbase,
1132
const std::string& joints_source_id, const std::string& inv_bind_mat_source_id)
1134
COLLADASW::JointsElement joints(mSW);
1135
COLLADASW::InputList &input = joints.getInputList();
1137
input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h
1138
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id)));
1139
input.push_back(COLLADASW::Input(COLLADASW::BINDMATRIX,
1140
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id)));
1144
void add_bind_shape_mat(Object *ob)
1146
double bind_mat[4][4];
1148
converter.mat4_to_dae_double(bind_mat, ob->obmat);
1150
addBindShapeTransform(bind_mat);
1153
std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
1155
std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
1159
for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
1160
if (is_bone_defgroup(ob_arm, def))
1164
COLLADASW::NameSource source(mSW);
1165
source.setId(source_id);
1166
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1167
source.setAccessorCount(totjoint);
1168
source.setAccessorStride(1);
1170
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
1171
param.push_back("JOINT");
1173
source.prepareToAppendValues();
1175
for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
1176
Bone *bone = get_bone_from_defgroup(ob_arm, def);
1178
source.appendValues(get_joint_sid(bone, ob_arm));
1186
std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
1188
std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
1190
COLLADASW::FloatSourceF source(mSW);
1191
source.setId(source_id);
1192
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1193
source.setAccessorCount(BLI_countlist(defbase));
1194
source.setAccessorStride(16);
1196
source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
1197
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
1198
param.push_back("TRANSFORM");
1200
source.prepareToAppendValues();
1202
bPose *pose = ob_arm->pose;
1203
bArmature *arm = (bArmature*)ob_arm->data;
1205
int flag = arm->flag;
1207
// put armature in rest position
1208
if (!(arm->flag & ARM_RESTPOS)) {
1209
arm->flag |= ARM_RESTPOS;
1210
where_is_pose(scene, ob_arm);
1213
for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) {
1214
if (is_bone_defgroup(ob_arm, def)) {
1216
bPoseChannel *pchan = get_pose_channel(pose, def->name);
1220
float inv_bind_mat[4][4];
1222
// make world-space matrix, pose_mat is armature-space
1223
mul_m4_m4m4(world, pchan->pose_mat, ob_arm->obmat);
1225
invert_m4_m4(mat, world);
1226
converter.mat4_to_dae(inv_bind_mat, mat);
1228
source.appendValues(inv_bind_mat);
1232
// back from rest positon
1233
if (!(flag & ARM_RESTPOS)) {
1235
where_is_pose(scene, ob_arm);
1243
Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def)
1245
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name);
1246
return pchan ? pchan->bone : NULL;
1249
bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def)
1251
return get_bone_from_defgroup(ob_arm, def) != NULL;
1254
std::string add_weights_source(Mesh *me, const std::string& controller_id)
1256
std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
1261
for (i = 0; i < me->totvert; i++) {
1262
totweight += me->dvert[i].totweight;
1265
COLLADASW::FloatSourceF source(mSW);
1266
source.setId(source_id);
1267
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1268
source.setAccessorCount(totweight);
1269
source.setAccessorStride(1);
1271
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
1272
param.push_back("WEIGHT");
1274
source.prepareToAppendValues();
1276
// NOTE: COLLADA spec says weights should be normalized
1278
for (i = 0; i < me->totvert; i++) {
1279
MDeformVert *vert = &me->dvert[i];
1280
for (int j = 0; j < vert->totweight; j++) {
1281
source.appendValues(vert->dw[j].weight);
1290
void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
1291
Object *ob_arm, ListBase *defbase)
1293
COLLADASW::VertexWeightsElement weights(mSW);
1294
COLLADASW::InputList &input = weights.getInputList();
1297
input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h
1298
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++));
1299
input.push_back(COLLADASW::Input(COLLADASW::WEIGHT,
1300
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++));
1302
weights.setCount(me->totvert);
1304
// write number of deformers per vertex
1305
COLLADASW::PrimitivesBase::VCountList vcount;
1307
for (i = 0; i < me->totvert; i++) {
1308
vcount.push_back(me->dvert[i].totweight);
1311
weights.prepareToAppendVCountValues();
1312
weights.appendVertexCount(vcount);
1314
// def group index -> joint index
1315
std::map<int, int> joint_index_by_def_index;
1318
for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
1319
if (is_bone_defgroup(ob_arm, def))
1320
joint_index_by_def_index[i] = j++;
1322
joint_index_by_def_index[i] = -1;
1325
weights.CloseVCountAndOpenVElement();
1327
// write deformer index - weight index pairs
1328
int weight_index = 0;
1329
for (i = 0; i < me->totvert; i++) {
1330
MDeformVert *dvert = &me->dvert[i];
1331
for (int j = 0; j < dvert->totweight; j++) {
1332
weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]);
1333
weights.appendValues(weight_index++);
1341
class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
1343
ArmatureExporter *arm_exporter;
1345
SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
1346
arm_exporter(arm) {}
1348
void exportScene(Scene *sce) {
1349
// <library_visual_scenes> <visual_scene>
1350
std::string id_naming = id_name(sce);
1351
openVisualScene(translate_id(id_naming), id_naming);
1354
//forEachMeshObjectInScene(sce, *this);
1355
//forEachCameraObjectInScene(sce, *this);
1356
//forEachLampObjectInScene(sce, *this);
1357
exportHierarchy(sce);
1359
// </visual_scene> </library_visual_scenes>
1365
void exportHierarchy(Scene *sce)
1367
Base *base= (Base*) sce->base.first;
1369
Object *ob = base->object;
1379
writeNodes(ob, sce);
1389
// called for each object
1390
//void operator()(Object *ob) {
1391
void writeNodes(Object *ob, Scene *sce)
1393
COLLADASW::Node node(mSW);
1394
node.setNodeId(translate_id(id_name(ob)));
1395
node.setType(COLLADASW::Node::NODE);
1399
bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
1401
if (ob->type == OB_MESH && is_skinned_mesh)
1402
// for skinned mesh we write obmat in <bind_shape_matrix>
1403
TransformWriter::add_node_transform_identity(node);
1405
TransformWriter::add_node_transform_ob(node, ob);
1407
// <instance_geometry>
1408
if (ob->type == OB_MESH) {
1409
if (is_skinned_mesh) {
1410
arm_exporter->add_instance_controller(ob);
1413
COLLADASW::InstanceGeometry instGeom(mSW);
1414
instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
1416
InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
1422
// <instance_controller>
1423
else if (ob->type == OB_ARMATURE) {
1424
arm_exporter->add_armature_bones(ob, sce);
1426
// XXX this looks unstable...
1430
// <instance_camera>
1431
else if (ob->type == OB_CAMERA) {
1432
COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
1437
else if (ob->type == OB_LAMP) {
1438
COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
1443
else if (ob->type == OB_EMPTY) {
1446
// write nodes for child objects
1447
Base *b = (Base*) sce->base.first;
1449
// cob - child object
1450
Object *cob = b->object;
1452
if (cob->parent == ob) {
1460
writeNodes(cob, sce);
1468
if (ob->type != OB_ARMATURE)
1473
class ImagesExporter: COLLADASW::LibraryImages
1475
const char *mfilename;
1476
std::vector<std::string> mImages; // contains list of written images, to avoid duplicates
1478
ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename)
1481
void exportImages(Scene *sce)
1485
forEachMaterialInScene(sce, *this);
1490
void operator()(Material *ma, Object *ob)
1493
for (a = 0; a < MAX_MTEX; a++) {
1494
MTex *mtex = ma->mtex[a];
1495
if (mtex && mtex->tex && mtex->tex->ima) {
1497
Image *image = mtex->tex->ima;
1498
std::string name(id_name(image));
1499
name = translate_id(name);
1505
BLI_split_dirfile(mfilename, dir, NULL);
1507
BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.sce, image->name, dir);
1509
if (abs[0] != '\0') {
1511
// make absolute source path
1512
BLI_strncpy(src, image->name, sizeof(src));
1513
BLI_path_abs(src, G.sce);
1515
// make dest directory if it doesn't exist
1516
BLI_make_existing_file(abs);
1518
if (BLI_copy_fileops(src, abs) != 0) {
1519
fprintf(stderr, "Cannot copy image to file's directory. \n");
1523
if (find(mImages.begin(), mImages.end(), name) == mImages.end()) {
1524
COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name);
1527
mImages.push_back(name);
1534
class EffectsExporter: COLLADASW::LibraryEffects
1537
EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){}
1538
void exportEffects(Scene *sce)
1542
forEachMaterialInScene(sce, *this);
1547
void operator()(Material *ma, Object *ob)
1549
// create a list of indices to textures of type TEX_IMAGE
1550
std::vector<int> tex_indices;
1551
createTextureIndices(ma, tex_indices);
1553
openEffect(translate_id(id_name(ma)) + "-effect");
1555
COLLADASW::EffectProfile ep(mSW);
1556
ep.setProfileType(COLLADASW::EffectProfile::COMMON);
1558
// set shader type - one of three blinn, phong or lambert
1559
if (ma->spec_shader == MA_SPEC_BLINN) {
1560
ep.setShaderType(COLLADASW::EffectProfile::BLINN);
1562
ep.setShininess(ma->spec);
1564
else if (ma->spec_shader == MA_SPEC_PHONG) {
1565
ep.setShaderType(COLLADASW::EffectProfile::PHONG);
1567
// XXX not sure, stolen this from previous Collada plugin
1568
ep.setShininess(ma->har / 4);
1571
// XXX write warning "Current shader type is not supported"
1572
ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
1574
// index of refraction
1575
if (ma->mode & MA_RAYTRANSP) {
1576
ep.setIndexOfRefraction(ma->ang);
1579
ep.setIndexOfRefraction(1.0f);
1582
COLLADASW::ColorOrTexture cot;
1585
// Tod: because we are in A_ONE mode transparency is calculated like this:
1586
ep.setTransparency(1.0f);
1587
cot = getcol(0.0f, 0.0f, 0.0f, ma->alpha);
1588
ep.setTransparent(cot);
1591
cot=getcol(ma->emit, ma->emit, ma->emit, 1.0f);
1592
ep.setEmission(cot);
1595
cot = getcol(ma->r, ma->g, ma->b, 1.0f);
1599
cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f);
1602
// reflective, reflectivity
1603
if (ma->mode & MA_RAYMIRROR) {
1604
cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f);
1605
ep.setReflective(cot);
1606
ep.setReflectivity(ma->ray_mirror);
1609
cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
1610
ep.setReflective(cot);
1611
ep.setReflectivity(ma->spec);
1615
if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
1616
cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
1617
ep.setSpecular(cot);
1620
// XXX make this more readable if possible
1622
// create <sampler> and <surface> for each image
1623
COLLADASW::Sampler samplers[MAX_MTEX];
1624
//COLLADASW::Surface surfaces[MAX_MTEX];
1625
//void *samp_surf[MAX_MTEX][2];
1626
void *samp_surf[MAX_MTEX][1];
1628
// image to index to samp_surf map
1629
// samp_surf[index] stores 2 pointers, sampler and surface
1630
std::map<std::string, int> im_samp_map;
1633
for (a = 0, b = 0; a < tex_indices.size(); a++) {
1634
MTex *t = ma->mtex[tex_indices[a]];
1635
Image *ima = t->tex->ima;
1637
std::string key(id_name(ima));
1638
key = translate_id(key);
1640
// create only one <sampler>/<surface> pair for each unique image
1641
if (im_samp_map.find(key) == im_samp_map.end()) {
1642
//<newparam> <surface> <init_from>
1643
// COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
1644
// key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
1645
// COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
1646
// sio.setImageReference(key);
1647
// surface.setInitOption(sio);
1649
//<newparam> <sampler> <source>
1650
COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
1651
key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
1652
key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
1653
sampler.setImageId(key);
1654
// copy values to arrays since they will live longer
1655
samplers[a] = sampler;
1656
//surfaces[a] = surface;
1658
// store pointers so they can be used later when we create <texture>s
1659
samp_surf[b][0] = &samplers[a];
1660
//samp_surf[b][1] = &surfaces[a];
1662
im_samp_map[key] = b;
1667
// used as fallback when MTex->uvname is "" (this is pretty common)
1668
// it is indeed the correct value to use in that case
1669
std::string active_uv(getActiveUVLayerName(ob));
1673
for (a = 0; a < tex_indices.size(); a++) {
1674
MTex *t = ma->mtex[tex_indices[a]];
1675
Image *ima = t->tex->ima;
1677
// we assume map input is always TEXCO_UV
1679
std::string key(id_name(ima));
1680
key = translate_id(key);
1681
int i = im_samp_map[key];
1682
COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0];
1683
//COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1];
1685
std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
1688
if (t->mapto & MAP_COL) {
1689
ep.setDiffuse(createTexture(ima, uvname, sampler));
1692
if (t->mapto & MAP_AMB) {
1693
ep.setAmbient(createTexture(ima, uvname, sampler));
1696
if (t->mapto & MAP_SPEC) {
1697
ep.setSpecular(createTexture(ima, uvname, sampler));
1700
if (t->mapto & MAP_EMIT) {
1701
ep.setEmission(createTexture(ima, uvname, sampler));
1704
if (t->mapto & MAP_REF) {
1705
ep.setReflective(createTexture(ima, uvname, sampler));
1708
if (t->mapto & MAP_ALPHA) {
1709
ep.setTransparent(createTexture(ima, uvname, sampler));
1712
// Normal map --> Must be stored with <extra> tag as different technique,
1713
// since COLLADA doesn't support normal maps, even in current COLLADA 1.5.
1714
if (t->mapto & MAP_NORM) {
1715
COLLADASW::Texture texture(key);
1716
texture.setTexcoord(uvname);
1717
texture.setSampler(*sampler);
1718
// technique FCOLLADA, with the <bump> tag, is most likely the best understood,
1719
// most widespread de-facto standard.
1720
texture.setProfileName("FCOLLADA");
1721
texture.setChildElementName("bump");
1722
#ifdef WIN32 // currently, Windows builds are using revision 746 of OpenCollada while Linux and Mac are using an older revision 721
1723
ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
1725
ep.setExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
1729
// performs the actual writing
1730
ep.addProfileElements();
1731
bool twoSided = false;
1732
if (ob->type == OB_MESH && ob->data) {
1733
Mesh *me = (Mesh*)ob->data;
1734
if (me->flag & ME_TWOSIDED)
1738
ep.addExtraTechniqueParameter("GOOGLEEARTH", "double_sided", 1);
1739
ep.addExtraTechniques(mSW);
1743
mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>");
1747
COLLADASW::ColorOrTexture createTexture(Image *ima,
1748
std::string& uv_layer_name,
1749
COLLADASW::Sampler *sampler
1750
/*COLLADASW::Surface *surface*/)
1753
COLLADASW::Texture texture(translate_id(id_name(ima)));
1754
texture.setTexcoord(uv_layer_name);
1755
//texture.setSurface(*surface);
1756
texture.setSampler(*sampler);
1758
COLLADASW::ColorOrTexture cot(texture);
1762
COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a)
1764
COLLADASW::Color color(r,g,b,a);
1765
COLLADASW::ColorOrTexture cot(color);
1769
//returns the array of mtex indices which have image
1770
//need this for exporting textures
1771
void createTextureIndices(Material *ma, std::vector<int> &indices)
1775
for (int a = 0; a < MAX_MTEX; a++) {
1777
ma->mtex[a]->tex->type == TEX_IMAGE &&
1778
ma->mtex[a]->texco == TEXCO_UV){
1779
indices.push_back(a);
1785
class MaterialsExporter: COLLADASW::LibraryMaterials
1788
MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryMaterials(sw){}
1789
void exportMaterials(Scene *sce)
1793
forEachMaterialInScene(sce, *this);
1798
void operator()(Material *ma, Object *ob)
1800
std::string name(id_name(ma));
1802
openMaterial(translate_id(name), name);
1804
std::string efid = translate_id(name) + "-effect";
1805
addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
1811
class CamerasExporter: COLLADASW::LibraryCameras
1814
CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){}
1815
void exportCameras(Scene *sce)
1819
forEachCameraObjectInScene(sce, *this);
1823
void operator()(Object *ob, Scene *sce)
1825
// XXX add other params later
1826
Camera *cam = (Camera*)ob->data;
1827
std::string cam_id(get_camera_id(ob));
1828
std::string cam_name(id_name(cam));
1830
if (cam->type == CAM_PERSP) {
1831
COLLADASW::PerspectiveOptic persp(mSW);
1833
persp.setAspectRatio(0.1);
1834
persp.setZFar(cam->clipend);
1835
persp.setZNear(cam->clipsta);
1836
COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name);
1840
COLLADASW::OrthographicOptic ortho(mSW);
1842
ortho.setAspectRatio(0.1);
1843
ortho.setZFar(cam->clipend);
1844
ortho.setZNear(cam->clipsta);
1845
COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name);
1851
class LightsExporter: COLLADASW::LibraryLights
1854
LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){}
1855
void exportLights(Scene *sce)
1859
forEachLampObjectInScene(sce, *this);
1863
void operator()(Object *ob)
1865
Lamp *la = (Lamp*)ob->data;
1866
std::string la_id(get_light_id(ob));
1867
std::string la_name(id_name(la));
1868
COLLADASW::Color col(la->r, la->g, la->b);
1869
float e = la->energy;
1872
if (la->type == LA_SUN) {
1873
COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e);
1878
else if (la->type == LA_HEMI) {
1879
COLLADASW::AmbientLight cla(mSW, la_id, la_name, e);
1884
else if (la->type == LA_SPOT) {
1885
COLLADASW::SpotLight cla(mSW, la_id, la_name, e);
1887
cla.setFallOffAngle(la->spotsize);
1888
cla.setFallOffExponent(la->spotblend);
1889
cla.setLinearAttenuation(la->att1);
1890
cla.setQuadraticAttenuation(la->att2);
1894
else if (la->type == LA_LOCAL) {
1895
COLLADASW::PointLight cla(mSW, la_id, la_name, e);
1897
cla.setLinearAttenuation(la->att1);
1898
cla.setQuadraticAttenuation(la->att2);
1901
// area lamp is not supported
1902
// it will be exported as a local lamp
1904
COLLADASW::PointLight cla(mSW, la_id, la_name, e);
1906
cla.setLinearAttenuation(la->att1);
1907
cla.setQuadraticAttenuation(la->att2);
147
DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) {}
1913
149
// TODO: it would be better to instantiate animations rather than create a new one per object
1914
150
// COLLADA allows this through multiple <channel>s in <animation>.
1915
151
// For this to work, we need to know objects that use a certain action.
1916
class AnimationExporter: COLLADASW::LibraryAnimations
1922
AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {}
1924
void exportAnimations(Scene *sce)
1930
forEachObjectInScene(sce, *this);
1935
// called for each exported object
1936
void operator() (Object *ob)
1938
if (!ob->adt || !ob->adt->action) return;
1940
FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
1942
if (ob->type == OB_ARMATURE) {
1943
if (!ob->data) return;
1945
bArmature *arm = (bArmature*)ob->data;
1946
for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
1947
write_bone_animation(ob, bone);
1951
// TODO "rotation_quaternion" is also possible for objects (although euler is default)
1952
if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
1953
(!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
1954
dae_animation(fcu, id_name(ob));
1963
void dae_animation(FCurve *fcu, std::string ob_name)
1965
const char *axis_names[] = {"X", "Y", "Z"};
1966
const char *axis_name = NULL;
1969
if (fcu->array_index < 3)
1970
axis_name = axis_names[fcu->array_index];
1972
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
1973
fcu->rna_path, axis_names[fcu->array_index]);
1975
// check rna_path is one of: rotation, scale, location
1977
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
1979
// create input source
1980
std::string input_id = create_source_from_fcurve(Sampler::INPUT, fcu, anim_id, axis_name);
1982
// create output source
1983
std::string output_id = create_source_from_fcurve(Sampler::OUTPUT, fcu, anim_id, axis_name);
1985
// create interpolations source
1986
std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
1988
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
1989
COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
1991
sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
1992
sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
1994
// this input is required
1995
sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
1997
addSampler(sampler);
1999
std::string target = translate_id(ob_name)
2000
+ "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
2001
addChannel(COLLADABU::URI(empty, sampler_id), target);
2006
void write_bone_animation(Object *ob_arm, Bone *bone)
2011
for (int i = 0; i < 3; i++)
2012
sample_and_write_bone_animation(ob_arm, bone, i);
2014
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
2015
write_bone_animation(ob_arm, child);
2018
void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
2020
bArmature *arm = (bArmature*)ob_arm->data;
2021
int flag = arm->flag;
2022
std::vector<float> fra;
2025
BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
2027
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
2031
switch (transform_type) {
2033
find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
2036
find_frames(ob_arm, fra, prefix, "scale");
2039
find_frames(ob_arm, fra, prefix, "location");
2045
// exit rest position
2046
if (flag & ARM_RESTPOS) {
2047
arm->flag &= ~ARM_RESTPOS;
2048
where_is_pose(scene, ob_arm);
2052
float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
2053
sample_animation(v, fra, transform_type, bone, ob_arm);
2055
if (transform_type == 0) {
2056
// write x, y, z curves separately if it is rotation
2057
float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
2058
for (int i = 0; i < 3; i++) {
2059
for (unsigned int j = 0; j < fra.size(); j++)
2060
c[j] = v[j * 3 + i];
2062
dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
2067
// write xyz at once if it is location or scale
2068
dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
2075
if (flag & ARM_RESTPOS)
2077
where_is_pose(scene, ob_arm);
2080
void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
2082
bPoseChannel *pchan, *parchan = NULL;
2083
bPose *pose = ob_arm->pose;
2085
pchan = get_pose_channel(pose, bone->name);
2090
parchan = pchan->parent;
2092
enable_fcurves(ob_arm->adt->action, bone->name);
2094
std::vector<float>::iterator it;
2095
for (it = frames.begin(); it != frames.end(); it++) {
2096
float mat[4][4], ipar[4][4];
2098
float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
2100
BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
2101
where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
2103
// compute bone local mat
2105
invert_m4_m4(ipar, parchan->pose_mat);
2106
mul_m4_m4m4(mat, pchan->pose_mat, ipar);
2109
copy_m4_m4(mat, pchan->pose_mat);
2113
mat4_to_eul(v, mat);
2116
mat4_to_size(v, mat);
2119
copy_v3_v3(v, mat[3]);
2126
enable_fcurves(ob_arm->adt->action, NULL);
2129
// dae_bone_animation -> add_bone_animation
2130
// (blend this into dae_bone_animation)
2131
void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
2133
const char *axis_names[] = {"X", "Y", "Z"};
2134
const char *axis_name = NULL;
2136
bool is_rot = tm_type == 0;
2142
BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
2143
tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
2146
axis_name = axis_names[axis];
2148
std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
2150
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
2151
(char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
2153
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
2155
// create input source
2156
std::string input_id = create_source_from_vector(Sampler::INPUT, fra, is_rot, anim_id, axis_name);
2158
// create output source
2159
std::string output_id;
2161
output_id = create_xyz_source(v, fra.size(), anim_id);
2163
output_id = create_source_from_array(Sampler::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
2165
// create interpolations source
2166
std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
2168
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
2169
COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
2171
sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
2172
sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
2174
// TODO create in/out tangents source
2176
// this input is required
2177
sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
2179
addSampler(sampler);
2181
std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
2182
addChannel(COLLADABU::URI(empty, sampler_id), target);
2187
float convert_time(float frame)
2189
return FRA2TIME(frame);
2192
float convert_angle(float angle)
2194
return COLLADABU::Math::Utils::radToDegF(angle);
2197
std::string get_semantic_suffix(Sampler::Semantic semantic)
2200
case Sampler::INPUT:
2201
return INPUT_SOURCE_ID_SUFFIX;
2202
case Sampler::OUTPUT:
2203
return OUTPUT_SOURCE_ID_SUFFIX;
2204
case Sampler::INTERPOLATION:
2205
return INTERPOLATION_SOURCE_ID_SUFFIX;
2206
case Sampler::IN_TANGENT:
2207
return INTANGENT_SOURCE_ID_SUFFIX;
2208
case Sampler::OUT_TANGENT:
2209
return OUTTANGENT_SOURCE_ID_SUFFIX;
2216
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
2217
Sampler::Semantic semantic, bool is_rot, const char *axis)
2220
case Sampler::INPUT:
2221
param.push_back("TIME");
2223
case Sampler::OUTPUT:
2225
param.push_back("ANGLE");
2229
param.push_back(axis);
2232
param.push_back("X");
2233
param.push_back("Y");
2234
param.push_back("Z");
2238
case Sampler::IN_TANGENT:
2239
case Sampler::OUT_TANGENT:
2240
param.push_back("X");
2241
param.push_back("Y");
2248
void get_source_values(BezTriple *bezt, Sampler::Semantic semantic, bool rotation, float *values, int *length)
2251
case Sampler::INPUT:
2253
values[0] = convert_time(bezt->vec[1][0]);
2255
case Sampler::OUTPUT:
2258
values[0] = convert_angle(bezt->vec[1][1]);
2261
values[0] = bezt->vec[1][1];
2264
case Sampler::IN_TANGENT:
2265
case Sampler::OUT_TANGENT:
2275
std::string create_source_from_fcurve(Sampler::Semantic semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
2277
std::string source_id = anim_id + get_semantic_suffix(semantic);
2279
//bool is_rotation = !strcmp(fcu->rna_path, "rotation");
2280
bool is_rotation = false;
2282
if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
2284
COLLADASW::FloatSourceF source(mSW);
2285
source.setId(source_id);
2286
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2287
source.setAccessorCount(fcu->totvert);
2288
source.setAccessorStride(1);
2290
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
2291
add_source_parameters(param, semantic, is_rotation, axis_name);
2293
source.prepareToAppendValues();
2295
for (unsigned int i = 0; i < fcu->totvert; i++) {
2296
float values[3]; // be careful!
2299
get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
2300
for (int j = 0; j < length; j++)
2301
source.appendValues(values[j]);
2309
std::string create_source_from_array(Sampler::Semantic semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
2311
std::string source_id = anim_id + get_semantic_suffix(semantic);
2313
COLLADASW::FloatSourceF source(mSW);
2314
source.setId(source_id);
2315
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2316
source.setAccessorCount(tot);
2317
source.setAccessorStride(1);
2319
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
2320
add_source_parameters(param, semantic, is_rot, axis_name);
2322
source.prepareToAppendValues();
2324
for (int i = 0; i < tot; i++) {
2326
if (semantic == Sampler::INPUT)
2327
val = convert_time(val);
2329
val = convert_angle(val);
2330
source.appendValues(val);
2338
std::string create_source_from_vector(Sampler::Semantic semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
2340
std::string source_id = anim_id + get_semantic_suffix(semantic);
2342
COLLADASW::FloatSourceF source(mSW);
2343
source.setId(source_id);
2344
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2345
source.setAccessorCount(fra.size());
2346
source.setAccessorStride(1);
2348
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
2349
add_source_parameters(param, semantic, is_rot, axis_name);
2351
source.prepareToAppendValues();
2353
std::vector<float>::iterator it;
2354
for (it = fra.begin(); it != fra.end(); it++) {
2356
if (semantic == Sampler::INPUT)
2357
val = convert_time(val);
2359
val = convert_angle(val);
2360
source.appendValues(val);
2368
// only used for sources with OUTPUT semantic
2369
std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
2371
Sampler::Semantic semantic = Sampler::OUTPUT;
2372
std::string source_id = anim_id + get_semantic_suffix(semantic);
2374
COLLADASW::FloatSourceF source(mSW);
2375
source.setId(source_id);
2376
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2377
source.setAccessorCount(tot);
2378
source.setAccessorStride(3);
2380
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
2381
add_source_parameters(param, semantic, false, NULL);
2383
source.prepareToAppendValues();
2385
for (int i = 0; i < tot; i++) {
2386
source.appendValues(*v, *(v + 1), *(v + 2));
2395
std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
2397
std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION);
2399
COLLADASW::NameSource source(mSW);
2400
source.setId(source_id);
2401
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2402
source.setAccessorCount(tot);
2403
source.setAccessorStride(1);
2405
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
2406
param.push_back("INTERPOLATION");
2408
source.prepareToAppendValues();
2410
for (int i = 0; i < tot; i++) {
2411
source.appendValues(LINEAR_NAME);
2419
// for rotation, axis name is always appended and the value of append_axis is ignored
2420
std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
2422
std::string tm_name;
2424
// when given rna_path, determine tm_type from it
2426
char *name = extract_transform_name(rna_path);
2428
if (strstr(name, "rotation"))
2430
else if (!strcmp(name, "scale"))
2432
else if (!strcmp(name, "location"))
2440
return std::string("rotation") + std::string(axis_name) + ".ANGLE";
2445
tm_name = "location";
2452
if (tm_name.size()) {
2454
return tm_name + std::string(".") + std::string(axis_name);
2459
return std::string("");
2462
char *extract_transform_name(char *rna_path)
2464
char *dot = strrchr(rna_path, '.');
2465
return dot ? (dot + 1) : rna_path;
2468
void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
2470
FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
2472
for (; fcu; fcu = fcu->next) {
2473
if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
2476
char *name = extract_transform_name(fcu->rna_path);
2477
if (!strcmp(name, tm_name)) {
2478
for (unsigned int i = 0; i < fcu->totvert; i++) {
2479
float f = fcu->bezt[i].vec[1][0];
2480
if (std::find(fra.begin(), fra.end(), f) == fra.end())
2486
// keep the keys in ascending order
2487
std::sort(fra.begin(), fra.end());
2490
void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
2493
find_frames(ob, fra, prefix, "rotation_euler");
2494
else if (rotmode == ROT_MODE_QUAT)
2495
find_frames(ob, fra, prefix, "rotation_quaternion");
2496
else if (rotmode == ROT_MODE_AXISANGLE)
2500
// enable fcurves driving a specific bone, disable all the rest
2501
// if bone_name = NULL enable all fcurves
2502
void enable_fcurves(bAction *act, char *bone_name)
2508
BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
2510
for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
2512
if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
2513
fcu->flag &= ~FCURVE_DISABLED;
2515
fcu->flag |= FCURVE_DISABLED;
2518
fcu->flag &= ~FCURVE_DISABLED;
2524
void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
153
void DocumentExporter::exportCurrentScene(Scene *sce)
155
PointerRNA sceneptr, unit_settings;
156
PropertyRNA *system; /* unused , *scale; */
158
clear_global_id_map();
2526
160
COLLADABU::NativeString native_filename =
2527
COLLADABU::NativeString(std::string(filename));
161
COLLADABU::NativeString(std::string(this->export_settings->filepath));
2528
162
COLLADASW::StreamWriter sw(native_filename);
2531
165
sw.startDocument();
2534
168
COLLADASW::Asset asset(&sw);
2535
// XXX ask blender devs about this?
2536
asset.setUnit("decimetre", 0.1);
170
RNA_id_pointer_create(&(sce->id), &sceneptr);
171
unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
172
system = RNA_struct_find_property(&unit_settings, "system");
173
//scale = RNA_struct_find_property(&unit_settings, "scale_length");
175
std::string unitname = "meter";
176
float linearmeasure = RNA_float_get(&unit_settings, "scale_length");
178
switch(RNA_property_enum_get(&unit_settings, system)) {
180
case USER_UNIT_METRIC:
181
if (linearmeasure == 0.001f) {
182
unitname = "millimeter";
184
else if (linearmeasure == 0.01f) {
185
unitname = "centimeter";
187
else if (linearmeasure == 0.1f) {
188
unitname = "decimeter";
190
else if (linearmeasure == 1.0f) {
193
else if (linearmeasure == 1000.0f) {
194
unitname = "kilometer";
197
case USER_UNIT_IMPERIAL:
198
if (linearmeasure == 0.0254f) {
201
else if (linearmeasure == 0.3048f) {
204
else if (linearmeasure == 0.9144f) {
212
asset.setUnit(unitname, linearmeasure);
2537
213
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
214
if (U.author[0] != '\0') {
215
asset.getContributor().mAuthor = U.author;
218
asset.getContributor().mAuthor = "Blender User";
220
char version_buf[128];
221
#ifdef WITH_BUILDINFO
222
sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
224
sprintf(version_buf, "Blender %d.%02d.%d", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION);
226
asset.getContributor().mAuthoringTool = version_buf;
2540
229
// <library_cameras>
2541
CamerasExporter ce(&sw);
2542
ce.exportCameras(sce);
230
if (has_object_type(sce, OB_CAMERA)) {
231
CamerasExporter ce(&sw, this->export_settings);
232
ce.exportCameras(sce);
2544
235
// <library_lights>
2545
LightsExporter le(&sw);
2546
le.exportLights(sce);
236
if (has_object_type(sce, OB_LAMP)) {
237
LightsExporter le(&sw, this->export_settings);
238
le.exportLights(sce);
2548
241
// <library_images>
2549
ImagesExporter ie(&sw, filename);
242
ImagesExporter ie(&sw, this->export_settings);
2550
243
ie.exportImages(sce);
2552
245
// <library_effects>
2553
EffectsExporter ee(&sw);
246
EffectsExporter ee(&sw, this->export_settings);
2554
247
ee.exportEffects(sce);
2556
249
// <library_materials>
2557
MaterialsExporter me(&sw);
250
MaterialsExporter me(&sw, this->export_settings);
2558
251
me.exportMaterials(sce);
2560
253
// <library_geometries>
2561
GeometryExporter ge(&sw);
254
if (has_object_type(sce, OB_MESH)) {
255
GeometryExporter ge(&sw, this->export_settings);
2564
259
// <library_animations>
2565
AnimationExporter ae(&sw);
260
AnimationExporter ae(&sw, this->export_settings);
2566
261
ae.exportAnimations(sce);
2568
263
// <library_controllers>
2569
ArmatureExporter arm_exporter(&sw);
2570
arm_exporter.export_controllers(sce);
264
ArmatureExporter arm_exporter(&sw, this->export_settings);
265
if (has_object_type(sce, OB_ARMATURE)) {
266
arm_exporter.export_controllers(sce);
2572
269
// <library_visual_scenes>
2573
SceneExporter se(&sw, &arm_exporter);
270
SceneExporter se(&sw, &arm_exporter, this->export_settings);
2574
271
se.exportScene(sce);