ft2_scope_macros.h (8635B)
1 #pragma once 2 3 #include <stdint.h> 4 #include "../ft2_header.h" 5 #include "ft2_scopes.h" 6 7 /* ----------------------------------------------------------------------- */ 8 /* SCOPE DRAWING MACROS */ 9 /* ----------------------------------------------------------------------- */ 10 11 #define SCOPE_INIT \ 12 const uint32_t color = video.palette[PAL_PATTEXT]; \ 13 uint32_t width = x + w; \ 14 int32_t sample; \ 15 int32_t position = s->position; \ 16 uint64_t positionFrac = 0; 17 18 #define SCOPE_INIT_BIDI \ 19 const uint32_t color = video.palette[PAL_PATTEXT]; \ 20 uint32_t width = x + w; \ 21 int32_t sample; \ 22 int32_t actualPos, position = s->position; \ 23 uint64_t positionFrac = 0; \ 24 bool samplingBackwards = s->samplingBackwards; 25 26 #define LINED_SCOPE_INIT \ 27 SCOPE_INIT \ 28 int32_t smpY1, smpY2; \ 29 width--; 30 31 #define LINED_SCOPE_INIT_BIDI \ 32 SCOPE_INIT_BIDI \ 33 int32_t smpY1, smpY2; \ 34 width--; 35 36 /* Note: Sample data already has fixed tap samples at the end of the sample, 37 ** so that out-of-bounds reads get the correct interpolation tap data. 38 */ 39 40 #define NEAREST_NEIGHGBOR8 \ 41 { \ 42 sample = s8[0] << 8; \ 43 } \ 44 45 #define LINEAR_INTERPOLATION8(frac) \ 46 { \ 47 const int32_t f = (frac) >> (SCOPE_FRAC_BITS-15); \ 48 sample = (s8[0] << 8) + ((((s8[1] - s8[0]) << 8) * f) >> 15); \ 49 } \ 50 51 #define NEAREST_NEIGHGBOR16 \ 52 { \ 53 sample = s16[0]; \ 54 } \ 55 56 #define LINEAR_INTERPOLATION16(frac) \ 57 { \ 58 const int32_t f = (frac) >> (SCOPE_FRAC_BITS-15); \ 59 sample = s16[0] + (((s16[1] - s16[0]) * f) >> 15); \ 60 } \ 61 62 #define CUBIC_SMP8(frac) \ 63 const int16_t *t = scopeIntrpLUT + (((frac) >> (SCOPE_FRAC_BITS-SCOPE_INTRP_PHASES_BITS)) << SCOPE_INTRP_WIDTH_BITS); \ 64 \ 65 sample = ((s8[-1] * t[0]) + \ 66 ( s8[0] * t[1]) + \ 67 ( s8[1] * t[2]) + \ 68 ( s8[2] * t[3])) >> (SCOPE_INTRP_SCALE_BITS-8); 69 70 #define CUBIC_SMP16(frac) \ 71 const int16_t *t = scopeIntrpLUT + (((frac) >> (SCOPE_FRAC_BITS-SCOPE_INTRP_PHASES_BITS)) << SCOPE_INTRP_WIDTH_BITS); \ 72 \ 73 sample = ((s16[-1] * t[0]) + \ 74 ( s16[0] * t[1]) + \ 75 ( s16[1] * t[2]) + \ 76 ( s16[2] * t[3])) >> SCOPE_INTRP_SCALE_BITS; 77 78 #define CUBIC_INTERPOLATION8(frac) \ 79 { \ 80 CUBIC_SMP8(frac) \ 81 } \ 82 83 #define CUBIC_INTERPOLATION16(frac) \ 84 { \ 85 CUBIC_SMP16(frac) \ 86 } \ 87 88 #define CUBIC_INTERPOLATION8_LOOP(pos, frac) \ 89 { \ 90 if (s->hasLooped && pos <= s->loopStart+MAX_LEFT_TAPS) \ 91 s8 = s->leftEdgeTaps8 + (pos - s->loopStart); \ 92 \ 93 CUBIC_SMP8(frac) \ 94 } \ 95 96 #define CUBIC_INTERPOLATION16_LOOP(pos, frac) \ 97 { \ 98 if (s->hasLooped && pos <= s->loopStart+MAX_LEFT_TAPS) \ 99 s16 = s->leftEdgeTaps16 + (pos - s->loopStart); \ 100 \ 101 CUBIC_SMP16(frac) \ 102 } \ 103 104 #define INTERPOLATE_SMP8(pos, frac) \ 105 const int8_t *s8 = s->base8 + pos; \ 106 if (config.interpolation == INTERPOLATION_DISABLED) \ 107 NEAREST_NEIGHGBOR8 \ 108 else if (config.interpolation == INTERPOLATION_LINEAR) \ 109 LINEAR_INTERPOLATION8(frac) \ 110 else \ 111 CUBIC_INTERPOLATION8(frac) \ 112 sample = (int32_t)roundf((float)sample * s->fVolume); \ 113 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ 114 115 #define INTERPOLATE_SMP16(pos, frac) \ 116 const int16_t *s16 = s->base16 + pos; \ 117 if (config.interpolation == INTERPOLATION_DISABLED) \ 118 NEAREST_NEIGHGBOR16 \ 119 else if (config.interpolation == INTERPOLATION_LINEAR) \ 120 LINEAR_INTERPOLATION16(frac) \ 121 else \ 122 CUBIC_INTERPOLATION16(frac) \ 123 sample = (int32_t)roundf((float)sample * s->fVolume); \ 124 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ 125 126 #define INTERPOLATE_SMP8_LOOP(pos, frac) \ 127 const int8_t *s8 = s->base8 + pos; \ 128 if (config.interpolation == INTERPOLATION_DISABLED) \ 129 NEAREST_NEIGHGBOR8 \ 130 else if (config.interpolation == INTERPOLATION_LINEAR) \ 131 LINEAR_INTERPOLATION8(frac) \ 132 else \ 133 CUBIC_INTERPOLATION8_LOOP(pos, frac) \ 134 sample = (int32_t)roundf((float)sample * s->fVolume); \ 135 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ 136 137 #define INTERPOLATE_SMP16_LOOP(pos, frac) \ 138 const int16_t *s16 = s->base16 + pos; \ 139 if (config.interpolation == INTERPOLATION_DISABLED) \ 140 NEAREST_NEIGHGBOR16 \ 141 else if (config.interpolation == INTERPOLATION_LINEAR) \ 142 LINEAR_INTERPOLATION16(frac) \ 143 else \ 144 CUBIC_INTERPOLATION16_LOOP(pos, frac) \ 145 sample = (int32_t)roundf((float)sample * s->fVolume); \ 146 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ 147 148 #define SCOPE_GET_SMP8 \ 149 if (s->active) \ 150 { \ 151 sample = (int32_t)roundf((float)(s->base8[position] << 8) * s->fVolume); \ 152 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \ 153 } \ 154 else \ 155 { \ 156 sample = 0; \ 157 } 158 159 #define SCOPE_GET_SMP16 \ 160 if (s->active) \ 161 { \ 162 sample = (int32_t)roundf((float)s->base16[position] * s->fVolume); \ 163 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \ 164 } \ 165 else \ 166 { \ 167 sample = 0; \ 168 } 169 170 #define SCOPE_GET_SMP8_BIDI \ 171 if (s->active) \ 172 { \ 173 GET_BIDI_POSITION \ 174 sample = (int32_t)roundf((float)(s->base8[actualPos] << 8) * s->fVolume); \ 175 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \ 176 } \ 177 else \ 178 { \ 179 sample = 0; \ 180 } 181 182 #define SCOPE_GET_SMP16_BIDI \ 183 if (s->active) \ 184 { \ 185 GET_BIDI_POSITION \ 186 sample = (int32_t)roundf((float)s->base16[actualPos] * s->fVolume); \ 187 if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \ 188 } \ 189 else \ 190 { \ 191 sample = 0; \ 192 } 193 194 #define SCOPE_GET_INTERPOLATED_SMP8 \ 195 if (s->active) \ 196 { \ 197 INTERPOLATE_SMP8(position, (uint32_t)positionFrac) \ 198 } \ 199 else \ 200 { \ 201 sample = 0; \ 202 } 203 204 #define SCOPE_GET_INTERPOLATED_SMP16 \ 205 if (s->active) \ 206 { \ 207 INTERPOLATE_SMP16(position, (uint32_t)positionFrac) \ 208 } \ 209 else \ 210 { \ 211 sample = 0; \ 212 } 213 214 #define SCOPE_GET_INTERPOLATED_SMP8_LOOP \ 215 if (s->active) \ 216 { \ 217 INTERPOLATE_SMP8_LOOP(position, (uint32_t)positionFrac) \ 218 } \ 219 else \ 220 { \ 221 sample = 0; \ 222 } 223 224 #define SCOPE_GET_INTERPOLATED_SMP16_LOOP \ 225 if (s->active) \ 226 { \ 227 INTERPOLATE_SMP16_LOOP(position, (uint32_t)positionFrac) \ 228 } \ 229 else \ 230 { \ 231 sample = 0; \ 232 } 233 234 #define GET_BIDI_POSITION \ 235 if (samplingBackwards) \ 236 actualPos = (s->sampleEnd - 1) - (position - s->loopStart); \ 237 else \ 238 actualPos = position; 239 240 #define SCOPE_GET_INTERPOLATED_SMP8_BIDI \ 241 if (s->active) \ 242 { \ 243 GET_BIDI_POSITION \ 244 INTERPOLATE_SMP8_LOOP(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : (uint32_t)positionFrac) \ 245 } \ 246 else \ 247 { \ 248 sample = 0; \ 249 } 250 251 #define SCOPE_GET_INTERPOLATED_SMP16_BIDI \ 252 if (s->active) \ 253 { \ 254 GET_BIDI_POSITION \ 255 INTERPOLATE_SMP16_LOOP(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : (uint32_t)positionFrac) \ 256 } \ 257 else \ 258 { \ 259 sample = 0; \ 260 } 261 262 #define SCOPE_UPDATE_READPOS \ 263 positionFrac += s->drawDelta; \ 264 position += positionFrac >> 32; \ 265 positionFrac &= UINT32_MAX; 266 267 #define SCOPE_DRAW_SMP \ 268 video.frameBuffer[((lineY - sample) * SCREEN_W) + x] = color; 269 270 #define LINED_SCOPE_PREPARE_SMP8 \ 271 SCOPE_GET_INTERPOLATED_SMP8 \ 272 smpY1 = lineY - sample; \ 273 SCOPE_UPDATE_READPOS 274 275 #define LINED_SCOPE_PREPARE_SMP16 \ 276 SCOPE_GET_INTERPOLATED_SMP16 \ 277 smpY1 = lineY - sample; \ 278 SCOPE_UPDATE_READPOS 279 280 #define LINED_SCOPE_PREPARE_SMP8_LOOP \ 281 SCOPE_GET_INTERPOLATED_SMP8_LOOP \ 282 smpY1 = lineY - sample; \ 283 SCOPE_UPDATE_READPOS 284 285 #define LINED_SCOPE_PREPARE_SMP16_LOOP \ 286 SCOPE_GET_INTERPOLATED_SMP16_LOOP \ 287 smpY1 = lineY - sample; \ 288 SCOPE_UPDATE_READPOS 289 290 #define LINED_SCOPE_PREPARE_SMP8_BIDI \ 291 SCOPE_GET_INTERPOLATED_SMP8_BIDI \ 292 smpY1 = lineY - sample; \ 293 SCOPE_UPDATE_READPOS 294 295 #define LINED_SCOPE_PREPARE_SMP16_BIDI \ 296 SCOPE_GET_INTERPOLATED_SMP16_BIDI \ 297 smpY1 = lineY - sample; \ 298 SCOPE_UPDATE_READPOS 299 300 #define LINED_SCOPE_DRAW_SMP \ 301 smpY2 = lineY - sample; \ 302 scopeLine(x, smpY1, smpY2, color); \ 303 smpY1 = smpY2; 304 305 #define SCOPE_HANDLE_POS_NO_LOOP \ 306 if (position >= s->sampleEnd) \ 307 s->active = false; 308 309 #define SCOPE_HANDLE_POS_LOOP \ 310 if (position >= s->sampleEnd) \ 311 { \ 312 if (s->loopLength >= 2) \ 313 position = s->loopStart + ((uint32_t)(position - s->sampleEnd) % (uint32_t)s->loopLength); \ 314 else \ 315 position = s->loopStart; \ 316 \ 317 s->hasLooped = true; \ 318 } 319 320 #define SCOPE_HANDLE_POS_BIDI \ 321 if (position >= s->sampleEnd) \ 322 { \ 323 if (s->loopLength >= 2) \ 324 { \ 325 const uint32_t overflow = position - s->sampleEnd; \ 326 const uint32_t cycles = overflow / (uint32_t)s->loopLength; \ 327 const uint32_t phase = overflow % (uint32_t)s->loopLength; \ 328 \ 329 position = s->loopStart + phase; \ 330 samplingBackwards ^= !(cycles & 1); \ 331 } \ 332 else \ 333 { \ 334 position = s->loopStart; \ 335 } \ 336 \ 337 s->hasLooped = true; \ 338 }