pouët.net

Go to bottom

Sluníčko by Řrřola [web]

; \|/ Slunicko
;>=O=< a 256-byte intro by rrrola <rrrola@gmail.com>
; /|\ greets to everyone who's ever got a bad sunburn

org 100h ; assume cs<=0x4000 ax=0 sp=di=-2 si=0x100

; macros to access constants
%define w(xx) word[byte bp+si-0x100+xx]
%define d(xx) dword[byte bp+si-0x100+xx]

  push ax       ; push zero for "ret"
  push 0xa000   ; screen segment
  mov ax,0x4f02 ; set VESA mode

;Run through a few constants.
;ab     stosw         ; di=0
;3f     aas
;22c2   and al,dl
;b7a3   mov bh,0xa3
;b783   mov bh,0x83
;bb0e01 mov bx,0x10e  ; mode 320x200 with 65536 colors

SMUL equ $-2 ; 1.34
  db 0xab,0x3f
AMUL equ $-2 ; -40.56 ~ -128/pi (-40.74)
  db 0x22,0xc2
XMUL equ $-3 ; -2.314e-5 ~ -2.441e-5 (320/256 / (256*200))
  db 0xb7
YMUL equ $-2 ; -1.952e-5 ~ -1.953e-5 (1 / (256*200))
  db 0xa3,0xb7
CMUL equ $-2 ; -0.004
  db 0x83,0xbb

  dw 0x010e

  int 10h       ; set mode 320x200 with 65536 colors
RMUL equ $-1 ; 1808
  pop es        ; es = screen segment
  lds bx,[si-3] ; bx = 0, ds = 0x5000 texture segment

;Generate 2D Brownian motion texture
; bx=count si=adr bp,dx,cx=random generator
; similar to baze's texture generator, used in Terén
M:
T lodsb         ; al = top right texel
  dec bp        ; do some pseudorandom stuff
  ror bp,cl
  xor dx,bp
  sar dx,3
  adc cx,dx     ; ch += random (-16..16)
  adc ch,al     ; ch += top right texel
  rcr cx,1
  mov [si+254],ch ; store texel
  dec bx
  jnz T ; loop 512x (65536x on init)

  pusha         ; we'll do more texture generation later

  mov cx,si     ; ch=time (texture offset)
  xor bp,bp     ; bp=0, si=0x100 (nice values)
  mov si,0x100

;Pixel loop: di=pixel address if the buffer was 8-bit
X mov ax,0xcccd ; convert width 320->65536 (from Tetraskelion)
  mul di
  xchg ax,bx    ; full 16-bit precision of X
  mov ax,0x4f05
  add bx,ax
  adc dx,0x9b80 ; center at [100, 159.5]: should be 0x9b804d46
  pusha ;{di si bp sp bx dx cx ax} to the stack
        ;                YY        Y = [-8-18]
        ;              X X         X = [-9-18]

;Is it time to switch the VESA bank?
  add di,di     ; switch when pixel address = 0
  jnz D
  cwd
  adc dx,dx     ; dx=page (0 or 1)
  xor bx,bx     ; bh=0 (set bank), bl=0 (window id)
  int 10h       ; assume 64kB granularity and window at 0xA000

;Build a (5,6,5)-bit pixel: approximate sRGB with [√R √G √B]
D call I        ; compute color
  xor ax,ax
  inc ax        ; ax=1 cx=6
  mov cl,6
P fsqrt         ;; 29656*[√R √G √B]
  fimul w(BIG)      ; store 15-bit color component (0..7fff)
  fistp word[bp+si] ; if it's > 0x7fff, clamp to 0x8000
  imul bx,[bp+si],2 ; double, set carry if it was > 0x3fff
  sbb bx,bp         ; clip overflow (0x8000*2) to 0xffff
  xor cl,5^6        ; shift lengths: [5 6 5]
  shld ax,bx,cl ; rrrrrggggggbbbbb: shift into ax
BIG: equ $-1 ; 29656
  jnc P ; loop 3x until you've shifted the 1 bit out of ax
  stosw
  popa
  inc di
  jnz X ; loop 65536x, di=0

  popa
  mov bh,2  ; advance time: the texture cycles every 128 frames

;Exit on ESC
  in al,60h
  cbw
  dec ax
  jne M ; loop until ESC
  mov al,3  ; textmode
  int 0x10  ; use "ret" from below

;Subroutine: compute color.
; using a subroutine saves a byte: +3 call, -4 main loop jumps
I fild word[bp-8-18]
  fmul d(YMUL)
  fild word[bp-9-18]
  fmul d(XMUL)  ;; x=X/(320*200) y=Y/(256*200)  ; y:-1..1

  add dh,ch     ; texture coords for background:
  add dh,0x80   ; dl = u = x
  push dx       ; dh = v = y+time

;Polar coordinates (from Polar Beat)
  fld st1       ;; y x y
  fpatan        ;; a=atan(x/y) y  ; a:-π..π, 0=vertical
  fld st0
  fcos          ;; cos(a) a y
  fdivp st2,st0 ;; a r=y/cos(a)   ; r=√(x²+y²)
  fmul d(AMUL)  ;; A=a*-128/π r   ; A:-128..128
  fistp dword[bp+si]
  mov bl,[bp+si]; bl = u texcoord = A

  fld st0       ;; 1808/r r       ; about 7.06 * 256 / r
  fidivr w(RMUL)
  fistp dword[bp+si]
  mov bh,[bp+si+1] ; t = [bp+si] = bottom bits of R (for later)
  add bh,ch     ; bh = v texcoord = R+time

;Sun
  fmul st0
  fld1          ;; 1-r┬▓
  fsubrp st1,st0
  fmul st0
  fmul st0
  fmul st0
  fmul st0      ;; s=(1-r²)¹⁶

  mov cx,2
O fld st0
  fmul d(SMUL)  ;; R=1.34┬▓*s G=1.34*s B=s
  loop O ; loop 2x

;Foreground: tunnel with chromatic aberration and interpolation
  mov cl,3      ; Linear interpolation between v and v+1:
F mov al,[bp+si]
  not al        ; al = 1-t
  mul byte[bx]
  xchg ax,dx    ; dx = (1-t) * tex[u,v]  ; 8*8 -> 16bit
  inc bh        ; chromatic aberration - R:v G:v+1 B:v+2
  mov al,[bp+si]
  mul byte[bx]  ; ax = t * tex(u,v+1)
  add ax,dx     ; ax = (1-t) * tex[u,v] + t * tex[u,v+1]
  shr ax,7      ; foreground is 2x brighter than background

  stc
  jmp A         ; accumulate one color channel, return to R
R loop F ; loop 3x

;Background: scrolling clouds
  pop bx        ; bx = background texture coordinates
  mov cl,3
B dec bh
  mov al,[bx]   ; keep white stars when ah>0

  clc           ; don't return to R

; Subroutine: accumulate one color channel: [R G B] += [x² x⁴ x⁸]
A mov [bp+si-2],ax
  fild word[bp+si-2]
  fmul d(CMUL)  ; x = -0.004*ax
  push cx
Q fmul st0
  loop Q ; loop 1x for R, 2x for G, 3x for B
  pop cx
  faddp
  fstp st3      ;; cycle: R G B -> G B R -> B R G
  jc R ; return to R

  loop B ; loop 3x
  ret
Go to top