;-----------------------------------------------------------------------------
; Tetris © Copyright 1990 Software Alchemy All Rights Reserved, V0.1 28-Dec-89
; Code generated by Transform © 1990 Software Alchemy All Rights Reserved
;-----------------------------------------------------------------------------
	include	'tetris.i'

;	Tetris renders to 5 bitplanes with one blit, the screen format is
;	"interleaved" to support this.  Andreas Hommel was the first person
;	to think of this idea (CMON, GAUNTLET).  S0ren Gronbech told me of
;	of rumors to that effect (he did SWORD OF SODAN, DATASTORM ect).
;	Interleaved bitplanes are a very common concept however, the hacker
;	intro to BackLash uses them for example, and thats 1987 technology.

;
;	Generate Mulu Table for rest of blits to rely upon
;
MakeMulu110
	lea	Mulu110(pc),a0
	moveq	#0,d0
1$	move.w	d0,(a0)+
	add.w	#110*8,d0
	cmp.w	#110*8*30,d0
	bne.s	1$

	lea	Mulu44(pc),a0
	moveq	#0,d0
2$	move.w	d0,(a0)+
	add.w	#44,d0
	cmp.w	#44*30,d0
	bne.s	2$
	rts

Mulu110			dcb.w	30,0
Mulu44			dcb.w	30,0

;
;	Draw a tetris tile to screen, with damage repair and teats.
;
DrawBlock

	moveq	#0,d1
	move.w	d1,d0
	move.b	BlockPos(a4),d1			; D1 = Byte X
	move.b	BlockPos+2(a4),d0		 ; D0 = Byte Y (0-30)

DrawBlockAt

	add.w	d0,d0				; Y * 2

	lea	TetrisByteMap(pc),a2
	add.w	Mulu44(pc,d0.w),a2
	add.w	d1,a2				; a2 = Current ByteMap Pos

	move.l	GameVideo2(pc),a0		; A0 = Half-Screen
	lea	Mulu110(pc),a1
	add.w	(a1,d0.w),a0			; + Y * 110*8  (add 1/2)

	add.l	a0,a0				; A0 = Raw Screen sans X
	add.w	d1,a0				; Add X Pos
	ror.w	#1,d1				; D1 = Pixel Shift

;
; Repair damaged backdrop if any prior to next render (if any)
;
	lea	BlitWorkSpace(a4),a1		; A1 = Source/Dest of Damage
	move.l	BlitRepairAddress(a4),d0	; D0 = Blit Repair Info
	beq.s	BlitSave			; (No Damage)
BlitRepair
	btst	#14-8,$02(a6)			; 680x0 stuff, force read ACK
1$	btst	#14-8,$02(a6)			; Wait for Blitter
	bne.s	1$
	move.l	d0,$54(a6)			; D0 = Old Place to repair
	move.l	a1,$48(a6)			; A1 = Source, Damage Buffer
	move.w	#44-6,$66(a6)			; Dest Mod
	move.w	#0,$60(a6)			; Source Mod
	move.l	#$03aa0000,$40(a6)		; D = C
	move.w	#64*5*34+3,$58(a6)		; Do 3 words by 34 lines

;
; Copy a hunk of object size for damage repair, d0 = source or dest
;
BlitSave
	move.l	a0,BlitRepairAddress(a4)	; Will Undo to here next pass
	btst	#14-8,$02(a6)			; 680x0 stuff, force read ACK
1$	btst	#14-8,$02(a6)			; Wait for Blitter
	bne.s	1$
	move.l	a0,$48(a6)			; A0 = Source (C) Damage Save
	move.l	a1,$54(a6)			; DEST
	move.w	#44-6,$60(a6)			; SRC Modulo (DMA C)
	move.w	#0,$66(a6)			; Dest Modulo
	move.l	#$03aa0000,$40(a6)		; Minterm is D = C
	move.w	#64*5*34+3,$58(a6)		; Do 3 words by 34 lines

;
; Get a Tetris Piece detailed TileMap in (a2)
;
GetPiece
	move.w	BlockID(a4),d2			; D2 = Pointer to Tile # * 2
	lsl.w	#3,d2				; (2>>3) = 16
	lea	TetrisDetails(pc),a1
	lea	(a1,d2.w),a1			; A1 = Detailed TileMap

	add.w	#2*220,a0			; Room for Teat

DrawLoop
;
; Loop thru all pieces of TileMap and render them...
;
	moveq	#4-1,d7				; D7 = Vertical
1$	moveq	#4-1,d6				; D6 = Horizontal
2$
	moveq	#0,d0				; (clean)
	move.b	(a1)+,d0			; D0 = Data
	beq.s	3$				; Don't draw where nothing
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	bsr	ContinueDraw			; Draw next piece...
;
; Render a teat here only if non-incident with tile or backdrop
;

	tst.b	-44(a2)				; Allowable on bytemap?
	bne.s	3$
	tst.b	-4-1(a1)			; Allowable on tile?
	bne.s	3$
	moveq	#0,d0
	move.b	-1(a1),d0
	or.b	#7,d0				; Get to teat data
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	sub.w	#8*220,a0			; (backup for teat)
	bsr	ContinueDraw			; Add the teat
	add.w	#8*220,a0
3$

;
; Get to Next Horizontal raw-write and bytemap position
;
	add.w	#$8000,d1			; Pixel Shift >>
	add.w	#1,a0				; Next Byte Also >>
	lea	1(a2),a2			; Next HLine of ByteMap
	dbf	d6,2$				; End horizontal loop
;
; Get to next Vertical raw-write and bytemap position
;
	add.w	#8*220-4,a0			; Next VLine of RAW
	lea	44-4(a2),a2			; Next VLine of ByteMap
	dbf	d7,1$				; End vertical loop
	rts



;
;	Draw one line of tetris bytemap to screen with teats
;	Supply Y Line #
;
DrawLine
						; D0.w = Y on ByteMap
	move.w	PlayerArea2+2(a4),d1		; D1.w = X on ByteMap
	lea	TetrisByteMap(pc),a2
	add.w	PlayerArea(a4),a2		; + Active Zone
	lea	Mulu44(pc),a1
	add.w	d0,d0				; Y * 2 (index)
	add.w	(a1,d0.w),a2			; + Y
						; a2 = Current ByteMap Pos

	add.w	#1,a2				; Don't draw left wall
	add.w	#1,d1				; Don't draw left wall
	add.w	PlayerArea2(a4),d0		; Add Raw Vertical Offset
	add.w	PlayerArea2(a4),d0

	move.l	GameVideo2(pc),a0		; A0 = Half-Screen
	lea	Mulu110(pc),a1
	add.w	(a1,d0.w),a0			; + Y * 110*8  (add 1/2)
	add.l	a0,a0				; A0 = Raw Screen sans X
	add.w	d1,a0				; Add X Pos
	ror.w	#1,d1				; D1 = Pixel Shift

	add.w	#2*220,a0			; Room for Teat

	moveq	#RECT_X-1,d2			; D2 = Horizontal
2$	moveq	#0,d0				; (clean)
	move.b	(a2)+,d0			; D0 = Data
						; (Do Draw where nothing)
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	bsr	ContinueDraw			; Draw next piece...

	tst.b	-1(a2)				; Anything here?
	beq.s	3$
	tst.b	-44-1(a2)			; Allowable on bytemap?
	bne.s	3$
	moveq	#0,d0
	move.b	-1(a2),d0
	or.b	#7,d0				; Get to teat data
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	sub.w	#8*220,a0			; (backup for teat)
	bsr	ContinueDraw			; Add the teat
	add.w	#8*220,a0
3$	add.w	#$8000,d1			; In pixel blitter shift
	add.w	#1,a0
	dbf	d2,2$				; End horizontal loop
	rts






;
;	Draw one element, part of a tile, to screen
;	Supply X,Y Byte Positions in D1,D0
;	Object to draw is in D2.w
;
DrawOne
						; D0.w = Y on ByteMap
						; D1.w = X on ByteMap
	lea	TetrisByteMap(pc),a2
	add.w	d1,a2				; + X
	lea	Mulu44(pc),a1
	add.w	d0,d0				; Y * 2 (index)
	add.w	(a1,d0.w),a2			; + Y

						; a2 = Current ByteMap Pos
	and.w	#$00ff,d2
	move.b	d2,(a2)				; Store Element

	move.l	GameVideo2(pc),a0		; A0 = Half-Screen
	lea	Mulu110(pc),a1
	add.w	(a1,d0.w),a0			; + Y * 110*8  (add 1/2)
	add.l	a0,a0				; A0 = Raw Screen sans X
	add.w	d1,a0				; Add X Pos
	ror.w	#1,d1				; D1 = Pixel Shift

	add.w	#2*220,a0			; Room for Teat

	move.w	d2,d0
	ext.l	d0				; (clean)
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	bsr	ContinueDraw			; Draw next piece...

	tst.b	-44(a2)				; Put Teat above?
	bne.s	2$
	move.w	d2,d0
	beq.s	2$
	sub.w	#8*220,a0			; (backup for teat if !0)
	or.b	#7,d0				; Get to teat data
	ext.l	d0				; (clean)
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	bra	ContinueDraw			; Add the teat
2$	rts

; Note that the Blitter always uses Post-Increment and Post-Decrement
; irregardless of if you are using it backwards or forwards.  Luckily
; however it does shift in reverse, and that is why I am using a backwards
; blit in this example:

DrawScroller
	move.l	GameVideo(pc),a0
	add.l	#232*44*5-2,a0
	btst	#14-8,$02(a6)
1$	btst	#14-8,$02(a6)
	bne.s	1$
	move.l	#$ffffffff,$44(a6)
	move.l	a0,$50(a6)
	move.l	a0,$54(a6)
	move.l	#0,$64(a6)
	move.l	#$89f00002,$40(a6)		; Backwards mode on
	move.w	#64*5*80+22,$58(a6)
	rts

DrawScrollBit
	move.l	GameVideo2(pc),a0		; A0 = Half-Screen
	lea	Mulu110(pc),a1
	add.w	d0,d0
	add.w	(a1,d0.w),a0			; + Y * 110*8  (add 1/2)
	add.l	a0,a0				; A0 = Raw Screen sans X
	add.w	d1,a0				; Add X Pos
	ror.w	#1,d1				; D1 = Pixel Shift
	add.w	#2*220,a0			; Room for Teat
	move.w	d2,d0
	ext.l	d0				; (clean)
	mulu	#2*5*8,d0
	add.l	PiecesMem(pc),d0
	bra	ContinueDraw

DrawScrollClear
	move.l	GameVideo(pc),a0
	add.l	#232*44*5-2,a0
	btst	#14-8,$02(a6)			; Erase Right Hand Side
2$	btst	#14-8,$02(a6)
	bne.s	2$
	move.l	a0,$54(a6)
	move.w	#44-2,$66(a6)
	move.l	#$01000002,$40(a6)		; (backwards also)
	move.w	#64*5*80+1,$58(a6)
	rts


;
; Draw a block anywhere (Renders to all 5 planes with one blit)
;
ContinueDraw
						; A0 = Raw Dest
						; D0 = Raw Source
						; D1 = 16 bit Pixel Shift

	btst	#14-8,$02(a6)			; 680x0 stuff, force read ACK
1$	btst	#14-8,$02(a6)			; Wait for Blitter
	bne.s	1$
	move.l	a0,$54(a6)			; DEST
	move.l	a0,$48(a6)			; DEST READ (DMA CHANNEL C)
	move.l	d0,$4c(a6)			; source grafix
	and.w	#$f000,d1			; (clean)
	move.w	d1,$42(a6)			; SOURCE Shift (DMA B)
	or.w	#$07ca,d1			; Minterm = Cookie, A is OFF
	move.w	d1,$40(a6)			; MASK Shifts also (DMA A)

				; (these can be moved for optimization)
	move.l	#$ffff0000,$44(a6)		; A MASK (Occurs before A*B)
	move.w	#$ff00,$74(a6)			; Source A (acts as mask on B)
	move.w	#-2,$64(a6)			; Src Modulo undoes over-blit
	move.w	#-2,$62(a6)
	move.w	#44-2-2,$60(a6)			; Dest Mod gets next bitplane
	move.w	#44-2-2,$66(a6)

	move.w	#64*5*8+2,$58(a6)		; Trigger 5 PLANE BLIT.
	rts




Erase
	move.l	GameVideo2(pc),a0		; A0 = Half-Screen
	lea	Mulu110(pc),a1
	add.w	d0,d0				; Y * 2
	add.w	(a1,d0.w),a0			; + Y * 110*8  (add 1/2)

	add.l	a0,a0				; A0 = Raw Screen sans X
	add.w	d1,a0				; Add X Pos

	btst	#14-8,$02(a6)
1$	btst	#14-8,$02(a6)
	bne.s	1$
	move.l	a0,$54(a6)
	move.w	#44-6,$66(a6)
	move.l	#$01000000,$40(a6)
	move.w	#64*5*34+3,$58(a6)
	rts


;
;	Raisers needs a faster redraw, and one that doesn't collide with tile
;	being moved by player.
;
RaisersDraw
	sub.l	#8*220,BlitRepairAddress(a4)	; hack, move up repair also

	move.w	PlayerArea2(a4),d0
	move.w	PlayerArea2+2(a4),d1
	addq.w	#1,d0				; Y++
	move.l	GameVideo2(pc),a0		; A0 = Half-Screen
	lea	Mulu110(pc),a1
	add.w	d0,d0
	add.w	(a1,d0.w),a0			; + Y * 110*8  (add 1/2)
	add.l	a0,a0				; A0 = Raw Screen sans X
	add.w	d1,a0				; Add X Pos
	move.l	a0,a1
	add.w	#16*220,a0
	add.w	#8*220,a1

	btst	#14-8,$02(a6)			; 680x0 stuff, force read ACK
1$	btst	#14-8,$02(a6)			; Wait for Blitter
	bne.s	1$
	move.l	a0,$50(a6)
	move.l	a1,$54(a6)
	move.l	#$ffffffff,$44(a6)		; A MASK (Occurs before A*B)
	move.w	#44-RECT_X-2,$64(a6)
	move.w	#44-RECT_X-2,$66(a6)
	move.l	#$09f00000,$40(a6)
	move.w	#(RECT_Y*8+2-8-8-8)*5*64+RECT_X/2+1,$58(a6)
	rts

;
;	Each tetris object is made up of small pieces.  Tetris
;	has all the pieces in one color internally.  The pieces
;	must be "unpacked" into 8 colors
;
;	There are 8 slots for pieces and
;	there are 4 rotations per piece and 8 colors per rotation
;	8*8*4 makes exactly 256 possible pieces (index 1).
;
;	Pieces are stored in a non-interleaved bitplane format 3 planes deep
;	and there are 8*4 pieces total
;
;	Pieces end up in interleaved bitplane format 5 planes deep
;
;	Pieces are one byte at source
;	Pieces are 8 tall
;

DataSize equ 5*2*8				; Depth*Width*Heigth
BankEls  equ 8*4				; (pieces * rotations)

UnpackPieces
	moveq	#7-1,d2				; D2 = Merge Generated Colors
1$	bsr	UnpackBank			; Do next color...
	dbf	d2,1$
	rts


UnpackBank
	move.l	PiecesMem(pc),a2		; A2 = Base of Dest
	move.l	d2,d3				; Color #?
	mulu	#BankEls*DataSize,d3		; Get Appropriate Color Bank
	add.w	d3,a2				; A2 = Color Bank of pieces

	moveq	#0,d5				; D5 = Counter (and Index)
0$
	lea	PiecesSource(pc),a0
	move.l	d5,d0
	lsl.w	#3,d0				; Graphic #
	add.w	d0,a0
	moveq	#8-1,d4				; D4 = Do One Object
1$	move.b	(a0)+,(a2)+			; Copy Black and White Info
	move.b	#0,(a2)+
	move.b	256-1(a0),(a2)+			; (next plane)
	move.b	#0,(a2)+
	moveq	#0,d0
	move.b	512-1(a0),d0			; D0 = Color Info
	lsl.w	#8,d0				; (force up)
	bsr	UnpackPiece
	lea	6(a2),a2			; Skip to next set of planes
	dbf	d4,1$
	add.w	#1,d5
	cmp.w	#BankEls,d5
	bne.s	0$
	rts


UnpackPiece
	clr.w	(a2)				; pre clean
	clr.w	2(a2)
	clr.w	4(a2)
	cmp.b	#0,d2				; moronic stupidity
	beq.s	zero
	cmp.b	#1,d2
	beq.s	one2
	cmp.b	#2,d2
	beq.s	two
	cmp.b	#3,d2
	beq.s	three
	cmp.b	#4,d2
	beq.s	four
	cmp.b	#5,d2
	beq.s	five
six	move.w	d0,(a2)
five	move.w	d0,2(a2)
three	move.w	d0,4(a2)
	rts
zero	move.w	d0,(a2)
	rts
two	move.w	d0,(a2)
one2	move.w	d0,2(a2)
	rts
four	move.w	d0,(a2)
	move.w	d0,4(a2)
	rts

; end of tetrisblit.s
