/*
 *  Copyright (C) 2009-2022 Exult Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA  02111-1307, USA.
 */

#ifndef INCL_SCALE_2XSAI_H
#define INCL_SCALE_2XSAI_H 1

/**
 ** Note: This file should only be included by source files that use the
 ** templates below; the templates will only be instantiated when they
 ** are used anyway.
 **/

/**
 ** 2xSaI scaling filter source code adapted for Exult
 ** August 29 2000, originally written in May 1999
 ** by Derek Liauw Kie Fa
 *(DerekL666@yahoo.com/D.A.K.L.LiauwKieFa@student.tudelft.nl)
 ** This source is made available under the terms of the GNU GPL
 ** I'd appreciate it I am given credit in the program or documentation
 **/

template <class Source_pixel, class Dest_pixel, class Manip_pixels>
inline Dest_pixel Interpolate_2xSaI(
		Source_pixel colorA, Source_pixel colorB, const Manip_pixels& manip) {
	unsigned int r0;
	unsigned int r1;
	unsigned int g0;
	unsigned int g1;
	unsigned int b0;
	unsigned int b1;
	manip.split_source(colorA, r0, g0, b0);
	manip.split_source(colorB, r1, g1, b1);
	int r = (r0 + r1) >> 1;
	int g = (g0 + g1) >> 1;
	int b = (b0 + b1) >> 1;
	return manip.rgb(r, g, b);
}

template <class Source_pixel, class Dest_pixel, class Manip_pixels>
inline Dest_pixel OInterpolate_2xSaI(
		Source_pixel colorA, Source_pixel colorB, Source_pixel colorC,
		const Manip_pixels& manip) {
	unsigned int r0;
	unsigned int r1;
	unsigned int g0;
	unsigned int g1;
	unsigned int b0;
	unsigned int b1;
	unsigned int r2;
	unsigned int g2;
	unsigned int b2;
	manip.split_source(colorA, r0, g0, b0);
	manip.split_source(colorB, r1, g1, b1);
	manip.split_source(colorC, r2, g2, b2);
	unsigned int r = ((r0 << 2) + (r0 << 1) + r1 + r2) >> 3;
	unsigned int g = ((g0 << 2) + (g0 << 1) + g1 + g2) >> 3;
	unsigned int b = ((b0 << 2) + (b0 << 1) + b1 + b2) >> 3;
	return manip.rgb(r, g, b);
}

template <class Source_pixel, class Dest_pixel, class Manip_pixels>
inline Dest_pixel QInterpolate_2xSaI(
		Source_pixel colorA, Source_pixel colorB, Source_pixel colorC,
		Source_pixel colorD, const Manip_pixels& manip) {
	unsigned int r0;
	unsigned int r1;
	unsigned int g0;
	unsigned int g1;
	unsigned int b0;
	unsigned int b1;
	unsigned int r2;
	unsigned int r3;
	unsigned int g2;
	unsigned int g3;
	unsigned int b2;
	unsigned int b3;
	manip.split_source(colorA, r0, g0, b0);
	manip.split_source(colorB, r1, g1, b1);
	manip.split_source(colorC, r2, g2, b2);
	manip.split_source(colorD, r3, g3, b3);
	unsigned int r = (r0 + r1 + r2 + r3) >> 2;
	unsigned int g = (g0 + g1 + g2 + g3) >> 2;
	unsigned int b = (b0 + b1 + b2 + b3) >> 2;
	return manip.rgb(r, g, b);
}

template <class Source_pixel>
inline int GetResult1(
		Source_pixel A, Source_pixel B, Source_pixel C, Source_pixel D) {
	int x = 0;
	int y = 0;
	int r = 0;
	if (A == C) {
		x += 1;
	} else if (B == C) {
		y += 1;
	}
	if (A == D) {
		x += 1;
	} else if (B == D) {
		y += 1;
	}
	if (x <= 1) {
		r += 1;
	}
	if (y <= 1) {
		r -= 1;
	}
	return r;
}

template <class Source_pixel>
inline int GetResult2(
		Source_pixel A, Source_pixel B, Source_pixel C, Source_pixel D) {
	int x = 0;
	int y = 0;
	int r = 0;
	if (A == C) {
		x += 1;
	} else if (B == C) {
		y += 1;
	}
	if (A == D) {
		x += 1;
	} else if (B == D) {
		y += 1;
	}
	if (x <= 1) {
		r -= 1;
	}
	if (y <= 1) {
		r += 1;
	}
	return r;
}

// 2xSaI scaler
template <class Source_pixel, class Dest_pixel, class Manip_pixels>
void Scale_2xSaI(
		Source_pixel* source,                // ->source pixels.
		int srcx, int srcy,                  // Start of rectangle within src.
		int srcw, int srch,                  // Dims. of rectangle.
		int                 sline_pixels,    // Pixels (words)/line for source.
		int                 sheight,         // Source height.
		Dest_pixel*         dest,            // ->dest pixels.
		int                 dline_pixels,    // Pixels (words)/line for dest.
		const Manip_pixels& manip            // Manipulator methods.
) {
	Source_pixel* srcPtr = source + (srcx + srcy * sline_pixels);
	Dest_pixel*   dstPtr = dest + (2 * srcy * dline_pixels + 2 * srcx);

	if (srcx + srcw >= sline_pixels) {
		srcw = sline_pixels - srcx;
	}
	// Init offset to prev. line, next 2.
	int prev1_yoff = srcy ? sline_pixels : 0;
	int next1_yoff = sline_pixels;
	int next2_yoff = 2 * sline_pixels;
	// Figure threshholds for counters.
	const int ybeforelast = sheight - 2 - srcy;
	const int xbeforelast = sline_pixels - 2 - srcx;
	for (int y = 0; y < srch; y++, prev1_yoff = sline_pixels) {
		if (y >= ybeforelast) {    // Last/next-to-last row?
			if (y == ybeforelast) {
				next2_yoff = sline_pixels;
			} else {    // Very last line?
				next2_yoff = next1_yoff = 0;
			}
		}

		Source_pixel* bP         = srcPtr;
		Dest_pixel*   dP         = dstPtr;
		int           prev1_xoff = srcx ? 1 : 0;
		int           next1_xoff = 1;
		int           next2_xoff = 2;

		for (int x = 0; x < srcw; x++) {
			Source_pixel colorA;
			Source_pixel colorB;
			Source_pixel colorC;
			Source_pixel colorD;
			Source_pixel colorE;
			Source_pixel colorF;
			Source_pixel colorG;
			Source_pixel colorH;
			Source_pixel colorI;
			Source_pixel colorJ;
			Source_pixel colorK;
			Source_pixel colorL;
			Source_pixel colorM;
			Source_pixel colorN;
			Source_pixel colorO /*, colorP*/;
			Dest_pixel   product;
			Dest_pixel   product1;
			Dest_pixel   product2;
			Dest_pixel   orig;

			// Last/next-to-last row?
			if (x >= xbeforelast) {
				if (x == xbeforelast) {
					next2_xoff = 1;
				} else {
					next2_xoff = next1_xoff = 0;
				}
			}

			//---------------------------------------
			// Map of the pixels:                    I|E F|J
			//                                       G|A B|K
			//                                       H|C D|L
			//                                       M|N O|P
			colorI = *(bP - prev1_yoff - prev1_xoff);
			colorE = *(bP - prev1_yoff);
			colorF = *(bP - prev1_yoff + next1_xoff);
			colorJ = *(bP - prev1_yoff + next2_xoff);

			colorG = *(bP - prev1_xoff);
			colorA = *(bP);
			colorB = *(bP + next1_xoff);
			colorK = *(bP + next2_xoff);

			colorH = *(bP + next1_yoff - prev1_xoff);
			colorC = *(bP + next1_yoff);
			colorD = *(bP + next1_yoff + next1_xoff);
			colorL = *(bP + next1_yoff + next2_xoff);

			colorM = *(bP + next2_yoff - prev1_xoff);
			colorN = *(bP + next2_yoff);
			colorO = *(bP + next2_yoff + next1_xoff);
			// colorP = *(bP + next2_yoff + next2_xoff);

			if ((colorA == colorD) && (colorB != colorC)) {
				if (((colorA == colorE) && (colorB == colorL))
					|| ((colorA == colorC) && (colorA == colorF)
						&& (colorB != colorE) && (colorB == colorJ))) {
					// product = colorA;
					manip.copy(product, colorA);
				} else {
					// product = INTERPOLATE(colorA, colorB);
					product = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorB, manip);
				}

				if (((colorA == colorG) && (colorC == colorO))
					|| ((colorA == colorB) && (colorA == colorH)
						&& (colorG != colorC) && (colorC == colorM))) {
					// product1 = colorA;
					manip.copy(product1, colorA);
				} else {
					// product1 = INTERPOLATE(colorA, colorC);
					product1 = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorC, manip);
				}
				// product2 = colorA;
				manip.copy(product2, colorA);
			} else if ((colorB == colorC) && (colorA != colorD)) {
				if (((colorB == colorF) && (colorA == colorH))
					|| ((colorB == colorE) && (colorB == colorD)
						&& (colorA != colorF) && (colorA == colorI))) {
					// product = colorB;
					manip.copy(product, colorB);
				} else {
					// product = INTERPOLATE(colorA, colorB);
					product = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorB, manip);
				}

				if (((colorC == colorH) && (colorA == colorF))
					|| ((colorC == colorG) && (colorC == colorD)
						&& (colorA != colorH) && (colorA == colorI))) {
					// product1 = colorC;
					manip.copy(product1, colorC);
				} else {
					// product1 = INTERPOLATE(colorA, colorC);
					product1 = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorC, manip);
				}
				// product2 = colorB;
				manip.copy(product2, colorB);
			} else if ((colorA == colorD) && (colorB == colorC)) {
				if (colorA == colorB) {
					// product = colorA;
					manip.copy(product, colorA);
					// product1 = colorA;
					manip.copy(product1, colorA);
					// product2 = colorA;
					manip.copy(product2, colorA);
				} else {
					int r = 0;
					// product1 = INTERPOLATE(colorA, colorC);
					product1 = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorC, manip);
					// product = INTERPOLATE(colorA, colorB);
					product = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorB, manip);

					r += GetResult1<Source_pixel>(
							colorA, colorB, colorG, colorE);
					r += GetResult2<Source_pixel>(
							colorB, colorA, colorK, colorF);
					r += GetResult2<Source_pixel>(
							colorB, colorA, colorH, colorN);
					r += GetResult1<Source_pixel>(
							colorA, colorB, colorL, colorO);

					if (r > 0) {
						// product2 = colorA;
						manip.copy(product2, colorA);
					} else if (r < 0) {
						// product2 = colorB;
						manip.copy(product2, colorB);
					} else {
						// product2 = Q_INTERPOLATE(colorA, colorB, colorC,
						// colorD);
						product2 = QInterpolate_2xSaI<
								Source_pixel, Dest_pixel, Manip_pixels>(
								colorA, colorB, colorC, colorD, manip);
					}
				}
			} else {
				// product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
				product2 = QInterpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						colorA, colorB, colorC, colorD, manip);

				if ((colorA == colorC) && (colorA == colorF)
					&& (colorB != colorE) && (colorB == colorJ)) {
					// product = colorA;
					manip.copy(product, colorA);
				} else if (
						(colorB == colorE) && (colorB == colorD)
						&& (colorA != colorF) && (colorA == colorI)) {
					// product = colorB;
					manip.copy(product, colorB);
				} else {
					// product = INTERPOLATE(colorA, colorB);
					product = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorB, manip);
				}

				if ((colorA == colorB) && (colorA == colorH)
					&& (colorG != colorC) && (colorC == colorM)) {
					// product1 = colorA;
					manip.copy(product1, colorA);
				} else if (
						(colorC == colorG) && (colorC == colorD)
						&& (colorA != colorH) && (colorA == colorI)) {
					// product1 = colorC;
					manip.copy(product1, colorC);
				} else {
					// product1 = INTERPOLATE(colorA, colorC);
					product1 = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							colorA, colorC, manip);
				}
			}

			// product = colorA | (product << 16);
			// product1 = product1 | (product2 << 16);
			manip.copy(orig, colorA);
			*dP                      = orig;
			*(dP + 1)                = product;
			*(dP + dline_pixels)     = product1;
			*(dP + dline_pixels + 1) = product2;

			bP += 1;
			dP += 2;
			prev1_xoff = 1;
		}    // end of for ( finish= width etc..)

		srcPtr += sline_pixels;
		dstPtr += 2 * dline_pixels;
		prev1_yoff = 1;
	}
}

template <class Source_pixel, class Dest_pixel, class Manip_pixels>
void Scale_Super2xSaI(
		Source_pixel* source,                // ->source pixels.
		int srcx, int srcy,                  // Start of rectangle within src.
		int srcw, int srch,                  // Dims. of rectangle.
		int                 sline_pixels,    // Pixels (words)/line for source.
		int                 sheight,         // Source height.
		Dest_pixel*         dest,            // ->dest pixels.
		int                 dline_pixels,    // Pixels (words)/line for dest.
		const Manip_pixels& manip            // Manipulator methods.
) {
	Source_pixel* srcPtr = source + (srcx + srcy * sline_pixels);
	Dest_pixel*   dstPtr = dest + (2 * srcy * dline_pixels + 2 * srcx);

	if (srcx + srcw >= sline_pixels) {
		srcw = sline_pixels - srcx;
	}

	const int ybeforelast1 = sheight - 1 - srcy;
	const int ybeforelast2 = sheight - 2 - srcy;
	const int xbeforelast1 = sline_pixels - 1 - srcx;
	const int xbeforelast2 = sline_pixels - 2 - srcx;

	for (int y = 0; y < srch; y++) {
		Source_pixel* bP = srcPtr;
		Dest_pixel*   dP = dstPtr;

		for (int x = 0; x < srcw; x++) {
			Source_pixel color4;
			Source_pixel color5;
			Source_pixel color6;
			Source_pixel color1;
			Source_pixel color2;
			Source_pixel color3;
			Source_pixel colorA0;
			Source_pixel colorA1;
			Source_pixel colorA2;
			Source_pixel colorA3;
			Source_pixel colorB0;
			Source_pixel colorB1;
			Source_pixel colorB2;
			Source_pixel colorB3;
			Source_pixel colorS1;
			Source_pixel colorS2;
			Dest_pixel   product1a;
			Dest_pixel   product1b;
			Dest_pixel   product2a;
			Dest_pixel   product2b;

			//---------------------------------------  B0 B1 B2 B3
			//                                         4  5  6  S2
			//                                         1  2  3  S1
			//                                         A0 A1 A2 A3
			//--------------------------------------
			int add1;
			int add2;
			int sub1;
			int nextl1;
			int nextl2;
			int prevl1;

			if (x == 0) {
				sub1 = 0;
			} else {
				sub1 = 1;
			}

			if (x >= xbeforelast2) {
				add2 = 0;
			} else {
				add2 = 1;
			}

			if (x >= xbeforelast1) {
				add1 = 0;
			} else {
				add1 = 1;
			}

			if (y == 0) {
				prevl1 = 0;
			} else {
				prevl1 = sline_pixels;
			}

			if (y >= ybeforelast2) {
				nextl2 = 0;
			} else {
				nextl2 = sline_pixels;
			}

			if (y >= ybeforelast1) {
				nextl1 = 0;
			} else {
				nextl1 = sline_pixels;
			}

			colorB0 = *(bP - prevl1 - sub1);
			colorB1 = *(bP - prevl1);
			colorB2 = *(bP - prevl1 + add1);
			colorB3 = *(bP - prevl1 + add1 + add2);

			color4  = *(bP - sub1);
			color5  = *(bP);
			color6  = *(bP + add1);
			colorS2 = *(bP + add1 + add2);

			color1  = *(bP + nextl1 - sub1);
			color2  = *(bP + nextl1);
			color3  = *(bP + nextl1 + add1);
			colorS1 = *(bP + nextl1 + add1 + add2);

			colorA0 = *(bP + nextl1 + nextl2 - sub1);
			colorA1 = *(bP + nextl1 + nextl2);
			colorA2 = *(bP + nextl1 + nextl2 + add1);
			colorA3 = *(bP + nextl1 + nextl2 + add1 + add2);

			if (color2 == color6 && color5 != color3) {
				// product2b = product1b = color2;
				manip.copy(product2b, color2);
				product1b = product2b;
			} else if (color5 == color3 && color2 != color6) {
				// product2b = product1b = color5;
				manip.copy(product2b, color5);
				product1b = product2b;
			} else if (color5 == color3 && color2 == color6) {
				int r = 0;

				// r += GetResult (color6, color5, color1, colorA1);
				// r += GetResult (color6, color5, color4, colorB1);
				// r += GetResult (color6, color5, colorA2, colorS1);
				// r += GetResult (color6, color5, colorB2, colorS2);
				r += GetResult1<Source_pixel>(color5, color6, color4, colorB1);
				r += GetResult2<Source_pixel>(color6, color5, colorA2, colorS1);
				r += GetResult2<Source_pixel>(color6, color5, color1, colorA1);
				r += GetResult1<Source_pixel>(color5, color6, colorB2, colorS2);

				if (r > 0) {
					// product2b = product1b = color6;
					manip.copy(product2b, color6);
					product1b = product2b;
				} else if (r < 0) {
					// product2b = product1b = color5;
					manip.copy(product2b, color5);
					product1b = product2b;
				} else {
					// product2b = product1b = INTERPOLATE (color5, color6);
					product1b = product2b = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color6, manip);
				}

			} else {
				if (color6 == color3 && color3 == colorA1 && color2 != colorA2
					&& color3 != colorA0) {
					// product2b = Q_INTERPOLATE (color3, color3, color3,
					// color2);
					product2b = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color3, color3, color3, color2, manip);
				} else if (
						color5 == color2 && color2 == colorA2
						&& colorA1 != color3 && color2 != colorA3) {
					// product2b = Q_INTERPOLATE (color2, color2, color2,
					// color3);
					product2b = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color3, color2, color2, color2, manip);
				} else {
					// product2b = INTERPOLATE (color2, color3);
					product2b = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color2, color3, manip);
				}

				if (color6 == color3 && color6 == colorB1 && color5 != colorB2
					&& color6 != colorB0) {
					// product1b = Q_INTERPOLATE (color6, color6, color6,
					// color5);
					product1b = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color6, color6, color6, manip);
				} else if (
						color5 == color2 && color5 == colorB2
						&& colorB1 != color6 && color5 != colorB3) {
					// product1b = Q_INTERPOLATE (color6, color5, color5,
					// color5);
					product1b = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color6, color5, color5, color5, manip);
				} else {
					// product1b = INTERPOLATE (color5, color6);
					product1b = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color6, manip);
				}
			}

			if (color5 == color3 && color2 != color6 && color4 == color5
				&& color5 != colorA2) {
				// product2a = INTERPOLATE (color2, color5);
				product2a = Interpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color5, color2, manip);
			} else if (
					color5 == color1 && color6 == color5 && color4 != color2
					&& color5 != colorA0) {
				// product2a = INTERPOLATE(color2, color5);
				product2a = Interpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color5, color2, manip);
			} else {
				// product2a = color2;
				manip.copy(product2a, color2);
			}

			if (color2 == color6 && color5 != color3 && color1 == color2
				&& color2 != colorB2) {
				// product1a = INTERPOLATE (color2, color5);
				product1a = Interpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color5, color2, manip);
			} else if (
					color4 == color2 && color3 == color2 && color1 != color5
					&& color2 != colorB0) {
				// product1a = INTERPOLATE(color2, color5);
				product1a = Interpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color5, color2, manip);
			} else {
				// product1a = color5;
				manip.copy(product1a, color5);
			}

			*dP                      = product1a;
			*(dP + 1)                = product1b;
			*(dP + dline_pixels)     = product2a;
			*(dP + dline_pixels + 1) = product2b;

			bP += 1;
			dP += 2;
		}
		srcPtr += sline_pixels;
		dstPtr += 2 * dline_pixels;
	}
}

template <class Source_pixel, class Dest_pixel, class Manip_pixels>
void Scale_SuperEagle(
		Source_pixel* source,                // ->source pixels.
		int srcx, int srcy,                  // Start of rectangle within src.
		int srcw, int srch,                  // Dims. of rectangle.
		int                 sline_pixels,    // Pixels (words)/line for source.
		int                 sheight,         // Source height.
		Dest_pixel*         dest,            // ->dest pixels.
		int                 dline_pixels,    // Pixels (words)/line for dest.
		const Manip_pixels& manip            // Manipulator methods.
) {
	// Need to ensure that the update is alligned to 4 pixels - Colourless
	// The idea was to prevent artifacts from appearing, but it doesn't seem
	// to help
	/*
	{
		int sx = ((srcx-4)/4)*4;
		int ex = ((srcx+srcw+7)/4)*4;
		int sy = ((srcy-4)/4)*4;
		int ey = ((srcy+srch+7)/4)*4;

		if (sx < 0) sx = 0;
		if (sy < 0) sy = 0;
		if (ex > sline_pixels) ex = sline_pixels;
		if (ey > sheight) ey = sheight;

		srcx = sx;
		srcy = sy;
		srcw = ex - sx;
		srch = ey - sy;
	}
	*/

	Source_pixel* srcPtr = source + (srcx + srcy * sline_pixels);
	Dest_pixel*   dstPtr = dest + (2 * srcy * dline_pixels + 2 * srcx);

	if (srcx + srcw >= sline_pixels) {
		srcw = sline_pixels - srcx;
	}

	const int ybeforelast1 = sheight - 1 - srcy;
	const int ybeforelast2 = sheight - 2 - srcy;
	const int xbeforelast1 = sline_pixels - 1 - srcx;
	const int xbeforelast2 = sline_pixels - 2 - srcx;

	for (int y = 0; y < srch; y++) {
		Source_pixel* bP = srcPtr;
		Dest_pixel*   dP = dstPtr;

		for (int x = 0; x < srcw; x++) {
			Source_pixel              color4;
			Source_pixel              color5;
			Source_pixel              color6;
			Source_pixel              color1;
			Source_pixel              color2;
			Source_pixel              color3;
			Source_pixel /*colorA0,*/ colorA1;
			Source_pixel /*colorA0,*/ colorA2;
			Source_pixel /*colorA0,*/ /*colorA3,*/
					/*colorB0,*/      colorB1;
			Source_pixel /*colorA0,*/ colorB2;
			Source_pixel /*colorA0,*/ /*colorB3,*/
									  colorS1;
			Source_pixel /*colorA0,*/ colorS2;
			Dest_pixel                product1a;
			Dest_pixel                product1b;
			Dest_pixel                product2a;
			Dest_pixel                product2b;

			//---------------------------------------  B0 B1 B2 B3
			//                                         4  5  6  S2
			//                                         1  2  3  S1
			//                                         A0 A1 A2 A3
			//--------------------------------------
			int add1;
			int add2;
			int sub1;
			int nextl1;
			int nextl2;
			int prevl1;

			if (x == 0) {
				sub1 = 0;
			} else {
				sub1 = 1;
			}

			if (x >= xbeforelast2) {
				add2 = 0;
			} else {
				add2 = 1;
			}

			if (x >= xbeforelast1) {
				add1 = 0;
			} else {
				add1 = 1;
			}

			if (y == 0) {
				prevl1 = 0;
			} else {
				prevl1 = sline_pixels;
			}

			if (y >= ybeforelast2) {
				nextl2 = 0;
			} else {
				nextl2 = sline_pixels;
			}

			if (y >= ybeforelast1) {
				nextl1 = 0;
			} else {
				nextl1 = sline_pixels;
			}

			// colorB0 = *(bP- prevl1 - sub1);
			colorB1 = *(bP - prevl1);
			colorB2 = *(bP - prevl1 + add1);
			// colorB3 = *(bP- prevl1 + add1 + add2);

			color4  = *(bP - sub1);
			color5  = *(bP);
			color6  = *(bP + add1);
			colorS2 = *(bP + add1 + add2);

			color1  = *(bP + nextl1 - sub1);
			color2  = *(bP + nextl1);
			color3  = *(bP + nextl1 + add1);
			colorS1 = *(bP + nextl1 + add1 + add2);

			// colorA0 = *(bP + nextl1 + nextl2 - sub1);
			colorA1 = *(bP + nextl1 + nextl2);
			colorA2 = *(bP + nextl1 + nextl2 + add1);
			// colorA3 = *(bP + nextl1 + nextl2 + add1 + add2);

			if (color2 == color6 && color5 != color3) {
				// product1b = product2a = color2;
				manip.copy(product2a, color2);
				product1b = product2a;

				if ((color1 == color2) || (color6 == colorB2)) {
					// product1a = INTERPOLATE (color2, color5);
					// product1a = INTERPOLATE (color2, product1a);
					product1a = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color2, color2, color2, color5, manip);

				} else {
					// product1a = INTERPOLATE (color5, color6);
					product1a = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color6, color5, manip);
				}

				if ((color6 == colorS2) || (color2 == colorA1)) {
					// product2b = INTERPOLATE (color2, color3);
					// product2b = INTERPOLATE (color2, product2b);
					product2b = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color2, color2, color2, color3, manip);

				} else {
					// product2b = INTERPOLATE (color2, color3);
					product2b = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color2, color3, manip);
				}
			} else if (color5 == color3 && color2 != color6) {
				// product2b = product1a = color5;
				manip.copy(product1a, color5);
				product2b = product1a;

				if ((colorB1 == color5) || (color3 == colorS1)) {
					// product1b = INTERPOLATE (color5, color6);
					// product1b = INTERPOLATE (color5, product1b);
					product1b = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color5, color5, color6, manip);
				} else {
					// product1b = INTERPOLATE (color5, color6);
					product1b = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color6, manip);
				}

				if ((color3 == colorA2) || (color4 == color5)) {
					// product2a = INTERPOLATE (color5, color2);
					// product2a = INTERPOLATE (color5, product2a);
					product2a = QInterpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color2, color5, color5, color5, manip);
				} else {
					// product2a = INTERPOLATE (color2, color3);
					product2a = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color3, color2, manip);
				}

			} else if (color5 == color3 && color2 == color6) {
				int r = 0;

				// r += GetResult (color6, color5, color1, colorA1);
				// r += GetResult (color6, color5, color4, colorB1);
				// r += GetResult (color6, color5, colorA2, colorS1);
				// r += GetResult (color6, color5, colorB2, colorS2);
				r += GetResult1<Source_pixel>(color5, color6, color4, colorB1);
				r += GetResult2<Source_pixel>(color6, color5, colorA2, colorS1);
				r += GetResult2<Source_pixel>(color6, color5, color1, colorA1);
				r += GetResult1<Source_pixel>(color5, color6, colorB2, colorS2);

				if (r > 0) {
					// product1b = product2a = color2;
					manip.copy(product2a, color2);
					product1b = product2a;
					// product1a = product2b = INTERPOLATE (color5, color6);
					product1a = product2b = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color6, manip);
				} else if (r < 0) {
					// product2b = product1a = color5;
					manip.copy(product1a, color5);
					product2b = product1a;
					// product1b = product2a = INTERPOLATE (color5, color6);
					product1b = product2a = Interpolate_2xSaI<
							Source_pixel, Dest_pixel, Manip_pixels>(
							color5, color6, manip);
				} else {
					// product2b = product1a = color5;
					manip.copy(product1a, color5);
					product2b = product1a;
					// product1b = product2a = color2;
					manip.copy(product2a, color2);
					product1b = product2a;
				}
			} else {
				// product2b = product1a = INTERPOLATE (color2, color6);
				// product2b = Q_INTERPOLATE (color3, color3, color3,
				// product2b); product1a = Q_INTERPOLATE (color5, color5,
				// color5, product1a);
				product2b = OInterpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color3, color2, color6, manip);
				product1a = OInterpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color5, color6, color2, manip);

				// product2a = product1b = INTERPOLATE (color5, color3);
				// product2a = Q_INTERPOLATE (color2, color2, color2,
				// product2a); product1b = Q_INTERPOLATE (color6, color6,
				// color6, product1b);
				product2a = OInterpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color2, color5, color3, manip);
				product1b = OInterpolate_2xSaI<
						Source_pixel, Dest_pixel, Manip_pixels>(
						color6, color5, color3, manip);
			}

			*dP                      = product1a;
			*(dP + 1)                = product1b;
			*(dP + dline_pixels)     = product2a;
			*(dP + dline_pixels + 1) = product2b;

			bP += 1;
			dP += 2;
		}
		srcPtr += sline_pixels;
		dstPtr += 2 * dline_pixels;
	}
}

/**
 ** End of 2xSaI code
 **/

#endif
