; ECS-Delta
; External Video Driver for
; Flaming Plus/4 emulator for the Amiga
;
; version 1.0

	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	macros.i

;*** Handler structure

 STRUCTURE vxd_handler,0
  LONG intuibase
  LONG graphbase
  LONG myscr
  LONG mywin
  LONG planes
  WORD xsize
  WORD ysize
  LONG chunkysize
  LONG palette
  LONG emuscr
  LONG delta
  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 0			;nothing to configure
;	dc.l drv_Configure
	dc.l drv_OpenScreen
	dc.l drv_CloseScreen
	dc.l drv_Refresh

Name:	dc.b	"ECS-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
        cmp.l	#0,d0
	beq.b	.1		;No mem
	movea.l	d0,a2
        move.l	(a0),graphbase(a2)	;Saving graphics.library base
        move.l	8(a0),intuibase(a2)	;Saving intuition.library base
.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:		-> Nothing to configure
;	rts

drv_OpenScreen:
	movea.l a0,a5
	move.w	(a1)+,xsize(a5)
	move.w	(a1)+,ysize(a5)

	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.w	xsize(a5),width+2
	move.w	ysize(a5),height+2
        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	#3,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	emuscr(a5),a1
        cmpa.l	#0,a1
	beq.b	.4
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate chunky buffer

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

.3	moveq.l	#0,d0
	move.l	d0,emuscr(a5)	;They were already freed
	move.l	d0,delta(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

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

	bra.w	.10


	SECTION	structs,data

;*** Constants

scrtags:
	dc.l    SA_Width
width:	dc.l	0
	dc.l	SA_Height
height:	dc.l	0
	dc.l	SA_Depth,3
	dc.l	SA_Colors32,palette32
	dc.l	SA_Title,scrtitle
	dc.l	SA_ShowTitle,FALSE
	dc.l	SA_DisplayID,LORES_KEY
	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

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

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

	EVEN

palette32:
	dc.w	8,0

offs	SET	$30
	REPT	8
	dc.l	offs<<24,offs<<24,offs<<24
offs	SET	offs+$1a
	ENDR

