/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef TEST #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wfloat-equal" #elif defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wfloat-equal" #endif static int exactly(double a, double b) { return a == b; } #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic pop #elif defined(__clang__) # pragma clang diagnostic pop #endif static void vconvolute(double *restrict raster, size_t rowsize, size_t width, size_t height, size_t kernelsize, const double *kernel) { size_t y, x, i; if (kernelsize == 3 && exactly(kernel[0], kernel[1]) && exactly(kernel[1], kernel[2])) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) raster[x] += raster[x + 1 * rowsize]; for (x = 0; x < width; x++) { raster[x] += raster[x + 2 * rowsize]; raster[x] *= kernel[0]; } raster = &raster[rowsize]; } for (x = 0; x < width; x++) { raster[x] += raster[x + rowsize]; raster[x] *= kernel[0]; raster[x + rowsize] *= kernel[0]; } } else { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) raster[x] *= kernel[0]; for (i = 1; i < kernelsize; i++) for (x = 0; x < width; x++) raster[x] = fma(raster[x + i * rowsize], kernel[i], raster[x]); raster = &raster[rowsize]; } for (y = 0; y < kernelsize - 1; y++) { for (x = 0; x < width; x++) raster[x] *= kernel[0]; for (i = 1; i < kernelsize - 1 - y; i++) for (x = 0; x < width; x++) raster[x] = fma(raster[x + i * rowsize], kernel[i], raster[x]); raster = &raster[rowsize]; } } } static void hconvolute(double *restrict raster, size_t rowsize, size_t width, size_t height, size_t kernelsize, const double *kernel) { size_t y, x, i; if (kernelsize == 3 && exactly(kernel[0], kernel[1]) && exactly(kernel[1], kernel[2])) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { raster[x + 1] += raster[x + 2]; raster[x] += raster[x + 2]; raster[x] *= kernel[0]; } raster[width] *= kernel[0]; raster[width + 1] *= kernel[0]; raster = &raster[rowsize]; } } else { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { raster[x] *= kernel[0]; for (i = 1; i < kernelsize; i++) raster[x] = fma(raster[x + i], kernel[i], raster[x]); } raster = &raster[width]; for (x = 0; x < kernelsize - 1; x++) { raster[x] *= kernel[0]; for (i = 1; i < kernelsize - 1 - x; i++) raster[x] = fma(raster[x + i], kernel[i], raster[x]); } raster = &raster[rowsize - width]; } } } void libglitter_redistribute_energy_double(double *restrict raster, size_t rowsize, size_t width, size_t height, size_t hkernelsize, size_t vkernelsize, const double *hkernel, const double *vkernel) { if (vkernelsize > 1) { raster -= (vkernelsize - 1) * rowsize; vconvolute(raster, rowsize, width, height, vkernelsize, vkernel); height += vkernelsize - 1; } if (hkernelsize > 1) { raster -= hkernelsize - 1; hconvolute(raster, rowsize, width, height, hkernelsize, hkernel); width += hkernelsize - 1; } } #else #define TOLERANCE 0.0001 static int eq(double a, double b) { double r = a - b; return (r < 0 ? -r : r) < TOLERANCE; } int main(void) { double raster[100], hkern[5], vkern[5]; size_t i, j; for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) raster[i] = (double)i; hkern[0] = vkern[0] = 0; libglitter_redistribute_energy_double(&raster[11], 10, 7, 8, 1, 1, NULL, NULL); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) ASSERT(raster[i] == (double)i); libglitter_redistribute_energy_double(&raster[11], 10, 7, 8, 1, 1, hkern, NULL); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) ASSERT(raster[i] == (double)i); libglitter_redistribute_energy_double(&raster[11], 10, 7, 8, 1, 1, NULL, vkern); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) ASSERT(raster[i] == (double)i); libglitter_redistribute_energy_double(&raster[11], 10, 7, 8, 1, 1, hkern, vkern); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) ASSERT(raster[i] == (double)i); memset(raster, 0, sizeof(raster)); raster[53] = 1; raster[57] = 2; hkern[0] = 1 / 3.; hkern[1] = 1 / 3.; hkern[2] = 1 / 3.; libglitter_redistribute_energy_double(&raster[12], 10, 7, 8, 3, 1, hkern, NULL); ASSERT(eq(raster[52 - 1], 1 / 3.)); ASSERT(eq(raster[53 - 1], 1 / 3.)); ASSERT(eq(raster[54 - 1], 1 / 3.)); ASSERT(eq(raster[56 - 1], 2 / 3.)); ASSERT(eq(raster[57 - 1], 2 / 3.)); ASSERT(eq(raster[58 - 1], 2 / 3.)); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) if (!(51 <= i && i <= 53) && !(55 <= i && i <= 57)) ASSERT(!raster[i]); memset(raster, 0, sizeof(raster)); raster[53] = 1; raster[57] = 2; hkern[0] = 1 / 4.; hkern[1] = 1 / 2.; hkern[2] = 1 / 4.; libglitter_redistribute_energy_double(&raster[12], 10, 7, 8, 3, 1, hkern, NULL); ASSERT(eq(raster[52 - 1], 1 / 4.)); ASSERT(eq(raster[53 - 1], 1 / 2.)); ASSERT(eq(raster[54 - 1], 1 / 4.)); ASSERT(eq(raster[56 - 1], 2 / 4.)); ASSERT(eq(raster[57 - 1], 2 / 2.)); ASSERT(eq(raster[58 - 1], 2 / 4.)); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) if (!(51 <= i && i <= 53) && !(55 <= i && i <= 57)) ASSERT(!raster[i]); memset(raster, 0, sizeof(raster)); raster[35] = 1; raster[75] = 2; vkern[0] = 1 / 3.; vkern[1] = 1 / 3.; vkern[2] = 1 / 3.; libglitter_redistribute_energy_double(&raster[21], 10, 8, 7, 1, 3, NULL, vkern); ASSERT(eq(raster[25 - 10], 1 / 3.)); ASSERT(eq(raster[35 - 10], 1 / 3.)); ASSERT(eq(raster[45 - 10], 1 / 3.)); ASSERT(eq(raster[65 - 10], 2 / 3.)); ASSERT(eq(raster[75 - 10], 2 / 3.)); ASSERT(eq(raster[85 - 10], 2 / 3.)); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) if (i != 15 && i != 25 && i != 35 && i != 55 && i != 65 && i != 75) ASSERT(!raster[i]); memset(raster, 0, sizeof(raster)); raster[35] = 1; raster[75] = 2; vkern[0] = 1 / 4.; vkern[1] = 1 / 2.; vkern[2] = 1 / 4.; libglitter_redistribute_energy_double(&raster[21], 10, 8, 7, 1, 3, NULL, vkern); ASSERT(eq(raster[25 - 10], 1 / 4.)); ASSERT(eq(raster[35 - 10], 1 / 2.)); ASSERT(eq(raster[45 - 10], 1 / 4.)); ASSERT(eq(raster[65 - 10], 2 / 4.)); ASSERT(eq(raster[75 - 10], 2 / 2.)); ASSERT(eq(raster[85 - 10], 2 / 4.)); for (i = 0; i < sizeof(raster) / sizeof(*raster); i++) if (i != 15 && i != 25 && i != 35 && i != 55 && i != 65 && i != 75) ASSERT(!raster[i]); memset(raster, 0, sizeof(raster)); for (j = 20; j < 100; j += 10) for (i = 2; i < 10; i += 1) raster[j + i] = 1; vkern[0] = 1 / 3.; vkern[1] = 1 / 3.; vkern[2] = 1 / 3.; hkern[0] = 1 / 3.; hkern[1] = 1 / 3.; hkern[2] = 1 / 3.; libglitter_redistribute_energy_double(&raster[22], 10, 8, 8, 3, 3, hkern, vkern); for (j = 0; j < 100; j += 10) for (i = 0; i < 10; i += 1) ASSERT(eq(raster[j + i], ((i == 0 || i == 9) ? 1 / 3. : (i == 1 || i == 8) ? 2 / 3. : 1.) * ((j == 0 || j == 90) ? 1 / 3. : (j == 10 || j == 80) ? 2 / 3. : 1.))); memset(raster, 0, sizeof(raster)); for (j = 20; j < 100; j += 10) for (i = 2; i < 10; i += 1) raster[j + i] = 1; vkern[0] = 1 / 3.; vkern[1] = 1 / 3.; vkern[2] = 1 / 3.; hkern[0] = 2 / 9.; hkern[1] = 5 / 9.; hkern[2] = 2 / 9.; libglitter_redistribute_energy_double(&raster[22], 10, 8, 8, 3, 3, hkern, vkern); for (j = 0; j < 100; j += 10) for (i = 0; i < 10; i += 1) ASSERT(eq(raster[j + i], ((i == 0 || i == 9) ? 2 / 9. : (i == 1 || i == 8) ? 7 / 9. : 1.) * ((j == 0 || j == 90) ? 1 / 3. : (j == 10 || j == 80) ? 2 / 3. : 1.))); memset(raster, 0, sizeof(raster)); for (j = 20; j < 100; j += 10) for (i = 2; i < 10; i += 1) raster[j + i] = 1; vkern[0] = 2 / 9.; vkern[1] = 5 / 9.; vkern[2] = 2 / 9.; hkern[0] = 1 / 3.; hkern[1] = 1 / 3.; hkern[2] = 1 / 3.; libglitter_redistribute_energy_double(&raster[22], 10, 8, 8, 3, 3, hkern, vkern); for (j = 0; j < 100; j += 10) for (i = 0; i < 10; i += 1) ASSERT(eq(raster[j + i], ((i == 0 || i == 9) ? 1 / 3. : (i == 1 || i == 8) ? 2 / 3. : 1.) * ((j == 0 || j == 90) ? 2 / 9. : (j == 10 || j == 80) ? 7 / 9. : 1.))); memset(raster, 0, sizeof(raster)); for (j = 20; j < 100; j += 10) for (i = 2; i < 10; i += 1) raster[j + i] = 1; vkern[0] = 2 / 9.; vkern[1] = 5 / 9.; vkern[2] = 2 / 9.; hkern[0] = 2 / 9.; hkern[1] = 5 / 9.; hkern[2] = 2 / 9.; libglitter_redistribute_energy_double(&raster[22], 10, 8, 8, 3, 3, hkern, vkern); for (j = 0; j < 100; j += 10) for (i = 0; i < 10; i += 1) ASSERT(eq(raster[j + i], ((i == 0 || i == 9) ? 2 / 9. : (i == 1 || i == 8) ? 7 / 9. : 1.) * ((j == 0 || j == 90) ? 2 / 9. : (j == 10 || j == 80) ? 7 / 9. : 1.))); memset(raster, 0, sizeof(raster)); for (j = 40; j < 100; j += 10) for (i = 4; i < 10; i += 1) raster[j + i] = 1; vkern[0] = 1 / 5.; vkern[1] = 1 / 5.; vkern[2] = 1 / 5.; vkern[3] = 1 / 5.; vkern[4] = 1 / 5.; hkern[0] = 1 / 9.; hkern[1] = 2 / 9.; hkern[2] = 3 / 9.; hkern[3] = 2 / 9.; hkern[4] = 1 / 9.; libglitter_redistribute_energy_double(&raster[44], 10, 6, 6, 5, 5, hkern, vkern); for (j = 0; j < 100; j += 10) for (i = 0; i < 10; i += 1) ASSERT(eq(raster[j + i], ((i == 0 || i == 9) ? 1 / 9. : (i == 1 || i == 8) ? 3 / 9. : (i == 2 || i == 7) ? 6 / 9. : (i == 3 || i == 6) ? 8 / 9. : 1.) * ((j == 0 || j == 90) ? 1 / 5. : (j == 10 || j == 80) ? 2 / 5. : (j == 20 || j == 70) ? 3 / 5. : (j == 30 || j == 60) ? 4 / 5. : 1.))); return 0; } #endif