.486              ;Target processor.  Use instructions for Pentium class machines
.MODEL FLAT, C    ;Use the flat memory model. Use C calling conventions

.CODE             ;Indicates the start of a code segment.


;void RGB_BGR(unsigned char *Data, unsigned PixelCount)
	public	RGB_BGR
RGB_BGR proc \
        uses esi, \
        Data:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]	; cx=amount of pixels        
        jecxz	ToEnd			; array has zero size

        mov     esi,[Data]		; Load data ptr.

LoopPix:mov	al,[esi]
	mov	ah,[esi+2]
	mov	[esi],ah
	mov	[esi+2],al
	add	esi,3
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGB_BGR	endp


;void RGB_BGR2(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB_BGR2
RGB_BGR2 proc \
        uses esi edi, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]	; cx=amount of pixels

        mov     esi,[InData]	;
        mov     edi,[OutData]	;

	sub	ecx,4
	jl	LoopSimple

		; Processing of 4px block with size 3xDWORD	
LoopPix4:lodsd			; EAX = R2 B1 G1 R1
	bswap	eax		; EAX = R1 G1 B1 R2
	
	mov	edx,[esi]	; EDX = G3 R3 B2 G2
	add	esi,4
	
	xchg	al,dh		; EAX = R1 G1 B1 B2, EDX=G3 R3 R2 G2
	ror	eax,8		; EAX = B2 R1 G1 B1 
	stosd			;	B2 R1 G1 B1	shipped out
	
	lodsd			; EAX = B4 G4 R4 B3
	bswap	eax		; EAX = B3 R4 G4 B4
	rol	eax,8		; EAX = R4 G4 B4 B3
	
	ror	edx,8		; EDX = G2 G3 R3 R2
	xchg	dh,al		;  B3 <-> R3	    , EAX=R4 G4 B4 R3
	rol	edx,8		; EDX = G3 B3 R2 G2
	
	mov	[edi],edx	;	G3 B3 R2 G2	shipped out
	add	edi,4
	
	stosd			; R4 G4 B4 R3	shipped out
	;mov	[edi],eax	;	(STOSD is slow on AMD, replaced, seems that Intel works reversed)
	;add	edi,4
	
	sub	ecx,4
	jae	LoopPix4

			; Simple loop for 0,1,2,3 pixels (works also for more px)
LoopSimple:
	add	ecx,4		; ecx was -4, correct counter
        jecxz	ToEnd		; array has zero size
LoopPix:lodsw
	mov	[edi+2],al
	mov	[edi+1],ah
	lodsb
	mov	[edi],al
	add	edi,3
	dec	ecx
	jz	ToEnd
	
	lodsb
	mov	[edi+2],al
	lodsw
	mov	[edi+1],al
	mov	[edi],ah
	add	edi,3
	
	loop	LoopPix
ToEnd:	ret
	
RGB_BGR2 endp		


;void RGB32_BGR24(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB32_BGR24
RGB32_BGR24 proc \
        uses esi edi ebx, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]	; ecx=amount of pixels

        mov     esi,[InData]		; source data
        mov     edi,[OutData]		; destination data
        
        sub	ecx,4
	jl	LoopSimple		; array size < 4

LoopPx4:mov	ebx,[esi]		; EBX = ?? B1 G1 R1
	add	esi,4
	bswap	ebx			; EBX = R1 G1 B1 ??
		
;	lodsd				; EAX = ?? B2 G2 R2
	mov	eax,[esi]
	add	esi,4
	bswap	eax			; EAX = R2 G2 B2 ??
	
	mov	bl,ah			; BL = B2
	ror	ebx,8			; EBX = B2 R1 G1 B1	
	mov	[edi],ebx		;	shipout B2 R1 G1 B1
	add	edi,4

	mov	ebx,[esi]		; EBX = ?? B3 G3 R3
	add	esi,4
	mov	dl,bl			; DL = R3
	
	mov	ah,bh			; EAX = R2 G2 G3 ??
	bswap	ebx			; EBX = R3 G3 B3 ??
	mov	al,bh			; EAX = R2 G2 G3 B3
	ror	eax,16			; EAX = G3 B3 R2 G2
	stosd				;	shipout G3 B3 R2 G2
	
	lodsd				; EAX = ?? B4 G4 R4
	bswap	eax			; EAX = R4 G4 B4 ??
	mov	al,dl			; EAX = R4 G4 B4 R3

	stosd				;	shipout R4 G4 B4 R3

	sub	ecx,4
	jae	LoopPx4

LoopSimple:
	add	ecx,4
	jz	ToEnd			; remaining size = 0

LoopPix:lodsd
	mov	[edi+2],al
	mov	[edi+1],ah
	shr	eax,8
	mov	[edi],ah
	add	edi,3
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGB32_BGR24 endp



;void RGB_Gray24(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB_Gray24simple
RGB_Gray24simple proc \
        uses esi edi ebx, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]     ; cx=amount of pixels
        cmp	ecx,1
        jle	ToEnd		; array has zero size

        mov     esi,[InData]	;
        mov     edi,[OutData]	;
	
	mov	bh,0	
LoopPix:mov	ah,0
	mov	al,[esi]
	mov	bl,[esi+1]
	add	ax,bx
	mov	bl,[esi+2]
	add	ax,bx
	mov	bl,3
	div	bl
	stosb
        stosb
        stosb
	add	esi,3
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGB_Gray24simple endp



;void BGR_Gray24(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	BGR_Gray24
BGR_Gray24 proc \
        uses esi edi ebx, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]     ; cx=amount of pixels
        cmp	ecx,1
        jle	ToEnd		; array has zero size

        mov     esi,[InData]	;
        mov     edi,[OutData]	;

LoopPix:mov	eax,0
	lodsb
        mov	edx,4731
        mul	edx
	mov	ebx,eax

	mov	eax,0
	lodsb
	mov	edx,46871
        mul	edx
	add	ebx,eax

	mov	eax,0
	lodsb
	mov	edx,13932
        mul	edx
	add	eax,ebx

	shr	eax,16	
	stosb
        stosb
        stosb
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
BGR_Gray24 endp



;void BGR32_Gray24(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	BGR32_Gray24
BGR32_Gray24 proc \
        uses esi edi ebx, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]     ; cx=amount of pixels
        cmp	ecx,1
        jle	ToEnd		; array has zero size

        mov     esi,[InData]	;
        mov     edi,[OutData]	;

LoopPix:mov	eax,0
	lodsb
        mov	edx,4731
        mul	edx
	mov	ebx,eax

	mov	eax,0
	lodsb
	mov	edx,46871
        mul	edx
	add	ebx,eax

	mov	eax,0
	lodsb
	mov	edx,13932
        mul	edx
	add	eax,ebx

	shr	eax,16	
	stosb
        stosb
        stosb
	inc	esi
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
BGR32_Gray24 endp


;void RGB32_Gray(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB32_Gray
RGB32_Gray proc \
        uses esi edi ebx, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]     ; cx=amount of pixels
        cmp	ecx,1
        jle	ToEnd		; array has zero size

        mov     esi,[InData]	;
        mov     edi,[OutData]	;
	
	mov	bh,0	
LoopPix:mov	ah,0
	mov	al,[esi]
	mov	bl,[esi+1]
	add	ax,bx
	mov	bl,[esi+2]
	add	ax,bx
	mov	bl,3
	div	bl
	stosb
	add	esi,4
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGB32_Gray endp


;void RGB_Gray(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB_Gray
RGB_Gray proc \
        uses esi edi ebx, \
	OutData:ptr byte, \
        InData:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]     ; cx=amount of pixels
        cmp	ecx,1
        jle	ToEnd		; array has zero size

        mov     esi,[InData]	;
        mov     edi,[OutData]	;
	
	mov	bh,0	
LoopPix:mov	ah,0
	mov	al,[esi]
	mov	bl,[esi+1]
	add	ax,bx
	mov	bl,[esi+2]
	add	ax,bx
	mov	bl,3
	div	bl
	stosb
	add	esi,3
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGB_Gray endp


;void NotR(char *R, unsigned DataSize)	//R1:=not(R1)
	public  NotR
NotR	proc \
        uses edi, \
        R:ptr byte, \
        DataSize:DWORD

        mov     ecx,[DataSize]     ; cx=amount of pixels/bytes
        mov     edi,[R]		; Row byte data

        sub	ecx,4
        jl	LoopPx1
        
LoopPx4:mov	eax,[edi]	; Invert DWORDs
        not	eax	
        mov	[edi],eax
        add	edi,4
        
        sub	ecx,4        
        jge	LoopPx4
        
LoopPx1:add	ecx,4        
	jz	ToEnd
	
LoopPix:mov	al,[edi]	; Invert BYTEs
	not	al
	mov	[edi],al
	inc	edi
	loop	LoopPix
ToEnd:
        ret                     ; _cdecl return
                
NotR	endp



;void YUV_RGB(unsigned char *OutData, const unsigned char *y, const unsigned char *u, const unsigned char *v, unsigned PixelCount)
	public YUV_RGB
YUV_RGB proc \
        uses edi esi ebx, \
        OutData: ptr BYTE, \
        y: ptr BYTE, \
        u: ptr BYTE, \
	v: ptr BYTE, \
	PixelCount: DWORD
	
	mov	edi,[OutData]
	mov	esi,[y]
	mov	ebx,[u]
	mov	ecx,[PixelCount]
	push	ebp
	mov	ebp,[v]
	
	sub	ecx,2
	jb	Exit

LoopPx:	xor	edx,edx
	mov	dh,[esi]	; 255*Y	

	xor	eax,eax
	mov	al,[ebp]	; V
	sub	eax,128	
	imul	eax,291		; 291*V	
	add	eax,edx
	
	js	SmallR1
	test	eax,0FFFF0000h
	jnz	BigR1
	mov	[edi],ah	; B1
	jmp	LoopX1R
BigR1:	mov	byte ptr [edi],255
        jmp	LoopX1R
SmallR1:mov	byte ptr [edi],0
LoopX1R:add	edi,2		; Shift to B

	xor	eax,eax
	mov	al,[ebx]	; U
	sub	eax,128
	imul	eax,521		; 291*V	
	add	eax,edx

	js	SmallB1
	test	eax,0FFFF0000h
	jnz	BigB1
	mov	[edi],ah	; B1
	jmp	LoopX1B
BigB1:	mov	byte ptr [edi],255
        jmp	LoopX1B
SmallB1:mov	byte ptr [edi],0
LoopX1B:dec	edi		; Shift back to G1

				;EDX = 255*Y
	xor	eax,eax	
	mov	al,[ebp]	; V
	sub	eax,128	
	imul	eax,148
	sub	edx,eax
	
	xor	eax,eax	
	mov	al,[ebx]	; U
	sub	eax,128
	imul	eax,102		; 102*U
	sub	edx,eax		; 255*Y - 102*U - 148*V

	js	SmallG1
	test	edx,0FFFF0000h
	jnz	BigG1
	mov	[edi],dh	; R1
	jmp	LoopX1G
BigG1:	mov	byte ptr [edi],255
        jmp	LoopX1G
SmallG1:mov	byte ptr [edi],0
LoopX1G:add	edi,2		; Shift to R2

	inc	esi	

		; 2nd pixel
	xor	edx,edx
	mov	dh,[esi]	; 255*Y		

	xor	eax,eax
	mov	al,[ebp]	; V
	sub	eax,128	
	imul	eax,291		; 291*V	
	add	eax,edx
	
	js	SmallR2
	test	eax,0FFFF0000h
	jnz	BigR2
	mov	[edi],ah	; B2
	jmp	LoopX2R
BigR2:	mov	byte ptr [edi],255
        jmp	LoopX2R
SmallR2:mov	byte ptr [edi],0
LoopX2R:add	edi,2		; Shift to B2

	xor	eax,eax
	mov	al,[ebx]	; U
	sub	eax,128
	imul	eax,521		; 291*V	
	add	eax,edx

	js	SmallB2
	test	eax,0FFFF0000h
	jnz	BigB2
	mov	[edi],ah	; B1
	jmp	LoopX2B
BigB2:	mov	byte ptr [edi],255
        jmp	LoopX2B
SmallB2:mov	byte ptr [edi],0
LoopX2B:dec	edi		; Shift back to G

				;EDX = 255*Y
	xor	eax,eax	
	mov	al,[ebp]	; V
	sub	eax,128	
	imul	eax,148
	sub	edx,eax
	
	xor	eax,eax	
	mov	al,[ebx]	; U
	sub	eax,128
	imul	eax,102		; 102*U
	sub	edx,eax		; 255*Y - 102*U - 148*V

	js	SmallG2
	test	edx,0FFFF0000h
	jnz	BigG2
	mov	[edi],dh	; R1
	jmp	LoopX2G
BigG2:	mov	byte ptr [edi],255
        jmp	LoopX2G
SmallG2:mov	byte ptr [edi],0
LoopX2G:add	edi,2		; Shift to R3

	inc	ebx		; inc U every 2nd pixel
	inc	ebp		; inc V every 2nd pixel

	inc	esi		; inc Y every pixel
	sub	ecx,2
	jae	LoopPx

Exit:	
	pop	ebp
	ret
YUV_RGB endp



;void YUYV_RGB(unsigned char *OutData, const unsigned char *yuyv, unsigned PixelCount);
	public YUYV_RGB
YUYV_RGB proc \
        uses edi esi ebx, \
        OutData: ptr BYTE, \
        yuyv: ptr BYTE, \
	PixelCount: DWORD
	
	mov	edi,[OutData]
	mov	esi,[yuyv]
	mov	ecx,[PixelCount]
	push	ebp	
	
	sub	ecx,2
	jb	Exit

LoopPx:	mov	ebx,[esi]
	
	xor	edx,edx
	mov	dh,bl		; 255*Y		

	mov	eax,ebx
	rol	eax,8
	and	eax,0FFh	; V
	sub	eax,128
	mov	ebp,eax		; store V to EBP
	imul	eax,291		; 291*V	
	add	eax,edx
	
	js	SmallR1
	test	eax,0FFFF0000h
	jnz	BigR1
	mov	[edi],ah	; B1
	jmp	LoopX1R
BigR1:	mov	byte ptr [edi],255
        jmp	LoopX1R
SmallR1:mov	byte ptr [edi],0
LoopX1R:add	edi,2		; Shift to B

	xor	eax,eax
	mov	al,bh		; U
	sub	eax,128
	imul	eax,521		; 291*U	
	add	eax,edx

	js	SmallB1
	test	eax,0FFFF0000h
	jnz	BigB1
	mov	[edi],ah	; B1
	jmp	LoopX1B
BigB1:	mov	byte ptr [edi],255
        jmp	LoopX1B
SmallB1:mov	byte ptr [edi],0
LoopX1B:dec	edi		; Shift back to G1

				;EDX = 255*Y
	
	imul	eax,ebp,148	; V normalised *148
	sub	edx,eax
	
	xor	eax,eax	
	mov	al,bh		; U
	sub	eax,128
	imul	eax,102		; 102*U
	sub	edx,eax		; 255*Y - 102*U - 148*V

	js	SmallG1
	test	edx,0FFFF0000h
	jnz	BigG1
	mov	[edi],dh	; R1
	jmp	LoopX1G
BigG1:	mov	byte ptr [edi],255
        jmp	LoopX1G
SmallG1:mov	byte ptr [edi],0
LoopX1G:add	edi,2		; Shift to R2

		; 2nd pixel
	mov	edx,ebx
	ror	edx,8
	and	edx,0FF00h	; 255*Y2
	
	imul	eax,ebp,291	; 291*V	
	add	eax,edx
	
	js	SmallR2
	test	eax,0FFFF0000h
	jnz	BigR2
	mov	[edi],ah	; R2
	jmp	LoopX2R
BigR2:	mov	byte ptr [edi],255
        jmp	LoopX2R
SmallR2:mov	byte ptr [edi],0
LoopX2R:add	edi,2		; Shift to B2

	mov	bl,bh		; U
	and	ebx,0FFh
	sub	ebx,128	
	imul	eax,ebx,521	; 521*U
	add	eax,edx

	js	SmallB2
	test	eax,0FFFF0000h
	jnz	BigB2
	mov	[edi],ah	; B2
	jmp	LoopX2B
BigB2:	mov	byte ptr [edi],255
        jmp	LoopX2B
SmallB2:mov	byte ptr [edi],0
LoopX2B:dec	edi		; Shift back to G

				;EDX = 255*Y	
	imul	eax,ebp,148	; V normalised * 148
	sub	edx,eax

	imul	eax,ebx,102	; 102*U normalised
	sub	edx,eax		; 255*Y - 102*U - 148*V

	js	SmallG2
	test	edx,0FFFF0000h
	jnz	BigG2
	mov	[edi],dh	; G2
	jmp	LoopX2G
BigG2:	mov	byte ptr [edi],255
        jmp	LoopX2G
SmallG2:mov	byte ptr [edi],0
LoopX2G:add	edi,2		; Shift to R3


	add	esi,4		; inc Y per 2 pixels
	sub	ecx,2
	jae	LoopPx

Exit:	
	pop	ebp
	ret
YUYV_RGB endp



;void swab16(unsigned char *Data, unsigned PixelCount)
	public	swab16
swab16 proc \
        uses esi, \
        Data:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]	; cx=amount of pixels
        jecxz	ToEnd			; array has zero size

	mov	esi,[Data]		; Load data ptr.

LoopPix:mov	ax,[esi]
	xchg	ah,al
	mov	[esi],ax
	add	esi,2
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return
swab16	endp


;void swab32(unsigned char *Data, unsigned PixelCount)
	public	swab32
swab32 proc \
        uses esi, \
        Data:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]	; cx=amount of pixels
        jecxz	ToEnd			; array has zero size

	mov	esi,[Data]		; Load data ptr.

LoopPix:mov	eax,[esi]
	bswap	eax
	mov	[esi],eax
	add	esi,4
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return
swab32	endp



;void swab64(unsigned char *Data, unsigned PixelCount)
	public	swab64
swab64 proc \
        uses esi, \
        Data:ptr byte, \
        PixelCount:DWORD

        mov     ecx,[PixelCount]	; cx=amount of pixels
        jecxz	ToEnd			; array has zero size

	mov	esi,[Data]		; Load data ptr.

LoopPix:mov	eax,[esi]
	mov	edx,[esi+4]
	bswap	eax
	bswap	edx
	mov	[esi+4],eax
	mov	[esi],edx
	add	esi,8
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return
swab64	endp


        end
