; AGA-Delta
; External Video Driver for
; Flaming Plus/4 emulator for the Amiga
;
; version 1.1

	MACHINE	68020

        INCDIR	Include:

	INCLUDE exec/types.i
	INCLUDE	exec/memory.i
	INCLUDE	exec/exec_lib.i
	INCLUDE	utility/tagitem.i
	INCLUDE	intuition/intuition.i
	INCLUDE	intuition/intuition_lib.i
	INCLUDE	intuition/screens.i
	INCLUDE	graphics/graphics_lib.i
	INCLUDE graphics/modeid.i
	INCLUDE	graphics/rastport.i
	INCLUDE	dos/dos.i
	INCLUDE	dos/dos_lib.i
	INCLUDE	libraries/asl.i
	INCLUDE	libraries/asl_lib.i
	INCLUDE	macros.i

;*** Handler structure

 STRUCTURE vxd_handler,0
  LONG intuibase
  LONG graphbase
  LONG dosbase
  LONG aslbase
  LONG myscr
  LONG mywin
  LONG planes
  WORD xsize
  WORD ysize
  LONG chunkysize
  LONG palette
  LONG palette32
  LONG emuscr
  LONG delta
  LONG scrmodereq
  LONG screendim
  WORD bytesperrow
 LABEL	vxd_handler_SIZEOF

 STRUCTURE c2p,4
  LONG C2PChunkyBufferAddress
  LONG C2PDeltaBufferAddress
  LONG C2PPlanarBufferAddress
  LONG C2PChunkyBufferWidth
  LONG C2PChunkyBufferWidthDiv8
  LONG C2PChunkyBufferHeight
  LONG C2PChunkyBufferSize
  LONG C2PBitplaneByteWidth
 LABEL c2p_SIZEOF

JSRLIB	MACRO
	jsr	_LVO\1(a6)
	ENDM

;*** Let's begin

	moveq.l	#0,d0
	rts

	dc.b "FLAMINGOXVD"
	dc.b "1"

	dc.l Name
	dc.l Author
	dc.w 1
	dc.w 1

	dc.l drv_Init
	dc.l drv_Done
	dc.l drv_Configure
	dc.l drv_OpenScreen
	dc.l drv_CloseScreen
	dc.l drv_Refresh

Name:	dc.b	"AGA-Delta External Video Driver",0
Author:	dc.b	"Álmos Rajnai (original C2P by Ferenc Zavacki)",0

	EVEN

;*** Functions

drv_Init:
	movem.l	a0-a1,-(sp)	;Saving infos
	move.l  4.w,a6		;Alloc memory for handler
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	move.l	#vxd_handler_SIZEOF,d0
	JSRLIB	AllocVec
	movem.l	(sp)+,a0-a1	;Recover infos
        tst.l	d0
	beq.b	.1		;No mem
	movea.l	d0,a2
        move.l	(a0),graphbase(a2)	;Saving graphics.library base
        move.l	4(a0),dosbase(a2)	;Saving dos.library base
        move.l	8(a0),intuibase(a2)	;Saving intuition.library base
        move.l	16(a0),aslbase(a2)	;Saving asl.library base
        movem.l	d0,-(sp)

	move.l	dosbase(a2),a6		;Reading config file
	move.l	#configfile,d1		;Config file is pretty simple:
	move.l	#MODE_OLDFILE,d2	;only a screenmode number
	JSRLIB	Open
	tst.l	d0
	beq.b	.2			;Failed open
	move.l	d0,d1
	move.l	(sp),a0
	lea	screendim(a0),a0
	move.l	a0,d2
	moveq.l	#4,d3
	movem.l	d0,-(sp)
	JSRLIB	Read			;Reading the 4 bytes
	cmp.l	#4,d0
	beq.b	.3
	move.l	(sp),a0			;Failed: set 0 instead garbage
	move.l	#0,screendim(a0)

.3	movem.l	(sp)+,d1
	JSRLIB	Close

.2	movem.l	(sp)+,d0
.1	move.l	#err_nomem,d1		;Ignored, if d0 not 0
	rts				;Result in d0 available for now

drv_Done:
	movea.l	a0,a1
	cmpa.l	#0,a1
	beq.b	.1
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate handler
.1
	rts

drv_Configure:			;Configure
				;A simple screenmode requester appears
	movem.l	a0,-(sp)
	move.l	screendim(a0),displayid
	move.l	#ASL_ScreenModeRequest,d0	
	move.l	aslbase(a0),a6
	lea	asltags,a0
	JSRLIB	AllocAslRequest
	move.l	(sp),a0
	move.l	d0,scrmodereq(a0)
	tst.l	d0
	bne.b	config2
	move.l	intuibase(a0),a6
	JSRLIB	DisplayBeep
	lea	4(sp),sp
	rts

config2:
	move.l	d0,a0
	suba.l	a1,a1
	JSRLIB	AslRequest
	tst.l	d0
	beq.b	.1

	move.l	(sp),a1
	move.l	scrmodereq(a1),a0
	move.l	sm_DisplayID(a0),screendim(a1)

	move.l	dosbase(a1),a6		;Writing config file
	move.l	#configfile,d1		;Config file is pretty simple:
	move.l	#MODE_NEWFILE,d2	;only a screenmode number
	JSRLIB	Open
	tst.l	d0
	beq.b	.1			;Failed open
	move.l	d0,d1
	move.l	(sp),a0
	lea	screendim(a0),a0
	move.l	a0,d2
	moveq.l	#4,d3
	movem.l	d0,-(sp)
	JSRLIB	Write			;Writing the 4 bytes

	movem.l	(sp)+,d1		;We don't care too much on
	JSRLIB	Close			;success...

.1	movem.l	(sp)+,a0
	move.l	aslbase(a0),a6
	move.l	scrmodereq(a0),a0
	JSRLIB	FreeAslRequest
	rts

drv_OpenScreen:
	movea.l a0,a5
	move.w	(a1)+,xsize(a5)
	move.w	(a1)+,ysize(a5)
	move.l	(a1)+,palette(a5)
	move.l	screendim(a5),screenmode	;screenmode from init

	moveq.l	#0,d0
	move.l	d0,d1
	move.w	xsize(a5),d0
	move.w	ysize(a5),d1
	mulu.w	d1,d0
	move.l	d0,chunkysize(a5)
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	move.l	4.w,a6
	JSRLIB	AllocVec
	move.l	d0,emuscr(a5)		;allocating emulator screen
	tst.l	d0
	beq.w	.1

	move.l	chunkysize(a5),d0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	move.l	4.w,a6
	JSRLIB	AllocVec
	move.l	d0,delta(a5)		;allocating delta buffer
	tst.l	d0
	beq.w	.1

	move.l	#MEMF_PUBLIC,d1
	move.l	#128*3*4+4+16,d0
	JSRLIB	AllocVec
	move.l	d0,palette32(a5)	;Convert palette to 32 bit per gun
	beq.w	.1
	movea.l	d0,a0
        move.l	palette(a5),a1
	move.w	#128,(a0)+
	move.w	#$0,(a0)+
	move.l	#128*3-1,d2
.2	moveq.l	#0,d0
	move.b	(a1)+,d0
	swap	d0
	asl.l	#8,d0
	move.l	d0,(a0)+
	dbf	d2,.2
	move.l	#0,(a0)+
	move.l	#0,(a0)+
	move.l	#0,(a0)+
	move.l	#0,(a0)+
	move.w	xsize(a5),width+2
	move.w	ysize(a5),height+2
	move.l	palette32(a5),pal

        suba.l	a0,a0			;No newscreen stuct
        lea	scrtags,a1
	movea.l	intuibase(a5),a6
	JSRLIB	OpenScreenTagList
	move.l	d0,myscr(a5)
	beq.w	.1
	move.l	d0,wscr
	move.l	d0,a0
	lea	sc_RastPort(a0),a0
	movea.l	rp_BitMap(a0),a0
	move.l	#BMA_FLAGS,d1
	movea.l	graphbase(a5),a6
	JSRLIB	GetBitMapAttr
	and.l	#BMF_STANDARD|BMF_INTERLEAVED,d0
	cmp.l	#BMF_STANDARD|BMF_INTERLEAVED,d0
	beq.b	.3
	movea.l	intuibase(a5),a6
	move.l	myscr(a5),a0
	JSRLIB	CloseScreen
	moveq.l	#0,d0
	move.l	d0,myscr(a5)
	bra.b	.1

.3	move.w	xsize(a5),wwidth+2
	move.w	ysize(a5),wheight+2
	suba.l	a0,a0
	lea	wintags,a1
	movea.l	intuibase(a5),a6
	JSRLIB	OpenWindowTagList
	move.l	d0,mywin(a5)
	beq.b	.1
	movea.l	d0,a1
	move.l  wd_RPort(a1),a0
	move.l	rp_BitMap(a0),a0
	move.l	bm_Planes(a0),planes(a5)
	move.w	bm_BytesPerRow(a0),d0
	and.l	#$ffff,d0
	moveq.l	#7,d1
	divu.w	d1,d0
	move.w	d0,bytesperrow(a5)
	move.l  wd_UserPort(a1),d0	;IDCMP port
	move.l	emuscr(a5),d2		;chunky buffer

.1	move.l	#err_noscr,d1
	moveq.l	#0,d3			;no chunky modulo
	rts

drv_CloseScreen:
	move.l	a0,a5
	move.l	intuibase(a5),a6
	move.l	mywin(a5),a0
	cmpa.l	#0,a0
	beq.b	.1
	JSRLIB	CloseWindow

.1	move.l	myscr(a5),a0
	cmpa.l	#0,a0
	beq.b	.2
	JSRLIB	CloseScreen

.2	movea.l	palette32(a5),a1
        cmpa.l	#0,a1
	beq.b	.3
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate translated palette

.3	movea.l	emuscr(a5),a1
        cmpa.l	#0,a1
	beq.b	.5
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate chunky buffer

.5	movea.l	delta(a5),a1
        cmpa.l	#0,a1
	beq.b	.4
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate delta buffer

.4	moveq.l	#0,d0
	move.l	d0,emuscr(a5)	;They were already freed
	move.l	d0,delta(a5)
	move.l	d0,palette32(a5)
	move.l	d0,myscr(a5)
	move.l	d0,mywin(a5)

	rts

drv_Refresh:
	suba.l	#c2p_SIZEOF,a7		;Storing all data on stack

	move.l	(emuscr,a0),(C2PChunkyBufferAddress,a7)
	move.l	(delta,a0),(C2PDeltaBufferAddress,a7)
	move.l	(planes,a0),(C2PPlanarBufferAddress,a7)
	move.l	(delta,a0),(emuscr,a0)			;exchange chunky and
	move.l	(C2PChunkyBufferAddress,a7),(delta,a0)	;delta buffer

	moveq.l	#0,d0
	move.w	(xsize,a0),d0
	move.l	d0,(C2PChunkyBufferWidth,a7)
	lsr.l	#3,d0
	move.l	d0,(C2PChunkyBufferWidthDiv8,a7)
	move.w	(ysize,a0),d0
	move.l	d0,(C2PChunkyBufferHeight,a7)
	move.w	(bytesperrow,a0),d0
	move.l	d0,(C2PBitplaneByteWidth,a7)
	move.l	(chunkysize,a0),(C2PChunkyBufferSize,a7)

        move.l  (C2PChunkyBufferAddress,a7),a0
	move.l	(C2PDeltaBufferAddress,a7),a1
        move.l  (C2PChunkyBufferSize,a7),d0
        lea     (a0,d0.L),a3

        move.l  (C2PPlanarBufferAddress,a7),a2

        move.l  (C2PBitplaneByteWidth,a7),D7

.12	move.l	(C2PChunkyBufferWidth,a7),d6
	lsr.l	#5,d6

.11	cmp.l	(a0)+,(a1)+
	bne.b	.1
	cmp.l	(a0)+,(a1)+
	bne.b	.2
	cmp.l	(a0)+,(a1)+
	bne.b	.3
	cmp.l	(a0)+,(a1)+
	bne.b	.4
	cmp.l	(a0)+,(a1)+
	bne.b	.5
	cmp.l	(a0)+,(a1)+
	bne.b	.6
	cmp.l	(a0)+,(a1)+
	bne.b	.7
	cmp.l	(a0)+,(a1)+
	bne.b	.8

.10	addq.l	#4,a2

	subq.l	#1,d6
	bne.b	.11

	suba.l	(C2PChunkyBufferWidthDiv8,a7),a2
	lea	(a2,d7.l*8),a2
	sub.l	d7,a2

	cmp.l	a0,a3
	bne.b	.12


	move.l	C2PDeltaBufferAddress(a7),d0	;giving back chunky buffer
        adda.l	#c2p_SIZEOF,a7			;changed to delta buffer
	
        rts

.1	subq.l	#1*4,a0
	add.l	#7*4,a1
	bra.b	.9

.2	subq.l	#2*4,a0
	add.l	#6*4,a1
	bra.b	.9

.3	sub.l	#3*4,a0
	add.l	#5*4,a1
	bra.b	.9

.4	sub.l	#4*4,a0
	add.l	#4*4,a1
	bra.b	.9

.5	sub.l	#5*4,a0
	add.l	#3*4,a1
	bra.b	.9

.6	sub.l	#6*4,a0
	addq.l	#2*4,a1
	bra.b	.9

.7	sub.l	#7*4,a0
	addq.l	#1*4,a1
	bra.b	.9

.8	sub.l	#8*4,a0
	add.l	#0*4,a1

.9	move.l	#$0F0F0F0F,d5

	move.l	(a0)+,d0
	and.l	d5,d0
	lsl.l	#4,d0
	move.l	(a0)+,d1
	and.l	d5,d1
	or.l	d1,d0

	move.l	(a0)+,d1
	and.l	d5,d1
	lsl.l	#4,d1
	move.l	(a0)+,d2
	and.l	d5,d2
	or.l	d2,d1

	move.l	(a0)+,d2
	and.l	d5,d2
	lsl.l	#4,d2
	move.l	(a0)+,d3
	and.l	d5,d3
	or.l	d3,d2

	move.l	(a0)+,d3
	and.l	d5,d3
	lsl.l	#4,d3
	move.l	(a0)+,d4
	and.l	d5,d4
	or.l	d4,d3

	move.w	d2,d4
	move.w	d0,d2
	swap	d2
	move.w	d2,d0
	move.w	d4,d2

	move.w	d3,d4
	move.w	d1,d3
	swap	d3
	move.w	d3,d1
	move.w	d4,d3

	move.l	#$00FF00FF,d5

	move.l	d1,d4
	lsr.l	#8,d4
	eor.l	d0,d4
	and.l	d5,d4
	eor.l	d4,d0
	lsl.l	#8,d4
	eor.l	d4,d1

	move.l	d3,d4
	lsr.l	#8,d4
	eor.l	d2,d4
	and.l	d5,d4
	eor.l	d4,d2
	lsl.l	#8,d4
	eor.l	d4,d3

	move.l	#$33333333,d5

	move.l	d2,d4
	lsr.l	#2,d4
	eor.l	d0,d4
	and.l	d5,d4
	eor.l	d4,d0
	lsl.l	#2,d4
	eor.l	d4,d2

	move.l	d3,d4
	lsr.l	#2,d4
	eor.l	d1,d4
	and.l	d5,d4
	eor.l	d4,d1
	lsl.l	#2,d4
	eor.l	d4,d3

	move.l	#$55555555,d5

	move.l	d1,d4
	lsr.l	#1,d4
	eor.l	d0,d4
	and.l	d5,d4
	eor.l	d4,d0
	lsl.l	#1,d4
	eor.l	d4,d1

	move.l	d1,(a2,d7.l*2)

	move.l	d3,d4
	lsr.l	#1,d4
	eor.l	d2,d4
	and.l	d5,d4
	eor.l	d4,d2
	lsl.l	#1,d4
	eor.l	d4,d3

	move.l	d0,a4
	move.l	d2,a5
	move.l	d3,a6

	sub.l	#8*4,a0

	move.l	#$F0F0F0F0,d5

	move.l	(a0)+,d0
	and.l	d5,d0
	move.l	(a0)+,d1
	and.l	d5,d1
	lsr.l	#4,d1
	or.l	d1,d0

	move.l	(a0)+,d1
	and.l	d5,d1
	move.l	(a0)+,d2
	and.l	d5,d2
	lsr.l	#4,d2
	or.l	d2,d1

	move.l	(a0)+,d2
	and.l	d5,d2
	move.l	(a0)+,d3
	and.l	d5,d3
	lsr.l	#4,d3
	or.l	d3,d2

	move.l	(a0)+,d3
	and.l	d5,d3
	move.l	(a0)+,d4
	and.l	d5,d4
	lsr.l	#4,d4
	or.l	d4,d3

	move.l	a6,(a2)

	move.w	d2,d4
	move.w	d0,d2
	swap	d2
	move.w	d2,d0
	move.w	d4,d2

	move.w	d3,d4
	move.w	d1,d3
	swap	d3
	move.w	d3,d1
	move.w	d4,d3

	move.l	#$00FF00FF,d5

	move.l	d1,d4
	lsr.l	#8,d4
	eor.l	d0,d4
	and.l	d5,d4
	eor.l	d4,d0
	lsl.l	#8,d4
	eor.l	d4,d1

	move.l	a5,(a2,d7.l)

	move.l	d3,d4
	lsr.l	#8,d4
	eor.l	d2,d4
	and.l	d5,d4
	eor.l	d4,d2
	lsl.l	#8,d4
	eor.l	d4,d3

	move.l	#$33333333,d5

	move.l	d2,d4
	lsr.l	#2,d4
	eor.l	d0,d4
	and.l	d5,d4
	eor.l	d4,d0
	lsl.l	#2,d4
	eor.l	d4,d2

	add.l	d7,a2
	move.l	a4,(a2,d7.l*2)
	sub.l	d7,a2

	move.l	d3,d4
	lsr.l	#2,d4
	eor.l	d1,d4
	and.l	d5,d4
	eor.l	d4,d1
	lsl.l	#2,d4
	eor.l	d4,d3

	move.l	#$55555555,d5

	and.l	d5,d0
	lsl.l	#1,d0
	and.l	d5,d1
	or.l	d0,d1

	lea	(a2,d7.l*4),a2
	move.l	d1,(a2,d7.l*2)

	move.l	d3,d4
	lsr.l	#1,d4
	eor.l	d2,d4
	and.l	d5,d4
	eor.l	d4,d2
	lsl.l	#1,d4
	eor.l	d4,d3

	move.l	d3,(a2)
	move.l	d2,(a2,d7.l)

	lsl.l	#2,d7
	sub.l	d7,a2
	lsr.l	#2,d7

	bra.w	.10

	EVEN

;*** Constants

scrtags:
	dc.l    SA_Width
width:	dc.l	0
	dc.l	SA_Height
height:	dc.l	0
	dc.l	SA_Depth,7
	dc.l	SA_Colors32
pal:	dc.l	0
	dc.l	SA_Title,scrtitle
	dc.l	SA_ShowTitle,FALSE
	dc.l	SA_DisplayID
screenmode:
	dc.l	0
	dc.l	SA_Interleaved,TRUE
	dc.l	SA_Type,CUSTOMSCREEN
	dc.l	SA_AutoScroll,TRUE
	dc.l	SA_Overscan,OSCAN_STANDARD
	dc.l	SA_Quiet,TRUE
	dc.l	TAG_DONE

wintags:
	dc.l    WA_Left,0
	dc.l	WA_Top,0
	dc.l	WA_Width
wwidth:	dc.l	0
	dc.l	WA_Height
wheight:	dc.l    0
	dc.l	WA_IDCMP,IDCMP_RAWKEY
	dc.l    WA_Title,0
	dc.l	WA_Backdrop,TRUE
	dc.l	WA_RMBTrap,TRUE
	dc.l	WA_Borderless,TRUE
	dc.l	WA_NoCareRefresh,TRUE
	dc.l	WA_CustomScreen
wscr:	dc.l    0
	dc.l	WA_SimpleRefresh,TRUE
	dc.l	WA_Activate,TRUE
	dc.l	TAG_DONE

asltags:
	dc.l	ASLSM_TitleText,configwintxt
	dc.l	ASLSM_InitialDisplayID
displayid:
	dc.l	0
	dc.l	TAG_DONE

scrtitle:	dc.b	'Flamingo Plus/4 emulator screen',0

configwintxt:	dc.b	'Choose desired screenmode',0

configfile:	dc.b	'aga-delta.cfg',0

;*** Errors

err_nomem:
	dc.b	'Run out of memory',0
err_noscr:
	dc.b	'Cannot open screen',0
