aboutsummaryrefslogblamecommitdiffstats
path: root/libglitter_redistribute_energy_double.c
blob: ce889dee7982e904e4e13295131a3e4a6a1505ec (plain) (tree)
1
2
3
4
5
6
7
8
9





                                                         
                                                                                                                         
 
                       

                                                                                  

                                                   
                                                                     
                                                     
                                                                     



                                                       

                                                         
                                               

                                                         






                                                           








                                                                                                       

                                                  
         



           
                                                                                                                         
 
                       



                                                                                  


                                                               
                         

                                                       









                                                                                             






                                                                                             
                 




         
                                                                                                           
                                                                                                                           
 
                              
                                                      
                                                                                 
                                          




                                                                                 


















                                            


























































































                                                                                         



      
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST


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 && kernel[0] == kernel[1] && 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 - i - 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 && kernel[0] == kernel[1] && 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[15], vkern[15];
	size_t i;

	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]);

	/* TODO test edges */
	/* TODO test hkern+vkern */

	return 0;
}


#endif