• Welcome to Forum graficzne Burning-Brushes.pl. Please log in or sign up.
 

Trochę o pisaniu skryptów w apophysis

Zaczęty przez Abik, Styczeń 01, 2012, 23:02:17

Poprzedni wątek - Następny wątek
Siema! Witam wszystkich bardzo serdecznie w nowym moim tutorialu, w którym nauczymy się pisać skrypty do wybitnego programu jakim jest Apophysis (zwłaszcza w wersji 7X, której używam). Tak prawdę mówiąc, nie kojarzę żadnego polskiego tutoriala opisującego dokładnie o tym o czym będziemy tu sobie gadać, więc najprawdopodobniej nie ma u nas na to zapotrzebowania, ale jak na speca do zadań specjalnych i takich, którymi nikt inny się nie zajmuje czuję się zobowiązany przedstawić wam jak sytuacja ze skryptami w apo wygląda.
Po co i o co w ogóle chodzi? Otóż jak dobrze wiecie (a jak nie to zapraszam do mojego wcześniejszego tutoriala na temat apo) w apo możemy tworzyć i edytować fraktale. Są one ekstremalnie użytecznym materiałem do tworzenia mgławic w space artach, dlatego też się tym trochę bliżej zainteresowałem. Stworzenie, albo raczej zedytowanie na własne (w domyśle moje :p) potrzeby fraktala jest w apo bajecznie łatwe przy odrobinie poznania programu. Jeśli chcemy tworzyć jakieś konkretne efekty z premedytacją to już bywa trudniej, mimo wszystko apophysis to dziewiąty cud świata (ósmy cud to ja) i warto poświęcić mu czas (mi też :D ).
No ale dobra, takie sranie w banie... tutaj będziemy tworzyć skrypty. Skrypty to takie małe programiki, które zawierają specjalne komendy, które wykonać może apo. Pisząc skrypt możemy zautomatyzować wiele czynności i mamy kontrolę nad fraktalem praktycznie taką samą jak poprzez graficzny interfejs. Świetnie się skrypty spisują też przy tworzeniu animacji. Tak! Animowane fraktale, wyobrażacie to sobie? Genialna sprawa, trochę przypomina wizualizacje muzyki z winampa, pamięta ktoś taki gadżet (te wizualizacje, a nie winampa :p)? Nie wiem czy tego się jeszcze dziś używa, ale fraktale animowane wygląda nawet jeszcze lepiej! Nie wiem czym w tym tutorialu ruszymy temat animacji czy nie, ale przynajmniej będziecie mieć jakieś podstawy, żeby coś w tym kierunku ruszyć, a może nawet bym... albo nie ważne, później o tym pogadamy!
W apo do pisania skryptów wykorzystujemy język bardzo zbliżony do tzw. pascala, który swego czasu był dość popularny. Czy to dobrze czy źle, że to akurat ten język, a nie inny to już pozostawiam wam do oceny. Ilość i różnorodność skryptów jakie powstają do apo świadczy o tym, że raczej nie stanowi to większego problemu, jeśli tylko się chce.
Nie wiem na ile ten tutek będzie zrozumiały dla osób, które nigdy nie miały do czynienia z programowaniem. Postaram się to opisywać w miarę jasny sposób, ale nie mogę obiecać, że wszystko będzie proste i oczywiste, ale jestem pewien, że warto spróbować i nie poddawać się zbyt szybko bo nie jest to żadna ezoteryczna i tajemna wiedza. Każdy może pisać skrypty do apo!

1.Gdzie te skrypty w apo są?
No dobre pytanie, my tu gadu gadu, ale gdzie je pisać, jak uruchamiać itp. itd. Włączcie apo i tam w  pasku narzędziowym znajdziecie taką ikonkę:

(ten zielony przycisk obok przypominający ,,play" pozwala uruchamiać aktualnie załadowany skrypt, a ten jeszcze bardziej obok pozwala je zatrzymywać)
Wciśnijcie ją, a zobaczycie takie oto okienko:

Fajne nie? Tu się pisze skrypty, w tym dużym białym polu. Te przyciski po boku są dość jasne chyba, pierwszy od góry to tworzenie nowego skryptu, niżej jest otwieranie istniejącego, jeszcze niżej zapisywanie, jeszcze niżej uruchamianie i zatrzymywanie. Prosta sprawa.

2.Czy tu w ogóle coś działa?
Zróbmy sobie taki mały test żeby mieć pewność, że to działa. Po pierwsze otwórzmy sobie okno transform editora, trzeba kliknąć tutaj jak nie wiecie o czym mówię:

W tym oknie w największej jego części z tą siatką fajową są trójkąty. Ich liczba jest różna zależnie od waszego fraktala, ale to jest nieistotne. Kliknijcie sobie na jeden z trójkątów. Każdy z nich to tzw. ,,transform", kliknięcie na niego spowoduje uczynienie go aktywnym, co wykorzystamy w naszym testowym skrypcie.
Nie zamykajcie transform editora, tylko przesuńcie tak żeby nie zasłaniał wam całego fraktala, ale tak żebyście go też widzieli i włączcie sobie okno do wpisywania skryptów. Tam wpiszcie:
rotate(90);
Co to oznacza zaraz się dowiemy, a może sami zczaicie, ale najpierw spójrzcie na pozycję waszego zaznaczonego transforma i spróbujcie ją zapamiętać. Wciśnijcie przycisk uruchamiający skrypt (Raz tylko!)... widać zmiany? Zarówno we fraktalu jak i w transformie? Funkcja rotate obraca aktywny transform (ktywny jest ten który oczywiście wybraliśmy) o tyle stopni ile podamy, w naszym przypadku 90. Uruchomcie skrypt jeszcze trzy razy (łącznie 4 razem z pierwszym, który mamy za sobą), a zobaczycie, że nasz fraktal znów wygląda tak samo, a transform jest znów w pierwotnej pozycji. A to znaczy, że wszystko działa!
Sami zobaczcie (ten żółty transform):

Hmm, no dobra, źle się wyraziłem, po czterech razach transform nie wróci na pierwotne miejsce, potrzebny byłby jeszcze piąty, ale czaicie o co chodzi. Wybaczcie tą nieścisłość, ale sam uczę się z wami!

3.Co jeszcze można zrobić z transformami?
Wiemy gdzie pisać skrypty, jak je obsłużyć, wiemy, że działają, czas zacząć prawdziwą zabawę. Wielką fraktalną imprezę zaczniemy od dokładne poznania transformów.
W skryptach możemy zrobić z nimi bardzo wiele, ale po pierwsze musimy jakiegoś transforma wybrać. Oczywiście możemy robić to za każdym razem w transform editorze i to czasem może być rozsądne zachowanie, ale najczęściej byłoby to bardzo niewygodne. Dlatego mamy do dyspozycji funkcję, która pozwala nam wybrać aktualnego transforma w skrypcie. Oto ona:
setActiveTransform(i);
Gdzie i to numer transforma, który chcemy wybrać. Tak przy okazji, w transform editorze numer transfroma możecie podejrzeć tutaj:

Przy czym od tej cyferki, która tam się pojawia, musicie odjąć 1. Czyli, transform pierwszy jest w skrypcie transformem numer 0, transform drugi transformem numer 1.
Ciekawe jakby tłumacze przetłumaczyli w apo nazwę transform... przekształcasz? :D
Wracając do naszej nowej funkcji. To dalej byłoby niewygodne, żeby sprawdzać numerek transforma i wpisywać do skryptu, nawet bardziej niewygodne niż to co robiliśmy wcześniej. Funkcja setActiveTransform przydaje się dużo bardziej gdy chcemy wykonać jakąś operację dla wszystkich transfromów, a taka sytuacja ma miejsce bardzo często jak się być może sami przekonacie. Na przykład jak byśmy chcieli obrócić każdy transform o 90 stopni, moglibyśmy zrobić coś takiego:
setActiveTransform(0);
rotate(90);
setActiveTransform(1);
rotate(90);

No i fajnie, to zadziała, tylko problem jest taki, że możemy mieć np. 3 transformy, 4... albo 1 i wtedy już nie jest dobrze. Chociaż i tak jest lepiej niż było.
Ale! Z pomocą przychodzi nam pętla for. Jak ktoś programował w czymkolwiek to działanie tej pętli jest dla niego oczywiste, jak ktoś nie programował to niech się teraz bardzo mocno skupi bo pętle są bardzo proste do zrozumienia pod warunkiem, że się skupi na nich.
Jak działa ta pętla for? Przyjmuje ona sobie pewną początkową wartość, którą jej nadamy. Zazwyczaj w postaci zmiennej ,,i" o wartości 0, ale możemy ją nazwać i ustawić jak chcemy, byle działało. Druga sprawa, pętla przyjmuje też pewną wartość końcową. Może ta wartość być zmienna, np. zależna od ilości transformów w pliku. No i jak już ma te wartości, to wykonuje wskazany przez nas kod (funkcje czy cokolwiek innego) dla każdej wartości pomiędzy początkową i końcową. Dla nas jest to idealna sprawa, bo jako wartość początkową moglibyśmy ustawić 0 (numer pierwszego transforma), a jako końcową wartość ilość wszystkich transformów odjąć jeden (trzeba odjąć jeden bo transformy są numerowane od 0!) i dla każdej wartości z tego przedziały wykonać obrót o 90 stopni. No to teraz jak wszystko jasne mam nadzieję, trzeba by to zapisać w skrypcie:
for i := 0 to Transforms–1 do
begin
setActiveTransform(i);
rotate(90);
end;

No i tu się dzieję trochę magi co nie? Wyjaśnijmy sobie wszystko. Po pierwsze – to działa. Jak nie wierzycie, to sprawdźcie, zresztą jak wierzycie to i tak sprawdźcie! Mamy ładne słówko ,,for", które oznacza, że mamy do czynienia z pętlą typu for. Dalej tworzymy wartość początkową, tak jak pisałem, nazywamy ją ,,i", a jej wartość ustawiamy na początku na 0. Jako wartość końcową powinniśmy mieć zgodnie z planem liczbę transformów minu jeden. I tak też jest! Apo dostarcza nam zmienną o nazwie ,,Transforms", które wartością jest liczba wszystkich transformów, bądźcie za to wdzięczni bo to ekstremalnie ułatwia wiele spraw. Dalej słowo ,,do" oznacza, że za nim pojawi się kod, który ma być wykonany przy każdym obrocie pętli. Jeśli tego kodu jest więcej niż jedna linijka, to koniecznie musimy zacząć go od słowa ,,begin" i zakończyć ,,end;", w przeciwny wypadku pętla nie będzie działać tak jak byśmy chcieli.
Teraz chyba widać już co się dzieje? Na początku nasza zmienna ,,i" ma wartość 0, to jest bardzo ważne, bo w pierwszym obrocie używamy tej wartości w funkcji setActiveTransform. Tu właśnie wybieramy transform numer 0 na aktywny, a w następnej linii kodu go obracamy. Po wykonaniu tych dwóch linii kodu, zmienna i jest zwiększana automatycznie o 1! To bardzo ważne bo dzięki temu teraz na aktywny transform wybrany będzie ten o numerze 1. Następnego obrotu pętli już nie będzie bo mamy dwa transformy, a dwa odjąć jeden, to jeden, a taką wartość już osiągnęliśmy czyli pętla się zakończy.
Moglibyśmy mieć dowolną liczbę transformów i ten skrypt będzie zawsze działał, o to chyba nam chodziło? Koniecznie musicie zaprzyjaźnić się z pętlą for, to jedno z najprzydatniejszych narzędzi, które pozwala rozwiązać wiele problemów.
Wszystko ekstra, ale na razie wychodzi na to, że transformy możemy tylko wybierać i obracać. Obracanie fajna rzecz (niekoniecznie akurat transformy) i bardzo ważna, ale niedobrze byłoby się ograniczać do niej samej. Mamy taką funkcję jak:
scale(i);
Która pozwala nam skalować transforma. Np.
scale(2);
Zwiększy transforma podwójnie, stanie się dwa razy większy niż jest. Gdybyśmy wpisali 0.5 zamiast 2, to stałby się o połowę mniejszy. To chyba proste no nie?
Mamy też coś takiego:
translate(x,y);
To teoretycznie przemieszcza transform o x jednostek względem osi x i y jednostek względem y. Teoretycznie, bo problem jest mały taki, że jeśli np. wcześniej przeskalujemy nasz transform np. o 2, to wtedy translate będzie przesuwać go o dwa razy tyle ile podamy. To samo jeśli go obrócimy, wtedy nie będzie przesuwał go względem osi x i y całego fraktala, tylko względem x i y obróconego o podany wcześniej kąt. Miejcie to na uwadze i jeśli to możliwe, przemieszczajcie transformy tak szybko jak się da bo w przeciwnym wypadku mogą wam wychodzić różne dziwactwa.

Żeby nie było nudno, w skrypcie nie musimy się ograniczać do istniejących już transformów. Możemy dodać nowe! Jest to bajecznie proste. Piszemy coś takiego:
addTransform
Voila! Mamy nowy transform. Spójrzcie sami, wygląd on tak (ten zielony):

Funkcja addTransform zawsze tworzy właśnie taki transform. ,,Właśnie taki" oznacza coś w stylu ,,czysty" czyli z domyślnymi ustawieniami, na domyślnej pozycji, możecie sobie obejrzeć w transform editorze dokładnie. Ważne jest żeby pamiętać, że w skrypcie po wywołaniu funkcji addTransform, ten nowy transform staje się natychmiast aktywny! I to na nim wykonywane są operacje. O tym trzeba pamiętać koniecznie.
Oprócz addTransform mamy coś takiego jak copyTransform. Działa to trochę podobnie. Różnica jest taka, że copyTransform tworzy nowy transform, który jest dokładną kopią tego, który był wybrany jako aktywny. Oczywiście po tym poleceniu to nowo utworzony transform staje się aktywny. Też całkiem przydatna funkcja.
Jak już ruszyliśmy temat tworzenia nowych transformów, to jak się domyślacie, powiązane z nim jest usuwanie transformów. No i mamy coś takiego jak deleteTransform, taką funkcyjkę, ale ona nie działa tak jakbyście tego chcieli. Nie usuwa aktywnego transforma, tylko zawsze ostatni na liście, przez co jej przydatność znacząco spada. No ale jeśli będziecie tworzyć transformy z sensem to ta funkcja do niczego wam się nie przyda, a transformy raczej dodaje się w konkretnym celu, a nie z myślą, żeby je później usunąć.
Co do tworzenia nowych transformów to zapiszcie sobie taki skrypcik krótki:
showMessage(intToStr(NXFORMS));
i wykonajcie.

No ale osochosi? Wyświetliliśmy zmienną NXFORMS właśnie, której wartość oznacza maksymalną liczbę transformów jakie możemy stworzyć. Ja nie mogę zmienić jej wartości, a jedynie odczytać i bardzo dobrze bo jeszcze mogłoby to spowodować różne kiksy.

To jeszcze nie koniec kombinacji z transformami. Mamy taki fajny i użyteczny obiekt o nazwie ,,Transform". On symbolizuje aktualnie aktywnego transforma i pozwala dobrać się do jego parametrów i oczywiście je edytować. W praktyce jakiś przykład może wyglądać np. tak:
Transform.a := 1;
Transform.b := 2;
Transform.c := 3;
Transform.d := 3.1;
Transform.e := 3.2;
Transform.f := 3.3; 

Widzicie prostą zasadę? Transform kropka jakiś parametr i dalej przypisujemy mu wartość. Ta kropeczka pozwala nam dopisać jakiś parametr jaki spośród tych, które obiekt Transform posiada. Co to są za parametry a, b, c, d, e, f? Nie są żadne zmyślone, naprawdę istnieją! Co one oznaczają? Wykonajcie ten skrypt, otwórzcie transform editora i przejdźcie do zakładki Transform, a sami się przekonacie:

Co to dokładnie daje to sobie sami sprawdzajcie, trening czyni mistrza, czy coś. W uproszczeniu edycja tych wartości zmienia położenie fraktala. Zwłaszcza bardzo przydatne są parametry E i F. Dzięki nim możemy przemieszczać nasze fraktale bez użycia funkcji translate (czyli bez ryzyka). Zwiększanie E o 1, ZAWSZE przesuwa cały fraktal o 1 jednostkę prawo, odjęcie 1, przesuwa w lewo. F, decyduje o przemieszczaniu w górę i w dół. A, b, c, d opisują pozycję dwóch wierzchołków  transforma względem tego głównego, zaznaczonego na biało w transform editorze.
Nie są to jedyne parametry jakie możemy zmienić w transformie. Patrzcie to:
Transform.weight :=1;
Zwiększa to ,,wagę" aktywnego transforma, czyli w praktyce jego wpływ na ogólny wygląd całego fraktala. Można by to trochę porównać do krycia warstw w programach do obróbki grafiki. W transform editorze możecie znaleźć wartość weight tutaj:

Weight Inny parametr:
Transform.symmetry := 1;
Ale co to daje i gdzie to znaleźć w apo to mnie nie pytajcie. Ważna rzecz,  symmetry może przyjmować wartości od 0 do 1. Jeszcze inny:
Transform.color := 0.875;
Ta formułka pozwala nam przekształcać aktualny kolor. Tylko wartości od 0 do 1 są poprawne. Sprawdźcie sami, że działa:

Ostatnią rzeczą, ale ważną, jaką zmienimy w transformie to parametr variatrion. Jest on specyficzny w porównaniu do tego z czym mieliśmy do czynienia do tej pory:
Transform.variation[1] := 1;
widzicie tam w nawiasie klamrowym jakąś cyferkę? To jest właśnie to co czyni ten parametr specyficznym. Nie jest to pojedyncza zmienna, a tak zwana tablica. Co to tablica? To jest taka zmienna, która ma jedną nazwę i ileś indeksów (w przykładzie użyliśmy indeks 1), a każdy z indeksów może mieć inną wartość. Bardzo przydatna rzecz. Pamiętajcie, że w apo różnych rodzajów ,,wariacji" jakie możemy przypisać transformowi (czy ogólnie fraktalowi) jest całkiem sporo i to w różnych wersjach apo ich ilość jest różna. Na szczęście mamy zmienną NVARS, która zawiera ilość wszystkich możliwych wariacji. Przy czym znów (tak jak w przypadku numerów transformów), numery wariacji zaczynają się od 0! Więc jeśli chcemy poznać ostatni numer, to od NVARS musimy odjąć 1! Skąd mamy znać kolejne numerki wariacji? No to dość proste, stąd:

Tak na wszelki wypadek gdybyście potrzebowali, a pewnie tak będzie, macie tutaj taki kodzik, który ,,czyści" wszystkie wariacje:
for i := 0 to NVARS-1 do
Transform.variation[i] := 0;

Teoretycznie powinno być to dla was oczywiste co ten kod oznacza, ale..... :D
W pętli oczywiście od 0 – czyli od pierwszego numeru wariacji, do ostatniego czyli do łącznej ich liczby (zmienna NVARS zawiera tą liczbę) odjąć jeden! To chyba jasne? Jedyny kod jaki wykonujemy to przypisanie aktualnie przetwarzanej wariacji, której numer wskazuje zmienna i, wartości 0, czyli prościej mówiąc, usunięcie tej wariacji. Nie ma tu tego begin i end; jak ostatnio przy pętli bo mam tylko jedną instrukcję. Żeby nie było tak nudno to może dopiszmy jeszcze taką linijkę za pętlą:
Transform.variation[0] := 1;
Czyli pierwszej (oficjalnie zerowej) wariacji przypisujemy wartość 1. U mnie jest to linear 3d, jeśli nie macie apo 7X albo chociaż 3D hack to u was pewnie będzie to zwykłe linear. Jak sobie to uruchomimy to transform editorze możemy zobaczyć, że to działa:

To tyle co do transformów panie i panowie. Umiemy z nimi teraz zrobić cholernie dużo, a dotychczas poznane operacje będą na pewno jednymi z najczęściej używanych w naszych skryptach! Ale jedziemy dalej.

Pamiętacie jeszcze tablice no nie? To bardzo ważny typ danych, dobrze by było abyście go zrozumieli, więc zrobimy sobie małą powtórkę i trochę poszerzymy to co wiemy. Tablica ukryta pod parametrem variation obiektu Transform nie jest jedyną dostępną tablicą jaką możemy użyć w skrypcie. Ba! Sami możemy robić swoje i trochę sobie o tym właśnie teraz powiemy. Jeszcze raz, co to jest tablica? Jest to zmienna, która posiada ileś indeksów i każdemu z nich możemy przypisać inną wartość. Można by powiedzieć, że to taka zmienna, która porządkuje kilka różnych zmiennych o podobnym znaczeniu. Jak możemy robić swoje? Nic prostszego:
Tablica := [1, 2, 3, 4];
Teraz możemy sobie używać tej naszej tablicy jak każdej innej, np. zróbcie coś takiego:
for i := 0 to 3 do
showMessage(intToStr(tablica[i]));

Uruchomcie. Fajne nie? :D
Pamiętajcie! Od ZERA, do LICZBA ELEMENTÓW ODJĄC JEDEN, u nas są 4 elementy, odjąć jeden, czyli ostatni indeks to 3. Ten zapis: tablica to oczywiście pobranie wartości elementu numer i. W tablicach możemy mieszać różne rodzaje danych, nie muszą być to cyferki, chociaż jeśli mamy jednego rodzaju dane to łatwiej to przetwarzać. Ale mniejsza o to, możemy robić wielowymiarowe tablice. Coś np. takiego:
Tablica2 := [ [1,2,3,4], [5,6,7,8]];
Teraz żeby się odwołać do jakiegoś elementu musimy skorzystać z dwóch indeksów. Pierwszy 0, albo 1 w tym wypadku bo główna tablica ma dwa elementy... widzicie to? Tablica2 := [ [tutaj element 1], [tutaj element2] ]. A te elementy też są tablicami, czteroelementowymi. No i możemy teraz zrobić coś takiego:
showMessage(intToStr(tablica2[0,2]));
Co powinno wyświetlić 3. Oczywiście dwuwymiarowe tablice też możemy wyświetlać w pętli... albo w zasadzie pętlach, bo potrzebne są dwie, jedna do przelecenia pierwszego indeksu, druga do drugiego. Nie jest to trudne, po prostu robimy pętlę w pętli:
for i := 0 to 1 do
begin
    for j:=0 to 3 do                 
        showMessage(intToStr(tablica2[i,j]));
end;

Ważne, żeby w tej wewnętrznej pęli skorzystać z innej zmiennej! Na przykład j, jak robią wszyscy programiści na świecie :D
Fajnie byłoby jeszcze wiedzieć jakie długie tablice mamy do przelecenia w pętli, no bo teraz jak robimy jedną to wiemy, ale czasem w skrypcie możemy mieć mnóstwo tablic i pętle, która może operować na różnych z nich, więc przydałoby się coś co pozwoliłoby nam poznać ilość elementów tablicy. No i oczywiście jak nie trudno się domyśleć, mamy taką funkcję, ALE ona zwraca INDEKS ostatniego elementu, a nie ilość elementów, więc trzeba do tej wartości dodać jeden i wtedy dopiero mamy ilość elementów, przetestujcie sami:
Tablica := ['a','b','c',4,1,35];
wielkosc := VarArrayHighBound(tablica, 1) + 1;
showMessage(intToStr(wielkosc));

Mi wyświetla 6, czyli działa. Pamiętajcie o tej funkcji – VarArrayHighBound!

4.Trochę matematyki
No jako, że fraktale silnie współpracują z wszelkimi zasadami matematyki, to w skryptach możemy użyć wiele matematycznych funkcji. Warto poznać je jak najszybciej bo nigdy nie możemy być pewni kiedy nam się akurat przydadzą, a w razie czego będziemy gotowi by ich użyć.
Zacznijmy może od funkcji intToStr. Trochę trudno nazwać ją funkcją matematyczną, ale do różnych obliczeń często się przydaje. Używaliśmy jej już nie raz zresztą, dlatego tym bardziej chciałbym wam powiedzieć co dokładnie ona robi, żeby nie było niedomówień. Przypominacie sobie w jakich okolicznościach? Zawsze wtedy gdy chcieliśmy coś wypisać. Funkcja ta przerabia liczbę, którą jej podamy na inny typ danych – na napis! Niestety nie można tak sobie wyświetlać czegokolwiek byśmy chcieli. Wyświetlać trzeba napisy, a liczby w komputerze reprezentowane są trochę inaczej i po to właśnie mamy tę funkcję. Nie ma się tu co więcej rozpisywać bo już widzieliśmy ją w akcji, to tylko taka mała formalność.
Przy okazji, jak wspomnieliśmy o tej konwersji to powiedzmy sobie jeszcze o konwersji liczb rzeczywistych na całkowite:
a := 1.5;
b := trunc(a);

Funkcja ta działa bardzo prosto. Usuwa po prostu to, co mamy po przecinku i tyle. Tyle co do konwersji, podstawowe operacje matematyczne są dość proste do ogarnięcia, ten przykład myślę, że wyjaśnia wszystko:
a := 2;
b := 4;
c := a + b;
d := b - a;
e := a * b;
f := b / a;
showMessage('c = ' + intToStr(c)); 
showMessage('d = ' + intToStr(d));
showMessage('e = ' + intToStr(e));
showMessage('f = ' + intToStr(f)); 

Kolejno dodawanie (+), odejmowanie (-), mnożenie (*), dzielenie (/) i dalej wyświetlanie wyników, przy okazji z użyciem wcześniej wspomnianej funkcji intToStr. Jak na koniec zaliczyliśmy dzielenie to przy okazji możemy wspomnieć o funkcji reszty z dzielenia:
a := 8 mod 5;
Da nam oczywiście a równe 3.  Z przydatnych operacji matematycznych (z czego niekoniecznie musicie zdawać sobie teraz sprawę, ale uwierzcie mi, że to jest naprawdę przydatne) mamy też inkrementację:
a := 1;
inc(a);

i dekrementację:
a := 1;
dec(a);

Co to jest in- i de- krementacja? Inkrementacja to po prostu zwiększenie danej zmiennej o jeden, a dekrementacja to zmniejszenie jej o jeden. Można by to zapisać np. tak:
a := a + 1;
a := a – 1;

ale na wszelki wypadek mamy i tak gotowe funkcje, nie ma na co narzekać :)
Fajny bajer, o którym sobie teraz wspomnimy to sinusy i cosinusy. Ja ich nie lubię, ale mogą się komuś przydać. Tutaj funkcje trygonometryczne jakich możemy sobie użyć:
a  := 1;
sin(a);
cos(a);
tan(a);

Odpowiednio sinus, cosinus i tangens. Jak ktoś się lubi bawić w radiany i te sprawy (ja nie lubię jak już pisałem) to mamy jeszcze stałą PI, która zawiera wartość liczby pi.
Ostatnią, ale bardzo ciekawą i przydatną matematyczną sprawką jaką się szybko zajmiemy to liczby losowe. W apo robi się je bardzo prosto, o tak:
a := random;
i gotowe! Mamy losową liczbę, w zakresie od 0 do 1. Jak chcemy np. w zakresie do 10, to piszemy:
a := 10*random;
i też gotowe! Jak widać wszelkie matematyczne bajery w naszych skryptach są dość łatwe w użyciu, co sprzyja ich użytkowaniu.

5.Operacje na całym fraktalu
To może nie być aż tak ciekawe jak bawienie się transformami, ale też jest ważne. W skryptach mamy dostęp do wielu opcji całego fraktala, co pozwala nam na zarządzanie jakby całym obrazem. Mamy taki obiekt jak ,,Flame" i dzięki niemu właśnie możemy korzystać z różnych opcji. Tak w praktyce to wygląda:
Flame.name := 'Inny';
W ten sposób zmieniamy nazwę naszego fraktala, spójrzcie sami:

Nazwę fraktala widzimy tam na pasku na dole, a przy okazji jest ona też używana przy renderowaniu fraktala. Możemy zrobić sobie zooooom'a naszego fraktala:
Flame.zoom :=  0.745;
dodatnie wartości przybliżają, ujemne oddalają. Nie wpisujcie tam raczej większych liczb niż 2 lub mniejszych niż -2. Ten parametr zoom jest odpowiednikiem tego suwaka:

Możemy sobie zmienić tło fraktala:

Flame.Background[0] := 255;
Flame.Background[1] := 255;
Flame.Background[2] := 255;

Podajemy tu kolejno wartości RGB nowego koloru tła, 0 – R, 1 – G, 2 – B.
Mamy też dostęp do opcji z tej zakładki (background też tu w sumie jest z tego co widzę :D ):

w następujący sposób:
Flame.Gamma := 5;
Flame.Vibrnacy := 1.5;
Flame.Brightness := 1.5;

to są bardzo fajne opcje, więc bardzo miło, że możemy je zmieniać w skrypcie.

O jeszcze coś takiego! ,,UpdateFlame". To taka zmienna, a nie parametr obiektu Flame, ale jest dość przydatne zwłaszcza przy skryptach. Pozwala wyłączyć odświeżanie się podglądu, wyłącza się to tak:
UpdateFlame := false;
później włącza tak:
UpdateFlame := true;
No i czasem może się przydać gdy wykonujemy bardzo wiele operacji co do których jesteśmy bardzo pewni i nie potrzebujemy renderowania ich podglądu. Podobna zmienna jeszcze jedna to ,,ResetLocation", też możemy nadać jej wartość true lub false, przy czym używanie jej z wartością false jest trochę bez sensu. Za to jeśli użyjemy jej z wartością true w skrypcie to nasz fraktal przesunie się w punkt, w którym był na samym początku.

May też parę funkcji związanych z operacjami na fraktalu. Pierwsza może taka trochę głupia, oto ona:
RandomFlame(0);
przekształca ona losowo nasz fraktal. Nazwałem ją trochę głupią bo nie kontrolujemy jej w żaden sposób, ale czasem może się przydać. Przydatna może być ta funkcja:
sciezka := GetSaveFileName;     
SaveFlame(sciezka);

w zasadzie dwie funkcje. GetSaveFileName wyświetla typowe okienko wybierania gdzie ma być zapisany plik (wiecie, takie jak wszystkie programy wyświetlają jak wybierzecie opcję ,,Zapisz jako") i zapisuje to miejsce w zmiennej ,,sciezka". W drugiej linii wykorzystujemy funkcję SaveFlame, aby zapisała nasz fraktal we wskazanym miejscu.
Mamy jeszcze taki gadżet:
RotateFlame(90);
co obraca fraktal o 90 stopni. Proste.

6.Opcje
Mamy coś takiego jak obiekt ,,Options". Wszystko co znajdziecie w ustawieniach apo może być zmienione poprzez ten obiekt, skupmy się na najważniejszych i najprzydatniejszych bajerach.
Options.RandomPrefix := ,,MojeSuperFraktale-"
Options.MinTransforms := 2;
Options.MaxTransforms := 3;
Options.BatchSize := 20;

Czujecie o co chodzi no nie? Jeśli kojarzycie te okienko od ustawień to łatwo poznacie co jaki parametr zmienia (z resztą, jeśli nie kojarzycie to i tak nie jest tutorial, w którym mam zamiar to opisywać). Fajne jest to:
Options.Variations[i] := false;
To blokuje w losowych fraktalach możliwość nadawania danej wariacji. Ofc, aby przywrócić daną wariację wystarczy false zamienić na true. No i pod i trzeba podstawić jakąś liczbę, albo, przelecieć w pętli.

Dobra, to by chyba było na tyle. Ogólnie jeśli ogarniacie operacje na transformach to rewelka, reszta to w zasadzie pierdoły, no i wszystko co się da zrobić w skryptach można też robić w transform editorze czy gdzieś indziej, dlatego nawet jak nie lubicie robić skryptów to może chociaż czegoś się z tego tutka dowiedzieliście. W praktyce jak tak patrze to bardziej chyba właśnie wyszedł tutorial o operacjach na transformach niż pisaniu skryptów. Ja i tak wolę bawić się w POV-Rayu :D Pozdrawiam i życzę szczęśliwego nowego roku!

TUTORIAL WYKONANY TYLKO I WYŁĄCZNIE DLA BURNING-BRUSHES.PL

PIERWSZY TEMAT W NOWYM ROKU, WOOOHOOO