
.CODE             ;Indicates the start of a code segment.


;void RGB_BGR(unsigned char *Data, unsigned PixelCount)
	public	RGB_BGR

RGB_BGR proc \
        uses rsi rbx
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

	mov	rsi,rcx		; Load data ptr.
	mov	rcx,rdx		; rcx=amount of pixels
	sub	rcx,4
	jl	LoopPix1

LoopPix4:
	mov	eax,[rsi]		;[R1, G1, B1, R2]
	mov	ebx,[rsi+4]		;[G2, B2, R3, G3]
	mov	[rsi+2],al		;R1
	shr	eax,16			;[B1, R2]
	mov	[rsi],al		;B1
	mov	[rsi+3],bh		;B2
	mov	[rsi+5],ah		;R2
	shr	ebx,16			;[R3, G3, 0, 0]
	mov	eax,[rsi+8]		;[B3, R4, G4, B4]
	mov	[rsi+8],bl		;R3
	mov	[rsi+6],al		;B3
	mov	[rsi+11],ah		;B4
	shr	eax,16			;[G4, B4, 0, 0]
	mov	[rsi+9],ah		;B4
	add	rsi,12
	sub	rcx,4
	jae	LoopPix4
	
LoopPix1:add	rcx,4	
	jz	ToEnd		; array has zero size
LoopPix:mov	al,[rsi]
	mov	ah,[rsi+2]
	mov	[rsi],ah
	mov	[rsi+2],al
	add	rsi,3
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGB_BGR	endp



;void RGBA32_BGRA32(char *Data, int PixelCount)
	public	RGBA32_BGRiA32

RGBA32_BGRiA32 proc \
        uses rsi
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

	mov	rsi,rcx		; Load data ptr.
	mov	rcx,rdx		; rcx=amount of pixels
	jrcxz	ToEnd		; array has zero size

LoopPix:mov	al,[rsi]
	mov	ah,[rsi+2]
	mov	[rsi],ah
	mov	[rsi+2],al
	mov	al,[rsi+3]
	not	al
	mov	[rsi+3],al
	add	rsi,4
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGBA32_BGRiA32 endp


;void RGBA64_BGRA64(char *Data, int PixelCount)
	public	RGBA64_BGRiA64

RGBA64_BGRiA64 proc \
        uses rsi
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

	mov	rsi,rcx		; Load data ptr.
	mov	rcx,rdx		; rcx=amount of pixels
	jrcxz	ToEnd		; array has zero size

LoopPix:mov	ax,[rsi]
	mov	dx,[rsi+4]
	mov	[rsi+4],ax
	mov	[rsi],dx	
	mov	ax,[rsi+6]
	not	ax
	mov	[rsi+6],ax	
		
	add	rsi,8
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
RGBA64_BGRiA64 endp


;void RGB_BGR2(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB_BGR2
RGB_BGR2 proc \
        uses rsi rdi
;       OutData: ptr byte,RCX
;       InData: ptr byte,RDX
;       PixelCount: QWORD R8

	mov	rsi,rdx
	mov	rdi,rcx

        mov     rcx,R8		; cx=amount of pixels

	sub	rcx,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,[rsi]	; EDX = G3 R3 B2 G2
	add	rsi,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	[rdi],edx	;	G3 B3 R2 G2	shipped out
	add	rdi,4

	stosd			; R4 G4 B4 R3	shipped out
	
	sub	rcx,4
	jae	LoopPix4

			; Simple loop for 0,1,2,3 pixels (works also for more px)
LoopSimple:
	add	rcx,4		; rcx was -4, correct counter
        jz	ToEnd		; array has zero size

LoopPix:lodsw
	mov	[rdi+2],al
	mov	[rdi+1],ah
	lodsb
	mov	[rdi],al
	add	rdi,3
	dec	rcx
	jz	ToEnd
	
	lodsb
	mov	[rdi+2],al
	lodsw
	mov	[rdi+1],al
	mov	[rdi],ah
	add	rdi,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 rsi rdi rbx
;       OutData: ptr byte,RCX
;       InData: ptr byte,RDX
;       PixelCount: QWORD R8

        mov     rsi,rdx			; source data
        mov     rdi,rcx			; destination data

	mov     rcx,R8			; rcx=amount of pixels

        sub	rcx,4
	jl	LoopSimple		; array size < 4

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

	mov	ebx,[rsi]		; EBX = ?? B3 G3 R3
	add	rsi,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	rcx,4
	jae	LoopPx4

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

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

ToEnd:
        ret                     ; _cdecl return
                
RGB32_BGR24 endp



;void RGB_Gray(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB_Gray
RGB_Gray proc \
        uses rsi rdi rbx
;	OutData:ptr byte, \
;       InData:ptr byte, \
;       PixelCount:DWORD

        mov     rsi,rdx			; source data
        mov     rdi,rcx			; destination data

        mov     rcx,R8			; rcx=amount of pixels
        
	mov	ebx,3

	sub	rcx,2
	jl	LoopPix1

LoopPix2:
	lodsw
	add	al,ah
	mov	ah,0
	rcl	ah,1
	mov	dx,[rsi]
	add	rsi,2
	add	al,dl
	adc	ah,0
	div	bl
	stosb

	lodsw
	add	al,ah
	mov	ah,0
	rcl	ah,1
	add	al,dh
	adc	ah,0
	div	bl
	stosb

	sub	rcx,2
	ja	LoopPix2
	
LoopPix1:
	add	rcx,2
        cmp	rcx,1
        jl	ToEnd			; array has zero size

	mov	dh,0
	
LoopPix:mov	ah,0
	mov	al,[rsi]
	mov	bl,[rsi+1]
	add	ax,bx
	mov	bl,[rsi+2]
	add	ax,bx
	mov	bl,3
	div	bl
	stosb
	add	rsi,3
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return

RGB_Gray endp


;void RGB_Gray24(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB_Gray24
RGB_Gray24 proc \
        uses rsi rdi rbx
;	OutData:ptr byte, \
;       InData:ptr byte, \
;       PixelCount:DWORD

        mov     rsi,rdx			; source data
        mov     rdi,rcx			; destination data

        mov     rcx,R8			; rcx=amount of pixels
        
	mov	ebx,3

	sub	rcx,2
	jl	LoopPix1

LoopPix2:
	lodsw
	add	al,ah
	mov	ah,0
	rcl	ah,1
	mov	dx,[rsi]
	add	rsi,2
	add	al,dl
	adc	ah,0
	div	bl
	stosb
	stosb
	stosb

	lodsw
	add	al,ah
	mov	ah,0
	rcl	ah,1
	add	al,dh
	adc	ah,0
	div	bl
	stosb
	stosb
	stosb

	sub	rcx,2
	ja	LoopPix2
	
LoopPix1:
	add	rcx,2
        cmp	rcx,1
        jl	ToEnd			; array has zero size

	mov	dh,0
	
LoopPix:mov	ah,0
	mov	al,[rsi]
	mov	bl,[rsi+1]
	add	ax,bx
	mov	bl,[rsi+2]
	add	ax,bx
	mov	bl,3
	div	bl
	stosb
	stosb
	stosb	
	add	rsi,3
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return

RGB_Gray24 endp


;void RGB32_Gray(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	RGB32_Gray
RGB32_Gray proc \
        uses rsi rdi rbx
;	OutData:ptr byte, \
;        InData:ptr byte, \
;        PixelCount:DWORD

	mov	rsi,rdx			; source data
	mov	rdi,rcx			; destination data

	mov	rcx,R8			; rcx=amount of pixels
	jrcxz	ToEnd			; array has zero size

	mov	bh,0	
LoopPix:mov	ah,0
	mov	al,[rsi]
	mov	bl,[rsi+1]
	add	ax,bx
	mov	bl,[rsi+2]
	add	ax,bx
	mov	bl,3
	div	bl
	stosb
	add	rsi,4
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return
                
RGB32_Gray endp


;void BGR_Gray24precise(unsigned char *OutData, const unsigned char *InData, unsigned PixelCount)
	public	BGR_Gray24precise
BGR_Gray24precise proc \
        uses rsi rdi rbx
;	OutData:ptr byte, \
;        InData:ptr byte, \
;        PixelCount:DWORD

	mov	rsi,rdx			; source data
	mov	rdi,rcx			; destination data

	mov	rcx,R8			; rcx=amount of pixels
	jrcxz	ToEnd			; array has zero size

	cld
LoopPix:movzx	eax,byte ptr[rsi]
	imul	edx,eax,4731

	movzx	eax,byte ptr[rsi+1]
	imul	eax,eax,46871
	add	edx,eax

	movzx	eax,byte ptr[rsi+2]
	imul	eax,eax,13932
	add	eax,edx

	shr	eax,16
	add	rsi,3
	stosb
	stosb
	stosb
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return

BGR_Gray24precise endp


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

	mov	rsi,rdx			; source data
	mov	rdi,rcx			; destination data

	mov	rcx,R8			; rcx=amount of pixels
	jrcxz	ToEnd			; array has zero size

LoopPix:movzx	eax,byte ptr[rsi]
	imul	edx,eax,4731

	movzx	eax,byte ptr[rsi+1]
	imul	eax,eax,46871
	add	edx,eax

	movzx	eax,byte ptr[rsi+2]
	imul	eax,eax,13932
	add	eax,edx			; return value to eax
	
	add	rsi,4
	shr	eax,16	
	stosb
	stosb
	stosb
	loop	LoopPix

ToEnd:
	ret                     ; _cdecl return

BGR32_Gray24 endp


;void NotR(char *R, unsigned DataSize)	//R1:=not(R1)
	public  NotR
NotR	proc \
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

	xchg	rcx,rdx		; rcx=amount of pixels/bytes

        sub	rcx,8
        jl	LoopPx1
        
LoopPx8:;mov	rax,[rdx]	;moving through register is slower on x64. On x32 it works better.
        ;not	rax
        ;mov	[rdx],rax
        not	qword ptr [rdx]	; Invert QWORDs
        add	rdx,8
        
        sub	rcx,8
        jge	LoopPx8

LoopPx1:add	rcx,8
	jz	ToEnd

LoopPix:not	byte ptr [rdx]	; Invert BYTE
	inc	rdx
	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
	
;IF @Version LT 1200
YUV_RGB proc \
        uses rdi rsi rbx,
        OutData: ptr BYTE,
        y: ptr BYTE,
        u: ptr BYTE,
	v: ptr BYTE,
	PixelCount: DWORD	; on stack

;ELSE
;; The ASM from MSVC2013 seems to be much more worse than previous one.
;YUV_RGB proc \
;        uses rdi rsi rbx
;ENDIF
	
	mov	rdi,rcx		; [OutData]
	mov	rsi,rdx		; [y]
IF @Version LT 1200
	mov	ecx,PixelCount
ELSE
	mov	ecx,[rsp+28h+4*8]	;28h stays for 5th arg; rbp,rdi,rsi,rbx are now on the stack
ENDIF

	sub	ecx,2
	jb	exit

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

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

	movzx	eax,byte ptr [R8]	; U
	sub	eax,128
	mov	R11,rax
	imul	eax,521		; 291*V	
	add	eax,edx

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

				;EDX = 255*Y
	mov	rax,R10		; V	
	imul	eax,148
	sub	edx,eax
	
	mov	rax,R11		; U
	imul	eax,102		; 102*U
	sub	edx,eax		; 255*Y - 102*U - 148*V

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

	inc	rsi	

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

	mov	rax,R10		; V	
	imul	eax,291		; 291*V	
	add	eax,edx
	
	js	SmallR2
	test	eax,0FFFF0000h
	jnz	BigR2
	mov	[rdi],ah	; B2
	jmp	LoopX2R
BigR2:	mov	byte ptr [rdi],255
        jmp	LoopX2R
SmallR2:mov	byte ptr [rdi],0
LoopX2R:add	rdi,2		; Shift to B2

	mov	rax,R11		; U
	imul	eax,521		; 521*U	
	add	eax,edx

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

				;EDX = 255*Y
	mov	rax,R10		; V	
	imul	eax,148
	sub	edx,eax
	
	mov	rax,R11		; U
	imul	eax,102		; 102*U
	sub	edx,eax		; 255*Y - 102*U - 148*V

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

	inc	R8		; inc U every 2nd pixel
	inc	R9		; inc V every 2nd pixel

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

Exit:	
	ret
YUV_RGB endp


;void YUYV_RGB(unsigned char *OutData, const unsigned char *yuyv, unsigned PixelCount);
	public YUYV_RGB
YUYV_RGB proc \
        uses rdi rsi rbx
;        OutData: ptr BYTE, \
;        yuyv: ptr BYTE, \
;	PixelCount: DWORD

	mov	rsi,rdx			; source data
	mov	rdi,rcx			; destination data
	mov	rcx,R8			; rcx=amount of pixels

	mov	R8,rbp
	
	sub	ecx,2
	jb	Exit

LoopPx:	mov	ebx,[rsi]
	
	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	[rdi],ah	; B1
	jmp	LoopX1R
BigR1:	mov	byte ptr [rdi],255
        jmp	LoopX1R
SmallR1:mov	byte ptr [rdi],0
LoopX1R:add	rdi,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	[rdi],ah	; B1
	jmp	LoopX1B
BigB1:	mov	byte ptr [rdi],255
        jmp	LoopX1B
SmallB1:mov	byte ptr [rdi],0
LoopX1B:dec	rdi		; 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	[rdi],dh	; R1
	jmp	LoopX1G
BigG1:	mov	byte ptr [rdi],255
        jmp	LoopX1G
SmallG1:mov	byte ptr [rdi],0
LoopX1G:add	rdi,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	[rdi],ah	; R2
	jmp	LoopX2R
BigR2:	mov	byte ptr [rdi],255
        jmp	LoopX2R
SmallR2:mov	byte ptr [rdi],0
LoopX2R:add	rdi,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	[rdi],ah	; B2
	jmp	LoopX2B
BigB2:	mov	byte ptr [rdi],255
        jmp	LoopX2B
SmallB2:mov	byte ptr [rdi],0
LoopX2B:dec	rdi		; 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	[rdi],dh	; G2
	jmp	LoopX2G
BigG2:	mov	byte ptr [rdi],255
        jmp	LoopX2G
SmallG2:mov	byte ptr [rdi],0
LoopX2G:add	rdi,2		; Shift to R3

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

Exit:	
	mov	rbp,R8
	ret
YUYV_RGB endp


;void swab16(unsigned char *Data, unsigned PixelCount)
	public	swab16

swab16 proc \
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

        xchg	rcx,rdx
        
        sub	rcx,2
	jl	LoopPx1

LoopPx2:mov	eax,[rdx]
	bswap	eax
	rol	eax,16
	mov	[rdx],eax
	add	rdx,4
        sub	rcx,2
	ja	LoopPx2

LoopPx1:add	rcx,2
	jz	ToEnd		; array has zero size

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

ToEnd:
        ret                     ; _cdecl return
                
swab16	endp



;void swab32(unsigned char *Data, unsigned PixelCount)
	public	swab32

swab32 proc
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

	xchg	rcx,rdx        

	sub	rcx,2
	jl	LoopPx1

LoopPx2:mov	rax,[rdx]
	bswap	rax
	rol	rax,32
	mov	[rdx],rax
	add	rdx,8
        sub	rcx,2
	ja	LoopPx2

LoopPx1:add	rcx,2
	jz	ToEnd		; array has zero size

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

ToEnd:
        ret                     ; _cdecl return
                
swab32	endp



;void swab64(unsigned char *Data, unsigned PixelCount)
	public	swab64

swab64 proc
;       Dest:ptr byte,	RCX
;       count:DWORD	RDX

	xchg	rdx,rcx
        jrcxz	ToEnd		; array has zero size

LoopPix:mov	rax,[rdx]
	bswap	rax
	mov	[rdx],rax
	add	rdx,8
	loop	LoopPix

ToEnd:
        ret                     ; _cdecl return
                
swab64	endp


        end
