;registers used as follows:
;	a2	-	address of old viewport struct
;	a3	-	address of new viewport struct
;	a4	-	address of our first bitplane
;	a5	-	address of our second bitplane

;	d2	-	number of screen flips before exit
;	d3	-	width of viewport
;	d4	-	height of viewport
;	d5	-	depth of viewport
;	d6	-	bitplane size in bytes (w*h/8)
;	d7	-	count of #bits that have been rotated
;*************************************************************
	include "flip.h"
	include "flip.macros"

	xdef	ud
;*************************************************************************
	xref	execbase
	xref	dosbase
	xref	gfxbase
	xref	intbase
	xref	totalpause
	amiref	Delay
	amiref	AllocMem
	amiref	FreeMem
	amiref	InitView
	amiref	InitVPort
	amiref	InitBitMap
	amiref	AllocRaster
	amiref	MakeVPort
	amiref	MrgCop
	amiref	BltClear
	amiref	LoadView
	amiref	FreeRaster
	amiref	FreeVPortCopLists
	amiref	FreeCprList
	amiref	DisplayAlert
	amiref	Forbid
	amiref	Permit
;*************************************************************************
;		Macros Start Here
;*************************************************************************
freeras	macro		;*plane
	zero	d0
	zero	d1
	move.l	\1,a0		;free the mem for each bitplane
	move.w	d3,d0		;feed function the width and height
	move.w	d4,d1		;and pointer to the plane mem
	gfxlib	FreeRaster
	endm

allrast	macro		;*plane
	zero	d0
	zero	d1
	move.w	d3,d0
	move.w	d4,d1
	gfxlib	AllocRaster	;allocate the mem for each bitplane
	move.l	d0,\1		;feed function the width,height
	move.l	d0,(a3)+	;and pointer to plane mem
	tst.l	d0
	beq	cleanupx	;branch to DisplayAlert if false
	endm

flip	macro		;*fromplane,*toplane
	pushreg	d6		;d6 contains the rassize, i.e.,
	zero	d0		;the # of bytes per bitplane
	zero	d1
	zero	d7
	move.b	#7,d7		;the rotate bit counter, we'll be working
	move.l	\1,a0		;with bytes, therefore, 8 bits,count 0 to 7
	adda	d6,a0		;start at last byte of old bitplane
	move.l	\2,a1
1$
	tst.l	d6		;see if we've done all the bytes
	dbeq	d6,2$		;if we have, then exit the macro
	bra	4$
2$
	move.b	-(a0),d0	;decrement, then move the old bitplane
	pushreg	d7		;byte to d0, save the bit count for later
3$
	roxr.b	#1,d0		;rotate the bits at d0 into d1
	roxl.b	#1,d1
	tst.b	d7		;after each bit rotation check the count
	dbeq	d7,3$		;to see if we're done with this byte
	move.b	d1,(a1)+	;if we are, then move the flipped byte
	pullreg	d7		;to the new bitplane and get back the count
	bra	1$		;then go back to get next byte
4$
	pullreg	d6		;get back the raster size
	endm

;************************************************************************
;		Macros End Here
;*************************************************************************
ud
	pushreg	d2-d6/a2-a5
	move.b	#0,check	;test later to see if view ever opened
				;at start we'll assume it did not
	move.l	gfxbase,a0
	move.l	gb_ActiView(a0),oldview		;get the active view

	move.l	intbase,a0
	move.l	ib_ActiveScreen(a0),a1		;get the active screen

	adda	#sc_ViewPort,a1			;move to screen's viewport
	move.l	a1,a2			;remember vport struct is inside screen

	zero	d5
	move.l	vp_RasInfo(a2),a1	;find old rasinfo inside vport
	move.l	ri_BitMap(a1),a0	;find old bitmap inside rasinfo
	move.b	bm_Depth(a0),d5		;find and save depth inside bitmap
	
	pushreg	d5
	tst.b	d5
	beq	gotoldplanes
	adda	#bm_Planes,a0		;move to first bitplane addr in bmap
	move.l	(a0)+,d0
	move.l	d0,oldplane1		;save old bitplane addr
	subq.b	#1,d5
	beq	gotoldplanes		;do same for each bitplane
	move.l	(a0)+,d0		;checking depth to see when done
	move.l	d0,oldplane2
	subq.b	#1,d5
	beq	gotoldplanes
	move.l	(a0)+,d0
	move.l	d0,oldplane3
	subq.b	#1,d5
	beq	gotoldplanes
	move.l	(a0)+,d0
	move.l	d0,oldplane4
	subq.b	#1,d5
	beq	gotoldplanes
	move.l	(a0)+,d0
	move.l	d0,oldplane5
	subq.b	#1,d5
	beq	gotoldplanes
	move.l	(a0),d0
	move.l	d0,oldplane6

gotoldplanes
	pullreg	d5

	zero	d3
	zero	d4
	move.w	vp_DWidth(a2),d3	;get vport width and height and save
	move.w	vp_DHeight(a2),d4
	zero	d6
	pushreg	d4
	mulu	d3,d4		;determine raster size from width and height
	lsr.l	#3,d4		;raster size = width*height/8
	move.l	d4,d6		;save raster size
	pullreg	d4

	getmem	#v_SIZEOF,#MEMF_CLEAR!MEMF_PUBLIC,v
	beq	cleanupx	;allocate mem for our view struct

	getmem	#vp_SIZEOF,#MEMF_CLEAR!MEMF_PUBLIC,a3
	tst.l	d0
	beq	cleanupx	;allocate mem for our viewport struct

	move.l	v,a1
	gfxlib	InitView	;initialize our view struct

	move.l	a3,a0
	gfxlib	InitVPort	;initialize our viewport struct

	move.l	v,a0
	move.l	a3,v_ViewPort(a0)	;link our viewport to our view
	move.l	oldview,a1
	move.l	v_Modes(a1),v_Modes(a0)	;set our modes to old modes

	getmem	#bm_SIZEOF,#MEMF_CLEAR!MEMF_PUBLIC,b
	beq	cleanupx		;allocate mem for our bitmap struct

	move.l	b,a0
	zero	d0
	move.b	d5,d0
	zero	d1
	move.w	d3,d1
	pushreg	d2
	zero	d2
	move.w	d4,d2
	gfxlib	InitBitMap	;initialize our bitmap struct
	pullreg	d2

	getmem	#ri_SIZEOF,#MEMF_CLEAR!MEMF_PUBLIC,ri
	beq	cleanupx	;alloc mem for our rasinfo struct

	move.l	ri,a0
	move.l	b,a1
	move.l	a1,ri_BitMap(a0)	;link our bitmap to our rasinfo
	move.l	#0,d0
	move.w	d0,ri_RxOffset(a0)	;set our rasinfo x,y offsets to zero
	move.w	d0,ri_RyOffset(a0)
	move.l	d0,ri_Next(a0)		;set pointer to next rasinfo to NULL

	move.w	d3,vp_DWidth(a3)	;set our vport width and height
	move.w	d4,vp_DHeight(a3)	;to the old values
	move.l	ri,vp_RasInfo(a3)	;link our rasinfo to our vport

	move.l	vp_ColorMap(a2),vp_ColorMap(a3)	;use the old vport colormap
	move.w	vp_Modes(a2),vp_Modes(a3)	;and modes

	pushreg	d5/a3
	move.l	b,a3
	adda	#bm_Planes,a3	;move to the first bitplane pointer
				;in our bitmap
	allrast	a4		;allocate space for each bitplane
	subi.b	#1,d5		;checking depth to see if finished
	beq	gotrasters	;save the address of each plane in
	allrast	a5		;register or pointer
	subi.b	#1,d5
	beq	gotrasters
	allrast	plane3
	subi.b	#1,d5
	beq	gotrasters
	allrast	plane4
	subi.b	#1,d5
	beq	gotrasters
	allrast	plane5
	subi.b	#1,d5
	beq	gotrasters
	allrast	plane6

gotrasters
	pullreg	d5/a3

	move.l	v,a0
	move.l	a3,a1
	gfxlib	MakeVPort	;got all the info so now make the vport

	move.l	v,a1
	gfxlib	MrgCop		;let copper do its thing
	move.b	#1,check	;flag to let us know if copper inst. generated

	move.l	a4,a1
	move.l	d6,d0
	zero	d1
	gfxlib	BltClear	;clear each of the bitplanes to zeros
				;after checking to see if we got them
	move.l	a5,d0
	beq	bltcleared
	move.l	a5,a1
	move.l	d6,d0
	zero	d1
	gfxlib	BltClear

	tst.l	plane3
	beq	bltcleared
	move.l	plane3,a1
	move.l	d6,d0
	zero	d1
	gfxlib	BltClear

	tst.l	plane4
	beq	bltcleared
	move.l	plane4,a1
	move.l	d6,d0
	zero	d1
	gfxlib	BltClear

	tst.l	plane5
	beq	bltcleared
	move.l	plane5,a1
	move.l	d6,d0
	zero	d1
	gfxlib	BltClear

	tst.l	plane6
	beq	bltcleared
	move.l	plane6,a1
	move.l	d6,d0
	zero	d1
	gfxlib	BltClear

bltcleared
	pushreg	d5		;now flip each plane upside down
fone	flip	oldplane1,a4	;after checking depth to see if done
	subi.b	#1,d5
	beq	readytopause
ftwo	flip	oldplane2,a5
	subi.b	#1,d5
	beq	readytopause
fthree	flip	oldplane3,plane3
	subi.b	#1,d5
	beq	readytopause
ffour	flip	oldplane4,plane4
	subi.b	#1,d5
	beq	readytopause
ffive	flip	oldplane5,plane5
	subi.b	#1,d5
	beq	readytopause
fsix	flip	oldplane6,plane6	

readytopause
	pullreg	d5
	execlib	Forbid		;not sure if this is necessary?
	move.l	v,a1
	gfxlib	LoadView	;now that we're flipped we can show the view

	pause	totalpause

	move.l	oldview,a1	;after pause, bring back old view
	gfxlib	LoadView
	execlib	Permit
cleanupy
	move.l	a4,d0		;free each of the bitplanes
	beq	freedrast
	freeras	a4
	move.l	a5,d0
	beq	freedrast
	freeras	a5
	tst.l	plane3
	beq	freedrast
	freeras	plane3
	tst.l	plane4
	beq	freedrast
	freeras	plane4
	tst.l	plane5
	beq	freedrast
	freeras	plane5
	tst.l	plane6
	beq	freedrast
	freeras	plane6

freedrast
	zero	d0
	move.b	check,d0	;free the viewport and view mem, only if we
	beq	3$		;showed the view, not sure why,but get free
	move.l	a3,a0
	move.l	a0,d0
	beq	7$
	gfxlib	FreeVPortCopLists	;free system allocated memory

1$	move.l	v,a1
	move.l	a1,d0
	beq	7$
	move.l	v_LOFCprList(a1),a0	;free more sys allocated mem
	move.l	a0,d0
	beq	7$
	gfxlib	FreeCprList

2$	move.l	v,a1
	move.l	a1,d0
	beq	7$
	zero	d1
	move.w	v_Modes(a1),d1
	andi.w	#4,d1			;check to see view was interlaced
	beq	3$			;if it wasn't skip this
	move.l	v_SHFCprList(a1),a0	;if it was then must free this
	move.l	a0,d0			;extra copperlist memory
	beq	3$
	gfxlib	FreeCprList
	
3$	move.l	ri,d1
	beq	4$
	byemem	#ri_SIZEOF,ri

4$	move.l	b,d1
	beq	5$
	byemem	#bm_SIZEOF,b		;free the bitmap mem

5$	zero	d0
	move.b	check,d0	;free the viewport and view mem, only if we
	beq	7$		;showed the view, not sure why,but get free
				;twice guru if we try to do this after
	move.l	a3,d1		;DisplayAlert is called.  Memory is still
	beq	7$		;lost however. Strange. I can't figure it
	byemem	#vp_SIZEOF,a3	;out. Only 64 bytes anyway, so who cares.
				;I do actually, bugs the hell out of me.
				;Is it colormap/table related?
6$	move.l	v,d1
	beq	7$
	byemem	#v_SIZEOF,v

7$	pullreg	d2-d6/a2-a5
	rts
;*************************************************************************
cleanupx
	move.l	#RECOVERY_ALERT,d0
	lea	almess,a0
	move.l	#50,d1			;only shown if any memory allocation
	intlib	DisplayAlert		;returns false
	bra	cleanupy

;************************************************************************
				DATA
;***********************************************************************
		evenpc
oldview		dc.l	0
oldplane1	dc.l	0
oldplane2	dc.l	0
oldplane3	dc.l	0
oldplane4	dc.l	0
oldplane5	dc.l	0
oldplane6	dc.l	0
v		dc.l	0
b		dc.l	0
ri		dc.l	0
plane3		dc.l	0
plane4		dc.l	0
plane5		dc.l	0
plane6		dc.l	0
check		dc.b	0
		evenpc
almess
		dc.b	$00,$ba,$14,'Could Not Allocate Enough Memory',0,1
		dc.b	$00,$b6,$22,'Press Either Mouse Button to Exit',0,0
		evenpc
	end
