VERSIONSTRING equ "Egfx v2.01" ! ! Filename: egfx.asm ! Module name: Egfx ! Description: enhanced-mode video driver ! ! Commands: ! string QueryVersion () - retrieve version string ! SetMode (byte numColors, byte refreshRate, byte bufferRezID) - turn ; egfx mode on or off ! RestoreMode () - turn egfx mode on without initialization ! CheckBufferSpace (byte width, byte height) - check for enough memory ! byte CreateBuffer (byte width, byte height) - create gfx buffer ! special ScriptInline (byte[] script) - execute gfx script ! ScriptResource (byte rezID) - execute gfx script stored as resource ! StartAutoScript (byte rezID, word speed) - periodically execute script ! StopAutoScript () - turn off auto-script ! ! IPC: ! IPC_Gfx_SetModeOff ! ! Timers: ! TIMER_Egfx - timer for auto-scripting ! ! Hooks: ! HOOK_GFX - graphics hook ! ! Comments: ! Enhanced-mode video is a significant improvement over standard mode. ! It allows an arbitrarily sized video buffer and number of colors, ! and provides functions for drawing objects in a variety of drawing ! modes. It also supports "scripts" for quickly excecuting a number ! of graphics commands. ! ! History: ! bv 9/21/98 - initial revision ! bv 7/19/99 - finally converted to cokeOS v3 module, ! added multiple buffers, AUTOMOVE_SCRIPT, other stuff... ! bv 7/28/99 - added RestoreMode command include include ; constants HEADER_xsize16 equ 0 HEADER_xsize equ 1 HEADER_ysize16 equ 2 HEADER_ysize equ 3 HEADER_bufferptr equ 4 HEADER_bufferptrlo equ 5 HEADER_bufsize equ 6 HEADER_bufsizelo equ 7 HEADER_bufend equ 8 HEADER_bufendlo equ 9 HEADER_CursorX0 equ 10 HEADER_CursorX1 equ 11 HEADER_CursorX2 equ 12 HEADER_CursorX3 equ 13 HEADER_CursorY0 equ 14 HEADER_CursorY1 equ 15 HEADER_CursorY2 equ 16 HEADER_CursorY3 equ 17 HEADERSIZE equ 18 ; direct page variables egfx_spt equ DIRPAGE_Egfx egfx_basecount equ DIRPAGE_Egfx+60 egfx_column equ DIRPAGE_Egfx+61 egfx_scanline equ DIRPAGE_Egfx+62 egfx_numcolors equ DIRPAGE_Egfx+64 egfx_baseline equ DIRPAGE_Egfx+65 ; the following do not NEED to go in the direct page, but I allocated ; the space, so I might as well use it. egfx_xcursor equ DIRPAGE_Egfx+66 egfx_ycursor equ DIRPAGE_Egfx+67 egfx_cursorptr equ DIRPAGE_Egfx+68 egfx_bufferptr equ DIRPAGE_Egfx+70 egfx_bufsize equ DIRPAGE_Egfx+72 egfx_bufend equ DIRPAGE_Egfx+74 egfx_xsize16 equ DIRPAGE_Egfx+76 egfx_xsize equ DIRPAGE_Egfx+77 egfx_ysize16 equ DIRPAGE_Egfx+78 egfx_ysize equ DIRPAGE_Egfx+79 ; EntryPoint EntryPoint subroutine cmpa #IPC_Coke_Hello beq .init cmpa #IPC_Coke_Goodbye beq .free cmpa #IPC_Gfx_SetModeOff beq .off sec rts .init ldx #CommandTable ; install command table jsr Coke_InstallCommandTable ldaa #ID_Egfx ; register IPC ldx #EntryPoint jsr Coke_RegisterIPC jsr InitEgfx ; init memory stuff clc rts .free ldx #CommandTable ; remove commands jsr Coke_RemoveCommandTable ldaa #TIMER_Egfx ; remove timer jsr Coke_RemoveTimer ldx #RefreshHookEnd ; remove the hook ldaa #HOOK_GFX jsr Coke_RemoveHook ldaa #ID_Doodad ; remove IPC jsr Coke_UnregisterIPC clc rts .off psha pshx tst egfx_active ; are we active? beq .notactive ldaa #HOOK_GFX ; if so, remove the hook ldx #RefreshHookEnd jsr Coke_RemoveHook clr egfx_active ; ain't active no more, eh? .notactive pulx pula clc rts ; InitEgfx initializes stuff... it does not start up the video mode. InitEgfx subroutine ldaa #OPCODE_JMPEXT ; prepare the vectors staa CurrentDmodeVec ; pixel draw vector staa AutoMoveVec ; automove vector staa PanVec ; pan vector clr egfx_ysize16 ; clear hibyte of ysize clr egfx_xsize16 ; clear hibyte of xsize clr egfx_active ; not active clr egfx_modeset ; never set mode rts ; Command_SetMode (byte numColors, byte refreshRate, byte rezID) Command_SetMode subroutine jsr Coke_GetChar ; get numColors staa egfx_stash1 jsr Coke_GetChar ; get refreshRate staa egfx_stash2 jsr Coke_GetChar ; get rezID staa egfx_stash3 tst egfx_stash1 ; is numcolors zero? bne .turnon ; if not, turn on the mode ; otherwise, turn off tst egfx_active ; are we on? beq .offdone ; if not, do nothing ldaa #HOOK_GFX ; if turning off, remove hook ldx #RefreshHookEnd jsr Coke_RemoveHook clr egfx_active ; clear active flag .offdone ldaa #COKE_ACK ; all good rts .turnon ldab egfx_stash3 ; make sure the resource ID is valid jsr Resource_GetResource bcs .badresource ldaa #IPC_Gfx_SetModeOff ; turn off all other graphics modes ldab #IPCFLAG_Broadcast ; send to all jsr Coke_CallIPC ldaa egfx_stash1 ; get numColors deca bne .goodcolors ; colors=1 is not allowed inca ; so make it 2 .goodcolors staa egfx_numcolors ; numcolors= number of colors - 1 ldab egfx_stash2 ; get refresh rate mul ; multiply by numcolors xgdx ; put into x ldd #8333 ; get divisor idiv ; quotient in x, remainder in d stx gfxdelay ; that's the new delay value ldab egfx_stash3 ; get the buffer rezID jsr SetBuffer ; set the buffer ldaa #$FF ; set initial baseline to zero staa egfx_baseline ldaa #1 ; reset mux counter staa egfx_basecount ldaa #DMODE_COPY ; set the drawing mode to copy jsr SetDrawingMode clra ; put zero in a and b clrb staa egfx_delta ; set delta to zero staa egfx_column ; reset the mux column staa egfx_color ; set inital color to zero (baseline) jsr CursorSet ; put the cursor in the top left jsr CursorStore ; put it in the store value too jsr ScreenSet ; set the screen to the top left jsr SetAutoMove ; turn off automove jsr SetPan ; turn off panning ldaa #1 staa egfx_active ; say that we're on staa egfx_modeset ; say that we set the mode ldaa #HOOK_GFX ; install our hook function ldx #RefreshHookEnd jsr Coke_InstallHook ldaa #COKE_ACK rts .badresource ldaa #COKE_FAIL ldab #ERROR_Coke_BadResourceID rts ; Command_RestoreMode () Command_RestoreMode subroutine ldaa egfx_modeset ; was the mode ever set? beq .badset ; if not, can't do this ldaa egfx_active ; are we already active? bne .done ; if so, we have nothing to do. ldaa #IPC_Gfx_SetModeOff ; turn off all other graphics modes ldab #IPCFLAG_Broadcast ; send to all jsr Coke_CallIPC ldaa #1 staa egfx_active ; say that we're on ldaa #HOOK_GFX ; install our hook function ldx #RefreshHookEnd jsr Coke_InstallHook .done ldaa #COKE_ACK rts .badset ldab #ERROR_Egfx_ModeNeverSet ldaa #COKE_FAIL rts ; Command_CheckBufferSpace (byte width, byte height) Command_CheckBufferSpace subroutine jsr Coke_GetChar ; get width tab ; put in b jsr Coke_GetChar ; get height mul ; put 'em together addd #HEADERSIZE ; add header size bcs .bad std egfx_stash1 ; store it jsr Resource_GetFreeSpace ; get free memory in d cpd egfx_stash1 ; compare it bhs .bad ldaa #COKE_ACK rts .bad ldaa #COKE_FAIL ldab #ERROR_Coke_NotEnoughMemory rts ; Command_CreateBuffer (byte width, byte height) Command_CreateBuffer subroutine jsr Coke_GetChar ; get width staa egfx_stash1 tab ; put in b jsr Coke_GetChar ; get height staa egfx_stash2 mul ; put 'em together addd #HEADERSIZE ; add header size bcs .bad jsr Resource_CreateResource ; allocate some memory (ID in b) bcs .bad stab egfx_stash3 ; store rez ID jsr Resource_GetResource ; get resource pointer in x ldaa egfx_stash1 ; get width staa HEADER_xsize,x ; store it in buffer header ldab egfx_stash2 ; get height stab HEADER_ysize,x ; store it in buffer header mul ; put product in d std HEADER_bufsize,x ; store size stx egfx_stash1 ; store header pointer ldd egfx_stash1 ; put it into d addd #HEADERSIZE ; get pointer to actual buffer std HEADER_bufferptr,x ; store that addd HEADER_bufsize,x ; add the buffer size std HEADER_bufend,x ; store the end of the buffer clra ; clear out other stuff staa HEADER_xsize16,x staa HEADER_ysize16,x staa HEADER_CursorX0,x staa HEADER_CursorX1,x staa HEADER_CursorX2,x staa HEADER_CursorX3,x staa HEADER_CursorY0,x staa HEADER_CursorY1,x staa HEADER_CursorY2,x staa HEADER_CursorY3,x ldaa #COKE_QUERY ; return a query response ldab #1 ; one byte long ldx #egfx_stash3 ; rez ID rts .bad ldaa #COKE_FAIL ldab #ERROR_Coke_NotEnoughMemory rts ; Command_StartAutoScript (byte rezID, word speed) Command_StartAutoScript subroutine jsr Coke_GetChar ; get rezID staa egfx_stash1 jsr Coke_GetChar ; get lobyte speed tab jsr Coke_GetChar ; get hibyte speed xgdy ; put speed in y ldab egfx_stash1 ; use rezID as timer parameter jsr Resource_GetResource ; but first check its valid bcs .bad ldaa #TIMER_Egfx ; timer ID ldx #TimerAutoScript ; timer function pointer jsr Coke_SetTimer ; set that timer ldaa #COKE_ACK ; we done rts .bad ldaa #COKE_FAIL ldab #ERROR_Coke_BadResourceID rts ; Command_StopAutoScript () Command_StopAutoScript subroutine ldaa #TIMER_Egfx ; timer ID jsr Coke_RemoveTimer ; remove the timer ldaa #COKE_ACK rts ; Command_ScriptResource (byte rezID) Command_ScriptResource subroutine jsr Coke_GetChar ; get rezID tab ; put in b jsr Resource_GetResource ; get the resource pointer bcs .bad jsr ExecuteScript ; do it ldaa #COKE_ACK rts .bad ldaa #COKE_FAIL ldab #ERROR_Coke_BadResourceID rts ; Command_ScriptInline (byte[] script) Command_ScriptInline subroutine ldx #0 jsr ExecuteScript ldaa #COKE_ACK rts ; TimerAutoScript is the timer function that does the autoscript. ; It accepts the script id as the parameter in a. TimerAutoScript subroutine pshb tab ; put resource ID in b jsr ScriptResource ; do the script pulb rts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; scripting functions ExecuteScript subroutine psha pshb pshx pshy ldy egfx_scriptpointer ; get the previous script pointer pshy ; and stash it, in case this is nested stx egfx_scriptpointer ; store new script pointer .scriptloop jsr GetNextChar ; get next command tsta ; is it zero? beq .done ; if so, we're done here tab ; put it in b pshb ; stash it for later andb #$F0 ; only want high nibble lsrb ; get high nibble times two in b lsrb lsrb ldx #FunctionTable ; put pointer to first table in x abx ; add offset to table pointer ldd 0,x ; get pointer to second table xgdx ; put it in x pulb ; get back command char andb #$0F ; only want low nibble cmpb 0,x ; compare to num of functions in table bhs .done ; if function doesn't exist, quit now! aslb ; put lo nibble times two in b incb ; plus one, for the function count abx ; add it to table pointer ldd 0,x ; get function pointer xgdx ; put it in x jsr 0,x ; do the function bra .scriptloop ; do some more! .done pulx stx egfx_scriptpointer ; restore the old script pointer puly pulx pulb pula rts ; GetNextChar gets the next character in the script. If scriptpointer ; is not null, it gets it from that and updates the pointer. If scriptpointer ; is null, it calls Coke_GetChar. ; char is returned in a. GetNextChar subroutine pshx ldx egfx_scriptpointer ; get current script pointer beq .nullptr ; if the ptr is 0, do the serial thang ldaa 0,x ; otherwise, get the char inx ; update the pointer stx egfx_scriptpointer ; store it pulx rts ; and return .nullptr jsr Coke_GetChar ; get something from the serial port pulx rts ; The Param functions are used to set up the proper registers for the ; Egfx call, using the parameters in the script. Param_None subroutine ; no parameters rts Param_A subroutine ; one parameter in the a register jmp GetNextChar Param_B subroutine ; one parameter in the b register jsr GetNextChar tab rts Param_AB subroutine ; first parameter in a, second in b jsr GetNextChar psha jsr GetNextChar tab pula rts Param_XX subroutine ; two byte parameter in x, low byte first jsr GetNextChar tab jsr GetNextChar xgdx rts Param_XAB subroutine ; one byte parameter in x, then a, then b jsr GetNextChar tab clra xgdx jsr GetNextChar psha jsr GetNextChar tab pula rts Param_XXAB subroutine ; two bytes in x, then one in a and one in b jsr GetNextChar tab jsr GetNextChar xgdx jsr GetNextChar psha jsr GetNextChar tab pula rts Param_XYAB subroutine ; byte in x, y, a, and b jsr GetNextChar tab clra xgdx jsr GetNextChar tab clra xgdy jsr GetNextChar psha jsr GetNextChar tab pula rts ; FunctionTable is a table to the graphics functions. It actually ; is a double table. Use the high nibble of the code to look up a pointer ; to another table, and then use the low nibble to look up the actual function ; within that table. The first entry of each second table is a byte that ; indicates how many functions are in that table, so we can terminate ; on illegal function codes. FunctionTable subroutine dc.w .dummy ; $0 dc.w .script ; $1 dc.w .settings ; $2 dc.w .cursor ; $3 dc.w .drawing ; $4 dc.w .font ; $5 dc.w .buffer ; $6 dc.w .screen ; $7 dc.w .dummy ; $8 dc.w .dummy ; $9 dc.w .dummy ; $A dc.w .dummy ; $B dc.w .dummy ; $C dc.w .dummy ; $D dc.w .dummy ; $E dc.w .dummy ; $F .dummy dc.b 0 .script dc.b 1 dc.w Egfx_ScriptResource .settings dc.b 7 dc.w Egfx_SetBuffer dc.w Egfx_SetColor dc.w Egfx_SetDelta dc.w Egfx_SetBaseline dc.w Egfx_SetDrawingMode dc.w Egfx_SetAutoMove dc.w Egfx_SetPan .cursor dc.b 9 dc.w Egfx_CursorSet dc.w Egfx_Xset dc.w Egfx_Yset dc.w Egfx_Xjump dc.w Egfx_Yjump dc.w Egfx_CursorStore dc.w Egfx_CursorStoreNum dc.w Egfx_CursorRestore dc.w Egfx_CursorRestoreNum .drawing dc.b 6 dc.w Egfx_Skip dc.w Egfx_Dot dc.w Egfx_Xline dc.w Egfx_Yline dc.w Egfx_Frame dc.w Egfx_Rect .font dc.b 0 ; dc.w Egfx_UseFontResource ; dc.w Egfx_Char ; dc.w Egfx_CharLine .buffer dc.b 1 dc.w Egfx_Wipe ; dc.w Egfx_Dump ; dc.w Egfx_DumpResource ; dc.w Egfx_DumpRect ; dc.w Egfx_DumpRectResource ; dc.w Egfx_MoveRect .screen dc.b 5 dc.w Egfx_ScreenSet dc.w Egfx_RangeSet dc.w Egfx_Pan dc.w Egfx_PanThis dc.w Egfx_PanRange ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; graphics functions include "egfx_core.asm" ; version stuff _versionstuff ; command table CommandTable subroutine dc.b CMD_Egfx_QueryVersion dc.w Command_QueryVersion dc.b CMD_Egfx_SetMode dc.w Command_SetMode dc.b CMD_Egfx_RestoreMode dc.w Command_RestoreMode dc.b CMD_Egfx_CreateBuffer dc.w Command_CreateBuffer dc.b CMD_Egfx_ScriptInline dc.w Command_ScriptInline dc.b CMD_Egfx_ScriptResource dc.w Command_ScriptResource dc.b CMD_Egfx_StartAutoScript dc.w Command_StartAutoScript dc.b CMD_Egfx_StopAutoScript dc.w Command_StopAutoScript dc.b 0 ; data segment egfx_color ds 1 egfx_delta ds 1 egfx_scriptpointer ds 2 egfx_active ds 1 egfx_headerptr ds 2 egfx_automovescript ds 1 egfx_hpt ds 60 egfx_stash1 ds 1 egfx_stash2 ds 1 egfx_stash3 ds 1 egfx_modeset ds 1 CurrentDmodeVec jmp DmodeNone AutoMoveVec jmp MoveNone PanVec jmp PanNone