ft2_scopedraw.c (6966B)
1 #include <stdio.h> 2 #include <stdint.h> 3 #include <stdbool.h> 4 #include <stdlib.h> 5 #include <math.h> 6 #include "../ft2_config.h" 7 #include "../ft2_video.h" 8 #include "../ft2_palette.h" 9 #include "ft2_scopes.h" 10 #include "ft2_scopedraw.h" 11 #include "ft2_scope_macros.h" 12 13 static int16_t *scopeIntrpLUT; 14 15 static void scopeLine(int32_t x1, int32_t y1, int32_t y2, const uint32_t color); 16 17 bool calcScopeIntrpLUT(void) 18 { 19 scopeIntrpLUT = (int16_t *)malloc(SCOPE_INTRP_WIDTH * SCOPE_INTRP_PHASES * sizeof (int16_t)); 20 if (scopeIntrpLUT == NULL) 21 return false; 22 23 /* Several tests have been done to figure out what interpolation method is most suitable 24 ** for the tracker scopes. After testing linear, cubic, Gaussian and windowed-sinc 25 ** interpolation, I have come to the conclusion that 4-point cubic B-spline is the best. 26 ** This interpolation method also has no overshoot. 27 */ 28 29 // 4-point cubic B-spline (no overshoot) 30 31 int16_t *ptr16 = scopeIntrpLUT; 32 for (int32_t i = 0; i < SCOPE_INTRP_PHASES; i++) 33 { 34 const double x1 = i * (1.0 / SCOPE_INTRP_PHASES); 35 const double x2 = x1 * x1; // x^2 36 const double x3 = x2 * x1; // x^3 37 38 double t1 = (-(1.0/6.0) * x3) + ( (1.0/2.0) * x2) + (-(1.0/2.0) * x1) + (1.0/6.0); 39 double t2 = ( (1.0/2.0) * x3) + ( -1.0 * x2) + (2.0/3.0); 40 double t3 = (-(1.0/2.0) * x3) + ( (1.0/2.0) * x2) + ( (1.0/2.0) * x1) + (1.0/6.0); 41 double t4 = (1.0/6.0) * x3; 42 43 // rounding here would make the scopes clip, but we clamp the scopes for another reason anyway 44 *ptr16++ = (int16_t)round(t1 * SCOPE_INTRP_SCALE); 45 *ptr16++ = (int16_t)round(t2 * SCOPE_INTRP_SCALE); 46 *ptr16++ = (int16_t)round(t3 * SCOPE_INTRP_SCALE); 47 *ptr16++ = (int16_t)round(t4 * SCOPE_INTRP_SCALE); 48 } 49 50 return true; 51 } 52 53 void freeScopeIntrpLUT(void) 54 { 55 if (scopeIntrpLUT != NULL) 56 { 57 free(scopeIntrpLUT); 58 scopeIntrpLUT = NULL; 59 } 60 } 61 62 /* ----------------------------------------------------------------------- */ 63 /* NON-LINED SCOPE DRAWING ROUTINES */ 64 /* ----------------------------------------------------------------------- */ 65 66 static void scopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 67 { 68 SCOPE_INIT 69 70 for (; x < width; x++) 71 { 72 SCOPE_GET_SMP8 73 SCOPE_DRAW_SMP 74 SCOPE_UPDATE_READPOS 75 SCOPE_HANDLE_POS_NO_LOOP 76 } 77 } 78 79 static void scopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 80 { 81 SCOPE_INIT 82 83 for (; x < width; x++) 84 { 85 SCOPE_GET_SMP8 86 SCOPE_DRAW_SMP 87 SCOPE_UPDATE_READPOS 88 SCOPE_HANDLE_POS_LOOP 89 } 90 } 91 92 static void scopeDrawBidiLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 93 { 94 SCOPE_INIT_BIDI 95 96 for (; x < width; x++) 97 { 98 SCOPE_GET_SMP8_BIDI 99 SCOPE_DRAW_SMP 100 SCOPE_UPDATE_READPOS 101 SCOPE_HANDLE_POS_BIDI 102 } 103 } 104 105 static void scopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 106 { 107 SCOPE_INIT 108 109 for (; x < width; x++) 110 { 111 SCOPE_GET_SMP16 112 SCOPE_DRAW_SMP 113 SCOPE_UPDATE_READPOS 114 SCOPE_HANDLE_POS_NO_LOOP 115 } 116 } 117 118 static void scopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 119 { 120 SCOPE_INIT 121 122 for (; x < width; x++) 123 { 124 SCOPE_GET_SMP16 125 SCOPE_DRAW_SMP 126 SCOPE_UPDATE_READPOS 127 SCOPE_HANDLE_POS_LOOP 128 } 129 } 130 131 static void scopeDrawBidiLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 132 { 133 SCOPE_INIT_BIDI 134 135 for (; x < width; x++) 136 { 137 SCOPE_GET_SMP16_BIDI 138 SCOPE_DRAW_SMP 139 SCOPE_UPDATE_READPOS 140 SCOPE_HANDLE_POS_BIDI 141 } 142 } 143 144 /* ----------------------------------------------------------------------- */ 145 /* LINED SCOPE DRAWING ROUTINES */ 146 /* ----------------------------------------------------------------------- */ 147 148 static void linedScopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 149 { 150 LINED_SCOPE_INIT 151 LINED_SCOPE_PREPARE_SMP8 152 SCOPE_HANDLE_POS_NO_LOOP 153 154 for (; x < width; x++) 155 { 156 SCOPE_GET_INTERPOLATED_SMP8 157 LINED_SCOPE_DRAW_SMP 158 SCOPE_UPDATE_READPOS 159 SCOPE_HANDLE_POS_NO_LOOP 160 } 161 } 162 163 static void linedScopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 164 { 165 LINED_SCOPE_INIT 166 LINED_SCOPE_PREPARE_SMP8_LOOP 167 SCOPE_HANDLE_POS_LOOP 168 169 for (; x < width; x++) 170 { 171 SCOPE_GET_INTERPOLATED_SMP8_LOOP 172 LINED_SCOPE_DRAW_SMP 173 SCOPE_UPDATE_READPOS 174 SCOPE_HANDLE_POS_LOOP 175 } 176 } 177 178 static void linedScopeDrawBidiLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 179 { 180 LINED_SCOPE_INIT_BIDI 181 LINED_SCOPE_PREPARE_SMP8_BIDI 182 SCOPE_HANDLE_POS_BIDI 183 184 for (; x < width; x++) 185 { 186 SCOPE_GET_INTERPOLATED_SMP8_BIDI 187 LINED_SCOPE_DRAW_SMP 188 SCOPE_UPDATE_READPOS 189 SCOPE_HANDLE_POS_BIDI 190 } 191 } 192 193 static void linedScopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 194 { 195 LINED_SCOPE_INIT 196 LINED_SCOPE_PREPARE_SMP16 197 SCOPE_HANDLE_POS_NO_LOOP 198 199 for (; x < width; x++) 200 { 201 SCOPE_GET_INTERPOLATED_SMP16 202 LINED_SCOPE_DRAW_SMP 203 SCOPE_UPDATE_READPOS 204 SCOPE_HANDLE_POS_NO_LOOP 205 } 206 } 207 208 static void linedScopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 209 { 210 LINED_SCOPE_INIT 211 LINED_SCOPE_PREPARE_SMP16_LOOP 212 SCOPE_HANDLE_POS_LOOP 213 214 for (; x < width; x++) 215 { 216 SCOPE_GET_INTERPOLATED_SMP16_LOOP 217 LINED_SCOPE_DRAW_SMP 218 SCOPE_UPDATE_READPOS 219 SCOPE_HANDLE_POS_LOOP 220 } 221 } 222 223 static void linedScopeDrawBidiLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) 224 { 225 LINED_SCOPE_INIT_BIDI 226 LINED_SCOPE_PREPARE_SMP16_BIDI 227 SCOPE_HANDLE_POS_BIDI 228 229 for (; x < width; x++) 230 { 231 SCOPE_GET_INTERPOLATED_SMP16_BIDI 232 LINED_SCOPE_DRAW_SMP 233 SCOPE_UPDATE_READPOS 234 SCOPE_HANDLE_POS_BIDI 235 } 236 } 237 238 // ----------------------------------------------------------------------- 239 240 static void scopeLine(int32_t x1, int32_t y1, int32_t y2, const uint32_t color) 241 { 242 #ifdef _DEBUG 243 if (x1 < 0 || x1 >= SCREEN_W || y1 < 0 || y1 >= SCREEN_H || y2 < 0 || y2 >= SCREEN_H) 244 return; 245 #endif 246 247 uint32_t *dst32 = &video.frameBuffer[(y1 * SCREEN_W) + x1]; 248 249 *dst32 = color; // set first pixel 250 251 const int32_t dy = y2 - y1; 252 if (dy == 0) // y1 == y2 253 { 254 dst32[1] = color; 255 return; 256 } 257 258 uint32_t ay = ABS(dy); 259 int32_t d = 1 - ay; 260 261 ay <<= 1; 262 263 if (y1 > y2) 264 { 265 for (; y1 != y2; y1--) 266 { 267 if (d >= 0) 268 { 269 d -= ay; 270 dst32++; 271 } 272 273 d += 2; 274 275 dst32 -= SCREEN_W; 276 *dst32 = color; 277 } 278 } 279 else 280 { 281 for (; y1 != y2; y1++) 282 { 283 if (d >= 0) 284 { 285 d -= ay; 286 dst32++; 287 } 288 289 d += 2; 290 291 dst32 += SCREEN_W; 292 *dst32 = color; 293 } 294 } 295 } 296 297 // ----------------------------------------------------------------------- 298 299 const scopeDrawRoutine scopeDrawRoutineTable[12] = 300 { 301 (scopeDrawRoutine)scopeDrawNoLoop_8bit, 302 (scopeDrawRoutine)scopeDrawLoop_8bit, 303 (scopeDrawRoutine)scopeDrawBidiLoop_8bit, 304 (scopeDrawRoutine)scopeDrawNoLoop_16bit, 305 (scopeDrawRoutine)scopeDrawLoop_16bit, 306 (scopeDrawRoutine)scopeDrawBidiLoop_16bit, 307 (scopeDrawRoutine)linedScopeDrawNoLoop_8bit, 308 (scopeDrawRoutine)linedScopeDrawLoop_8bit, 309 (scopeDrawRoutine)linedScopeDrawBidiLoop_8bit, 310 (scopeDrawRoutine)linedScopeDrawNoLoop_16bit, 311 (scopeDrawRoutine)linedScopeDrawLoop_16bit, 312 (scopeDrawRoutine)linedScopeDrawBidiLoop_16bit 313 };