; _____ __ ; / _ \_______| | ______ ______ ; / /_\ \_ __ \ |/ / _ \/ ___/ ; / | \ | \/ < <_> )___ \ ; \____|__ /__| |__|_ \____/____ > ; \/ \/ \/ ; Twither, a 256 bytes intro presented at Forever 2009. ; (252 bytes exactly =) ; ; Hires(640x200) and fullscreen twister bar with some sort ; of dithering effet (not exactly what I planned first but ; I miserably failed to squeeze it all in 256 bytes =). ; ; The twister is 256 (mode 2) pixels wide with 256 steps. ; ; It works on CRTC type 0, 1 and 3. ; It should work on CRTC type 4 (not tested) ; It simply can't work on CRTC type 2. ; ; Grim/Arkos^Semilanceata ; ; NOTES ; - content at &0Cxx corrupted by the fx 64us innerloop, DO NOT USE! ;*** Configuration ************************************************************ ; Compile a small build test-code and debug stuff rubberbar_debug equ 0 ; Configure CRTC synchronization ; &E0 - Type 0. ; &F0 - Type 1, 3 (probably 4). rubberbar_cnf_crtcsync equ &F0 ; Sinus lookup tables addresses rubberbar_data_lut_sinus1024 equ &8800 rubberbar_data_lut_sinus256 equ &0900 ; opt - hibyte used as CRTC Select reg 9 ;****************************************************************************** if rubberbar_debug org &9F00 run $ ; clear screen ld a,2 call &BC0E jp rubberbar_exec else run rubberbar_exec endif org &A000 ; Dithering patterns rubberbar_data_dither_seq db 1,17,21,85,87,119,127,255 ;rubberbar_data_dither_seq db 255,127,119,87,85,21,17,1 rubberbar_exec: ; disable 300Hz interrupts di ; select screen mode 2 ld bc,&7F8E out (c),c ; set ink 1 color to red (&4C) ld de,&014C out (c),d out (c),e ; Wild CRTC 6845 initialization ld hl,&0701 ;ld de,&0100+16 ld e,16 call rubberbar_crtset ;*** Generate a 1024 bytes sinus (8bits unsigned) lookup table ***************** cnf_math_singen_sizeopt_store equ rubberbar_data_lut_sinus1024 cnf_math_singen_inline equ 1 cnf_math_singen_unsigned equ 1 read "math.singen.sizeopt.asm" ; Output ; HL=0 ; DE=0 ; BC=1 ; save HL=&0000 (used as VRAM pointer later) push hl ; clear vram inc e ld (hl),l ld bc,&87FF ldir ;*** Generate a 256 bytes sinus (8bits unsigned) lookup table ****************** ; 256 bytes sinus ;ld h,rubberbar_data_lut_sinus1024/256 inc hl ld d,rubberbar_data_lut_sinus256/256 ld c,4 _rubberbar_256b_singen_loop ld a,(hl) add a,e ld (de),a add hl,bc inc e jr nz,_rubberbar_256b_singen_loop ;*** Generate the twisterbar graphic ******************************************* ld hl,rubberbar_data_lut_sinus1024 + &180 ; pi/2+pi/4 exx pop hl ;ld hl,&0000 call rubberbar_generator call rubberbar_generator ;*** 50Hz Twister display loop ************************************************* ; *** 50Hz loop *** rubberbar_sync ld b,&F5 in a,(c) rra jr nc,rubberbar_sync+2 ; On first frame, VCC will overflow, and the ; display will be fucked up. No space to waste ; for a clean first 20ms frame =) ; CRTC0 => Wait VCC=2 & VLC=7 (last scanline) ; CRTC1 => Wait VCC=0 & VLC=0 (new screen) ld b,rubberbar_cnf_crtcsync djnz $ ; setup CRTC for rubberbar fx ld hl,&0400 ld de,&0900 ; doube usage, &0900 => CRTCReg9=0 & 256bytes sinus LUT address call rubberbar_crtset ; update twister-sin pointers ld hl,&0131 _rubberbar_var_sinptr equ $-2 ld bc,&FD04 add hl,bc ld (_rubberbar_var_sinptr),hl ld e,h ld h,d ;ld h,rubberbar_data_lut_sinus256/256 ;ld d,h ; rubberbar height (rasterlines) ld bc,287 ; *** 64us innerloop *** _rubberbar_fx_loop ; A=(sin(DE)+sin(HL)) AND 255 ld a,(de) inc e add a,(hl) inc l exx ; convert A into screen offset ld h,&0C ld (hl),a xor a rld ld d,a ld e,(hl) ; AE=%xxxxPPLL.LLLL0000 and h ;%1100 = &C add a,a add a,a or d ; AE=%xxPPxxLL.LLLL0000 ld l,a ld d,&0D call rubberbar_crtset exx ; 64us rasterline loop dec bc ld a,b or c jr nz,_rubberbar_fx_loop ; *** end of splitscreen *** ;ld hl,&0907 ld l,7 ld de,&0402 call rubberbar_crtset ; loop forever jr rubberbar_sync ;*** Subroutines *************************************************************** rubberbar_crtset: ; write two CRTC registers ld b,&BC out (c),h ; select register inc b out (c),l ; write register dec b out (c),d ; select register inc b out (c),e ; write register ret rubberbar_generator: ; draw 64 lines of the twister per 16k page. ; there's 4 pages => 256 lines. Only the firsts ; &800 bytes of each pages is used. ld b,64 _rubberbar_generator_16k ;save vram pointer push hl dec l exx ; save sin pointer push hl ; read x1 = cos(a+45) ld a,(hl) ld c,a ; set the plotter to the x1 position exx inc a ld c,%0000001 _rubberbar_generator_locate rrc c jr nc,$+2+1 inc l dec a jr nz,_rubberbar_generator_locate exx ; read x2 = cos(a-45) dec h ;res 2,h ld a,(hl) sub c ; x2-x1 = Line lenght ld b,a _rubberbar_generator_plot ; 8bits dither level ld a,(hl) ;res 2,h ; 3bits dither index rlca rlca rlca and %111 ; 8bits dither value ld e,a ld d,rubberbar_data_dither_seq/256 ld a,(de) ; read dithering byte ; plot pixel exx and c ; apply bitmask or (hl) ; merge with vram ld (hl),a rrc c ; next pixel, rotate bitmask jr nc,$+3 inc hl ; move to next byte exx jr nc,$+3 inc hl ; repeat for line-lenght pixels djnz _rubberbar_generator_plot _rubberbar_generator_plot_skip ; restore sin pointer pop hl ; move to next angle (0, 511) inc hl ;res 2,h exx ; move to the next line pop hl ld de,32 add hl,de djnz _rubberbar_generator_16k ; move to the next 16k page ld de,&3800 add hl,de jr nc,rubberbar_generator ; exit after 4x16k pages processed ret