Merge branch 'blender2.7'
[blender.git] / source / blender / collada / collada_internal.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file \ingroup collada
18  */
19
20
21 /* COLLADABU_ASSERT, may be able to remove later */
22 #include "COLLADABUPlatform.h"
23 #include "collada_utils.h"
24
25 #include "BLI_linklist.h"
26 #include "ED_armature.h"
27
28 UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP)
29 {
30         axis_angle_to_mat4_single(x_up_mat4, 'Y', -0.5 * M_PI);
31         axis_angle_to_mat4_single(y_up_mat4, 'X', 0.5 * M_PI);
32
33         unit_m4(z_up_mat4);
34         unit_m4(scale_mat4);
35 }
36
37 void UnitConverter::read_asset(const COLLADAFW::FileInfo *asset)
38 {
39         unit = asset->getUnit();
40         up_axis = asset->getUpAxisType();
41 }
42
43 UnitConverter::UnitSystem UnitConverter::isMetricSystem()
44 {
45         switch (unit.getLinearUnitUnit()) {
46                 case COLLADAFW::FileInfo::Unit::MILLIMETER:
47                 case COLLADAFW::FileInfo::Unit::CENTIMETER:
48                 case COLLADAFW::FileInfo::Unit::DECIMETER:
49                 case COLLADAFW::FileInfo::Unit::METER:
50                 case COLLADAFW::FileInfo::Unit::KILOMETER:
51                         return UnitConverter::Metric;
52                 case COLLADAFW::FileInfo::Unit::INCH:
53                 case COLLADAFW::FileInfo::Unit::FOOT:
54                 case COLLADAFW::FileInfo::Unit::YARD:
55                         return UnitConverter::Imperial;
56                 default:
57                         return UnitConverter::None;
58         }
59 }
60
61 float UnitConverter::getLinearMeter()
62 {
63         return (float)unit.getLinearUnitMeter();
64 }
65
66 void UnitConverter::convertVector3(COLLADABU::Math::Vector3 &vec, float *v)
67 {
68         v[0] = vec.x;
69         v[1] = vec.y;
70         v[2] = vec.z;
71 }
72
73 // TODO need also for angle conversion, time conversion...
74
75 void UnitConverter::dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in)
76 {
77         // in DAE, matrices use columns vectors, (see comments in COLLADABUMathMatrix4.h)
78         // so here, to make a blender matrix, we swap columns and rows
79         for (int i = 0; i < 4; i++) {
80                 for (int j = 0; j < 4; j++) {
81                         out[i][j] = in[j][i];
82                 }
83         }
84 }
85
86 void UnitConverter::mat4_to_dae(float out[4][4], float in[4][4])
87 {
88         transpose_m4_m4(out, in);
89 }
90
91 void UnitConverter::mat4_to_dae_double(double out[4][4], float in[4][4])
92 {
93         float mat[4][4];
94
95         mat4_to_dae(mat, in);
96
97         for (int i = 0; i < 4; i++)
98                 for (int j = 0; j < 4; j++)
99                         out[i][j] = mat[i][j];
100 }
101
102 float(&UnitConverter::get_rotation())[4][4]
103 {
104         switch (up_axis) {
105                 case COLLADAFW::FileInfo::X_UP:
106                         return x_up_mat4;
107                         break;
108                 case COLLADAFW::FileInfo::Y_UP:
109                         return y_up_mat4;
110                         break;
111                 default:
112                         return z_up_mat4;
113                         break;
114         }
115 }
116
117
118 float(&UnitConverter::get_scale())[4][4]
119 {
120         return scale_mat4;
121 }
122
123 void UnitConverter::calculate_scale(Scene &sce)
124 {
125         PointerRNA scene_ptr, unit_settings;
126         PropertyRNA *system_ptr, *scale_ptr;
127         RNA_id_pointer_create(&sce.id, &scene_ptr);
128
129         unit_settings = RNA_pointer_get(&scene_ptr, "unit_settings");
130         system_ptr    = RNA_struct_find_property(&unit_settings, "system");
131         scale_ptr     = RNA_struct_find_property(&unit_settings, "scale_length");
132
133         int   type    = RNA_property_enum_get(&unit_settings, system_ptr);
134
135         float bl_scale;
136
137         switch (type) {
138                 case USER_UNIT_NONE:
139                         bl_scale = 1.0; // map 1 Blender unit to 1 Meter
140                         break;
141
142                 case USER_UNIT_METRIC:
143                         bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
144                         break;
145
146                 default :
147                         bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
148                         // it looks like the conversion to Imperial is done implicitly.
149                         // So nothing to do here.
150                         break;
151         }
152
153         float rescale[3];
154         rescale[0] = rescale[1] = rescale[2] = getLinearMeter() / bl_scale;
155
156         size_to_mat4(scale_mat4, rescale);
157 }
158
159 /**
160  * Translation map.
161  * Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
162  * included. Look at the IDREF XSD declaration for more.
163  * Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars,
164  * like special chars (e.g. micro sign), umlauts and so on.
165  * The COLLADA spec also allows additional chars for member access ('.'), these
166  * must obviously be removed too, otherwise they would be heavily misinterpreted.
167  */
168 const unsigned char translate_start_name_map[256] = {
169
170         95, 95, 95, 95, 95, 95, 95, 95,
171         95, 95, 95, 95, 95, 95, 95, 95,
172         95, 95, 95, 95, 95, 95, 95, 95,
173         95, 95, 95, 95, 95, 95, 95, 95,
174         95, 95, 95, 95, 95, 95, 95, 95,
175         95, 95, 95, 95, 95, 95, 95, 95,
176         95, 95, 95, 95, 95, 95, 95, 95,
177         95, 95, 95, 95, 95, 95, 95, 95,
178         95, 65, 66, 67, 68, 69, 70, 71,
179         72, 73, 74, 75, 76, 77, 78, 79,
180         80, 81, 82, 83, 84, 85, 86, 87,
181         88, 89, 90, 95, 95, 95, 95, 95,
182         95, 97, 98, 99, 100, 101, 102, 103,
183         104, 105, 106, 107, 108, 109, 110, 111,
184         112, 113, 114, 115, 116, 117, 118, 119,
185         120, 121, 122, 95, 95, 95, 95, 95,
186
187         128, 129, 130, 131, 132, 133, 134, 135,
188         136, 137, 138, 139, 140, 141, 142, 143,
189         144, 145, 146, 147, 148, 149, 150, 151,
190         152, 153, 154, 155, 156, 157, 158, 159,
191         160, 161, 162, 163, 164, 165, 166, 167,
192         168, 169, 170, 171, 172, 173, 174, 175,
193         176, 177, 178, 179, 180, 181, 182, 183,
194         184, 185, 186, 187, 188, 189, 190, 191,
195         192, 193, 194, 195, 196, 197, 198, 199,
196         200, 201, 202, 203, 204, 205, 206, 207,
197         208, 209, 210, 211, 212, 213, 214, 215,
198         216, 217, 218, 219, 220, 221, 222, 223,
199         224, 225, 226, 227, 228, 229, 230, 231,
200         232, 233, 234, 235, 236, 237, 238, 239,
201         240, 241, 242, 243, 244, 245, 246, 247,
202         248, 249, 250, 251, 252, 253, 254, 255,
203 };
204
205 const unsigned char translate_name_map[256] = {
206
207         95, 95, 95, 95, 95, 95, 95, 95,
208         95, 95, 95, 95, 95, 95, 95, 95,
209         95, 95, 95, 95, 95, 95, 95, 95,
210         95, 95, 95, 95, 95, 95, 95, 95,
211         95, 95, 95, 95, 95, 95, 95, 95,
212         95, 95, 95, 95, 95, 45, 95, 95,
213         48, 49, 50, 51, 52, 53, 54, 55,
214         56, 57, 95, 95, 95, 95, 95, 95,
215         95, 65, 66, 67, 68, 69, 70, 71,
216         72, 73, 74, 75, 76, 77, 78, 79,
217         80, 81, 82, 83, 84, 85, 86, 87,
218         88, 89, 90, 95, 95, 95, 95, 95,
219         95, 97, 98, 99, 100, 101, 102, 103,
220         104, 105, 106, 107, 108, 109, 110, 111,
221         112, 113, 114, 115, 116, 117, 118, 119,
222         120, 121, 122, 95, 95, 95, 95, 95,
223
224         128, 129, 130, 131, 132, 133, 134, 135,
225         136, 137, 138, 139, 140, 141, 142, 143,
226         144, 145, 146, 147, 148, 149, 150, 151,
227         152, 153, 154, 155, 156, 157, 158, 159,
228         160, 161, 162, 163, 164, 165, 166, 167,
229         168, 169, 170, 171, 172, 173, 174, 175,
230         176, 177, 178, 179, 180, 181, 182, 183,
231         184, 185, 186, 187, 188, 189, 190, 191,
232         192, 193, 194, 195, 196, 197, 198, 199,
233         200, 201, 202, 203, 204, 205, 206, 207,
234         208, 209, 210, 211, 212, 213, 214, 215,
235         216, 217, 218, 219, 220, 221, 222, 223,
236         224, 225, 226, 227, 228, 229, 230, 231,
237         232, 233, 234, 235, 236, 237, 238, 239,
238         240, 241, 242, 243, 244, 245, 246, 247,
239         248, 249, 250, 251, 252, 253, 254, 255,
240 };
241
242 typedef std::map< std::string, std::vector<std::string> > map_string_list;
243 map_string_list global_id_map;
244
245 void clear_global_id_map()
246 {
247         global_id_map.clear();
248 }
249
250 /** Look at documentation of translate_map */
251 std::string translate_id(const char *idString)
252 {
253         std::string id = std::string(idString);
254         return translate_id(id);
255 }
256
257 std::string translate_id(const std::string &id)
258 {
259         if (id.size() == 0) {
260                 return id;
261         }
262
263         std::string id_translated = id;
264         id_translated[0] = translate_start_name_map[(unsigned int)id_translated[0]];
265         for (unsigned int i = 1; i < id_translated.size(); i++) {
266                 id_translated[i] = translate_name_map[(unsigned int)id_translated[i]];
267         }
268         // It's so much workload now, the if () should speed up things.
269         if (id_translated != id) {
270                 // Search duplicates
271                 map_string_list::iterator iter = global_id_map.find(id_translated);
272                 if (iter != global_id_map.end()) {
273                         unsigned int i = 0;
274                         bool found = false;
275                         for (i = 0; i < iter->second.size(); i++) {
276                                 if (id == iter->second[i]) {
277                                         found = true;
278                                         break;
279                                 }
280                         }
281                         bool convert = false;
282                         if (found) {
283                                 if (i > 0) {
284                                         convert = true;
285                                 }
286                         }
287                         else {
288                                 convert = true;
289                                 global_id_map[id_translated].push_back(id);
290                         }
291                         if (convert) {
292                                 std::stringstream out;
293                                 out << ++i;
294                                 id_translated += out.str();
295                         }
296                 }
297                 else { global_id_map[id_translated].push_back(id); }
298         }
299         return id_translated;
300 }
301
302 std::string id_name(void *id)
303 {
304         return ((ID *)id)->name + 2;
305 }
306
307 std::string encode_xml(std::string xml)
308 {
309         const std::map<char, std::string> escape {
310                 {'<' , "&lt;"  },
311                 {'>' , "&gt;"  },
312                 {'"' , "&quot;"},
313                 {'\'', "&apos;"},
314                 {'&' , "&amp;" }
315         };
316
317         std::map<char, std::string>::const_iterator it;
318         std::string encoded_xml = "";
319
320         for (unsigned int i = 0; i < xml.size(); i++) {
321                 char c = xml.at(i);
322                 it = escape.find(c);
323
324                 if (it == escape.end()) {
325                         encoded_xml += c;
326                 }
327                 else {
328                         encoded_xml += it->second;
329                 }
330         }
331         return encoded_xml;
332 }
333
334 std::string get_geometry_id(Object *ob)
335 {
336         return translate_id(id_name(ob->data)) + "-mesh";
337 }
338
339 std::string get_geometry_id(Object *ob, bool use_instantiation)
340 {
341         std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
342
343         return translate_id(geom_name) + "-mesh";
344 }
345
346 std::string get_light_id(Object *ob)
347 {
348         return translate_id(id_name(ob)) + "-light";
349 }
350
351 std::string get_joint_sid(Bone *bone)
352 {
353         return translate_id(bone->name);
354 }
355 std::string get_joint_sid(EditBone *bone)
356 {
357         return translate_id(bone->name);
358 }
359
360 std::string get_camera_id(Object *ob)
361 {
362         return translate_id(id_name(ob)) + "-camera";
363 }
364
365 std::string get_effect_id(Material *mat)
366 {
367         return translate_id(id_name(mat)) + "-effect";
368 }
369
370 std::string get_material_id(Material *mat)
371 {
372         return translate_id(id_name(mat)) + "-material";
373 }
374
375 std::string get_morph_id(Object *ob)
376 {
377         return translate_id(id_name(ob)) + "-morph";
378 }