/*

Title: Smoothen filter for Ass Paint
Author: Ted Percival
Date: May 2004

(Ass Paint by Ben Kenny and Aaron someone )

*/

#include <vcl.h>
#include <windows.h>
#include <math.h>
#pragma hdrstop
#pragma argsused

// for ADJ (horizontally, vertically adjacent)
// and for DIAGonally "touching" pixels.
#define AA_ADJ_AMT 0.05f // amount of colour
#define AA_DIAG_AMT 0.05f

enum rgb { red, green, blue };

// Ted's union for easy RGB manipulation of TColor vars
union clr {
	tTColor tc;
	struct {
		unsigned char r;
		unsigned char g;
		unsigned char b;
	} rgb;
};

// end of types

extern "C" __declspec(dllexport) TImage* Filter(TImage* Image);

/*
// I thought these functions might help increase modularity, but I don't know that they do.
// The code will be faster inline anyway.

float calc_diff(const clr, const clr, enum rgb);
unsigned char chan_strength(const clr*, enum rgb); // colour channel strength

float calc_diff(const clr base, const clr alt, enum rgb col) {
	return chan_strength(alt, col) - chan_strength(base, col);
}

unsigned char chan_strength(const clr colour, enum rgb rgb) {
	switch (rgb) {
	case red:
		return colour.rgb.r;
	case green:
		return colour.rgb.g;
	case blue:
		return colour.rgb.b;
	}
	return 0; // stop compilers whinging (?) :)
}
*/

//////////

TImage* Filter(TImage* Image) {

	bool useleft, useright, usetop, usebottom;
	float adj_r, adj_g, adj_b;
	float diag_r, diag_g, diag_b;
	int x, y;
	clr dest, cur, alt; // destination pixel, currently being manipulated pixel, alternate (diag/adj) pixel
	TImage *destimg = new TImage(); // don't operate on the image itself

	destimg->Stretch = true; // Ben says I need this
	destimg->Height = Image->Height;
	destimg->Width = Image->Width;

	for (int x = 0; x < Image->Width - 1; ++x) {
		useleft = !(x == 1);
		useright = !(x == Image->Width);

		for (int y = 0; y < Image->Height - 1; ++y) {
			usetop = !(y == 1);
			usebottom = !(y == Image->Height);

			dest.tc = Image->Canvas->Pixels[x][y];
			adj_r = adj_g = adj_b = 0.0;
			diag_r = diag_g = diag_b = 0.0;

			// (base for) currently being calculated
			cur.tc = Image->Canvas->Pixels[x][y];

			if (usetop) {
				alt.tc = Image->Canvas->Pixels[x][y-1];
				adj_r += AA_ADJ_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_ADJ_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_ADJ_AMT * (alt.rgb.b - cur.rgb.b);
			}

			if (useleft) {
				alt.tc = Image->Canvas->Pixels[x-1][y];

				adj_r += AA_ADJ_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_ADJ_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_ADJ_AMT * (alt.rgb.b - cur.rgb.b);
			}

			if (useright) {
				alt.tc = Image->Canvas->Pixels[x+1][y];
				adj_r += AA_ADJ_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_ADJ_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_ADJ_AMT * (alt.rgb.b - cur.rgb.b);
			}

			if (usebottom) {
				alt.tc = Image->Canvas->Pixels[x][y+1];
				adj_r += AA_ADJ_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_ADJ_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_ADJ_AMT * (alt.rgb.b - cur.rgb.b);
			}

			// now for the diagonals
			if (usetop && useleft) {
				alt.tc = Image->Canvas->Pixels[x-1][y-1];
				adj_r += AA_DIAG_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_DIAG_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_DIAG_AMT * (alt.rgb.b - cur.rgb.b);
			}

			if (usetop && useright) {
				alt.tc = Image->Canvas->Pixels[x-1][y+1];
				adj_r += AA_DIAG_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_DIAG_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_DIAG_AMT * (alt.rgb.b - cur.rgb.b);
			}

			if (usebottom && useleft) {
				alt.tc = Image->Canvas->Pixels[x+1][y-1];
				adj_r += AA_DIAG_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_DIAG_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_DIAG_AMT * (alt.rgb.b - cur.rgb.b);
			}

			if (usebottom && useright) {
				alt.tc = Image->Canvas->Pixels[x+1][y+1];
				adj_r += AA_DIAG_AMT * (alt.rgb.r - cur.rgb.r);
				adj_g += AA_DIAG_AMT * (alt.rgb.g - cur.rgb.g);
				adj_b += AA_DIAG_AMT * (alt.rgb.b - cur.rgb.b);
			}

			dest.rgb.r += (unsigned char) adj_r;
			dest.rgb.g += (unsigned char) adj_g;
			dest.rgb.b += (unsigned char) adj_b;

			destimg->Canvas->Pixels[x][y] = dest.tc;
		}
	}

	// overwrite the original image
	// fingers crossed it has a copy constructor to take care of this :)
	*Image = *destimg;

	delete destimg; // free memory associated with the temp/dest image

	return Image;
}

