; ECS
; 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 emuscr
  LONG scrmodereq
  LONG screendim
  WORD bytesperrow
 LABEL	vxd_handler_SIZEOF

 STRUCTURE c2p,4
  LONG C2PChunkyBufferAddress
  LONG C2PPlanarBufferAddress
  LONG C2PChunkyBufferWidth
  LONG C2PChunkyBufferHeight
  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	"ECS 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
	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	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	#MEMF_PUBLIC|MEMF_CLEAR,d1
	move.l	4.w,a6
	JSRLIB	AllocVec
	move.l	d0,emuscr(a5)		;allocating emulator screen
	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	.3
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate translated palette

.3	moveq.l	#0,d0
	move.l	d0,emuscr(a5)	;They were already freed
	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	(planes,A0),(C2PPlanarBufferAddress,A7)
	MOVEQ.L	#0,D0
	MOVE.W	(xsize,A0),D0
	MOVE.L	D0,(C2PChunkyBufferWidth,A7)
	MOVE.W	(ysize,A0),D0
	MOVE.L	D0,(C2PChunkyBufferHeight,A7)
	MOVE.W	(bytesperrow,A0),D0
	MOVE.L	D0,(C2PBitplaneByteWidth,A7)


        MOVE.L  (C2PChunkyBufferAddress,A7),A0
        MOVE.L  (C2PChunkyBufferWidth,A7),D0
        MULU.L  (C2PChunkyBufferHeight,A7),D0
        LEA     (A0,D0.L),A2

        MOVE.L  (C2PPlanarBufferAddress,A7),A1

        MOVE.L  (C2PChunkyBufferWidth,A7),D6
        LSR.L   #5,D6

        MOVE.L  (C2PBitplaneByteWidth,A7),D7

        MOVE.L  #$70707070,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.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  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,A3
        MOVE.L  D1,A4
        MOVE.L  D2,A5
        MOVE.L  D3,A6

.1      MOVE.L  #$70707070,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,(A1)+

        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,(-4,A1,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

        MOVE.L  A4,(-4,A1,D7.L*2)

        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  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,A3
        MOVE.L  D1,A4
        MOVE.L  D2,A5
        MOVE.L  D3,A6

        SUBQ.L   #1,D6
        BNE.B   .2

        MOVE.L  (C2PChunkyBufferWidth,A7),D6
        LSR.L   #3,D6
        SUB.L   D6,A1
        LSR.L   #2,D6
        LEA     (A1,D7.L*4),A1
	SUBA.L	D7,A1

.2      CMP.L   A2,A0
        BNE     .1

	MOVE.L	C2PChunkyBufferAddress(A7),D0	;giving back chunky buffer
        ADDA.L	#c2p_SIZEOF,A7
	
        RTS

	EVEN

;*** 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
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

palette32:
	dc.w	8,0

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

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

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

configfile:	dc.b	'ecs.cfg',0

;*** Errors

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

