]> icculus.org git repositories - divverent/darkplaces.git/blob - matrixlib.c
fixed CL_SendMove packet rate limiting to not have a heartattack when going from...
[divverent/darkplaces.git] / matrixlib.c
1
2 #include <math.h>
3 #include "matrixlib.h"
4
5 const matrix4x4_t identitymatrix =
6 {
7         {
8                 {1, 0, 0, 0},
9                 {0, 1, 0, 0},
10                 {0, 0, 1, 0},
11                 {0, 0, 0, 1}
12         }
13 };
14
15 void Matrix4x4_Copy (matrix4x4_t *out, const matrix4x4_t *in)
16 {
17         *out = *in;
18 }
19
20 void Matrix4x4_CopyRotateOnly (matrix4x4_t *out, const matrix4x4_t *in)
21 {
22         out->m[0][0] = in->m[0][0];
23         out->m[0][1] = in->m[0][1];
24         out->m[0][2] = in->m[0][2];
25         out->m[0][3] = 0.0f;
26         out->m[1][0] = in->m[1][0];
27         out->m[1][1] = in->m[1][1];
28         out->m[1][2] = in->m[1][2];
29         out->m[1][3] = 0.0f;
30         out->m[2][0] = in->m[2][0];
31         out->m[2][1] = in->m[2][1];
32         out->m[2][2] = in->m[2][2];
33         out->m[2][3] = 0.0f;
34         out->m[3][0] = 0.0f;
35         out->m[3][1] = 0.0f;
36         out->m[3][2] = 0.0f;
37         out->m[3][3] = 1.0f;
38 }
39
40 void Matrix4x4_CopyTranslateOnly (matrix4x4_t *out, const matrix4x4_t *in)
41 {
42         out->m[0][0] = 0.0f;
43         out->m[0][1] = 0.0f;
44         out->m[0][2] = 0.0f;
45         out->m[0][3] = in->m[0][3];
46         out->m[1][0] = 0.0f;
47         out->m[1][1] = 0.0f;
48         out->m[1][2] = 0.0f;
49         out->m[1][3] = in->m[1][3];
50         out->m[2][0] = 0.0f;
51         out->m[2][1] = 0.0f;
52         out->m[2][2] = 0.0f;
53         out->m[2][3] = in->m[2][3];
54         out->m[3][0] = 0.0f;
55         out->m[3][1] = 0.0f;
56         out->m[3][2] = 0.0f;
57         out->m[3][3] = 1.0f;
58 }
59
60 void Matrix4x4_Concat (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2)
61 {
62         out->m[0][0] = in1->m[0][0] * in2->m[0][0] + in1->m[0][1] * in2->m[1][0] + in1->m[0][2] * in2->m[2][0] + in1->m[0][3] * in2->m[3][0];
63         out->m[0][1] = in1->m[0][0] * in2->m[0][1] + in1->m[0][1] * in2->m[1][1] + in1->m[0][2] * in2->m[2][1] + in1->m[0][3] * in2->m[3][1];
64         out->m[0][2] = in1->m[0][0] * in2->m[0][2] + in1->m[0][1] * in2->m[1][2] + in1->m[0][2] * in2->m[2][2] + in1->m[0][3] * in2->m[3][2];
65         out->m[0][3] = in1->m[0][0] * in2->m[0][3] + in1->m[0][1] * in2->m[1][3] + in1->m[0][2] * in2->m[2][3] + in1->m[0][3] * in2->m[3][3];
66         out->m[1][0] = in1->m[1][0] * in2->m[0][0] + in1->m[1][1] * in2->m[1][0] + in1->m[1][2] * in2->m[2][0] + in1->m[1][3] * in2->m[3][0];
67         out->m[1][1] = in1->m[1][0] * in2->m[0][1] + in1->m[1][1] * in2->m[1][1] + in1->m[1][2] * in2->m[2][1] + in1->m[1][3] * in2->m[3][1];
68         out->m[1][2] = in1->m[1][0] * in2->m[0][2] + in1->m[1][1] * in2->m[1][2] + in1->m[1][2] * in2->m[2][2] + in1->m[1][3] * in2->m[3][2];
69         out->m[1][3] = in1->m[1][0] * in2->m[0][3] + in1->m[1][1] * in2->m[1][3] + in1->m[1][2] * in2->m[2][3] + in1->m[1][3] * in2->m[3][3];
70         out->m[2][0] = in1->m[2][0] * in2->m[0][0] + in1->m[2][1] * in2->m[1][0] + in1->m[2][2] * in2->m[2][0] + in1->m[2][3] * in2->m[3][0];
71         out->m[2][1] = in1->m[2][0] * in2->m[0][1] + in1->m[2][1] * in2->m[1][1] + in1->m[2][2] * in2->m[2][1] + in1->m[2][3] * in2->m[3][1];
72         out->m[2][2] = in1->m[2][0] * in2->m[0][2] + in1->m[2][1] * in2->m[1][2] + in1->m[2][2] * in2->m[2][2] + in1->m[2][3] * in2->m[3][2];
73         out->m[2][3] = in1->m[2][0] * in2->m[0][3] + in1->m[2][1] * in2->m[1][3] + in1->m[2][2] * in2->m[2][3] + in1->m[2][3] * in2->m[3][3];
74         out->m[3][0] = in1->m[3][0] * in2->m[0][0] + in1->m[3][1] * in2->m[1][0] + in1->m[3][2] * in2->m[2][0] + in1->m[3][3] * in2->m[3][0];
75         out->m[3][1] = in1->m[3][0] * in2->m[0][1] + in1->m[3][1] * in2->m[1][1] + in1->m[3][2] * in2->m[2][1] + in1->m[3][3] * in2->m[3][1];
76         out->m[3][2] = in1->m[3][0] * in2->m[0][2] + in1->m[3][1] * in2->m[1][2] + in1->m[3][2] * in2->m[2][2] + in1->m[3][3] * in2->m[3][2];
77         out->m[3][3] = in1->m[3][0] * in2->m[0][3] + in1->m[3][1] * in2->m[1][3] + in1->m[3][2] * in2->m[2][3] + in1->m[3][3] * in2->m[3][3];
78 }
79
80 void Matrix4x4_Transpose (matrix4x4_t *out, const matrix4x4_t *in1)
81 {
82         out->m[0][0] = in1->m[0][0];
83         out->m[0][1] = in1->m[1][0];
84         out->m[0][2] = in1->m[2][0];
85         out->m[0][3] = in1->m[3][0];
86         out->m[1][0] = in1->m[0][1];
87         out->m[1][1] = in1->m[1][1];
88         out->m[1][2] = in1->m[2][1];
89         out->m[1][3] = in1->m[3][1];
90         out->m[2][0] = in1->m[0][2];
91         out->m[2][1] = in1->m[1][2];
92         out->m[2][2] = in1->m[2][2];
93         out->m[2][3] = in1->m[3][2];
94         out->m[3][0] = in1->m[0][3];
95         out->m[3][1] = in1->m[1][3];
96         out->m[3][2] = in1->m[2][3];
97         out->m[3][3] = in1->m[3][3];
98 }
99
100 void Matrix4x4_Transpose3x3 (matrix4x4_t *out, const matrix4x4_t *in1)
101 {
102         out->m[0][0] = in1->m[0][0];
103         out->m[0][1] = in1->m[1][0];
104         out->m[0][2] = in1->m[2][0];
105         out->m[1][0] = in1->m[0][1];
106         out->m[1][1] = in1->m[1][1];
107         out->m[1][2] = in1->m[2][1];
108         out->m[2][0] = in1->m[0][2];
109         out->m[2][1] = in1->m[1][2];
110         out->m[2][2] = in1->m[2][2];
111
112         out->m[0][3] = in1->m[0][3];
113         out->m[1][3] = in1->m[1][3];
114         out->m[2][3] = in1->m[2][3];
115         out->m[3][0] = in1->m[0][3];
116         out->m[3][1] = in1->m[1][3];
117         out->m[3][2] = in1->m[2][3];
118         out->m[3][3] = in1->m[3][3];
119 }
120
121 void Matrix4x4_Invert_Simple (matrix4x4_t *out, const matrix4x4_t *in1)
122 {
123         // we only support uniform scaling, so assume the first row is enough
124         // (note the lack of sqrt here, because we're trying to undo the scaling,
125         // this means multiplying by the inverse scale twice - squaring it, which
126         // makes the sqrt a waste of time)
127 #if 1
128         double scale = 1.0 / (in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]);
129 #else
130         double scale = 3.0 / sqrt
131                  (in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]
132                 + in1->m[1][0] * in1->m[1][0] + in1->m[1][1] * in1->m[1][1] + in1->m[1][2] * in1->m[1][2]
133                 + in1->m[2][0] * in1->m[2][0] + in1->m[2][1] * in1->m[2][1] + in1->m[2][2] * in1->m[2][2]);
134         scale *= scale;
135 #endif
136
137         // invert the rotation by transposing and multiplying by the squared
138         // recipricol of the input matrix scale as described above
139         out->m[0][0] = (float)(in1->m[0][0] * scale);
140         out->m[0][1] = (float)(in1->m[1][0] * scale);
141         out->m[0][2] = (float)(in1->m[2][0] * scale);
142         out->m[1][0] = (float)(in1->m[0][1] * scale);
143         out->m[1][1] = (float)(in1->m[1][1] * scale);
144         out->m[1][2] = (float)(in1->m[2][1] * scale);
145         out->m[2][0] = (float)(in1->m[0][2] * scale);
146         out->m[2][1] = (float)(in1->m[1][2] * scale);
147         out->m[2][2] = (float)(in1->m[2][2] * scale);
148
149         // invert the translate
150         out->m[0][3] = -(in1->m[0][3] * out->m[0][0] + in1->m[1][3] * out->m[0][1] + in1->m[2][3] * out->m[0][2]);
151         out->m[1][3] = -(in1->m[0][3] * out->m[1][0] + in1->m[1][3] * out->m[1][1] + in1->m[2][3] * out->m[1][2]);
152         out->m[2][3] = -(in1->m[0][3] * out->m[2][0] + in1->m[1][3] * out->m[2][1] + in1->m[2][3] * out->m[2][2]);
153
154         // don't know if there's anything worth doing here
155         out->m[3][0] = 0;
156         out->m[3][1] = 0;
157         out->m[3][2] = 0;
158         out->m[3][3] = 1;
159 }
160
161 void Matrix4x4_CreateIdentity (matrix4x4_t *out)
162 {
163         out->m[0][0]=1.0f;
164         out->m[0][1]=0.0f;
165         out->m[0][2]=0.0f;
166         out->m[0][3]=0.0f;
167         out->m[1][0]=0.0f;
168         out->m[1][1]=1.0f;
169         out->m[1][2]=0.0f;
170         out->m[1][3]=0.0f;
171         out->m[2][0]=0.0f;
172         out->m[2][1]=0.0f;
173         out->m[2][2]=1.0f;
174         out->m[2][3]=0.0f;
175         out->m[3][0]=0.0f;
176         out->m[3][1]=0.0f;
177         out->m[3][2]=0.0f;
178         out->m[3][3]=1.0f;
179 }
180
181 void Matrix4x4_CreateTranslate (matrix4x4_t *out, float x, float y, float z)
182 {
183         out->m[0][0]=1.0f;
184         out->m[0][1]=0.0f;
185         out->m[0][2]=0.0f;
186         out->m[0][3]=x;
187         out->m[1][0]=0.0f;
188         out->m[1][1]=1.0f;
189         out->m[1][2]=0.0f;
190         out->m[1][3]=y;
191         out->m[2][0]=0.0f;
192         out->m[2][1]=0.0f;
193         out->m[2][2]=1.0f;
194         out->m[2][3]=z;
195         out->m[3][0]=0.0f;
196         out->m[3][1]=0.0f;
197         out->m[3][2]=0.0f;
198         out->m[3][3]=1.0f;
199 }
200
201 void Matrix4x4_CreateRotate (matrix4x4_t *out, float angle, float x, float y, float z)
202 {
203         float len, c, s;
204
205         len = x*x+y*y+z*z;
206         if (len != 0.0f)
207                 len = 1.0f / (float)sqrt(len);
208         x *= len;
209         y *= len;
210         z *= len;
211
212         angle *= (float)(-M_PI / 180.0);
213         c = (float)cos(angle);
214         s = (float)sin(angle);
215
216         out->m[0][0]=x * x + c * (1 - x * x);
217         out->m[0][1]=x * y * (1 - c) + z * s;
218         out->m[0][2]=z * x * (1 - c) - y * s;
219         out->m[0][3]=0.0f;
220         out->m[1][0]=x * y * (1 - c) - z * s;
221         out->m[1][1]=y * y + c * (1 - y * y);
222         out->m[1][2]=y * z * (1 - c) + x * s;
223         out->m[1][3]=0.0f;
224         out->m[2][0]=z * x * (1 - c) + y * s;
225         out->m[2][1]=y * z * (1 - c) - x * s;
226         out->m[2][2]=z * z + c * (1 - z * z);
227         out->m[2][3]=0.0f;
228         out->m[3][0]=0.0f;
229         out->m[3][1]=0.0f;
230         out->m[3][2]=0.0f;
231         out->m[3][3]=1.0f;
232 }
233
234 void Matrix4x4_CreateScale (matrix4x4_t *out, float x)
235 {
236         out->m[0][0]=x;
237         out->m[0][1]=0.0f;
238         out->m[0][2]=0.0f;
239         out->m[0][3]=0.0f;
240         out->m[1][0]=0.0f;
241         out->m[1][1]=x;
242         out->m[1][2]=0.0f;
243         out->m[1][3]=0.0f;
244         out->m[2][0]=0.0f;
245         out->m[2][1]=0.0f;
246         out->m[2][2]=x;
247         out->m[2][3]=0.0f;
248         out->m[3][0]=0.0f;
249         out->m[3][1]=0.0f;
250         out->m[3][2]=0.0f;
251         out->m[3][3]=1.0f;
252 }
253
254 void Matrix4x4_CreateScale3 (matrix4x4_t *out, float x, float y, float z)
255 {
256         out->m[0][0]=x;
257         out->m[0][1]=0.0f;
258         out->m[0][2]=0.0f;
259         out->m[0][3]=0.0f;
260         out->m[1][0]=0.0f;
261         out->m[1][1]=y;
262         out->m[1][2]=0.0f;
263         out->m[1][3]=0.0f;
264         out->m[2][0]=0.0f;
265         out->m[2][1]=0.0f;
266         out->m[2][2]=z;
267         out->m[2][3]=0.0f;
268         out->m[3][0]=0.0f;
269         out->m[3][1]=0.0f;
270         out->m[3][2]=0.0f;
271         out->m[3][3]=1.0f;
272 }
273
274 void Matrix4x4_CreateFromQuakeEntity(matrix4x4_t *out, float x, float y, float z, float pitch, float yaw, float roll, float scale)
275 {
276         double angle, sr, sp, sy, cr, cp, cy;
277
278         if (roll)
279         {
280                 angle = yaw * (M_PI*2 / 360);
281                 sy = sin(angle);
282                 cy = cos(angle);
283                 angle = pitch * (M_PI*2 / 360);
284                 sp = sin(angle);
285                 cp = cos(angle);
286                 angle = roll * (M_PI*2 / 360);
287                 sr = sin(angle);
288                 cr = cos(angle);
289                 out->m[0][0] = (float)((cp*cy) * scale);
290                 out->m[0][1] = (float)((sr*sp*cy+cr*-sy) * scale);
291                 out->m[0][2] = (float)((cr*sp*cy+-sr*-sy) * scale);
292                 out->m[0][3] = x;
293                 out->m[1][0] = (float)((cp*sy) * scale);
294                 out->m[1][1] = (float)((sr*sp*sy+cr*cy) * scale);
295                 out->m[1][2] = (float)((cr*sp*sy+-sr*cy) * scale);
296                 out->m[1][3] = y;
297                 out->m[2][0] = (float)((-sp) * scale);
298                 out->m[2][1] = (float)((sr*cp) * scale);
299                 out->m[2][2] = (float)((cr*cp) * scale);
300                 out->m[2][3] = z;
301                 out->m[3][0] = 0;
302                 out->m[3][1] = 0;
303                 out->m[3][2] = 0;
304                 out->m[3][3] = 1;
305         }
306         else if (pitch)
307         {
308                 angle = yaw * (M_PI*2 / 360);
309                 sy = sin(angle);
310                 cy = cos(angle);
311                 angle = pitch * (M_PI*2 / 360);
312                 sp = sin(angle);
313                 cp = cos(angle);
314                 out->m[0][0] = (float)((cp*cy) * scale);
315                 out->m[0][1] = (float)((-sy) * scale);
316                 out->m[0][2] = (float)((sp*cy) * scale);
317                 out->m[0][3] = x;
318                 out->m[1][0] = (float)((cp*sy) * scale);
319                 out->m[1][1] = (float)((cy) * scale);
320                 out->m[1][2] = (float)((sp*sy) * scale);
321                 out->m[1][3] = y;
322                 out->m[2][0] = (float)((-sp) * scale);
323                 out->m[2][1] = 0;
324                 out->m[2][2] = (float)((cp) * scale);
325                 out->m[2][3] = z;
326                 out->m[3][0] = 0;
327                 out->m[3][1] = 0;
328                 out->m[3][2] = 0;
329                 out->m[3][3] = 1;
330         }
331         else if (yaw)
332         {
333                 angle = yaw * (M_PI*2 / 360);
334                 sy = sin(angle);
335                 cy = cos(angle);
336                 out->m[0][0] = (float)((cy) * scale);
337                 out->m[0][1] = (float)((-sy) * scale);
338                 out->m[0][2] = 0;
339                 out->m[0][3] = x;
340                 out->m[1][0] = (float)((sy) * scale);
341                 out->m[1][1] = (float)((cy) * scale);
342                 out->m[1][2] = 0;
343                 out->m[1][3] = y;
344                 out->m[2][0] = 0;
345                 out->m[2][1] = 0;
346                 out->m[2][2] = scale;
347                 out->m[2][3] = z;
348                 out->m[3][0] = 0;
349                 out->m[3][1] = 0;
350                 out->m[3][2] = 0;
351                 out->m[3][3] = 1;
352         }
353         else
354         {
355                 out->m[0][0] = scale;
356                 out->m[0][1] = 0;
357                 out->m[0][2] = 0;
358                 out->m[0][3] = x;
359                 out->m[1][0] = 0;
360                 out->m[1][1] = scale;
361                 out->m[1][2] = 0;
362                 out->m[1][3] = y;
363                 out->m[2][0] = 0;
364                 out->m[2][1] = 0;
365                 out->m[2][2] = scale;
366                 out->m[2][3] = z;
367                 out->m[3][0] = 0;
368                 out->m[3][1] = 0;
369                 out->m[3][2] = 0;
370                 out->m[3][3] = 1;
371         }
372 }
373
374 void Matrix4x4_ToVectors(const matrix4x4_t *in, float vx[3], float vy[3], float vz[3], float t[3])
375 {
376         vx[0] = in->m[0][0];
377         vx[1] = in->m[1][0];
378         vx[2] = in->m[2][0];
379         vy[0] = in->m[0][1];
380         vy[1] = in->m[1][1];
381         vy[2] = in->m[2][1];
382         vz[0] = in->m[0][2];
383         vz[1] = in->m[1][2];
384         vz[2] = in->m[2][2];
385         t[0] = in->m[0][3];
386         t[1] = in->m[1][3];
387         t[2] = in->m[2][3];
388 }
389
390 void Matrix4x4_FromVectors(matrix4x4_t *out, const float vx[3], const float vy[3], const float vz[3], const float t[3])
391 {
392         out->m[0][0] = vx[0];
393         out->m[0][1] = vy[0];
394         out->m[0][2] = vz[0];
395         out->m[0][3] = t[0];
396         out->m[1][0] = vx[1];
397         out->m[1][1] = vy[1];
398         out->m[1][2] = vz[1];
399         out->m[1][3] = t[1];
400         out->m[2][0] = vx[2];
401         out->m[2][1] = vy[2];
402         out->m[2][2] = vz[2];
403         out->m[2][3] = t[2];
404         out->m[3][0] = 0.0f;
405         out->m[3][1] = 0.0f;
406         out->m[3][2] = 0.0f;
407         out->m[3][3] = 1.0f;
408 }
409
410 void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, float blend)
411 {
412         float iblend = 1 - blend;
413         out->m[0][0] = in1->m[0][0] * iblend + in2->m[0][0] * blend;
414         out->m[0][1] = in1->m[0][1] * iblend + in2->m[0][1] * blend;
415         out->m[0][2] = in1->m[0][2] * iblend + in2->m[0][2] * blend;
416         out->m[0][3] = in1->m[0][3] * iblend + in2->m[0][3] * blend;
417         out->m[1][0] = in1->m[1][0] * iblend + in2->m[1][0] * blend;
418         out->m[1][1] = in1->m[1][1] * iblend + in2->m[1][1] * blend;
419         out->m[1][2] = in1->m[1][2] * iblend + in2->m[1][2] * blend;
420         out->m[1][3] = in1->m[1][3] * iblend + in2->m[1][3] * blend;
421         out->m[2][0] = in1->m[2][0] * iblend + in2->m[2][0] * blend;
422         out->m[2][1] = in1->m[2][1] * iblend + in2->m[2][1] * blend;
423         out->m[2][2] = in1->m[2][2] * iblend + in2->m[2][2] * blend;
424         out->m[2][3] = in1->m[2][3] * iblend + in2->m[2][3] * blend;
425         out->m[3][0] = in1->m[3][0] * iblend + in2->m[3][0] * blend;
426         out->m[3][1] = in1->m[3][1] * iblend + in2->m[3][1] * blend;
427         out->m[3][2] = in1->m[3][2] * iblend + in2->m[3][2] * blend;
428         out->m[3][3] = in1->m[3][3] * iblend + in2->m[3][3] * blend;
429 }
430
431
432 void Matrix4x4_Transform (const matrix4x4_t *in, const float v[3], float out[3])
433 {
434         out[0] = v[0] * in->m[0][0] + v[1] * in->m[0][1] + v[2] * in->m[0][2] + in->m[0][3];
435         out[1] = v[0] * in->m[1][0] + v[1] * in->m[1][1] + v[2] * in->m[1][2] + in->m[1][3];
436         out[2] = v[0] * in->m[2][0] + v[1] * in->m[2][1] + v[2] * in->m[2][2] + in->m[2][3];
437 }
438
439 void Matrix4x4_Transform4 (const matrix4x4_t *in, const float v[4], float out[4])
440 {
441         out[0] = v[0] * in->m[0][0] + v[1] * in->m[0][1] + v[2] * in->m[0][2] + v[3] * in->m[0][3];
442         out[1] = v[0] * in->m[1][0] + v[1] * in->m[1][1] + v[2] * in->m[1][2] + v[3] * in->m[1][3];
443         out[2] = v[0] * in->m[2][0] + v[1] * in->m[2][1] + v[2] * in->m[2][2] + v[3] * in->m[2][3];
444         out[3] = v[0] * in->m[3][0] + v[1] * in->m[3][1] + v[2] * in->m[3][2] + v[3] * in->m[3][3];
445 }
446
447 void Matrix4x4_Transform3x3 (const matrix4x4_t *in, const float v[3], float out[3])
448 {
449         out[0] = v[0] * in->m[0][0] + v[1] * in->m[0][1] + v[2] * in->m[0][2];
450         out[1] = v[0] * in->m[1][0] + v[1] * in->m[1][1] + v[2] * in->m[1][2];
451         out[2] = v[0] * in->m[2][0] + v[1] * in->m[2][1] + v[2] * in->m[2][2];
452 }
453
454 /*
455 void Matrix4x4_SimpleUntransform (const matrix4x4_t *in, const float v[3], float out[3])
456 {
457         float t[3];
458         t[0] = v[0] - in->m[0][3];
459         t[1] = v[1] - in->m[1][3];
460         t[2] = v[2] - in->m[2][3];
461         out[0] = t[0] * in->m[0][0] + t[1] * in->m[1][0] + t[2] * in->m[2][0];
462         out[1] = t[0] * in->m[0][1] + t[1] * in->m[1][1] + t[2] * in->m[2][1];
463         out[2] = t[0] * in->m[0][2] + t[1] * in->m[1][2] + t[2] * in->m[2][2];
464 }
465 */
466
467 // FIXME: optimize
468 void Matrix4x4_ConcatTranslate (matrix4x4_t *out, float x, float y, float z)
469 {
470         matrix4x4_t base, temp;
471         base = *out;
472         Matrix4x4_CreateTranslate(&temp, x, y, z);
473         Matrix4x4_Concat(out, &base, &temp);
474 }
475
476 // FIXME: optimize
477 void Matrix4x4_ConcatRotate (matrix4x4_t *out, float angle, float x, float y, float z)
478 {
479         matrix4x4_t base, temp;
480         base = *out;
481         Matrix4x4_CreateRotate(&temp, angle, x, y, z);
482         Matrix4x4_Concat(out, &base, &temp);
483 }
484
485 // FIXME: optimize
486 void Matrix4x4_ConcatScale (matrix4x4_t *out, float x)
487 {
488         matrix4x4_t base, temp;
489         base = *out;
490         Matrix4x4_CreateScale(&temp, x);
491         Matrix4x4_Concat(out, &base, &temp);
492 }
493
494 // FIXME: optimize
495 void Matrix4x4_ConcatScale3 (matrix4x4_t *out, float x, float y, float z)
496 {
497         matrix4x4_t base, temp;
498         base = *out;
499         Matrix4x4_CreateScale3(&temp, x, y, z);
500         Matrix4x4_Concat(out, &base, &temp);
501 }
502
503 void Matrix4x4_OriginFromMatrix (const matrix4x4_t *in, float *out)
504 {
505         out[0] = in->m[0][3];
506         out[1] = in->m[1][3];
507         out[2] = in->m[2][3];
508 }
509
510 float Matrix4x4_ScaleFromMatrix (const matrix4x4_t *in)
511 {
512         // we only support uniform scaling, so assume the first row is enough
513         return (float)sqrt(in->m[0][0] * in->m[0][0] + in->m[0][1] * in->m[0][1] + in->m[0][2] * in->m[0][2]);
514 }
515