INLINE void video_filter16(int *out_r, int *out_g, int *out_b, UINT16* vbuff, UINT8* hbuff, const UINT32 hres);
INLINE void divot_filter16(UINT8* r, UINT8* g, UINT8* b, UINT16* fbuff, UINT32 fbuff_index);
INLINE void restore_filter16(INT32* r, INT32* g, INT32* b, UINT16* fbuff, UINT32 fbuff_index, UINT32 hres);
INLINE void divot_filter16_buffer(INT32* r, INT32* g, INT32* b, N64::RDP::Color* vibuffer);
INLINE void restore_filter16_buffer(INT32* r, INT32* g, INT32* b, N64::RDP::Color* vibuff, UINT32 hres);
INLINE void restore_two(N64::RDP::Color* filtered, N64::RDP::Color* neighbour);
INLINE void video_max(UINT32* Pixels, UINT8* max, UINT32* enb);
INLINE UINT32 ge_two(UINT32 enb);
INLINE void video_filter16(int *out_r, int *out_g, int *out_b, UINT16* vbuff, UINT8* hbuff, const UINT32 hres)
{
N64::RDP::Color penumax, penumin, max, min;
UINT16 pix = *vbuff;
const UINT8 centercvg = (*hbuff & 3) + ((pix & 1) << 2) + 1;
UINT32 numoffull = 1;
UINT32 cvg;
UINT32 backr[7], backg[7], backb[7];
UINT32 invr[7], invg[7], invb[7];
INT32 coeff;
INT32 leftup = -hres - 2;
INT32 leftdown = hres - 2;
INT32 toleft = -2;
UINT32 colr, colg, colb;
UINT32 enb;
UINT32 r = ((pix >> 8) & 0xf8) | (pix >> 13);
UINT32 g = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
UINT32 b = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
*out_r = *out_g = *out_b = 0;
backr[0] = r;
backg[0] = g;
backb[0] = b;
invr[0] = ~r;
invg[0] = ~g;
invb[0] = ~b;
if (centercvg == 8)
{
*out_r = r;
*out_g = g;
*out_b = b;
return;
}
for(int i = 0; i < 5; i++)
{
pix = vbuff[leftup ^ WORD_ADDR_XOR];
cvg = hbuff[leftup ^ BYTE_ADDR_XOR] & 3;
if(i & 1)
{
if (cvg == 3 && (pix & 1))
{
backr[numoffull] = ((pix >> 8) & 0xf8) | (pix >> 13);
backg[numoffull] = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
backb[numoffull] = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
invr[numoffull] = ~backr[numoffull];
invg[numoffull] = ~backg[numoffull];
invb[numoffull] = ~backb[numoffull];
}
else
{
backr[numoffull] = invr[numoffull] = 0;
backg[numoffull] = invg[numoffull] = 0;
backb[numoffull] = invb[numoffull] = 0;
}
numoffull++;
}
leftup++;
}
for(int i = 0; i < 5; i++)
{
pix = vbuff[leftdown ^ WORD_ADDR_XOR];
cvg = hbuff[leftdown ^ BYTE_ADDR_XOR] & 3;
if (i&1)
{
if (cvg == 3 && (pix & 1))
{
backr[numoffull] = ((pix >> 8) & 0xf8) | (pix >> 13);
backg[numoffull] = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
backb[numoffull] = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
invr[numoffull] = ~backr[numoffull];
invg[numoffull] = ~backg[numoffull];
invb[numoffull] = ~backb[numoffull];
}
else
{
backr[numoffull] = invr[numoffull] = 0;
backg[numoffull] = invg[numoffull] = 0;
backb[numoffull] = invb[numoffull] = 0;
}
numoffull++;
}
leftdown++;
}
for(int i = 0; i < 5; i++)
{
pix = vbuff[toleft ^ WORD_ADDR_XOR];
cvg = hbuff[toleft ^ BYTE_ADDR_XOR] & 3;
if (!(i&3))
{
if (cvg == 3 && (pix & 1))
{
backr[numoffull] = ((pix >> 8) & 0xf8) | (pix >> 13);
backg[numoffull] = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
backb[numoffull] = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
invr[numoffull] = ~backr[numoffull];
invg[numoffull] = ~backg[numoffull];
invb[numoffull] = ~backb[numoffull];
}
else
{
backr[numoffull] = invr[numoffull] = 0;
backg[numoffull] = invg[numoffull] = 0;
backb[numoffull] = invb[numoffull] = 0;
}
numoffull++;
}
toleft++;
}
video_max(&backr[0], &max.i.r, &enb);
for(int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backr[i] = 0;
}
}
video_max(&backg[0], &max.i.g, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backg[i] = 0;
}
}
video_max(&backb[0], &max.i.b, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backb[i] = 0;
}
}
video_max(&invr[0], &min.i.r, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backr[i] = 0;
}
}
video_max(&invg[0], &min.i.g, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backg[i] = 0;
}
}
video_max(&invb[0], &min.i.b, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backb[i] = 0;
}
}
video_max(&backr[0], &penumax.i.r, &enb);
penumax.i.r = ge_two(enb) ? max.i.r : penumax.i.r;
video_max(&backg[0], &penumax.i.g, &enb);
penumax.i.g = ge_two(enb) ? max.i.g : penumax.i.g;
video_max(&backb[0], &penumax.i.b, &enb);
penumax.i.b = ge_two(enb) ? max.i.b : penumax.i.b;
video_max(&invr[0], &penumin.i.r, &enb);
penumin.i.r = ge_two(enb) ? min.i.r : penumin.i.r;
video_max(&invg[0], &penumin.i.g, &enb);
penumin.i.g = ge_two(enb) ? min.i.g : penumin.i.g;
video_max(&invb[0], &penumin.i.b, &enb);
penumin.i.b = ge_two(enb) ? min.i.b : penumin.i.b;
penumin.i.r = ~penumin.i.r;
penumin.i.g = ~penumin.i.g;
penumin.i.b = ~penumin.i.b;
colr = (UINT32)penumin.i.r + (UINT32)penumax.i.r - (r << 1);
colg = (UINT32)penumin.i.g + (UINT32)penumax.i.g - (g << 1);
colb = (UINT32)penumin.i.b + (UINT32)penumax.i.b - (b << 1);
coeff = 8 - centercvg;
colr = (((colr * coeff) + 4) >> 3) + r;
colg = (((colg * coeff) + 4) >> 3) + g;
colb = (((colb * coeff) + 4) >> 3) + b;
*out_r = colr & 0xff;
*out_g = colg & 0xff;
*out_b = colb & 0xff;
return;
}
// This needs to be fixed for endianness.
INLINE void divot_filter16(UINT8* r, UINT8* g, UINT8* b, UINT16* fbuff, UINT32 fbuff_index)
{
UINT8 leftr, leftg, leftb, rightr, rightg, rightb;
UINT16 leftpix, rightpix;
UINT16* next, *prev;
UINT32 Lsw = fbuff_index & 1;
next = (Lsw) ? (UINT16*)(fbuff - 1) : (UINT16*)(fbuff + 3);
prev = (Lsw) ? (UINT16*)(fbuff - 3) : (UINT16*)(fbuff + 1);
leftpix = *prev;
rightpix = *next;
//leftpix = *(fbuff - 1); //for BE targets
//rightpix = *(fbuff + 1);
leftr = ((leftpix >> 8) & 0xf8) | (leftpix >> 13);
leftg = ((leftpix >> 3) & 0xf8) | ((leftpix >> 8) & 0x07);
leftb = ((leftpix << 2) & 0xf8) | ((leftpix >> 3) & 0x07);
rightr = ((rightpix >> 8) & 0xf8) | (rightpix >> 13);
rightg = ((rightpix >> 3) & 0xf8) | ((rightpix >> 8) & 0x07);
rightb = ((rightpix << 2) & 0xf8) | ((rightpix >> 3) & 0x07);
if ((leftr >= *r && rightr >= leftr) || (leftr >= rightr && *r >= leftr))
{
*r = leftr; //left = median value
}
if ((rightr >= *r && leftr >= rightr) || (rightr >= leftr && *r >= rightr))
{
*r = rightr; //right = median, else *r itself is median
}
if ((leftg >= *g && rightg >= leftg) || (leftg >= rightg && *g >= leftg))
{
*g = leftg;
}
if ((rightg >= *g && leftg >= rightg) || (rightg >= leftg && *g >= rightg))
{
*g = rightg;
}
if ((leftb >= *b && rightb >= leftb) || (leftb >= rightb && *b >= leftb))
{
*b = leftb;
}
if ((rightb >= *b && leftb >= rightb) || (rightb >= leftb && *b >= rightb))
{
*b = rightb;
}
}
INLINE void divot_filter16_buffer(int* r, int* g, int* b, N64::RDP::Color* vibuffer)
{
N64::RDP::Color leftpix = vibuffer[-1];
N64::RDP::Color rightpix = vibuffer[1];
N64::RDP::Color filtered = *vibuffer;
*r = filtered.i.r;
*g = filtered.i.g;
*b = filtered.i.b;
UINT32 leftr = leftpix.i.r;
UINT32 leftg = leftpix.i.g;
UINT32 leftb = leftpix.i.b;
UINT32 rightr = rightpix.i.r;
UINT32 rightg = rightpix.i.g;
UINT32 rightb = rightpix.i.b;
if ((leftr >= *r && rightr >= leftr) || (leftr >= rightr && *r >= leftr))
{
*r = leftr; //left = median value
}
if ((rightr >= *r && leftr >= rightr) || (rightr >= leftr && *r >= rightr))
{
*r = rightr; //right = median, else *r itself is median
}
if ((leftg >= *g && rightg >= leftg) || (leftg >= rightg && *g >= leftg))
{
*g = leftg;
}
if ((rightg >= *g && leftg >= rightg) || (rightg >= leftg && *g >= rightg))
{
*g = rightg;
}
if ((leftb >= *b && rightb >= leftb) || (leftb >= rightb && *b >= leftb))
{
*b = leftb;
}
if ((rightb >= *b && leftb >= rightb) || (rightb >= leftb && *b >= rightb))
{
*b = rightb;
}
filtered.i.r = *r;
filtered.i.g = *g;
filtered.i.b = *b;
}
// Fix me.
INLINE void restore_filter16(int* r, int* g, int* b, UINT16* fbuff, UINT32 fbuff_index, UINT32 hres)
{
INT32 leftuppix = -hres - 1;
INT32 leftdownpix = hres - 1;
INT32 toleftpix = -1;
UINT8 tempr, tempg, tempb;
UINT16 pix;
int i;
UINT8 r5 = *r;
UINT8 g5 = *g;
UINT8 b5 = *b;
r5 &= ~7;
g5 &= ~7;
b5 &= ~7;
for (i = 0; i < 3; i++)
{
pix = fbuff[leftuppix ^ 1];
tempr = ((pix >> 8) & 0xf8) | (pix >> 13);
tempg = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
tempb = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
tempr &= ~7;
tempg &= ~7;
tempb &= ~7;
if (tempr > r5)
{
*r += 1;
}
if (tempr < r5)
{
*r -= 1;
}
if (tempg > g5)
{
*g += 1;
}
if (tempg < g5)
{
*g -= 1;
}
if (tempb > b5)
{
*b += 1;
}
if (tempb < b5)
{
*b -= 1;
}
leftuppix++;
}
for (i = 0; i < 3; i++)
{
pix = fbuff[leftdownpix ^ 1];
tempr = ((pix >> 8) & 0xf8) | (pix >> 13);
tempg = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
tempb = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
tempr &= ~7;
tempg &= ~7;
tempb &= ~7;
if (tempr > r5)
{
*r += 1;
}
if (tempr < r5)
{
*r -= 1;
}
if (tempg > g5)
{
*g += 1;
}
if (tempg < g5)
{
*g -= 1;
}
if (tempb > b5)
{
*b += 1;
}
if (tempb < b5)
{
*b -= 1;
}
leftdownpix++;
}
for(i = 0; i < 3; i++)
{
if (!(i & 1))
{
pix = fbuff[toleftpix ^ 1];
tempr = ((pix >> 8) & 0xf8) | (pix >> 13);
tempg = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
tempb = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
tempr &= ~7;
tempg &= ~7;
tempb &= ~7;
if (tempr > r5)
{
*r += 1;
}
if (tempr < r5)
{
*r -= 1;
}
if (tempg > g5)
{
*g += 1;
}
if (tempg < g5)
{
*g -= 1;
}
if (tempb > b5)
{
*b += 1;
}
if (tempb < b5)
{
*b -= 1;
}
}
toleftpix++;
}
}
INLINE void restore_filter16_buffer(INT32* r, INT32* g, INT32* b, N64::RDP::Color* vibuff, UINT32 hres)
{
N64::RDP::Color filtered;
N64::RDP::Color leftuppix, leftdownpix, leftpix;
N64::RDP::Color rightuppix, rightdownpix, rightpix;
N64::RDP::Color uppix, downpix;
INT32 ihres = (INT32)hres; //can't apply unary minus to unsigned
leftuppix = vibuff[-ihres - 1];
leftdownpix = vibuff[ihres - 1];
leftpix = vibuff[-1];
rightuppix = vibuff[-ihres + 1];
rightdownpix = vibuff[ihres + 1];
rightpix = vibuff[1];
uppix = vibuff[-ihres];
downpix = vibuff[ihres];
filtered = *vibuff;
restore_two(&filtered, &leftuppix);
restore_two(&filtered, &uppix);
restore_two(&filtered, &rightuppix);
restore_two(&filtered, &leftpix);
restore_two(&filtered, &rightpix);
restore_two(&filtered, &leftdownpix);
restore_two(&filtered, &downpix);
restore_two(&filtered, &rightdownpix);
*r = filtered.i.r;
*g = filtered.i.g;
*b = filtered.i.b;
if(*r < 0) *r = 0;
else if(*r > 255) *r = 255;
if(*g < 0) *g = 0;
else if(*g > 255) *g = 255;
if(*b < 0) *b = 0;
else if(*b > 255) *b = 255;
}
// This is wrong, only the 5 upper bits are compared.
INLINE void restore_two(N64::RDP::Color* filtered, N64::RDP::Color* neighbour)
{
if (neighbour->i.r > filtered->i.r)
{
filtered->i.r += 1;
}
if (neighbour->i.r < filtered->i.r)
{
filtered->i.r -= 1;
}
if (neighbour->i.g > filtered->i.g)
{
filtered->i.g += 1;
}
if (neighbour->i.g < filtered->i.g)
{
filtered->i.g -= 1;
}
if (neighbour->i.b > filtered->i.b)
{
filtered->i.b += 1;
}
if (neighbour->i.b < filtered->i.b)
{
filtered->i.b -= 1;
}
}
INLINE void video_max(UINT32* Pixels, UINT8* max, UINT32* enb)
{
int i;
int pos = 0;
*enb = 0;
for(i = 0; i < 7; i++)
{
if (Pixels[i] > Pixels[pos])
{
*enb += (1 << i);
pos = i;
}
else if (Pixels[i] < Pixels[pos])
{
*enb += (1 << i);
}
else
{
pos = i;
}
}
*max = Pixels[pos];
}
INLINE UINT32 ge_two(UINT32 enb)
{
if(enb & 1)
{
if(enb & 2)
return 1;
if(enb & 4)
return 1;
if(enb & 8)
return 1;
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 2)
{
if(enb & 4)
return 1;
if(enb & 8)
return 1;
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 4)
{
if(enb & 8)
return 1;
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 8)
{
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 16)
{
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 32)
{
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 64)
{
if(enb & 128)
return 1;
return 0;
}
return 0;
}