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
18  * \ingroup collada
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 float (&UnitConverter::get_scale())[4][4]
118 {
119   return scale_mat4;
120 }
121
122 void UnitConverter::calculate_scale(Scene &sce)
123 {
124   PointerRNA scene_ptr, unit_settings;
125   PropertyRNA *system_ptr, *scale_ptr;
126   RNA_id_pointer_create(&sce.id, &scene_ptr);
127
128   unit_settings = RNA_pointer_get(&scene_ptr, "unit_settings");
129   system_ptr = RNA_struct_find_property(&unit_settings, "system");
130   scale_ptr = RNA_struct_find_property(&unit_settings, "scale_length");
131
132   int type = RNA_property_enum_get(&unit_settings, system_ptr);
133
134   float bl_scale;
135
136   switch (type) {
137     case USER_UNIT_NONE:
138       bl_scale = 1.0;  // map 1 Blender unit to 1 Meter
139       break;
140
141     case USER_UNIT_METRIC:
142       bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
143       break;
144
145     default:
146       bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
147       // it looks like the conversion to Imperial is done implicitly.
148       // So nothing to do here.
149       break;
150   }
151
152   float rescale[3];
153   rescale[0] = rescale[1] = rescale[2] = getLinearMeter() / bl_scale;
154
155   size_to_mat4(scale_mat4, rescale);
156 }
157
158 /**
159  * Translation map.
160  * Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
161  * included. Look at the IDREF XSD declaration for more.
162  * Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars,
163  * like special chars (e.g. micro sign), umlauts and so on.
164  * The COLLADA spec also allows additional chars for member access ('.'), these
165  * must obviously be removed too, otherwise they would be heavily misinterpreted.
166  */
167 const unsigned char translate_start_name_map[256] = {
168
169     95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,
170     95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,
171     95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,
172     95,  95,  95,  95,  95,  95,  95,  95,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
173     76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  95,  95,  95,  95,
174     95,  95,  97,  98,  99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
175     114, 115, 116, 117, 118, 119, 120, 121, 122, 95,  95,  95,  95,  95,
176
177     128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
178     147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
179     166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
180     185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
181     204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
182     223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
183     242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
184 };
185
186 const unsigned char translate_name_map[256] = {
187
188     95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,
189     95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,
190     95,  95,  95,  95,  95,  95,  95,  45,  95,  95,  48,  49,  50,  51,  52,  53,  54,  55,  56,
191     57,  95,  95,  95,  95,  95,  95,  95,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
192     76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  95,  95,  95,  95,
193     95,  95,  97,  98,  99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
194     114, 115, 116, 117, 118, 119, 120, 121, 122, 95,  95,  95,  95,  95,
195
196     128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
197     147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
198     166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
199     185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
200     204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
201     223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
202     242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
203 };
204
205 typedef std::map<std::string, std::vector<std::string>> map_string_list;
206 map_string_list global_id_map;
207
208 void clear_global_id_map()
209 {
210   global_id_map.clear();
211 }
212
213 /** Look at documentation of translate_map */
214 std::string translate_id(const char *idString)
215 {
216   std::string id = std::string(idString);
217   return translate_id(id);
218 }
219
220 std::string translate_id(const std::string &id)
221 {
222   if (id.size() == 0) {
223     return id;
224   }
225
226   std::string id_translated = id;
227   id_translated[0] = translate_start_name_map[(unsigned int)id_translated[0]];
228   for (unsigned int i = 1; i < id_translated.size(); i++) {
229     id_translated[i] = translate_name_map[(unsigned int)id_translated[i]];
230   }
231   // It's so much workload now, the if () should speed up things.
232   if (id_translated != id) {
233     // Search duplicates
234     map_string_list::iterator iter = global_id_map.find(id_translated);
235     if (iter != global_id_map.end()) {
236       unsigned int i = 0;
237       bool found = false;
238       for (i = 0; i < iter->second.size(); i++) {
239         if (id == iter->second[i]) {
240           found = true;
241           break;
242         }
243       }
244       bool convert = false;
245       if (found) {
246         if (i > 0) {
247           convert = true;
248         }
249       }
250       else {
251         convert = true;
252         global_id_map[id_translated].push_back(id);
253       }
254       if (convert) {
255         std::stringstream out;
256         out << ++i;
257         id_translated += out.str();
258       }
259     }
260     else {
261       global_id_map[id_translated].push_back(id);
262     }
263   }
264   return id_translated;
265 }
266
267 std::string id_name(void *id)
268 {
269   return ((ID *)id)->name + 2;
270 }
271
272 std::string encode_xml(std::string xml)
273 {
274   const std::map<char, std::string> escape{
275       {'<', "&lt;"}, {'>', "&gt;"}, {'"', "&quot;"}, {'\'', "&apos;"}, {'&', "&amp;"}};
276
277   std::map<char, std::string>::const_iterator it;
278   std::string encoded_xml = "";
279
280   for (unsigned int i = 0; i < xml.size(); i++) {
281     char c = xml.at(i);
282     it = escape.find(c);
283
284     if (it == escape.end()) {
285       encoded_xml += c;
286     }
287     else {
288       encoded_xml += it->second;
289     }
290   }
291   return encoded_xml;
292 }
293
294 std::string get_geometry_id(Object *ob)
295 {
296   return translate_id(id_name(ob->data)) + "-mesh";
297 }
298
299 std::string get_geometry_id(Object *ob, bool use_instantiation)
300 {
301   std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
302
303   return translate_id(geom_name) + "-mesh";
304 }
305
306 std::string get_light_id(Object *ob)
307 {
308   return translate_id(id_name(ob)) + "-light";
309 }
310
311 std::string get_joint_sid(Bone *bone)
312 {
313   return translate_id(bone->name);
314 }
315 std::string get_joint_sid(EditBone *bone)
316 {
317   return translate_id(bone->name);
318 }
319
320 std::string get_camera_id(Object *ob)
321 {
322   return translate_id(id_name(ob)) + "-camera";
323 }
324
325 std::string get_effect_id(Material *mat)
326 {
327   return translate_id(id_name(mat)) + "-effect";
328 }
329
330 std::string get_material_id(Material *mat)
331 {
332   return translate_id(id_name(mat)) + "-material";
333 }
334
335 std::string get_morph_id(Object *ob)
336 {
337   return translate_id(id_name(ob)) + "-morph";
338 }