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