/*          ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      24 bit linear graphics functions.
 *
 *      By Michal Mertl.
 *
 *      See readme.txt for copyright information.
 */


#include "asmdefs.inc"

#ifdef ALLEGRO_COLOR24

.text



/* void _linear_putpixel24(BITMAP *bmp, int x, int y, int color);
 *  Draws a pixel onto a linear bitmap.
 */
FUNC(_linear_putpixel24)
   pushl %ebp
   movl %esp, %ebp
   pushl %ebx
   pushw %es

   movl ARG1, %edx               /* edx = bmp */
   movl ARG2, %ecx               /* ecx = x */
   movl ARG3, %eax               /* eax = y */

   cmpl $0, BMP_CLIP(%edx)       /* test clip flag */
   je putpix_noclip
   cmpl %ecx, BMP_CL(%edx)       /* test cl */
   jg putpix_done
   cmpl %ecx, BMP_CR(%edx)       /* test cr */
   jle putpix_done
   cmpl %eax, BMP_CT(%edx)       /* test ct */
   jg putpix_done
   cmpl %eax, BMP_CB(%edx)       /* test cb */
   jle putpix_done

putpix_noclip:
   movw BMP_SEG(%edx), %es       /* segment selector */
   movl ARG4, %ebx               /* bx = color */

   cmpl $DRAW_SOLID, GLOBL(_drawing_mode)
   je putpix_solid_mode          /* solid draw? */

   cmpl $DRAW_XOR, GLOBL(_drawing_mode)
   je putpix_xor_mode            /* XOR? */

   cmpl $DRAW_TRANS, GLOBL(_drawing_mode)
   je putpix_trans_mode          /* translucent? */

   LOOKUP_PATTERN_POS(%ecx, %eax, %edx)
   leal (%ecx, %ecx, 2), %ecx
   movl (%eax, %ecx), %ebx       /* read pixel from pattern bitmap */
   andl $0xFFFFFF, %ebx

   movl ARG1, %edx               /* reload clobbered registers */
   movl ARG2, %ecx
   movl ARG3, %eax

   cmpl $DRAW_COPY_PATTERN, GLOBL(_drawing_mode)
   je putpix_solid_mode          /* draw the pattern pixel? */

   cmpl $MASK_COLOR_24, %ebx     /* test the pattern pixel */
   je putpix_zero_pattern

   movl ARG4, %ebx               /* if set, draw color */
   jmp putpix_solid_mode

   _align_
putpix_zero_pattern:
   cmpl $DRAW_MASKED_PATTERN, GLOBL(_drawing_mode)
   je putpix_done                /* skip zero pixels in masked mode */
   xorl %ebx, %ebx
   jmp putpix_solid_mode         /* draw zero pixels in solid mode */

   _align_
putpix_xor_mode:
   READ_BANK()                   /* read pixel from screen, and XOR it */
   leal (%ecx, %ecx, 2), %ecx    /* ecx *= 3 */
   movl %es:(%eax, %ecx), %eax
   xorl %eax, %ebx
   movl ARG3, %eax               /* re-read Y position */
   WRITE_BANK()
   movw %bx, %es:(%eax, %ecx)
   shrl $16, %ebx
   movb %bl, %es:2(%eax, %ecx)
   jmp putpix_done

   _align_
putpix_trans_mode:
   READ_BANK() 
   leal (%ecx, %ecx, 2), %ecx    /* ecx *= 3 */
   pushl %ecx
   pushl %edx
   pushl GLOBL(_blender_alpha)
   pushl %es:(%eax, %ecx)        /* read pixel from screen */
   pushl %ebx                    /* and the drawing color */
   call *GLOBL(_blender_func24)  /* blend */
   addl $12, %esp
   popl %edx
   popl %ecx
   movl %eax, %ebx
   movl ARG3, %eax               /* re-read Y position */
   WRITE_BANK()
   movw %bx, %es:(%eax, %ecx)
   shrl $16, %ebx
   movb %bl, %es:2(%eax, %ecx)
   jmp putpix_done

   _align_
putpix_solid_mode:
   WRITE_BANK()                  /* write the pixel */
   leal (%ecx, %ecx, 2), %ecx
   movw %bx, %es:(%eax, %ecx)
   shrl $16, %ebx
   movb %bl, %es:2(%eax, %ecx)
putpix_done:
   popw %es

   UNWRITE_BANK()

   popl %ebx
   movl %ebp, %esp
   popl %ebp
   ret                           /* end of _linear_putpixel24() */




/* int _linear_getpixel24(BITMAP *bmp, int x, int y);
 *  Reads a pixel from a linear bitmap.
 */
FUNC(_linear_getpixel24)
   pushl %ebp
   movl %esp, %ebp
   pushl %ebx
   pushw %es

   xorl %eax, %eax
   xorl %edx, %edx
   movl ARG1, %edx               /* edx = bmp */
   movl ARG2, %ecx               /* ecx = x */
   movl ARG3, %eax               /* eax = y */

   testl %ecx, %ecx              /* test that we are on the bitmap */
   jl getpix_skip
   cmpl %ecx, BMP_W(%edx)
   jle getpix_skip
   testl %eax, %eax
   jl getpix_skip
   cmpl %eax, BMP_H(%edx)
   jg getpix_ok

   _align_
getpix_skip:                     /* return -1 if we are off the edge */
   movl $-1, %ebx
   jmp getpix_done

   _align_
getpix_ok:
   READ_BANK()                   /* select the bank */

   movw BMP_SEG(%edx), %es       /* segment selector */
   leal (%ecx, %ecx, 2), %ecx
   movl %es:(%eax, %ecx), %ebx
   andl $0xFFFFFF, %ebx

getpix_done:
   popw %es

   UNWRITE_BANK()

   movl %ebx, %eax
   popl %ebx
   movl %ebp, %esp
   popl %ebp
   ret                           /* end of _linear_getpixel24() */




/* void _linear_hline24(BITMAP *bmp, int x1, int y, int x2, int color);
 *  Draws a horizontal line onto a linear bitmap.
 */
FUNC(_linear_hline24)
   pushl %ebp
   movl %esp, %ebp
   pushl %ebx
   pushl %esi
   pushl %edi
   pushw %es

   movl ARG1, %edx               /* edx = bmp */
   movl ARG2, %ebx               /* ebx = x1 */
   movl ARG3, %eax               /* eax = y */
   movl ARG4, %ecx               /* ecx = x2 */
   cmpl %ebx, %ecx
   jge hline_no_xswap
   xchgl %ecx, %ebx

hline_no_xswap:
   cmpl $0, BMP_CLIP(%edx)       /* test bmp->clip */
   je hline_noclip

   cmpl BMP_CT(%edx), %eax       /* test bmp->ct */
   jl hline_done

   cmpl BMP_CB(%edx), %eax       /* test bmp->cb */
   jge hline_done

   cmpl BMP_CL(%edx), %ebx       /* test x1, bmp->cl */
   jge hline_x1_ok
   cmpl BMP_CL(%edx), %ecx       /* test x2, bmp->cl */
   jl hline_done
   movl BMP_CL(%edx), %ebx       /* clip x1 */

hline_x1_ok:
   cmpl BMP_CR(%edx), %ecx       /* test x2, bmp->cr */
   jl hline_noclip
   cmpl BMP_CR(%edx), %ebx       /* test x1, bmp->cr */
   jge hline_done
   movl BMP_CR(%edx), %ecx       /* clip x2 */
   decl %ecx

hline_noclip:
   subl %ebx, %ecx               /* loop counter */
   incl %ecx

   movw BMP_SEG(%edx), %es       /* segment selector */

   WRITE_BANK()                  /* select write bank */

   pushl %ebx
   leal (%ebx, %ebx, 2), %ebx    /* ebx *= 3 */
   leal (%eax, %ebx), %edi       /* dest address in edi=eax+ebx */
   popl %ebx

   cmpl $DRAW_SOLID, GLOBL(_drawing_mode)
   je hline_solid_mode           /* solid draw? */

   cmpl $DRAW_XOR, GLOBL(_drawing_mode)
   jne hline_not_xor             /* XOR? */

   movl ARG3, %eax               /* select read bank */
   READ_BANK()
   leal (%ebx, %ebx, 2), %ebx
   leal (%eax, %ebx), %esi       /* source address in esi */

   movl ARG5, %eax               /* pixel color */
   movl %eax, %ebx
   movl %eax, ARG2               /* ARG2 == 12(%ebp) */
   movl %eax, 15(%ebp)           /* overwrite ARG2, ARG3, ARG4 */
   movl %eax, 18(%ebp)
   movw %ax, 21(%ebp)
   shrl $16, %eax
   movb %al, 23(%ebp)
   cmpl $4, %ecx
   jb hline_xor_short
   subl $4, %ecx

   _align_
hline_xor_loop:
   movl %es:(%esi), %eax         /* read 1st 4 bytes */
   xorl ARG2, %eax               /* xor it */
   movl %eax, %es:(%edi)         /* write it back */
   movl %es:4(%esi), %eax        /* 2nd 4 bytes */
   xorl ARG3, %eax
   movl %eax, %es:4(%edi)
   movl %es:8(%esi), %eax        /* 3rd 4 bytes */
   xorl ARG4, %eax
   movl %eax, %es:8(%edi)
   addl $12, %esi
   addl $12, %edi
   subl $4, %ecx
   jns  hline_xor_loop
   addl $4, %ecx
   jz  hline_done
   _align_
hline_xor_short:
   movl %es:(%esi), %eax
   xorl ARG5, %eax               /* xor */
   movw %ax, %es:(%edi)
   shrl $16, %eax
   movb %al, %es:2(%edi)
   addl $3, %esi
   addl $3, %edi
   decl %ecx
   jg hline_xor_short
   jmp hline_done

   _align_
hline_not_xor:
   cmpl $DRAW_TRANS, GLOBL(_drawing_mode)
   jne hline_not_trans           /* translucent? */

   movl ARG3, %eax               /* select read bank */
   READ_BANK() 
   leal (%ebx, %ebx, 2), %ebx
   leal (%eax, %ebx), %esi       /* source address in esi */

   movl %ecx, ARG4               /* loop counter on the stack */

   _align_
hline_trans_loop:
   pushl GLOBL(_blender_alpha)
   pushl %es:(%esi)              /* read pixel from screen */
   pushl ARG5                    /* and the drawing color */
   call *GLOBL(_blender_func24)  /* blend */
   addl $12, %esp
   movw %ax, %es:(%edi)          /* and write it */
   shrl $16, %eax
   movb %al, %es:2(%edi)
   addl $3, %esi
   addl $3, %edi
   decl ARG4
   jg hline_trans_loop
   jmp hline_done

   _align_
hline_not_trans:
   movl ARG3, %eax               /* get position in pattern bitmap */
   movl ARG2, %ebx
   LOOKUP_PATTERN_POS(%ebx, %eax, %edx)
   movl %eax, %esi
   movl GLOBL(_drawing_x_mask), %edx

   cmpl $DRAW_COPY_PATTERN, GLOBL(_drawing_mode)
   je hline_copy_pattern

   cmpl $DRAW_SOLID_PATTERN, GLOBL(_drawing_mode)
   je hline_solid_pattern_loop

   _align_
hline_masked_pattern_loop:
   leal (%ebx, %ebx, 2), %eax
   movl (%esi, %eax), %eax       /* read a pixel */
   andl $0xFFFFFF, %eax
   cmpl $MASK_COLOR_24, %eax     /* test it */
   je hline_masked_skip
   movl ARG5, %eax
   movw %ax, %es:(%edi)
   shrl $16, %eax 
   movb %al, %es:2(%edi)
   _align_
hline_masked_skip:
   incl %ebx 
   andl %edx, %ebx
   addl $3, %edi
   decl %ecx
   jg hline_masked_pattern_loop
   jmp hline_done

hline_copy_pattern:
   decl %ecx
   jz short_copy_pattern
   _align_
hline_copy_pattern_loop:
   leal (%ebx, %ebx, 2), %eax
   movl (%esi, %eax), %eax       /* read a pixel */
   movl %eax, %es:(%edi)
   incl %ebx
   andl %edx, %ebx
   addl $3, %edi
   decl %ecx
   jg hline_copy_pattern_loop
short_copy_pattern:
   leal (%ebx, %ebx, 2), %eax
   movl (%esi, %eax), %eax       /* read a pixel */
   movw %ax, %es:(%edi)
   shrl $16, %eax
   movb %al, %es:2(%edi)

   jmp hline_done

   _align_
hline_solid_pattern_loop:
   leal (%ebx, %ebx, 2), %eax
   movl (%esi, %eax), %eax       /* read a pixel */
   andl $0xFFFFFF, %eax
   cmpl $MASK_COLOR_24, %eax     /* test it */
   je hline_solid_zero

   movl ARG5, %eax
   movw %ax, %es:(%edi)
   shrl $16, %eax 
   movb %al, %es:2(%edi)         /* write a colored pixel */
   incl %ebx
   andl %edx, %ebx
   addl $3, %edi
   decl %ecx
   jg hline_solid_pattern_loop
   jmp hline_done

   _align_
hline_solid_zero:
   movw $0, %es:(%edi)           /* write a zero pixel */
   movb $0, %es:2(%edi)
   incl %ebx
   andl %edx, %ebx
   addl $3, %edi
   decl %ecx
   jg hline_solid_pattern_loop
   jmp hline_done

   _align_
hline_solid_mode:                /* regular hline drawer */
   movl ARG5, %eax               /* ARG2 = 12(%ebp) pixel color */
   movl %eax, ARG2               /* overwrite ARG2, ARG3 */
   movl %eax, 15(%ebp)
   movl ARG2, %eax
   movl 13(%ebp), %ebx
   movl 14(%ebp), %edx

     /*   al,ah,high al,ah,bl,bh ,high bl,bh,dl,dh,high dl,dh  */
     /*   1st pixel    ,2nd pixel,3rd pixel    ,4th pixel      */ 
     /*   ------eax-------,------ebx--------,------edx-------  */

   cmpl $4, %ecx 
   jb short_line 
   subl $4, %ecx                 /* test for sign flag */
   cld
   _align_
hline_solid_loop:                /* plots 4 pixels an once */
   movl %eax, %es:(%edi)
   movl %ebx, %es:4(%edi)
   movl %edx, %es:8(%edi)
   addl $12, %edi
   subl $4, %ecx
   jns  hline_solid_loop
   addl $4, %ecx                 /* add the helper back */
   jz  hline_done
   _align_
short_line:
   movw %ax, %es:(%edi)          /* plots remaining pixels (max 3) */
   movb %dl, %es:2(%edi)
   addl $3, %edi
   decl %ecx
   jg short_line
hline_done:
   popw %es

   movl ARG1, %edx
   UNWRITE_BANK()

   popl %edi
   popl %esi
   popl %ebx
   movl %ebp, %esp
   popl %ebp
   ret                           /* end of _linear_hline24 */




/* void _linear_vline24(BITMAP *bmp, int x, int y1, int y2, int color);
 *  Draws a vertical line onto a linear bitmap.
 */
FUNC(_linear_vline24)
   pushl %ebp
   movl %esp, %ebp
   pushl %ebx
   pushl %esi
   pushl %edi
   pushw %es

   movl ARG1, %edx               /* edx = bmp */
   movl ARG2, %edi               /* edi = x */
   movl ARG3, %esi               /* esi = y1 */
   movl ARG4, %ecx               /* ecx = y2 */
   cmpl %esi, %ecx
   jge vline_no_xswap
   xchgl %ecx, %esi

vline_no_xswap:
   cmpl $0, BMP_CLIP(%edx)       /* test bmp->clip */
   je vline_noclip

   cmpl BMP_CL(%edx), %edi       /* test bmp->cl */
   jl vline_done

   cmpl BMP_CR(%edx), %edi       /* test bmp->cr */
   jge vline_done

   cmpl BMP_CT(%edx), %esi       /* test y1, bmp->ct */
   jge vline_y1_ok
   cmpl BMP_CT(%edx), %ecx       /* test y2, bmp->ct */
   jl vline_done
   movl BMP_CT(%edx), %esi       /* clip y1 */

vline_y1_ok:
   cmpl BMP_CB(%edx), %ecx       /* test y2, bmp->cb */
   jl vline_noclip
   cmpl BMP_CB(%edx), %esi       /* test y1, bmp->cb */
   jge vline_done
   movl BMP_CB(%edx), %ecx       /* clip y2 */
   decl %ecx

vline_noclip:
   subl %esi, %ecx               /* loop counter */
   incl %ecx

   movw BMP_SEG(%edx), %es       /* load segment */

   cmpl $DRAW_SOLID, GLOBL(_drawing_mode)
   je vline_solid_mode           /* solid draw? */

   movl BMP_CLIP(%edx), %eax     /* store destination clipping flag */
   pushl %eax
   movl $0, BMP_CLIP(%edx)       /* turn clipping off (we already did it) */

   movl ARG5, %eax
   pushl %eax                    /* push color */
   pushl %esi                    /* push y */
   pushl %edi                    /* push x */
   pushl %edx                    /* push bitmap */

   movl %ecx, %ebx               /* ebx = loop counter */

   _align_
vline_special_mode_loop:         /* vline drawer for funny modes */
   call GLOBL(_linear_putpixel24)/* draw the pixel */
   incl 8(%esp)                  /* next y */
   decl %ebx
   jg vline_special_mode_loop    /* loop */

   popl %edx                     /* clean up stack */
   addl $12, %esp
   popl %eax
   movl %eax, BMP_CLIP(%edx)     /* restore bitmap clipping flag */
   jmp vline_done

   _align_
vline_solid_mode:                /* normal vline drawer */
   movl ARG5, %ebx               /* get color */
   leal (%edi, %edi, 2), %edi    /* xadd on each line */
   movl %ebx, %eax
   shrl $16, %eax
   movl %eax, ARG4

   _align_
vline_loop:
   movl %esi, %eax
   WRITE_BANK()                  /* select bank */

   movl ARG5, %ebx
   movw %bx, %es:(%eax, %edi)
   movl ARG4, %ebx
   movb %bl, %es:2(%eax, %edi)

   incl %esi
   decl %ecx
   jg vline_loop                 /* loop */

vline_done:
   popw %es

   UNWRITE_BANK()

   popl %edi
   popl %esi
   popl %ebx
   movl %ebp, %esp
   popl %ebp
   ret                           /* end of _linear_vline24() */




#endif      /* ifdef ALLEGRO_COLOR24 */

