Start | Super Packer | Atari Graphics Studio | Graph2Font | Mads | MadPascal | YouTube http://madteam.atari8.info  
MEMBERS
PRODUCTIONS
S C E N E
G A M E S
T O O L S
V B X E
GRAPHICS
WORK IN PROGRESS
Bubble Shooter
HARDWARE
Snes2Joy / Pad4Aatari / TOM rev2
Sio2SD / Pajero
Sio2SD / Rocky
Stereo / Pajero
GTIA / Psychol
ANTIC + VBXE test
ARTICLES / MAGAZINES
DEMO EFFECTS
LINKS
   

WSTĘP

Większo¶ć efektów tu prezentowanych ma wspóln± cechę, aby działały odpowiednio szybko potrzebuj± odpowiednio wyliczonej wcze¶niej tablicy tzw. "lookup tables" (LUT). Tablicowanie pozwala pozbyć się najbardziej spowalniaj±cych fragmentów programu, operacji mnożenia, funkcji trygonometrycznych. Ostatecznie pozostaj± najszybsze operacje takie jakie dodawanie i odejmowanie.

Operacje trygonometryczne podane w poniższych przykładach mog± wymagać podania parametru w radianach, st±d przelicznik stopni na radiany ANGLE*PI/180. Funkcja SQR oznacza potęgowanie (np. x*x = SQR(x)), SQRT pierwiastkowanie (np. pierwiastek drugiego stopnia z 9 = SQRT(9)). Funkcja ROUND zaokr±gla warto¶ć rzeczywist± do warto¶ci całkowitej (np. ROUND(3.124) = 3), ABS zwraca warto¶ć absolutn± czyli bez znaku (np. ABS(-3) = 3), DIV dzielenie bez reszty (np. 9 div 2 = 4), MOD reszta z dzielenia DIV (np. 9 MOD 2 = 1). Operator '<<' oznacza operację przesuwania bitów w lewo (shift left) czyli mnożenie przez potęgę dwójki, operator '>>' oznacza przesuwanie bitów w prawo (shift right) czyli dzielenie przez potęgę dwójki.

Większo¶ć zał±czonych przykładów w Delphi działa w pętli bez końca, zatrzymanie takiego programu wymaga naci¶nięcia klawisza ESC.

A Compilation of Advanced Atari 8-bit Programming Techniques
HORIZONTAL SCROLL FIRE EFFECT
KEFRENSBAR PLASMA EFFECT
PLOTTER LENS EFFECT
SHADE BOB 2D BUMP MAPPING
UNLIMITED BOBS TWIRL
X-ROTATOR SIERPINSKI FRACTALS
ZOOM SCROLL WATER / RAIN EFFECT
ROTOZOOMER / ZOOMROTATOR METABALLS / BLOBS
CHESS ZOOMROTATOR TEXTURE-MAPPED TUNNEL
FILL RECTANGLE TWISTER

HORIZONTAL SCROLLING

Najpopularniejszy sposób pzekazywania informacji w różnego typu produkcjach na każdej platformie sprzętowej to płynnie przesuwaj±ce się napisy - scrolle, poruszaj± się najczę¶ciej od prawej do lewej strony ekranu, albo od dołu do góry ekranu.

Przesuw w poziomie jest ułatwiony dzięki programowi ANTIC-a (Display List), wystarczy ustawić adres LMS (Load Memory Scan) dla linii, najlepiej na pocz±tku jakiego¶ 4KB bloku pamięci, potem tylko modyfikować taki adres zwiększaj±c go kolejno, uzyskamy w ten sposób przesuw zgrubny - co jeden znak, np.:

       org $600

dlist  dta $70,$70,$70    ; 24 puste linie ($70 = 8 pustych linii)
       dta $42            ; rozkaz ANTIC-a LMS ($42) dla trybu $02
adres  dta a(text)        ; adres scrolla
       dta $41,a(dlist)   ; zakończenie programu ANTIC-a

main   mwa #dlist 560     ; ustawiamy nowy adres programu ANTIC-a

loop   ldx #6             ; pętla opóĽniaj±ca 6 ramek
@      lda:cmp:req 20
       dex
       bne @-

       inw adres          ; zwiększanie adresu (WORD)

       jmp loop
		  
       org $a000
text   dta d'                        atari xe/xl'

       run main           ; adres uruchomienia tego przykładu

W serii Atari XE/XL zostały przewidziane rejestry sprzętowe ANTIC-a pozwalaj±ce realizować płynny przesuw w poziomie i pionie. Płynne przesuwanie linii w poziomie realizuje rejestr HSCROL ($D404). Wpisuj±c do tego rejestru kolejne warto¶ci 3,2,1,0 uzyskamy płynne przesunięcie o 4 cykle koloru. Poniższy przykład realizuje taki scroll dla trybu $02 ANTIC-a (standardowy tryb znakowy).

       org $600

dlist  dta $70,$70,$70   ; 24 puste linie ($70 = 8 pustych linii)
       dta $42|$10       ; rozkaz ANTIC-a LMS ($42) dla trybu $02 + $10 dla HSCROL
adres  dta a(text)       ; adres scrolla
       dta $41,a(dlist)  ; zakończenie programu ANTIC-a

main   mwa #dlist 560    ; ustawiamy nowy adres programu ANTIC-a

loop   lda tmp           ; płynny scroll, przepisanie warto¶ci TMP do rejestru HSCROL
       sta hscrol        ; koniecznie przed poniższ± pętl± opóĽniaj±c±

       ldx #6            ; pętla opóĽniaj±ca 6 ramek
@      lda:cmp:req 20
       dex
       bne @-

       dec tmp           ; zmniejszenie komórki TMP [3,2,1,0]
       bpl loop          ; pętla
       
       mva #3 tmp        ; odnowienie warto¶ci komórki TMP

       inw adres         ; scroll zgrubny

       jmp loop

tmp    dta 3             ; pomocnicza komórka pamięci TMP

       org $a000
text   dta d'                           atari xe/xl'

       run main          ; adres uruchomienia tego przykładu

Powyższe przykłady scrolli można zakwalifikować jako DXCP (Different X Character Position). S± też inne ich rodzaje, bardziej widowiskowe i bardziej wymagaj±ce obliczeniowo jak DYCP (Different Y Character Position), DYPP (Different Y Pixel Position), DXPP (Different X Pixel Position).

Scroll typu DYCP oznacza że nadal używany jest tryb znakowy jednak znaki przemieszczaj± się dodatkowo w pionie. Dla XE/XL i pewnie wszystkich platform ery 8-bit nie ma możliwo¶ci ustawienia sprzętowego scrolla pionowego dla każdego znaku z osobna, dlatego efekt taki realizowany jest poprzez modyfikację pamięci zestawu znaków. Znaki zostaj± zorganizowane parami lub trójkami lub czwórkami itd. tak aby dostęp do pamięci je opisuj±cej był liniowy. Poniżej przykład takiego układu w którym dostajemy możliwo¶ć przemieszczania znaku w zakresie 24-8 linii, w obrębie jednego zestawu 128 znaków:

 a d g j...
 b e h k...
 c f i l...

Pierwszy układ znaków zaczyna się od adresu CHARSET+'a'*8, kolejny CHARSET+'d'*8, CHARSET+'g'*8, CHARSET+'j'*8. Odpowiednia procedura będzie przemieszczała standardowy 8-liniowy znak w przestrzeni 24-8 linii, uzyskuj±c efekt falowania, przesuw poziomy realizowany jest poprzez HSCROL. Taki scroll DYCP to najczę¶ciej sinus-scroll.


KEFRENS BARS

Pionowe raster bary, najpewniej po raz pierwszy zaprezentowane przez Amigow± grupę Kefrens, st±d nazwa efektu KEFRENS BARS. Wszelkie kombinacje raster barów można obejrzeć w demie z 1990 roku "Copper master by angels"

Zasada działania efektu sprowadza się do wyrenderowania obrazu składaj±cego się z pionowych pasów "raster bara". Pozycja pozioma ustalana jest na podstawie prekalkulowanej tablicy sinus-a, pozycja pionowa jest zwiększana o stał± warto¶ć kroku, "raster bar" jest rysowany od aktualnej pozycji pionowej do końca obrazu.

Przykład pętli renderuj±cej dwa pionowe rasterbary:

  c = 0

  while c < height

   d = 160+sinLUT[ (add1+c) and $ff ] + sinLUT[ (add2+c+32) and $ff ]
   draw_raster_bar( Point(d,c), Point(d,height) )

   d = 140+sinLUT2[ (add2+c) and $ff ] + sinLUT2[ (add1+c+64) and $ff ]
   draw_raster_bar( Point(d,c), Point(d,height) )

   c = c + add_y
  end

  add1 = add1 + 2
  add2 = add2 + 3

sinLUT i sinLUT2 to wcze¶niej prekalkulowane tablice z kształtem sinus-a.

 for a = 0 to 255
  sinLUT[a]  = round( (sin(a*(360/256) * pi/180) )*64)
  sinLUT2[a] = round( (sin(a*(360/256) * pi/180) )*48)
 next a

KEFRENSBAR w Delphi.


PLOTTER

Efekt jak największej liczby poruszaj±cych się piksli po ciekawej trajektorii.


SHADE BOB

Inna odmiana plottera, tym razem stawiamy piksle jakiej¶ jedno-kolorowej bitmapy (np. 8x8 piksli) dokonuj±c operacji EOR na zawarto¶ci ekranu. Im więcej powtórzeń tym bardziej kolorowy efekt końcowy.


UNLIMITED BOBS

"Nieskończona" liczba ruchomych obiektów, czyli zapętlona animacja. Do realizacji potrzebnych jest kilka buforów pamięci (maksymalnie 8 powinno wystarczyć), każdy z takich buforów będzie wy¶wietlał inn± fazę animacji, kiedy trajektoria ruchu naszych obiektów ulega zapętleniu dostajemy złudzenie animacji, wydaje się że porusza się nieskończona liczba obiektów gdy tak naprawdę widzimy tylko kilku klatkow± animację. Trochę dodatkowych informacji na ten temat w artykule Jak stworzyć ciekawe efekty?


X-ROTATOR

Efekt tocz±cego się sze¶cianu, obracanego tylko wokół jednej osi X (prawoskrętny układ współrzędnych). Jest to "udawany" obrót bo nie maj±cy wiele wspólnego z obliczeniami 3D i perspektyw±, małym nakładem wykorzystuj±c funkcję SIN-us można uzyskać efekt przypominaj±cy tocz±cy się w naszym kierunku sze¶cian.

Obliczamy tablicę sinusa sinLut dla SIZE kroków:

size         = 64          // rozmiar szescianu

 k = 0

 for i = 0 to size-1

  sinLut[i] = (round(sin(k*pi/180)*(size div 4)))

  k = k + (180 / size)

 next i

Obliczanie szeroko¶ci odcinka na podstawie sinusa, odcinek porusza się z góry na dół. Odcinki górny i dolny wyznaczaj±ce krawędzie sze¶cianu pozostaj± nieruchome.

 l = screen_width div 2 - size div 2   // lewa krawedz szescianu
 r = screen_width div 2 + size div 2   // prawa krawedz szescianu

 for anm = 0 to size-1

  u := sinLut[anm];

  Polygon( [Point(l,0), Point(r,0), Point(r+u, anm),
            Point(r, size-1), Point(l, size-1), Point(l-u, anm)] )

// poruszajacy sie odcinek symulujacy ruch bryły 
  Line( Point(l-u, anm), Point(r+u, anm) )

 next anm

Efekt ten i jego inne kombinacje najczę¶ciej wykorzystywany jest do pokazywania teksturowanych obracaj±cych się brył typu sze¶cian, prostopadło¶cian itp. w różnych konfiguracjach. Długo¶ci wszystkich odcinków znamy musimy tylko posiadać teksturę we wszystkich wariantach długo¶ci odcinka, potem tylko podmieniać odpowiednio linie aby uzyskać efekt obrotu.

Można także pokusić się o dokonanie prawdziwego obrotu 3D bryły sze¶cianu i stablicować odcinki które zostan± obliczone, na ich podstawie generować teksturowany sze¶cian, szybko¶ć działania powinna być ta sama kosztem niewiele większej zajętej pamięci na tablicę odcinków.

Tutaj przykład w Delphi obrazuj±cy obrót sze¶cianu.


FIRE EFFECT

Efekt ognia to pochodna efektu BLUR, który polega na postawieniu nowego piksla w kolorze wyliczonym na podstawie piksli s±siaduj±cych, konkretniej na podstawie ¶redniej kolorów s±siaduj±cych. Aby ogień mógł płon±ć potrzebne jest "paliwo", będ± to wstawiane do naszego bufora ognia poza widocznym obszarem piksle o najwyższej warto¶ci koloru, dzięki temu operacja blurowania będzie stale podsycana, dodatkowo losowe pozycje takich podsycaj±cych piksli wpłyn± na powstawanie mniejszych lub większych płomieni. Nic też nie szkodzi na przeszkodzie aby "palić" inne obiekty na ekranie, wektorowe druciki, napisy itp.

Przykład w pseudokodzie dla operacji ognia:

for y = 0 to height+1
 for x = 0 to width-1

  pixels[x,y] = ( pixels[x-1,y] +
                  pixels[x+1,y] +
                  pixels[x,y+1] +
                  pixels[x+1,y+1] ) >> 2
 next x
next y                  

Przykład w pseudokodzie dla operacji podsycania ognia:

x = random(width)

pixels[x,   height]   = 15
pixels[x+1, height]   = 14
pixels[x,   height+1] = 13

Dodatkowe informacje na temat efektu ognia pozwalaj±ce ulepszyć jego stronę wizualn±, upodobnić zachowanie do prawdziwego ognia.


PLASMA EFFECT

Popularny bo atrakcyjny wizulanie efekt zniekształceń sinusopodobnych. Do efektu końcowego dochodzimy najczę¶ciej metod± prób i błędów zmieniaj±c poszczególne parametry aż do uzyskania zadowalaj±cego efektu wizualnego.

Przykład w pseudokodzie wyliczenia trzech tablic typu BYTE S4[0..255], S8[0..255], S16[0..255] dla plazmy:

k = 0

for i = 0 to 255

 s16[i] = round(32*sin(k)*pi)
 s8[i]  = round(16*cos(k))
 s4[i]  = round(8*sin(k)*pi)

 k = k+6.284/128
 
next i

Warto¶ci tablic S4, S8, S16 musz± ulegać zapętleniu, sinus ze względu na swoj± okresowo¶ć jest do tego celu bardzo przydatny.

Przykład w pseudokodzie głównej pętli realizuj±cej animację plazmy (tablice XBUF, YBUF oraz pozostałe parametry towarzysz±ce ich wyliczaniu decyduj± o ostatecznym wygl±dzie plazmy):

 a1 = a1bak
 a2 = a2bak
 a3 = a3bak

(* XBUF *)
for i = 0 to width-1

 xbuf[i] = s16[a1]+s8[a2]+s4[a3]

 a1 = a1 + 1
 a2 = a2 + 2
 a3 = a3 + 4 

next i

a1bak = a1bak + 1
a2bak = a2bak + 3
a3bak = a3bak + 2

a4 = a4bak
a5 = a5bak

(* YBUF *)
for i = 0 to height-1

 ybuf[i] = s16[a4]+s8[a5]

 a4 = a4 + 1
 a5 = a5 + 3

next i

a4bak = a4bak + 1
a5bak = a5bak - 1

(* MAIN LOOP *)
for j = 0 to height-1
 for i = 0 to width-1

  pixels[i,j] = xbuf[i] + ybuf[j]

 next i
next j 

Powyższy efekt plazmy wykorzystany był m.in. w takich demach jak TIT, Ilusia, C-Drug


ROTOZOOMER / ZOOMROTATOR

Efekt obracaj±cej, powiększaj±cej i pomniejszaj±cej się bitmapy, wszystko to na podstawie wzoru obrotu punktu wokół osi Z:

 for y = 0 to height-1
   for x = 0 to width-1

     u = round(x*cos(angle)-y*(sin(angle)))
     v = round(x*sin(angle)+y*(cos(angle)))

     pixels[x,y] = texture[u,v]

   next x
  next y 

Widać że powtarzaj± się operacje mnożenia sinus i cosinus k±ta ANGLE. Aby przyspieszyć działanie potrzebne będzie stablicowanie tych powtarzaj±cych się wyników operacji. Przykład w pseudokodzie wyliczenia tablic typu WORD SIN_TABLE[0..255] i COS_TABLE[0..255] dla obrotu i skali powiększenia:

angle = (6.284/128)*96
dzo   = 0.05
zo    = dzo*21
ml    = 256       ; pozwoli zamienić ułamek w liczbę całkowit±

for a = 0 to 255

 zo = zo-dzo
 if (a mod 64) = 0
  dzo = -dzo
 endif

 sin_table[a] = round((-zo*sin(angle))*ml)

 cos_table[a] = round((-zo*cos(angle))*ml)

 angle = angle+6.284/128

next a

Tablice SIN_TABLE i COS_TABLE przechowuj± warto¶ci ułamkowe reprezentowane na 16 bitach, możliwa jest reprezentacja 8 bitowa kosztem mniejszej głębi rotozoomera, czyli większego k±ta obrotu i mniejszego zakresu powiększenia/zmniejszenia.

Przykład w pseudokodzie głównej pętli realizuj±cej animację rotozoomera (tablica z tekstur± TEXTURE[0..63, 0..63]):

 zx = sin_table[angle]
 zy = cos_table[angle]

{ centrowanie }
 fx_ = 65536-((height div 2)*(zx+zy))
 fy_ = 65536-((width div 2)*(zx-zy))

 for j = 0 to height-1

  fx = fx_
  fy = fy_

  for i = 0 to width-1
  
   pixels[i,j] = texture[(fx >> 8) mod 64 , (fy >> 8) mod 64]

   fx = fx+zx
   fy = fy-zy

  next i

  fx_ = fx_+zy
  fy_ = fy_+zx
  
 next j

Warto¶ci± całkowit± ułamków reprezentowanych na 16 bitach jest najstarszy bajt słowa, st±d operacja przesuwania o¶miu bitów w prawo '>> 8'. Modulo 'MOD 64' pomaga ograniczyć zakres X:Y dla tekstury 64x64 piksle. Je¶li pozbędziemy się operacji centrowania, ¶rodek obrotu rotozoomera znajdzie się w punkcie (0,0) obrazu. Dodatkowe efekty jak STRETCH, PERSPECTIVE uzyskuje się modyfikuj±c parametry FX_, FY_.

W demie Igor znalazł się rotozoomer z animowan± tekstur±, efekt polega na umieszczeniu danych tekstury w dodatkowych bankach pamięci i ich przeł±czaniu.

W demie TIT tekstur± rotozoomera liczonego na 8 bitowych ułamkach jest tunel.


ZOOM SCROLL

Efekt po raz pierwszy zaprezentowany w Just Fancy. Sposób jego realizacji został owiany tajemnic±, któr± rozja¶niał jeden z artykułów Barymag-a #2. Od tamtej pory powtórzony tylko w demie Recall.

Efekciarskie efekciki 2 [Soused Teat/Slight], Wiosna 1995 (Barymag #2)

Dzisiaj chcę przedstawić wam scroll nr 2 - czyli zoomer (można go zobaczyć w moim starym demie "JUST FANCY"). Do dzisiaj niewiele osób wie (nawet widz±c kod), w jaki sposób się go uzyskuje. Na pocz±tek wyja¶nię, jak każdy by chciał taki scroll zrobić. Pierwszym problemem, jaki napotyka jest jak rozci±gn±ć znaki w poziomie i zaraz zaczyna kombinować z LSR-owaniem lub ASL-owaniem. Ja też w ten sposób my¶lałem i nawet coraz lepiej mi szło, ale wci±ż nie było mowy o scrollu w jednej ramce. Pewnego dnia przyszło niespodziewane ol¶nienie, a gdyby tak trzymać w pamięci scrolla bokiem???. Z wolna zacz±ł się pojawiać coraz bardziej klarowny obraz póĽniejszej procedury, aż w końcu zjawił się na skrawku kartki (jak większo¶ć moich programów) pełny obraz tego jakże prostego do uzyskania efektu.

Teraz pora, żebym Ci wyja¶nił na czym polega owo "trzymanie" scrolla bokiem. Załóżmy, że zwykłego scrolla chcemy zrobić graficznie, czyli litery z rolowanego bufora będziemy przepisywać na ekran, uzyskuj±c efekt "przesuwu poziomego". I teraz... jak wygl±da litera "A" w takim scrollu rozpisana na bity, każdy chyba wie:

     ........ bajt nr 0
     ...**... bajt nr 1
     ..****.. bajt nr 2
     .**..**. bajt nr 3
     .**..**. bajt nr 4
     .******. bajt nr 5
     .**..**. bajt nr 6
     ........ bajt nr 7

...co dla tekstu, np. "ALA" będzie wygl±dać tak:

             bajt         bajt         bajt

     ........ $00 ........ $08 ........ $10
     ...**... $01 .**..... $09 ...**... $11
     ..****.. $02 .**..... $0A ..****.. $12
     .**..**. $03 .**..... $0B .**..**. $13
     .**..**. $04 .**..... $0C .**..**. $14
     .******. $05 .**..... $0D .******. $15
     .**..**. $06 .******. $0E .**..**. $16
     ........ $07 ........ $0F ........ $17

W zoomscrollerze musimy zmienić nieco nasze przyzwyczajenie i zorganizować bufor tak, aby litera "A" wygl±dała następuj±co:

     ........ bajt nr 0
     .****... bajt nr 1
     .*****.. bajt nr 2
     ..*..**. bajt nr 3
     ..*..**. bajt nr 4
     .*****.. bajt nr 5
     .****... bajt nr 6
     ........ bajt nr 7

...czyli tekst "ALA" będzie teraz wygl±dał tak:

             bajt         bajt         bajt

     ........ $00 ........ $08 ........ $10
     .****... $01 .******. $09 .****... $11
     .*****.. $02 .******. $0A .*****.. $12
     ..*..**. $03 .*...... $0B ..*..**. $13
     ..*..**. $04 .*...... $0C ..*..**. $14
     .*****.. $05 .*...... $0D .*****.. $15
     .****... $06 .*...... $0E .****... $16
     ........ $07 ........ $0F ........ $17

Taki bufor oczywi¶cie trzeba odpowiednio przepisać na ekran, co załatwi taka oto procedurka:

     LDA BUFOR+$00
     ASL A
     ROL ZERO_PAGE+$00
     ASL A
     ROL ZERO_PAGE+$01  ...

...i tak dalej, żeby wyszedł jeden słupek bitów na ekranie, np.

     0xxxxxxx
     1xxxxxxx
     1xxxxxxx
     1xxxxxxx
     0xxxxxxx
     1xxxxxxx
     0xxxxxxx
     0xxxxxxx

Następnie:

     LDA BUFOR+$01
     ASL A

I tak powtarzamy to dla o¶miu bajtów bufora. Na końcu przepisujemy komórki ZERO_PAGE na ekran. W ten sposób przepisujemy 8 linii po 256 punktów. Oczywi¶cie takim przepisywaniem nie uzyskamy efektu zoomera, więc musimy wcze¶niej przygotować tablicę, w której indeksem jest numer kolumny punktów na ekranie, a warto¶ci± w tablicy jest odpowiadaj±cy jej numer bajtu w buforze. Do naszej procedury dopisujemy przed każdym "LDA" LDX TABLICA:

     LDX TABLICA
     LDA BUFOR,X
     ASL A  ...

...a cało¶ć smarujemy hektarem kodu, który będzie rysował odpowiednio na ekranie. Ponieważ mamy do czynienia z komputerem posiadaj±cym co¶ takiego, jak DList, to "rozci±ganie" w pionie uzyskujemy wła¶nie na nim. Ponieważ, jak już wcze¶niej zaznaczyłem, artykuł ten jest dla Bn¦Z (Bardziej niż ¦rednio Zaawansowanych), nie muszę tłumaczyć w jaki sposób wyliczać TABLICĘ (chociaż muszę powiedzieć od razu, że w "JUST FANCY" nie wykorzystałem dzielenia, przez co upro¶ciłem sobie procedurę).


CHESS ZOOMROTATOR

Modyfikacja głównej pętli renderuj±cej ZOOMROTATOR-a pozwala na uzyskanie obracaj±cej i powiększaj±cej się szachownicy bez potrzeby używania dodatkowych bitmap z tekstur±. Efektown± modyfikacj± tego efektu jest CHESS ZOOMER realizowany na kilku nachodz±cych na siebie "bitplanach".

  zx = sin_table[angle]
  zy = cos_table[angle]

  { konieczne centrowanie aby zachować symetrię względem ¶rodka ekranu }
  fx_ = 65536-((width div 2)*(zx+zy))
  fy_ = 65536-((height div 2)*(zx-zy))

   for j = 0 to height-1

      fx = fx_
      fy = fy_

      for i = 0 to width-1

       if (fx xor fy) >> 8 and $10 = 0
        Pixels[i,j] = $ff
       else
        Pixels[i,j] = $00
       endif

       fx = fx+zx      ; zaremować dla CHESS ZOOMER-a
       fy = fy-zy

      next i

      fx_ = fx_+zy
      fy_ = fy_+zx     ; zaremować dla CHESS ZOOMER-a

   next j

W tym samym przebiegu stawiamy i kasujemy odpowiednie piksle. Kolor pikseli determinuje wynik operacji XOR na warto¶ciach całkowitych (najstarszy bajt) ułamków przyrostów X i Y.

CHESS ZOOMER najbardziej podatny jest na optymalizację ze względu na powtarzaj±ce się linie poziome, dobrym tego przykładem jest jedna z czę¶ci dema Just Fancy.

Inn± wła¶ciwo¶ci± sprzyjaj±c± przyspieszeniu tworzenia tego efektu jest to że każd± klatkę niezależnie od skali powiększenia możemy zaprezentować za pomoc± 16 kombinacji bloków 2x2 piksele.

; piksle (0,0) (1,0) (0,1) (1,1)

00,00,00,00
00,00,00,FF
00,00,FF,00
00,00,FF,FF
00,FF,00,00
00,FF,00,FF
00,FF,FF,00
00,FF,FF,FF
FF,00,00,00
FF,00,00,FF
FF,00,FF,00
FF,00,FF,FF
FF,FF,00,00
FF,FF,00,FF
FF,FF,FF,00
FF,FF,FF,FF

Dodatkowo je¶li nie używamy efektu STRETCH tylko zachowujemy symetryczno¶ć względem ¶rodka ekranu możemy zauważyć że dolna czę¶ć szachownicy jest odbiciem lustrzanym górnej czę¶ci, dodatkowo prawa górna ćwiartka jest odbiciem lewej ćwiartki obróconej o 90 stotpni i zanegowanej, wystarczy więc generować tylko jedn± ćwiartkę szachownicy a pozostałe odpowiednio skopiować. Warunkiem powodzenia dla kopiowania symetrycznego jest ta sama wysoko¶ć i szeroko¶ć szachownicy, np. width=128, height=128.

Stworzenie prawej górnej ćwiartki obrazu poprzez obrót o 90 stopni i negację lewej górnej ćwiartki:

 for j = 0 to height div 2 - 1
 
  for i = 0 to width div 2-1 do
  
   Pixels[width-i-1,j] = Pixels[j,i] xor $ff
   
  next i
 
 next j

Kopiowanie ostatnich dwóch dolnych ćwiartek obrazu:

 for j = 0 to height div 2 - 1

  for i = 0 to width - 1

   Pixels[width-i-1,height-j-1] = Pixels[i,j]

  next i

 next j

Warto też zwrócić uwagę że nie trzeba wykonywać pełnego obrotu, wystarczy obrót o 90 stopni, reszta się powtarza tylko jest w inwersie. W przypadku XE/XL oznacza to że po obrocie o 90 stopni zamieniamy kolory w rejestrach na przeciwne i powtarzamy ten sam obrót o 90 stopni, animacja ulega zapętleniu.

CHESS ZOOMROTATOR w Delphi.


FILL RECTANGLE

Wypełnianie czworok±tów. Dysponuj±c przeliczonymi k±tami obrotu w zakresie 90 stopni można wyrysować czworok±t o zadanej długo¶ci boku.

 zx:=txB[byt mod 16];
 zy:=tyB[byt mod 16];


 for dir := 0 to 3 do begin

  case dir of
   1: miny:=fy shr 8;
   3: maxy:=fy shr 8;
  end;

 for i := 0 to len-1 do begin

  case dir of
   0: begin
       fx:=fx+zx;
       fy:=fy-zy;

       edge[fy shr 8]:=fx shr 8;
      end;

   1: begin
       fx:=fx+zy;
       fy:=fy+zx;

       edge[$100+fy shr 8]:=fx shr 8;
      end;

   2: begin
       fx:=fx-zx;
       fy:=fy+zy;

       edge[$100+fy shr 8]:=fx shr 8;
      end;

   3: begin
       fx:=fx-zy;
       fy:=fy-zx;

       edge[fy shr 8]:=fx shr 8;
      end;

  end;

 end;

 end;  

LENS EFFECT

Efekt powiększenia soczewki albo mapowanie powierzchni sferycznej. Podstaw± dla tego efektu jest tablica TFM typu WORD, starszy bajt takiej tablicy będzie pozycj± poziom± tekstury, młodszy bajt pozycj± pionow±. Parametrami s± promień soczewki RADIUS i moc powiększenia POWER.

 s = sqrt( sqr(radius) - sqr(power) )

 for y = -radius to radius-1
  for x = -radius to radius-1

        if x*x+y*y >= s*s
          A = X
          B = Y
        else
          Z = sqrt( sqr(radius)- sqr(x) - sqr(y) )
          A = round(X*power/Z)
          B = round(Y*power/Z)
        endif

       tfm[x+radius , y+radius] = (b+radius) + (a+radius) << 8

  next x
 next y

Dysponuj±c tablic± z prekalkulowanymi współrzędnymi tekstury możemy wyrenderować efekt (parametry PX i PY pozwalaj± ustalić dodatkow± trajektorię poruszania się soczewki):

 for y = 0 to radius << 1-1
  for x = 0 to radius << 1-1

    u = tfm[ x,y ] >> 8
    v = tfm[ x,y ] and $ff

    pixels[x + px, y + py] = texture[u + px, v + py]

  next x
 next y

Tutaj przykład w Delphi realizacji efektu soczewki.


2D BUMP MAPPING

Mapowanie wypukło¶ci, efekt podobny obliczeniowo do efektu ognia, z t± różnic± że w obliczeniach kolejnych piksli bierze udział dodatkowa tablica z tekstur± ¶wiatła.

Tablicę TLIGHT z tekstur± ¶wiatła liczymy na podstawie odległo¶ci punktu od ¶rodka okręgu - wzór Pitagorasa (LIGHT definiuje maksymalny promień okręgu):

 for y = 0 to light-1
  for x = 0 to light-1

   dist = (light div 2) - round(sqrt( sqr(x-light div 2) + sqr(y-light div 2))) - 1

   if dist<0
    dist = 0
   endif

   tlight[x,y] = dist

  next x
 next y

Obliczamy ofset poziomy XDIF i pionowy YDIF na podstawie piksli tekstury, obliczone warto¶ci posłuż± nam do odczytania koloru z tablicy tekstury ¶wiatła TLIGHT:

 for y = 1 to height-2
  for x = 1 to width-2

   xdif = texture[x+1,y] - texture[x-1,y]
   ydif = texture[x,y+1] - texture[x,y-1]

   pixels[x,y] = tlight[xdif+x, ydif+y]

  next x
 next y
 

Przykład w Delphi realizacji efektu Bump Mapping-u dla tekstury w 16 odcieniach szaro¶ci.


TWIRL

Efekt wiruj±cej tekstury, polegaj±cy na przedstawieniu dwuwymiarowej tekstury za pomoc± koncentrycznych okręgów których ¶rodek leży w ¶rodku symetrii takiej tekstury. Dzięki odpowiednio wyliczonym tablicom ANGLES, RADIUSES oraz odpowiednio przeliczonej tablicy z tekstur± OUTPUT_TEXTURE mamy kontrolę nad każdym takim okręgiem, możemy taki okręg z tekstur± obracać o zadany k±t. Je¶li k±t obrotu będzie stały dla każdego z okręgów uzyskamy zwykły efekt obrotu tekstury, je¶li k±t obrotu będzie odpowiednio wzrastał dla każdego kolejnego okręgu uzyskamy efekt wiruj±cej tekstury. Twirl można "ożenić" z Wormhol-em albo innym efektem korzystaj±cym z "lookup tables". Taka tablica generuj±ca klatkę "zakręconego" tunelu będzie poddawana przeliczeniu z użyciem Twirl-a uzyskuj±c efekt obracaj±cego się Wormhola. Po odpowiednich modyfikacjach kilkana¶cie wygenerowanych tablic efektu Twirl dla różnych rozmiarów okna obrazu złoży się na szybki efekt zoomrotatora (Warto nadmienić, że o bardzo kiepskiej precyzji skalowania. Do poprawy potrzeba byłoby dużych ilo¶ci pamięci, na które nie stać maluszka. - przypis Konop/Shadows). Inne zastosowania można odnaleĽć eksperymentuj±c z główn± pętl± renderuj±c± efekt Twirl.

Przykład obliczeń dla tablic ANGLES, RADIUSES (opracował Konop/Shadows):

  max_radius = sqrt( sqr(picture_size_x div 2) + sqr(picture_size_y div 2) )

  for y = 0 to picture_size_y-1 

    y_screen = -(y - (picture_size_y div 2))

    for x = 0 to picture_size_x-1

      x_screen   = x - (picture_size_x div 2)

      angle      = ArcTan2(y_screen, x_screen)
      angle      = angle / (2.0 * pi)
      angle_int  = round(angle * circle_steps)

      radius     = sqrt(x_screen * x_screen + y_screen * y_screen)
      radius     = radius / (max_radius * sqrt(2))
      radius_int = round(radius * (max_radiuses-1))

      angles[x, y]   = angle_int
      radiuses[x, y] = radius_int

    next x

  next y

Przykład przeliczenia tekstury, odczytane kolejno piksle TEXTURE_INPUT po okręgu zostaj± zapisane liniowo do TEXTURE_OUTPUT (opracował Konop/Shadows):

 for r = 0 to max_radiuses-1
  for a = 0 to circle_steps-1

    angle = a / circle_steps
    angle = angle * 2.0 * pi

    x = cos(angle) * r
    y = sin(angle) * r

    x_int = round(x) + texture_size_x div 2
    y_int = round(y) + texture_size_y div 2

    output_texture[a,r] = input_texture[x_int, y_int]

  next a
 next r

Renderowanie klatki efektu będzie polegało na odczytaniu aktualnie rysowanego numeru okręgu z tablicy RADIUSES, odczytana warto¶ć będzie indeksem do tablicy z 16-bitowymi ułamkami reprezentuj±cymi prędko¶ć SPEED [0..MAX_RADIUSES-1], starszy bajt (warto¶ć całkowita z ułamka 16-bit) odczytanej prędko¶ci dodamy do aktualnego k±ta obrotu odczytanego z tablicy ANGLES.

  for y = 0 to picture_size_y  
   for x = 0 to picture_size_x

    rad = radiuses[x,y]

    add = speed[rad] >> 8

    c = output_texture[ byte(angles[x,y] + add) , rad ]

    pixels[x,y] = c

   next x
  next y

Po zakończeniu renderowania klatki efektu potrzebujemy już tylko uaktualnić tablicę z prędko¶ciami SPEED, w tym celu warto¶ci tej tablicy podbijamy o prekalkulowane warto¶ci tablicy z ułamkami precyzji 16-bit ADDITION [0..511], zawieraj±cej sinusopodobne warto¶ci gwarantuj±ce okresowo¶ć ruchu twirla. Tablice SPEED i ADDITION można zrealizować także z precyzj± 8-bitow±, odbije się to jednak na mniejszej dynamice efektu.

  for i = 0 to max_radiuses-1 
  
   speed[i] = WORD( speed[i] + addition[i+i+anm] )
   
  next i

  anm = anm + 1	

Program w Delphi Twirl prezentuj±cy "zakręcon±" i "zwykł±" wersję obrotu tekstury.


SIERPINSKI FRACTALS

Na stronie Lode's Computer Graphics Tutorial podane zostały różne sposoby na uzyskanie efektu trójk±ta i dywanu Sierpińskiego. Poniżej przykłady najszybszych metod, które s± w zasięgu możliwo¶ci XE/XL.

Trójk±t:

 for  y = 0 to height - 1
  for x = 0 to width - 1

   if x and y = 0
    pixels[x,y] = clWhite
   else
    pixels[x,y] = clBlack
   endif

  next x
 next y

Dywan, który jest ciekawszy wzorniczo od trók±ta i jak pokazuje intro "Unlimited drunk carpet" Epi/Tristesse można wykorzystać go do generowania tekstury.


 for  y = 0 to height - 1
  for x = 0 to width - 1

        if
            //Not both the first (rightmost) digits are '1' in base 3
            not( ((x mod 3)=1) and ((y mod 3)=1) )

            and

            //Not both the second digits are '1' in base 3
            not( ((x div 3) mod 3=1) and ((y div 3) mod 3=1) )

            and

            //Not both the third digits are '1' in base 3
            not( ((x div 9) mod 3=1) and ((y div 9) mod 3=1) )

            and

            //Not both the fourth digits are '1' in base 3
            not( ((x div 27) mod 3=1) and ((y div 27) mod 3=1) )

            and

            //Not both the fourth digits are '1' in base 3
            not( ((x div 81) mod 3=1) and ((y div 81) mod 3=1) )

             pixels[x,y] = clWhite

            else

             pixels[x,y] = clBlack
             
        endif    

  next x
 next y

Dla powyższego przykładu aż prosi się aby stworzyć pięć tablic z prekalkulowanymi warto¶ciami operacji <0..255> div [1,3,9,27,81] mod 3.

Program w Delphi Fraktal Sierpinskiego prezentuj±cy działanie obu powyższych algorytmów.


WATER / RAIN EFFECT

Ciekawy, mało spotykany efekt zniekształcenia symuluj±cy rozchodz±ce się fale na wodzie. Mało spotykany na platformie 8-bit ze względu na liczbę obliczeń i zapotrzebowania pamięci. Główna pętla renderuj±ca efekt przypomina t± z Bump-a, a obliczenia efektu wody to rozbudowana wersja obliczeń dla efektu ognia. Aby efekt zadziałał potrzebne s± dwie tablice wielko¶ci okna ekranu, w pierwszym przebiegu będziemy przeprowadzać operacje na tablicy 1 i 2, w kolejnym na tablicy 2 i 1, czyli będziemy zamieniać je miejscami. Obie tablice służ±ce obliczeniom efektu wody s± typu SHORTINT (-128..127).

Pętla realizuj±ca obliczenia efektu wody, przypomina t± z efektu ognia (DENSITY <1..8> wpływa na wielko¶ć rozchodz±cej się fali), obliczenia dokonywane s± na o¶miu pikslach co zapewnia ładniejszy efekt, mniejsza liczba piksli to większa szybko¶ć działania kosztem efektu wizualnego:

; CALC_WATER (SOURCE, DEST)

 for y = 1 to height-2
  for x = 1 to width-2

      pixel = (source[x,y+1]
             + source[x,y-1]
             + source[x+1,y]
             + source[x-1,y]
             + source[x-1,y-1]
             + source[x+1, y-1]
             + source[x-1, y+1]
             + source[x+1, y+1]

             - dest[x,y] << 2 ) >> 2

   dest[x,y] =  pixel  - (pixel >> density)
   
  next x
 next y

Pętla renderuj±ca efekt wody, przypomina t± z efektu bumpa (TEXTURE o rozmiarze okna ekranu to tablica z bitmap± na któr± spadaj± krople wody):

; DRAW_WATER (SOURCE)

 for y = 1 to height-2
  for x = 1 to width-2

      dx = source[x-1,y] - source[x+1,y]
      dy = source[x,y-1] - source[x,y+1]

      pixels[x,y] = texture[x+dx , y+dy]

  next x
 next y

Postawienie kropli wody, wystarczy je stawiać tylko w pierwszym buforze:

; DROP_WATER (SOURCE)

  x = random(width-2) + 1
  y = random(height-2) + 1
  
  drop = random(128)
  
  source[x,y]   = drop
  source[x-1,y] = drop
  source[x+1,y] = drop
  source[x,y-1] = drop
  source[x,y+1] = drop

Główna pętla zarz±dzaj±ca wywołaniami CALC_WATER, DRAW_WATER, DROP_WATER (zmienna SWITCH typu BOOLEAN pomaga przeł±czać kolejno¶ć operacji dokonywanych na buforach), jedno wywołanie tej pętli to jedna klatka obrazu z efektem wody:

loop

  drop_water(buf1)
  
  if switch

   calc_water(buf1, buf2)
   draw_water(buf2)

  else

   calc_water(buf2, buf1)
   draw_water(buf1)

  endif 

  switch = !switch	
	
goto loop

Tutaj przykład w Delphi realizacji powyższego pseudo kodu.

Dodatkowe informacje na temat genezy i sposobu działania efektu wody http://freespace.virgin.net/hugo.elias/graphics/x_water.htm


METABALLS / BLOBS

Efekt poruszaj±cych się blobów obdarzonych energi±, któr± oddziaływuj± na inne bloby. Efekt nie jest zbyt popularny na 8-bitowym sprzęcie pewnie ze względu na liczbę obliczeń jakie s± wykonywane, przynajmniej w tej podstawowej metodzie "brute force". Metoda ta polega na obliczeniu dla każdego piksla obrazu odległo¶ci od ¶rodka bloba, na tej podstawie liczona jest "energia"/"gęsto¶ć" blobów któr± sumujemy i reprezentujemy w postaci koloru. Szybko¶ć działania jest tutaj ograniczona poprzez rozmiar okna i liczbę blobów.

 for y = 0 to height - 1
  for x = 0 to width - 1

   pixel_brightness = 0

   for i = 0 to number_of_blobs - 1

    u = x - blobs[i].x
    v = y - blobs[i].y

    distance = sqrt ( sqr(u) + sqr(v) )

    if distance > blobs[i].r
     density = 0
    else
     fraction = sqr(distance / blobs[i].r)
     density = round(sqr(1-fraction)*256)
    endif

    pixel_brightness = (pixel_brightness+density) mod 160

   next i

   pixels[x,y] = pixel_brightness

  nexy x
 nexy y

Tablica BLOBS zawiera informację o pozycji X:Y bloba oraz jego ¶rednicy R (niektórzy nazywaj± to mas±), w powyższym przykładzie nie s± wykorzystywane żadne tekstury ¶wiatła, tylko prymitywne obliczenia z udziałem pierwiastkowania (SQRT), potęgowania (SQR), dzielenia, mnożenia, czyli wszystko to czego chcieliby¶my się pozbyć aby była realna szansa przeniesienia tego efektu na XE/XL. Spore pole do popisu dla programisty, sposobów realizacji znowu może być wiele, np. podzielenie ekranu na kwadraty, wyznaczenie wspólnych obszarów i dokonywania obliczeń tylko w tych obszarach. Bardziej realnie dla XE/XL będzie je¶li co¶ stablicujemy.

Pierwszym założeniem jakie możemy przyj±ć to stała ¶rednica bloba RADIUS, możemy też trochę skrócić obliczenia, doprowadzaj±c je do postaci któr± można zast±pić tablic± "lookup table" TDENSITY typu BYTE reprezentuj±c± ułamki.

for y = 0 to height - 1
 for x = 0 to width - 1

    distance = sqrt ( sqr(x) + sqr(y) )

    if distance < radius
     g = 1
    else
     g = radius / distance
    endif

    tdensity[x, y] = round(g * 64)

 next x
next y 

Teraz pozostały nam już tylko operacje dodawania, odejmowania oraz funkcja ABS (warto¶ć absolutna bez znaku) wykonywane tylko na bajtach, wszystko to kosztem tablicy TDENSITY której rozmiar zależny jest od wielko¶ci okna, np. dla ekranu w±skiego i trybu Konopa 64x64 piksle tablica zajmie 4KB.

 for y = 0 to height - 1
  for x = 0 to width - 1

   density = 0

   for i = 0 to number_of_blobs - 1

    u = abs(x - blobs[i].x)
    v = abs(y - blobs[i].y)

    density = density + tdensity[u, v]

   next i

   if density > 96
    c = 255
   else
    c = 0
   endif

   pixels[x,y] = c

  next x
 next y

Tutaj przykład w Delphi działania obu powyższych przykładów, PLOBS.EXE i szybki FBLOBS.EXE który da się przenie¶ć na platformę 8-bit.


TEXTURE-MAPPED TUNNEL

Tunnel, Wormhole, Ceiling-Floor opieraj± swoje działanie na odpowiednio wyliczonej tablicy z indeksami do tablicy tekstury. Tablicę wyliczamy dokonuj±c przeliczenia współrzędnych układu kartezjańskiego na współrzędne układu biegunowego (polarnego).

W przypadku tablicy dla tunelu "na wprost" możliwa jest optymalizacja polegaj±ca na przechowywaniu w pamięci tylko ćwiartki tablicy, resztę można skopiować poprzez lustrzane odbicia, albo wygenerować tylko ćwiartkę obrazu a pozostałe fragmenty generować poddaj±c bajty/linie obrazu odpowiednim transformacjom.

Jak w większo¶ci przypadków różnych efektów 2D, duża złożono¶ć obliczeniowa dla tunelu to iluzja, można go zrealizować na skróty, w sposób daj±cy dodatkowe możliwo¶ci realizacji innych efektów np. Ceiling-Floor (efekt poruszanie się po przestrzeni ograniczonej z góry sufitem, z dołu podłog±).

Aby stworzyć tunel i jemu podobne efekty potrzebujemy "wyrysować" dwie tablice. W przypadku tunelu pierwsza tablica będzie zawierać koncentryczne okręgi, druga promienie wychodz±ce z centrum. Istotne jest aby kolejne okręgi, promienie rysować innym coraz większym "kolorem", np. z zakresu 0..15 dla tekstur 16x16 piksli. Te dwie tablice dadz± nam indeks (współrzędne X:Y) do tekstury tunelu. Efekt ruchu uzyskujemy zwiększaj±c/zmniejszaj±c indeks, +1, -1, +16, -16 dla tekstury o rozmiarze 16x16 pikseli. Aby uzyskać dodatkowy efekt ruchu gdzie ¶ciany tunelu przemieszczaj± się po całej widocznej powierzchni ekranu musimy wygenerować tablice większe niż rozmiar ekranu. Potem już tylko odpowiednio ustawiać punkt pocz±tkowy X:Y odczytu naszej dużej tablicy indeksów tekstury tunelu.

Dla efektu Ceiling-Floor tablica z promieniami zostaje, zmieniamy tablicę z okręgami na tablicę z liniami poziomymi odpowiednio "wyrysowanymi" dla sufitu i podłogi. Możemy pokusić się o inne kształty, zamiast okręgów "rysować" kwadraty, albo inne wielok±ty, zniekształcone okręgi, elipsy.

Kiedy mamy już nasze obie tablice, wyrysowanie tunelu jest proste, przykład w pseudo kodzie:

 for y = 0 to height-1
  for x = 0 to width-1

   u = circles[x,y]
   v = rays[x,y]

   pixels[x,y] = texture[u,v]

  next x
 next y 

Przykład programu w Delphi realizuj±cego TUNNEL na trzy różne sposoby oraz WORMHOLE, efektem działania jest 16KB plik TUNNEL.DAT z tablic± dla ekranu 128x128, młodszy nibbl bajtu takiej tablicy to pozycja pozioma dla tekstury, starszy nibbl pozycja pionowa dla tekstury.

W przypadku tunelu można zauważyć że poszczególne metody prezentowane w zał±czonym pliku różni± się jako¶ci± odwzorowania głębi oraz symetrii, najlepiej wypada metoda #2. W przypadku metody #1 powstaje najmniej zakłóceń-mory po¶rodku tunelu.

Opisy tego efektu na innych stronach http://benryves.com/tutorials/tunnel/, Lode's Computer Graphics Tutorial


TWISTER

Efekt obracaj±cego się prostopadło¶cianu, który sprowadza się do stworzenia tablicy z wyliczonymi klatkami pełnego obrotu jednej linii, następnie kolejne linie s± już tylko kopiowane na ekran z takiej tablicy wg k±ta obrotu. Można też sobie utrudnić, w demie Ilusia klatki obrotu linii zostały wyliczone na podstawie obrotu 3D płaszczyzny przecinaj±cej prostopadło¶cian z perspektyw±, na tej podstawie powstała tablica z informacj± o kolejnych widocznych pikselach tekstury. Dla każdego k±ta obrotu na podstawie wyliczonych tablic została wygenerowana osobna procedura realizuj±ca tworzenie linii obrazu. Takie podej¶cie pozwoliło na realizację twistera z tekstur± plazmy liczonej w czasie rzeczywistym.

Sposobów realizacji może być wiele, jednak koniec końców cało¶ć sprowadza się do obrotu 4 punktów, perspektywę możemy sobie darować ze względu na nisk± rozdzielczo¶ć.

Przykład twistera w pseudo kodzie:

ang = 0.0

damp = 0.02

amp = 0.0

loop

  clear_screen;

  for a = 0 to height-1

   x1 = round(((Sin(((a*amp)*pi/180)+ang))*40)+160)
   x2 = round(((Sin(((a*amp)*pi/180)+ang+90*pi/180))*40)+160)
   x3 = round(((Sin(((a*amp)*pi/180)+ang+90*2*pi/180))*40)+160)
   x4 = round(((Sin(((a*amp)*pi/180)+ang+90*3*pi/180))*40)+160)

   if x1<x2
    color = clRed
    line( point(x1,a), point(x2,a) )
   endif

   if x2<x3
    color = clYellow
    line( point(x2,a), point(x3,a) )
   endif

   if x3<x4
    color = clGreen   
    line( point(x3,a), point(x4,a) )
   endif

   if x4<x1
    color = clBlue
    line( point(x4,a), point(x1,a) )
   endif

  next a

  ang = ang+0.3

  amp = amp+damp

  if (amp>1) or (amp<-1)
   damp = -damp
  endif

goto loop

Powyższy kod udostępnia informację o długo¶ci odcinków które mamy wyrysować, daje to podstawę do teksturowania twistera.

Tutaj powyższy przykład kodu twistera w Delphi.

 

madteam.atari8.info © MadTeam, hosted: www.atari8.info