; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Draw library contains procedures for drawing oprtations.
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: This file contains OS independent part and includes OS dependent files.
;_________________________________________________________________________________________
module "Draw library"


;include "%TargetOS%/draw.asm"



proc DrawSolidRect, .pDstImage, .x, .y, .width, .height, .color
.drect RECT
.rect  RECT
begin
        pushad

        mov     esi, [.pDstImage]

        xor     eax, eax
        mov     ecx, [esi+TImage.width]
        mov     edx, [esi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish


        stdcall LockImg, esi
        jc      .finish

; [.drect] contains the destination rectangle

        mov     ecx, [.drect.right]
        mov     edx, [.drect.bottom]
        sub     ecx, [.drect.left]
        sub     edx, [.drect.top]

        mov     edi, [.drect.top]
        imul    edi, [esi+TImage.width]
        add     edi, [.drect.left]
        lea     edi, [edi*4]
        add     edi, [esi+TImage.pPixels]

        mov     esi, [esi+TImage.width]
        lea     esi, [4*esi]

        stdcall __fix_color, [.color], regEAX

.loopY:

        mov     ebx, ecx     ; the width of the source rectangle

.loopX:
        dec     ebx
        mov     [edi+4*ebx], eax        ; fill the color
        jnz     .loopX

        add     edi, esi
        dec     edx
        jnz     .loopY

        stdcall UnlockImg, [.pDstImage]

.finish:
        popad
        return
endp





proc BlendSolidRect, .pDstImage, .x, .y, .width, .height, .color
.drect RECT
.rect  RECT
begin
        pushad

        mov     esi, [.pDstImage]

        xor     eax, eax
        mov     ecx, [esi+TImage.width]
        mov     edx, [esi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish


        stdcall LockImg, esi
        jc      .finish

; here [.srect] contains the source rectange
; [.drect] contains the destination rectangle
; the width and height of the rectangles  is the same.

        mov     ecx, [.drect.right]
        mov     edx, [.drect.bottom]
        sub     ecx, [.drect.left]
        sub     edx, [.drect.top]

        mov     edi, [.drect.top]
        imul    edi, [esi+TImage.width]
        add     edi, [.drect.left]
        lea     edi, [edi*4]
        add     edi, [esi+TImage.pPixels]

        mov     esi, [esi+TImage.width]
        lea     esi, [4*esi]

        stdcall __fix_color, [.color], regEAX

; prepare MMX constants

        pxor    mm0, mm0        ; mm0 = 0000 0000 0000 0000
        pcmpeqw mm1, mm1                                        ; mm1 = ffff ffff ffff ffff
        psrlw   mm1, 8                                         ; mm1 = 00ff 00ff 00ff 00ff

; the color
        movd    mm7, eax

        movq    mm5, mm7
        psrlq   mm5, 24                 ; alpha source
        punpckldq mm5, mm5
        packssdw  mm5, mm5              ; mm5 = As, As, As, As

        movq    mm4, mm1
        psubw   mm4, mm5                ; mm4 = Bs Bs Bs Bs     (Bs = $100 - As)

        punpcklbw mm7, mm0              ; byte to word source pixel
        psllw     mm7, 8                ; Cs = Cs*256


.loopY:
        mov     ebx, ecx        ; the width of the source rectangle

.loopX:
        dec     ebx                     ; The ZF will not be changed later in the inner loop.

        movd    mm6, [edi+4*ebx]        ; destination pixel.
        punpcklbw mm6, mm0              ; byte to word destination pixel
        pmullw  mm6, mm4                ; mm6 = Cd = Cd * (256-As) = Cd * Bs   (For alpha Ad = Ad*Bs)
        paddusw mm6, mm7                ; Cd = Cs + Cd
        psrlw   mm6, 8                  ; Cd = Cd/256

        packuswb mm6, mm0               ; pack words to bytes 0A 0R 0G 0B -> 0000ARGB
        movd     [edi+4*ebx], mm6

        jnz     .loopX

.nextY:
        add     edi, esi
        dec     edx
        jnz     .loopY

        emms
        stdcall UnlockImg, [.pDstImage]


.finish:
        popad
        return
endp







proc __fix_color, .color, .reg
begin
        pushad

        movzx   ebx, byte [.color+3]    ; alpha
        mov     ecx, ebx

        mov     esi, $ff

        movzx   eax, byte [.color+2]    ; red
        mul     ebx
        div     esi

        shl     ecx, 8
        mov     cl, al

        movzx   eax, byte [.color+1]    ; green
        mul     ebx
        div     esi

        shl     ecx, 8
        mov     cl, al

        movzx   eax, byte [.color]      ; blue
        mul     ebx
        div     esi

        shl     ecx, 8
        mov     cl, al

        mov     eax, [.reg]
        lea     eax, [esp+4*eax]

        mov     [eax], ecx
        popad
        return
endp



; Draws horizontal line from .x1 to .x2 on y with color [.color]
;
;

proc DrawHLine, .pImage, .x1, .x2, .y, .color
begin






        return
endp






proc DrawVLine, .pImage, .y1, .y2, .x, .color
begin


        return
endp



proc ScrollRectUp, .pDstImage, .x, .y, .width, .height, .lines
.drect RECT
.rect  RECT
begin
        pushad

        mov     esi, [.pDstImage]

        xor     eax, eax
        mov     ecx, [esi+TImage.width]
        mov     edx, [esi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish


        stdcall LockImg, esi
        jc      .finish

; here [.srect] contains the source rectange
; [.drect] contains the destination rectangle
; the width and height of the rectangles  is the same.

        mov     ebx, [.drect.right]
        mov     edx, [.drect.bottom]
        sub     ebx, [.drect.left]      ; width of the rect in pixels.
        sub     edx, [.drect.top]
        sub     edx, [.lines]           ; height of the rect.
        jc      .end_scroll

        mov     edi, [.drect.top]
        imul    edi, [esi+TImage.width]
        add     edi, [.drect.left]
        lea     edi, [edi*4]
        add     edi, [esi+TImage.pPixels]

        mov     eax, [esi+TImage.width]
        mov     ecx, eax
        sub     eax, ebx
        lea     eax, [4*eax]            ; the skip count in bytes.

        imul    ecx, [.lines]
        lea     esi, [edi+4*ecx]        ; the source address.

.loopY:
        mov     ecx, ebx
        rep movsd               ; loop X

        lea     esi, [esi+eax]
        lea     edi, [edi+eax]

        dec     edx
        jnz     .loopY

.end_scroll:
        stdcall UnlockImg, [.pDstImage]

.finish:
        popad
        return
endp



proc ScrollRectDn, .pDstImage, .x, .y, .width, .height, .lines
.drect RECT
.rect  RECT
begin
        pushad

        mov     esi, [.pDstImage]

        xor     eax, eax
        mov     ecx, [esi+TImage.width]
        mov     edx, [esi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish

        stdcall LockImg, esi
        jc      .finish

        mov     ebx, [.drect.right]
        mov     edx, [.drect.bottom]
        sub     ebx, [.drect.left]      ; width of the rect in pixels.
        sub     edx, [.drect.top]
        sub     edx, [.lines]           ; height of the rect.
        jc      .end_scroll

        mov     edi, [.drect.bottom]
        dec     edi
        imul    edi, [esi+TImage.width]
        add     edi, [.drect.left]

        lea     edi, [edi*4]
        add     edi, [esi+TImage.pPixels]

        mov     eax, [esi+TImage.width]
        mov     ecx, eax
        add     eax, ebx
        lea     eax, [4*eax]            ; the skip count in bytes.
        neg     eax

        imul    ecx, [.lines]
        neg     ecx
        lea     esi, [edi+4*ecx]        ; the source address.
        neg     ecx

.loopY:
        mov     ecx, ebx
        rep movsd               ; loop X

        lea     esi, [esi+eax]
        lea     edi, [edi+eax]

        dec     edx
        jnz     .loopY

.end_scroll:

        cld
        stdcall UnlockImg, [.pDstImage]

.finish:
        popad
        return
endp






proc ScrollRectLeft, .pDstImage, .x, .y, .width, .height, .cols
.drect RECT
.rect  RECT
begin
        pushad

        mov     esi, [.pDstImage]

        xor     eax, eax
        mov     ecx, [esi+TImage.width]
        mov     edx, [esi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish


        stdcall LockImg, esi
        jc      .finish

; [.drect] contains the destination rectangle

        mov     ebx, [.drect.bottom]
        mov     edx, [.drect.right]
        sub     ebx, [.drect.top]       ; height of the rect.
        sub     edx, [.drect.left]      ; width of the rect in pixels.
        sub     edx, [.cols]
        jc      .end_scroll

        mov     edi, [.drect.top]
        imul    edi, [esi+TImage.width]
        add     edi, [.drect.left]
        lea     edi, [edi*4]
        add     edi, [esi+TImage.pPixels]       ; pointer to the begining of the drect

        mov     eax, [esi+TImage.width]
        mov     ecx, [.cols]
        sub     eax, edx

        lea     esi, [edi+4*ecx]        ; the source address.

.loopY:
        mov     ecx, edx
        rep movsd               ; loop X

        lea     esi, [esi+4*eax]
        lea     edi, [edi+4*eax]

        dec     ebx
        jnz     .loopY

.end_scroll:
        stdcall UnlockImg, [.pDstImage]

.finish:
        popad
        return
endp




proc ScrollRectRight, .pDstImage, .x, .y, .width, .height, .cols
.drect RECT
.rect  RECT
begin
        pushad

        mov     esi, [.pDstImage]

        xor     eax, eax
        mov     ecx, [esi+TImage.width]
        mov     edx, [esi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish


        stdcall LockImg, esi
        jc      .finish

; [.drect] contains the destination rectangle

        mov     ebx, [.drect.bottom]
        mov     edx, [.drect.right]
        sub     ebx, [.drect.top]       ; height of the rect.
        sub     edx, [.drect.left]      ; width of the rect in pixels.
        sub     edx, [.cols]
        jc      .end_scroll

        mov     edi, [.drect.top]
        imul    edi, [esi+TImage.width]
        add     edi, [.drect.left]
        add     edi, edx

        lea     edi, [edi*4-4]
        add     edi, [esi+TImage.pPixels]       ; pointer to the begining of the drect

        mov     eax, [esi+TImage.width]
        mov     ecx, [.cols]
        add     eax, edx

        neg     ecx
        lea     esi, [edi+4*ecx]        ; the source address.

        std

.loopY:
        mov     ecx, edx
        rep movsd               ; loop X

        lea     esi, [esi+4*eax]
        lea     edi, [edi+4*eax]

        dec     ebx
        jnz     .loopY

        cld

.end_scroll:
        stdcall UnlockImg, [.pDstImage]

.finish:
        popad
        return
endp




proc ApplyAlphaRect, .pImage, .x, .y, .width, .height, .alpha
.drect RECT
.rect  RECT
begin
        pushad

        mov     edi, [.pImage]

        xor     eax, eax
        mov     ecx, [edi+TImage.width]
        mov     edx, [edi+TImage.height]

        mov     [.drect.left], eax
        mov     [.drect.top], eax
        mov     [.drect.right], ecx
        mov     [.drect.bottom], edx

        mov     ecx, [.x]
        mov     edx, [.y]

        mov     [.rect.left], ecx
        mov     [.rect.top], edx

        add     ecx, [.width]
        add     edx, [.height]

        mov     [.rect.right], ecx
        mov     [.rect.bottom], edx

        lea     ecx, [.drect]
        lea     edx, [.rect]
        stdcall RectIntersect, ecx, ecx, edx
        jc      .finish


        stdcall LockImg, edi

; here [.drect] contains the destination rectangle

        mov     ecx, [.drect.left]
        mov     edx, [.drect.top]
        sub     [.drect.right], ecx
        sub     [.drect.bottom], edx

        imul    edx, [edi+TImage.width]
        add     edx, [.drect.left]
        shl     edx, 2

        add     edx, [edi+TImage.pPixels]       ; pointer to the upper left corner of the rect.

        mov     edi, [edi+TImage.width]
        lea     edi, [4*edi]


.loopY:
        mov     ebx, [.drect.right]     ; the width of the source rectangle

.loopX:
        dec     ebx                     ; The ZF will not be changed later in the inner loop.
        js      .nextY


        movzx   eax, byte [edx+4*ebx+3]         ; dest alpha.
        movzx   ecx, byte [.alpha]

; Ad = Ad * [.alpha]/256

        imul    eax, ecx
        sar     eax, 8

        mov     [edx+4*ebx+3], al
        jmp     .loopX

.nextY:
        add     edx, edi
        dec     [.drect.bottom]
        jnz     .loopY


        stdcall UnlockImg, [.pImage]

.finish:
        popad
        return
endp




proc FilterDisabled, .pImage, .no_alpha
.gray dd ?
.alpha dd ?
begin
        pushad

        mov     edi, [.pImage]

        stdcall LockImg, edi

        mov     ebx, [edi+TImage.width]
        mov     ecx, [edi+TImage.height]

        mov     edi, [edi+TImage.pPixels]


.outloop:
        dec     ecx
        js      .finish

        mov     esi, ebx      ; Counter from 0 to IconWidth-1
        inc     esi

.inloop:
        dec     esi
        jz      .outloop

        movzx   eax, byte [edi]         ; blue
        movzx   edx, byte [edi+1]       ; green

        lea     edx, [edx+2*eax]        ;  2*Blue + Green

        movzx   eax, byte [edi+2]
        add     edx, eax                ; + Red

        movzx   eax, byte [edi+3]       ; Alpha
        mov     [.alpha], eax

        shr     edx, 2          ; div 4 -> Grayscale pixel.
                                ; This formula gives more realistic view.

        mov     [.gray], edx

; blend alpha

        cmp     [.no_alpha], 0
        jne     .store

        imul    eax, esi
        cdq
        div     ebx
        mov     [.alpha], eax

        mov     eax, [.gray]
        imul    eax, esi
        cdq
        div     ebx
        mov     [.gray], eax

.store:

        mov     al, byte [.alpha]
        shl     eax, 8
        mov     al ,byte [.gray]
        shl     eax, 8
        mov     al ,byte [.gray]
        shl     eax, 8
        mov     al ,byte [.gray]

        stosd
        jmp     .inloop

.finish:
        stdcall UnlockImg, [.pImage]

        popad
        return
endp


endmodule