; Mono
; 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 palette
  LONG palettemono
  LONG emuscr
  LONG cmpbuffer
  LONG scrmodereq
  LONG screendim
  WORD bytesperrow
  WORD skip
 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	"Mono (B&W) External Video Driver",0
Author:	dc.b	"Álmos Rajnai",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	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
	movem.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,d7	
	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.l	d7,d0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	JSRLIB	AllocVec
	move.l	d0,cmpbuffer(a5)	;allocating cmp buffer
	beq.w	.1

	move.l	#MEMF_PUBLIC,d1
	move.l	#8*128,d0
	JSRLIB	AllocVec
	move.l	d0,palettemono(a5)	;Convert palette to 1 bit
	beq.w	.1
	movea.l	d0,a0
	move.l	#128-1,d2
        move.l	palette(a5),a1
	moveq.w	#0,d0
.2	moveq.w	#0,d1
	move.b	(a1)+,d1		;Sum of R,G,B
	move.b	(a1)+,d0
	add.w	d0,d1
	move.b	(a1)+,d0
	add.w	d0,d1
	cmp.w	#255,d1			;Less than a third?
	blt.b	.less
	move.b	#$ff,d3
	bra.b	.cont
.less	move.b	#$0,d3
.cont	move.b	d3,d4
	and.b	#1<<0,d4
	move.b	d4,128*7(a0)
	move.b	d3,d4
	and.b	#1<<1,d4
	move.b	d4,128*6(a0)
	move.b	d3,d4
	and.b	#1<<2,d4
	move.b	d4,128*5(a0)
	move.b	d3,d4
	and.b	#1<<3,d4
	move.b	d4,128*4(a0)
	move.b	d3,d4
	and.b	#1<<4,d4
	move.b	d4,128*3(a0)
	move.b	d3,d4
	and.b	#1<<5,d4
	move.b	d4,128*2(a0)
	move.b	d3,d4
	and.b	#1<<6,d4
	move.b	d4,128*1(a0)
	move.b	d3,d4
	and.b	#1<<7,d4
	move.b	d4,(a0)+
	dbf	d2,.2
	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,d0
	cmp.l	#BMF_STANDARD,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	xsize(a5),d0
	lsr.w	#3,d0
	move.w	d0,d1
	move.w	d1,bytesperrow(a5)
	move.w	bm_BytesPerRow(a0),d1
	sub.w	d0,d1
	move.w	d1,skip(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 modulo for the chunky screen
	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	palettemono(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	.4
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate chunky buffer
.4
	movea.l	cmpbuffer(a5),a1
        cmpa.l	#0,a1
	beq.b	.5
	move.l	4.w,a6
	JSRLIB	FreeVec		;Deallocate delta buffer
.5
	moveq.l	#0,d0
	move.l	d0,emuscr(a5)	;They were already freed
	move.l	d0,cmpbuffer(a5)
	move.l	d0,palettemono(a5)
	move.l	d0,myscr(a5)
	move.l	d0,mywin(a5)

	rts

drv_Refresh:

	move.w	ysize(a0),d0
	subq.w	#1,d0
	movea.l	emuscr(a0),a1
	movem.l	a1,-(sp)		;storing chunky buffer
	movea.l	palettemono(a0),a4
	movea.l	planes(a0),a3
	moveq.l	#0,d3
	move.l	d3,d5
	move.l	d3,d7
	move.l	d3,d4
	move.w	skip(a0),d7
	move.w	bytesperrow(a0),d5
	move.w	xsize(a0),d4
	movea.l	cmpbuffer(a0),a0

.difcyc2
	move.w	d4,d6
	lsr.w	#2,d6
	subq.w	#1,d6
	movea.l	a1,a6
	movea.l	a0,a5
.difcyc	cmp.l	(a6)+,(a5)+
	beq.b	.nodifference

	move.w	d5,d6	
	subq.l	#1,d6
.cyc	moveq.b	#0,d2
	movea.l	a4,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2
	adda.l	#128,a2

	move.b	(a1)+,d3
	move.b	d3,(a0)+
	or.b	(a2,d3.w),d2

	move.b	d2,(a3)+
	dbf	d6,.cyc
	bra.b	.cont

.nodifference
	dbf	d6,.difcyc
	adda.l	d5,a3
	adda.l	d4,a1
	adda.l	d4,a0
.cont	adda.l	d7,a3
	dbf	d0,.difcyc2

	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,1
	dc.l	SA_Colors32,mypalette
	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

mypalette:
	dc.w	2,0
	dc.l	0,0,0,$ff000000,$ff000000,$ff000000,0,0,0,0

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	'mono.cfg',0

;*** Errors

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