/*
    Border Control (was Border Smear) filter for VirtualDub.
	
	 
	This filter will replicate the most useful line at the top and bottom
	in order to fill the
	frame with  "pseudo" video instead of normally using a solid border
	or re-sizing to acheive standard frame size compliance for making
	VCDs. (You've got to start somewhere :-)

    
	Copyright (C) 2000-2002 Simon Walters
	
	V0.1 - option to stretch top and bottom of picture- very neat on progressive (film) material

	V0.4 has options to use add a solid border and to make the smear and fade regions
	independant of each other.
	Known bug - the Fade settings are being copied from the Smear settings somehow!
	
	V0.3 introduces a fade to black option that disguises the smear better.
	V1 introduced the global stretch factor that diguises the smeared region
		at the expense of increasing the region itself.

	V2	Added ability to alter sides as well.  Thanks to skgh@gmx.de for giving
		impetus to doing this - I'm not a Completer Finisher :-)
		Also renamed Border Control and re-compiled as Multithreaded DLL.

	V2.1b1 Added individual stretchfactors for all borders
	V2.2b2 Corrected parameter list bug
	V2.3a1 Added ability to changre border colour (for debuggin ViewFields Filter)
	V2.31 Quick fix to limit paras to 16 - border colour change disabled
	V2.32 Another fix to stop spurious settings appearing in dialog boxes
	V2.33 Remove off by one line bug
	V2.34 Really fix it this time?
	V2.35 Add in changes from Antonio Foranna from v22b1!
			Also finally add ability to change Border Colour

	Based on code by Avery Lee, Jim Casaburi, Gunnar Thalin and Donald Graft.
	Inital impetus to writing filters given by Donald Graft.
		

    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.

    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.

	The author can be contacted at:
	Simon Walters
	siwalters@hotmail.com

	New versions of the source code and the compiled filter can be 
	found at http://www.geocities.com/siwalters_uk/virtualdub/filters.html
*/

#include "filter.h"
#include "resource.h"
#include "ScriptError.h"
#include "ScriptInterpreter.h"
#include "ScriptValue.h"
#include "stdio.h"

// Added to use Donald Graft's Dialog Box
#include <windows.h>
#include <commctrl.h>
#include <crtdbg.h>

inline unsigned int RGBCombine(unsigned int R,unsigned int G,unsigned int B) {
	return ((R*256*256) + (G*256) + B);
}

///////////////////////
int BorderControlRunProc(const FilterActivation *fa, const FilterFunctions *ff);
int BorderControlInitProc(FilterActivation *fa, const FilterFunctions *ff);
int BorderControlStartProc(FilterActivation *fa, const FilterFunctions *ff);
int BorderControlEndProc(FilterActivation *fa, const FilterFunctions *ff);
int BorderControlConfigProc(FilterActivation *fa, const FilterFunctions *ff, HWND hwnd);
void BorderControlStringProc(const FilterActivation *fa, const FilterFunctions *ff, char *buf); 
bool BorderControlFssProc(FilterActivation *fa, const FilterFunctions *ff, char *buf, int buflen);
void BorderControlScriptConfig(IScriptInterpreter *isi, void *lpVoid, CScriptValue *argv, int argc);


typedef struct MyFilterData {
	IFilterPreview		*ifp;  // Sometting to do with preview
	int YTop; // Start of top smear
	int YBot; // Start of bottom smear
	int XLeft;
	int XRight;
	int YTopBorder;
	int YBotBorder;
	int XLeftBorder;
	int XRightBorder;
	int YTopFade;
	int YBotFade;
	int XLeftFade;
	int XRightFade;
	int StretchFactorTop;
	int StretchFactorBottom;
	int StretchFactorLeft;
	int StretchFactorRight;
	bool bOrder;
	unsigned int GlobalBorderColour;
	unsigned int GBColR;
	unsigned int GBColG;
	unsigned int GBColB;

    } MyFilterData;

//Script code????


ScriptFunctionDef BorderControl_func_defs[]={
    { (ScriptFunctionPtr)BorderControlScriptConfig, "Config", "0iiiiiiiiiiiii" },
    { NULL },
};

//////////////////////////////////////////////////////////////////
CScriptObject BorderControl_obj={
    NULL, BorderControl_func_defs
};


//////////////////////////////////////////////////////////////////




///////////////////////////////////////////////////////////////////////
struct FilterDefinition filterDef_BorderControl = {

    NULL, NULL, NULL,						// next, prev, module
	#ifdef _DEBUG
		"0 Border Control - Debug",// name
	#else
		"Border Control - 2.34",		// name
	#endif
	"Improves picture near borders",	// desc
    "Simon Walters",							// maker
    NULL,						// private_data
    sizeof(MyFilterData),		// inst_data_size

    BorderControlInitProc,			// initProc
    NULL,						// deinitProc
    BorderControlRunProc,			// runProc
    NULL,						// paramProc
	BorderControlConfigProc,			// configProc
    BorderControlStringProc,			// stringProc
    BorderControlStartProc,			// startProc
    BorderControlEndProc,			// endProc

    &BorderControl_obj,				// script_obj
    BorderControlFssProc,			// fssProc


};


///////////////////////////////////////////////////////////////
extern "C" int __declspec(dllexport) __cdecl VirtualdubFilterModuleInit2(FilterModule *fm, const FilterFunctions *ff, int& vdfd_ver, int& vdfd_compat);
extern "C" void __declspec(dllexport) __cdecl VirtualdubFilterModuleDeinit(FilterModule *fm, const FilterFunctions *ff);

static FilterDefinition *fd_BorderControl;
////////////////////////////////////////////////////////////
int __declspec(dllexport) __cdecl VirtualdubFilterModuleInit2(FilterModule *fm, const FilterFunctions *ff, int& vdfd_ver, int& vdfd_compat) {
    if (!(fd_BorderControl = ff->addFilter(fm, &filterDef_BorderControl, sizeof(FilterDefinition))))
        return 1;

    vdfd_ver    = VIRTUALDUB_FILTERDEF_VERSION;
    vdfd_compat = VIRTUALDUB_FILTERDEF_COMPATIBLE;

    return 0;
}

void __declspec(dllexport) __cdecl VirtualdubFilterModuleDeinit(FilterModule *fm, const FilterFunctions *ff) {
    ff->removeFilter(fd_BorderControl);
}
//////////////////////////////////////
static int BorderControlRunProc(const FilterActivation *fa, const FilterFunctions *ff) {
   PixDim w, h;
   Pixel32 *src, *dst;
   src = (Pixel32 *)fa->src.data;
   dst = (Pixel32 *)fa->dst.data;
	MyFilterData *mfd = (MyFilterData *)fa->filter_data;
	Pixel32 r,b,g;
//	int Y1 = mfd->YTop; // Smear Top boundary
//	int Y2 = mfd->YBot; // Smear bottom boundary
	// Smear/Stretch Factors
//	bool YTopDoSmear = ((h < (Y1+mfd->StretchFactor)) && (h > mfd->YTopBorder));
//	const int YTopSmearLineCode = (fa->src.h - Y1 - (int)((mfd->StretchFactor + 1)*(h - mfd->YTopBorder)/(mfd->YTop + mfd->StretchFactor - mfd->YTopBorder))));

//Copy src to dst
   src = (Pixel32 *)fa->src.data;
   dst = (Pixel32 *)fa->dst.data;

   h = fa->src.h;
	do {
        w = fa->src.w;
        do {
            Pixel32 old_pixel, new_pixel;
            old_pixel = *src++;
            new_pixel = old_pixel;
				*dst++ = new_pixel;
        } while(--w);
        src = (Pixel32 *)((char *)src + fa->src.modulo);
        dst = (Pixel32 *)((char *)dst + fa->dst.modulo);
    } while(--h);	
	
	//Order processing
	for (int lLoop = 0; lLoop < 2; ++lLoop ) {
		if (((lLoop == 0) && mfd->bOrder) || ((lLoop == 1) && (mfd->bOrder == FALSE))) {
// Do Top/Bottom edges

	//Top		
			src = (Pixel32 *)fa->src.data;
			src = (Pixel32 *)((char *)src + (fa->src.pitch * fa->src.h) - fa->src.modulo);

			dst = (Pixel32 *)fa->dst.data;
			dst = (Pixel32 *)((char *)dst + (fa->src.pitch * fa->src.h) - fa->src.modulo);

			src--;
			dst--;

			h = 1;
			do {
				w = 1;
				do {
					Pixel32 old_pixel, new_pixel, c;
					old_pixel = *dst;
					new_pixel = old_pixel;
					//Top
					if (h <= mfd->YTopBorder) {
						new_pixel = mfd->GlobalBorderColour;
					}
					if ((h <= (mfd->YTop+mfd->StretchFactorTop)) && (h > mfd->YTopBorder)) {
						new_pixel = *((Pixel32 *)fa->dst.data + ((fa->src.pitch/4)*
						(fa->src.h - mfd->YTop - (int)((mfd->StretchFactorTop + 1)*
						(h - mfd->YTopBorder)/(mfd->YTop + mfd->StretchFactorTop - mfd->YTopBorder)))) +
						(fa->src.w - w));
					}
					if ((h > mfd->YTopBorder) && (h < mfd->YTopFade)) {
						c=new_pixel;
						r = (((c>>16) & 255) *(h - mfd->YTopBorder)/(mfd->YTopFade - mfd->YTopBorder)) & 255;
						g = (((c>>8) & 255) *(h - mfd->YTopBorder)/(mfd->YTopFade - mfd->YTopBorder)) & 255;
						b = (((c) & 255) *(h - mfd->YTopBorder)/(mfd->YTopFade - mfd->YTopBorder)) & 255;
						new_pixel = (r<<16) + (g<<8) + b;
					}
					src = src - 1;
					*dst-- = new_pixel;
					w++;
				} while(w <= fa->src.w);
				src = (Pixel32 *)((char *)src - fa->src.modulo);
				dst = (Pixel32 *)((char *)dst - fa->dst.modulo);
				h++;
			} while(h <= fa->src.h); //end top

//Bottom
			src = (Pixel32 *)fa->src.data;
			dst = (Pixel32 *)fa->dst.data;
			h = fa->src.h;
			do {
				w = fa->src.w;
		      do {
					Pixel32 old_pixel, new_pixel, c;
					old_pixel = *dst;
					new_pixel = old_pixel;
					if ((fa->src.h - h) < mfd->YBotBorder) {
						new_pixel = mfd->GlobalBorderColour;
					}
					if (((fa->src.h - h) <= (mfd->YBot+mfd->StretchFactorBottom)) && ((fa->src.h - h) >= mfd->YBotBorder)) {
						new_pixel = *((Pixel32 *)fa->dst.data +
						((fa->src.pitch/4)*
						(mfd->YBot +(int)((((mfd->StretchFactorBottom+1)*(fa->src.h - h))/(mfd->YBot+mfd->StretchFactorBottom + 1))))) +
						(fa->src.w -w));
					}
					if (((fa->src.h - h) >= mfd->YBotBorder) && ((fa->src.h - h) < mfd->YBotFade)) {
						c=new_pixel;
						r = (((c>>16) & 255) *((fa->src.h - h) - mfd->YBotBorder)/(mfd->YBotFade - mfd->YBotBorder)) & 255;
						g = (((c>>8) & 255) *((fa->src.h - h) - mfd->YBotBorder)/(mfd->YBotFade - mfd->YBotBorder)) & 255;
						b = (((c) & 255) *((fa->src.h - h) - mfd->YBotBorder)/(mfd->YBotFade - mfd->YBotBorder)) & 255;
						new_pixel = (r<<16) + (g<<8) + b;
					}

					src = src + 1;
				   *dst++ = new_pixel;
		      } while(--w);
		      src = (Pixel32 *)((char *)src + fa->src.modulo);
		      dst = (Pixel32 *)((char *)dst + fa->dst.modulo);
			} while(--h);//end bottom
		} //end top/bottom if

		if (((lLoop == 1) && mfd->bOrder) || ((lLoop == 0) && (mfd->bOrder == FALSE))) {



// Do Right/Left sides
			//RIGHT
			src = (Pixel32 *)fa->src.data;
			src = (Pixel32 *)((char *)src + (fa->src.pitch * fa->src.h) - fa->src.modulo);

			dst = (Pixel32 *)fa->dst.data;
			dst = (Pixel32 *)((char *)dst + (fa->src.pitch * fa->src.h) - fa->src.modulo);

			src--;
			dst--;

			h = 1;
			do {
				w = 1;
				do {
					Pixel32 old_pixel, new_pixel, c;
					old_pixel = *dst;
					new_pixel = old_pixel;

					if (w <= mfd->XRightBorder) {
						new_pixel = mfd->GlobalBorderColour;
					}

					if ((w <= (mfd->XRight+mfd->StretchFactorRight)) && (w > mfd->XRightBorder)) {
				
						new_pixel = *((Pixel32 *)fa->dst.data + ((fa->src.pitch/4) * (fa->src.h - h)+
							(fa->src.w - mfd->XRight - 
							(int)((mfd->StretchFactorRight + 1)*(w - mfd->XRightBorder)/
							(mfd->XRight + mfd->StretchFactorRight - mfd->XRightBorder)))));
					}

					if ((w > mfd->XRightBorder) && (w < mfd->XRightFade)) {
						c=new_pixel;
						r = (((c>>16) & 255) *(w - mfd->XRightBorder)/(mfd->XRightFade - mfd->XRightBorder)) & 255;
						g = (((c>>8) & 255) *(w - mfd->XRightBorder)/(mfd->XRightFade - mfd->XRightBorder)) & 255;
						b = (((c) & 255) *(w - mfd->XRightBorder)/(mfd->XRightFade - mfd->XRightBorder)) & 255;
						new_pixel = (r<<16) + (g<<8) + b;
					}
	
					src = src - 1;
		         *dst-- = new_pixel;
					w++;
				} while(w <= fa->src.w);
				src = (Pixel32 *)((char *)src - fa->src.modulo);
				dst = (Pixel32 *)((char *)dst - fa->dst.modulo);
				h++;
			} while(h <= fa->src.h); // end Right

			
			//Left
		   src = (Pixel32 *)fa->src.data;
		   dst = (Pixel32 *)fa->dst.data;
		   h = fa->src.h;
			do {
				w = fa->src.w;
		      do {
					Pixel32 old_pixel, new_pixel, c;
					old_pixel = *dst;
					new_pixel = old_pixel;

					if ((fa->src.w - w) < mfd->XLeftBorder) {
						new_pixel = mfd->GlobalBorderColour;
					}

					if (((fa->src.w - w) <= (mfd->XLeft+mfd->StretchFactorLeft)) && ((fa->src.w - w) > mfd->XLeftBorder)) {
						new_pixel = *((Pixel32 *)fa->dst.data + ((fa->src.pitch/4)*(fa->src.h -h)+
						(mfd->XLeft+(int)((((mfd->StretchFactorLeft+1)*(fa->src.w - w))/(mfd->XLeft+mfd->StretchFactorLeft))))));
					}

					if (((fa->src.w - w) > mfd->XLeftBorder) && ((fa->src.w - w) < mfd->XLeftFade)) {
						c=new_pixel;
						r = (((c>>16) & 255) *((fa->src.w - w) - mfd->XLeftBorder)/(mfd->XLeftFade - mfd->XLeftBorder)) & 255;
						g = (((c>>8) & 255) *((fa->src.w - w) - mfd->XLeftBorder)/(mfd->XLeftFade - mfd->XLeftBorder)) & 255;
						b = (((c) & 255) *((fa->src.w - w) - mfd->XLeftBorder)/(mfd->XLeftFade - mfd->XLeftBorder)) & 255;
						new_pixel = (r<<16) + (g<<8) + b;
					}
	
					src = src + 1;
		         *dst++ = new_pixel;
				} while(--w);
				src = (Pixel32 *)((char *)src + fa->src.modulo);
				dst = (Pixel32 *)((char *)dst + fa->dst.modulo);
			} while(--h); // end Left
		}//end sides if
	} // end for lLoop

	return 0;
}

////////////////////////////////////////////////////////////////////////////////

static int BorderControlInitProc(FilterActivation *fa, const FilterFunctions *ff) {
    MyFilterData *mfd = (MyFilterData *)fa->filter_data;

	mfd->YTop	=	0;
	mfd->YBot	=	0;
	mfd->XLeft	=	0;
	mfd->XRight	=	0;
	mfd->YTopBorder		= 0;
	mfd->YBotBorder		= 0;
	mfd->XLeftBorder	=	0;
	mfd->XRightBorder	=	0;
	mfd->YTopFade	=	0;
	mfd->YBotFade	=	0;
	mfd->XLeftFade	=	0;
	mfd->XRightFade	=	0;
	mfd->StretchFactorTop	=	0;
	mfd->StretchFactorBottom	=	0;
	mfd->StretchFactorLeft	=	0;
	mfd->StretchFactorRight	=	0;
	mfd->bOrder = 1;
	mfd->GlobalBorderColour = 0x00;
	mfd->GBColR = 0;
	mfd->GBColG = 0;
	mfd->GBColB = 0;
	
	return 0;
}

static int BorderControlStartProc(FilterActivation *fa, const FilterFunctions *ff) {
    MyFilterData *mfd = (MyFilterData *)fa->filter_data;

    return 0;
}

static int BorderControlEndProc(FilterActivation *fa, const FilterFunctions *ff) {
    MyFilterData *mfd = (MyFilterData *)fa->filter_data;

    return 0;
}

BOOL CALLBACK BorderControlConfigDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) {
	MyFilterData *mfd = (MyFilterData *)GetWindowLong(hdlg, DWL_USER);

	switch(msg) {
		case WM_INITDIALOG:
			SetWindowLong(hdlg, DWL_USER, lParam);

			mfd = (MyFilterData *)lParam;
			HWND hWnd;
			// Auto enable Preview
			mfd->ifp->Toggle(hdlg);

			//TOP
			SetDlgItemInt(hdlg, IDC_YTOPEDIT, mfd->YTop, FALSE);
			SetDlgItemInt(hdlg, IDC_YTOPEDITBORDER, mfd->YTopBorder, FALSE);
			SetDlgItemInt(hdlg, IDC_YTOPEDITFADE, mfd->YTopFade, FALSE);
			//BOT
			SetDlgItemInt(hdlg, IDC_YBOTEDIT, mfd->YBot, FALSE);
			SetDlgItemInt(hdlg, IDC_YBOTEDITBORDER, mfd->YBotBorder, FALSE);
			SetDlgItemInt(hdlg, IDC_YBOTEDITFADE, mfd->YBotFade, FALSE);
			//LEFT
			SetDlgItemInt(hdlg, IDC_XLEFTEDIT, mfd->XLeft, FALSE);
			SetDlgItemInt(hdlg, IDC_XLEFTEDITBORDER, mfd->XLeftBorder, FALSE);
			SetDlgItemInt(hdlg, IDC_XLEFTEDITFADE, mfd->XLeftFade, FALSE);
			//RIGHT
			SetDlgItemInt(hdlg, IDC_XRIGHTEDIT, mfd->XRight, FALSE);
			SetDlgItemInt(hdlg, IDC_XRIGHTEDITBORDER, mfd->XRightBorder, FALSE);
			SetDlgItemInt(hdlg, IDC_XRIGHTEDITFADE, mfd->XRightFade, FALSE);

			SetDlgItemInt(hdlg, IDC_STRETCHFACTORTOPEDIT, mfd->StretchFactorTop, FALSE);
			SetDlgItemInt(hdlg, IDC_STRETCHFACTORBOTTOMEDIT, mfd->StretchFactorBottom, FALSE);
			SetDlgItemInt(hdlg, IDC_STRETCHFACTORLEFTEDIT, mfd->StretchFactorLeft, FALSE);
			SetDlgItemInt(hdlg, IDC_STRETCHFACTORRIGHTEDIT, mfd->StretchFactorRight, FALSE);

         CheckDlgButton(hdlg, IDC_CHECK1, mfd->bOrder?BST_CHECKED:BST_UNCHECKED);

			SetDlgItemInt(hdlg, IDC_EDIT1, mfd->GBColR, FALSE);
			SetDlgItemInt(hdlg, IDC_EDIT2, mfd->GBColG, FALSE);
			SetDlgItemInt(hdlg, IDC_EDIT3, mfd->GBColB, FALSE);
			
			//YTOPSPIN
			hWnd = GetDlgItem(hdlg, IDC_YTOPSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255, 0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->YTop);
			//YTOPBORDER
			hWnd = GetDlgItem(hdlg, IDC_YTOPSPINBORDER);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255, 0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->YTopBorder);
			//YTOPFADE
			hWnd = GetDlgItem(hdlg, IDC_YTOPSPINFADE);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255, 0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->YTopFade);

			//YBOTSPIN
			hWnd = GetDlgItem(hdlg, IDC_YBOTSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->YBot);
			//YBOTBORDER
			hWnd = GetDlgItem(hdlg, IDC_YBOTSPINBORDER);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->YBotBorder);
			//YBOTFADE
			hWnd = GetDlgItem(hdlg, IDC_YBOTSPINFADE);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->YBotFade);

			//XLEFTSPIN
			hWnd = GetDlgItem(hdlg, IDC_XLEFTSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->XLeft);
			//XLEFTBORDER
			hWnd = GetDlgItem(hdlg, IDC_XLEFTSPINBORDER);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->XLeftBorder);
			//XLEFTFADE
			hWnd = GetDlgItem(hdlg, IDC_XLEFTSPINFADE);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->XLeftFade);

			//XRIGHTSPIN
			hWnd = GetDlgItem(hdlg, IDC_XRIGHTSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->XRight);
			//XRIGHTBORDER
			hWnd = GetDlgItem(hdlg, IDC_XRIGHTSPINBORDER);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->XRightBorder);
			//XRIGHTFADE
			hWnd = GetDlgItem(hdlg, IDC_XRIGHTSPINFADE);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->XRightFade);

			
			//STRETCHFACTORTOP
			hWnd = GetDlgItem(hdlg, IDC_STRETCHFACTORTOPSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->StretchFactorTop);

			//STRETCHFACTORBOTTOM
			hWnd = GetDlgItem(hdlg, IDC_STRETCHFACTORBOTTOMSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->StretchFactorBottom);

			//STRETCHFACTORLEFT
			hWnd = GetDlgItem(hdlg, IDC_STRETCHFACTORLEFTSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->StretchFactorLeft);

			//STRETCHFACTORIGHT
			hWnd = GetDlgItem(hdlg, IDC_STRETCHFACTORRIGHTSPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255,0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->StretchFactorRight);

			//EDIT1SPIN
			hWnd = GetDlgItem(hdlg, IDC_EDIT1SPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255, 0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->GBColR);
			//EDIT2SPIN
			hWnd = GetDlgItem(hdlg, IDC_EDIT2SPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255, 0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->GBColG);
			//EDIT3SPIN
			hWnd = GetDlgItem(hdlg, IDC_EDIT3SPIN);
			SendMessage(hWnd, UDM_SETRANGE, (WPARAM)TRUE, MAKELONG(255, 0));
			SendMessage(hWnd, UDM_SETPOS, (WPARAM)TRUE, mfd->GBColB);



			mfd->ifp->InitButton(GetDlgItem(hdlg, IDPREVIEW));

			return TRUE;
		case WM_VSCROLL:
			//TOP
			if ((HWND) lParam == GetDlgItem(hdlg, IDC_YTOPSPIN))
			{
				int YTop = SendMessage(GetDlgItem(hdlg, IDC_YTOPSPIN), UDM_GETPOS, 0, 0);
				if (YTop != mfd->YTop)
				{
					mfd->YTop = YTop;
//					SendMessage(GetDlgItem(hdlg, IDC_SY2CLIP), TBM_SETPOS, (WPARAM)TRUE, (mfd->YTop));
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_YTOPSPINBORDER))
			{
				int YTopBorder = SendMessage(GetDlgItem(hdlg, IDC_YTOPSPINBORDER), UDM_GETPOS, 0, 0);
				if (YTopBorder != mfd->YTopBorder)
				{
					mfd->YTopBorder = YTopBorder;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_YTOPSPINFADE))
			{
				int YTopFade = SendMessage(GetDlgItem(hdlg, IDC_YTOPSPINFADE), UDM_GETPOS, 0, 0);
				if (YTopFade != mfd->YTopFade)
				{
					mfd->YTopFade = YTopFade;
					mfd->ifp->RedoFrame();
				}
			}
			//BOT
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_YBOTSPIN))
			{
				int YBot = SendMessage(GetDlgItem(hdlg, IDC_YBOTSPIN), UDM_GETPOS, 0, 0);
				if (YBot != mfd->YBot)
				{
					mfd->YBot = YBot;
//					SendMessage(GetDlgItem(hdlg, IDC_SY2CLIP), TBM_SETPOS, (WPARAM)TRUE, (mfd->YBot));
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_YBOTSPINBORDER))
			{
				int YBotBorder = SendMessage(GetDlgItem(hdlg, IDC_YBOTSPINBORDER), UDM_GETPOS, 0, 0);
				if (YBotBorder != mfd->YBotBorder)
				{
					mfd->YBotBorder = YBotBorder;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_YBOTSPINFADE))
			{
				int YBotFade = SendMessage(GetDlgItem(hdlg, IDC_YBOTSPINFADE), UDM_GETPOS, 0, 0);
				if (YBotFade != mfd->YBotFade)
				{
					mfd->YBotFade = YBotFade;
					mfd->ifp->RedoFrame();
				}
			}
			//LEFT
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_XLEFTSPIN))
			{
				int XLeft = SendMessage(GetDlgItem(hdlg, IDC_XLEFTSPIN), UDM_GETPOS, 0, 0);
				if (XLeft != mfd->XLeft)
				{
					mfd->XLeft = XLeft;
//					SendMessage(GetDlgItem(hdlg, IDC_SY2CLIP), TBM_SETPOS, (WPARAM)TRUE, (mfd->XLeft));
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_XLEFTSPINBORDER))
			{
				int XLeftBorder = SendMessage(GetDlgItem(hdlg, IDC_XLEFTSPINBORDER), UDM_GETPOS, 0, 0);
				if (XLeftBorder != mfd->XLeftBorder)
				{
					mfd->XLeftBorder = XLeftBorder;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_XLEFTSPINFADE))
			{
				int XLeftFade = SendMessage(GetDlgItem(hdlg, IDC_XLEFTSPINFADE), UDM_GETPOS, 0, 0);
				if (XLeftFade != mfd->XLeftFade)
				{
					mfd->XLeftFade = XLeftFade;
					mfd->ifp->RedoFrame();
				}
			}
			//RIGHT
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_XRIGHTSPIN))
			{
				int XRight = SendMessage(GetDlgItem(hdlg, IDC_XRIGHTSPIN), UDM_GETPOS, 0, 0);
				if (XRight != mfd->XRight)
				{
					mfd->XRight = XRight;
//					SendMessage(GetDlgItem(hdlg, IDC_SY2CLIP), TBM_SETPOS, (WPARAM)TRUE, (mfd->XRight));
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_XRIGHTSPINBORDER))
			{
				int XRightBorder = SendMessage(GetDlgItem(hdlg, IDC_XRIGHTSPINBORDER), UDM_GETPOS, 0, 0);
				if (XRightBorder != mfd->XRightBorder)
				{
					mfd->XRightBorder = XRightBorder;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_XRIGHTSPINFADE))
			{
				int XRightFade = SendMessage(GetDlgItem(hdlg, IDC_XRIGHTSPINFADE), UDM_GETPOS, 0, 0);
				if (XRightFade != mfd->XRightFade)
				{
					mfd->XRightFade = XRightFade;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_STRETCHFACTORTOPSPIN))
			{
				int StretchFactorTop = SendMessage(GetDlgItem(hdlg, IDC_STRETCHFACTORTOPSPIN), UDM_GETPOS, 0, 0);
				if (StretchFactorTop != mfd->StretchFactorTop)
				{
					mfd->StretchFactorTop = StretchFactorTop;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_STRETCHFACTORBOTTOMSPIN))
			{
				int StretchFactorBottom = SendMessage(GetDlgItem(hdlg, IDC_STRETCHFACTORBOTTOMSPIN), UDM_GETPOS, 0, 0);
				if (StretchFactorBottom != mfd->StretchFactorBottom)
				{
					mfd->StretchFactorBottom = StretchFactorBottom;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_STRETCHFACTORLEFTSPIN))
			{
				int StretchFactorLeft = SendMessage(GetDlgItem(hdlg, IDC_STRETCHFACTORLEFTSPIN), UDM_GETPOS, 0, 0);
				if (StretchFactorLeft != mfd->StretchFactorLeft)
				{
					mfd->StretchFactorLeft = StretchFactorLeft;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_STRETCHFACTORRIGHTSPIN))
			{
				int StretchFactorRight = SendMessage(GetDlgItem(hdlg, IDC_STRETCHFACTORRIGHTSPIN), UDM_GETPOS, 0, 0);                                                     
				if (StretchFactorRight != mfd->StretchFactorRight)
				{
					mfd->StretchFactorRight = StretchFactorRight;
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_EDIT1SPIN))
			{
				unsigned int GBColR = SendMessage(GetDlgItem(hdlg, IDC_EDIT1SPIN), UDM_GETPOS, 0, 0);                                                     
				if (GBColR != mfd->GBColR)
				{
					mfd->GBColR = GBColR;
					mfd->GlobalBorderColour = RGBCombine(mfd->GBColR,mfd->GBColG,mfd->GBColB);
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_EDIT2SPIN))
			{
				unsigned int GBColG = SendMessage(GetDlgItem(hdlg, IDC_EDIT2SPIN), UDM_GETPOS, 0, 0);                                                     
				if (GBColG != mfd->GBColG)
				{
					mfd->GBColG = GBColG;
					mfd->GlobalBorderColour = RGBCombine(mfd->GBColR,mfd->GBColG,mfd->GBColB);
					mfd->ifp->RedoFrame();
				}
			}
			else if ((HWND) lParam == GetDlgItem(hdlg, IDC_EDIT3SPIN))
			{
				unsigned int GBColB = SendMessage(GetDlgItem(hdlg, IDC_EDIT3SPIN), UDM_GETPOS, 0, 0);                                                     
				if (GBColB != mfd->GBColB)
				{
					mfd->GBColB = GBColB;
					mfd->GlobalBorderColour = RGBCombine(mfd->GBColR,mfd->GBColG,mfd->GBColB);
					mfd->ifp->RedoFrame();
				}
			}

			break;
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
			case IDPREVIEW:
				mfd->ifp->Toggle(hdlg);
				break;
			case IDOK:
				mfd->GBColR = GetDlgItemInt(hdlg, IDC_EDIT1, NULL, FALSE);
				mfd->GBColG = GetDlgItemInt(hdlg, IDC_EDIT2, NULL, FALSE);
				mfd->GBColB = GetDlgItemInt(hdlg, IDC_EDIT3, NULL, FALSE);
				mfd->GlobalBorderColour = RGBCombine(mfd->GBColR,mfd->GBColG,mfd->GBColB);
				EndDialog(hdlg, 0);
				return TRUE;
			case IDHELP:
				{
				char prog[256];
				char path[256];
				LPTSTR ptr;
				GetModuleFileName(NULL, prog, 255);
				GetFullPathName(prog, 255, path, &ptr);
				*ptr = 0;
				strcat(path, "plugins\\bdrcntrl.txt");
				OutputDebugString(path);
				OutputDebugString("\n");
				strcpy(prog, "Notepad ");
				strcat(prog, path);
				WinExec(prog, SW_SHOW);
				return TRUE;
				}
			case IDCANCEL:
				EndDialog(hdlg, 1);
				return TRUE;
			case IDC_CHECK1:
				mfd->bOrder = !!IsDlgButtonChecked(hdlg, IDC_CHECK1);
				mfd->ifp->RedoFrame();
				break;
			}
			break;
		}

		return FALSE;
}

static int BorderControlConfigProc(FilterActivation *fa, const FilterFunctions *ff, HWND hwnd)
{
	MyFilterData *mfd = (MyFilterData *) fa->filter_data;
	MyFilterData mfd_old = *mfd;
	int ret;

	mfd->ifp = fa->ifp;


	if (DialogBoxParam(fa->filter->module->hInstModule,
			MAKEINTRESOURCE(IDD_FILTER), hwnd,
			BorderControlConfigDlgProc, (LPARAM) mfd))
	{
		*mfd = mfd_old;
		ret = TRUE;
	}
	else
	{
		ret = FALSE;
	}
	return(ret);
}




static void BorderControlStringProc(const FilterActivation *fa, const FilterFunctions *ff, char *str) {

    MyFilterData *mfd = (MyFilterData *)fa->filter_data;
	
	// write the parameters to a string (YT: xxx, YB: xxx Blur: x)
	sprintf(str, "(Top: %d,%d,%d,%d. Bot: %d,%d,%d,%d)",
		mfd->YTop, mfd->YTopBorder, mfd->YTopFade, mfd->StretchFactorTop,
		mfd->YBot, mfd->YBotBorder, mfd->YBotFade, mfd->StretchFactorBottom);
}

//Script/Batch Handling Code


static bool BorderControlFssProc(FilterActivation *fa, const FilterFunctions *ff, char *buf, int buflen) {
    MyFilterData *mfd = (MyFilterData *)fa->filter_data;

	// Write the parameters to a string 
    _snprintf(buf, buflen, "Config(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d))",
		mfd->YTop|
		(mfd->YTopBorder<<16),
		mfd->YTopFade|
		(mfd->StretchFactorTop<<16),
		mfd->YBot|
		(mfd->YBotBorder<<16),
		mfd->YBotFade|
		(mfd->StretchFactorBottom<<16),
		mfd->XRight|
		(mfd->XRightBorder<<16),
		mfd->XRightFade|
		(mfd->StretchFactorRight<<16),
		mfd->XLeft|
		(mfd->XLeftBorder<<16),
		mfd->XLeftFade|
		(mfd->StretchFactorLeft<<16),
		mfd->bOrder);
		mfd->GBColR;
		mfd->GBColG;
		mfd->GBColB;
		mfd->GlobalBorderColour;


	 return true;
}

static void BorderControlScriptConfig(IScriptInterpreter *isi, void *lpVoid, CScriptValue *argv, int argc) {
    FilterActivation *fa = (FilterActivation *)lpVoid;
    MyFilterData *mfd = (MyFilterData *)fa->filter_data;
	// Extract the parameters from the arguments provided
    mfd->YTop					= argv[0].asInt()&0xffff;
    mfd->YTopBorder				= argv[0].asInt()>>16;
    mfd->YTopFade				= argv[1].asInt()&0xffff;
	mfd->StretchFactorTop		= argv[1].asInt()>>16;
    mfd->YBot					= argv[2].asInt()&0xffff;
    mfd->YBotBorder				= argv[2].asInt()>>16;
    mfd->YBotFade				= argv[3].asInt()&0xffff;
	mfd->StretchFactorBottom	= argv[3].asInt()>>16;
    mfd->XRight					= argv[4].asInt()&0xffff;
    mfd->XRightBorder			= argv[4].asInt()>>16;
    mfd->XRightFade				= argv[5].asInt()&0xffff;
	mfd->StretchFactorRight		= argv[5].asInt()>>16;
    mfd->XLeft					= argv[6].asInt()&0xffff;
    mfd->XLeftBorder			= argv[6].asInt()>>16;
    mfd->XLeftFade				= argv[7].asInt()&0xffff;
	mfd->StretchFactorLeft		= argv[7].asInt()>>16;
	mfd->bOrder						= !!argv[8].asInt();
	mfd->GBColR						= argv[9].asInt();
	mfd->GBColG						= argv[10].asInt();
	mfd->GBColB						= argv[11].asInt();
	mfd->GlobalBorderColour		= argv[12].asInt();


}
