Skip to content
Permalink
9ad5619ac2
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
3613 lines (2991 sloc) 140 KB
; Tandy64 Intro
; Pungas de Villa Martelli - http://pungas.space
;
; code: riq (http://retro.moe)
bits 16
cpu 8086
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; MACROS
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
%define DEBUG 0 ;0=diabled, 1=enabled
GFX_SEG equ 0x1800 ;0x1800 for PCJr with 32k video ram
;0xb800 for Tandy
VGA_ADDRESS equ 0x03da ;Tandy == PCJr.
VGA_DATA equ 0x03da ;Tandy = 0x03de. PCJr. 0x03da
TEXT_WRITER_START_Y equ 19 ;start at line 19
BOTTOM_OFFSET equ 21*2*160-160 ;start at line 21:160 bytes per line, lines are every 4 -> 8/4 =2
SCROLL_OFFSET equ 22*2*160 ;start at line 22:160 bytes per line, lines are every 4 -> 8/4 =2
SCROLL_COLS_TO_SCROLL equ 116 ;how many cols to scroll. max 160 (width 320, but we scroll 2 pixels at the time)
SCROLL_COLS_MARGIN equ ((160-SCROLL_COLS_TO_SCROLL)/2)
SCROLL_RIGHT_X equ (160-SCROLL_COLS_MARGIN-1) ;col in which the scroll starts from the right
SCROLL_LEFT_X equ (SCROLL_COLS_MARGIN) ;col in which the scroll ends from the left
PLASMA_TEX_OFFSET equ 21*2*160 ;plasma texture: video offset. +160 bc it starts from right to left
PLASMA_TEX_WIDTH equ 160 ;plasma texture: pixels wide
PLASMA_TEX_HEIGHT equ 32 ;plasma texture: pixels height
PLASMA_OFFSET equ 22*2*160+0 ;plasma: video offset
PLASMA_WIDTH equ 20 ;plasma: pixels wide
PLASMA_HEIGHT equ 16 ;plasma: pixels height
RASTER_BAR_LOOP_FOR_EACH_COLOR equ 4 ;4 loops for each color before switching to the next one
LETTER_P_COLOR_IDX equ 1 ;color index for the letters
LETTER_V_COLOR_IDX equ 2
LETTER_M_COLOR_IDX equ 3
LETTER_BKG_COLOR_IDX equ 4
LETTER_BORDER_COLOR_IDX equ 5
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; render vertically 4 bits needed for the scroll. grabs the firts for bytes from the cache,
; use the MSB bit. If it is on, use white, else black color
;
; IN: ds:si -> bit to render (pointer to cache)
; dx -> pointer to pixel color table
; bp -> row index
; cl -> 0b1100_0000
; Args: %1: offset line.
%macro RENDER_BIT 1
mov di,SCROLL_OFFSET+160*%1+SCROLL_RIGHT_X ;es:di points to video memory
%rep 4
lodsb ;fetches byte from the cache
mov ah,al ;save value in ah for later use
and al,cl ;cl = 0b1100_0000
rol al,1
rol al,1
mov bx,dx
xlat ;al = [scroll_pixel_color_tbl+ al]
stosb
add di,8192-1 ;draw in next bank. di was incremented by
; one in stosb.
shl ah,1 ;al << 2. bit 7,6 contains next bits to render
shl ah,1 ;
mov bx,bp ;index by bp
mov [cache_charset+bx],ah ;update cache for next iteration
inc bp ;inc row index
%endrep
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; render horizontally 4 bytes (8 pixels)
; useful to render a char from a 1x1 charset
;
; IN:
; es:di -> where to render (ponter to video memory)
; bx -> offset of nibble to render
; ah -> must be 0
%macro RENDER_CHAR_ROW 0
mov al,byte [c64_charset+bx] ;first byte to print from charset. represents 8 pixels
mov dl,al ;save al
shr al,1 ;process hi nibble. shift 3 times to right
shr al,1 ; instead of shifting 4 times
shr al,1 ; and then one shift left (needed for table offset)
and al,0b0001_1110 ;turn off bit 0 in case it is one
mov si,text_writer_bitmap_to_video_tbl
add si,ax
movsw ;render MSB nibble (4 pixels, 2 bytes)
mov al,dl ;restore al, and process LSB nibble
and al,0b0000_1111
shl al,1 ;times 2. offset to table
mov si,text_writer_bitmap_to_video_tbl ;reset si
add si,ax ;offset to bytes
movsw ;render LSB nibble (4 pixels, 2 bytes)
inc bx ;get ready for next call
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; render horizontally 8 bytes (16 pixels)
; useful to render a blocky double char
;
; IN:
; es:di -> where to render (ponter to video memory)
; bx -> pattern for first char
; cx -> pattern for 2nd char
%macro RENDER_DOUBLE_ROW 0
mov ax,bx
stosw
stosw
mov ax,cx
stosw
stosw
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; renders a boy-walk/dance frame
;
; IN:
; ds:si -> source (frame data)
; es:di -> destination (video memory)
;
%macro RENDER_BOY_FRAME 0
sub al,al ;clean MSB bit from previous frame
mov cx,8192-5 ;increment value after each row
mov dx,24576-155 ;decrement value after 4 rows
stosb ;row 0
movsw
movsw
add di,cx ;row 1
stosb
movsw
movsw
add di,cx ;row 2
stosb
movsw
movsw
add di,cx ;row 3
stosb
movsw
movsw
sub di,dx ;row 4
stosb
movsw
movsw
add di,cx ;row 5
stosb
movsw
movsw
add di,cx ;row 6
stosb
movsw
movsw
add di,cx ;row 7
stosb
movsw
movsw
sub di,dx ;row 8
stosb
movsw
movsw
add di,cx ;row 9
stosb
movsw
movsw
add di,cx ;row 10
stosb
movsw
movsw
add di,cx ;row 11
stosb
movsw
movsw
sub di,dx ;row 12
stosb
movsw
movsw
add di,cx ;row 13
stosb
movsw
movsw
add di,cx ;row 14
stosb
movsw
movsw
add di,cx ;row 15
stosb
movsw
movsw
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; renders an empty boy-walk/dance frame
;
; IN:
; es:di -> destination (video memory)
;
%macro RENDER_BOY_FRAME_EMPTY 0
sub ax,ax ;clean MSB bit from previous frame
mov cx,8192-5 ;increment value after each row
mov dx,24576-155 ;decrement value after 4 rows
stosb ;row 0
stosw
stosw
add di,cx ;row 1
stosb
stosw
stosw
add di,cx ;row 2
stosb
stosw
stosw
add di,cx ;row 3
stosb
stosw
stosw
sub di,dx ;row 4
stosb
stosw
stosw
add di,cx ;row 5
stosb
stosw
stosw
add di,cx ;row 6
stosb
stosw
stosw
add di,cx ;row 7
stosb
stosw
stosw
sub di,dx ;row 8
stosb
stosw
stosw
add di,cx ;row 9
stosb
stosw
stosw
add di,cx ;row 10
stosb
stosw
stosw
add di,cx ;row 11
stosb
stosw
stosw
sub di,dx ;row 12
stosb
stosw
stosw
add di,cx ;row 13
stosb
stosw
stosw
add di,cx ;row 14
stosb
stosw
stosw
add di,cx ;row 15
stosb
stosw
stosw
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; refreshes the palette. used as a macro, and not function, since it is being
; called from time-critical sections
;
; IN:
; ds:si -> table with the palette to update
; cx -> number of colors to update times 2, since it does 2 colors per h-line
; bl -> starting color + 0x10. example: use 0x1f for white: 0x10 + 0xf
; dx -> VGA_ADDRESS
;
; Arg: 0 -> don't wait for horizontal retrace
; 1 -> wait fro horizontal retrace
%macro REFRESH_PALETTE 1
;%%repeat:
;
; mov al,bl ;color to update
; out dx,al ;dx=0x03da (register)
;
; lodsb ;load one color value in al
; mov ah,al ;move it ah
;
; mov al,ah
; out dx,al ;update color (data)
;
; inc bl ;next color
;
; sub al,al ;set reg 0 so display works again
; out dx,al ;(register)
;
;%if %1
; WAIT_HORIZONTAL_RETRACE ;reset to register again
;%else
; in al,dx ;reset to register again
;%endif
;
; loop %%repeat
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; inline vertical retrace
; IN:
; dx -> VGA_ADDRESS
%macro WAIT_VERTICAL_RETRACE 0
%%wait:
in al,dx ;wait for vertical retrace
test al,8 ; to finish
jnz %%wait
%%retrace:
in al,dx ;wait for vertical retrace
test al,8 ; to start
jz %%retrace
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; inline horizontal retrace
; IN:
; dx -> VGA_ADDRESS
%macro WAIT_HORIZONTAL_RETRACE 0
%%wait:
;FIXME PCJr
in al,dx ;wait for horizontal retrace
; ror al,1
; jc %%wait
;%%retrace:
; in al,dx ;wait for horizontal retrace
; ror al,1
; jnc %%retrace
%endmacro
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
;
; CODE
;
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
section .text
global intro_start
intro_start:
cld
mov ax,data ;init segments
mov ds,ax ;these values must always be true
mov ax,GFX_SEG ; through the whole intro.
mov es,ax ; push/pop otherwise
call intro_init
call irq_init
call main_loop
call sound_cleanup
call irq_cleanup
call fake_crash
call sound_cleanup
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; installs a timer IRQ that triggers at the correct horizontal scan line
; for the scroll
irq_init:
PIT_DIVIDER equ (262*76) ;262 lines * 76 PIT cycles each
; make it sync with vertical retrace
cli ;disable interrupts
mov bp,es ;save es
sub ax,ax
mov es,ax ;es = page 0
;Keyboard
; mov ax,new_i09
; mov dx,cs
; xchg ax,[es:9*4] ;new/old IRQ 9: offset
; xchg dx,[es:9*4+2] ;new/old IRQ 9: segment
; mov [old_i09],ax
; mov [old_i09+2],dx
;Vertical retrace
mov ax,new_i0d
mov dx,cs
xchg ax,[es:0x0d*4] ;new/old IRQ 0x0d: offset
xchg dx,[es:0x0d*4+2] ;new/old IRQ 0x0d: segment
mov [old_i0d],ax
mov [old_i0d+2],dx
;PIC
; mov ax,new_i08_simple
; mov dx,cs
; xchg ax,[es:8*4] ;new/old IRQ 8: offset
; xchg dx,[es:8*4+2] ;new/old IRQ 8: segment
; mov [old_i08],ax
; mov [old_i08+2],dx
mov es,bp ;restore es
; mov dx,VGA_ADDRESS
; WAIT_VERTICAL_RETRACE
;
; mov cx,194 ;and wait for scanlines
;.repeat:
; WAIT_HORIZONTAL_RETRACE ;inlining, so timing in real machine
; loop .repeat ; is closer to emulators
;
; mov bx,PIT_DIVIDER ;Configure the PIT to
; call setup_pit ;setup PIT
;
in al,0x21 ;Read primary PIC Interrupt Mask Register
mov [old_pic_imr],al ;Store it for later
; mov al,0b1001_1111 ;Mask off everything except IRQ 0 (timer)
and al,0b1101_1111 ;Mask off everything except IRQ 0 (timer)
out 0x21,al ;IRQ5 (vert retrace)
sti
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_new_i08_multi_color_init:
cli ;disable interrupts
; while setting the interrupt
; mov bp,es ;save es
; sub ax,ax
; mov es,ax
;
; mov ax,new_i08_bottom_multi_color
; mov dx,cs
; mov [es:8*4],ax ;new/old IRQ 8: offset
; mov [es:8*4+2],dx ;new/old IRQ 8: segment
;
; mov es,bp ;restore es
;
; mov dx,VGA_ADDRESS
; WAIT_VERTICAL_RETRACE
;
; mov cx,156 ;and wait for scanlines
;.repeat:
; WAIT_HORIZONTAL_RETRACE ;inlining, so timing in real machine
; loop .repeat ; is closer to emulators
;
; mov bx,PIT_DIVIDER ;Configure the PIT to
; call setup_pit ;setup PIT
sti
jmp main_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_new_i08_full_color_init:
cli ;disable interrupts
; while setting the interrupt
; mov bp,es ;save es
;
; sub ax,ax
; mov es,ax
;
; mov ax,new_i08_bottom_full_color
; mov dx,cs
; mov [es:8*4],ax ;new/old IRQ 8: offset
; mov [es:8*4+2],dx ;new/old IRQ 8: segment
;
; mov es,bp ;restore es
;
; mov dx,VGA_ADDRESS
; WAIT_VERTICAL_RETRACE
;
; mov cx,168 ;and wait for scanlines
;.repeat:
; WAIT_HORIZONTAL_RETRACE ;inlining, so timing in real machine
; loop .repeat ; is closer to emulators
;
; mov bx,PIT_DIVIDER ;Configure the PIT to
; call setup_pit ;setup PIT
sti
jmp main_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_signal_letter_state_sem_init:
mov byte [letter_state_semaphore],1
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
irq_cleanup:
cli ;disable interrupts
; mov al,[old_pic_imr] ;Get old PIC settings
; out 0x21,al ;Set primary PIC Interrupt Mask Register
mov bx,0 ;Reset PIT to defaults (~18.2 Hz)
call setup_pit ; actually means 0x10000
push ds
push es
xor ax,ax
mov ds,ax ;ds = page 0
mov cx,data
mov es,cx
; les si,[es:old_i08]
; mov [8*4],si
; mov [8*4+2],es ;Restore the old INT 08 vector (timer)
les si,[es:old_i0d]
mov [0x0d*4],si
mov [0x0d*4+2],es ;Restore the old INT 0x0d vector (vert. retrace)
; les si,[cs:old_i09]
; mov [9*4],si
; mov [9*4+2],es ;Restore the old INT 09 vector (keyboard)
pop es
pop ds
sti ;enable interrupts
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
setup_pit:
; IN bx = PIT clock period
; (Divider to 1193180 Hz)
mov al,0b0011_0100 ;0x34: channel 0, access mode lo/hi, rate generator, 16-bit binary
out 0x43,al ;command port
mov ax,bx
out 0x40,al ;data port for IRQ0: freq LSB
mov al,ah
nop ;some pause
nop
out 0x40,al ;data port for IRQ0: freq MSB
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
;waits until the beam is about to return to the top-left
;should be the one to call for the effects
global wait_vertical_retrace
wait_vertical_retrace:
mov dx,VGA_ADDRESS
WAIT_VERTICAL_RETRACE
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
global wait_horiz_retrace
wait_horiz_retrace:
mov dx,VGA_ADDRESS
WAIT_HORIZONTAL_RETRACE
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
fake_crash:
;uses 5 bit (31 values) LFSR maximal.
mov byte [fake_crash_lfsr_state],1 ;init LFSR state
.repeat:
call wait_vertical_retrace ;wait x 2 to create
call wait_vertical_retrace ; a better effect
call music_anim ;4x speed for music
call music_anim
call music_anim
call music_anim
call scroll_anim ;4x speed for scroll
call scroll_anim
call scroll_anim
call scroll_anim
call central_screen_anim ;text writer and/or boy walk
call central_screen_anim ;text writer and/or boy walk
call central_screen_anim ;text writer and/or boy walk
call central_screen_anim ;text writer and/or boy walk
call scroll_effect_anim ;plasma / rasterbar from scroll
call scroll_effect_anim ;plasma / rasterbar from scroll
call scroll_effect_anim ;plasma / rasterbar from scroll
call scroll_effect_anim ;plasma / rasterbar from scroll
mov al,[fake_crash_lfsr_state]
mov ah,al
shr al,1
jnc .skip
xor al,0b0001_0100 ;Taps 5 and 3 for maximal
.skip:
mov [fake_crash_lfsr_state],al
mov ah,al ;use bx as new crtc start address
and ax,0b0000_1010_1000_0000 ; but limit its range for more
mov [crtc_start_addr],ax ; pleasant visual effect
call crtc_addr_anim ; and update the start address
cmp byte [fake_crash_lfsr_state],1 ;lfsr cycle complete?
jne .repeat
.end:
ret:
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
intro_init:
sub al,al
mov byte [letter_state],al
mov byte [main_state],al
call [main_state_inits+0] ;init main state 0
call [letter_state_inits+0] ;init letter state 0
call music_init
call central_screen_init
call crtc_addr_init
call palette_colors_init
jmp scroll_init
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
main_loop:
.loop:
; cmp byte [tick],0 ;in theory, the tick is not needed
; je .loop ; since i'm not doing anything, but
; ; in practice, if not used, the interrupt could be triggered
; ; in the middle of the BIOS call, some intructions are longer than others,
; ; and it could generate some flicker in the raster bar routine
;
; mov byte [tick],0 ;mov ,0, instead of dec. since two inc could happen together
; if running on a slow machine. not a big issue, but ctrl+alt+del won't work
; and a switch on/off will be required (arggh.)
cli
mov cx,ds
sub ax,ax
mov ds,ax ;ds = zeor page
mov ax, [0x41a] ;keyboard buffer head
cmp ax, [0x41c] ;keyboard buffer tail
mov ds,cx
sti
jz .loop
; cmp byte [key_pressed],0 ;faster way to check keyboard than calling int 0x16
; jz .loop
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; IRQ
new_i09:
;own keyboard handler to make it faster to ready keys
mov ax,data
mov ds,ax
mov byte [key_pressed],1
iret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; IRQ
new_i0d:
new_i08_simple:
;not saving any variable, since the code at main loop
;happens after the tick
mov ax,data
mov ds,ax
;update top-screen palette
; mov si,top_palette ;points to colors used at the top of the screen
; mov cx,6 ;update 6 colors
; mov bl,0x10 ; starting with color 0 (black)
; mov dx,VGA_ADDRESS ;dx should be 0x03da
; REFRESH_PALETTE 1 ;refresh the palette, wait for horizontal retrace
; mov al,2 ;select border color register
; out dx,al ;(register)
; mov al,[border_color]
; out dx,al ;update border color (data)
jmp new_i08_main
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; IRQ
new_i08_bottom_multi_color:
;not saving any variable, since the code at main loop
;happens after the tick
; mov ax,data
; mov ds,ax
;update bottom-screen palette
mov dx,VGA_ADDRESS ;register address
mov si,bottom_palette+1 ;points to colors used at the bottom. skips black
mov cx,6 ;only update a few colors
mov bl,0x11 ; starting with color 1 (skip black)
REFRESH_PALETTE 1 ;refresh the palette, wait for horizontal retrace
;wait a few raster lines
;FIXME: could be used to place logic code.
mov dx,bp
mov cx,BOTTOM_TOP_LINES_TO_WAIT ;total number of raster bars
.l0:
lodsb ;fetch color
mov ah,al ; and save it for later
WAIT_HORIZONTAL_RETRACE
loop .l0 ;and do it 17 times
;update top-screen palette
mov si,top_palette+1 ;points to colors used at the top of the screen. skips black
mov cx,6 ;update a few colors
mov bl,0x11 ; starting with color 1 (skips black)
REFRESH_PALETTE 1 ;refresh the palette, wait for horizontal retrace
jmp new_i08_main
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; IRQ
new_i08_bottom_full_color:
;not saving any variable, since the code at main loop
;happens after the tick
; mov ax,data
; mov ds,ax
;update bottom-screen palette
mov dx,VGA_ADDRESS ;register address
mov si,bottom_palette+1 ;points to colors used at the bottom. skips black
mov cx,6 ;only update a few colors
mov bl,0x11 ; starting with color 1 (skip black)
REFRESH_PALETTE 1 ;refresh the palette, wait for horizontal retrace
mov si,raster_colors_tbl ;where the colors are for each raster bar
;BEGIN raster bar code
;should be done as fast as possible
%rep 17 ;FIXME: must be RASTER_COLORS_MAX
mov al,0x1f ;select palette color 15 (white)
out dx,al ;(register)
lodsb ;fetch color
mov ah,al ; and save it for later
mov al,ah
out dx,al ;set new color (data)
sub al,al ;set reg 0 so display works again
out dx,al ;(register)
WAIT_HORIZONTAL_RETRACE ;reset to register
%endrep
;END raster bar code
;update top-screen palette
mov si,top_palette+1 ;points to colors used at the top of the screen. skips black
mov cl,6 ;update a few colors
mov bl,0x11 ; starting with color 1. skips black
REFRESH_PALETTE 1 ;refresh the palette. don't wait for horizontal retrace
new_i08_main:
%if DEBUG
call inc_d020
%endif
;after raster baster finishes
;animate "main state machine"
sub bh,bh
mov bl,byte [main_state] ;fetch main state machine value
shl bx,1 ; and convert it into offset (2 bytes per offset)
call [main_state_callbacks+bx] ; and call correct state callback
;animate "letter state machine"
sub bh,bh
mov bl,byte [letter_state] ;fetch pvm-letters state machine value
shl bx,1 ; and convert it into offset (2 bytes per offset)
call [letter_state_callbacks+bx] ; and call correct state callback
; call crtc_addr_anim ;change CRTC start address
call music_anim ;play music
call central_screen_anim ;text writer and/or boy walk
call scroll_effect_anim ;plasma / rasterbar from scroll
call scroll_anim ;anim scroll
%if DEBUG
call dec_d020
%endif
inc byte [tick] ;tell main_loop that it could process
; whatever he wants
mov al,0x20 ;send the EOI signal
out 0x20,al ; to the IRQ controller
iret ;exit interrupt
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
sound_cleanup:
mov si,volume_0 ;volume to 0 data
mov cx,VOLUME_0_MAX
.repeat:
lodsb
out 0xc0,al ;set volume to 0
loop .repeat
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
main_state_next:
inc byte [main_state]
sub bh,bh
mov bl,byte [main_state]
shl bx,1
jmp [main_state_inits+bx]
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_next:
inc byte [letter_state]
sub bh,bh
mov bl,byte [letter_state]
shl bx,1
jmp [letter_state_inits+bx]
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
palette_colors_init:
mov byte [top_palette+0],1 ;black in blue
mov byte [bottom_palette+0],1 ;black is blue
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_fade_to_black_init:
mov word [palette_black_delay],15
mov word [palette_black_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_fade_to_black_anim:
dec word [palette_black_delay]
jz .animate
ret
.animate:
mov word [palette_black_delay],4 ;reset delay
mov bx,word [palette_black_idx] ;fetch idx to table
sub ah,ah ;MSB for the index. used later
mov cx,6 ;first six colors: 0-5
sub di,di ;di=index to colors (reverse of cx)
.loop:
mov al,[palette_black_tbl+bx] ;new color for the color
mov [top_palette+di],al ;update color in color table
inc di
loop .loop ; and loop
mov [bottom_palette+0],al ;update black for bottom part as well
mov [border_color],al
inc word [palette_black_idx]
cmp word [palette_black_idx],PALETTE_BLACK_MAX
je .next_state
ret
.next_state:
jmp main_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_500ms_init:
mov word [main_state_delay_frames],30 ;wait 30 cycles. half second
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_2s_init:
mov word [main_state_delay_frames],60*2 ;wait 2 seconds before showing logo
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_3s_init:
mov word [main_state_delay_frames],60*3 ;wait 3 seconds before showing logo
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_5s_init:
mov word [main_state_delay_frames],60*5 ;wait 5 seconds before showing logo
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_6s_init:
mov word [main_state_delay_frames],60*6 ;wait 6 seconds before showing logo
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_10s_init:
mov word [main_state_delay_frames],60*10 ;wait 5 seconds before showing logo
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_delay_anim:
dec word [main_state_delay_frames]
jz .next
ret
.next:
jmp main_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_gfx_fade_in_init:
mov word [clemente_lfsr_current_state],LFSR_START_STATE
; set default for colors 8-16
mov cx,10 ;update colors 10 colors
mov bl,0x10+6 ; starting with color 6
mov si,palette_default+6 ;points to colors used at the top of the screen
mov dx,VGA_ADDRESS ;dx should be 0x03da
REFRESH_PALETTE 0 ;refresh the palette, don't wait for horizontal retrace
;logo should be turned off by default
mov ax,0x0101 ;blue/blue color
mov word [top_palette+0],ax ;color idx 0,1 = blue
mov word [top_palette+2],ax ;color idx 2,3 = blue
mov word [top_palette+4],ax ;color idx 4,5 = blue
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; Uses Linear Feedback Shift Register 15-bit
; https://en.wikipedia.org/wiki/Linear-feedback_shift_register
state_gfx_fade_in_anim:
mov bp,ds ;save ds for later
mov ax,[clemente_lfsr_current_state]
mov bx,gfx ;set segments
mov ds,bx ;ds: gfx segment
;es: video memory (alread points to it)
mov cx,150 ;pixels to draw per frame
.loop:
mov di,ax
mov si,ax
mov dx,di
and dx,0x1800 ;don't write pixel if in scroll space
cmp dx,0x1800 ;areas: 1800-1fff,3800-3fff,5800-5fff,7800-7fff should not be written
je .skip_write
movsb ;update pixel
.skip_write:
shr ax,1
jnc .skip
xor ax,0110_0000_0000_0000b ;Taps 15,14 for maximum lenght
.skip:
cmp ax,LFSR_START_STATE
je .end
loop .loop
mov ds,bp ;restore ds
mov [clemente_lfsr_current_state],ax
ret
.end:
mov ds,bp ;restore ds
jmp main_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_nothing_init:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_nothing_anim:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_skip_anim:
jmp main_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_delay_200ms_init:
mov word [letter_state_delay_frames],60/5 ;wait 200ms
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_delay_2s_init:
mov word [letter_state_delay_frames],60*2 ;wait 2 seconds
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_delay_5s_init:
mov word [letter_state_delay_frames],60*5 ;wait 5 seconds
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_delay_10s_init:
mov word [letter_state_delay_frames],60*10 ;wait 10 seconds
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_delay_anim:
cmp word [letter_state_delay_frames],0
je .next
dec word [letter_state_delay_frames]
ret
.next:
jmp letter_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_out_p_init:
mov byte [letter_state_color_to_fade],LETTER_P_COLOR_IDX
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_out_v_init:
mov byte [letter_state_color_to_fade],LETTER_V_COLOR_IDX
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_out_m_init:
mov byte [letter_state_color_to_fade],LETTER_M_COLOR_IDX
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_out_letter_anim:
mov bl,[palette_letter_color_idx]
cmp bl,PALETTE_GRAYSCALE_OUT_MAX
je .next
sub bh,bh
mov al,[palette_grascale_out_tbl+bx] ;get color to be used
mov bl,[letter_state_color_to_fade] ;color index to fade
mov [top_palette+bx],al ;update letter color
inc byte [palette_letter_color_idx] ;next color to be used
ret
.next:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_in_p_init:
mov byte [letter_state_color_to_fade],LETTER_P_COLOR_IDX
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_in_v_init:
mov byte [letter_state_color_to_fade],LETTER_V_COLOR_IDX
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_in_m_init:
mov byte [letter_state_color_to_fade],LETTER_M_COLOR_IDX
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_to_pink_letter_anim:
mov bl,[palette_letter_color_idx]
cmp bl,PALETTE_BLACK_TO_PINK_MAX
je .next
sub bh,bh
mov al,[palette_black_to_pink_tbl+bx] ;get color to be used
mov bl,[letter_state_color_to_fade] ;color index to fade
mov [top_palette+bx],al ;update letter color
inc byte [palette_letter_color_idx] ;next color to be used
ret
.next:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_to_green_letter_anim:
mov bl,[palette_letter_color_idx]
cmp bl,PALETTE_BLACK_TO_GREEN_MAX
je .next
sub bh,bh
mov al,[palette_black_to_green_tbl+bx] ;get color to be used
mov bl,[letter_state_color_to_fade] ;color index to fade
mov [top_palette+bx],al ;update letter color
inc byte [palette_letter_color_idx] ;next color to be used
ret
.next:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_to_cyan_letter_anim:
mov bl,[palette_letter_color_idx]
cmp bl,PALETTE_BLACK_TO_CYAN_MAX
je .next
sub bh,bh
mov al,[palette_black_to_cyan_tbl+bx] ;get color to be used
mov bl,[letter_state_color_to_fade] ;color index to fade
mov [top_palette+bx],al ;update letter color
inc byte [palette_letter_color_idx] ;next color to be used
ret
.next:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_in_1_at_time_init:
mov byte [palette_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_fade_in_1_at_time_anim:
mov bl,byte [palette_idx]
cmp bl,PALETTE_PVM_LOGO_FADE_MAX
je .end
sub bh,bh
;letter P
mov al,[palette_pvm_logo_fade_tbl+bx] ;fetch color value
mov [top_palette+LETTER_P_COLOR_IDX],al ;update color index for P
;letter V
sub bx,8 ;offset -8
mov al,[palette_pvm_logo_fade_tbl+bx] ;fetch color value
mov [top_palette+LETTER_V_COLOR_IDX],al ;update color index for V
;letter M
sub bx,8 ;offset -8
mov al,[palette_pvm_logo_fade_tbl+bx] ;fetch color value
mov [top_palette+LETTER_M_COLOR_IDX],al ;update color index for M
inc byte [palette_idx] ;update palette offset
ret
.end:
jmp letter_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_fade_init:
mov byte [palette_letter_color_idx],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_fade_in_anim:
mov bl,byte [palette_letter_color_idx]
cmp bl,PALETTE_GRAYSCALE_IN_MAX
je .end
sub bh,bh
mov al,[palette_grayscale_in_tbl+bx] ;fetch color value
mov [top_palette+LETTER_BORDER_COLOR_IDX],al
inc byte [palette_letter_color_idx]
ret
.end:
jmp letter_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_fade_out_anim:
mov bl,byte [palette_letter_color_idx]
cmp bl,PALETTE_GRAYSCALE_OUT_MAX
je .end
sub bh,bh
mov al,[palette_grascale_out_tbl+bx] ;fetch color value
mov [top_palette+LETTER_BORDER_COLOR_IDX],al
inc byte [palette_letter_color_idx]
ret
.end:
jmp letter_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_fade_to_final_anim:
mov bl,byte [palette_letter_color_idx]
cmp bl,PALETTE_OUTLINE_FADE_TO_FINAL_MAX
je .end
sub bh,bh
mov al,[palette_outline_fade_to_final_tbl+bx] ;fetch color value
mov [top_palette+LETTER_BORDER_COLOR_IDX],al
inc byte [palette_letter_color_idx]
ret
.end:
jmp letter_state_next ;set next state and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_bkg_in_out_init:
mov byte [palette_letter_color_idx],0 ;reusing variable
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_bkg_in_out_anim:
mov bl,[palette_letter_color_idx]
cmp bl,PALETTE_BLACK_WHITE_BLACK_MAX
je .end
sub bh,bh
mov al,[palette_black_white_black_tbl+bx]
mov [top_palette+LETTER_BKG_COLOR_IDX],al
inc byte [palette_letter_color_idx]
ret
.end:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_wait_sem_init:
mov byte [letter_state_semaphore],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_wait_sem_anim:
cmp byte [letter_state_semaphore],0
jnz .next_state
ret
.next_state:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_restart_loop_init:
mov byte [letter_state],1
jmp [letter_state_inits+2] ;init entry 1 (skip the "sem wait" state)
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_restart_loop_anim:
ret ;nothing.
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_noise_5s_init:
mov byte [noise_fade_color_idx],0
mov word [letter_state_delay_frames],60*5 ;for 10 seconds
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_noise_10s_init:
mov byte [noise_fade_color_idx],0
mov word [letter_state_delay_frames],60*10 ;for 10 seconds
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
letter_state_outline_noise_anim:
dec word [letter_state_delay_frames]
jz .next_state
cmp byte [noise_triggered],0
je .skip
mov byte [noise_fade_color_idx],0 ;if triggered, reset anim
.skip:
cmp byte [noise_fade_color_idx],NOISE_FADE_COLORS_MAX ;end of anim?
je .exit
sub bh,bh
mov bl,[noise_fade_color_idx] ;bx with index to table
mov al,[noise_fade_colors_tbl+bx] ;fetch color
mov [top_palette+LETTER_BORDER_COLOR_IDX],al
inc byte [noise_fade_color_idx]
.exit:
ret
.next_state:
jmp letter_state_next
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
scroll_effect_anim:
cmp byte [scroll_effect_enabled],0
jz .exit
call plasma_anim
call plasma_effect_update
jmp raster_bars_anim
.exit:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
raster_bars_init:
mov byte [raster_colors_sine_idx],0
mov byte [raster_colors_loops_for_each_color],RASTER_BAR_LOOP_FOR_EACH_COLOR
mov word [raster_bars_colors_addr],raster_bars_colors_addr_start+RASTER_BARS_COLOR_MAX ;point to next color
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
raster_bars_anim:
mov bp,es ;save for later
sub bh,bh
mov ax,ds
mov es,ax ;ds:di -> dst
mov di,raster_colors_tbl
; table_offset = sine_tbl[sine_idx]
mov bl,[raster_colors_sine_idx] ;pointer to sine table
mov bl,[raster_colors_sine_tbl+bx] ;sine index for source colors
mov si,raster_colors_anim_tbl
add si,bx
mov cx,(RASTER_COLORS_MAX-1)/2 ;don't overwrite last color
;assert (cx == 8)
rep movsw
mov es,bp ;restore es
inc byte [raster_colors_sine_idx] ;0?
jnz .exit
dec byte [raster_colors_loops_for_each_color]
jz .change_color
.exit:
ret ;exit
.change_color:
mov byte [raster_colors_loops_for_each_color],RASTER_BAR_LOOP_FOR_EACH_COLOR
;change raster bar colors
mov bx,es
mov ax,ds
mov es,ax ;ds=es
mov si,[raster_bars_colors_addr] ;ds:si src
mov di,raster_colors_color_tbl ;es:di: dst
mov cx,RASTER_BARS_COLOR_MAX ;colors to copy
rep movsb
mov es,bx ;restore es
cmp si,raster_bars_colors_addr_end
jne .update_addr
mov si,raster_bars_colors_addr_start
.update_addr:
mov [raster_bars_colors_addr],si ;update position of next color bar
mov byte [plasma_effect_trigger],1 ;start effect transition
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
scroll_init:
mov byte [scroll_enabled],0 ;disabled by default
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
scroll_anim:
cmp byte [scroll_enabled],0
jne .anim
ret
.anim:
mov bp,ds ;save ds for later
mov ax,es ;ds and es point to video memory
mov ds,ax
mov dx,SCROLL_COLS_TO_SCROLL/2 ;div 2 since we use movsw instead of movsb
;scroll 16 rows in total
%assign XX 0
%rep 4
%assign YY 0
%rep 4
mov cx,dx ;scroll 4 lines of 80 chars
mov si,SCROLL_OFFSET+8192*XX+160*YY+SCROLL_LEFT_X+1 ;source: last char of screen
mov di,SCROLL_OFFSET+8192*XX+160*YY+SCROLL_LEFT_X ;dest: last char of screen - 1
rep movsw ;do the copy
%assign YY YY+1
%endrep
%assign XX XX+1
%endrep
mov ds,bp ;restore ds
;HACK: scroll_bit_idx & scroll_col_used are contiguos in memory
;using "word" to compare them
cmp word [scroll_bit_idx],0 ;if scroll_bit_idx == 0 and scroll_col_used == 0
jnz .render_bits ; and scroll_col_used == 0
.read_and_process_char:
;update the cache with the next 32 bytes (2x2 chars)
mov bx,[scroll_char_idx] ;scroll text offset
mov bl,byte [scroll_text+bx] ;char to print
test bl,0b1000_0000 ;control code?
jnz .control_code
and bl,0b0011_1111 ;only use lower 63 numbers
sub bh,bh
shl bx,1 ;bx * 8 since each char takes 8
shl bx,1 ; bytes in the charset
shl bx,1
lea si,[charset+bx] ;ds:si: charset
mov bp,es ;save es for later
mov ax,ds
mov es,ax ;es = ds
mov di,cache_charset ;es:di: cache
mov cx,4 ;copy first char (4 words == 8 bytes)
rep movsw
mov cl,4
add si,(128-1)*8 ;point to next char. offset=128
rep movsw
mov cl,4
sub si,(64+1)*8 ;point to next char. offset=64
rep movsw
mov cl,4
add si,(128-1)*8 ;point to next char. offset=192
rep movsw
mov es,bp ;restore es
;fall-through
.render_bits:
mov si,cache_charset ;ds:si points to cache_charset
sub bp,bp ;used for the cache index in the macros
mov dx,scroll_pixel_color_tbl ;table for colors used in the macros
mov cl,0b1100_0000 ;mask used in macros
RENDER_BIT 0
RENDER_BIT 1
RENDER_BIT 2
RENDER_BIT 3
add byte [scroll_bit_idx],2 ;two incs, since it prints 2 bits at the time
test byte [scroll_bit_idx],8 ;should use 2nd chars?
jz .end ;if not, exit
test byte [scroll_col_used],1 ;reached bit 8... already using
jnz .next_char ; col 2? If so, next char
;update cache with remaing 16-bytes (the 2nd col)
mov bp,es ;save es
mov ax,ds ;copy 2nd-col chars to cache
mov es,ax ;es = data
mov si,cache_charset+16 ;pointer to 2nd-col chars
mov di,cache_charset ;pointer to 1st-col chars
mov cx,8
rep movsw ;copy 16 bytes
mov es,bp ;restore es
inc byte [scroll_col_used] ;2nd column to be used
mov byte [scroll_bit_idx],cl ;0
ret
.control_code:
inc word [scroll_char_idx] ;consume control code. offset += 1
and bl,0b0111_1111 ;turn off bit 7
shl bl,1 ;al * 2, since each address takes 2 bytes
sub bh,bh
call [scroll_control_code_tbl+bx] ;FIXME: embarrasing. instead of call + ret + jmp
jmp .read_and_process_char ; two jmp's should be enough
.next_char:
sub ax,ax
mov byte [scroll_col_used],al ;reset to 0
mov byte [scroll_bit_idx],al ;reset bit idx
inc word [scroll_char_idx] ;scroll_char_idx++
cmp word [scroll_char_idx],SCROLL_TEXT_LEN ;end of scroll?
jnz .end ; if so, reset index
mov word [scroll_char_idx],ax ;reset to 0
.end:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
music_init:
in al,0x61 ;PCJr only:
or al,0b0110_0000 ; source for music is the SN76496
out 0x61,al
mov word [pvm_offset],pvm_song + 0x10 ;update start offset
sub al,al
mov byte [pvm_wait],al ;don't wait at start
mov byte [noise_triggered],al ;noise not playing
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
music_anim:
DATA equ 0b0000_0000
DATA_EXTRA equ 0b0010_0000
DELAY equ 0b0100_0000
DELAY_EXTRA equ 0b0110_0000
END equ 0b1000_0000
sub cx,cx ;cx=0... needed later
mov si,[pvm_offset]
cmp byte [pvm_wait],0
je .l0
dec byte [pvm_wait]
ret
.l0:
lodsb ;fetch command byte
mov ah,al
and al,0b1110_0000 ;al=command only
and ah,0b0001_1111 ;ah=command args only
cmp al,DATA ;data?
je .is_data
cmp al,DATA_EXTRA ;data extra?
je .is_data_extra
cmp al,DELAY ;delay?
je .is_delay
cmp al,DELAY_EXTRA ;delay extra?
je .is_delay_extra
cmp al,END ;end?
je .is_end
.unsupported:
int 3
mov [pvm_offset],si ;save offset
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
.is_data:
mov cl,ah ;ch is already zero
jmp .repeat
.is_data_extra:
lodsb ;fetch lenght from next byte
mov cl,al
.repeat:
lodsb
out 0xc0,al
mov byte [noise_triggered],0
and al,0b1111_0000 ;is noise?
cmp al,0b1110_0000
jne .not_noise
inc byte [noise_triggered] ;notify noise is playing
.not_noise:
loop .repeat
jmp .l0 ; repeat... fetch next command
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
.is_delay:
dec ah ;minus one, since we are returning
mov [pvm_wait],ah ; from here now
mov [pvm_offset],si
ret
.is_delay_extra:
lodsb ;fetch wait from next byte
dec al ;minus one, since we are returning
mov [pvm_wait],al ; from here now
mov [pvm_offset],si
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
.is_end:
mov byte [pvm_wait],5 ;wait 5 cycles before starting again
mov word [pvm_offset],pvm_song+0x10 ; beginning of song
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
central_screen_init:
mov byte [central_screen_state],CENTRAL_SCREEN_STATE_WAIT
call boy_walk_init ;init its two other states
jmp text_writer_init
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
central_screen_anim:
mov al,[central_screen_state]
or al,al ;0 == exit
jz .exit
shr al,1 ;1 == do boy_walk
jc .do_boy_walk
jmp text_writer_anim ;>2 == do text_writer
.do_boy_walk:
jmp boy_do_anim
.exit:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
boy_walk_init:
mov word [boy_anim_vid_addr],TEXT_WRITER_START_Y*2*160 ;hardcode writing position
sub al,al
mov byte [boy_anim_delay],50 ;some delay to get sync with letter noise anim
mov byte [boy_walk_frame_idx],al
mov byte [boy_walk_col_pos],al
mov byte [boy_anim_state],al
mov word [boy_dance_timeout],10*60 ;dance for 10 seconds
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
boy_do_anim:
mov al,[boy_anim_state]
or al,al
jz boy_walk_anim
shr al,1
jc boy_dance_anim
;fall through
mov di,[boy_anim_vid_addr] ;clear boy walk frame
RENDER_BOY_FRAME_EMPTY
mov byte [central_screen_state],CENTRAL_SCREEN_STATE_TEXT_WRITTER ;enable text writer
jmp text_writer_init ;init text writer
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
boy_walk_anim:
dec byte [boy_anim_delay]
jz .anim
ret
.anim:
mov byte [boy_anim_delay],5 ;reset delay
sub bh,bh
mov bl,[boy_walk_frame_idx]
shl bl,1 ;each address takes 2 bytes
mov si,[boy_walk_animation_tbl+bx] ;src: ds:si (frame data)
mov di,[boy_anim_vid_addr] ;dst: es:di (video memory)
RENDER_BOY_FRAME
inc word [boy_anim_vid_addr] ;move sprite 2 pixels to the right
inc byte [boy_walk_col_pos] ;next column
cmp byte [boy_walk_col_pos],70 ;half screen
je .enable_dance
cmp byte [boy_walk_col_pos],154 ;end of screen
je .enable_end_anim
inc byte [boy_walk_frame_idx] ;points to next frame
cmp byte [boy_walk_frame_idx],BOY_WALK_ANIM_FRAME_MAX
jne .exit
mov byte [boy_walk_frame_idx],0
.exit:
ret
.enable_dance:
mov byte [boy_anim_state],BOY_ANIM_STATE_DANCE
ret
.enable_end_anim:
mov byte [boy_anim_state],BOY_ANIM_STATE_END
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
boy_dance_anim:
dec word [boy_dance_timeout] ;only dance for 10 senconds
jz .end_dance
mov di,[boy_anim_vid_addr]
cmp byte [noise_triggered],0
jne .foot_up
.foot_down:
dec byte [boy_anim_delay] ;if 0, draw foot down
jnz .exit ; after drawing foot down, delay will be 255
; exactly what we wanted... to just fake a delay
; so that we don't draw the foot down during all the frames
mov si,boy_anim_frame_1 ;foot_down
jmp .render
.foot_up:
mov si,boy_anim_frame_0 ;foot up
mov byte [boy_anim_delay],3 ;three frames with foot up
;fall-through
.render:
RENDER_BOY_FRAME
.exit:
ret
.end_dance:
mov byte [boy_anim_delay],1 ;reset delay to min
mov byte [boy_anim_state],BOY_ANIM_STATE_WALK ;walk again...to right margin
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_init:
sub ax,ax
mov byte [text_writer_state],TW_STATE_PRINT_CHAR
mov word [text_writer_idx],-1 ;HACK: data offset is -1, because we do a +1 at anim
mov byte [text_writer_delay],10 ;waits 10 refreshes
mov byte [text_writer_cursor_blink_delay],al ;how many blinks to wait
mov byte [text_writer_x_pos],al ;at pos 0
mov byte [text_writer_x_dst],al ;dst pos 0
mov byte [text_writer_y_pos],TEXT_WRITER_START_Y
mov byte [text_writer_y_dst],TEXT_WRITER_START_Y
mov word [text_writer_addr],TEXT_WRITER_START_Y*2*160+160 ;half line ahead
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_anim:
sub bh,bh ;fetch state
mov bl,[text_writer_state] ; and get state address from
shl bl,1 ; table, and call it
jmp [text_writer_callbacks_anim+bx] ; and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_print_char_init:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_print_char_anim:
mov bx,word [text_writer_idx] ;data offset
inc bx ;data offset += 1
cmp bx,TEXT_WRITER_DATA_LEN ;end of line?
jne .l0
mov byte [central_screen_state],CENTRAL_SCREEN_STATE_BOY_ANIM ;switch to walk state
jmp boy_walk_init ; and init it
.l0:
mov word [text_writer_idx],bx ;save offset
mov al,byte [text_writer_data+bx] ;get char to print or state
cmp al,TW_STATE_MAX ;is it a char, or a new state?
jb .new_state
call text_writer_print_char ;print the char
inc byte [text_writer_x_pos] ;cursor pos += 1
add word [text_writer_addr],4 ;video address +4 (each char takes 4 bytes)
mov al,0x77 ;select "reverse" space (all gray char)
call text_writer_fill_one_char ; and print it
mov byte [text_writer_delay],2 ;cycles to wait
mov byte [text_writer_state],TW_STATE_IDLE ;after writing a char, switch to
; delay state to make the writing slower
ret
.new_state:
mov byte [text_writer_state],al ;store new state
sub bh,bh ;move it to bx so we can use it
mov bl,al ; as index
shl bl,1 ;bx *= 2 since each addr takes 2 bytes
jmp [text_writer_callbacks_init+bx] ;call init callback and return
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_idle_init:
inc word [text_writer_idx] ;offset += 1
mov bx,[text_writer_idx] ;get current data offset
mov al,[text_writer_data+bx] ;fetch value value using offset
mov [text_writer_delay],al ;move it to delay
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_idle_anim:
dec byte [text_writer_delay]
jz .end_delay
ret
.end_delay:
mov byte [text_writer_state],TW_STATE_PRINT_CHAR ;print char is next state
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_goto_x_init:
inc word [text_writer_idx] ;data offset += 1
mov bx,word [text_writer_idx] ;get data offset
mov al,byte [text_writer_data+bx] ;pos to go back to
mov byte [text_writer_x_dst],al ;update destination
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_goto_x_anim:
mov al,byte [text_writer_x_dst] ;fetch destination pos
cmp byte [text_writer_x_pos],al ; and compare with current pos
jb .right
ja .left
mov byte [text_writer_state],TW_STATE_PRINT_CHAR ;if equal, means finished
ret ; then change state to read chars again
.right:
mov ax,0x0077 ;ah=black/black, al=gray/gray
call text_writer_fill_two_chars
inc byte [text_writer_x_pos] ;cursor += 1. destintation is to the right
add word [text_writer_addr],4 ;video addr += 4 (each char takes 4 bytes)
ret
.left:
dec byte [text_writer_x_pos] ;cursor -= 1. destintation is to the left
sub word [text_writer_addr],4 ;video addr -= 4 (each char takes 4 bytes)
mov ax,0x7700 ;ah=gray/gray, black/black
jmp text_writer_fill_two_chars
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_goto_y_init:
inc word [text_writer_idx] ;data offset += 1
mov bx,word [text_writer_idx] ;get data offset
mov al,byte [text_writer_data+bx] ;pos to go back to
mov byte [text_writer_y_dst],al ;update destination
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_goto_y_anim:
mov al,byte [text_writer_y_dst] ;fetch destination pos
cmp byte [text_writer_y_pos],al ; and compare with current pos
jb .down
ja .up
mov byte [text_writer_state],TW_STATE_PRINT_CHAR ;if equal, means finished
ret ; then change state to read chars again
.down:
sub al,al ;char to write: empty
call text_writer_fill_one_char
inc byte [text_writer_y_pos] ;cursor.y += 1 (going down)
add word [text_writer_addr],320 ;video addr += 320
mov al,0x77 ;char to write: full
jmp text_writer_fill_one_char
.up:
sub al,al ;char to write: empty
call text_writer_fill_one_char
dec byte [text_writer_y_pos] ;cursor.y -= 1. (going up)
sub word [text_writer_addr],320 ;video addr -= 320
mov al,0x77 ;char to write: full
jmp text_writer_fill_one_char
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_call_action_init:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; fetch the next byte from the stream, and use it as an
; index to the action_call table, and call that action function
text_writer_state_call_action_anim:
inc word [text_writer_idx] ;offset + 1
mov bx,word [text_writer_idx] ;fetch next char
mov al,[text_writer_data+bx] ; which is the action to perform
;al == 0 -> turn off cursor
.do_cursor_off:
mov byte [text_writer_state],TW_STATE_PRINT_CHAR ;print char is next state
sub al,al ;char to write: empty
jmp text_writer_fill_one_char
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_cursor_blink_init:
inc word [text_writer_idx] ;offset += 1
mov bx,[text_writer_idx] ;get current data offset
mov al,[text_writer_data+bx] ;fetch value value using offset
mov [text_writer_cursor_blink_delay],al ;move it to blinks-to-wait
mov byte [text_writer_delay],30 ;delay blink lasts 30 cycles
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
text_writer_state_cursor_blink_anim:
dec byte [text_writer_delay]
jz .next_blink
cmp byte [text_writer_delay],15 ;half cycles
je .cursor_off
ret
.next_blink:
dec byte [text_writer_cursor_blink_delay]
jz .end_blink_state
mov byte [text_writer_delay],30 ;init blink delay
mov al,0x77 ;select all gray char
jmp text_writer_fill_one_char ; print it, and return
.cursor_off:
sub al,al ;select all black char
jmp text_writer_fill_one_char ; print it, and return
.end_blink_state:
mov byte [text_writer_state],TW_STATE_PRINT_CHAR ;print char is next state
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
crtc_addr_init:
mov word [crtc_start_addr],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
crtc_addr_anim:
;FIXME PCJr.
mov bx,[crtc_start_addr]
mov dx,0x03d4
mov al,0x0c ;select CRTC start address hi
out dx,al
inc dx ;set value for CRTC hi address
mov al,bh
out dx,al
dec dx
mov al,0x0d
out dx,al ;select CRTC start address lo
inc dx
mov al,bl
out dx,al ;set value for CRTC lo address
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_enable_boy_walk:
mov byte [central_screen_state],CENTRAL_SCREEN_STATE_BOY_ANIM
jmp boy_walk_init
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_enable_text_writer:
mov byte [central_screen_state],CENTRAL_SCREEN_STATE_TEXT_WRITTER
jmp text_writer_init
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_enable_scroll:
mov byte [scroll_enabled],1 ;start the scroll
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_enable_scroll_effects:
inc byte [scroll_effect_enabled] ;enable effects
call raster_bars_init
jmp plasma_init
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_clear_bottom_init:
mov byte [clear_bottom_state],0
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_clear_bottom_anim:
;clear the bottom part with black pixels
;previously it was filled with the plasma pixels
;do it in two parts since there is not enough CPU power to do it in
;just one pass
sub ax,ax ;black * 4
cmp byte [clear_bottom_state],0
jne .second_half
.first_half:
mov cx,640 ;8 rows
mov di,BOTTOM_OFFSET+8192*0 ;destination
rep stosw ;do the 'clean screen'
mov cx,640 ;8 rows
mov di,BOTTOM_OFFSET+8192*1 ;destination
rep stosw ;do the 'clean screen'
inc byte [clear_bottom_state] ;ready for next half
ret
.second_half:
mov cx,640 ;8 rows
mov di,BOTTOM_OFFSET+8192*2 ;destination
rep stosw ;do the 'clean screen'
mov cx,640 ;8 rows
mov di,BOTTOM_OFFSET+8192*3 ;destination
rep stosw ;do the 'clean screen'
jmp main_state_next ;finish and set next state
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
plasma_tex_init_sine_table:
mov ax,ds
mov es,ax ;es = ds
; x
mov dh,[plasma_tex_inc_x0]
mov dl,[plasma_tex_inc_x1]
;HACK: works because fn_table_1 and
;fn_table_2 are 256-aligned
mov bx,fn_table_1
mov si,fn_table_2
mov cx,si
mov di,plasma_tex_xbuf ;es:di -> dst
%assign XX 0
%rep PLASMA_TEX_WIDTH
mov al,[bx] ;xbuf[idx] = sine[bx]+sine[si]
add al,[si]
stosb
add bl,dh ;dh=5. update offsets to sine tables
add cl,dl ;cx=8
mov si,cx
%assign XX XX+1
%endrep
; y
mov dh,[plasma_tex_inc_y0]
mov dl,[plasma_tex_inc_y1]
;HACK: works because fn_table_1 and
;fn_table_2 are 256-aligned
mov bx,fn_table_1
mov si,fn_table_2
mov cx,si
mov di,plasma_tex_ybuf ;es:di -> dst
%assign YY 0
%rep PLASMA_TEX_HEIGHT
mov al,[bx] ;ybuf[idx] = sine[bx]+sine[si]
add al,[si]
stosb
add bl,dh ;dh=3
add cl,dl ;cx=5
mov si,cx
%assign YY YY+1
%endrep
mov dx,GFX_SEG
mov es,dx ;restore es
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_plasma_red_tex_init:
sub ax,ax ;faster to use register than value
mov word [plasma_tex_x_offset],ax
mov byte [plasma_tex_state],al ;initial state
mov byte [plasma_tex_colors_updated],al
mov byte [plasma_tex_delay],1
mov word [plasma_tex_palette_addr],plasma_tex_red_palette
mov byte [plasma_tex_letter_color],LETTER_P_COLOR_IDX ;letter P color idx
mov byte [plasma_tex_inc_x0],250 ;texture generator parameters
mov byte [plasma_tex_inc_x1],255
mov byte [plasma_tex_inc_y0],127
mov byte [plasma_tex_inc_y1],129
mov bx,es ;save es in bx for later
mov ax,ds
mov es,ax ;es is data segment
mov cx,8 ;repeat it 8 times
sub ax,ax ;ax=0
mov di,bottom_palette ;es:di -> bottom palette
rep stosw ;bottom palette is all black
mov es,bx ;restore es. es=GFX_SEG
jmp plasma_tex_init_sine_table
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_plasma_green_tex_init:
sub ax,ax ;faster to use register than value
mov word [plasma_tex_x_offset],ax
mov byte [plasma_tex_state],al ;initial state
mov byte [plasma_tex_colors_updated],al
mov byte [plasma_tex_delay],1
mov word [plasma_tex_palette_addr],plasma_tex_green_palette
mov byte [plasma_tex_letter_color],LETTER_V_COLOR_IDX ;letter V color idx
mov byte [plasma_tex_inc_x0],4 ;texture generator parameters
mov byte [plasma_tex_inc_x1],7
mov byte [plasma_tex_inc_y0],129
mov byte [plasma_tex_inc_y1],3
mov bx,es ;save es in bx for later
mov ax,ds
mov es,ax ;es is data segment
mov cx,8 ;repeat it 8 times
sub ax,ax ;ax=0
mov di,bottom_palette ;es:di -> bottom palette
rep stosw ;bottom palette is all black
mov es,bx ;restore es. es=GFX_SEG
jmp plasma_tex_init_sine_table
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_plasma_magenta_tex_init:
sub ax,ax ;faster to use register than value
mov word [plasma_tex_x_offset],ax
mov byte [plasma_tex_state],al ;initial state
mov byte [plasma_tex_colors_updated],al
mov byte [plasma_tex_delay],1
mov word [plasma_tex_palette_addr],plasma_tex_magenta_palette
mov byte [plasma_tex_letter_color],LETTER_M_COLOR_IDX ;letter M color idx
mov byte [plasma_tex_inc_x0],4 ;texture generator parameters
mov byte [plasma_tex_inc_x1],3
mov byte [plasma_tex_inc_y0],127
mov byte [plasma_tex_inc_y1],132
mov bx,es ;save es in bx for later
mov ax,ds
mov es,ax ;es is data segment
mov cx,8 ;repeat it 8 times
sub ax,ax ;ax=0
mov di,bottom_palette ;es:di -> bottom palette
rep stosw ;bottom palette is all black
mov es,bx ;restore es. es=GFX_SEG
jmp plasma_tex_init_sine_table
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
state_plasma_tex_anim:
;has 3 states:
;0 = render texture
;1 = texture fade in
;2 = texture fade out
cmp byte [plasma_tex_state],0
je .render_texture
cmp byte [plasma_tex_state],1
je .palette_fade_in
.palette_fade_out:
;shift right the palette colors one by one
;until all all black
cmp byte [plasma_tex_colors_updated],0
je .next_state
dec byte [plasma_tex_delay]
jz .do_out
ret
.do_out:
mov byte [plasma_tex_delay],4 ;reset delay
mov bx,es ;save it for later
mov ax,ds
mov es,ax
sub ch,ch
mov cl,[plasma_tex_colors_updated] ;numbers of colors to copy
dec cl ; minus one, since previous state left it +1
std ;copy backwards
mov si,bottom_palette+1
mov si,bottom_palette+1+PLASMA_TEX_PALETTE_MAX-2 ;last element -1
mov di,bottom_palette+1+PLASMA_TEX_PALETTE_MAX-1 ;last element
rep movsb
mov byte [di],0 ;fill the first element with black, since
; we are fading to black
cld ;restore direction flag
dec byte [plasma_tex_colors_updated];number of colors updated -= 1
mov es,bx ;restore es
mov al,[bottom_palette+1+PLASMA_TEX_PALETTE_MAX-1] ;color value
sub bh,bh
mov bl,[plasma_tex_letter_color] ;color to update
mov [top_palette+bx],al ;update color with value
ret
.next_state:
jmp main_state_next
.palette_fade_in:
;shift left the colors one by one
;until all of them are in the final position
cmp byte [plasma_tex_colors_updated],PLASMA_TEX_PALETTE_MAX
je .next_internal_state
dec byte [plasma_tex_delay] ;end of wait?
jz .do_in ; if so, jump to the effect
ret
.do_in:
mov byte [plasma_tex_delay],4 ;reset delay
mov bx,es ;save it for later
mov ax,ds
mov es,ax
sub ch,ch
mov cl,[plasma_tex_colors_updated] ;number colors to copy
inc cl ;plus 1 (when 0, copy 1 color)
mov di,bottom_palette+1 ;skip color black
mov si,[plasma_tex_palette_addr] ;fetch plasma palette to use
add si,PLASMA_TEX_PALETTE_MAX ; and make it point to the end
sub si,cx ; minus the colors already copied
rep movsb
inc byte [plasma_tex_colors_updated];number of colors updated +=1
mov es,bx
mov al,[bottom_palette+1] ;color value
sub bh,bh ;MSB bx = 0
mov bl,[plasma_tex_letter_color] ;color to update
mov [top_palette+bx],al ;update color with value
ret
.next_internal_state:
mov byte [plasma_tex_delay],4 ;delay before starting next state
inc byte [plasma_tex_state] ;set next state
ret
.render_texture:
mov cx,5
.anim:
push cx
call plasma_tex_render_to_video
pop cx
loop .anim
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
plasma_tex_render_to_video:
mov bx,luminances_6_colors ;to be used by xlat. has the colors for the plasma
mov si,[plasma_tex_x_offset] ;to be used for the plasma_tex_xbuff offset
mov di,si
not di ;going from right to left
%assign YY 0
%rep PLASMA_TEX_HEIGHT
mov al,[plasma_tex_xbuf+si] ;fetch plasma X buffer
add al,[plasma_tex_ybuf+YY] ; and add it to plasma Y buffer
xlat ; and get the color value from luminances_tble
mov [es:PLASMA_TEX_OFFSET+(YY/4)*160+(YY % 4)*8192+di],al
%assign YY YY+1
%endrep
cmp word [plasma_tex_x_offset],159 ;rendered 159 lines (whole width)?
je .next_internal_state ; if so, trigger next state
inc word [plasma_tex_x_offset] ;offset_x++. render in next column next time
ret
.next_internal_state:
inc byte [plasma_tex_state] ;trigger next internal state
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
scroll_control_code_color_red:
mov al,[scroll_pixel_red_tbl+1] ;skip first byte. it is black in all conf
mov bx,[scroll_pixel_red_tbl+2]
mov [scroll_pixel_color_tbl+1],al
mov [scroll_pixel_color_tbl+2],bx
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
scroll_control_code_color_yellow:
mov al,[scroll_pixel_yellow_tbl+1] ;skip first byte. it is black in all conf
mov bx,[scroll_pixel_yellow_tbl+2]
mov [scroll_pixel_color_tbl+1],al
mov [scroll_pixel_color_tbl+2],bx
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
scroll_control_code_color_anim:
mov al,[scroll_pixel_anim_tbl+1] ;skip first byte. it is black in all conf
mov bx,[scroll_pixel_anim_tbl+2]
mov [scroll_pixel_color_tbl+1],al
mov [scroll_pixel_color_tbl+2],bx
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
plasma_init:
mov bp,es ;save es for later
mov ax,ds
mov es,ax ;es=ds
sub al,al ;black color
mov cx,PLASMA_TEX_PALETTE_MAX ;set bottom palette to black
mov di,bottom_palette+1 ;destination: bottom palette, skipping black
rep stosb ;copy the new palette
mov es,bp ;restore es
mov byte [plasma_effect_transition_state],0
mov byte [plasma_effect_idx],0
mov byte [plasma_effect_trigger],1 ;trigger effect
mov byte [plasma_effect_delay],3 ;delay
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; updates the plasma effect
plasma_effect_update:
cmp byte [plasma_effect_trigger],0
jnz .do
ret
.do:
dec byte [plasma_effect_delay]
jz .do_effect
ret
.do_effect:
mov byte [plasma_effect_delay],3
sub bh,bh
mov bl,[plasma_effect_transition_state]
inc byte [plasma_effect_transition_state]
cmp bl,13
je .finish_transition
cmp bl,6
jb .fade_out
je .change_plasma_effect
;fall through
.fade_in: ;called with bl 7-12
sub bh,bh
sub bl,7 ;re-range to 0-5
mov dl,5 ;re-range to 5-0
sub dl,bl ;inverse it. fetch last color first
mov bp,es
mov ax,ds
mov es,ax
mov cx,5
mov si,bottom_palette+1+4 ;shift colors to the left
mov di,bottom_palette+1+5 ;after 6 iterations all colors should be in
std
rep movsb ; their final position
cld
mov es,bp ;restore bp
mov bl,[plasma_effect_idx] ;fetch plasma effect index
shl bl,1 ;*2, since each entry takes 2 bytes
mov si,[plasma_palettes_tbl+bx] ;pointer to palette to be used
mov bl,dl ;color to be used
mov al,[si+bx]
mov [bottom_palette+1+0],al ;move it for 1st position
;and rotate colors to the right
ret
.fade_out: ;called with bl 0-5
mov bp,es
mov ax,ds
mov es,ax
mov cx,5
mov si,bottom_palette+1+1 ;shift colors to the left (black is color idx 5)
mov di,bottom_palette+1+0 ;after 6 iterations, everything will be black
rep movsb
mov es,bp ;restore bp
ret
.change_plasma_effect: ;called with bl==6
sub bh,bh
mov bl,[plasma_effect_idx] ;fetch plasma effect index
shl bl,1 ;*2, since each entry takes 2 bytes
mov ax,[plasma_inc_x0_x1_tbl+bx] ;update plasma inc x0 x0
mov [plasma_inc_x0_x1],ax
mov ax,[plasma_inc_y0_y1_tbl+bx] ;update plasma inc y0 y1
mov [plasma_inc_y0_y1],ax
mov ax,[plasma_off_x0_x1_inc_tbl+bx] ;update plasma offset inc x0 x1
mov [plasma_off_x0_x1_inc],ax
mov ax,[plasma_off_y0_y1_inc_tbl+bx] ;update plasma offset inc y0 y1
mov [plasma_off_y0_y1_inc],ax
ret
.finish_transition: ;called with bl=13
sub al,al
mov [plasma_effect_trigger],al ;disable the "trigger effect" condition
mov [plasma_effect_transition_state],al ;reset state for next transition
inc byte [plasma_effect_idx]
cmp byte [plasma_effect_idx],PLASMA_EFFECT_MAX
jne .exit
mov byte [plasma_effect_idx],al
.exit:
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
plasma_anim:
ror byte [plasma_anim_state],1 ;plasma at 30FPS:
jc .generate_tables ; on frame it generates the tables
jmp .render_plasma ; on the other frame renders the plasma
.generate_tables:
;
;update xbuf and ybuf tables
;
mov ax,ds
mov es,ax ;es = ds
; x
mov ax,word [plasma_off_x0_x1] ;fetches both xbuf_1 and xbuf_2
mov bp,ax ;save ax for later
mov dx,[plasma_inc_x0_x1] ;inc x0 / x1 values
;HACK: works because fn_table_1 and
;fn_table_2 are 256-aligned
mov bx,fn_table_1
add bl,al
mov cx,fn_table_2
add cl,ah
mov si,cx
mov di,plasma_xbuf ;es:di -> dst
%assign XX 0
%rep PLASMA_WIDTH
mov al,[bx] ;xbuf[idx] = sine[bx]+sine[si]
add al,[si]
stosb ;update plasma xbuf
add bl,dl ;update offsets to sine tables
add cl,dh
mov si,cx
%assign XX XX+1
%endrep
add bp,[plasma_off_x0_x1_inc] ;update offset x0/x1
mov word [plasma_off_x0_x1],bp ; and save it for next iteration
; y
mov ax,word [plasma_off_y0_y1] ;fetches both ybuf_1 and ybuf_2
mov bp,ax ;save ax for later
mov dx,[plasma_inc_y0_y1] ;inc y0 / y1 values
;HACK: works because fn_table_1 and
;fn_table_2 are 256-aligned
mov bx,fn_table_1
add bl,al
mov cx,fn_table_2
add cl,ah
mov si,cx
mov di,plasma_ybuf ;es:di -> dst
%assign YY 0
%rep PLASMA_HEIGHT
mov al,[bx] ;ybuff[YY] = sine[bx]+sine[si]
add al,[si]
stosb ;update plasma ybuf
add bl,dl
add cl,dh
mov si,cx
%assign YY YY+1
%endrep
add bp,[plasma_off_y0_y1_inc] ;update offset y0/y1
mov word [plasma_off_y0_y1],bp ; and save it for next iteration
mov ax,GFX_SEG
mov es,ax ;restore es
ret
.render_plasma:
;
;render plasma
;
mov bx,luminances_6_colors ;to be used by xlat. has the colors for the plasma
mov di,plasma_ybuf ;di -> pointer to plasma_ybuf
mov cx,plasma_xbuf ;dx -> pointer to plasma_xbuf
%assign YY 0
%rep PLASMA_HEIGHT
mov ah,[di] ;fetch y buf value. to be used inside loop x
mov si,cx ;reset xbuf pointer before starting loop x
%assign XX 0
%rep PLASMA_WIDTH
lodsb ;fetch plasma X buffer
add al,ah ; and add both plasma buf x and y
xlat ; and get the color value from luminances_tble
mov [es:PLASMA_OFFSET+(YY/4)*160+(YY % 4)*8192+XX],al ;left-to-right
mov [es:PLASMA_OFFSET+(YY/4)*160+(YY % 4)*8192+159-XX],al ;mirror: right-to-left
%assign XX XX+1
%endrep
inc di ;inc Y ref
%assign YY YY+1
%endrep
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; IN: al=char to print
; ASSUMES: es: pointer to video segment
; ds: pointer to charset segment
text_writer_print_char:
sub ah,ah
mov bx,ax ;bx = ax (char to print)
shl bx,1
shl bx,1
shl bx,1 ;bx*8 since each char takes 8 bytes
mov bp,8192-4 ;faster to operate with registers
mov di,[text_writer_addr] ;video destination address
RENDER_CHAR_ROW ;1st row
add di,bp
RENDER_CHAR_ROW ;2nd row
add di,bp
RENDER_CHAR_ROW ;3rd row
add di,bp
RENDER_CHAR_ROW ;4th row
sub di,24576-156 ;160-4
RENDER_CHAR_ROW ;5th row
add di,bp
RENDER_CHAR_ROW ;6th row
add di,bp
RENDER_CHAR_ROW ;7th row
add di,bp
RENDER_CHAR_ROW ;8th row
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; Since text_writer_print_char is somewhat slow, this function renders two
; blocky chars (based) on the pattern passed. More efficient than calling
; text_writer_print_char twice, once with an empty char, and one with a full
; char
;
; IN: ah=pattern (color) to be used for left char
; al=pattern (color) to be used for right char
; ASSUMES: es: pointer to video segment
text_writer_fill_two_chars:
mov bl,ah ;save for later
mov bh,bl ;bx = second char pattern
mov cl,al
mov ch,cl ;cx = first char pattern
mov bp,8192-8 ;faster to do operations with registers
mov di,[text_writer_addr]
RENDER_DOUBLE_ROW ;1st row
add di,bp
RENDER_DOUBLE_ROW ;2nd row
add di,bp
RENDER_DOUBLE_ROW ;3rd row
add di,bp
RENDER_DOUBLE_ROW ;4th row
sub di,24576-152 ;160-8
RENDER_DOUBLE_ROW ;5th row
add di,bp
RENDER_DOUBLE_ROW ;6th row
add di,bp
RENDER_DOUBLE_ROW ;7th row
add di,bp
RENDER_DOUBLE_ROW ;8th row
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; Since text_writer_print_char is somewhat slow, this function renders one
; blocky chars (based) on the pattern passed.
;
; IN: al=pattern (color) to be used for the char
; ASSUMES: es: pointer to video segment
text_writer_fill_one_char:
mov ah,al ;ax has color info for 4 pixels
mov cx,8192-4 ;faster to add from reg, than immediate
mov di,[text_writer_addr]
stosw ;1st row
stosw
add di,cx
stosw ;2nd row
stosw
add di,cx
stosw ;3rd row
stosw
add di,cx
stosw ;4th row
stosw
sub di,24576-156 ;160-4
stosw ;5th row
stosw
add di,cx
stosw ;6th row
stosw
add di,cx
stosw ;7th row
stosw
add di,cx
stosw ;8th row
stosw
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
inc_d020:
mov dx,VGA_ADDRESS ;show how many raster barts it consumes
mov al,2 ;select border color
out dx,al ;(register)
mov al,0x0f
out dx,al ;change border to white (data)
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
dec_d020:
mov dx,VGA_ADDRESS ;show how many raster barts it consumes
mov al,2 ;select border color
out dx,al ;(register)
sub al,al
out dx,al ;change border back to black (data)
ret
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
;
; DATA GFX
;
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
section .gfx data
incbin 'src/logo.raw' ;MUST be the first variable in the segment
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
;
; DATA MUSIC + CHARSET + MISC
;
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
section .data data
pvm_song:
incbin "src/uctumi-song.pvm"
pvm_wait: ;cycles to read divided 0x2df
db 0
pvm_offset: ;pointer to next byte to read
dw 0
noise_triggered:
db 0 ;boolen. whether noise is playing
noise_fade_color_idx: ;offset in color table
db 0
noise_fade_colors_tbl:
db 8,7,11,8,1,0
NOISE_FADE_COLORS_MAX equ $-noise_fade_colors_tbl
LFSR_START_STATE equ 1973 ;lfsr start state
clemente_lfsr_current_state dw 0 ;lfsr current state
fake_crash_lfsr_state: db 0 ;lfsr for crash
palette_black_delay:
dw 0
palette_black_idx:
dw 0
palette_black_tbl: ;fade to white/fade to black colors
db 9,11,3,7,8,0
PALETTE_BLACK_MAX equ $-palette_black_tbl
global c64_charset
c64_charset:
incbin 'src/c64_charset-charset.bin'
charset:
incbin 'src/font_unknown_2x2-charset.bin'
scroll_control_code_tbl:
dw scroll_control_code_color_red
dw scroll_control_code_color_anim
dw scroll_control_code_color_yellow
; # = tm
; % = closing double quotes
; $ = smiley
; ; = ~ (kind of separator)
; < = heart
; bit 7=on (128) - control code
; 128 = color red
; 129 = color with raster bar
; 130 = color yellow
scroll_text:
; db 128 ;color white
; db 'HI THERE. '
; db 129,'PUNGAS DE '
; db 129,'VILLA '
; db 129,'M'
; db 128,'ARTELLI HERE, WITH OUR FIRST TANDY RELEASE. '
db 129 ;color with raster bar
db 'IT ALL BEGAN WHEN WE WENT TO PICK UP A COMMODORE 64 BUNDLE '
db 'AND THE SELLER INCLUDED TWO TANDY 1000 HX IN IT. '
db 'WTF IS A TANDY 1000 HX? WE GOOGLED IT, AND WE LIKED IT. '
db `HEY, IT HAS AN 8088 (THAT CPU FROM 1979), SOME NON-`
db 'STANDARD VIDEO MODES, A BETTER-THAN-SPEAKER SOUNDCARD, AND JOYSTICK PORTS '
db '(UNIJOYSTICLE COMING SOON#). '
db 'AND HERE WE ARE, WITH OUR FIRST TANDY 1000 RELEASE. WE CALL IT '
db `"TANDY 64%... GOT IT ? `
db 130,'&',129 ;emoticons in yellow
db '.'
db ' ; '
db 'MANY THANKS TO DEMOSPLASH FOR GOING THE EXTRA MILE, AND ADDING TANDY 1000 SUPPORT!!! '
db 128 ;color yellow
db 27,28,29,30,31,42,43 ;Radio Shack (using Radio Shack font)
db 129 ;color with raster bar
db ' DESERVES IT ! '
db ' ; '
db 'SENDING OUR REGARDS TO ALL THE 8088 SCENE, AND TO OUR =64 / PC FRIENDS'
db ' ; '
db 'BESO GRANDE A LA CANTANTE MAS GROSA DE TODAS: '
db 130,'<<<',129 ;hears in yellow
db ' LIA CRUCET '
db 130,'<<<',129 ;hears in yellow
db ' ; '
db 'CODE:RIQ, MUSIC: UCTUMI, GRAPHICS: ALAKRAN'
db ' ',130,'> > > > >',129,
db ' '
SCROLL_TEXT_LEN equ $-scroll_text
scroll_char_idx: ;pointer to the next char
dw 0
scroll_bit_idx: ;pointer to the next bit in the char
db 0 ;HACK: scroll_bit_idx must be placed RIGHT BEFORE scroll_col_used
scroll_col_used: ;HACK: scroll_col_used MUST be placed RIGHT AFTER scroll_bit_idx
db 0 ;chars are 2x2. col indicates which col is being used
scroll_pixel_color_tbl: ;the colors for the scroll letters
db 0,0,0,0 ; it contains a copy of one of the tables below
scroll_pixel_red_tbl: ;these are pixels, not palette colors
db 0x00 ;00 - black/black
db 0x0c ;01 - black/white
db 0xc0 ;10 - white/black
db 0xcc ;11 - white/white
scroll_pixel_yellow_tbl: ;these are pixels, not palette colors
db 0x00 ;00 - black/black
db 0x0e ;01 - black/white
db 0xe0 ;10 - white/black
db 0xee ;11 - white/white
scroll_pixel_anim_tbl: ;these are pixels, not palette colors
db 0x00 ;00 - black/black
db 0x0f ;01 - black/white
db 0xf0 ;10 - white/black
db 0xff ;11 - white/white
scroll_enabled: ;boolean: enabled?
db 0
scroll_effect_enabled: ;boolean. whether to enable plasma + raster bar
db 0
palette_letter_color_idx: ;index for table used in fade in/out effects
db 0
palette_grayscale_in_tbl: ;fade in in grayscale
db 8,8,7,7,15,15,15,15
PALETTE_GRAYSCALE_IN_MAX equ $-palette_grayscale_in_tbl
palette_grascale_out_tbl: ;fade out in grayscale
db 7,7,8,8,0
PALETTE_GRAYSCALE_OUT_MAX equ $-palette_grascale_out_tbl
palette_black_to_pink_tbl:
db 0,1,9,5,13
PALETTE_BLACK_TO_PINK_MAX equ $-palette_black_to_pink_tbl
palette_black_to_cyan_tbl:
db 0,2,10,3,11
PALETTE_BLACK_TO_CYAN_MAX equ $-palette_black_to_cyan_tbl
palette_black_to_green_tbl:
db 0,6,14,2,10
PALETTE_BLACK_TO_GREEN_MAX equ $-palette_black_to_green_tbl
palette_outline_fade_to_final_tbl: ;fade in until gets final color
db 8,8,7,7,11,11,11,11,7,7,8,8,1
PALETTE_OUTLINE_FADE_TO_FINAL_MAX equ $-palette_outline_fade_to_final_tbl
palette_black_white_black_tbl:
db 0,8,8,8,7,7,15,15,7,7,8,8,8,0
PALETTE_BLACK_WHITE_BLACK_MAX equ $-palette_black_white_black_tbl
palette_idx:
db 0
db 0,0,0,0,0,0,0,0 ;buffer for letter M
db 0,0,0,0,0,0,0,0 ;buffer for letter P
palette_pvm_logo_fade_tbl: ;inner logo color
db 8,8,8,8,7,7,7,7
db 11,11,11,11,9,9,9,9
db 9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9
PALETTE_PVM_LOGO_FADE_MAX equ $-palette_pvm_logo_fade_tbl
volume_0:
db 0b1001_1111 ;vol 0 channel 0
db 0b1011_1111 ;vol 0 channel 1
db 0b1101_1111 ;vol 0 channel 2
db 0b1111_1111 ;vol 0 channel 3
VOLUME_0_MAX equ $ - volume_0
main_state_delay_frames:
dw 0 ;frames to wait before doing something
main_state: ;main state. index for the
db 0 ; function to call.
main_state_inits:
dw state_gfx_fade_in_init ;a
dw state_fade_to_black_init ;b
dw state_delay_500ms_init ;c
dw state_new_i08_multi_color_init ;d
dw state_plasma_red_tex_init ;e
dw state_plasma_green_tex_init ;f
dw state_plasma_magenta_tex_init ;g
dw state_clear_bottom_init ;h
dw state_new_i08_full_color_init ;i
dw state_signal_letter_state_sem_init ;j
dw state_clear_bottom_init ;l
dw state_enable_scroll ;m
dw state_delay_2s_init ;n
dw state_enable_scroll_effects ;p
dw state_delay_2s_init ;n'
; dw state_enable_text_writer ;o
dw state_enable_boy_walk ;o
dw state_nothing_init ;q
main_state_callbacks:
dw state_gfx_fade_in_anim ;a
dw state_fade_to_black_anim ;b
dw state_delay_anim ;c
dw state_skip_anim ;d
dw state_plasma_tex_anim ;e
dw state_plasma_tex_anim ;f
dw state_plasma_tex_anim ;g
dw state_clear_bottom_anim ;h
dw state_skip_anim ;i
dw state_skip_anim ;j
dw state_clear_bottom_anim ;l
dw state_skip_anim ;m
dw state_delay_anim ;n
dw state_skip_anim ;p
dw state_delay_anim ;n'
dw state_skip_anim ;o
dw state_nothing_anim ;q
letter_state_delay_frames:
dw 0 ;frames to wait before doing something
letter_state: ;PVM letters animation state machine
db 0
letter_state_inits: ;initialization callbacks
dw letter_state_wait_sem_init ;a
; PVM in blue, like IBM
dw letter_state_fade_in_1_at_time_init ;b
dw letter_state_outline_fade_init ;c
dw letter_state_delay_10s_init ;d
; dw letter_state_bkg_in_out_init ;e
dw letter_state_outline_noise_10s_init ;f
; dw letter_state_bkg_in_out_init ;g
dw letter_state_delay_200ms_init ;h
dw letter_state_outline_fade_init ;i
;P in
dw letter_state_fade_out_p_init ;j
dw letter_state_fade_in_p_init ;k
dw letter_state_delay_200ms_init ;l
;V in
dw letter_state_fade_out_v_init ;m
dw letter_state_fade_in_v_init ;n
dw letter_state_delay_200ms_init ;o
;M in
dw letter_state_fade_out_m_init ;p
dw letter_state_fade_in_m_init ;q
dw letter_state_delay_5s_init ;r
;PVM out
dw letter_state_fade_out_p_init ;s
dw letter_state_delay_200ms_init ;t
dw letter_state_fade_out_v_init ;u
dw letter_state_delay_200ms_init ;v
dw letter_state_fade_out_m_init ;w
dw letter_state_delay_5s_init ;x
;music rythm
dw letter_state_outline_noise_10s_init ;y
dw letter_state_outline_fade_init ;y'
;PVM in (left to right)
dw letter_state_fade_in_p_init ;z
dw letter_state_delay_200ms_init ;aa
dw letter_state_fade_in_v_init ;ab
dw letter_state_delay_200ms_init ;ac
dw letter_state_fade_in_m_init ;ad
dw letter_state_delay_200ms_init ;ae
;music rythm
dw letter_state_outline_noise_10s_init ;af
dw letter_state_outline_fade_init ;af'
;PVM out (left to right)
dw letter_state_fade_out_p_init ;ag
dw letter_state_delay_200ms_init ;ah
dw letter_state_fade_out_v_init ;ai
dw letter_state_delay_200ms_init ;aj
dw letter_state_fade_out_m_init ;ak
dw letter_state_delay_5s_init ;al
;PVM in (right to left)
dw letter_state_fade_in_m_init ;am
dw letter_state_delay_200ms_init ;an
dw letter_state_fade_in_v_init ;ao
dw letter_state_delay_200ms_init ;ap
dw letter_state_fade_in_p_init ;aq
dw letter_state_delay_200ms_init ;ar
;music rythm
dw letter_state_outline_noise_10s_init ;as
dw letter_state_outline_fade_init ;as'
;PVM out (right to left)
dw letter_state_fade_out_m_init ;at
dw letter_state_delay_200ms_init ;au
dw letter_state_fade_out_v_init ;av
dw letter_state_delay_200ms_init ;aw
dw letter_state_fade_out_p_init ;ax
dw letter_state_delay_5s_init ;ay
dw letter_state_restart_loop_init ;az
letter_state_callbacks: ;animation callbacks
dw letter_state_wait_sem_anim ;a
; PVM in blue, like IBM
dw letter_state_fade_in_1_at_time_anim ;b
dw letter_state_outline_fade_to_final_anim ;c
dw letter_state_delay_anim ;d
; dw letter_state_bkg_in_out_anim ;e
dw letter_state_outline_noise_anim ;f
; dw letter_state_bkg_in_out_anim ;g
dw letter_state_delay_anim ;h
dw letter_state_outline_fade_out_anim ;i
;P in
dw letter_state_fade_out_letter_anim ;j
dw letter_state_fade_to_cyan_letter_anim ;k
dw letter_state_delay_anim ;l
;V in
dw letter_state_fade_out_letter_anim ;m
dw letter_state_fade_to_green_letter_anim ;n
dw letter_state_delay_anim ;o
;M in
dw letter_state_fade_out_letter_anim ;p
dw letter_state_fade_to_pink_letter_anim ;q
dw letter_state_delay_anim ;r
;PVM out
dw letter_state_fade_out_letter_anim ;s
dw letter_state_delay_anim ;t
dw letter_state_fade_out_letter_anim ;u
dw letter_state_delay_anim ;v
dw letter_state_fade_out_letter_anim ;w
dw letter_state_delay_anim ;x
;music rythm
dw letter_state_outline_noise_anim ;y
dw letter_state_outline_fade_out_anim ;y'
;PVM in (left to right)
dw letter_state_fade_to_cyan_letter_anim ;z
dw letter_state_delay_anim ;aa
dw letter_state_fade_to_green_letter_anim ;ab
dw letter_state_delay_anim ;ac
dw letter_state_fade_to_pink_letter_anim ;ad
dw letter_state_delay_anim ;ae
;music rythm
dw letter_state_outline_noise_anim ;af
dw letter_state_outline_fade_out_anim ;af'
;PVM out (left to right)
dw letter_state_fade_out_letter_anim ;ag
dw letter_state_delay_anim ;ah
dw letter_state_fade_out_letter_anim ;ai
dw letter_state_delay_anim ;aj
dw letter_state_fade_out_letter_anim ;ak
dw letter_state_delay_anim ;al
;PVM in (right to left)
dw letter_state_fade_to_cyan_letter_anim ;am
dw letter_state_delay_anim ;an
dw letter_state_fade_to_green_letter_anim ;ao
dw letter_state_delay_anim ;ap
dw letter_state_fade_to_pink_letter_anim ;aq
dw letter_state_delay_anim ;ar
;music rythm
dw letter_state_outline_noise_anim ;as
dw letter_state_outline_fade_out_anim ;as'
;PVM out (right to left)
dw letter_state_fade_out_letter_anim ;at
dw letter_state_delay_anim ;au
dw letter_state_fade_out_letter_anim ;av
dw letter_state_delay_anim ;aw
dw letter_state_fade_out_letter_anim ;ax
dw letter_state_delay_anim ;ay
dw letter_state_restart_loop_anim ;az
letter_state_semaphore: ;semaphore used in letter state machine
db 0
letter_state_color_to_fade: ;which color idx to fade
db 0
CENTRAL_SCREEN_STATE_WAIT equ 0
CENTRAL_SCREEN_STATE_BOY_ANIM equ 1
CENTRAL_SCREEN_STATE_TEXT_WRITTER equ 2
central_screen_state: ;state machine for the "central part of the screen"
db 0
text_writer_addr: ;address where the char will be written
dw 0
text_writer_x_pos: ;position x for the cursor. 0-39
db 0 ; but supports in the range of -127,128
text_writer_x_dst: ;dst position x for the cursor. 0-39
db 0
text_writer_y_pos: ;position y for the cursor. 0-24
db 0 ; but supports in the range of -127,128
text_writer_y_dst: ;dst position 0 for the cursor. 0-24
db 0
text_writer_bitmap_to_video_tbl: ;converts charset (bitmap) to video bytes. nibble only
db 0x00,0x00 ;0000
db 0x00,0x07 ;0001
db 0x00,0x70 ;0010
db 0x00,0x77 ;0011
db 0x07,0x00 ;0100
db 0x07,0x07 ;0101
db 0x07,0x70 ;0110
db 0x07,0x77 ;0111
db 0x70,0x00 ;1000
db 0x70,0x07 ;1001
db 0x70,0x70 ;1010
db 0x70,0x77 ;1011
db 0x77,0x00 ;1100
db 0x77,0x07 ;1101
db 0x77,0x70 ;1110
db 0x77,0x77 ;1111
text_writer_idx: ;offset to the text_writer_data
dw 0
text_writer_state:
db 0
;text writer enums. must be synced with callbacks order
TW_STATE_PRINT_CHAR equ 0
TW_STATE_IDLE equ 1
TW_STATE_GOTO_X equ 2
TW_STATE_GOTO_Y equ 3
TW_STATE_CALL_ACTION equ 4
TW_STATE_CURSOR_BLINK equ 5
TW_STATE_MAX equ 6 ;should be the last state
text_writer_callbacks_init:
dw 0 ;no init for print_char
dw text_writer_state_idle_init
dw text_writer_state_goto_x_init
dw text_writer_state_goto_y_init
dw text_writer_state_call_action_init
dw text_writer_state_cursor_blink_init
text_writer_callbacks_anim:
dw text_writer_state_print_char_anim
dw text_writer_state_idle_anim
dw text_writer_state_goto_x_anim
dw text_writer_state_goto_y_anim
dw text_writer_state_call_action_anim
dw text_writer_state_cursor_blink_anim
;control codes: think of it as a printer
; 0 - idle
; 2 - print char
; 3 - go to
; 4 - carriage return
; 5,n - perform an immediate action: eg: call enable_something
text_writer_data:
;0123456789012345678901234567890123456789
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,17 ;go to pos
db 'Hi!'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,8 ;go to pos
db 'Pungas de Villa Martelli'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,7 ;go to pos
db ' proudly presents',31
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,11 ;go to pos
db '*** Tandy 64 ***'
db TW_STATE_CURSOR_BLINK,4 ;wait blinks
db TW_STATE_GOTO_X,7 ;go to pos
db '(our first Tandy release)'
db TW_STATE_CURSOR_BLINK,5 ;wait blinks
db TW_STATE_GOTO_X,6 ;go to pos
db ' Run it using real hardware'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,6 ;go to pos 5
db ' Requirements:'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,6 ;go to pos 5
db 'Tandy 1000 HX (or compatible)'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,5 ;go to pos 5
db ' at least 256Kb RAM'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,5 ;go to pos 5
db `If the colors don't look good`,31
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,4 ;go to pos 5
db ' ',31,`don't use composite output`,31
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,4 ;go to pos 5
db ' ',31,'use RGBI output instead'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,5 ;go to pos 5
db 'Runs under DosBox / DosBox-x',31
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,5 ;go to pos 5
db ' ',31,'but with some glitches'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,6 ;go to pos 5
db 'Feel free to contact us at:'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,4 ;go to pos 5
db ' http://pungas.space'
db TW_STATE_CURSOR_BLINK,4 ;wait blinks
db TW_STATE_GOTO_X,0 ;go to pos 5
db 'Thanks Demosplash for supporting Tandy!'
db TW_STATE_CURSOR_BLINK,4 ;wait blinks
db TW_STATE_GOTO_X,0 ;go to pos 5
db ' code: riq'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,13 ;go to pos 5
db 'music: Uctumi'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,11 ;go to pos 5
db 'graphics: Alakran'
db TW_STATE_CURSOR_BLINK,3 ;wait blinks
db TW_STATE_GOTO_X,8 ;go to pos 5
db 'Until our next release!'
db TW_STATE_CURSOR_BLINK,5 ;wait blinks
db TW_STATE_GOTO_X,0 ;go to pos 5
db TW_STATE_CALL_ACTION,0 ;cursor off
db TW_STATE_IDLE,230 ;wait some cycles
; to make it sync with the letters
TEXT_WRITER_DATA_LEN equ $-text_writer_data
text_writer_cursor_blink_delay: ;how many cursor blinks to wait
db 0
text_writer_delay: ;used by 'delay state' to know who many
db 0 ; vert retrace to wait
BOY_ANIM_STATE_WALK equ 0
BOY_ANIM_STATE_DANCE equ 1
BOY_ANIM_STATE_END equ 2
boy_anim_state: ;states for boy animation
db 0
boy_anim_delay: ;how many frames to wait
db 0
boy_anim_vid_addr: ;video address to where draw the next frame
dw 0
boy_anim_frame_0: ;dance: right root up
db 0x00,0x00,0x00,0x00,0x07,0x77,0x70,0x00,0x7f,0x77,0x77,0x00,0xf0,0xff,0x0f,0x00
db 0xff,0xff,0xff,0x00,0x8f,0x8f,0xf8,0x00,0x0f,0xff,0xf0,0x00,0x00,0x07,0x70,0x00
db 0x00,0xff,0xff,0x00,0x08,0xff,0xff,0x80,0x07,0x77,0xff,0x80,0x00,0xff,0xff,0x00
db 0x00,0x77,0x87,0x70,0x00,0x70,0x00,0x70,0x00,0x70,0x00,0x88,0x08,0x80,0x00,0x00
boy_anim_frame_1: ;dance: both feet on floor
db 0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x00,0x07,0x7f,0x77,0x70,0x0f,0x0f,0xf0,0xf0
db 0x0f,0xff,0xff,0xf0,0x08,0xf8,0x8f,0x80,0x00,0xff,0xff,0x00,0x00,0x07,0x70,0x00
db 0x00,0xff,0xff,0x00,0x08,0xff,0xff,0x80,0x08,0xff,0xff,0x80,0x00,0xff,0xff,0x00
db 0x00,0x77,0x87,0x00,0x00,0x70,0x07,0x00,0x00,0x70,0x07,0x00,0x08,0x80,0x08,0x80
boy_anim_frame_2: ;dance: left foot up
db 0x00,0x00,0x00,0x00,0x00,0x07,0x77,0x70,0x00,0x77,0x7f,0x77,0x00,0xf0,0xff,0x0f
db 0x00,0xff,0xff,0xff,0x00,0x8f,0xf8,0xf8,0x00,0x0f,0xff,0xf0,0x00,0x07,0x70,0x00
db 0x00,0xff,0xff,0x00,0x08,0xff,0xff,0x80,0x08,0xff,0x77,0x70,0x00,0xff,0xff,0x00
db 0x07,0x78,0x77,0x00,0x07,0x00,0x07,0x00,0x88,0x00,0x07,0x00,0x00,0x00,0x08,0x80
boy_anim_frame_3: ;walk 0
db 0x00,0x00,0x00,0x00,0x00,0x07,0x77,0x70,0x00,0x77,0x77,0x77,0x00,0x77,0xf0,0xf0
db 0x00,0x7f,0xff,0xff,0x00,0x87,0xff,0x8f,0x00,0x08,0xff,0xf0,0x00,0x07,0x70,0x00
db 0x00,0x7f,0xf8,0x00,0x00,0x7f,0xff,0x00,0x00,0x07,0x7f,0x00,0x00,0x7f,0xff,0x00
db 0x00,0x77,0x87,0x00,0x87,0x70,0x07,0x00,0x80,0x00,0x07,0x00,0x00,0x00,0x08,0x80
boy_anim_frame_4: ;walk 1
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x77,0x70,0x00,0x77,0x77,0x77
db 0x00,0x77,0xf0,0xf0,0x00,0x7f,0xff,0xff,0x00,0x87,0xff,0x8f,0x00,0x08,0xff,0xf0
db 0x00,0x07,0x70,0x00,0x00,0x7f,0xf8,0x00,0x00,0x7f,0xff,0x00,0x00,0x0f,0xff,0x00
db 0x00,0x07,0x87,0x00,0x00,0x77,0x07,0x00,0x00,0x70,0x70,0x00,0x00,0x88,0x88,0x00
boy_anim_frame_5: ;walk 2
db 0x00,0x00,0x00,0x00,0x00,0x07,0x77,0x70,0x00,0x77,0x77,0x77,0x00,0x77,0xf0,0xf0
db 0x00,0x7f,0xff,0xff,0x00,0x87,0xff,0x8f,0x00,0x08,0xff,0xf0,0x00,0x07,0x70,0x00
db 0x00,0x7f,0xf7,0x00,0x07,0x7f,0xff,0x00,0x07,0x0f,0xff,0x70,0x00,0x0f,0xff,0x00
db 0x00,0x07,0x78,0x00,0x08,0x88,0x87,0x00,0x08,0x00,0x07,0x00,0x00,0x00,0x08,0x80
boy_dance_timeout: ;how many frames should the dance animation be active
dw 0
boy_walk_col_pos: ;in which col the boy is positioned
db 0
boy_walk_frame_idx: ;which frame is being displayed
db 0
boy_walk_animation_tbl: ;frames for a full walk cycle
dw boy_anim_frame_3
dw boy_anim_frame_4
dw boy_anim_frame_5
dw boy_anim_frame_4
BOY_WALK_ANIM_FRAME_MAX equ ($-boy_walk_animation_tbl)/2 ;each frame addr takes 2 bytes
key_pressed: ;boolean. non-zero when a key was pressed
db 0
tick: ;to trigger once the irq was called
db 0
old_i08: ;segment + offset to old int 8 (timer)
dd 0
old_i09: ;segment + offset to old int 9 (keyboard)
dd 0
old_i0d: ;segment + offset to old int 0xd (vertical retrace)
dd 0
old_pic_imr: ;PIC IMR original value
db 0
raster_colors_tbl: ;used for the raster bars, at the
db 15,15,15,15,15 ; bottom of the screen
db 15,15,15,15,15 ;these are the default colors. used when the anim
db 15,15,15,15,15,15 ; is not started yet
raster_color_restore: ;must be after raster_colors_tbl
db 15 ; it restores white color to its default palette
RASTER_COLORS_MAX equ $-raster_colors_tbl
raster_colors_anim_tbl: ;colors than will be copied to raster_colors_tbl
db 15,15,15,15,15
db 15,15,15,15,15
db 15,15,15,15,15,15
db 7
raster_colors_color_tbl: ;here starts the real colors to be updated
db 9,8,1,8,9
db 7
db 15,15,15,15,15
db 15,15,15,15,15
db 15,15,15,15,15,15
db 15,15,15,15,15 ;buffer
raster_bars_colors_addr_start: ;used as an address: start of colors
raster_bars_blue_tbl: ;HACK: order must be the same as in
db 9,8,1,8,9 ; plasma_palettes_tbl
raster_bars_magenta_tbl:
db 13,8,5,8,13
raster_bars_cyan_tbl:
db 11,8,3,8,11
raster_bars_red_tbl:
db 12,8,4,8,12
raster_bars_green_tbl:
db 10,8,2,8,10
raster_bars_yellow_tbl:
db 14,8,6,8,14
RASTER_BARS_COLOR_MAX equ $-raster_bars_yellow_tbl
raster_bars_colors_addr_end: ;used as an address: end of colors
raster_bars_colors_addr:
dw 0 ;current address for colors
raster_colors_loops_for_each_color: ;how many sine loops to do before chaning colors
db 0
raster_colors_sine_idx: ;index to be used with the sine table
db 0
raster_colors_sine_tbl: ;table that manipulates the raster_colors_anim_idx
; autogenerated table: easing_table_generator.py -s256 -m24 -aTrue sin
db 0, 1, 1, 1, 1, 2, 2, 2
db 3, 3, 3, 4, 4, 4, 4, 5
db 5, 5, 6, 6, 6, 6, 7, 7
db 7, 8, 8, 8, 8, 9, 9, 9
db 9, 10, 10, 10, 11, 11, 11, 11
db 12, 12, 12, 12, 13, 13, 13, 13
db 14, 14, 14, 14, 15, 15, 15, 15
db 15, 16, 16, 16, 16, 17, 17, 17
db 17, 17, 18, 18, 18, 18, 18, 19
db 19, 19, 19, 19, 19, 20, 20, 20
db 20, 20, 20, 21, 21, 21, 21, 21
db 21, 21, 22, 22, 22, 22, 22, 22
db 22, 22, 22, 23, 23, 23, 23, 23
db 23, 23, 23, 23, 23, 23, 23, 24
db 24, 24, 24, 24, 24, 24, 24, 24
db 24, 24, 24, 24, 24, 24, 24, 24
db 24, 24, 24, 24, 24, 24, 24, 24
db 24, 24, 24, 24, 24, 24, 24, 24
db 23, 23, 23, 23, 23, 23, 23, 23
db 23, 23, 23, 23, 22, 22, 22, 22
db 22, 22, 22, 22, 22, 21, 21, 21
db 21, 21, 21, 21, 20, 20, 20, 20
db 20, 20, 19, 19, 19, 19, 19, 19
db 18, 18, 18, 18, 18, 17, 17, 17
db 17, 17, 16, 16, 16, 16, 15, 15
db 15, 15, 15, 14, 14, 14, 14, 13
db 13, 13, 13, 12, 12, 12, 12, 11
db 11, 11, 11, 10, 10, 10, 9, 9
db 9, 9, 8, 8, 8, 8, 7, 7
db 7, 6, 6, 6, 6, 5, 5, 5
db 4, 4, 4, 4, 3, 3, 3, 2
db 2, 2, 1, 1, 1, 1, 0, 0
BOTTOM_TOP_LINES_TO_WAIT equ 32
top_palette: ;palette used for the upper part of the screen
db 0,1,2,3,4,5,6,7,8,9
db 4 ;color 10 should be 4 (red)
db 11,12
db 1 ;color 13 should be 1 (blue)
db 14,15
bottom_palette: ;palette used for the bottom part of the screen
db 0
db 1,2,3,4,5,6 ;only colors 1-6 are modified
db 7,8,9,4,11,12,1,14,15 ;these colors are ignored
palette_default:
db 0,1,2,3,4,5,6,7,8,9 ;default palette
db 4 ;color 10 should be 4 (red)
db 11,12
db 1 ;color 13 should be 1 (blue)
db 14,15
border_color: ;border color
db 9
; red, green and blue palettes, ALL MUST HAVE
; the same size
plasma_tex_red_palette:
db 0xf ;white
db 0x7 ;light gray
db 0xc ;light red
db 0x8 ;gray
db 0x4 ;red
db 0 ;black
PLASMA_TEX_PALETTE_MAX equ $-plasma_tex_red_palette
plasma_tex_green_palette:
db 0xf ;white
db 0x7 ;light gray
db 0xa ;light green
db 0x8 ;gray
db 0x2 ;green
db 0 ;black
plasma_tex_magenta_palette:
db 0xf ;white
db 0x7 ;light gray
db 0xd ;light magenta
db 0x8 ;gray
db 0x5 ;magenta
db 0 ;black
plasma_tex_blue_palette:
db 0xf ;white
db 0x7 ;light gray
db 0x9 ;light blue
db 0x8 ;gray
db 0x1 ;blue
db 0 ;black
plasma_tex_cyan_palette:
db 0xf ;white
db 0x7 ;light gray
db 0xb ;light cyan
db 0x8 ;gray
db 0x3 ;cyan
db 0 ;black
plasma_tex_yellow_palette:
db 0xf ;white
db 0x7 ;light gray
db 0xe ;yellow
db 0x8 ;gray
db 0x6 ;brown
db 0 ;black
plasma_effect_delay: ;delay used while in transition to slow it down
db 0
plasma_effect_trigger: ;boolean, when enabled start effect transition
db 0
plasma_effect_transition_state: ;state of the transition effect
db 0
plasma_effect_idx: ;plasma effect index
db 0
plasma_palettes_tbl: ;table that contains the different palettes
dw plasma_tex_blue_palette ; order must same as in raster_bars_colors_addr_start
dw plasma_tex_magenta_palette
dw plasma_tex_cyan_palette
dw plasma_tex_red_palette
dw plasma_tex_green_palette
dw plasma_tex_yellow_palette
PLASMA_EFFECT_MAX equ ($-plasma_palettes_tbl)/2 ;div 2, since each entry takes 2 bytes (dw)
plasma_inc_x0_x1_tbl: ;table that contains the different inc values for x
dw 0x0406
dw 0x0104
dw 0x0304
dw 0x0304
dw 0x0305
dw 0x8003
plasma_inc_y0_y1_tbl: ;table that contains the different inc values for y
dw 0x0500
dw 0x0202
dw 0x8302
dw 0x837f
dw 0xfb02
dw 0xff02
plasma_off_x0_x1_inc_tbl: ;table that contains the different off inc values for x
dw 0x0300
dw 0x0004
dw 0x0004
dw 0x0002
dw 0x0703
dw 0xff01
plasma_off_y0_y1_inc_tbl: ;table that contains the different off inc values for y
dw 0xff00
dw 0x0400
dw 0x0403
dw 0x0403
dw 0xfcfd
dw 0x03ff
plasma_tex_state: ;internal state used inside the state_plasma_tex state
db 0 ;0=render texture, 1=fade in palette
plasma_tex_colors_updated: ;number of palette colors that were updated
db 0
plasma_tex_delay: ;refreshes to wait for the palette update
db 0
plasma_tex_palette_addr: ;palette address to use
dw 0
plasma_tex_letter_color: ;color of the PVM letter to update
db 0
plasma_tex_x_offset: ;plama x offset. to make it scroll
dw 0
plasma_tex_inc_x0: ;plasma xbuf increment a
db 0
plasma_tex_inc_x1: ;plasma xbuf increment b
db 0
plasma_tex_inc_y0: ;plasma ybuf increment a
db 0
plasma_tex_inc_y1: ;plasma ybuf incrment b
db 0
cycle_palette_delay: ;delay for the palette cycle animation
db 1
clear_bottom_state: ;used by state_clearn_bottom_anim
db 0 ;when 0, clear first half. when 1, clear second half
crtc_start_addr:
dw 0 ;crtc start address
plasma_inc_x0_x1: ;plasma: inc x0 x1
dw 0
plasma_inc_y0_y1: ;plasma: inc y0 y1
dw 0
plasma_off_x0_x1: ;plasma: offset x0 y1
dw 0
plasma_off_x0_x1_inc: ;plasma: offset increment x0 y1
dw 0
plasma_off_y0_y1: ;plasma: offset x0 y1
dw 0
plasma_off_y0_y1_inc: ;plasma: offset increment x0 y1
dw 0
plasma_anim_state:
db 0b1010_1010 ;cycles between 1 and 0 with a ror
luminances_6_colors:
db 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11 ;white (0xff)
db 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11
db 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11
db 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22 ;should be: 0x77
db 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22
db 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22
db 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33 ;should be 0xcc
db 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33
db 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44 ;should be 0x88
db 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44
db 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44
db 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 ;should be 0x44
db 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
db 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66 ;should be 0x00
db 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66
db 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66
;HACK: must be 256 aligned to be faster at calculating the plasma table
align 256
fn_table_1:
fn_table_2:
; autogenerated table: easing_table_generator.py -s128 -m128 -aTrue -r bezier:0,0.02,0.98,1
db 0, 0, 0, 1, 1, 1, 1, 2
db 2, 3, 3, 4, 4, 5, 5, 6
db 7, 8, 8, 9, 10, 11, 12, 13
db 13, 14, 15, 16, 17, 19, 20, 21
db 22, 23, 24, 25, 27, 28, 29, 30
db 32, 33, 34, 36, 37, 38, 40, 41
db 42, 44, 45, 47, 48, 49, 51, 52
db 54, 55, 57, 58, 60, 61, 63, 64
db 65, 67, 68, 70, 71, 73, 74, 76
db 77, 79, 80, 81, 83, 84, 86, 87
db 88, 90, 91, 92, 94, 95, 96, 98
db 99,100,101,103,104,105,106,107
db 108,109,111,112,113,114,115,115
db 116,117,118,119,120,120,121,122
db 123,123,124,124,125,125,126,126
db 127,127,127,127,128,128,128,128
; reversed
db 128,128,128,127,127,127,127,126
db 126,125,125,124,124,123,123,122
db 121,120,120,119,118,117,116,115
db 115,114,113,112,111,109,108,107
db 106,105,104,103,101,100, 99, 98
db 96, 95, 94, 92, 91, 90, 88, 87
db 86, 84, 83, 81, 80, 79, 77, 76
db 74, 73, 71, 70, 68, 67, 65, 64
db 63, 61, 60, 58, 57, 55, 54, 52
db 51, 49, 48, 47, 45, 44, 42, 41
db 40, 38, 37, 36, 34, 33, 32, 30
db 29, 28, 27, 25, 24, 23, 22, 21
db 20, 19, 17, 16, 15, 14, 13, 13
db 12, 11, 10, 9, 8, 8, 7, 6
db 5, 5, 4, 4, 3, 3, 2, 2
db 1, 1, 1, 1, 0, 0, 0, 0
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
; resb/resw
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;
cache_charset:
resb 32 ;the 32 bytes to print in the current frame
; char aligned like: top-left, bottom-left,
; top-right, bottom-right
plasma_tex_xbuf: ;plasma tex xbuffer
resb PLASMA_TEX_WIDTH
plasma_tex_ybuf: ;plasma tex ybuffer
resb PLASMA_TEX_HEIGHT
plasma_xbuf: ;plasma xbuffer
resb PLASMA_WIDTH
plasma_ybuf: ;plasma ybuffer
resb PLASMA_HEIGHT