soodan sivut

arkisto

238 kirjotelmaa.

avainsanat

Loppukuun viikonloppuna pidettiin pitkästä aikaa Graffathon eli parin vuorokauden mittainen demoparty-hackathon-sekoitus DOT ry:n järkkäämänä. Perinteiseen tapaan olin mukana järjestelyissä mutta ehdin vähän koodaamaankin. Inspiroiduin lattioiden moppaamisesta partyjä varten niin, että demoni aiheeksi tuli juurikin se. Jatkoin saman hauskan työkalun käyttöä kuin Instansseilla vuoden alussa, josta itseasiassa pitikin kirjoittaa jo aiemmin mutta juttu jäi johonkin. Tässä ehkä molemmista. Jutun juju on grafiikka hassunhauskalla pino-ohjelmointikielellä Forth.

Otaniemen biletilojen SLA ehkä vastaa biletilojen tyypillistä käyttöä, mutta kun tarttee tassutella sukkasilteen pari vuorokautta samassa tilassa, niin ois hyvä ettei lattia olisi ihan tahmea. No joka tapauksessa siinä missä nykyään tavanomaisempi ohjelmointikieli toimisi vaikka muuttujilla tai assykieli rekistereillä, niin Forthissa ei mitään tuollaista ole käytössä vaan numeroita pidetään pinorakenteessa. Kukin ohjelman sana eli pieni käsky tai funktio olettaa pinon pinnalla olevan jotain lukuja ja sitten tekee niillä jotain ja yleensä lykkää laskutoimituksen tuloksen pinoon takaisin. RPN-laskimet operoivat samalla käsitteellä. Kun ohjelmassa esiintyy numeroita, ne lykätään pinoon, ja ohjelmassa esiintyvät ajoympäristön varatut sanat (kuten "+") operoivat pinon pintaa.

Ajoympäristö

Forthista puhuessa kyse on aina jostain tietystä dialektista tai ympäristöstä, vähän sama kuin lispeissä tai assyssä. Forth Haiku Salon on Forth-ympäristö, "Shadertoy mutta Forthilla". Shadertoyssä ajetaan GLSL:ää ja siitä -- tai ylipäänsä menetelmästä "pelkkä shader-ajo per pikseli eikä perinteistä kolmiogeometriaa" onkin tullut tietokonegraffan erikoistapauksena ihan käsite demoskenessä. Kullekin pikselille ajetaan GPU-ohjelma, jolla on tieto x- ja y-koordinaateista sekä ajankulusta, sekä ehkä saatavilla joitain jaettuja resursseja kuten kuvia. Näistä tiedoista sitten ohjelma laskee pikselin RGB-värin. Sama homma Forth Haiku Salonissa, nimensä mukaisesti kehotuksella pyrkiä muodostamaan ohjelman pituus 5-7-5-runomittaan.

Demo

No aivan tuohon runomittaan en yltänyt. Alla koko sorsa, partyiltä kummemmin siistimättä. Kaksoispisteen ja puolipisteen välissä oleva kama määrittelee uuden sanan ja muu ajetaan heti. Demo on myös nähtävillä jossain väliaikaisosoitteessa (painele playnappia jos ääni ei soi). Piti ottaa snapshotti haikuympäristöstä ja editoida maksimipituutta vähän mutta muuten on yhteensopiva.

: ang -0.2 ;
: xtwist ang cos x * ang sin y * - ;
: ytwist ang sin x * ang cos y * + ;
: xtile xtwist 0.3 mod 3 * ; : ytile ytwist 0.3 mod 3 * ;
: gaps 0.023 ; : bandsz 0.02 ;
: waves
 x 7 * y 1.3 * +
  t 5 * 3.14159 2 * mod +
  sin 0.1 * 0.5 +
 y  x 0.1 *  -
 t sin 0.7 * - <
;
: foot1x 0.5 ; : foot1y 0.5 ; : foot2x 0.5 0.11 - ;
: foot1sz 0.07 ; : foot2sz 0.053 ;
: foot
 0 ! 1 ! 2 !
  x foot1x 2 @ + - 0.7 * dup * y foot1y 1 @ + - dup * + sqrt foot1sz <
  x foot2x 2 @ + - 0.9 * dup * y foot1y 1 @ + 0 @ + - dup * + sqrt foot2sz <
 or
 x foot1x 2 @ + - bandsz mod bandsz 2 / < *
;
: left 0.15 -0.01 foot ; : right -0.15 0.01 foot ;
-0.5 left -0.35 right +
   0 left  0.15 right +
 0.5 left  0.65 right +
+ +

: walk 1 waves - *  3.14159 -0.5 * t + sin x > * ; walk

: rnd x 12.9898 * y 78.233 * + sin 43758.5453123 * 1 mod ;
: gr 0.7 rnd 0.05 * + ; : dirt rnd 0.2 * + ;

if  0.423 dirt 0.164 dirt 0.094 dirt else
 xtile gaps < ytile gaps < or
 if  0.223 dirt 0.164 dirt 0.094 dirt  else  gr gr gr  then
then

: wavefade waves t 3.14159 0.5 * + sin 0.5 + 0.5 * * + ;
waves + rot wavefade rot wavefade rot

random 3.14159 0.5 * t + sin 10 pow * audio

Tuo sitten piirtää animoituna jotain tälläistä:

Peruutetaan vähän. Tässä ohjelma, joka värjää koko ruudun harmaasävyliu'uksi vasemmalta oikealle. X-koordinaatti menee ruudun mitassa nollasta ykköseen.

x x x

Tässä vastaava, mutta vain punaiselle värikanavalle.

x 0 0

Tässä muutama pystypalkki. Sinifunktio saa arvoja väliltä miinus ykkösestä ykköseen ja värit määritellään nollasta ykköseen, niin otetaan itseisarvo (abs).

x 3.14159 * 4 * sin abs

Pinoilussa on välillä useampi tapa kirjoittaa sama laskutoimitus laittamalla numerot ja operaattorit eri järjestykseen. Tässä sama kuin aiempi.

x 3.14159 4 * * sin abs

Koska ryhdyin suoraan prototyyppailemaan, niin demon eri vaiheista ei ole tallella autenttisia yksittäisiä versioita. Avataan tuon toimintaa kuitenkin vähän.

Jalanjäljet

Ekana muodostuivat "jalanjäljet" liikkumattomana. Jos koodista poistaa kaiken kohdasta "walk" alkaen, jää jäljelle tämä:

Kukin jalanjälki koostuu kahdesta soikiosta, joita "moduloidaan" pystysuuntaisilla raidoilla edes vähän kiinnostavan tekstuurin aikaansaamiseksi. Foot-sana on määritelty muistipaikkoja käyttäen, jotta pysyin edes itse kärryillä keskellä yötä koodatessa. Homman nimi on kuitenkin nuo soikiot -- tässä kengän etuosa:

x foot1x 2 @ + - 0.7 * dup * y foot1y 1 @ + - dup * + sqrt foot1sz <

Vaikkapa monille tutummaksi Pythoniksi muokattuna tuo menisi suunnilleen näin:

def foot(a, b, c):
    dx = 0.7 * (x() - (foot1x + c))
    dy = y() - (foot1y + b)
    bigpart = sqrt(dx * dx + dy * dy) < foot1sz
    # etc.

Alkaa näyttää ympyrän tai jonkunlaisen soikion yhtälöltä vai? Bigpart-muuttujan arvoksi tulisi totuusarvo 1, jos ollaan jalan kohdalla, muutoin 0.

Iso juju on se, että täytyy pitää aika tarkkaan mielessä nuo välitulosten sijainnit pinossa. Pinon kolmeen päällimmäiseen pääsee vielä helposti käsiksi kun niitä voi keskenään pyöritellä eri Forth-operaatioilla, mutta yli kolme parametriä vaatisi jo vähän jumppaa, toista pinoa, tai sitten purkkavirinä noita Forth Salonin muistipaikkoja, joita huutomerkillä ja ät-merkillä käytetään.

Hyvä tapa toki olisi jakaa ohjelma todella pieniin sanoihin, joiden pinotoiminta olisi dokumentoitu, mutta ei demokoodailussa partypaikalla ole sellaiseen aikaa ja johonkin strukturoimiseen ryhtyminen kesken kaiken rikkoisi hyvän koodausflown.

Askellusanimaatio

Jalanjäljet animoituvat esille liukuen ja sitten aallokko pyyhkii ne pois. Se hoituu tällä koodinpätkällä:

: walk 1 waves - *  3.14159 -0.5 * t + sin x > * ; walk

Tuossa luodaan uusi walk-sana ja käytetään sitä heti. Nuo laskut voisi tehdä suoraankin mutta ehkä tähän oli joku hyvä syy, ainakin helpottaa iteratiivista devausta kun pätkiä ohjelmasta saa helpommin pois päältä. Unohdetaan tuo waves hetkeksi ja tarkastellaan ensin tätä pätkää:

3.14159 -0.5 * t + sin x > *

Eli infix-notaatiossa (sin(-0.5 * 3.14159 + t) > x) * (pinon päällimmäinen arvo). (Vertailu saa arvokseen 0 tai 1.) Pinossa on päällimmäisenä ykkönen tai nolla kuvastamassa kengänjälkeä. Sinifunktion vertaaminen x-koordinaattiin saa aikaan esiintymisliukuefektin. Puolikkaan piin summaaminen sinin argumenttiin synkronoi animaation ajallisesti muihinkin liikkuviin elementteihin.

waves kuvastaa ylhäältä alas kaatuvaa aallokkoa ja on aiemmin määritelty:

: waves
 x 7 * y 1.3 * +
  t 5 * 3.14159 2 * mod +
  sin 0.1 * 0.5 +
 y  x 0.1 *  -
 t sin 0.7 * - <
;

Tätä voidaan tarkastella omana ohjelmanaan. Infix-notaatiossa ja jaettuna vähän osiin (mod on jakojäännösoperaattori):

a = (
  (x * 7)
+
  (y * 1.3)
)
b = (
 (t * 5) mod (3.14159 * 2)
)
c = a + b
d = sin(c)
e = 0.1 * d + 0.5
f = y - 0.1 * x
g = sin(t) * 0.7
h = e - f < g

Ja kun eliminoidaan tuosta välistä niin:

h = 0.1 * sin(a + b) + 0.5 - (y - 0.1 * x) < sin(t) * 0.7

Voi olla että meni pieleenkin, en ajanut tuota infix-muotoa missään. Taikalukujen merkitystä:

  • 7 määrää, montako aallonharjaa ruudulla näkyy laidasta laitaan
  • 1.3 muotoilee aallonharjat, kun aalto on artistisesti vähän vinossa
  • 5 säätää, kuinka nopeasti aallokko liikkuu vaakatasossa; jakojäännös 2*piistä saa periodisen liikkeen synkkaan muun kanssa
  • 0.1 muovaa aallonharjojen mitan pystysuunnassa
  • 0.5 vain kääntää sinin lukuarvot sopivalle alueelle keskelle ruutua
  • toinen 0.1 kalibroi sitä artistista vinoutta, kun x:n kasvaessa aalto kohoaa ruudun nurkkaa kohti
  • 0.7 säätää sitä, miten kauas ruudun keskeltä aallokko liikkuu pystysuunnassa (suunnilleen laidasta laitaan)

Kuten arvata saattaa, niin onhan tämä melko write-only-koodia. Niin kyllä on suurten gurujen glsl-sorsatkin kaikkine taikavakioineen joista riittää nysvätä numerot kuntoon siinä hetkessä ja sitten on valmis, ellei varta vasten ole tehty kiireen puuttuessa ja opetus- tai uudelleenkäyttötarkoituksessa. Postfix-notaatio pinon kanssa ehkä on merkittävin eksoottisuus, ja se samalla pitää sorsan koon todella kompaktina.

Kaakelilattia

Ei sen kummempaa kuin:

: ang -0.2 ;
: xtwist ang cos x * ang sin y * - ;
: ytwist ang sin x * ang cos y * + ;
: xtile xtwist 0.3 mod 3 * ; : ytile ytwist 0.3 mod 3 * ;
: gaps 0.023 ; : bandsz 0.02 ;
0
: rnd x 12.9898 * y 78.233 * + sin 43758.5453123 * 1 mod ;
: gr 0.7 rnd 0.05 * + ; : dirt rnd 0.2 * + ;
if  0.423 dirt 0.164 dirt 0.094 dirt else
 xtile gaps < ytile gaps < or
 if  0.223 dirt 0.164 dirt 0.094 dirt  else  gr gr gr  then
then

Näyttää kokoaan pidemmältä, kun on jaettu osiin ettei hajoa pää. Tämänhän itseasiassa taisin koodata ekana enkä noita kengänjälkiä. Juju on tehdä jakojäännösruudukko ja pyörittää sitä ruudukkoa taiteellisesti vähän vinoon (xtwist ja ytwist ovat kuin 2d-pyöritysmatriisikertolasku). Tuo yksinäinen nolla yksinkertaistetussa otteessa koko koodista kuvastaa sitä, ettei tähän kohtaan piirry kengänpohjaa vaan lattia.

Satunnaisuus lisättiin myöhemmin vain lisäämään vähän tekstuuria, kun työskentelyaikaa jäi. Tuo randomluku on internetin ihmemaailmassa joka paikasta löytyvä "glsl-random", jonka alkuperä on hämärä ja satunnaisuuden laatu pelkästään visuaalinen. Forth Haikuissa olisi ympäristön omatkin satunnaisluvut, mutta tälläinen itsetehty on spatiaalisesti stabiili eli ei välky ruudusta toiseen.

Aallokko

Waves-funktio (Forth-kielellä "sana") esiteltiin yllä. Se peittää kengänjälkien piirtoa sekä värjää lattiaa seuraavasti:

: wavefade waves t 3.14159 0.5 * + sin 0.5 + 0.5 * * + ;
waves + rot wavefade rot wavefade rot

Wavefade on taas kerran sinianimaatio. Nyt se vaihtelee vain kirkkauskerrointa. Tässä lasketaan ajasta joku sopiva kerroin ja ynnätään se punaiseen ja vihreään värikanavaan. Kohdassa waves + pinossa on sininen väri, johon aallokko ynnätään ilman kirkkausefektiä -- siellä missä aallokko menee on ainakin todella sinistä. Kun punainen ja vihreä kasvavat aallon edetessä, aalto muuttuu läpinäkyvänsinisestä peittävänvalkoiseksi.

Vähän huijataan

Demoskeneproduissa ja varmaan tietokonepeleissäkin on se etu, että sinne minne ei näy voi laittaa mitä vaan sotkua. Kengänjälkianimaatio liukuu säännöllisesti esille, mutta sinianimoitunahan se liukuu yhtä säännöllisesti pois näkyviltä. Poisliukuminen ei olisi luonnollisen kävelyn näköistä, mutta esille liukuva vesipeite peittää sen näkyvistä, eikä siten kengänjälkien poisliukumista tarvitse korjata.

Ja eihän tälläiset jekut rajoitu pelkästään tietokonegraffaan. Elokuvissakin hämätään rakentamalla näyttämö, eikä kukaan näe kameran taakse eikä kulissien väliin. Taidetta ohjelmoidessa on suuri etu nähdä (erityisesti ennalta), että missä kulissijekuilla voi säästää.

Ääntäkin

Forth-ympäristö tukee myös akustiikkaa eli ääniaaltosamplejen generointia. Ajatuksena oli läiskiä askelien kanssa synkassa soimaan jotain sellaista ritinää, jota tulee kun kenkä irtoaa tahmeasta lattiasta. Oli kuitenkin tarpeeksi muutakin tekemistä partyhenkilökuntahommassa, niin tyydyin aallokkoa simuloivaan ääneen eli kohinaan. Ääniefekti on pelkkää satunnaislukua, jonka voimakkuutta rajaa aaltoefektiin sopivasti synkronoitu sinifunktio kymmenenteen potenssiin. Potenssilasku saa siniaallon kärjistä terävämpiä, jolloin kohinaääni ilmenee ja vaimenee ripeämmin.

random 3.14159 0.5 * t + sin 10 pow * audio

eli infixiniä

audio = pow(sin(3.14159 * 0.5 + time()), 10) * random()

Kompaktia sorsaa hattuun

Jo useampi vuosi on saanut assyjen aikaan unelmoida, kuinka jonain päivänä koodaan siihen hattuun kentällä ohjelmoitavan valaistusympäristön, tai siis valaistushan on jo mutta Forth-ympäristön implementoi triviaalisti tuollekin pienelle mikrokontrollerille. Oma haasteensa on, miten koodaaminen pysyy (ilman vaikka mitään modernia kännykkäsoftaa) hanskassa assyillä tai viereisillä kallioilla tai muualla, mutta sehän olisi osa hauskuutta. Sanat tietysti olisivat tekstin sijaan värejä, ja ledinauha näyttäisi ohjelmointimoodissa ohjelman koodin. Hatussa on toki vain yksi akseli x:n ja y:n sijaan mutta sama juju kuin Forth Haikuissa tai Shadertoyssä tai IBNIZissä (josta taisin ajatuksen alunperin saada). IBNIZ on myös pinokone ja itseasiassa suomalainen keksintö.

Oli muuten assytkin just nyt äsken tänä viikonloppuna ja törmäsin ibnizin kehittäjään ja piti mainita kallioilla että mullahan on tämmöinen sinnepäin hattukoodi-idea. Moi viznut.

Natiivikoodia

Ihan vähän saatiin debugata segfaulttiakin kuten perinteisesti kuuluu, ja sain kontribuoidakin pitkästä aikaa johonkin, joskin tällä kertaa oli triviaali typofiksi. Aloittelijakävijöille esitelty ehdoteltu suositeltu perusframework oli edelleen Processing + Rocket -yhdistelmä (Rocketista vaihtoehtoinen editori). Jos Processingin Rocket-kirjastona käyttää ikivanhaa bugista versiota, niin kai se nyt bugaa. Luultiin uudemmaksi asennukseksi.

Instansseilla

Vierailin Instanssi-demopartyillä Jyväskylässä maaliskuun alussa. Siellä koodasin ekaa kertaa tuolla forthhärvelillä jotain jolla myös osallistuin. Kun kyseessä oli kuitenkin suoritettava ohjelma, niin se meni hassusta alustasta riippumatta noilla partyillä demo-kategoriaan. Instanssit on kovin hauskat ja omaperäiset partyt ja wild-kategoriaan eli Summamutikkaan menee vieläkin obskuurimpaa materiaalia. Mutta ehkä kuitenkin kirjoitan siitä erillisen raportin, kun tämä nyt näin venähti.

0 kommenttia

Oma kommenttisi

Mielipide tämän sivun asiasta? Kirjoita toki. Älä raapusta kuitenkaan ihan asiattomia juttuja.

Jos on yksityisempää asiaa, tarkkaa kysyttävää tai aihetta pidemmälle keskustelulle, käytä yhteydenottolomaketta kommentoinnin sijaan.

Hölmöt kommentit saatetaan moderoida pois jälkikäteen.

Nimimerkki:

Spammibottiesto: Mikä on kahdeksan ja yhden erotus? (vastaus numeroina)