*******************************************************************************
*
*   Source Control
*   --------------
*   $Header: ReadPixelArray.asm,v 35.0 88/04/22 11:50:46 bart Exp $
*
*   by Bart Whitebook
*
* Copyright (c) 1988 Commodore-Amiga, Inc.
*
* Executables based on this information may be used in software
* for Commodore Amiga computers.  All other rights reserved.
*
* This information is provided "as is"; no warranties are made.
* All use is at your own risk, and no liability or responsibility is assumed.
*
*******************************************************************************


  include 'exec/types.i'        * Required data type definitions
  include 'graphics/gfx.i'      * BitMap structure definition
  include 'exec/nodes.i'
  include 'exec/lists.i'
  include 'exec/interrupts.i'
  include 'exec/ports.i'
  include 'exec/libraries.i'
  include 'graphics/gfxbase.i'
  include 'graphics/clip.i'     * Layer structure definition
  include 'graphics/rastport.i' * RastPort structure definition
  include 'hardware/blit.i'     * Minterm definitions

  xdef _ReadPixelArray  * Define public entry points
  xdef _ReadPixelLine

  PAGE

******* graphics.library/ReadPixelArray **************************************
*
*   NAME
*       ReadPixelArray -- read the pen number value of a rectangular array 
*           of pixels starting at a specified x,y location and continuing 
*           through to another x,y location within a certain RastPort.
*
*   SYNOPSIS
*     count = ReadPixelArray(rp,xstart,ystart,xstop,ystop,array,defval,temprp)
*      d0                    a0 d0:16  d1:16  d2:16 d3:16  a2    d7:8    a1
*
*   LONG    count;
*   struct  RastPort *rp;
*   SHORT   xstart, ystart;
*   SHORT   xstop, ystop;
*   UBYTE   *array;
*   UBYTE   defval;
*   struct  RastPort *temprp;
*
*   FUNCTION
*       For each pixel in a rectangular region, combine the bits from each
*       of the bit-planes used to describe a particular RastPort into the pen
*       number selector which that bit combination normally forms for the
*       system hardware selection of pixel color.
*
*   INPUTS
*       rp -  pointer to a RastPort structure
*       (xstart,ystart) starting point in the RastPort
*       (xstop,ystop) stopping point in the RastPort
*       array - pointer to an array of uwords in which to store the pixel data
*       temprp - temporary rastport (copy of rp with Layer set == NULL,
*                                   temporary memory allocated for temp BitMap
*                                   temprp->BitMap with Rows set == 1,
*                                   and with BytesPerrow set == 
*                                   ((((xstart-xstop+1)+0xf)>>4)<<1),
*                                   and temporary memory allocated for
*                                   temprp->BitMap->Planes[])
*
*   RESULT
*       For each pixel in the array:
*           Pen - (0..255) number at that position is returned
*                 (defval) is returned if cannot read that pixel
*
*   NOTE
*       xstop must be >= xstart
*       ystop must be >= ystart
*
*   BUGS
*
*   SEE ALSO
*       WritePixel  graphics/rastport.h
*
******************************************************************************
    xref    _LVOLockLayerRom
    xref    _LVOWaitBlit
    xref    _LVOUnlockLayerRom
    xref    _LVOClipBlit
    xref    _GfxBase

_ReadPixelArray:
    movem.l d2/d3/d7/a2/a6,-(sp)
    move.l  _GfxBase,a6
    move.l  24(sp),a0           ; rp
    movem.l 28(sp),d0/d1/d2/d3  ; xstart, ystart, xstop, ystop
    movea.l 44(sp),a2           ; array
    move.l  48(sp),d7           ; defval
    movea.l 52(sp),a1           ; temprp
    jsr readpixelarray
    movem.l (sp)+,d2/d3/d7/a2/a6
    rts

readpixelarray:

    movem.l d2/d3/d4/d5/d6/d7/a2/a3/a4,-(sp)

    sub.w   d0,d2       ; width of rectangle to read
    ext.l   d2
    addq.l  #1,d2
    ble.s   array_error ; width non-positive ?
    move.w  d0,d4       ; temp storage for current x
    move.w  d1,d5       ; temp storage for current y

    sub.w   d1,d3       ; height of rectangle to read
    ext.l   d3
    addq.l  #1,d3
    ble.s   array_error ; height non-positive ?

    movea.l a0,a3       ; protect rastport pointer -- does not modify cc
    movea.l a1,a4       ; protect temprp pointer -- does not modify cc

    moveq.l #0,d6       ; clear count of pixels returned

    bra.s   rpxaloop_count

rpxaloop_start:

    movea.l a3,a0       ; rp
    move.l  d4,d0       ; x
    move.l  d5,d1       ; y (current line)
                        ; width in d2 (see above)
                        ; array in a2 (see above)
    movea.l a4,a1       ; temprp 

    jsr readpixelline

    addq.l  #1,d5       ; next line
    adda.l  d2,a2       ; increment base pointer to array by width words
    adda.l  d2,a2
    add.l   d2,d6       ; add one line of pixels to pixel count

rpxaloop_count:

    dbra    d3,rpxaloop_start

rpxaloop_end:

    move.l  d6,d0       ; return pixel count
    movem.l (sp)+,d2/d3/d4/d5/d6/d7/a2/a3/a4
    rts

array_error:

    moveq.l #-1,d0
    movem.l (sp)+,d2/d3/d4/d5/d6/d7/a2/a3/a4
    rts

******* graphics.library/ReadPixelLine ***************************************
*
*   NAME
*       ReadPixelLine -- read the pen number value of a horizontal line 
*           of pixels starting at a specified x,y location and continuing 
*           right for count pixels.
*
*   SYNOPSIS
*       count = ReadPixelLine(rp,xstart,ystart,width,array,defval,temprp)
*       d0                    a0 d0:16  d1:16   d2     a2   d7:8    a1 
*
*   LONG    count;
*   struct  RastPort *rp;
*   SHORT   xstart, ystart;
*   LONG    width;
*   UBYTE   *array;
*   UBYTE   defval;
*   struct  RastPort *temprp;
*
*   FUNCTION
*       For each pixel in a rectangular region, combine the bits from each
*       of the bit-planes used to describe a particular RastPort into the pen
*       number selector which that bit combination normally forms for the
*       system hardware selection of pixel color.
*
*   INPUTS
*       rp -  pointer to a RastPort structure
*       (x,y) a point in the RastPort
*       width - count of horizontal pixels to read
*       array - pointer to an array of uwords in which to store the pixel data
*       temprp - temporary rastport (copy of rp with Layer set == NULL,
*                                    temporary memory allocated for
*                                    temprp->BitMap with Rows set == 1,
*                                    and temporary memory allocated for
*                                    temprp->BitMap->Planes[])
*
*   RESULT
*       For each pixel in the array:
*           Pen - (0..255) number at that position is returned
*                 (defval) is returned if cannot read that pixel
*
*   NOTE
*       width must be non negative
*
*   BUGS
*
*   SEE ALSO
*       WritePixel  graphics/rastport.h
*
******************************************************************************

_ReadPixelLine:
    movem.l d2/d7/a2/a6,-(sp)
    move.l  _GfxBase,a6
    move.l  20(sp),a0       ; rp
    movem.l 24(sp),d0/d1/d2 ; xstart, ystart, width
    movea.l 36(sp),a2       ; array
    move.l  40(sp),d7       ; defval
    movea.l 44(sp),a1       ; temprp
    jsr readpixelline
    movem.l (sp)+,d2/d7/a2/a6
    rts

readpixelline:

    movem.l d2/d3/d4/d5/d6/d7/a2,-(sp)

    move.l  d2,d4           ; copy "width" pixels
    moveq.l #1,d5           ; copy one row of pixels
    move.l  #(ABC+ABNC),d6  ; vanilla copy
    moveq.l #0,d2           ; copy to temprp(0,0)
    moveq.l #0,d3

******************************************************************************

    jsr tmploop_init        ; initialize tmpras to default value

******************************************************************************

    move.l  a1,-(sp)        ; save temprp
    jsr _LVOClipBlit(a6)    ; do it the easy way
    move.l  (sp)+,a1        ; restore temprp
                            ; width now in d5

    movea.l rp_BitMap(a1),a1    ; get BitMap pointer
    move.b  bm_Depth(a1),d2     ; Depth in d2
    lea.l   bm_Planes(a1),a1    ; address of first plane pointer in a1
    moveq.l #0,d0               ; source word offset

rplloop_init:

    moveq.l #$10,d3         ; set counter - 16 bits in a word

    bra.s   rplloop_count

rplloop_start:

    subq.l  #1,d3           ; advance to next bit
    bge.s   same_word       ; not time to move onto next word just yet

    moveq.l #$0f,d3         ; reset counter - account for 'subq.l #1' above
;   addq.l  #4,d0           ; increment source LONGWORD offset
    addq.l  #2,d0           ; increment source WORD offset

same_word:

    move.l  d2,d1           ; number of planes in d1
    moveq.l #0,d5           ; storage to build pixel desription

    lsl.l   #2,d1           ;convert to long index
    bra.s   shift_count

*-----------------------------------------------------------------------------

shift_start:

;   move.l  d1,d6           ; plane number in d6
;   lsl.l   #2,d6           ; build plane pointer offset in d6
;   movea.l 0(a1,d6),a0     ; get plane pointer
    movea.l 0(a1,d1),a0     ; get plane pointer

    roxl.l  0(a0,d0)        ; rol high bit left into extend
    roxl.l  #1,d5           ; rol extend bit left into pixel description

shift_count:

    subq.l  #4,d1           ; decrement long offset
    bge.s   shift_start
;   dbra    d1,shift_start

shift_end:

    move.w  d5,(a2)+        ; store pixel description in destination array

*-----------------------------------------------------------------------------

rplloop_count:

    dbra    d4,rplloop_start    ; loop back if not done entire width

rplloop_end:

    movem.l (sp)+,d2/d3/d4/d5/d6/d7/a2
    rts


******************************************************************************

tmploop_init:

    movem.l d0/d1/d2/d3/d4/d5/d7/a0/a1,-(sp)

    movea.l rp_BitMap(a1),a1        ; get BitMap pointer
    move.b  bm_Depth(a1),d2         ; Depth in d2
    moveq.l #0,d3
    move.w  bm_BytesPerRow(a1),d3   ; numbytes in d3

    lea.l   bm_Planes(a1),a1    ; address of first plane pointer in a1

    move.l  d2,d1               ; number of planes in d1
    subq.l  #1,d2               ; adjust # of planes for low to high count

    bra.s   tmpshift_count

tmpshift_start: ; fill temprp with defval

    moveq.l #0,d0
    roxr.l  #1,d7           ; ror low bit of d7 into extend bit
    roxr.l  #1,d0           ; ror extend bit into high bit of d0
    beq.s   stuff0          ; stuff null

stuff1:

    moveq.l #-1,d0          ; stuff ~null

stuff0:

    move.l  d2,d5           ; build plane number in d5
    sub.l   d1,d5           ; plane number in d5 (low to high) 
    lsl.l   #2,d5           ; build plane pointer offset in d5
    movea.l 0(a1,d5),a0     ; get plane pointer

    move.l  d3,d4               ; init numbytes
    lsr.l   #1,d4               ; convert to numwords

    bra.s   tmploop_count

tmploop_start:

    move.w  d0,(a0)+        ; stuff proper word into this plane of the tmpras

tmploop_count:

    dbra    d4,tmploop_start    ; d4 words

tmploop_end:

tmpshift_count:

    dbra    d1,tmpshift_start

tmpshift_end:

    movem.l (sp)+,d0/d1/d2/d3/d4/d5/d7/a0/a1
    rts
******************************************************************************

    end

