ft2-clone

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

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 };