;------------------------------------------------------------------------------
;
; 100% systemfriendly PlanarToChunky converter for use with intuition
; screens in applications/games/whatever.
;
; Coded in 1994 by Morten Eriksen.
; Reach me through email: mortene@stud.unit.no.
;
; Use and modify as you like - give credit where appropriate.
;
; Timings on my A1200 with 68EC020 and 32-bit fastram:
;
;  Testcase    Dimensions       This routine             C='s ReadPixelArray8
;
;  1  320x256x5 - 10 frames (0.20 seconds)   41 frames
;  2  320x256x8 - 16 frames (0.32 seconds)   51 frames
;  3  640x512x4 - 34 frames (0.68 seconds)   158 frames
;  4     1024x1024x1 -  35 frames (0.70 seconds)   312 frames
;  5  752x578x8 - 89 frames (1.78 seconds)   312 frames
;
; Please suggest speed-ups in the code if you see any (by changing the
; algorithm, using other instructions with less executiontime, better
; pipelining, etc etc). The 'convert32pixels' is of course the bottleneck,
; as this subroutine accounts for almost all processing done in the
; converter.
;
; Some modifications (stack use instead global data, no 68000 support) in
; 1998 by Stephan Rupprecht
;
; This routine takes a buffer of chunkybytes and fills it with converted
; planar datas from the source BitMap.
;
; As a replacement for C='s ReadPixelArray8 routine, this one is more than
; three times as fast (in worst case) and works directly on bitmaps (instead
; of RastPorts). All cases handled (any width and height > 0, no alignment
; restrictions). Works on OCS/ECS/AGA, all Kickstarts and any MC680x0 CPU.
; The downside is that it does not do clipping and does not work with
; interleaved bitmaps (support for interleaved bitmaps should be piece of
; cake to implement, though).
;
;------------------------------------------------------------------------------
;
; C interface:
;
; extern void __asm PlanarToChunkyAsm(register __a0 struct p2cStruct *);
;
; struct p2cStruct
; {
;  struct BitMap *bmap;
;  UWORD startX, startY, width, height;
;  UBYTE *chunkybuffer;
; } p2c;
;
; p2c.bmap = mybitmap;
; p2c.startX = x0;
; p2c.startY = y0;
; p2c.width = x1 - x0 + 1;
; p2c.height = y1 - y0 + 1;
; p2c.chunkybuffer = chunkybytes;
;
; SyncSBitMap(mywindow->RPort->Layer);
; PlanarToChunkyAsm(&p2c);
;------------------------------------------------------------------------------
;
; Assembler interface:
;
; In:    a0 - p2c struct.
; Out:   Nothing.
;------------------------------------------------------------------------------
 
_PlanarToChunkyAsm:
   movem.l  d2-d7/a2-a6,-(sp)
   
   lea.l -sizeof_buffer(sp),sp   

   move.l   bmap(a0),a1
   move.l   chunkybuffer(a0),a3
   lea   p2c,a4

   moveq #0,d1
   move.w   startX(a0),d0
   andi.w   #%111,d0
   tst.w d0
   beq.s noleftpix
   moveq #8,d1
   sub.w d0,d1
noleftpix
   move.w   d1,leftpix(sp)

   move.w   width(a0),d0
   move.w   d0,Width(sp)
hit   cmp.w d1,d0
   bhs.s notinsidebyte
   move.b   #1,insidebyte(sp)
   moveq #0,d1
   bra.s isinside

notinsidebyte
   clr.b insidebyte(sp)
   move.w   Width(sp),d0
   sub.w leftpix(sp),d0
   move.w   d0,d1
   lsr.w #5,d0
   lsl.w #5,d0
   sub.w d0,d1
isinside
   move.w   d1,rightpix(sp)

   * find initial offset in bytes into bitmap given by (startX, startY)
   moveq #0,d0
   move.w   startX(a0),d0
   lsr.w #3,d0
   moveq #0,d2
   move.w   BytesPerRow(a1),d2
   move.b   Flags(a1),d3
   and.b #BMF_INTERLEAVED,d3
   beq.b 1$
   divu.w   Depth(a1),d2
1$ move.w   startY(a0),d1
   tst.w d1
   beq.s line0
   subq  #1,d1
makeoffset
   add.l d2,d0
   dbra  d1,makeoffset

line0 move.l   d0,a2

   tst.w leftpix(sp)
   beq.s nol1
   subq  #3,a2

nol1  move.w   Width(sp),d0
   sub.w rightpix(sp),d0
   move.w   d2,d1
   lsr.w #3,d0
   sub.w d0,d1
   move.w   d1,Modulo(sp)

   tst.b insidebyte(sp)
   bne.s nol2
   tst.w leftpix(sp)
   beq.s nol2
   subq  #4,Modulo(sp)
nol2

   move.w   height(a0),Height(sp)

   ; a0 - c2p struct, a1 - bmap,
   ; a2 - offset from Planes pointer, a3 - chunkybuffer
   ; a4 - bitspread table

   move.l   a1,a6
   add.w #Planes,a6
   moveq #0,d0
   move.b   Depth(a1),d0
   move.w   d0,depth(sp)
   lsl.w #2,d0
   add.l d0,a6
   move.l   a6,lastplaneptr(sp)

convertline
   tst.b insidebyte(sp)
   beq.s notinsidesinglebyte
   bsr.w convert32pixels
   lea   buffer+32(sp),a5
   movem.l  d0-d7,-(a5)
   moveq #32,d0
   sub.w leftpix(sp),d0
   add.l d0,a5
   move.w   Width(sp),d0
   subq  #1,d0
singleinsert
   move.b   (a5)+,(a3)+
   dbra  d0,singleinsert
   bra.w linedone

notinsidesinglebyte
   tst.w leftpix(sp)
   beq.s noleftpixels

   tst.w Width(sp)
   beq.w linedone

   bsr.w convert32pixels
   lea   buffer+32(sp),a5
   movem.l  d0-d7,-(a5)
   moveq #32,d0
   sub.w leftpix(sp),d0
   add.l d0,a5
   move.w   leftpix(sp),d0
   move.w   d0,d1
   subq  #1,d0
leftinsert
   move.b   (a5)+,(a3)+
   dbra  d0,leftinsert
   sub.w d1,Width(sp)
   addq  #4,a2
   
noleftpixels
   cmp.w #32,Width(sp)
   blo.s trailbits

   bsr.w convert32pixels

flushall
   add.w #32,a3
   movem.l  d0-d7,-(a3)
   add.w #32,a3

nolongflush
   sub.w #32,Width(sp)
   addq  #4,a2
   bra.b noleftpixels

trailbits
   tst.w Width(sp)
   beq.s linedone

   bsr.b convert32pixels
   lea   buffer+32(sp),a5
   movem.l  d0-d7,-(a5)
   move.w   rightpix(sp),d0
   subq  #1,d0
rightinsert
   move.b   (a5)+,(a3)+
   dbra  d0,rightinsert

linedone
   move.w   width(a0),Width(sp)
   add.w Modulo(sp),a2
   subq  #1,Height(sp)
   tst.w Height(sp)
   bne.w convertline

   lea.l sizeof_buffer(sp),sp

   movem.l  (sp)+,d2-d7/a2-a6
   rts

;------------------------------------------------------------------------------  

   cnop  0,8

convert32pixels:
   move.l   a3,-(sp)
   move.l   a0,-(sp)
   move.w   depth+12(sp),a3
   move.l   lastplaneptr+12(sp),a6
   
   move.l   -(a6),a5
   add.l a2,a5
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   movem.l  0(a4,d7.w),d0/d1
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   movem.l  0(a4,d7.w),d2/d3
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   movem.l  0(a4,d7.w),d4/d5
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   movem.l  0(a4,d7.w),d6/d7

convert32pixelsloop
   subq.w   #1,a3
   cmp.w #0,a3
   beq.s done

   move.l   -(a6),a5
   add.l a2,a5
   move.w   d7,a0
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   add.l d0,d0
   or.l  0(a4,d7.w),d0
   add.l d1,d1
   or.l  4(a4,d7.w),d1
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   add.l d2,d2
   or.l  0(a4,d7.w),d2
   add.l d3,d3
   or.l  4(a4,d7.w),d3
   clr.w d7
   move.b   (a5)+,d7
   lsl.w #3,d7
   add.l d4,d4
   or.l  0(a4,d7.w),d4
   add.l d5,d5
   or.l  4(a4,d7.w),d5
   move.w   a0,d7
   move.w   d5,a0
   clr.w d5
   move.b   (a5)+,d5
   lsl.w #3,d5
   add.l d6,d6
   or.l  0(a4,d5.w),d6
   add.l d7,d7
   or.l  4(a4,d5.w),d7
   move.w   a0,d5
   bra.s convert32pixelsloop

done  move.l   (sp)+,a0
   move.l   (sp)+,a3
   rts

   cnop  0,8
* bitspread table *
p2c   ds.b  256*8

;------------------------------------------------------------------------------

