Collada exporter update
[blender.git] / source / blender / collada / BCSampleData.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  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 #include "BCSampleData.h"
21 #include "collada_utils.h"
22
23 BCSample::~BCSample()
24 {
25   BCBoneMatrixMap::iterator it;
26   for (it = bonemats.begin(); it != bonemats.end(); ++it) {
27     delete it->second;
28   }
29 }
30
31 void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
32 {
33   BCMatrix *matrix;
34   BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
35   if (it != bonemats.end()) {
36     throw std::invalid_argument("bone " + std::string(bone->name) + " already defined before");
37   }
38   matrix = new BCMatrix(mat);
39   bonemats[bone] = matrix;
40 }
41
42 BCMatrix::BCMatrix(const BCMatrix &mat)
43 {
44   set_transform(mat.matrix);
45 }
46
47 BCMatrix::BCMatrix(Matrix &mat)
48 {
49   set_transform(mat);
50 }
51
52 BCMatrix::BCMatrix(Object *ob)
53 {
54   set_transform(ob);
55 }
56
57 BCMatrix::BCMatrix()
58 {
59   unit();
60 }
61
62 BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis global_up_axis)
63 {
64   float mrot[3][3];
65   float mat[4][4];
66   mat3_from_axis_conversion(
67       BC_DEFAULT_FORWARD, BC_DEFAULT_UP, global_forward_axis, global_up_axis, mrot);
68
69   transpose_m3(mrot); // TODO: Verify that mat3_from_axis_conversion() returns a transposed matrix
70   copy_m4_m3(mat, mrot);
71   set_transform(mat);
72 }
73
74 void BCMatrix::add_transform(const Matrix &mat, bool inverse)
75 {
76   add_transform(this->matrix, mat, this->matrix, inverse);
77 }
78
79 void BCMatrix::add_transform(const BCMatrix &mat, bool inverse)
80 {
81   add_transform(this->matrix, mat.matrix, this->matrix, inverse);
82 }
83
84 void BCMatrix::apply_transform(const BCMatrix &mat, bool inverse)
85 {
86   apply_transform(this->matrix, mat.matrix, this->matrix, inverse);
87 }
88
89 void BCMatrix::add_transform(Matrix &to, const Matrix &transform, const Matrix &from, bool inverse)
90 {
91   if (inverse) {
92     Matrix globinv;
93     invert_m4_m4(globinv, transform);
94     add_transform(to, globinv, from, /*inverse=*/false);
95   }
96   else {
97     mul_m4_m4m4(to, transform, from);
98   }
99 }
100
101 void BCMatrix::apply_transform(Matrix &to, const Matrix &transform, const Matrix &from, bool inverse)
102 {
103   Matrix globinv;
104   invert_m4_m4(globinv, transform);
105   if (inverse) {
106     add_transform(to, globinv, from, /*inverse=*/false);
107   }
108   else {
109     mul_m4_m4m4(to, transform, from);
110     mul_m4_m4m4(to, to, globinv);
111   }
112 }
113
114 void BCMatrix::add_inverted_transform(Matrix &to, const Matrix &transform, const Matrix &from)
115 {
116   Matrix workmat;
117   invert_m4_m4(workmat, transform);
118   mul_m4_m4m4(to, workmat, from);
119 }
120
121 void BCMatrix::set_transform(Object *ob)
122 {
123   Matrix lmat;
124
125   BKE_object_matrix_local_get(ob, lmat);
126   copy_m4_m4(matrix, lmat);
127
128   mat4_decompose(this->loc, this->q, this->size, lmat);
129   quat_to_compatible_eul(this->rot, ob->rot, this->q);
130 }
131
132 void BCMatrix::set_transform(Matrix &mat)
133 {
134   copy_m4_m4(matrix, mat);
135   mat4_decompose(this->loc, this->q, this->size, mat);
136   quat_to_eul(this->rot, this->q);
137 }
138
139 const BCMatrix *BCSample::get_matrix(Bone *bone) const
140 {
141   BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
142   if (it == bonemats.end()) {
143     return NULL;
144   }
145   return it->second;
146 }
147
148 const BCMatrix &BCSample::get_matrix() const
149 {
150   return obmat;
151 }
152
153 /* Get channel value */
154 const bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
155 {
156   if (channel_target == "location") {
157     *val = obmat.location()[array_index];
158   }
159   else if (channel_target == "scale") {
160     *val = obmat.scale()[array_index];
161   }
162   else if (channel_target == "rotation" || channel_target == "rotation_euler") {
163     *val = obmat.rotation()[array_index];
164   }
165   else if (channel_target == "rotation_quat") {
166     *val = obmat.quat()[array_index];
167   }
168   else {
169     *val = 0;
170     return false;
171   }
172
173   return true;
174 }
175
176 void BCMatrix::copy(Matrix &out, Matrix &in)
177 {
178   /* destination comes first: */
179   memcpy(out, in, sizeof(Matrix));
180 }
181
182 void BCMatrix::transpose(Matrix &mat)
183 {
184   transpose_m4(mat);
185 }
186
187 void BCMatrix::sanitize(Matrix &mat, int precision)
188 {
189   bc_sanitize_mat(mat, precision);
190 }
191
192 void BCMatrix::unit()
193 {
194   unit_m4(this->matrix);
195   mat4_decompose(this->loc, this->q, this->size, this->matrix);
196   quat_to_eul(this->rot, this->q);
197 }
198
199 /* We need double here because the OpenCollada API needs it.
200  * precision = -1 indicates to not limit the precision. */
201 void BCMatrix::get_matrix(DMatrix &mat, const bool transposed, const int precision) const
202 {
203   for (int i = 0; i < 4; i++)
204     for (int j = 0; j < 4; j++) {
205       float val = (transposed) ? matrix[j][i] : matrix[i][j];
206       if (precision >= 0)
207         val = floor((val * pow(10, precision) + 0.5)) / pow(10, precision);
208       mat[i][j] = val;
209     }
210 }
211
212 void BCMatrix::get_matrix(Matrix &mat,
213                           const bool transposed,
214                           const int precision,
215                           const bool inverted) const
216 {
217   for (int i = 0; i < 4; i++)
218     for (int j = 0; j < 4; j++) {
219       float val = (transposed) ? matrix[j][i] : matrix[i][j];
220       if (precision >= 0)
221         val = floor((val * pow(10, precision) + 0.5)) / pow(10, precision);
222       mat[i][j] = val;
223     }
224
225   if (inverted) {
226     invert_m4(mat);
227   }
228 }
229
230 const bool BCMatrix::in_range(const BCMatrix &other, float distance) const
231 {
232   for (int i = 0; i < 4; i++) {
233     for (int j = 0; j < 4; j++) {
234       if (fabs(other.matrix[i][j] - matrix[i][j]) > distance) {
235         return false;
236       }
237     }
238   }
239   return true;
240 }
241
242 float (&BCMatrix::location() const)[3]
243 {
244   return loc;
245 }
246
247 float (&BCMatrix::rotation() const)[3]
248 {
249   return rot;
250 }
251
252 float (&BCMatrix::scale() const)[3]
253 {
254   return size;
255 }
256
257 float (&BCMatrix::quat() const)[4]
258 {
259   return q;
260 }