ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

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 	}