;; This example shows how to double buffer a standard 16K screen ;; using the hardware. ;; ;; This example shows how to lock the double buffer rate. ;; ;; The disadvantage: ;; - game is locked at a fixed rate so is slow ;; Advantage: ;; - game is the same speed and doesn't speed up or slow down ;; - game is always flicker free because of the way we manage the double buffer. ;; ;; 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 ;; rate is in multiples of 50hz. buffer_rate equ 2 ;; 1 = 50hz, 2 = 25Hz ;;--------------------------------------------------------------------------- start: xor a ld (double_buffer_done),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. ;; go back and syncronise. ;; our code must be done within the time defined by the rate ;; e.g. if 1, we must complete our code within 50th of a second. ;; if 2 we must complete our code within 25th of a second. 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 ;; decrement count and check if it's reached zero ld a,(buffer_swap_count) dec a jr nz,int_handler2 ;; reached zero, so we can perform swap now ;; 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 ld a,1 ld (double_buffer_done),a ;; reset count ld a,buffer_rate int_handler2: ;; store count ld (buffer_swap_count),a pop hl pop bc ei reti ;;--------------------------------------------------------------------------- ;; this is the counter, when it reaches zero the double buffer swap is done ;; it is then reset back to it's initial value for next time buffer_swap_count: defb buffer_rate ;;--------------------------------------------------------------------------- ;; 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 ;;--------------------------------------------------------------------------- ;; this is the visible screen base_visible: defb &c0 ;; this is the hidden screen we draw to base_hidden: defb &40 end