| 17 | u8 v11, u8 dx, u8 dy); |
| 18 | |
| 19 | void upscaleRectangular(const CRGB *input, CRGB *output, u16 inputWidth, |
| 20 | u16 inputHeight, u16 outputWidth, u16 outputHeight) { |
| 21 | const u16 scale_factor = 256; // Using 8 bits for the fractional part |
| 22 | |
| 23 | for (u16 y = 0; y < outputHeight; y++) { |
| 24 | for (u16 x = 0; x < outputWidth; x++) { |
| 25 | // Calculate the corresponding position in the input grid |
| 26 | u32 fx = ((u32)x * (inputWidth - 1) * scale_factor) / |
| 27 | (outputWidth - 1); |
| 28 | u32 fy = ((u32)y * (inputHeight - 1) * scale_factor) / |
| 29 | (outputHeight - 1); |
| 30 | |
| 31 | u16 ix = fx / scale_factor; // Integer part of x |
| 32 | u16 iy = fy / scale_factor; // Integer part of y |
| 33 | u16 dx = fx % scale_factor; // Fractional part of x |
| 34 | u16 dy = fy % scale_factor; // Fractional part of y |
| 35 | |
| 36 | u16 ix1 = (ix + 1 < inputWidth) ? ix + 1 : ix; |
| 37 | u16 iy1 = (iy + 1 < inputHeight) ? iy + 1 : iy; |
| 38 | |
| 39 | // Direct array access - no XY mapping overhead |
| 40 | u16 i00 = iy * inputWidth + ix; |
| 41 | u16 i10 = iy * inputWidth + ix1; |
| 42 | u16 i01 = iy1 * inputWidth + ix; |
| 43 | u16 i11 = iy1 * inputWidth + ix1; |
| 44 | |
| 45 | CRGB c00 = input[i00]; |
| 46 | CRGB c10 = input[i10]; |
| 47 | CRGB c01 = input[i01]; |
| 48 | CRGB c11 = input[i11]; |
| 49 | |
| 50 | CRGB result; |
| 51 | result.r = bilinearInterpolate(c00.r, c10.r, c01.r, c11.r, dx, dy); |
| 52 | result.g = bilinearInterpolate(c00.g, c10.g, c01.g, c11.g, dx, dy); |
| 53 | result.b = bilinearInterpolate(c00.b, c10.b, c01.b, c11.b, dx, dy); |
| 54 | |
| 55 | // Direct array access - no XY mapping overhead |
| 56 | u16 idx = y * outputWidth + x; |
| 57 | output[idx] = result; |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | void upscaleRectangularPowerOf2(const CRGB *input, CRGB *output, u8 inputWidth, |
| 63 | u8 inputHeight, u8 outputWidth, u8 outputHeight) { |
no test coverage detected