-
Notifications
You must be signed in to change notification settings - Fork 101
/
Copy pathaffine_transform.h
143 lines (128 loc) · 6.37 KB
/
affine_transform.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _AFFINE_TRANSFORM_H_
#define _AFFINE_TRANSFORM_H_
// Stolen from RISCBoy
#include <stdint.h>
#include "pico/platform.h"
// Store unpacked affine transforms as signed 16.16 fixed point in the following order:
// a00, a01, b0, a10, a11, b1
// i.e. the top two rows of the matrix
// [ a00 a01 b0 ]
// [ a01 a11 b1 ]
// [ 0 0 1 ]
// Then pack integers appropriately
typedef int32_t affine_transform_t[6];
static const int32_t AF_ONE = 1 << 16;
static inline __attribute__((always_inline)) int32_t mul_fp1616(int32_t x, int32_t y) {
// TODO this results in an aeabi call?!
int64_t result = (int64_t) x * y;
return result >> 16;
}
// result can not be == left or right
static inline void affine_mul(affine_transform_t result, const affine_transform_t left,
const affine_transform_t right) {
result[0] = mul_fp1616(left[0], right[0]) + mul_fp1616(left[1], right[3]);
result[1] = mul_fp1616(left[0], right[1]) + mul_fp1616(left[1], right[4]);
result[2] = mul_fp1616(left[0], right[2]) + mul_fp1616(left[1], right[5]) + left[2];
result[3] = mul_fp1616(left[3], right[0]) + mul_fp1616(left[4], right[3]);
result[4] = mul_fp1616(left[3], right[1]) + mul_fp1616(left[4], right[4]);
result[5] = mul_fp1616(left[3], right[2]) + mul_fp1616(left[4], right[5]) + left[5];
}
static inline void affine_copy(affine_transform_t dst, const affine_transform_t src) {
for (int i = 0; i < 6; ++i)
dst[i] = src[i];
}
// User is describing a sequence of transformations from texture space to
// screen space, which are applied by premultiplying a column vector. However,
// hardware transforms *from* screenspace *to* texture space, so we want the
// inverse of the transform the user is building. Therefore our functions each
// produce the inverse of the requested transform, and we apply transforms by
// *post*-multiplication.
static inline void affine_identity(affine_transform_t current_trans) {
int32_t tmp[6] = {
AF_ONE, 0, 0,
0, AF_ONE, 0
};
affine_copy(current_trans, tmp);
}
static inline void affine_translate(affine_transform_t current_trans, int32_t x, int32_t y) {
int32_t tmp[6];
int32_t transform[6] = {
AF_ONE, 0, -AF_ONE * x,
0, AF_ONE, -AF_ONE * y
};
affine_mul(tmp, current_trans, transform);
affine_copy(current_trans, tmp);
}
// TODO this is shit
static const int32_t __not_in_flash("atrans") sin_lookup_fp1616[256] = {
0x0, 0x648, 0xc8f, 0x12d5, 0x1917, 0x1f56, 0x2590, 0x2bc4, 0x31f1, 0x3817,
0x3e33, 0x4447, 0x4a50, 0x504d, 0x563e, 0x5c22, 0x61f7, 0x67bd, 0x6d74,
0x7319, 0x78ad, 0x7e2e, 0x839c, 0x88f5, 0x8e39, 0x9368, 0x987f, 0x9d7f,
0xa267, 0xa736, 0xabeb, 0xb085, 0xb504, 0xb968, 0xbdae, 0xc1d8, 0xc5e4,
0xc9d1, 0xcd9f, 0xd14d, 0xd4db, 0xd848, 0xdb94, 0xdebe, 0xe1c5, 0xe4aa,
0xe76b, 0xea09, 0xec83, 0xeed8, 0xf109, 0xf314, 0xf4fa, 0xf6ba, 0xf853,
0xf9c7, 0xfb14, 0xfc3b, 0xfd3a, 0xfe13, 0xfec4, 0xff4e, 0xffb1, 0xffec,
0x10000, 0xffec, 0xffb1, 0xff4e, 0xfec4, 0xfe13, 0xfd3a, 0xfc3b, 0xfb14,
0xf9c7, 0xf853, 0xf6ba, 0xf4fa, 0xf314, 0xf109, 0xeed8, 0xec83, 0xea09,
0xe76b, 0xe4aa, 0xe1c5, 0xdebe, 0xdb94, 0xd848, 0xd4db, 0xd14d, 0xcd9f,
0xc9d1, 0xc5e4, 0xc1d8, 0xbdae, 0xb968, 0xb504, 0xb085, 0xabeb, 0xa736,
0xa267, 0x9d7f, 0x987f, 0x9368, 0x8e39, 0x88f5, 0x839c, 0x7e2e, 0x78ad,
0x7319, 0x6d74, 0x67bd, 0x61f7, 0x5c22, 0x563e, 0x504d, 0x4a50, 0x4447,
0x3e33, 0x3817, 0x31f1, 0x2bc4, 0x2590, 0x1f56, 0x1917, 0x12d5, 0xc8f, 0x648,
0x0, 0xfffff9b8, 0xfffff371, 0xffffed2b, 0xffffe6e9, 0xffffe0aa, 0xffffda70,
0xffffd43c, 0xffffce0f, 0xffffc7e9, 0xffffc1cd, 0xffffbbb9, 0xffffb5b0,
0xffffafb3, 0xffffa9c2, 0xffffa3de, 0xffff9e09, 0xffff9843, 0xffff928c,
0xffff8ce7, 0xffff8753, 0xffff81d2, 0xffff7c64, 0xffff770b, 0xffff71c7,
0xffff6c98, 0xffff6781, 0xffff6281, 0xffff5d99, 0xffff58ca, 0xffff5415,
0xffff4f7b, 0xffff4afc, 0xffff4698, 0xffff4252, 0xffff3e28, 0xffff3a1c,
0xffff362f, 0xffff3261, 0xffff2eb3, 0xffff2b25, 0xffff27b8, 0xffff246c,
0xffff2142, 0xffff1e3b, 0xffff1b56, 0xffff1895, 0xffff15f7, 0xffff137d,
0xffff1128, 0xffff0ef7, 0xffff0cec, 0xffff0b06, 0xffff0946, 0xffff07ad,
0xffff0639, 0xffff04ec, 0xffff03c5, 0xffff02c6, 0xffff01ed, 0xffff013c,
0xffff00b2, 0xffff004f, 0xffff0014, 0xffff0000, 0xffff0014, 0xffff004f,
0xffff00b2, 0xffff013c, 0xffff01ed, 0xffff02c6, 0xffff03c5, 0xffff04ec,
0xffff0639, 0xffff07ad, 0xffff0946, 0xffff0b06, 0xffff0cec, 0xffff0ef7,
0xffff1128, 0xffff137d, 0xffff15f7, 0xffff1895, 0xffff1b56, 0xffff1e3b,
0xffff2142, 0xffff246c, 0xffff27b8, 0xffff2b25, 0xffff2eb3, 0xffff3261,
0xffff362f, 0xffff3a1c, 0xffff3e28, 0xffff4252, 0xffff4698, 0xffff4afc,
0xffff4f7b, 0xffff5415, 0xffff58ca, 0xffff5d99, 0xffff6281, 0xffff6781,
0xffff6c98, 0xffff71c7, 0xffff770b, 0xffff7c64, 0xffff81d2, 0xffff8753,
0xffff8ce7, 0xffff928c, 0xffff9843, 0xffff9e09, 0xffffa3de, 0xffffa9c2,
0xffffafb3, 0xffffb5b0, 0xffffbbb9, 0xffffc1cd, 0xffffc7e9, 0xffffce0f,
0xffffd43c, 0xffffda70, 0xffffe0aa, 0xffffe6e9, 0xffffed2b, 0xfffff371,
0xfffff9b8
};
static inline int32_t sin_fp1616(uint8_t theta) {
return sin_lookup_fp1616[theta];
}
static inline int32_t cos_fp1616(uint8_t theta) {
return sin_lookup_fp1616[(theta + 64) & 0xff];
}
// Appears as a counterclockwise rotation (when viewed from texture space to screen space)
// Units of angle are 256 = one turn
static inline void affine_rotate(affine_transform_t current_trans, uint8_t theta) {
int32_t tmp[6];
int32_t transform[6] = {
cos_fp1616(theta), -sin_fp1616(theta), 0,
sin_fp1616(theta), cos_fp1616(theta), 0
};
affine_mul(tmp, current_trans, transform);
affine_copy(current_trans, tmp);
}
static inline void affine_scale(affine_transform_t current_trans, int32_t sx, int32_t sy) {
int32_t sx_inv = ((int64_t) AF_ONE * AF_ONE) / sx;
int32_t sy_inv = ((int64_t) AF_ONE * AF_ONE) / sy;
int32_t tmp[6];
int32_t transform[6] = {
sx_inv, 0, 0,
0, sy_inv, 0
};
affine_mul(tmp, current_trans, transform);
affine_copy(current_trans, tmp);
}
#endif // _AFFINE_TRANSFORM_H_