; PPCAGA-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
	INCLUDE	powerpc/powerpc.i

;*** Handler structure

 STRUCTURE vxd_handler,0
  LONG intuibase
  LONG graphbase
  LONG dosbase
  LONG aslbase
  LONG powerpcbase
  LONG myscr
  LONG mywin
  LONG planes
  WORD xsize
  WORD ysize
  LONG chunkysize
  LONG palette
  LONG palette32
  LONG emuscr1
  LONG emuscr2
  LONG delta
  LONG bytesperrow
  LONG wait
  LONG scrmodereq
  LONG screendim
 LABEL	vxd_handler_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	"PPCAGA-Delta External Video Driver",0
Author:	dc.b	"Álmos Rajnai (original C2P by James McCoull & Peter McGavin)",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	drv_Init_nomem	;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	a2,-(sp)
	lea	powerpclibname,a1
	moveq.l	#7,d0
	JSRLIB	OpenLibrary
	movem.l	(sp)+,a2
	move.l	d0,powerpcbase(a2)
	tst.l	d0
	beq.b	drv_Init_nopowerlib
	movem.l	a2,-(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		;Give back handler address
	rts

drv_Init_nomem:
	moveq.l	#0,d0
	move.l	#err_nomem,d1
	rts

drv_Init_nopowerlib:
	move.l	a2,a1
	JSRLIB	FreeVec		;Deallocate handler
	moveq.l	#0,d0
	move.l	#err_nopowerlib,d1
	rts

drv_Done:
	tst.l	a0
	beq.b	.1
	move.l	4.w,a6
	movem.l	a0,-(sp)
	move.l	powerpcbase(a0),a1
	tst.l	a1
	beq.b	.2
	JSRLIB	CloseLibrary
.2	movem.l	(sp)+,a1
	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,emuscr1(a5)		;allocating emulator screen1
	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,emuscr2(a5)		;allocating emulator screen2
	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)
	moveq.l	#0,d0
	move.w	bm_BytesPerRow(a0),d0
	lsr.w	#3,d0
	move.l	d0,bytesperrow(a5)
	move.l  wd_UserPort(a1),d0	;IDCMP port
	move.l	emuscr1(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	mywin(a5),a0
	cmpa.l	#0,a0
	beq.b	.1

; Wait for PPC
	tst.l	wait(a5)
	beq.b	.skip
	clr.l	wait(a5)

	lea     -PP_SIZE(sp),sp
	move.l  sp,a0
	move.l  powerpcbase(a5),a6
	jsr     -36(a6)                 ;WaitForPPC
	lea     PP_SIZE(sp),sp
.skip
	move.l	intuibase(a5),a6
	move.l	mywin(a5),a0
	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	emuscr1(a5),a1
        cmpa.l	#0,a1
	beq.b	.6
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate chunky buffer

.6	movea.l	emuscr2(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,emuscr1(a5)	;They were already freed
	move.l	d0,emuscr2(a5)
	move.l	d0,delta(a5)
	move.l	d0,palette32(a5)
	move.l	d0,myscr(a5)
	move.l	d0,mywin(a5)

	rts

drv_Refresh:
	move.l	a0,a5
	move.l	powerpcbase(a5),a6	;powerpc.library base

; Wait for PPC, workaround, don't do the same!
	tst.l	wait(a5)
	beq.b	.skip
	clr.l	wait(a5)

	lea     -PP_SIZE(sp),sp
	move.l  sp,a0
	jsr     -36(a6)                 ;WaitForPPC
	lea     PP_SIZE(sp),sp
.skip
	move.l	delta(a5),a0	;Delta buffer
	move.l	emuscr1(a5),d0	;Chunky pixels
	move.l	emuscr2(a5),d5	;Exchange chunky buffers
	move.l	d0,emuscr2(a5)
	move.l	d5,emuscr1(a5)
	movem.l	d5,-(sp)	;Saving next chunky buffer address

	move.l	planes(a5),d1	;Plane address
	move.l	bytesperrow(a5),d2
	moveq.l	#0,d3
	move.w	xsize(a5),d3
	move.l	chunkysize(a5),d4

;	RUNPOWERPC c2p_8_ppc ,,PPF_ASYNC	;Let's go for a ride (asynchron)

				;Instead of the macro I should use
				;direct code for PPC process call
				;So this is a workaround, don't do the same!
;--- snip ---
	move.l	#TRUE,wait(a5)
	lea     -PP_SIZE(sp),sp
	move.l  d0,PP_REGS(sp)
	move.l  d1,PP_REGS+1*4(sp)
	move.l  d2,PP_REGS+2*4(sp)	;Was not in the macro!
	move.l  d3,PP_REGS+3*4(sp)	;Was not in the macro!
	move.l  d4,PP_REGS+4*4(sp)	;Was not in the macro!
	move.l  a0,PP_REGS+8*4(sp)
	move.l  sp,a0

        XREF    @_c2p_8_ppc		;c2p routine

        move.l	@_c2p_8_ppc,a1
        move.l  a1,PP_CODE(a0)
	clr.l   PP_OFFSET(a0)
        move.l	#PPF_ASYNC,PP_FLAGS(a0)
	clr.l   PP_STACKPTR(a0)
	clr.l   PP_STACKSIZE(a0)
	jsr     -30(a6)			;RunPPC
	lea     PP_SIZE(sp),sp
;--- snip ---

	movem.l	(sp)+,d0	;giving back chunky buffer
        rts


;*** Constants

scrtags:
	dc.l    SA_Width
width:	dc.l	0
	dc.l	SA_Height
height:	dc.l	0
	dc.l	SA_Depth,8
	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

powerpclibname:	dc.b	"powerpc.library",0

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

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

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

;*** Errors

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

