;; This example shows how to handle a variable frame rate. ;; This example shows how to use a variable rate double buffer. ;; The disadvantage is that the game speeds up and slows down, but the update of the screen ;; remains free of flicker. ;; ;; Advantage: ;; - our code can take longer than 1/2 frames ;; Disadvantage: ;; - game speeds up and slows down depending on how much is going on. ;; Game will never go faster than 50hz, but will appear to speed up and slow down. ;; The example is minimal and just shows how ;; you set the screen base to do the double buffer it doesn't show ;; how to draw on double buffered screens. ;; ;; One screen will be at &4000-&7fff. ;; Second screen will be at &c000-&ffff. ;; ;; ;; location for our code, not inside visible screen area (this allows ;; us to scroll the screen if we need) org &8000 ;;--------------------------------------------------------------------------- start: ;; this indicates a swap has been done xor a ld (double_buffer_done),a ;; we set this to indicate we want a swap done xor a ld (double_buffer_swap),a di im 1 ld a,&c3 ld hl,int_handler ld (&0038),a ld (int_handler),hl ei ;; we display the visible screen ld a,&c0 ld (base_visible),a ;; we draw to the hidden screen, this is it's initial state ld a,&40 ld (base_hidden),a loop: ;; wait for indication that swap has been done ;; if we're quicker than the rate, we wait until the swap is done ;; before continuing. ld a,(double_buffer_done) or a jr z,loop ;; reset that we've seen it xor a ld (double_buffer_done),a ;; ... ;; perform code. ;; ... ;; we want to swap please. ld a,1 ld (double_buffer_swap),a ;; now wait until it's been done jp loop ;;--------------------------------------------------------------------------- int_handler: ;; store registers we will change push af push bc push hl ;; in VSYNC? ld b,&f5 in a,(c) rra jr nc,int_handler2 ;; no, skip double buffer ;; in vsync, this is the unit of our frame rate ;; code wants swap to be performed? ld a,(double_buffer_swap) or a jr z,int_handler2 ;; reset flag so code can set it next time xor a ld (double_buffer_swap),a ;; reached zero, so we can perform swap now ;; do the work ;; in VSYNC ;; ;; here we update our double buffer ;; set screen address using CRTC ;; ;; we set R12/R13. ld a,(base_visible) ;; make the value correct for crtc srl a srl a ld bc,&bc0c ;; CRTC R12 out (c),c ;; B = &BD inc b out (c),a dec b inc c ;; BC=&BC0D out (c),c ;; CRTC R13 inc b ;; B = &BD xor a out (c),a ;; ;; &c0-&40 AND &40-&c0 ld a,(base_visible) xor &80 ld (base_visible),a ;; code should now use this to work out how to draw ;; &40-&c0 AND &c0-&40 ld a,(base_hidden) xor &80 ld (base_hidden),a ;; indicate to code we did the buffer swap ;; code will see this ld a,1 ld (double_buffer_done),a int_handler2: pop hl pop bc ei reti ;;--------------------------------------------------------------------------- ;; this is 0 if the swap is not done, 1 otherwise. ;; this indicates to the code that the swap has been done double_buffer_done: defb 0 ;;--------------------------------------------------------------------------- ;; code sets this to 1 when it wants the swap. ;; it then waits until the swap is done and then resets this. double_buffer_swap: defb 0 ;;--------------------------------------------------------------------------- ;; this is the visible screen base_visible: defb &c0 ;; this is the hidden screen we draw to base_hidden: defb &40 end