****************************************************************
*															  ;
*			Pixelmap flipping and rotation routines		   ;
*______________________________________________________________*
*															  ;
*		Pixelmaps are flipped and rotated with 4-bit Q_Pixels.  ;
*	(For once, I'm glad that there ISN'T a 640x400 one bit-   ;
*	per-pixel mode!!)  640 pixel maps that are an odd number  ;
*	of (640) Q_Pixels wide will lose a column when rotated.	 ;
*	TANSTAAFL.  Shit happens.								 ;
*															  ;
*		It's rather strange, but the SCB for a pixelmap in a  ;
*	picture is ALWAYS the same as the picture's SCB.  This is ;
*	incredibly fortuitous, since we only have to worry about  ;
*	one mode at a time now.								   ;
*															  ;
*		(At least, I've never SEEN them different....)		;
*															  ;
****************************************************************

	LOAD	'Macros.dump'
	INCLUDE 'Pict.equ'
	INCLUDE	'Driver.equ'

	IMPORT	D_BeachBall
	IMPORT	Q_ChangePictSize
	IMPORT	Q_Copy2
	IMPORT	Q_Copy4
	IMPORT	Q_FixRect
	IMPORT	Q_JustRect
	IMPORT	Q_JustRgn
	IMPORT	Q_manglePt
	IMPORT	Q_Nop
	IMPORT	Q_PixelTable
	IMPORT	Q_addbytes
	IMPORT	Q_center
	IMPORT	Q_dstpixsize
	IMPORT	newptr
	IMPORT	oldptr
	IMPORT	Q_picterr
	IMPORT	Q_pixSCB
	IMPORT	Q_pixbounds
	IMPORT	Q_srcpixsize
	IMPORT	thepoint
	IMPORT	what

****************************************************************
*
*   Q_PixOps -- handle picture opcodes Q_PixRect and Q_PixRgn
*
****************************************************************
Q_PixOps	PROC		EXPORT
			;Using	Q_PictData
		EXPORT	Q_PixRgn
		EXPORT	Q_PixRect

Q_Mask		DS.B 2					 ; is there a Q_Mask Q_Region?
toppt		DS.B 4					 ; upper left of old bounds

*--------------------------------------------------------------*
*		  Copy a pixelmap opcode and mangle its data		  ;
*--------------------------------------------------------------*
Q_PixRgn		;		
		inc	  Q_Mask
		bra	  dopixels

Q_PixRect		;		
		stz	  Q_Mask

dopixels	jsl	  Q_Nop					; copy opcode
		lda	  [<oldptr]
		and	  #$80				   ; D_Save mode
		sta	  Q_pixSCB
		jsl	  Q_Copy4				  ; copy SCB and BWvsColor

		spacelong				; get the size of the old pixelmap
		pushword [<oldptr]					  ; old width
		subword  [<oldptr]:#6,[<oldptr]:#2,s	; old height
		_Multiply
		pulllong Q_srcpixsize

		movelong [<oldptr]:#2,toppt	 ; get upper left Q_Point of bounds

		cmpw	 <what,#Q_rotr	 ; am I rotating?
		jlt	  pixflip		 ; must not be
*--------------------------------------------------------------*
*							ROTATE							;
*--------------------------------------------------------------*
		subword  [<oldptr]:#6,toppt,a   ; get height of bounds
		dec	  a					  ; convert Q_Pixels->bytes
		lsr	  a
		inc	  a
		sta	  [<newptr]	   ; this is the width of the rotated map

		movelong #0,[<newptr]:#2				; adjust first pt. to 0
		subword  [<oldptr]:#6,toppt,<thepoint		   ; get the bounds
		subword  [<oldptr]:#8,toppt+2,<thepoint+2	   ; and adjust

		ldx	  <thepoint	   ; flip the Q_Point diagonally
		lda	  <thepoint+2
		sta	  <thepoint
		stx	  <thepoint+2

		movelong <thepoint,Q_pixbounds	; remember the D_New bounds NOW

		lda	  Q_pixSCB		  ; adjust for 640 mode?
		beq	  newboundsok
		lsr	  <thepoint	   ; if so, halve the old width
		asl	  <thepoint+2	 ; and double the D_New width

newboundsok	movelong <thepoint,[<newptr]:#6 ; store D_New (adjusted) bounds

		spacelong				; compute the size of the dest. map
		pushword [<newptr]	   ; D_New width
		pushword [<newptr]:#6	; D_New height
		_Multiply
		pulllong Q_dstpixsize

		addwl	#10,<oldptr	 ; adjust the pointers
		addwl	#10,<newptr

		sublong  Q_dstpixsize,Q_srcpixsize,Q_addbytes
		jsl	  Q_ChangePictSize
		jcc	  rotsrcrect
		sta	  Q_picterr
		brl	  bye

rotsrcrect	pushlong Q_center				 ; Flip around the pixelmap's
		movelong Q_pixbounds,Q_center	   ; Q_center, not the picture's

noshift	subword  [<oldptr],toppt,<thepoint+2	; adjust upper left pt
		subword  [<oldptr]:#2,toppt+2,<thepoint ; and flip diagonally

getsrc1	lda	  <what		   ; Now r-rotation becomes	   HACK
		dec	  a			   ; h-flipping, and l-rotation
		dec	  a			   ; becomes v-flipping
		jtl	  Q_manglePt		;							  KCAH

		lda	  Q_pixSCB		  ; adjust for 640 mode?
		beq	  srcok1
		lsr	  <thepoint
		asl	  <thepoint+2

srcok1	movelong <thepoint,[<newptr]

		subword  [<oldptr]:#4,toppt,<thepoint+2		 ; repeat for
		subword  [<oldptr]:#6,toppt+2,<thepoint		 ; lower right pt

getsrc2	lda	  <what		   ; Now r-rotation becomes	   HACK
		dec	  a			   ; h-flipping, and l-rotation
		dec	  a			   ; becomes v-flipping
		jtl	  Q_manglePt		;							  KCAH

		lda	  Q_pixSCB		  ; adjust for 640 mode?
		beq	  srcok2
		lsr	  <thepoint
		asl	  <thepoint+2

srcok2	movelong <thepoint,[<newptr]:#4

		pulllong Q_center		  ; back to the picture's Q_center

		addwl	#8,<oldptr
		jsl	  Q_FixRect		 ; legalize the D_New source rectangle
		brl	  gotsrcrect
*--------------------------------------------------------------*
*							 FLIP							 ;
*--------------------------------------------------------------*
pixflip	jsl	  Q_Copy2		   ; copy width

		subword  [<oldptr]:#4,toppt,Q_pixbounds		   ; get 'Q_center'
		subword  [<oldptr]:#6,toppt+2,Q_pixbounds+2	   ; of bounds

		movelong #0,[<newptr]		   ; adjust the D_New bounds
		movelong Q_pixbounds,[<newptr]:#4 ; Q_Rect to (0,0)

		addwl	#8,<oldptr	  ; adjust the pointers (duh...)
		addwl	#8,<newptr

		movelong Q_srcpixsize,Q_dstpixsize  ; the D_New map is the same size!

		pushlong Q_center				 ; flip the source Q_Rect around
		movelong Q_pixbounds,Q_center	   ; the Q_center of the bounds Q_Rect

		subword  [<oldptr],toppt,<thepoint		; adjust src Q_Rect
		subword  [<oldptr]:#2,toppt+2,<thepoint+2 ; to match bounds
		jtl	  Q_manglePt,<what
		movelong <thepoint,[<newptr]

		subword  [<oldptr]:#4,toppt,<thepoint
		subword  [<oldptr]:#6,toppt+2,<thepoint+2
		jtl	  Q_manglePt,<what
		movelong <thepoint,[<newptr]:#4

		jsl	  Q_FixRect
		addwl	#8,<oldptr

		pulllong Q_center		  ; back to the picture's coordinates

gotsrcrect	jsl	  Q_JustRect		; copy/mangle the dstrect
		jsl	  Q_Copy2		   ; copy the transfer mode

		lda	  Q_Mask			; is there a Q_Mask Q_Region?
		jeq	  noregion

		jsl	  Q_JustRgn		 ; if so, mangle it!

noregion	pushlong <oldptr				; now for the real work....
		pushlong <newptr
		jtl	  Q_PixelTable,<what	   ; (no errors possible)

		addlong  <oldptr,Q_srcpixsize,<oldptr
		addlong  <newptr,Q_dstpixsize,<newptr

		clc
bye	rtl

		ENDP

****************************************************************
*
*   Q_FlipHMap(srcpix:l,dstpix:l) -- flip a pixelmap horizontally
*_______________________________________________________________
*
*   NOTE:  The destination bitmap is assumed to be allocated.
*		Q_pixbounds should contain the coordinates of the lower
*		right corner of the destination map, and Q_pixSCB should
*		contain the pixel map's SCB byte.  Row sizes and total
*		sizes (bytes) are derived from this Q_Point.  No error
*		checking is performed -- Q_FlipHMap and its siblings
*		simply D_Write over whatever memory you Q_Point them at.
*
****************************************************************
Q_FlipHMap	PROC		EXPORT
			;Using	Q_PictData

		input	srcpix:l,dstpix:l

		local	rowsize:w,slop:w,rcount:w,mode:w
		local	soffset:w,doffset:w,pixel:w,temp:w

		begin

		spaceword
		_GetMasterSCB
		pla
		and	  #$80
		sta	  mode

		lda	  Q_pixbounds+2	 ; get rowsize in bytes
		dec	  a
		lsr	  a
		ldx	  Q_pixSCB		  ; 640 mode?
		beq	  gotwid
		lsr	  a
gotwid	inc	  a
		sta	  rowsize

		lda	  Q_pixbounds+2	 ; is there an extra pixel on the edge?
		ldx	  Q_pixSCB		  ; am i 640 mode?
		beq	  getslop
		dec	  a			   ; if so, then are there two or three
		lsr	  a			   ;  extra Q_Pixels on the edge?
		inc	  a
getslop	and	  #1
		sta	  slop			; (slop = number of ununsed low nybbles)

		stz	  rcount		  ; start at row zero

*--------------------------------------------------------------*
*						   ROW LOOP						   ;
*--------------------------------------------------------------*
rloop	
		jsl		D_BeachBall
		stz	  soffset		 ; start at the left end of source...
		moveword rowsize,doffset ; ...and the right end of dest.

		lda	  slop			; sloppy?
		jne	  slopstart

*--------------------------------------------------------------*
*  Neat point loop: the maps are an even number of Q_Pixels wide ;
*--------------------------------------------------------------*
neatloop	moveword [srcpix]:soffset,a	 ; get the byte

		and	  #$ff			; a = 0 0 X Y	 reverse the nybbles
		asl	  a
		asl	  a
		asl	  a
		asl	  a			   ; a = 0 X Y 0
		sta	  pixel
		xba					  ; a = Y 0 0 B
		ora	  pixel		   ; a = Y X Y X

;			   ldx	  mode
;			   beq	  neat320
;			   jsr	  FlipNyps

neat320	dec	  doffset		 ; adjust the offset
		movebyte a,[dstpix]:doffset	 ; put the byte

		lda	  doffset		 ; done?
		jeq	  rdone

		inc	  soffset		 ; adjust the offset
		brl	  neatloop

*--------------------------------------------------------------*
* Sloppy Q_Point loop: the maps are an odd number of Q_Pixels wide ;
*--------------------------------------------------------------*
slopstart	stz	  pixel		   ; initialize this.

sloploop	moveword [srcpix]:soffset,a	 ; get the byte
		pha							 ; D_Save it
		and	  #$f0				   ; get the high nybble
		ora	  pixel				  ; fill up the byte

;			   ldx	  mode
;			   beq	  slop320
;			   jsr	  FlipNyps

slop320	dec	  doffset
		movebyte a,[dstpix]:doffset	 ; D_Write it out

		lda	  doffset				; fix the offset
		jeq	  endslop				; am I done yet?

		pla							 ; restore the byte from above
		and	  #$f					; get the low nybble
		sta	  pixel				  ; initialize the byte
		inc	  soffset				; fix the offset

		brl	  sloploop			   ; repeat

endslop	plx					  ; clear up the stack
*--------------------------------------------------------------*
rdone	addwl	rowsize,srcpix  ; We're done with one row.
		addwl	rowsize,dstpix  ; D_Update the pointers.

		inc	  rcount		  ; have I reached the last row?
		cmpw	 rcount,Q_pixbounds
		jlt	  rloop		   ; nope.  try again.

		return				   ; If so, I'm done!!

; ;--------------------------------------------------------------*
; ;	 FlipNyps -- reverse the nyp order in each nyble in a	 ;
; ;	 (For those who don't know, a 'nyp' is Q_half a nybble.)	;
; ;--------------------------------------------------------------*
; FlipNyps	   tax
;				and	  #$3333		  ; get the low nyps
;				asl	  a
;				asl	  a			   ; move them up
;				sta	  temp
;				txa
;				and	  #$cccc		  ; get the high nyps
;				lsr	  a
;				lsr	  a			   ; move them down
;				ora	  temp
;				rts
;
		ENDP

****************************************************************
*
*   Q_FlipVMap(srcpix:l,dstpix:l) -- flip a pixelmap vertically
*
****************************************************************
Q_FlipVMap	PROC		EXPORT
			;Using Q_PictData

		input	srcpix:l,dstpix:l

		local	rowsize:w,rcount:w

		begin

		lda	  Q_pixbounds+2	 ; get rowsize in bytes
		dec	  a
		lsr	  a
		ldx	  Q_pixSCB		  ; 640 mode?
		beq	  gotwid
		lsr	  a
gotwid	inc	  a
		sta	  rowsize

		stz	  rcount		  ; start at (source) row zero

		spacelong
		subword  Q_pixbounds,#1,s
		pushword rowsize
		_Multiply
		addlong  s,dstpix,dstpix ; start at the last destination row

rloop	
		jsl		D_BeachBall
		pushlong srcpix		  ; copy a row
		pushlong dstpix
		pushword #0			  ; amount high word
		pushword rowsize		 ; amount low word
		_BlockMove

		addwl	rowsize,srcpix  ; D_Update the pointers
		subwl	rowsize,dstpix

		inc	  rcount
		cmpw	 rcount,Q_pixbounds	   ; done?
		jlt	  rloop

		return

		ENDP

****************************************************************
*
*   Q_RotRMap(srcpix:l,dstpix:l) -- rotate a pixelmap clockwise
*
*   Source is scanned rightwards a column at a time, starting
*		at the top of each column.  Destination is scanned
*		downward a row at a time, starting at the right end
*		of each row.
*
****************************************************************
Q_RotRMap	PROC		EXPORT
			;Using	Q_PictData

		input	srcpix:l,dstpix:l

		local	srowsize:w,drowsize:w
		local	soffset:w,doffset:w,rcount:w,srcrow:l
		local	pixel:w,slop:w,dside:w,sside:w

		begin

		lda	  Q_pixSCB
		beq	  boundsok

		dec	  Q_pixbounds	   ; adjust OLD width of bounds ONLY
		lsr	  Q_pixbounds
		inc	  Q_pixbounds	   ; <for use by Q_RotRMap and Q_RotLMap>

boundsok	lda	  Q_pixbounds	   ; get source rowsize in bytes
		dec	  a
		lsr	  a			   ; (already adjusted for mode)
		inc	  a
		sta	  srowsize

		lda	  Q_pixbounds+2	 ; get destination rowsize in bytes
		dec	  a
		lsr	  a			   ; (already adjusted for mode)
		inc	  a
		sta	  drowsize

		lda	  Q_pixbounds+2	 ; is there an extra pixel on the edge
		and	  #1			  ;  of the destination map?
		sta	  slop

		moveword Q_pixbounds,rcount
		moveword #1,sside
		stz	  soffset		 ; (start at the left of source)

rloop	
		jsl		D_BeachBall
		moveword drowsize,doffset	   ; initialize the offsets
		movelong srcpix,srcrow		  ; (start at the top of source)
		moveword slop,dside			 ; and other goodies
		stz	  pixel

ploop	moveword [srcrow]:soffset,a	 ; get the source byte

		ldx	  sside		   ; which side is the pixel on?
		bne	  shipixel

		and	  #$f			 ; it's low.
		ldx	  dside		   ; should it be?
		beq	  putpixel
		asl	  a
		asl	  a
		asl	  a
		asl	  a
		bra	  gotpixel

shipixel	and	  #$f0			; it's high
		ldx	  dside		   ; should it be?
		bne	  gotpixel
		lsr	  a
		lsr	  a
		lsr	  a
		lsr	  a

gotpixel	ora	  pixel
putpixel	sta	  pixel

		lda	  dside		   ; am I done with this byte?
		beq	  nowrite

		dec	  doffset		 ; move backwards through the dest. row
		movebyte pixel,[dstpix]:doffset
		lda	  doffset		 ; am I done with this row?
		jeq	  rdone

		stz	  dside
		stz	  pixel
		bra	  nextp

nowrite	inc	  dside

nextp	addwl	srowsize,srcrow ; next source row.
		brl	  ploop

rdone	dec	  rcount
		jeq	  bye

		addwl	drowsize,dstpix ; next destination row
		lda	  sside
		eor	  #1
		sta	  sside
		beq	  stayput		 ; if sside = 0, same src byte column

		addwl	#1,soffset	  ; else, use next one
stayput	brl	  rloop

bye	return

		ENDP

****************************************************************
*
*   Q_RotLMap(srcpix:l,dstpix:l) -- rotate a pixelmap anticlockwise
*
*   Source is scanned leftwards a column at a time, starting
*		at the bottom of each column.  Destination is scanned
*		downward a row at a time, starting at the right end
*		of each row.
*
****************************************************************
Q_RotLMap	PROC		EXPORT
			;Using	Q_PictData

		input	srcpix:l,dstpix:l

		local	srowsize:w,drowsize:w,spicsize:l
		local	soffset:w,doffset:w,rcount:w,srcrow:l
		local	pixel:w,slop:w,dside:w,sside:w

		begin

		lda	  Q_pixSCB
		beq	  boundsok

		dec	  Q_pixbounds	   ; adjust OLD width of bounds ONLY
		lsr	  Q_pixbounds
		inc	  Q_pixbounds	   ; <for use by Q_RotRMap and Q_RotLMap>

boundsok	lda	  Q_pixbounds	   ; get source rowsize in bytes
		dec	  a
		lsr	  a			   ; (already adjusted for mode)
		inc	  a
		sta	  srowsize

		lda	  Q_pixbounds+2	 ; get destination rowsize in bytes
		dec	  a
		lsr	  a			   ; (already adjusted for mode)
		inc	  a
		sta	  drowsize

		lda	  Q_pixbounds+2	 ; is there an extra pixel on the edge
		and	  #1			  ;  of the destination map?
		sta	  slop

		moveword Q_pixbounds,rcount

		lda	  Q_pixbounds	   ; how about the source map?
		and	  #1
		sta	  sside

		spacelong				; how big is the whole thing?
		pushword srowsize
		subword  Q_pixbounds+2,#1,s
		_Multiply
		pulllong spicsize

		moveword srowsize,soffset	   ; start at right of source map
		dec	  soffset

rloop	
		jsl		D_BeachBall
		moveword drowsize,doffset	   ; initialize the offsets
		addlong  srcpix,spicsize,srcrow ; (start at bottom of source)
;			   subwl	srowsize,srcrow
		moveword slop,dside			 ; and other goodies
		stz	  pixel

ploop	moveword [srcrow]:soffset,a	 ; get the source byte

		ldx	  sside		   ; which side is the pixel on?
		bne	  shipixel

		and	  #$f			 ; it's low.
		ldx	  dside		   ; should it be?
		beq	  gotpixel
		asl	  a
		asl	  a
		asl	  a
		asl	  a
		bra	  gotpixel

shipixel	and	  #$f0			; it's high
		ldx	  dside		   ; should it be?
		bne	  gotpixel
		lsr	  a
		lsr	  a
		lsr	  a
		lsr	  a

gotpixel	ora	  pixel
putpixel	sta	  pixel

		lda	  dside		   ; am I done with this byte?
		beq	  nowrite

		dec	  doffset		 ; move backwards through the dest. row
		movebyte pixel,[dstpix]:doffset
		lda	  doffset		 ; am I done with this row?
		jeq	  rdone

		stz	  dside
		stz	  pixel
		bra	  nextp

nowrite	inc	  dside

nextp	subwl	srowsize,srcrow ; previous source row.
		brl	  ploop

rdone	dec	  rcount
		jeq	  bye

		addwl	drowsize,dstpix ; next destination row
		lda	  sside
		eor	  #1
		sta	  sside
		bne	  stayput		 ; if sside = 1, same src byte column

		dec	  soffset		 ; else, use previous one
stayput	brl	  rloop

bye	return

		ENDP
		END

