.486
  xpocz equ 80           ; Granice ekranu lub ewentualnie okna, w
  xkonc equ -80          ; ktorym bedzie rysowany tunel.
  ypocz equ 50
  ykonc equ -50
  diadd equ 320

Assume cs:Code,ds:Code

Code    Segment USE16
        Org     100h      ; Oczywiscie *.COM
Start:
        mov     al,13h    ; Wlacz tryb graficzny
        int     10h

        push 0a000h
        pop es            ; Zaladuj do es adres bufora VGA

        mov dx,3c8h       ; Zwykla, syfna paleta, ale na lepsza nie ma
        xor ax,ax         ; miejsca - w zasadzie ustawia 4 razy 64 odcienie
        out dx,al         ; szarosci :-((
        inc dx
Paleta:
        out dx,al
        out dx,al
        out dx,al
        inc al
        jnz Paleta

        fld dalfa         ; Kat obrotow od 0.03 zeby nie bylo kropy na koncu
; For y:=-99 to 100 do dx=y
; ###########################################################################
Kolejna_Klatka:
        xor di,di         ; Wyzeruj di
        inc bx
        inc bx
        mov bp,ypocz      ; dx:=ypocz
Jedna_Klatka_Tunelu:
; For x:=-160 to 160 do cx=x
; @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        mov cx,xpocz      ; cx:=xpocz
        mov yd,bp         ; yd:=dx=y - to nie jest wyrazenie logiczne
Jedna_Linia_Tunelu:
        fild yd           ; st(0)=yd st(1)=alfa
        mov xd,cx         ; xd:=xpocz
        fild xd           ; st(0)=xd, st(1)=yd st(2)=alfa
        fld zd            ; st(0)=zd, st(1)=xd, st(2)=yd st(3)=alfa
; ***************************************************************************
; Wejscie: st(0)=zd; st(1)=xd, st(2)=yd, st(3)=alfa
; Najpierw obrot wokol osi Oy:
; direction.x:=x*cos(alfa)-z*sin(alfa)
        fld st(3)   ; st=alfa st1=zd, st2=xd, st3=yd, st4=alfa
        fsin        ; st=sin st1=zd, st2=xd, st3=yd, st4=alfa
        fld st(4)   ; st=alfa st1=sin st2=zd, st3=xd, st4=yd, st5=alfa
        fcos        ; st=cos st1=sin st2=zd, st3=xd, st4=yd, st5=alfa
        fld st(2)   ; st=zd st1=cos st2=sin st3=zd st4=xd st5=yd, st6=alfa
        fmul st,st(2) ;st=sin*z st1=cos st2=sin st3=zd st4=xd st5=yd st6=alfa
        fld st(4);st=xd st1=s*z st2=cos st3=sin st4=zd st5=xd st6=yd st7=alfa
        fmul st,st(2);st=x*c st1=s*z st2=c st3=s st4=zd st5=xd st6=yd st7=alf
        fsubrp st(1);st=x*cos-z*sin st1=c st2=s st3=zd st4=xd st5=yd st6=alfa
; direction.y:=y;
; Wejscie: st=direction.x, st1=cos, st2=sin, st3=zd, st4=xd, st5=yd, st6=alfa
; direction.z:=x*sin(alfa)+z*cos(alfa)
        fxch st(1)  ; st=cos, st1=nx st2=sin st3=zd st4=xd st5=yd st6=alfa
        fmulp st(3) ; st=nx st1=sin st2=zd*cos st3=xd st4=yd st5=alfa
        fxch st(1)  ; st=sin st1=nx st2=zd*cos st3=xd st4=yd st5=alfa
        fmulp st(3) ; st=nx st1=zd*cos st2=xd*sin st3=yd st4=alfa
        fxch st(2)  ; st=xd*sin st1=zd*cos st2=nx st3=yd st4=alfa
        faddp st(1) ; st=xd*sin+zd*cos st2=nx st3=yd st4=alfa
; Wyjscie: ; st=zd st2=xd st3=yd st4=alfa
; Normalize(direction);
; direction.x:=x - obrocone
; direction.y:=y
; direction.z:=z - obrocone
; Normalize(direction)
        fld st        ; st0=zd,        st1=zd   st2=xd, st3=yd st4=alfa
        fmul st,st    ; st0=zd^2,      st1=zd   st2=xd, st3=yd st4=alfa
        fld st(3)     ; st0=yd,        st1=zd^2 st2=zd, st3=xd st4=yd st5=alfa
        fmul st,st    ; st0=yd^2,      st1=zd^2 st2=zd, st3=xd st4=yd st5=alfa
        faddp st(1)   ; st0=yd^2+zd^2, st1=zd   st2=xd, st3=yd  st4=alfa
        fld st(2)     ; st0=xd,   st1=yd^2+zd^2 st2=zd, st3=xd st4=yd st5=alfa
        fmul st,st    ; st0=xd^2, st1=yd^2+zd^2 st2=zd, st3=xd st4=yd st5=alfa
        faddp st(1)   ; st0=xd^2+yd^2+zd^2       st1=zd, st2=xd st3=yd st4=alf
        fsqrt         ; st0=sqrt(xd^2+yd^2+zd^2) st1=zd, st2=xd st3=yd st4=alf
; Teraz jest nastepujaco: st(0)=length, st(1)=zd,st(2)=xd,st(3)=yd, st(4)=alfa
; Trzeba policzyc:
; x:=x/length
; y:=y/length
; z:=z/length
; Lepej byloby policzyc 1/length i mnozyc (oszczednosc okolo 60 cykli), ale na
; razie liczy sie objetosc, nie szybkosc !!!
        fdiv st(3),st ; st(3):=yd/length
        fdiv st(2),st ; st(2):=xd/length
        fdivp st(1)   ; st(1):=zd/length, pop
; Stan na wyjsciu (znormalizowane): st(0)=zd, st(1)=xd, st(2)=yd, st(3)=alfa
; ***************************************************************************

; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
; Policzyc: a:=sqr(direction.x)+sqr(direction.y)
        fld st(2)     ; st0=yd         st1=zd   st2=xd st3=yd st4=alfa
        fmul st,st    ; st0=yd^2       st1=zd   st2=xd st3=yd st4=alfa
        fld st(2)     ; st0=xd         st1=yd^2 st2=zd st3=xd st4=yd st5=alfa
        fmul st,st    ; st0=xd^2       st1=yd^2 st2=zd st3=xd st4=yd st5=alfa
        faddp st(1)   ; st0=yd^2+xd^2  st1=zd   st2=xd st3=yd st4=alfa
; 000000000000000000000000000000000000000000000000000000000000000000000000000
; Na razie nie dodaje, zeby zaoszczedzic miejsce: zamiast 2a jest a
;        fadd st,st    ; st0=2*(yd^2+xd^2), st1=zd,   st2=xd, st3=yd
; 000000000000000000000000000000000000000000000000000000000000000000000000000

; Wyjscie: st0=2*(sqr(direction.x)+sqr(direction.y))=2a
; st0=2a, st1=zd, st2=xd, st3=yd, st4=alfa
; Policzyc: c:=sqr(origin.x)+sqr(origin.y)-sqr(r);
        fld r         ; st0=oy^2+ox^2+r^2 st1=a st2=zd st3=xd st4=yd st5=alfa
; Wyjscie st0=sqr(origin.x)+sqr(origin.y)+sqr(r)=c=-c
; st0=-c, st1=a, st2=zd, st3=xd, st4=yd, st5=alfa
; Policz: delta:=sqr(b)-a*c; - taki maly przekret
        fld st(1)     ; st0=a  st1=-c st2=a st3=zd st4=xd st5=yd st6=alfa
        fmulp st(1)   ; st0=-ac st1=a st2=zd st3=xd st4=yd st5=alfa
; 000000000000000000000000000000000000000000000000000000000000000000000000000
; Na razie nie dodaje, zeby zaoszczedzic miejsce: zamiast -4ac jest -ac
      ;  fadd st,st    ; st0=-4ac,st1=2a, st2=zd, st3=xd, st4=yd
; 000000000000000000000000000000000000000000000000000000000000000000000000000

; Wyjscie: st0=b^2-4*a*c=delta - prawie, ale to niewazne st0=-ac (przekret)
; Po prostu b=0 zawsze w przypadku mojego tunelu, a zamiast -4ac jest -ac !!!
; st0=delta, st1=a, st2=zd, st3=xd, st4=yd
; Policz: delta:=sqrt(delta);
        fsqrt         ; st0=sqrt(delta),st1=a,st2=zd,st3=xd,st4=yd
; $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

; ***************************************************************************
; Stan: st0=sqrt(delta), st1=a, st2=zd, st3=xd, st4=yd, st5=alfa
; Policzyc t:=(-b+sqrt(delta))/(2a) - tak powinno sie liczyc;
        fdivrp st(1)  ; st0=(-b+sqrt(delta))/(a) st1=zd st2=xd st3=yd st4=alfa
; Wyjscie: st0=sqrt(delta)/a=t -dokladniej to teoretycznie (-b+sqrt(delta))/a
; Liczenie korekcji koloru w zaleznosci od odleglosci od kamery
        fld col       ; st=20000 st1=t, st2=zd, st3=xd, st4=yd st5=alfa
        fdiv st,st(1) ; Potrzebne do depth shading
        fistp kol     ; tutaj mamy 20000/t, w kol.
; st0=t, st1=zd, st2=xd, st3=yd
; ***************************************************************************

; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
; Stan: st0=t, st1=zd, st2=xd, st3=yd
; Policz:
;         Intersection.x:=origin.x+t*direction.x
;         Intersectoin.y:=origin.y+t*direction.y
;         Intersection.z:=origin.z+t*direction.z
        fmul st(1),st  ; st0=t,    st1=zd*t, st2=xd,   st3=yd, st4=alfa
        fmul st(2),st  ; st0=t,    st1=zd*t, st2=xd*t, st3=yd, st4=alfa
        fmulp st(3)    ; st0=zd*t, st1=xd*t, st2=yd*t, st3=alfa
        fiadd origin_z ; st0=origin.z+zd*t, st1=xd*t, st2=yd*t, st4=alfa
; Wyjscie: st0=intersection.z st1=intersection.y st2=intersection.x st3=alfa
; Pliczyc wspolrzedne U i V textury.
; U:=round(intersection.z)
        fistp U          ; st=iz, U:=st pop => st=ix, st1=iy, st2=alfa
; V:=(round(128*atan(intersection.x/intersection.y)/pi);
        fpatan           ; st:=atan(iy,ix)        st1=alfa
        fmul factor      ; st:=atan(iy/ix)*128/pi st1=alfa
        fistp V          ; st=alfa
        mov al,byte ptr V[0] ; Chyba krocej nie da sie tego zrobic :(
        sub al,bl
        xor al,byte ptr U[0] ; Po prostu kawalek tekstury - kolor w al
        imul ax,kol          ; Takie prostackie cieniowanie:
        shr ax,10            ; kol:=20000/t; ax:=kol*al div 1024
; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        mov ah,al            ; Zeby rysowal cale duze pixele 2x2. Teraz 2
        mov es:[di+diadd],ax ; I pod spodem 2 pixele
        stosw                ; Bo zajmuje mniej niz mov es:[di],al inc di
        xor ah,ah            ; Musi zostac wyzerowane na pozniej - kolor
        dec cx               ; Czy juz koniec tej linijki tunelu ?
        cmp cx,xkonc
        jne Jedna_Linia_Tunelu ; Jesli nie to licz nastepny pixel
; Koniec kolejnej linijki tunelu
; @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        add di,diadd         ; Korekcja, gdyz trace jest co 2 pixel
        dec bp               ; Czy juz gotowa cala jedna klatka
        cmp bp,ykonc
        jne Jedna_Klatka_Tunelu ; Jesli nie to rysuj nastepna linijke
; Jedla klatka gotowa
; ###########################################################################
        add origin_z,5     ; Zeby tunel sie conieco poruszal do przodu

        cmp bx,100         ; Zeby przez pewien czas tunel wygladal
        jl ZwyklyT         ; jak zwykly tunel na LUT'cie (umm jak to brzmi).

        fadd dalfa         ; Jesli juz minelo 100 klatek - zwiekszaj kat

ZwyklyT:                   ; Jeszcze nie obracaj :-)))

        in      al,60h     ; Czekaj na nacisniecie ESC
        cmp     al,1
        jnz Kolejna_Klatka ; Jesli nie nacisnieto ESC, licz nastepna klatke

        ret                ; Koniec

  r  dd 1089.0             ; Od razu r^2, r=33 i tym samym -c w rownaniu.
  ; Bo c=-r^2= - czyli tak jak zadeklarowalem, to -c=r^2
  factor dd 40.7436654     ; 128/pi - potrzebne przy teksturze - do fpatan
  dalfa dd -0.03           ; Przyrost kata obrotu
  zd dd 80.0               ; Skladowa z wektora direction
  col dd 8000.0            ; Zmienna do wyciemniania tunelu
  kol dw ?                 ; Zmienna na 20000/t - do cieniowania

  origin_z dw ?            ; Jedyna wspolrzedna, ktora sie zmienia - ruch
  U dw ?                   ; Wiadomo wspolrzedne w texturze
  V dw ?

  xd dw ?                  ; skladowe x i y do opisu wektora direction
  yd dw ?

CODE    ENDS

END     Start