	XDEF _IntuitionBase
	XDEF _GadToolsBase
	XDEF _SysBase

	Section MainCode,Code

	incdir include:
	include "includes:libs/exec"
	include "includes:libs/graphics"
	include "includes:libs/intuition"
	include "includes:libs/dos"
	include "includes:libs/gadtools"

	include "includes:librarymacros"
	include "includes:startend"
	include "includes:VBlankServer"
	include "c4p.s"

	include "include:hardware/dmabits.i"
	include "include:exec/exec.i"
	include "include:dos/dos.i"
	include "include:graphics/gfxbase.i"
	include "include:graphics/gfx.i"
	include "include:intuition/intuition.i"
	include "include:libraries/gadtools.i"

	include "StarPrefs.i"

	Section MainCode,Code

DMACON equ $96

	STRUCTURE Star,0
		WORD Star_X
		WORD Star_Y
		WORD Star_Z
		WORD Star_Delay
		WORD Star_Offset		;Used for undraw after draw
		WORD Star_Bit
		LABEL Star_SIZE

Random macro					;Quick and dirty random numbers
	move.l d7,d6
	ror.l #5,d6
	eor.l d6,d7
	add.l #$1865643,d7
	endm

main:
	move.l $4,_SysBase

	move.l #173267,LastRand		;This really should vary, but hey.
	OpenLib Graphics
	beq exit
	OpenLib Intuition
	beq exit
	OpenLibVer GadTools,37
	beq exit
	OpenLib Dos
	beq exit

	bsr LoadPrefs

	move.l #-1,d0
	ExecLib AllocSignal			;Allocate the signal used to tell this task
	move.b d0,SigNum			;when to produce fire (sent during vblanks)
	tst.b d0
	bmi exit
	moveq.l #1,d1
	lsl.l d0,d1
	move.l d1,SigMask

	sub.l a1,a1
	ExecLib FindTask
	move.l d0,SigTask

	bsr InstallVBlankServer		;Adds a vblank server which calls a user
	tst.l d0					;function if one is specified.
	bne exit

	bsr HelloWorld


	bsr WaitMode				;This is the main wait for signal loop
exit:

	bsr GoodbyeWorld

	tst.b SigNum
	bmi exit_skipfreesig
	move.b SigNum,d0
	ExecLib FreeSignal
exit_skipfreesig:
	bsr RemoveVBlankServer
	CloseLib Dos
	CloseLib GadTools
	CloseLib Intuition
	CloseLib Graphics
	rts

WaitMode:
	move.l #SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F,d0
	or.l SigMask,d0
	ExecLib Wait			;Wait for all 4 DOS signals, and our own do fire
	tst.l d0				;signal.  The DOS signals are QUIT,BLANK,UNBLANK
	beq WaitMode			;and PREFS, in that order.
	btst #SIGBREAKB_CTRL_C,d0
	bne QuitBlanker
	btst #SIGBREAKB_CTRL_D,d0
	beq NotBlankScreen
	move.l d0,-(a7)
	bsr BlankScreen
	move.l (a7)+,d0

NotBlankScreen:
	btst #SIGBREAKB_CTRL_E,d0
	beq NotUnblankScreen
	move.l d0,-(a7)
	bsr UnblankScreen
	move.l (a7)+,d0

NotUnblankScreen:
	btst #SIGBREAKB_CTRL_F,d0
	beq NotPrefsWindow
	bsr PreferencesWindow
	bra WaitMode

NotPrefsWindow:
	move.b SigNum,d1
	btst d1,d0
	beq NotStarSig
	bsr CalcSomeStars
NotStarSig:
	bra WaitMode

QuitBlanker:				;When quitting, unblank if necessary.
	bsr UnblankScreen
	rts

BlankScreen:
	tst.w isBlanked			;if already blanked, ignore this request.
	beq BlankScreen_continue
	rts
BlankScreen_continue:
	move.w NumStars,d0
	mulu #Star_SIZE,d0
	move.l #$10000,d1
	ExecLib AllocMem
	move.l d0,StarBuffer
	tst.l d0
	beq BlankScreen_fail

	bsr InitStarField

	lea $0,a0				;open a screen...should be a View really...
	lea ScreenTags,a1
	UseLib Intuition,OpenScreenTagList
	move.l d0,OpenedScreen
	tst.l d0
	beq BlankScreen_fail2

	move.l #SigForStars,UserVBlankInterrupt		;Tell VBlank handler about
												;our user code.
	lea $dff000,a5
	move.w #DMAF_SPRITE,DMACON(a5)

	move.w #1,isBlanked		;set mode as blanked
BlankScreen_fail:
	rts
BlankScreen_fail2:
	move.w NumStars,d0
	mulu #Star_SIZE,d0
	move.l StarBuffer,a1
	ExecLib FreeMem
	rts

UnblankScreen:
	tst.w isBlanked					;If not blanked, ignore
	bne UnblankScreen_continue
	rts
UnblankScreen_continue:
	lea $dff000,a5
	move.w #$8000+DMAF_SPRITE,DMACON(a5)

	move.w #0,isBlanked				;Set as not blanked

	move.l #0,UserVBlankInterrupt	;Remove code pointer for VBlank Handler

	tst.l OpenedScreen				;if the screen was open, close it
	beq UnblankScreen_noscreen

	move.l OpenedScreen,a0
	UseLib Intuition,CloseScreen
	move.l #0,OpenedScreen			;remembering to say there is no screen.

UnblankScreen_noscreen:
	move.l StarBuffer,a1
	move.w NumStars,d0
	mulu #Star_SIZE,d0
	ExecLib FreeMem

	rts

PreferencesWindow:					;This is the really complex pref window.
	jsr SetupScreen					;Ok, so it's one of the worst ever made,
	tst.l d0						;but you're not supposed to be learning
	bne prefs_noscreen				;gadtools here, just PowerManagerBlankers
	jsr OpenStarBlankerWindow
	tst.l d0
	bne prefs_nowindow

	move.l StarBlankerWnd,a1
	lea $0,a2
	lea SetGadgetTags,a3
	move.l StarBlankerGadgets+4*GD_SpeedStar,a0
	move.l #0,SetGadgetTags_newvalue
	move.w ZSpeed,SetGadgetTags_newvalue+2
	UseLib GadTools,GT_SetGadgetAttrsA

	move.l StarBlankerWnd,a1
	lea $0,a2
	lea SetGadgetTags,a3
	move.l StarBlankerGadgets+4*GD_NumStars,a0
	move.l #0,SetGadgetTags_newvalue
	move.w NumStars,SetGadgetTags_newvalue+2
	UseLib GadTools,GT_SetGadgetAttrsA

WaitPrefs:
	move.l StarBlankerWnd,a0
	move.l wd_UserPort(a0),a0
	move.b MP_SIGBIT(a0),d1
	moveq.l #1,d0
	lsl.l d1,d0
	or.l #SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E,d0
	move.b SigNum,d1
	moveq.l #1,d2
	lsl.l d1,d2
	add.l d2,d0
	ExecLib Wait
	move.l d0,d1
	and.l #SIGBREAKF_CTRL_D,d1
	beq WaitPrefs_NotBlank
	sub.l #SIGBREAKF_CTRL_D,d0
	move.l d0,-(a7)
	bsr BlankScreen
	move.l (a7)+,d0
WaitPrefs_NotBlank:
	move.b SigNum,d1
	btst d1,d0
	beq WaitPrefs_NotCalc
	moveq.l #1,d2
	lsl.l d1,d2
	sub.l d2,d0
	move.l d0,-(a7)
	bsr CalcSomeStars
	move.l (a7)+,d0
WaitPrefs_NotCalc:
	move.l d0,d1
	and.l #SIGBREAKF_CTRL_E,d1
	beq WaitPrefs_NotUnBlank
	sub.l #SIGBREAKF_CTRL_E,d0
	move.l d0,-(a7)
	bsr UnblankScreen
	move.l (a7)+,d0
WaitPrefs_NotUnBlank:
	tst.l d0
	beq WaitPrefs					;any signals left (userport)?
WaitPrefs2:							;Just get msg
	move.l StarBlankerWnd,a0
	move.l wd_UserPort(a0),a0
	ExecLib GetMsg
	tst.l d0
	beq WaitPrefs					;if no messages THEN wait for sigs
	move.l d0,a1
	move.l im_Class(a1),d0
	move.l im_IAddress(a1),a2
	move.l d0,-(a7)
	ExecLib ReplyMsg
	move.l (a7)+,d0
	cmp.l #IDCMP_CLOSEWINDOW,d0
	beq prefs_close
	cmp.l #IDCMP_GADGETUP,d0
	bne WaitPrefs2

	bsr AcceptPrefs

	cmp.l StarBlankerGadgets+4*GD_StarBlankUse,a2
	beq prefs_use

	cmp.l StarBlankerGadgets+4*GD_StarBlankSave,a2
	beq prefs_save

	move.l StarBlankerWnd,a1
	lea $0,a2
	lea SetGadgetTags,a3
	move.l StarBlankerGadgets+4*GD_SpeedStar,a0
	move.l #0,SetGadgetTags_newvalue
	move.w ZSpeed,SetGadgetTags_newvalue+2
	UseLib GadTools,GT_SetGadgetAttrsA

	move.l StarBlankerWnd,a1
	lea $0,a2
	lea SetGadgetTags,a3
	move.l StarBlankerGadgets+4*GD_NumStars,a0
	move.l #0,SetGadgetTags_newvalue
	move.w NumStars,SetGadgetTags_newvalue+2
	UseLib GadTools,GT_SetGadgetAttrsA

	bra WaitPrefs2

prefs_close:
	bsr AcceptPrefs
	bra prefs_use

prefs_save:
	bsr AcceptPrefs
	bsr SavePrefs
prefs_use:
	jsr CloseStarBlankerWindow
prefs_nowindow:
	jsr CloseDownScreen
prefs_noscreen:

	moveq.l #0,d0					;Remove any request except for quit

	move.l #SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F,d1
	ExecLib SetSignal
	rts

AcceptPrefs:
	move.l StarBlankerGadgets+4*GD_SpeedStar,a0
	move.l gg_SpecialInfo(a0),a1
	move.w si_LongInt+2(a1),ZSpeed
	tst.w ZSpeed
	bmi prefs_SpeedBad
	beq prefs_SpeedBad
	bra prefs_SpeedOk
prefs_SpeedBad:
	move.l #8,si_LongInt(a1)
	move.w #8,ZSpeed
prefs_SpeedOk:

	move.l StarBlankerGadgets+4*GD_NumStars,a0
	move.l gg_SpecialInfo(a0),a1
	move.w si_LongInt+2(a1),NumStars
	tst.w NumStars
	bmi prefs_NumBad
	beq prefs_NumBad
	bra prefs_NumOk
prefs_NumBad:
	move.l #200,si_LongInt(a1)
	move.w #200,NumStars
prefs_NumOk:
	rts

SigForStars:	;interrupt call back - tell main task to do some funky stars
	movem.l d0-d1/a0-a1/a6,-(a7)
	move.l SigMask,d0		;by only going 15Hz.
	move.l SigTask,a1
	ExecLib Signal
SigOff:
	movem.l (a7)+,d0-d1/a0-a1/a6
	rts

CalcSomeStars:

;*******************
;** DISPLAY STARS **
;*******************
	tst.l OpenedScreen
	bne Calc_IsAScreen
	rts
Calc_IsAScreen:
	move.l OpenedScreen,a1
	lea sc_RastPort(a1),a1
	move.l rp_BitMap(a1),a1			;dest bitmap

	move.l 8(a1),a2
	move.l 12(a1),a3
	move.l 16(a1),a4

	move.l LastRand,d7
	move.w NumStars,d3
	sub.w #1,d3

	move.l StarBuffer,a0
	moveq.l #0,d2					;so d2 can be a long displacement

ShowNextStar:
	tst.w Star_Delay(a0)
	beq ShowStarGo
	sub.w #1,Star_Delay(a0)
	bra EndOfStar
ShowStarGo:
	moveq.l #0,d2

	move.w Star_Offset(a0),d2		;Get coords (from last calc)
	move.w Star_Bit(a0),d1

	not.b d1						;d1=not bit
	and.b d1,(a2,d2.l)
	and.b d1,(a3,d2.l)
	and.b d1,(a4,d2.l)				;This should erase the star

	move.w ZSpeed,d1
	sub.w d1,Star_Z(a0)
	bmi ShowOverFlow
	beq ShowOverFlow

	move.w Star_X(a0),d0			;Get both x and y
	ext.l d0
	move.w Star_Y(a0),d1
	ext.l d1

	divs Star_Z(a0),d0
	add.w #160,d0
	cmp.w #319,d0
	bhi ShowOverFlow

	divs Star_Z(a0),d1
	add.w #100,d1
	cmp.w #199,d1
	bhi ShowOverFlow

	mulu (a1),d1					;*bytes per row
	move.w d1,d2

	move.w d0,d1
	lsr.w #3,d0
	add.w d0,d2						;+col/8
	moveq.l #0,d0
	not.b d1
	and.w #$7,d1					;from top bit to lower bits
	bset d1,d0						;d0=bit

	move.w Star_Z(a0),d4
	lsr.w #7,d4
	not.w d4
	and.w #$3,d4					;Colors based on Z
	btst #0,Star_X(a0)
	beq NotBlue

	or.b d0,(a4,d2.l)				;do color change

NotBlue:

	move.w d0,Star_Bit(a0)			;Save coords for undraw
	move.w d2,Star_Offset(a0)		;by this time we know it's on the bitmap

	lsr.w #1,d4
	bcc ShowNoPlane0
	or.b d0,(a2,d2.l)
ShowNoPlane0:
	lsr.w #1,d4
	bcc ShowNoPlane1
	or.b d0,(a3,d2.l)
ShowNoPlane1:						;and plot it

EndOfStar:
	lea Star_SIZE(a0),a0
	dbf d3,ShowNextStar
	move.l d7,LastRand
	rts
ShowOverFlow:
	Random

	move.l d7,d6
	and.w #$ffff,d6
	cmp.w #$9fff,d6
	bhi ShowOverFlow
	sub.w #$5000,d6
	move.w d6,Star_X(a0)

ShowOverFlow2:
	Random
	and.w #$7fff,d6
	cmp.w #25600,d6
	bge ShowOverFlow2
	sub.w #25600/2,d6
	move.w d6,Star_Y(a0)
	move.w #512,Star_Z(a0)

	Random
	move.l d7,d6
	and.w #$ff,d6
	move.w d6,Star_Delay(a0)
	bra EndOfStar
	
InitStarField:			;Setup star data area
	move.l LastRand,d7
	move.l StarBuffer,a0

	move.w NumStars,d0
	sub.w #1,d0
InitNextStar:

Init_recalc:
	Random

	move.l d7,d6
	and.w #$ffff,d6
;	cmp.w #$9fff,d6
;	bhi Init_recalc
;	sub.w #$5000,d6
	sub.w #$8000,d6
	move.w d6,Star_X(a0)

	swap d6
	and.w #$7fff,d6
;	cmp.w #25600,d6
;	bge Init_recalc
;	sub.w #25600/2,d6
	sub.w #32768/2,d6

	move.w d6,Star_Y(a0)
	move.w #512,Star_Z(a0)

	Random
	move.l d7,d6
	and.w #$3ff,d6
	move.w d6,Star_Delay(a0)

	lea Star_SIZE(a0),a0
	dbf d0,InitNextStar
	move.l d7,LastRand
	rts

SavePrefs:
	move.l #PrefName,d1
	move.l #1006,d2
	UseLib Dos,Open
	tst.l d0
	beq SavePrefs_no
	move.l d0,d1
	move.l d0,d4
	move.l #NumStars,d2
	move.l #4,d3
	CurLib Write
	move.l d4,d1
	CurLib Close
SavePrefs_no:
	rts

LoadPrefs:
	move.w #200,NumStars
	move.w #8,ZSpeed			;In case of no file

	move.l #PrefName,d1
	move.l #1005,d2
	UseLib Dos,Open
	tst.l d0
	beq LoadPrefs_no
	move.l d0,d1
	move.l d0,d4
	move.l #NumStars,d2
	move.l #4,d3
	CurLib Read
	move.l d4,d1
	CurLib Close
LoadPrefs_no:
	rts

HelloWorld:
	ExecLib Forbid
	lea PMPortName,a1
	ExecLib FindPort
	tst.l d0
	beq HW_Fail
	move.l d0,PMPort
	move.l #MN_SIZE,d0
	move.l #$10000,d1
	ExecLib AllocMem
	tst.l d0
	beq HW_Fail
	move.l d0,a1
	move.l PMPort,a0
	move.w #MN_SIZE,MN_LENGTH(a1)
	move.l SigTask,LN_NAME(a1)
	ExecLib PutMsg
HW_Fail:
	ExecLib Permit
	rts

GoodbyeWorld:
	ExecLib Forbid
	lea PMPortName,a1
	ExecLib FindPort
	tst.l d0
	beq GW_Fail
	move.l d0,PMPort
	move.l #MN_SIZE,d0
	move.l #$10000,d1
	ExecLib AllocMem
	tst.l d0
	beq GW_Fail
	move.l d0,a1
	move.l PMPort,a0
	move.w #MN_SIZE,MN_LENGTH(a1)
	move.l #0,LN_NAME(a1)
	ExecLib PutMsg
GW_Fail:
	ExecLib Permit
	rts

	Section MainData,Data
PMPortName:	dc.b 'PowerManagerBlank',0
	CNOP 0,2
PMPort:	dc.l 0

LastRand:	dc.l 0

_GfxBase:
Graphics:
	dc.l 0
	dc.b 'graphics.library',0
	CNOP 0,2

_SysBase:	dc.l 0

_GadToolsBase:
GadTools:
	dc.l 0
	dc.b 'gadtools.library',0
	CNOP 0,2

_IntuitionBase:
Intuition:
	dc.l 0
	dc.b 'intuition.library',0
	CNOP 0,2

Dos:
	dc.l 0
	dc.b 'dos.library',0
	CNOP 0,2

isBlanked:	dc.w 0
OpenedScreen:	dc.l 0

ScreenTags:
	dc.l	SA_Width,320
	dc.l	SA_Height,200
	dc.l	SA_Depth,3
	dc.l	SA_Colors,BlankerColorSpec
	dc.l	SA_Type,CUSTOMSCREEN
	dc.l	SA_ShowTitle,0
	dc.l	SA_Quiet,1
	dc.l	SA_Draggable,0
	dc.l	TAG_END,0

BlankerColorSpec:
	dc.w 0,0,0,0
	dc.w 1,$c/3,$e/3,$f/3
	dc.w 2,$c*2/3,$e*2/3,$f*2/3
	dc.w 3,$c,$e,$f
	dc.w 4,0,0,0
	dc.w 5,$f/3,$e/3,$a/3
	dc.w 6,$f*2/3,$e*2/3,$a*2/3
	dc.w 7,$f,$e,$a
	dc.w -1

SigNum:	dc.b -1,0

	include "wci.i"

PrefName:	dc.b 'envarc:StarBlank.prefs',0
	CNOP 0,2

SetGadgetTags:
	dc.l GTIN_Number
SetGadgetTags_newvalue:
	dc.l 0
	dc.l TAG_END,0

	Section FireBSS,BSS
SigTask:	ds.l 1
SigMask:	ds.l 1
NumStars:	ds.w 1
ZSpeed:		ds.w 1
StarBuffer:	ds.l 1				;pointer to NumStars*Star_SIZE
	end
