KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
matrix.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 dc/matrix.h
4 Copyright (C) 2000 Megan Potter
5 Copyright (C) 2013, 2014 Josh "PH3NOM" Pearson
6 Copyright (C) 2018 Lawrence Sebald
7
8*/
9
10/** \file dc/matrix.h
11 \brief Basic matrix operations.
12 \ingroup math_matrices
13
14 This file contains various basic matrix math functionality for using the
15 SH4's matrix transformation unit. Higher level functionality, like the 3D
16 functionality is built off of these operations.
17
18 \see dc/matrix3d.h
19
20 \author Megan Potter
21 \author Josh "PH3NOM" Pearson
22*/
23
24#ifndef __DC_MATRIX_H
25#define __DC_MATRIX_H
26
27#include <sys/cdefs.h>
28__BEGIN_DECLS
29
30#include <dc/vector.h>
31
32/** \defgroup math_matrices Matrices
33 \brief SH4-optimized matrix and linear algebra routines
34 \ingroup math
35 @{
36*/
37
38/** \brief Copy the internal matrix to a memory one.
39
40 This function stores the current internal matrix to one in memory.
41
42 \warning
43 \p out MUST be at least 8-byte aligned!
44
45 \note
46 For best performance, 32-byte alignment of \p out is recommended.
47
48 \param out A pointer to where to store the matrix (must be at
49 least 8-byte aligned, should be 32-byte aligned).
50*/
52
53/** \brief Copy a memory matrix into the internal one.
54
55 This function loads the internal matrix with the values of one in memory.
56
57 \warning
58 \p out MUST be at least 8-byte aligned!
59
60 \note
61 For best performance, 32-byte alignment of \p out is recommended.
62
63 \param src A pointer to where to load the matrix from (must be
64 at least 8-byte aligned, should be 32-byte aligned).
65*/
66void mat_load(const matrix_t *src);
67
68/** \brief Clear the internal matrix to identity.
69
70 This function clears the internal matrix to a standard identity matrix.
71*/
72void mat_identity(void);
73
74/** \brief Apply a matrix.
75
76 This function multiplies a matrix in memory onto the internal matrix.
77
78 \warning
79 \p src MUST be at least 8-byte aligned!
80
81 \note
82 For best performance, 32-byte alignment of \p src is recommended.
83
84 \param src A pointer to the matrix to multiply.
85*/
86void mat_apply(const matrix_t *src);
87
88/** \brief Transform vectors by the internal matrix.
89
90 This function transforms zero or more sets of vectors by the current
91 internal matrix. Each vector is 3 single-precision floats long.
92
93 \param invecs The list of input vectors.
94 \param outvecs The list of output vectors.
95 \param veccnt How many vectors are in the list.
96 \param stride Number of bytes between vectors.
97*/
98void mat_transform(const vector_t *invecs, vector_t *outvecs,
99 int veccnt, int stride);
100
101/** \brief Transform vectors by the internal matrix into the store queues.
102
103 This function transforms one or more sets of vertices using the current
104 internal matrix directly into the store queues. Each vertex is exactly
105 32-bytes long, and the non-xyz data that is with it will be copied over with
106 the transformed coordinates. This is perfect, for instance, for transforming
107 pvr_vertex_t vertices.
108
109 \note sq_lock() must have been called beforehand
110
111 \param input The list of input vertices.
112 \param output The output pointer (SQ address)
113 \param veccnt The number of vertices to transform.
114
115 \author Jim Ursetto
116*/
117void mat_transform_sq(void *input, void *output, int veccnt);
118
119/** \brief Macro to transform a single vertex by the internal matrix.
120
121 This macro is an inline assembly operation to transform a single vertex. It
122 works most efficiently if the x value is in fr0, y is in fr1, and z is in
123 fr2 before using the macro.
124
125 \param x The X coordinate to transform.
126 \param y The Y coordinate to transform.
127 \param z The Z coordinate to transform.
128*/
129#define mat_trans_single(x, y, z) { \
130 register float __x __asm__("fr0") = (x); \
131 register float __y __asm__("fr1") = (y); \
132 register float __z __asm__("fr2") = (z); \
133 __asm__ __volatile__( \
134 "fldi1 fr3\n" \
135 "ftrv xmtrx,fv0\n" \
136 "fldi1 fr2\n" \
137 "fdiv fr3,fr2\n" \
138 "fmul fr2,fr0\n" \
139 "fmul fr2,fr1\n" \
140 : "=f" (__x), "=f" (__y), "=f" (__z) \
141 : "0" (__x), "1" (__y), "2" (__z) \
142 : "fr3" ); \
143 x = __x; y = __y; z = __z; \
144 }
145
146/** \brief Macro to transform a single vertex by the internal matrix.
147
148 This macro is an inline assembly operation to transform a single vertex. It
149 works most efficiently if the x value is in fr0, y is in fr1, z is in
150 fr2, and w is in fr3 before using the macro. This macro is similar to
151 \ref mat_trans_single(), but this one allows an input to and preserves the
152 Z/W value.
153
154 \param x The X coordinate to transform.
155 \param y The Y coordinate to transform.
156 \param z The Z coordinate to transform.
157 \param w The W coordinate to transform.
158*/
159#define mat_trans_single4(x, y, z, w) { \
160 register float __x __asm__("fr0") = (x); \
161 register float __y __asm__("fr1") = (y); \
162 register float __z __asm__("fr2") = (z); \
163 register float __w __asm__("fr3") = (w); \
164 __asm__ __volatile__( \
165 "ftrv xmtrx,fv0\n" \
166 "fdiv fr3,fr0\n" \
167 "fdiv fr3,fr1\n" \
168 "fdiv fr3,fr2\n" \
169 "fldi1 fr4\n" \
170 "fdiv fr3,fr4\n" \
171 "fmov fr4,fr3\n" \
172 : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) \
173 : "0" (__x), "1" (__y), "2" (__z), "3" (__w) \
174 : "fr4" ); \
175 x = __x; y = __y; z = __z; w = __w; \
176 }
177
178/** \brief Macro to transform a single vertex by the internal matrix.
179
180 This macro is an inline assembly operation to transform a single vertex. It
181 works most efficiently if the x value is in fr0, y is in fr1, and z is in
182 fr2 before using the macro. This macro is similar to
183 \ref mat_trans_single(), but this one leaves z/w instead of 1/w for the z
184 component.
185
186 \param x The X coordinate to transform.
187 \param y The Y coordinate to transform.
188 \param z The Z coordinate to transform.
189*/
190#define mat_trans_single3(x, y, z) { \
191 register float __x __asm__("fr0") = (x); \
192 register float __y __asm__("fr1") = (y); \
193 register float __z __asm__("fr2") = (z); \
194 __asm__ __volatile__( \
195 "fldi1 fr3\n" \
196 "ftrv xmtrx,fv0\n" \
197 "fdiv fr3,fr0\n" \
198 "fdiv fr3,fr1\n" \
199 "fdiv fr3,fr2\n" \
200 : "=f" (__x), "=f" (__y), "=f" (__z) \
201 : "0" (__x), "1" (__y), "2" (__z) \
202 : "fr3" ); \
203 x = __x; y = __y; z = __z; \
204 }
205
206/** \brief Macro to transform a single vertex by the internal matrix with no
207 perspective division.
208
209 This macro is an inline assembly operation to transform a single vertex. It
210 works most efficiently if the x value is in fr0, y is in fr1, z is in
211 fr2, and w is in fr3 before using the macro. This macro is similar to
212 \ref mat_trans_single(), but this one does not do any perspective division.
213
214 \param x The X coordinate to transform.
215 \param y The Y coordinate to transform.
216 \param z The Z coordinate to transform.
217 \param w The W coordinate to transform.
218*/
219#define mat_trans_nodiv(x, y, z, w) { \
220 register float __x __asm__("fr0") = (x); \
221 register float __y __asm__("fr1") = (y); \
222 register float __z __asm__("fr2") = (z); \
223 register float __w __asm__("fr3") = (w); \
224 __asm__ __volatile__( \
225 "ftrv xmtrx,fv0\n" \
226 : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) \
227 : "0" (__x), "1" (__y), "2" (__z), "3" (__w) ); \
228 x = __x; y = __y; z = __z; w = __w; \
229 }
230
231/** \brief Macro to transform a single 3d vertex coordinate by the internal
232 matrix with no perspective division.
233
234 This macro is an inline assembly operation to transform a 3 float vertex
235 coordinate. It works most efficiently if the x value is in fr12, y is in
236 fr13, and z is in fr14 before using the macro. This macro is similar to
237 \ref mat_trans_nodiv(), but this one sets the W component to 1 for use with
238 a 3d vector.
239
240 \param x The X coordinate to transform.
241 \param y The Y coordinate to transform.
242 \param z The Z coordinate to transform.
243*/
244#define mat_trans_single3_nodiv(x, y, z) { \
245 register float __x __asm__("fr12") = (x); \
246 register float __y __asm__("fr13") = (y); \
247 register float __z __asm__("fr14") = (z); \
248 __asm__ __volatile__( \
249 "fldi1 fr15\n" \
250 "ftrv xmtrx, fv12\n" \
251 : "=f" (__x), "=f" (__y), "=f" (__z) \
252 : "0" (__x), "1" (__y), "2" (__z) \
253 : "fr15" ); \
254 x = __x; y = __y; z = __z; \
255 }
256
257/** \brief Macro to transform a single 3d vertex coordinate by the internal
258 matrix with perspective division.
259
260 This macro is an inline assembly operation to transform a 3 float vertex
261 coordinate. It works most efficiently if the x value is in fr12, y is in
262 fr13, and z is in fr14 before using the macro. This macro is similar to
263 \ref mat_trans_single(), but this one does not modify the input operands,
264 instead storing the transformed vector to the output operands.
265
266 \param x The X coordinate to input transform.
267 \param y The Y coordinate to input transform.
268 \param z The Z coordinate to input transform.
269 \param x2 The X coordinate to output transform.
270 \param y2 The Y coordinate to output transform.
271 \param z2 The Z coordinate to output transform.
272*/
273#define mat_trans_single3_nomod(x, y, z, x2, y2, z2) { \
274 register float __x __asm__("fr12") = (x); \
275 register float __y __asm__("fr13") = (y); \
276 register float __z __asm__("fr14") = (z); \
277 __asm__ __volatile__( \
278 "fldi1 fr15\n" \
279 "ftrv xmtrx, fv12\n" \
280 "fldi1 fr14\n" \
281 "fdiv fr15, fr14\n" \
282 "fmul fr14, fr12\n" \
283 "fmul fr14, fr13\n" \
284 : "=f" (__x), "=f" (__y), "=f" (__z) \
285 : "0" (__x), "1" (__y), "2" (__z) \
286 : "fr15" ); \
287 x2 = __x; y2 = __y; z2 = __z; \
288 }
289
290/** \brief Macro to transform a single 3d vertex coordinate by the internal
291 matrix.
292
293 This macro is an inline assembly operation to transform a 3 float vertex
294 coordinate. It works most efficiently if the x value is in fr12, y is in
295 fr13, and z is in fr14 before using the macro. This macro is similar to
296 \ref mat_trans_single3_nodiv(), but this one does not modify the input
297 operands, instead storing the transformed vector to the output operands.
298
299 \param x The X coordinate to input transform.
300 \param y The Y coordinate to input transform.
301 \param z The Z coordinate to input transform.
302 \param x2 The X coordinate to output transform.
303 \param y2 The Y coordinate to output transform.
304 \param z2 The Z coordinate to output transform.
305*/
306#define mat_trans_single3_nodiv_nomod(x, y, z, x2, y2, z2) { \
307 register float __x __asm__("fr12") = (x); \
308 register float __y __asm__("fr13") = (y); \
309 register float __z __asm__("fr14") = (z); \
310 __asm__ __volatile__( \
311 "fldi1 fr15\n" \
312 "ftrv xmtrx, fv12\n" \
313 : "=f" (__x), "=f" (__y), "=f" (__z) \
314 : "0" (__x), "1" (__y), "2" (__z) \
315 : "fr15" ); \
316 x2 = __x; y2 = __y; z2 = __z; \
317 }
318
319/** \brief Macro to transform a single 3d vertex coordinate by the internal
320 matrix.
321
322 This macro is an inline assembly operation to transform a 3 float vertex
323 coordinate. It works most efficiently if the x value is in fr12, y is in
324 fr13, and z is in fr14 before using the macro. This macro is similar to
325 \ref mat_trans_single3_nodiv(), but this one stores the W component of
326 transform for later perspective divide.
327
328 \param x The X coordinate to transform.
329 \param y The Y coordinate to transform.
330 \param z The Z coordinate to transform.
331 \param w The W coordinate output of transform.
332*/
333#define mat_trans_single3_nodivw(x, y, z, w) { \
334 register float __x __asm__("fr12") = (x); \
335 register float __y __asm__("fr13") = (y); \
336 register float __z __asm__("fr14") = (z); \
337 register float __w __asm__("fr15") = 1.0f; \
338 __asm__ __volatile__( \
339 "ftrv xmtrx, fv12\n" \
340 : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) \
341 : "0" (__x), "1" (__y), "2" (__z), "3" (__w) ); \
342 x = __x; y = __y; z = __z; w = __w; \
343 }
344
345/** \brief Macro to transform a single 3d vertex coordinate by the internal
346 matrix both with and without perspective division.
347
348 This macro is an inline assembly operation to transform a 3 float vertex
349 coordinate. It works most efficiently if the x value is in fr0, y is in fr1,
350 and z is in fr2 before using the macro. This macro is similar to
351 \ref mat_trans_single(), but this one is used for transforming input vertex
352 with and without perspective division.
353
354 \param x The X coordinate to transform without perspective
355 divide.
356 \param y The Y coordinate to transform without perspective
357 divide.
358 \param z The Z coordinate to transform without perspective
359 divide.
360 \param xd The X coordinate to output transform with
361 perspective divide.
362 \param yd The Y coordinate to output transform with
363 perspective divide.
364 \param zd The Z coordinate to output transform with
365 perspective divide.
366*/
367#define mat_trans_single3_nodiv_div(x, y, z, xd, yd, zd) { \
368 register float __x __asm__("fr0") = (x); \
369 register float __y __asm__("fr1") = (y); \
370 register float __z __asm__("fr2") = (z); \
371 register float __xd __asm__("fr4"); \
372 register float __yd __asm__("fr5"); \
373 register float __zd __asm__("fr6"); \
374 __asm__ __volatile__( \
375 "fldi1 fr3\n" \
376 "ftrv xmtrx, fv0\n" \
377 "fmov fr0, fr4\n" \
378 "fmov fr1, fr5\n" \
379 "fmov fr3, fr7\n" \
380 "fldi1 fr6\n" \
381 "fdiv fr7, fr6\n" \
382 "fmul fr6, fr4\n" \
383 "fmul fr6, fr5\n" \
384 : "=f" (__x), "=f" (__y), "=f" (__z), \
385 "=f" (__xd), "=f" (__yd), "=f" (__zd) \
386 : "0" (__x), "1" (__y), "2" (__z) \
387 : "fr3" ); \
388 x = __x; y = __y; z = __z; xd = __xd; yd = __yd; zd = __zd; \
389 }
390
391/** \brief Macro to transform a single vertex normal by the internal matrix.
392
393 This macro is an inline assembly operation to transform a 3 float vertex
394 normal. It works most efficiently if the x value is in fr8, y is in fr9,
395 and z is in fr10 before using the macro. This macro is similar to
396 \ref mat_trans_nodiv(), but this one sets the W component to 0 in order to
397 transform a vertex normal, rather than 1 for a vertex position.
398
399 \param x The X normal to transform.
400 \param y The Y normal to transform.
401 \param z The Z normal to transform.
402*/
403#define mat_trans_normal3(x, y, z) { \
404 register float __x __asm__("fr8") = (x); \
405 register float __y __asm__("fr9") = (y); \
406 register float __z __asm__("fr10") = (z); \
407 __asm__ __volatile__( \
408 "fldi0 fr11\n" \
409 "ftrv xmtrx, fv8\n" \
410 : "=f" (__x), "=f" (__y), "=f" (__z) \
411 : "0" (__x), "1" (__y), "2" (__z) \
412 : "fr11" ); \
413 x = __x; y = __y; z = __z; \
414 }
415
416/** \brief Macro to transform a single vertex normal by the internal matrix.
417
418 This macro is an inline assembly operation to transform a 3 float vertex
419 normal. It works most efficiently if the x value is in fr8, y is in fr9,
420 and z is in fr10 before using the macro. This macro is similar to
421 \ref mat_trans_normal3(), but this one does not modify the input operands,
422 instead storing the transformed vector to the output operands.
423
424 \param x The X normal to input transform.
425 \param y The Y normal to input transform.
426 \param z The Z normal to input transform.
427 \param x2 The X normal to output transform.
428 \param y2 The Y normal to output transform.
429 \param z2 The Z normal to output transform.
430*/
431#define mat_trans_normal3_nomod(x, y, z, x2, y2, z2) { \
432 register float __x __asm__("fr8") = (x); \
433 register float __y __asm__("fr9") = (y); \
434 register float __z __asm__("fr10") = (z); \
435 __asm__ __volatile__( \
436 "fldi0 fr11\n" \
437 "ftrv xmtrx, fv8\n" \
438 : "=f" (__x), "=f" (__y), "=f" (__z) \
439 : "0" (__x), "1" (__y), "2" (__z) \
440 : "fr11" ); \
441 x2 = __x; y2 = __y; z2 = __z; \
442 }
443
444/** @} */
445
446__END_DECLS
447
448#endif /* !__DC_MATRIX_H */
void mat_transform_sq(void *input, void *output, int veccnt)
Transform vectors by the internal matrix into the store queues.
void mat_identity(void)
Clear the internal matrix to identity.
void mat_apply(const matrix_t *src)
Apply a matrix.
void mat_load(const matrix_t *src)
Copy a memory matrix into the internal one.
void mat_transform(const vector_t *invecs, vector_t *outvecs, int veccnt, int stride)
Transform vectors by the internal matrix.
float matrix_t[4][4]
Basic 4x4 matrix type.
Definition vector.h:37
void mat_store(matrix_t *out)
Copy the internal matrix to a memory one.
Primitive matrix, vector, and point types.
4-part vector type.
Definition vector.h:42