Twither / Arkos

Twither, a 256 bytes intro by Arkos. Released at Forever 2009.

This is my third attempt at a 256 bytes twister effect, in hires (mode 2 - 640×200), fullscreen and twisting at fullframe rate. I wanted to do a great looking lighting/dithering effect applied to the twister but I failed to squeeze it into 256 bytes. So I ended up with a much simpler and not so good looking dithering effect, but it fits the size limitation.

It was released at Forever Next 2009 (and was unfortunately the only CPC entry, thus the CPC compo was canceled).

» Twither (DSK and sources included).

The twister is 256 pixels wide with 256 twisting-steps. It requires 64Kb RAM and should work on CRTC type 0,1 or 3 (probably 4 too). CRTC type 2 is not supported. See readme.txt to hack the intro and play with the colors.

How to compile with WinAPE

  • In the Settings, select CRTC type 0.
  • Open “Twither (Arkos).asm” in the Assembler window.
  • Compile and Run (press F9).

Source

;    _____         __
;   /  _  \_______|  | ______  ______
;  /  /_\  \_  __ \  |/ /  _ \/  ___/
; /    |    \  | \/    <  <_> )___ \
; \____|__  /__|  |__|_ \____/____  >
;         \/           \/         \/
; 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 1
 
					; 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.lib.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
sources/twither.txt · Last modified: 2009/09/24 00:24 by grim