// svefilt.c
//
// Version 2.00 Datei hinzugefügt am 30.05.2001
//
// Funktion SVEdeinterlace1 (30.05.2001): Einfacher Deinterlacer durch Interpolation
// input: y,u,v-Buffer (Jeweils unsigned char*) -> Originalstream im Format YUV444
//        Width,Height (int) -> Breite und Höhe des Originalstreams
// output:y,u,v-Buffer (Die werden hier überschrieben)
//
// Funktion SVEdeinterlace2 (02.06.2001): Motion-Based Deinterlacer durch Interpolation
// input: y,u,v-Buffer (Jeweils unsigned char*) -> Originalstream im Format YUV444
//        Width,Height (int) -> Breite und Höhe des Originalstreams
// output:y,u,v-Buffer (Die werden hier überschrieben)
//
// Funktion SVEdeinterlace3 (03.06.2001): Schneller Deinterlacer durch Interpolation
// input: y-Buffer (unsigned char*) -> Y-Kanal des Originalstreams
//        Width,Height (int) -> Breite und Höhe des Originalstreams
// output:y-Buffer (Der wird hier überschrieben)
//
// Funktion SVEsharpen (02.06.2001): Schärfen des Frames
// input: iHow (int) Art des Schärfens: 
//						1 = Einfaches Schärfen des Y-Streams mit Kernel-Durchmesser 3
//						2 = Stärkeres Schärfen des Y-Streams mit Kernel-Durchmesser 5
//						3 = Stärkeres Schärfen des Y-Streams mit Kernel-Durchmesser 5
//							+ Entfernen vom Grisseln in Videoaufnahmen (sehr langsam)
//					Nur in Verbindung mit einem Deinterlacer (YUV444 erforderlich):
//						4 = Einfaches Schärfen der Y,U,V-Streams mit Kernel-Durchmesser 3
//						5 = Stärkeres Schärfen der Y,U,V-Streams mit Kernel-Durchmesser 5
//						6 = Stärkeres Schärfen der Y,U,V-Streams mit Kernel-Durchmesser 5
//							+ Entfernen vom Grisseln in Videoaufnahmen (sehr langsam)
//        y,u,v-Buffer (Jeweils unsigned char*) -> Originalstream im Format YUV4*
//        oWidth,oHeight (int) -> Breite und Höhe des Originalstreams
//        rWidth,rHeight (int) -> Breite und Höhe des Bildausschnitts
// output:y,u,v-Buffer (Jeweils unsigned char*) -> Ausgabestream im Format YUV4*

#include <windows.h>
#include <math.h>
#include "config.h"
#include "global.h"

#define ConstEpsilon  1.0e-12
#define ConstPI  3.14159265358979323846264338327950288419716939937510

// Funktion SVEdeinterlace1: Einfacher Deinterlacer durch Interpolation
void SVEdeinterlace1(unsigned char* lpYin, unsigned char* lpUin, unsigned char* lpVin,
				 int iWidth, int iHeight)
{
	int i1,i2;
	unsigned char *lpY,*lpU,*lpV;
	lpY=lpYin;
	lpU=lpUin;
	lpV=lpVin;

	__asm
	{	
		mov ecx, dword ptr [iWidth]		// Anzahl Spalten in ecx
		mov dword ptr [i1],0			// Zeilenzähler
	Schleife1:
		mov dword ptr [i2],0			// Spaltenzähler
	Schleife2:
		mov edx, dword ptr [lpY]		// 1. Zeile Y
		mov edi, edx					// 2. Zeile Y
		add edi, ecx
		mov esi, edi					// 3. Zeile Y
		add esi, ecx
		xor eax, eax	
		mov al, byte ptr [edx]			// Punkt aus Zeile 1
		xor ebx, ebx	
		mov bl, byte ptr [esi]			// Punkt aus Zeile 3
		add eax, ebx
		sar eax, 1
		mov byte ptr [edi], al			// Speichern in Zeile 2

		mov edx, dword ptr [lpU]		// 1. Zeile U
		mov edi, edx					// 2. Zeile U
		add edi, ecx
		mov esi, edi					// 3. Zeile U
		add esi, ecx
		xor eax, eax	
		mov al, byte ptr [edx]			// Punkt aus Zeile 1
		xor ebx, ebx	
		mov bl, byte ptr [esi]			// Punkt aus Zeile 3
		add eax, ebx
		sar eax, 1
		mov byte ptr [edi], al			// Speichern in Zeile 2
		
		mov edx, dword ptr [lpY]		// 1. Zeile V
		mov edi, edx					// 2. Zeile V
		add edi, ecx
		mov esi, edi					// 3. Zeile V
		add esi, ecx
		xor eax, eax	
		mov al, byte ptr [edx]			// Punkt aus Zeile 1
		xor ebx, ebx	
		mov bl, byte ptr [esi]			// Punkt aus Zeile 3
		add eax, ebx
		sar eax, 1
		mov byte ptr [edi], al			// Speichern in Zeile 2

		mov eax, dword ptr [lpY]
		inc eax
		mov dword ptr [lpY], eax
		mov eax, dword ptr [lpU]
		inc eax
		mov dword ptr [lpU], eax
		mov eax, dword ptr [lpV]
		inc eax
		mov dword ptr [lpV], eax
		add dword ptr [i2],1			// Spalte 1 hoch
		mov eax, dword ptr [i2]
		cmp eax, ecx					// Prüfen
		jl Schleife2
		mov eax, dword ptr [lpY]
		add eax, ecx
		mov dword ptr [lpY], eax
		mov eax, dword ptr [lpU]
		add eax, ecx
		mov dword ptr [lpU], eax
		mov eax, dword ptr [lpV]
		add eax, ecx
		mov dword ptr [lpV], eax
		add dword ptr [i1],2			// Zeile 2 hoch
		mov eax, dword ptr [i1]
		add eax, 2						// Prüfen, aber 2 Zeilen höher
		cmp eax, iHeight
		jl Schleife1
		emms
	}

}

// Funktion SVEdeinterlace2: Motion-Based Deinterlacer durch Interpolation
void SVEdeinterlace2(unsigned char* lpYin, unsigned char* lpUin, unsigned char* lpVin,
				 int iWidth, int iHeight)
{
	static int iFirst=0;
	int i1,i2;
	unsigned char *lpY,*lpU,*lpV;
	unsigned char *lpYL,*lpUL,*lpVL;
	static unsigned char *lpY1,*lpU1,*lpV1;
	static unsigned char *lpY2,*lpU2,*lpV2;
	lpY=lpYin;
	lpU=lpUin;
	lpV=lpVin;
	lpYL=lpY1;
	lpUL=lpU1;
	lpVL=lpV1;

	if(!iFirst)
	{
		iFirst=1;
		lpY1=(unsigned char*) malloc(iWidth*iHeight);
		lpU1=(unsigned char*) malloc(iWidth*iHeight);
		lpV1=(unsigned char*) malloc(iWidth*iHeight);
		lpY2=(unsigned char*) malloc(iWidth*iHeight);
		lpU2=(unsigned char*) malloc(iWidth*iHeight);
		lpV2=(unsigned char*) malloc(iWidth*iHeight);
		memcpy(lpY2,lpYin,iWidth*iHeight);
		memcpy(lpU2,lpUin,iWidth*iHeight);
		memcpy(lpV2,lpVin,iWidth*iHeight);
		__asm
		{	
			mov ecx, dword ptr [iWidth]		// Anzahl Spalten in ecx
			mov dword ptr [i1],0			// Zeilenzähler
		Schleife11:
			mov dword ptr [i2],0			// Spaltenzähler
		Schleife12:
			mov edx, dword ptr [lpY]		// 1. Zeile Y
			mov edi, edx					// 2. Zeile Y
			add edi, ecx
			mov esi, edi					// 3. Zeile Y
			add esi, ecx
			mov eax, 0	
			mov al, byte ptr [edx]			// Punkt aus Zeile 1
			mov ebx, 0	
			mov bl, byte ptr [esi]			// Punkt aus Zeile 3
			add eax, ebx
			sar eax, 1
			mov byte ptr [edi], al			// Speichern in Zeile 2

			mov edx, dword ptr [lpU]		// 1. Zeile U
			mov edi, edx					// 2. Zeile U
			add edi, ecx
			mov esi, edi					// 3. Zeile U
			add esi, ecx
			mov eax, 0	
			mov al, byte ptr [edx]			// Punkt aus Zeile 1
			mov ebx, 0	
			mov bl, byte ptr [esi]			// Punkt aus Zeile 3
			add eax, ebx
			sar eax, 1
			mov byte ptr [edi], al			// Speichern in Zeile 2
		
			mov edx, dword ptr [lpY]		// 1. Zeile V
			mov edi, edx					// 2. Zeile V
			add edi, ecx
			mov esi, edi					// 3. Zeile V
			add esi, ecx
			xor eax, eax	
			mov al, byte ptr [edx]			// Punkt aus Zeile 1
			xor ebx, ebx	
			mov bl, byte ptr [esi]			// Punkt aus Zeile 3
			add eax, ebx
			sar eax, 1
			mov byte ptr [edi], al			// Speichern in Zeile 2

			mov eax, dword ptr [lpY]
			inc eax
			mov dword ptr [lpY], eax
			mov eax, dword ptr [lpU]
			inc eax
			mov dword ptr [lpU], eax
			mov eax, dword ptr [lpV]
			inc eax
			mov dword ptr [lpV], eax
			add dword ptr [i2],1			// Spalte 1 hoch
			mov eax, dword ptr [i2]
			cmp eax, ecx					// Prüfen
			jl Schleife12
			mov eax, dword ptr [lpY]
			add eax, ecx
			mov dword ptr [lpY], eax
			mov eax, dword ptr [lpU]
			add eax, ecx
			mov dword ptr [lpU], eax
			mov eax, dword ptr [lpV]
			add eax, ecx
			mov dword ptr [lpV], eax
			add dword ptr [i1],2			// Zeile 2 hoch
			mov eax, dword ptr [i1]
			add eax, 2						// Prüfen, aber 2 Zeilen höher
			cmp eax, iHeight
			jl Schleife11
			emms
		}
	}
	else
	{
		memcpy(lpY1,lpY2,iWidth*iHeight);
		memcpy(lpU1,lpU2,iWidth*iHeight);
		memcpy(lpV1,lpV2,iWidth*iHeight);
		memcpy(lpY2,lpYin,iWidth*iHeight);
		memcpy(lpU2,lpUin,iWidth*iHeight);
		memcpy(lpV2,lpVin,iWidth*iHeight);
		lpYL=lpY1;
		lpUL=lpU1;
		lpVL=lpV1;
		__asm
		{	
			mov ecx, dword ptr [iWidth]		// Anzahl Spalten in ecx
			mov dword ptr [i1],0			// Zeilenzähler
		Schleife21:
			mov dword ptr [i2],0			// Spaltenzähler
		Schleife22:
			mov edx, dword ptr [lpY]		// 2. Zeile Y
			add edx, ecx
			xor eax, eax
			mov al, byte ptr [edx]
			
			mov edx, dword ptr [lpYL]		// 2. Zeile Y letzter Frame
			add edx, ecx
			xor ebx, ebx
			mov bl, byte ptr [edx]

			cmp eax, ebx
			jne TagInterpolate

			mov edx, dword ptr [lpU]		// 2. Zeile U
			add edx, ecx
			xor eax, eax
			mov al, byte ptr [edx]
			
			mov edx, dword ptr [lpUL]		// 2. Zeile U letzter Frame
			add edx, ecx
			xor ebx, ebx
			mov bl, byte ptr [edx]

			cmp eax, ebx
			jne TagInterpolate

			mov edx, dword ptr [lpV]		// 2. Zeile V
			add edx, ecx
			xor eax, eax
			mov al, byte ptr [edx]
			
			mov edx, dword ptr [lpVL]		// 2. Zeile V letzter Frame
			add edx, ecx
			xor ebx, ebx
			mov bl, byte ptr [edx]

			cmp eax, ebx
			jne TagInterpolate

			jmp TagNext

		TagInterpolate:
			mov edx, dword ptr [lpY]		// 1. Zeile Y
			mov edi, edx					// 2. Zeile Y
			add edi, ecx
			mov esi, edi					// 3. Zeile Y
			add esi, ecx
			mov eax, 0	
			mov al, byte ptr [edx]			// Punkt aus Zeile 1
			mov ebx, 0	
			mov bl, byte ptr [esi]			// Punkt aus Zeile 3
			add eax, ebx
			sar eax, 1
			mov byte ptr [edi], al			// Speichern in Zeile 2

			mov edx, dword ptr [lpU]		// 1. Zeile U
			mov edi, edx					// 2. Zeile U
			add edi, ecx
			mov esi, edi					// 3. Zeile U
			add esi, ecx
			mov eax, 0	
			mov al, byte ptr [edx]			// Punkt aus Zeile 1
			mov ebx, 0	
			mov bl, byte ptr [esi]			// Punkt aus Zeile 3
			add eax, ebx
			sar eax, 1
			mov byte ptr [edi], al			// Speichern in Zeile 2
		
			mov edx, dword ptr [lpY]		// 1. Zeile V
			mov edi, edx					// 2. Zeile V
			add edi, ecx
			mov esi, edi					// 3. Zeile V
			add esi, ecx
			mov eax, 0	
			mov al, byte ptr [edx]			// Punkt aus Zeile 1
			mov ebx, 0	
			mov bl, byte ptr [esi]			// Punkt aus Zeile 3
			add eax, ebx
			sar eax, 1
			mov byte ptr [edi], al			// Speichern in Zeile 2

		TagNext:
			add dword ptr [lpY],1
			add dword ptr [lpU],1
			add dword ptr [lpV],1
			add dword ptr [lpYL],1
			add dword ptr [lpUL],1
			add dword ptr [lpVL],1
			add dword ptr [i2],1			// Spalte 1 hoch
			mov eax, dword ptr [i2]
			cmp eax, ecx					// Prüfen
			jl Schleife22
			add dword ptr [lpY],ecx			// Zeile überspringen
			add dword ptr [lpU],ecx			// Zeile überspringen
			add dword ptr [lpV],ecx			// Zeile überspringen
			add dword ptr [lpYL],ecx			// Zeile überspringen
			add dword ptr [lpUL],ecx			// Zeile überspringen
			add dword ptr [lpVL],ecx			// Zeile überspringen
			add dword ptr [i1],2			// Zeile 2 hoch
			mov eax, dword ptr [i1]
			add eax, 2						// Prüfen, aber 2 Zeilen höher
			cmp eax, iHeight
			jl Schleife21
			emms
		}
	}
}

// Funktion SVEdeinterlace3: Schneller Deinterlacer durch Interpolation
void SVEdeinterlace3(unsigned char* lpYin,
				 int iWidth, int iHeight)
{
	int i1,i2;
	unsigned char *lpY;
	lpY=lpYin;

	__asm
	{	
		mov ecx, dword ptr [iWidth]		// Anzahl Spalten in ecx
		mov dword ptr [i1],0			// Zeilenzähler
	Schleife1:
		mov dword ptr [i2],0			// Spaltenzähler
	Schleife2:
		mov edx, dword ptr [lpY]		// 1. Zeile Y
		mov edi, edx					// 2. Zeile Y
		add edi, ecx
		mov esi, edi					// 3. Zeile Y
		add esi, ecx
		mov eax, 0	
		mov al, byte ptr [edx]			// Punkt aus Zeile 1
		mov ebx, 0	
		mov bl, byte ptr [esi]			// Punkt aus Zeile 3
		add eax, ebx
		sar eax, 1
		mov byte ptr [edi], al			// Speichern in Zeile 2

		add dword ptr [lpY],1
		add dword ptr [i2],1			// Spalte 1 hoch
		mov eax, dword ptr [i2]
		cmp eax, ecx					// Prüfen
		jl Schleife2
		add dword ptr [lpY],ecx			// Zeile überspringen
		add dword ptr [i1],2			// Zeile 2 hoch
		mov eax, dword ptr [i1]
		add eax, 2						// Prüfen, aber 2 Zeilen höher
		cmp eax, iHeight
		jl Schleife1
		emms
	}

}

// Funktion SVEhull: Interne Funktion, benötigt für SVEsharpen
void SVEhull(const int x_offset,const int y_offset,const int polarity,
  unsigned char *f,unsigned char *g,
  unsigned int left, unsigned int right, unsigned int top,unsigned int bottom, 
  const unsigned int ocolumns)
{
  int
    y;

  register int
    x;

  register unsigned char
    *p,
    *q,
    *r,
    *s;

  unsigned char
    v;

  for (y=top; y < bottom; y++)
  {
	p=f+y*ocolumns;
	q=g+y*ocolumns;
	r=p+(y_offset*((int) ocolumns)+x_offset);
    p++;
    q++;
    r++;
    if (polarity > 0)
      for (x=left; x<right; x++)
      {
        v=(*p);
        if (*r > v)
          v++;
        *q=v;
        p++;
        q++;
        r++;
      }
    else
      for (x=left; x<right; x++)
      {
        v=(*p);
        if (v > (unsigned char) (*r+1))
          v--;
        *q=v;
        p++;
        q++;
        r++;
      }
  }
  for (y=top; y<bottom; y++)
  {
	p=f+y*ocolumns;
	q=g+y*ocolumns;
	r=q+(y_offset*((int) ocolumns)+x_offset);
	s=q-(y_offset*((int) ocolumns)+x_offset);
    p++;
    q++;
    r++;
    s++;
    if (polarity > 0)
      for (x=left; x<right; x++)
      {
        v=(*q);
        if (((unsigned char) (*s+1) > v) && (*r > v))
          v++;
        *p=v;
        p++;
        q++;
        r++;
        s++;
      }
    else
      for (x=left; x<right; x++)
      {
        v=(*q);
        if (((unsigned char) (*s+1) < v) && (*r < v))
          v--;
        *p=v;
        p++;
        q++;
        r++;
        s++;
      }
  }
}

// Funktion SVEsharpen: Schärfen des Frames
void SVEsharpen(int iHow, unsigned char* lpYS, unsigned char* lpUS, unsigned char* lpVS,unsigned char* lpYT, unsigned char* lpUT, unsigned char* lpVT,long oWidth,long oHeight,long rWidth,long rHeight)
{
	static int first_iteration=1;
	static const int
		X[4]= {0, 1, 1,-1},
		Y[4]= {1, 0, 1, 1};
	LONG a,b,c;
	long i,x,y,u,v;
	double r;
	static double *kernel;
	static double mkernel;
	static LONG *dwkernel;
	static LONG dwmkernel;
    static double normalize;
    static LONG dwnormalize;
	static long width, ende, wende, hende,left,right,top,bottom;
	static unsigned char* lpTemp;
	unsigned char *lpY;

	if(first_iteration)
	{
		first_iteration=0;
		if(iHow==1 || iHow==4)
			width=3;
		else
			width=5;
		ende=width>>1;
		wende=rWidth-ende;
		hende=rHeight-ende;
		left=(oWidth-rWidth)>>1;
		right=left+rWidth;
		top=(oHeight-rHeight)>>1;
		bottom=top+rHeight;
		kernel=(double*) malloc(width*width*sizeof(double));
		dwkernel=(LONG*) malloc(width*width*sizeof(LONG));
		lpTemp=(unsigned char*) malloc(oWidth*oHeight);
		i=0;
		normalize=0.0;
		for (v=-ende; v<=ende; v++)
			for (u=-ende; u<=ende; u++)
			{
				kernel[i]=-exp((double) -(u*u+v*v)/(m_dSigma*m_dSigma));
				kernel[i]=-kernel[i];
				normalize+=kernel[i];
				i++;
			}
		kernel[0]=kernel[width-1];
		if(iHow!=1 && iHow!=4)
		{
			kernel[1]=kernel[width-2];
			kernel[width*width-2]=kernel[width*width-width+1];
			kernel[width*width-1]=kernel[width*width-width];
		}
		normalize=0.0;
		for(i=0; i<width*width; i++) normalize+=kernel[i];
		mkernel=(2000.0)*normalize;
		i=0;
		for (v=-ende; v<=ende; v++)
			for (u=-ende; u<=ende; u++)
			{
				kernel[i]*=1000.0;
				dwkernel[i]=kernel[i];
				i++;
			}
		dwmkernel=mkernel;
		dwkernel[(width*width)/2]=0;
		dwnormalize=dwmkernel;
		for(i=0; i<width*width; i++) dwnormalize-=dwkernel[i];
	}

	// "Grisseln" entfernen
	if(iHow==3 || iHow==6)
	{
		memset(lpTemp,0,oWidth*oHeight);
		top++; left++;
		bottom--; right--;
		for (i=0; i < 4; i++)
		{
			SVEhull(X[i],Y[i],1,lpYS,lpTemp,left,left,right,top,bottom,oWidth);
			SVEhull(-X[i],-Y[i],1,lpYS,lpTemp,left,right,top,bottom,oWidth);
			SVEhull(-X[i],-Y[i],-1,lpYS,lpTemp,left,right,top,bottom,oWidth);
			SVEhull(X[i],Y[i],-1,lpYS,lpTemp,left,right,top,bottom,oWidth);
		}
		top--; left--;
		bottom++; right++;
		lpY=lpTemp;
	}
	else
		lpY=lpYS;

	if(iHow<4)
	{
		__asm
		{	
			mov dword ptr [y], 0x00		// Zeilenzähler y
		Schleife11:
			mov dword ptr [x], 0x00		// Spaltenzähler x
		Schleife12:
			mov eax, dword ptr [y]
			cmp eax, ende
			jl Tag1Copy					// Ist y < ende, Pixel kopieren
			cmp eax, hende
			jge Tag1Copy				// Ist y >= hende, Pixel kopieren
			mov eax, dword ptr [x]
			cmp eax, ende
			jl Tag1Copy					// Ist x < ende, Pixel kopieren
			cmp eax, wende
			jge Tag1Copy				// Ist x >= wende, Pixel kopieren

			mov ecx, dword ptr [top]
			add ecx, dword ptr [y]
			imul ecx, dword ptr [oWidth]
			add ecx, dword ptr [left]
			add ecx, dword ptr [x]
			add ecx, dword ptr [lpY]	// hier haben wir den mittleren Punkt
			xor edx, edx				// edx bekommt den Inhalt dieses punktes
			mov dl, byte ptr [ecx]
			sub edx, 0x10
			imul edx, dwmkernel
			mov dword ptr [a], edx		// So, von diesem wird jetzt alles abgezogen

			mov edi, dword ptr [dwkernel] // edi ist die Position im Kernel
			xor eax, eax				// eax ist der Additionswert für die Zeile
		Schleife13:
			xor ebx, ebx				// ebx ist der Additionswert für die Spalte
		Schleife14:
			mov ecx, dword ptr [top]
			add ecx, dword ptr [y]
			add ecx, eax
			sub ecx, dword ptr [ende]
			imul ecx, dword ptr [oWidth]
			add ecx, dword ptr [left]
			add ecx, dword ptr [x]
			add ecx, ebx
			sub ecx, dword ptr [ende]
			add ecx, dword ptr [lpY]
			xor edx, edx				// edx bekommt den Inhalt des Sourcepixels
			mov dl, byte ptr [ecx]
			sub edx, 0x10
			imul edx, dword ptr [edi]
			sub dword ptr [a], edx
			inc edi						// Jedes Kernelelement ist 4 Byte breit
			inc edi
			inc edi
			inc edi
			inc ebx
			cmp ebx, width
			jl Schleife14
			inc eax
			cmp eax, width
			jl Schleife13

			mov eax, dword ptr [a]
			cmp eax, 0x00
			jle Tag1Ynok
			cdq
			idiv dword ptr [dwnormalize]
			add eax, 0x10
			cmp eax, 0x10
			jl Tag1Ynok
			cmp eax, 0xeb
			jle Tag1Yok
			mov eax, 0xeb
			jmp Tag1Yok
		Tag1Ynok:
			mov eax, 0x10
		Tag1Yok:
			mov ebx, dword ptr [top]
			add ebx, dword ptr [y]
			imul ebx, dword ptr [oWidth]
			add ebx, dword ptr [left]
			add ebx, dword ptr [x]
			add ebx, dword ptr [lpYT]
			mov byte ptr [ebx], al
			jmp Tag1Next

		Tag1Copy:
			mov eax, dword ptr [top]
			add eax, dword ptr [y]
			imul eax, dword ptr [oWidth]
			add eax, dword ptr [left]
			add eax, dword ptr [x]
			mov ebx, dword ptr [lpYT]
			add ebx, eax
			mov ecx, dword ptr [lpY]
			add ecx, eax
			xor edx, edx
			mov dl, byte ptr [ecx]
			mov byte ptr [ebx], dl		// Pixel kopieren

		Tag1Next:
			mov eax, dword ptr [x]
			inc eax
			mov dword ptr [x], eax
			cmp eax, rWidth
			jl Schleife12

			mov eax, dword ptr [y]
			inc eax
			mov dword ptr [y], eax
			cmp eax, rHeight
			jl Schleife11

			emms
		}
	}
	else
	{
		__asm
		{	
			mov dword ptr [y], 0x00		// Zeilenzähler y
		Schleife21:
			mov dword ptr [x], 0x00		// Spaltenzähler x
		Schleife22:
			mov eax, dword ptr [top]
			mov eax, dword ptr [y]
			cmp eax, ende
			jl Tag2Copy					// Ist y < ende, Pixel kopieren
			cmp eax, hende
			jge Tag2Copy				// Ist y >= hende, Pixel kopieren
			mov eax, dword ptr [x]
			cmp eax, ende
			jl Tag2Copy					// Ist x < ende, Pixel kopieren
			cmp eax, wende
			jge Tag2Copy				// Ist x >= wende, Pixel kopieren

			mov ecx, dword ptr [top]
			add ecx, dword ptr [y]
			imul ecx, dword ptr [oWidth]
			add ecx, dword ptr [left]
			add ecx, dword ptr [x]
			mov esi, ecx
			add esi, dword ptr [lpY]	// hier haben wir den mittleren Punkt
			xor edx, edx				// edx bekommt den Inhalt dieses punktes
			mov dl, byte ptr [esi]
			sub edx, 0x10
			imul edx, dwmkernel
			mov dword ptr [a], edx		// So, von diesem wird jetzt alles abgezogen
			mov esi, ecx
			add esi, dword ptr [lpUS]	// hier haben wir den mittleren Punkt
			xor edx, edx				// edx bekommt den Inhalt dieses punktes
			mov dl, byte ptr [esi]
			sub edx, 0x10
			imul edx, dwmkernel
			mov dword ptr [b], edx		// So, von diesem wird jetzt alles abgezogen
			mov esi, ecx
			add esi, dword ptr [lpVS]	// hier haben wir den mittleren Punkt
			xor edx, edx				// edx bekommt den Inhalt dieses punktes
			mov dl, byte ptr [esi]
			sub edx, 0x10
			imul edx, dwmkernel
			mov dword ptr [c], edx		// So, von diesem wird jetzt alles abgezogen


			mov edi, dword ptr [dwkernel] // edi ist die Position im Kernel
			xor eax, eax				// eax ist der Additionswert für die Zeile
		Schleife23:
			xor ebx, ebx				// ebx ist der Additionswert für die Spalte
		Schleife24:
			mov ecx, dword ptr [top]
			add ecx, dword ptr [y]
			add ecx, eax
			sub ecx, dword ptr [ende]
			imul ecx, dword ptr [oWidth]
			add ecx, dword ptr [left]
			add ecx, dword ptr [x]
			add ecx, ebx
			sub ecx, dword ptr [ende]
			mov esi, ecx
			add esi, dword ptr [lpY]
			xor edx, edx				// edx bekommt den Inhalt des Sourcepixels
			mov dl, byte ptr [esi]
			sub edx, 0x10
			imul edx, dword ptr [edi]
			sub dword ptr [a], edx
			mov esi, ecx
			add esi, dword ptr [lpUS]
			xor edx, edx				// edx bekommt den Inhalt des Sourcepixels
			mov dl, byte ptr [esi]
			sub edx, 0x10
			imul edx, dword ptr [edi]
			sub dword ptr [b], edx
			mov esi, ecx
			add esi, dword ptr [lpVS]
			xor edx, edx				// edx bekommt den Inhalt des Sourcepixels
			mov dl, byte ptr [esi]
			sub edx, 0x10
			imul edx, dword ptr [edi]
			sub dword ptr [c], edx

			inc edi						// Jedes Kernelelement ist 4 Byte breit
			inc edi
			inc edi
			inc edi
			inc ebx
			cmp ebx, width
			jl Schleife24
			inc eax
			cmp eax, width
			jl Schleife23

			// EBX erhält die Speicheradresse des Ziels
			mov ebx, dword ptr [top]
			add ebx, dword ptr [y]
			imul ebx, dword ptr [oWidth]
			add ebx, dword ptr [left]
			add ebx, dword ptr [x]

			mov eax, dword ptr [a]
			cmp eax, 0x00
			jle Tag2Ynok
			cdq
			idiv dword ptr [dwnormalize]
			add eax, 0x10
			cmp eax, 0x10
			jl Tag2Ynok
			cmp eax, 0xeb
			jle Tag2Yok
			mov eax, 0xeb
			jmp Tag2Yok
		Tag2Ynok:
			mov eax, 0x10
		Tag2Yok:
			mov esi, ebx
			add esi, dword ptr [lpYT]
			mov byte ptr [esi], al

			mov eax, dword ptr [b]
			cmp eax, 0x00
			jle Tag2Unok
			cdq
			idiv dword ptr [dwnormalize]
			add eax, 0x10
			cmp eax, 0x10
			jl Tag2Unok
			cmp eax, 0xeb
			jle Tag2Uok
			mov eax, 0xeb
			jmp Tag2Uok
		Tag2Unok:
			mov eax, 0x10
		Tag2Uok:
			mov esi, ebx
			add esi, dword ptr [lpUT]
			mov byte ptr [esi], al

			mov eax, dword ptr [c]
			cmp eax, 0x00
			jle Tag2Vnok
			cdq
			idiv dword ptr [dwnormalize]
			add eax, 0x10
			cmp eax, 0x10
			jl Tag2Vnok
			cmp eax, 0xeb
			jle Tag2Vok
			mov eax, 0xeb
			jmp Tag2Vok
		Tag2Vnok:
			mov eax, 0x10
		Tag2Vok:
			mov esi, ebx
			add esi, dword ptr [lpVT]
			mov byte ptr [esi], al

			jmp Tag2Next

		Tag2Copy:
			mov eax, dword ptr [top]
			add eax, dword ptr [y]
			imul eax, dword ptr [oWidth]
			add eax, dword ptr [left]
			add eax, dword ptr [x]
			
			mov ebx, dword ptr [lpYT]
			add ebx, eax
			mov ecx, dword ptr [lpY]
			add ecx, eax
			xor edx, edx
			mov dl, byte ptr [ecx]
			mov byte ptr [ebx], dl		// Pixel kopieren

			mov ebx, dword ptr [lpUT]
			add ebx, eax
			mov ecx, dword ptr [lpUS]
			add ecx, eax
			xor edx, edx
			mov dl, byte ptr [ecx]
			mov byte ptr [ebx], dl		// Pixel kopieren

			mov ebx, dword ptr [lpVT]
			add ebx, eax
			mov ecx, dword ptr [lpVS]
			add ecx, eax
			xor edx, edx
			mov dl, byte ptr [ecx]
			mov byte ptr [ebx], dl		// Pixel kopieren

		Tag2Next:
			mov eax, dword ptr [x]
			inc eax
			mov dword ptr [x], eax
			cmp eax, rWidth
			jl Schleife22

			mov eax, dword ptr [y]
			inc eax
			mov dword ptr [y], eax
			cmp eax, rHeight
			jl Schleife21

			emms
		}
    }
}


