//fibe.h	FAST IIR BLUR ENGINE

/*
Copyright (C) 2011  Marko Cebokli    http://lea.hamradio.si/~s57uuu


 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

/*  
   NOTE: float_rgba must be declared externally as
 
 typedef struct
	{
	float r;
	float g;
	float b;
	float a;
	} float_rgba;

	--------------------------------
	   CONTENTS OF FIBE.H FILE:
	--------------------------------

calcab_lp1()	auxilliary function to calculate lowpass
		tap coefficients for FIBE-2

young_vliet()	auxilliary function to calculate tap coefs
		for Gauss approximation with FIBE-3

rep()		auxilliary function to calculate wraparound
		values for FIBE-2

fibe1o_8()	one tap quadrilateral IIR filter
		speed optimized C function
		includes 8bit/float conversions

fibe2o_8()	two tap quadrilateral IIR filter
		speed optimized C function
		includes 8bit/float conversions

fibe3_8()	three tap quadrilateral IIR filter
		includes 8bit/float conversions

The functions work internally with floats. I have included
the 8bit/float conversion into the first and last
processing loops, to avoid two additional cache polluting
and therefore time consuming "walks" through memory.

*/



//edge compensation average size
#define EDGEAVG 8

#include <sys/types.h>


//---------------------------------------------------------
//koeficienti za biquad lowpass  iz f in q
// f v Nyquistih    0.0 < f < 0.5
void calcab_lp1(float f, float q, float *a0, float *a1, float *a2, float *b0, float *b1, float *b2)
{
float a,b;

a=sinf(PI*f)/2.0/q;
b=cosf(PI*f);
*b0=(1.0-b)/2.0;
*b1=1.0-b;
*b2=(1.0-b)/2.0;
*a0=1.0+a;
*a1=-2.0*b;
*a2=1.0-a;
}

//---------------------------------------------------------
//3tap iir coefficients for Gauss approximation according to:
//Ian T. Young, Lucas J. van Vliet:
//Recursive implementation of the Gaussian filter
//Signal Processing 44 (1995) 139-151
// s=sigma    0.5 < s < 200.0
void young_vliet(float s, float *a0, float *a1, float *a2, float *a3)
{
float q;

q=0.0;
if (s>2.5)
	{
	q = 0.98711*s - 0.96330;
	}
else
	{	//to velja za s>0.5 !!!!
	q = 3.97156 - 4.14554*sqrtf(1.0-0.26891*s);
	}

*a0 = 1.57825 + 2.44413*q + 1.4281*q*q + 0.422205*q*q*q;
*a1 = 2.44413*q + 2.85619*q*q + 1.26661*q*q*q;
*a2 = -1.4281*q*q - 1.26661*q*q*q;
*a3 = 0.422205*q*q*q;
}

//---------------------------------------------------
//kompenzacija na desni
//c=0.0 "odziv na zacetno stanje" (zunaj crno)
//gain ni kompenziran
void rep(float v1, float v2, float c, float *i1, float *i2, int n,  float a1, float a2)
{
int i;
float lb[8192];

lb[0]=v1;lb[1]=v2;
for (i=2;i<n-2;i++)
	{
	lb[i]=c-a1*lb[i-1]-a2*lb[i-2];
	}

lb[n-2]=0.0;lb[n-1]=0.0;
for (i=n-3;i>=0;i--)
	{
	lb[i]=lb[i]-a1*lb[i+1]-a2*lb[i+2];
	}

*i1=lb[0]; *i2=lb[1];
}

//---------------------------------------------------------
// 1-tap IIR v 4 smereh
//optimized for speed
//loops rearanged for more locality (better cache hit ratio)
//outer (vertical) loop 2x unroll to break dependency chain
//simplified indexes
void fibe1o_8(const uint32_t* inframe, uint32_t* outframe, float_rgba *s, int w, int h, float a, int ec)
{
int i,j;
float b,g,g4,avg,avg1,cr,cg,cb,g4a,g4b;
int p,pw,pj,pwj,pww,pmw;

avg=EDGEAVG;	//koliko vzorcev za povprecje pri edge comp
avg1=1.0/avg;

g=1.0/(1.0-a);
g4=1.0/g/g/g/g;

//predpostavimo, da je "zunaj" crnina (nicle)
b=1.0/(1.0-a)/(1.0+a);

//prvih avg vrstic
for (i=0;i<avg;i++)
	{
	p=i*w;pw=p+w;
	if (ec!=0)
		{
		cr=0.0;cg=0.0;cb=0.0;
		for (j=0;j<avg;j++)
			{
			s[p+j].r=(float)(inframe[p+j]&0xFF);
			s[p+j].g=(float)((inframe[p+j]&0xFF00)>>8);
			s[p+j].b=(float)((inframe[p+j]&0xFF0000)>>16);
			cr=cr+s[p+j].r;
			cg=cg+s[p+j].g;
			cb=cb+s[p+j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[p].r=cr*g+b*(s[p].r-cr);
		s[p].g=cg*g+b*(s[p].g-cg);
		s[p].b=cb*g+b*(s[p].b-cb);
		}
	else
		for (j=0;j<avg;j++)
			{
			s[p+j].r=(float)(inframe[p+j]&0xFF);
			s[p+j].g=(float)((inframe[p+j]&0xFF00)>>8);
			s[p+j].b=(float)((inframe[p+j]&0xFF0000)>>16);
			}

	for (j=1;j<avg;j++)	//tja  (ze pretvorjeni)
		{
		s[p+j].r=s[p+j].r+a*s[p+j-1].r;
		s[p+j].g=s[p+j].g+a*s[p+j-1].g;
		s[p+j].b=s[p+j].b+a*s[p+j-1].b;
		}
	for (j=avg;j<w;j++)	//tja  (s pretvorbo)
		{
		s[p+j].r=(float)(inframe[p+j]&0xFF);
		s[p+j].g=(float)((inframe[p+j]&0xFF00)>>8);
		s[p+j].b=(float)((inframe[p+j]&0xFF0000)>>16);
		s[p+j].r=s[p+j].r+a*s[p+j-1].r;
		s[p+j].g=s[p+j].g+a*s[p+j-1].g;
		s[p+j].b=s[p+j].b+a*s[p+j-1].b;
		}

	if (ec!=0)
		{
		cr=0.0;cg=0.0;cb=0.0;
		for (j=w-avg;j<w;j++)
			{
			cr=cr+s[p+j].r;
			cg=cg+s[p+j].g;
			cb=cb+s[p+j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[pw-1].r=cr*g+b*(s[pw-1].r-cr);
		s[pw-1].g=cg*g+b*(s[pw-1].g-cg);
		s[pw-1].b=cb*g+b*(s[pw-1].b-cb);
		}
	else
		{
		s[pw-1].r=b*s[pw-1].r;
		s[pw-1].g=b*s[pw-1].g;
		s[pw-1].b=b*s[pw-1].b;
		}
	for (j=w-2;j>=0;j--)	//nazaj
		{
		s[p+j].r=a*s[p+j+1].r+s[p+j].r;
		s[p+j].g=a*s[p+j+1].g+s[p+j].g;
		s[p+j].b=a*s[p+j+1].b+s[p+j].b;
		}
	}

//prvih avg vrstic samo navzdol (nazaj so ze)
for (i=0;i<w;i++)
	{
	if (ec!=0)
		{
		cr=0.0;cg=0.0;cb=0.0;
		for (j=0;j<avg;j++)
			{
			cr=cr+s[i+w*j].r;
			cg=cg+s[i+w*j].g;
			cb=cb+s[i+w*j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[i].r=cr*g+b*(s[i].r-cr);
		s[i].g=cg*g+b*(s[i].g-cg);
		s[i].b=cb*g+b*(s[i].b-cb);
		}
	for (j=1;j<avg;j++)	//dol
		{
		s[i+j*w].r=s[i+j*w].r+a*s[i+w*(j-1)].r;
		s[i+j*w].g=s[i+j*w].g+a*s[i+w*(j-1)].g;
		s[i+j*w].b=s[i+j*w].b+a*s[i+w*(j-1)].b;
		}
	}

for (i=avg;i<h-1;i=i+2)	//po vrsticah navzdol
	{
	p=i*w; pw=p+w; pww=pw+w; pmw=p-w;
	if (ec!=0)
		{
		cr=0.0;cg=0.0;cb=0.0;
		for (j=0;j<avg;j++)
			{
			s[p+j].r=(float)(inframe[p+j]&0xFF);
			s[p+j].g=(float)((inframe[p+j]&0xFF00)>>8);
			s[p+j].b=(float)((inframe[p+j]&0xFF0000)>>16);
			cr=cr+s[p+j].r;
			cg=cg+s[p+j].g;
			cb=cb+s[p+j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[p].r=cr*g+b*(s[p].r-cr);
		s[p].g=cg*g+b*(s[p].g-cg);
		s[p].b=cb*g+b*(s[p].b-cb);
		cr=0.0;cg=0.0;cb=0.0;
		for (j=0;j<avg;j++)
			{
			s[pw+j].r=(float)(inframe[pw+j]&0xFF);
			s[pw+j].g=(float)((inframe[pw+j]&0xFF00)>>8);
			s[pw+j].b=(float)((inframe[pw+j]&0xFF0000)>>16);
			cr=cr+s[pw+j].r;
			cg=cg+s[pw+j].g;
			cb=cb+s[pw+j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[pw].r=cr*g+b*(s[pw].r-cr);
		s[pw].g=cg*g+b*(s[pw].g-cg);
		s[pw].b=cb*g+b*(s[pw].b-cb);
		}
	else
		{
		for (j=0;j<avg;j++)
			{
			s[p+j].r=(float)(inframe[p+j]&0xFF);
			s[p+j].g=(float)((inframe[p+j]&0xFF00)>>8);
			s[p+j].b=(float)((inframe[p+j]&0xFF0000)>>16);
			}
		for (j=0;j<avg;j++)
			{
			s[pw+j].r=(float)(inframe[pw+j]&0xFF);
			s[pw+j].g=(float)((inframe[pw+j]&0xFF00)>>8);
			s[pw+j].b=(float)((inframe[pw+j]&0xFF0000)>>16);
			}
		}
	for (j=1;j<avg;j++)	//tja  (ze pretvojeni)
		{
		pj=p+j;pwj=pw+j;
		s[pj].r=s[pj].r+a*s[pj-1].r;
		s[pj].g=s[pj].g+a*s[pj-1].g;
		s[pj].b=s[pj].b+a*s[pj-1].b;
		s[pwj].r=s[pwj].r+a*s[pwj-1].r;
		s[pwj].g=s[pwj].g+a*s[pwj-1].g;
		s[pwj].b=s[pwj].b+a*s[pwj-1].b;
		}
	for (j=avg;j<w;j++)	//tja  (s pretvorbo)
		{
		pj=p+j;pwj=pw+j;
		s[pj].r=(float)(inframe[pj]&0xFF);
		s[pj].g=(float)((inframe[pj]&0xFF00)>>8);
		s[pj].b=(float)((inframe[pj]&0xFF0000)>>16);
		s[pj].r=s[pj].r+a*s[pj-1].r;
		s[pj].g=s[pj].g+a*s[pj-1].g;
		s[pj].b=s[pj].b+a*s[pj-1].b;
		s[pwj].r=(float)(inframe[pwj]&0xFF);
		s[pwj].g=(float)((inframe[pwj]&0xFF00)>>8);
		s[pwj].b=(float)((inframe[pwj]&0xFF0000)>>16);
		s[pwj].r=s[pwj].r+a*s[pwj-1].r;
		s[pwj].g=s[pwj].g+a*s[pwj-1].g;
		s[pwj].b=s[pwj].b+a*s[pwj-1].b;
		}

	if (ec!=0)
		{
		cr=0.0;cg=0.0;cb=0.0;
		for (j=w-avg;j<w;j++)
			{
			cr=cr+s[p+j].r;
			cg=cg+s[p+j].g;
			cb=cb+s[p+j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[pw-1].r=cr*g+b*(s[pw-1].r-cr);
		s[pw-1].g=cg*g+b*(s[pw-1].g-cg);
		s[pw-1].b=cb*g+b*(s[pw-1].b-cb);
		cr=0.0;cg=0.0;cb=0.0;
		for (j=w-avg;j<w;j++)
			{
			cr=cr+s[pw+j].r;
			cg=cg+s[pw+j].g;
			cb=cb+s[pw+j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[pww-1].r=cr*g+b*(s[pww-1].r-cr);
		s[pww-1].g=cg*g+b*(s[pww-1].g-cg);
		s[pww-1].b=cb*g+b*(s[pww-1].b-cb);
		}
	else
		{
		s[pw-1].r=b*s[pw-1].r;	//rep H
		s[pw-1].g=b*s[pw-1].g;
		s[pw-1].b=b*s[pw-1].b;
		s[pww-1].r=b*s[pww-1].r;
		s[pww-1].g=b*s[pww-1].g;
		s[pww-1].b=b*s[pww-1].b;
		}

//zacetek na desni
	s[pw-2].r=s[pw-2].r+a*s[pw-1].r;	//nazaj
	s[pw-2].g=s[pw-2].g+a*s[pw-1].g;
	s[pw-2].b=s[pw-2].b+a*s[pw-1].b;
	s[pw-1].r=s[pw-1].r+a*s[p-1].r;		//dol
	s[pw-1].g=s[pw-1].g+a*s[p-1].g;
	s[pw-1].b=s[pw-1].b+a*s[p-1].b;

	for (j=w-2;j>=1;j--)	//nazaj
		{
		pj=p+j;pwj=pw+j;
		s[pj-1].r=a*s[pj].r+s[pj-1].r;
		s[pj-1].g=a*s[pj].g+s[pj-1].g;
		s[pj-1].b=a*s[pj].b+s[pj-1].b;
		s[pwj].r=a*s[pwj+1].r+s[pwj].r;
		s[pwj].g=a*s[pwj+1].g+s[pwj].g;
		s[pwj].b=a*s[pwj+1].b+s[pwj].b;
//zdaj naredi se en piksel vertikalno dol, za vse stolpce
//dva nazaj, da ne vpliva na H nazaj
		s[pj].r=s[pj].r+a*s[pmw+j].r;
		s[pj].g=s[pj].g+a*s[pmw+j].g;
		s[pj].b=s[pj].b+a*s[pmw+j].b;
		s[pwj+1].r=s[pwj+1].r+a*s[pj+1].r;
		s[pwj+1].g=s[pwj+1].g+a*s[pj+1].g;
		s[pwj+1].b=s[pwj+1].b+a*s[pj+1].b;
		}
//konec levo
	s[pw].r=s[pw].r+a*s[pw+1].r;	//nazaj
	s[pw].g=s[pw].g+a*s[pw+1].g;
	s[pw].b=s[pw].b+a*s[pw+1].b;
	s[p].r=s[p].r+a*s[pmw].r;	//dol
	s[p].g=s[p].g+a*s[pmw].g;
	s[p].b=s[p].b+a*s[pmw].b;
	s[pw+1].r=s[pw+1].r+a*s[p+1].r;	//dol
	s[pw+1].g=s[pw+1].g+a*s[p+1].g;
	s[pw+1].b=s[pw+1].b+a*s[p+1].b;
	s[pw].r=s[pw].r+a*s[p].r;	//dol
	s[pw].g=s[pw].g+a*s[p].g;
	s[pw].b=s[pw].b+a*s[p].b;
	}

//ce je sodo stevilo vrstic, moras zadnjo posebej
if (i!=h)
	{
	p=i*w; pw=p+w;
	for (j=1;j<w;j++)	//tja
		{
		s[p+j].r=s[p+j].r+a*s[p+j-1].r;
		s[p+j].g=s[p+j].g+a*s[p+j-1].g;
		s[p+j].b=s[p+j].b+a*s[p+j-1].b;
		}

	s[pw-1].r=b*s[pw-1].r;	//rep H
	s[pw-1].g=b*s[pw-1].g;
	s[pw-1].b=b*s[pw-1].b;

	for (j=w-2;j>=0;j--)	//nazaj in dol
		{
		s[p+j].r=a*s[p+j+1].r+s[p+j].r;
		s[p+j].g=a*s[p+j+1].g+s[p+j].g;
		s[p+j].b=a*s[p+j+1].b+s[p+j].b;

//zdaj naredi se en piksel vertikalno dol, za vse stolpce
//dva nazaj, da ne vpliva na H nazaj
		s[p+j+1].r=s[p+j+1].r+a*s[p-w+j+1].r;
		s[p+j+1].g=s[p+j+1].g+a*s[p-w+j+1].g;
		s[p+j+1].b=s[p+j+1].b+a*s[p-w+j+1].b;
		}
//levi piksel vert
	s[p].r=s[p].r+a*s[p-w].r;
	s[p].g=s[p].g+a*s[p-w].g;
	s[p].b=s[p].b+a*s[p-w].b;
	}

//zadnja vrstica (h-1)
g4b=g4*b;
g4a=g4/(1.0-a);
p=(h-1)*w;
if (ec!=0)
	{
	for (i=0;i<w;i++)	//po stolpcih
		{
		cr=0.0;cg=0.0;cb=0.0;
		for (j=h-avg;j<h;j++)
			{
			cr=cr+s[i+w*j].r;
			cg=cg+s[i+w*j].g;
			cb=cb+s[i+w*j].b;
			}
		cr=cr*avg1; cg=cg*avg1; cb=cb*avg1;
		s[i+p].r=g4a*cr+g4b*(s[i+p].r-cr);
		s[i+p].g=g4a*cg+g4b*(s[i+p].g-cg);
		s[i+p].b=g4a*cb+g4b*(s[i+p].b-cb);
		outframe[p+i]=((uint32_t)s[p+i].r&0xFF) + (((uint32_t)s[p+i].g&0xFF)<<8) + (((uint32_t)s[p+i].b&0xFF)<<16);
		}
	}
else
	{
	for (j=0;j<w;j++)	//po stolpcih
		{
		s[j+p].r=g4b*s[j+p].r;	//rep V
		s[j+p].g=g4b*s[j+p].g;
		s[j+p].b=g4b*s[j+p].b;
		outframe[p+j]=((uint32_t)s[p+j].r&0xFF) + (((uint32_t)s[p+j].g&0xFF)<<8) + (((uint32_t)s[p+j].b&0xFF)<<16);
		}
	}

for (i=h-2;i>=0;i--)	//po vrsticah navzgor
	{
	p=i*w; pw=p+w;
	for (j=0;j<w;j++)	//po stolpcih
		{
		s[p+j].r=a*s[pw+j].r+g4*s[p+j].r;
		s[p+j].g=a*s[pw+j].g+g4*s[p+j].g;
		s[p+j].b=a*s[pw+j].b+g4*s[p+j].b;
		outframe[p+j]=((uint32_t)s[p+j].r&0xFF) + (((uint32_t)s[p+j].g&0xFF)<<8) + (((uint32_t)s[p+j].b&0xFF)<<16);
		}
	}

}

//-------------------------------------------------------
// 2-tap IIR v stirih smereh   a only verzija, a0=1.0
//desno kompenzacijo izracuna direktno (rdx,rsx,rcx)
//optimized for speed
void fibe2o_8(const uint32_t* inframe, uint32_t* outframe, float_rgba s[], int w, int h, float a1, float a2,  float rd1, float rd2, float rs1, float rs2, float rc1, float rc2, int ec)
{
float cr,cg,cb,g,g4,avg,gavg,avgg,iavg;
float_rgba rep1,rep2;
int i,j;
int jw,jww,h1w,h2w,iw,i1w,i2w;

g=1.0/(1.0+a1+a2);
g4=1.0/g/g/g/g;
avg=EDGEAVG;	//koliko vzorcev za povprecje pri edge comp
gavg=g4/avg;
avgg=1.0/g/avg;
iavg=1.0/avg;

for (j=0;j<avg;j++)	//prvih avg vrstic tja in nazaj
	{
	jw=j*w; jww=jw+w;
	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp (popvprecje prvih)
		for (i=0;i<avg;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			cr=cr+s[jw+i].r;
			cg=cg+s[jw+i].g;
			cb=cb+s[jw+i].b;
			}
		cr=cr*gavg; cg=cg*gavg; cb=cb*gavg;
		}
	else
		for (i=0;i<avg;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			}

	s[jw].r=g4*s[jw].r-(a1+a2)*g*cr;
	s[jw].g=g4*s[jw].g-(a1+a2)*g*cg;
	s[jw].b=g4*s[jw].b-(a1+a2)*g*cb;
	s[jw+1].r=g4*s[jw+1].r-a1*s[jw].r-a2*g*cr;
	s[jw+1].g=g4*s[jw+1].g-a1*s[jw].g-a2*g*cg;
	s[jw+1].b=g4*s[jw+1].b-a1*s[jw].b-a2*g*cb;

	if (ec!=0)
		{	//edge comp za nazaj
		cr=0.0;cg=0.0;cb=0.0;
		for (i=w-avg;i<w;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			cr=cr+s[jw+i].r;
			cg=cg+s[jw+i].g;
			cb=cb+s[jw+i].b;
			}
		cr=cr*gavg; cg=cg*gavg; cb=cb*gavg;
		}
	else
		for (i=w-avg;i<w;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			}

	for (i=2;i<avg;i++)	//tja (ze pretv. levo)
		{
		s[jw+i].r=g4*s[jw+i].r-a1*s[jw+i-1].r-a2*s[jw+i-2].r;
		s[jw+i].g=g4*s[jw+i].g-a1*s[jw+i-1].g-a2*s[jw+i-2].g;
		s[jw+i].b=g4*s[jw+i].b-a1*s[jw+i-1].b-a2*s[jw+i-2].b;
		}

	for (i=avg;i<w-avg;i++)	//tja (s pretvorbo)
		{
		s[jw+i].r=(float)(inframe[jw+i]&0xFF);
		s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
		s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
		s[jw+i].r=g4*s[jw+i].r-a1*s[jw+i-1].r-a2*s[jw+i-2].r;
		s[jw+i].g=g4*s[jw+i].g-a1*s[jw+i-1].g-a2*s[jw+i-2].g;
		s[jw+i].b=g4*s[jw+i].b-a1*s[jw+i-1].b-a2*s[jw+i-2].b;
		}

	for (i=w-avg;i<w;i++)	//tja (ze pretv. desno)
		{
		s[jw+i].r=g4*s[jw+i].r-a1*s[jw+i-1].r-a2*s[jw+i-2].r;
		s[jw+i].g=g4*s[jw+i].g-a1*s[jw+i-1].g-a2*s[jw+i-2].g;
		s[jw+i].b=g4*s[jw+i].b-a1*s[jw+i-1].b-a2*s[jw+i-2].b;
		}

	rep1.r=(s[jww-1].r+s[jww-2].r)*0.5*rs1+(s[jww-1].r-s[jww-2].r)*rd1;
	rep1.g=(s[jww-1].g+s[jww-2].g)*0.5*rs1+(s[jww-1].g-s[jww-2].g)*rd1;
	rep1.b=(s[jww-1].b+s[jww-2].b)*0.5*rs1+(s[jww-1].b-s[jww-2].b)*rd1;
	rep2.r=(s[jww-1].r+s[jww-2].r)*0.5*rs2+(s[jww-1].r-s[jww-2].r)*rd2;
	rep2.g=(s[jww-1].g+s[jww-2].g)*0.5*rs2+(s[jww-1].g-s[jww-2].g)*rd2;
	rep2.b=(s[jww-1].b+s[jww-2].b)*0.5*rs2+(s[jww-1].b-s[jww-2].b)*rd2;

	if (ec!=0)
		{
		rep1.r=rep1.r+rc1*cr;
		rep1.g=rep1.g+rc1*cg;
		rep1.b=rep1.b+rc1*cb;
		rep2.r=rep2.r+rc2*cr;
		rep2.g=rep2.g+rc2*cg;
		rep2.b=rep2.b+rc2*cb;
		}

	s[jww-1].r=s[jww-1].r-a1*rep1.r-a2*rep2.r;
	s[jww-1].g=s[jww-1].g-a1*rep1.g-a2*rep2.g;
	s[jww-1].b=s[jww-1].b-a1*rep1.b-a2*rep2.b;
	s[jww-2].r=s[jww-2].r-a1*s[jww-1].r-a2*rep1.r;
	s[jww-2].g=s[jww-2].g-a1*s[jww-1].g-a2*rep1.g;
	s[jww-2].b=s[jww-2].b-a1*s[jww-1].b-a2*rep1.b;

	for (i=w-3;i>=0;i--)		//nazaj
		{
		s[jw+i].r=s[jw+i].r-a1*s[jw+i+1].r-a2*s[jw+i+2].r;
		s[jw+i].g=s[jw+i].g-a1*s[jw+i+1].g-a2*s[jw+i+2].g;
		s[jw+i].b=s[jw+i].b-a1*s[jw+i+1].b-a2*s[jw+i+2].b;
		}
	}	//prvih avg vrstic

//edge comp zgoraj za navzdol
for (j=0;j<w;j++)	//po stolpcih
	{
	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp (popvprecje prvih)
		for (i=0;i<avg;i++)
			{
			cr=cr+s[j+w*i].r;
			cg=cg+s[j+w*i].g;
			cb=cb+s[j+w*i].b;
			}
		cr=cr*iavg; cg=cg*iavg; cb=cb*iavg;
		}

//zgornji vrstici
	s[j].r=s[j].r-(a1+a2)*g*cr;
	s[j].g=s[j].g-(a1+a2)*g*cg;
	s[j].b=s[j].b-(a1+a2)*g*cb;
	s[j+w].r=s[j+w].r-a1*s[j].r-a2*g*cr;
	s[j+w].g=s[j+w].g-a1*s[j].g-a2*g*cg;
	s[j+w].b=s[j+w].b-a1*s[j].b-a2*g*cb;
	}

//tretja do avg, samo navzdol (nazaj so ze)
for (i=2;i<avg;i++)
	{
	iw=i*w; i1w=iw-w;
	for (j=0;j<w;j++)	//po stolpcih
		{
		s[j+iw].r=s[j+iw].r-a1*s[j+i1w].r-a2*s[j+i1w-w].r;
		s[j+iw].g=s[j+iw].g-a1*s[j+i1w].g-a2*s[j+i1w-w].g;
		s[j+iw].b=s[j+iw].b-a1*s[j+i1w].b-a2*s[j+i1w-w].b;
		}
	}

for (j=avg;j<h;j++)	//po vrsticah tja, nazaj in dol
	{
	jw=j*w; jww=jw+w;
	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp (popvprecje prvih)
		for (i=0;i<avg;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			cr=cr+s[jw+i].r;
			cg=cg+s[jw+i].g;
			cb=cb+s[jw+i].b;
			}
		cr=cr*gavg; cg=cg*gavg; cb=cb*gavg;
		}
	else
		for (i=0;i<avg;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			}
	s[jw].r=g4*s[jw].r-(a1+a2)*g*cr;
	s[jw].g=g4*s[jw].g-(a1+a2)*g*cg;
	s[jw].b=g4*s[jw].b-(a1+a2)*g*cb;
	s[jw+1].r=g4*s[jw+1].r-a1*s[jw].r-a2*g*cr;
	s[jw+1].g=g4*s[jw+1].g-a1*s[jw].g-a2*g*cg;
	s[jw+1].b=g4*s[jw+1].b-a1*s[jw].b-a2*g*cb;

	if (ec!=0)
		{	//edge comp za nazaj
		cr=0.0;cg=0.0;cb=0.0;
		for (i=w-avg;i<w;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			cr=cr+s[jw+i].r;
			cg=cg+s[jw+i].g;
			cb=cb+s[jw+i].b;
			}
		cr=cr*gavg; cg=cg*gavg; cb=cb*gavg;
		}
	else
		for (i=w-avg;i<w;i++)
			{
			s[jw+i].r=(float)(inframe[jw+i]&0xFF);
			s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
			s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
			}

	for (i=2;i<avg;i++)	//tja  (ze pretv. levo)
		{
		s[jw+i].r=g4*s[jw+i].r-a1*s[jw+i-1].r-a2*s[jw+i-2].r;
		s[jw+i].g=g4*s[jw+i].g-a1*s[jw+i-1].g-a2*s[jw+i-2].g;
		s[jw+i].b=g4*s[jw+i].b-a1*s[jw+i-1].b-a2*s[jw+i-2].b;
		}

	for (i=avg;i<w-avg;i++)	//tja  (s retvorbo)
		{
		s[jw+i].r=(float)(inframe[jw+i]&0xFF);
		s[jw+i].g=(float)((inframe[jw+i]&0xFF00)>>8);
		s[jw+i].b=(float)((inframe[jw+i]&0xFF0000)>>16);
		s[jw+i].r=g4*s[jw+i].r-a1*s[jw+i-1].r-a2*s[jw+i-2].r;
		s[jw+i].g=g4*s[jw+i].g-a1*s[jw+i-1].g-a2*s[jw+i-2].g;
		s[jw+i].b=g4*s[jw+i].b-a1*s[jw+i-1].b-a2*s[jw+i-2].b;
		}

	for (i=w-avg;i<w;i++)	//tja  (ze pretv. desno)
		{
		s[jw+i].r=g4*s[jw+i].r-a1*s[jw+i-1].r-a2*s[jw+i-2].r;
		s[jw+i].g=g4*s[jw+i].g-a1*s[jw+i-1].g-a2*s[jw+i-2].g;
		s[jw+i].b=g4*s[jw+i].b-a1*s[jw+i-1].b-a2*s[jw+i-2].b;
		}

	rep1.r=(s[jww-1].r+s[jww-2].r)*0.5*rs1+(s[jww-1].r-s[jww-2].r)*rd1;
	rep1.g=(s[jww-1].g+s[jww-2].g)*0.5*rs1+(s[jww-1].g-s[jww-2].g)*rd1;
	rep1.b=(s[jww-1].b+s[jww-2].b)*0.5*rs1+(s[jww-1].b-s[jww-2].b)*rd1;
	rep2.r=(s[jww-1].r+s[jww-2].r)*0.5*rs2+(s[jww-1].r-s[jww-2].r)*rd2;
	rep2.g=(s[jww-1].g+s[jww-2].g)*0.5*rs2+(s[jww-1].g-s[jww-2].g)*rd2;
	rep2.b=(s[jww-1].b+s[jww-2].b)*0.5*rs2+(s[jww-1].b-s[jww-2].b)*rd2;

	if (ec!=0)
		{
		rep1.r=rep1.r+rc1*cr;
		rep1.g=rep1.g+rc1*cg;
		rep1.b=rep1.b+rc1*cb;
		rep2.r=rep2.r+rc2*cr;
		rep2.g=rep2.g+rc2*cg;
		rep2.b=rep2.b+rc2*cb;
		}

	s[jww-1].r=s[jww-1].r-a1*rep1.r-a2*rep2.r;
	s[jww-1].g=s[jww-1].g-a1*rep1.g-a2*rep2.g;
	s[jww-1].b=s[jww-1].b-a1*rep1.b-a2*rep2.b;
	s[jww-2].r=s[jww-2].r-a1*s[jww-1].r-a2*rep1.r;
	s[jww-2].g=s[jww-2].g-a1*s[jww-1].g-a2*rep1.g;
	s[jww-2].b=s[jww-2].b-a1*s[jww-1].b-a2*rep1.b;

	for (i=w-3;i>=0;i--)	//po stolpcih
		{ //nazaj
		s[jw+i].r=s[jw+i].r-a1*s[jw+i+1].r-a2*s[jw+i+2].r;
		s[jw+i].g=s[jw+i].g-a1*s[jw+i+1].g-a2*s[jw+i+2].g;
		s[jw+i].b=s[jw+i].b-a1*s[jw+i+1].b-a2*s[jw+i+2].b;
//dol
		s[jw+i+2].r=s[jw+i+2].r-a1*s[jw-w+i+2].r-a2*s[jw-w-w+i+2].r;
		s[jw+i+2].g=s[jw+i+2].g-a1*s[jw-w+i+2].g-a2*s[jw-w-w+i+2].g;
		s[jw+i+2].b=s[jw+i+2].b-a1*s[jw-w+i+2].b-a2*s[jw-w-w+i+2].b;
		}

//se leva stolpca dol
	s[jw+1].r=s[jw+1].r-a1*s[jw-w+1].r-a2*s[jw-w-w+1].r;
	s[jw+1].g=s[jw+1].g-a1*s[jw-w+1].g-a2*s[jw-w-w+1].g;
	s[jw+1].b=s[jw+1].b-a1*s[jw-w+1].b-a2*s[jw-w-w+1].b;
	s[jw].r=s[jw].r-a1*s[jw-w].r-a2*s[jw-w-w].r;
	s[jw].g=s[jw].g-a1*s[jw-w].g-a2*s[jw-w-w].g;
	s[jw].b=s[jw].b-a1*s[jw-w].b-a2*s[jw-w-w].b;

	}	//po vrsticah

//pa se navzgor
//spodnji dve vrstici
h1w=(h-1)*w; h2w=(h-2)*w;
for (j=0;j<w;j++)	//po stolpcih
	{
	if (ec!=0)
		{	//edge comp za gor
		cr=0.0;cg=0.0;cb=0.0;
		for (i=h-avg;i<h;i++)
			{
			cr=cr+s[j+w*i].r;
			cg=cg+s[j+w*i].g;
			cb=cb+s[j+w*i].b;
			}
		cr=cr*avgg; cg=cg*avgg; cb=cb*avgg;
		}

	rep1.r=(s[j+h1w].r+s[j+h2w].r)*0.5*rs1+(s[j+h1w].r-s[j+h2w].r)*rd1;
	rep1.g=(s[j+h1w].g+s[j+h2w].g)*0.5*rs1+(s[j+h1w].g-s[j+h2w].g)*rd1;
	rep1.b=(s[j+h1w].b+s[j+h2w].b)*0.5*rs1+(s[j+h1w].b-s[j+h2w].b)*rd1;
	rep2.r=(s[j+h1w].r+s[j+h2w].r)*0.5*rs2+(s[j+h1w].r-s[j+h2w].r)*rd2;
	rep2.g=(s[j+h1w].g+s[j+h2w].g)*0.5*rs2+(s[j+h1w].g-s[j+h2w].g)*rd2;
	rep2.b=(s[j+h1w].b+s[j+h2w].b)*0.5*rs2+(s[j+h1w].b-s[j+h2w].b)*rd2;

	if (ec!=0)
		{	//edge comp
		rep1.r=rep1.r+rc1*cr;
		rep1.g=rep1.g+rc1*cg;
		rep1.b=rep1.b+rc1*cb;
		rep2.r=rep2.r+rc2*cr;
		rep2.g=rep2.g+rc2*cg;
		rep2.b=rep2.b+rc2*cb;
		}

	s[j+h1w].r=s[j+h1w].r-a1*rep1.r-a2*rep2.r;
	s[j+h1w].g=s[j+h1w].g-a1*rep1.g-a2*rep2.g;
	s[j+h1w].b=s[j+h1w].b-a1*rep1.b-a2*rep2.b;
	if (s[j+h1w].r>255) s[j+h1w].r=255.0;
	if (s[j+h1w].r<0.0) s[j+h1w].r=0.0;
	if (s[j+h1w].g>255) s[j+h1w].g=255.0;
	if (s[j+h1w].g<0.0) s[j+h1w].g=0.0;
	if (s[j+h1w].b>255) s[j+h1w].b=255.0;
	if (s[j+h1w].b<0.0) s[j+h1w].b=0.0;
	outframe[j+h1w]=((uint32_t)s[j+h1w].r&0xFF) + (((uint32_t)s[j+h1w].g&0xFF)<<8) + (((uint32_t)s[j+h1w].b&0xFF)<<16);
	s[j+h2w].r=s[j+h2w].r-a1*s[j+h1w].r-a2*rep1.r;
	s[j+h2w].g=s[j+h2w].g-a1*s[j+h1w].g-a2*rep1.g;
	s[j+h2w].b=s[j+h2w].b-a1*s[j+h1w].b-a2*rep1.b;
	if (s[j+h2w].r>255) s[j+h2w].r=255.0;
	if (s[j+h2w].r<0.0) s[j+h2w].r=0.0;
	if (s[j+h2w].g>255) s[j+h2w].g=255.0;
	if (s[j+h2w].g<0.0) s[j+h2w].g=0.0;
	if (s[j+h2w].b>255) s[j+h2w].b=255.0;
	if (s[j+h2w].b<0.0) s[j+h2w].b=0.0;
	outframe[j+h2w]=((uint32_t)s[j+h2w].r&0xFF) + (((uint32_t)s[j+h2w].g&0xFF)<<8) + (((uint32_t)s[j+h2w].b&0xFF)<<16);
	}

//ostale vrstice
for (i=h-3;i>=0;i--)		//gor
	{
	iw=i*w; i1w=iw+w; i2w=i1w+w;
	for (j=0;j<w;j++)
		{
		s[j+iw].r=s[j+iw].r-a1*s[j+i1w].r-a2*s[j+i2w].r;
		s[j+iw].g=s[j+iw].g-a1*s[j+i1w].g-a2*s[j+i2w].g;
		s[j+iw].b=s[j+iw].b-a1*s[j+i1w].b-a2*s[j+i2w].b;
		if (s[j+iw].r>255) s[j+iw].r=255.0;
		if (s[j+iw].r<0.0) s[j+iw].r=0.0;
		if (s[j+iw].g>255) s[j+iw].g=255.0;
		if (s[j+iw].g<0.0) s[j+iw].g=0.0;
		if (s[j+iw].b>255) s[j+iw].b=255.0;
		if (s[j+iw].b<0.0) s[j+iw].b=0.0;
		outframe[j+iw]=((uint32_t)s[j+iw].r&0xFF) + (((uint32_t)s[j+iw].g&0xFF)<<8) + (((uint32_t)s[j+iw].b&0xFF)<<16);
		}
	}

}

//-------------------------------------------------------
// 3-tap IIR v stirih smereh
//a only verzija, a0=1.0
//edge efekt na desni kompenzira tako, da racuna 256 vzorcev
//cez rob in in gre potem nazaj
void fibe3_8(const uint32_t* inframe, uint32_t* outframe, float_rgba s[], int w, int h, float a1, float a2, float a3, int ec)
{
float cr,cg,cb,g,g4,avg;
int i,j;
float_rgba lb[4096];
int cez;

g=1.0/(1.0+a1+a2+a3); g4=1.0/g/g/g/g;

avg=EDGEAVG;	//koliko vzorcev za povprecje pri edge comp
cez=256;	//koliko vzorcev gre cez na desni

for (j=0;j<h;j++)	//po vrsticah
	{
	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp (popvprecje prvih)
		for (i=0;i<avg;i++)
			{
			s[j*w+i].r=(float)(inframe[j*w+i]&0xFF);
			s[j*w+i].g=(float)((inframe[j*w+i]&0xFF00)>>8);
			s[j*w+i].b=(float)((inframe[j*w+i]&0xFF0000)>>16);
			cr=cr+s[j*w+i].r;
			cg=cg+s[j*w+i].g;
			cb=cb+s[j*w+i].b;
			}
		cr=g4*cr/avg; cg=g4*cg/avg; cb=g4*cb/avg;
		}
	else
		for (i=0;i<avg;i++)
			{
			s[j*w+i].r=(float)(inframe[j*w+i]&0xFF);
			s[j*w+i].g=(float)((inframe[j*w+i]&0xFF00)>>8);
			s[j*w+i].b=(float)((inframe[j*w+i]&0xFF0000)>>16);
			}
	lb[0].r=g4*s[j*w].r-(a1+a2+a3)*g*cr;
	lb[0].g=g4*s[j*w].g-(a1+a2+a3)*g*cg;
	lb[0].b=g4*s[j*w].b-(a1+a2+a3)*g*cb;
	lb[1].r=g4*s[j*w+1].r-a1*lb[0].r-(a2+a3)*g*cr;
	lb[1].g=g4*s[j*w+1].g-a1*lb[0].g-(a2+a3)*g*cg;
	lb[1].b=g4*s[j*w+1].b-a1*lb[0].b-(a2+a3)*g*cb;
	lb[2].r=g4*s[j*w+2].r-a1*lb[1].r-a2*lb[0].r-a3*g*cr;
	lb[2].g=g4*s[j*w+2].g-a1*lb[1].g-a2*lb[0].g-a3*g*cg;
	lb[2].b=g4*s[j*w+2].b-a1*lb[1].b-a2*lb[0].b-a3*g*cb;

	for (i=3;i<avg;i++)	//tja  (ze pretvorjeni)
		{
		lb[i].r=g4*s[j*w+i].r-a1*lb[i-1].r-a2*lb[i-2].r-a3*lb[i-3].r;
		lb[i].g=g4*s[j*w+i].g-a1*lb[i-1].g-a2*lb[i-2].g-a3*lb[i-3].g;
		lb[i].b=g4*s[j*w+i].b-a1*lb[i-1].b-a2*lb[i-2].b-a3*lb[i-3].b;
		}

	for (i=avg;i<w;i++)	//tja  (s pretvorbo)
		{
		s[j*w+i].r=(float)(inframe[j*w+i]&0xFF);
		s[j*w+i].g=(float)((inframe[j*w+i]&0xFF00)>>8);
		s[j*w+i].b=(float)((inframe[j*w+i]&0xFF0000)>>16);
		lb[i].r=g4*s[j*w+i].r-a1*lb[i-1].r-a2*lb[i-2].r-a3*lb[i-3].r;
		lb[i].g=g4*s[j*w+i].g-a1*lb[i-1].g-a2*lb[i-2].g-a3*lb[i-3].g;
		lb[i].b=g4*s[j*w+i].b-a1*lb[i-1].b-a2*lb[i-2].b-a3*lb[i-3].b;
		}

	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp
		for (i=w-avg;i<w;i++)
			{
			cr=cr+s[j*w+i].r;
			cg=cg+s[j*w+i].g;
			cb=cb+s[j*w+i].b;
			}
		cr=g4*cr/avg; cg=g4*cg/avg; cb=g4*cb/avg;
		}

	for (i=w;i<(w+cez);i++)	//naprej cez rob
		{
		lb[i].r=cr-a1*lb[i-1].r-a2*lb[i-2].r-a3*lb[i-3].r;
		lb[i].g=cr-a1*lb[i-1].g-a2*lb[i-2].g-a3*lb[i-3].g;
		lb[i].b=cr-a1*lb[i-1].b-a2*lb[i-2].b-a3*lb[i-3].b;
		}
	//nazaj do roba
	lb[w+cez-2].r=lb[w+cez-2].r-a1*lb[w+cez-1].r;
	lb[w+cez-2].g=lb[w+cez-2].g-a1*lb[w+cez-1].g;
	lb[w+cez-2].b=lb[w+cez-2].b-a1*lb[w+cez-1].b;
	lb[w+cez-3].r=lb[w+cez-3].r-a1*lb[w+cez-2].r-a2*lb[w+cez-1].r;
	lb[w+cez-3].g=lb[w+cez-3].g-a1*lb[w+cez-2].g-a2*lb[w+cez-1].g;
	lb[w+cez-3].b=lb[w+cez-3].b-a1*lb[w+cez-2].b-a2*lb[w+cez-1].b;
	for (i=(w+cez-4);i>=w;i--)
		{
		lb[i].r=lb[i].r-a1*lb[i+1].r-a2*lb[i+2].r-a3*lb[i+3].r;
		lb[i].g=lb[i].g-a1*lb[i+1].g-a2*lb[i+2].g-a3*lb[i+3].g;
		lb[i].b=lb[i].b-a1*lb[i+1].b-a2*lb[i+2].b-a3*lb[i+3].b;
		}

	s[j*w+w-1].r=lb[w-1].r-a1*lb[w].r-a2*lb[w+1].r-a3*lb[w+2].r;
	s[j*w+w-1].g=lb[w-1].g-a1*lb[w].g-a2*lb[w+1].g-a3*lb[w+2].g;
	s[j*w+w-1].b=lb[w-1].b-a1*lb[w].b-a2*lb[w+1].b-a3*lb[w+2].b;
	s[j*w+w-2].r=lb[w-2].r-a1*s[j*w+w-1].r-a2*lb[w].r-a3*lb[w+1].r;
	s[j*w+w-2].g=lb[w-2].g-a1*s[j*w+w-1].g-a2*lb[w].g-a3*lb[w+1].g;
	s[j*w+w-2].b=lb[w-2].b-a1*s[j*w+w-1].b-a2*lb[w].b-a3*lb[w+1].b;
	s[j*w+w-3].r=lb[w-3].r-a1*s[j*w+w-2].r-a2*s[j*w+w-1].r-a3*lb[w].r;
	s[j*w+w-3].g=lb[w-3].g-a1*s[j*w+w-2].g-a2*s[j*w+w-1].g-a3*lb[w].g;
	s[j*w+w-3].b=lb[w-3].b-a1*s[j*w+w-2].b-a2*s[j*w+w-1].b-a3*lb[w].b;

	for (i=w-4;i>=0;i--)		//nazaj
		{
		s[j*w+i].r=lb[i].r-a1*s[j*w+i+1].r-a2*s[j*w+i+2].r-a3*s[j*w+i+3].r;
		s[j*w+i].g=lb[i].g-a1*s[j*w+i+1].g-a2*s[j*w+i+2].g-a3*s[j*w+i+3].g;
		s[j*w+i].b=lb[i].b-a1*s[j*w+i+1].b-a2*s[j*w+i+2].b-a3*s[j*w+i+3].b;
		}
	}	//po vrsticah

for (j=0;j<w;j++)	//po stolpcih
	{
	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp (popvprecje prvih)
		for (i=0;i<avg;i++)
			{
			cr=cr+s[j+w*i].r;
			cg=cg+s[j+w*i].g;
			cb=cb+s[j+w*i].b;
			}
		cr=cr/avg; cg=cg/avg; cb=cb/avg;
		}
	lb[0].r=s[j].r-(a1+a2+a3)*g*cr;
	lb[0].g=s[j].g-(a1+a2+a3)*g*cg;
	lb[0].b=s[j].b-(a1+a2+a3)*g*cb;
	lb[1].r=s[j+w].r-a1*lb[0].r-(a2+a3)*g*cr;
	lb[1].g=s[j+w].g-a1*lb[0].g-(a2+a3)*g*cg;
	lb[1].b=s[j+w].b-a1*lb[0].b-(a2+a3)*g*cb;
	lb[2].r=s[j+2*w].r-a1*lb[1].r-a2*lb[0].r-a3*g*cr;
	lb[2].g=s[j+2*w].g-a1*lb[1].g-a2*lb[0].g-a3*g*cg;
	lb[2].b=s[j+2*w].b-a1*lb[1].b-a2*lb[0].b-a3*g*cb;

	for (i=3;i<h;i++)		//dol
		{
		lb[i].r=s[j+w*i].r-a1*lb[i-1].r-a2*lb[i-2].r-a3*lb[i-3].r;
		lb[i].g=s[j+w*i].g-a1*lb[i-1].g-a2*lb[i-2].g-a3*lb[i-3].g;
		lb[i].b=s[j+w*i].b-a1*lb[i-1].b-a2*lb[i-2].b-a3*lb[i-3].b;
		}

	cr=0.0;cg=0.0;cb=0.0;
	if (ec!=0)
		{	//edge comp
		for (i=h-avg;i<h;i++)
			{
			cr=cr+s[j+w*i].r;
			cg=cg+s[j+w*i].g;
			cb=cb+s[j+w*i].b;
			}
		cr=cr/avg; cg=cg/avg; cb=cb/avg;
		}

	for (i=h;i<(h+cez);i++)	//naprej cez rob
		{
		lb[i].r=cr-a1*lb[i-1].r-a2*lb[i-2].r-a3*lb[i-3].r;
		lb[i].g=cg-a1*lb[i-1].g-a2*lb[i-2].g-a3*lb[i-3].g;
		lb[i].b=cb-a1*lb[i-1].b-a2*lb[i-2].b-a3*lb[i-3].b;
		}
	//nazaj do roba
	lb[h+cez-2].r=lb[h+cez-2].r-a1*lb[h+cez-1].r;
	lb[h+cez-2].g=lb[h+cez-2].g-a1*lb[h+cez-1].g;
	lb[h+cez-2].b=lb[h+cez-2].b-a1*lb[h+cez-1].b;
	lb[h+cez-3].r=lb[h+cez-3].r-a1*lb[h+cez-2].r-a2*lb[h+cez-1].r;
	lb[h+cez-3].g=lb[h+cez-3].g-a1*lb[h+cez-2].g-a2*lb[h+cez-1].g;
	lb[h+cez-3].b=lb[h+cez-3].b-a1*lb[h+cez-2].b-a2*lb[h+cez-1].b;
	for (i=(h+cez-4);i>=h;i--)
		{
		lb[i].r=lb[i].r-a1*lb[i+1].r-a2*lb[i+2].r-a3*lb[i+3].r;
		lb[i].g=lb[i].g-a1*lb[i+1].g-a2*lb[i+2].g-a3*lb[i+3].g;
		lb[i].b=lb[i].b-a1*lb[i+1].b-a2*lb[i+2].b-a3*lb[i+3].b;
		}

	s[j+(h-1)*w].r=lb[h-1].r-a1*lb[h].r-a2*lb[h+1].r-a3*lb[h+2].r;
	s[j+(h-1)*w].g=lb[h-1].g-a1*lb[h].g-a2*lb[h+1].g-a3*lb[h+2].g;
	s[j+(h-1)*w].b=lb[h-1].b-a1*lb[h].b-a2*lb[h+1].b-a3*lb[h+2].b;
	s[j+(h-2)*w].r=lb[h-2].r-a1*s[j+(h-1)*w].r-a2*lb[h].r-a3*lb[h+1].r;
	s[j+(h-2)*w].g=lb[h-2].g-a1*s[j+(h-1)*w].g-a2*lb[h].g-a3*lb[h+1].g;
	s[j+(h-2)*w].b=lb[h-2].b-a1*s[j+(h-1)*w].b-a2*lb[h].b-a3*lb[h+1].b;
	s[j+(h-3)*w].r=lb[h-3].r-a1*s[j+(h-2)*w].r-a2*s[j+(h-1)*w].r-a3*lb[h].r;
	s[j+(h-3)*w].g=lb[h-3].g-a1*s[j+(h-2)*w].g-a2*s[j+(h-1)*w].g-a3*lb[h].g;
	s[j+(h-3)*w].b=lb[h-3].b-a1*s[j+(h-2)*w].b-a2*s[j+(h-1)*w].b-a3*lb[h].b;

	for (i=h-4;i>=0;i--)		//gor
		{
		s[j+w*i].r=lb[i].r-a1*s[j+w*(i+1)].r-a2*s[j+w*(i+2)].r-a3*s[j+w*(i+3)].r;
		s[j+w*i].g=lb[i].g-a1*s[j+w*(i+1)].g-a2*s[j+w*(i+2)].g-a3*s[j+w*(i+3)].g;
		s[j+w*i].b=lb[i].b-a1*s[j+w*(i+1)].b-a2*s[j+w*(i+2)].b-a3*s[j+w*(i+3)].b;
		outframe[j+w*i]=((uint32_t)s[j+w*i].r&0xFF) + (((uint32_t)s[j+w*i].g&0xFF)<<8) + (((uint32_t)s[j+w*i].b&0xFF)<<16);
		}
	}	//po stolpcih

}


