123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738 |
- (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
- // build script for generating processing.js
-
- var Browser = {
- isDomPresent: true,
- navigator: navigator,
- window: window,
- document: document,
- ajax: function(url) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", url, false);
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType("text/plain");
- }
- xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT");
- xhr.send(null);
- // failed request?
- if (xhr.status !== 200 && xhr.status !== 0) { throw ("XMLHttpRequest failed, status code " + xhr.status); }
- return xhr.responseText;
- }
- };
-
- window.Processing = require('./src/')(Browser);
-
- },{"./src/":28}],2:[function(require,module,exports){
- module.exports={
- "name": "processing-js",
- "version": "1.4.13",
- "author": "Processing.js",
- "repository": {
- "type": "git",
- "url": "git@github.com/processing-js/processing-js.git"
- },
- "main": "processing.min.js",
- "bugs": "https://github.com/processing-js/processing-js/issues",
- "devDependencies": {
- "argv": "~0.0.2",
- "browserify": "~2.18.1",
- "express": "~3.3.3",
- "node-minify": "~0.7.3",
- "nunjucks": "~0.1.9",
- "open": "0.0.3",
- "grunt": "~0.4.1",
- "grunt-cli": "~0.1.8",
- "grunt-contrib-jshint": "~0.4.3"
- },
- "scripts": {
- "test": "node test"
- },
- "license": "MIT"
- }
-
- },{}],3:[function(require,module,exports){
- /**
- * A ObjectIterator is an iterator wrapper for objects. If passed object contains
- * the iterator method, the object instance will be replaced by the result returned by
- * this method call. If passed object is an array, the ObjectIterator instance iterates
- * through its items.
- *
- * @param {Object} obj The object to be iterated.
- */
- module.exports = function ObjectIterator(obj) {
- if (obj instanceof Array) {
- // iterate through array items
- var index = -1;
- this.hasNext = function() {
- return ++index < obj.length;
- };
- this.next = function() {
- return obj[index];
- };
- } else if (obj.iterator instanceof Function) {
- return obj.iterator();
- } else {
- throw "Unable to iterate: " + obj;
- }
- };
-
- },{}],4:[function(require,module,exports){
- /**
- * Processing.js environment constants
- */
- module.exports = {
- X: 0,
- Y: 1,
- Z: 2,
-
- R: 3,
- G: 4,
- B: 5,
- A: 6,
-
- U: 7,
- V: 8,
-
- NX: 9,
- NY: 10,
- NZ: 11,
-
- EDGE: 12,
-
- // Stroke
- SR: 13,
- SG: 14,
- SB: 15,
- SA: 16,
-
- SW: 17,
-
- // Transformations (2D and 3D)
- TX: 18,
- TY: 19,
- TZ: 20,
-
- VX: 21,
- VY: 22,
- VZ: 23,
- VW: 24,
-
- // Material properties
- AR: 25,
- AG: 26,
- AB: 27,
-
- DR: 3,
- DG: 4,
- DB: 5,
- DA: 6,
-
- SPR: 28,
- SPG: 29,
- SPB: 30,
-
- SHINE: 31,
-
- ER: 32,
- EG: 33,
- EB: 34,
-
- BEEN_LIT: 35,
-
- VERTEX_FIELD_COUNT: 36,
-
- // Renderers
- P2D: 1,
- JAVA2D: 1,
- WEBGL: 2,
- P3D: 2,
- OPENGL: 2,
- PDF: 0,
- DXF: 0,
-
- // Platform IDs
- OTHER: 0,
- WINDOWS: 1,
- MAXOSX: 2,
- LINUX: 3,
-
- EPSILON: 0.0001,
-
- MAX_FLOAT: 3.4028235e+38,
- MIN_FLOAT: -3.4028235e+38,
- MAX_INT: 2147483647,
- MIN_INT: -2147483648,
-
- PI: Math.PI,
- TWO_PI: 2 * Math.PI,
- TAU: 2 * Math.PI,
- HALF_PI: Math.PI / 2,
- THIRD_PI: Math.PI / 3,
- QUARTER_PI: Math.PI / 4,
-
- DEG_TO_RAD: Math.PI / 180,
- RAD_TO_DEG: 180 / Math.PI,
-
- WHITESPACE: " \t\n\r\f\u00A0",
-
- // Color modes
- RGB: 1,
- ARGB: 2,
- HSB: 3,
- ALPHA: 4,
- CMYK: 5,
-
- // Image file types
- TIFF: 0,
- TARGA: 1,
- JPEG: 2,
- GIF: 3,
-
- // Filter/convert types
- BLUR: 11,
- GRAY: 12,
- INVERT: 13,
- OPAQUE: 14,
- POSTERIZE: 15,
- THRESHOLD: 16,
- ERODE: 17,
- DILATE: 18,
-
- // Blend modes
- REPLACE: 0,
- BLEND: 1 << 0,
- ADD: 1 << 1,
- SUBTRACT: 1 << 2,
- LIGHTEST: 1 << 3,
- DARKEST: 1 << 4,
- DIFFERENCE: 1 << 5,
- EXCLUSION: 1 << 6,
- MULTIPLY: 1 << 7,
- SCREEN: 1 << 8,
- OVERLAY: 1 << 9,
- HARD_LIGHT: 1 << 10,
- SOFT_LIGHT: 1 << 11,
- DODGE: 1 << 12,
- BURN: 1 << 13,
-
- // Color component bit masks
- ALPHA_MASK: 0xff000000,
- RED_MASK: 0x00ff0000,
- GREEN_MASK: 0x0000ff00,
- BLUE_MASK: 0x000000ff,
-
- // Projection matrices
- CUSTOM: 0,
- ORTHOGRAPHIC: 2,
- PERSPECTIVE: 3,
-
- // Shapes
- POINT: 2,
- POINTS: 2,
- LINE: 4,
- LINES: 4,
- TRIANGLE: 8,
- TRIANGLES: 9,
- TRIANGLE_STRIP: 10,
- TRIANGLE_FAN: 11,
- QUAD: 16,
- QUADS: 16,
- QUAD_STRIP: 17,
- POLYGON: 20,
- PATH: 21,
- RECT: 30,
- ELLIPSE: 31,
- ARC: 32,
- SPHERE: 40,
- BOX: 41,
-
- GROUP: 0,
- PRIMITIVE: 1,
- //PATH: 21, // shared with Shape PATH
- GEOMETRY: 3,
-
- // Shape Vertex
- VERTEX: 0,
- BEZIER_VERTEX: 1,
- CURVE_VERTEX: 2,
- BREAK: 3,
- CLOSESHAPE: 4,
-
- // Shape closing modes
- OPEN: 1,
- CLOSE: 2,
-
- // Shape drawing modes
- CORNER: 0, // Draw mode convention to use (x, y) to (width, height)
- CORNERS: 1, // Draw mode convention to use (x1, y1) to (x2, y2) coordinates
- RADIUS: 2, // Draw mode from the center, and using the radius
- CENTER_RADIUS: 2, // Deprecated! Use RADIUS instead
- CENTER: 3, // Draw from the center, using second pair of values as the diameter
- DIAMETER: 3, // Synonym for the CENTER constant. Draw from the center
- CENTER_DIAMETER: 3, // Deprecated! Use DIAMETER instead
-
- // Text vertical alignment modes
- BASELINE: 0, // Default vertical alignment for text placement
- TOP: 101, // Align text to the top
- BOTTOM: 102, // Align text from the bottom, using the baseline
-
- // UV Texture coordinate modes
- NORMAL: 1,
- NORMALIZED: 1,
- IMAGE: 2,
-
- // Text placement modes
- MODEL: 4,
- SHAPE: 5,
-
- // Stroke modes
- SQUARE: 'butt',
- ROUND: 'round',
- PROJECT: 'square',
- MITER: 'miter',
- BEVEL: 'bevel',
-
- // Lighting modes
- AMBIENT: 0,
- DIRECTIONAL: 1,
- //POINT: 2, Shared with Shape constant
- SPOT: 3,
-
- // Key constants
-
- // Both key and keyCode will be equal to these values
- BACKSPACE: 8,
- TAB: 9,
- ENTER: 10,
- RETURN: 13,
- ESC: 27,
- DELETE: 127,
- CODED: 0xffff,
-
- // p.key will be CODED and p.keyCode will be this value
- SHIFT: 16,
- CONTROL: 17,
- ALT: 18,
- CAPSLK: 20,
- PGUP: 33,
- PGDN: 34,
- END: 35,
- HOME: 36,
- LEFT: 37,
- UP: 38,
- RIGHT: 39,
- DOWN: 40,
- F1: 112,
- F2: 113,
- F3: 114,
- F4: 115,
- F5: 116,
- F6: 117,
- F7: 118,
- F8: 119,
- F9: 120,
- F10: 121,
- F11: 122,
- F12: 123,
- NUMLK: 144,
- META: 157,
- INSERT: 155,
-
- // Cursor types
- ARROW: 'default',
- CROSS: 'crosshair',
- HAND: 'pointer',
- MOVE: 'move',
- TEXT: 'text',
- WAIT: 'wait',
- NOCURSOR: "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), auto",
-
- // Hints
- DISABLE_OPENGL_2X_SMOOTH: 1,
- ENABLE_OPENGL_2X_SMOOTH: -1,
- ENABLE_OPENGL_4X_SMOOTH: 2,
- ENABLE_NATIVE_FONTS: 3,
- DISABLE_DEPTH_TEST: 4,
- ENABLE_DEPTH_TEST: -4,
- ENABLE_DEPTH_SORT: 5,
- DISABLE_DEPTH_SORT: -5,
- DISABLE_OPENGL_ERROR_REPORT: 6,
- ENABLE_OPENGL_ERROR_REPORT: -6,
- ENABLE_ACCURATE_TEXTURES: 7,
- DISABLE_ACCURATE_TEXTURES: -7,
- HINT_COUNT: 10,
-
- // PJS defined constants
- SINCOS_LENGTH: 720, // every half degree
- PRECISIONB: 15, // fixed point precision is limited to 15 bits!!
- PRECISIONF: 1 << 15,
- PREC_MAXVAL: (1 << 15) - 1,
- PREC_ALPHA_SHIFT: 24 - 15,
- PREC_RED_SHIFT: 16 - 15,
- NORMAL_MODE_AUTO: 0,
- NORMAL_MODE_SHAPE: 1,
- NORMAL_MODE_VERTEX: 2,
- MAX_LIGHTS: 8
- };
-
- },{}],5:[function(require,module,exports){
- // the logger for println()
- module.exports = function PjsConsole(document) {
- var e = { BufferMax: 200 },
- style = document.createElement("style"),
- added = false;
-
- style.textContent = [
- ".pjsconsole.hidden {",
- " display: none!important;",
- "}"
- ].join('\n');
-
- e.wrapper = document.createElement("div");
- style.textContent += [
- "",
- ".pjsconsole {",
- " opacity: .75;",
- " display: block;",
- " position: fixed;",
- " bottom: 0px;",
- " left: 0px;",
- " right: 0px;",
- " height: 50px;",
- " background-color: #aaa;",
- "}"
- ].join('\n');
- e.wrapper.classList.add("pjsconsole");
-
- e.dragger = document.createElement("div");
- style.textContent += [
- "",
- ".pjsconsole .dragger {",
- " display: block;",
- " border: 3px black raised;",
- " cursor: n-resize;",
- " position: absolute;",
- " top: 0px;",
- " left: 0px;",
- " right: 0px;",
- " height: 5px;",
- " background-color: #333;",
- "}"
- ].join('\n');
- e.dragger.classList.add("dragger");
-
- e.closer = document.createElement("div");
- style.textContent += [
- "",
- ".pjsconsole .closer {",
- " opacity: .5;",
- " display: block;",
- " border: 3px black raised;",
- " position: absolute;",
- " top: 10px;",
- " right: 30px;",
- " height: 20px;",
- " width: 20px;",
- " background-color: #ddd;",
- " color: #000;",
- " line-height: 20px;",
- " text-align: center;",
- " cursor: pointer",
- "}"
- ].join('\n');
- e.closer.classList.add("closer");
- e.closer.innerHTML = "✖";
-
- e.javaconsole = document.createElement("div");
- style.textContent += [
- "",
- ".pjsconsole .console {",
- " overflow-x: auto;",
- " display: block;",
- " position: absolute;",
- " left: 10px;",
- " right: 0px;",
- " bottom: 5px;",
- " top: 10px;",
- " overflow-y: scroll;",
- " height: 40px;",
- "}"
- ].join('\n');
- e.javaconsole.setAttribute("class", "console");
-
- e.wrapper.appendChild(e.dragger);
- e.wrapper.appendChild(e.javaconsole);
- e.wrapper.appendChild(e.closer);
-
- e.dragger.onmousedown = function (t) {
- e.divheight = e.wrapper.style.height;
- if (document.selection) document.selection.empty();
- else window.getSelection().removeAllRanges();
- var n = t.screenY;
- window.onmousemove = function (t) {
- e.wrapper.style.height = parseFloat(e.divheight) + (n - t.screenY) + "px";
- e.javaconsole.style.height = parseFloat(e.divheight) + (n - t.screenY) - 10 + "px";
- };
- window.onmouseup = function (t) {
- if (document.selection) document.selection.empty();
- else window.getSelection().removeAllRanges();
- e.wrapper.style.height = parseFloat(e.divheight) + (n - t.screenY) + "px";
- e.javaconsole.style.height = parseFloat(e.divheight) + (n - t.screenY) - 10 + "px";
- window.onmousemove = null;
- window.onmouseup = null;
- };
- };
-
- e.BufferArray = [];
-
- e.print = e.log = function () {
- var args = Array.prototype.slice.call(arguments);
- t = args.map(function(t, idx) { return t + (idx+1 === args.length ? "" : " "); }).join('');
- if (e.BufferArray[e.BufferArray.length - 1]) e.BufferArray[e.BufferArray.length - 1] += (t) + "";
- else e.BufferArray.push(t);
- e.javaconsole.innerHTML = e.BufferArray.join('');
- e.showconsole();
- };
-
- e.println = function () {
- if(!added) {
- document.body.appendChild(style);
- document.body.appendChild(e.wrapper);
- added = true;
- }
- var args = Array.prototype.slice.call(arguments);
- args.push('<br>');
- e.print.apply(e, args);
- if (e.BufferArray.length > e.BufferMax) {
- e.BufferArray.splice(0, 1);
- } else {
- e.javaconsole.scrollTop = e.javaconsole.scrollHeight;
- }
- };
-
- e.showconsole = function () { e.wrapper.classList.remove("hidden"); };
- e.hideconsole = function () { e.wrapper.classList.add("hidden"); };
-
- e.closer.onclick = function () { e.hideconsole(); };
-
- e.hideconsole();
-
- return e;
- };
-
- },{}],6:[function(require,module,exports){
- /**
- * Processing.js default scope
- */
- module.exports = function(options) {
-
- // Building defaultScope. Changing of the prototype protects
- // internal Processing code from the changes in defaultScope
- function DefaultScope() {}
- DefaultScope.prototype = options.PConstants;
-
- var defaultScope = new DefaultScope();
-
- // copy over all known Object types and helper objects
- Object.keys(options).forEach(function(prop) {
- defaultScope[prop] = options[prop];
- });
-
- ////////////////////////////////////////////////////////////////////////////
- // Class inheritance helper methods
- ////////////////////////////////////////////////////////////////////////////
-
- defaultScope.defineProperty = function(obj, name, desc) {
- if("defineProperty" in Object) {
- Object.defineProperty(obj, name, desc);
- } else {
- if (desc.hasOwnProperty("get")) {
- obj.__defineGetter__(name, desc.get);
- }
- if (desc.hasOwnProperty("set")) {
- obj.__defineSetter__(name, desc.set);
- }
- }
- };
-
- /**
- * class overloading, part 1
- */
- function overloadBaseClassFunction(object, name, basefn) {
- if (!object.hasOwnProperty(name) || typeof object[name] !== 'function') {
- // object method is not a function or just inherited from Object.prototype
- object[name] = basefn;
- return;
- }
- var fn = object[name];
- if ("$overloads" in fn) {
- // the object method already overloaded (see defaultScope.addMethod)
- // let's just change a fallback method
- fn.$defaultOverload = basefn;
- return;
- }
- if (!("$overloads" in basefn) && fn.length === basefn.length) {
- // special case when we just overriding the method
- return;
- }
- var overloads, defaultOverload;
- if ("$overloads" in basefn) {
- // let's inherit base class overloads to speed up things
- overloads = basefn.$overloads.slice(0);
- overloads[fn.length] = fn;
- defaultOverload = basefn.$defaultOverload;
- } else {
- overloads = [];
- overloads[basefn.length] = basefn;
- overloads[fn.length] = fn;
- defaultOverload = fn;
- }
- var hubfn = function() {
- var fn = hubfn.$overloads[arguments.length] ||
- ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ?
- hubfn.$overloads[hubfn.$methodArgsIndex] : null) ||
- hubfn.$defaultOverload;
- return fn.apply(this, arguments);
- };
- hubfn.$overloads = overloads;
- if ("$methodArgsIndex" in basefn) {
- hubfn.$methodArgsIndex = basefn.$methodArgsIndex;
- }
- hubfn.$defaultOverload = defaultOverload;
- hubfn.name = name;
- object[name] = hubfn;
- }
-
- /**
- * class overloading, part 2
- */
-
- function extendClass(subClass, baseClass) {
- function extendGetterSetter(propertyName) {
- defaultScope.defineProperty(subClass, propertyName, {
- get: function() {
- return baseClass[propertyName];
- },
- set: function(v) {
- baseClass[propertyName]=v;
- },
- enumerable: true
- });
- }
-
- var properties = [];
- for (var propertyName in baseClass) {
- if (typeof baseClass[propertyName] === 'function') {
- overloadBaseClassFunction(subClass, propertyName, baseClass[propertyName]);
- } else if(propertyName.charAt(0) !== "$" && !(propertyName in subClass)) {
- // Delaying the properties extension due to the IE9 bug (see #918).
- properties.push(propertyName);
- }
- }
- while (properties.length > 0) {
- extendGetterSetter(properties.shift());
- }
-
- subClass.$super = baseClass;
- }
-
- /**
- * class overloading, part 3
- */
- defaultScope.extendClassChain = function(base) {
- var path = [base];
- for (var self = base.$upcast; self; self = self.$upcast) {
- extendClass(self, base);
- path.push(self);
- base = self;
- }
- while (path.length > 0) {
- path.pop().$self=base;
- }
- };
-
- // static
- defaultScope.extendStaticMembers = function(derived, base) {
- extendClass(derived, base);
- };
-
- // interface
- defaultScope.extendInterfaceMembers = function(derived, base) {
- extendClass(derived, base);
- };
-
- /**
- * Java methods and JavaScript functions differ enough that
- * we need a special function to make sure it all links up
- * as classical hierarchical class chains.
- */
- defaultScope.addMethod = function(object, name, fn, hasMethodArgs) {
- var existingfn = object[name];
- if (existingfn || hasMethodArgs) {
- var args = fn.length;
- // builds the overload methods table
- if ("$overloads" in existingfn) {
- existingfn.$overloads[args] = fn;
- } else {
- var hubfn = function() {
- var fn = hubfn.$overloads[arguments.length] ||
- ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ?
- hubfn.$overloads[hubfn.$methodArgsIndex] : null) ||
- hubfn.$defaultOverload;
- return fn.apply(this, arguments);
- };
- var overloads = [];
- if (existingfn) {
- overloads[existingfn.length] = existingfn;
- }
- overloads[args] = fn;
- hubfn.$overloads = overloads;
- hubfn.$defaultOverload = existingfn || fn;
- if (hasMethodArgs) {
- hubfn.$methodArgsIndex = args;
- }
- hubfn.name = name;
- object[name] = hubfn;
- }
- } else {
- object[name] = fn;
- }
- };
-
- // internal helper function
- function isNumericalJavaType(type) {
- if (typeof type !== "string") {
- return false;
- }
- return ["byte", "int", "char", "color", "float", "long", "double"].indexOf(type) !== -1;
- }
-
- /**
- * Java's arrays are pre-filled when declared with
- * an initial size, but no content. JS arrays are not.
- */
- defaultScope.createJavaArray = function(type, bounds) {
- var result = null,
- defaultValue = null;
- if (typeof type === "string") {
- if (type === "boolean") {
- defaultValue = false;
- } else if (isNumericalJavaType(type)) {
- defaultValue = 0;
- }
- }
- if (typeof bounds[0] === 'number') {
- var itemsCount = 0 | bounds[0];
- if (bounds.length <= 1) {
- result = [];
- result.length = itemsCount;
- for (var i = 0; i < itemsCount; ++i) {
- result[i] = defaultValue;
- }
- } else {
- result = [];
- var newBounds = bounds.slice(1);
- for (var j = 0; j < itemsCount; ++j) {
- result.push(defaultScope.createJavaArray(type, newBounds));
- }
- }
- }
- return result;
- };
-
- // screenWidth and screenHeight are shared by all instances.
- // and return the width/height of the browser's viewport.
- defaultScope.defineProperty(defaultScope, 'screenWidth',
- { get: function() { return window.innerWidth; } });
-
- defaultScope.defineProperty(defaultScope, 'screenHeight',
- { get: function() { return window.innerHeight; } });
-
- return defaultScope;
- };
-
- },{}],7:[function(require,module,exports){
- /**
- * Finalise the Processing.js object.
- */
- module.exports = function finalizeProcessing(Processing, options) {
-
- // unpack options
- var window = options.window,
- document = options.document,
- XMLHttpRequest = window.XMLHttpRequest,
- noop = options.noop,
- isDOMPresent = options.isDOMPresent,
- version = options.version,
- undef;
-
- // versioning
- Processing.version = (version ? version : "@DEV-VERSION@");
-
- // Share lib space
- Processing.lib = {};
-
- /**
- * External libraries can be added to the global Processing
- * objects with the `registerLibrary` function.
- */
- Processing.registerLibrary = function(name, library) {
- Processing.lib[name] = library;
- if(library.hasOwnProperty("init")) {
- library.init(defaultScope);
- }
- };
-
- /**
- * This is the object that acts as our version of PApplet.
- * This can be called as Processing.Sketch() or as
- * Processing.Sketch(function) in which case the function
- * must be an already-compiled-to-JS sketch function.
- */
- Processing.Sketch = function(attachFunction) {
- this.attachFunction = attachFunction;
- this.options = {
- pauseOnBlur: false,
- globalKeyEvents: false
- };
-
- /* Optional Sketch event hooks:
- * onLoad - parsing/preloading is done, before sketch starts
- * onSetup - setup() has been called, before first draw()
- * onPause - noLoop() has been called, pausing draw loop
- * onLoop - loop() has been called, resuming draw loop
- * onFrameStart - draw() loop about to begin
- * onFrameEnd - draw() loop finished
- * onExit - exit() done being called
- */
- this.onLoad = noop;
- this.onSetup = noop;
- this.onPause = noop;
- this.onLoop = noop;
- this.onFrameStart = noop;
- this.onFrameEnd = noop;
- this.onExit = noop;
-
- this.params = {};
- this.imageCache = {
- pending: 0,
- images: {},
- // Opera requires special administration for preloading
- operaCache: {},
- // Specify an optional img arg if the image is already loaded in the DOM,
- // otherwise href will get loaded.
- add: function(href, img) {
- // Prevent muliple loads for an image, in case it gets
- // preloaded more than once, or is added via JS and then preloaded.
- if (this.images[href]) {
- return;
- }
-
- if (!isDOMPresent) {
- this.images[href] = null;
- }
-
- // No image in the DOM, kick-off a background load
- if (!img) {
- img = new Image();
- img.onload = (function(owner) {
- return function() {
- owner.pending--;
- };
- }(this));
- this.pending++;
- img.src = href;
- }
-
- this.images[href] = img;
-
- // Opera will not load images until they are inserted into the DOM.
- if (window.opera) {
- var div = document.createElement("div");
- div.appendChild(img);
- // we can't use "display: none", since that makes it invisible, and thus not load
- div.style.position = "absolute";
- div.style.opacity = 0;
- div.style.width = "1px";
- div.style.height= "1px";
- if (!this.operaCache[href]) {
- document.body.appendChild(div);
- this.operaCache[href] = div;
- }
- }
- }
- };
-
- this.sourceCode = undefined;
- this.attach = function(processing) {
- // either attachFunction or sourceCode must be present on attach
- if(typeof this.attachFunction === "function") {
- this.attachFunction(processing);
- } else if(this.sourceCode) {
- var func = ((new Function("return (" + this.sourceCode + ");"))());
- func(processing);
- this.attachFunction = func;
- } else {
- throw "Unable to attach sketch to the processing instance";
- }
- };
-
- this.toString = function() {
- var i;
- var code = "((function(Sketch) {\n";
- code += "var sketch = new Sketch(\n" + this.sourceCode + ");\n";
- for(i in this.options) {
- if(this.options.hasOwnProperty(i)) {
- var value = this.options[i];
- code += "sketch.options." + i + " = " +
- (typeof value === 'string' ? '\"' + value + '\"' : "" + value) + ";\n";
- }
- }
- for(i in this.imageCache) {
- if(this.options.hasOwnProperty(i)) {
- code += "sketch.imageCache.add(\"" + i + "\");\n";
- }
- }
- // TODO serialize fonts
- code += "return sketch;\n})(Processing.Sketch))";
- return code;
- };
- };
-
- /**
- * aggregate all source code into a single file, then rewrite that
- * source and bind to canvas via new Processing(canvas, sourcestring).
- * @param {CANVAS} canvas The html canvas element to bind to
- * @param {String[]} source The array of files that must be loaded
- */
- var loadSketchFromSources = Processing.loadSketchFromSources = function(canvas, sources) {
- var code = [], errors = [], sourcesCount = sources.length, loaded = 0;
-
- function ajaxAsync(url, callback) {
- var xhr = new XMLHttpRequest();
- xhr.onreadystatechange = function() {
- if (xhr.readyState === 4) {
- var error;
- if (xhr.status !== 200 && xhr.status !== 0) {
- error = "Invalid XHR status " + xhr.status;
- } else if (xhr.responseText === "") {
- // Give a hint when loading fails due to same-origin issues on file:/// urls
- if ( ("withCredentials" in new XMLHttpRequest()) &&
- (new XMLHttpRequest()).withCredentials === false &&
- window.location.protocol === "file:" ) {
- error = "XMLHttpRequest failure, possibly due to a same-origin policy violation. You can try loading this page in another browser, or load it from http://localhost using a local webserver. See the Processing.js README for a more detailed explanation of this problem and solutions.";
- } else {
- error = "File is empty.";
- }
- }
-
- callback(xhr.responseText, error);
- }
- };
- xhr.open("GET", url, true);
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType("application/json");
- }
- xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); // no cache
- xhr.send(null);
- }
-
- function loadBlock(index, filename) {
- function callback(block, error) {
- code[index] = block;
- ++loaded;
- if (error) {
- errors.push(filename + " ==> " + error);
- }
- if (loaded === sourcesCount) {
- if (errors.length === 0) {
- // This used to throw, but it was constantly getting in the way of debugging where things go wrong!
- return new Processing(canvas, code.join("\n"));
- } else {
- throw "Processing.js: Unable to load pjs sketch files: " + errors.join("\n");
- }
- }
- }
- if (filename.charAt(0) === '#') {
- // trying to get script from the element
- var scriptElement = document.getElementById(filename.substring(1));
- if (scriptElement) {
- callback(scriptElement.text || scriptElement.textContent);
- } else {
- callback("", "Unable to load pjs sketch: element with id \'" + filename.substring(1) + "\' was not found");
- }
- return;
- }
-
- ajaxAsync(filename, callback);
- }
-
- for (var i = 0; i < sourcesCount; ++i) {
- loadBlock(i, sources[i]);
- }
- };
-
- /**
- * Automatic initialization function.
- */
- var init = function() {
- document.removeEventListener('DOMContentLoaded', init, false);
- var i;
-
- // before running through init, clear the instances list, to prevent
- // sketch duplication when page content is dynamically swapped without
- // swapping out processing.js
- while (Processing.instances.length > 0) {
- for (i = Processing.instances.length - 1; i >= 0; i--) {
- if (Processing.instances[i]) {
- Processing.instances[i].exit();
- }
- }
- }
-
- var canvas = document.getElementsByTagName('canvas'),
- filenames;
-
- for (i = 0, l = canvas.length; i < l; i++) {
- // datasrc and data-src are deprecated.
- var processingSources = canvas[i].getAttribute('data-processing-sources');
- if (processingSources === null) {
- // Temporary fallback for datasrc and data-src
- processingSources = canvas[i].getAttribute('data-src');
- if (processingSources === null) {
- processingSources = canvas[i].getAttribute('datasrc');
- }
- }
- if (processingSources) {
- filenames = processingSources.split(/\s+/g);
- for (var j = 0; j < filenames.length;) {
- if (filenames[j]) {
- j++;
- } else {
- filenames.splice(j, 1);
- }
- }
- loadSketchFromSources(canvas[i], filenames);
- }
- }
-
- // also process all <script>-indicated sketches, if there are any
- var s, last, source, instance,
- nodelist = document.getElementsByTagName('script'),
- scripts=[];
-
- // snapshot the DOM, as the nodelist is only a DOM view, and is
- // updated instantly when a script element is added or removed.
- for (s = nodelist.length - 1; s >= 0; s--) {
- scripts.push(nodelist[s]);
- }
-
- // iterate over all script elements to see if they contain Processing code
- for (s = 0, last = scripts.length; s < last; s++) {
- var script = scripts[s];
- if (!script.getAttribute) {
- continue;
- }
-
- var type = script.getAttribute("type");
- if (type && (type.toLowerCase() === "text/processing" || type.toLowerCase() === "application/processing")) {
- var target = script.getAttribute("data-processing-target");
- canvas = undef;
- if (target) {
- canvas = document.getElementById(target);
- } else {
- var nextSibling = script.nextSibling;
- while (nextSibling && nextSibling.nodeType !== 1) {
- nextSibling = nextSibling.nextSibling;
- }
- if (nextSibling && nextSibling.nodeName.toLowerCase() === "canvas") {
- canvas = nextSibling;
- }
- }
-
- if (canvas) {
- if (script.getAttribute("src")) {
- filenames = script.getAttribute("src").split(/\s+/);
- loadSketchFromSources(canvas, filenames);
- continue;
- }
- source = script.textContent || script.text;
- instance = new Processing(canvas, source);
- }
- }
- }
- };
-
- /**
- * automatic loading of all sketches on the page
- */
- document.addEventListener('DOMContentLoaded', init, false);
-
- /**
- * Make Processing run through init after already having
- * been set up for a page. This function exists mostly for pages
- * that swap content in/out without reloading a page.
- */
- Processing.reload = init;
-
- /**
- * Disable the automatic loading of all sketches on the page.
- * This will work as long as it's issued before DOMContentLoaded.
- */
- Processing.disableInit = function() {
- document.removeEventListener('DOMContentLoaded', init, false);
- };
-
- // done.
- return Processing;
- };
-
- },{}],8:[function(require,module,exports){
- /**
- * Returns Java equals() result for two objects. If the first object
- * has the "equals" function, it preforms the call of this function.
- * Otherwise the method uses the JavaScript === operator.
- *
- * @param {Object} obj The first object.
- * @param {Object} other The second object.
- *
- * @returns {boolean} true if the objects are equal.
- */
- module.exports = function virtEquals(obj, other) {
- if (obj === null || other === null) {
- return (obj === null) && (other === null);
- }
- if (typeof (obj) === "string") {
- return obj === other;
- }
- if (typeof(obj) !== "object") {
- return obj === other;
- }
- if (obj.equals instanceof Function) {
- return obj.equals(other);
- }
- return obj === other;
- };
-
- },{}],9:[function(require,module,exports){
- /**
- * Returns Java hashCode() result for the object. If the object has the "hashCode" function,
- * it preforms the call of this function. Otherwise it uses/creates the "$id" property,
- * which is used as the hashCode.
- *
- * @param {Object} obj The object.
- * @returns {int} The object's hash code.
- */
- module.exports = function virtHashCode(obj, undef) {
- if (typeof(obj) === "string") {
- var hash = 0;
- for (var i = 0; i < obj.length; ++i) {
- hash = (hash * 31 + obj.charCodeAt(i)) & 0xFFFFFFFF;
- }
- return hash;
- }
- if (typeof(obj) !== "object") {
- return obj & 0xFFFFFFFF;
- }
- if (obj.hashCode instanceof Function) {
- return obj.hashCode();
- }
- if (obj.$id === undef) {
- obj.$id = ((Math.floor(Math.random() * 0x10000) - 0x8000) << 16) | Math.floor(Math.random() * 0x10000);
- }
- return obj.$id;
- };
-
- },{}],10:[function(require,module,exports){
- /**
- * An ArrayList stores a variable number of objects.
- *
- * @param {int} initialCapacity optional defines the initial capacity of the list, it's empty by default
- *
- * @returns {ArrayList} new ArrayList object
- */
- module.exports = function(options) {
- var virtHashCode = options.virtHashCode,
- virtEquals = options.virtEquals;
-
- function Iterator(array) {
- var index = -1;
- this.hasNext = function() {
- return (index + 1) < array.length;
- };
-
- this.next = function() {
- return array[++index];
- };
-
- this.remove = function() {
- array.splice(index--, 1);
- };
- }
-
- function ArrayList(a) {
- var array = [];
-
- if (a && a.toArray) {
- array = a.toArray();
- }
-
- /**
- * @member ArrayList
- * ArrayList.get() Returns the element at the specified position in this list.
- *
- * @param {int} i index of element to return
- *
- * @returns {Object} the element at the specified position in this list.
- */
- this.get = function(i) {
- return array[i];
- };
- /**
- * @member ArrayList
- * ArrayList.contains() Returns true if this list contains the specified element.
- *
- * @param {Object} item element whose presence in this List is to be tested.
- *
- * @returns {boolean} true if the specified element is present; false otherwise.
- */
- this.contains = function(item) {
- return this.indexOf(item)>-1;
- };
- /**
- * @member ArrayList
- * ArrayList.indexOf() Returns the position this element takes in the list, or -1 if the element is not found.
- *
- * @param {Object} item element whose position in this List is to be tested.
- *
- * @returns {int} the list position that the first match for this element holds in the list, or -1 if it is not in the list.
- */
- this.indexOf = function(item) {
- for (var i = 0, len = array.length; i < len; ++i) {
- if (virtEquals(item, array[i])) {
- return i;
- }
- }
- return -1;
- };
- /**
- * @member ArrayList
- * ArrayList.lastIndexOf() Returns the index of the last occurrence of the specified element in this list,
- * or -1 if this list does not contain the element. More formally, returns the highest index i such that
- * (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
- *
- * @param {Object} item element to search for.
- *
- * @returns {int} the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
- */
- this.lastIndexOf = function(item) {
- for (var i = array.length-1; i >= 0; --i) {
- if (virtEquals(item, array[i])) {
- return i;
- }
- }
- return -1;
- };
- /**
- * @member ArrayList
- * ArrayList.add() Adds the specified element to this list.
- *
- * @param {int} index optional index at which the specified element is to be inserted
- * @param {Object} object element to be added to the list
- */
- this.add = function() {
- if (arguments.length === 1) {
- array.push(arguments[0]); // for add(Object)
- } else if (arguments.length === 2) {
- var arg0 = arguments[0];
- if (typeof arg0 === 'number') {
- if (arg0 >= 0 && arg0 <= array.length) {
- array.splice(arg0, 0, arguments[1]); // for add(i, Object)
- } else {
- throw(arg0 + " is not a valid index");
- }
- } else {
- throw(typeof arg0 + " is not a number");
- }
- } else {
- throw("Please use the proper number of parameters.");
- }
- };
- /**
- * @member ArrayList
- * ArrayList.addAll(collection) appends all of the elements in the specified
- * Collection to the end of this list, in the order that they are returned by
- * the specified Collection's Iterator.
- *
- * When called as addAll(index, collection) the elements are inserted into
- * this list at the position indicated by index.
- *
- * @param {index} Optional; specifies the position the colletion should be inserted at
- * @param {collection} Any iterable object (ArrayList, HashMap.keySet(), etc.)
- * @throws out of bounds error for negative index, or index greater than list size.
- */
- this.addAll = function(arg1, arg2) {
- // addAll(int, Collection)
- var it;
- if (typeof arg1 === "number") {
- if (arg1 < 0 || arg1 > array.length) {
- throw("Index out of bounds for addAll: " + arg1 + " greater or equal than " + array.length);
- }
- it = new ObjectIterator(arg2);
- while (it.hasNext()) {
- array.splice(arg1++, 0, it.next());
- }
- }
- // addAll(Collection)
- else {
- it = new ObjectIterator(arg1);
- while (it.hasNext()) {
- array.push(it.next());
- }
- }
- };
- /**
- * @member ArrayList
- * ArrayList.set() Replaces the element at the specified position in this list with the specified element.
- *
- * @param {int} index index of element to replace
- * @param {Object} object element to be stored at the specified position
- */
- this.set = function() {
- if (arguments.length === 2) {
- var arg0 = arguments[0];
- if (typeof arg0 === 'number') {
- if (arg0 >= 0 && arg0 < array.length) {
- array.splice(arg0, 1, arguments[1]);
- } else {
- throw(arg0 + " is not a valid index.");
- }
- } else {
- throw(typeof arg0 + " is not a number");
- }
- } else {
- throw("Please use the proper number of parameters.");
- }
- };
-
- /**
- * @member ArrayList
- * ArrayList.size() Returns the number of elements in this list.
- *
- * @returns {int} the number of elements in this list
- */
- this.size = function() {
- return array.length;
- };
-
- /**
- * @member ArrayList
- * ArrayList.clear() Removes all of the elements from this list. The list will be empty after this call returns.
- */
- this.clear = function() {
- array.length = 0;
- };
-
- /**
- * @member ArrayList
- * ArrayList.remove() Removes an element either based on index, if the argument is a number, or
- * by equality check, if the argument is an object.
- *
- * @param {int|Object} item either the index of the element to be removed, or the element itself.
- *
- * @returns {Object|boolean} If removal is by index, the element that was removed, or null if nothing was removed. If removal is by object, true if removal occurred, otherwise false.
- */
- this.remove = function(item) {
- if (typeof item === 'number') {
- return array.splice(item, 1)[0];
- }
- item = this.indexOf(item);
- if (item > -1) {
- array.splice(item, 1);
- return true;
- }
- return false;
- };
-
- /**
- * @member ArrayList
- * ArrayList.removeAll Removes from this List all of the elements from
- * the current ArrayList which are present in the passed in paramater ArrayList 'c'.
- * Shifts any succeeding elements to the left (reduces their index).
- *
- * @param {ArrayList} the ArrayList to compare to the current ArrayList
- *
- * @returns {boolean} true if the ArrayList had an element removed; false otherwise
- */
- this.removeAll = function(c) {
- var i, x, item,
- newList = new ArrayList();
- newList.addAll(this);
- this.clear();
- // For every item that exists in the original ArrayList and not in the c ArrayList
- // copy it into the empty 'this' ArrayList to create the new 'this' Array.
- for (i = 0, x = 0; i < newList.size(); i++) {
- item = newList.get(i);
- if (!c.contains(item)) {
- this.add(x++, item);
- }
- }
- if (this.size() < newList.size()) {
- return true;
- }
- return false;
- };
-
- /**
- * @member ArrayList
- * ArrayList.isEmpty() Tests if this list has no elements.
- *
- * @returns {boolean} true if this list has no elements; false otherwise
- */
- this.isEmpty = function() {
- return !array.length;
- };
-
- /**
- * @member ArrayList
- * ArrayList.clone() Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)
- *
- * @returns {ArrayList} a clone of this ArrayList instance
- */
- this.clone = function() {
- return new ArrayList(this);
- };
-
- /**
- * @member ArrayList
- * ArrayList.toArray() Returns an array containing all of the elements in this list in the correct order.
- *
- * @returns {Object[]} Returns an array containing all of the elements in this list in the correct order
- */
- this.toArray = function() {
- return array.slice(0);
- };
-
- this.iterator = function() {
- return new Iterator(array);
- };
- }
-
- return ArrayList;
- };
-
- },{}],11:[function(require,module,exports){
- module.exports = (function(charMap, undef) {
-
- var Char = function(chr) {
- if (typeof chr === 'string' && chr.length === 1) {
- this.code = chr.charCodeAt(0);
- } else if (typeof chr === 'number') {
- this.code = chr;
- } else if (chr instanceof Char) {
- this.code = chr;
- } else {
- this.code = NaN;
- }
- return (charMap[this.code] === undef) ? charMap[this.code] = this : charMap[this.code];
- };
-
- Char.prototype.toString = function() {
- return String.fromCharCode(this.code);
- };
-
- Char.prototype.valueOf = function() {
- return this.code;
- };
-
- return Char;
- }({}));
-
- },{}],12:[function(require,module,exports){
- /**
- * A HashMap stores a collection of objects, each referenced by a key. This is similar to an Array, only
- * instead of accessing elements with a numeric index, a String is used. (If you are familiar with
- * associative arrays from other languages, this is the same idea.)
- *
- * @param {int} initialCapacity defines the initial capacity of the map, it's 16 by default
- * @param {float} loadFactor the load factor for the map, the default is 0.75
- * @param {Map} m gives the new HashMap the same mappings as this Map
- */
- module.exports = function(options) {
- var virtHashCode = options.virtHashCode,
- virtEquals = options.virtEquals;
-
- /**
- * @member HashMap
- * A HashMap stores a collection of objects, each referenced by a key. This is similar to an Array, only
- * instead of accessing elements with a numeric index, a String is used. (If you are familiar with
- * associative arrays from other languages, this is the same idea.)
- *
- * @param {int} initialCapacity defines the initial capacity of the map, it's 16 by default
- * @param {float} loadFactor the load factor for the map, the default is 0.75
- * @param {Map} m gives the new HashMap the same mappings as this Map
- */
- function HashMap() {
- if (arguments.length === 1 && arguments[0] instanceof HashMap) {
- return arguments[0].clone();
- }
-
- var initialCapacity = arguments.length > 0 ? arguments[0] : 16;
- var loadFactor = arguments.length > 1 ? arguments[1] : 0.75;
- var buckets = [];
- buckets.length = initialCapacity;
- var count = 0;
- var hashMap = this;
-
- function getBucketIndex(key) {
- var index = virtHashCode(key) % buckets.length;
- return index < 0 ? buckets.length + index : index;
- }
- function ensureLoad() {
- if (count <= loadFactor * buckets.length) {
- return;
- }
- var allEntries = [];
- for (var i = 0; i < buckets.length; ++i) {
- if (buckets[i] !== undefined) {
- allEntries = allEntries.concat(buckets[i]);
- }
- }
- var newBucketsLength = buckets.length * 2;
- buckets = [];
- buckets.length = newBucketsLength;
- for (var j = 0; j < allEntries.length; ++j) {
- var index = getBucketIndex(allEntries[j].key);
- var bucket = buckets[index];
- if (bucket === undefined) {
- buckets[index] = bucket = [];
- }
- bucket.push(allEntries[j]);
- }
- }
-
- function Iterator(conversion, removeItem) {
- var bucketIndex = 0;
- var itemIndex = -1;
- var endOfBuckets = false;
- var currentItem;
-
- function findNext() {
- while (!endOfBuckets) {
- ++itemIndex;
- if (bucketIndex >= buckets.length) {
- endOfBuckets = true;
- } else if (buckets[bucketIndex] === undefined || itemIndex >= buckets[bucketIndex].length) {
- itemIndex = -1;
- ++bucketIndex;
- } else {
- return;
- }
- }
- }
-
- /*
- * @member Iterator
- * Checks if the Iterator has more items
- */
- this.hasNext = function() {
- return !endOfBuckets;
- };
-
- /*
- * @member Iterator
- * Return the next Item
- */
- this.next = function() {
- currentItem = conversion(buckets[bucketIndex][itemIndex]);
- findNext();
- return currentItem;
- };
-
- /*
- * @member Iterator
- * Remove the current item
- */
- this.remove = function() {
- if (currentItem !== undefined) {
- removeItem(currentItem);
- --itemIndex;
- findNext();
- }
- };
-
- findNext();
- }
-
- function Set(conversion, isIn, removeItem) {
- this.clear = function() {
- hashMap.clear();
- };
-
- this.contains = function(o) {
- return isIn(o);
- };
-
- this.containsAll = function(o) {
- var it = o.iterator();
- while (it.hasNext()) {
- if (!this.contains(it.next())) {
- return false;
- }
- }
- return true;
- };
-
- this.isEmpty = function() {
- return hashMap.isEmpty();
- };
-
- this.iterator = function() {
- return new Iterator(conversion, removeItem);
- };
-
- this.remove = function(o) {
- if (this.contains(o)) {
- removeItem(o);
- return true;
- }
- return false;
- };
-
- this.removeAll = function(c) {
- var it = c.iterator();
- var changed = false;
- while (it.hasNext()) {
- var item = it.next();
- if (this.contains(item)) {
- removeItem(item);
- changed = true;
- }
- }
- return true;
- };
-
- this.retainAll = function(c) {
- var it = this.iterator();
- var toRemove = [];
- while (it.hasNext()) {
- var entry = it.next();
- if (!c.contains(entry)) {
- toRemove.push(entry);
- }
- }
- for (var i = 0; i < toRemove.length; ++i) {
- removeItem(toRemove[i]);
- }
- return toRemove.length > 0;
- };
-
- this.size = function() {
- return hashMap.size();
- };
-
- this.toArray = function() {
- var result = [];
- var it = this.iterator();
- while (it.hasNext()) {
- result.push(it.next());
- }
- return result;
- };
- }
-
- function Entry(pair) {
- this._isIn = function(map) {
- return map === hashMap && (pair.removed === undefined);
- };
-
- this.equals = function(o) {
- return virtEquals(pair.key, o.getKey());
- };
-
- this.getKey = function() {
- return pair.key;
- };
-
- this.getValue = function() {
- return pair.value;
- };
-
- this.hashCode = function(o) {
- return virtHashCode(pair.key);
- };
-
- this.setValue = function(value) {
- var old = pair.value;
- pair.value = value;
- return old;
- };
- }
-
- this.clear = function() {
- count = 0;
- buckets = [];
- buckets.length = initialCapacity;
- };
-
- this.clone = function() {
- var map = new HashMap();
- map.putAll(this);
- return map;
- };
-
- this.containsKey = function(key) {
- var index = getBucketIndex(key);
- var bucket = buckets[index];
- if (bucket === undefined) {
- return false;
- }
- for (var i = 0; i < bucket.length; ++i) {
- if (virtEquals(bucket[i].key, key)) {
- return true;
- }
- }
- return false;
- };
-
- this.containsValue = function(value) {
- for (var i = 0; i < buckets.length; ++i) {
- var bucket = buckets[i];
- if (bucket === undefined) {
- continue;
- }
- for (var j = 0; j < bucket.length; ++j) {
- if (virtEquals(bucket[j].value, value)) {
- return true;
- }
- }
- }
- return false;
- };
-
- this.entrySet = function() {
- return new Set(
-
- function(pair) {
- return new Entry(pair);
- },
-
- function(pair) {
- return (pair instanceof Entry) && pair._isIn(hashMap);
- },
-
- function(pair) {
- return hashMap.remove(pair.getKey());
- });
- };
-
- this.get = function(key) {
- var index = getBucketIndex(key);
- var bucket = buckets[index];
- if (bucket === undefined) {
- return null;
- }
- for (var i = 0; i < bucket.length; ++i) {
- if (virtEquals(bucket[i].key, key)) {
- return bucket[i].value;
- }
- }
- return null;
- };
-
- this.isEmpty = function() {
- return count === 0;
- };
-
- this.keySet = function() {
- return new Set(
- // get key from pair
- function(pair) {
- return pair.key;
- },
- // is-in test
- function(key) {
- return hashMap.containsKey(key);
- },
- // remove from hashmap by key
- function(key) {
- return hashMap.remove(key);
- }
- );
- };
-
- this.values = function() {
- return new Set(
- // get value from pair
- function(pair) {
- return pair.value;
- },
- // is-in test
- function(value) {
- return hashMap.containsValue(value);
- },
- // remove from hashmap by value
- function(value) {
- return hashMap.removeByValue(value);
- }
- );
- };
-
- this.put = function(key, value) {
- var index = getBucketIndex(key);
- var bucket = buckets[index];
- if (bucket === undefined) {
- ++count;
- buckets[index] = [{
- key: key,
- value: value
- }];
- ensureLoad();
- return null;
- }
- for (var i = 0; i < bucket.length; ++i) {
- if (virtEquals(bucket[i].key, key)) {
- var previous = bucket[i].value;
- bucket[i].value = value;
- return previous;
- }
- }
- ++count;
- bucket.push({
- key: key,
- value: value
- });
- ensureLoad();
- return null;
- };
-
- this.putAll = function(m) {
- var it = m.entrySet().iterator();
- while (it.hasNext()) {
- var entry = it.next();
- this.put(entry.getKey(), entry.getValue());
- }
- };
-
- this.remove = function(key) {
- var index = getBucketIndex(key);
- var bucket = buckets[index];
- if (bucket === undefined) {
- return null;
- }
- for (var i = 0; i < bucket.length; ++i) {
- if (virtEquals(bucket[i].key, key)) {
- --count;
- var previous = bucket[i].value;
- bucket[i].removed = true;
- if (bucket.length > 1) {
- bucket.splice(i, 1);
- } else {
- buckets[index] = undefined;
- }
- return previous;
- }
- }
- return null;
- };
-
- this.removeByValue = function(value) {
- var bucket, i, ilen, pair;
- for (bucket in buckets) {
- if (buckets.hasOwnProperty(bucket)) {
- for (i = 0, ilen = buckets[bucket].length; i < ilen; i++) {
- pair = buckets[bucket][i];
- // removal on values is based on identity, not equality
- if (pair.value === value) {
- buckets[bucket].splice(i, 1);
- return true;
- }
- }
- }
- }
- return false;
- };
-
- this.size = function() {
- return count;
- };
- }
-
- return HashMap;
- };
-
- },{}],13:[function(require,module,exports){
- // module export
- module.exports = function(options,undef) {
- var window = options.Browser.window,
- document = options.Browser.document,
- noop = options.noop;
-
- /**
- * [internal function] computeFontMetrics() calculates various metrics for text
- * placement. Currently this function computes the ascent, descent and leading
- * (from "lead", used for vertical space) values for the currently active font.
- */
- function computeFontMetrics(pfont) {
- var emQuad = 250,
- correctionFactor = pfont.size / emQuad,
- canvas = document.createElement("canvas");
- canvas.width = 2*emQuad;
- canvas.height = 2*emQuad;
- canvas.style.opacity = 0;
- var cfmFont = pfont.getCSSDefinition(emQuad+"px", "normal"),
- ctx = canvas.getContext("2d");
- ctx.font = cfmFont;
-
- // Size the canvas using a string with common max-ascent and max-descent letters.
- // Changing the canvas dimensions resets the context, so we must reset the font.
- var protrusions = "dbflkhyjqpg";
- canvas.width = ctx.measureText(protrusions).width;
- ctx.font = cfmFont;
-
- // for text lead values, we meaure a multiline text container.
- var leadDiv = document.createElement("div");
- leadDiv.style.position = "absolute";
- leadDiv.style.opacity = 0;
- leadDiv.style.fontFamily = '"' + pfont.name + '"';
- leadDiv.style.fontSize = emQuad + "px";
- leadDiv.innerHTML = protrusions + "<br/>" + protrusions;
- document.body.appendChild(leadDiv);
-
- var w = canvas.width,
- h = canvas.height,
- baseline = h/2;
-
- // Set all canvas pixeldata values to 255, with all the content
- // data being 0. This lets us scan for data[i] != 255.
- ctx.fillStyle = "white";
- ctx.fillRect(0, 0, w, h);
- ctx.fillStyle = "black";
- ctx.fillText(protrusions, 0, baseline);
- var pixelData = ctx.getImageData(0, 0, w, h).data;
-
- // canvas pixel data is w*4 by h*4, because R, G, B and A are separate,
- // consecutive values in the array, rather than stored as 32 bit ints.
- var i = 0,
- w4 = w * 4,
- len = pixelData.length;
-
- // Finding the ascent uses a normal, forward scanline
- while (++i < len && pixelData[i] === 255) {
- noop();
- }
- var ascent = Math.round(i / w4);
-
- // Finding the descent uses a reverse scanline
- i = len - 1;
- while (--i > 0 && pixelData[i] === 255) {
- noop();
- }
- var descent = Math.round(i / w4);
-
- // set font metrics
- pfont.ascent = correctionFactor * (baseline - ascent);
- pfont.descent = correctionFactor * (descent - baseline);
-
- // Then we try to get the real value from the browser
- if (document.defaultView.getComputedStyle) {
- var leadDivHeight = document.defaultView.getComputedStyle(leadDiv,null).getPropertyValue("height");
- leadDivHeight = correctionFactor * leadDivHeight.replace("px","");
- if (leadDivHeight >= pfont.size * 2) {
- pfont.leading = Math.round(leadDivHeight/2);
- }
- }
- document.body.removeChild(leadDiv);
-
- // if we're caching, cache the context used for this pfont
- if (pfont.caching) {
- return ctx;
- }
- }
-
- /**
- * Constructor for a system or from-file (non-SVG) font.
- */
- function PFont(name, size) {
- // according to the P5 API, new PFont() is legal (albeit completely useless)
- if (name === undef) {
- name = "";
- }
- this.name = name;
- if (size === undef) {
- size = 0;
- }
- this.size = size;
- this.glyph = false;
- this.ascent = 0;
- this.descent = 0;
- // For leading, the "safe" value uses the standard TEX ratio
- this.leading = 1.2 * size;
-
- // Note that an italic, bold font must used "... Bold Italic"
- // in P5. "... Italic Bold" is treated as normal/normal.
- var illegalIndicator = name.indexOf(" Italic Bold");
- if (illegalIndicator !== -1) {
- name = name.substring(0, illegalIndicator);
- }
-
- // determine font style
- this.style = "normal";
- var italicsIndicator = name.indexOf(" Italic");
- if (italicsIndicator !== -1) {
- name = name.substring(0, italicsIndicator);
- this.style = "italic";
- }
-
- // determine font weight
- this.weight = "normal";
- var boldIndicator = name.indexOf(" Bold");
- if (boldIndicator !== -1) {
- name = name.substring(0, boldIndicator);
- this.weight = "bold";
- }
-
- // determine font-family name
- this.family = "sans-serif";
- if (name !== undef) {
- switch(name) {
- case "sans-serif":
- case "serif":
- case "monospace":
- case "fantasy":
- case "cursive":
- this.family = name;
- break;
- default:
- this.family = '"' + name + '", sans-serif';
- break;
- }
- }
- // Calculate the ascent/descent/leading value based on
- // how the browser renders this font.
- this.context2d = computeFontMetrics(this);
- this.css = this.getCSSDefinition();
- if (this.context2d) {
- this.context2d.font = this.css;
- }
- }
-
- /**
- * regulates whether or not we're caching the canvas
- * 2d context for quick text width computation.
- */
- PFont.prototype.caching = true;
-
- /**
- * This function generates the CSS "font" string for this PFont
- */
- PFont.prototype.getCSSDefinition = function(fontSize, lineHeight) {
- if(fontSize===undef) {
- fontSize = this.size + "px";
- }
- if(lineHeight===undef) {
- lineHeight = this.leading + "px";
- }
- // CSS "font" definition: font-style font-variant font-weight font-size/line-height font-family
- var components = [this.style, "normal", this.weight, fontSize + "/" + lineHeight, this.family];
- return components.join(" ");
- };
-
- /**
- * Rely on the cached context2d measureText function.
- */
- PFont.prototype.measureTextWidth = function(string) {
- return this.context2d.measureText(string).width;
- };
-
- /**
- * FALLBACK FUNCTION -- replaces Pfont.prototype.measureTextWidth
- * when the font cache becomes too large. This contructs a new
- * canvas 2d context object for calling measureText on.
- */
- PFont.prototype.measureTextWidthFallback = function(string) {
- var canvas = document.createElement("canvas"),
- ctx = canvas.getContext("2d");
- ctx.font = this.css;
- return ctx.measureText(string).width;
- };
-
- /**
- * Global "loaded fonts" list, internal to PFont
- */
- PFont.PFontCache = { length: 0 };
-
- /**
- * This function acts as single access point for getting and caching
- * fonts across all sketches handled by an instance of Processing.js
- */
- PFont.get = function(fontName, fontSize) {
- // round fontSize to one decimal point
- fontSize = ((fontSize*10)+0.5|0)/10;
- var cache = PFont.PFontCache,
- idx = fontName+"/"+fontSize;
- if (!cache[idx]) {
- cache[idx] = new PFont(fontName, fontSize);
- cache.length++;
-
- // FALLBACK FUNCTIONALITY 1:
- // If the cache has become large, switch over from full caching
- // to caching only the static metrics for each new font request.
- if (cache.length === 50) {
- PFont.prototype.measureTextWidth = PFont.prototype.measureTextWidthFallback;
- PFont.prototype.caching = false;
- // clear contexts stored for each cached font
- var entry;
- for (entry in cache) {
- if (entry !== "length") {
- cache[entry].context2d = null;
- }
- }
- return new PFont(fontName, fontSize);
- }
-
- // FALLBACK FUNCTIONALITY 2:
- // If the cache has become too large, switch off font caching entirely.
- if (cache.length === 400) {
- PFont.PFontCache = {};
- PFont.get = PFont.getFallback;
- return new PFont(fontName, fontSize);
- }
- }
- return cache[idx];
- };
-
- /**
- * FALLBACK FUNCTION -- replaces PFont.get when the font cache
- * becomes too large. This function bypasses font caching entirely.
- */
- PFont.getFallback = function(fontName, fontSize) {
- return new PFont(fontName, fontSize);
- };
-
- /**
- * Lists all standard fonts. Due to browser limitations, this list is
- * not the system font list, like in P5, but the CSS "genre" list.
- */
- PFont.list = function() {
- return ["sans-serif", "serif", "monospace", "fantasy", "cursive"];
- };
-
- /**
- * Loading external fonts through @font-face rules is handled by PFont,
- * to ensure fonts loaded in this way are globally available.
- */
- PFont.preloading = {
- // template element used to compare font sizes
- template: {},
- // indicates whether or not the reference tiny font has been loaded
- initialized: false,
- // load the reference tiny font via a css @font-face rule
- initialize: function() {
- var generateTinyFont = function() {
- var encoded = "#E3KAI2wAgT1MvMg7Eo3VmNtYX7ABi3CxnbHlm" +
- "7Abw3kaGVhZ7ACs3OGhoZWE7A53CRobXR47AY3" +
- "AGbG9jYQ7G03Bm1heH7ABC3CBuYW1l7Ae3AgcG" +
- "9zd7AI3AE#B3AQ2kgTY18PPPUACwAg3ALSRoo3" +
- "#yld0xg32QAB77#E777773B#E3C#I#Q77773E#" +
- "Q7777777772CMAIw7AB77732B#M#Q3wAB#g3B#" +
- "E#E2BB//82BB////w#B7#gAEg3E77x2B32B#E#" +
- "Q#MTcBAQ32gAe#M#QQJ#E32M#QQJ#I#g32Q77#";
- var expand = function(input) {
- return "AAAAAAAA".substr(~~input ? 7-input : 6);
- };
- return encoded.replace(/[#237]/g, expand);
- };
- var fontface = document.createElement("style");
- fontface.setAttribute("type","text/css");
- fontface.innerHTML = "@font-face {\n" +
- ' font-family: "PjsEmptyFont";' + "\n" +
- " src: url('data:application/x-font-ttf;base64,"+generateTinyFont()+"')\n" +
- " format('truetype');\n" +
- "}";
- document.head.appendChild(fontface);
-
- // set up the template element
- var element = document.createElement("span");
- element.style.cssText = 'position: absolute; top: -1000; left: 0; opacity: 0; font-family: "PjsEmptyFont", fantasy;';
- element.innerHTML = "AAAAAAAA";
- document.body.appendChild(element);
- this.template = element;
-
- this.initialized = true;
- },
- // Shorthand function to get the computed width for an element.
- getElementWidth: function(element) {
- return document.defaultView.getComputedStyle(element,"").getPropertyValue("width");
- },
- // time taken so far in attempting to load a font
- timeAttempted: 0,
- // returns false if no fonts are pending load, or true otherwise.
- pending: function(intervallength) {
- if (!this.initialized) {
- this.initialize();
- }
- var element,
- computedWidthFont,
- computedWidthRef = this.getElementWidth(this.template);
- for (var i = 0; i < this.fontList.length; i++) {
- // compares size of text in pixels. if equal, custom font is not yet loaded
- element = this.fontList[i];
- computedWidthFont = this.getElementWidth(element);
- if (this.timeAttempted < 4000 && computedWidthFont === computedWidthRef) {
- this.timeAttempted += intervallength;
- return true;
- } else {
- document.body.removeChild(element);
- this.fontList.splice(i--, 1);
- this.timeAttempted = 0;
- }
- }
- // if there are no more fonts to load, pending is false
- if (this.fontList.length === 0) {
- return false;
- }
- // We should have already returned before getting here.
- // But, if we do get here, length!=0 so fonts are pending.
- return true;
- },
- // fontList contains elements to compare font sizes against a template
- fontList: [],
- // addedList contains the fontnames of all the fonts loaded via @font-face
- addedList: {},
- // adds a font to the font cache
- // creates an element using the font, to start loading the font,
- // and compare against a default font to see if the custom font is loaded
- add: function(fontSrc) {
- if (!this.initialized) {
- this.initialize();
- }
- // fontSrc can be a string or a javascript object
- // acceptable fonts are .ttf, .otf, and data uri
- var fontName = (typeof fontSrc === 'object' ? fontSrc.fontFace : fontSrc),
- fontUrl = (typeof fontSrc === 'object' ? fontSrc.url : fontSrc);
-
- // check whether we already created the @font-face rule for this font
- if (this.addedList[fontName]) {
- return;
- }
-
- // if we didn't, create the @font-face rule
- var style = document.createElement("style");
- style.setAttribute("type","text/css");
- style.innerHTML = "@font-face{\n font-family: '" + fontName + "';\n src: url('" + fontUrl + "');\n}\n";
- document.head.appendChild(style);
- this.addedList[fontName] = true;
-
- // also create the element to load and compare the new font
- var element = document.createElement("span");
- element.style.cssText = "position: absolute; top: 0; left: 0; opacity: 0;";
- element.style.fontFamily = '"' + fontName + '", "PjsEmptyFont", fantasy';
- element.innerHTML = "AAAAAAAA";
- document.body.appendChild(element);
- this.fontList.push(element);
- }
- };
-
- return PFont;
- };
- },{}],14:[function(require,module,exports){
- module.exports = function(options, undef) {
-
- // FIXME: hack
- var p = options.p;
-
- /**
- * PMatrix2D is a 3x2 affine matrix implementation. The constructor accepts another PMatrix2D or a list of six float elements.
- * If no parameters are provided the matrix is set to the identity matrix.
- *
- * @param {PMatrix2D} matrix the initial matrix to set to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fifth element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- var PMatrix2D = function() {
- if (arguments.length === 0) {
- this.reset();
- } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- this.set(arguments[0].array());
- } else if (arguments.length === 6) {
- this.set(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
- }
- };
-
- /**
- * PMatrix2D methods
- */
- PMatrix2D.prototype = {
- /**
- * @member PMatrix2D
- * The set() function sets the matrix elements. The function accepts either another PMatrix2D, an array of elements, or a list of six floats.
- *
- * @param {PMatrix2D} matrix the matrix to set this matrix to
- * @param {float[]} elements an array of elements to set this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fith element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- set: function() {
- if (arguments.length === 6) {
- var a = arguments;
- this.set([a[0], a[1], a[2],
- a[3], a[4], a[5]]);
- } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- this.elements = arguments[0].array();
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- this.elements = arguments[0].slice();
- }
- },
- /**
- * @member PMatrix2D
- * The get() function returns a copy of this PMatrix2D.
- *
- * @return {PMatrix2D} a copy of this PMatrix2D
- */
- get: function() {
- var outgoing = new PMatrix2D();
- outgoing.set(this.elements);
- return outgoing;
- },
- /**
- * @member PMatrix2D
- * The reset() function sets this PMatrix2D to the identity matrix.
- */
- reset: function() {
- this.set([1, 0, 0, 0, 1, 0]);
- },
- /**
- * @member PMatrix2D
- * The array() function returns a copy of the element values.
- * @addon
- *
- * @return {float[]} returns a copy of the element values
- */
- array: function array() {
- return this.elements.slice();
- },
- /**
- * @member PMatrix2D
- * The translate() function translates this matrix by moving the current coordinates to the location specified by tx and ty.
- *
- * @param {float} tx the x-axis coordinate to move to
- * @param {float} ty the y-axis coordinate to move to
- */
- translate: function(tx, ty) {
- this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this.elements[2];
- this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this.elements[5];
- },
- /**
- * @member PMatrix2D
- * The invTranslate() function translates this matrix by moving the current coordinates to the negative location specified by tx and ty.
- *
- * @param {float} tx the x-axis coordinate to move to
- * @param {float} ty the y-axis coordinate to move to
- */
- invTranslate: function(tx, ty) {
- this.translate(-tx, -ty);
- },
- /**
- * @member PMatrix2D
- * The transpose() function is not used in processingjs.
- */
- transpose: function() {
- // Does nothing in Processing.
- },
- /**
- * @member PMatrix2D
- * The mult() function multiplied this matrix.
- * If two array elements are passed in the function will multiply a two element vector against this matrix.
- * If target is null or not length four, a new float array will be returned.
- * The values for vec and target can be the same (though that's less efficient).
- * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix.
- *
- * @param {PVector} source, target the PVectors used to multiply this matrix
- * @param {float[]} source, target the arrays used to multiply this matrix
- *
- * @return {PVector|float[]} returns a PVector or an array representing the new matrix
- */
- mult: function(source, target) {
- var x, y;
- if (source instanceof PVector) {
- x = source.x;
- y = source.y;
- if (!target) {
- target = new PVector();
- }
- } else if (source instanceof Array) {
- x = source[0];
- y = source[1];
- if (!target) {
- target = [];
- }
- }
- if (target instanceof Array) {
- target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2];
- target[1] = this.elements[3] * x + this.elements[4] * y + this.elements[5];
- } else if (target instanceof PVector) {
- target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2];
- target.y = this.elements[3] * x + this.elements[4] * y + this.elements[5];
- target.z = 0;
- }
- return target;
- },
- /**
- * @member PMatrix2D
- * The multX() function calculates the x component of a vector from a transformation.
- *
- * @param {float} x the x component of the vector being transformed
- * @param {float} y the y component of the vector being transformed
- *
- * @return {float} returnes the result of the calculation
- */
- multX: function(x, y) {
- return (x * this.elements[0] + y * this.elements[1] + this.elements[2]);
- },
- /**
- * @member PMatrix2D
- * The multY() function calculates the y component of a vector from a transformation.
- *
- * @param {float} x the x component of the vector being transformed
- * @param {float} y the y component of the vector being transformed
- *
- * @return {float} returnes the result of the calculation
- */
- multY: function(x, y) {
- return (x * this.elements[3] + y * this.elements[4] + this.elements[5]);
- },
- /**
- * @member PMatrix2D
- * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewX: function(angle) {
- this.apply(1, 0, 1, angle, 0, 0);
- },
- /**
- * @member PMatrix2D
- * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewY: function(angle) {
- this.apply(1, 0, 1, 0, angle, 0);
- },
- /**
- * @member PMatrix2D
- * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- shearX: function(angle) {
- this.apply(1, 0, 1, Math.tan(angle) , 0, 0);
- },
- /**
- * @member PMatrix2D
- * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- shearY: function(angle) {
- this.apply(1, 0, 1, 0, Math.tan(angle), 0);
- },
- /**
- * @member PMatrix2D
- * The determinant() function calvculates the determinant of this matrix.
- *
- * @return {float} the determinant of the matrix
- */
- determinant: function() {
- return (this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3]);
- },
- /**
- * @member PMatrix2D
- * The invert() function inverts this matrix
- *
- * @return {boolean} true if successful
- */
- invert: function() {
- var d = this.determinant();
- if (Math.abs( d ) > PConstants.MIN_INT) {
- var old00 = this.elements[0];
- var old01 = this.elements[1];
- var old02 = this.elements[2];
- var old10 = this.elements[3];
- var old11 = this.elements[4];
- var old12 = this.elements[5];
- this.elements[0] = old11 / d;
- this.elements[3] = -old10 / d;
- this.elements[1] = -old01 / d;
- this.elements[4] = old00 / d;
- this.elements[2] = (old01 * old12 - old11 * old02) / d;
- this.elements[5] = (old10 * old02 - old00 * old12) / d;
- return true;
- }
- return false;
- },
- /**
- * @member PMatrix2D
- * The scale() function increases or decreases the size of a shape by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions.
- * This is equivalent to a two parameter call.
- *
- * @param {float} sx the amount to scale on the x-axis
- * @param {float} sy the amount to scale on the y-axis
- */
- scale: function(sx, sy) {
- if (sx && !sy) {
- sy = sx;
- }
- if (sx && sy) {
- this.elements[0] *= sx;
- this.elements[1] *= sy;
- this.elements[3] *= sx;
- this.elements[4] *= sy;
- }
- },
- /**
- * @member PMatrix2D
- * The invScale() function decreases or increases the size of a shape by contracting and expanding vertices. When only one parameter is specified scale will occur in all dimensions.
- * This is equivalent to a two parameter call.
- *
- * @param {float} sx the amount to scale on the x-axis
- * @param {float} sy the amount to scale on the y-axis
- */
- invScale: function(sx, sy) {
- if (sx && !sy) {
- sy = sx;
- }
- this.scale(1 / sx, 1 / sy);
- },
- /**
- * @member PMatrix2D
- * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix2D or a list of floats can be passed in.
- *
- * @param {PMatrix2D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fith element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- apply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- source = arguments[0].array();
- } else if (arguments.length === 6) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
-
- var result = [0, 0, this.elements[2],
- 0, 0, this.elements[5]];
- var e = 0;
- for (var row = 0; row < 2; row++) {
- for (var col = 0; col < 3; col++, e++) {
- result[e] += this.elements[row * 3 + 0] * source[col + 0] +
- this.elements[row * 3 + 1] * source[col + 3];
- }
- }
- this.elements = result.slice();
- },
- /**
- * @member PMatrix2D
- * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix2D or elements of a matrix can be passed in.
- *
- * @param {PMatrix2D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fith element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- preApply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- source = arguments[0].array();
- } else if (arguments.length === 6) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
- var result = [0, 0, source[2],
- 0, 0, source[5]];
- result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1];
- result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4];
- result[0] = this.elements[0] * source[0] + this.elements[3] * source[1];
- result[3] = this.elements[0] * source[3] + this.elements[3] * source[4];
- result[1] = this.elements[1] * source[0] + this.elements[4] * source[1];
- result[4] = this.elements[1] * source[3] + this.elements[4] * source[4];
- this.elements = result.slice();
- },
- /**
- * @member PMatrix2D
- * The rotate() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotate: function(angle) {
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- var temp1 = this.elements[0];
- var temp2 = this.elements[1];
- this.elements[0] = c * temp1 + s * temp2;
- this.elements[1] = -s * temp1 + c * temp2;
- temp1 = this.elements[3];
- temp2 = this.elements[4];
- this.elements[3] = c * temp1 + s * temp2;
- this.elements[4] = -s * temp1 + c * temp2;
- },
- /**
- * @member PMatrix2D
- * The rotateZ() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateZ: function(angle) {
- this.rotate(angle);
- },
- /**
- * @member PMatrix2D
- * The invRotateZ() function rotates the matrix in opposite direction.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- invRotateZ: function(angle) {
- this.rotateZ(angle - Math.PI);
- },
- /**
- * @member PMatrix2D
- * The print() function prints out the elements of this matrix
- */
- print: function() {
- var digits = printMatrixHelper(this.elements);
- var output = "" + p.nfs(this.elements[0], digits, 4) + " " +
- p.nfs(this.elements[1], digits, 4) + " " +
- p.nfs(this.elements[2], digits, 4) + "\n" +
- p.nfs(this.elements[3], digits, 4) + " " +
- p.nfs(this.elements[4], digits, 4) + " " +
- p.nfs(this.elements[5], digits, 4) + "\n\n";
- p.println(output);
- }
- };
-
- return PMatrix2D;
- };
-
- },{}],15:[function(require,module,exports){
- module.exports = function(options, undef) {
-
- // FIXME: hack
- var p = options.p;
-
- /**
- * PMatrix3D is a 4x4 matrix implementation. The constructor accepts another PMatrix3D or a list of six or sixteen float elements.
- * If no parameters are provided the matrix is set to the identity matrix.
- */
- var PMatrix3D = function() {
- // When a matrix is created, it is set to an identity matrix
- this.reset();
- };
-
- /**
- * PMatrix3D methods
- */
- PMatrix3D.prototype = {
- /**
- * @member PMatrix2D
- * The set() function sets the matrix elements. The function accepts either another PMatrix3D, an array of elements, or a list of six or sixteen floats.
- *
- * @param {PMatrix3D} matrix the initial matrix to set to
- * @param {float[]} elements an array of elements to set this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- */
- set: function() {
- if (arguments.length === 16) {
- this.elements = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) {
- this.elements = arguments[0].array();
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- this.elements = arguments[0].slice();
- }
- },
- /**
- * @member PMatrix3D
- * The get() function returns a copy of this PMatrix3D.
- *
- * @return {PMatrix3D} a copy of this PMatrix3D
- */
- get: function() {
- var outgoing = new PMatrix3D();
- outgoing.set(this.elements);
- return outgoing;
- },
- /**
- * @member PMatrix3D
- * The reset() function sets this PMatrix3D to the identity matrix.
- */
- reset: function() {
- this.elements = [1,0,0,0,
- 0,1,0,0,
- 0,0,1,0,
- 0,0,0,1];
- },
- /**
- * @member PMatrix3D
- * The array() function returns a copy of the element values.
- * @addon
- *
- * @return {float[]} returns a copy of the element values
- */
- array: function array() {
- return this.elements.slice();
- },
- /**
- * @member PMatrix3D
- * The translate() function translates this matrix by moving the current coordinates to the location specified by tx, ty, and tz.
- *
- * @param {float} tx the x-axis coordinate to move to
- * @param {float} ty the y-axis coordinate to move to
- * @param {float} tz the z-axis coordinate to move to
- */
- translate: function(tx, ty, tz) {
- if (tz === undef) {
- tz = 0;
- }
-
- this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2];
- this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6];
- this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10];
- this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + tz * this.elements[14];
- },
- /**
- * @member PMatrix3D
- * The transpose() function transpose this matrix.
- */
- transpose: function() {
- var temp = this.elements[4];
- this.elements[4] = this.elements[1];
- this.elements[1] = temp;
-
- temp = this.elements[8];
- this.elements[8] = this.elements[2];
- this.elements[2] = temp;
-
- temp = this.elements[6];
- this.elements[6] = this.elements[9];
- this.elements[9] = temp;
-
- temp = this.elements[3];
- this.elements[3] = this.elements[12];
- this.elements[12] = temp;
-
- temp = this.elements[7];
- this.elements[7] = this.elements[13];
- this.elements[13] = temp;
-
- temp = this.elements[11];
- this.elements[11] = this.elements[14];
- this.elements[14] = temp;
- },
- /**
- * @member PMatrix3D
- * The mult() function multiplied this matrix.
- * If two array elements are passed in the function will multiply a two element vector against this matrix.
- * If target is null or not length four, a new float array will be returned.
- * The values for vec and target can be the same (though that's less efficient).
- * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix.
- *
- * @param {PVector} source, target the PVectors used to multiply this matrix
- * @param {float[]} source, target the arrays used to multiply this matrix
- *
- * @return {PVector|float[]} returns a PVector or an array representing the new matrix
- */
- mult: function(source, target) {
- var x, y, z, w;
- if (source instanceof PVector) {
- x = source.x;
- y = source.y;
- z = source.z;
- w = 1;
- if (!target) {
- target = new PVector();
- }
- } else if (source instanceof Array) {
- x = source[0];
- y = source[1];
- z = source[2];
- w = source[3] || 1;
-
- if ( !target || (target.length !== 3 && target.length !== 4) ) {
- target = [0, 0, 0];
- }
- }
-
- if (target instanceof Array) {
- if (target.length === 3) {
- target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11];
- } else if (target.length === 4) {
- target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w;
- target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w;
- target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w;
- target[3] = this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w;
- }
- }
- if (target instanceof PVector) {
- target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- target.y = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- target.z = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11];
- }
- return target;
- },
- /**
- * @member PMatrix3D
- * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix3D or elements of a matrix can be passed in.
- *
- * @param {PMatrix3D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- */
- preApply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) {
- source = arguments[0].array();
- } else if (arguments.length === 16) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
-
- var result = [0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0];
- var e = 0;
- for (var row = 0; row < 4; row++) {
- for (var col = 0; col < 4; col++, e++) {
- result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] *
- source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] +
- this.elements[col + 12] * source[row * 4 + 3];
- }
- }
- this.elements = result.slice();
- },
- /**
- * @member PMatrix3D
- * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix3D or a list of floats can be passed in.
- *
- * @param {PMatrix3D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- */
- apply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) {
- source = arguments[0].array();
- } else if (arguments.length === 16) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
-
- var result = [0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0];
- var e = 0;
- for (var row = 0; row < 4; row++) {
- for (var col = 0; col < 4; col++, e++) {
- result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] *
- source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] +
- this.elements[row * 4 + 3] * source[col + 12];
- }
- }
- this.elements = result.slice();
- },
- /**
- * @member PMatrix3D
- * The rotate() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotate: function(angle, v0, v1, v2) {
- if (!v1) {
- this.rotateZ(angle);
- } else {
- // TODO should make sure this vector is normalized
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- var t = 1.0 - c;
-
- this.apply((t * v0 * v0) + c,
- (t * v0 * v1) - (s * v2),
- (t * v0 * v2) + (s * v1),
- 0,
- (t * v0 * v1) + (s * v2),
- (t * v1 * v1) + c,
- (t * v1 * v2) - (s * v0),
- 0,
- (t * v0 * v2) - (s * v1),
- (t * v1 * v2) + (s * v0),
- (t * v2 * v2) + c,
- 0,
- 0, 0, 0, 1);
- }
- },
- /**
- * @member PMatrix3D
- * The invApply() function applies the inverted matrix to this matrix.
- *
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- *
- * @return {boolean} returns true if the operation was successful.
- */
- invApply: function() {
- if (inverseCopy === undef) {
- inverseCopy = new PMatrix3D();
- }
- var a = arguments;
- inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
- a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
-
- if (!inverseCopy.invert()) {
- return false;
- }
- this.preApply(inverseCopy);
- return true;
- },
- /**
- * @member PMatrix3D
- * The rotateZ() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateX: function(angle) {
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]);
- },
- /**
- * @member PMatrix3D
- * The rotateY() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateY: function(angle) {
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- this.apply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]);
- },
- /**
- * @member PMatrix3D
- * The rotateZ() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateZ: function(angle) {
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
- },
- /**
- * @member PMatrix3D
- * The scale() function increases or decreases the size of a matrix by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions.
- * This is equivalent to a three parameter call.
- *
- * @param {float} sx the amount to scale on the x-axis
- * @param {float} sy the amount to scale on the y-axis
- * @param {float} sz the amount to scale on the z-axis
- */
- scale: function(sx, sy, sz) {
- if (sx && !sy && !sz) {
- sy = sz = sx;
- } else if (sx && sy && !sz) {
- sz = 1;
- }
-
- if (sx && sy && sz) {
- this.elements[0] *= sx;
- this.elements[1] *= sy;
- this.elements[2] *= sz;
- this.elements[4] *= sx;
- this.elements[5] *= sy;
- this.elements[6] *= sz;
- this.elements[8] *= sx;
- this.elements[9] *= sy;
- this.elements[10] *= sz;
- this.elements[12] *= sx;
- this.elements[13] *= sy;
- this.elements[14] *= sz;
- }
- },
- /**
- * @member PMatrix3D
- * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewX: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- /**
- * @member PMatrix3D
- * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewY: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- /**
- * @member PMatrix3D
- * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of shear specified in radians
- */
- shearX: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- /**
- * @member PMatrix3D
- * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of shear specified in radians
- */
- shearY: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- multX: function(x, y, z, w) {
- if (!z) {
- return this.elements[0] * x + this.elements[1] * y + this.elements[3];
- }
- if (!w) {
- return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- }
- return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w;
- },
- multY: function(x, y, z, w) {
- if (!z) {
- return this.elements[4] * x + this.elements[5] * y + this.elements[7];
- }
- if (!w) {
- return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- }
- return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w;
- },
- multZ: function(x, y, z, w) {
- if (!w) {
- return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11];
- }
- return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w;
- },
- multW: function(x, y, z, w) {
- if (!w) {
- return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15];
- }
- return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w;
- },
- /**
- * @member PMatrix3D
- * The invert() function inverts this matrix
- *
- * @return {boolean} true if successful
- */
- invert: function() {
- var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this.elements[4];
- var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this.elements[4];
- var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this.elements[4];
- var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this.elements[5];
- var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this.elements[5];
- var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this.elements[6];
- var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this.elements[12];
- var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * this.elements[12];
- var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * this.elements[12];
- var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * this.elements[13];
- var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * this.elements[13];
- var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * this.elements[14];
-
- // Determinant
- var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0;
-
- // Account for a very small value
- // return false if not successful.
- if (Math.abs(fDet) <= 1e-9) {
- return false;
- }
-
- var kInv = [];
- kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elements[7] * fB3;
- kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elements[7] * fB1;
- kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elements[7] * fB0;
- kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.elements[6] * fB0;
- kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elements[3] * fB3;
- kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elements[3] * fB1;
- kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elements[3] * fB0;
- kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.elements[2] * fB0;
- kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elements[15] * fA3;
- kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elements[15] * fA1;
- kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.elements[15] * fA0;
- kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.elements[14] * fA0;
- kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.elements[11] * fA3;
- kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.elements[11] * fA1;
- kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.elements[11] * fA0;
- kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.elements[10] * fA0;
-
- // Inverse using Determinant
- var fInvDet = 1.0 / fDet;
- kInv[0] *= fInvDet;
- kInv[1] *= fInvDet;
- kInv[2] *= fInvDet;
- kInv[3] *= fInvDet;
- kInv[4] *= fInvDet;
- kInv[5] *= fInvDet;
- kInv[6] *= fInvDet;
- kInv[7] *= fInvDet;
- kInv[8] *= fInvDet;
- kInv[9] *= fInvDet;
- kInv[10] *= fInvDet;
- kInv[11] *= fInvDet;
- kInv[12] *= fInvDet;
- kInv[13] *= fInvDet;
- kInv[14] *= fInvDet;
- kInv[15] *= fInvDet;
-
- this.elements = kInv.slice();
- return true;
- },
- toString: function() {
- var str = "";
- for (var i = 0; i < 15; i++) {
- str += this.elements[i] + ", ";
- }
- str += this.elements[15];
- return str;
- },
- /**
- * @member PMatrix3D
- * The print() function prints out the elements of this matrix
- */
- print: function() {
- var digits = printMatrixHelper(this.elements);
-
- var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) +
- " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs(this.elements[3], digits, 4) +
- "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) +
- " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) +
- "\n" + p.nfs(this.elements[8], digits, 4) + " " + p.nfs(this.elements[9], digits, 4) +
- " " + p.nfs(this.elements[10], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) +
- "\n" + p.nfs(this.elements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) +
- " " + p.nfs(this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n\n";
- p.println(output);
- },
- invTranslate: function(tx, ty, tz) {
- this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1);
- },
- invRotateX: function(angle) {
- var c = Math.cos(-angle);
- var s = Math.sin(-angle);
- this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]);
- },
- invRotateY: function(angle) {
- var c = Math.cos(-angle);
- var s = Math.sin(-angle);
- this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]);
- },
- invRotateZ: function(angle) {
- var c = Math.cos(-angle);
- var s = Math.sin(-angle);
- this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
- },
- invScale: function(x, y, z) {
- this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]);
- }
- };
-
- return PMatrix3D;
- };
- },{}],16:[function(require,module,exports){
- module.exports = function(options) {
- var PConstants = options.PConstants,
- PMatrix2D = options.PMatrix2D,
- PMatrix3D = options.PMatrix3D;
-
- /**
- * Datatype for storing shapes. Processing can currently load and display SVG (Scalable Vector Graphics) shapes.
- * Before a shape is used, it must be loaded with the <b>loadShape()</b> function. The <b>shape()</b> function is used to draw the shape to the display window.
- * The <b>PShape</b> object contain a group of methods, linked below, that can operate on the shape data.
- * <br><br>The <b>loadShape()</b> method supports SVG files created with Inkscape and Adobe Illustrator.
- * It is not a full SVG implementation, but offers some straightforward support for handling vector data.
- *
- * @param {int} family the shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY
- *
- * @see #shape()
- * @see #loadShape()
- * @see #shapeMode()
- */
- var PShape = function(family) {
- this.family = family || PConstants.GROUP;
- this.visible = true;
- this.style = true;
- this.children = [];
- this.nameTable = [];
- this.params = [];
- this.name = "";
- this.image = null; //type PImage
- this.matrix = null;
- this.kind = null;
- this.close = null;
- this.width = null;
- this.height = null;
- this.parent = null;
- };
- /**
- * PShape methods
- * missing: findChild(), apply(), contains(), findChild(), getPrimitive(), getParams(), getVertex() , getVertexCount(),
- * getVertexCode() , getVertexCodes() , getVertexCodeCount(), getVertexX(), getVertexY(), getVertexZ()
- */
- PShape.prototype = {
- /**
- * @member PShape
- * The isVisible() function returns a boolean value "true" if the image is set to be visible, "false" if not. This is modified with the <b>setVisible()</b> parameter.
- * <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file.
- * For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator.
- *
- * @return {boolean} returns "true" if the image is set to be visible, "false" if not
- */
- isVisible: function(){
- return this.visible;
- },
- /**
- * @member PShape
- * The setVisible() function sets the shape to be visible or invisible. This is determined by the value of the <b>visible</b> parameter.
- * <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file.
- * For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator.
- *
- * @param {boolean} visible "false" makes the shape invisible and "true" makes it visible
- */
- setVisible: function (visible){
- this.visible = visible;
- },
- /**
- * @member PShape
- * The disableStyle() function disables the shape's style data and uses Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints.
- * Overrides this shape's style information and uses PGraphics styles and colors. Identical to ignoreStyles(true). Also disables styles for all child shapes.
- */
- disableStyle: function(){
- this.style = false;
- for(var i = 0, j=this.children.length; i<j; i++) {
- this.children[i].disableStyle();
- }
- },
- /**
- * @member PShape
- * The enableStyle() function enables the shape's style data and ignores Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints.
- */
- enableStyle: function(){
- this.style = true;
- for(var i = 0, j=this.children.length; i<j; i++) {
- this.children[i].enableStyle();
- }
- },
- /**
- * @member PShape
- * The getFamily function returns the shape type
- *
- * @return {int} the shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY
- */
- getFamily: function(){
- return this.family;
- },
- /**
- * @member PShape
- * The getWidth() function gets the width of the drawing area (not necessarily the shape boundary).
- */
- getWidth: function(){
- return this.width;
- },
- /**
- * @member PShape
- * The getHeight() function gets the height of the drawing area (not necessarily the shape boundary).
- */
- getHeight: function(){
- return this.height;
- },
- /**
- * @member PShape
- * The setName() function sets the name of the shape
- *
- * @param {String} name the name of the shape
- */
- setName: function(name){
- this.name = name;
- },
- /**
- * @member PShape
- * The getName() function returns the name of the shape
- *
- * @return {String} the name of the shape
- */
- getName: function(){
- return this.name;
- },
- /**
- * @member PShape
- * Called by the following (the shape() command adds the g)
- * PShape s = loadShapes("blah.svg");
- * shape(s);
- */
- draw: function(renderContext) {
- if(!renderContext) {
- throw "render context missing for draw() in PShape";
- }
- if (this.visible) {
- this.pre(renderContext);
- this.drawImpl(renderContext);
- this.post(renderContext);
- }
- },
- /**
- * @member PShape
- * the drawImpl() function draws the SVG document.
- */
- drawImpl: function(renderContext) {
- if (this.family === PConstants.GROUP) {
- this.drawGroup(renderContext);
- } else if (this.family === PConstants.PRIMITIVE) {
- this.drawPrimitive(renderContext);
- } else if (this.family === PConstants.GEOMETRY) {
- this.drawGeometry(renderContext);
- } else if (this.family === PConstants.PATH) {
- this.drawPath(renderContext);
- }
- },
- /**
- * @member PShape
- * The drawPath() function draws the <path> part of the SVG document.
- */
- drawPath: function(renderContext) {
- var i, j;
- if (this.vertices.length === 0) { return; }
- renderContext.beginShape();
- if (this.vertexCodes.length === 0) { // each point is a simple vertex
- if (this.vertices[0].length === 2) { // drawing 2D vertices
- for (i = 0, j = this.vertices.length; i < j; i++) {
- renderContext.vertex(this.vertices[i][0], this.vertices[i][1]);
- }
- } else { // drawing 3D vertices
- for (i = 0, j = this.vertices.length; i < j; i++) {
- renderContext.vertex(this.vertices[i][0],
- this.vertices[i][1],
- this.vertices[i][2]);
- }
- }
- } else { // coded set of vertices
- var index = 0;
- if (this.vertices[0].length === 2) { // drawing a 2D path
- for (i = 0, j = this.vertexCodes.length; i < j; i++) {
- if (this.vertexCodes[i] === PConstants.VERTEX) {
- renderContext.vertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index].moveTo);
- renderContext.breakShape = false;
- index++;
- } else if (this.vertexCodes[i] === PConstants.BEZIER_VERTEX) {
- renderContext.bezierVertex(this.vertices[index+0][0],
- this.vertices[index+0][1],
- this.vertices[index+1][0],
- this.vertices[index+1][1],
- this.vertices[index+2][0],
- this.vertices[index+2][1]);
- index += 3;
- } else if (this.vertexCodes[i] === PConstants.CURVE_VERTEX) {
- renderContext.curveVertex(this.vertices[index][0],
- this.vertices[index][1]);
- index++;
- } else if (this.vertexCodes[i] === PConstants.BREAK) {
- renderContext.breakShape = true;
- }
- }
- } else { // drawing a 3D path
- for (i = 0, j = this.vertexCodes.length; i < j; i++) {
- if (this.vertexCodes[i] === PConstants.VERTEX) {
- renderContext.vertex(this.vertices[index][0],
- this.vertices[index][1],
- this.vertices[index][2]);
- if (this.vertices[index].moveTo === true) {
- vertArray[vertArray.length-1].moveTo = true;
- } else if (this.vertices[index].moveTo === false) {
- vertArray[vertArray.length-1].moveTo = false;
- }
- renderContext.breakShape = false;
- } else if (this.vertexCodes[i] === PConstants.BEZIER_VERTEX) {
- renderContext.bezierVertex(this.vertices[index+0][0],
- this.vertices[index+0][1],
- this.vertices[index+0][2],
- this.vertices[index+1][0],
- this.vertices[index+1][1],
- this.vertices[index+1][2],
- this.vertices[index+2][0],
- this.vertices[index+2][1],
- this.vertices[index+2][2]);
- index += 3;
- } else if (this.vertexCodes[i] === PConstants.CURVE_VERTEX) {
- renderContext.curveVertex(this.vertices[index][0],
- this.vertices[index][1],
- this.vertices[index][2]);
- index++;
- } else if (this.vertexCodes[i] === PConstants.BREAK) {
- renderContext.breakShape = true;
- }
- }
- }
- }
- renderContext.endShape(this.close ? PConstants.CLOSE : PConstants.OPEN);
- },
- /**
- * @member PShape
- * The drawGeometry() function draws the geometry part of the SVG document.
- */
- drawGeometry: function(renderContext) {
- var i, j;
- renderContext.beginShape(this.kind);
- if (this.style) {
- for (i = 0, j = this.vertices.length; i < j; i++) {
- renderContext.vertex(this.vertices[i]);
- }
- } else {
- for (i = 0, j = this.vertices.length; i < j; i++) {
- var vert = this.vertices[i];
- if (vert[2] === 0) {
- renderContext.vertex(vert[0], vert[1]);
- } else {
- renderContext.vertex(vert[0], vert[1], vert[2]);
- }
- }
- }
- renderContext.endShape();
- },
- /**
- * @member PShape
- * The drawGroup() function draws the <g> part of the SVG document.
- */
- drawGroup: function(renderContext) {
- for (var i = 0, j = this.children.length; i < j; i++) {
- this.children[i].draw(renderContext);
- }
- },
- /**
- * @member PShape
- * The drawPrimitive() function draws SVG document shape elements. These can be point, line, triangle, quad, rect, ellipse, arc, box, or sphere.
- */
- drawPrimitive: function(renderContext) {
- if (this.kind === PConstants.POINT) {
- renderContext.point(this.params[0], this.params[1]);
- } else if (this.kind === PConstants.LINE) {
- if (this.params.length === 4) { // 2D
- renderContext.line(this.params[0], this.params[1],
- this.params[2], this.params[3]);
- } else { // 3D
- renderContext.line(this.params[0], this.params[1], this.params[2],
- this.params[3], this.params[4], this.params[5]);
- }
- } else if (this.kind === PConstants.TRIANGLE) {
- renderContext.triangle(this.params[0], this.params[1],
- this.params[2], this.params[3],
- this.params[4], this.params[5]);
- } else if (this.kind === PConstants.QUAD) {
- renderContext.quad(this.params[0], this.params[1],
- this.params[2], this.params[3],
- this.params[4], this.params[5],
- this.params[6], this.params[7]);
- } else if (this.kind === PConstants.RECT) {
- if (this.image !== null) {
- var imMode = imageModeConvert;
- renderContext.imageMode(PConstants.CORNER);
- renderContext.image(this.image,
- this.params[0],
- this.params[1],
- this.params[2],
- this.params[3]);
- imageModeConvert = imMode;
- } else {
- var rcMode = renderContext.curRectMode;
- renderContext.rectMode(PConstants.CORNER);
- renderContext.rect(this.params[0],
- this.params[1],
- this.params[2],
- this.params[3]);
- renderContext.curRectMode = rcMode;
- }
- } else if (this.kind === PConstants.ELLIPSE) {
- var elMode = renderContext.curEllipseMode;
- renderContext.ellipseMode(PConstants.CORNER);
- renderContext.ellipse(this.params[0],
- this.params[1],
- this.params[2],
- this.params[3]);
- renderContext.curEllipseMode = elMode;
- } else if (this.kind === PConstants.ARC) {
- var eMode = curEllipseMode;
- renderContext.ellipseMode(PConstants.CORNER);
- renderContext.arc(this.params[0],
- this.params[1],
- this.params[2],
- this.params[3],
- this.params[4],
- this.params[5]);
- curEllipseMode = eMode;
- } else if (this.kind === PConstants.BOX) {
- if (this.params.length === 1) {
- renderContext.box(this.params[0]);
- } else {
- renderContext.box(this.params[0], this.params[1], this.params[2]);
- }
- } else if (this.kind === PConstants.SPHERE) {
- renderContext.sphere(this.params[0]);
- }
- },
- /**
- * @member PShape
- * The pre() function performs the preparations before the SVG is drawn. This includes doing transformations and storing previous styles.
- */
- pre: function(renderContext) {
- if (this.matrix) {
- renderContext.pushMatrix();
- renderContext.transform(this.matrix);
- }
- if (this.style) {
- renderContext.pushStyle();
- this.styles(renderContext);
- }
- },
- /**
- * @member PShape
- * The post() function performs the necessary actions after the SVG is drawn. This includes removing transformations and removing added styles.
- */
- post: function(renderContext) {
- if (this.matrix) {
- renderContext.popMatrix();
- }
- if (this.style) {
- renderContext.popStyle();
- }
- },
- /**
- * @member PShape
- * The styles() function changes the Processing's current styles
- */
- styles: function(renderContext) {
- if (this.stroke) {
- renderContext.stroke(this.strokeColor);
- renderContext.strokeWeight(this.strokeWeight);
- renderContext.strokeCap(this.strokeCap);
- renderContext.strokeJoin(this.strokeJoin);
- } else {
- renderContext.noStroke();
- }
-
- if (this.fill) {
- renderContext.fill(this.fillColor);
-
- } else {
- renderContext.noFill();
- }
- },
- /**
- * @member PShape
- * The getChild() function extracts a child shape from a parent shape. Specify the name of the shape with the <b>target</b> parameter or the
- * layer position of the shape to get with the <b>index</b> parameter.
- * The shape is returned as a <b>PShape</b> object, or <b>null</b> is returned if there is an error.
- *
- * @param {String} target the name of the shape to get
- * @param {int} index the layer position of the shape to get
- *
- * @return {PShape} returns a child element of a shape as a PShape object or null if there is an error
- */
- getChild: function(child) {
- var i, j;
- if (typeof child === 'number') {
- return this.children[child];
- }
- var found;
- if(child === "" || this.name === child){
- return this;
- }
- if(this.nameTable.length > 0) {
- for(i = 0, j = this.nameTable.length; i < j || found; i++) {
- if(this.nameTable[i].getName === child) {
- found = this.nameTable[i];
- break;
- }
- }
- if (found) { return found; }
- }
- for(i = 0, j = this.children.length; i < j; i++) {
- found = this.children[i].getChild(child);
- if(found) { return found; }
- }
- return null;
- },
- /**
- * @member PShape
- * The getChildCount() returns the number of children
- *
- * @return {int} returns a count of children
- */
- getChildCount: function () {
- return this.children.length;
- },
- /**
- * @member PShape
- * The addChild() adds a child to the PShape.
- *
- * @param {PShape} child the child to add
- */
- addChild: function( child ) {
- this.children.push(child);
- child.parent = this;
- if (child.getName() !== null) {
- this.addName(child.getName(), child);
- }
- },
- /**
- * @member PShape
- * The addName() functions adds a shape to the name lookup table.
- *
- * @param {String} name the name to be added
- * @param {PShape} shape the shape
- */
- addName: function(name, shape) {
- if (this.parent !== null) {
- this.parent.addName( name, shape );
- } else {
- this.nameTable.push( [name, shape] );
- }
- },
- /**
- * @member PShape
- * The translate() function specifies an amount to displace the shape. The <b>x</b> parameter specifies left/right translation, the <b>y</b> parameter specifies up/down translation, and the <b>z</b> parameter specifies translations toward/away from the screen.
- * Subsequent calls to the method accumulates the effect. For example, calling <b>translate(50, 0)</b> and then <b>translate(20, 0)</b> is the same as <b>translate(70, 0)</b>.
- * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
- * <br><br>Using this method with the <b>z</b> parameter requires using the P3D or OPENGL parameter in combination with size.
- *
- * @param {int|float} x left/right translation
- * @param {int|float} y up/down translation
- * @param {int|float} z forward/back translation
- *
- * @see PMatrix2D#translate
- * @see PMatrix3D#translate
- */
- translate: function() {
- if(arguments.length === 2)
- {
- this.checkMatrix(2);
- this.matrix.translate(arguments[0], arguments[1]);
- } else {
- this.checkMatrix(3);
- this.matrix.translate(arguments[0], arguments[1], 0);
- }
- },
- /**
- * @member PShape
- * The checkMatrix() function makes sure that the shape's matrix is 1) not null, and 2) has a matrix
- * that can handle <em>at least</em> the specified number of dimensions.
- *
- * @param {int} dimensions the specified number of dimensions
- */
- checkMatrix: function(dimensions) {
- if(this.matrix === null) {
- if(dimensions === 2) {
- this.matrix = new PMatrix2D();
- } else {
- this.matrix = new PMatrix3D();
- }
- }else if(dimensions === 3 && this.matrix instanceof PMatrix2D) {
- this.matrix = new PMatrix3D();
- }
- },
- /**
- * @member PShape
- * The rotateX() function rotates a shape around the x-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
- * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
- * Subsequent calls to the method accumulates the effect. For example, calling <b>rotateX(HALF_PI)</b> and then <b>rotateX(HALF_PI)</b> is the same as <b>rotateX(PI)</b>.
- * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
- * <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
- *
- * @param {float}angle angle of rotation specified in radians
- *
- * @see PMatrix3D#rotateX
- */
- rotateX: function(angle) {
- this.rotate(angle, 1, 0, 0);
- },
- /**
- * @member PShape
- * The rotateY() function rotates a shape around the y-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
- * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
- * Subsequent calls to the method accumulates the effect. For example, calling <b>rotateY(HALF_PI)</b> and then <b>rotateY(HALF_PI)</b> is the same as <b>rotateY(PI)</b>.
- * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
- * <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
- *
- * @param {float}angle angle of rotation specified in radians
- *
- * @see PMatrix3D#rotateY
- */
- rotateY: function(angle) {
- this.rotate(angle, 0, 1, 0);
- },
- /**
- * @member PShape
- * The rotateZ() function rotates a shape around the z-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
- * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
- * Subsequent calls to the method accumulates the effect. For example, calling <b>rotateZ(HALF_PI)</b> and then <b>rotateZ(HALF_PI)</b> is the same as <b>rotateZ(PI)</b>.
- * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
- * <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
- *
- * @param {float}angle angle of rotation specified in radians
- *
- * @see PMatrix3D#rotateZ
- */
- rotateZ: function(angle) {
- this.rotate(angle, 0, 0, 1);
- },
- /**
- * @member PShape
- * The rotate() function rotates a shape the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
- * <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
- * Transformations apply to everything that happens after and subsequent calls to the method accumulates the effect.
- * For example, calling <b>rotate(HALF_PI)</b> and then <b>rotate(HALF_PI)</b> is the same as <b>rotate(PI)</b>.
- * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
- * If optional parameters x,y,z are supplied, the rotate is about the point (x, y, z).
- *
- * @param {float}angle angle of rotation specified in radians
- * @param {float}x x-coordinate of the point
- * @param {float}y y-coordinate of the point
- * @param {float}z z-coordinate of the point
- * @see PMatrix2D#rotate
- * @see PMatrix3D#rotate
- */
- rotate: function() {
- if(arguments.length === 1){
- this.checkMatrix(2);
- this.matrix.rotate(arguments[0]);
- } else {
- this.checkMatrix(3);
- this.matrix.rotate(arguments[0],
- arguments[1],
- arguments[2],
- arguments[3]);
- }
- },
- /**
- * @member PShape
- * The scale() function increases or decreases the size of a shape by expanding and contracting vertices. Shapes always scale from the relative origin of their bounding box.
- * Scale values are specified as decimal percentages. For example, the method call <b>scale(2.0)</b> increases the dimension of a shape by 200%.
- * Subsequent calls to the method multiply the effect. For example, calling <b>scale(2.0)</b> and then <b>scale(1.5)</b> is the same as <b>scale(3.0)</b>.
- * This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
- * <br><br>Using this fuction with the <b>z</b> parameter requires passing P3D or OPENGL into the size() parameter.
- *
- * @param {float}s percentage to scale the object
- * @param {float}x percentage to scale the object in the x-axis
- * @param {float}y percentage to scale the object in the y-axis
- * @param {float}z percentage to scale the object in the z-axis
- *
- * @see PMatrix2D#scale
- * @see PMatrix3D#scale
- */
- scale: function() {
- if(arguments.length === 2) {
- this.checkMatrix(2);
- this.matrix.scale(arguments[0], arguments[1]);
- } else if (arguments.length === 3) {
- this.checkMatrix(2);
- this.matrix.scale(arguments[0], arguments[1], arguments[2]);
- } else {
- this.checkMatrix(2);
- this.matrix.scale(arguments[0]);
- }
- },
- /**
- * @member PShape
- * The resetMatrix() function resets the matrix
- *
- * @see PMatrix2D#reset
- * @see PMatrix3D#reset
- */
- resetMatrix: function() {
- this.checkMatrix(2);
- this.matrix.reset();
- },
- /**
- * @member PShape
- * The applyMatrix() function multiplies this matrix by another matrix of type PMatrix3D or PMatrix2D.
- * Individual elements can also be provided
- *
- * @param {PMatrix3D|PMatrix2D} matrix the matrix to multiply by
- *
- * @see PMatrix2D#apply
- * @see PMatrix3D#apply
- */
- applyMatrix: function(matrix) {
- if (arguments.length === 1) {
- this.applyMatrix(matrix.elements[0],
- matrix.elements[1], 0,
- matrix.elements[2],
- matrix.elements[3],
- matrix.elements[4], 0,
- matrix.elements[5],
- 0, 0, 1, 0,
- 0, 0, 0, 1);
- } else if (arguments.length === 6) {
- this.checkMatrix(2);
- this.matrix.apply(arguments[0], arguments[1], arguments[2], 0,
- arguments[3], arguments[4], arguments[5], 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1);
-
- } else if (arguments.length === 16) {
- this.checkMatrix(3);
- this.matrix.apply(arguments[0],
- arguments[1],
- arguments[2],
- arguments[3],
- arguments[4],
- arguments[5],
- arguments[6],
- arguments[7],
- arguments[8],
- arguments[9],
- arguments[10],
- arguments[11],
- arguments[12],
- arguments[13],
- arguments[14],
- arguments[15]);
- }
- }
- };
-
- return PShape;
- };
- },{}],17:[function(require,module,exports){
- /**
- * SVG stands for Scalable Vector Graphics, a portable graphics format. It is
- * a vector format so it allows for infinite resolution and relatively small
- * file sizes. Most modern media software can view SVG files, including Adobe
- * products, Firefox, etc. Illustrator and Inkscape can edit SVG files.
- *
- * @param {PApplet} parent typically use "this"
- * @param {String} filename name of the SVG file to load
- * @param {XMLElement} xml an XMLElement element
- * @param {PShapeSVG} parent the parent PShapeSVG
- *
- * @see PShape
- */
- module.exports = function(options) {
- var CommonFunctions = options.CommonFunctions,
- PConstants = options.PConstants,
- PShape = options.PShape,
- XMLElement = options.XMLElement,
- colors = options.colors;
-
- var PShapeSVG = function() {
- PShape.call(this); // PShape is the base class.
- if (arguments.length === 1) { // xml element coming in
- this.element = arguments[0];
-
- // set values to their defaults according to the SVG spec
- this.vertexCodes = [];
- this.vertices = [];
- this.opacity = 1;
-
- this.stroke = false;
- this.strokeColor = PConstants.ALPHA_MASK;
- this.strokeWeight = 1;
- this.strokeCap = PConstants.SQUARE; // BUTT in svg spec
- this.strokeJoin = PConstants.MITER;
- this.strokeGradient = null;
- this.strokeGradientPaint = null;
- this.strokeName = null;
- this.strokeOpacity = 1;
-
- this.fill = true;
- this.fillColor = PConstants.ALPHA_MASK;
- this.fillGradient = null;
- this.fillGradientPaint = null;
- this.fillName = null;
- this.fillOpacity = 1;
-
- if (this.element.getName() !== "svg") {
- throw("root is not <svg>, it's <" + this.element.getName() + ">");
- }
- }
- else if (arguments.length === 2) {
- if (typeof arguments[1] === 'string') {
- if (arguments[1].indexOf(".svg") > -1) { //its a filename
- this.element = new XMLElement(true, arguments[1]);
- // set values to their defaults according to the SVG spec
- this.vertexCodes = [];
- this.vertices = [];
- this.opacity = 1;
-
- this.stroke = false;
- this.strokeColor = PConstants.ALPHA_MASK;
- this.strokeWeight = 1;
- this.strokeCap = PConstants.SQUARE; // BUTT in svg spec
- this.strokeJoin = PConstants.MITER;
- this.strokeGradient = "";
- this.strokeGradientPaint = "";
- this.strokeName = "";
- this.strokeOpacity = 1;
-
- this.fill = true;
- this.fillColor = PConstants.ALPHA_MASK;
- this.fillGradient = null;
- this.fillGradientPaint = null;
- this.fillOpacity = 1;
-
- }
- } else { // XMLElement
- if (arguments[0]) { // PShapeSVG
- this.element = arguments[1];
- this.vertexCodes = arguments[0].vertexCodes.slice();
- this.vertices = arguments[0].vertices.slice();
-
- this.stroke = arguments[0].stroke;
- this.strokeColor = arguments[0].strokeColor;
- this.strokeWeight = arguments[0].strokeWeight;
- this.strokeCap = arguments[0].strokeCap;
- this.strokeJoin = arguments[0].strokeJoin;
- this.strokeGradient = arguments[0].strokeGradient;
- this.strokeGradientPaint = arguments[0].strokeGradientPaint;
- this.strokeName = arguments[0].strokeName;
-
- this.fill = arguments[0].fill;
- this.fillColor = arguments[0].fillColor;
- this.fillGradient = arguments[0].fillGradient;
- this.fillGradientPaint = arguments[0].fillGradientPaint;
- this.fillName = arguments[0].fillName;
- this.strokeOpacity = arguments[0].strokeOpacity;
- this.fillOpacity = arguments[0].fillOpacity;
- this.opacity = arguments[0].opacity;
- }
- }
- }
-
- this.name = this.element.getStringAttribute("id");
- var displayStr = this.element.getStringAttribute("display", "inline");
- this.visible = displayStr !== "none";
- var str = this.element.getAttribute("transform");
- if (str) {
- this.matrix = this.parseMatrix(str);
- }
- // not proper parsing of the viewBox, but will cover us for cases where
- // the width and height of the object is not specified
- var viewBoxStr = this.element.getStringAttribute("viewBox");
- if ( viewBoxStr !== null ) {
- var viewBox = viewBoxStr.split(" ");
- this.width = viewBox[2];
- this.height = viewBox[3];
- }
-
- // TODO if viewbox is not same as width/height, then use it to scale
- // the original objects. for now, viewbox only used when width/height
- // are empty values (which by the spec means w/h of "100%"
- var unitWidth = this.element.getStringAttribute("width");
- var unitHeight = this.element.getStringAttribute("height");
- if (unitWidth !== null) {
- this.width = this.parseUnitSize(unitWidth);
- this.height = this.parseUnitSize(unitHeight);
- } else {
- if ((this.width === 0) || (this.height === 0)) {
- // For the spec, the default is 100% and 100%. For purposes
- // here, insert a dummy value because this is prolly just a
- // font or something for which the w/h doesn't matter.
- this.width = 1;
- this.height = 1;
-
- //show warning
- throw("The width and/or height is not " +
- "readable in the <svg> tag of this file.");
- }
- }
- this.parseColors(this.element);
- this.parseChildren(this.element);
-
- };
- /**
- * PShapeSVG methods are inherited from the PShape prototype
- */
- PShapeSVG.prototype = new PShape();
- /**
- * @member PShapeSVG
- * The parseMatrix() function parses the specified SVG matrix into a PMatrix2D. Note that PMatrix2D
- * is rotated relative to the SVG definition, so parameters are rearranged
- * here. More about the transformation matrices in
- * <a href="http://www.w3.org/TR/SVG/coords.html#TransformAttribute">this section</a>
- * of the SVG documentation.
- *
- * @param {String} str text of the matrix param.
- *
- * @return {PMatrix2D} a PMatrix2D
- */
- PShapeSVG.prototype.parseMatrix = (function() {
- function getCoords(s) {
- var m = [];
- s.replace(/\((.*?)\)/, (function() {
- return function(all, params) {
- // get the coordinates that can be separated by spaces or a comma
- m = params.replace(/,+/g, " ").split(/\s+/);
- };
- }()));
- return m;
- }
-
- return function(str) {
- this.checkMatrix(2);
- var pieces = [];
- str.replace(/\s*(\w+)\((.*?)\)/g, function(all) {
- // get a list of transform definitions
- pieces.push(CommonFunctions.trim(all));
- });
- if (pieces.length === 0) {
- return null;
- }
-
- for (var i = 0, j = pieces.length; i < j; i++) {
- var m = getCoords(pieces[i]);
-
- if (pieces[i].indexOf("matrix") !== -1) {
- this.matrix.set(m[0], m[2], m[4], m[1], m[3], m[5]);
- } else if (pieces[i].indexOf("translate") !== -1) {
- var tx = m[0];
- var ty = (m.length === 2) ? m[1] : 0;
- this.matrix.translate(tx,ty);
- } else if (pieces[i].indexOf("scale") !== -1) {
- var sx = m[0];
- var sy = (m.length === 2) ? m[1] : m[0];
- this.matrix.scale(sx,sy);
- } else if (pieces[i].indexOf("rotate") !== -1) {
- var angle = m[0];
- if (m.length === 1) {
- this.matrix.rotate(CommonFunctions.radians(angle));
- } else if (m.length === 3) {
- this.matrix.translate(m[1], m[2]);
- this.matrix.rotate(CommonFunctions.radians(m[0]));
- this.matrix.translate(-m[1], -m[2]);
- }
- } else if (pieces[i].indexOf("skewX") !== -1) {
- this.matrix.skewX(parseFloat(m[0]));
- } else if (pieces[i].indexOf("skewY") !== -1) {
- this.matrix.skewY(m[0]);
- } else if (pieces[i].indexOf("shearX") !== -1) {
- this.matrix.shearX(m[0]);
- } else if (pieces[i].indexOf("shearY") !== -1) {
- this.matrix.shearY(m[0]);
- }
- }
- return this.matrix;
- };
- }());
-
- /**
- * @member PShapeSVG
- * The parseChildren() function parses the specified XMLElement
- *
- * @param {XMLElement}element the XMLElement to parse
- */
- PShapeSVG.prototype.parseChildren = function(element) {
- var newelement = element.getChildren();
- var base = new PShape();
- var i, j;
- for (i = 0, j = newelement.length; i < j; i++) {
- var kid = this.parseChild(newelement[i]);
- if (kid) {
- base.addChild(kid);
- }
- }
- for (i = 0, j = base.children.length; i < j; i++) {
- this.children.push(base.children[i]);
- }
- };
- /**
- * @member PShapeSVG
- * The getName() function returns the name
- *
- * @return {String} the name
- */
- PShapeSVG.prototype.getName = function() {
- return this.name;
- };
- /**
- * @member PShapeSVG
- * The parseChild() function parses a child XML element.
- *
- * @param {XMLElement} elem the element to parse
- *
- * @return {PShape} the newly created PShape
- */
- PShapeSVG.prototype.parseChild = function( elem ) {
- var name = elem.getName();
- var shape;
- if (name === "g") {
- shape = new PShapeSVG(this, elem);
- } else if (name === "defs") {
- // generally this will contain gradient info, so may
- // as well just throw it into a group element for parsing
- shape = new PShapeSVG(this, elem);
- } else if (name === "line") {
- shape = new PShapeSVG(this, elem);
- shape.parseLine();
- } else if (name === "circle") {
- shape = new PShapeSVG(this, elem);
- shape.parseEllipse(true);
- } else if (name === "ellipse") {
- shape = new PShapeSVG(this, elem);
- shape.parseEllipse(false);
- } else if (name === "rect") {
- shape = new PShapeSVG(this, elem);
- shape.parseRect();
- } else if (name === "polygon") {
- shape = new PShapeSVG(this, elem);
- shape.parsePoly(true);
- } else if (name === "polyline") {
- shape = new PShapeSVG(this, elem);
- shape.parsePoly(false);
- } else if (name === "path") {
- shape = new PShapeSVG(this, elem);
- shape.parsePath();
- } else if (name === "radialGradient") {
- //return new RadialGradient(this, elem);
- unimplemented('PShapeSVG.prototype.parseChild, name = radialGradient');
- } else if (name === "linearGradient") {
- //return new LinearGradient(this, elem);
- unimplemented('PShapeSVG.prototype.parseChild, name = linearGradient');
- } else if (name === "text") {
- unimplemented('PShapeSVG.prototype.parseChild, name = text');
- } else if (name === "filter") {
- unimplemented('PShapeSVG.prototype.parseChild, name = filter');
- } else if (name === "mask") {
- unimplemented('PShapeSVG.prototype.parseChild, name = mask');
- } else {
- // ignoring
- }
- return shape;
- };
- /**
- * @member PShapeSVG
- * The parsePath() function parses the <path> element of the svg file
- * A path is defined by including a path element which contains a d="(path data)" attribute, where the d attribute contains
- * the moveto, line, curve (both cubic and quadratic Beziers), arc and closepath instructions.
- **/
- PShapeSVG.prototype.parsePath = function() {
- this.family = PConstants.PATH;
- this.kind = 0;
- var pathDataChars = [];
- var c;
- //change multiple spaces and commas to single space
- var pathData = CommonFunctions.trim(this.element.getStringAttribute("d").replace(/[\s,]+/g,' '));
- if (pathData === null) {
- return;
- }
- pathData = pathData.split('');
- var cx = 0,
- cy = 0,
- ctrlX = 0,
- ctrlY = 0,
- ctrlX1 = 0,
- ctrlX2 = 0,
- ctrlY1 = 0,
- ctrlY2 = 0,
- endX = 0,
- endY = 0,
- ppx = 0,
- ppy = 0,
- px = 0,
- py = 0,
- i = 0,
- valOf = 0;
- var str = "";
- var tmpArray = [];
- var flag = false;
- var lastInstruction;
- var command;
- var j, k;
- while (i< pathData.length) {
- valOf = pathData[i].charCodeAt(0);
- if ((valOf >= 65 && valOf <= 90) || (valOf >= 97 && valOf <= 122)) {
- // if it's a letter
- // populate the tmpArray with coordinates
- j = i;
- i++;
- if (i < pathData.length) { // don't go over boundary of array
- tmpArray = [];
- valOf = pathData[i].charCodeAt(0);
- while (!((valOf >= 65 && valOf <= 90) ||
- (valOf >= 97 && valOf <= 100) ||
- (valOf >= 102 && valOf <= 122)) && flag === false) { // if its NOT a letter
- if (valOf === 32) { //if its a space and the str isn't empty
- // sometimes you get a space after the letter
- if (str !== "") {
- tmpArray.push(parseFloat(str));
- str = "";
- }
- i++;
- } else if (valOf === 45) { //if it's a -
- // allow for 'e' notation in numbers, e.g. 2.10e-9
- if (pathData[i-1].charCodeAt(0) === 101) {
- str += pathData[i].toString();
- i++;
- } else {
- // sometimes no space separator after (ex: 104.535-16.322)
- if (str !== "") {
- tmpArray.push(parseFloat(str));
- }
- str = pathData[i].toString();
- i++;
- }
- } else {
- str += pathData[i].toString();
- i++;
- }
- if (i === pathData.length) { // don't go over boundary of array
- flag = true;
- } else {
- valOf = pathData[i].charCodeAt(0);
- }
- }
- }
- if (str !== "") {
- tmpArray.push(parseFloat(str));
- str = "";
- }
- command = pathData[j];
- valOf = command.charCodeAt(0);
- if (valOf === 77) { // M - move to (absolute)
- if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) {
- // need one+ pairs of co-ordinates
- cx = tmpArray[0];
- cy = tmpArray[1];
- this.parsePathMoveto(cx, cy);
- if (tmpArray.length > 2) {
- for (j = 2, k = tmpArray.length; j < k; j+=2) {
- // absolute line to
- cx = tmpArray[j];
- cy = tmpArray[j+1];
- this.parsePathLineto(cx,cy);
- }
- }
- }
- } else if (valOf === 109) { // m - move to (relative)
- if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) {
- // need one+ pairs of co-ordinates
- cx += tmpArray[0];
- cy += tmpArray[1];
- this.parsePathMoveto(cx,cy);
- if (tmpArray.length > 2) {
- for (j = 2, k = tmpArray.length; j < k; j+=2) {
- // relative line to
- cx += tmpArray[j];
- cy += tmpArray[j + 1];
- this.parsePathLineto(cx,cy);
- }
- }
- }
- } else if (valOf === 76) { // L - lineto (absolute)
- if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) {
- // need one+ pairs of co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=2) {
- cx = tmpArray[j];
- cy = tmpArray[j + 1];
- this.parsePathLineto(cx,cy);
- }
- }
- } else if (valOf === 108) { // l - lineto (relative)
- if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) {
- // need one+ pairs of co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=2) {
- cx += tmpArray[j];
- cy += tmpArray[j+1];
- this.parsePathLineto(cx,cy);
- }
- }
- } else if (valOf === 72) { // H - horizontal lineto (absolute)
- for (j = 0, k = tmpArray.length; j < k; j++) {
- // multiple x co-ordinates can be provided
- cx = tmpArray[j];
- this.parsePathLineto(cx, cy);
- }
- } else if (valOf === 104) { // h - horizontal lineto (relative)
- for (j = 0, k = tmpArray.length; j < k; j++) {
- // multiple x co-ordinates can be provided
- cx += tmpArray[j];
- this.parsePathLineto(cx, cy);
- }
- } else if (valOf === 86) { // V - vertical lineto (absolute)
- for (j = 0, k = tmpArray.length; j < k; j++) {
- // multiple y co-ordinates can be provided
- cy = tmpArray[j];
- this.parsePathLineto(cx, cy);
- }
- } else if (valOf === 118) { // v - vertical lineto (relative)
- for (j = 0, k = tmpArray.length; j < k; j++) {
- // multiple y co-ordinates can be provided
- cy += tmpArray[j];
- this.parsePathLineto(cx, cy);
- }
- } else if (valOf === 67) { // C - curve to (absolute)
- if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) {
- // need one+ multiples of 6 co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=6) {
- ctrlX1 = tmpArray[j];
- ctrlY1 = tmpArray[j + 1];
- ctrlX2 = tmpArray[j + 2];
- ctrlY2 = tmpArray[j + 3];
- endX = tmpArray[j + 4];
- endY = tmpArray[j + 5];
- this.parsePathCurveto(ctrlX1,
- ctrlY1,
- ctrlX2,
- ctrlY2,
- endX,
- endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 99) { // c - curve to (relative)
- if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) {
- // need one+ multiples of 6 co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=6) {
- ctrlX1 = cx + tmpArray[j];
- ctrlY1 = cy + tmpArray[j + 1];
- ctrlX2 = cx + tmpArray[j + 2];
- ctrlY2 = cy + tmpArray[j + 3];
- endX = cx + tmpArray[j + 4];
- endY = cy + tmpArray[j + 5];
- this.parsePathCurveto(ctrlX1,
- ctrlY1,
- ctrlX2,
- ctrlY2,
- endX,
- endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 83) { // S - curve to shorthand (absolute)
- if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) {
- // need one+ multiples of 4 co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=4) {
- if (lastInstruction.toLowerCase() === "c" ||
- lastInstruction.toLowerCase() === "s") {
- ppx = this.vertices[ this.vertices.length-2 ][0];
- ppy = this.vertices[ this.vertices.length-2 ][1];
- px = this.vertices[ this.vertices.length-1 ][0];
- py = this.vertices[ this.vertices.length-1 ][1];
- ctrlX1 = px + (px - ppx);
- ctrlY1 = py + (py - ppy);
- } else {
- //If there is no previous curve,
- //the current point will be used as the first control point.
- ctrlX1 = this.vertices[this.vertices.length-1][0];
- ctrlY1 = this.vertices[this.vertices.length-1][1];
- }
- ctrlX2 = tmpArray[j];
- ctrlY2 = tmpArray[j + 1];
- endX = tmpArray[j + 2];
- endY = tmpArray[j + 3];
- this.parsePathCurveto(ctrlX1,
- ctrlY1,
- ctrlX2,
- ctrlY2,
- endX,
- endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 115) { // s - curve to shorthand (relative)
- if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) {
- // need one+ multiples of 4 co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=4) {
- if (lastInstruction.toLowerCase() === "c" ||
- lastInstruction.toLowerCase() === "s") {
- ppx = this.vertices[this.vertices.length-2][0];
- ppy = this.vertices[this.vertices.length-2][1];
- px = this.vertices[this.vertices.length-1][0];
- py = this.vertices[this.vertices.length-1][1];
- ctrlX1 = px + (px - ppx);
- ctrlY1 = py + (py - ppy);
- } else {
- //If there is no previous curve,
- //the current point will be used as the first control point.
- ctrlX1 = this.vertices[this.vertices.length-1][0];
- ctrlY1 = this.vertices[this.vertices.length-1][1];
- }
- ctrlX2 = cx + tmpArray[j];
- ctrlY2 = cy + tmpArray[j + 1];
- endX = cx + tmpArray[j + 2];
- endY = cy + tmpArray[j + 3];
- this.parsePathCurveto(ctrlX1,
- ctrlY1,
- ctrlX2,
- ctrlY2,
- endX,
- endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 81) { // Q - quadratic curve to (absolute)
- if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) {
- // need one+ multiples of 4 co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=4) {
- ctrlX = tmpArray[j];
- ctrlY = tmpArray[j + 1];
- endX = tmpArray[j + 2];
- endY = tmpArray[j + 3];
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 113) { // q - quadratic curve to (relative)
- if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) {
- // need one+ multiples of 4 co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=4) {
- ctrlX = cx + tmpArray[j];
- ctrlY = cy + tmpArray[j + 1];
- endX = cx + tmpArray[j + 2];
- endY = cy + tmpArray[j + 3];
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 84) {
- // T - quadratic curve to shorthand (absolute)
- if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) {
- // need one+ pairs of co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=2) {
- if (lastInstruction.toLowerCase() === "q" ||
- lastInstruction.toLowerCase() === "t") {
- ppx = this.vertices[this.vertices.length-2][0];
- ppy = this.vertices[this.vertices.length-2][1];
- px = this.vertices[this.vertices.length-1][0];
- py = this.vertices[this.vertices.length-1][1];
- ctrlX = px + (px - ppx);
- ctrlY = py + (py - ppy);
- } else {
- // If there is no previous command or if the previous command
- // was not a Q, q, T or t, assume the control point is
- // coincident with the current point.
- ctrlX = cx;
- ctrlY = cy;
- }
- endX = tmpArray[j];
- endY = tmpArray[j + 1];
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 116) {
- // t - quadratic curve to shorthand (relative)
- if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) {
- // need one+ pairs of co-ordinates
- for (j = 0, k = tmpArray.length; j < k; j+=2) {
- if (lastInstruction.toLowerCase() === "q" ||
- lastInstruction.toLowerCase() === "t") {
- ppx = this.vertices[this.vertices.length-2][0];
- ppy = this.vertices[this.vertices.length-2][1];
- px = this.vertices[this.vertices.length-1][0];
- py = this.vertices[this.vertices.length-1][1];
- ctrlX = px + (px - ppx);
- ctrlY = py + (py - ppy);
- } else {
- // If there is no previous command or if the previous command
- // was not a Q, q, T or t, assume the control point is
- // coincident with the current point.
- ctrlX = cx;
- ctrlY = cy;
- }
- endX = cx + tmpArray[j];
- endY = cy + tmpArray[j + 1];
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- }
- }
- } else if (valOf === 90 || valOf === 122) { // Z or z (these do the same thing)
- this.close = true;
- }
- lastInstruction = command.toString();
- } else { i++;}
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parsePath() helper function
- *
- * @see PShapeSVG#parsePath
- */
- PShapeSVG.prototype.parsePathQuadto = function(x1, y1, cx, cy, x2, y2) {
- if (this.vertices.length > 0) {
- this.parsePathCode(PConstants.BEZIER_VERTEX);
- // x1/y1 already covered by last moveto, lineto, or curveto
- this.parsePathVertex(x1 + ((cx-x1)*2/3), y1 + ((cy-y1)*2/3));
- this.parsePathVertex(x2 + ((cx-x2)*2/3), y2 + ((cy-y2)*2/3));
- this.parsePathVertex(x2, y2);
- } else {
- throw ("Path must start with M/m");
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parsePath() helper function
- *
- * @see PShapeSVG#parsePath
- */
- PShapeSVG.prototype.parsePathCurveto = function(x1, y1, x2, y2, x3, y3) {
- if (this.vertices.length > 0) {
- this.parsePathCode(PConstants.BEZIER_VERTEX );
- this.parsePathVertex(x1, y1);
- this.parsePathVertex(x2, y2);
- this.parsePathVertex(x3, y3);
- } else {
- throw ("Path must start with M/m");
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parsePath() helper function
- *
- * @see PShapeSVG#parsePath
- */
- PShapeSVG.prototype.parsePathLineto = function(px, py) {
- if (this.vertices.length > 0) {
- this.parsePathCode(PConstants.VERTEX);
- this.parsePathVertex(px, py);
- // add property to distinguish between curContext.moveTo
- // or curContext.lineTo
- this.vertices[this.vertices.length-1].moveTo = false;
- } else {
- throw ("Path must start with M/m");
- }
- };
-
- PShapeSVG.prototype.parsePathMoveto = function(px, py) {
- if (this.vertices.length > 0) {
- this.parsePathCode(PConstants.BREAK);
- }
- this.parsePathCode(PConstants.VERTEX);
- this.parsePathVertex(px, py);
- // add property to distinguish between curContext.moveTo
- // or curContext.lineTo
- this.vertices[this.vertices.length-1].moveTo = true;
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parsePath() helper function
- *
- * @see PShapeSVG#parsePath
- */
- PShapeSVG.prototype.parsePathVertex = function(x, y) {
- var verts = [];
- verts[0] = x;
- verts[1] = y;
- this.vertices.push(verts);
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parsePath() helper function
- *
- * @see PShapeSVG#parsePath
- */
- PShapeSVG.prototype.parsePathCode = function(what) {
- this.vertexCodes.push(what);
- };
- /**
- * @member PShapeSVG
- * The parsePoly() function parses a polyline or polygon from an SVG file.
- *
- * @param {boolean}val true if shape is closed (polygon), false if not (polyline)
- */
- PShapeSVG.prototype.parsePoly = function(val) {
- this.family = PConstants.PATH;
- this.close = val;
- var pointsAttr = CommonFunctions.trim(this.element.getStringAttribute("points").replace(/[,\s]+/g,' '));
- if (pointsAttr !== null) {
- //split into array
- var pointsBuffer = pointsAttr.split(" ");
- if (pointsBuffer.length % 2 === 0) {
- for (var i = 0, j = pointsBuffer.length; i < j; i++) {
- var verts = [];
- verts[0] = pointsBuffer[i];
- verts[1] = pointsBuffer[++i];
- this.vertices.push(verts);
- }
- } else {
- throw("Error parsing polygon points: odd number of coordinates provided");
- }
- }
- };
- /**
- * @member PShapeSVG
- * The parseRect() function parses a rect from an SVG file.
- */
- PShapeSVG.prototype.parseRect = function() {
- this.kind = PConstants.RECT;
- this.family = PConstants.PRIMITIVE;
- this.params = [];
- this.params[0] = this.element.getFloatAttribute("x");
- this.params[1] = this.element.getFloatAttribute("y");
- this.params[2] = this.element.getFloatAttribute("width");
- this.params[3] = this.element.getFloatAttribute("height");
- if (this.params[2] < 0 || this.params[3] < 0) {
- throw("svg error: negative width or height found while parsing <rect>");
- }
- };
- /**
- * @member PShapeSVG
- * The parseEllipse() function handles parsing ellipse and circle tags.
- *
- * @param {boolean}val true if this is a circle and not an ellipse
- */
- PShapeSVG.prototype.parseEllipse = function(val) {
- this.kind = PConstants.ELLIPSE;
- this.family = PConstants.PRIMITIVE;
- this.params = [];
-
- this.params[0] = this.element.getFloatAttribute("cx") | 0 ;
- this.params[1] = this.element.getFloatAttribute("cy") | 0;
-
- var rx, ry;
- if (val) {
- rx = ry = this.element.getFloatAttribute("r");
- if (rx < 0) {
- throw("svg error: negative radius found while parsing <circle>");
- }
- } else {
- rx = this.element.getFloatAttribute("rx");
- ry = this.element.getFloatAttribute("ry");
- if (rx < 0 || ry < 0) {
- throw("svg error: negative x-axis radius or y-axis radius found while parsing <ellipse>");
- }
- }
- this.params[0] -= rx;
- this.params[1] -= ry;
-
- this.params[2] = rx*2;
- this.params[3] = ry*2;
- };
- /**
- * @member PShapeSVG
- * The parseLine() function handles parsing line tags.
- *
- * @param {boolean}val true if this is a circle and not an ellipse
- */
- PShapeSVG.prototype.parseLine = function() {
- this.kind = PConstants.LINE;
- this.family = PConstants.PRIMITIVE;
- this.params = [];
- this.params[0] = this.element.getFloatAttribute("x1");
- this.params[1] = this.element.getFloatAttribute("y1");
- this.params[2] = this.element.getFloatAttribute("x2");
- this.params[3] = this.element.getFloatAttribute("y2");
- };
- /**
- * @member PShapeSVG
- * The parseColors() function handles parsing the opacity, strijem stroke-width, stroke-linejoin,stroke-linecap, fill, and style attributes
- *
- * @param {XMLElement}element the element of which attributes to parse
- */
- PShapeSVG.prototype.parseColors = function(element) {
- if (element.hasAttribute("opacity")) {
- this.setOpacity(element.getAttribute("opacity"));
- }
- if (element.hasAttribute("stroke")) {
- this.setStroke(element.getAttribute("stroke"));
- }
- if (element.hasAttribute("stroke-width")) {
- // if NaN (i.e. if it's 'inherit') then default
- // back to the inherit setting
- this.setStrokeWeight(element.getAttribute("stroke-width"));
- }
- if (element.hasAttribute("stroke-linejoin") ) {
- this.setStrokeJoin(element.getAttribute("stroke-linejoin"));
- }
- if (element.hasAttribute("stroke-linecap")) {
- this.setStrokeCap(element.getStringAttribute("stroke-linecap"));
- }
- // fill defaults to black (though stroke defaults to "none")
- // http://www.w3.org/TR/SVG/painting.html#FillProperties
- if (element.hasAttribute("fill")) {
- this.setFill(element.getStringAttribute("fill"));
- }
- if (element.hasAttribute("style")) {
- var styleText = element.getStringAttribute("style");
- var styleTokens = styleText.toString().split( ";" );
-
- for (var i = 0, j = styleTokens.length; i < j; i++) {
- var tokens = CommonFunctions.trim(styleTokens[i].split( ":" ));
- if (tokens[0] === "fill") {
- this.setFill(tokens[1]);
- } else if (tokens[0] === "fill-opacity") {
- this.setFillOpacity(tokens[1]);
- } else if (tokens[0] === "stroke") {
- this.setStroke(tokens[1]);
- } else if (tokens[0] === "stroke-width") {
- this.setStrokeWeight(tokens[1]);
- } else if (tokens[0] === "stroke-linecap") {
- this.setStrokeCap(tokens[1]);
- } else if (tokens[0] === "stroke-linejoin") {
- this.setStrokeJoin(tokens[1]);
- } else if (tokens[0] === "stroke-opacity") {
- this.setStrokeOpacity(tokens[1]);
- } else if (tokens[0] === "opacity") {
- this.setOpacity(tokens[1]);
- } // Other attributes are not yet implemented
- }
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} opacityText the value of fillOpacity
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setFillOpacity = function(opacityText) {
- this.fillOpacity = parseFloat(opacityText);
- this.fillColor = this.fillOpacity * 255 << 24 |
- this.fillColor & 0xFFFFFF;
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} fillText the value of fill
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setFill = function (fillText) {
- var opacityMask = this.fillColor & 0xFF000000;
- if (fillText === "none") {
- this.fill = false;
- } else if (fillText.indexOf("#") === 0) {
- this.fill = true;
- if (fillText.length === 4) {
- // convert #00F to #0000FF
- fillText = fillText.replace(/#(.)(.)(.)/,"#$1$1$2$2$3$3");
- }
- this.fillColor = opacityMask |
- (parseInt(fillText.substring(1), 16 )) &
- 0xFFFFFF;
- } else if (fillText.indexOf("rgb") === 0) {
- this.fill = true;
- this.fillColor = opacityMask | this.parseRGB(fillText);
- } else if (fillText.indexOf("url(#") === 0) {
- this.fillName = fillText.substring(5, fillText.length - 1 );
- } else if (colors[fillText]) {
- this.fill = true;
- this.fillColor = opacityMask |
- (parseInt(colors[fillText].substring(1), 16)) &
- 0xFFFFFF;
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} opacity the value of opacity
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setOpacity = function(opacity) {
- this.strokeColor = parseFloat(opacity) * 255 << 24 |
- this.strokeColor & 0xFFFFFF;
- this.fillColor = parseFloat(opacity) * 255 << 24 |
- this.fillColor & 0xFFFFFF;
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} strokeText the value to set stroke to
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setStroke = function(strokeText) {
- var opacityMask = this.strokeColor & 0xFF000000;
- if (strokeText === "none") {
- this.stroke = false;
- } else if (strokeText.charAt( 0 ) === "#") {
- this.stroke = true;
- if (strokeText.length === 4) {
- // convert #00F to #0000FF
- strokeText = strokeText.replace(/#(.)(.)(.)/,"#$1$1$2$2$3$3");
- }
- this.strokeColor = opacityMask |
- (parseInt( strokeText.substring( 1 ), 16 )) &
- 0xFFFFFF;
- } else if (strokeText.indexOf( "rgb" ) === 0 ) {
- this.stroke = true;
- this.strokeColor = opacityMask | this.parseRGB(strokeText);
- } else if (strokeText.indexOf( "url(#" ) === 0) {
- this.strokeName = strokeText.substring(5, strokeText.length - 1);
- } else if (colors[strokeText]) {
- this.stroke = true;
- this.strokeColor = opacityMask |
- (parseInt(colors[strokeText].substring(1), 16)) &
- 0xFFFFFF;
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} weight the value to set strokeWeight to
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setStrokeWeight = function(weight) {
- this.strokeWeight = this.parseUnitSize(weight);
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} linejoin the value to set strokeJoin to
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setStrokeJoin = function(linejoin) {
- if (linejoin === "miter") {
- this.strokeJoin = PConstants.MITER;
-
- } else if (linejoin === "round") {
- this.strokeJoin = PConstants.ROUND;
-
- } else if (linejoin === "bevel") {
- this.strokeJoin = PConstants.BEVEL;
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} linecap the value to set strokeCap to
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setStrokeCap = function (linecap) {
- if (linecap === "butt") {
- this.strokeCap = PConstants.SQUARE;
-
- } else if (linecap === "round") {
- this.strokeCap = PConstants.ROUND;
-
- } else if (linecap === "square") {
- this.strokeCap = PConstants.PROJECT;
- }
- };
- /**
- * @member PShapeSVG
- * PShapeSVG.parseColors() helper function
- *
- * @param {String} opacityText the value to set stroke opacity to
- *
- * @see PShapeSVG#parseColors
- */
- PShapeSVG.prototype.setStrokeOpacity = function (opacityText) {
- this.strokeOpacity = parseFloat(opacityText);
- this.strokeColor = this.strokeOpacity * 255 << 24 |
- this.strokeColor &
- 0xFFFFFF;
- };
- /**
- * @member PShapeSVG
- * The parseRGB() function parses an rbg() color string and returns a color int
- *
- * @param {String} color the color to parse in rbg() format
- *
- * @return {int} the equivalent color int
- */
- PShapeSVG.prototype.parseRGB = function(color) {
- var sub = color.substring(color.indexOf('(') + 1, color.indexOf(')'));
- var values = sub.split(", ");
- return (values[0] << 16) | (values[1] << 8) | (values[2]);
- };
- /**
- * @member PShapeSVG
- * The parseUnitSize() function parse a size that may have a suffix for its units.
- * Ignoring cases where this could also be a percentage.
- * The <A HREF="http://www.w3.org/TR/SVG/coords.html#Units">units</A> spec:
- * <UL>
- * <LI>"1pt" equals "1.25px" (and therefore 1.25 user units)
- * <LI>"1pc" equals "15px" (and therefore 15 user units)
- * <LI>"1mm" would be "3.543307px" (3.543307 user units)
- * <LI>"1cm" equals "35.43307px" (and therefore 35.43307 user units)
- * <LI>"1in" equals "90px" (and therefore 90 user units)
- * </UL>
- */
- PShapeSVG.prototype.parseUnitSize = function (text) {
- var len = text.length - 2;
- if (len < 0) { return text; }
- if (text.indexOf("pt") === len) {
- return parseFloat(text.substring(0, len)) * 1.25;
- }
- if (text.indexOf("pc") === len) {
- return parseFloat( text.substring( 0, len)) * 15;
- }
- if (text.indexOf("mm") === len) {
- return parseFloat( text.substring(0, len)) * 3.543307;
- }
- if (text.indexOf("cm") === len) {
- return parseFloat(text.substring(0, len)) * 35.43307;
- }
- if (text.indexOf("in") === len) {
- return parseFloat(text.substring(0, len)) * 90;
- }
- if (text.indexOf("px") === len) {
- return parseFloat(text.substring(0, len));
- }
- return parseFloat(text);
- };
-
- return PShapeSVG;
- };
-
- },{}],18:[function(require,module,exports){
- module.exports = function(options, undef) {
- var PConstants = options.PConstants;
-
- function PVector(x, y, z) {
- this.x = x || 0;
- this.y = y || 0;
- this.z = z || 0;
- }
-
- PVector.fromAngle = function(angle, v) {
- if (v === undef || v === null) {
- v = new PVector();
- }
- v.x = Math.cos(angle);
- v.y = Math.sin(angle);
- return v;
- };
-
- PVector.random2D = function(v) {
- return PVector.fromAngle(Math.random() * PConstants.TWO_PI, v);
- };
-
- PVector.random3D = function(v) {
- var angle = Math.random() * PConstants.TWO_PI;
- var vz = Math.random() * 2 - 1;
- var mult = Math.sqrt(1 - vz * vz);
- var vx = mult * Math.cos(angle);
- var vy = mult * Math.sin(angle);
- if (v === undef || v === null) {
- v = new PVector(vx, vy, vz);
- } else {
- v.set(vx, vy, vz);
- }
- return v;
- };
-
- PVector.dist = function(v1, v2) {
- return v1.dist(v2);
- };
-
- PVector.dot = function(v1, v2) {
- return v1.dot(v2);
- };
-
- PVector.cross = function(v1, v2) {
- return v1.cross(v2);
- };
-
- PVector.sub = function(v1, v2) {
- return new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
- };
-
- PVector.angleBetween = function(v1, v2) {
- return Math.acos(v1.dot(v2) / (v1.mag() * v2.mag()));
- };
-
- PVector.lerp = function(v1, v2, amt) {
- // non-static lerp mutates object, but this version returns a new vector
- var retval = new PVector(v1.x, v1.y, v1.z);
- retval.lerp(v2, amt);
- return retval;
- };
-
- // Common vector operations for PVector
- PVector.prototype = {
- set: function(v, y, z) {
- if (arguments.length === 1) {
- this.set(v.x || v[0] || 0,
- v.y || v[1] || 0,
- v.z || v[2] || 0);
- } else {
- this.x = v;
- this.y = y;
- this.z = z;
- }
- },
- get: function() {
- return new PVector(this.x, this.y, this.z);
- },
- mag: function() {
- var x = this.x,
- y = this.y,
- z = this.z;
- return Math.sqrt(x * x + y * y + z * z);
- },
- magSq: function() {
- var x = this.x,
- y = this.y,
- z = this.z;
- return (x * x + y * y + z * z);
- },
- setMag: function(v_or_len, len) {
- if (len === undef) {
- len = v_or_len;
- this.normalize();
- this.mult(len);
- } else {
- var v = v_or_len;
- v.normalize();
- v.mult(len);
- return v;
- }
- },
- add: function(v, y, z) {
- if (arguments.length === 1) {
- this.x += v.x;
- this.y += v.y;
- this.z += v.z;
- } else {
- this.x += v;
- this.y += y;
- this.z += z;
- }
- },
- sub: function(v, y, z) {
- if (arguments.length === 1) {
- this.x -= v.x;
- this.y -= v.y;
- this.z -= v.z;
- } else {
- this.x -= v;
- this.y -= y;
- this.z -= z;
- }
- },
- mult: function(v) {
- if (typeof v === 'number') {
- this.x *= v;
- this.y *= v;
- this.z *= v;
- } else {
- this.x *= v.x;
- this.y *= v.y;
- this.z *= v.z;
- }
- },
- div: function(v) {
- if (typeof v === 'number') {
- this.x /= v;
- this.y /= v;
- this.z /= v;
- } else {
- this.x /= v.x;
- this.y /= v.y;
- this.z /= v.z;
- }
- },
- rotate: function(angle) {
- var prev_x = this.x;
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- this.x = c * this.x - s * this.y;
- this.y = s * prev_x + c * this.y;
- },
- dist: function(v) {
- var dx = this.x - v.x,
- dy = this.y - v.y,
- dz = this.z - v.z;
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
- },
- dot: function(v, y, z) {
- if (arguments.length === 1) {
- return (this.x * v.x + this.y * v.y + this.z * v.z);
- }
- return (this.x * v + this.y * y + this.z * z);
- },
- cross: function(v) {
- var x = this.x,
- y = this.y,
- z = this.z;
- return new PVector(y * v.z - v.y * z,
- z * v.x - v.z * x,
- x * v.y - v.x * y);
- },
- lerp: function(v_or_x, amt_or_y, z, amt) {
- var lerp_val = function(start, stop, amt) {
- return start + (stop - start) * amt;
- };
- var x, y;
- if (arguments.length === 2) {
- // given vector and amt
- amt = amt_or_y;
- x = v_or_x.x;
- y = v_or_x.y;
- z = v_or_x.z;
- } else {
- // given x, y, z and amt
- x = v_or_x;
- y = amt_or_y;
- }
- this.x = lerp_val(this.x, x, amt);
- this.y = lerp_val(this.y, y, amt);
- this.z = lerp_val(this.z, z, amt);
- },
- normalize: function() {
- var m = this.mag();
- if (m > 0) {
- this.div(m);
- }
- },
- limit: function(high) {
- if (this.mag() > high) {
- this.normalize();
- this.mult(high);
- }
- },
- heading: function() {
- return (-Math.atan2(-this.y, this.x));
- },
- heading2D: function() {
- return this.heading();
- },
- toString: function() {
- return "[" + this.x + ", " + this.y + ", " + this.z + "]";
- },
- array: function() {
- return [this.x, this.y, this.z];
- }
- };
-
- function createPVectorMethod(method) {
- return function(v1, v2) {
- var v = v1.get();
- v[method](v2);
- return v;
- };
- }
-
- for (var method in PVector.prototype) {
- if (PVector.prototype.hasOwnProperty(method) && !PVector.hasOwnProperty(method)) {
- PVector[method] = createPVectorMethod(method);
- }
- }
-
- return PVector;
- };
-
-
- },{}],19:[function(require,module,exports){
- /**
- * XMLAttribute is an attribute of a XML element.
- *
- * @param {String} fname the full name of the attribute
- * @param {String} n the short name of the attribute
- * @param {String} namespace the namespace URI of the attribute
- * @param {String} v the value of the attribute
- * @param {String }t the type of the attribute
- *
- * @see XMLElement
- */
- module.exports = function() {
-
- var XMLAttribute = function (fname, n, nameSpace, v, t){
- this.fullName = fname || "";
- this.name = n || "";
- this.namespace = nameSpace || "";
- this.value = v;
- this.type = t;
- };
-
- XMLAttribute.prototype = {
- /**
- * @member XMLAttribute
- * The getName() function returns the short name of the attribute
- *
- * @return {String} the short name of the attribute
- */
- getName: function() {
- return this.name;
- },
- /**
- * @member XMLAttribute
- * The getFullName() function returns the full name of the attribute
- *
- * @return {String} the full name of the attribute
- */
- getFullName: function() {
- return this.fullName;
- },
- /**
- * @member XMLAttribute
- * The getNamespace() function returns the namespace of the attribute
- *
- * @return {String} the namespace of the attribute
- */
- getNamespace: function() {
- return this.namespace;
- },
- /**
- * @member XMLAttribute
- * The getValue() function returns the value of the attribute
- *
- * @return {String} the value of the attribute
- */
- getValue: function() {
- return this.value;
- },
- /**
- * @member XMLAttribute
- * The getValue() function returns the type of the attribute
- *
- * @return {String} the type of the attribute
- */
- getType: function() {
- return this.type;
- },
- /**
- * @member XMLAttribute
- * The setValue() function sets the value of the attribute
- *
- * @param {String} newval the new value
- */
- setValue: function(newval) {
- this.value = newval;
- }
- };
-
- return XMLAttribute;
- };
-
- },{}],20:[function(require,module,exports){
- /**
- * XMLElement is a representation of an XML object. The object is able to parse XML code
- *
- * @param {PApplet} parent typically use "this"
- * @param {String} filename name of the XML/SVG file to load
- * @param {String} xml the xml/svg string
- * @param {String} fullname the full name of the element
- * @param {String} namespace the namespace of the URI
- * @param {String} systemID the system ID of the XML data where the element starts
- * @param {Integer }lineNr the line in the XML data where the element starts
- */
- module.exports = function(options, undef) {
-
- var Browser = options.Browser,
- ajax = Browser.ajax,
- window = Browser.window,
- XMLHttpRequest = window.XMLHttpRequest,
- DOMParser = window.DOMParser,
- XMLAttribute = options. XMLAttribute;
-
- var XMLElement = function(selector, uri, sysid, line) {
- this.attributes = [];
- this.children = [];
- this.fullName = null;
- this.name = null;
- this.namespace = "";
- this.content = null;
- this.parent = null;
- this.lineNr = "";
- this.systemID = "";
- this.type = "ELEMENT";
-
- if (selector) {
- if (typeof selector === "string") {
- if (uri === undef && selector.indexOf("<") > -1) {
- // load XML from text string
- this.parse(selector);
- } else {
- // XMLElement(fullname, namespace, sysid, line) format
- this.fullName = selector;
- this.namespace = uri;
- this.systemId = sysid;
- this.lineNr = line;
- }
- } else {
- // XMLElement(this, file uri) format
- this.parse(uri, true);
- }
- }
- };
- /**
- * XMLElement methods
- * missing: enumerateAttributeNames(), enumerateChildren(),
- * NOTE: parse does not work when a url is passed in
- */
- XMLElement.prototype = {
- /**
- * @member XMLElement
- * The parse() function retrieves the file via ajax() and uses DOMParser()
- * parseFromString method to make an XML document
- * @addon
- *
- * @param {String} filename name of the XML/SVG file to load
- *
- * @throws ExceptionType Error loading document
- *
- * @see XMLElement#parseChildrenRecursive
- */
- parse: function(textstring, stringIsURI) {
- var xmlDoc;
- try {
- var extension = textstring.substring(textstring.length-4);
- if (stringIsURI) {
- textstring = ajax(textstring);
- }
- xmlDoc = new DOMParser().parseFromString(textstring, "text/xml");
- var elements = xmlDoc.documentElement;
- if (elements) {
- this.parseChildrenRecursive(null, elements);
- } else {
- throw ("Error loading document");
- }
- return this;
- } catch(e) {
- throw(e);
- }
- },
- /**
- * @member XMLElement
- * Internal helper function for parse().
- * Loops through the
- * @addon
- *
- * @param {XMLElement} parent the parent node
- * @param {XML document childNodes} elementpath the remaining nodes that need parsing
- *
- * @return {XMLElement} the new element and its children elements
- */
- parseChildrenRecursive: function (parent, elementpath){
- var xmlelement,
- xmlattribute,
- tmpattrib,
- l, m,
- child;
- if (!parent) { // this element is the root element
- this.fullName = elementpath.localName;
- this.name = elementpath.nodeName;
- xmlelement = this;
- } else { // this element has a parent
- xmlelement = new XMLElement(elementpath.nodeName);
- xmlelement.parent = parent;
- }
-
- // if this is a text node, return a PCData element (parsed character data)
- if (elementpath.nodeType === 3 && elementpath.textContent !== "") {
- return this.createPCDataElement(elementpath.textContent);
- }
-
- // if this is a CDATA node, return a CData element (unparsed character data)
- if (elementpath.nodeType === 4) {
- return this.createCDataElement(elementpath.textContent);
- }
-
- // bind all attributes, if there are any
- if (elementpath.attributes) {
- for (l = 0, m = elementpath.attributes.length; l < m; l++) {
- tmpattrib = elementpath.attributes[l];
- xmlattribute = new XMLAttribute(tmpattrib.getname,
- tmpattrib.nodeName,
- tmpattrib.namespaceURI,
- tmpattrib.nodeValue,
- tmpattrib.nodeType);
- xmlelement.attributes.push(xmlattribute);
- }
- }
-
- // bind all children, if there are any
- if (elementpath.childNodes) {
- for (l = 0, m = elementpath.childNodes.length; l < m; l++) {
- var node = elementpath.childNodes[l];
- child = xmlelement.parseChildrenRecursive(xmlelement, node);
- if (child !== null) {
- xmlelement.children.push(child);
- }
- }
- }
-
- return xmlelement;
- },
- /**
- * @member XMLElement
- * The createElement() function Creates an empty element
- *
- * @param {String} fullName the full name of the element
- * @param {String} namespace the namespace URI
- * @param {String} systemID the system ID of the XML data where the element starts
- * @param {int} lineNr the line in the XML data where the element starts
- */
- createElement: function (fullname, namespaceuri, sysid, line) {
- if (sysid === undef) {
- return new XMLElement(fullname, namespaceuri);
- }
- return new XMLElement(fullname, namespaceuri, sysid, line);
- },
- /**
- * @member XMLElement
- * The createPCDataElement() function creates an element to be used for #PCDATA content.
- * Because Processing discards whitespace TEXT nodes, this method will not build an element
- * if the passed content is empty after trimming for whitespace.
- *
- * @return {XMLElement} new "pcdata" XMLElement, or null if content consists only of whitespace
- */
- createPCDataElement: function (content, isCDATA) {
- if (content.replace(/^\s+$/g,"") === "") {
- return null;
- }
- var pcdata = new XMLElement();
- pcdata.type = "TEXT";
- pcdata.content = content;
- return pcdata;
- },
- /**
- * @member XMLElement
- * The createCDataElement() function creates an element to be used for CDATA content.
- *
- * @return {XMLElement} new "cdata" XMLElement, or null if content consists only of whitespace
- */
- createCDataElement: function (content) {
- var cdata = this.createPCDataElement(content);
- if (cdata === null) {
- return null;
- }
-
- cdata.type = "CDATA";
- var htmlentities = {"<": "<", ">": ">", "'": "'", '"': """},
- entity;
- for (entity in htmlentities) {
- if (!Object.hasOwnProperty(htmlentities,entity)) {
- content = content.replace(new RegExp(entity, "g"), htmlentities[entity]);
- }
- }
- cdata.cdata = content;
- return cdata;
- },
- /**
- * @member XMLElement
- * The hasAttribute() function returns whether an attribute exists
- *
- * @param {String} name name of the attribute
- * @param {String} namespace the namespace URI of the attribute
- *
- * @return {boolean} true if the attribute exists
- */
- hasAttribute: function () {
- if (arguments.length === 1) {
- return this.getAttribute(arguments[0]) !== null;
- }
- if (arguments.length === 2) {
- return this.getAttribute(arguments[0],arguments[1]) !== null;
- }
- },
- /**
- * @member XMLElement
- * The equals() function checks to see if the XMLElement being passed in equals another XMLElement
- *
- * @param {XMLElement} rawElement the element to compare to
- *
- * @return {boolean} true if the element equals another element
- */
- equals: function(other) {
- if (!(other instanceof XMLElement)) {
- return false;
- }
- var i, j;
- if (this.fullName !== other.fullName) { return false; }
- if (this.attributes.length !== other.getAttributeCount()) { return false; }
- // attributes may be ordered differently
- if (this.attributes.length !== other.attributes.length) { return false; }
- var attr_name, attr_ns, attr_value, attr_type, attr_other;
- for (i = 0, j = this.attributes.length; i < j; i++) {
- attr_name = this.attributes[i].getName();
- attr_ns = this.attributes[i].getNamespace();
- attr_other = other.findAttribute(attr_name, attr_ns);
- if (attr_other === null) { return false; }
- if (this.attributes[i].getValue() !== attr_other.getValue()) { return false; }
- if (this.attributes[i].getType() !== attr_other.getType()) { return false; }
- }
- // children must be ordered identically
- if (this.children.length !== other.getChildCount()) { return false; }
- if (this.children.length>0) {
- var child1, child2;
- for (i = 0, j = this.children.length; i < j; i++) {
- child1 = this.getChild(i);
- child2 = other.getChild(i);
- if (!child1.equals(child2)) { return false; }
- }
- return true;
- }
- return (this.content === other.content);
- },
- /**
- * @member XMLElement
- * The getContent() function returns the content of an element. If there is no such content, null is returned
- *
- * @return {String} the (possibly null) content
- */
- getContent: function(){
- if (this.type === "TEXT" || this.type === "CDATA") {
- return this.content;
- }
- var children = this.children;
- if (children.length === 1 && (children[0].type === "TEXT" || children[0].type === "CDATA")) {
- return children[0].content;
- }
- return null;
- },
- /**
- * @member XMLElement
- * The getAttribute() function returns the value of an attribute
- *
- * @param {String} name the non-null full name of the attribute
- * @param {String} namespace the namespace URI, which may be null
- * @param {String} defaultValue the default value of the attribute
- *
- * @return {String} the value, or defaultValue if the attribute does not exist
- */
- getAttribute: function (){
- var attribute;
- if (arguments.length === 2) {
- attribute = this.findAttribute(arguments[0]);
- if (attribute) {
- return attribute.getValue();
- }
- return arguments[1];
- } else if (arguments.length === 1) {
- attribute = this.findAttribute(arguments[0]);
- if (attribute) {
- return attribute.getValue();
- }
- return null;
- } else if (arguments.length === 3) {
- attribute = this.findAttribute(arguments[0],arguments[1]);
- if (attribute) {
- return attribute.getValue();
- }
- return arguments[2];
- }
- },
- /**
- * @member XMLElement
- * The getStringAttribute() function returns the string attribute of the element
- * If the <b>defaultValue</b> parameter is used and the attribute doesn't exist, the <b>defaultValue</b> value is returned.
- * When calling the function without the <b>defaultValue</b> parameter, if the attribute doesn't exist, the value 0 is returned.
- *
- * @param name the name of the attribute
- * @param defaultValue value returned if the attribute is not found
- *
- * @return {String} the value, or defaultValue if the attribute does not exist
- */
- getStringAttribute: function() {
- if (arguments.length === 1) {
- return this.getAttribute(arguments[0]);
- }
- if (arguments.length === 2) {
- return this.getAttribute(arguments[0], arguments[1]);
- }
- return this.getAttribute(arguments[0], arguments[1],arguments[2]);
- },
- /**
- * Processing 1.5 XML API wrapper for the generic String
- * attribute getter. This may only take one argument.
- */
- getString: function(attributeName) {
- return this.getStringAttribute(attributeName);
- },
- /**
- * @member XMLElement
- * The getFloatAttribute() function returns the float attribute of the element.
- * If the <b>defaultValue</b> parameter is used and the attribute doesn't exist, the <b>defaultValue</b> value is returned.
- * When calling the function without the <b>defaultValue</b> parameter, if the attribute doesn't exist, the value 0 is returned.
- *
- * @param name the name of the attribute
- * @param defaultValue value returned if the attribute is not found
- *
- * @return {float} the value, or defaultValue if the attribute does not exist
- */
- getFloatAttribute: function() {
- if (arguments.length === 1 ) {
- return parseFloat(this.getAttribute(arguments[0], 0));
- }
- if (arguments.length === 2 ) {
- return this.getAttribute(arguments[0], arguments[1]);
- }
- return this.getAttribute(arguments[0], arguments[1],arguments[2]);
- },
- /**
- * Processing 1.5 XML API wrapper for the generic float
- * attribute getter. This may only take one argument.
- */
- getFloat: function(attributeName) {
- return this.getFloatAttribute(attributeName);
- },
- /**
- * @member XMLElement
- * The getIntAttribute() function returns the integer attribute of the element.
- * If the <b>defaultValue</b> parameter is used and the attribute doesn't exist, the <b>defaultValue</b> value is returned.
- * When calling the function without the <b>defaultValue</b> parameter, if the attribute doesn't exist, the value 0 is returned.
- *
- * @param name the name of the attribute
- * @param defaultValue value returned if the attribute is not found
- *
- * @return {int} the value, or defaultValue if the attribute does not exist
- */
- getIntAttribute: function () {
- if (arguments.length === 1) {
- return this.getAttribute( arguments[0], 0 );
- }
- if (arguments.length === 2) {
- return this.getAttribute(arguments[0], arguments[1]);
- }
- return this.getAttribute(arguments[0], arguments[1],arguments[2]);
- },
- /**
- * Processing 1.5 XML API wrapper for the generic int
- * attribute getter. This may only take one argument.
- */
- getInt: function(attributeName) {
- return this.getIntAttribute(attributeName);
- },
- /**
- * @member XMLElement
- * The hasChildren() function returns whether the element has children.
- *
- * @return {boolean} true if the element has children.
- */
- hasChildren: function () {
- return this.children.length > 0 ;
- },
- /**
- * @member XMLElement
- * The addChild() function adds a child element
- *
- * @param {XMLElement} child the non-null child to add.
- */
- addChild: function (child) {
- if (child !== null) {
- child.parent = this;
- this.children.push(child);
- }
- },
- /**
- * @member XMLElement
- * The insertChild() function inserts a child element at the index provided
- *
- * @param {XMLElement} child the non-null child to add.
- * @param {int} index where to put the child.
- */
- insertChild: function (child, index) {
- if (child) {
- if ((child.getLocalName() === null) && (! this.hasChildren())) {
- var lastChild = this.children[this.children.length -1];
- if (lastChild.getLocalName() === null) {
- lastChild.setContent(lastChild.getContent() + child.getContent());
- return;
- }
- }
- child.parent = this;
- this.children.splice(index,0,child);
- }
- },
- /**
- * @member XMLElement
- * The getChild() returns the child XMLElement as specified by the <b>index</b> parameter.
- * The value of the <b>index</b> parameter must be less than the total number of children to avoid going out of the array storing the child elements.
- * When the <b>path</b> parameter is specified, then it will return all children that match that path. The path is a series of elements and sub-elements, separated by slashes.
- *
- * @param {int} index where to put the child.
- * @param {String} path path to a particular element
- *
- * @return {XMLElement} the element
- */
- getChild: function (selector) {
- if (typeof selector === "number") {
- return this.children[selector];
- }
- if (selector.indexOf('/') !== -1) {
- // path traversal is required
- return this.getChildRecursive(selector.split("/"), 0);
- }
- var kid, kidName;
- for (var i = 0, j = this.getChildCount(); i < j; i++) {
- kid = this.getChild(i);
- kidName = kid.getName();
- if (kidName !== null && kidName === selector) {
- return kid;
- }
- }
- return null;
- },
- /**
- * @member XMLElement
- * The getChildren() returns all of the children as an XMLElement array.
- * When the <b>path</b> parameter is specified, then it will return all children that match that path.
- * The path is a series of elements and sub-elements, separated by slashes.
- *
- * @param {String} path element name or path/to/element
- *
- * @return {XMLElement} array of child elements that match
- *
- * @see XMLElement#getChildCount()
- * @see XMLElement#getChild()
- */
- getChildren: function(){
- if (arguments.length === 1) {
- if (typeof arguments[0] === "number") {
- return this.getChild( arguments[0]);
- }
- if (arguments[0].indexOf('/') !== -1) { // path was given
- return this.getChildrenRecursive( arguments[0].split("/"), 0);
- }
- var matches = [];
- var kid, kidName;
- for (var i = 0, j = this.getChildCount(); i < j; i++) {
- kid = this.getChild(i);
- kidName = kid.getName();
- if (kidName !== null && kidName === arguments[0]) {
- matches.push(kid);
- }
- }
- return matches;
- }
- return this.children;
- },
- /**
- * @member XMLElement
- * The getChildCount() returns the number of children for the element.
- *
- * @return {int} the count
- *
- * @see XMLElement#getChild()
- * @see XMLElement#getChildren()
- */
- getChildCount: function() {
- return this.children.length;
- },
- /**
- * @member XMLElement
- * Internal helper function for getChild().
- *
- * @param {String[]} items result of splitting the query on slashes
- * @param {int} offset where in the items[] array we're currently looking
- *
- * @return {XMLElement} matching element or null if no match
- */
- getChildRecursive: function (items, offset) {
- // terminating clause: we are the requested candidate
- if (offset === items.length) {
- return this;
- }
- // continuation clause
- var kid, kidName, matchName = items[offset];
- for(var i = 0, j = this.getChildCount(); i < j; i++) {
- kid = this.getChild(i);
- kidName = kid.getName();
- if (kidName !== null && kidName === matchName) {
- return kid.getChildRecursive(items, offset+1);
- }
- }
- return null;
- },
- /**
- * @member XMLElement
- * Internal helper function for getChildren().
- *
- * @param {String[]} items result of splitting the query on slashes
- * @param {int} offset where in the items[] array we're currently looking
- *
- * @return {XMLElement[]} matching elements or empty array if no match
- */
- getChildrenRecursive: function (items, offset) {
- if (offset === items.length-1) {
- return this.getChildren(items[offset]);
- }
- var matches = this.getChildren(items[offset]);
- var kidMatches = [];
- for (var i = 0; i < matches.length; i++) {
- kidMatches = kidMatches.concat(matches[i].getChildrenRecursive(items, offset+1));
- }
- return kidMatches;
- },
- /**
- * @member XMLElement
- * The isLeaf() function returns whether the element is a leaf element.
- *
- * @return {boolean} true if the element has no children.
- */
- isLeaf: function() {
- return !this.hasChildren();
- },
- /**
- * @member XMLElement
- * The listChildren() function put the names of all children into an array. Same as looping through
- * each child and calling getName() on each XMLElement.
- *
- * @return {String[]} a list of element names.
- */
- listChildren: function() {
- var arr = [];
- for (var i = 0, j = this.children.length; i < j; i++) {
- arr.push( this.getChild(i).getName());
- }
- return arr;
- },
- /**
- * @member XMLElement
- * The removeAttribute() function removes an attribute
- *
- * @param {String} name the non-null name of the attribute.
- * @param {String} namespace the namespace URI of the attribute, which may be null.
- */
- removeAttribute: function (name , namespace) {
- this.namespace = namespace || "";
- for (var i = 0, j = this.attributes.length; i < j; i++) {
- if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) {
- this.attributes.splice(i, 1);
- break;
- }
- }
- },
- /**
- * @member XMLElement
- * The removeChild() removes a child element.
- *
- * @param {XMLElement} child the the non-null child to be renoved
- */
- removeChild: function(child) {
- if (child) {
- for (var i = 0, j = this.children.length; i < j; i++) {
- if (this.children[i].equals(child)) {
- this.children.splice(i, 1);
- break;
- }
- }
- }
- },
- /**
- * @member XMLElement
- * The removeChildAtIndex() removes the child located at a certain index
- *
- * @param {int} index the index of the child, where the first child has index 0
- */
- removeChildAtIndex: function(index) {
- if (this.children.length > index) { //make sure its not outofbounds
- this.children.splice(index, 1);
- }
- },
- /**
- * @member XMLElement
- * The findAttribute() function searches an attribute
- *
- * @param {String} name fullName the non-null full name of the attribute
- * @param {String} namespace the name space, which may be null
- *
- * @return {XMLAttribute} the attribute, or null if the attribute does not exist.
- */
- findAttribute: function (name, namespace) {
- this.namespace = namespace || "";
- for (var i = 0, j = this.attributes.length; i < j; i++) {
- if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) {
- return this.attributes[i];
- }
- }
- return null;
- },
- /**
- * @member XMLElement
- * The setAttribute() function sets an attribute.
- *
- * @param {String} name the non-null full name of the attribute
- * @param {String} namespace the non-null value of the attribute
- */
- setAttribute: function() {
- var attr;
- if (arguments.length === 3) {
- var index = arguments[0].indexOf(':');
- var name = arguments[0].substring(index + 1);
- attr = this.findAttribute(name, arguments[1]);
- if (attr) {
- attr.setValue(arguments[2]);
- } else {
- attr = new XMLAttribute(arguments[0], name, arguments[1], arguments[2], "CDATA");
- this.attributes.push(attr);
- }
- } else {
- attr = this.findAttribute(arguments[0]);
- if (attr) {
- attr.setValue(arguments[1]);
- } else {
- attr = new XMLAttribute(arguments[0], arguments[0], null, arguments[1], "CDATA");
- this.attributes.push(attr);
- }
- }
- },
- /**
- * Processing 1.5 XML API wrapper for the generic String
- * attribute setter. This must take two arguments.
- */
- setString: function(attribute, value) {
- this.setAttribute(attribute, value);
- },
- /**
- * Processing 1.5 XML API wrapper for the generic int
- * attribute setter. This must take two arguments.
- */
- setInt: function(attribute, value) {
- this.setAttribute(attribute, value);
- },
- /**
- * Processing 1.5 XML API wrapper for the generic float
- * attribute setter. This must take two arguments.
- */
- setFloat: function(attribute, value) {
- this.setAttribute(attribute, value);
- },
- /**
- * @member XMLElement
- * The setContent() function sets the #PCDATA content. It is an error to call this method with a
- * non-null value if there are child objects.
- *
- * @param {String} content the (possibly null) content
- */
- setContent: function(content) {
- if (this.children.length > 0) {
- Processing.debug("Tried to set content for XMLElement with children"); }
- this.content = content;
- },
- /**
- * @member XMLElement
- * The setName() function sets the full name. This method also sets the short name and clears the
- * namespace URI.
- *
- * @param {String} name the non-null name
- * @param {String} namespace the namespace URI, which may be null.
- */
- setName: function() {
- if (arguments.length === 1) {
- this.name = arguments[0];
- this.fullName = arguments[0];
- this.namespace = null;
- } else {
- var index = arguments[0].indexOf(':');
- if ((arguments[1] === null) || (index < 0)) {
- this.name = arguments[0];
- } else {
- this.name = arguments[0].substring(index + 1);
- }
- this.fullName = arguments[0];
- this.namespace = arguments[1];
- }
- },
- /**
- * @member XMLElement
- * The getName() function returns the full name (i.e. the name including an eventual namespace
- * prefix) of the element.
- *
- * @return {String} the name, or null if the element only contains #PCDATA.
- */
- getName: function() {
- return this.fullName;
- },
- /**
- * @member XMLElement
- * The getLocalName() function returns the local name (i.e. the name excluding an eventual namespace
- * prefix) of the element.
- *
- * @return {String} the name, or null if the element only contains #PCDATA.
- */
- getLocalName: function() {
- return this.name;
- },
- /**
- * @member XMLElement
- * The getAttributeCount() function returns the number of attributes for the node
- * that this XMLElement represents.
- *
- * @return {int} the number of attributes in this XMLElement
- */
- getAttributeCount: function() {
- return this.attributes.length;
- },
- /**
- * @member XMLElement
- * The toString() function returns the XML definition of an XMLElement.
- *
- * @return {String} the XML definition of this XMLElement
- */
- toString: function() {
- // shortcut for text and cdata nodes
- if (this.type === "TEXT") {
- return this.content || "";
- }
-
- if (this.type === "CDATA") {
- return this.cdata || "";
- }
-
- // real XMLElements
- var tagstring = this.fullName;
- var xmlstring = "<" + tagstring;
- var a,c;
-
- // serialize the attributes to XML string
- for (a = 0; a<this.attributes.length; a++) {
- var attr = this.attributes[a];
- xmlstring += " " + attr.getName() + "=" + '"' + attr.getValue() + '"';
- }
-
- // serialize all children to XML string
- if (this.children.length === 0) {
- if (this.content === "" || this.content === null || this.content === undefined) {
- xmlstring += "/>";
- } else {
- xmlstring += ">" + this.content + "</"+tagstring+">";
- }
- } else {
- xmlstring += ">";
- for (c = 0; c<this.children.length; c++) {
- xmlstring += this.children[c].toString();
- }
- xmlstring += "</" + tagstring + ">";
- }
- return xmlstring;
- }
- };
-
- /**
- * static Processing 1.5 XML API wrapper for the
- * parse method. This may only take one argument.
- */
- XMLElement.parse = function(xmlstring) {
- var element = new XMLElement();
- element.parse(xmlstring);
- return element;
- };
-
- return XMLElement;
- };
-
- },{}],21:[function(require,module,exports){
- /**
- * web colors, by name
- */
- module.exports = {
- aliceblue: "#f0f8ff",
- antiquewhite: "#faebd7",
- aqua: "#00ffff",
- aquamarine: "#7fffd4",
- azure: "#f0ffff",
- beige: "#f5f5dc",
- bisque: "#ffe4c4",
- black: "#000000",
- blanchedalmond: "#ffebcd",
- blue: "#0000ff",
- blueviolet: "#8a2be2",
- brown: "#a52a2a",
- burlywood: "#deb887",
- cadetblue: "#5f9ea0",
- chartreuse: "#7fff00",
- chocolate: "#d2691e",
- coral: "#ff7f50",
- cornflowerblue: "#6495ed",
- cornsilk: "#fff8dc",
- crimson: "#dc143c",
- cyan: "#00ffff",
- darkblue: "#00008b",
- darkcyan: "#008b8b",
- darkgoldenrod: "#b8860b",
- darkgray: "#a9a9a9",
- darkgreen: "#006400",
- darkkhaki: "#bdb76b",
- darkmagenta: "#8b008b",
- darkolivegreen: "#556b2f",
- darkorange: "#ff8c00",
- darkorchid: "#9932cc",
- darkred: "#8b0000",
- darksalmon: "#e9967a",
- darkseagreen: "#8fbc8f",
- darkslateblue: "#483d8b",
- darkslategray: "#2f4f4f",
- darkturquoise: "#00ced1",
- darkviolet: "#9400d3",
- deeppink: "#ff1493",
- deepskyblue: "#00bfff",
- dimgray: "#696969",
- dodgerblue: "#1e90ff",
- firebrick: "#b22222",
- floralwhite: "#fffaf0",
- forestgreen: "#228b22",
- fuchsia: "#ff00ff",
- gainsboro: "#dcdcdc",
- ghostwhite: "#f8f8ff",
- gold: "#ffd700",
- goldenrod: "#daa520",
- gray: "#808080",
- green: "#008000",
- greenyellow: "#adff2f",
- honeydew: "#f0fff0",
- hotpink: "#ff69b4",
- indianred: "#cd5c5c",
- indigo: "#4b0082",
- ivory: "#fffff0",
- khaki: "#f0e68c",
- lavender: "#e6e6fa",
- lavenderblush: "#fff0f5",
- lawngreen: "#7cfc00",
- lemonchiffon: "#fffacd",
- lightblue: "#add8e6",
- lightcoral: "#f08080",
- lightcyan: "#e0ffff",
- lightgoldenrodyellow: "#fafad2",
- lightgrey: "#d3d3d3",
- lightgreen: "#90ee90",
- lightpink: "#ffb6c1",
- lightsalmon: "#ffa07a",
- lightseagreen: "#20b2aa",
- lightskyblue: "#87cefa",
- lightslategray: "#778899",
- lightsteelblue: "#b0c4de",
- lightyellow: "#ffffe0",
- lime: "#00ff00",
- limegreen: "#32cd32",
- linen: "#faf0e6",
- magenta: "#ff00ff",
- maroon: "#800000",
- mediumaquamarine: "#66cdaa",
- mediumblue: "#0000cd",
- mediumorchid: "#ba55d3",
- mediumpurple: "#9370d8",
- mediumseagreen: "#3cb371",
- mediumslateblue: "#7b68ee",
- mediumspringgreen: "#00fa9a",
- mediumturquoise: "#48d1cc",
- mediumvioletred: "#c71585",
- midnightblue: "#191970",
- mintcream: "#f5fffa",
- mistyrose: "#ffe4e1",
- moccasin: "#ffe4b5",
- navajowhite: "#ffdead",
- navy: "#000080",
- oldlace: "#fdf5e6",
- olive: "#808000",
- olivedrab: "#6b8e23",
- orange: "#ffa500",
- orangered: "#ff4500",
- orchid: "#da70d6",
- palegoldenrod: "#eee8aa",
- palegreen: "#98fb98",
- paleturquoise: "#afeeee",
- palevioletred: "#d87093",
- papayawhip: "#ffefd5",
- peachpuff: "#ffdab9",
- peru: "#cd853f",
- pink: "#ffc0cb",
- plum: "#dda0dd",
- powderblue: "#b0e0e6",
- purple: "#800080",
- red: "#ff0000",
- rosybrown: "#bc8f8f",
- royalblue: "#4169e1",
- saddlebrown: "#8b4513",
- salmon: "#fa8072",
- sandybrown: "#f4a460",
- seagreen: "#2e8b57",
- seashell: "#fff5ee",
- sienna: "#a0522d",
- silver: "#c0c0c0",
- skyblue: "#87ceeb",
- slateblue: "#6a5acd",
- slategray: "#708090",
- snow: "#fffafa",
- springgreen: "#00ff7f",
- steelblue: "#4682b4",
- tan: "#d2b48c",
- teal: "#008080",
- thistle: "#d8bfd8",
- tomato: "#ff6347",
- turquoise: "#40e0d0",
- violet: "#ee82ee",
- wheat: "#f5deb3",
- white: "#ffffff",
- whitesmoke: "#f5f5f5",
- yellow: "#ffff00",
- yellowgreen: "#9acd32"
- };
-
- },{}],22:[function(require,module,exports){
- module.exports = function(virtHashCode, virtEquals, undef) {
-
- return function withProxyFunctions(p, removeFirstArgument) {
- /**
- * The contains(string) function returns true if the string passed in the parameter
- * is a substring of this string. It returns false if the string passed
- * in the parameter is not a substring of this string.
- *
- * @param {String} The string to look for in the current string
- *
- * @return {boolean} returns true if this string contains
- * the string passed as parameter. returns false, otherwise.
- *
- */
- p.__contains = function (subject, subStr) {
- if (typeof subject !== "string") {
- return subject.contains.apply(subject, removeFirstArgument(arguments));
- }
- //Parameter is not null AND
- //The type of the parameter is the same as this object (string)
- //The javascript function that finds a substring returns 0 or higher
- return (
- (subject !== null) &&
- (subStr !== null) &&
- (typeof subStr === "string") &&
- (subject.indexOf(subStr) > -1)
- );
- };
-
- /**
- * The __replaceAll() function searches all matches between a substring (or regular expression) and a string,
- * and replaces the matched substring with a new substring
- *
- * @param {String} subject a substring
- * @param {String} regex a substring or a regular expression
- * @param {String} replace the string to replace the found value
- *
- * @return {String} returns result
- *
- * @see #match
- */
- p.__replaceAll = function(subject, regex, replacement) {
- if (typeof subject !== "string") {
- return subject.replaceAll.apply(subject, removeFirstArgument(arguments));
- }
-
- return subject.replace(new RegExp(regex, "g"), replacement);
- };
-
- /**
- * The __replaceFirst() function searches first matche between a substring (or regular expression) and a string,
- * and replaces the matched substring with a new substring
- *
- * @param {String} subject a substring
- * @param {String} regex a substring or a regular expression
- * @param {String} replace the string to replace the found value
- *
- * @return {String} returns result
- *
- * @see #match
- */
- p.__replaceFirst = function(subject, regex, replacement) {
- if (typeof subject !== "string") {
- return subject.replaceFirst.apply(subject, removeFirstArgument(arguments));
- }
-
- return subject.replace(new RegExp(regex, ""), replacement);
- };
-
- /**
- * The __replace() function searches all matches between a substring and a string,
- * and replaces the matched substring with a new substring
- *
- * @param {String} subject a substring
- * @param {String} what a substring to find
- * @param {String} replacement the string to replace the found value
- *
- * @return {String} returns result
- */
- p.__replace = function(subject, what, replacement) {
- if (typeof subject !== "string") {
- return subject.replace.apply(subject, removeFirstArgument(arguments));
- }
- if (what instanceof RegExp) {
- return subject.replace(what, replacement);
- }
-
- if (typeof what !== "string") {
- what = what.toString();
- }
- if (what === "") {
- return subject;
- }
-
- var i = subject.indexOf(what);
- if (i < 0) {
- return subject;
- }
-
- var j = 0, result = "";
- do {
- result += subject.substring(j, i) + replacement;
- j = i + what.length;
- } while ( (i = subject.indexOf(what, j)) >= 0);
- return result + subject.substring(j);
- };
-
- /**
- * The __equals() function compares two strings (or objects) to see if they are the same.
- * This method is necessary because it's not possible to compare strings using the equality operator (==).
- * Returns true if the strings are the same and false if they are not.
- *
- * @param {String} subject a string used for comparison
- * @param {String} other a string used for comparison with
- *
- * @return {boolean} true is the strings are the same false otherwise
- */
- p.__equals = function(subject, other) {
- if (subject.equals instanceof Function) {
- return subject.equals.apply(subject, removeFirstArgument(arguments));
- }
-
- return virtEquals(subject, other);
- };
-
- /**
- * The __equalsIgnoreCase() function compares two strings to see if they are the same.
- * Returns true if the strings are the same, either when forced to all lower case or
- * all upper case.
- *
- * @param {String} subject a string used for comparison
- * @param {String} other a string used for comparison with
- *
- * @return {boolean} true is the strings are the same, ignoring case. false otherwise
- */
- p.__equalsIgnoreCase = function(subject, other) {
- if (typeof subject !== "string") {
- return subject.equalsIgnoreCase.apply(subject, removeFirstArgument(arguments));
- }
-
- return subject.toLowerCase() === other.toLowerCase();
- };
-
- /**
- * The __toCharArray() function splits the string into a char array.
- *
- * @param {String} subject The string
- *
- * @return {Char[]} a char array
- */
- p.__toCharArray = function(subject) {
- if (typeof subject !== "string") {
- return subject.toCharArray.apply(subject, removeFirstArgument(arguments));
- }
-
- var chars = [];
- for (var i = 0, len = subject.length; i < len; ++i) {
- chars[i] = new Char(subject.charAt(i));
- }
- return chars;
- };
-
- /**
- * The __split() function splits a string using the regex delimiter
- * specified. If limit is specified, the resultant array will have number
- * of elements equal to or less than the limit.
- *
- * @param {String} subject string to be split
- * @param {String} regexp regex string used to split the subject
- * @param {int} limit max number of tokens to be returned
- *
- * @return {String[]} an array of tokens from the split string
- */
- p.__split = function(subject, regex, limit) {
- if (typeof subject !== "string") {
- return subject.split.apply(subject, removeFirstArgument(arguments));
- }
-
- var pattern = new RegExp(regex);
-
- // If limit is not specified, use JavaScript's built-in String.split.
- if ((limit === undef) || (limit < 1)) {
- return subject.split(pattern);
- }
-
- // If limit is specified, JavaScript's built-in String.split has a
- // different behaviour than Java's. A Java-compatible implementation is
- // provided here.
- var result = [], currSubject = subject, pos;
- while (((pos = currSubject.search(pattern)) !== -1) && (result.length < (limit - 1))) {
- var match = pattern.exec(currSubject).toString();
- result.push(currSubject.substring(0, pos));
- currSubject = currSubject.substring(pos + match.length);
- }
- if ((pos !== -1) || (currSubject !== "")) {
- result.push(currSubject);
- }
- return result;
- };
-
- /**
- * The codePointAt() function returns the unicode value of the character at a given index of a string.
- *
- * @param {int} idx the index of the character
- *
- * @return {String} code the String containing the unicode value of the character
- */
- p.__codePointAt = function(subject, idx) {
- var code = subject.charCodeAt(idx),
- hi,
- low;
- if (0xD800 <= code && code <= 0xDBFF) {
- hi = code;
- low = subject.charCodeAt(idx + 1);
- return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
- }
- return code;
- };
-
- /**
- * The matches() function checks whether or not a string matches a given regular expression.
- *
- * @param {String} str the String on which the match is tested
- * @param {String} regexp the regexp for which a match is tested
- *
- * @return {boolean} true if the string fits the regexp, false otherwise
- */
- p.__matches = function(str, regexp) {
- return (new RegExp(regexp)).test(str);
- };
-
- /**
- * The startsWith() function tests if a string starts with the specified prefix. If the prefix
- * is the empty String or equal to the subject String, startsWith() will also return true.
- *
- * @param {String} prefix the String used to compare against the start of the subject String.
- * @param {int} toffset (optional) an offset into the subject String where searching should begin.
- *
- * @return {boolean} true if the subject String starts with the prefix.
- */
- p.__startsWith = function(subject, prefix, toffset) {
- if (typeof subject !== "string") {
- return subject.startsWith.apply(subject, removeFirstArgument(arguments));
- }
-
- toffset = toffset || 0;
- if (toffset < 0 || toffset > subject.length) {
- return false;
- }
- return (prefix === '' || prefix === subject) ? true : (subject.indexOf(prefix) === toffset);
- };
-
- /**
- * The endsWith() function tests if a string ends with the specified suffix. If the suffix
- * is the empty String, endsWith() will also return true.
- *
- * @param {String} suffix the String used to compare against the end of the subject String.
- *
- * @return {boolean} true if the subject String starts with the prefix.
- */
- p.__endsWith = function(subject, suffix) {
- if (typeof subject !== "string") {
- return subject.endsWith.apply(subject, removeFirstArgument(arguments));
- }
-
- var suffixLen = suffix ? suffix.length : 0;
- return (suffix === '' || suffix === subject) ? true :
- (subject.indexOf(suffix) === subject.length - suffixLen);
- };
-
- /**
- * The returns hash code of the.
- *
- * @param {Object} subject The string
- *
- * @return {int} a hash code
- */
- p.__hashCode = function(subject) {
- if (subject.hashCode instanceof Function) {
- return subject.hashCode.apply(subject, removeFirstArgument(arguments));
- }
- return virtHashCode(subject);
- };
-
- /**
- * The __printStackTrace() prints stack trace to the console.
- *
- * @param {Exception} subject The error
- */
- p.__printStackTrace = function(subject) {
- p.println("Exception: " + subject.toString() );
- };
- };
-
- };
-
- },{}],23:[function(require,module,exports){
- /**
- * For many "math" functions, we can delegate
- * to the Math object. For others, we can't.
- */
- module.exports = function withMath(p, undef) {
- var internalRandomGenerator = function() { return Math.random(); };
-
- /**
- * Calculates the absolute value (magnitude) of a number. The absolute value of a number is always positive.
- *
- * @param {int|float} value int or float
- *
- * @returns {int|float}
- */
- p.abs = Math.abs;
-
- /**
- * Calculates the closest int value that is greater than or equal to the value of the parameter.
- * For example, ceil(9.03) returns the value 10.
- *
- * @param {float} value float
- *
- * @returns {int}
- *
- * @see floor
- * @see round
- */
- p.ceil = Math.ceil;
-
- /**
- * Returns Euler's number e (2.71828...) raised to the power of the value parameter.
- *
- * @param {int|float} value int or float: the exponent to raise e to
- *
- * @returns {float}
- */
- p.exp = Math.exp;
-
- /**
- * Calculates the closest int value that is less than or equal to the value of the parameter.
- *
- * @param {int|float} value the value to floor
- *
- * @returns {int|float}
- *
- * @see ceil
- * @see round
- */
- p.floor = Math.floor;
-
- /**
- * Calculates the natural logarithm (the base-e logarithm) of a number. This function
- * expects the values greater than 0.0.
- *
- * @param {int|float} value int or float: number must be greater then 0.0
- *
- * @returns {float}
- */
- p.log = Math.log;
-
- /**
- * Facilitates exponential expressions. The pow() function is an efficient way of
- * multiplying numbers by themselves (or their reciprocal) in large quantities.
- * For example, pow(3, 5) is equivalent to the expression 3*3*3*3*3 and pow(3, -5)
- * is equivalent to 1 / 3*3*3*3*3.
- *
- * @param {int|float} num base of the exponential expression
- * @param {int|float} exponent power of which to raise the base
- *
- * @returns {float}
- *
- * @see sqrt
- */
- p.pow = Math.pow;
-
- /**
- * Calculates the integer closest to the value parameter. For example, round(9.2) returns the value 9.
- *
- * @param {float} value number to round
- *
- * @returns {int}
- *
- * @see floor
- * @see ceil
- */
- p.round = Math.round;
- /**
- * Calculates the square root of a number. The square root of a number is always positive,
- * even though there may be a valid negative root. The square root s of number a is such
- * that s*s = a. It is the opposite of squaring.
- *
- * @param {float} value int or float, non negative
- *
- * @returns {float}
- *
- * @see pow
- * @see sq
- */
-
- p.sqrt = Math.sqrt;
-
- // Trigonometry
- /**
- * The inverse of cos(), returns the arc cosine of a value. This function expects the
- * values in the range of -1 to 1 and values are returned in the range 0 to PI (3.1415927).
- *
- * @param {float} value the value whose arc cosine is to be returned
- *
- * @returns {float}
- *
- * @see cos
- * @see asin
- * @see atan
- */
- p.acos = Math.acos;
-
- /**
- * The inverse of sin(), returns the arc sine of a value. This function expects the values
- * in the range of -1 to 1 and values are returned in the range -PI/2 to PI/2.
- *
- * @param {float} value the value whose arc sine is to be returned
- *
- * @returns {float}
- *
- * @see sin
- * @see acos
- * @see atan
- */
- p.asin = Math.asin;
-
- /**
- * The inverse of tan(), returns the arc tangent of a value. This function expects the values
- * in the range of -Infinity to Infinity (exclusive) and values are returned in the range -PI/2 to PI/2 .
- *
- * @param {float} value -Infinity to Infinity (exclusive)
- *
- * @returns {float}
- *
- * @see tan
- * @see asin
- * @see acos
- */
- p.atan = Math.atan;
-
- /**
- * Calculates the angle (in radians) from a specified point to the coordinate origin as measured from
- * the positive x-axis. Values are returned as a float in the range from PI to -PI. The atan2() function
- * is most often used for orienting geometry to the position of the cursor. Note: The y-coordinate of the
- * point is the first parameter and the x-coordinate is the second due the the structure of calculating the tangent.
- *
- * @param {float} y y-coordinate of the point
- * @param {float} x x-coordinate of the point
- *
- * @returns {float}
- *
- * @see tan
- */
- p.atan2 = Math.atan2;
-
- /**
- * Calculates the cosine of an angle. This function expects the values of the angle parameter to be provided
- * in radians (values from 0 to PI*2). Values are returned in the range -1 to 1.
- *
- * @param {float} value an angle in radians
- *
- * @returns {float}
- *
- * @see tan
- * @see sin
- */
- p.cos = Math.cos;
-
- /**
- * Calculates the sine of an angle. This function expects the values of the angle parameter to be provided in
- * radians (values from 0 to 6.28). Values are returned in the range -1 to 1.
- *
- * @param {float} value an angle in radians
- *
- * @returns {float}
- *
- * @see cos
- * @see radians
- */
- p.sin = Math.sin;
-
- /**
- * Calculates the ratio of the sine and cosine of an angle. This function expects the values of the angle
- * parameter to be provided in radians (values from 0 to PI*2). Values are returned in the range infinity to -infinity.
- *
- * @param {float} value an angle in radians
- *
- * @returns {float}
- *
- * @see cos
- * @see sin
- * @see radians
- */
- p.tan = Math.tan;
-
- /**
- * Constrains a value to not exceed a maximum and minimum value.
- *
- * @param {int|float} value the value to constrain
- * @param {int|float} value minimum limit
- * @param {int|float} value maximum limit
- *
- * @returns {int|float}
- *
- * @see max
- * @see min
- */
- p.constrain = function(aNumber, aMin, aMax) {
- return aNumber > aMax ? aMax : aNumber < aMin ? aMin : aNumber;
- };
-
- /**
- * Calculates the distance between two points.
- *
- * @param {int|float} x1 int or float: x-coordinate of the first point
- * @param {int|float} y1 int or float: y-coordinate of the first point
- * @param {int|float} z1 int or float: z-coordinate of the first point
- * @param {int|float} x2 int or float: x-coordinate of the second point
- * @param {int|float} y2 int or float: y-coordinate of the second point
- * @param {int|float} z2 int or float: z-coordinate of the second point
- *
- * @returns {float}
- */
- p.dist = function() {
- var dx, dy, dz;
- if (arguments.length === 4) {
- dx = arguments[0] - arguments[2];
- dy = arguments[1] - arguments[3];
- return Math.sqrt(dx * dx + dy * dy);
- }
- if (arguments.length === 6) {
- dx = arguments[0] - arguments[3];
- dy = arguments[1] - arguments[4];
- dz = arguments[2] - arguments[5];
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
- }
- };
-
- /**
- * Calculates a number between two numbers at a specific increment. The amt parameter is the
- * amount to interpolate between the two values where 0.0 equal to the first point, 0.1 is very
- * near the first point, 0.5 is half-way in between, etc. The lerp function is convenient for
- * creating motion along a straight path and for drawing dotted lines.
- *
- * @param {int|float} value1 float or int: first value
- * @param {int|float} value2 float or int: second value
- * @param {int|float} amt float: between 0.0 and 1.0
- *
- * @returns {float}
- *
- * @see curvePoint
- * @see bezierPoint
- */
- p.lerp = function(value1, value2, amt) {
- return ((value2 - value1) * amt) + value1;
- };
-
- /**
- * Calculates the magnitude (or length) of a vector. A vector is a direction in space commonly
- * used in computer graphics and linear algebra. Because it has no "start" position, the magnitude
- * of a vector can be thought of as the distance from coordinate (0,0) to its (x,y) value.
- * Therefore, mag() is a shortcut for writing "dist(0, 0, x, y)".
- *
- * @param {int|float} a float or int: first value
- * @param {int|float} b float or int: second value
- * @param {int|float} c float or int: third value
- *
- * @returns {float}
- *
- * @see dist
- */
- p.mag = function(a, b, c) {
- if (c) {
- return Math.sqrt(a * a + b * b + c * c);
- }
-
- return Math.sqrt(a * a + b * b);
- };
-
- /**
- * Re-maps a number from one range to another. In the example above, the number '25' is converted from
- * a value in the range 0..100 into a value that ranges from the left edge (0) to the right edge (width) of the screen.
- * Numbers outside the range are not clamped to 0 and 1, because out-of-range values are often intentional and useful.
- *
- * @param {float} value The incoming value to be converted
- * @param {float} istart Lower bound of the value's current range
- * @param {float} istop Upper bound of the value's current range
- * @param {float} ostart Lower bound of the value's target range
- * @param {float} ostop Upper bound of the value's target range
- *
- * @returns {float}
- *
- * @see norm
- * @see lerp
- */
- p.map = function(value, istart, istop, ostart, ostop) {
- return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
- };
-
- /**
- * Determines the largest value in a sequence of numbers.
- *
- * @param {int|float} value1 int or float
- * @param {int|float} value2 int or float
- * @param {int|float} value3 int or float
- * @param {int|float} array int or float array
- *
- * @returns {int|float}
- *
- * @see min
- */
- p.max = function() {
- if (arguments.length === 2) {
- return arguments[0] < arguments[1] ? arguments[1] : arguments[0];
- }
- var numbers = arguments.length === 1 ? arguments[0] : arguments; // if single argument, array is used
- if (! ("length" in numbers && numbers.length > 0)) {
- throw "Non-empty array is expected";
- }
- var max = numbers[0],
- count = numbers.length;
- for (var i = 1; i < count; ++i) {
- if (max < numbers[i]) {
- max = numbers[i];
- }
- }
- return max;
- };
-
- /**
- * Determines the smallest value in a sequence of numbers.
- *
- * @param {int|float} value1 int or float
- * @param {int|float} value2 int or float
- * @param {int|float} value3 int or float
- * @param {int|float} array int or float array
- *
- * @returns {int|float}
- *
- * @see max
- */
- p.min = function() {
- if (arguments.length === 2) {
- return arguments[0] < arguments[1] ? arguments[0] : arguments[1];
- }
- var numbers = arguments.length === 1 ? arguments[0] : arguments; // if single argument, array is used
- if (! ("length" in numbers && numbers.length > 0)) {
- throw "Non-empty array is expected";
- }
- var min = numbers[0],
- count = numbers.length;
- for (var i = 1; i < count; ++i) {
- if (min > numbers[i]) {
- min = numbers[i];
- }
- }
- return min;
- };
-
- /**
- * Normalizes a number from another range into a value between 0 and 1.
- * Identical to map(value, low, high, 0, 1);
- * Numbers outside the range are not clamped to 0 and 1, because out-of-range
- * values are often intentional and useful.
- *
- * @param {float} aNumber The incoming value to be converted
- * @param {float} low Lower bound of the value's current range
- * @param {float} high Upper bound of the value's current range
- *
- * @returns {float}
- *
- * @see map
- * @see lerp
- */
- p.norm = function(aNumber, low, high) {
- return (aNumber - low) / (high - low);
- };
-
- /**
- * Squares a number (multiplies a number by itself). The result is always a positive number,
- * as multiplying two negative numbers always yields a positive result. For example, -1 * -1 = 1.
- *
- * @param {float} value int or float
- *
- * @returns {float}
- *
- * @see sqrt
- */
- p.sq = function(aNumber) {
- return aNumber * aNumber;
- };
-
- /**
- * Converts a radian measurement to its corresponding value in degrees. Radians and degrees are two ways of
- * measuring the same thing. There are 360 degrees in a circle and 2*PI radians in a circle. For example,
- * 90 degrees = PI/2 = 1.5707964. All trigonometric methods in Processing require their parameters to be specified in radians.
- *
- * @param {int|float} value an angle in radians
- *
- * @returns {float}
- *
- * @see radians
- */
- p.degrees = function(aAngle) {
- return (aAngle * 180) / Math.PI;
- };
-
- /**
- * Generates random numbers. Each time the random() function is called, it returns an unexpected value within
- * the specified range. If one parameter is passed to the function it will return a float between zero and the
- * value of the high parameter. The function call random(5) returns values between 0 and 5 (starting at zero,
- * up to but not including 5). If two parameters are passed, it will return a float with a value between the
- * parameters. The function call random(-5, 10.2) returns values starting at -5 up to (but not including) 10.2.
- * To convert a floating-point random number to an integer, use the int() function.
- *
- * @param {int|float} value1 if one parameter is used, the top end to random from, if two params the low end
- * @param {int|float} value2 the top end of the random range
- *
- * @returns {float}
- *
- * @see randomSeed
- * @see noise
- */
- p.random = function() {
- if(arguments.length === 0) {
- return internalRandomGenerator();
- }
- if(arguments.length === 1) {
- return internalRandomGenerator() * arguments[0];
- }
- var aMin = arguments[0], aMax = arguments[1];
- return internalRandomGenerator() * (aMax - aMin) + aMin;
- };
-
- // Pseudo-random generator
- function Marsaglia(i1, i2) {
- // from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c
- var z=i1 || 362436069, w= i2 || 521288629;
- var intGenerator = function() {
- z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF;
- w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF;
- return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF;
- };
-
- this.doubleGenerator = function() {
- var i = intGenerator() / 4294967296;
- return i < 0 ? 1 + i : i;
- };
- this.intGenerator = intGenerator;
- }
-
- Marsaglia.createRandomized = function() {
- var now = new Date();
- return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF);
- };
-
- /**
- * Sets the seed value for random(). By default, random() produces different results each time the
- * program is run. Set the value parameter to a constant to return the same pseudo-random numbers
- * each time the software is run.
- *
- * @param {int|float} seed int
- *
- * @see random
- * @see noise
- * @see noiseSeed
- */
- p.randomSeed = function(seed) {
- internalRandomGenerator = (new Marsaglia(seed, (seed<<16)+(seed>>16))).doubleGenerator;
- this.haveNextNextGaussian = false;
- };
-
- /**
- * Returns a float from a random series of numbers having a mean of 0 and standard deviation of 1. Each time
- * the randomGaussian() function is called, it returns a number fitting a Gaussian, or normal, distribution.
- * There is theoretically no minimum or maximum value that randomGaussian() might return. Rather, there is just a
- * very low probability that values far from the mean will be returned; and a higher probability that numbers
- * near the mean will be returned.
- *
- * @returns {float}
- *
- * @see random
- * @see noise
- */
- p.randomGaussian = function() {
- if (this.haveNextNextGaussian) {
- this.haveNextNextGaussian = false;
- return this.nextNextGaussian;
- }
- var v1, v2, s;
- do {
- v1 = 2 * internalRandomGenerator() - 1; // between -1.0 and 1.0
- v2 = 2 * internalRandomGenerator() - 1; // between -1.0 and 1.0
- s = v1 * v1 + v2 * v2;
- }
- while (s >= 1 || s === 0);
-
- var multiplier = Math.sqrt(-2 * Math.log(s) / s);
- this.nextNextGaussian = v2 * multiplier;
- this.haveNextNextGaussian = true;
-
- return v1 * multiplier;
- };
-
- // Noise functions and helpers
- function PerlinNoise(seed) {
- var rnd = seed !== undef ? new Marsaglia(seed, (seed<<16)+(seed>>16)) : Marsaglia.createRandomized();
- var i, j;
- // http://www.noisemachine.com/talk1/17b.html
- // http://mrl.nyu.edu/~perlin/noise/
- // generate permutation
- var perm = new Uint8Array(512);
- for(i=0;i<256;++i) { perm[i] = i; }
- for(i=0;i<256;++i) {
- // NOTE: we can only do this because we've made sure the Marsaglia generator
- // gives us numbers where the last byte in a pseudo-random number is
- // still pseudo-random. If no 2nd argument is passed in the constructor,
- // that is no longer the case and this pair swap will always run identically.
- var t = perm[j = rnd.intGenerator() & 0xFF];
- perm[j] = perm[i];
- perm[i] = t;
- }
- // copy to avoid taking mod in perm[0];
- for(i=0;i<256;++i) { perm[i + 256] = perm[i]; }
-
- function grad3d(i,x,y,z) {
- var h = i & 15; // convert into 12 gradient directions
- var u = h<8 ? x : y,
- v = h<4 ? y : h===12||h===14 ? x : z;
- return ((h&1) === 0 ? u : -u) + ((h&2) === 0 ? v : -v);
- }
-
- function grad2d(i,x,y) {
- var v = (i & 1) === 0 ? x : y;
- return (i&2) === 0 ? -v : v;
- }
-
- function grad1d(i,x) {
- return (i&1) === 0 ? -x : x;
- }
-
- function lerp(t,a,b) { return a + t * (b - a); }
-
- this.noise3d = function(x, y, z) {
- var X = Math.floor(x)&255, Y = Math.floor(y)&255, Z = Math.floor(z)&255;
- x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
- var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y, fz = (3-2*z)*z*z;
- var p0 = perm[X]+Y, p00 = perm[p0] + Z, p01 = perm[p0 + 1] + Z,
- p1 = perm[X + 1] + Y, p10 = perm[p1] + Z, p11 = perm[p1 + 1] + Z;
- return lerp(fz,
- lerp(fy, lerp(fx, grad3d(perm[p00], x, y, z), grad3d(perm[p10], x-1, y, z)),
- lerp(fx, grad3d(perm[p01], x, y-1, z), grad3d(perm[p11], x-1, y-1,z))),
- lerp(fy, lerp(fx, grad3d(perm[p00 + 1], x, y, z-1), grad3d(perm[p10 + 1], x-1, y, z-1)),
- lerp(fx, grad3d(perm[p01 + 1], x, y-1, z-1), grad3d(perm[p11 + 1], x-1, y-1,z-1))));
- };
-
- this.noise2d = function(x, y) {
- var X = Math.floor(x)&255, Y = Math.floor(y)&255;
- x -= Math.floor(x); y -= Math.floor(y);
- var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y;
- var p0 = perm[X]+Y, p1 = perm[X + 1] + Y;
- return lerp(fy,
- lerp(fx, grad2d(perm[p0], x, y), grad2d(perm[p1], x-1, y)),
- lerp(fx, grad2d(perm[p0 + 1], x, y-1), grad2d(perm[p1 + 1], x-1, y-1)));
- };
-
- this.noise1d = function(x) {
- var X = Math.floor(x)&255;
- x -= Math.floor(x);
- var fx = (3-2*x)*x*x;
- return lerp(fx, grad1d(perm[X], x), grad1d(perm[X+1], x-1));
- };
- }
-
- // processing defaults
- var noiseProfile = { generator: undef, octaves: 4, fallout: 0.5, seed: undef};
-
- /**
- * Returns the Perlin noise value at specified coordinates. Perlin noise is a random sequence
- * generator producing a more natural ordered, harmonic succession of numbers compared to the
- * standard random() function. It was invented by Ken Perlin in the 1980s and been used since
- * in graphical applications to produce procedural textures, natural motion, shapes, terrains etc.
- * The main difference to the random() function is that Perlin noise is defined in an infinite
- * n-dimensional space where each pair of coordinates corresponds to a fixed semi-random value
- * (fixed only for the lifespan of the program). The resulting value will always be between 0.0
- * and 1.0. Processing can compute 1D, 2D and 3D noise, depending on the number of coordinates
- * given. The noise value can be animated by moving through the noise space as demonstrated in
- * the example above. The 2nd and 3rd dimension can also be interpreted as time.
- * The actual noise is structured similar to an audio signal, in respect to the function's use
- * of frequencies. Similar to the concept of harmonics in physics, perlin noise is computed over
- * several octaves which are added together for the final result.
- * Another way to adjust the character of the resulting sequence is the scale of the input
- * coordinates. As the function works within an infinite space the value of the coordinates
- * doesn't matter as such, only the distance between successive coordinates does (eg. when using
- * noise() within a loop). As a general rule the smaller the difference between coordinates, the
- * smoother the resulting noise sequence will be. Steps of 0.005-0.03 work best for most applications,
- * but this will differ depending on use.
- *
- * @param {float} x x coordinate in noise space
- * @param {float} y y coordinate in noise space
- * @param {float} z z coordinate in noise space
- *
- * @returns {float}
- *
- * @see random
- * @see noiseDetail
- */
- p.noise = function(x, y, z) {
- if(noiseProfile.generator === undef) {
- // caching
- noiseProfile.generator = new PerlinNoise(noiseProfile.seed);
- }
- var generator = noiseProfile.generator;
- var effect = 1, k = 1, sum = 0;
- for(var i=0; i<noiseProfile.octaves; ++i) {
- effect *= noiseProfile.fallout;
- switch (arguments.length) {
- case 1:
- sum += effect * (1 + generator.noise1d(k*x))/2; break;
- case 2:
- sum += effect * (1 + generator.noise2d(k*x, k*y))/2; break;
- case 3:
- sum += effect * (1 + generator.noise3d(k*x, k*y, k*z))/2; break;
- }
- k *= 2;
- }
- return sum;
- };
-
- /**
- * Adjusts the character and level of detail produced by the Perlin noise function.
- * Similar to harmonics in physics, noise is computed over several octaves. Lower octaves
- * contribute more to the output signal and as such define the overal intensity of the noise,
- * whereas higher octaves create finer grained details in the noise sequence. By default,
- * noise is computed over 4 octaves with each octave contributing exactly half than its
- * predecessor, starting at 50% strength for the 1st octave. This falloff amount can be
- * changed by adding an additional function parameter. Eg. a falloff factor of 0.75 means
- * each octave will now have 75% impact (25% less) of the previous lower octave. Any value
- * between 0.0 and 1.0 is valid, however note that values greater than 0.5 might result in
- * greater than 1.0 values returned by noise(). By changing these parameters, the signal
- * created by the noise() function can be adapted to fit very specific needs and characteristics.
- *
- * @param {int} octaves number of octaves to be used by the noise() function
- * @param {float} falloff falloff factor for each octave
- *
- * @see noise
- */
- p.noiseDetail = function(octaves, fallout) {
- noiseProfile.octaves = octaves;
- if(fallout !== undef) {
- noiseProfile.fallout = fallout;
- }
- };
-
- /**
- * Sets the seed value for noise(). By default, noise() produces different results each
- * time the program is run. Set the value parameter to a constant to return the same
- * pseudo-random numbers each time the software is run.
- *
- * @param {int} seed int
- *
- * @returns {float}
- *
- * @see random
- * @see radomSeed
- * @see noise
- * @see noiseDetail
- */
- p.noiseSeed = function(seed) {
- noiseProfile.seed = seed;
- noiseProfile.generator = undef;
- };
- };
-
- },{}],24:[function(require,module,exports){
- /**
- * Common functions traditionally on "p" that should be class functions
- * that get bound to "p" when an instance is actually built, instead.
- */
- module.exports = (function commonFunctions(undef) {
-
- var CommonFunctions = {
- /**
- * Remove whitespace characters from the beginning and ending
- * of a String or a String array. Works like String.trim() but includes the
- * unicode nbsp character as well. If an array is passed in the function will return a new array not effecting the array passed in.
- *
- * @param {String} str the string to trim
- * @param {String[]} str the string array to trim
- *
- * @return {String|String[]} retrurns a string or an array will removed whitespaces
- */
- trim: function(str) {
- if (str instanceof Array) {
- var arr = [];
- for (var i = 0; i < str.length; i++) {
- arr.push(str[i].replace(/^\s*/, '').replace(/\s*$/, '').replace(/\r*$/, ''));
- }
- return arr;
- }
- return str.replace(/^\s*/, '').replace(/\s*$/, '').replace(/\r*$/, '');
- },
-
- /**
- * Converts a degree measurement to its corresponding value in radians. Radians and degrees are two ways of
- * measuring the same thing. There are 360 degrees in a circle and 2*PI radians in a circle. For example,
- * 90 degrees = PI/2 = 1.5707964. All trigonometric methods in Processing require their parameters to be specified in radians.
- *
- * @param {int|float} value an angle in radians
- *
- * @returns {float}
- *
- * @see degrees
- */
- radians: function(aAngle) {
- return (aAngle / 180) * Math.PI;
- },
-
- /**
- * Number-to-String formatting function. Prepends "plus" or "minus" depending
- * on whether the value is positive or negative, respectively, after padding
- * the value with zeroes on the left and right, the number of zeroes used dictated
- * by the values 'leftDigits' and 'rightDigits'. 'value' cannot be an array.
- *
- * @param {int|float} value the number to format
- * @param {String} plus the prefix for positive numbers
- * @param {String} minus the prefix for negative numbers
- * @param {int} left number of digits to the left of the decimal point
- * @param {int} right number of digits to the right of the decimal point
- * @param {String} group string delimited for groups, such as the comma in "1,000"
- *
- * @returns {String or String[]}
- *
- * @see nfCore
- */
- nfCoreScalar: function (value, plus, minus, leftDigits, rightDigits, group) {
- var sign = (value < 0) ? minus : plus;
- var autoDetectDecimals = rightDigits === 0;
- var rightDigitsOfDefault = (rightDigits === undef || rightDigits < 0) ? 0 : rightDigits;
-
- var absValue = Math.abs(value);
- if (autoDetectDecimals) {
- rightDigitsOfDefault = 1;
- absValue *= 10;
- while (Math.abs(Math.round(absValue) - absValue) > 1e-6 && rightDigitsOfDefault < 7) {
- ++rightDigitsOfDefault;
- absValue *= 10;
- }
- } else if (rightDigitsOfDefault !== 0) {
- absValue *= Math.pow(10, rightDigitsOfDefault);
- }
-
- // Using Java's default rounding policy HALF_EVEN. This policy is based
- // on the idea that 0.5 values round to the nearest even number, and
- // everything else is rounded normally.
- var number, doubled = absValue * 2;
- if (Math.floor(absValue) === absValue) {
- number = absValue;
- } else if (Math.floor(doubled) === doubled) {
- var floored = Math.floor(absValue);
- number = floored + (floored % 2);
- } else {
- number = Math.round(absValue);
- }
-
- var buffer = "";
- var totalDigits = leftDigits + rightDigitsOfDefault;
- while (totalDigits > 0 || number > 0) {
- totalDigits--;
- buffer = "" + (number % 10) + buffer;
- number = Math.floor(number / 10);
- }
- if (group !== undef) {
- var i = buffer.length - 3 - rightDigitsOfDefault;
- while(i > 0) {
- buffer = buffer.substring(0,i) + group + buffer.substring(i);
- i-=3;
- }
- }
- if (rightDigitsOfDefault > 0) {
- return sign + buffer.substring(0, buffer.length - rightDigitsOfDefault) +
- "." + buffer.substring(buffer.length - rightDigitsOfDefault, buffer.length);
- }
- return sign + buffer;
- },
-
- /**
- * Number-to-String formatting function. Prepends "plus" or "minus" depending
- * on whether the value is positive or negative, respectively, after padding
- * the value with zeroes on the left and right, the number of zeroes used dictated
- * by the values 'leftDigits' and 'rightDigits'. 'value' can be an array;
- * if the input is an array, each value in it is formatted separately, and
- * an array with formatted values is returned.
- *
- * @param {int|int[]|float|float[]} value the number(s) to format
- * @param {String} plus the prefix for positive numbers
- * @param {String} minus the prefix for negative numbers
- * @param {int} left number of digits to the left of the decimal point
- * @param {int} right number of digits to the right of the decimal point
- * @param {String} group string delimited for groups, such as the comma in "1,000"
- *
- * @returns {String or String[]}
- *
- * @see nfCoreScalar
- */
- nfCore: function(value, plus, minus, leftDigits, rightDigits, group) {
- if (value instanceof Array) {
- var arr = [];
- for (var i = 0, len = value.length; i < len; i++) {
- arr.push(CommonFunctions.nfCoreScalar(value[i], plus, minus, leftDigits, rightDigits, group));
- }
- return arr;
- }
- return CommonFunctions.nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group);
- },
-
- /**
- * Utility function for formatting numbers into strings. There are two versions, one for
- * formatting floats and one for formatting ints. The values for the digits, left, and
- * right parameters should always be positive integers.
- * As shown in the above example, nf() is used to add zeros to the left and/or right
- * of a number. This is typically for aligning a list of numbers. To remove digits from
- * a floating-point number, use the int(), ceil(), floor(), or round() functions.
- *
- * @param {int|int[]|float|float[]} value the number(s) to format
- * @param {int} left number of digits to the left of the decimal point
- * @param {int} right number of digits to the right of the decimal point
- *
- * @returns {String or String[]}
- *
- * @see nfs
- * @see nfp
- * @see nfc
- */
- nf: function(value, leftDigits, rightDigits) {
- return CommonFunctions.nfCore(value, "", "-", leftDigits, rightDigits);
- },
-
- /**
- * Utility function for formatting numbers into strings. Similar to nf() but leaves a blank space in front
- * of positive numbers so they align with negative numbers in spite of the minus symbol. There are two
- * versions, one for formatting floats and one for formatting ints. The values for the digits, left,
- * and right parameters should always be positive integers.
- *
- * @param {int|int[]|float|float[]} value the number(s) to format
- * @param {int} left number of digits to the left of the decimal point
- * @param {int} right number of digits to the right of the decimal point
- *
- * @returns {String or String[]}
- *
- * @see nf
- * @see nfp
- * @see nfc
- */
- nfs: function(value, leftDigits, rightDigits) {
- return CommonFunctions.nfCore(value, " ", "-", leftDigits, rightDigits);
- },
-
- /**
- * Utility function for formatting numbers into strings. Similar to nf() but puts a "+" in front of
- * positive numbers and a "-" in front of negative numbers. There are two versions, one for formatting
- * floats and one for formatting ints. The values for the digits, left, and right parameters should
- * always be positive integers.
- *
- * @param {int|int[]|float|float[]} value the number(s) to format
- * @param {int} left number of digits to the left of the decimal point
- * @param {int} right number of digits to the right of the decimal point
- *
- * @returns {String or String[]}
- *
- * @see nfs
- * @see nf
- * @see nfc
- */
- nfp: function(value, leftDigits, rightDigits) {
- return CommonFunctions.nfCore(value, "+", "-", leftDigits, rightDigits);
- },
-
- /**
- * Utility function for formatting numbers into strings and placing appropriate commas to mark
- * units of 1000. There are two versions, one for formatting ints and one for formatting an array
- * of ints. The value for the digits parameter should always be a positive integer.
- *
- * @param {int|int[]|float|float[]} value the number(s) to format
- * @param {int} left number of digits to the left of the decimal point
- * @param {int} right number of digits to the right of the decimal point
- *
- * @returns {String or String[]}
- *
- * @see nf
- * @see nfs
- * @see nfp
- */
- nfc: function(value, rightDigits) {
- return CommonFunctions.nfCore(value, "", "-", 0, rightDigits, ",");
- },
-
- // used to bind all common functions to "p"
- withCommonFunctions: function withCommonFunctions(p) {
- ["trim", "radians", "nf", "nfs", "nfp", "nfc"].forEach(function(f){
- p[f] = CommonFunctions[f];
- });
- }
- };
-
- return CommonFunctions;
- }());
-
- },{}],25:[function(require,module,exports){
- /**
- * Touch and Mouse event handling
- */
- module.exports = function withTouch(p, curElement, attachEventHandler, document, PConstants, undef) {
-
- /**
- * Determine the location of the (mouse) pointer.
- */
- function calculateOffset(curElement, event) {
- var element = curElement,
- offsetX = 0,
- offsetY = 0;
-
- p.pmouseX = p.mouseX;
- p.pmouseY = p.mouseY;
-
- // Find element offset
- if (element.offsetParent) {
- do {
- offsetX += element.offsetLeft;
- offsetY += element.offsetTop;
- } while (!!(element = element.offsetParent));
- }
-
- // Find Scroll offset
- element = curElement;
- do {
- offsetX -= element.scrollLeft || 0;
- offsetY -= element.scrollTop || 0;
- } while (!!(element = element.parentNode));
-
- // Get padding and border style widths for mouse offsets
- var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
- if (document.defaultView && document.defaultView.getComputedStyle) {
- stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(curElement, null).paddingLeft, 10) || 0;
- stylePaddingTop = parseInt(document.defaultView.getComputedStyle(curElement, null).paddingTop, 10) || 0;
- styleBorderLeft = parseInt(document.defaultView.getComputedStyle(curElement, null).borderLeftWidth, 10) || 0;
- styleBorderTop = parseInt(document.defaultView.getComputedStyle(curElement, null).borderTopWidth, 10) || 0;
- }
-
- // Add padding and border style widths to offset
- offsetX += stylePaddingLeft;
- offsetY += stylePaddingTop;
-
- offsetX += styleBorderLeft;
- offsetY += styleBorderTop;
-
- // Take into account any scrolling done
- offsetX += window.pageXOffset;
- offsetY += window.pageYOffset;
-
- return {'X':offsetX,'Y':offsetY};
- }
-
- // simple relative position
- function updateMousePosition(curElement, event) {
- var offset = calculateOffset(curElement, event);
- // Dropping support for IE clientX and clientY, switching to pageX and pageY
- // so we don't have to calculate scroll offset.
- // Removed in ticket #184. See rev: 2f106d1c7017fed92d045ba918db47d28e5c16f4
- p.mouseX = event.pageX - offset.X;
- p.mouseY = event.pageY - offset.Y;
- }
-
- /**
- * Return a TouchEvent with canvas-specific x/y co-ordinates
- */
- function addTouchEventOffset(t) {
- var offset = calculateOffset(t.changedTouches[0].target, t.changedTouches[0]),
- i;
-
- for (i = 0; i < t.touches.length; i++) {
- var touch = t.touches[i];
- touch.offsetX = touch.pageX - offset.X;
- touch.offsetY = touch.pageY - offset.Y;
- }
- for (i = 0; i < t.targetTouches.length; i++) {
- var targetTouch = t.targetTouches[i];
- targetTouch.offsetX = targetTouch.pageX - offset.X;
- targetTouch.offsetY = targetTouch.pageY - offset.Y;
- }
- for (i = 0; i < t.changedTouches.length; i++) {
- var changedTouch = t.changedTouches[i];
- changedTouch.offsetX = changedTouch.pageX - offset.X;
- changedTouch.offsetY = changedTouch.pageY - offset.Y;
- }
-
- return t;
- }
-
- /**
- * Touch event support.
- */
- attachEventHandler(curElement, "touchstart", function (t) {
- // Removes unwanted behaviour of the canvas when touching canvas
- curElement.setAttribute("style","-webkit-user-select: none");
- curElement.setAttribute("onclick","void(0)");
- curElement.setAttribute("style","-webkit-tap-highlight-color:rgba(0,0,0,0)");
- // Loop though eventHandlers and remove mouse listeners
- for (var i=0, ehl=eventHandlers.length; i<ehl; i++) {
- var type = eventHandlers[i].type;
- // Have this function remove itself from the eventHandlers list too
- if (type === "mouseout" || type === "mousemove" ||
- type === "mousedown" || type === "mouseup" ||
- type === "DOMMouseScroll" || type === "mousewheel" || type === "touchstart") {
- detachEventHandler(eventHandlers[i]);
- }
- }
-
- // If there are any native touch events defined in the sketch, connect all of them
- // Otherwise, connect all of the emulated mouse events
- if (p.touchStart !== undef || p.touchMove !== undef ||
- p.touchEnd !== undef || p.touchCancel !== undef) {
- attachEventHandler(curElement, "touchstart", function(t) {
- if (p.touchStart !== undef) {
- t = addTouchEventOffset(t);
- p.touchStart(t);
- }
- });
-
- attachEventHandler(curElement, "touchmove", function(t) {
- if (p.touchMove !== undef) {
- t.preventDefault(); // Stop the viewport from scrolling
- t = addTouchEventOffset(t);
- p.touchMove(t);
- }
- });
-
- attachEventHandler(curElement, "touchend", function(t) {
- if (p.touchEnd !== undef) {
- t = addTouchEventOffset(t);
- p.touchEnd(t);
- }
- });
-
- attachEventHandler(curElement, "touchcancel", function(t) {
- if (p.touchCancel !== undef) {
- t = addTouchEventOffset(t);
- p.touchCancel(t);
- }
- });
-
- } else {
- // Emulated touch start/mouse down event
- attachEventHandler(curElement, "touchstart", function(e) {
- updateMousePosition(curElement, e.touches[0]);
-
- p.__mousePressed = true;
- p.mouseDragging = false;
- p.mouseButton = PConstants.LEFT;
-
- if (typeof p.mousePressed === "function") {
- p.mousePressed();
- }
- });
-
- // Emulated touch move/mouse move event
- attachEventHandler(curElement, "touchmove", function(e) {
- e.preventDefault();
- updateMousePosition(curElement, e.touches[0]);
-
- if (typeof p.mouseMoved === "function" && !p.__mousePressed) {
- p.mouseMoved();
- }
- if (typeof p.mouseDragged === "function" && p.__mousePressed) {
- p.mouseDragged();
- p.mouseDragging = true;
- }
- });
-
- // Emulated touch up/mouse up event
- attachEventHandler(curElement, "touchend", function(e) {
- p.__mousePressed = false;
-
- if (typeof p.mouseClicked === "function" && !p.mouseDragging) {
- p.mouseClicked();
- }
-
- if (typeof p.mouseReleased === "function") {
- p.mouseReleased();
- }
- });
- }
-
- // Refire the touch start event we consumed in this function
- curElement.dispatchEvent(t);
- });
-
- /**
- * Context menu toggles. Most often you will not want the
- * browser's context menu to show on a right click, but
- * sometimes, you do, so we add two unofficial functions
- * that can be used to trigger context menu behaviour.
- */
- (function() {
- var enabled = true,
- contextMenu = function(e) {
- e.preventDefault();
- e.stopPropagation();
- };
-
- p.disableContextMenu = function() {
- if (!enabled) {
- return;
- }
- attachEventHandler(curElement, 'contextmenu', contextMenu);
- enabled = false;
- };
-
- p.enableContextMenu = function() {
- if (enabled) {
- return;
- }
- detachEventHandler({elem: curElement, type: 'contextmenu', fn: contextMenu});
- enabled = true;
- };
- }());
-
- /**
- * Mouse moved or dragged
- */
- attachEventHandler(curElement, "mousemove", function(e) {
- updateMousePosition(curElement, e);
- if (typeof p.mouseMoved === "function" && !p.__mousePressed) {
- p.mouseMoved();
- }
- if (typeof p.mouseDragged === "function" && p.__mousePressed) {
- p.mouseDragged();
- p.mouseDragging = true;
- }
- });
-
- /**
- * Unofficial mouse-out handling
- */
- attachEventHandler(curElement, "mouseout", function(e) {
- if (typeof p.mouseOut === "function") {
- p.mouseOut();
- }
- });
-
- /**
- * Mouse over
- */
- attachEventHandler(curElement, "mouseover", function(e) {
- updateMousePosition(curElement, e);
- if (typeof p.mouseOver === "function") {
- p.mouseOver();
- }
- });
-
- /**
- * Disable browser's default handling for click-drag of a canvas.
- */
- curElement.onmousedown = function () {
- // make sure focus happens, but nothing else
- curElement.focus();
- return false;
- };
-
- /**
- * Mouse pressed or drag
- */
- attachEventHandler(curElement, "mousedown", function(e) {
- p.__mousePressed = true;
- p.mouseDragging = false;
- switch (e.which) {
- case 1:
- p.mouseButton = PConstants.LEFT;
- break;
- case 2:
- p.mouseButton = PConstants.CENTER;
- break;
- case 3:
- p.mouseButton = PConstants.RIGHT;
- break;
- }
-
- if (typeof p.mousePressed === "function") {
- p.mousePressed();
- }
- });
-
- /**
- * Mouse clicked or released
- */
- attachEventHandler(curElement, "mouseup", function(e) {
- p.__mousePressed = false;
-
- if (typeof p.mouseClicked === "function" && !p.mouseDragging) {
- p.mouseClicked();
- }
-
- if (typeof p.mouseReleased === "function") {
- p.mouseReleased();
- }
- });
-
- /**
- * Unofficial scroll wheel handling.
- */
- var mouseWheelHandler = function(e) {
- var delta = 0;
-
- if (e.wheelDelta) {
- delta = e.wheelDelta / 120;
- if (window.opera) {
- delta = -delta;
- }
- } else if (e.detail) {
- delta = -e.detail / 3;
- }
-
- p.mouseScroll = delta;
-
- if (delta && typeof p.mouseScrolled === 'function') {
- p.mouseScrolled();
- }
- };
-
- // Support Gecko and non-Gecko scroll events
- attachEventHandler(document, 'DOMMouseScroll', mouseWheelHandler);
- attachEventHandler(document, 'mousewheel', mouseWheelHandler);
-
- };
-
- },{}],26:[function(require,module,exports){
- /**
- * The parser for turning Processing syntax into Pjs JavaScript.
- * This code is not trivial; unless you know what you're doing,
- * you shouldn't be changing things in here =)
- */
- module.exports = function setupParser(Processing, options) {
-
- var defaultScope = options.defaultScope,
- PConstants = defaultScope.PConstants,
- aFunctions = options.aFunctions,
- Browser = options.Browser,
- document = Browser.document,
- undef;
-
- // Processing global methods and constants for the parser
- function getGlobalMembers() {
- // The names array contains the names of everything that is inside "p."
- // When something new is added to "p." it must also be added to this list.
- var names = [ /* this code is generated by jsglobals.js */
- "abs", "acos", "alpha", "ambient", "ambientLight", "append", "applyMatrix",
- "arc", "arrayCopy", "asin", "atan", "atan2", "background", "beginCamera",
- "beginDraw", "beginShape", "bezier", "bezierDetail", "bezierPoint",
- "bezierTangent", "bezierVertex", "binary", "blend", "blendColor",
- "blit_resize", "blue", "box", "breakShape", "brightness",
- "camera", "ceil", "Character", "color", "colorMode",
- "concat", "constrain", "copy", "cos", "createFont",
- "createGraphics", "createImage", "cursor", "curve", "curveDetail",
- "curvePoint", "curveTangent", "curveTightness", "curveVertex", "day",
- "degrees", "directionalLight", "disableContextMenu",
- "dist", "draw", "ellipse", "ellipseMode", "emissive", "enableContextMenu",
- "endCamera", "endDraw", "endShape", "exit", "exp", "expand", "externals",
- "fill", "filter", "floor", "focused", "frameCount", "frameRate", "frustum",
- "get", "glyphLook", "glyphTable", "green", "height", "hex", "hint", "hour",
- "hue", "image", "imageMode", "intersect", "join", "key",
- "keyCode", "keyPressed", "keyReleased", "keyTyped", "lerp", "lerpColor",
- "lightFalloff", "lights", "lightSpecular", "line", "link", "loadBytes",
- "loadFont", "loadGlyphs", "loadImage", "loadPixels", "loadShape", "loadXML",
- "loadStrings", "log", "loop", "mag", "map", "match", "matchAll", "max",
- "millis", "min", "minute", "mix", "modelX", "modelY", "modelZ", "modes",
- "month", "mouseButton", "mouseClicked", "mouseDragged", "mouseMoved",
- "mouseOut", "mouseOver", "mousePressed", "mouseReleased", "mouseScroll",
- "mouseScrolled", "mouseX", "mouseY", "name", "nf", "nfc", "nfp", "nfs",
- "noCursor", "noFill", "noise", "noiseDetail", "noiseSeed", "noLights",
- "noLoop", "norm", "normal", "noSmooth", "noStroke", "noTint", "ortho",
- "param", "parseBoolean", "parseByte", "parseChar", "parseFloat",
- "parseInt", "parseXML", "peg", "perspective", "PImage", "pixels",
- "PMatrix2D", "PMatrix3D", "PMatrixStack", "pmouseX", "pmouseY", "point",
- "pointLight", "popMatrix", "popStyle", "pow", "print", "printCamera",
- "println", "printMatrix", "printProjection", "PShape", "PShapeSVG",
- "pushMatrix", "pushStyle", "quad", "radians", "random", "randomGaussian",
- "randomSeed", "rect", "rectMode", "red", "redraw", "requestImage",
- "resetMatrix", "reverse", "rotate", "rotateX", "rotateY", "rotateZ",
- "round", "saturation", "save", "saveFrame", "saveStrings", "scale",
- "screenX", "screenY", "screenZ", "second", "set", "setup", "shape",
- "shapeMode", "shared", "shearX", "shearY", "shininess", "shorten", "sin", "size", "smooth",
- "sort", "specular", "sphere", "sphereDetail", "splice", "split",
- "splitTokens", "spotLight", "sq", "sqrt", "status", "str", "stroke",
- "strokeCap", "strokeJoin", "strokeWeight", "subset", "tan", "text",
- "textAlign", "textAscent", "textDescent", "textFont", "textLeading",
- "textMode", "textSize", "texture", "textureMode", "textWidth", "tint", "toImageData",
- "touchCancel", "touchEnd", "touchMove", "touchStart", "translate", "transform",
- "triangle", "trim", "unbinary", "unhex", "updatePixels", "use3DContext",
- "vertex", "width", "XMLElement", "XML", "year", "__contains", "__equals",
- "__equalsIgnoreCase", "__frameRate", "__hashCode", "__int_cast",
- "__instanceof", "__keyPressed", "__mousePressed", "__printStackTrace",
- "__replace", "__replaceAll", "__replaceFirst", "__toCharArray", "__split",
- "__codePointAt", "__startsWith", "__endsWith", "__matches"];
-
- // custom functions and properties are added here
- if(aFunctions) {
- Object.keys(aFunctions).forEach(function(name) {
- names.push(name);
- });
- }
-
- // custom libraries that were attached to Processing
- var members = {};
- var i, l;
- for (i = 0, l = names.length; i < l ; ++i) {
- members[names[i]] = null;
- }
- for (var lib in Processing.lib) {
- if (Processing.lib.hasOwnProperty(lib)) {
- if (Processing.lib[lib].exports) {
- var exportedNames = Processing.lib[lib].exports;
- for (i = 0, l = exportedNames.length; i < l; ++i) {
- members[exportedNames[i]] = null;
- }
- }
- }
- }
- return members;
- }
-
- /*
-
- Parser converts Java-like syntax into JavaScript.
- Creates an Abstract Syntax Tree -- "Light AST" from the Java-like code.
-
- It is an object tree. The root object is created from the AstRoot class, which contains statements.
-
- A statement object can be of type: AstForStatement, AstCatchStatement, AstPrefixStatement, AstMethod, AstClass,
- AstInterface, AstFunction, AstStatementBlock and AstLabel.
-
- AstPrefixStatement can be a statement of type: if, switch, while, with, do, else, finally, return, throw, try, break, and continue.
-
- These object's toString function returns the JavaScript code for the statement.
-
- Any processing calls need "processing." prepended to them.
-
- Similarly, calls from inside classes need "$this_1.", prepended to them,
- with 1 being the depth level for inner classes.
- This includes members passed down from inheritance.
-
- The resulting code is then eval'd and run.
-
- */
-
- function parseProcessing(code) {
- var globalMembers = getGlobalMembers();
-
- // masks parentheses, brackets and braces with '"A5"'
- // where A is the bracket type, and 5 is the index in an array containing all brackets split into atoms
- // 'while(true){}' -> 'while"B1""A2"'
- // parentheses() = B, brackets[] = C and braces{} = A
- function splitToAtoms(code) {
- var atoms = [];
- var items = code.split(/([\{\[\(\)\]\}])/);
- var result = items[0];
-
- var stack = [];
- for(var i=1; i < items.length; i += 2) {
- var item = items[i];
- if(item === '[' || item === '{' || item === '(') {
- stack.push(result); result = item;
- } else if(item === ']' || item === '}' || item === ')') {
- var kind = item === '}' ? 'A' : item === ')' ? 'B' : 'C';
- var index = atoms.length; atoms.push(result + item);
- result = stack.pop() + '"' + kind + (index + 1) + '"';
- }
- result += items[i + 1];
- }
- atoms.unshift(result);
- return atoms;
- }
-
- // replaces strings and regexs keyed by index with an array of strings
- function injectStrings(code, strings) {
- return code.replace(/'(\d+)'/g, function(all, index) {
- var val = strings[index];
- if(val.charAt(0) === "/") {
- return val;
- }
- return (/^'((?:[^'\\\n])|(?:\\.[0-9A-Fa-f]*))'$/).test(val) ? "(new $p.Character(" + val + "))" : val;
- });
- }
-
- // trims off leading and trailing spaces
- // returns an object. object.left, object.middle, object.right, object.untrim
- function trimSpaces(string) {
- var m1 = /^\s*/.exec(string), result;
- if(m1[0].length === string.length) {
- result = {left: m1[0], middle: "", right: ""};
- } else {
- var m2 = /\s*$/.exec(string);
- result = {left: m1[0], middle: string.substring(m1[0].length, m2.index), right: m2[0]};
- }
- result.untrim = function(t) { return this.left + t + this.right; };
- return result;
- }
-
- // simple trim of leading and trailing spaces
- function trim(string) {
- return string.replace(/^\s+/,'').replace(/\s+$/,'');
- }
-
- function appendToLookupTable(table, array) {
- for(var i=0,l=array.length;i<l;++i) {
- table[array[i]] = null;
- }
- return table;
- }
-
- function isLookupTableEmpty(table) {
- for(var i in table) {
- if(table.hasOwnProperty(i)) {
- return false;
- }
- }
- return true;
- }
-
- function getAtomIndex(templ) { return templ.substring(2, templ.length - 1); }
-
- // remove carriage returns "\r"
- var codeWoExtraCr = code.replace(/\r\n?|\n\r/g, "\n");
-
- // masks strings and regexs with "'5'", where 5 is the index in an array containing all strings and regexs
- // also removes all comments
- var strings = [];
- var codeWoStrings = codeWoExtraCr.replace(/("(?:[^"\\\n]|\\.)*")|('(?:[^'\\\n]|\\.)*')|(([\[\(=|&!\^:?]\s*)(\/(?![*\/])(?:[^\/\\\n]|\\.)*\/[gim]*)\b)|(\/\/[^\n]*\n)|(\/\*(?:(?!\*\/)(?:.|\n))*\*\/)/g,
- function(all, quoted, aposed, regexCtx, prefix, regex, singleComment, comment) {
- var index;
- if(quoted || aposed) { // replace strings
- index = strings.length; strings.push(all);
- return "'" + index + "'";
- }
- if(regexCtx) { // replace RegExps
- index = strings.length; strings.push(regex);
- return prefix + "'" + index + "'";
- }
- // kill comments
- return comment !== "" ? " " : "\n";
- });
-
- // protect character codes from namespace collision
- codeWoStrings = codeWoStrings.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) {
- // $ = __x0024
- // _ = __x005F
- // this protects existing character codes from conversion
- // __x0024 = __x005F_x0024
- return "__x005F_x" + hexCode;
- });
-
- // convert dollar sign to character code
- codeWoStrings = codeWoStrings.replace(/\$/g, "__x0024");
-
- // Remove newlines after return statements
- codeWoStrings = codeWoStrings.replace(/return\s*[\n\r]+/g, "return ");
-
- // removes generics
- var genericsWereRemoved;
- var codeWoGenerics = codeWoStrings;
- var replaceFunc = function(all, before, types, after) {
- if(!!before || !!after) {
- return all;
- }
- genericsWereRemoved = true;
- return "";
- };
-
- do {
- genericsWereRemoved = false;
- codeWoGenerics = codeWoGenerics.replace(/([<]?)<\s*((?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?(?:\s*,\s*(?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?)*)\s*>([=]?)/g, replaceFunc);
- } while (genericsWereRemoved);
-
- var atoms = splitToAtoms(codeWoGenerics);
- var replaceContext;
- var declaredClasses = {}, currentClassId, classIdSeed = 0;
-
- function addAtom(text, type) {
- var lastIndex = atoms.length;
- atoms.push(text);
- return '"' + type + lastIndex + '"';
- }
-
- function generateClassId() {
- return "class" + (++classIdSeed);
- }
-
- function appendClass(class_, classId, scopeId) {
- class_.classId = classId;
- class_.scopeId = scopeId;
- declaredClasses[classId] = class_;
- }
-
- // functions defined below
- var transformClassBody, transformInterfaceBody, transformStatementsBlock, transformStatements, transformMain, transformExpression;
-
- var classesRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)(class|interface)\s+([A-Za-z_$][\w$]*\b)(\s+extends\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?(\s+implements\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?\s*("A\d+")/g;
- var methodsRegex = /\b((?:(?:public|private|final|protected|static|abstract|synchronized)\s+)*)((?!(?:else|new|return|throw|function|public|private|protected)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+"|;)/g;
- var fieldTest = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:else|new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*(?:"C\d+"\s*)*([=,]|$)/;
- var cstrsRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+")/g;
- var attrAndTypeRegex = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*/;
- var functionsRegex = /\bfunction(?:\s+([A-Za-z_$][\w$]*))?\s*("B\d+")\s*("A\d+")/g;
-
- // This converts classes, methods and functions into atoms, and adds them to the atoms array.
- // classes = E, methods = D and functions = H
- function extractClassesAndMethods(code) {
- var s = code;
- s = s.replace(classesRegex, function(all) {
- return addAtom(all, 'E');
- });
- s = s.replace(methodsRegex, function(all) {
- return addAtom(all, 'D');
- });
- s = s.replace(functionsRegex, function(all) {
- return addAtom(all, 'H');
- });
- return s;
- }
-
- // This converts constructors into atoms, and adds them to the atoms array.
- // constructors = G
- function extractConstructors(code, className) {
- var result = code.replace(cstrsRegex, function(all, attr, name, params, throws_, body) {
- if(name !== className) {
- return all;
- }
- return addAtom(all, 'G');
- });
- return result;
- }
-
- // AstParam contains the name of a parameter inside a function declaration
- function AstParam(name) {
- this.name = name;
- }
- AstParam.prototype.toString = function() {
- return this.name;
- };
- // AstParams contains an array of AstParam objects
- function AstParams(params, methodArgsParam) {
- this.params = params;
- this.methodArgsParam = methodArgsParam;
- }
- AstParams.prototype.getNames = function() {
- var names = [];
- for(var i=0,l=this.params.length;i<l;++i) {
- names.push(this.params[i].name);
- }
- return names;
- };
- AstParams.prototype.prependMethodArgs = function(body) {
- if (!this.methodArgsParam) {
- return body;
- }
- return "{\nvar " + this.methodArgsParam.name +
- " = Array.prototype.slice.call(arguments, " +
- this.params.length + ");\n" + body.substring(1);
- };
- AstParams.prototype.toString = function() {
- if(this.params.length === 0) {
- return "()";
- }
- var result = "(";
- for(var i=0,l=this.params.length;i<l;++i) {
- result += this.params[i] + ", ";
- }
- return result.substring(0, result.length - 2) + ")";
- };
-
- function transformParams(params) {
- var paramsWoPars = trim(params.substring(1, params.length - 1));
- var result = [], methodArgsParam = null;
- if(paramsWoPars !== "") {
- var paramList = paramsWoPars.split(",");
- for(var i=0; i < paramList.length; ++i) {
- var param = /\b([A-Za-z_$][\w$]*\b)(\s*"[ABC][\d]*")*\s*$/.exec(paramList[i]);
- if (i === paramList.length - 1 && paramList[i].indexOf('...') >= 0) {
- methodArgsParam = new AstParam(param[1]);
- break;
- }
- result.push(new AstParam(param[1]));
- }
- }
- return new AstParams(result, methodArgsParam);
- }
-
- function preExpressionTransform(expr) {
- var s = expr;
- // new type[] {...} --> {...}
- s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"C\d+")+\s*("A\d+")/g, function(all, type, init) {
- return init;
- });
- // new Runnable() {...} --> "F???"
- s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"B\d+")\s*("A\d+")/g, function(all, type, init) {
- return addAtom(all, 'F');
- });
- // function(...) { } --> "H???"
- s = s.replace(functionsRegex, function(all) {
- return addAtom(all, 'H');
- });
- // new type[?] --> createJavaArray('type', [?])
- s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*("C\d+"(?:\s*"C\d+")*)/g, function(all, type, index) {
- var args = index.replace(/"C(\d+)"/g, function(all, j) { return atoms[j]; })
- .replace(/\[\s*\]/g, "[null]").replace(/\s*\]\s*\[\s*/g, ", ");
- var arrayInitializer = "{" + args.substring(1, args.length - 1) + "}";
- var createArrayArgs = "('" + type + "', " + addAtom(arrayInitializer, 'A') + ")";
- return '$p.createJavaArray' + addAtom(createArrayArgs, 'B');
- });
- // .length() --> .length
- s = s.replace(/(\.\s*length)\s*"B\d+"/g, "$1");
- // #000000 --> 0x000000
- s = s.replace(/#([0-9A-Fa-f]{6})\b/g, function(all, digits) {
- return "0xFF" + digits;
- });
- // delete (type)???, except (int)???
- s = s.replace(/"B(\d+)"(\s*(?:[\w$']|"B))/g, function(all, index, next) {
- var atom = atoms[index];
- if(!/^\(\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\s*(?:"C\d+"\s*)*\)$/.test(atom)) {
- return all;
- }
- if(/^\(\s*int\s*\)$/.test(atom)) {
- return "(int)" + next;
- }
- var indexParts = atom.split(/"C(\d+)"/g);
- if(indexParts.length > 1) {
- // even items contains atom numbers, can check only first
- if(! /^\[\s*\]$/.test(atoms[indexParts[1]])) {
- return all; // fallback - not a cast
- }
- }
- return "" + next;
- });
- // (int)??? -> __int_cast(???)
- s = s.replace(/\(int\)([^,\]\)\}\?\:\*\+\-\/\^\|\%\&\~<\>\=]+)/g, function(all, arg) {
- var trimmed = trimSpaces(arg);
- return trimmed.untrim("__int_cast(" + trimmed.middle + ")");
- });
- // super() -> $superCstr(), super. -> $super.;
- s = s.replace(/\bsuper(\s*"B\d+")/g, "$$superCstr$1").replace(/\bsuper(\s*\.)/g, "$$super$1");
- // 000.43->0.43 and 0010f->10, but not 0010
- s = s.replace(/\b0+((\d*)(?:\.[\d*])?(?:[eE][\-\+]?\d+)?[fF]?)\b/, function(all, numberWo0, intPart) {
- if( numberWo0 === intPart) {
- return all;
- }
- return intPart === "" ? "0" + numberWo0 : numberWo0;
- });
- // 3.0f -> 3.0
- s = s.replace(/\b(\.?\d+\.?)[fF]\b/g, "$1");
- // Weird (?) parsing errors with %
- s = s.replace(/([^\s])%([^=\s])/g, "$1 % $2");
- // Since frameRate() and frameRate are different things,
- // we need to differentiate them somehow. So when we parse
- // the Processing.js source, replace frameRate so it isn't
- // confused with frameRate(), as well as keyPressed and mousePressed
- s = s.replace(/\b(frameRate|keyPressed|mousePressed)\b(?!\s*"B)/g, "__$1");
- // "boolean", "byte", "int", etc. => "parseBoolean", "parseByte", "parseInt", etc.
- s = s.replace(/\b(boolean|byte|char|float|int)\s*"B/g, function(all, name) {
- return "parse" + name.substring(0, 1).toUpperCase() + name.substring(1) + "\"B";
- });
- // "pixels" replacements:
- // pixels[i] = c => pixels.setPixel(i,c) | pixels[i] => pixels.getPixel(i)
- // pixels.length => pixels.getLength()
- // pixels = ar => pixels.set(ar) | pixels => pixels.toArray()
- s = s.replace(/\bpixels\b\s*(("C(\d+)")|\.length)?(\s*=(?!=)([^,\]\)\}]+))?/g,
- function(all, indexOrLength, index, atomIndex, equalsPart, rightSide) {
- if(index) {
- var atom = atoms[atomIndex];
- if(equalsPart) {
- return "pixels.setPixel" + addAtom("(" +atom.substring(1, atom.length - 1) +
- "," + rightSide + ")", 'B');
- }
- return "pixels.getPixel" + addAtom("(" + atom.substring(1, atom.length - 1) +
- ")", 'B');
- }
- if(indexOrLength) {
- // length
- return "pixels.getLength" + addAtom("()", 'B');
- }
- if(equalsPart) {
- return "pixels.set" + addAtom("(" + rightSide + ")", 'B');
- }
- return "pixels.toArray" + addAtom("()", 'B');
- });
- // Java method replacements for: replace, replaceAll, replaceFirst, equals, hashCode, etc.
- // xxx.replace(yyy) -> __replace(xxx, yyy)
- // "xx".replace(yyy) -> __replace("xx", yyy)
- var repeatJavaReplacement;
- function replacePrototypeMethods(all, subject, method, atomIndex) {
- var atom = atoms[atomIndex];
- repeatJavaReplacement = true;
- var trimmed = trimSpaces(atom.substring(1, atom.length - 1));
- return "__" + method + ( trimmed.middle === "" ? addAtom("(" + subject.replace(/\.\s*$/, "") + ")", 'B') :
- addAtom("(" + subject.replace(/\.\s*$/, "") + "," + trimmed.middle + ")", 'B') );
- }
- do {
- repeatJavaReplacement = false;
- s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*\.\s*(?:[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*\.\s*)*)(replace|replaceAll|replaceFirst|contains|equals|equalsIgnoreCase|hashCode|toCharArray|printStackTrace|split|startsWith|endsWith|codePointAt|matches)\s*"B(\d+)"/g,
- replacePrototypeMethods);
- } while (repeatJavaReplacement);
- // xxx instanceof yyy -> __instanceof(xxx, yyy)
- function replaceInstanceof(all, subject, type) {
- repeatJavaReplacement = true;
- return "__instanceof" + addAtom("(" + subject + ", " + type + ")", 'B');
- }
- do {
- repeatJavaReplacement = false;
- s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*(?:\.\s*[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*)*)instanceof\s+([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)/g,
- replaceInstanceof);
- } while (repeatJavaReplacement);
- // this() -> $constr()
- s = s.replace(/\bthis(\s*"B\d+")/g, "$$constr$1");
-
- return s;
- }
-
- function AstInlineClass(baseInterfaceName, body) {
- this.baseInterfaceName = baseInterfaceName;
- this.body = body;
- body.owner = this;
- }
- AstInlineClass.prototype.toString = function() {
- return "new (" + this.body + ")";
- };
-
- function transformInlineClass(class_) {
- var m = new RegExp(/\bnew\s*([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)\s*"B\d+"\s*"A(\d+)"/).exec(class_);
- var oldClassId = currentClassId, newClassId = generateClassId();
- currentClassId = newClassId;
- var uniqueClassName = m[1] + "$" + newClassId;
- var inlineClass = new AstInlineClass(uniqueClassName,
- transformClassBody(atoms[m[2]], uniqueClassName, "", "implements " + m[1]));
- appendClass(inlineClass, newClassId, oldClassId);
- currentClassId = oldClassId;
- return inlineClass;
- }
-
- function AstFunction(name, params, body) {
- this.name = name;
- this.params = params;
- this.body = body;
- }
- AstFunction.prototype.toString = function() {
- var oldContext = replaceContext;
- // saving "this." and parameters
- var names = appendToLookupTable({"this":null}, this.params.getNames());
- replaceContext = function (subject) {
- return names.hasOwnProperty(subject.name) ? subject.name : oldContext(subject);
- };
- var result = "function";
- if(this.name) {
- result += " " + this.name;
- }
- var body = this.params.prependMethodArgs(this.body.toString());
- result += this.params + " " + body;
- replaceContext = oldContext;
- return result;
- };
-
- function transformFunction(class_) {
- var m = new RegExp(/\b([A-Za-z_$][\w$]*)\s*"B(\d+)"\s*"A(\d+)"/).exec(class_);
- return new AstFunction( m[1] !== "function" ? m[1] : null,
- transformParams(atoms[m[2]]), transformStatementsBlock(atoms[m[3]]));
- }
-
- function AstInlineObject(members) {
- this.members = members;
- }
- AstInlineObject.prototype.toString = function() {
- var oldContext = replaceContext;
- replaceContext = function (subject) {
- return subject.name === "this" ? "this" : oldContext(subject); // saving "this."
- };
- var result = "";
- for(var i=0,l=this.members.length;i<l;++i) {
- if(this.members[i].label) {
- result += this.members[i].label + ": ";
- }
- result += this.members[i].value.toString() + ", ";
- }
- replaceContext = oldContext;
- return result.substring(0, result.length - 2);
- };
-
- function transformInlineObject(obj) {
- var members = obj.split(',');
- for(var i=0; i < members.length; ++i) {
- var label = members[i].indexOf(':');
- if(label < 0) {
- members[i] = { value: transformExpression(members[i]) };
- } else {
- members[i] = { label: trim(members[i].substring(0, label)),
- value: transformExpression( trim(members[i].substring(label + 1)) ) };
- }
- }
- return new AstInlineObject(members);
- }
-
- function expandExpression(expr) {
- if(expr.charAt(0) === '(' || expr.charAt(0) === '[') {
- return expr.charAt(0) + expandExpression(expr.substring(1, expr.length - 1)) + expr.charAt(expr.length - 1);
- }
- if(expr.charAt(0) === '{') {
- if(/^\{\s*(?:[A-Za-z_$][\w$]*|'\d+')\s*:/.test(expr)) {
- return "{" + addAtom(expr.substring(1, expr.length - 1), 'I') + "}";
- }
- return "[" + expandExpression(expr.substring(1, expr.length - 1)) + "]";
- }
- var trimmed = trimSpaces(expr);
- var result = preExpressionTransform(trimmed.middle);
- result = result.replace(/"[ABC](\d+)"/g, function(all, index) {
- return expandExpression(atoms[index]);
- });
- return trimmed.untrim(result);
- }
-
- function replaceContextInVars(expr) {
- return expr.replace(/(\.\s*)?((?:\b[A-Za-z_]|\$)[\w$]*)(\s*\.\s*([A-Za-z_$][\w$]*)(\s*\()?)?/g,
- function(all, memberAccessSign, identifier, suffix, subMember, callSign) {
- if(memberAccessSign) {
- return all;
- }
- var subject = { name: identifier, member: subMember, callSign: !!callSign };
- return replaceContext(subject) + (suffix === undef ? "" : suffix);
- });
- }
-
- function AstExpression(expr, transforms) {
- this.expr = expr;
- this.transforms = transforms;
- }
- AstExpression.prototype.toString = function() {
- var transforms = this.transforms;
- var expr = replaceContextInVars(this.expr);
- return expr.replace(/"!(\d+)"/g, function(all, index) {
- return transforms[index].toString();
- });
- };
-
- transformExpression = function(expr) {
- var transforms = [];
- var s = expandExpression(expr);
- s = s.replace(/"H(\d+)"/g, function(all, index) {
- transforms.push(transformFunction(atoms[index]));
- return '"!' + (transforms.length - 1) + '"';
- });
- s = s.replace(/"F(\d+)"/g, function(all, index) {
- transforms.push(transformInlineClass(atoms[index]));
- return '"!' + (transforms.length - 1) + '"';
- });
- s = s.replace(/"I(\d+)"/g, function(all, index) {
- transforms.push(transformInlineObject(atoms[index]));
- return '"!' + (transforms.length - 1) + '"';
- });
-
- return new AstExpression(s, transforms);
- };
-
- function AstVarDefinition(name, value, isDefault) {
- this.name = name;
- this.value = value;
- this.isDefault = isDefault;
- }
- AstVarDefinition.prototype.toString = function() {
- return this.name + ' = ' + this.value;
- };
-
- function transformVarDefinition(def, defaultTypeValue) {
- var eqIndex = def.indexOf("=");
- var name, value, isDefault;
- if(eqIndex < 0) {
- name = def;
- value = defaultTypeValue;
- isDefault = true;
- } else {
- name = def.substring(0, eqIndex);
- value = transformExpression(def.substring(eqIndex + 1));
- isDefault = false;
- }
- return new AstVarDefinition( trim(name.replace(/(\s*"C\d+")+/g, "")),
- value, isDefault);
- }
-
- function getDefaultValueForType(type) {
- if(type === "int" || type === "float") {
- return "0";
- }
- if(type === "boolean") {
- return "false";
- }
- if(type === "color") {
- return "0x00000000";
- }
- return "null";
- }
-
- function AstVar(definitions, varType) {
- this.definitions = definitions;
- this.varType = varType;
- }
- AstVar.prototype.getNames = function() {
- var names = [];
- for(var i=0,l=this.definitions.length;i<l;++i) {
- names.push(this.definitions[i].name);
- }
- return names;
- };
- AstVar.prototype.toString = function() {
- return "var " + this.definitions.join(",");
- };
- function AstStatement(expression) {
- this.expression = expression;
- }
- AstStatement.prototype.toString = function() {
- return this.expression.toString();
- };
-
- function transformStatement(statement) {
- if(fieldTest.test(statement)) {
- var attrAndType = attrAndTypeRegex.exec(statement);
- var definitions = statement.substring(attrAndType[0].length).split(",");
- var defaultTypeValue = getDefaultValueForType(attrAndType[2]);
- for(var i=0; i < definitions.length; ++i) {
- definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue);
- }
- return new AstVar(definitions, attrAndType[2]);
- }
- return new AstStatement(transformExpression(statement));
- }
-
- function AstForExpression(initStatement, condition, step) {
- this.initStatement = initStatement;
- this.condition = condition;
- this.step = step;
- }
- AstForExpression.prototype.toString = function() {
- return "(" + this.initStatement + "; " + this.condition + "; " + this.step + ")";
- };
-
- function AstForInExpression(initStatement, container) {
- this.initStatement = initStatement;
- this.container = container;
- }
- AstForInExpression.prototype.toString = function() {
- var init = this.initStatement.toString();
- if(init.indexOf("=") >= 0) { // can be without var declaration
- init = init.substring(0, init.indexOf("="));
- }
- return "(" + init + " in " + this.container + ")";
- };
-
- function AstForEachExpression(initStatement, container) {
- this.initStatement = initStatement;
- this.container = container;
- }
- AstForEachExpression.iteratorId = 0;
- AstForEachExpression.prototype.toString = function() {
- var init = this.initStatement.toString();
- var iterator = "$it" + (AstForEachExpression.iteratorId++);
- var variableName = init.replace(/^\s*var\s*/, "").split("=")[0];
- var initIteratorAndVariable = "var " + iterator + " = new $p.ObjectIterator(" + this.container + "), " +
- variableName + " = void(0)";
- var nextIterationCondition = iterator + ".hasNext() && ((" +
- variableName + " = " + iterator + ".next()) || true)";
- return "(" + initIteratorAndVariable + "; " + nextIterationCondition + ";)";
- };
-
- function transformForExpression(expr) {
- var content;
- if (/\bin\b/.test(expr)) {
- content = expr.substring(1, expr.length - 1).split(/\bin\b/g);
- return new AstForInExpression( transformStatement(trim(content[0])),
- transformExpression(content[1]));
- }
- if (expr.indexOf(":") >= 0 && expr.indexOf(";") < 0) {
- content = expr.substring(1, expr.length - 1).split(":");
- return new AstForEachExpression( transformStatement(trim(content[0])),
- transformExpression(content[1]));
- }
- content = expr.substring(1, expr.length - 1).split(";");
- return new AstForExpression( transformStatement(trim(content[0])),
- transformExpression(content[1]), transformExpression(content[2]));
- }
-
- function sortByWeight(array) {
- array.sort(function (a,b) {
- return b.weight - a.weight;
- });
- }
-
- function AstInnerInterface(name, body, isStatic) {
- this.name = name;
- this.body = body;
- this.isStatic = isStatic;
- body.owner = this;
- }
- AstInnerInterface.prototype.toString = function() {
- return "" + this.body;
- };
- function AstInnerClass(name, body, isStatic) {
- this.name = name;
- this.body = body;
- this.isStatic = isStatic;
- body.owner = this;
- }
- AstInnerClass.prototype.toString = function() {
- return "" + this.body;
- };
-
- function transformInnerClass(class_) {
- var m = classesRegex.exec(class_); // 1 - attr, 2 - class|int, 3 - name, 4 - extends, 5 - implements, 6 - body
- classesRegex.lastIndex = 0;
- var isStatic = m[1].indexOf("static") >= 0;
- var body = atoms[getAtomIndex(m[6])], innerClass;
- var oldClassId = currentClassId, newClassId = generateClassId();
- currentClassId = newClassId;
- if(m[2] === "interface") {
- innerClass = new AstInnerInterface(m[3], transformInterfaceBody(body, m[3], m[4]), isStatic);
- } else {
- innerClass = new AstInnerClass(m[3], transformClassBody(body, m[3], m[4], m[5]), isStatic);
- }
- appendClass(innerClass, newClassId, oldClassId);
- currentClassId = oldClassId;
- return innerClass;
- }
-
- function AstClassMethod(name, params, body, isStatic) {
- this.name = name;
- this.params = params;
- this.body = body;
- this.isStatic = isStatic;
- }
- AstClassMethod.prototype.toString = function(){
- var paramNames = appendToLookupTable({}, this.params.getNames());
- var oldContext = replaceContext;
- replaceContext = function (subject) {
- return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject);
- };
- var body = this.params.prependMethodArgs(this.body.toString());
- var result = "function " + this.methodId + this.params + " " + body +"\n";
- replaceContext = oldContext;
- return result;
- };
-
- function transformClassMethod(method) {
- var m = methodsRegex.exec(method);
- methodsRegex.lastIndex = 0;
- var isStatic = m[1].indexOf("static") >= 0;
- var body = m[6] !== ';' ? atoms[getAtomIndex(m[6])] : "{}";
- return new AstClassMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]),
- transformStatementsBlock(body), isStatic );
- }
-
- function AstClassField(definitions, fieldType, isStatic) {
- this.definitions = definitions;
- this.fieldType = fieldType;
- this.isStatic = isStatic;
- }
- AstClassField.prototype.getNames = function() {
- var names = [];
- for(var i=0,l=this.definitions.length;i<l;++i) {
- names.push(this.definitions[i].name);
- }
- return names;
- };
- AstClassField.prototype.toString = function() {
- var thisPrefix = replaceContext({ name: "[this]" });
- if(this.isStatic) {
- var className = this.owner.name;
- var staticDeclarations = [];
- for(var i=0,l=this.definitions.length;i<l;++i) {
- var definition = this.definitions[i];
- var name = definition.name, staticName = className + "." + name;
- var declaration = "if(" + staticName + " === void(0)) {\n" +
- " " + staticName + " = " + definition.value + "; }\n" +
- "$p.defineProperty(" + thisPrefix + ", " +
- "'" + name + "', { get: function(){return " + staticName + ";}, " +
- "set: function(val){" + staticName + " = val;} });\n";
- staticDeclarations.push(declaration);
- }
- return staticDeclarations.join("");
- }
- return thisPrefix + "." + this.definitions.join("; " + thisPrefix + ".");
- };
-
- function transformClassField(statement) {
- var attrAndType = attrAndTypeRegex.exec(statement);
- var isStatic = attrAndType[1].indexOf("static") >= 0;
- var definitions = statement.substring(attrAndType[0].length).split(/,\s*/g);
- var defaultTypeValue = getDefaultValueForType(attrAndType[2]);
- for(var i=0; i < definitions.length; ++i) {
- definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue);
- }
- return new AstClassField(definitions, attrAndType[2], isStatic);
- }
-
- function AstConstructor(params, body) {
- this.params = params;
- this.body = body;
- }
- AstConstructor.prototype.toString = function() {
- var paramNames = appendToLookupTable({}, this.params.getNames());
- var oldContext = replaceContext;
- replaceContext = function (subject) {
- return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject);
- };
- var prefix = "function $constr_" + this.params.params.length + this.params.toString();
- var body = this.params.prependMethodArgs(this.body.toString());
- if(!/\$(superCstr|constr)\b/.test(body)) {
- body = "{\n$superCstr();\n" + body.substring(1);
- }
- replaceContext = oldContext;
- return prefix + body + "\n";
- };
-
- function transformConstructor(cstr) {
- var m = new RegExp(/"B(\d+)"\s*"A(\d+)"/).exec(cstr);
- var params = transformParams(atoms[m[1]]);
-
- return new AstConstructor(params, transformStatementsBlock(atoms[m[2]]));
- }
-
- function AstInterfaceBody(name, interfacesNames, methodsNames, fields, innerClasses, misc) {
- var i,l;
- this.name = name;
- this.interfacesNames = interfacesNames;
- this.methodsNames = methodsNames;
- this.fields = fields;
- this.innerClasses = innerClasses;
- this.misc = misc;
- for(i=0,l=fields.length; i<l; ++i) {
- fields[i].owner = this;
- }
- }
- AstInterfaceBody.prototype.getMembers = function(classFields, classMethods, classInners) {
- if(this.owner.base) {
- this.owner.base.body.getMembers(classFields, classMethods, classInners);
- }
- var i, j, l, m;
- for(i=0,l=this.fields.length;i<l;++i) {
- var fieldNames = this.fields[i].getNames();
- for(j=0,m=fieldNames.length;j<m;++j) {
- classFields[fieldNames[j]] = this.fields[i];
- }
- }
- for(i=0,l=this.methodsNames.length;i<l;++i) {
- var methodName = this.methodsNames[i];
- classMethods[methodName] = true;
- }
- for(i=0,l=this.innerClasses.length;i<l;++i) {
- var innerClass = this.innerClasses[i];
- classInners[innerClass.name] = innerClass;
- }
- };
- AstInterfaceBody.prototype.toString = function() {
- function getScopeLevel(p) {
- var i = 0;
- while(p) {
- ++i;
- p=p.scope;
- }
- return i;
- }
-
- var scopeLevel = getScopeLevel(this.owner);
-
- var className = this.name;
- var staticDefinitions = "";
- var metadata = "";
-
- var thisClassFields = {}, thisClassMethods = {}, thisClassInners = {};
- this.getMembers(thisClassFields, thisClassMethods, thisClassInners);
-
- var i, l, j, m;
-
- if (this.owner.interfaces) {
- // interface name can be present, but interface is not
- var resolvedInterfaces = [], resolvedInterface;
- for (i = 0, l = this.interfacesNames.length; i < l; ++i) {
- if (!this.owner.interfaces[i]) {
- continue;
- }
- resolvedInterface = replaceContext({name: this.interfacesNames[i]});
- resolvedInterfaces.push(resolvedInterface);
- staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n";
- }
- metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n";
- }
- metadata += className + ".$isInterface = true;\n";
- metadata += className + ".$methods = [\'" + this.methodsNames.join("\', \'") + "\'];\n";
-
- sortByWeight(this.innerClasses);
- for (i = 0, l = this.innerClasses.length; i < l; ++i) {
- var innerClass = this.innerClasses[i];
- if (innerClass.isStatic) {
- staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n";
- }
- }
-
- for (i = 0, l = this.fields.length; i < l; ++i) {
- var field = this.fields[i];
- if (field.isStatic) {
- staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n";
- }
- }
-
- return "(function() {\n" +
- "function " + className + "() { throw \'Unable to create the interface\'; }\n" +
- staticDefinitions +
- metadata +
- "return " + className + ";\n" +
- "})()";
- };
-
- transformInterfaceBody = function(body, name, baseInterfaces) {
- var declarations = body.substring(1, body.length - 1);
- declarations = extractClassesAndMethods(declarations);
- declarations = extractConstructors(declarations, name);
- var methodsNames = [], classes = [];
- declarations = declarations.replace(/"([DE])(\d+)"/g, function(all, type, index) {
- if(type === 'D') { methodsNames.push(index); }
- else if(type === 'E') { classes.push(index); }
- return "";
- });
- var fields = declarations.split(/;(?:\s*;)*/g);
- var baseInterfaceNames;
- var i, l;
-
- if(baseInterfaces !== undef) {
- baseInterfaceNames = baseInterfaces.replace(/^\s*extends\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g);
- }
-
- for(i = 0, l = methodsNames.length; i < l; ++i) {
- var method = transformClassMethod(atoms[methodsNames[i]]);
- methodsNames[i] = method.name;
- }
- for(i = 0, l = fields.length - 1; i < l; ++i) {
- var field = trimSpaces(fields[i]);
- fields[i] = transformClassField(field.middle);
- }
- var tail = fields.pop();
- for(i = 0, l = classes.length; i < l; ++i) {
- classes[i] = transformInnerClass(atoms[classes[i]]);
- }
-
- return new AstInterfaceBody(name, baseInterfaceNames, methodsNames, fields, classes, { tail: tail });
- };
-
- function AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, innerClasses, misc) {
- var i,l;
- this.name = name;
- this.baseClassName = baseClassName;
- this.interfacesNames = interfacesNames;
- this.functions = functions;
- this.methods = methods;
- this.fields = fields;
- this.cstrs = cstrs;
- this.innerClasses = innerClasses;
- this.misc = misc;
- for(i=0,l=fields.length; i<l; ++i) {
- fields[i].owner = this;
- }
- }
- AstClassBody.prototype.getMembers = function(classFields, classMethods, classInners) {
- if(this.owner.base) {
- this.owner.base.body.getMembers(classFields, classMethods, classInners);
- }
- var i, j, l, m;
- for(i=0,l=this.fields.length;i<l;++i) {
- var fieldNames = this.fields[i].getNames();
- for(j=0,m=fieldNames.length;j<m;++j) {
- classFields[fieldNames[j]] = this.fields[i];
- }
- }
- for(i=0,l=this.methods.length;i<l;++i) {
- var method = this.methods[i];
- classMethods[method.name] = method;
- }
- for(i=0,l=this.innerClasses.length;i<l;++i) {
- var innerClass = this.innerClasses[i];
- classInners[innerClass.name] = innerClass;
- }
- };
- AstClassBody.prototype.toString = function() {
- function getScopeLevel(p) {
- var i = 0;
- while(p) {
- ++i;
- p=p.scope;
- }
- return i;
- }
-
- var scopeLevel = getScopeLevel(this.owner);
-
- var selfId = "$this_" + scopeLevel;
- var className = this.name;
- var result = "var " + selfId + " = this;\n";
- var staticDefinitions = "";
- var metadata = "";
-
- var thisClassFields = {}, thisClassMethods = {}, thisClassInners = {};
- this.getMembers(thisClassFields, thisClassMethods, thisClassInners);
-
- var oldContext = replaceContext;
- replaceContext = function (subject) {
- var name = subject.name;
- if(name === "this") {
- // returns "$this_N.$self" pointer instead of "this" in cases:
- // "this()", "this.XXX()", "this", but not for "this.XXX"
- return subject.callSign || !subject.member ? selfId + ".$self" : selfId;
- }
- if(thisClassFields.hasOwnProperty(name)) {
- return thisClassFields[name].isStatic ? className + "." + name : selfId + "." + name;
- }
- if(thisClassInners.hasOwnProperty(name)) {
- return selfId + "." + name;
- }
- if(thisClassMethods.hasOwnProperty(name)) {
- return thisClassMethods[name].isStatic ? className + "." + name : selfId + ".$self." + name;
- }
- return oldContext(subject);
- };
-
- var resolvedBaseClassName;
- if (this.baseClassName) {
- resolvedBaseClassName = oldContext({name: this.baseClassName});
- result += "var $super = { $upcast: " + selfId + " };\n";
- result += "function $superCstr(){" + resolvedBaseClassName +
- ".apply($super,arguments);if(!('$self' in $super)) $p.extendClassChain($super)}\n";
- metadata += className + ".$base = " + resolvedBaseClassName + ";\n";
- } else {
- result += "function $superCstr(){$p.extendClassChain("+ selfId +")}\n";
- }
-
- if (this.owner.base) {
- // base class name can be present, but class is not
- staticDefinitions += "$p.extendStaticMembers(" + className + ", " + resolvedBaseClassName + ");\n";
- }
-
- var i, l, j, m;
-
- if (this.owner.interfaces) {
- // interface name can be present, but interface is not
- var resolvedInterfaces = [], resolvedInterface;
- for (i = 0, l = this.interfacesNames.length; i < l; ++i) {
- if (!this.owner.interfaces[i]) {
- continue;
- }
- resolvedInterface = oldContext({name: this.interfacesNames[i]});
- resolvedInterfaces.push(resolvedInterface);
- staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n";
- }
- metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n";
- }
-
- if (this.functions.length > 0) {
- result += this.functions.join('\n') + '\n';
- }
-
- sortByWeight(this.innerClasses);
- for (i = 0, l = this.innerClasses.length; i < l; ++i) {
- var innerClass = this.innerClasses[i];
- if (innerClass.isStatic) {
- staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n";
- result += selfId + "." + innerClass.name + " = " + className + "." + innerClass.name + ";\n";
- } else {
- result += selfId + "." + innerClass.name + " = " + innerClass + ";\n";
- }
- }
-
- for (i = 0, l = this.fields.length; i < l; ++i) {
- var field = this.fields[i];
- if (field.isStatic) {
- staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n";
- for (j = 0, m = field.definitions.length; j < m; ++j) {
- var fieldName = field.definitions[j].name, staticName = className + "." + fieldName;
- result += "$p.defineProperty(" + selfId + ", '" + fieldName + "', {" +
- "get: function(){return " + staticName + "}, " +
- "set: function(val){" + staticName + " = val}});\n";
- }
- } else {
- result += selfId + "." + field.definitions.join(";\n" + selfId + ".") + ";\n";
- }
- }
- var methodOverloads = {};
- for (i = 0, l = this.methods.length; i < l; ++i) {
- var method = this.methods[i];
- var overload = methodOverloads[method.name];
- var methodId = method.name + "$" + method.params.params.length;
- var hasMethodArgs = !!method.params.methodArgsParam;
- if (overload) {
- ++overload;
- methodId += "_" + overload;
- } else {
- overload = 1;
- }
- method.methodId = methodId;
- methodOverloads[method.name] = overload;
- if (method.isStatic) {
- staticDefinitions += method;
- staticDefinitions += "$p.addMethod(" + className + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n";
- result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n";
- } else {
- result += method;
- result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n";
- }
- }
- result += trim(this.misc.tail);
-
- if (this.cstrs.length > 0) {
- result += this.cstrs.join('\n') + '\n';
- }
-
- result += "function $constr() {\n";
- var cstrsIfs = [];
- for (i = 0, l = this.cstrs.length; i < l; ++i) {
- var paramsLength = this.cstrs[i].params.params.length;
- var methodArgsPresent = !!this.cstrs[i].params.methodArgsParam;
- cstrsIfs.push("if(arguments.length " + (methodArgsPresent ? ">=" : "===") +
- " " + paramsLength + ") { " +
- "$constr_" + paramsLength + ".apply(" + selfId + ", arguments); }");
- }
- if(cstrsIfs.length > 0) {
- result += cstrsIfs.join(" else ") + " else ";
- }
- // ??? add check if length is 0, otherwise fail
- result += "$superCstr();\n}\n";
- result += "$constr.apply(null, arguments);\n";
-
- replaceContext = oldContext;
- return "(function() {\n" +
- "function " + className + "() {\n" + result + "}\n" +
- staticDefinitions +
- metadata +
- "return " + className + ";\n" +
- "})()";
- };
-
- transformClassBody = function(body, name, baseName, interfaces) {
- var declarations = body.substring(1, body.length - 1);
- declarations = extractClassesAndMethods(declarations);
- declarations = extractConstructors(declarations, name);
- var methods = [], classes = [], cstrs = [], functions = [];
- declarations = declarations.replace(/"([DEGH])(\d+)"/g, function(all, type, index) {
- if(type === 'D') { methods.push(index); }
- else if(type === 'E') { classes.push(index); }
- else if(type === 'H') { functions.push(index); }
- else { cstrs.push(index); }
- return "";
- });
- var fields = declarations.replace(/^(?:\s*;)+/, "").split(/;(?:\s*;)*/g);
- var baseClassName, interfacesNames;
- var i;
-
- if(baseName !== undef) {
- baseClassName = baseName.replace(/^\s*extends\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*$/g, "$1");
- }
-
- if(interfaces !== undef) {
- interfacesNames = interfaces.replace(/^\s*implements\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g);
- }
-
- for(i = 0; i < functions.length; ++i) {
- functions[i] = transformFunction(atoms[functions[i]]);
- }
- for(i = 0; i < methods.length; ++i) {
- methods[i] = transformClassMethod(atoms[methods[i]]);
- }
- for(i = 0; i < fields.length - 1; ++i) {
- var field = trimSpaces(fields[i]);
- fields[i] = transformClassField(field.middle);
- }
- var tail = fields.pop();
- for(i = 0; i < cstrs.length; ++i) {
- cstrs[i] = transformConstructor(atoms[cstrs[i]]);
- }
- for(i = 0; i < classes.length; ++i) {
- classes[i] = transformInnerClass(atoms[classes[i]]);
- }
-
- return new AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs,
- classes, { tail: tail });
- };
-
- function AstInterface(name, body) {
- this.name = name;
- this.body = body;
- body.owner = this;
- }
- AstInterface.prototype.toString = function() {
- return "var " + this.name + " = " + this.body + ";\n" +
- "$p." + this.name + " = " + this.name + ";\n";
- };
- function AstClass(name, body) {
- this.name = name;
- this.body = body;
- body.owner = this;
- }
- AstClass.prototype.toString = function() {
- return "var " + this.name + " = " + this.body + ";\n" +
- "$p." + this.name + " = " + this.name + ";\n";
- };
-
- function transformGlobalClass(class_) {
- var m = classesRegex.exec(class_); // 1 - attr, 2 - class|int, 3 - name, 4 - extends, 5 - implements, 6 - body
- classesRegex.lastIndex = 0;
- var body = atoms[getAtomIndex(m[6])];
- var oldClassId = currentClassId, newClassId = generateClassId();
- currentClassId = newClassId;
- var globalClass;
- if(m[2] === "interface") {
- globalClass = new AstInterface(m[3], transformInterfaceBody(body, m[3], m[4]) );
- } else {
- globalClass = new AstClass(m[3], transformClassBody(body, m[3], m[4], m[5]) );
- }
- appendClass(globalClass, newClassId, oldClassId);
- currentClassId = oldClassId;
- return globalClass;
- }
-
- function AstMethod(name, params, body) {
- this.name = name;
- this.params = params;
- this.body = body;
- }
- AstMethod.prototype.toString = function(){
- var paramNames = appendToLookupTable({}, this.params.getNames());
- var oldContext = replaceContext;
- replaceContext = function (subject) {
- return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject);
- };
- var body = this.params.prependMethodArgs(this.body.toString());
- var result = "function " + this.name + this.params + " " + body + "\n" +
- "$p." + this.name + " = " + this.name + ";\n" +
- this.name + " = " + this.name + ".bind($p);";
- // "$p." + this.name + " = " + this.name + ";";
- replaceContext = oldContext;
- return result;
- };
-
- function transformGlobalMethod(method) {
- var m = methodsRegex.exec(method);
- var result =
- methodsRegex.lastIndex = 0;
- return new AstMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]),
- transformStatementsBlock(atoms[getAtomIndex(m[6])]));
- }
-
- function preStatementsTransform(statements) {
- var s = statements;
- // turns multiple catch blocks into one, because we have no way to properly get into them anyway.
- s = s.replace(/\b(catch\s*"B\d+"\s*"A\d+")(\s*catch\s*"B\d+"\s*"A\d+")+/g, "$1");
- return s;
- }
-
- function AstForStatement(argument, misc) {
- this.argument = argument;
- this.misc = misc;
- }
- AstForStatement.prototype.toString = function() {
- return this.misc.prefix + this.argument.toString();
- };
- function AstCatchStatement(argument, misc) {
- this.argument = argument;
- this.misc = misc;
- }
- AstCatchStatement.prototype.toString = function() {
- return this.misc.prefix + this.argument.toString();
- };
- function AstPrefixStatement(name, argument, misc) {
- this.name = name;
- this.argument = argument;
- this.misc = misc;
- }
- AstPrefixStatement.prototype.toString = function() {
- var result = this.misc.prefix;
- if(this.argument !== undef) {
- result += this.argument.toString();
- }
- return result;
- };
- function AstSwitchCase(expr) {
- this.expr = expr;
- }
- AstSwitchCase.prototype.toString = function() {
- return "case " + this.expr + ":";
- };
- function AstLabel(label) {
- this.label = label;
- }
- AstLabel.prototype.toString = function() {
- return this.label;
- };
-
- transformStatements = function(statements, transformMethod, transformClass) {
- var nextStatement = new RegExp(/\b(catch|for|if|switch|while|with)\s*"B(\d+)"|\b(do|else|finally|return|throw|try|break|continue)\b|("[ADEH](\d+)")|\b(case)\s+([^:]+):|\b([A-Za-z_$][\w$]*\s*:)|(;)/g);
- var res = [];
- statements = preStatementsTransform(statements);
- var lastIndex = 0, m, space;
- // m contains the matches from the nextStatement regexp, null if there are no matches.
- // nextStatement.exec starts searching at nextStatement.lastIndex.
- while((m = nextStatement.exec(statements)) !== null) {
- if(m[1] !== undef) { // catch, for ...
- var i = statements.lastIndexOf('"B', nextStatement.lastIndex);
- var statementsPrefix = statements.substring(lastIndex, i);
- if(m[1] === "for") {
- res.push(new AstForStatement(transformForExpression(atoms[m[2]]),
- { prefix: statementsPrefix }) );
- } else if(m[1] === "catch") {
- res.push(new AstCatchStatement(transformParams(atoms[m[2]]),
- { prefix: statementsPrefix }) );
- } else {
- res.push(new AstPrefixStatement(m[1], transformExpression(atoms[m[2]]),
- { prefix: statementsPrefix }) );
- }
- } else if(m[3] !== undef) { // do, else, ...
- res.push(new AstPrefixStatement(m[3], undef,
- { prefix: statements.substring(lastIndex, nextStatement.lastIndex) }) );
- } else if(m[4] !== undef) { // block, class and methods
- space = statements.substring(lastIndex, nextStatement.lastIndex - m[4].length);
- if(trim(space).length !== 0) { continue; } // avoiding new type[] {} construct
- res.push(space);
- var kind = m[4].charAt(1), atomIndex = m[5];
- if(kind === 'D') {
- res.push(transformMethod(atoms[atomIndex]));
- } else if(kind === 'E') {
- res.push(transformClass(atoms[atomIndex]));
- } else if(kind === 'H') {
- res.push(transformFunction(atoms[atomIndex]));
- } else {
- res.push(transformStatementsBlock(atoms[atomIndex]));
- }
- } else if(m[6] !== undef) { // switch case
- res.push(new AstSwitchCase(transformExpression(trim(m[7]))));
- } else if(m[8] !== undef) { // label
- space = statements.substring(lastIndex, nextStatement.lastIndex - m[8].length);
- if(trim(space).length !== 0) { continue; } // avoiding ?: construct
- res.push(new AstLabel(statements.substring(lastIndex, nextStatement.lastIndex)) );
- } else { // semicolon
- var statement = trimSpaces(statements.substring(lastIndex, nextStatement.lastIndex - 1));
- res.push(statement.left);
- res.push(transformStatement(statement.middle));
- res.push(statement.right + ";");
- }
- lastIndex = nextStatement.lastIndex;
- }
- var statementsTail = trimSpaces(statements.substring(lastIndex));
- res.push(statementsTail.left);
- if(statementsTail.middle !== "") {
- res.push(transformStatement(statementsTail.middle));
- res.push(";" + statementsTail.right);
- }
- return res;
- };
-
- function getLocalNames(statements) {
- var localNames = [];
- for(var i=0,l=statements.length;i<l;++i) {
- var statement = statements[i];
- if(statement instanceof AstVar) {
- localNames = localNames.concat(statement.getNames());
- } else if(statement instanceof AstForStatement &&
- statement.argument.initStatement instanceof AstVar) {
- localNames = localNames.concat(statement.argument.initStatement.getNames());
- } else if(statement instanceof AstInnerInterface || statement instanceof AstInnerClass ||
- statement instanceof AstInterface || statement instanceof AstClass ||
- statement instanceof AstMethod || statement instanceof AstFunction) {
- localNames.push(statement.name);
- }
- }
- return appendToLookupTable({}, localNames);
- }
-
- function AstStatementsBlock(statements) {
- this.statements = statements;
- }
- AstStatementsBlock.prototype.toString = function() {
- var localNames = getLocalNames(this.statements);
- var oldContext = replaceContext;
-
- // replacing context only when necessary
- if(!isLookupTableEmpty(localNames)) {
- replaceContext = function (subject) {
- return localNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject);
- };
- }
-
- var result = "{\n" + this.statements.join('') + "\n}";
- replaceContext = oldContext;
- return result;
- };
-
- transformStatementsBlock = function(block) {
- var content = trimSpaces(block.substring(1, block.length - 1));
- return new AstStatementsBlock(transformStatements(content.middle));
- };
-
- function AstRoot(statements) {
- this.statements = statements;
- }
- AstRoot.prototype.toString = function() {
- var classes = [], otherStatements = [], statement;
- for (var i = 0, len = this.statements.length; i < len; ++i) {
- statement = this.statements[i];
- if (statement instanceof AstClass || statement instanceof AstInterface) {
- classes.push(statement);
- } else {
- otherStatements.push(statement);
- }
- }
- sortByWeight(classes);
-
- var localNames = getLocalNames(this.statements);
- replaceContext = function (subject) {
- var name = subject.name;
- if(localNames.hasOwnProperty(name)) {
- return name;
- }
- if(globalMembers.hasOwnProperty(name) ||
- PConstants.hasOwnProperty(name) ||
- defaultScope.hasOwnProperty(name)) {
- return "$p." + name;
- }
- return name;
- };
- var result = "// this code was autogenerated from PJS\n" +
- "(function($p) {\n" +
- classes.join('') + "\n" +
- otherStatements.join('') + "\n})";
- replaceContext = null;
- return result;
- };
-
- transformMain = function() {
- var statements = extractClassesAndMethods(atoms[0]);
- statements = statements.replace(/\bimport\s+[^;]+;/g, "");
- return new AstRoot( transformStatements(statements,
- transformGlobalMethod, transformGlobalClass) );
- };
-
- function generateMetadata(ast) {
- var globalScope = {};
- var id, class_;
- for(id in declaredClasses) {
- if(declaredClasses.hasOwnProperty(id)) {
- class_ = declaredClasses[id];
- var scopeId = class_.scopeId, name = class_.name;
- if(scopeId) {
- var scope = declaredClasses[scopeId];
- class_.scope = scope;
- if(scope.inScope === undef) {
- scope.inScope = {};
- }
- scope.inScope[name] = class_;
- } else {
- globalScope[name] = class_;
- }
- }
- }
-
- function findInScopes(class_, name) {
- var parts = name.split('.');
- var currentScope = class_.scope, found;
- while(currentScope) {
- if(currentScope.hasOwnProperty(parts[0])) {
- found = currentScope[parts[0]]; break;
- }
- currentScope = currentScope.scope;
- }
- if(found === undef) {
- found = globalScope[parts[0]];
- }
- for(var i=1,l=parts.length;i<l && found;++i) {
- found = found.inScope[parts[i]];
- }
- return found;
- }
-
- for(id in declaredClasses) {
- if(declaredClasses.hasOwnProperty(id)) {
- class_ = declaredClasses[id];
- var baseClassName = class_.body.baseClassName;
- if(baseClassName) {
- var parent = findInScopes(class_, baseClassName);
- if (parent) {
- class_.base = parent;
- if (!parent.derived) {
- parent.derived = [];
- }
- parent.derived.push(class_);
- }
- }
- var interfacesNames = class_.body.interfacesNames,
- interfaces = [], i, l;
- if (interfacesNames && interfacesNames.length > 0) {
- for (i = 0, l = interfacesNames.length; i < l; ++i) {
- var interface_ = findInScopes(class_, interfacesNames[i]);
- interfaces.push(interface_);
- if (!interface_) {
- continue;
- }
- if (!interface_.derived) {
- interface_.derived = [];
- }
- interface_.derived.push(class_);
- }
- if (interfaces.length > 0) {
- class_.interfaces = interfaces;
- }
- }
- }
- }
- }
-
- function setWeight(ast) {
- var queue = [], tocheck = {};
- var id, scopeId, class_;
- // queue most inner and non-inherited
- for (id in declaredClasses) {
- if (declaredClasses.hasOwnProperty(id)) {
- class_ = declaredClasses[id];
- if (!class_.inScope && !class_.derived) {
- queue.push(id);
- class_.weight = 0;
- } else {
- var dependsOn = [];
- if (class_.inScope) {
- for (scopeId in class_.inScope) {
- if (class_.inScope.hasOwnProperty(scopeId)) {
- dependsOn.push(class_.inScope[scopeId]);
- }
- }
- }
- if (class_.derived) {
- dependsOn = dependsOn.concat(class_.derived);
- }
- tocheck[id] = dependsOn;
- }
- }
- }
- function removeDependentAndCheck(targetId, from) {
- var dependsOn = tocheck[targetId];
- if (!dependsOn) {
- return false; // no need to process
- }
- var i = dependsOn.indexOf(from);
- if (i < 0) {
- return false;
- }
- dependsOn.splice(i, 1);
- if (dependsOn.length > 0) {
- return false;
- }
- delete tocheck[targetId];
- return true;
- }
- while (queue.length > 0) {
- id = queue.shift();
- class_ = declaredClasses[id];
- if (class_.scopeId && removeDependentAndCheck(class_.scopeId, class_)) {
- queue.push(class_.scopeId);
- declaredClasses[class_.scopeId].weight = class_.weight + 1;
- }
- if (class_.base && removeDependentAndCheck(class_.base.classId, class_)) {
- queue.push(class_.base.classId);
- class_.base.weight = class_.weight + 1;
- }
- if (class_.interfaces) {
- var i, l;
- for (i = 0, l = class_.interfaces.length; i < l; ++i) {
- if (!class_.interfaces[i] ||
- !removeDependentAndCheck(class_.interfaces[i].classId, class_)) {
- continue;
- }
- queue.push(class_.interfaces[i].classId);
- class_.interfaces[i].weight = class_.weight + 1;
- }
- }
- }
- }
-
- var transformed = transformMain();
- generateMetadata(transformed);
- setWeight(transformed);
-
- var redendered = transformed.toString();
-
- // remove empty extra lines with space
- redendered = redendered.replace(/\s*\n(?:[\t ]*\n)+/g, "\n\n");
-
- // convert character codes to characters
- redendered = redendered.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) {
- return String.fromCharCode(parseInt(hexCode,16));
- });
-
- return injectStrings(redendered, strings);
- }// Parser ends
-
- function preprocessCode(aCode, sketch) {
- // Parse out @pjs directive, if any.
- var dm = new RegExp(/\/\*\s*@pjs\s+((?:[^\*]|\*+[^\*\/])*)\*\//g).exec(aCode);
- if (dm && dm.length === 2) {
- // masks contents of a JSON to be replaced later
- // to protect the contents from further parsing
- var jsonItems = [],
- directives = dm.splice(1, 2)[0].replace(/\{([\s\S]*?)\}/g, (function() {
- return function(all, item) {
- jsonItems.push(item);
- return "{" + (jsonItems.length-1) + "}";
- };
- }())).replace('\n', '').replace('\r', '').split(";");
-
- // We'll L/RTrim, and also remove any surrounding double quotes (e.g., just take string contents)
- var clean = function(s) {
- return s.replace(/^\s*["']?/, '').replace(/["']?\s*$/, '');
- };
-
- for (var i = 0, dl = directives.length; i < dl; i++) {
- var pair = directives[i].split('=');
- if (pair && pair.length === 2) {
- var key = clean(pair[0]),
- value = clean(pair[1]),
- list = [];
- // A few directives require work beyond storying key/value pairings
- if (key === "preload") {
- list = value.split(',');
- // All pre-loaded images will get put in imageCache, keyed on filename
- for (var j = 0, jl = list.length; j < jl; j++) {
- var imageName = clean(list[j]);
- sketch.imageCache.add(imageName);
- }
- // fonts can be declared as a string containing a url,
- // or a JSON object, containing a font name, and a url
- } else if (key === "font") {
- list = value.split(",");
- for (var x = 0, xl = list.length; x < xl; x++) {
- var fontName = clean(list[x]),
- index = /^\{(\d*?)\}$/.exec(fontName);
- // if index is not null, send JSON, otherwise, send string
- PFont.preloading.add(index ? JSON.parse("{" + jsonItems[index[1]] + "}") : fontName);
- }
- } else if (key === "pauseOnBlur") {
- sketch.options.pauseOnBlur = value === "true";
- } else if (key === "globalKeyEvents") {
- sketch.options.globalKeyEvents = value === "true";
- } else if (key.substring(0, 6) === "param-") {
- sketch.params[key.substring(6)] = value;
- } else {
- sketch.options[key] = value;
- }
- }
- }
- }
- return aCode;
- }
-
- // Parse/compiles Processing (Java-like) syntax to JavaScript syntax
- Processing.compile = function(pdeCode) {
- var sketch = new Processing.Sketch();
- var code = preprocessCode(pdeCode, sketch);
- var compiledPde = parseProcessing(code);
- sketch.sourceCode = compiledPde;
- return sketch;
- };
-
- var PjsConsole = require("../Helpers/PjsConsole");
- Processing.logger = new PjsConsole(document);
-
- // done
- return Processing;
- };
-
- },{"../Helpers/PjsConsole":5}],27:[function(require,module,exports){
- /**
- * Processing.js object
- */
- module.exports = function(options, undef) {
- var defaultScope = options.defaultScope,
- extend = options.extend,
- Browser = options.Browser,
- ajax = Browser.ajax,
- navigator = Browser.navigator,
- window = Browser.window,
- XMLHttpRequest = window.XMLHttpRequest,
- document = Browser.document,
- noop = options.noop,
-
- PConstants = defaultScope.PConstants;
- PFont = defaultScope.PFont,
- PShapeSVG = defaultScope.PShapeSVG,
- PVector = defaultScope.PVector,
- Char = Character = defaultScope.Char,
- ObjectIterator = defaultScope.ObjectIterator,
- XMLElement = defaultScope.XMLElement,
- XML = defaultScope.XML;
-
- // fascinating "read only" jshint error if we don't start a new var block here.
- var HTMLCanvasElement = window.HTMLCanvasElement,
- HTMLImageElement = window.HTMLImageElement;
-
- // window.localStorage cannot be accessed if a user is blocking cookies.
- // In that case, we make it a temporary source cache object.
- var localStorage;
- try { localStorage = window.localStorage; } catch (e) { localStorage = {}; }
-
- var isDOMPresent = ("document" in this) && !("fake" in this.document);
-
- // document.head polyfill for the benefit of Firefox 3.6
- if (!document.head) {
- document.head = document.getElementsByTagName('head')[0];
- }
-
- var Float32Array = setupTypedArray("Float32Array", "WebGLFloatArray"),
- Int32Array = setupTypedArray("Int32Array", "WebGLIntArray"),
- Uint16Array = setupTypedArray("Uint16Array", "WebGLUnsignedShortArray"),
- Uint8Array = setupTypedArray("Uint8Array", "WebGLUnsignedByteArray");
-
- // Typed Arrays: fallback to WebGL arrays or Native JS arrays if unavailable
- function setupTypedArray(name, fallback) {
- // Check if TypedArray exists, and use if so.
- if (name in window) {
- return window[name];
- }
-
- // Check if WebGLArray exists
- if (typeof window[fallback] === "function") {
- return window[fallback];
- }
-
- // Use Native JS array
- return function(obj) {
- if (obj instanceof Array) {
- return obj;
- }
- if (typeof obj === "number") {
- var arr = [];
- arr.length = obj;
- return arr;
- }
- };
- }
-
- /* IE9+ quirks mode check - ticket #1606 */
- if (document.documentMode >= 9 && !document.doctype) {
- throw("The doctype directive is missing. The recommended doctype in Internet Explorer is the HTML5 doctype: <!DOCTYPE html>");
- }
-
- // Manage multiple Processing instances
- var processingInstances = [];
- var processingInstanceIds = {};
-
- /**
- * instance tracking - adding new instances
- */
- var addInstance = function(processing) {
- if (processing.externals.canvas.id === undef || !processing.externals.canvas.id.length) {
- processing.externals.canvas.id = "__processing" + processingInstances.length;
- }
- processingInstanceIds[processing.externals.canvas.id] = processingInstances.length;
- processingInstances.push(processing);
- };
-
- /**
- * instance tracking - removal
- */
- var removeInstance = function(id) {
- processingInstances.splice(processingInstanceIds[id], 1);
- delete processingInstanceIds[id];
- };
-
-
- /**
- * The Processing object
- */
- var Processing = this.Processing = function(aCanvas, aCode, aFunctions) {
-
- if (!(this instanceof Processing)) {
- throw("called Processing constructor as if it were a function: missing 'new'.");
- }
-
- var curElement = {},
- pgraphicsMode = (aCanvas === undef && aCode === undef);
-
- if (pgraphicsMode) {
- curElement = document.createElement("canvas");
- } else {
- // We'll take a canvas element or a string for a canvas element's id
- curElement = typeof aCanvas === "string" ? document.getElementById(aCanvas) : aCanvas;
- }
-
- if (!('getContext' in curElement)) {
- throw("called Processing constructor without passing canvas element reference or id.");
- }
-
- function unimplemented(s) {
- Processing.debug('Unimplemented - ' + s);
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // JavaScript event binding and releasing
- ////////////////////////////////////////////////////////////////////////////
-
- var eventHandlers = [];
-
- function attachEventHandler(elem, type, fn) {
- if (elem.addEventListener) {
- elem.addEventListener(type, fn, false);
- } else {
- elem.attachEvent("on" + type, fn);
- }
- eventHandlers.push({elem: elem, type: type, fn: fn});
- }
-
- function detachEventHandler(eventHandler) {
- var elem = eventHandler.elem,
- type = eventHandler.type,
- fn = eventHandler.fn;
- if (elem.removeEventListener) {
- elem.removeEventListener(type, fn, false);
- } else if (elem.detachEvent) {
- elem.detachEvent("on" + type, fn);
- }
- }
-
- function removeFirstArgument(args) {
- return Array.prototype.slice.call(args, 1);
- }
-
- // When something new is added to "p." it must also be added to the "names" array.
- // The names array contains the names of everything that is inside "p."
- var p = this;
-
- p.Char = p.Character = Char;
-
- // add in the Processing API functions
- extend.withCommonFunctions(p);
- extend.withMath(p);
- extend.withProxyFunctions(p, removeFirstArgument);
- extend.withTouch(p, curElement, attachEventHandler, document, PConstants);
-
- // custom functions and properties are added here
- if(aFunctions) {
- Object.keys(aFunctions).forEach(function(name) {
- p[name] = aFunctions[name];
- });
- }
-
- // PJS specific (non-p5) methods and properties to externalize
- p.externals = {
- canvas: curElement,
- context: undef,
- sketch: undef,
- window: window
- };
-
- p.name = 'Processing.js Instance'; // Set Processing defaults / environment variables
- p.use3DContext = false; // default '2d' canvas context
-
- /**
- * Confirms if a Processing program is "focused", meaning that it is
- * active and will accept input from mouse or keyboard. This variable
- * is "true" if it is focused and "false" if not. This variable is
- * often used when you want to warn people they need to click on the
- * browser before it will work.
- */
- p.focused = false;
- p.breakShape = false;
-
- // Glyph path storage for textFonts
- p.glyphTable = {};
-
- // Global vars for tracking mouse position
- p.pmouseX = 0;
- p.pmouseY = 0;
- p.mouseX = 0;
- p.mouseY = 0;
- p.mouseButton = 0;
- p.mouseScroll = 0;
-
- // Undefined event handlers to be replaced by user when needed
- p.mouseClicked = undef;
- p.mouseDragged = undef;
- p.mouseMoved = undef;
- p.mousePressed = undef;
- p.mouseReleased = undef;
- p.mouseScrolled = undef;
- p.mouseOver = undef;
- p.mouseOut = undef;
- p.touchStart = undef;
- p.touchEnd = undef;
- p.touchMove = undef;
- p.touchCancel = undef;
- p.key = undef;
- p.keyCode = undef;
- p.keyPressed = noop; // needed to remove function checks
- p.keyReleased = noop;
- p.keyTyped = noop;
- p.draw = undef;
- p.setup = undef;
-
- // Remapped vars
- p.__mousePressed = false;
- p.__keyPressed = false;
- p.__frameRate = 60;
-
- // The current animation frame
- p.frameCount = 0;
-
- // The height/width of the canvas
- p.width = 100;
- p.height = 100;
-
- // "Private" variables used to maintain state
- var curContext,
- curSketch,
- drawing, // hold a Drawing2D or Drawing3D object
- doFill = true,
- fillStyle = [1.0, 1.0, 1.0, 1.0],
- currentFillColor = 0xFFFFFFFF,
- isFillDirty = true,
- doStroke = true,
- strokeStyle = [0.0, 0.0, 0.0, 1.0],
- currentStrokeColor = 0xFF000000,
- isStrokeDirty = true,
- lineWidth = 1,
- loopStarted = false,
- renderSmooth = false,
- doLoop = true,
- looping = 0,
- curRectMode = PConstants.CORNER,
- curEllipseMode = PConstants.CENTER,
- normalX = 0,
- normalY = 0,
- normalZ = 0,
- normalMode = PConstants.NORMAL_MODE_AUTO,
- curFrameRate = 60,
- curMsPerFrame = 1000/curFrameRate,
- curCursor = PConstants.ARROW,
- oldCursor = curElement.style.cursor,
- curShape = PConstants.POLYGON,
- curShapeCount = 0,
- curvePoints = [],
- curTightness = 0,
- curveDet = 20,
- curveInited = false,
- backgroundObj = -3355444, // rgb(204, 204, 204) is the default gray background colour
- bezDetail = 20,
- colorModeA = 255,
- colorModeX = 255,
- colorModeY = 255,
- colorModeZ = 255,
- pathOpen = false,
- mouseDragging = false,
- pmouseXLastFrame = 0,
- pmouseYLastFrame = 0,
- curColorMode = PConstants.RGB,
- curTint = null,
- curTint3d = null,
- getLoaded = false,
- start = Date.now(),
- timeSinceLastFPS = start,
- framesSinceLastFPS = 0,
- textcanvas,
- curveBasisMatrix,
- curveToBezierMatrix,
- curveDrawMatrix,
- bezierDrawMatrix,
- bezierBasisInverse,
- bezierBasisMatrix,
- curContextCache = { attributes: {}, locations: {} },
- // Shaders
- programObject3D,
- programObject2D,
- programObjectUnlitShape,
- boxBuffer,
- boxNormBuffer,
- boxOutlineBuffer,
- rectBuffer,
- rectNormBuffer,
- sphereBuffer,
- lineBuffer,
- fillBuffer,
- fillColorBuffer,
- strokeColorBuffer,
- pointBuffer,
- shapeTexVBO,
- canTex, // texture for createGraphics
- textTex, // texture for 3d tex
- curTexture = {width:0,height:0},
- curTextureMode = PConstants.IMAGE,
- usingTexture = false,
- textBuffer,
- textureBuffer,
- indexBuffer,
- // Text alignment
- horizontalTextAlignment = PConstants.LEFT,
- verticalTextAlignment = PConstants.BASELINE,
- textMode = PConstants.MODEL,
- // Font state
- curFontName = "Arial",
- curTextSize = 12,
- curTextAscent = 9,
- curTextDescent = 2,
- curTextLeading = 14,
- curTextFont = PFont.get(curFontName, curTextSize),
- // Pixels cache
- originalContext,
- proxyContext = null,
- isContextReplaced = false,
- setPixelsCached,
- maxPixelsCached = 1000,
- pressedKeysMap = [],
- lastPressedKeyCode = null,
- codedKeys = [ PConstants.SHIFT, PConstants.CONTROL, PConstants.ALT, PConstants.CAPSLK, PConstants.PGUP, PConstants.PGDN,
- PConstants.END, PConstants.HOME, PConstants.LEFT, PConstants.UP, PConstants.RIGHT, PConstants.DOWN, PConstants.NUMLK,
- PConstants.INSERT, PConstants.F1, PConstants.F2, PConstants.F3, PConstants.F4, PConstants.F5, PConstants.F6, PConstants.F7,
- PConstants.F8, PConstants.F9, PConstants.F10, PConstants.F11, PConstants.F12, PConstants.META ];
-
- // User can only have MAX_LIGHTS lights
- var lightCount = 0;
-
- //sphere stuff
- var sphereDetailV = 0,
- sphereDetailU = 0,
- sphereX = [],
- sphereY = [],
- sphereZ = [],
- sinLUT = new Float32Array(PConstants.SINCOS_LENGTH),
- cosLUT = new Float32Array(PConstants.SINCOS_LENGTH),
- sphereVerts,
- sphereNorms;
-
- // Camera defaults and settings
- var cam,
- cameraInv,
- modelView,
- modelViewInv,
- userMatrixStack,
- userReverseMatrixStack,
- inverseCopy,
- projection,
- manipulatingCamera = false,
- frustumMode = false,
- cameraFOV = 60 * (Math.PI / 180),
- cameraX = p.width / 2,
- cameraY = p.height / 2,
- cameraZ = cameraY / Math.tan(cameraFOV / 2),
- cameraNear = cameraZ / 10,
- cameraFar = cameraZ * 10,
- cameraAspect = p.width / p.height;
-
- var vertArray = [],
- curveVertArray = [],
- curveVertCount = 0,
- isCurve = false,
- isBezier = false,
- firstVert = true;
-
- //PShape stuff
- var curShapeMode = PConstants.CORNER;
-
- // Stores states for pushStyle() and popStyle().
- var styleArray = [];
-
- // The vertices for the box cannot be specified using a triangle strip since each
- // side of the cube must have its own set of normals.
- // Vertices are specified in a counter-clockwise order.
- // Triangles are in this order: back, front, right, bottom, left, top.
- var boxVerts = new Float32Array([
- 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5,
- 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5,
- 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5,
- 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5,
- -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5,
- 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5]);
-
- var boxOutlineVerts = new Float32Array([
- 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5,
- -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5,
- 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5,
- -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
- 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5,
- -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5]);
-
- var boxNorms = new Float32Array([
- 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1,
- 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
- 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
- 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
- -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0,
- 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0]);
-
- // These verts are used for the fill and stroke using TRIANGLE_FAN and LINE_LOOP.
- var rectVerts = new Float32Array([0,0,0, 0,1,0, 1,1,0, 1,0,0]);
-
- var rectNorms = new Float32Array([0,0,1, 0,0,1, 0,0,1, 0,0,1]);
-
- // Shader for points and lines in begin/endShape.
- var vertexShaderSrcUnlitShape =
- "varying vec4 vFrontColor;" +
-
- "attribute vec3 aVertex;" +
- "attribute vec4 aColor;" +
-
- "uniform mat4 uView;" +
- "uniform mat4 uProjection;" +
- "uniform float uPointSize;" +
-
- "void main(void) {" +
- " vFrontColor = aColor;" +
- " gl_PointSize = uPointSize;" +
- " gl_Position = uProjection * uView * vec4(aVertex, 1.0);" +
- "}";
-
- var fragmentShaderSrcUnlitShape =
- "#ifdef GL_ES\n" +
- "precision highp float;\n" +
- "#endif\n" +
-
- "varying vec4 vFrontColor;" +
- "uniform bool uSmooth;" +
-
- "void main(void){" +
- " if(uSmooth == true){" +
- " float dist = distance(gl_PointCoord, vec2(0.5));" +
- " if(dist > 0.5){" +
- " discard;" +
- " }" +
- " }" +
- " gl_FragColor = vFrontColor;" +
- "}";
-
- // Shader for rect, text, box outlines, sphere outlines, point() and line().
- var vertexShaderSrc2D =
- "varying vec4 vFrontColor;" +
-
- "attribute vec3 aVertex;" +
- "attribute vec2 aTextureCoord;" +
- "uniform vec4 uColor;" +
-
- "uniform mat4 uModel;" +
- "uniform mat4 uView;" +
- "uniform mat4 uProjection;" +
- "uniform float uPointSize;" +
- "varying vec2 vTextureCoord;"+
-
- "void main(void) {" +
- " gl_PointSize = uPointSize;" +
- " vFrontColor = uColor;" +
- " gl_Position = uProjection * uView * uModel * vec4(aVertex, 1.0);" +
- " vTextureCoord = aTextureCoord;" +
- "}";
-
- var fragmentShaderSrc2D =
- "#ifdef GL_ES\n" +
- "precision highp float;\n" +
- "#endif\n" +
-
- "varying vec4 vFrontColor;" +
- "varying vec2 vTextureCoord;"+
-
- "uniform sampler2D uSampler;"+
- "uniform int uIsDrawingText;"+
- "uniform bool uSmooth;" +
-
- "void main(void){" +
- // WebGL does not support POINT_SMOOTH, so we do it ourselves
- " if(uSmooth == true){" +
- " float dist = distance(gl_PointCoord, vec2(0.5));" +
- " if(dist > 0.5){" +
- " discard;" +
- " }" +
- " }" +
-
- " if(uIsDrawingText == 1){" +
- " float alpha = texture2D(uSampler, vTextureCoord).a;"+
- " gl_FragColor = vec4(vFrontColor.rgb * alpha, alpha);"+
- " }" +
- " else{" +
- " gl_FragColor = vFrontColor;" +
- " }" +
- "}";
-
- var webglMaxTempsWorkaround = /Windows/.test(navigator.userAgent);
-
- // Vertex shader for boxes and spheres.
- var vertexShaderSrc3D =
- "varying vec4 vFrontColor;" +
-
- "attribute vec3 aVertex;" +
- "attribute vec3 aNormal;" +
- "attribute vec4 aColor;" +
- "attribute vec2 aTexture;" +
- "varying vec2 vTexture;" +
-
- "uniform vec4 uColor;" +
-
- "uniform bool uUsingMat;" +
- "uniform vec3 uSpecular;" +
- "uniform vec3 uMaterialEmissive;" +
- "uniform vec3 uMaterialAmbient;" +
- "uniform vec3 uMaterialSpecular;" +
- "uniform float uShininess;" +
-
- "uniform mat4 uModel;" +
- "uniform mat4 uView;" +
- "uniform mat4 uProjection;" +
- "uniform mat4 uNormalTransform;" +
-
- "uniform int uLightCount;" +
- "uniform vec3 uFalloff;" +
-
- // Careful changing the order of these fields. Some cards
- // have issues with memory alignment.
- "struct Light {" +
- " int type;" +
- " vec3 color;" +
- " vec3 position;" +
- " vec3 direction;" +
- " float angle;" +
- " vec3 halfVector;" +
- " float concentration;" +
- "};" +
-
- // nVidia cards have issues with arrays of structures
- // so instead we create 8 instances of Light.
- "uniform Light uLights0;" +
- "uniform Light uLights1;" +
- "uniform Light uLights2;" +
- "uniform Light uLights3;" +
- "uniform Light uLights4;" +
- "uniform Light uLights5;" +
- "uniform Light uLights6;" +
- "uniform Light uLights7;" +
-
- // GLSL does not support switch.
- "Light getLight(int index){" +
- " if(index == 0) return uLights0;" +
- " if(index == 1) return uLights1;" +
- " if(index == 2) return uLights2;" +
- " if(index == 3) return uLights3;" +
- " if(index == 4) return uLights4;" +
- " if(index == 5) return uLights5;" +
- " if(index == 6) return uLights6;" +
- // Do not use a conditional for the last return statement
- // because some video cards will fail and complain that
- // "not all paths return".
- " return uLights7;" +
- "}" +
-
- "void AmbientLight( inout vec3 totalAmbient, in vec3 ecPos, in Light light ) {" +
- // Get the vector from the light to the vertex and
- // get the distance from the current vector to the light position.
- " float d = length( light.position - ecPos );" +
- " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" +
- " totalAmbient += light.color * attenuation;" +
- "}" +
-
- /*
- col - accumulated color
- spec - accumulated specular highlight
- vertNormal - Normal of the vertex
- ecPos - eye coordinate position
- light - light structure
- */
- "void DirectionalLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" +
- " float powerFactor = 0.0;" +
- " float nDotVP = max(0.0, dot( vertNormal, normalize(-light.position) ));" +
- " float nDotVH = max(0.0, dot( vertNormal, normalize(-light.position-normalize(ecPos) )));" +
-
- " if( nDotVP != 0.0 ){" +
- " powerFactor = pow( nDotVH, uShininess );" +
- " }" +
-
- " col += light.color * nDotVP;" +
- " spec += uSpecular * powerFactor;" +
- "}" +
-
- /*
- col - accumulated color
- spec - accumulated specular highlight
- vertNormal - Normal of the vertex
- ecPos - eye coordinate position
- light - light structure
- */
- "void PointLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" +
- " float powerFactor;" +
-
- // Get the vector from the light to the vertex.
- " vec3 VP = light.position - ecPos;" +
-
- // Get the distance from the current vector to the light position.
- " float d = length( VP ); " +
-
- // Normalize the light ray so it can be used in the dot product operation.
- " VP = normalize( VP );" +
-
- " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" +
-
- " float nDotVP = max( 0.0, dot( vertNormal, VP ));" +
- " vec3 halfVector = normalize( VP - normalize(ecPos) );" +
- " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" +
-
- " if( nDotVP == 0.0 ) {" +
- " powerFactor = 0.0;" +
- " }" +
- " else {" +
- " powerFactor = pow( nDotHV, uShininess );" +
- " }" +
-
- " spec += uSpecular * powerFactor * attenuation;" +
- " col += light.color * nDotVP * attenuation;" +
- "}" +
-
- /*
- col - accumulated color
- spec - accumulated specular highlight
- vertNormal - Normal of the vertex
- ecPos - eye coordinate position
- light - light structure
- */
- "void SpotLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" +
- " float spotAttenuation;" +
- " float powerFactor = 0.0;" +
-
- // Calculate the vector from the current vertex to the light.
- " vec3 VP = light.position - ecPos;" +
- " vec3 ldir = normalize( -light.direction );" +
-
- // Get the distance from the spotlight and the vertex
- " float d = length( VP );" +
- " VP = normalize( VP );" +
-
- " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ) );" +
-
- // Dot product of the vector from vertex to light and light direction.
- " float spotDot = dot( VP, ldir );" +
-
- // If the vertex falls inside the cone
- (webglMaxTempsWorkaround ? // Windows reports max temps error if light.angle is used
- " spotAttenuation = 1.0; " :
- " if( spotDot > cos( light.angle ) ) {" +
- " spotAttenuation = pow( spotDot, light.concentration );" +
- " }" +
- " else{" +
- " spotAttenuation = 0.0;" +
- " }" +
- " attenuation *= spotAttenuation;" +
- "") +
-
- " float nDotVP = max( 0.0, dot( vertNormal, VP ) );" +
- " vec3 halfVector = normalize( VP - normalize(ecPos) );" +
- " float nDotHV = max( 0.0, dot( vertNormal, halfVector ) );" +
-
- " if( nDotVP != 0.0 ) {" +
- " powerFactor = pow( nDotHV, uShininess );" +
- " }" +
-
- " spec += uSpecular * powerFactor * attenuation;" +
- " col += light.color * nDotVP * attenuation;" +
- "}" +
-
- "void main(void) {" +
- " vec3 finalAmbient = vec3( 0.0 );" +
- " vec3 finalDiffuse = vec3( 0.0 );" +
- " vec3 finalSpecular = vec3( 0.0 );" +
-
- " vec4 col = uColor;" +
-
- " if ( uColor[0] == -1.0 ){" +
- " col = aColor;" +
- " }" +
-
- // We use the sphere vertices as the normals when we create the sphere buffer.
- // But this only works if the sphere vertices are unit length, so we
- // have to normalize the normals here. Since this is only required for spheres
- // we could consider placing this in a conditional later on.
- " vec3 norm = normalize(vec3( uNormalTransform * vec4( aNormal, 0.0 ) ));" +
-
- " vec4 ecPos4 = uView * uModel * vec4(aVertex, 1.0);" +
- " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
-
- // If there were no lights this draw call, just use the
- // assigned fill color of the shape and the specular value.
- " if( uLightCount == 0 ) {" +
- " vFrontColor = col + vec4(uMaterialSpecular, 1.0);" +
- " }" +
- " else {" +
- // WebGL forces us to iterate over a constant value
- // so we can't iterate using lightCount.
- " for( int i = 0; i < 8; i++ ) {" +
- " Light l = getLight(i);" +
-
- // We can stop iterating if we know we have gone past
- // the number of lights which are actually on. This gives us a
- // significant performance increase with high vertex counts.
- " if( i >= uLightCount ){" +
- " break;" +
- " }" +
-
- " if( l.type == 0 ) {" +
- " AmbientLight( finalAmbient, ecPos, l );" +
- " }" +
- " else if( l.type == 1 ) {" +
- " DirectionalLight( finalDiffuse, finalSpecular, norm, ecPos, l );" +
- " }" +
- " else if( l.type == 2 ) {" +
- " PointLight( finalDiffuse, finalSpecular, norm, ecPos, l );" +
- " }" +
- " else {" +
- " SpotLight( finalDiffuse, finalSpecular, norm, ecPos, l );" +
- " }" +
- " }" +
-
- " if( uUsingMat == false ) {" +
- " vFrontColor = vec4(" +
- " vec3( col ) * finalAmbient +" +
- " vec3( col ) * finalDiffuse +" +
- " vec3( col ) * finalSpecular," +
- " col[3] );" +
- " }" +
- " else{" +
- " vFrontColor = vec4( " +
- " uMaterialEmissive + " +
- " (vec3(col) * uMaterialAmbient * finalAmbient ) + " +
- " (vec3(col) * finalDiffuse) + " +
- " (uMaterialSpecular * finalSpecular), " +
- " col[3] );" +
- " }" +
- " }" +
-
- " vTexture.xy = aTexture.xy;" +
- " gl_Position = uProjection * uView * uModel * vec4( aVertex, 1.0 );" +
- "}";
-
- var fragmentShaderSrc3D =
- "#ifdef GL_ES\n" +
- "precision highp float;\n" +
- "#endif\n" +
-
- "varying vec4 vFrontColor;" +
-
- "uniform sampler2D uSampler;" +
- "uniform bool uUsingTexture;" +
- "varying vec2 vTexture;" +
-
- // In Processing, when a texture is used, the fill color is ignored
- // vec4(1.0,1.0,1.0,0.5)
- "void main(void){" +
- " if( uUsingTexture ){" +
- " gl_FragColor = vec4(texture2D(uSampler, vTexture.xy)) * vFrontColor;" +
- " }"+
- " else{" +
- " gl_FragColor = vFrontColor;" +
- " }" +
- "}";
-
- ////////////////////////////////////////////////////////////////////////////
- // 3D Functions
- ////////////////////////////////////////////////////////////////////////////
-
- /*
- * Sets a uniform variable in a program object to a particular
- * value. Before calling this function, ensure the correct
- * program object has been installed as part of the current
- * rendering state by calling useProgram.
- *
- * On some systems, if the variable exists in the shader but isn't used,
- * the compiler will optimize it out and this function will fail.
- *
- * @param {String} cacheId
- * @param {WebGLProgram} programObj program object returned from
- * createProgramObject
- * @param {String} varName the name of the variable in the shader
- * @param {float | Array} varValue either a scalar value or an Array
- *
- * @returns none
- *
- * @see uniformi
- * @see uniformMatrix
- */
- function uniformf(cacheId, programObj, varName, varValue) {
- var varLocation = curContextCache.locations[cacheId];
- if(varLocation === undef) {
- varLocation = curContext.getUniformLocation(programObj, varName);
- curContextCache.locations[cacheId] = varLocation;
- }
- // the variable won't be found if it was optimized out.
- if (varLocation !== null) {
- if (varValue.length === 4) {
- curContext.uniform4fv(varLocation, varValue);
- } else if (varValue.length === 3) {
- curContext.uniform3fv(varLocation, varValue);
- } else if (varValue.length === 2) {
- curContext.uniform2fv(varLocation, varValue);
- } else {
- curContext.uniform1f(varLocation, varValue);
- }
- }
- }
-
- /**
- * Sets a uniform int or int array in a program object to a particular
- * value. Before calling this function, ensure the correct
- * program object has been installed as part of the current
- * rendering state.
- *
- * On some systems, if the variable exists in the shader but isn't used,
- * the compiler will optimize it out and this function will fail.
- *
- * @param {String} cacheId
- * @param {WebGLProgram} programObj program object returned from
- * createProgramObject
- * @param {String} varName the name of the variable in the shader
- * @param {int | Array} varValue either a scalar value or an Array
- *
- * @returns none
- *
- * @see uniformf
- * @see uniformMatrix
- */
- function uniformi(cacheId, programObj, varName, varValue) {
- var varLocation = curContextCache.locations[cacheId];
- if(varLocation === undef) {
- varLocation = curContext.getUniformLocation(programObj, varName);
- curContextCache.locations[cacheId] = varLocation;
- }
- // the variable won't be found if it was optimized out.
- if (varLocation !== null) {
- if (varValue.length === 4) {
- curContext.uniform4iv(varLocation, varValue);
- } else if (varValue.length === 3) {
- curContext.uniform3iv(varLocation, varValue);
- } else if (varValue.length === 2) {
- curContext.uniform2iv(varLocation, varValue);
- } else {
- curContext.uniform1i(varLocation, varValue);
- }
- }
- }
-
- /**
- * Sets the value of a uniform matrix variable in a program
- * object. Before calling this function, ensure the correct
- * program object has been installed as part of the current
- * rendering state.
- *
- * On some systems, if the variable exists in the shader but
- * isn't used, the compiler will optimize it out and this
- * function will fail.
- *
- * @param {String} cacheId
- * @param {WebGLProgram} programObj program object returned from
- * createProgramObject
- * @param {String} varName the name of the variable in the shader
- * @param {boolean} transpose must be false
- * @param {Array} matrix an array of 4, 9 or 16 values
- *
- * @returns none
- *
- * @see uniformi
- * @see uniformf
- */
- function uniformMatrix(cacheId, programObj, varName, transpose, matrix) {
- var varLocation = curContextCache.locations[cacheId];
- if(varLocation === undef) {
- varLocation = curContext.getUniformLocation(programObj, varName);
- curContextCache.locations[cacheId] = varLocation;
- }
- // The variable won't be found if it was optimized out.
- if (varLocation !== -1) {
- if (matrix.length === 16) {
- curContext.uniformMatrix4fv(varLocation, transpose, matrix);
- } else if (matrix.length === 9) {
- curContext.uniformMatrix3fv(varLocation, transpose, matrix);
- } else {
- curContext.uniformMatrix2fv(varLocation, transpose, matrix);
- }
- }
- }
-
- /**
- * Binds the VBO, sets the vertex attribute data for the program
- * object and enables the attribute.
- *
- * On some systems, if the attribute exists in the shader but
- * isn't used, the compiler will optimize it out and this
- * function will fail.
- *
- * @param {String} cacheId
- * @param {WebGLProgram} programObj program object returned from
- * createProgramObject
- * @param {String} varName the name of the variable in the shader
- * @param {int} size the number of components per vertex attribute
- * @param {WebGLBuffer} VBO Vertex Buffer Object
- *
- * @returns none
- *
- * @see disableVertexAttribPointer
- */
- function vertexAttribPointer(cacheId, programObj, varName, size, VBO) {
- var varLocation = curContextCache.attributes[cacheId];
- if(varLocation === undef) {
- varLocation = curContext.getAttribLocation(programObj, varName);
- curContextCache.attributes[cacheId] = varLocation;
- }
- if (varLocation !== -1) {
- curContext.bindBuffer(curContext.ARRAY_BUFFER, VBO);
- curContext.vertexAttribPointer(varLocation, size, curContext.FLOAT, false, 0, 0);
- curContext.enableVertexAttribArray(varLocation);
- }
- }
-
- /**
- * Disables a program object attribute from being sent to WebGL.
- *
- * @param {String} cacheId
- * @param {WebGLProgram} programObj program object returned from
- * createProgramObject
- * @param {String} varName name of the attribute
- *
- * @returns none
- *
- * @see vertexAttribPointer
- */
- function disableVertexAttribPointer(cacheId, programObj, varName){
- var varLocation = curContextCache.attributes[cacheId];
- if(varLocation === undef) {
- varLocation = curContext.getAttribLocation(programObj, varName);
- curContextCache.attributes[cacheId] = varLocation;
- }
- if (varLocation !== -1) {
- curContext.disableVertexAttribArray(varLocation);
- }
- }
-
- /**
- * Creates a WebGL program object.
- *
- * @param {String} vetexShaderSource
- * @param {String} fragmentShaderSource
- *
- * @returns {WebGLProgram} A program object
- */
- var createProgramObject = function(curContext, vetexShaderSource, fragmentShaderSource) {
- var vertexShaderObject = curContext.createShader(curContext.VERTEX_SHADER);
- curContext.shaderSource(vertexShaderObject, vetexShaderSource);
- curContext.compileShader(vertexShaderObject);
- if (!curContext.getShaderParameter(vertexShaderObject, curContext.COMPILE_STATUS)) {
- throw curContext.getShaderInfoLog(vertexShaderObject);
- }
-
- var fragmentShaderObject = curContext.createShader(curContext.FRAGMENT_SHADER);
- curContext.shaderSource(fragmentShaderObject, fragmentShaderSource);
- curContext.compileShader(fragmentShaderObject);
- if (!curContext.getShaderParameter(fragmentShaderObject, curContext.COMPILE_STATUS)) {
- throw curContext.getShaderInfoLog(fragmentShaderObject);
- }
-
- var programObject = curContext.createProgram();
- curContext.attachShader(programObject, vertexShaderObject);
- curContext.attachShader(programObject, fragmentShaderObject);
- curContext.linkProgram(programObject);
- if (!curContext.getProgramParameter(programObject, curContext.LINK_STATUS)) {
- throw "Error linking shaders.";
- }
-
- return programObject;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // 2D/3D drawing handling
- ////////////////////////////////////////////////////////////////////////////
- var imageModeCorner = function(x, y, w, h, whAreSizes) {
- return {
- x: x,
- y: y,
- w: w,
- h: h
- };
- };
- var imageModeConvert = imageModeCorner;
-
- var imageModeCorners = function(x, y, w, h, whAreSizes) {
- return {
- x: x,
- y: y,
- w: whAreSizes ? w : w - x,
- h: whAreSizes ? h : h - y
- };
- };
-
- var imageModeCenter = function(x, y, w, h, whAreSizes) {
- return {
- x: x - w / 2,
- y: y - h / 2,
- w: w,
- h: h
- };
- };
-
- // Objects for shared, 2D and 3D contexts
- var DrawingShared = function(){};
- var Drawing2D = function(){};
- var Drawing3D = function(){};
- var DrawingPre = function(){};
-
- // Setup the prototype chain
- Drawing2D.prototype = new DrawingShared();
- Drawing2D.prototype.constructor = Drawing2D;
- Drawing3D.prototype = new DrawingShared();
- Drawing3D.prototype.constructor = Drawing3D;
- DrawingPre.prototype = new DrawingShared();
- DrawingPre.prototype.constructor = DrawingPre;
-
- // A no-op function for when the user calls 3D functions from a 2D sketch
- // We can change this to a throw or console.error() later if we want
- DrawingShared.prototype.a3DOnlyFunction = noop;
-
- /**
- * The shape() function displays shapes to the screen.
- * Processing currently works with SVG shapes only.
- * The <b>shape</b> parameter specifies the shape to display and the <b>x</b>
- * and <b>y</b> parameters define the location of the shape from its
- * upper-left corner.
- * The shape is displayed at its original size unless the <b>width</b>
- * and <b>height</b> parameters specify a different size.
- * The <b>shapeMode()</b> function changes the way the parameters work.
- * A call to <b>shapeMode(CORNERS)</b>, for example, will change the width
- * and height parameters to define the x and y values of the opposite corner
- * of the shape.
- * <br><br>
- * Note complex shapes may draw awkwardly with P2D, P3D, and OPENGL. Those
- * renderers do not yet support shapes that have holes or complicated breaks.
- *
- * @param {PShape} shape the shape to display
- * @param {int|float} x x-coordinate of the shape
- * @param {int|float} y y-coordinate of the shape
- * @param {int|float} width width to display the shape
- * @param {int|float} height height to display the shape
- *
- * @see PShape
- * @see loadShape()
- * @see shapeMode()
- */
- p.shape = function(shape, x, y, width, height) {
- if (arguments.length >= 1 && arguments[0] !== null) {
- if (shape.isVisible()) {
- p.pushMatrix();
- if (curShapeMode === PConstants.CENTER) {
- if (arguments.length === 5) {
- p.translate(x - width/2, y - height/2);
- p.scale(width / shape.getWidth(), height / shape.getHeight());
- } else if (arguments.length === 3) {
- p.translate(x - shape.getWidth()/2, - shape.getHeight()/2);
- } else {
- p.translate(-shape.getWidth()/2, -shape.getHeight()/2);
- }
- } else if (curShapeMode === PConstants.CORNER) {
- if (arguments.length === 5) {
- p.translate(x, y);
- p.scale(width / shape.getWidth(), height / shape.getHeight());
- } else if (arguments.length === 3) {
- p.translate(x, y);
- }
- } else if (curShapeMode === PConstants.CORNERS) {
- if (arguments.length === 5) {
- width -= x;
- height -= y;
- p.translate(x, y);
- p.scale(width / shape.getWidth(), height / shape.getHeight());
- } else if (arguments.length === 3) {
- p.translate(x, y);
- }
- }
- shape.draw(p);
- if ((arguments.length === 1 && curShapeMode === PConstants.CENTER ) || arguments.length > 1) {
- p.popMatrix();
- }
- }
- }
- };
-
- /**
- * The shapeMode() function modifies the location from which shapes draw.
- * The default mode is <b>shapeMode(CORNER)</b>, which specifies the
- * location to be the upper left corner of the shape and uses the third
- * and fourth parameters of <b>shape()</b> to specify the width and height.
- * The syntax <b>shapeMode(CORNERS)</b> uses the first and second parameters
- * of <b>shape()</b> to set the location of one corner and uses the third
- * and fourth parameters to set the opposite corner.
- * The syntax <b>shapeMode(CENTER)</b> draws the shape from its center point
- * and uses the third and forth parameters of <b>shape()</b> to specify the
- * width and height.
- * The parameter must be written in "ALL CAPS" because Processing syntax
- * is case sensitive.
- *
- * @param {int} mode One of CORNER, CORNERS, CENTER
- *
- * @see shape()
- * @see rectMode()
- */
- p.shapeMode = function (mode) {
- curShapeMode = mode;
- };
-
- /**
- * The loadShape() function loads vector shapes into a variable of type PShape. Currently, only SVG files may be loaded.
- * In most cases, <b>loadShape()</b> should be used inside <b>setup()</b> because loading shapes inside <b>draw()</b> will reduce the speed of a sketch.
- *
- * @param {String} filename an SVG file
- *
- * @return {PShape} a object of type PShape or null
- * @see PShape
- * @see PApplet#shape()
- * @see PApplet#shapeMode()
- */
- p.loadShape = function (filename) {
- if (arguments.length === 1) {
- if (filename.indexOf(".svg") > -1) {
- return new PShapeSVG(null, filename);
- }
- }
- return null;
- };
-
- /**
- * Processing 2.0 function for loading XML files.
- *
- * @param {String} uri The uri for the xml file to load.
- *
- * @return {XML} An XML object representing the xml data.
- */
- p.loadXML = function(uri) {
- return new XML(p, uri);
- };
-
- /**
- * Processing 2.0 function for creating XML elements from string
- *
- * @param {String} xml the XML source code
- *
- * @return {XML} An XML object representation of the input XML markup.
- */
- p.parseXML = function(xmlstring) {
- var element = new XML();
- element.parse(xmlstring);
- return element;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // 2D Matrix
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Helper function for printMatrix(). Finds the largest scalar
- * in the matrix, then number of digits left of the decimal.
- * Call from PMatrix2D and PMatrix3D's print() function.
- */
- var printMatrixHelper = function(elements) {
- var big = 0;
- for (var i = 0; i < elements.length; i++) {
- if (i !== 0) {
- big = Math.max(big, Math.abs(elements[i]));
- } else {
- big = Math.abs(elements[i]);
- }
- }
-
- var digits = (big + "").indexOf(".");
- if (digits === 0) {
- digits = 1;
- } else if (digits === -1) {
- digits = (big + "").length;
- }
-
- return digits;
- };
- /**
- * PMatrix2D is a 3x2 affine matrix implementation. The constructor accepts another PMatrix2D or a list of six float elements.
- * If no parameters are provided the matrix is set to the identity matrix.
- *
- * @param {PMatrix2D} matrix the initial matrix to set to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fifth element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- var PMatrix2D = p.PMatrix2D = function() {
- if (arguments.length === 0) {
- this.reset();
- } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- this.set(arguments[0].array());
- } else if (arguments.length === 6) {
- this.set(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
- }
- };
- /**
- * PMatrix2D methods
- */
- PMatrix2D.prototype = {
- /**
- * @member PMatrix2D
- * The set() function sets the matrix elements. The function accepts either another PMatrix2D, an array of elements, or a list of six floats.
- *
- * @param {PMatrix2D} matrix the matrix to set this matrix to
- * @param {float[]} elements an array of elements to set this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fith element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- set: function() {
- if (arguments.length === 6) {
- var a = arguments;
- this.set([a[0], a[1], a[2],
- a[3], a[4], a[5]]);
- } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- this.elements = arguments[0].array();
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- this.elements = arguments[0].slice();
- }
- },
- /**
- * @member PMatrix2D
- * The get() function returns a copy of this PMatrix2D.
- *
- * @return {PMatrix2D} a copy of this PMatrix2D
- */
- get: function() {
- var outgoing = new PMatrix2D();
- outgoing.set(this.elements);
- return outgoing;
- },
- /**
- * @member PMatrix2D
- * The reset() function sets this PMatrix2D to the identity matrix.
- */
- reset: function() {
- this.set([1, 0, 0, 0, 1, 0]);
- },
- /**
- * @member PMatrix2D
- * The array() function returns a copy of the element values.
- * @addon
- *
- * @return {float[]} returns a copy of the element values
- */
- array: function array() {
- return this.elements.slice();
- },
- /**
- * @member PMatrix2D
- * The translate() function translates this matrix by moving the current coordinates to the location specified by tx and ty.
- *
- * @param {float} tx the x-axis coordinate to move to
- * @param {float} ty the y-axis coordinate to move to
- */
- translate: function(tx, ty) {
- this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this.elements[2];
- this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this.elements[5];
- },
- /**
- * @member PMatrix2D
- * The invTranslate() function translates this matrix by moving the current coordinates to the negative location specified by tx and ty.
- *
- * @param {float} tx the x-axis coordinate to move to
- * @param {float} ty the y-axis coordinate to move to
- */
- invTranslate: function(tx, ty) {
- this.translate(-tx, -ty);
- },
- /**
- * @member PMatrix2D
- * The transpose() function is not used in processingjs.
- */
- transpose: function() {
- // Does nothing in Processing.
- },
- /**
- * @member PMatrix2D
- * The mult() function multiplied this matrix.
- * If two array elements are passed in the function will multiply a two element vector against this matrix.
- * If target is null or not length four, a new float array will be returned.
- * The values for vec and target can be the same (though that's less efficient).
- * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix.
- *
- * @param {PVector} source, target the PVectors used to multiply this matrix
- * @param {float[]} source, target the arrays used to multiply this matrix
- *
- * @return {PVector|float[]} returns a PVector or an array representing the new matrix
- */
- mult: function(source, target) {
- var x, y;
- if (source instanceof PVector) {
- x = source.x;
- y = source.y;
- if (!target) {
- target = new PVector();
- }
- } else if (source instanceof Array) {
- x = source[0];
- y = source[1];
- if (!target) {
- target = [];
- }
- }
- if (target instanceof Array) {
- target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2];
- target[1] = this.elements[3] * x + this.elements[4] * y + this.elements[5];
- } else if (target instanceof PVector) {
- target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2];
- target.y = this.elements[3] * x + this.elements[4] * y + this.elements[5];
- target.z = 0;
- }
- return target;
- },
- /**
- * @member PMatrix2D
- * The multX() function calculates the x component of a vector from a transformation.
- *
- * @param {float} x the x component of the vector being transformed
- * @param {float} y the y component of the vector being transformed
- *
- * @return {float} returnes the result of the calculation
- */
- multX: function(x, y) {
- return (x * this.elements[0] + y * this.elements[1] + this.elements[2]);
- },
- /**
- * @member PMatrix2D
- * The multY() function calculates the y component of a vector from a transformation.
- *
- * @param {float} x the x component of the vector being transformed
- * @param {float} y the y component of the vector being transformed
- *
- * @return {float} returnes the result of the calculation
- */
- multY: function(x, y) {
- return (x * this.elements[3] + y * this.elements[4] + this.elements[5]);
- },
- /**
- * @member PMatrix2D
- * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewX: function(angle) {
- this.apply(1, 0, 1, angle, 0, 0);
- },
- /**
- * @member PMatrix2D
- * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewY: function(angle) {
- this.apply(1, 0, 1, 0, angle, 0);
- },
- /**
- * @member PMatrix2D
- * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- shearX: function(angle) {
- this.apply(1, 0, 1, Math.tan(angle) , 0, 0);
- },
- /**
- * @member PMatrix2D
- * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- shearY: function(angle) {
- this.apply(1, 0, 1, 0, Math.tan(angle), 0);
- },
- /**
- * @member PMatrix2D
- * The determinant() function calvculates the determinant of this matrix.
- *
- * @return {float} the determinant of the matrix
- */
- determinant: function() {
- return (this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3]);
- },
- /**
- * @member PMatrix2D
- * The invert() function inverts this matrix
- *
- * @return {boolean} true if successful
- */
- invert: function() {
- var d = this.determinant();
- if (Math.abs( d ) > PConstants.MIN_INT) {
- var old00 = this.elements[0];
- var old01 = this.elements[1];
- var old02 = this.elements[2];
- var old10 = this.elements[3];
- var old11 = this.elements[4];
- var old12 = this.elements[5];
- this.elements[0] = old11 / d;
- this.elements[3] = -old10 / d;
- this.elements[1] = -old01 / d;
- this.elements[4] = old00 / d;
- this.elements[2] = (old01 * old12 - old11 * old02) / d;
- this.elements[5] = (old10 * old02 - old00 * old12) / d;
- return true;
- }
- return false;
- },
- /**
- * @member PMatrix2D
- * The scale() function increases or decreases the size of a shape by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions.
- * This is equivalent to a two parameter call.
- *
- * @param {float} sx the amount to scale on the x-axis
- * @param {float} sy the amount to scale on the y-axis
- */
- scale: function(sx, sy) {
- if (sx && !sy) {
- sy = sx;
- }
- if (sx && sy) {
- this.elements[0] *= sx;
- this.elements[1] *= sy;
- this.elements[3] *= sx;
- this.elements[4] *= sy;
- }
- },
- /**
- * @member PMatrix2D
- * The invScale() function decreases or increases the size of a shape by contracting and expanding vertices. When only one parameter is specified scale will occur in all dimensions.
- * This is equivalent to a two parameter call.
- *
- * @param {float} sx the amount to scale on the x-axis
- * @param {float} sy the amount to scale on the y-axis
- */
- invScale: function(sx, sy) {
- if (sx && !sy) {
- sy = sx;
- }
- this.scale(1 / sx, 1 / sy);
- },
- /**
- * @member PMatrix2D
- * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix2D or a list of floats can be passed in.
- *
- * @param {PMatrix2D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fith element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- apply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- source = arguments[0].array();
- } else if (arguments.length === 6) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
-
- var result = [0, 0, this.elements[2],
- 0, 0, this.elements[5]];
- var e = 0;
- for (var row = 0; row < 2; row++) {
- for (var col = 0; col < 3; col++, e++) {
- result[e] += this.elements[row * 3 + 0] * source[col + 0] +
- this.elements[row * 3 + 1] * source[col + 3];
- }
- }
- this.elements = result.slice();
- },
- /**
- * @member PMatrix2D
- * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix2D or elements of a matrix can be passed in.
- *
- * @param {PMatrix2D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the third element of the matrix
- * @param {float} m10 the fourth element of the matrix
- * @param {float} m11 the fith element of the matrix
- * @param {float} m12 the sixth element of the matrix
- */
- preApply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) {
- source = arguments[0].array();
- } else if (arguments.length === 6) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
- var result = [0, 0, source[2],
- 0, 0, source[5]];
- result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1];
- result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4];
- result[0] = this.elements[0] * source[0] + this.elements[3] * source[1];
- result[3] = this.elements[0] * source[3] + this.elements[3] * source[4];
- result[1] = this.elements[1] * source[0] + this.elements[4] * source[1];
- result[4] = this.elements[1] * source[3] + this.elements[4] * source[4];
- this.elements = result.slice();
- },
- /**
- * @member PMatrix2D
- * The rotate() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotate: function(angle) {
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- var temp1 = this.elements[0];
- var temp2 = this.elements[1];
- this.elements[0] = c * temp1 + s * temp2;
- this.elements[1] = -s * temp1 + c * temp2;
- temp1 = this.elements[3];
- temp2 = this.elements[4];
- this.elements[3] = c * temp1 + s * temp2;
- this.elements[4] = -s * temp1 + c * temp2;
- },
- /**
- * @member PMatrix2D
- * The rotateZ() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateZ: function(angle) {
- this.rotate(angle);
- },
- /**
- * @member PMatrix2D
- * The invRotateZ() function rotates the matrix in opposite direction.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- invRotateZ: function(angle) {
- this.rotateZ(angle - Math.PI);
- },
- /**
- * @member PMatrix2D
- * The print() function prints out the elements of this matrix
- */
- print: function() {
- var digits = printMatrixHelper(this.elements);
- var output = "" + p.nfs(this.elements[0], digits, 4) + " " +
- p.nfs(this.elements[1], digits, 4) + " " +
- p.nfs(this.elements[2], digits, 4) + "\n" +
- p.nfs(this.elements[3], digits, 4) + " " +
- p.nfs(this.elements[4], digits, 4) + " " +
- p.nfs(this.elements[5], digits, 4) + "\n\n";
- p.println(output);
- }
- };
-
- /**
- * PMatrix3D is a 4x4 matrix implementation. The constructor accepts another PMatrix3D or a list of six or sixteen float elements.
- * If no parameters are provided the matrix is set to the identity matrix.
- */
- var PMatrix3D = p.PMatrix3D = function() {
- // When a matrix is created, it is set to an identity matrix
- this.reset();
- };
- /**
- * PMatrix3D methods
- */
- PMatrix3D.prototype = {
- /**
- * @member PMatrix2D
- * The set() function sets the matrix elements. The function accepts either another PMatrix3D, an array of elements, or a list of six or sixteen floats.
- *
- * @param {PMatrix3D} matrix the initial matrix to set to
- * @param {float[]} elements an array of elements to set this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- */
- set: function() {
- if (arguments.length === 16) {
- this.elements = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) {
- this.elements = arguments[0].array();
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- this.elements = arguments[0].slice();
- }
- },
- /**
- * @member PMatrix3D
- * The get() function returns a copy of this PMatrix3D.
- *
- * @return {PMatrix3D} a copy of this PMatrix3D
- */
- get: function() {
- var outgoing = new PMatrix3D();
- outgoing.set(this.elements);
- return outgoing;
- },
- /**
- * @member PMatrix3D
- * The reset() function sets this PMatrix3D to the identity matrix.
- */
- reset: function() {
- this.elements = [1,0,0,0,
- 0,1,0,0,
- 0,0,1,0,
- 0,0,0,1];
- },
- /**
- * @member PMatrix3D
- * The array() function returns a copy of the element values.
- * @addon
- *
- * @return {float[]} returns a copy of the element values
- */
- array: function array() {
- return this.elements.slice();
- },
- /**
- * @member PMatrix3D
- * The translate() function translates this matrix by moving the current coordinates to the location specified by tx, ty, and tz.
- *
- * @param {float} tx the x-axis coordinate to move to
- * @param {float} ty the y-axis coordinate to move to
- * @param {float} tz the z-axis coordinate to move to
- */
- translate: function(tx, ty, tz) {
- if (tz === undef) {
- tz = 0;
- }
-
- this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2];
- this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6];
- this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10];
- this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + tz * this.elements[14];
- },
- /**
- * @member PMatrix3D
- * The transpose() function transpose this matrix.
- */
- transpose: function() {
- var temp = this.elements[4];
- this.elements[4] = this.elements[1];
- this.elements[1] = temp;
-
- temp = this.elements[8];
- this.elements[8] = this.elements[2];
- this.elements[2] = temp;
-
- temp = this.elements[6];
- this.elements[6] = this.elements[9];
- this.elements[9] = temp;
-
- temp = this.elements[3];
- this.elements[3] = this.elements[12];
- this.elements[12] = temp;
-
- temp = this.elements[7];
- this.elements[7] = this.elements[13];
- this.elements[13] = temp;
-
- temp = this.elements[11];
- this.elements[11] = this.elements[14];
- this.elements[14] = temp;
- },
- /**
- * @member PMatrix3D
- * The mult() function multiplied this matrix.
- * If two array elements are passed in the function will multiply a two element vector against this matrix.
- * If target is null or not length four, a new float array will be returned.
- * The values for vec and target can be the same (though that's less efficient).
- * If two PVectors are passed in the function multiply the x and y coordinates of a PVector against this matrix.
- *
- * @param {PVector} source, target the PVectors used to multiply this matrix
- * @param {float[]} source, target the arrays used to multiply this matrix
- *
- * @return {PVector|float[]} returns a PVector or an array representing the new matrix
- */
- mult: function(source, target) {
- var x, y, z, w;
- if (source instanceof PVector) {
- x = source.x;
- y = source.y;
- z = source.z;
- w = 1;
- if (!target) {
- target = new PVector();
- }
- } else if (source instanceof Array) {
- x = source[0];
- y = source[1];
- z = source[2];
- w = source[3] || 1;
-
- if ( !target || (target.length !== 3 && target.length !== 4) ) {
- target = [0, 0, 0];
- }
- }
-
- if (target instanceof Array) {
- if (target.length === 3) {
- target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11];
- } else if (target.length === 4) {
- target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w;
- target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w;
- target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w;
- target[3] = this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w;
- }
- }
- if (target instanceof PVector) {
- target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- target.y = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- target.z = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11];
- }
- return target;
- },
- /**
- * @member PMatrix3D
- * The preApply() function applies another matrix to the left of this one. Note that either a PMatrix3D or elements of a matrix can be passed in.
- *
- * @param {PMatrix3D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- */
- preApply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) {
- source = arguments[0].array();
- } else if (arguments.length === 16) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
-
- var result = [0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0];
- var e = 0;
- for (var row = 0; row < 4; row++) {
- for (var col = 0; col < 4; col++, e++) {
- result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] *
- source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] +
- this.elements[col + 12] * source[row * 4 + 3];
- }
- }
- this.elements = result.slice();
- },
- /**
- * @member PMatrix3D
- * The apply() function multiplies the current matrix by the one specified through the parameters. Note that either a PMatrix3D or a list of floats can be passed in.
- *
- * @param {PMatrix3D} matrix the matrix to apply this matrix to
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- */
- apply: function() {
- var source;
- if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) {
- source = arguments[0].array();
- } else if (arguments.length === 16) {
- source = Array.prototype.slice.call(arguments);
- } else if (arguments.length === 1 && arguments[0] instanceof Array) {
- source = arguments[0];
- }
-
- var result = [0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0];
- var e = 0;
- for (var row = 0; row < 4; row++) {
- for (var col = 0; col < 4; col++, e++) {
- result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] *
- source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] +
- this.elements[row * 4 + 3] * source[col + 12];
- }
- }
- this.elements = result.slice();
- },
- /**
- * @member PMatrix3D
- * The rotate() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotate: function(angle, v0, v1, v2) {
- if (arguments.length < 4) {
- this.rotateZ(angle);
- } else {
- var v = new PVector(v0, v1, v2);
- var m = v.mag();
- if (m === 0) {
- return;
- } else if (m != 1) {
- v.normalize();
- v0 = v.x;
- v1 = v.y;
- v2 = v.z;
- }
- var c = p.cos(angle);
- var s = p.sin(angle);
- var t = 1.0 - c;
-
- this.apply((t * v0 * v0) + c,
- (t * v0 * v1) - (s * v2),
- (t * v0 * v2) + (s * v1),
- 0,
- (t * v0 * v1) + (s * v2),
- (t * v1 * v1) + c,
- (t * v1 * v2) - (s * v0),
- 0,
- (t * v0 * v2) - (s * v1),
- (t * v1 * v2) + (s * v0),
- (t * v2 * v2) + c,
- 0,
- 0, 0, 0, 1);
- }
- },
- /**
- * @member PMatrix3D
- * The invApply() function applies the inverted matrix to this matrix.
- *
- * @param {float} m00 the first element of the matrix
- * @param {float} m01 the second element of the matrix
- * @param {float} m02 the third element of the matrix
- * @param {float} m03 the fourth element of the matrix
- * @param {float} m10 the fifth element of the matrix
- * @param {float} m11 the sixth element of the matrix
- * @param {float} m12 the seventh element of the matrix
- * @param {float} m13 the eight element of the matrix
- * @param {float} m20 the nineth element of the matrix
- * @param {float} m21 the tenth element of the matrix
- * @param {float} m22 the eleventh element of the matrix
- * @param {float} m23 the twelveth element of the matrix
- * @param {float} m30 the thirteenth element of the matrix
- * @param {float} m31 the fourtheenth element of the matrix
- * @param {float} m32 the fivetheenth element of the matrix
- * @param {float} m33 the sixteenth element of the matrix
- *
- * @return {boolean} returns true if the operation was successful.
- */
- invApply: function() {
- if (inverseCopy === undef) {
- inverseCopy = new PMatrix3D();
- }
- var a = arguments;
- inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
- a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
-
- if (!inverseCopy.invert()) {
- return false;
- }
- this.preApply(inverseCopy);
- return true;
- },
- /**
- * @member PMatrix3D
- * The rotateZ() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateX: function(angle) {
- var c = p.cos(angle);
- var s = p.sin(angle);
- this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]);
- },
- /**
- * @member PMatrix3D
- * The rotateY() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateY: function(angle) {
- var c = p.cos(angle);
- var s = p.sin(angle);
- this.apply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]);
- },
- /**
- * @member PMatrix3D
- * The rotateZ() function rotates the matrix.
- *
- * @param {float} angle the angle of rotation in radiants
- */
- rotateZ: function(angle) {
- var c = Math.cos(angle);
- var s = Math.sin(angle);
- this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
- },
- /**
- * @member PMatrix3D
- * The scale() function increases or decreases the size of a matrix by expanding and contracting vertices. When only one parameter is specified scale will occur in all dimensions.
- * This is equivalent to a three parameter call.
- *
- * @param {float} sx the amount to scale on the x-axis
- * @param {float} sy the amount to scale on the y-axis
- * @param {float} sz the amount to scale on the z-axis
- */
- scale: function(sx, sy, sz) {
- if (sx && !sy && !sz) {
- sy = sz = sx;
- } else if (sx && sy && !sz) {
- sz = 1;
- }
-
- if (sx && sy && sz) {
- this.elements[0] *= sx;
- this.elements[1] *= sy;
- this.elements[2] *= sz;
- this.elements[4] *= sx;
- this.elements[5] *= sy;
- this.elements[6] *= sz;
- this.elements[8] *= sx;
- this.elements[9] *= sy;
- this.elements[10] *= sz;
- this.elements[12] *= sx;
- this.elements[13] *= sy;
- this.elements[14] *= sz;
- }
- },
- /**
- * @member PMatrix3D
- * The skewX() function skews the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewX: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- /**
- * @member PMatrix3D
- * The skewY() function skews the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of skew specified in radians
- */
- skewY: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- /**
- * @member PMatrix3D
- * The shearX() function shears the matrix along the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of shear specified in radians
- */
- shearX: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- /**
- * @member PMatrix3D
- * The shearY() function shears the matrix along the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians with the <b>radians()</b> function.
- *
- * @param {float} angle angle of shear specified in radians
- */
- shearY: function(angle) {
- var t = Math.tan(angle);
- this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
- },
- multX: function(x, y, z, w) {
- if (!z) {
- return this.elements[0] * x + this.elements[1] * y + this.elements[3];
- }
- if (!w) {
- return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- }
- return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w;
- },
- multY: function(x, y, z, w) {
- if (!z) {
- return this.elements[4] * x + this.elements[5] * y + this.elements[7];
- }
- if (!w) {
- return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- }
- return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w;
- },
- multZ: function(x, y, z, w) {
- if (!w) {
- return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11];
- }
- return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w;
- },
- multW: function(x, y, z, w) {
- if (!w) {
- return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15];
- }
- return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w;
- },
- /**
- * @member PMatrix3D
- * The invert() function inverts this matrix
- *
- * @return {boolean} true if successful
- */
- invert: function() {
- var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this.elements[4];
- var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this.elements[4];
- var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this.elements[4];
- var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this.elements[5];
- var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this.elements[5];
- var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this.elements[6];
- var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this.elements[12];
- var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * this.elements[12];
- var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * this.elements[12];
- var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * this.elements[13];
- var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * this.elements[13];
- var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * this.elements[14];
-
- // Determinant
- var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0;
-
- // Account for a very small value
- // return false if not successful.
- if (Math.abs(fDet) <= 1e-9) {
- return false;
- }
-
- var kInv = [];
- kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elements[7] * fB3;
- kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elements[7] * fB1;
- kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elements[7] * fB0;
- kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.elements[6] * fB0;
- kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elements[3] * fB3;
- kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elements[3] * fB1;
- kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elements[3] * fB0;
- kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.elements[2] * fB0;
- kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elements[15] * fA3;
- kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elements[15] * fA1;
- kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.elements[15] * fA0;
- kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.elements[14] * fA0;
- kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.elements[11] * fA3;
- kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.elements[11] * fA1;
- kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.elements[11] * fA0;
- kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.elements[10] * fA0;
-
- // Inverse using Determinant
- var fInvDet = 1.0 / fDet;
- kInv[0] *= fInvDet;
- kInv[1] *= fInvDet;
- kInv[2] *= fInvDet;
- kInv[3] *= fInvDet;
- kInv[4] *= fInvDet;
- kInv[5] *= fInvDet;
- kInv[6] *= fInvDet;
- kInv[7] *= fInvDet;
- kInv[8] *= fInvDet;
- kInv[9] *= fInvDet;
- kInv[10] *= fInvDet;
- kInv[11] *= fInvDet;
- kInv[12] *= fInvDet;
- kInv[13] *= fInvDet;
- kInv[14] *= fInvDet;
- kInv[15] *= fInvDet;
-
- this.elements = kInv.slice();
- return true;
- },
- toString: function() {
- var str = "";
- for (var i = 0; i < 15; i++) {
- str += this.elements[i] + ", ";
- }
- str += this.elements[15];
- return str;
- },
- /**
- * @member PMatrix3D
- * The print() function prints out the elements of this matrix
- */
- print: function() {
- var digits = printMatrixHelper(this.elements);
-
- var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) +
- " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs(this.elements[3], digits, 4) +
- "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) +
- " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) +
- "\n" + p.nfs(this.elements[8], digits, 4) + " " + p.nfs(this.elements[9], digits, 4) +
- " " + p.nfs(this.elements[10], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) +
- "\n" + p.nfs(this.elements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) +
- " " + p.nfs(this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n\n";
- p.println(output);
- },
- invTranslate: function(tx, ty, tz) {
- this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1);
- },
- invRotateX: function(angle) {
- var c = Math.cos(-angle);
- var s = Math.sin(-angle);
- this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]);
- },
- invRotateY: function(angle) {
- var c = Math.cos(-angle);
- var s = Math.sin(-angle);
- this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]);
- },
- invRotateZ: function(angle) {
- var c = Math.cos(-angle);
- var s = Math.sin(-angle);
- this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
- },
- invScale: function(x, y, z) {
- this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]);
- }
- };
-
- /**
- * @private
- * The matrix stack stores the transformations and translations that occur within the space.
- */
- var PMatrixStack = p.PMatrixStack = function() {
- this.matrixStack = [];
- };
-
- /**
- * @member PMatrixStack
- * load pushes the matrix given in the function into the stack
- *
- * @param {Object | Array} matrix the matrix to be pushed into the stack
- */
- PMatrixStack.prototype.load = function() {
- var tmpMatrix = drawing.$newPMatrix();
-
- if (arguments.length === 1) {
- tmpMatrix.set(arguments[0]);
- } else {
- tmpMatrix.set(arguments);
- }
- this.matrixStack.push(tmpMatrix);
- };
-
- Drawing2D.prototype.$newPMatrix = function() {
- return new PMatrix2D();
- };
-
- Drawing3D.prototype.$newPMatrix = function() {
- return new PMatrix3D();
- };
-
- /**
- * @member PMatrixStack
- * push adds a duplicate of the top of the stack onto the stack - uses the peek function
- */
- PMatrixStack.prototype.push = function() {
- this.matrixStack.push(this.peek());
- };
-
- /**
- * @member PMatrixStack
- * pop removes returns the matrix at the top of the stack
- *
- * @returns {Object} the matrix at the top of the stack
- */
- PMatrixStack.prototype.pop = function() {
- return this.matrixStack.pop();
- };
-
- /**
- * @member PMatrixStack
- * peek returns but doesn't remove the matrix at the top of the stack
- *
- * @returns {Object} the matrix at the top of the stack
- */
- PMatrixStack.prototype.peek = function() {
- var tmpMatrix = drawing.$newPMatrix();
-
- tmpMatrix.set(this.matrixStack[this.matrixStack.length - 1]);
- return tmpMatrix;
- };
-
- /**
- * @member PMatrixStack
- * this function multiplies the matrix at the top of the stack with the matrix given as a parameter
- *
- * @param {Object | Array} matrix the matrix to be multiplied into the stack
- */
- PMatrixStack.prototype.mult = function(matrix) {
- this.matrixStack[this.matrixStack.length - 1].apply(matrix);
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Array handling
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * The split() function breaks a string into pieces using a character or string
- * as the divider. The delim parameter specifies the character or characters that
- * mark the boundaries between each piece. A String[] array is returned that contains
- * each of the pieces.
- * If the result is a set of numbers, you can convert the String[] array to to a float[]
- * or int[] array using the datatype conversion functions int() and float() (see example above).
- * The splitTokens() function works in a similar fashion, except that it splits using a range
- * of characters instead of a specific character or sequence.
- *
- * @param {String} str the String to be split
- * @param {String} delim the character or String used to separate the data
- *
- * @returns {string[]} The new string array
- *
- * @see splitTokens
- * @see join
- * @see trim
- */
- p.split = function(str, delim) {
- return str.split(delim);
- };
-
- /**
- * The splitTokens() function splits a String at one or many character "tokens." The tokens
- * parameter specifies the character or characters to be used as a boundary.
- * If no tokens character is specified, any whitespace character is used to split.
- * Whitespace characters include tab (\t), line feed (\n), carriage return (\r), form
- * feed (\f), and space. To convert a String to an array of integers or floats, use the
- * datatype conversion functions int() and float() to convert the array of Strings.
- *
- * @param {String} str the String to be split
- * @param {Char[]} tokens list of individual characters that will be used as separators
- *
- * @returns {string[]} The new string array
- *
- * @see split
- * @see join
- * @see trim
- */
- p.splitTokens = function(str, tokens) {
- if (tokens === undef) {
- return str.split(/\s+/g);
- }
-
- var chars = tokens.split(/()/g),
- buffer = "",
- len = str.length,
- i, c,
- tokenized = [];
-
- for (i = 0; i < len; i++) {
- c = str[i];
- if (chars.indexOf(c) > -1) {
- if (buffer !== "") {
- tokenized.push(buffer);
- }
- buffer = "";
- } else {
- buffer += c;
- }
- }
-
- if (buffer !== "") {
- tokenized.push(buffer);
- }
-
- return tokenized;
- };
-
- /**
- * Expands an array by one element and adds data to the new position. The datatype of
- * the element parameter must be the same as the datatype of the array.
- * When using an array of objects, the data returned from the function must be cast to
- * the object array's data type. For example: SomeClass[] items = (SomeClass[])
- * append(originalArray, element).
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array boolean[],
- * byte[], char[], int[], float[], or String[], or an array of objects
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} element new data for the array
- *
- * @returns Array (the same datatype as the input)
- *
- * @see shorten
- * @see expand
- */
- p.append = function(array, element) {
- array[array.length] = element;
- return array;
- };
-
- /**
- * Concatenates two arrays. For example, concatenating the array { 1, 2, 3 } and the
- * array { 4, 5, 6 } yields { 1, 2, 3, 4, 5, 6 }. Both parameters must be arrays of the
- * same datatype.
- * When using an array of objects, the data returned from the function must be cast to the
- * object array's data type. For example: SomeClass[] items = (SomeClass[]) concat(array1, array2).
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array1 boolean[],
- * byte[], char[], int[], float[], String[], or an array of objects
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array2 boolean[],
- * byte[], char[], int[], float[], String[], or an array of objects
- *
- * @returns Array (the same datatype as the input)
- *
- * @see splice
- */
- p.concat = function(array1, array2) {
- return array1.concat(array2);
- };
-
- /**
- * Sorts an array of numbers from smallest to largest and puts an array of
- * words in alphabetical order. The original array is not modified, a
- * re-ordered array is returned. The count parameter states the number of
- * elements to sort. For example if there are 12 elements in an array and
- * if count is the value 5, only the first five elements on the array will
- * be sorted. Alphabetical ordering is case insensitive.
- *
- * @param {String[] | int[] | float[]} array Array of elements to sort
- * @param {int} numElem Number of elements to sort
- *
- * @returns {String[] | int[] | float[]} Array (same datatype as the input)
- *
- * @see reverse
- */
- p.sort = function(array, numElem) {
- var ret = [];
-
- // depending on the type used (int, float) or string
- // we'll need to use a different compare function
- if (array.length > 0) {
- // copy since we need to return another array
- var elemsToCopy = numElem > 0 ? numElem : array.length;
- for (var i = 0; i < elemsToCopy; i++) {
- ret.push(array[i]);
- }
- if (typeof array[0] === "string") {
- ret.sort();
- }
- // int or float
- else {
- ret.sort(function(a, b) {
- return a - b;
- });
- }
-
- // copy on the rest of the elements that were not sorted in case the user
- // only wanted a subset of an array to be sorted.
- if (numElem > 0) {
- for (var j = ret.length; j < array.length; j++) {
- ret.push(array[j]);
- }
- }
- }
- return ret;
- };
-
- /**
- * Inserts a value or array of values into an existing array. The first two parameters must
- * be of the same datatype. The array parameter defines the array which will be modified
- * and the second parameter defines the data which will be inserted. When using an array
- * of objects, the data returned from the function must be cast to the object array's data
- * type. For example: SomeClass[] items = (SomeClass[]) splice(array1, array2, index).
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array boolean[],
- * byte[], char[], int[], float[], String[], or an array of objects
- * @param {boolean|byte|char|int|float|String|boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects}
- * value boolean, byte, char, int, float, String, boolean[], byte[], char[], int[],
- * float[], String[], or other Object: value or an array of objects to be spliced in
- * @param {int} index position in the array from which to insert data
- *
- * @returns Array (the same datatype as the input)
- *
- * @see contract
- * @see subset
- */
- p.splice = function(array, value, index) {
-
- // Trying to splice an empty array into "array" in P5 won't do
- // anything, just return the original.
- if(value.length === 0)
- {
- return array;
- }
-
- // If the second argument was an array, we'll need to iterate over all
- // the "value" elements and add one by one because
- // array.splice(index, 0, value);
- // would create a multi-dimensional array which isn't what we want.
- if(value instanceof Array) {
- for(var i = 0, j = index; i < value.length; j++,i++) {
- array.splice(j, 0, value[i]);
- }
- } else {
- array.splice(index, 0, value);
- }
-
- return array;
- };
-
- /**
- * Extracts an array of elements from an existing array. The array parameter defines the
- * array from which the elements will be copied and the offset and length parameters determine
- * which elements to extract. If no length is given, elements will be extracted from the offset
- * to the end of the array. When specifying the offset remember the first array element is 0.
- * This function does not change the source array.
- * When using an array of objects, the data returned from the function must be cast to the
- * object array's data type.
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array boolean[],
- * byte[], char[], int[], float[], String[], or an array of objects
- * @param {int} offset position to begin
- * @param {int} length number of values to extract
- *
- * @returns Array (the same datatype as the input)
- *
- * @see splice
- */
- p.subset = function(array, offset, length) {
- var end = (length !== undef) ? offset + length : array.length;
- return array.slice(offset, end);
- };
-
- /**
- * Combines an array of Strings into one String, each separated by the character(s) used for
- * the separator parameter. To join arrays of ints or floats, it's necessary to first convert
- * them to strings using nf() or nfs().
- *
- * @param {Array} array array of Strings
- * @param {char|String} separator char or String to be placed between each item
- *
- * @returns {String} The combined string
- *
- * @see split
- * @see trim
- * @see nf
- * @see nfs
- */
- p.join = function(array, seperator) {
- return array.join(seperator);
- };
-
- /**
- * Decreases an array by one element and returns the shortened array. When using an
- * array of objects, the data returned from the function must be cast to the object array's
- * data type. For example: SomeClass[] items = (SomeClass[]) shorten(originalArray).
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} array
- * boolean[], byte[], char[], int[], float[], or String[], or an array of objects
- *
- * @returns Array (the same datatype as the input)
- *
- * @see append
- * @see expand
- */
- p.shorten = function(ary) {
- var newary = [];
-
- // copy array into new array
- var len = ary.length;
- for (var i = 0; i < len; i++) {
- newary[i] = ary[i];
- }
- newary.pop();
-
- return newary;
- };
-
- /**
- * Increases the size of an array. By default, this function doubles the size of the array,
- * but the optional newSize parameter provides precise control over the increase in size.
- * When using an array of objects, the data returned from the function must be cast to the
- * object array's data type. For example: SomeClass[] items = (SomeClass[]) expand(originalArray).
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]|array of objects} ary
- * boolean[], byte[], char[], int[], float[], String[], or an array of objects
- * @param {int} newSize positive int: new size for the array
- *
- * @returns Array (the same datatype as the input)
- *
- * @see contract
- */
- p.expand = function(ary, targetSize) {
- var temp = ary.slice(0),
- newSize = targetSize || ary.length * 2;
- temp.length = newSize;
- return temp;
- };
-
- /**
- * Copies an array (or part of an array) to another array. The src array is copied to the
- * dst array, beginning at the position specified by srcPos and into the position specified
- * by dstPos. The number of elements to copy is determined by length. The simplified version
- * with two arguments copies an entire array to another of the same size. It is equivalent
- * to "arrayCopy(src, 0, dst, 0, src.length)". This function is far more efficient for copying
- * array data than iterating through a for and copying each element.
- *
- * @param {Array} src an array of any data type: the source array
- * @param {Array} dest an array of any data type (as long as it's the same as src): the destination array
- * @param {int} srcPos starting position in the source array
- * @param {int} destPos starting position in the destination array
- * @param {int} length number of array elements to be copied
- *
- * @returns none
- */
- p.arrayCopy = function() { // src, srcPos, dest, destPos, length) {
- var src, srcPos = 0, dest, destPos = 0, length;
-
- if (arguments.length === 2) {
- // recall itself and copy src to dest from start index 0 to 0 of src.length
- src = arguments[0];
- dest = arguments[1];
- length = src.length;
- } else if (arguments.length === 3) {
- // recall itself and copy src to dest from start index 0 to 0 of length
- src = arguments[0];
- dest = arguments[1];
- length = arguments[2];
- } else if (arguments.length === 5) {
- src = arguments[0];
- srcPos = arguments[1];
- dest = arguments[2];
- destPos = arguments[3];
- length = arguments[4];
- }
-
- // copy src to dest from index srcPos to index destPos of length recursivly on objects
- for (var i = srcPos, j = destPos; i < length + srcPos; i++, j++) {
- if (dest[j] !== undef) {
- dest[j] = src[i];
- } else {
- throw "array index out of bounds exception";
- }
- }
- };
-
- /**
- * Reverses the order of an array.
- *
- * @param {boolean[]|byte[]|char[]|int[]|float[]|String[]} array
- * boolean[], byte[], char[], int[], float[], or String[]
- *
- * @returns Array (the same datatype as the input)
- *
- * @see sort
- */
- p.reverse = function(array) {
- return array.reverse();
- };
-
-
- ////////////////////////////////////////////////////////////////////////////
- // Color functions
- ////////////////////////////////////////////////////////////////////////////
-
- // helper functions for internal blending modes
- p.mix = function(a, b, f) {
- return a + (((b - a) * f) >> 8);
- };
-
- p.peg = function(n) {
- return (n < 0) ? 0 : ((n > 255) ? 255 : n);
- };
-
- // blending modes
- /**
- * These are internal blending modes used for BlendColor()
- *
- * @param {Color} c1 First Color to blend
- * @param {Color} c2 Second Color to blend
- *
- * @returns {Color} The blended Color
- *
- * @see BlendColor
- * @see Blend
- */
- p.modes = (function() {
- var ALPHA_MASK = PConstants.ALPHA_MASK,
- RED_MASK = PConstants.RED_MASK,
- GREEN_MASK = PConstants.GREEN_MASK,
- BLUE_MASK = PConstants.BLUE_MASK,
- min = Math.min,
- max = Math.max;
-
- function applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) {
- var a = min(((c1 & 0xff000000) >>> 24) + f, 0xff) << 24;
-
- var r = (ar + (((cr - ar) * f) >> 8));
- r = ((r < 0) ? 0 : ((r > 255) ? 255 : r)) << 16;
-
- var g = (ag + (((cg - ag) * f) >> 8));
- g = ((g < 0) ? 0 : ((g > 255) ? 255 : g)) << 8;
-
- var b = ab + (((cb - ab) * f) >> 8);
- b = (b < 0) ? 0 : ((b > 255) ? 255 : b);
-
- return (a | r | g | b);
- }
-
- return {
- replace: function(c1, c2) {
- return c2;
- },
- blend: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK),
- ag = (c1 & GREEN_MASK),
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK),
- bg = (c2 & GREEN_MASK),
- bb = (c2 & BLUE_MASK);
-
- return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (ar + (((br - ar) * f) >> 8)) & RED_MASK |
- (ag + (((bg - ag) * f) >> 8)) & GREEN_MASK |
- (ab + (((bb - ab) * f) >> 8)) & BLUE_MASK);
- },
- add: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24;
- return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- min(((c1 & RED_MASK) + ((c2 & RED_MASK) >> 8) * f), RED_MASK) & RED_MASK |
- min(((c1 & GREEN_MASK) + ((c2 & GREEN_MASK) >> 8) * f), GREEN_MASK) & GREEN_MASK |
- min((c1 & BLUE_MASK) + (((c2 & BLUE_MASK) * f) >> 8), BLUE_MASK));
- },
- subtract: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24;
- return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- max(((c1 & RED_MASK) - ((c2 & RED_MASK) >> 8) * f), GREEN_MASK) & RED_MASK |
- max(((c1 & GREEN_MASK) - ((c2 & GREEN_MASK) >> 8) * f), BLUE_MASK) & GREEN_MASK |
- max((c1 & BLUE_MASK) - (((c2 & BLUE_MASK) * f) >> 8), 0));
- },
- lightest: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24;
- return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- max(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f) & RED_MASK |
- max(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f) & GREEN_MASK |
- max(c1 & BLUE_MASK, ((c2 & BLUE_MASK) * f) >> 8));
- },
- darkest: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK),
- ag = (c1 & GREEN_MASK),
- ab = (c1 & BLUE_MASK),
- br = min(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f),
- bg = min(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f),
- bb = min(c1 & BLUE_MASK, ((c2 & BLUE_MASK) * f) >> 8);
-
- return (min(((c1 & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (ar + (((br - ar) * f) >> 8)) & RED_MASK |
- (ag + (((bg - ag) * f) >> 8)) & GREEN_MASK |
- (ab + (((bb - ab) * f) >> 8)) & BLUE_MASK);
- },
- difference: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = (ar > br) ? (ar - br) : (br - ar),
- cg = (ag > bg) ? (ag - bg) : (bg - ag),
- cb = (ab > bb) ? (ab - bb) : (bb - ab);
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- exclusion: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = ar + br - ((ar * br) >> 7),
- cg = ag + bg - ((ag * bg) >> 7),
- cb = ab + bb - ((ab * bb) >> 7);
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- multiply: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = (ar * br) >> 8,
- cg = (ag * bg) >> 8,
- cb = (ab * bb) >> 8;
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- screen: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = 255 - (((255 - ar) * (255 - br)) >> 8),
- cg = 255 - (((255 - ag) * (255 - bg)) >> 8),
- cb = 255 - (((255 - ab) * (255 - bb)) >> 8);
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- hard_light: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = (br < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7)),
- cg = (bg < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7)),
- cb = (bb < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7));
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- soft_light: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = ((ar * br) >> 7) + ((ar * ar) >> 8) - ((ar * ar * br) >> 15),
- cg = ((ag * bg) >> 7) + ((ag * ag) >> 8) - ((ag * ag * bg) >> 15),
- cb = ((ab * bb) >> 7) + ((ab * ab) >> 8) - ((ab * ab * bb) >> 15);
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- overlay: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK),
- cr = (ar < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7)),
- cg = (ag < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7)),
- cb = (ab < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7));
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- dodge: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK);
-
- var cr = 255;
- if (br !== 255) {
- cr = (ar << 8) / (255 - br);
- cr = (cr < 0) ? 0 : ((cr > 255) ? 255 : cr);
- }
-
- var cg = 255;
- if (bg !== 255) {
- cg = (ag << 8) / (255 - bg);
- cg = (cg < 0) ? 0 : ((cg > 255) ? 255 : cg);
- }
-
- var cb = 255;
- if (bb !== 255) {
- cb = (ab << 8) / (255 - bb);
- cb = (cb < 0) ? 0 : ((cb > 255) ? 255 : cb);
- }
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- },
- burn: function(c1, c2) {
- var f = (c2 & ALPHA_MASK) >>> 24,
- ar = (c1 & RED_MASK) >> 16,
- ag = (c1 & GREEN_MASK) >> 8,
- ab = (c1 & BLUE_MASK),
- br = (c2 & RED_MASK) >> 16,
- bg = (c2 & GREEN_MASK) >> 8,
- bb = (c2 & BLUE_MASK);
-
- var cr = 0;
- if (br !== 0) {
- cr = ((255 - ar) << 8) / br;
- cr = 255 - ((cr < 0) ? 0 : ((cr > 255) ? 255 : cr));
- }
-
- var cg = 0;
- if (bg !== 0) {
- cg = ((255 - ag) << 8) / bg;
- cg = 255 - ((cg < 0) ? 0 : ((cg > 255) ? 255 : cg));
- }
-
- var cb = 0;
- if (bb !== 0) {
- cb = ((255 - ab) << 8) / bb;
- cb = 255 - ((cb < 0) ? 0 : ((cb > 255) ? 255 : cb));
- }
-
- return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb);
- }
- };
- }());
-
- function color$4(aValue1, aValue2, aValue3, aValue4) {
- var r, g, b, a;
-
- if (curColorMode === PConstants.HSB) {
- var rgb = p.color.toRGB(aValue1, aValue2, aValue3);
- r = rgb[0];
- g = rgb[1];
- b = rgb[2];
- } else {
- r = Math.round(255 * (aValue1 / colorModeX));
- g = Math.round(255 * (aValue2 / colorModeY));
- b = Math.round(255 * (aValue3 / colorModeZ));
- }
-
- a = Math.round(255 * (aValue4 / colorModeA));
-
- // Limit values less than 0 and greater than 255
- r = (r < 0) ? 0 : r;
- g = (g < 0) ? 0 : g;
- b = (b < 0) ? 0 : b;
- a = (a < 0) ? 0 : a;
- r = (r > 255) ? 255 : r;
- g = (g > 255) ? 255 : g;
- b = (b > 255) ? 255 : b;
- a = (a > 255) ? 255 : a;
-
- // Create color int
- return (a << 24) & PConstants.ALPHA_MASK | (r << 16) & PConstants.RED_MASK | (g << 8) & PConstants.GREEN_MASK | b & PConstants.BLUE_MASK;
- }
-
- function color$2(aValue1, aValue2) {
- var a;
-
- // Color int and alpha
- if (aValue1 & PConstants.ALPHA_MASK) {
- a = Math.round(255 * (aValue2 / colorModeA));
- // Limit values less than 0 and greater than 255
- a = (a > 255) ? 255 : a;
- a = (a < 0) ? 0 : a;
-
- return aValue1 - (aValue1 & PConstants.ALPHA_MASK) + ((a << 24) & PConstants.ALPHA_MASK);
- }
- // Grayscale and alpha
- if (curColorMode === PConstants.RGB) {
- return color$4(aValue1, aValue1, aValue1, aValue2);
- }
- if (curColorMode === PConstants.HSB) {
- return color$4(0, 0, (aValue1 / colorModeX) * colorModeZ, aValue2);
- }
- }
-
- function color$1(aValue1) {
- // Grayscale
- if (aValue1 <= colorModeX && aValue1 >= 0) {
- if (curColorMode === PConstants.RGB) {
- return color$4(aValue1, aValue1, aValue1, colorModeA);
- }
- if (curColorMode === PConstants.HSB) {
- return color$4(0, 0, (aValue1 / colorModeX) * colorModeZ, colorModeA);
- }
- }
- // Color int
- if (aValue1) {
- if (aValue1 > 2147483647) {
- // Java Overflow
- aValue1 -= 4294967296;
- }
- return aValue1;
- }
- }
-
- /**
- * Creates colors for storing in variables of the color datatype. The parameters are
- * interpreted as RGB or HSB values depending on the current colorMode(). The default
- * mode is RGB values from 0 to 255 and therefore, the function call color(255, 204, 0)
- * will return a bright yellow color. More about how colors are stored can be found in
- * the reference for the color datatype.
- *
- * @param {int|float} aValue1 red or hue or grey values relative to the current color range.
- * Also can be color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00)
- * @param {int|float} aValue2 green or saturation values relative to the current color range
- * @param {int|float} aValue3 blue or brightness values relative to the current color range
- * @param {int|float} aValue4 relative to current color range. Represents alpha
- *
- * @returns {color} the color
- *
- * @see colorMode
- */
- p.color = function(aValue1, aValue2, aValue3, aValue4) {
-
- // 4 arguments: (R, G, B, A) or (H, S, B, A)
- if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef && aValue4 !== undef) {
- return color$4(aValue1, aValue2, aValue3, aValue4);
- }
-
- // 3 arguments: (R, G, B) or (H, S, B)
- if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef) {
- return color$4(aValue1, aValue2, aValue3, colorModeA);
- }
-
- // 2 arguments: (Color, A) or (Grayscale, A)
- if (aValue1 !== undef && aValue2 !== undef) {
- return color$2(aValue1, aValue2);
- }
-
- // 1 argument: (Grayscale) or (Color)
- if (typeof aValue1 === "number") {
- return color$1(aValue1);
- }
-
- // Default
- return color$4(colorModeX, colorModeY, colorModeZ, colorModeA);
- };
-
- // Ease of use function to extract the colour bits into a string
- p.color.toString = function(colorInt) {
- return "rgba(" + ((colorInt & PConstants.RED_MASK) >>> 16) + "," + ((colorInt & PConstants.GREEN_MASK) >>> 8) +
- "," + ((colorInt & PConstants.BLUE_MASK)) + "," + ((colorInt & PConstants.ALPHA_MASK) >>> 24) / 255 + ")";
- };
-
- // Easy of use function to pack rgba values into a single bit-shifted color int.
- p.color.toInt = function(r, g, b, a) {
- return (a << 24) & PConstants.ALPHA_MASK | (r << 16) & PConstants.RED_MASK | (g << 8) & PConstants.GREEN_MASK | b & PConstants.BLUE_MASK;
- };
-
- // Creates a simple array in [R, G, B, A] format, [255, 255, 255, 255]
- p.color.toArray = function(colorInt) {
- return [(colorInt & PConstants.RED_MASK) >>> 16, (colorInt & PConstants.GREEN_MASK) >>> 8,
- colorInt & PConstants.BLUE_MASK, (colorInt & PConstants.ALPHA_MASK) >>> 24];
- };
-
- // Creates a WebGL color array in [R, G, B, A] format. WebGL wants the color ranges between 0 and 1, [1, 1, 1, 1]
- p.color.toGLArray = function(colorInt) {
- return [((colorInt & PConstants.RED_MASK) >>> 16) / 255, ((colorInt & PConstants.GREEN_MASK) >>> 8) / 255,
- (colorInt & PConstants.BLUE_MASK) / 255, ((colorInt & PConstants.ALPHA_MASK) >>> 24) / 255];
- };
-
- // HSB conversion function from Mootools, MIT Licensed
- p.color.toRGB = function(h, s, b) {
- // Limit values greater than range
- h = (h > colorModeX) ? colorModeX : h;
- s = (s > colorModeY) ? colorModeY : s;
- b = (b > colorModeZ) ? colorModeZ : b;
-
- h = (h / colorModeX) * 360;
- s = (s / colorModeY) * 100;
- b = (b / colorModeZ) * 100;
-
- var br = Math.round(b / 100 * 255);
-
- if (s === 0) { // Grayscale
- return [br, br, br];
- }
- var hue = h % 360;
- var f = hue % 60;
- var p = Math.round((b * (100 - s)) / 10000 * 255);
- var q = Math.round((b * (6000 - s * f)) / 600000 * 255);
- var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255);
- switch (Math.floor(hue / 60)) {
- case 0:
- return [br, t, p];
- case 1:
- return [q, br, p];
- case 2:
- return [p, br, t];
- case 3:
- return [p, q, br];
- case 4:
- return [t, p, br];
- case 5:
- return [br, p, q];
- }
- };
-
- function colorToHSB(colorInt) {
- var red, green, blue;
-
- red = ((colorInt & PConstants.RED_MASK) >>> 16) / 255;
- green = ((colorInt & PConstants.GREEN_MASK) >>> 8) / 255;
- blue = (colorInt & PConstants.BLUE_MASK) / 255;
-
- var max = p.max(p.max(red,green), blue),
- min = p.min(p.min(red,green), blue),
- hue, saturation;
-
- if (min === max) {
- return [0, 0, max*colorModeZ];
- }
- saturation = (max - min) / max;
-
- if (red === max) {
- hue = (green - blue) / (max - min);
- } else if (green === max) {
- hue = 2 + ((blue - red) / (max - min));
- } else {
- hue = 4 + ((red - green) / (max - min));
- }
-
- hue /= 6;
-
- if (hue < 0) {
- hue += 1;
- } else if (hue > 1) {
- hue -= 1;
- }
- return [hue*colorModeX, saturation*colorModeY, max*colorModeZ];
- }
-
- /**
- * Extracts the brightness value from a color.
- *
- * @param {color} colInt any value of the color datatype
- *
- * @returns {float} The brightness color value.
- *
- * @see red
- * @see green
- * @see blue
- * @see hue
- * @see saturation
- */
- p.brightness = function(colInt){
- return colorToHSB(colInt)[2];
- };
-
- /**
- * Extracts the saturation value from a color.
- *
- * @param {color} colInt any value of the color datatype
- *
- * @returns {float} The saturation color value.
- *
- * @see red
- * @see green
- * @see blue
- * @see hue
- * @see brightness
- */
- p.saturation = function(colInt){
- return colorToHSB(colInt)[1];
- };
-
- /**
- * Extracts the hue value from a color.
- *
- * @param {color} colInt any value of the color datatype
- *
- * @returns {float} The hue color value.
- *
- * @see red
- * @see green
- * @see blue
- * @see saturation
- * @see brightness
- */
- p.hue = function(colInt){
- return colorToHSB(colInt)[0];
- };
-
- /**
- * Extracts the red value from a color, scaled to match current colorMode().
- * This value is always returned as a float so be careful not to assign it to an int value.
- *
- * @param {color} aColor any value of the color datatype
- *
- * @returns {float} The red color value.
- *
- * @see green
- * @see blue
- * @see alpha
- * @see >> right shift
- * @see hue
- * @see saturation
- * @see brightness
- */
- p.red = function(aColor) {
- return ((aColor & PConstants.RED_MASK) >>> 16) / 255 * colorModeX;
- };
-
- /**
- * Extracts the green value from a color, scaled to match current colorMode().
- * This value is always returned as a float so be careful not to assign it to an int value.
- *
- * @param {color} aColor any value of the color datatype
- *
- * @returns {float} The green color value.
- *
- * @see red
- * @see blue
- * @see alpha
- * @see >> right shift
- * @see hue
- * @see saturation
- * @see brightness
- */
- p.green = function(aColor) {
- return ((aColor & PConstants.GREEN_MASK) >>> 8) / 255 * colorModeY;
- };
-
- /**
- * Extracts the blue value from a color, scaled to match current colorMode().
- * This value is always returned as a float so be careful not to assign it to an int value.
- *
- * @param {color} aColor any value of the color datatype
- *
- * @returns {float} The blue color value.
- *
- * @see red
- * @see green
- * @see alpha
- * @see >> right shift
- * @see hue
- * @see saturation
- * @see brightness
- */
- p.blue = function(aColor) {
- return (aColor & PConstants.BLUE_MASK) / 255 * colorModeZ;
- };
-
- /**
- * Extracts the alpha value from a color, scaled to match current colorMode().
- * This value is always returned as a float so be careful not to assign it to an int value.
- *
- * @param {color} aColor any value of the color datatype
- *
- * @returns {float} The alpha color value.
- *
- * @see red
- * @see green
- * @see blue
- * @see >> right shift
- * @see hue
- * @see saturation
- * @see brightness
- */
- p.alpha = function(aColor) {
- return ((aColor & PConstants.ALPHA_MASK) >>> 24) / 255 * colorModeA;
- };
-
- /**
- * Calculates a color or colors between two colors at a specific increment.
- * The amt parameter is the amount to interpolate between the two values where 0.0
- * equal to the first point, 0.1 is very near the first point, 0.5 is half-way in between, etc.
- *
- * @param {color} c1 interpolate from this color
- * @param {color} c2 interpolate to this color
- * @param {float} amt between 0.0 and 1.0
- *
- * @returns {float} The blended color.
- *
- * @see blendColor
- * @see color
- */
- p.lerpColor = function(c1, c2, amt) {
- var r, g, b, a, r1, g1, b1, a1, r2, g2, b2, a2;
- var hsb1, hsb2, rgb, h, s;
- var colorBits1 = p.color(c1);
- var colorBits2 = p.color(c2);
-
- if (curColorMode === PConstants.HSB) {
- // Special processing for HSB mode.
- // Get HSB and Alpha values for Color 1 and 2
- hsb1 = colorToHSB(colorBits1);
- a1 = ((colorBits1 & PConstants.ALPHA_MASK) >>> 24) / colorModeA;
- hsb2 = colorToHSB(colorBits2);
- a2 = ((colorBits2 & PConstants.ALPHA_MASK) >>> 24) / colorModeA;
-
- // Return lerp value for each channel, for HSB components
- h = p.lerp(hsb1[0], hsb2[0], amt);
- s = p.lerp(hsb1[1], hsb2[1], amt);
- b = p.lerp(hsb1[2], hsb2[2], amt);
- rgb = p.color.toRGB(h, s, b);
- // ... and for Alpha-range
- a = (p.lerp(a1, a2, amt) * colorModeA + 0.5) | 0;
-
- return (a << 24) & PConstants.ALPHA_MASK |
- (rgb[0] << 16) & PConstants.RED_MASK |
- (rgb[1] << 8) & PConstants.GREEN_MASK |
- rgb[2] & PConstants.BLUE_MASK;
- }
-
- // Get RGBA values for Color 1 to floats
- r1 = (colorBits1 & PConstants.RED_MASK) >>> 16;
- g1 = (colorBits1 & PConstants.GREEN_MASK) >>> 8;
- b1 = (colorBits1 & PConstants.BLUE_MASK);
- a1 = ((colorBits1 & PConstants.ALPHA_MASK) >>> 24) / colorModeA;
-
- // Get RGBA values for Color 2 to floats
- r2 = (colorBits2 & PConstants.RED_MASK) >>> 16;
- g2 = (colorBits2 & PConstants.GREEN_MASK) >>> 8;
- b2 = (colorBits2 & PConstants.BLUE_MASK);
- a2 = ((colorBits2 & PConstants.ALPHA_MASK) >>> 24) / colorModeA;
-
- // Return lerp value for each channel, INT for color, Float for Alpha-range
- r = (p.lerp(r1, r2, amt) + 0.5) | 0;
- g = (p.lerp(g1, g2, amt) + 0.5) | 0;
- b = (p.lerp(b1, b2, amt) + 0.5) | 0;
- a = (p.lerp(a1, a2, amt) * colorModeA + 0.5) | 0;
-
- return (a << 24) & PConstants.ALPHA_MASK |
- (r << 16) & PConstants.RED_MASK |
- (g << 8) & PConstants.GREEN_MASK |
- b & PConstants.BLUE_MASK;
- };
-
- /**
- * Changes the way Processing interprets color data. By default, fill(), stroke(), and background()
- * colors are set by values between 0 and 255 using the RGB color model. It is possible to change the
- * numerical range used for specifying colors and to switch color systems. For example, calling colorMode(RGB, 1.0)
- * will specify that values are specified between 0 and 1. The limits for defining colors are altered by setting the
- * parameters range1, range2, range3, and range 4.
- *
- * @param {MODE} mode Either RGB or HSB, corresponding to Red/Green/Blue and Hue/Saturation/Brightness
- * @param {int|float} range range for all color elements
- * @param {int|float} range1 range for the red or hue depending on the current color mode
- * @param {int|float} range2 range for the green or saturation depending on the current color mode
- * @param {int|float} range3 range for the blue or brightness depending on the current color mode
- * @param {int|float} range4 range for the alpha
- *
- * @returns none
- *
- * @see background
- * @see fill
- * @see stroke
- */
- p.colorMode = function() { // mode, range1, range2, range3, range4
- curColorMode = arguments[0];
- if (arguments.length > 1) {
- colorModeX = arguments[1];
- colorModeY = arguments[2] || arguments[1];
- colorModeZ = arguments[3] || arguments[1];
- colorModeA = arguments[4] || arguments[1];
- }
- };
-
- /**
- * Blends two color values together based on the blending mode given as the MODE parameter.
- * The possible modes are described in the reference for the blend() function.
- *
- * @param {color} c1 color: the first color to blend
- * @param {color} c2 color: the second color to blend
- * @param {MODE} MODE Either BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY,
- * SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, or BURN
- *
- * @returns {float} The blended color.
- *
- * @see blend
- * @see color
- */
- p.blendColor = function(c1, c2, mode) {
- if (mode === PConstants.REPLACE) {
- return p.modes.replace(c1, c2);
- } else if (mode === PConstants.BLEND) {
- return p.modes.blend(c1, c2);
- } else if (mode === PConstants.ADD) {
- return p.modes.add(c1, c2);
- } else if (mode === PConstants.SUBTRACT) {
- return p.modes.subtract(c1, c2);
- } else if (mode === PConstants.LIGHTEST) {
- return p.modes.lightest(c1, c2);
- } else if (mode === PConstants.DARKEST) {
- return p.modes.darkest(c1, c2);
- } else if (mode === PConstants.DIFFERENCE) {
- return p.modes.difference(c1, c2);
- } else if (mode === PConstants.EXCLUSION) {
- return p.modes.exclusion(c1, c2);
- } else if (mode === PConstants.MULTIPLY) {
- return p.modes.multiply(c1, c2);
- } else if (mode === PConstants.SCREEN) {
- return p.modes.screen(c1, c2);
- } else if (mode === PConstants.HARD_LIGHT) {
- return p.modes.hard_light(c1, c2);
- } else if (mode === PConstants.SOFT_LIGHT) {
- return p.modes.soft_light(c1, c2);
- } else if (mode === PConstants.OVERLAY) {
- return p.modes.overlay(c1, c2);
- } else if (mode === PConstants.DODGE) {
- return p.modes.dodge(c1, c2);
- } else if (mode === PConstants.BURN) {
- return p.modes.burn(c1, c2);
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Canvas-Matrix manipulation
- ////////////////////////////////////////////////////////////////////////////
-
- function saveContext() {
- curContext.save();
- }
-
- function restoreContext() {
- curContext.restore();
- isStrokeDirty = true;
- isFillDirty = true;
- }
-
- /**
- * Prints the current matrix to the text window.
- *
- * @returns none
- *
- * @see pushMatrix
- * @see popMatrix
- * @see resetMatrix
- * @see applyMatrix
- */
- p.printMatrix = function() {
- modelView.print();
- };
-
- /**
- * Specifies an amount to displace objects within the display window. The x parameter specifies left/right translation,
- * the y parameter specifies up/down translation, and the z parameter specifies translations toward/away from the screen.
- * Using this function with the z parameter requires using the P3D or OPENGL parameter in combination with size as shown
- * in the above example. Transformations apply to everything that happens after and subsequent calls to the function
- * accumulates the effect. For example, calling translate(50, 0) and then translate(20, 0) is the same as translate(70, 0).
- * If translate() is called within draw(), the transformation is reset when the loop begins again.
- * This function can be further controlled by the pushMatrix() and popMatrix().
- *
- * @param {int|float} x left/right translation
- * @param {int|float} y up/down translation
- * @param {int|float} z forward/back translation
- *
- * @returns none
- *
- * @see pushMatrix
- * @see popMatrix
- * @see scale
- * @see rotate
- * @see rotateX
- * @see rotateY
- * @see rotateZ
- */
- Drawing2D.prototype.translate = function(x, y) {
- modelView.translate(x, y);
- modelViewInv.invTranslate(x, y);
- curContext.translate(x, y);
- };
-
- Drawing3D.prototype.translate = function(x, y, z) {
- modelView.translate(x, y, z);
- modelViewInv.invTranslate(x, y, z);
- };
-
- /**
- * Increases or decreases the size of a shape by expanding and contracting vertices. Objects always scale from their
- * relative origin to the coordinate system. Scale values are specified as decimal percentages. For example, the
- * function call scale(2.0) increases the dimension of a shape by 200%. Transformations apply to everything that
- * happens after and subsequent calls to the function multiply the effect. For example, calling scale(2.0) and
- * then scale(1.5) is the same as scale(3.0). If scale() is called within draw(), the transformation is reset when
- * the loop begins again. Using this fuction with the z parameter requires passing P3D or OPENGL into the size()
- * parameter as shown in the example above. This function can be further controlled by pushMatrix() and popMatrix().
- *
- * @param {int|float} size percentage to scale the object
- * @param {int|float} x percentage to scale the object in the x-axis
- * @param {int|float} y percentage to scale the object in the y-axis
- * @param {int|float} z percentage to scale the object in the z-axis
- *
- * @returns none
- *
- * @see pushMatrix
- * @see popMatrix
- * @see translate
- * @see rotate
- * @see rotateX
- * @see rotateY
- * @see rotateZ
- */
- Drawing2D.prototype.scale = function(x, y) {
- modelView.scale(x, y);
- modelViewInv.invScale(x, y);
- curContext.scale(x, y || x);
- };
-
- Drawing3D.prototype.scale = function(x, y, z) {
- modelView.scale(x, y, z);
- modelViewInv.invScale(x, y, z);
- };
-
-
- /**
- * helper function for applying a transfrom matrix to a 2D context.
- */
- Drawing2D.prototype.transform = function(pmatrix) {
- var e = pmatrix.array();
- curContext.transform(e[0],e[3],e[1],e[4],e[2],e[5]);
- };
-
- /**
- * helper function for applying a transfrom matrix to a 3D context.
- * not currently implemented.
- */
- Drawing3D.prototype.transformm = function(pmatrix3d) {
- throw("p.transform is currently not supported in 3D mode");
- };
-
-
- /**
- * Pushes the current transformation matrix onto the matrix stack. Understanding pushMatrix() and popMatrix()
- * requires understanding the concept of a matrix stack. The pushMatrix() function saves the current coordinate
- * system to the stack and popMatrix() restores the prior coordinate system. pushMatrix() and popMatrix() are
- * used in conjuction with the other transformation methods and may be embedded to control the scope of
- * the transformations.
- *
- * @returns none
- *
- * @see popMatrix
- * @see translate
- * @see rotate
- * @see rotateX
- * @see rotateY
- * @see rotateZ
- */
- Drawing2D.prototype.pushMatrix = function() {
- userMatrixStack.load(modelView);
- userReverseMatrixStack.load(modelViewInv);
- saveContext();
- };
-
- Drawing3D.prototype.pushMatrix = function() {
- userMatrixStack.load(modelView);
- userReverseMatrixStack.load(modelViewInv);
- };
-
- /**
- * Pops the current transformation matrix off the matrix stack. Understanding pushing and popping requires
- * understanding the concept of a matrix stack. The pushMatrix() function saves the current coordinate system to
- * the stack and popMatrix() restores the prior coordinate system. pushMatrix() and popMatrix() are used in
- * conjuction with the other transformation methods and may be embedded to control the scope of the transformations.
- *
- * @returns none
- *
- * @see popMatrix
- * @see pushMatrix
- */
- Drawing2D.prototype.popMatrix = function() {
- modelView.set(userMatrixStack.pop());
- modelViewInv.set(userReverseMatrixStack.pop());
- restoreContext();
- };
-
- Drawing3D.prototype.popMatrix = function() {
- modelView.set(userMatrixStack.pop());
- modelViewInv.set(userReverseMatrixStack.pop());
- };
-
- /**
- * Replaces the current matrix with the identity matrix. The equivalent function in OpenGL is glLoadIdentity().
- *
- * @returns none
- *
- * @see popMatrix
- * @see pushMatrix
- * @see applyMatrix
- * @see printMatrix
- */
- Drawing2D.prototype.resetMatrix = function() {
- modelView.reset();
- modelViewInv.reset();
- curContext.setTransform(1,0,0,1,0,0);
- };
-
- Drawing3D.prototype.resetMatrix = function() {
- modelView.reset();
- modelViewInv.reset();
- };
-
- /**
- * Multiplies the current matrix by the one specified through the parameters. This is very slow because it will
- * try to calculate the inverse of the transform, so avoid it whenever possible. The equivalent function
- * in OpenGL is glMultMatrix().
- *
- * @param {int|float} n00-n15 numbers which define the 4x4 matrix to be multiplied
- *
- * @returns none
- *
- * @see popMatrix
- * @see pushMatrix
- * @see resetMatrix
- * @see printMatrix
- */
- DrawingShared.prototype.applyMatrix = function() {
- var a = arguments;
- modelView.apply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
- modelViewInv.invApply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
- };
-
- Drawing2D.prototype.applyMatrix = function() {
- var a = arguments;
- for (var cnt = a.length; cnt < 16; cnt++) {
- a[cnt] = 0;
- }
- a[10] = a[15] = 1;
- DrawingShared.prototype.applyMatrix.apply(this, a);
- };
-
- /**
- * Rotates a shape around the x-axis the amount specified by the angle parameter. Angles should be
- * specified in radians (values from 0 to PI*2) or converted to radians with the radians() function.
- * Objects are always rotated around their relative position to the origin and positive numbers
- * rotate objects in a counterclockwise direction. Transformations apply to everything that happens
- * after and subsequent calls to the function accumulates the effect. For example, calling rotateX(PI/2)
- * and then rotateX(PI/2) is the same as rotateX(PI). If rotateX() is called within the draw(), the
- * transformation is reset when the loop begins again. This function requires passing P3D or OPENGL
- * into the size() parameter as shown in the example above.
- *
- * @param {int|float} angleInRadians angle of rotation specified in radians
- *
- * @returns none
- *
- * @see rotateY
- * @see rotateZ
- * @see rotate
- * @see translate
- * @see scale
- * @see popMatrix
- * @see pushMatrix
- */
- p.rotateX = function(angleInRadians) {
- modelView.rotateX(angleInRadians);
- modelViewInv.invRotateX(angleInRadians);
- };
-
- /**
- * Rotates a shape around the z-axis the amount specified by the angle parameter. Angles should be
- * specified in radians (values from 0 to PI*2) or converted to radians with the radians() function.
- * Objects are always rotated around their relative position to the origin and positive numbers
- * rotate objects in a counterclockwise direction. Transformations apply to everything that happens
- * after and subsequent calls to the function accumulates the effect. For example, calling rotateZ(PI/2)
- * and then rotateZ(PI/2) is the same as rotateZ(PI). If rotateZ() is called within the draw(), the
- * transformation is reset when the loop begins again. This function requires passing P3D or OPENGL
- * into the size() parameter as shown in the example above.
- *
- * @param {int|float} angleInRadians angle of rotation specified in radians
- *
- * @returns none
- *
- * @see rotateX
- * @see rotateY
- * @see rotate
- * @see translate
- * @see scale
- * @see popMatrix
- * @see pushMatrix
- */
- Drawing2D.prototype.rotateZ = function() {
- throw "rotateZ() is not supported in 2D mode. Use rotate(float) instead.";
- };
-
- Drawing3D.prototype.rotateZ = function(angleInRadians) {
- modelView.rotateZ(angleInRadians);
- modelViewInv.invRotateZ(angleInRadians);
- };
-
- /**
- * Rotates a shape around the y-axis the amount specified by the angle parameter. Angles should be
- * specified in radians (values from 0 to PI*2) or converted to radians with the radians() function.
- * Objects are always rotated around their relative position to the origin and positive numbers
- * rotate objects in a counterclockwise direction. Transformations apply to everything that happens
- * after and subsequent calls to the function accumulates the effect. For example, calling rotateY(PI/2)
- * and then rotateY(PI/2) is the same as rotateY(PI). If rotateY() is called within the draw(), the
- * transformation is reset when the loop begins again. This function requires passing P3D or OPENGL
- * into the size() parameter as shown in the example above.
- *
- * @param {int|float} angleInRadians angle of rotation specified in radians
- *
- * @returns none
- *
- * @see rotateX
- * @see rotateZ
- * @see rotate
- * @see translate
- * @see scale
- * @see popMatrix
- * @see pushMatrix
- */
- p.rotateY = function(angleInRadians) {
- modelView.rotateY(angleInRadians);
- modelViewInv.invRotateY(angleInRadians);
- };
-
- /**
- * Rotates a shape the amount specified by the angle parameter. Angles should be specified in radians
- * (values from 0 to TWO_PI) or converted to radians with the radians() function. Objects are always
- * rotated around their relative position to the origin and positive numbers rotate objects in a
- * clockwise direction. Transformations apply to everything that happens after and subsequent calls
- * to the function accumulates the effect. For example, calling rotate(HALF_PI) and then rotate(HALF_PI)
- * is the same as rotate(PI). All tranformations are reset when draw() begins again. Technically,
- * rotate() multiplies the current transformation matrix by a rotation matrix. This function can be
- * further controlled by the pushMatrix() and popMatrix().
- *
- * @param {int|float} angleInRadians angle of rotation specified in radians
- *
- * @returns none
- *
- * @see rotateX
- * @see rotateY
- * @see rotateZ
- * @see rotate
- * @see translate
- * @see scale
- * @see popMatrix
- * @see pushMatrix
- */
- Drawing2D.prototype.rotate = function(angleInRadians) {
- modelView.rotateZ(angleInRadians);
- modelViewInv.invRotateZ(angleInRadians);
- curContext.rotate(angleInRadians);
- };
-
- Drawing3D.prototype.rotate = function(angleInRadians) {
- if (arguments.length < 4) {
- p.rotateZ(angleInRadians);
- } else {
- modelView.rotate(angleInRadians, arguments[1], arguments[2], arguments[3]);
- modelViewInv.rotate((-angleInRadians), arguments[1], arguments[2], arguments[3]);
- }
- };
-
- /**
- * Shears a shape around the x-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to radians
- * with the radians() function. Objects are always sheared around their relative position
- * to the origin and positive numbers shear objects in a clockwise direction. Transformations
- * apply to everything that happens after and subsequent calls to the function accumulates the
- * effect. For example, calling shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI)
- *
- * @param {int|float} angleInRadians angle of rotation specified in radians
- *
- * @returns none
- *
- * @see rotateX
- * @see rotateY
- * @see rotateZ
- * @see rotate
- * @see translate
- * @see scale
- * @see popMatrix
- * @see pushMatrix
- */
-
- Drawing2D.prototype.shearX = function(angleInRadians) {
- modelView.shearX(angleInRadians);
- curContext.transform(1,0,angleInRadians,1,0,0);
- };
-
- Drawing3D.prototype.shearX = function(angleInRadians) {
- modelView.shearX(angleInRadians);
- };
-
- /**
- * Shears a shape around the y-axis the amount specified by the angle parameter.
- * Angles should be specified in radians (values from 0 to PI*2) or converted to
- * radians with the radians() function. Objects are always sheared around their
- * relative position to the origin and positive numbers shear objects in a
- * clockwise direction. Transformations apply to everything that happens after
- * and subsequent calls to the function accumulates the effect. For example,
- * calling shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI).
- *
- * @param {int|float} angleInRadians angle of rotation specified in radians
- *
- * @returns none
- *
- * @see rotateX
- * @see rotateY
- * @see rotateZ
- * @see rotate
- * @see translate
- * @see scale
- * @see popMatrix
- * @see pushMatrix
- * @see shearX
- */
-
- Drawing2D.prototype.shearY = function(angleInRadians) {
- modelView.shearY(angleInRadians);
- curContext.transform(1,angleInRadians,0,1,0,0);
- };
-
- Drawing3D.prototype.shearY = function(angleInRadians) {
- modelView.shearY(angleInRadians);
- };
-
- /**
- * The pushStyle() function saves the current style settings and popStyle() restores the prior settings.
- * Note that these functions are always used together. They allow you to change the style settings and later
- * return to what you had. When a new style is started with pushStyle(), it builds on the current style information.
- * The pushStyle() and popStyle() functions can be embedded to provide more control (see the second example
- * above for a demonstration.)
- * The style information controlled by the following functions are included in the style: fill(), stroke(), tint(),
- * strokeWeight(), strokeCap(), strokeJoin(), imageMode(), rectMode(), ellipseMode(), shapeMode(), colorMode(),
- * textAlign(), textFont(), textMode(), textSize(), textLeading(), emissive(), specular(), shininess(), ambient()
- *
- * @returns none
- *
- * @see popStyle
- */
- p.pushStyle = function() {
- // Save the canvas state.
- saveContext();
-
- p.pushMatrix();
-
- var newState = {
- 'doFill': doFill,
- 'currentFillColor': currentFillColor,
- 'doStroke': doStroke,
- 'currentStrokeColor': currentStrokeColor,
- 'curTint': curTint,
- 'curRectMode': curRectMode,
- 'curColorMode': curColorMode,
- 'colorModeX': colorModeX,
- 'colorModeZ': colorModeZ,
- 'colorModeY': colorModeY,
- 'colorModeA': colorModeA,
- 'curTextFont': curTextFont,
- 'horizontalTextAlignment': horizontalTextAlignment,
- 'verticalTextAlignment': verticalTextAlignment,
- 'textMode': textMode,
- 'curFontName': curFontName,
- 'curTextSize': curTextSize,
- 'curTextAscent': curTextAscent,
- 'curTextDescent': curTextDescent,
- 'curTextLeading': curTextLeading
- };
-
- styleArray.push(newState);
- };
-
- /**
- * The pushStyle() function saves the current style settings and popStyle() restores the prior settings; these
- * functions are always used together. They allow you to change the style settings and later return to what you had.
- * When a new style is started with pushStyle(), it builds on the current style information. The pushStyle() and
- * popStyle() functions can be embedded to provide more control (see the second example above for a demonstration.)
- *
- * @returns none
- *
- * @see pushStyle
- */
- p.popStyle = function() {
- var oldState = styleArray.pop();
-
- if (oldState) {
- restoreContext();
-
- p.popMatrix();
-
- doFill = oldState.doFill;
- currentFillColor = oldState.currentFillColor;
- doStroke = oldState.doStroke;
- currentStrokeColor = oldState.currentStrokeColor;
- curTint = oldState.curTint;
- curRectMode = oldState.curRectMode;
- curColorMode = oldState.curColorMode;
- colorModeX = oldState.colorModeX;
- colorModeZ = oldState.colorModeZ;
- colorModeY = oldState.colorModeY;
- colorModeA = oldState.colorModeA;
- curTextFont = oldState.curTextFont;
- curFontName = oldState.curFontName;
- curTextSize = oldState.curTextSize;
- horizontalTextAlignment = oldState.horizontalTextAlignment;
- verticalTextAlignment = oldState.verticalTextAlignment;
- textMode = oldState.textMode;
- curTextAscent = oldState.curTextAscent;
- curTextDescent = oldState.curTextDescent;
- curTextLeading = oldState.curTextLeading;
- } else {
- throw "Too many popStyle() without enough pushStyle()";
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Time based functions
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Processing communicates with the clock on your computer.
- * The year() function returns the current year as an integer (2003, 2004, 2005, etc).
- *
- * @returns {float} The current year.
- *
- * @see millis
- * @see second
- * @see minute
- * @see hour
- * @see day
- * @see month
- */
- p.year = function() {
- return new Date().getFullYear();
- };
- /**
- * Processing communicates with the clock on your computer.
- * The month() function returns the current month as a value from 1 - 12.
- *
- * @returns {float} The current month.
- *
- * @see millis
- * @see second
- * @see minute
- * @see hour
- * @see day
- * @see year
- */
- p.month = function() {
- return new Date().getMonth() + 1;
- };
- /**
- * Processing communicates with the clock on your computer.
- * The day() function returns the current day as a value from 1 - 31.
- *
- * @returns {float} The current day.
- *
- * @see millis
- * @see second
- * @see minute
- * @see hour
- * @see month
- * @see year
- */
- p.day = function() {
- return new Date().getDate();
- };
- /**
- * Processing communicates with the clock on your computer.
- * The hour() function returns the current hour as a value from 0 - 23.
- *
- * @returns {float} The current hour.
- *
- * @see millis
- * @see second
- * @see minute
- * @see month
- * @see day
- * @see year
- */
- p.hour = function() {
- return new Date().getHours();
- };
- /**
- * Processing communicates with the clock on your computer.
- * The minute() function returns the current minute as a value from 0 - 59.
- *
- * @returns {float} The current minute.
- *
- * @see millis
- * @see second
- * @see month
- * @see hour
- * @see day
- * @see year
- */
- p.minute = function() {
- return new Date().getMinutes();
- };
- /**
- * Processing communicates with the clock on your computer.
- * The second() function returns the current second as a value from 0 - 59.
- *
- * @returns {float} The current minute.
- *
- * @see millis
- * @see month
- * @see minute
- * @see hour
- * @see day
- * @see year
- */
- p.second = function() {
- return new Date().getSeconds();
- };
- /**
- * Returns the number of milliseconds (thousandths of a second) since starting a sketch.
- * This information is often used for timing animation sequences.
- *
- * @returns {long} The number of milliseconds since starting the sketch.
- *
- * @see month
- * @see second
- * @see minute
- * @see hour
- * @see day
- * @see year
- */
- p.millis = function() {
- return Date.now() - start;
- };
-
- /**
- * Executes the code within draw() one time. This functions allows the program to update
- * the display window only when necessary, for example when an event registered by
- * mousePressed() or keyPressed() occurs.
- * In structuring a program, it only makes sense to call redraw() within events such as
- * mousePressed(). This is because redraw() does not run draw() immediately (it only sets
- * a flag that indicates an update is needed).
- * Calling redraw() within draw() has no effect because draw() is continuously called anyway.
- *
- * @returns none
- *
- * @see noLoop
- * @see loop
- */
- function redrawHelper() {
- var sec = (Date.now() - timeSinceLastFPS) / 1000;
- framesSinceLastFPS++;
- var fps = framesSinceLastFPS / sec;
-
- // recalculate FPS every half second for better accuracy.
- if (sec > 0.5) {
- timeSinceLastFPS = Date.now();
- framesSinceLastFPS = 0;
- p.__frameRate = fps;
- }
-
- p.frameCount++;
- }
-
- Drawing2D.prototype.redraw = function() {
- redrawHelper();
-
- curContext.lineWidth = lineWidth;
- var pmouseXLastEvent = p.pmouseX,
- pmouseYLastEvent = p.pmouseY;
- p.pmouseX = pmouseXLastFrame;
- p.pmouseY = pmouseYLastFrame;
-
- saveContext();
- p.draw();
- restoreContext();
-
- pmouseXLastFrame = p.mouseX;
- pmouseYLastFrame = p.mouseY;
- p.pmouseX = pmouseXLastEvent;
- p.pmouseY = pmouseYLastEvent;
- };
-
- Drawing3D.prototype.redraw = function() {
- redrawHelper();
-
- var pmouseXLastEvent = p.pmouseX,
- pmouseYLastEvent = p.pmouseY;
- p.pmouseX = pmouseXLastFrame;
- p.pmouseY = pmouseYLastFrame;
- // even if the color buffer isn't cleared with background(),
- // the depth buffer needs to be cleared regardless.
- curContext.clear(curContext.DEPTH_BUFFER_BIT);
- curContextCache = { attributes: {}, locations: {} };
- // Delete all the lighting states and the materials the
- // user set in the last draw() call.
- p.noLights();
- p.lightFalloff(1, 0, 0);
- p.shininess(1);
- p.ambient(255, 255, 255);
- p.specular(0, 0, 0);
- p.emissive(0, 0, 0);
- p.camera();
- p.draw();
-
- pmouseXLastFrame = p.mouseX;
- pmouseYLastFrame = p.mouseY;
- p.pmouseX = pmouseXLastEvent;
- p.pmouseY = pmouseYLastEvent;
- };
-
- /**
- * Stops Processing from continuously executing the code within draw(). If loop() is
- * called, the code in draw() begin to run continuously again. If using noLoop() in
- * setup(), it should be the last line inside the block.
- * When noLoop() is used, it's not possible to manipulate or access the screen inside event
- * handling functions such as mousePressed() or keyPressed(). Instead, use those functions
- * to call redraw() or loop(), which will run draw(), which can update the screen properly.
- * This means that when noLoop() has been called, no drawing can happen, and functions like
- * saveFrame() or loadPixels() may not be used.
- * Note that if the sketch is resized, redraw() will be called to update the sketch, even
- * after noLoop() has been specified. Otherwise, the sketch would enter an odd state until
- * loop() was called.
- *
- * @returns none
- *
- * @see redraw
- * @see draw
- * @see loop
- */
- p.noLoop = function() {
- doLoop = false;
- loopStarted = false;
- clearInterval(looping);
- curSketch.onPause();
- };
-
- /**
- * Causes Processing to continuously execute the code within draw(). If noLoop() is called,
- * the code in draw() stops executing.
- *
- * @returns none
- *
- * @see noLoop
- */
- p.loop = function() {
- if (loopStarted) {
- return;
- }
-
- timeSinceLastFPS = Date.now();
- framesSinceLastFPS = 0;
-
- looping = window.setInterval(function() {
- try {
- curSketch.onFrameStart();
- p.redraw();
- curSketch.onFrameEnd();
- } catch(e_loop) {
- window.clearInterval(looping);
- throw e_loop;
- }
- }, curMsPerFrame);
- doLoop = true;
- loopStarted = true;
- curSketch.onLoop();
- };
-
- /**
- * Specifies the number of frames to be displayed every second. If the processor is not
- * fast enough to maintain the specified rate, it will not be achieved. For example, the
- * function call frameRate(30) will attempt to refresh 30 times a second. It is recommended
- * to set the frame rate within setup(). The default rate is 60 frames per second.
- *
- * @param {int} aRate number of frames per second.
- *
- * @returns none
- *
- * @see delay
- */
- p.frameRate = function(aRate) {
- curFrameRate = aRate;
- curMsPerFrame = 1000 / curFrameRate;
-
- // clear and reset interval
- if (doLoop) {
- p.noLoop();
- p.loop();
- }
- };
-
- /**
- * Quits/stops/exits the program.
- * Rather than terminating immediately, exit() will cause the sketch to exit after draw()
- * has completed (or after setup() completes if called during the setup() method).
- *
- * @returns none
- */
- p.exit = function() {
- // cleanup
- window.clearInterval(looping);
- removeInstance(p.externals.canvas.id);
- delete(curElement.onmousedown);
-
- // Step through the libraries to detach them
- for (var lib in Processing.lib) {
- if (Processing.lib.hasOwnProperty(lib)) {
- if (Processing.lib[lib].hasOwnProperty("detach")) {
- Processing.lib[lib].detach(p);
- }
- }
- }
-
- // clean up all event handling
- var i = eventHandlers.length;
- while (i--) {
- detachEventHandler(eventHandlers[i]);
- }
- curSketch.onExit();
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // MISC functions
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Sets the cursor to a predefined symbol, an image, or turns it on if already hidden.
- * If you are trying to set an image as the cursor, it is recommended to make the size
- * 16x16 or 32x32 pixels. It is not possible to load an image as the cursor if you are
- * exporting your program for the Web. The values for parameters x and y must be less
- * than the dimensions of the image.
- *
- * @param {MODE} MODE either ARROW, CROSS, HAND, MOVE, TEXT, WAIT
- * @param {PImage} image any variable of type PImage
- * @param {int} x the horizonal active spot of the cursor
- * @param {int} y the vertical active spot of the cursor
- *
- * @returns none
- *
- * @see noCursor
- */
- p.cursor = function() {
- if (arguments.length > 1 || (arguments.length === 1 && arguments[0] instanceof p.PImage)) {
- var image = arguments[0],
- x, y;
- if (arguments.length >= 3) {
- x = arguments[1];
- y = arguments[2];
- if (x < 0 || y < 0 || y >= image.height || x >= image.width) {
- throw "x and y must be non-negative and less than the dimensions of the image";
- }
- } else {
- x = image.width >>> 1;
- y = image.height >>> 1;
- }
-
- // see https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
- var imageDataURL = image.toDataURL();
- var style = "url(\"" + imageDataURL + "\") " + x + " " + y + ", default";
- curCursor = curElement.style.cursor = style;
- } else if (arguments.length === 1) {
- var mode = arguments[0];
- curCursor = curElement.style.cursor = mode;
- } else {
- curCursor = curElement.style.cursor = oldCursor;
- }
- };
-
- /**
- * Hides the cursor from view.
- *
- * @returns none
- *
- * @see cursor
- */
- p.noCursor = function() {
- curCursor = curElement.style.cursor = PConstants.NOCURSOR;
- };
-
- /**
- * Links to a webpage either in the same window or in a new window. The complete URL
- * must be specified.
- *
- * @param {String} href complete url as a String in quotes
- * @param {String} target name of the window to load the URL as a string in quotes
- *
- * @returns none
- */
- p.link = function(href, target) {
- if (target !== undef) {
- window.open(href, target);
- } else {
- window.location = href;
- }
- };
-
- // PGraphics methods
- // These functions exist only for compatibility with P5
- p.beginDraw = noop;
- p.endDraw = noop;
-
- /**
- * This function takes content from a canvas and turns it into an ImageData object to be used with a PImage
- *
- * @returns {ImageData} ImageData object to attach to a PImage (1D array of pixel data)
- *
- * @see PImage
- */
- Drawing2D.prototype.toImageData = function(x, y, w, h) {
- x = x !== undef ? x : 0;
- y = y !== undef ? y : 0;
- w = w !== undef ? w : p.width;
- h = h !== undef ? h : p.height;
- return curContext.getImageData(x, y, w, h);
- };
-
- Drawing3D.prototype.toImageData = function(x, y, w, h) {
- x = x !== undef ? x : 0;
- y = y !== undef ? y : 0;
- w = w !== undef ? w : p.width;
- h = h !== undef ? h : p.height;
- var c = document.createElement("canvas"),
- ctx = c.getContext("2d"),
- obj = ctx.createImageData(w, h),
- uBuff = new Uint8Array(w * h * 4);
- curContext.readPixels(x, y, w, h, curContext.RGBA, curContext.UNSIGNED_BYTE, uBuff);
- for (var i=0, ul=uBuff.length, obj_data=obj.data; i < ul; i++) {
- obj_data[i] = uBuff[(h - 1 - Math.floor(i / 4 / w)) * w * 4 + (i % (w * 4))];
- }
- return obj;
- };
-
- /**
- * Displays message in the browser's status area. This is the text area in the lower
- * left corner of the browser. The status() function will only work when the
- * Processing program is running in a web browser.
- *
- * @param {String} text any valid String
- *
- * @returns none
- */
- p.status = function(text) {
- window.status = text;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Binary Functions
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Converts a byte, char, int, or color to a String containing the equivalent binary
- * notation. For example color(0, 102, 153, 255) will convert to the String
- * "11111111000000000110011010011001". This function can help make your geeky debugging
- * sessions much happier.
- *
- * @param {byte|char|int|color} num byte, char, int, color: value to convert
- * @param {int} numBits number of digits to return
- *
- * @returns {String}
- *
- * @see unhex
- * @see hex
- * @see unbinary
- */
- p.binary = function(num, numBits) {
- var bit;
- if (numBits > 0) {
- bit = numBits;
- } else if(num instanceof Char) {
- bit = 16;
- num |= 0; // making it int
- } else {
- // autodetect, skipping zeros
- bit = 32;
- while (bit > 1 && !((num >>> (bit - 1)) & 1)) {
- bit--;
- }
- }
- var result = "";
- while (bit > 0) {
- result += ((num >>> (--bit)) & 1) ? "1" : "0";
- }
- return result;
- };
-
- /**
- * Converts a String representation of a binary number to its equivalent integer value.
- * For example, unbinary("00001000") will return 8.
- *
- * @param {String} binaryString String
- *
- * @returns {Int}
- *
- * @see hex
- * @see binary
- * @see unbinary
- */
- p.unbinary = function(binaryString) {
- var i = binaryString.length - 1, mask = 1, result = 0;
- while (i >= 0) {
- var ch = binaryString[i--];
- if (ch !== '0' && ch !== '1') {
- throw "the value passed into unbinary was not an 8 bit binary number";
- }
- if (ch === '1') {
- result += mask;
- }
- mask <<= 1;
- }
- return result;
- };
-
- var decimalToHex = function(d, padding) {
- //if there is no padding value added, default padding to 8 else go into while statement.
- padding = (padding === undef || padding === null) ? padding = 8 : padding;
- if (d < 0) {
- d = 0xFFFFFFFF + d + 1;
- }
- var hex = Number(d).toString(16).toUpperCase();
- while (hex.length < padding) {
- hex = "0" + hex;
- }
- if (hex.length >= padding) {
- hex = hex.substring(hex.length - padding, hex.length);
- }
- return hex;
- };
-
- // note: since we cannot keep track of byte, int types by default the returned string is 8 chars long
- // if no 2nd argument is passed. closest compromise we can use to match java implementation Feb 5 2010
- // also the char parser has issues with chars that are not digits or letters IE: !@#$%^&*
- /**
- * Converts a byte, char, int, or color to a String containing the equivalent hexadecimal notation.
- * For example color(0, 102, 153, 255) will convert to the String "FF006699". This function can help
- * make your geeky debugging sessions much happier.
- *
- * @param {byte|char|int|Color} value the value to turn into a hex string
- * @param {int} digits the number of digits to return
- *
- * @returns {String}
- *
- * @see unhex
- * @see binary
- * @see unbinary
- */
- p.hex = function(value, len) {
- if (arguments.length === 1) {
- if (value instanceof Char) {
- len = 4;
- } else { // int or byte, indistinguishable at the moment, default to 8
- len = 8;
- }
- }
- return decimalToHex(value, len);
- };
-
- function unhexScalar(hex) {
- var value = parseInt("0x" + hex, 16);
-
- // correct for int overflow java expectation
- if (value > 2147483647) {
- value -= 4294967296;
- }
- return value;
- }
-
- /**
- * Converts a String representation of a hexadecimal number to its equivalent integer value.
- *
- * @param {String} hex the hex string to convert to an int
- *
- * @returns {int}
- *
- * @see hex
- * @see binary
- * @see unbinary
- */
- p.unhex = function(hex) {
- if (hex instanceof Array) {
- var arr = [];
- for (var i = 0; i < hex.length; i++) {
- arr.push(unhexScalar(hex[i]));
- }
- return arr;
- }
- return unhexScalar(hex);
- };
-
- // Load a file or URL into strings
- /**
- * Reads the contents of a file or url and creates a String array of its individual lines.
- * The filename parameter can also be a URL to a file found online. If the file is not available or an error occurs,
- * null will be returned and an error message will be printed to the console. The error message does not halt
- * the program.
- *
- * @param {String} filename name of the file or url to load
- *
- * @returns {String[]}
- *
- * @see loadBytes
- * @see saveStrings
- * @see saveBytes
- */
- p.loadStrings = function(filename) {
- if (localStorage[filename]) {
- return localStorage[filename].split("\n");
- }
-
- var filecontent = ajax(filename);
- if(typeof filecontent !== "string" || filecontent === "") {
- return [];
- }
-
- // deal with the fact that Windows uses \r\n, Unix uses \n,
- // Mac uses \r, and we actually expect \n
- filecontent = filecontent.replace(/(\r\n?)/g,"\n").replace(/\n$/,"");
-
- return filecontent.split("\n");
- };
-
- // Writes an array of strings to a file, one line per string
- /**
- * Writes an array of strings to a file, one line per string. This file is saved to the localStorage.
- *
- * @param {String} filename name of the file to save to localStorage
- * @param {String[]} strings string array to be written
- *
- * @see loadBytes
- * @see loadStrings
- * @see saveBytes
- */
- p.saveStrings = function(filename, strings) {
- localStorage[filename] = strings.join('\n');
- };
-
- /**
- * Reads the contents of a file or url and places it in a byte array. If a file is specified, it must be located in the localStorage.
- * The filename parameter can also be a URL to a file found online.
- *
- * @param {String} filename name of a file in the localStorage or a URL.
- *
- * @returns {byte[]}
- *
- * @see loadStrings
- * @see saveStrings
- * @see saveBytes
- */
- p.loadBytes = function(url) {
- var string = ajax(url);
- var ret = [];
-
- for (var i = 0; i < string.length; i++) {
- ret.push(string.charCodeAt(i));
- }
-
- return ret;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // String Functions
- ////////////////////////////////////////////////////////////////////////////
- /**
- * The matchAll() function is identical to match(), except that it returns an array of all matches in
- * the specified String, rather than just the first.
- *
- * @param {String} aString the String to search inside
- * @param {String} aRegExp the regexp to be used for matching
- *
- * @return {String[]} returns an array of matches
- *
- * @see #match
- */
- p.matchAll = function(aString, aRegExp) {
- var results = [],
- latest;
- var regexp = new RegExp(aRegExp, "g");
- while ((latest = regexp.exec(aString)) !== null) {
- results.push(latest);
- if (latest[0].length === 0) {
- ++regexp.lastIndex;
- }
- }
- return results.length > 0 ? results : null;
- };
- /**
- * The match() function matches a string with a regular expression, and returns the match as an
- * array. The first index is the matching expression, and array elements
- * [1] and higher represent each of the groups (sequences found in parens).
- *
- * @param {String} str the String to be searched
- * @param {String} regexp the regexp to be used for matching
- *
- * @return {String[]} an array of matching strings
- */
- p.match = function(str, regexp) {
- return str.match(regexp);
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Other java specific functions
- ////////////////////////////////////////////////////////////////////////////
-
-
- var logBuffer = [];
-
- /**
- * The println() function writes to the console area of the Processing environment.
- * Each call to this function creates a new line of output. Individual elements can be separated with quotes ("") and joined with the string concatenation operator (+).
- *
- * @param {String} message the string to write to the console
- *
- * @see #join
- * @see #print
- */
- p.println = function() {
- Processing.logger.println.apply(Processing.logger, arguments);
- };
- /**
- * The print() function writes to the console area of the Processing environment.
- *
- * @param {String} message the string to write to the console
- *
- * @see #join
- */
- p.print = function() {
- Processing.logger.print.apply(Processing.logger, arguments);
- };
-
- // Alphanumeric chars arguments automatically converted to numbers when
- // passed in, and will come out as numbers.
- p.str = function(val) {
- if (val instanceof Array) {
- var arr = [];
- for (var i = 0; i < val.length; i++) {
- arr.push(val[i].toString() + "");
- }
- return arr;
- }
- return (val.toString() + "");
- };
-
-
- // Conversion
- function booleanScalar(val) {
- if (typeof val === 'number') {
- return val !== 0;
- }
- if (typeof val === 'boolean') {
- return val;
- }
- if (typeof val === 'string') {
- return val.toLowerCase() === 'true';
- }
- if (val instanceof Char) {
- // 1, T or t
- return val.code === 49 || val.code === 84 || val.code === 116;
- }
- }
-
- /**
- * Converts the passed parameter to the function to its boolean value.
- * It will return an array of booleans if an array is passed in.
- *
- * @param {int, byte, string} val the parameter to be converted to boolean
- * @param {int[], byte[], string[]} val the array to be converted to boolean[]
- *
- * @return {boolean|boolean[]} returns a boolean or an array of booleans
- */
- p.parseBoolean = function (val) {
- if (val instanceof Array) {
- var ret = [];
- for (var i = 0; i < val.length; i++) {
- ret.push(booleanScalar(val[i]));
- }
- return ret;
- }
- return booleanScalar(val);
- };
-
- /**
- * Converts the passed parameter to the function to its byte value.
- * A byte is a number between -128 and 127.
- * It will return an array of bytes if an array is passed in.
- *
- * @param {int, char} what the parameter to be conveted to byte
- * @param {int[], char[]} what the array to be converted to byte[]
- *
- * @return {byte|byte[]} returns a byte or an array of bytes
- */
- p.parseByte = function(what) {
- if (what instanceof Array) {
- var bytes = [];
- for (var i = 0; i < what.length; i++) {
- bytes.push((0 - (what[i] & 0x80)) | (what[i] & 0x7F));
- }
- return bytes;
- }
- return (0 - (what & 0x80)) | (what & 0x7F);
- };
-
- /**
- * Converts the passed parameter to the function to its char value.
- * It will return an array of chars if an array is passed in.
- *
- * @param {int, byte} key the parameter to be conveted to char
- * @param {int[], byte[]} key the array to be converted to char[]
- *
- * @return {char|char[]} returns a char or an array of chars
- */
- p.parseChar = function(key) {
- if (typeof key === "number") {
- return new Char(String.fromCharCode(key & 0xFFFF));
- }
- if (key instanceof Array) {
- var ret = [];
- for (var i = 0; i < key.length; i++) {
- ret.push(new Char(String.fromCharCode(key[i] & 0xFFFF)));
- }
- return ret;
- }
- throw "char() may receive only one argument of type int, byte, int[], or byte[].";
- };
-
- // Processing doc claims good argument types are: int, char, byte, boolean,
- // String, int[], char[], byte[], boolean[], String[].
- // floats should not work. However, floats with only zeroes right of the
- // decimal will work because JS converts those to int.
- function floatScalar(val) {
- if (typeof val === 'number') {
- return val;
- }
- if (typeof val === 'boolean') {
- return val ? 1 : 0;
- }
- if (typeof val === 'string') {
- return parseFloat(val);
- }
- if (val instanceof Char) {
- return val.code;
- }
- }
-
- /**
- * Converts the passed parameter to the function to its float value.
- * It will return an array of floats if an array is passed in.
- *
- * @param {int, char, boolean, string} val the parameter to be conveted to float
- * @param {int[], char[], boolean[], string[]} val the array to be converted to float[]
- *
- * @return {float|float[]} returns a float or an array of floats
- */
- p.parseFloat = function(val) {
- if (val instanceof Array) {
- var ret = [];
- for (var i = 0; i < val.length; i++) {
- ret.push(floatScalar(val[i]));
- }
- return ret;
- }
- return floatScalar(val);
- };
-
- function intScalar(val, radix) {
- if (typeof val === 'number') {
- return val & 0xFFFFFFFF;
- }
- if (typeof val === 'boolean') {
- return val ? 1 : 0;
- }
- if (typeof val === 'string') {
- var number = parseInt(val, radix || 10); // Default to decimal radix.
- return number & 0xFFFFFFFF;
- }
- if (val instanceof Char) {
- return val.code;
- }
- }
-
- /**
- * Converts the passed parameter to the function to its int value.
- * It will return an array of ints if an array is passed in.
- *
- * @param {string, char, boolean, float} val the parameter to be conveted to int
- * @param {string[], char[], boolean[], float[]} val the array to be converted to int[]
- * @param {int} radix optional the radix of the number (for js compatibility)
- *
- * @return {int|int[]} returns a int or an array of ints
- */
- p.parseInt = function(val, radix) {
- if (val instanceof Array) {
- var ret = [];
- for (var i = 0; i < val.length; i++) {
- if (typeof val[i] === 'string' && !/^\s*[+\-]?\d+\s*$/.test(val[i])) {
- ret.push(0);
- } else {
- ret.push(intScalar(val[i], radix));
- }
- }
- return ret;
- }
- return intScalar(val, radix);
- };
-
- p.__int_cast = function(val) {
- return 0|val;
- };
-
- p.__instanceof = function(obj, type) {
- if (typeof type !== "function") {
- throw "Function is expected as type argument for instanceof operator";
- }
-
- if (typeof obj === "string") {
- // special case for strings
- return type === Object || type === String;
- }
-
- if (obj instanceof type) {
- // fast check if obj is already of type instance
- return true;
- }
-
- if (typeof obj !== "object" || obj === null) {
- return false; // not an object or null
- }
-
- var objType = obj.constructor;
- if (type.$isInterface) {
- // expecting the interface
- // queueing interfaces from type and its base classes
- var interfaces = [];
- while (objType) {
- if (objType.$interfaces) {
- interfaces = interfaces.concat(objType.$interfaces);
- }
- objType = objType.$base;
- }
- while (interfaces.length > 0) {
- var i = interfaces.shift();
- if (i === type) {
- return true;
- }
- // wide search in base interfaces
- if (i.$interfaces) {
- interfaces = interfaces.concat(i.$interfaces);
- }
- }
- return false;
- }
-
- while (objType.hasOwnProperty("$base")) {
- objType = objType.$base;
- if (objType === type) {
- return true; // object was found
- }
- }
-
- return false;
- };
-
- /**
- * Defines the dimension of the display window in units of pixels. The size() function must
- * be the first line in setup(). If size() is not called, the default size of the window is
- * 100x100 pixels. The system variables width and height are set by the parameters passed to
- * the size() function.
- *
- * @param {int} aWidth width of the display window in units of pixels
- * @param {int} aHeight height of the display window in units of pixels
- * @param {MODE} aMode Either P2D, P3D, JAVA2D, or OPENGL
- *
- * @see createGraphics
- * @see screen
- */
- DrawingShared.prototype.size = function(aWidth, aHeight, aMode) {
- if (doStroke) {
- p.stroke(0);
- }
-
- if (doFill) {
- p.fill(255);
- }
-
- // The default 2d context has already been created in the p.init() stage if
- // a 3d context was not specified. This is so that a 2d context will be
- // available if size() was not called.
- var savedProperties = {
- fillStyle: curContext.fillStyle,
- strokeStyle: curContext.strokeStyle,
- lineCap: curContext.lineCap,
- lineJoin: curContext.lineJoin
- };
- // remove the style width and height properties to ensure that the canvas gets set to
- // aWidth and aHeight coming in
- if (curElement.style.length > 0 ) {
- curElement.style.removeProperty("width");
- curElement.style.removeProperty("height");
- }
-
- curElement.width = p.width = aWidth || 100;
- curElement.height = p.height = aHeight || 100;
-
- for (var prop in savedProperties) {
- if (savedProperties.hasOwnProperty(prop)) {
- curContext[prop] = savedProperties[prop];
- }
- }
-
- // make sure to set the default font the first time round.
- p.textFont(curTextFont);
-
- // Set the background to whatever it was called last as if background() was called before size()
- // If background() hasn't been called before, set background() to a light gray
- p.background();
-
- // set 5% for pixels to cache (or 1000)
- maxPixelsCached = Math.max(1000, aWidth * aHeight * 0.05);
-
- // Externalize the context
- p.externals.context = curContext;
-
- for (var i = 0; i < PConstants.SINCOS_LENGTH; i++) {
- sinLUT[i] = p.sin(i * (PConstants.PI / 180) * 0.5);
- cosLUT[i] = p.cos(i * (PConstants.PI / 180) * 0.5);
- }
- };
-
- Drawing2D.prototype.size = function(aWidth, aHeight, aMode) {
- if (curContext === undef) {
- // size() was called without p.init() default context, i.e. p.createGraphics()
- curContext = curElement.getContext("2d");
- userMatrixStack = new PMatrixStack();
- userReverseMatrixStack = new PMatrixStack();
- modelView = new PMatrix2D();
- modelViewInv = new PMatrix2D();
- }
-
- DrawingShared.prototype.size.apply(this, arguments);
- };
-
- Drawing3D.prototype.size = (function() {
- var size3DCalled = false;
-
- return function size(aWidth, aHeight, aMode) {
- if (size3DCalled) {
- throw "Multiple calls to size() for 3D renders are not allowed.";
- }
- size3DCalled = true;
-
- function getGLContext(canvas) {
- var ctxNames = ['experimental-webgl', 'webgl', 'webkit-3d'],
- gl;
-
- for (var i=0, l=ctxNames.length; i<l; i++) {
- gl = canvas.getContext(ctxNames[i], {antialias: false, preserveDrawingBuffer: true});
- if (gl) {
- break;
- }
- }
-
- return gl;
- }
-
- // Get the 3D rendering context.
- try {
- // If the HTML <canvas> dimensions differ from the
- // dimensions specified in the size() call in the sketch, for
- // 3D sketches, browsers will either not render or render the
- // scene incorrectly. To fix this, we need to adjust the
- // width and height attributes of the canvas.
- curElement.width = p.width = aWidth || 100;
- curElement.height = p.height = aHeight || 100;
- curContext = getGLContext(curElement);
- canTex = curContext.createTexture();
- textTex = curContext.createTexture();
- } catch(e_size) {
- Processing.debug(e_size);
- }
-
- if (!curContext) {
- throw "WebGL context is not supported on this browser.";
- }
-
- // Set defaults
- curContext.viewport(0, 0, curElement.width, curElement.height);
- curContext.enable(curContext.DEPTH_TEST);
- curContext.enable(curContext.BLEND);
- curContext.blendFunc(curContext.SRC_ALPHA, curContext.ONE_MINUS_SRC_ALPHA);
-
- // Create the program objects to render 2D (points, lines) and
- // 3D (spheres, boxes) shapes. Because 2D shapes are not lit,
- // lighting calculations are ommitted from this program object.
- programObject2D = createProgramObject(curContext, vertexShaderSrc2D, fragmentShaderSrc2D);
-
- programObjectUnlitShape = createProgramObject(curContext, vertexShaderSrcUnlitShape, fragmentShaderSrcUnlitShape);
-
- // Set the default point and line width for the 2D and unlit shapes.
- p.strokeWeight(1);
-
- // Now that the programs have been compiled, we can set the default
- // states for the lights.
- programObject3D = createProgramObject(curContext, vertexShaderSrc3D, fragmentShaderSrc3D);
- curContext.useProgram(programObject3D);
-
- // Assume we aren't using textures by default.
- uniformi("usingTexture3d", programObject3D, "usingTexture", usingTexture);
-
- // Set some defaults.
- p.lightFalloff(1, 0, 0);
- p.shininess(1);
- p.ambient(255, 255, 255);
- p.specular(0, 0, 0);
- p.emissive(0, 0, 0);
-
- // Create buffers for 3D primitives
- boxBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, boxBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, boxVerts, curContext.STATIC_DRAW);
-
- boxNormBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, boxNormBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, boxNorms, curContext.STATIC_DRAW);
-
- boxOutlineBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, boxOutlineBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, boxOutlineVerts, curContext.STATIC_DRAW);
-
- // used to draw the rectangle and the outline
- rectBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, rectBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, rectVerts, curContext.STATIC_DRAW);
-
- rectNormBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, rectNormBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, rectNorms, curContext.STATIC_DRAW);
-
- // The sphere vertices are specified dynamically since the user
- // can change the level of detail. Everytime the user does that
- // using sphereDetail(), the new vertices are calculated.
- sphereBuffer = curContext.createBuffer();
-
- lineBuffer = curContext.createBuffer();
-
- // Shape buffers
- fillBuffer = curContext.createBuffer();
- fillColorBuffer = curContext.createBuffer();
- strokeColorBuffer = curContext.createBuffer();
- shapeTexVBO = curContext.createBuffer();
-
- pointBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, pointBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 0]), curContext.STATIC_DRAW);
-
- textBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, textBuffer );
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([1,1,0,-1,1,0,-1,-1,0,1,-1,0]), curContext.STATIC_DRAW);
-
- textureBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, textureBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0,0,1,0,1,1,0,1]), curContext.STATIC_DRAW);
-
- indexBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer);
- curContext.bufferData(curContext.ELEMENT_ARRAY_BUFFER, new Uint16Array([0,1,2,2,3,0]), curContext.STATIC_DRAW);
-
- cam = new PMatrix3D();
- cameraInv = new PMatrix3D();
- modelView = new PMatrix3D();
- modelViewInv = new PMatrix3D();
- projection = new PMatrix3D();
- p.camera();
- p.perspective();
-
- userMatrixStack = new PMatrixStack();
- userReverseMatrixStack = new PMatrixStack();
- // used by both curve and bezier, so just init here
- curveBasisMatrix = new PMatrix3D();
- curveToBezierMatrix = new PMatrix3D();
- curveDrawMatrix = new PMatrix3D();
- bezierDrawMatrix = new PMatrix3D();
- bezierBasisInverse = new PMatrix3D();
- bezierBasisMatrix = new PMatrix3D();
- bezierBasisMatrix.set(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0);
-
- DrawingShared.prototype.size.apply(this, arguments);
- };
- }());
-
- ////////////////////////////////////////////////////////////////////////////
- // Lights
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Adds an ambient light. Ambient light doesn't come from a specific direction,
- * the rays have light have bounced around so much that objects are evenly lit
- * from all sides. Ambient lights are almost always used in combination with
- * other types of lights. Lights need to be included in the <b>draw()</b> to
- * remain persistent in a looping program. Placing them in the <b>setup()</b>
- * of a looping program will cause them to only have an effect the first time
- * through the loop. The effect of the parameters is determined by the current
- * color mode.
- *
- * @param {int | float} r red or hue value
- * @param {int | float} g green or hue value
- * @param {int | float} b blue or hue value
- *
- * @param {int | float} x x position of light (used for falloff)
- * @param {int | float} y y position of light (used for falloff)
- * @param {int | float} z z position of light (used for falloff)
- *
- * @returns none
- *
- * @see lights
- * @see directionalLight
- * @see pointLight
- * @see spotLight
- */
- Drawing2D.prototype.ambientLight = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.ambientLight = function(r, g, b, x, y, z) {
- if (lightCount === PConstants.MAX_LIGHTS) {
- throw "can only create " + PConstants.MAX_LIGHTS + " lights";
- }
-
- var pos = new PVector(x, y, z);
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.mult(pos, pos);
-
- // Instead of calling p.color, we do the calculations ourselves to
- // reduce property lookups.
- var col = color$4(r, g, b, 0);
- var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255,
- ((col & PConstants.GREEN_MASK) >>> 8) / 255,
- (col & PConstants.BLUE_MASK) / 255 ];
-
- curContext.useProgram(programObject3D);
- uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol);
- uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array());
- uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 0);
- uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount);
- };
-
- /**
- * Adds a directional light. Directional light comes from one direction and
- * is stronger when hitting a surface squarely and weaker if it hits at a
- * gentle angle. After hitting a surface, a directional lights scatters in
- * all directions. Lights need to be included in the <b>draw()</b> to remain
- * persistent in a looping program. Placing them in the <b>setup()</b> of a
- * looping program will cause them to only have an effect the first time
- * through the loop. The affect of the <br>r</b>, <br>g</b>, and <br>b</b>
- * parameters is determined by the current color mode. The <b>nx</b>,
- * <b>ny</b>, and <b>nz</b> parameters specify the direction the light is
- * facing. For example, setting <b>ny</b> to -1 will cause the geometry to be
- * lit from below (the light is facing directly upward).
- *
- * @param {int | float} r red or hue value
- * @param {int | float} g green or hue value
- * @param {int | float} b blue or hue value
- *
- * @param {int | float} nx direction along the x axis
- * @param {int | float} ny direction along the y axis
- * @param {int | float} nz direction along the z axis
- *
- * @returns none
- *
- * @see lights
- * @see ambientLight
- * @see pointLight
- * @see spotLight
- */
- Drawing2D.prototype.directionalLight = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.directionalLight = function(r, g, b, nx, ny, nz) {
- if (lightCount === PConstants.MAX_LIGHTS) {
- throw "can only create " + PConstants.MAX_LIGHTS + " lights";
- }
-
- curContext.useProgram(programObject3D);
-
- var mvm = new PMatrix3D();
- mvm.scale(1, -1, 1);
- mvm.apply(modelView.array());
- mvm = mvm.array();
-
- // We need to multiply the direction by the model view matrix, but
- // the mult function checks the w component of the vector, if it isn't
- // present, it uses 1, so we manually multiply.
- var dir = [
- mvm[0] * nx + mvm[4] * ny + mvm[8] * nz,
- mvm[1] * nx + mvm[5] * ny + mvm[9] * nz,
- mvm[2] * nx + mvm[6] * ny + mvm[10] * nz
- ];
-
- // Instead of calling p.color, we do the calculations ourselves to
- // reduce property lookups.
- var col = color$4(r, g, b, 0);
- var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255,
- ((col & PConstants.GREEN_MASK) >>> 8) / 255,
- (col & PConstants.BLUE_MASK) / 255 ];
-
- uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol);
- uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", dir);
- uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 1);
- uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount);
- };
-
- /**
- * Sets the falloff rates for point lights, spot lights, and ambient lights.
- * The parameters are used to determine the falloff with the following equation:
- *
- * d = distance from light position to vertex position
- * falloff = 1 / (CONSTANT + d * LINEAR + (d*d) * QUADRATIC)
- *
- * Like <b>fill()</b>, it affects only the elements which are created after it in the
- * code. The default value if <b>LightFalloff(1.0, 0.0, 0.0)</b>. Thinking about an
- * ambient light with a falloff can be tricky. It is used, for example, if you
- * wanted a region of your scene to be lit ambiently one color and another region
- * to be lit ambiently by another color, you would use an ambient light with location
- * and falloff. You can think of it as a point light that doesn't care which direction
- * a surface is facing.
- *
- * @param {int | float} constant constant value for determining falloff
- * @param {int | float} linear linear value for determining falloff
- * @param {int | float} quadratic quadratic value for determining falloff
- *
- * @returns none
- *
- * @see lights
- * @see ambientLight
- * @see pointLight
- * @see spotLight
- * @see lightSpecular
- */
- Drawing2D.prototype.lightFalloff = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.lightFalloff = function(constant, linear, quadratic) {
- curContext.useProgram(programObject3D);
- uniformf("uFalloff3d", programObject3D, "uFalloff", [constant, linear, quadratic]);
- };
-
- /**
- * Sets the specular color for lights. Like <b>fill()</b>, it affects only the
- * elements which are created after it in the code. Specular refers to light
- * which bounces off a surface in a perferred direction (rather than bouncing
- * in all directions like a diffuse light) and is used for creating highlights.
- * The specular quality of a light interacts with the specular material qualities
- * set through the <b>specular()</b> and <b>shininess()</b> functions.
- *
- * @param {int | float} r red or hue value
- * @param {int | float} g green or hue value
- * @param {int | float} b blue or hue value
- *
- * @returns none
- *
- * @see lights
- * @see ambientLight
- * @see pointLight
- * @see spotLight
- */
- Drawing2D.prototype.lightSpecular = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.lightSpecular = function(r, g, b) {
-
- // Instead of calling p.color, we do the calculations ourselves to
- // reduce property lookups.
- var col = color$4(r, g, b, 0);
- var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255,
- ((col & PConstants.GREEN_MASK) >>> 8) / 255,
- (col & PConstants.BLUE_MASK) / 255 ];
-
- curContext.useProgram(programObject3D);
- uniformf("uSpecular3d", programObject3D, "uSpecular", normalizedCol);
- };
-
- /**
- * Sets the default ambient light, directional light, falloff, and specular
- * values. The defaults are ambientLight(128, 128, 128) and
- * directionalLight(128, 128, 128, 0, 0, -1), lightFalloff(1, 0, 0), and
- * lightSpecular(0, 0, 0). Lights need to be included in the draw() to remain
- * persistent in a looping program. Placing them in the setup() of a looping
- * program will cause them to only have an effect the first time through the
- * loop.
- *
- * @returns none
- *
- * @see ambientLight
- * @see directionalLight
- * @see pointLight
- * @see spotLight
- * @see noLights
- *
- */
- p.lights = function() {
- p.ambientLight(128, 128, 128);
- p.directionalLight(128, 128, 128, 0, 0, -1);
- p.lightFalloff(1, 0, 0);
- p.lightSpecular(0, 0, 0);
- };
-
- /**
- * Adds a point light. Lights need to be included in the <b>draw()</b> to remain
- * persistent in a looping program. Placing them in the <b>setup()</b> of a
- * looping program will cause them to only have an effect the first time through
- * the loop. The affect of the <b>r</b>, <b>g</b>, and <b>b</b> parameters
- * is determined by the current color mode. The <b>x</b>, <b>y</b>, and <b>z</b>
- * parameters set the position of the light.
- *
- * @param {int | float} r red or hue value
- * @param {int | float} g green or hue value
- * @param {int | float} b blue or hue value
- * @param {int | float} x x coordinate of the light
- * @param {int | float} y y coordinate of the light
- * @param {int | float} z z coordinate of the light
- *
- * @returns none
- *
- * @see lights
- * @see directionalLight
- * @see ambientLight
- * @see spotLight
- */
- Drawing2D.prototype.pointLight = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.pointLight = function(r, g, b, x, y, z) {
- if (lightCount === PConstants.MAX_LIGHTS) {
- throw "can only create " + PConstants.MAX_LIGHTS + " lights";
- }
-
- // Place the point in view space once instead of once per vertex
- // in the shader.
- var pos = new PVector(x, y, z);
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.mult(pos, pos);
-
- // Instead of calling p.color, we do the calculations ourselves to
- // reduce property lookups.
- var col = color$4(r, g, b, 0);
- var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255,
- ((col & PConstants.GREEN_MASK) >>> 8) / 255,
- (col & PConstants.BLUE_MASK) / 255 ];
-
- curContext.useProgram(programObject3D);
- uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol);
- uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array());
- uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 2);
- uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount);
- };
-
- /**
- * Disable all lighting. Lighting is turned off by default and enabled with
- * the lights() method. This function can be used to disable lighting so
- * that 2D geometry (which does not require lighting) can be drawn after a
- * set of lighted 3D geometry.
- *
- * @returns none
- *
- * @see lights
- */
- Drawing2D.prototype.noLights = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.noLights = function() {
- lightCount = 0;
- curContext.useProgram(programObject3D);
- uniformi("uLightCount3d", programObject3D, "uLightCount", lightCount);
- };
-
- /**
- * Adds a spot light. Lights need to be included in the <b>draw()</b> to
- * remain persistent in a looping program. Placing them in the <b>setup()</b>
- * of a looping program will cause them to only have an effect the first time
- * through the loop. The affect of the <b>r</b>, <b>g</b>, and <b>b</b> parameters
- * is determined by the current color mode. The <b>x</b>, <b>y</b>, and <b>z</b>
- * parameters specify the position of the light and <b>nx</b>, <b>ny</b>, <b>nz</b>
- * specify the direction or light. The angle parameter affects <b>angle</b> of the
- * spotlight cone.
- *
- * @param {int | float} r red or hue value
- * @param {int | float} g green or hue value
- * @param {int | float} b blue or hue value
- * @param {int | float} x coordinate of the light
- * @param {int | float} y coordinate of the light
- * @param {int | float} z coordinate of the light
- * @param {int | float} nx direction along the x axis
- * @param {int | float} ny direction along the y axis
- * @param {int | float} nz direction along the z axis
- * @param {float} angle angle of the spotlight cone
- * @param {float} concentration exponent determining the center bias of the cone
- *
- * @returns none
- *
- * @see lights
- * @see directionalLight
- * @see ambientLight
- * @see pointLight
- */
- Drawing2D.prototype.spotLight = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.spotLight = function(r, g, b, x, y, z, nx, ny, nz, angle, concentration) {
- if (lightCount === PConstants.MAX_LIGHTS) {
- throw "can only create " + PConstants.MAX_LIGHTS + " lights";
- }
-
- curContext.useProgram(programObject3D);
-
- // multiply the position and direction by the model view matrix
- // once per object rather than once per vertex.
- var pos = new PVector(x, y, z);
- var mvm = new PMatrix3D();
- mvm.scale(1, -1, 1);
- mvm.apply(modelView.array());
- mvm.mult(pos, pos);
-
- // Convert to array since we need to directly access the elements.
- mvm = mvm.array();
-
- // We need to multiply the direction by the model view matrix, but
- // the mult function checks the w component of the vector, if it isn't
- // present, it uses 1, so we use a very small value as a work around.
- var dir = [
- mvm[0] * nx + mvm[4] * ny + mvm[8] * nz,
- mvm[1] * nx + mvm[5] * ny + mvm[9] * nz,
- mvm[2] * nx + mvm[6] * ny + mvm[10] * nz
- ];
-
- // Instead of calling p.color, we do the calculations ourselves to
- // reduce property lookups.
- var col = color$4(r, g, b, 0);
- var normalizedCol = [ ((col & PConstants.RED_MASK) >>> 16) / 255,
- ((col & PConstants.GREEN_MASK) >>> 8) / 255,
- (col & PConstants.BLUE_MASK) / 255 ];
-
- uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol);
- uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array());
- uniformf("uLights.direction.3d." + lightCount, programObject3D, "uLights" + lightCount + ".direction", dir);
- uniformf("uLights.concentration.3d." + lightCount, programObject3D, "uLights" + lightCount + ".concentration", concentration);
- uniformf("uLights.angle.3d." + lightCount, programObject3D, "uLights" + lightCount + ".angle", angle);
- uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 3);
- uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount);
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Camera functions
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * The <b>beginCamera()</b> and <b>endCamera()</b> functions enable advanced customization of the camera space.
- * The functions are useful if you want to more control over camera movement, however for most users, the <b>camera()</b>
- * function will be sufficient.<br /><br />The camera functions will replace any transformations (such as <b>rotate()</b>
- * or <b>translate()</b>) that occur before them in <b>draw()</b>, but they will not automatically replace the camera
- * transform itself. For this reason, camera functions should be placed at the beginning of <b>draw()</b> (so that
- * transformations happen afterwards), and the <b>camera()</b> function can be used after <b>beginCamera()</b> if
- * you want to reset the camera before applying transformations.<br /><br />This function sets the matrix mode to the
- * camera matrix so calls such as <b>translate()</b>, <b>rotate()</b>, applyMatrix() and resetMatrix() affect the camera.
- * <b>beginCamera()</b> should always be used with a following <b>endCamera()</b> and pairs of <b>beginCamera()</b> and
- * <b>endCamera()</b> cannot be nested.
- *
- * @see camera
- * @see endCamera
- * @see applyMatrix
- * @see resetMatrix
- * @see translate
- * @see rotate
- * @see scale
- */
- Drawing2D.prototype.beginCamera = function() {
- throw ("beginCamera() is not available in 2D mode");
- };
-
- Drawing3D.prototype.beginCamera = function() {
- if (manipulatingCamera) {
- throw ("You cannot call beginCamera() again before calling endCamera()");
- }
- manipulatingCamera = true;
- modelView = cameraInv;
- modelViewInv = cam;
- };
-
- /**
- * The <b>beginCamera()</b> and <b>endCamera()</b> functions enable advanced customization of the camera space.
- * Please see the reference for <b>beginCamera()</b> for a description of how the functions are used.
- *
- * @see beginCamera
- */
- Drawing2D.prototype.endCamera = function() {
- throw ("endCamera() is not available in 2D mode");
- };
-
- Drawing3D.prototype.endCamera = function() {
- if (!manipulatingCamera) {
- throw ("You cannot call endCamera() before calling beginCamera()");
- }
- modelView.set(cam);
- modelViewInv.set(cameraInv);
- manipulatingCamera = false;
- };
-
- /**
- * Sets the position of the camera through setting the eye position, the center of the scene, and which axis is facing
- * upward. Moving the eye position and the direction it is pointing (the center of the scene) allows the images to be
- * seen from different angles. The version without any parameters sets the camera to the default position, pointing to
- * the center of the display window with the Y axis as up. The default values are camera(width/2.0, height/2.0,
- * (height/2.0) / tan(PI*60.0 / 360.0), width/2.0, height/2.0, 0, 0, 1, 0). This function is similar to gluLookAt()
- * in OpenGL, but it first clears the current camera settings.
- *
- * @param {float} eyeX x-coordinate for the eye
- * @param {float} eyeY y-coordinate for the eye
- * @param {float} eyeZ z-coordinate for the eye
- * @param {float} centerX x-coordinate for the center of the scene
- * @param {float} centerY y-coordinate for the center of the scene
- * @param {float} centerZ z-coordinate for the center of the scene
- * @param {float} upX usually 0.0, 1.0, -1.0
- * @param {float} upY usually 0.0, 1.0, -1.0
- * @param {float} upZ usually 0.0, 1.0, -1.0
- *
- * @see beginCamera
- * @see endCamera
- * @see frustum
- */
- p.camera = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
- if (eyeX === undef) {
- // Workaround if createGraphics is used.
- cameraX = p.width / 2;
- cameraY = p.height / 2;
- cameraZ = cameraY / Math.tan(cameraFOV / 2);
- eyeX = cameraX;
- eyeY = cameraY;
- eyeZ = cameraZ;
- centerX = cameraX;
- centerY = cameraY;
- centerZ = 0;
- upX = 0;
- upY = 1;
- upZ = 0;
- }
-
- var z = new PVector(eyeX - centerX, eyeY - centerY, eyeZ - centerZ);
- var y = new PVector(upX, upY, upZ);
- z.normalize();
- var x = PVector.cross(y, z);
- y = PVector.cross(z, x);
- x.normalize();
- y.normalize();
-
- var xX = x.x,
- xY = x.y,
- xZ = x.z;
-
- var yX = y.x,
- yY = y.y,
- yZ = y.z;
-
- var zX = z.x,
- zY = z.y,
- zZ = z.z;
-
- cam.set(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1);
-
- cam.translate(-eyeX, -eyeY, -eyeZ);
-
- cameraInv.reset();
- cameraInv.invApply(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1);
-
- cameraInv.translate(eyeX, eyeY, eyeZ);
-
- modelView.set(cam);
- modelViewInv.set(cameraInv);
- };
-
- /**
- * Sets a perspective projection applying foreshortening, making distant objects appear smaller than closer ones. The
- * parameters define a viewing volume with the shape of truncated pyramid. Objects near to the front of the volume appear
- * their actual size, while farther objects appear smaller. This projection simulates the perspective of the world more
- * accurately than orthographic projection. The version of perspective without parameters sets the default perspective and
- * the version with four parameters allows the programmer to set the area precisely. The default values are:
- * perspective(PI/3.0, width/height, cameraZ/10.0, cameraZ*10.0) where cameraZ is ((height/2.0) / tan(PI*60.0/360.0));
- *
- * @param {float} fov field-of-view angle (in radians) for vertical direction
- * @param {float} aspect ratio of width to height
- * @param {float} zNear z-position of nearest clipping plane
- * @param {float} zFar z-positions of farthest clipping plane
- */
- p.perspective = function(fov, aspect, near, far) {
- if (arguments.length === 0) {
- //in case canvas is resized
- cameraY = curElement.height / 2;
- cameraZ = cameraY / Math.tan(cameraFOV / 2);
- cameraNear = cameraZ / 10;
- cameraFar = cameraZ * 10;
- cameraAspect = p.width / p.height;
- fov = cameraFOV;
- aspect = cameraAspect;
- near = cameraNear;
- far = cameraFar;
- }
-
- var yMax, yMin, xMax, xMin;
- yMax = near * Math.tan(fov / 2);
- yMin = -yMax;
- xMax = yMax * aspect;
- xMin = yMin * aspect;
- p.frustum(xMin, xMax, yMin, yMax, near, far);
- };
-
- /**
- * Sets a perspective matrix defined through the parameters. Works like glFrustum, except it wipes out the current
- * perspective matrix rather than muliplying itself with it.
- *
- * @param {float} left left coordinate of the clipping plane
- * @param {float} right right coordinate of the clipping plane
- * @param {float} bottom bottom coordinate of the clipping plane
- * @param {float} top top coordinate of the clipping plane
- * @param {float} near near coordinate of the clipping plane
- * @param {float} far far coordinate of the clipping plane
- *
- * @see beginCamera
- * @see camera
- * @see endCamera
- * @see perspective
- */
- Drawing2D.prototype.frustum = function() {
- throw("Processing.js: frustum() is not supported in 2D mode");
- };
-
- Drawing3D.prototype.frustum = function(left, right, bottom, top, near, far) {
- frustumMode = true;
- projection = new PMatrix3D();
- projection.set((2 * near) / (right - left), 0, (right + left) / (right - left),
- 0, 0, (2 * near) / (top - bottom), (top + bottom) / (top - bottom),
- 0, 0, 0, -(far + near) / (far - near), -(2 * far * near) / (far - near),
- 0, 0, -1, 0);
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- curContext.useProgram(programObject2D);
- uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array());
- curContext.useProgram(programObject3D);
- uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array());
- curContext.useProgram(programObjectUnlitShape);
- uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array());
- };
-
- /**
- * Sets an orthographic projection and defines a parallel clipping volume. All objects with the same dimension appear
- * the same size, regardless of whether they are near or far from the camera. The parameters to this function specify
- * the clipping volume where left and right are the minimum and maximum x values, top and bottom are the minimum and
- * maximum y values, and near and far are the minimum and maximum z values. If no parameters are given, the default
- * is used: ortho(0, width, 0, height, -10, 10).
- *
- * @param {float} left left plane of the clipping volume
- * @param {float} right right plane of the clipping volume
- * @param {float} bottom bottom plane of the clipping volume
- * @param {float} top top plane of the clipping volume
- * @param {float} near maximum distance from the origin to the viewer
- * @param {float} far maximum distance from the origin away from the viewer
- */
- p.ortho = function(left, right, bottom, top, near, far) {
- if (arguments.length === 0) {
- left = 0;
- right = p.width;
- bottom = 0;
- top = p.height;
- near = -10;
- far = 10;
- }
-
- var x = 2 / (right - left);
- var y = 2 / (top - bottom);
- var z = -2 / (far - near);
-
- var tx = -(right + left) / (right - left);
- var ty = -(top + bottom) / (top - bottom);
- var tz = -(far + near) / (far - near);
-
- projection = new PMatrix3D();
- projection.set(x, 0, 0, tx, 0, y, 0, ty, 0, 0, z, tz, 0, 0, 0, 1);
-
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- curContext.useProgram(programObject2D);
- uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array());
- curContext.useProgram(programObject3D);
- uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array());
- curContext.useProgram(programObjectUnlitShape);
- uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array());
- frustumMode = false;
- };
- /**
- * The printProjection() prints the current projection matrix to the text window.
- */
- p.printProjection = function() {
- projection.print();
- };
- /**
- * The printCamera() function prints the current camera matrix.
- */
- p.printCamera = function() {
- cam.print();
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Shapes
- ////////////////////////////////////////////////////////////////////////////
- /**
- * The box() function renders a box. A box is an extruded rectangle. A box with equal dimension on all sides is a cube.
- * Calling this function with only one parameter will create a cube.
- *
- * @param {int|float} w dimension of the box in the x-dimension
- * @param {int|float} h dimension of the box in the y-dimension
- * @param {int|float} d dimension of the box in the z-dimension
- */
- Drawing2D.prototype.box = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.box = function(w, h, d) {
- // user can uniformly scale the box by
- // passing in only one argument.
- if (!h || !d) {
- h = d = w;
- }
-
- // Modeling transformation
- var model = new PMatrix3D();
- model.scale(w, h, d);
-
- // Viewing transformation needs to have Y flipped
- // becuase that's what Processing does.
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- if (doFill) {
- curContext.useProgram(programObject3D);
- uniformMatrix("model3d", programObject3D, "uModel", false, model.array());
- uniformMatrix("view3d", programObject3D, "uView", false, view.array());
- // Fix stitching problems. (lines get occluded by triangles
- // since they share the same depth values). This is not entirely
- // working, but it's a start for drawing the outline. So
- // developers can start playing around with styles.
- curContext.enable(curContext.POLYGON_OFFSET_FILL);
- curContext.polygonOffset(1, 1);
- uniformf("color3d", programObject3D, "uColor", fillStyle);
-
- // Calculating the normal matrix can be expensive, so only
- // do it if it's necessary.
- if(lightCount > 0){
- // Create the normal transformation matrix.
- var v = new PMatrix3D();
- v.set(view);
-
- var m = new PMatrix3D();
- m.set(model);
-
- v.mult(m);
-
- var normalMatrix = new PMatrix3D();
- normalMatrix.set(v);
- normalMatrix.invert();
- normalMatrix.transpose();
-
- uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array());
- vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, boxNormBuffer);
- }
- else{
- disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal");
- }
-
- vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, boxBuffer);
-
- // Turn off per vertex colors.
- disableVertexAttribPointer("aColor3d", programObject3D, "aColor");
- disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture");
-
- curContext.drawArrays(curContext.TRIANGLES, 0, boxVerts.length / 3);
- curContext.disable(curContext.POLYGON_OFFSET_FILL);
- }
-
- // Draw the box outline.
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array());
- uniformMatrix("uView2d", programObject2D, "uView", false, view.array());
- uniformf("uColor2d", programObject2D, "uColor", strokeStyle);
- uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false);
- vertexAttribPointer("vertex2d", programObject2D, "aVertex", 3, boxOutlineBuffer);
- disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord");
- curContext.drawArrays(curContext.LINES, 0, boxOutlineVerts.length / 3);
- }
- };
-
- /**
- * The initSphere() function is a helper function used by <b>sphereDetail()</b>
- * This function creates and stores sphere vertices every time the user changes sphere detail.
- *
- * @see #sphereDetail
- */
- var initSphere = function() {
- var i;
- sphereVerts = [];
-
- for (i = 0; i < sphereDetailU; i++) {
- sphereVerts.push(0);
- sphereVerts.push(-1);
- sphereVerts.push(0);
- sphereVerts.push(sphereX[i]);
- sphereVerts.push(sphereY[i]);
- sphereVerts.push(sphereZ[i]);
- }
- sphereVerts.push(0);
- sphereVerts.push(-1);
- sphereVerts.push(0);
- sphereVerts.push(sphereX[0]);
- sphereVerts.push(sphereY[0]);
- sphereVerts.push(sphereZ[0]);
-
- var v1, v11, v2;
-
- // middle rings
- var voff = 0;
- for (i = 2; i < sphereDetailV; i++) {
- v1 = v11 = voff;
- voff += sphereDetailU;
- v2 = voff;
- for (var j = 0; j < sphereDetailU; j++) {
- sphereVerts.push(sphereX[v1]);
- sphereVerts.push(sphereY[v1]);
- sphereVerts.push(sphereZ[v1++]);
- sphereVerts.push(sphereX[v2]);
- sphereVerts.push(sphereY[v2]);
- sphereVerts.push(sphereZ[v2++]);
- }
-
- // close each ring
- v1 = v11;
- v2 = voff;
-
- sphereVerts.push(sphereX[v1]);
- sphereVerts.push(sphereY[v1]);
- sphereVerts.push(sphereZ[v1]);
- sphereVerts.push(sphereX[v2]);
- sphereVerts.push(sphereY[v2]);
- sphereVerts.push(sphereZ[v2]);
- }
-
- // add the northern cap
- for (i = 0; i < sphereDetailU; i++) {
- v2 = voff + i;
-
- sphereVerts.push(sphereX[v2]);
- sphereVerts.push(sphereY[v2]);
- sphereVerts.push(sphereZ[v2]);
- sphereVerts.push(0);
- sphereVerts.push(1);
- sphereVerts.push(0);
- }
-
- sphereVerts.push(sphereX[voff]);
- sphereVerts.push(sphereY[voff]);
- sphereVerts.push(sphereZ[voff]);
- sphereVerts.push(0);
- sphereVerts.push(1);
- sphereVerts.push(0);
-
- //set the buffer data
- curContext.bindBuffer(curContext.ARRAY_BUFFER, sphereBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(sphereVerts), curContext.STATIC_DRAW);
- };
-
- /**
- * The sphereDetail() function controls the detail used to render a sphere by adjusting the number of
- * vertices of the sphere mesh. The default resolution is 30, which creates
- * a fairly detailed sphere definition with vertices every 360/30 = 12
- * degrees. If you're going to render a great number of spheres per frame,
- * it is advised to reduce the level of detail using this function.
- * The setting stays active until <b>sphereDetail()</b> is called again with
- * a new parameter and so should <i>not</i> be called prior to every
- * <b>sphere()</b> statement, unless you wish to render spheres with
- * different settings, e.g. using less detail for smaller spheres or ones
- * further away from the camera. To control the detail of the horizontal
- * and vertical resolution independently, use the version of the functions
- * with two parameters. Calling this function with one parameter sets the number of segments
- *(minimum of 3) used per full circle revolution. This is equivalent to calling the function with
- * two identical values.
- *
- * @param {int} ures number of segments used horizontally (longitudinally) per full circle revolution
- * @param {int} vres number of segments used vertically (latitudinally) from top to bottom
- *
- * @see #sphere()
- */
- p.sphereDetail = function(ures, vres) {
- var i;
-
- if (arguments.length === 1) {
- ures = vres = arguments[0];
- }
-
- if (ures < 3) {
- ures = 3;
- } // force a minimum res
- if (vres < 2) {
- vres = 2;
- } // force a minimum res
- // if it hasn't changed do nothing
- if ((ures === sphereDetailU) && (vres === sphereDetailV)) {
- return;
- }
-
- var delta = PConstants.SINCOS_LENGTH / ures;
- var cx = new Float32Array(ures);
- var cz = new Float32Array(ures);
- // calc unit circle in XZ plane
- for (i = 0; i < ures; i++) {
- cx[i] = cosLUT[((i * delta) % PConstants.SINCOS_LENGTH) | 0];
- cz[i] = sinLUT[((i * delta) % PConstants.SINCOS_LENGTH) | 0];
- }
-
- // computing vertexlist
- // vertexlist starts at south pole
- var vertCount = ures * (vres - 1) + 2;
- var currVert = 0;
-
- // re-init arrays to store vertices
- sphereX = new Float32Array(vertCount);
- sphereY = new Float32Array(vertCount);
- sphereZ = new Float32Array(vertCount);
-
- var angle_step = (PConstants.SINCOS_LENGTH * 0.5) / vres;
- var angle = angle_step;
-
- // step along Y axis
- for (i = 1; i < vres; i++) {
- var curradius = sinLUT[(angle % PConstants.SINCOS_LENGTH) | 0];
- var currY = -cosLUT[(angle % PConstants.SINCOS_LENGTH) | 0];
- for (var j = 0; j < ures; j++) {
- sphereX[currVert] = cx[j] * curradius;
- sphereY[currVert] = currY;
- sphereZ[currVert++] = cz[j] * curradius;
- }
- angle += angle_step;
- }
- sphereDetailU = ures;
- sphereDetailV = vres;
-
- // make the sphere verts and norms
- initSphere();
- };
-
- /**
- * The sphere() function draws a sphere with radius r centered at coordinate 0, 0, 0.
- * A sphere is a hollow ball made from tessellated triangles.
- *
- * @param {int|float} r the radius of the sphere
- */
- Drawing2D.prototype.sphere = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.sphere = function() {
- var sRad = arguments[0];
-
- if ((sphereDetailU < 3) || (sphereDetailV < 2)) {
- p.sphereDetail(30);
- }
-
- // Modeling transformation.
- var model = new PMatrix3D();
- model.scale(sRad, sRad, sRad);
-
- // viewing transformation needs to have Y flipped
- // becuase that's what Processing does.
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- if (doFill) {
- // Calculating the normal matrix can be expensive, so only
- // do it if it's necessary.
- if(lightCount > 0){
- // Create a normal transformation matrix.
- var v = new PMatrix3D();
- v.set(view);
-
- var m = new PMatrix3D();
- m.set(model);
-
- v.mult(m);
-
- var normalMatrix = new PMatrix3D();
- normalMatrix.set(v);
- normalMatrix.invert();
- normalMatrix.transpose();
-
- uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array());
- vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, sphereBuffer);
- }
- else{
- disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal");
- }
-
- curContext.useProgram(programObject3D);
- disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture");
-
- uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array());
- uniformMatrix("uView3d", programObject3D, "uView", false, view.array());
- vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, sphereBuffer);
-
- // Turn off per vertex colors.
- disableVertexAttribPointer("aColor3d", programObject3D, "aColor");
-
- // fix stitching problems. (lines get occluded by triangles
- // since they share the same depth values). This is not entirely
- // working, but it's a start for drawing the outline. So
- // developers can start playing around with styles.
- curContext.enable(curContext.POLYGON_OFFSET_FILL);
- curContext.polygonOffset(1, 1);
- uniformf("uColor3d", programObject3D, "uColor", fillStyle);
- curContext.drawArrays(curContext.TRIANGLE_STRIP, 0, sphereVerts.length / 3);
- curContext.disable(curContext.POLYGON_OFFSET_FILL);
- }
-
- // Draw the sphere outline.
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array());
- uniformMatrix("uView2d", programObject2D, "uView", false, view.array());
- vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, sphereBuffer);
- disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord");
- uniformf("uColor2d", programObject2D, "uColor", strokeStyle);
- uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false);
- curContext.drawArrays(curContext.LINE_STRIP, 0, sphereVerts.length / 3);
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Coordinates
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Returns the three-dimensional X, Y, Z position in model space. This returns
- * the X value for a given coordinate based on the current set of transformations
- * (scale, rotate, translate, etc.) The X value can be used to place an object
- * in space relative to the location of the original point once the transformations
- * are no longer in use.<br />
- * <br />
- *
- * @param {int | float} x 3D x coordinate to be mapped
- * @param {int | float} y 3D y coordinate to be mapped
- * @param {int | float} z 3D z coordinate to be mapped
- *
- * @returns {float}
- *
- * @see modelY
- * @see modelZ
- */
- p.modelX = function(x, y, z) {
- var mv = modelView.array();
- var ci = cameraInv.array();
-
- var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
- var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
- var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
- var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
-
- var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw;
- var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
-
- return (ow !== 0) ? ox / ow : ox;
- };
-
- /**
- * Returns the three-dimensional X, Y, Z position in model space. This returns
- * the Y value for a given coordinate based on the current set of transformations
- * (scale, rotate, translate, etc.) The Y value can be used to place an object in
- * space relative to the location of the original point once the transformations
- * are no longer in use.<br />
- * <br />
- *
- * @param {int | float} x 3D x coordinate to be mapped
- * @param {int | float} y 3D y coordinate to be mapped
- * @param {int | float} z 3D z coordinate to be mapped
- *
- * @returns {float}
- *
- * @see modelX
- * @see modelZ
- */
- p.modelY = function(x, y, z) {
- var mv = modelView.array();
- var ci = cameraInv.array();
-
- var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
- var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
- var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
- var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
-
- var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw;
- var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
-
- return (ow !== 0) ? oy / ow : oy;
- };
-
- /**
- * Returns the three-dimensional X, Y, Z position in model space. This returns
- * the Z value for a given coordinate based on the current set of transformations
- * (scale, rotate, translate, etc.) The Z value can be used to place an object in
- * space relative to the location of the original point once the transformations
- * are no longer in use.
- *
- * @param {int | float} x 3D x coordinate to be mapped
- * @param {int | float} y 3D y coordinate to be mapped
- * @param {int | float} z 3D z coordinate to be mapped
- *
- * @returns {float}
- *
- * @see modelX
- * @see modelY
- */
- p.modelZ = function(x, y, z) {
- var mv = modelView.array();
- var ci = cameraInv.array();
-
- var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
- var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
- var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
- var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
-
- var oz = ci[8] * ax + ci[9] * ay + ci[10] * az + ci[11] * aw;
- var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
-
- return (ow !== 0) ? oz / ow : oz;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Material Properties
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Sets the ambient reflectance for shapes drawn to the screen. This is
- * combined with the ambient light component of environment. The color
- * components set through the parameters define the reflectance. For example in
- * the default color mode, setting v1=255, v2=126, v3=0, would cause all the
- * red light to reflect and half of the green light to reflect. Used in combination
- * with <b>emissive()</b>, <b>specular()</b>, and <b>shininess()</b> in setting
- * the materal properties of shapes.
- *
- * @param {int | float} gray
- *
- * @returns none
- *
- * @see emissive
- * @see specular
- * @see shininess
- */
- Drawing2D.prototype.ambient = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.ambient = function(v1, v2, v3) {
- curContext.useProgram(programObject3D);
- uniformi("uUsingMat3d", programObject3D, "uUsingMat", true);
- var col = p.color(v1, v2, v3);
- uniformf("uMaterialAmbient3d", programObject3D, "uMaterialAmbient", p.color.toGLArray(col).slice(0, 3));
- };
-
- /**
- * Sets the emissive color of the material used for drawing shapes
- * drawn to the screen. Used in combination with ambient(), specular(),
- * and shininess() in setting the material properties of shapes.
- *
- * Can be called in the following ways:
- *
- * emissive(gray)
- * @param {int | float} gray number specifying value between white and black
- *
- * emissive(color)
- * @param {color} color any value of the color datatype
- *
- * emissive(v1, v2, v3)
- * @param {int | float} v1 red or hue value
- * @param {int | float} v2 green or saturation value
- * @param {int | float} v3 blue or brightness value
- *
- * @returns none
- *
- * @see ambient
- * @see specular
- * @see shininess
- */
- Drawing2D.prototype.emissive = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.emissive = function(v1, v2, v3) {
- curContext.useProgram(programObject3D);
- uniformi("uUsingMat3d", programObject3D, "uUsingMat", true);
- var col = p.color(v1, v2, v3);
- uniformf("uMaterialEmissive3d", programObject3D, "uMaterialEmissive", p.color.toGLArray(col).slice(0, 3));
- };
-
- /**
- * Sets the amount of gloss in the surface of shapes. Used in combination with
- * <b>ambient()</b>, <b>specular()</b>, and <b>emissive()</b> in setting the
- * material properties of shapes.
- *
- * @param {float} shine degree of shininess
- *
- * @returns none
- */
- Drawing2D.prototype.shininess = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.shininess = function(shine) {
- curContext.useProgram(programObject3D);
- uniformi("uUsingMat3d", programObject3D, "uUsingMat", true);
- uniformf("uShininess3d", programObject3D, "uShininess", shine);
- };
-
- /**
- * Sets the specular color of the materials used for shapes drawn to the screen,
- * which sets the color of hightlights. Specular refers to light which bounces
- * off a surface in a perferred direction (rather than bouncing in all directions
- * like a diffuse light). Used in combination with emissive(), ambient(), and
- * shininess() in setting the material properties of shapes.
- *
- * Can be called in the following ways:
- *
- * specular(gray)
- * @param {int | float} gray number specifying value between white and black
- *
- * specular(gray, alpha)
- * @param {int | float} gray number specifying value between white and black
- * @param {int | float} alpha opacity
- *
- * specular(color)
- * @param {color} color any value of the color datatype
- *
- * specular(v1, v2, v3)
- * @param {int | float} v1 red or hue value
- * @param {int | float} v2 green or saturation value
- * @param {int | float} v3 blue or brightness value
- *
- * specular(v1, v2, v3, alpha)
- * @param {int | float} v1 red or hue value
- * @param {int | float} v2 green or saturation value
- * @param {int | float} v3 blue or brightness value
- * @param {int | float} alpha opacity
- *
- * @returns none
- *
- * @see ambient
- * @see emissive
- * @see shininess
- */
- Drawing2D.prototype.specular = DrawingShared.prototype.a3DOnlyFunction;
-
- Drawing3D.prototype.specular = function(v1, v2, v3) {
- curContext.useProgram(programObject3D);
- uniformi("uUsingMat3d", programObject3D, "uUsingMat", true);
- var col = p.color(v1, v2, v3);
- uniformf("uMaterialSpecular3d", programObject3D, "uMaterialSpecular", p.color.toGLArray(col).slice(0, 3));
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Coordinates
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Takes a three-dimensional X, Y, Z position and returns the X value for
- * where it will appear on a (two-dimensional) screen.
- *
- * @param {int | float} x 3D x coordinate to be mapped
- * @param {int | float} y 3D y coordinate to be mapped
- * @param {int | float} z 3D z optional coordinate to be mapped
- *
- * @returns {float}
- *
- * @see screenY
- * @see screenZ
- */
- p.screenX = function( x, y, z ) {
- var mv = modelView.array();
- if( mv.length === 16 )
- {
- var ax = mv[ 0]*x + mv[ 1]*y + mv[ 2]*z + mv[ 3];
- var ay = mv[ 4]*x + mv[ 5]*y + mv[ 6]*z + mv[ 7];
- var az = mv[ 8]*x + mv[ 9]*y + mv[10]*z + mv[11];
- var aw = mv[12]*x + mv[13]*y + mv[14]*z + mv[15];
-
- var pj = projection.array();
-
- var ox = pj[ 0]*ax + pj[ 1]*ay + pj[ 2]*az + pj[ 3]*aw;
- var ow = pj[12]*ax + pj[13]*ay + pj[14]*az + pj[15]*aw;
-
- if ( ow !== 0 ){
- ox /= ow;
- }
- return p.width * ( 1 + ox ) / 2.0;
- }
- // We assume that we're in 2D
- return modelView.multX(x, y);
- };
-
- /**
- * Takes a three-dimensional X, Y, Z position and returns the Y value for
- * where it will appear on a (two-dimensional) screen.
- *
- * @param {int | float} x 3D x coordinate to be mapped
- * @param {int | float} y 3D y coordinate to be mapped
- * @param {int | float} z 3D z optional coordinate to be mapped
- *
- * @returns {float}
- *
- * @see screenX
- * @see screenZ
- */
- p.screenY = function screenY( x, y, z ) {
- var mv = modelView.array();
- if( mv.length === 16 ) {
- var ax = mv[ 0]*x + mv[ 1]*y + mv[ 2]*z + mv[ 3];
- var ay = mv[ 4]*x + mv[ 5]*y + mv[ 6]*z + mv[ 7];
- var az = mv[ 8]*x + mv[ 9]*y + mv[10]*z + mv[11];
- var aw = mv[12]*x + mv[13]*y + mv[14]*z + mv[15];
-
- var pj = projection.array();
-
- var oy = pj[ 4]*ax + pj[ 5]*ay + pj[ 6]*az + pj[ 7]*aw;
- var ow = pj[12]*ax + pj[13]*ay + pj[14]*az + pj[15]*aw;
-
- if ( ow !== 0 ){
- oy /= ow;
- }
- return p.height * ( 1 + oy ) / 2.0;
- }
- // We assume that we're in 2D
- return modelView.multY(x, y);
- };
-
- /**
- * Takes a three-dimensional X, Y, Z position and returns the Z value for
- * where it will appear on a (two-dimensional) screen.
- *
- * @param {int | float} x 3D x coordinate to be mapped
- * @param {int | float} y 3D y coordinate to be mapped
- * @param {int | float} z 3D z coordinate to be mapped
- *
- * @returns {float}
- *
- * @see screenX
- * @see screenY
- */
- p.screenZ = function screenZ( x, y, z ) {
- var mv = modelView.array();
- if( mv.length !== 16 ) {
- return 0;
- }
-
- var pj = projection.array();
-
- var ax = mv[ 0]*x + mv[ 1]*y + mv[ 2]*z + mv[ 3];
- var ay = mv[ 4]*x + mv[ 5]*y + mv[ 6]*z + mv[ 7];
- var az = mv[ 8]*x + mv[ 9]*y + mv[10]*z + mv[11];
- var aw = mv[12]*x + mv[13]*y + mv[14]*z + mv[15];
-
- var oz = pj[ 8]*ax + pj[ 9]*ay + pj[10]*az + pj[11]*aw;
- var ow = pj[12]*ax + pj[13]*ay + pj[14]*az + pj[15]*aw;
-
- if ( ow !== 0 ) {
- oz /= ow;
- }
- return ( oz + 1 ) / 2.0;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Style functions
- ////////////////////////////////////////////////////////////////////////////
- /**
- * The fill() function sets the color used to fill shapes. For example, if you run <b>fill(204, 102, 0)</b>, all subsequent shapes will be filled with orange.
- * This color is either specified in terms of the RGB or HSB color depending on the current <b>colorMode()</b>
- *(the default color space is RGB, with each value in the range from 0 to 255).
- * <br><br>When using hexadecimal notation to specify a color, use "#" or "0x" before the values (e.g. #CCFFAA, 0xFFCCFFAA).
- * The # syntax uses six digits to specify a color (the way colors are specified in HTML and CSS). When using the hexadecimal notation starting with "0x",
- * the hexadecimal value must be specified with eight characters; the first two characters define the alpha component and the remainder the red, green, and blue components.
- * <br><br>The value for the parameter "gray" must be less than or equal to the current maximum value as specified by <b>colorMode()</b>. The default maximum value is 255.
- * <br><br>To change the color of an image (or a texture), use tint().
- *
- * @param {int|float} gray number specifying value between white and black
- * @param {int|float} value1 red or hue value
- * @param {int|float} value2 green or saturation value
- * @param {int|float} value3 blue or brightness value
- * @param {int|float} alpha opacity of the fill
- * @param {Color} color any value of the color datatype
- * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00)
- *
- * @see #noFill()
- * @see #stroke()
- * @see #tint()
- * @see #background()
- * @see #colorMode()
- */
- DrawingShared.prototype.fill = function() {
- var color = p.color.apply(this, arguments);
- if(color === currentFillColor && doFill) {
- return;
- }
- doFill = true;
- currentFillColor = color;
- };
-
- Drawing2D.prototype.fill = function() {
- DrawingShared.prototype.fill.apply(this, arguments);
- isFillDirty = true;
- };
-
- Drawing3D.prototype.fill = function() {
- DrawingShared.prototype.fill.apply(this, arguments);
- fillStyle = p.color.toGLArray(currentFillColor);
- };
-
- function executeContextFill() {
- if(doFill) {
- if(isFillDirty) {
- curContext.fillStyle = p.color.toString(currentFillColor);
- isFillDirty = false;
- }
- curContext.fill();
- }
- }
-
- /**
- * The noFill() function disables filling geometry. If both <b>noStroke()</b> and <b>noFill()</b>
- * are called, no shapes will be drawn to the screen.
- *
- * @see #fill()
- *
- */
- p.noFill = function() {
- doFill = false;
- };
-
- /**
- * The stroke() function sets the color used to draw lines and borders around shapes. This color
- * is either specified in terms of the RGB or HSB color depending on the
- * current <b>colorMode()</b> (the default color space is RGB, with each
- * value in the range from 0 to 255).
- * <br><br>When using hexadecimal notation to specify a color, use "#" or
- * "0x" before the values (e.g. #CCFFAA, 0xFFCCFFAA). The # syntax uses six
- * digits to specify a color (the way colors are specified in HTML and CSS).
- * When using the hexadecimal notation starting with "0x", the hexadecimal
- * value must be specified with eight characters; the first two characters
- * define the alpha component and the remainder the red, green, and blue
- * components.
- * <br><br>The value for the parameter "gray" must be less than or equal
- * to the current maximum value as specified by <b>colorMode()</b>.
- * The default maximum value is 255.
- *
- * @param {int|float} gray number specifying value between white and black
- * @param {int|float} value1 red or hue value
- * @param {int|float} value2 green or saturation value
- * @param {int|float} value3 blue or brightness value
- * @param {int|float} alpha opacity of the stroke
- * @param {Color} color any value of the color datatype
- * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00)
- *
- * @see #fill()
- * @see #noStroke()
- * @see #tint()
- * @see #background()
- * @see #colorMode()
- */
- DrawingShared.prototype.stroke = function() {
- var color = p.color.apply(this, arguments);
- if(color === currentStrokeColor && doStroke) {
- return;
- }
- doStroke = true;
- currentStrokeColor = color;
- };
-
- Drawing2D.prototype.stroke = function() {
- DrawingShared.prototype.stroke.apply(this, arguments);
- isStrokeDirty = true;
- };
-
- Drawing3D.prototype.stroke = function() {
- DrawingShared.prototype.stroke.apply(this, arguments);
- strokeStyle = p.color.toGLArray(currentStrokeColor);
- };
-
- function executeContextStroke() {
- if(doStroke) {
- if(isStrokeDirty) {
- curContext.strokeStyle = p.color.toString(currentStrokeColor);
- isStrokeDirty = false;
- }
- curContext.stroke();
- }
- }
-
- /**
- * The noStroke() function disables drawing the stroke (outline). If both <b>noStroke()</b> and
- * <b>noFill()</b> are called, no shapes will be drawn to the screen.
- *
- * @see #stroke()
- */
- p.noStroke = function() {
- doStroke = false;
- };
-
- /**
- * The strokeWeight() function sets the width of the stroke used for lines, points, and the border around shapes.
- * All widths are set in units of pixels.
- *
- * @param {int|float} w the weight (in pixels) of the stroke
- */
- DrawingShared.prototype.strokeWeight = function(w) {
- lineWidth = w;
- };
-
- Drawing2D.prototype.strokeWeight = function(w) {
- DrawingShared.prototype.strokeWeight.apply(this, arguments);
- curContext.lineWidth = w;
- };
-
- Drawing3D.prototype.strokeWeight = function(w) {
- DrawingShared.prototype.strokeWeight.apply(this, arguments);
-
- // Processing groups the weight of points and lines under this one function,
- // but for WebGL, we need to set a uniform for points and call a function for line.
-
- curContext.useProgram(programObject2D);
- uniformf("pointSize2d", programObject2D, "uPointSize", w);
-
- curContext.useProgram(programObjectUnlitShape);
- uniformf("pointSizeUnlitShape", programObjectUnlitShape, "uPointSize", w);
-
- curContext.lineWidth(w);
- };
-
- /**
- * The strokeCap() function sets the style for rendering line endings. These ends are either squared, extended, or rounded and
- * specified with the corresponding parameters SQUARE, PROJECT, and ROUND. The default cap is ROUND.
- * This function is not available with the P2D, P3D, or OPENGL renderers
- *
- * @param {int} value Either SQUARE, PROJECT, or ROUND
- */
- p.strokeCap = function(value) {
- drawing.$ensureContext().lineCap = value;
- };
-
- /**
- * The strokeJoin() function sets the style of the joints which connect line segments.
- * These joints are either mitered, beveled, or rounded and specified with the corresponding parameters MITER, BEVEL, and ROUND. The default joint is MITER.
- * This function is not available with the P2D, P3D, or OPENGL renderers
- *
- * @param {int} value Either SQUARE, PROJECT, or ROUND
- */
- p.strokeJoin = function(value) {
- drawing.$ensureContext().lineJoin = value;
- };
-
- /**
- * The smooth() function draws all geometry with smooth (anti-aliased) edges. This will slow down the frame rate of the application,
- * but will enhance the visual refinement. <br/><br/>
- * Note that smooth() will also improve image quality of resized images, and noSmooth() will disable image (and font) smoothing altogether.
- * When working with a 3D sketch, smooth will draw points as circles rather than squares.
- *
- * @see #noSmooth()
- * @see #hint()
- * @see #size()
- */
-
- Drawing2D.prototype.smooth = function() {
- renderSmooth = true;
- var style = curElement.style;
- style.setProperty("image-rendering", "optimizeQuality", "important");
- style.setProperty("-ms-interpolation-mode", "bicubic", "important");
- if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) {
- curContext.mozImageSmoothingEnabled = true;
- }
- };
-
- Drawing3D.prototype.smooth = function(){
- renderSmooth = true;
- };
-
- /**
- * The noSmooth() function draws all geometry with jagged (aliased) edges.
- *
- * @see #smooth()
- */
-
- Drawing2D.prototype.noSmooth = function() {
- renderSmooth = false;
- var style = curElement.style;
- style.setProperty("image-rendering", "optimizeSpeed", "important");
- style.setProperty("image-rendering", "-moz-crisp-edges", "important");
- style.setProperty("image-rendering", "-webkit-optimize-contrast", "important");
- style.setProperty("image-rendering", "optimize-contrast", "important");
- style.setProperty("-ms-interpolation-mode", "nearest-neighbor", "important");
- if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) {
- curContext.mozImageSmoothingEnabled = false;
- }
- };
-
- Drawing3D.prototype.noSmooth = function(){
- renderSmooth = false;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Vector drawing functions
- ////////////////////////////////////////////////////////////////////////////
- /**
- * The point() function draws a point, a coordinate in space at the dimension of one pixel.
- * The first parameter is the horizontal value for the point, the second
- * value is the vertical value for the point, and the optional third value
- * is the depth value. Drawing this shape in 3D using the <b>z</b>
- * parameter requires the P3D or OPENGL parameter in combination with
- * size as shown in the above example.
- *
- * @param {int|float} x x-coordinate of the point
- * @param {int|float} y y-coordinate of the point
- * @param {int|float} z z-coordinate of the point
- *
- * @see #beginShape()
- */
- Drawing2D.prototype.point = function(x, y) {
- if (!doStroke) {
- return;
- }
- if (!renderSmooth) {
- x = Math.round(x);
- y = Math.round(y);
- }
- curContext.fillStyle = p.color.toString(currentStrokeColor);
- isFillDirty = true;
- // Draw a circle for any point larger than 1px
- if (lineWidth > 1) {
- curContext.beginPath();
- curContext.arc(x, y, lineWidth / 2, 0, PConstants.TWO_PI, false);
- curContext.fill();
- } else {
- curContext.fillRect(x, y, 1, 1);
- }
- };
-
- Drawing3D.prototype.point = function(x, y, z) {
- var model = new PMatrix3D();
-
- // move point to position
- model.translate(x, y, z || 0);
- model.transpose();
-
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- curContext.useProgram(programObject2D);
- uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array());
- uniformMatrix("uView2d", programObject2D, "uView", false, view.array());
-
- if (lineWidth > 0 && doStroke) {
- // this will be replaced with the new bit shifting color code
- uniformf("uColor2d", programObject2D, "uColor", strokeStyle);
- uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false);
- uniformi("uSmooth2d", programObject2D, "uSmooth", renderSmooth);
- vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, pointBuffer);
- disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord");
- curContext.drawArrays(curContext.POINTS, 0, 1);
- }
- };
-
- /**
- * Using the <b>beginShape()</b> and <b>endShape()</b> functions allow creating more complex forms.
- * <b>beginShape()</b> begins recording vertices for a shape and <b>endShape()</b> stops recording.
- * The value of the <b>MODE</b> parameter tells it which types of shapes to create from the provided vertices.
- * With no mode specified, the shape can be any irregular polygon. After calling the <b>beginShape()</b> function,
- * a series of <b>vertex()</b> commands must follow. To stop drawing the shape, call <b>endShape()</b>.
- * The <b>vertex()</b> function with two parameters specifies a position in 2D and the <b>vertex()</b>
- * function with three parameters specifies a position in 3D. Each shape will be outlined with the current
- * stroke color and filled with the fill color.
- *
- * @param {int} MODE either POINTS, LINES, TRIANGLES, TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP.
- *
- * @see endShape
- * @see vertex
- * @see curveVertex
- * @see bezierVertex
- */
- p.beginShape = function(type) {
- curShape = type;
- curvePoints = [];
- vertArray = [];
- };
-
- /**
- * All shapes are constructed by connecting a series of vertices. <b>vertex()</b> is used to specify the vertex
- * coordinates for points, lines, triangles, quads, and polygons and is used exclusively within the <b>beginShape()</b>
- * and <b>endShape()</b> function. <br /><br />Drawing a vertex in 3D using the <b>z</b> parameter requires the P3D or
- * OPENGL parameter in combination with size as shown in the above example.<br /><br />This function is also used to map a
- * texture onto the geometry. The <b>texture()</b> function declares the texture to apply to the geometry and the <b>u</b>
- * and <b>v</b> coordinates set define the mapping of this texture to the form. By default, the coordinates used for
- * <b>u</b> and <b>v</b> are specified in relation to the image's size in pixels, but this relation can be changed with
- * <b>textureMode()</b>.
- *
- * @param {int | float} x x-coordinate of the vertex
- * @param {int | float} y y-coordinate of the vertex
- * @param {boolean} moveto flag to indicate whether this is a new subpath
- *
- * @see beginShape
- * @see endShape
- * @see bezierVertex
- * @see curveVertex
- * @see texture
- */
-
- Drawing2D.prototype.vertex = function(x, y, moveTo) {
- var vert = [];
-
- if (firstVert) { firstVert = false; }
- vert.isVert = true;
-
- vert[0] = x;
- vert[1] = y;
- vert[2] = 0;
- vert[3] = 0;
- vert[4] = 0;
-
- // fill and stroke color
- vert[5] = currentFillColor;
- vert[6] = currentStrokeColor;
-
- vertArray.push(vert);
- if (moveTo) {
- vertArray[vertArray.length-1].moveTo = moveTo;
- }
- };
-
- Drawing3D.prototype.vertex = function(x, y, z, u, v) {
- var vert = [];
-
- if (firstVert) { firstVert = false; }
- vert.isVert = true;
-
- if (v === undef && usingTexture) {
- v = u;
- u = z;
- z = 0;
- }
-
- // Convert u and v to normalized coordinates
- if (u !== undef && v !== undef) {
- if (curTextureMode === PConstants.IMAGE) {
- u /= curTexture.width;
- v /= curTexture.height;
- }
- u = u > 1 ? 1 : u;
- u = u < 0 ? 0 : u;
- v = v > 1 ? 1 : v;
- v = v < 0 ? 0 : v;
- }
-
- vert[0] = x;
- vert[1] = y;
- vert[2] = z || 0;
- vert[3] = u || 0;
- vert[4] = v || 0;
-
- // fill rgba
- vert[5] = fillStyle[0];
- vert[6] = fillStyle[1];
- vert[7] = fillStyle[2];
- vert[8] = fillStyle[3];
- // stroke rgba
- vert[9] = strokeStyle[0];
- vert[10] = strokeStyle[1];
- vert[11] = strokeStyle[2];
- vert[12] = strokeStyle[3];
- //normals
- vert[13] = normalX;
- vert[14] = normalY;
- vert[15] = normalZ;
-
- vertArray.push(vert);
- };
-
- /**
- * @private
- * Renders 3D points created from calls to vertex and beginShape/endShape
- *
- * @param {Array} vArray an array of vertex coordinate
- * @param {Array} cArray an array of colours used for the vertices
- *
- * @see beginShape
- * @see endShape
- * @see vertex
- */
- var point3D = function(vArray, cArray){
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- curContext.useProgram(programObjectUnlitShape);
-
- uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array());
- uniformi("uSmoothUS", programObjectUnlitShape, "uSmooth", renderSmooth);
-
- vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, pointBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW);
-
- vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, fillColorBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW);
-
- curContext.drawArrays(curContext.POINTS, 0, vArray.length/3);
- };
-
- /**
- * @private
- * Renders 3D lines created from calls to beginShape/vertex/endShape - based on the mode specified LINES, LINE_LOOP, etc.
- *
- * @param {Array} vArray an array of vertex coordinate
- * @param {String} mode either LINES, LINE_LOOP, or LINE_STRIP
- * @param {Array} cArray an array of colours used for the vertices
- *
- * @see beginShape
- * @see endShape
- * @see vertex
- */
- var line3D = function(vArray, mode, cArray){
- var ctxMode;
- if (mode === "LINES"){
- ctxMode = curContext.LINES;
- }
- else if(mode === "LINE_LOOP"){
- ctxMode = curContext.LINE_LOOP;
- }
- else{
- ctxMode = curContext.LINE_STRIP;
- }
-
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- curContext.useProgram(programObjectUnlitShape);
- uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array());
- vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, lineBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW);
- vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, strokeColorBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW);
- curContext.drawArrays(ctxMode, 0, vArray.length/3);
- };
-
- /**
- * @private
- * Render filled shapes created from calls to beginShape/vertex/endShape - based on the mode specified TRIANGLES, etc.
- *
- * @param {Array} vArray an array of vertex coordinate
- * @param {String} mode either LINES, LINE_LOOP, or LINE_STRIP
- * @param {Array} cArray an array of colours used for the vertices
- * @param {Array} tArray an array of u,v coordinates for textures
- *
- * @see beginShape
- * @see endShape
- * @see vertex
- */
- var fill3D = function(vArray, mode, cArray, tArray){
- var ctxMode;
- if (mode === "TRIANGLES") {
- ctxMode = curContext.TRIANGLES;
- } else if(mode === "TRIANGLE_FAN") {
- ctxMode = curContext.TRIANGLE_FAN;
- } else {
- ctxMode = curContext.TRIANGLE_STRIP;
- }
-
- var view = new PMatrix3D();
- view.scale( 1, -1, 1 );
- view.apply( modelView.array() );
- view.transpose();
-
- curContext.useProgram( programObject3D );
- uniformMatrix( "model3d", programObject3D, "uModel", false, [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] );
- uniformMatrix( "view3d", programObject3D, "uView", false, view.array() );
- curContext.enable( curContext.POLYGON_OFFSET_FILL );
- curContext.polygonOffset( 1, 1 );
- uniformf( "color3d", programObject3D, "uColor", [-1,0,0,0] );
- vertexAttribPointer( "vertex3d", programObject3D, "aVertex", 3, fillBuffer );
- curContext.bufferData( curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW );
-
- // if we are using a texture and a tint, then overwrite the
- // contents of the color buffer with the current tint
- if ( usingTexture && curTint !== null ){
- curTint3d( cArray );
- }
-
- vertexAttribPointer( "aColor3d", programObject3D, "aColor", 4, fillColorBuffer );
- curContext.bufferData( curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW );
-
- // No support for lights....yet
- disableVertexAttribPointer( "aNormal3d", programObject3D, "aNormal" );
-
- if ( usingTexture ) {
- uniformi( "uUsingTexture3d", programObject3D, "uUsingTexture", usingTexture );
- vertexAttribPointer( "aTexture3d", programObject3D, "aTexture", 2, shapeTexVBO );
- curContext.bufferData( curContext.ARRAY_BUFFER, new Float32Array(tArray), curContext.STREAM_DRAW );
- }
-
- curContext.drawArrays( ctxMode, 0, vArray.length/3 );
- curContext.disable( curContext.POLYGON_OFFSET_FILL );
- };
-
- /**
- * this series of three operations is used a lot in Drawing2D.prototype.endShape
- * and has been split off as its own function, to tighten the code and allow for
- * fewer bugs.
- */
- function fillStrokeClose() {
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
-
- /**
- * The endShape() function is the companion to beginShape() and may only be called after beginShape().
- * When endshape() is called, all of image data defined since the previous call to beginShape() is written
- * into the image buffer.
- *
- * @param {int} MODE Use CLOSE to close the shape
- *
- * @see beginShape
- */
- Drawing2D.prototype.endShape = function(mode) {
- // Duplicated in Drawing3D; too many variables used
- if (vertArray.length === 0) { return; }
-
- var closeShape = mode === PConstants.CLOSE;
-
- // if the shape is closed, the first element is also the last element
- if (closeShape) {
- vertArray.push(vertArray[0]);
- }
-
- var lineVertArray = [];
- var fillVertArray = [];
- var colorVertArray = [];
- var strokeVertArray = [];
- var texVertArray = [];
- var cachedVertArray;
-
- firstVert = true;
- var i, j, k;
- var vertArrayLength = vertArray.length;
-
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- fillVertArray.push(cachedVertArray[j]);
- }
- }
-
- // 5,6,7,8
- // R,G,B,A - fill colour
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 5; j < 9; j++) {
- colorVertArray.push(cachedVertArray[j]);
- }
- }
-
- // 9,10,11,12
- // R, G, B, A - stroke colour
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(cachedVertArray[j]);
- }
- }
-
- // texture u,v
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- texVertArray.push(cachedVertArray[3]);
- texVertArray.push(cachedVertArray[4]);
- }
-
- // curveVertex
- if ( isCurve && (curShape === PConstants.POLYGON || curShape === undef) ) {
- if (vertArrayLength > 3) {
- var b = [],
- s = 1 - curTightness;
- curContext.beginPath();
- curContext.moveTo(vertArray[1][0], vertArray[1][1]);
- /*
- * Matrix to convert from Catmull-Rom to cubic Bezier
- * where t = curTightness
- * |0 1 0 0 |
- * |(t-1)/6 1 (1-t)/6 0 |
- * |0 (1-t)/6 1 (t-1)/6 |
- * |0 0 0 0 |
- */
- for (i = 1; (i+2) < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- b[0] = [cachedVertArray[0], cachedVertArray[1]];
- b[1] = [cachedVertArray[0] + (s * vertArray[i+1][0] - s * vertArray[i-1][0]) / 6,
- cachedVertArray[1] + (s * vertArray[i+1][1] - s * vertArray[i-1][1]) / 6];
- b[2] = [vertArray[i+1][0] + (s * vertArray[i][0] - s * vertArray[i+2][0]) / 6,
- vertArray[i+1][1] + (s * vertArray[i][1] - s * vertArray[i+2][1]) / 6];
- b[3] = [vertArray[i+1][0], vertArray[i+1][1]];
- curContext.bezierCurveTo(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]);
- }
- fillStrokeClose();
- }
- }
-
- // bezierVertex
- else if ( isBezier && (curShape === PConstants.POLYGON || curShape === undef) ) {
- curContext.beginPath();
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- if (vertArray[i].isVert) { //if it is a vertex move to the position
- if (vertArray[i].moveTo) {
- curContext.moveTo(cachedVertArray[0], cachedVertArray[1]);
- } else {
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
- }
- } else { //otherwise continue drawing bezier
- curContext.bezierCurveTo(vertArray[i][0], vertArray[i][1], vertArray[i][2], vertArray[i][3], vertArray[i][4], vertArray[i][5]);
- }
- }
- fillStrokeClose();
- }
-
- // render the vertices provided
- else {
- if (curShape === PConstants.POINTS) {
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- if (doStroke) {
- p.stroke(cachedVertArray[6]);
- }
- p.point(cachedVertArray[0], cachedVertArray[1]);
- }
- } else if (curShape === PConstants.LINES) {
- for (i = 0; (i + 1) < vertArrayLength; i+=2) {
- cachedVertArray = vertArray[i];
- if (doStroke) {
- p.stroke(vertArray[i+1][6]);
- }
- p.line(cachedVertArray[0], cachedVertArray[1], vertArray[i+1][0], vertArray[i+1][1]);
- }
- } else if (curShape === PConstants.TRIANGLES) {
- for (i = 0; (i + 2) < vertArrayLength; i+=3) {
- cachedVertArray = vertArray[i];
- curContext.beginPath();
- curContext.moveTo(cachedVertArray[0], cachedVertArray[1]);
- curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]);
- curContext.lineTo(vertArray[i+2][0], vertArray[i+2][1]);
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
-
- if (doFill) {
- p.fill(vertArray[i+2][5]);
- executeContextFill();
- }
- if (doStroke) {
- p.stroke(vertArray[i+2][6]);
- executeContextStroke();
- }
-
- curContext.closePath();
- }
- } else if (curShape === PConstants.TRIANGLE_STRIP) {
- for (i = 0; (i+1) < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- curContext.beginPath();
- curContext.moveTo(vertArray[i+1][0], vertArray[i+1][1]);
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
-
- if (doStroke) {
- p.stroke(vertArray[i+1][6]);
- }
- if (doFill) {
- p.fill(vertArray[i+1][5]);
- }
-
- if (i + 2 < vertArrayLength) {
- curContext.lineTo(vertArray[i+2][0], vertArray[i+2][1]);
- if (doStroke) {
- p.stroke(vertArray[i+2][6]);
- }
- if (doFill) {
- p.fill(vertArray[i+2][5]);
- }
- }
- fillStrokeClose();
- }
- } else if (curShape === PConstants.TRIANGLE_FAN) {
- if (vertArrayLength > 2) {
- curContext.beginPath();
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- curContext.lineTo(vertArray[1][0], vertArray[1][1]);
- curContext.lineTo(vertArray[2][0], vertArray[2][1]);
-
- if (doFill) {
- p.fill(vertArray[2][5]);
- executeContextFill();
- }
- if (doStroke) {
- p.stroke(vertArray[2][6]);
- executeContextStroke();
- }
-
- curContext.closePath();
- for (i = 3; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- curContext.beginPath();
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- curContext.lineTo(vertArray[i-1][0], vertArray[i-1][1]);
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
-
- if (doFill) {
- p.fill(cachedVertArray[5]);
- executeContextFill();
- }
- if (doStroke) {
- p.stroke(cachedVertArray[6]);
- executeContextStroke();
- }
-
- curContext.closePath();
- }
- }
- } else if (curShape === PConstants.QUADS) {
- for (i = 0; (i + 3) < vertArrayLength; i+=4) {
- cachedVertArray = vertArray[i];
- curContext.beginPath();
- curContext.moveTo(cachedVertArray[0], cachedVertArray[1]);
- for (j = 1; j < 4; j++) {
- curContext.lineTo(vertArray[i+j][0], vertArray[i+j][1]);
- }
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
-
- if (doFill) {
- p.fill(vertArray[i+3][5]);
- executeContextFill();
- }
- if (doStroke) {
- p.stroke(vertArray[i+3][6]);
- executeContextStroke();
- }
-
- curContext.closePath();
- }
- } else if (curShape === PConstants.QUAD_STRIP) {
- if (vertArrayLength > 3) {
- for (i = 0; (i+1) < vertArrayLength; i+=2) {
- cachedVertArray = vertArray[i];
- curContext.beginPath();
- if (i+3 < vertArrayLength) {
- curContext.moveTo(vertArray[i+2][0], vertArray[i+2][1]);
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
- curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]);
- curContext.lineTo(vertArray[i+3][0], vertArray[i+3][1]);
-
- if (doFill) {
- p.fill(vertArray[i+3][5]);
- }
- if (doStroke) {
- p.stroke(vertArray[i+3][6]);
- }
- } else {
- curContext.moveTo(cachedVertArray[0], cachedVertArray[1]);
- curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]);
- }
- fillStrokeClose();
- }
- }
- } else {
- curContext.beginPath();
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- for (i = 1; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- if (cachedVertArray.isVert) { //if it is a vertex move to the position
- if (cachedVertArray.moveTo) {
- curContext.moveTo(cachedVertArray[0], cachedVertArray[1]);
- } else {
- curContext.lineTo(cachedVertArray[0], cachedVertArray[1]);
- }
- }
- }
- fillStrokeClose();
- }
- }
-
- // Reset some settings
- isCurve = false;
- isBezier = false;
- curveVertArray = [];
- curveVertCount = 0;
-
- // If the shape is closed, the first element was added as last element.
- // We must remove it again to prevent the list of vertices from growing
- // over successive calls to endShape(CLOSE)
- if (closeShape) {
- vertArray.pop();
- }
- };
-
- Drawing3D.prototype.endShape = function(mode) {
- // Duplicated in Drawing3D; too many variables used
- if (vertArray.length === 0) { return; }
-
- var closeShape = mode === PConstants.CLOSE;
- var lineVertArray = [];
- var fillVertArray = [];
- var colorVertArray = [];
- var strokeVertArray = [];
- var texVertArray = [];
- var cachedVertArray;
-
- firstVert = true;
- var i, j, k;
- var vertArrayLength = vertArray.length;
-
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- fillVertArray.push(cachedVertArray[j]);
- }
- }
-
- // 5,6,7,8
- // R,G,B,A - fill colour
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 5; j < 9; j++) {
- colorVertArray.push(cachedVertArray[j]);
- }
- }
-
- // 9,10,11,12
- // R, G, B, A - stroke colour
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(cachedVertArray[j]);
- }
- }
-
- // texture u,v
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- texVertArray.push(cachedVertArray[3]);
- texVertArray.push(cachedVertArray[4]);
- }
-
- // if shape is closed, push the first point into the last point (including colours)
- if (closeShape) {
- fillVertArray.push(vertArray[0][0]);
- fillVertArray.push(vertArray[0][1]);
- fillVertArray.push(vertArray[0][2]);
-
- for (i = 5; i < 9; i++) {
- colorVertArray.push(vertArray[0][i]);
- }
-
- for (i = 9; i < 13; i++) {
- strokeVertArray.push(vertArray[0][i]);
- }
-
- texVertArray.push(vertArray[0][3]);
- texVertArray.push(vertArray[0][4]);
- }
- // End duplication
-
- // curveVertex
- if ( isCurve && (curShape === PConstants.POLYGON || curShape === undef) ) {
- lineVertArray = fillVertArray;
- if (doStroke) {
- line3D(lineVertArray, null, strokeVertArray);
- }
- if (doFill) {
- fill3D(fillVertArray, null, colorVertArray);
- }
- }
- // bezierVertex
- else if ( isBezier && (curShape === PConstants.POLYGON || curShape === undef) ) {
- lineVertArray = fillVertArray;
- lineVertArray.splice(lineVertArray.length - 3);
- strokeVertArray.splice(strokeVertArray.length - 4);
- if (doStroke) {
- line3D(lineVertArray, null, strokeVertArray);
- }
- if (doFill) {
- fill3D(fillVertArray, "TRIANGLES", colorVertArray);
- }
- }
-
- // render the vertices provided
- else {
- if (curShape === PConstants.POINTS) { // if POINTS was the specified parameter in beginShape
- for (i = 0; i < vertArrayLength; i++) { // loop through and push the point location information to the array
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- lineVertArray.push(cachedVertArray[j]);
- }
- }
- point3D(lineVertArray, strokeVertArray); // render function for points
- } else if (curShape === PConstants.LINES) { // if LINES was the specified parameter in beginShape
- for (i = 0; i < vertArrayLength; i++) { // loop through and push the point location information to the array
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- lineVertArray.push(cachedVertArray[j]);
- }
- }
- for (i = 0; i < vertArrayLength; i++) { // loop through and push the color information to the array
- cachedVertArray = vertArray[i];
- for (j = 5; j < 9; j++) {
- colorVertArray.push(cachedVertArray[j]);
- }
- }
- line3D(lineVertArray, "LINES", strokeVertArray); // render function for lines
- } else if (curShape === PConstants.TRIANGLES) { // if TRIANGLES was the specified parameter in beginShape
- if (vertArrayLength > 2) {
- for (i = 0; (i+2) < vertArrayLength; i+=3) { // loop through the array per triangle
- fillVertArray = [];
- texVertArray = [];
- lineVertArray = [];
- colorVertArray = [];
- strokeVertArray = [];
- for (j = 0; j < 3; j++) {
- for (k = 0; k < 3; k++) { // loop through and push
- lineVertArray.push(vertArray[i+j][k]); // the line point location information
- fillVertArray.push(vertArray[i+j][k]); // and fill point location information
- }
- }
- for (j = 0; j < 3; j++) { // loop through and push the texture information
- for (k = 3; k < 5; k++) {
- texVertArray.push(vertArray[i+j][k]);
- }
- }
- for (j = 0; j < 3; j++) {
- for (k = 5; k < 9; k++) { // loop through and push
- colorVertArray.push(vertArray[i+j][k]); // the colour information
- strokeVertArray.push(vertArray[i+j][k+4]);// and the stroke information
- }
- }
- if (doStroke) {
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray ); // line render function
- }
- if (doFill || usingTexture) {
- fill3D(fillVertArray, "TRIANGLES", colorVertArray, texVertArray); // fill shape render function
- }
- }
- }
- } else if (curShape === PConstants.TRIANGLE_STRIP) { // if TRIANGLE_STRIP was the specified parameter in beginShape
- if (vertArrayLength > 2) {
- for (i = 0; (i+2) < vertArrayLength; i++) {
- lineVertArray = [];
- fillVertArray = [];
- strokeVertArray = [];
- colorVertArray = [];
- texVertArray = [];
- for (j = 0; j < 3; j++) {
- for (k = 0; k < 3; k++) {
- lineVertArray.push(vertArray[i+j][k]);
- fillVertArray.push(vertArray[i+j][k]);
- }
- }
- for (j = 0; j < 3; j++) {
- for (k = 3; k < 5; k++) {
- texVertArray.push(vertArray[i+j][k]);
- }
- }
- for (j = 0; j < 3; j++) {
- for (k = 5; k < 9; k++) {
- strokeVertArray.push(vertArray[i+j][k+4]);
- colorVertArray.push(vertArray[i+j][k]);
- }
- }
-
- if (doFill || usingTexture) {
- fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray);
- }
- if (doStroke) {
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray);
- }
- }
- }
- } else if (curShape === PConstants.TRIANGLE_FAN) {
- if (vertArrayLength > 2) {
- for (i = 0; i < 3; i++) {
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- lineVertArray.push(cachedVertArray[j]);
- }
- }
- for (i = 0; i < 3; i++) {
- cachedVertArray = vertArray[i];
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(cachedVertArray[j]);
- }
- }
- if (doStroke) {
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray);
- }
-
- for (i = 2; (i+1) < vertArrayLength; i++) {
- lineVertArray = [];
- strokeVertArray = [];
- lineVertArray.push(vertArray[0][0]);
- lineVertArray.push(vertArray[0][1]);
- lineVertArray.push(vertArray[0][2]);
-
- strokeVertArray.push(vertArray[0][9]);
- strokeVertArray.push(vertArray[0][10]);
- strokeVertArray.push(vertArray[0][11]);
- strokeVertArray.push(vertArray[0][12]);
-
- for (j = 0; j < 2; j++) {
- for (k = 0; k < 3; k++) {
- lineVertArray.push(vertArray[i+j][k]);
- }
- }
- for (j = 0; j < 2; j++) {
- for (k = 9; k < 13; k++) {
- strokeVertArray.push(vertArray[i+j][k]);
- }
- }
- if (doStroke) {
- line3D(lineVertArray, "LINE_STRIP",strokeVertArray);
- }
- }
- if (doFill || usingTexture) {
- fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray);
- }
- }
- } else if (curShape === PConstants.QUADS) {
- for (i = 0; (i + 3) < vertArrayLength; i+=4) {
- lineVertArray = [];
- for (j = 0; j < 4; j++) {
- cachedVertArray = vertArray[i+j];
- for (k = 0; k < 3; k++) {
- lineVertArray.push(cachedVertArray[k]);
- }
- }
- if (doStroke) {
- line3D(lineVertArray, "LINE_LOOP",strokeVertArray);
- }
-
- if (doFill) {
- fillVertArray = [];
- colorVertArray = [];
- texVertArray = [];
- for (j = 0; j < 3; j++) {
- fillVertArray.push(vertArray[i][j]);
- }
- for (j = 5; j < 9; j++) {
- colorVertArray.push(vertArray[i][j]);
- }
-
- for (j = 0; j < 3; j++) {
- fillVertArray.push(vertArray[i+1][j]);
- }
- for (j = 5; j < 9; j++) {
- colorVertArray.push(vertArray[i+1][j]);
- }
-
- for (j = 0; j < 3; j++) {
- fillVertArray.push(vertArray[i+3][j]);
- }
- for (j = 5; j < 9; j++) {
- colorVertArray.push(vertArray[i+3][j]);
- }
-
- for (j = 0; j < 3; j++) {
- fillVertArray.push(vertArray[i+2][j]);
- }
- for (j = 5; j < 9; j++) {
- colorVertArray.push(vertArray[i+2][j]);
- }
-
- if (usingTexture) {
- texVertArray.push(vertArray[i+0][3]);
- texVertArray.push(vertArray[i+0][4]);
- texVertArray.push(vertArray[i+1][3]);
- texVertArray.push(vertArray[i+1][4]);
- texVertArray.push(vertArray[i+3][3]);
- texVertArray.push(vertArray[i+3][4]);
- texVertArray.push(vertArray[i+2][3]);
- texVertArray.push(vertArray[i+2][4]);
- }
-
- fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray);
- }
- }
- } else if (curShape === PConstants.QUAD_STRIP) {
- var tempArray = [];
- if (vertArrayLength > 3) {
- for (i = 0; i < 2; i++) {
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- lineVertArray.push(cachedVertArray[j]);
- }
- }
-
- for (i = 0; i < 2; i++) {
- cachedVertArray = vertArray[i];
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(cachedVertArray[j]);
- }
- }
-
- line3D(lineVertArray, "LINE_STRIP", strokeVertArray);
- if (vertArrayLength > 4 && vertArrayLength % 2 > 0) {
- tempArray = fillVertArray.splice(fillVertArray.length - 3);
- vertArray.pop();
- }
- for (i = 0; (i+3) < vertArrayLength; i+=2) {
- lineVertArray = [];
- strokeVertArray = [];
- for (j = 0; j < 3; j++) {
- lineVertArray.push(vertArray[i+1][j]);
- }
- for (j = 0; j < 3; j++) {
- lineVertArray.push(vertArray[i+3][j]);
- }
- for (j = 0; j < 3; j++) {
- lineVertArray.push(vertArray[i+2][j]);
- }
- for (j = 0; j < 3; j++) {
- lineVertArray.push(vertArray[i+0][j]);
- }
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(vertArray[i+1][j]);
- }
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(vertArray[i+3][j]);
- }
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(vertArray[i+2][j]);
- }
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(vertArray[i+0][j]);
- }
- if (doStroke) {
- line3D(lineVertArray, "LINE_STRIP", strokeVertArray);
- }
- }
-
- if (doFill || usingTexture) {
- fill3D(fillVertArray, "TRIANGLE_LIST", colorVertArray, texVertArray);
- }
- }
- }
- // If the user didn't specify a type (LINES, TRIANGLES, etc)
- else {
- // If only one vertex was specified, it must be a point
- if (vertArrayLength === 1) {
- for (j = 0; j < 3; j++) {
- lineVertArray.push(vertArray[0][j]);
- }
- for (j = 9; j < 13; j++) {
- strokeVertArray.push(vertArray[0][j]);
- }
- point3D(lineVertArray,strokeVertArray);
- } else {
- for (i = 0; i < vertArrayLength; i++) {
- cachedVertArray = vertArray[i];
- for (j = 0; j < 3; j++) {
- lineVertArray.push(cachedVertArray[j]);
- }
- for (j = 5; j < 9; j++) {
- strokeVertArray.push(cachedVertArray[j]);
- }
- }
- if (doStroke && closeShape) {
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray);
- } else if (doStroke && !closeShape) {
- line3D(lineVertArray, "LINE_STRIP", strokeVertArray);
- }
-
- // fill is ignored if textures are used
- if (doFill || usingTexture) {
- fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray);
- }
- }
- }
- // everytime beginShape is followed by a call to
- // texture(), texturing it turned back on. We do this to
- // figure out if the shape should be textured or filled
- // with a color.
- usingTexture = false;
- curContext.useProgram(programObject3D);
- uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture);
- }
-
- // Reset some settings
- isCurve = false;
- isBezier = false;
- curveVertArray = [];
- curveVertCount = 0;
- };
-
- /**
- * The function splineForward() setup forward-differencing matrix to be used for speedy
- * curve rendering. It's based on using a specific number
- * of curve segments and just doing incremental adds for each
- * vertex of the segment, rather than running the mathematically
- * expensive cubic equation. This function is used by both curveDetail and bezierDetail.
- *
- * @param {int} segments number of curve segments to use when drawing
- * @param {PMatrix3D} matrix target object for the new matrix
- */
- var splineForward = function(segments, matrix) {
- var f = 1.0 / segments;
- var ff = f * f;
- var fff = ff * f;
-
- matrix.set(0, 0, 0, 1, fff, ff, f, 0, 6 * fff, 2 * ff, 0, 0, 6 * fff, 0, 0, 0);
- };
-
- /**
- * The curveInit() function set the number of segments to use when drawing a Catmull-Rom
- * curve, and setting the s parameter, which defines how tightly
- * the curve fits to each vertex. Catmull-Rom curves are actually
- * a subset of this curve type where the s is set to zero.
- * This in an internal function used by curveDetail() and curveTightness().
- */
- var curveInit = function() {
- // allocate only if/when used to save startup time
- if (!curveDrawMatrix) {
- curveBasisMatrix = new PMatrix3D();
- curveDrawMatrix = new PMatrix3D();
- curveInited = true;
- }
-
- var s = curTightness;
- curveBasisMatrix.set((s - 1) / 2, (s + 3) / 2, (-3 - s) / 2, (1 - s) / 2,
- (1 - s), (-5 - s) / 2, (s + 2), (s - 1) / 2,
- (s - 1) / 2, 0, (1 - s) / 2, 0, 0, 1, 0, 0);
-
- splineForward(curveDet, curveDrawMatrix);
-
- if (!bezierBasisInverse) {
- //bezierBasisInverse = bezierBasisMatrix.get();
- //bezierBasisInverse.invert();
- curveToBezierMatrix = new PMatrix3D();
- }
-
- // TODO only needed for PGraphicsJava2D? if so, move it there
- // actually, it's generally useful for other renderers, so keep it
- // or hide the implementation elsewhere.
- curveToBezierMatrix.set(curveBasisMatrix);
- curveToBezierMatrix.preApply(bezierBasisInverse);
-
- // multiply the basis and forward diff matrices together
- // saves much time since this needn't be done for each curve
- curveDrawMatrix.apply(curveBasisMatrix);
- };
-
- /**
- * Specifies vertex coordinates for Bezier curves. Each call to <b>bezierVertex()</b> defines the position of two control
- * points and one anchor point of a Bezier curve, adding a new segment to a line or shape. The first time
- * <b>bezierVertex()</b> is used within a <b>beginShape()</b> call, it must be prefaced with a call to <b>vertex()</b>
- * to set the first anchor point. This function must be used between <b>beginShape()</b> and <b>endShape()</b> and only
- * when there is no MODE parameter specified to <b>beginShape()</b>. Using the 3D version of requires rendering with P3D
- * or OPENGL (see the Environment reference for more information). <br /> <br /> <b>NOTE: </b> Fill does not work properly yet.
- *
- * @param {float | int} cx1 The x-coordinate of 1st control point
- * @param {float | int} cy1 The y-coordinate of 1st control point
- * @param {float | int} cz1 The z-coordinate of 1st control point
- * @param {float | int} cx2 The x-coordinate of 2nd control point
- * @param {float | int} cy2 The y-coordinate of 2nd control point
- * @param {float | int} cz2 The z-coordinate of 2nd control point
- * @param {float | int} x The x-coordinate of the anchor point
- * @param {float | int} y The y-coordinate of the anchor point
- * @param {float | int} z The z-coordinate of the anchor point
- *
- * @see curveVertex
- * @see vertex
- * @see bezier
- */
- Drawing2D.prototype.bezierVertex = function() {
- isBezier = true;
- var vert = [];
- if (firstVert) {
- throw ("vertex() must be used at least once before calling bezierVertex()");
- }
-
- for (var i = 0; i < arguments.length; i++) {
- vert[i] = arguments[i];
- }
- vertArray.push(vert);
- vertArray[vertArray.length -1].isVert = false;
- };
-
- Drawing3D.prototype.bezierVertex = function() {
- isBezier = true;
- var vert = [];
- if (firstVert) {
- throw ("vertex() must be used at least once before calling bezierVertex()");
- }
-
- if (arguments.length === 9) {
- if (bezierDrawMatrix === undef) {
- bezierDrawMatrix = new PMatrix3D();
- }
- // setup matrix for forward differencing to speed up drawing
- var lastPoint = vertArray.length - 1;
- splineForward( bezDetail, bezierDrawMatrix );
- bezierDrawMatrix.apply( bezierBasisMatrix );
- var draw = bezierDrawMatrix.array();
- var x1 = vertArray[lastPoint][0],
- y1 = vertArray[lastPoint][1],
- z1 = vertArray[lastPoint][2];
- var xplot1 = draw[4] * x1 + draw[5] * arguments[0] + draw[6] * arguments[3] + draw[7] * arguments[6];
- var xplot2 = draw[8] * x1 + draw[9] * arguments[0] + draw[10]* arguments[3] + draw[11]* arguments[6];
- var xplot3 = draw[12]* x1 + draw[13]* arguments[0] + draw[14]* arguments[3] + draw[15]* arguments[6];
-
- var yplot1 = draw[4] * y1 + draw[5] * arguments[1] + draw[6] * arguments[4] + draw[7] * arguments[7];
- var yplot2 = draw[8] * y1 + draw[9] * arguments[1] + draw[10]* arguments[4] + draw[11]* arguments[7];
- var yplot3 = draw[12]* y1 + draw[13]* arguments[1] + draw[14]* arguments[4] + draw[15]* arguments[7];
-
- var zplot1 = draw[4] * z1 + draw[5] * arguments[2] + draw[6] * arguments[5] + draw[7] * arguments[8];
- var zplot2 = draw[8] * z1 + draw[9] * arguments[2] + draw[10]* arguments[5] + draw[11]* arguments[8];
- var zplot3 = draw[12]* z1 + draw[13]* arguments[2] + draw[14]* arguments[5] + draw[15]* arguments[8];
- for (var j = 0; j < bezDetail; j++) {
- x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
- y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
- z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
- p.vertex(x1, y1, z1);
- }
- p.vertex(arguments[6], arguments[7], arguments[8]);
- }
- };
-
- /**
- * Sets a texture to be applied to vertex points. The <b>texture()</b> function
- * must be called between <b>beginShape()</b> and <b>endShape()</b> and before
- * any calls to vertex().
- *
- * When textures are in use, the fill color is ignored. Instead, use tint() to
- * specify the color of the texture as it is applied to the shape.
- *
- * @param {PImage} pimage the texture to apply
- *
- * @returns none
- *
- * @see textureMode
- * @see beginShape
- * @see endShape
- * @see vertex
- */
- p.texture = function(pimage) {
- var curContext = drawing.$ensureContext();
-
- if (pimage.__texture) {
- curContext.bindTexture(curContext.TEXTURE_2D, pimage.__texture);
- } else if (pimage.localName === "canvas") {
- curContext.bindTexture(curContext.TEXTURE_2D, canTex);
- curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, pimage);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR);
- curContext.generateMipmap(curContext.TEXTURE_2D);
- curTexture.width = pimage.width;
- curTexture.height = pimage.height;
- } else {
- var texture = curContext.createTexture(),
- cvs = document.createElement('canvas'),
- cvsTextureCtx = cvs.getContext('2d'),
- pot;
-
- // WebGL requires power of two textures
- if (pimage.width & (pimage.width-1) === 0) {
- cvs.width = pimage.width;
- } else {
- pot = 1;
- while (pot < pimage.width) {
- pot *= 2;
- }
- cvs.width = pot;
- }
-
- if (pimage.height & (pimage.height-1) === 0) {
- cvs.height = pimage.height;
- } else {
- pot = 1;
- while (pot < pimage.height) {
- pot *= 2;
- }
- cvs.height = pot;
- }
-
- cvsTextureCtx.drawImage(pimage.sourceImg, 0, 0, pimage.width, pimage.height, 0, 0, cvs.width, cvs.height);
-
- curContext.bindTexture(curContext.TEXTURE_2D, texture);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR_MIPMAP_LINEAR);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE);
- curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, cvs);
- curContext.generateMipmap(curContext.TEXTURE_2D);
-
- pimage.__texture = texture;
- curTexture.width = pimage.width;
- curTexture.height = pimage.height;
- }
-
- usingTexture = true;
- curContext.useProgram(programObject3D);
- uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture);
- };
-
- /**
- * Sets the coordinate space for texture mapping. There are two options, IMAGE,
- * which refers to the actual coordinates of the image, and NORMALIZED, which
- * refers to a normalized space of values ranging from 0 to 1. The default mode
- * is IMAGE. In IMAGE, if an image is 100 x 200 pixels, mapping the image onto
- * the entire size of a quad would require the points (0,0) (0,100) (100,200) (0,200).
- * The same mapping in NORMAL_SPACE is (0,0) (0,1) (1,1) (0,1).
- *
- * @param MODE either IMAGE or NORMALIZED
- *
- * @returns none
- *
- * @see texture
- */
- p.textureMode = function(mode){
- curTextureMode = mode;
- };
- /**
- * The curveVertexSegment() function handle emitting a specific segment of Catmull-Rom curve. Internal helper function used by <b>curveVertex()</b>.
- */
- var curveVertexSegment = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) {
- var x0 = x2;
- var y0 = y2;
- var z0 = z2;
-
- var draw = curveDrawMatrix.array();
-
- var xplot1 = draw[4] * x1 + draw[5] * x2 + draw[6] * x3 + draw[7] * x4;
- var xplot2 = draw[8] * x1 + draw[9] * x2 + draw[10] * x3 + draw[11] * x4;
- var xplot3 = draw[12] * x1 + draw[13] * x2 + draw[14] * x3 + draw[15] * x4;
-
- var yplot1 = draw[4] * y1 + draw[5] * y2 + draw[6] * y3 + draw[7] * y4;
- var yplot2 = draw[8] * y1 + draw[9] * y2 + draw[10] * y3 + draw[11] * y4;
- var yplot3 = draw[12] * y1 + draw[13] * y2 + draw[14] * y3 + draw[15] * y4;
-
- var zplot1 = draw[4] * z1 + draw[5] * z2 + draw[6] * z3 + draw[7] * z4;
- var zplot2 = draw[8] * z1 + draw[9] * z2 + draw[10] * z3 + draw[11] * z4;
- var zplot3 = draw[12] * z1 + draw[13] * z2 + draw[14] * z3 + draw[15] * z4;
-
- p.vertex(x0, y0, z0);
- for (var j = 0; j < curveDet; j++) {
- x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
- y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
- z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
- p.vertex(x0, y0, z0);
- }
- };
-
- /**
- * Specifies vertex coordinates for curves. This function may only be used between <b>beginShape()</b> and
- * <b>endShape()</b> and only when there is no MODE parameter specified to <b>beginShape()</b>. The first and last points
- * in a series of <b>curveVertex()</b> lines will be used to guide the beginning and end of a the curve. A minimum of four
- * points is required to draw a tiny curve between the second and third points. Adding a fifth point with
- * <b>curveVertex()</b> will draw the curve between the second, third, and fourth points. The <b>curveVertex()</b> function
- * is an implementation of Catmull-Rom splines. Using the 3D version of requires rendering with P3D or OPENGL (see the
- * Environment reference for more information). <br /> <br /><b>NOTE: </b> Fill does not work properly yet.
- *
- * @param {float | int} x The x-coordinate of the vertex
- * @param {float | int} y The y-coordinate of the vertex
- * @param {float | int} z The z-coordinate of the vertex
- *
- * @see curve
- * @see beginShape
- * @see endShape
- * @see vertex
- * @see bezierVertex
- */
- Drawing2D.prototype.curveVertex = function(x, y) {
- isCurve = true;
-
- p.vertex(x, y);
- };
-
- Drawing3D.prototype.curveVertex = function(x, y, z) {
- isCurve = true;
-
- if (!curveInited) {
- curveInit();
- }
- var vert = [];
- vert[0] = x;
- vert[1] = y;
- vert[2] = z;
- curveVertArray.push(vert);
- curveVertCount++;
-
- if (curveVertCount > 3) {
- curveVertexSegment( curveVertArray[curveVertCount-4][0],
- curveVertArray[curveVertCount-4][1],
- curveVertArray[curveVertCount-4][2],
- curveVertArray[curveVertCount-3][0],
- curveVertArray[curveVertCount-3][1],
- curveVertArray[curveVertCount-3][2],
- curveVertArray[curveVertCount-2][0],
- curveVertArray[curveVertCount-2][1],
- curveVertArray[curveVertCount-2][2],
- curveVertArray[curveVertCount-1][0],
- curveVertArray[curveVertCount-1][1],
- curveVertArray[curveVertCount-1][2] );
- }
- };
-
- /**
- * The curve() function draws a curved line on the screen. The first and second parameters
- * specify the beginning control point and the last two parameters specify
- * the ending control point. The middle parameters specify the start and
- * stop of the curve. Longer curves can be created by putting a series of
- * <b>curve()</b> functions together or using <b>curveVertex()</b>.
- * An additional function called <b>curveTightness()</b> provides control
- * for the visual quality of the curve. The <b>curve()</b> function is an
- * implementation of Catmull-Rom splines. Using the 3D version of requires
- * rendering with P3D or OPENGL (see the Environment reference for more
- * information).
- *
- * @param {int|float} x1 coordinates for the beginning control point
- * @param {int|float} y1 coordinates for the beginning control point
- * @param {int|float} z1 coordinates for the beginning control point
- * @param {int|float} x2 coordinates for the first point
- * @param {int|float} y2 coordinates for the first point
- * @param {int|float} z2 coordinates for the first point
- * @param {int|float} x3 coordinates for the second point
- * @param {int|float} y3 coordinates for the second point
- * @param {int|float} z3 coordinates for the second point
- * @param {int|float} x4 coordinates for the ending control point
- * @param {int|float} y4 coordinates for the ending control point
- * @param {int|float} z4 coordinates for the ending control point
- *
- * @see #curveVertex()
- * @see #curveTightness()
- * @see #bezier()
- */
- Drawing2D.prototype.curve = function(x1, y1, x2, y2, x3, y3, x4, y4) {
- p.beginShape();
- p.curveVertex(x1, y1);
- p.curveVertex(x2, y2);
- p.curveVertex(x3, y3);
- p.curveVertex(x4, y4);
- p.endShape();
- };
-
- Drawing3D.prototype.curve = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) {
- if (z4 !== undef) {
- p.beginShape();
- p.curveVertex(x1, y1, z1);
- p.curveVertex(x2, y2, z2);
- p.curveVertex(x3, y3, z3);
- p.curveVertex(x4, y4, z4);
- p.endShape();
- return;
- }
- p.beginShape();
- p.curveVertex(x1, y1);
- p.curveVertex(z1, x2);
- p.curveVertex(y2, z2);
- p.curveVertex(x3, y3);
- p.endShape();
- };
-
- /**
- * The curveTightness() function modifies the quality of forms created with <b>curve()</b> and
- * <b>curveVertex()</b>. The parameter <b>squishy</b> determines how the
- * curve fits to the vertex points. The value 0.0 is the default value for
- * <b>squishy</b> (this value defines the curves to be Catmull-Rom splines)
- * and the value 1.0 connects all the points with straight lines.
- * Values within the range -5.0 and 5.0 will deform the curves but
- * will leave them recognizable and as values increase in magnitude,
- * they will continue to deform.
- *
- * @param {float} tightness amount of deformation from the original vertices
- *
- * @see #curve()
- * @see #curveVertex()
- *
- */
- p.curveTightness = function(tightness) {
- curTightness = tightness;
- };
-
- /**
- * The curveDetail() function sets the resolution at which curves display. The default value is 20.
- * This function is only useful when using the P3D or OPENGL renderer.
- *
- * @param {int} detail resolution of the curves
- *
- * @see curve()
- * @see curveVertex()
- * @see curveTightness()
- */
- p.curveDetail = function(detail) {
- curveDet = detail;
- curveInit();
- };
-
- /**
- * Modifies the location from which rectangles draw. The default mode is rectMode(CORNER), which
- * specifies the location to be the upper left corner of the shape and uses the third and fourth
- * parameters of rect() to specify the width and height. The syntax rectMode(CORNERS) uses the
- * first and second parameters of rect() to set the location of one corner and uses the third and
- * fourth parameters to set the opposite corner. The syntax rectMode(CENTER) draws the image from
- * its center point and uses the third and forth parameters of rect() to specify the image's width
- * and height. The syntax rectMode(RADIUS) draws the image from its center point and uses the third
- * and forth parameters of rect() to specify half of the image's width and height. The parameter must
- * be written in ALL CAPS because Processing is a case sensitive language. Note: In version 125, the
- * mode named CENTER_RADIUS was shortened to RADIUS.
- *
- * @param {MODE} MODE Either CORNER, CORNERS, CENTER, or RADIUS
- *
- * @see rect
- */
- p.rectMode = function(aRectMode) {
- curRectMode = aRectMode;
- };
-
- /**
- * Modifies the location from which images draw. The default mode is imageMode(CORNER), which specifies
- * the location to be the upper left corner and uses the fourth and fifth parameters of image() to set
- * the image's width and height. The syntax imageMode(CORNERS) uses the second and third parameters of
- * image() to set the location of one corner of the image and uses the fourth and fifth parameters to
- * set the opposite corner. Use imageMode(CENTER) to draw images centered at the given x and y position.
- * The parameter to imageMode() must be written in ALL CAPS because Processing is a case sensitive language.
- *
- * @param {MODE} MODE Either CORNER, CORNERS, or CENTER
- *
- * @see loadImage
- * @see PImage
- * @see image
- * @see background
- */
- p.imageMode = function(mode) {
- switch (mode) {
- case PConstants.CORNER:
- imageModeConvert = imageModeCorner;
- break;
- case PConstants.CORNERS:
- imageModeConvert = imageModeCorners;
- break;
- case PConstants.CENTER:
- imageModeConvert = imageModeCenter;
- break;
- default:
- throw "Invalid imageMode";
- }
- };
-
- /**
- * The origin of the ellipse is modified by the ellipseMode() function. The default configuration is
- * ellipseMode(CENTER), which specifies the location of the ellipse as the center of the shape. The RADIUS
- * mode is the same, but the width and height parameters to ellipse() specify the radius of the ellipse,
- * rather than the diameter. The CORNER mode draws the shape from the upper-left corner of its bounding box.
- * The CORNERS mode uses the four parameters to ellipse() to set two opposing corners of the ellipse's bounding
- * box. The parameter must be written in "ALL CAPS" because Processing is a case sensitive language.
- *
- * @param {MODE} MODE Either CENTER, RADIUS, CORNER, or CORNERS.
- *
- * @see ellipse
- */
- p.ellipseMode = function(aEllipseMode) {
- curEllipseMode = aEllipseMode;
- };
-
- /**
- * The arc() function draws an arc in the display window.
- * Arcs are drawn along the outer edge of an ellipse defined by the
- * <b>x</b>, <b>y</b>, <b>width</b> and <b>height</b> parameters.
- * The origin or the arc's ellipse may be changed with the
- * <b>ellipseMode()</b> function.
- * The <b>start</b> and <b>stop</b> parameters specify the angles
- * at which to draw the arc.
- *
- * @param {float} a x-coordinate of the arc's ellipse
- * @param {float} b y-coordinate of the arc's ellipse
- * @param {float} c width of the arc's ellipse
- * @param {float} d height of the arc's ellipse
- * @param {float} start angle to start the arc, specified in radians
- * @param {float} stop angle to stop the arc, specified in radians
- *
- * @see #ellipseMode()
- * @see #ellipse()
- */
- p.arc = function(x, y, width, height, start, stop) {
- if (width <= 0 || stop < start) { return; }
-
- if (curEllipseMode === PConstants.CORNERS) {
- width = width - x;
- height = height - y;
- } else if (curEllipseMode === PConstants.RADIUS) {
- x = x - width;
- y = y - height;
- width = width * 2;
- height = height * 2;
- } else if (curEllipseMode === PConstants.CENTER) {
- x = x - width/2;
- y = y - height/2;
- }
- // make sure that we're starting at a useful point
- while (start < 0) {
- start += PConstants.TWO_PI;
- stop += PConstants.TWO_PI;
- }
- if (stop - start > PConstants.TWO_PI) {
- start = 0;
- stop = PConstants.TWO_PI;
- }
- var hr = width / 2,
- vr = height / 2,
- centerX = x + hr,
- centerY = y + vr,
- startLUT = 0 | (0.5 + start * p.RAD_TO_DEG * 2),
- stopLUT = 0 | (0.5 + stop * p.RAD_TO_DEG * 2),
- i, j;
- if (doFill) {
- // shut off stroke for a minute
- var savedStroke = doStroke;
- doStroke = false;
- p.beginShape();
- p.vertex(centerX, centerY);
- for (i = startLUT; i <= stopLUT; i++) {
- j = i % PConstants.SINCOS_LENGTH;
- p.vertex(centerX + cosLUT[j] * hr, centerY + sinLUT[j] * vr);
- }
- p.endShape(PConstants.CLOSE);
- doStroke = savedStroke;
- }
-
- if (doStroke) {
- // and doesn't include the first (center) vertex.
- var savedFill = doFill;
- doFill = false;
- p.beginShape();
- for (i = startLUT; i <= stopLUT; i++) {
- j = i % PConstants.SINCOS_LENGTH;
- p.vertex(centerX + cosLUT[j] * hr, centerY + sinLUT[j] * vr);
- }
- p.endShape();
- doFill = savedFill;
- }
- };
-
- /**
- * Draws a line (a direct path between two points) to the screen. The version of line() with four parameters
- * draws the line in 2D. To color a line, use the stroke() function. A line cannot be filled, therefore the
- * fill() method will not affect the color of a line. 2D lines are drawn with a width of one pixel by default,
- * but this can be changed with the strokeWeight() function. The version with six parameters allows the line
- * to be placed anywhere within XYZ space. Drawing this shape in 3D using the z parameter requires the P3D or
- * OPENGL parameter in combination with size.
- *
- * @param {int|float} x1 x-coordinate of the first point
- * @param {int|float} y1 y-coordinate of the first point
- * @param {int|float} z1 z-coordinate of the first point
- * @param {int|float} x2 x-coordinate of the second point
- * @param {int|float} y2 y-coordinate of the second point
- * @param {int|float} z2 z-coordinate of the second point
- *
- * @see strokeWeight
- * @see strokeJoin
- * @see strokeCap
- * @see beginShape
- */
- Drawing2D.prototype.line = function(x1, y1, x2, y2) {
- if (!doStroke) {
- return;
- }
- if (!renderSmooth) {
- x1 = Math.round(x1);
- x2 = Math.round(x2);
- y1 = Math.round(y1);
- y2 = Math.round(y2);
- }
-
- // A line is only defined if it has different start and end coordinates.
- // If they are the same, we call point instead.
- if (x1 === x2 && y1 === y2) {
- p.point(x1, y1);
- return;
- }
-
- var swap = undef,
- lineCap = undef,
- drawCrisp = true,
- currentModelView = modelView.array(),
- identityMatrix = [1, 0, 0, 0, 1, 0];
- // Test if any transformations have been applied to the sketch
- for (var i = 0; i < 6 && drawCrisp; i++) {
- drawCrisp = currentModelView[i] === identityMatrix[i];
- }
- /* Draw crisp lines if the line is vertical or horizontal with the following method
- * If any transformations have been applied to the sketch, don't make the line crisp
- * If the line is directed up or to the left, reverse it by swapping x1/x2 or y1/y2
- * Make the line 1 pixel longer to work around cross-platform canvas implementations
- * If the lineWidth is odd, translate the line by 0.5 in the perpendicular direction
- * Even lineWidths do not need to be translated because the canvas will draw them on pixel boundaries
- * Change the cap to butt-end to work around cross-platform canvas implementations
- * Reverse the translate and lineCap canvas state changes after drawing the line
- */
- if (drawCrisp) {
- if (x1 === x2) {
- if (y1 > y2) {
- swap = y1;
- y1 = y2;
- y2 = swap;
- }
- y2++;
- if (lineWidth % 2 === 1) {
- curContext.translate(0.5, 0.0);
- }
- } else if (y1 === y2) {
- if (x1 > x2) {
- swap = x1;
- x1 = x2;
- x2 = swap;
- }
- x2++;
- if (lineWidth % 2 === 1) {
- curContext.translate(0.0, 0.5);
- }
- }
- if (lineWidth === 1) {
- lineCap = curContext.lineCap;
- curContext.lineCap = 'butt';
- }
- }
- curContext.beginPath();
- curContext.moveTo(x1 || 0, y1 || 0);
- curContext.lineTo(x2 || 0, y2 || 0);
- executeContextStroke();
- if (drawCrisp) {
- if (x1 === x2 && lineWidth % 2 === 1) {
- curContext.translate(-0.5, 0.0);
- } else if (y1 === y2 && lineWidth % 2 === 1) {
- curContext.translate(0.0, -0.5);
- }
- if (lineWidth === 1) {
- curContext.lineCap = lineCap;
- }
- }
- };
-
- Drawing3D.prototype.line = function(x1, y1, z1, x2, y2, z2) {
- if (y2 === undef || z2 === undef) { // 2D line called in 3D context
- z2 = 0;
- y2 = x2;
- x2 = z1;
- z1 = 0;
- }
-
- // a line is only defined if it has different start and end coordinates.
- // If they are the same, we call point instead.
- if (x1===x2 && y1===y2 && z1===z2) {
- p.point(x1,y1,z1);
- return;
- }
-
- var lineVerts = [x1, y1, z1, x2, y2, z2];
-
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
-
- uniformMatrix("uModel2d", programObject2D, "uModel", false, [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
- uniformMatrix("uView2d", programObject2D, "uView", false, view.array());
-
- uniformf("uColor2d", programObject2D, "uColor", strokeStyle);
- uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false);
-
- vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, lineBuffer);
- disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord");
-
- curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(lineVerts), curContext.STREAM_DRAW);
- curContext.drawArrays(curContext.LINES, 0, 2);
- }
- };
-
- /**
- * Draws a Bezier curve on the screen. These curves are defined by a series of anchor and control points. The first
- * two parameters specify the first anchor point and the last two parameters specify the other anchor point. The
- * middle parameters specify the control points which define the shape of the curve. Bezier curves were developed
- * by French engineer Pierre Bezier. Using the 3D version of requires rendering with P3D or OPENGL (see the
- * Environment reference for more information).
- *
- * @param {int | float} x1,y1,z1 coordinates for the first anchor point
- * @param {int | float} cx1,cy1,cz1 coordinates for the first control point
- * @param {int | float} cx2,cy2,cz2 coordinates for the second control point
- * @param {int | float} x2,y2,z2 coordinates for the second anchor point
- *
- * @see bezierVertex
- * @see curve
- */
- Drawing2D.prototype.bezier = function() {
- if (arguments.length !== 8) {
- throw("You must use 8 parameters for bezier() in 2D mode");
- }
-
- p.beginShape();
- p.vertex( arguments[0], arguments[1] );
- p.bezierVertex( arguments[2], arguments[3],
- arguments[4], arguments[5],
- arguments[6], arguments[7] );
- p.endShape();
- };
-
- Drawing3D.prototype.bezier = function() {
- if (arguments.length !== 12) {
- throw("You must use 12 parameters for bezier() in 3D mode");
- }
-
- p.beginShape();
- p.vertex( arguments[0], arguments[1], arguments[2] );
- p.bezierVertex( arguments[3], arguments[4], arguments[5],
- arguments[6], arguments[7], arguments[8],
- arguments[9], arguments[10], arguments[11] );
- p.endShape();
- };
-
- /**
- * Sets the resolution at which Beziers display. The default value is 20. This function is only useful when using the P3D
- * or OPENGL renderer as the default (JAVA2D) renderer does not use this information.
- *
- * @param {int} detail resolution of the curves
- *
- * @see curve
- * @see curveVertex
- * @see curveTightness
- */
- p.bezierDetail = function( detail ){
- bezDetail = detail;
- };
-
- /**
- * The bezierPoint() function evalutes quadratic bezier at point t for points a, b, c, d.
- * The parameter t varies between 0 and 1. The a and d parameters are the
- * on-curve points, b and c are the control points. To make a two-dimensional
- * curve, call this function once with the x coordinates and a second time
- * with the y coordinates to get the location of a bezier curve at t.
- *
- * @param {float} a coordinate of first point on the curve
- * @param {float} b coordinate of first control point
- * @param {float} c coordinate of second control point
- * @param {float} d coordinate of second point on the curve
- * @param {float} t value between 0 and 1
- *
- * @see #bezier()
- * @see #bezierVertex()
- * @see #curvePoint()
- */
- p.bezierPoint = function(a, b, c, d, t) {
- return (1 - t) * (1 - t) * (1 - t) * a + 3 * (1 - t) * (1 - t) * t * b + 3 * (1 - t) * t * t * c + t * t * t * d;
- };
-
- /**
- * The bezierTangent() function calculates the tangent of a point on a Bezier curve. There is a good
- * definition of "tangent" at Wikipedia: <a href="http://en.wikipedia.org/wiki/Tangent" target="new">http://en.wikipedia.org/wiki/Tangent</a>
- *
- * @param {float} a coordinate of first point on the curve
- * @param {float} b coordinate of first control point
- * @param {float} c coordinate of second control point
- * @param {float} d coordinate of second point on the curve
- * @param {float} t value between 0 and 1
- *
- * @see #bezier()
- * @see #bezierVertex()
- * @see #curvePoint()
- */
- p.bezierTangent = function(a, b, c, d, t) {
- return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
- };
-
- /**
- * The curvePoint() function evalutes the Catmull-Rom curve at point t for points a, b, c, d. The
- * parameter t varies between 0 and 1, a and d are points on the curve,
- * and b and c are the control points. This can be done once with the x
- * coordinates and a second time with the y coordinates to get the
- * location of a curve at t.
- *
- * @param {int|float} a coordinate of first point on the curve
- * @param {int|float} b coordinate of second point on the curve
- * @param {int|float} c coordinate of third point on the curve
- * @param {int|float} d coordinate of fourth point on the curve
- * @param {float} t value between 0 and 1
- *
- * @see #curve()
- * @see #curveVertex()
- * @see #bezierPoint()
- */
- p.curvePoint = function(a, b, c, d, t) {
- return 0.5 * ((2 * b) + (-a + c) * t + (2 * a - 5 * b + 4 * c - d) * t * t + (-a + 3 * b - 3 * c + d) * t * t * t);
- };
-
- /**
- * The curveTangent() function calculates the tangent of a point on a Catmull-Rom curve.
- * There is a good definition of "tangent" at Wikipedia: <a href="http://en.wikipedia.org/wiki/Tangent" target="new">http://en.wikipedia.org/wiki/Tangent</a>.
- *
- * @param {int|float} a coordinate of first point on the curve
- * @param {int|float} b coordinate of first control point
- * @param {int|float} c coordinate of second control point
- * @param {int|float} d coordinate of second point on the curve
- * @param {float} t value between 0 and 1
- *
- * @see #curve()
- * @see #curveVertex()
- * @see #curvePoint()
- * @see #bezierTangent()
- */
- p.curveTangent = function(a, b, c, d, t) {
- return 0.5 * ((-a + c) + 2 * (2 * a - 5 * b + 4 * c - d) * t + 3 * (-a + 3 * b - 3 * c + d) * t * t);
- };
-
- /**
- * A triangle is a plane created by connecting three points. The first two arguments specify the first point,
- * the middle two arguments specify the second point, and the last two arguments specify the third point.
- *
- * @param {int | float} x1 x-coordinate of the first point
- * @param {int | float} y1 y-coordinate of the first point
- * @param {int | float} x2 x-coordinate of the second point
- * @param {int | float} y2 y-coordinate of the second point
- * @param {int | float} x3 x-coordinate of the third point
- * @param {int | float} y3 y-coordinate of the third point
- */
- p.triangle = function(x1, y1, x2, y2, x3, y3) {
- p.beginShape(PConstants.TRIANGLES);
- p.vertex(x1, y1, 0);
- p.vertex(x2, y2, 0);
- p.vertex(x3, y3, 0);
- p.endShape();
- };
-
- /**
- * A quad is a quadrilateral, a four sided polygon. It is similar to a rectangle, but the angles between its
- * edges are not constrained to ninety degrees. The first pair of parameters (x1,y1) sets the first vertex
- * and the subsequent pairs should proceed clockwise or counter-clockwise around the defined shape.
- *
- * @param {float | int} x1 x-coordinate of the first corner
- * @param {float | int} y1 y-coordinate of the first corner
- * @param {float | int} x2 x-coordinate of the second corner
- * @param {float | int} y2 y-coordinate of the second corner
- * @param {float | int} x3 x-coordinate of the third corner
- * @param {float | int} y3 y-coordinate of the third corner
- * @param {float | int} x4 x-coordinate of the fourth corner
- * @param {float | int} y4 y-coordinate of the fourth corner
- */
- p.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) {
- p.beginShape(PConstants.QUADS);
- p.vertex(x1, y1, 0);
- p.vertex(x2, y2, 0);
- p.vertex(x3, y3, 0);
- p.vertex(x4, y4, 0);
- p.endShape();
- };
-
- var roundedRect$2d = function(x, y, width, height, tl, tr, br, bl) {
- if (bl === undef) {
- tr = tl;
- br = tl;
- bl = tl;
- }
- var halfWidth = width / 2,
- halfHeight = height / 2;
- if (tl > halfWidth || tl > halfHeight) {
- tl = Math.min(halfWidth, halfHeight);
- }
- if (tr > halfWidth || tr > halfHeight) {
- tr = Math.min(halfWidth, halfHeight);
- }
- if (br > halfWidth || br > halfHeight) {
- br = Math.min(halfWidth, halfHeight);
- }
- if (bl > halfWidth || bl > halfHeight) {
- bl = Math.min(halfWidth, halfHeight);
- }
- // Translate the stroke by (0.5, 0.5) to draw a crisp border
- if (!doFill || doStroke) {
- curContext.translate(0.5, 0.5);
- }
- curContext.beginPath();
- curContext.moveTo(x + tl, y);
- curContext.lineTo(x + width - tr, y);
- curContext.quadraticCurveTo(x + width, y, x + width, y + tr);
- curContext.lineTo(x + width, y + height - br);
- curContext.quadraticCurveTo(x + width, y + height, x + width - br, y + height);
- curContext.lineTo(x + bl, y + height);
- curContext.quadraticCurveTo(x, y + height, x, y + height - bl);
- curContext.lineTo(x, y + tl);
- curContext.quadraticCurveTo(x, y, x + tl, y);
- if (!doFill || doStroke) {
- curContext.translate(-0.5, -0.5);
- }
- executeContextFill();
- executeContextStroke();
- };
-
- /**
- * Draws a rectangle to the screen. A rectangle is a four-sided shape with every angle at ninety
- * degrees. The first two parameters set the location, the third sets the width, and the fourth
- * sets the height. The origin is changed with the rectMode() function.
- *
- * @param {int|float} x x-coordinate of the rectangle
- * @param {int|float} y y-coordinate of the rectangle
- * @param {int|float} width width of the rectangle
- * @param {int|float} height height of the rectangle
- *
- * @see rectMode
- * @see quad
- */
- Drawing2D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) {
- if (!width && !height) {
- return;
- }
-
- if (curRectMode === PConstants.CORNERS) {
- width -= x;
- height -= y;
- } else if (curRectMode === PConstants.RADIUS) {
- width *= 2;
- height *= 2;
- x -= width / 2;
- y -= height / 2;
- } else if (curRectMode === PConstants.CENTER) {
- x -= width / 2;
- y -= height / 2;
- }
-
- if (!renderSmooth) {
- x = Math.round(x);
- y = Math.round(y);
- width = Math.round(width);
- height = Math.round(height);
- }
- if (tl !== undef) {
- roundedRect$2d(x, y, width, height, tl, tr, br, bl);
- return;
- }
-
- // Translate the line by (0.5, 0.5) to draw a crisp rectangle border
- if (doStroke && lineWidth % 2 === 1) {
- curContext.translate(0.5, 0.5);
- }
- curContext.beginPath();
- curContext.rect(x, y, width, height);
- executeContextFill();
- executeContextStroke();
- if (doStroke && lineWidth % 2 === 1) {
- curContext.translate(-0.5, -0.5);
- }
- };
-
- Drawing3D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) {
- if (tl !== undef) {
- throw "rect() with rounded corners is not supported in 3D mode";
- }
-
- if (curRectMode === PConstants.CORNERS) {
- width -= x;
- height -= y;
- } else if (curRectMode === PConstants.RADIUS) {
- width *= 2;
- height *= 2;
- x -= width / 2;
- y -= height / 2;
- } else if (curRectMode === PConstants.CENTER) {
- x -= width / 2;
- y -= height / 2;
- }
-
- // Modeling transformation
- var model = new PMatrix3D();
- model.translate(x, y, 0);
- model.scale(width, height, 1);
- model.transpose();
-
- // viewing transformation needs to have Y flipped
- // becuase that's what Processing does.
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array());
- uniformMatrix("uView2d", programObject2D, "uView", false, view.array());
- uniformf("uColor2d", programObject2D, "uColor", strokeStyle);
- uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false);
- vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, rectBuffer);
- disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord");
- curContext.drawArrays(curContext.LINE_LOOP, 0, rectVerts.length / 3);
- }
-
- if (doFill) {
- curContext.useProgram(programObject3D);
- uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array());
- uniformMatrix("uView3d", programObject3D, "uView", false, view.array());
-
- // fix stitching problems. (lines get occluded by triangles
- // since they share the same depth values). This is not entirely
- // working, but it's a start for drawing the outline. So
- // developers can start playing around with styles.
- curContext.enable(curContext.POLYGON_OFFSET_FILL);
- curContext.polygonOffset(1, 1);
-
- uniformf("color3d", programObject3D, "uColor", fillStyle);
-
- if(lightCount > 0){
- var v = new PMatrix3D();
- v.set(view);
-
- var m = new PMatrix3D();
- m.set(model);
-
- v.mult(m);
-
- var normalMatrix = new PMatrix3D();
- normalMatrix.set(v);
- normalMatrix.invert();
- normalMatrix.transpose();
-
- uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array());
- vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, rectNormBuffer);
- }
- else{
- disableVertexAttribPointer("normal3d", programObject3D, "aNormal");
- }
-
- vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, rectBuffer);
-
- curContext.drawArrays(curContext.TRIANGLE_FAN, 0, rectVerts.length / 3);
- curContext.disable(curContext.POLYGON_OFFSET_FILL);
- }
- };
-
- /**
- * Draws an ellipse (oval) in the display window. An ellipse with an equal <b>width</b> and <b>height</b> is a circle.
- * The first two parameters set the location, the third sets the width, and the fourth sets the height. The origin may be
- * changed with the <b>ellipseMode()</b> function.
- *
- * @param {float|int} x x-coordinate of the ellipse
- * @param {float|int} y y-coordinate of the ellipse
- * @param {float|int} width width of the ellipse
- * @param {float|int} height height of the ellipse
- *
- * @see ellipseMode
- */
- Drawing2D.prototype.ellipse = function(x, y, width, height) {
- x = x || 0;
- y = y || 0;
-
- if (width <= 0 && height <= 0) {
- return;
- }
-
- if (curEllipseMode === PConstants.RADIUS) {
- width *= 2;
- height *= 2;
- } else if (curEllipseMode === PConstants.CORNERS) {
- width = width - x;
- height = height - y;
- x += width / 2;
- y += height / 2;
- } else if (curEllipseMode === PConstants.CORNER) {
- x += width / 2;
- y += height / 2;
- }
-
- // Shortcut for drawing a 2D circle
- if (width === height) {
- curContext.beginPath();
- curContext.arc(x, y, width / 2, 0, PConstants.TWO_PI, false);
- executeContextFill();
- executeContextStroke();
- } else {
- var w = width / 2,
- h = height / 2,
- C = 0.5522847498307933,
- c_x = C * w,
- c_y = C * h;
-
- p.beginShape();
- p.vertex(x + w, y);
- p.bezierVertex(x + w, y - c_y, x + c_x, y - h, x, y - h);
- p.bezierVertex(x - c_x, y - h, x - w, y - c_y, x - w, y);
- p.bezierVertex(x - w, y + c_y, x - c_x, y + h, x, y + h);
- p.bezierVertex(x + c_x, y + h, x + w, y + c_y, x + w, y);
- p.endShape();
- }
- };
-
- Drawing3D.prototype.ellipse = function(x, y, width, height) {
- x = x || 0;
- y = y || 0;
-
- if (width <= 0 && height <= 0) {
- return;
- }
-
- if (curEllipseMode === PConstants.RADIUS) {
- width *= 2;
- height *= 2;
- } else if (curEllipseMode === PConstants.CORNERS) {
- width = width - x;
- height = height - y;
- x += width / 2;
- y += height / 2;
- } else if (curEllipseMode === PConstants.CORNER) {
- x += width / 2;
- y += height / 2;
- }
-
- var w = width / 2,
- h = height / 2,
- C = 0.5522847498307933,
- c_x = C * w,
- c_y = C * h;
-
- p.beginShape();
- p.vertex(x + w, y);
- p.bezierVertex(x + w, y - c_y, 0, x + c_x, y - h, 0, x, y - h, 0);
- p.bezierVertex(x - c_x, y - h, 0, x - w, y - c_y, 0, x - w, y, 0);
- p.bezierVertex(x - w, y + c_y, 0, x - c_x, y + h, 0, x, y + h, 0);
- p.bezierVertex(x + c_x, y + h, 0, x + w, y + c_y, 0, x + w, y, 0);
- p.endShape();
-
- if (doFill) {
- //temporary workaround to not working fills for bezier -- will fix later
- var xAv = 0, yAv = 0, i, j;
- for (i = 0; i < vertArray.length; i++) {
- xAv += vertArray[i][0];
- yAv += vertArray[i][1];
- }
- xAv /= vertArray.length;
- yAv /= vertArray.length;
- var vert = [],
- fillVertArray = [],
- colorVertArray = [];
- vert[0] = xAv;
- vert[1] = yAv;
- vert[2] = 0;
- vert[3] = 0;
- vert[4] = 0;
- vert[5] = fillStyle[0];
- vert[6] = fillStyle[1];
- vert[7] = fillStyle[2];
- vert[8] = fillStyle[3];
- vert[9] = strokeStyle[0];
- vert[10] = strokeStyle[1];
- vert[11] = strokeStyle[2];
- vert[12] = strokeStyle[3];
- vert[13] = normalX;
- vert[14] = normalY;
- vert[15] = normalZ;
- vertArray.unshift(vert);
- for (i = 0; i < vertArray.length; i++) {
- for (j = 0; j < 3; j++) {
- fillVertArray.push(vertArray[i][j]);
- }
- for (j = 5; j < 9; j++) {
- colorVertArray.push(vertArray[i][j]);
- }
- }
- fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray);
- }
- };
-
- /**
- * Sets the current normal vector. This is for drawing three dimensional shapes and surfaces and
- * specifies a vector perpendicular to the surface of the shape which determines how lighting affects
- * it. Processing attempts to automatically assign normals to shapes, but since that's imperfect,
- * this is a better option when you want more control. This function is identical to glNormal3f() in OpenGL.
- *
- * @param {float} nx x direction
- * @param {float} ny y direction
- * @param {float} nz z direction
- *
- * @see beginShape
- * @see endShape
- * @see lights
- */
- p.normal = function(nx, ny, nz) {
- if (arguments.length !== 3 || !(typeof nx === "number" && typeof ny === "number" && typeof nz === "number")) {
- throw "normal() requires three numeric arguments.";
- }
-
- normalX = nx;
- normalY = ny;
- normalZ = nz;
-
- if (curShape !== 0) {
- if (normalMode === PConstants.NORMAL_MODE_AUTO) {
- normalMode = PConstants.NORMAL_MODE_SHAPE;
- } else if (normalMode === PConstants.NORMAL_MODE_SHAPE) {
- normalMode = PConstants.NORMAL_MODE_VERTEX;
- }
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Raster drawing functions
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Saves an image from the display window. Images are saved in TIFF, TARGA, JPEG, and PNG format
- * depending on the extension within the filename parameter. For example, "image.tif" will have
- * a TIFF image and "image.png" will save a PNG image. If no extension is included in the filename,
- * the image will save in TIFF format and .tif will be added to the name. These files are saved to
- * the sketch's folder, which may be opened by selecting "Show sketch folder" from the "Sketch" menu.
- * It is not possible to use save() while running the program in a web browser. All images saved
- * from the main drawing window will be opaque. To save images without a background, use createGraphics().
- *
- * @param {String} filename any sequence of letters and numbers
- *
- * @see saveFrame
- * @see createGraphics
- */
- p.save = function(file, img) {
- // file is unused at the moment
- // may implement this differently in later release
- if (img !== undef) {
- return window.open(img.toDataURL(),"_blank");
- }
- return window.open(p.externals.canvas.toDataURL(),"_blank");
- };
-
- var saveNumber = 0;
-
- p.saveFrame = function(file) {
- if(file === undef) {
- // use default name template if parameter is not specified
- file = "screen-####.png";
- }
- // Increment changeable part: screen-0000.png, screen-0001.png, ...
- var frameFilename = file.replace(/#+/, function(all) {
- var s = "" + (saveNumber++);
- while(s.length < all.length) {
- s = "0" + s;
- }
- return s;
- });
- p.save(frameFilename);
- };
-
- var utilityContext2d = document.createElement("canvas").getContext("2d");
-
- var canvasDataCache = [undef, undef, undef]; // we need three for now
-
- function getCanvasData(obj, w, h) {
- var canvasData = canvasDataCache.shift();
-
- if (canvasData === undef) {
- canvasData = {};
- canvasData.canvas = document.createElement("canvas");
- canvasData.context = canvasData.canvas.getContext('2d');
- }
-
- canvasDataCache.push(canvasData);
-
- var canvas = canvasData.canvas, context = canvasData.context,
- width = w || obj.width, height = h || obj.height;
-
- canvas.width = width;
- canvas.height = height;
-
- if (!obj) {
- context.clearRect(0, 0, width, height);
- } else if ("data" in obj) { // ImageData
- context.putImageData(obj, 0, 0);
- } else {
- context.clearRect(0, 0, width, height);
- context.drawImage(obj, 0, 0, width, height);
- }
- return canvasData;
- }
-
- /**
- * Handle the sketch code for pixels[] and pixels.length
- * parser code converts pixels[] to getPixels()
- * or setPixels(), .length becomes getLength()
- */
- function buildPixelsObject(pImage) {
- return {
-
- getLength: (function(aImg) {
- return function() {
- if (aImg.isRemote) {
- throw "Image is loaded remotely. Cannot get length.";
- } else {
- return aImg.imageData.data.length ? aImg.imageData.data.length/4 : 0;
- }
- };
- }(pImage)),
-
- getPixel: (function(aImg) {
- return function(i) {
- var offset = i*4,
- data = aImg.imageData.data;
-
- if (aImg.isRemote) {
- throw "Image is loaded remotely. Cannot get pixels.";
- }
-
- return (data[offset+3] << 24) & PConstants.ALPHA_MASK |
- (data[offset] << 16) & PConstants.RED_MASK |
- (data[offset+1] << 8) & PConstants.GREEN_MASK |
- data[offset+2] & PConstants.BLUE_MASK;
- };
- }(pImage)),
-
- setPixel: (function(aImg) {
- return function(i, c) {
- var offset = i*4,
- data = aImg.imageData.data;
-
- if (aImg.isRemote) {
- throw "Image is loaded remotely. Cannot set pixel.";
- }
-
- data[offset+0] = (c & PConstants.RED_MASK) >>> 16;
- data[offset+1] = (c & PConstants.GREEN_MASK) >>> 8;
- data[offset+2] = (c & PConstants.BLUE_MASK);
- data[offset+3] = (c & PConstants.ALPHA_MASK) >>> 24;
- aImg.__isDirty = true;
- };
- }(pImage)),
-
- toArray: (function(aImg) {
- return function() {
- var arr = [],
- data = aImg.imageData.data,
- length = aImg.width * aImg.height;
-
- if (aImg.isRemote) {
- throw "Image is loaded remotely. Cannot get pixels.";
- }
-
- for (var i = 0, offset = 0; i < length; i++, offset += 4) {
- arr.push( (data[offset+3] << 24) & PConstants.ALPHA_MASK |
- (data[offset] << 16) & PConstants.RED_MASK |
- (data[offset+1] << 8) & PConstants.GREEN_MASK |
- data[offset+2] & PConstants.BLUE_MASK );
- }
- return arr;
- };
- }(pImage)),
-
- set: (function(aImg) {
- return function(arr) {
- var offset,
- data,
- c;
- if (this.isRemote) {
- throw "Image is loaded remotely. Cannot set pixels.";
- }
-
- data = aImg.imageData.data;
- for (var i = 0, aL = arr.length; i < aL; i++) {
- c = arr[i];
- offset = i*4;
-
- data[offset+0] = (c & PConstants.RED_MASK) >>> 16;
- data[offset+1] = (c & PConstants.GREEN_MASK) >>> 8;
- data[offset+2] = (c & PConstants.BLUE_MASK);
- data[offset+3] = (c & PConstants.ALPHA_MASK) >>> 24;
- }
- aImg.__isDirty = true;
- };
- }(pImage))
-
- };
- }
-
- /**
- * Datatype for storing images. Processing can display .gif, .jpg, .tga, and .png images. Images may be
- * displayed in 2D and 3D space. Before an image is used, it must be loaded with the loadImage() function.
- * The PImage object contains fields for the width and height of the image, as well as an array called
- * pixels[] which contains the values for every pixel in the image. A group of methods, described below,
- * allow easy access to the image's pixels and alpha channel and simplify the process of compositing.
- * Before using the pixels[] array, be sure to use the loadPixels() method on the image to make sure that the
- * pixel data is properly loaded. To create a new image, use the createImage() function (do not use new PImage()).
- *
- * @param {int} width image width
- * @param {int} height image height
- * @param {MODE} format Either RGB, ARGB, ALPHA (grayscale alpha channel)
- *
- * @returns {PImage}
- *
- * @see loadImage
- * @see imageMode
- * @see createImage
- */
- var PImage = function(aWidth, aHeight, aFormat) {
-
- // Keep track of whether or not the cached imageData has been touched.
- this.__isDirty = false;
-
- if (aWidth instanceof HTMLImageElement) {
- // convert an <img> to a PImage
- this.fromHTMLImageData(aWidth);
- } else if (aHeight || aFormat) {
- this.width = aWidth || 1;
- this.height = aHeight || 1;
-
- // Stuff a canvas into sourceImg so image() calls can use drawImage like an <img>
- var canvas = this.sourceImg = document.createElement("canvas");
- canvas.width = this.width;
- canvas.height = this.height;
-
- var imageData = this.imageData = canvas.getContext('2d').createImageData(this.width, this.height);
- this.format = (aFormat === PConstants.ARGB || aFormat === PConstants.ALPHA) ? aFormat : PConstants.RGB;
- if (this.format === PConstants.RGB) {
- // Set the alpha channel of an RGB image to opaque.
- for (var i = 3, data = this.imageData.data, len = data.length; i < len; i += 4) {
- data[i] = 255;
- }
- }
-
- this.__isDirty = true;
- this.updatePixels();
- } else {
- this.width = 0;
- this.height = 0;
- this.imageData = utilityContext2d.createImageData(1, 1);
- this.format = PConstants.ARGB;
- }
-
- this.pixels = buildPixelsObject(this);
- };
- PImage.prototype = {
-
- /**
- * Temporary hack to deal with cross-Processing-instance created PImage. See
- * tickets #1623 and #1644.
- */
- __isPImage: true,
-
- /**
- * @member PImage
- * Updates the image with the data in its pixels[] array. Use in conjunction with loadPixels(). If
- * you're only reading pixels from the array, there's no need to call updatePixels().
- * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the rule
- * is that any time you want to manipulate the pixels[] array, you must first call loadPixels(), and
- * after changes have been made, call updatePixels(). Even if the renderer may not seem to use this
- * function in the current Processing release, this will always be subject to change.
- * Currently, none of the renderers use the additional parameters to updatePixels().
- */
- updatePixels: function() {
- var canvas = this.sourceImg;
- if (canvas && canvas instanceof HTMLCanvasElement && this.__isDirty) {
- canvas.getContext('2d').putImageData(this.imageData, 0, 0);
- }
- this.__isDirty = false;
- },
-
- fromHTMLImageData: function(htmlImg) {
- // convert an <img> to a PImage
- var canvasData = getCanvasData(htmlImg);
- try {
- var imageData = canvasData.context.getImageData(0, 0, htmlImg.width, htmlImg.height);
- this.fromImageData(imageData);
- } catch(e) {
- if (htmlImg.width && htmlImg.height) {
- this.isRemote = true;
- this.width = htmlImg.width;
- this.height = htmlImg.height;
- }
- }
- this.sourceImg = htmlImg;
- },
-
- 'get': function(x, y, w, h) {
- if (!arguments.length) {
- return p.get(this);
- }
- if (arguments.length === 2) {
- return p.get(x, y, this);
- }
- if (arguments.length === 4) {
- return p.get(x, y, w, h, this);
- }
- },
-
- /**
- * @member PImage
- * Changes the color of any pixel or writes an image directly into the image. The x and y parameter
- * specify the pixel or the upper-left corner of the image. The color parameter specifies the color value.
- * Setting the color of a single pixel with set(x, y) is easy, but not as fast as putting the data
- * directly into pixels[]. The equivalent statement to "set(x, y, #000000)" using pixels[] is
- * "pixels[y*width+x] = #000000". Processing requires calling loadPixels() to load the display window
- * data into the pixels[] array before getting the values and calling updatePixels() to update the window.
- *
- * @param {int} x x-coordinate of the pixel or upper-left corner of the image
- * @param {int} y y-coordinate of the pixel or upper-left corner of the image
- * @param {color} color any value of the color datatype
- *
- * @see get
- * @see pixels[]
- * @see copy
- */
- 'set': function(x, y, c) {
- p.set(x, y, c, this);
- this.__isDirty = true;
- },
-
- /**
- * @member PImage
- * Blends a region of pixels into the image specified by the img parameter. These copies utilize full
- * alpha channel support and a choice of the following modes to blend the colors of source pixels (A)
- * with the ones of pixels in the destination image (B):
- * BLEND - linear interpolation of colours: C = A*factor + B
- * ADD - additive blending with white clip: C = min(A*factor + B, 255)
- * SUBTRACT - subtractive blending with black clip: C = max(B - A*factor, 0)
- * DARKEST - only the darkest colour succeeds: C = min(A*factor, B)
- * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)
- * DIFFERENCE - subtract colors from underlying image.
- * EXCLUSION - similar to DIFFERENCE, but less extreme.
- * MULTIPLY - Multiply the colors, result will always be darker.
- * SCREEN - Opposite multiply, uses inverse values of the colors.
- * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and screens light values.
- * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
- * SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not as harsh.
- * DODGE - Lightens light tones and increases contrast, ignores darks. Called "Color Dodge" in Illustrator and Photoshop.
- * BURN - Darker areas are applied, increasing contrast, ignores lights. Called "Color Burn" in Illustrator and Photoshop.
- * All modes use the alpha information (highest byte) of source image pixels as the blending factor.
- * If the source and destination regions are different sizes, the image will be automatically resized to
- * match the destination size. If the srcImg parameter is not used, the display window is used as the source image.
- * This function ignores imageMode().
- *
- * @param {int} x X coordinate of the source's upper left corner
- * @param {int} y Y coordinate of the source's upper left corner
- * @param {int} width source image width
- * @param {int} height source image height
- * @param {int} dx X coordinate of the destinations's upper left corner
- * @param {int} dy Y coordinate of the destinations's upper left corner
- * @param {int} dwidth destination image width
- * @param {int} dheight destination image height
- * @param {PImage} srcImg an image variable referring to the source image
- * @param {MODE} MODE Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION,
- * MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
- *
- * @see alpha
- * @see copy
- */
- blend: function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE) {
- if (arguments.length === 9) {
- p.blend(this, srcImg, x, y, width, height, dx, dy, dwidth, dheight, this);
- } else if (arguments.length === 10) {
- p.blend(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE, this);
- }
- delete this.sourceImg;
- },
-
- /**
- * @member PImage
- * Copies a region of pixels from one image into another. If the source and destination regions
- * aren't the same size, it will automatically resize source pixels to fit the specified target region.
- * No alpha information is used in the process, however if the source image has an alpha channel set,
- * it will be copied as well. This function ignores imageMode().
- *
- * @param {int} sx X coordinate of the source's upper left corner
- * @param {int} sy Y coordinate of the source's upper left corner
- * @param {int} swidth source image width
- * @param {int} sheight source image height
- * @param {int} dx X coordinate of the destinations's upper left corner
- * @param {int} dy Y coordinate of the destinations's upper left corner
- * @param {int} dwidth destination image width
- * @param {int} dheight destination image height
- * @param {PImage} srcImg an image variable referring to the source image
- *
- * @see alpha
- * @see blend
- */
- copy: function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) {
- if (arguments.length === 8) {
- p.blend(this, srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, PConstants.REPLACE, this);
- } else if (arguments.length === 9) {
- p.blend(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight, PConstants.REPLACE, this);
- }
- delete this.sourceImg;
- },
-
- /**
- * @member PImage
- * Filters an image as defined by one of the following modes:
- * THRESHOLD - converts the image to black and white pixels depending if they are above or below
- * the threshold defined by the level parameter. The level must be between 0.0 (black) and 1.0(white).
- * If no level is specified, 0.5 is used.
- * GRAY - converts any colors in the image to grayscale equivalents
- * INVERT - sets each pixel to its inverse value
- * POSTERIZE - limits each channel of the image to the number of colors specified as the level parameter
- * BLUR - executes a Guassian blur with the level parameter specifying the extent of the blurring.
- * If no level parameter is used, the blur is equivalent to Guassian blur of radius 1.
- * OPAQUE - sets the alpha channel to entirely opaque.
- * ERODE - reduces the light areas with the amount defined by the level parameter.
- * DILATE - increases the light areas with the amount defined by the level parameter
- *
- * @param {MODE} MODE Either THRESHOLD, GRAY, INVERT, POSTERIZE, BLUR, OPAQUE, ERODE, or DILATE
- * @param {int|float} param in the range from 0 to 1
- */
- filter: function(mode, param) {
- if (arguments.length === 2) {
- p.filter(mode, param, this);
- } else if (arguments.length === 1) {
- // no param specified, send null to show its invalid
- p.filter(mode, null, this);
- }
- delete this.sourceImg;
- },
-
- /**
- * @member PImage
- * Saves the image into a file. Images are saved in TIFF, TARGA, JPEG, and PNG format depending on
- * the extension within the filename parameter. For example, "image.tif" will have a TIFF image and
- * "image.png" will save a PNG image. If no extension is included in the filename, the image will save
- * in TIFF format and .tif will be added to the name. These files are saved to the sketch's folder,
- * which may be opened by selecting "Show sketch folder" from the "Sketch" menu. It is not possible to
- * use save() while running the program in a web browser.
- * To save an image created within the code, rather than through loading, it's necessary to make the
- * image with the createImage() function so it is aware of the location of the program and can therefore
- * save the file to the right place. See the createImage() reference for more information.
- *
- * @param {String} filename a sequence of letters and numbers
- */
- save: function(file){
- p.save(file,this);
- },
-
- /**
- * @member PImage
- * Resize the image to a new width and height. To make the image scale proportionally, use 0 as the
- * value for the wide or high parameter.
- *
- * @param {int} wide the resized image width
- * @param {int} high the resized image height
- *
- * @see get
- */
- resize: function(w, h) {
- if (this.isRemote) { // Remote images cannot access imageData
- throw "Image is loaded remotely. Cannot resize.";
- }
- if (this.width !== 0 || this.height !== 0) {
- // make aspect ratio if w or h is 0
- if (w === 0 && h !== 0) {
- w = Math.floor(this.width / this.height * h);
- } else if (h === 0 && w !== 0) {
- h = Math.floor(this.height / this.width * w);
- }
- // put 'this.imageData' into a new canvas
- var canvas = getCanvasData(this.imageData).canvas;
- // pull imageData object out of canvas into ImageData object
- var imageData = getCanvasData(canvas, w, h).context.getImageData(0, 0, w, h);
- // set this as new pimage
- this.fromImageData(imageData);
- }
- },
-
- /**
- * @member PImage
- * Masks part of an image from displaying by loading another image and using it as an alpha channel.
- * This mask image should only contain grayscale data, but only the blue color channel is used. The
- * mask image needs to be the same size as the image to which it is applied.
- * In addition to using a mask image, an integer array containing the alpha channel data can be
- * specified directly. This method is useful for creating dynamically generated alpha masks. This
- * array must be of the same length as the target image's pixels array and should contain only grayscale
- * data of values between 0-255.
- *
- * @param {PImage} maskImg any PImage object used as the alpha channel for "img", needs to be same
- * size as "img"
- * @param {int[]} maskArray any array of Integer numbers used as the alpha channel, needs to be same
- * length as the image's pixel array
- */
- mask: function(mask) {
- var obj = this.toImageData(),
- i,
- size;
-
- if (mask instanceof PImage || mask.__isPImage) {
- if (mask.width === this.width && mask.height === this.height) {
- mask = mask.toImageData();
-
- for (i = 2, size = this.width * this.height * 4; i < size; i += 4) {
- // using it as an alpha channel
- obj.data[i + 1] = mask.data[i];
- // but only the blue color channel
- }
- } else {
- throw "mask must have the same dimensions as PImage.";
- }
- } else if (mask instanceof Array) {
- if (this.width * this.height === mask.length) {
- for (i = 0, size = mask.length; i < size; ++i) {
- obj.data[i * 4 + 3] = mask[i];
- }
- } else {
- throw "mask array must be the same length as PImage pixels array.";
- }
- }
-
- this.fromImageData(obj);
- },
-
- // These are intentionally left blank for PImages, we work live with pixels and draw as necessary
- /**
- * @member PImage
- * Loads the pixel data for the image into its pixels[] array. This function must always be called
- * before reading from or writing to pixels[].
- * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the
- * rule is that any time you want to manipulate the pixels[] array, you must first call loadPixels(),
- * and after changes have been made, call updatePixels(). Even if the renderer may not seem to use
- * this function in the current Processing release, this will always be subject to change.
- */
- loadPixels: noop,
-
- toImageData: function() {
- if (this.isRemote) {
- return this.sourceImg;
- }
-
- if (!this.__isDirty) {
- return this.imageData;
- }
-
- var canvasData = getCanvasData(this.sourceImg);
- return canvasData.context.getImageData(0, 0, this.width, this.height);
- },
-
- toDataURL: function() {
- if (this.isRemote) { // Remote images cannot access imageData
- throw "Image is loaded remotely. Cannot create dataURI.";
- }
- var canvasData = getCanvasData(this.imageData);
- return canvasData.canvas.toDataURL();
- },
-
- fromImageData: function(canvasImg) {
- var w = canvasImg.width,
- h = canvasImg.height,
- canvas = document.createElement('canvas'),
- ctx = canvas.getContext('2d');
-
- this.width = canvas.width = w;
- this.height = canvas.height = h;
-
- ctx.putImageData(canvasImg, 0, 0);
-
- // changed for 0.9
- this.format = PConstants.ARGB;
-
- this.imageData = canvasImg;
- this.sourceImg = canvas;
- }
- };
-
- p.PImage = PImage;
-
- /**
- * Creates a new PImage (the datatype for storing images). This provides a fresh buffer of pixels to play
- * with. Set the size of the buffer with the width and height parameters. The format parameter defines how
- * the pixels are stored. See the PImage reference for more information.
- * Be sure to include all three parameters, specifying only the width and height (but no format) will
- * produce a strange error.
- * Advanced users please note that createImage() should be used instead of the syntax new PImage().
- *
- * @param {int} width image width
- * @param {int} height image height
- * @param {MODE} format Either RGB, ARGB, ALPHA (grayscale alpha channel)
- *
- * @returns {PImage}
- *
- * @see PImage
- * @see PGraphics
- */
- p.createImage = function(w, h, mode) {
- return new PImage(w,h,mode);
- };
-
- // Loads an image for display. Type is an extension. Callback is fired on load.
- /**
- * Loads an image into a variable of type PImage. Four types of images ( .gif, .jpg, .tga, .png) images may
- * be loaded. To load correctly, images must be located in the data directory of the current sketch. In most
- * cases, load all images in setup() to preload them at the start of the program. Loading images inside draw()
- * will reduce the speed of a program.
- * The filename parameter can also be a URL to a file found online. For security reasons, a Processing sketch
- * found online can only download files from the same server from which it came. Getting around this restriction
- * requires a signed applet.
- * The extension parameter is used to determine the image type in cases where the image filename does not end
- * with a proper extension. Specify the extension as the second parameter to loadImage(), as shown in the
- * third example on this page.
- * If an image is not loaded successfully, the null value is returned and an error message will be printed to
- * the console. The error message does not halt the program, however the null value may cause a NullPointerException
- * if your code does not check whether the value returned from loadImage() is null.
- * Depending on the type of error, a PImage object may still be returned, but the width and height of the image
- * will be set to -1. This happens if bad image data is returned or cannot be decoded properly. Sometimes this happens
- * with image URLs that produce a 403 error or that redirect to a password prompt, because loadImage() will attempt
- * to interpret the HTML as image data.
- *
- * @param {String} filename name of file to load, can be .gif, .jpg, .tga, or a handful of other image
- * types depending on your platform.
- * @param {String} extension the type of image to load, for example "png", "gif", "jpg"
- *
- * @returns {PImage}
- *
- * @see PImage
- * @see image
- * @see imageMode
- * @see background
- */
- p.loadImage = function(file, type, callback) {
- // if type is specified, we just ignore it
-
- var pimg;
- // if image is in the preloader cache return a new PImage
- if (curSketch.imageCache.images[file]) {
- pimg = new PImage(curSketch.imageCache.images[file]);
- pimg.loaded = true;
- return pimg;
- }
- // else async load it
- pimg = new PImage();
- var img = document.createElement('img');
-
- pimg.sourceImg = img;
-
- img.onload = (function(aImage, aPImage, aCallback) {
- var image = aImage;
- var pimg = aPImage;
- var callback = aCallback;
- return function() {
- // change the <img> object into a PImage now that its loaded
- pimg.fromHTMLImageData(image);
- pimg.loaded = true;
- if (callback) {
- callback();
- }
- };
- }(img, pimg, callback));
-
- img.src = file; // needs to be called after the img.onload function is declared or it wont work in opera
- return pimg;
- };
-
- // async loading of large images, same functionality as loadImage above
- /**
- * This function load images on a separate thread so that your sketch does not freeze while images load during
- * setup(). While the image is loading, its width and height will be 0. If an error occurs while loading the image,
- * its width and height will be set to -1. You'll know when the image has loaded properly because its width and
- * height will be greater than 0. Asynchronous image loading (particularly when downloading from a server) can
- * dramatically improve performance.
- * The extension parameter is used to determine the image type in cases where the image filename does not end
- * with a proper extension. Specify the extension as the second parameter to requestImage().
- *
- * @param {String} filename name of file to load, can be .gif, .jpg, .tga, or a handful of other image
- * types depending on your platform.
- * @param {String} extension the type of image to load, for example "png", "gif", "jpg"
- *
- * @returns {PImage}
- *
- * @see PImage
- * @see loadImage
- */
- p.requestImage = p.loadImage;
-
- function get$2(x,y) {
- var data;
- // return the color at x,y (int) of curContext
- if (x >= p.width || x < 0 || y < 0 || y >= p.height) {
- // x,y is outside image return transparent black
- return 0;
- }
-
- // loadPixels() has been called
- if (isContextReplaced) {
- var offset = ((0|x) + p.width * (0|y)) * 4;
- data = p.imageData.data;
- return (data[offset + 3] << 24) & PConstants.ALPHA_MASK |
- (data[offset] << 16) & PConstants.RED_MASK |
- (data[offset + 1] << 8) & PConstants.GREEN_MASK |
- data[offset + 2] & PConstants.BLUE_MASK;
- }
-
- // x,y is inside canvas space
- data = p.toImageData(0|x, 0|y, 1, 1).data;
- return (data[3] << 24) & PConstants.ALPHA_MASK |
- (data[0] << 16) & PConstants.RED_MASK |
- (data[1] << 8) & PConstants.GREEN_MASK |
- data[2] & PConstants.BLUE_MASK;
- }
- function get$3(x,y,img) {
- if (img.isRemote) { // Remote images cannot access imageData
- throw "Image is loaded remotely. Cannot get x,y.";
- }
- // PImage.get(x,y) was called, return the color (int) at x,y of img
- var offset = y * img.width * 4 + (x * 4),
- data = img.imageData.data;
- return (data[offset + 3] << 24) & PConstants.ALPHA_MASK |
- (data[offset] << 16) & PConstants.RED_MASK |
- (data[offset + 1] << 8) & PConstants.GREEN_MASK |
- data[offset + 2] & PConstants.BLUE_MASK;
- }
- function get$4(x, y, w, h) {
- // return a PImage of w and h from cood x,y of curContext
- var c = new PImage(w, h, PConstants.ARGB);
- c.fromImageData(p.toImageData(x, y, w, h));
- return c;
- }
- function get$5(x, y, w, h, img) {
- if (img.isRemote) { // Remote images cannot access imageData
- throw "Image is loaded remotely. Cannot get x,y,w,h.";
- }
- // PImage.get(x,y,w,h) was called, return x,y,w,h PImage of img
- // offset start point needs to be *4
- var c = new PImage(w, h, PConstants.ARGB), cData = c.imageData.data,
- imgWidth = img.width, imgHeight = img.height, imgData = img.imageData.data;
- // Don't need to copy pixels from the image outside ranges.
- var startRow = Math.max(0, -y), startColumn = Math.max(0, -x),
- stopRow = Math.min(h, imgHeight - y), stopColumn = Math.min(w, imgWidth - x);
- for (var i = startRow; i < stopRow; ++i) {
- var sourceOffset = ((y + i) * imgWidth + (x + startColumn)) * 4;
- var targetOffset = (i * w + startColumn) * 4;
- for (var j = startColumn; j < stopColumn; ++j) {
- cData[targetOffset++] = imgData[sourceOffset++];
- cData[targetOffset++] = imgData[sourceOffset++];
- cData[targetOffset++] = imgData[sourceOffset++];
- cData[targetOffset++] = imgData[sourceOffset++];
- }
- }
- c.__isDirty = true;
- return c;
- }
-
- // Gets a single pixel or block of pixels from the current Canvas Context or a PImage
- /**
- * Reads the color of any pixel or grabs a section of an image. If no parameters are specified, the entire
- * image is returned. Get the value of one pixel by specifying an x,y coordinate. Get a section of the display
- * window by specifying an additional width and height parameter. If the pixel requested is outside of the image
- * window, black is returned. The numbers returned are scaled according to the current color ranges, but only RGB
- * values are returned by this function. For example, even though you may have drawn a shape with colorMode(HSB),
- * the numbers returned will be in RGB.
- * Getting the color of a single pixel with get(x, y) is easy, but not as fast as grabbing the data directly
- * from pixels[]. The equivalent statement to "get(x, y)" using pixels[] is "pixels[y*width+x]". Processing
- * requires calling loadPixels() to load the display window data into the pixels[] array before getting the values.
- * This function ignores imageMode().
- *
- * @param {int} x x-coordinate of the pixel
- * @param {int} y y-coordinate of the pixel
- * @param {int} width width of pixel rectangle to get
- * @param {int} height height of pixel rectangle to get
- *
- * @returns {Color|PImage}
- *
- * @see set
- * @see pixels[]
- * @see imageMode
- */
- p.get = function(x, y, w, h, img) {
- // for 0 2 and 4 arguments use curContext, otherwise PImage.get was called
- if (img !== undefined) {
- return get$5(x, y, w, h, img);
- }
- if (h !== undefined) {
- return get$4(x, y, w, h);
- }
- if (w !== undefined) {
- return get$3(x, y, w);
- }
- if (y !== undefined) {
- return get$2(x, y);
- }
- if (x !== undefined) {
- // PImage.get() was called, return a new PImage
- return get$5(0, 0, x.width, x.height, x);
- }
-
- return get$4(0, 0, p.width, p.height);
- };
-
- /**
- * Creates and returns a new <b>PGraphics</b> object of the types P2D, P3D, and JAVA2D. Use this class if you need to draw
- * into an off-screen graphics buffer. It's not possible to use <b>createGraphics()</b> with OPENGL, because it doesn't
- * allow offscreen use. The DXF and PDF renderers require the filename parameter. <br /><br /> It's important to call
- * any drawing commands between beginDraw() and endDraw() statements. This is also true for any commands that affect
- * drawing, such as smooth() or colorMode().<br /><br /> Unlike the main drawing surface which is completely opaque,
- * surfaces created with createGraphics() can have transparency. This makes it possible to draw into a graphics and
- * maintain the alpha channel.
- *
- * @param {int} width width in pixels
- * @param {int} height height in pixels
- * @param {int} renderer Either P2D, P3D, JAVA2D, PDF, DXF
- * @param {String} filename the name of the file (not supported yet)
- */
- p.createGraphics = function(w, h, render) {
- var pg = new Processing();
- pg.size(w, h, render);
- pg.background(0,0);
- return pg;
- };
-
- // pixels caching
- function resetContext() {
- if(isContextReplaced) {
- curContext = originalContext;
- isContextReplaced = false;
-
- p.updatePixels();
- }
- }
- function SetPixelContextWrapper() {
- function wrapFunction(newContext, name) {
- function wrapper() {
- resetContext();
- curContext[name].apply(curContext, arguments);
- }
- newContext[name] = wrapper;
- }
- function wrapProperty(newContext, name) {
- function getter() {
- resetContext();
- return curContext[name];
- }
- function setter(value) {
- resetContext();
- curContext[name] = value;
- }
- p.defineProperty(newContext, name, { get: getter, set: setter });
- }
- for(var n in curContext) {
- if(typeof curContext[n] === 'function') {
- wrapFunction(this, n);
- } else {
- wrapProperty(this, n);
- }
- }
- }
- function replaceContext() {
- if(isContextReplaced) {
- return;
- }
- p.loadPixels();
- if(proxyContext === null) {
- originalContext = curContext;
- proxyContext = new SetPixelContextWrapper();
- }
- isContextReplaced = true;
- curContext = proxyContext;
- setPixelsCached = 0;
- }
-
- function set$3(x, y, c) {
- if (x < p.width && x >= 0 && y >= 0 && y < p.height) {
- replaceContext();
- p.pixels.setPixel((0|x)+p.width*(0|y), c);
- if(++setPixelsCached > maxPixelsCached) {
- resetContext();
- }
- }
- }
- function set$4(x, y, obj, img) {
- if (img.isRemote) { // Remote images cannot access imageData
- throw "Image is loaded remotely. Cannot set x,y.";
- }
- var c = p.color.toArray(obj);
- var offset = y * img.width * 4 + (x*4);
- var data = img.imageData.data;
- data[offset] = c[0];
- data[offset+1] = c[1];
- data[offset+2] = c[2];
- data[offset+3] = c[3];
- }
-
- // Paints a pixel array into the canvas
- /**
- * Changes the color of any pixel or writes an image directly into the display window. The x and y parameters
- * specify the pixel to change and the color parameter specifies the color value. The color parameter is affected
- * by the current color mode (the default is RGB values from 0 to 255). When setting an image, the x and y
- * parameters define the coordinates for the upper-left corner of the image.
- * Setting the color of a single pixel with set(x, y) is easy, but not as fast as putting the data directly
- * into pixels[]. The equivalent statement to "set(x, y, #000000)" using pixels[] is "pixels[y*width+x] = #000000".
- * You must call loadPixels() to load the display window data into the pixels[] array before setting the values
- * and calling updatePixels() to update the window with any changes. This function ignores imageMode().
- *
- * @param {int} x x-coordinate of the pixel
- * @param {int} y y-coordinate of the pixel
- * @param {Color} obj any value of the color datatype
- * @param {PImage} img any valid variable of type PImage
- *
- * @see get
- * @see pixels[]
- * @see imageMode
- */
- p.set = function(x, y, obj, img) {
- var color, oldFill;
- if (arguments.length === 3) {
- // called p.set(), was it with a color or a img ?
- if (typeof obj === "number") {
- set$3(x, y, obj);
- } else if (obj instanceof PImage || obj.__isPImage) {
- p.image(obj, x, y);
- }
- } else if (arguments.length === 4) {
- // PImage.set(x,y,c) was called, set coordinate x,y color to c of img
- set$4(x, y, obj, img);
- }
- };
- p.imageData = {};
-
- // handle the sketch code for pixels[]
- // parser code converts pixels[] to getPixels() or setPixels(),
- // .length becomes getLength()
- /**
- * Array containing the values for all the pixels in the display window. These values are of the color datatype.
- * This array is the size of the display window. For example, if the image is 100x100 pixels, there will be 10000
- * values and if the window is 200x300 pixels, there will be 60000 values. The index value defines the position
- * of a value within the array. For example, the statment color b = pixels[230] will set the variable b to be
- * equal to the value at that location in the array.
- * Before accessing this array, the data must loaded with the loadPixels() function. After the array data has
- * been modified, the updatePixels() function must be run to update the changes.
- *
- * @param {int} index must not exceed the size of the array
- *
- * @see loadPixels
- * @see updatePixels
- * @see get
- * @see set
- * @see PImage
- */
- p.pixels = {
- getLength: function() { return p.imageData.data.length ? p.imageData.data.length/4 : 0; },
- getPixel: function(i) {
- var offset = i*4, data = p.imageData.data;
- return (data[offset+3] << 24) & 0xff000000 |
- (data[offset+0] << 16) & 0x00ff0000 |
- (data[offset+1] << 8) & 0x0000ff00 |
- data[offset+2] & 0x000000ff;
- },
- setPixel: function(i,c) {
- var offset = i*4, data = p.imageData.data;
- data[offset+0] = (c & 0x00ff0000) >>> 16; // RED_MASK
- data[offset+1] = (c & 0x0000ff00) >>> 8; // GREEN_MASK
- data[offset+2] = (c & 0x000000ff); // BLUE_MASK
- data[offset+3] = (c & 0xff000000) >>> 24; // ALPHA_MASK
- },
- toArray: function() {
- var arr = [], length = p.imageData.width * p.imageData.height, data = p.imageData.data;
- for (var i = 0, offset = 0; i < length; i++, offset += 4) {
- arr.push((data[offset+3] << 24) & 0xff000000 |
- (data[offset+0] << 16) & 0x00ff0000 |
- (data[offset+1] << 8) & 0x0000ff00 |
- data[offset+2] & 0x000000ff);
- }
- return arr;
- },
- set: function(arr) {
- for (var i = 0, aL = arr.length; i < aL; i++) {
- this.setPixel(i, arr[i]);
- }
- }
- };
-
- // Gets a 1-Dimensional pixel array from Canvas
- /**
- * Loads the pixel data for the display window into the pixels[] array. This function must always be called
- * before reading from or writing to pixels[].
- * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the rule is that
- * any time you want to manipulate the pixels[] array, you must first call loadPixels(), and after changes
- * have been made, call updatePixels(). Even if the renderer may not seem to use this function in the current
- * Processing release, this will always be subject to change.
- *
- * @see pixels[]
- * @see updatePixels
- */
- p.loadPixels = function() {
- p.imageData = drawing.$ensureContext().getImageData(0, 0, p.width, p.height);
- };
-
- // Draws a 1-Dimensional pixel array to Canvas
- /**
- * Updates the display window with the data in the pixels[] array. Use in conjunction with loadPixels(). If
- * you're only reading pixels from the array, there's no need to call updatePixels() unless there are changes.
- * Certain renderers may or may not seem to require loadPixels() or updatePixels(). However, the rule is that
- * any time you want to manipulate the pixels[] array, you must first call loadPixels(), and after changes
- * have been made, call updatePixels(). Even if the renderer may not seem to use this function in the current
- * Processing release, this will always be subject to change.
- * Currently, none of the renderers use the additional parameters to updatePixels(), however this may be
- * implemented in the future.
- *
- * @see loadPixels
- * @see pixels[]
- */
- p.updatePixels = function() {
- if (p.imageData) {
- drawing.$ensureContext().putImageData(p.imageData, 0, 0);
- }
- };
-
- /**
- * Set various hints and hacks for the renderer. This is used to handle obscure rendering features that cannot be
- * implemented in a consistent manner across renderers. Many options will often graduate to standard features
- * instead of hints over time.
- * hint(ENABLE_OPENGL_4X_SMOOTH) - Enable 4x anti-aliasing for OpenGL. This can help force anti-aliasing if
- * it has not been enabled by the user. On some graphics cards, this can also be set by the graphics driver's
- * control panel, however not all cards make this available. This hint must be called immediately after the
- * size() command because it resets the renderer, obliterating any settings and anything drawn (and like size(),
- * re-running the code that came before it again).
- * hint(DISABLE_OPENGL_2X_SMOOTH) - In Processing 1.0, Processing always enables 2x smoothing when the OpenGL
- * renderer is used. This hint disables the default 2x smoothing and returns the smoothing behavior found in
- * earlier releases, where smooth() and noSmooth() could be used to enable and disable smoothing, though the
- * quality was inferior.
- * hint(ENABLE_NATIVE_FONTS) - Use the native version fonts when they are installed, rather than the bitmapped
- * version from a .vlw file. This is useful with the JAVA2D renderer setting, as it will improve font rendering
- * speed. This is not enabled by default, because it can be misleading while testing because the type will look
- * great on your machine (because you have the font installed) but lousy on others' machines if the identical
- * font is unavailable. This option can only be set per-sketch, and must be called before any use of textFont().
- * hint(DISABLE_DEPTH_TEST) - Disable the zbuffer, allowing you to draw on top of everything at will. When depth
- * testing is disabled, items will be drawn to the screen sequentially, like a painting. This hint is most often
- * used to draw in 3D, then draw in 2D on top of it (for instance, to draw GUI controls in 2D on top of a 3D
- * interface). Starting in release 0149, this will also clear the depth buffer. Restore the default with
- * hint(ENABLE_DEPTH_TEST), but note that with the depth buffer cleared, any 3D drawing that happens later in
- * draw() will ignore existing shapes on the screen.
- * hint(ENABLE_DEPTH_SORT) - Enable primitive z-sorting of triangles and lines in P3D and OPENGL. This can slow
- * performance considerably, and the algorithm is not yet perfect. Restore the default with hint(DISABLE_DEPTH_SORT).
- * hint(DISABLE_OPENGL_ERROR_REPORT) - Speeds up the OPENGL renderer setting by not checking for errors while
- * running. Undo with hint(ENABLE_OPENGL_ERROR_REPORT).
- * As of release 0149, unhint() has been removed in favor of adding additional ENABLE/DISABLE constants to reset
- * the default behavior. This prevents the double negatives, and also reinforces which hints can be enabled or disabled.
- *
- * @param {MODE} item constant: name of the hint to be enabled or disabled
- *
- * @see PGraphics
- * @see createGraphics
- * @see size
- */
- p.hint = function(which) {
- var curContext = drawing.$ensureContext();
- if (which === PConstants.DISABLE_DEPTH_TEST) {
- curContext.disable(curContext.DEPTH_TEST);
- curContext.depthMask(false);
- curContext.clear(curContext.DEPTH_BUFFER_BIT);
- }
- else if (which === PConstants.ENABLE_DEPTH_TEST) {
- curContext.enable(curContext.DEPTH_TEST);
- curContext.depthMask(true);
- }
- else if (which === PConstants.ENABLE_OPENGL_2X_SMOOTH ||
- which === PConstants.ENABLE_OPENGL_4X_SMOOTH){
- renderSmooth = true;
- }
- else if (which === PConstants.DISABLE_OPENGL_2X_SMOOTH){
- renderSmooth = false;
- }
- };
-
- /**
- * The background() function sets the color used for the background of the Processing window.
- * The default background is light gray. In the <b>draw()</b> function, the background color is used to clear the display window at the beginning of each frame.
- * An image can also be used as the background for a sketch, however its width and height must be the same size as the sketch window.
- * To resize an image 'b' to the size of the sketch window, use b.resize(width, height).
- * Images used as background will ignore the current <b>tint()</b> setting.
- * For the main drawing surface, the alpha value will be ignored. However,
- * alpha can be used on PGraphics objects from <b>createGraphics()</b>. This is
- * the only way to set all the pixels partially transparent, for instance.
- * If the 'gray' parameter is passed in the function sets the background to a grayscale value, based on the
- * current colorMode.
- * <p>
- * Note that background() should be called before any transformations occur,
- * because some implementations may require the current transformation matrix
- * to be identity before drawing.
- *
- * @param {int|float} gray specifies a value between white and black
- * @param {int|float} value1 red or hue value (depending on the current color mode)
- * @param {int|float} value2 green or saturation value (depending on the current color mode)
- * @param {int|float} value3 blue or brightness value (depending on the current color mode)
- * @param {int|float} alpha opacity of the background
- * @param {Color} color any value of the color datatype
- * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00)
- * @param {PImage} image an instance of a PImage to use as a background
- *
- * @see #stroke()
- * @see #fill()
- * @see #tint()
- * @see #colorMode()
- */
- var backgroundHelper = function(arg1, arg2, arg3, arg4) {
- var obj;
-
- if (arg1 instanceof PImage || arg1.__isPImage) {
- obj = arg1;
-
- if (!obj.loaded) {
- throw "Error using image in background(): PImage not loaded.";
- }
- if(obj.width !== p.width || obj.height !== p.height){
- throw "Background image must be the same dimensions as the canvas.";
- }
- } else {
- obj = p.color(arg1, arg2, arg3, arg4);
- }
-
- backgroundObj = obj;
- };
-
- Drawing2D.prototype.background = function(arg1, arg2, arg3, arg4) {
- if (arg1 !== undef) {
- backgroundHelper(arg1, arg2, arg3, arg4);
- }
-
- if (backgroundObj instanceof PImage || backgroundObj.__isPImage) {
- saveContext();
- curContext.setTransform(1, 0, 0, 1, 0, 0);
- p.image(backgroundObj, 0, 0);
- restoreContext();
- } else {
- saveContext();
- curContext.setTransform(1, 0, 0, 1, 0, 0);
-
- // If the background is transparent
- if (p.alpha(backgroundObj) !== colorModeA) {
- curContext.clearRect(0,0, p.width, p.height);
- }
- curContext.fillStyle = p.color.toString(backgroundObj);
- curContext.fillRect(0, 0, p.width, p.height);
- isFillDirty = true;
- restoreContext();
- }
- };
-
- Drawing3D.prototype.background = function(arg1, arg2, arg3, arg4) {
- if (arguments.length > 0) {
- backgroundHelper(arg1, arg2, arg3, arg4);
- }
-
- var c = p.color.toGLArray(backgroundObj);
- curContext.clearColor(c[0], c[1], c[2], c[3]);
- curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT);
-
- // An image as a background in 3D is not implemented yet
- };
-
- // Draws an image to the Canvas
- /**
- * Displays images to the screen. The images must be in the sketch's "data" directory to load correctly. Select "Add
- * file..." from the "Sketch" menu to add the image. Processing currently works with GIF, JPEG, and Targa images. The
- * color of an image may be modified with the tint() function and if a GIF has transparency, it will maintain its
- * transparency. The img parameter specifies the image to display and the x and y parameters define the location of
- * the image from its upper-left corner. The image is displayed at its original size unless the width and height
- * parameters specify a different size. The imageMode() function changes the way the parameters work. A call to
- * imageMode(CORNERS) will change the width and height parameters to define the x and y values of the opposite
- * corner of the image.
- *
- * @param {PImage} img the image to display
- * @param {int|float} x x-coordinate of the image
- * @param {int|float} y y-coordinate of the image
- * @param {int|float} width width to display the image
- * @param {int|float} height height to display the image
- *
- * @see loadImage
- * @see PImage
- * @see imageMode
- * @see tint
- * @see background
- * @see alpha
- */
- Drawing2D.prototype.image = function(img, x, y, w, h) {
- // Fix fractional positions
- x = Math.round(x);
- y = Math.round(y);
-
- if (img.width > 0) {
- var wid = w || img.width;
- var hgt = h || img.height;
-
- var bounds = imageModeConvert(x || 0, y || 0, w || img.width, h || img.height, arguments.length < 4);
- var fastImage = !!img.sourceImg && curTint === null;
- if (fastImage) {
- var htmlElement = img.sourceImg;
- if (img.__isDirty) {
- img.updatePixels();
- }
- // Using HTML element's width and height in case if the image was resized.
- curContext.drawImage(htmlElement, 0, 0,
- htmlElement.width, htmlElement.height, bounds.x, bounds.y, bounds.w, bounds.h);
- } else {
- var obj = img.toImageData();
-
- // Tint the image
- if (curTint !== null) {
- curTint(obj);
- img.__isDirty = true;
- }
-
- curContext.drawImage(getCanvasData(obj).canvas, 0, 0,
- img.width, img.height, bounds.x, bounds.y, bounds.w, bounds.h);
- }
- }
- };
-
- Drawing3D.prototype.image = function(img, x, y, w, h) {
- if (img.width > 0) {
- // Fix fractional positions
- x = Math.round(x);
- y = Math.round(y);
- w = w || img.width;
- h = h || img.height;
-
- p.beginShape(p.QUADS);
- p.texture(img);
- p.vertex(x, y, 0, 0, 0);
- p.vertex(x, y+h, 0, 0, h);
- p.vertex(x+w, y+h, 0, w, h);
- p.vertex(x+w, y, 0, w, 0);
- p.endShape();
- }
- };
-
- /**
- * The tint() function sets the fill value for displaying images. Images can be tinted to
- * specified colors or made transparent by setting the alpha.
- * <br><br>To make an image transparent, but not change it's color,
- * use white as the tint color and specify an alpha value. For instance,
- * tint(255, 128) will make an image 50% transparent (unless
- * <b>colorMode()</b> has been used).
- *
- * <br><br>When using hexadecimal notation to specify a color, use "#" or
- * "0x" before the values (e.g. #CCFFAA, 0xFFCCFFAA). The # syntax uses six
- * digits to specify a color (the way colors are specified in HTML and CSS).
- * When using the hexadecimal notation starting with "0x", the hexadecimal
- * value must be specified with eight characters; the first two characters
- * define the alpha component and the remainder the red, green, and blue
- * components.
- * <br><br>The value for the parameter "gray" must be less than or equal
- * to the current maximum value as specified by <b>colorMode()</b>.
- * The default maximum value is 255.
- * <br><br>The tint() method is also used to control the coloring of
- * textures in 3D.
- *
- * @param {int|float} gray any valid number
- * @param {int|float} alpha opacity of the image
- * @param {int|float} value1 red or hue value
- * @param {int|float} value2 green or saturation value
- * @param {int|float} value3 blue or brightness value
- * @param {int|float} color any value of the color datatype
- * @param {int} hex color value in hexadecimal notation (i.e. #FFCC00 or 0xFFFFCC00)
- *
- * @see #noTint()
- * @see #image()
- */
- p.tint = function(a1, a2, a3, a4) {
- var tintColor = p.color(a1, a2, a3, a4);
- var r = p.red(tintColor) / colorModeX;
- var g = p.green(tintColor) / colorModeY;
- var b = p.blue(tintColor) / colorModeZ;
- var a = p.alpha(tintColor) / colorModeA;
- curTint = function(obj) {
- var data = obj.data,
- length = 4 * obj.width * obj.height;
- for (var i = 0; i < length;) {
- data[i++] *= r;
- data[i++] *= g;
- data[i++] *= b;
- data[i++] *= a;
- }
- };
- // for overriding the color buffer when 3d rendering
- curTint3d = function(data){
- for (var i = 0; i < data.length;) {
- data[i++] = r;
- data[i++] = g;
- data[i++] = b;
- data[i++] = a;
- }
- };
- };
-
- /**
- * The noTint() function removes the current fill value for displaying images and reverts to displaying images with their original hues.
- *
- * @see #tint()
- * @see #image()
- */
- p.noTint = function() {
- curTint = null;
- curTint3d = null;
- };
-
- /**
- * Copies a region of pixels from the display window to another area of the display window and copies a region of pixels from an
- * image used as the srcImg parameter into the display window. If the source and destination regions aren't the same size, it will
- * automatically resize the source pixels to fit the specified target region. No alpha information is used in the process, however
- * if the source image has an alpha channel set, it will be copied as well. This function ignores imageMode().
- *
- * @param {int} x X coordinate of the source's upper left corner
- * @param {int} y Y coordinate of the source's upper left corner
- * @param {int} width source image width
- * @param {int} height source image height
- * @param {int} dx X coordinate of the destination's upper left corner
- * @param {int} dy Y coordinate of the destination's upper left corner
- * @param {int} dwidth destination image width
- * @param {int} dheight destination image height
- * @param {PImage} srcImg image variable referring to the source image
- *
- * @see blend
- * @see get
- */
- p.copy = function(src, sx, sy, sw, sh, dx, dy, dw, dh) {
- if (dh === undef) {
- // shift everything, and introduce p
- dh = dw;
- dw = dy;
- dy = dx;
- dx = sh;
- sh = sw;
- sw = sy;
- sy = sx;
- sx = src;
- src = p;
- }
- p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, PConstants.REPLACE);
- };
-
- /**
- * Blends a region of pixels from one image into another (or in itself again) with full alpha channel support. There
- * is a choice of the following modes to blend the source pixels (A) with the ones of pixels in the destination image (B):
- * BLEND - linear interpolation of colours: C = A*factor + B
- * ADD - additive blending with white clip: C = min(A*factor + B, 255)
- * SUBTRACT - subtractive blending with black clip: C = max(B - A*factor, 0)
- * DARKEST - only the darkest colour succeeds: C = min(A*factor, B)
- * LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)
- * DIFFERENCE - subtract colors from underlying image.
- * EXCLUSION - similar to DIFFERENCE, but less extreme.
- * MULTIPLY - Multiply the colors, result will always be darker.
- * SCREEN - Opposite multiply, uses inverse values of the colors.
- * OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and screens light values.
- * HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
- * SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not as harsh.
- * DODGE - Lightens light tones and increases contrast, ignores darks. Called "Color Dodge" in Illustrator and Photoshop.
- * BURN - Darker areas are applied, increasing contrast, ignores lights. Called "Color Burn" in Illustrator and Photoshop.
- * All modes use the alpha information (highest byte) of source image pixels as the blending factor. If the source and
- * destination regions are different sizes, the image will be automatically resized to match the destination size. If the
- * srcImg parameter is not used, the display window is used as the source image. This function ignores imageMode().
- *
- * @param {int} x X coordinate of the source's upper left corner
- * @param {int} y Y coordinate of the source's upper left corner
- * @param {int} width source image width
- * @param {int} height source image height
- * @param {int} dx X coordinate of the destination's upper left corner
- * @param {int} dy Y coordinate of the destination's upper left corner
- * @param {int} dwidth destination image width
- * @param {int} dheight destination image height
- * @param {PImage} srcImg image variable referring to the source image
- * @param {PImage} MODE Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN,
- * OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
- * @see filter
- */
- p.blend = function(src, sx, sy, sw, sh, dx, dy, dw, dh, mode, pimgdest) {
- if (src.isRemote) {
- throw "Image is loaded remotely. Cannot blend image.";
- }
-
- if (mode === undef) {
- // shift everything, and introduce p
- mode = dh;
- dh = dw;
- dw = dy;
- dy = dx;
- dx = sh;
- sh = sw;
- sw = sy;
- sy = sx;
- sx = src;
- src = p;
- }
-
- var sx2 = sx + sw,
- sy2 = sy + sh,
- dx2 = dx + dw,
- dy2 = dy + dh,
- dest = pimgdest || p;
-
- // check if pimgdest is there and pixels, if so this was a call from pimg.blend
- if (pimgdest === undef || mode === undef) {
- p.loadPixels();
- }
-
- src.loadPixels();
-
- if (src === p && p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) {
- p.blit_resize(p.get(sx, sy, sx2 - sx, sy2 - sy), 0, 0, sx2 - sx - 1, sy2 - sy - 1,
- dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode);
- } else {
- p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode);
- }
-
- if (pimgdest === undef) {
- p.updatePixels();
- }
- };
-
- // helper function for filter()
- var buildBlurKernel = function(r) {
- var radius = p.floor(r * 3.5), i;
- radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248);
- if (p.shared.blurRadius !== radius) {
- p.shared.blurRadius = radius;
- p.shared.blurKernelSize = 1 + (p.shared.blurRadius<<1);
- p.shared.blurKernel = new Float32Array(p.shared.blurKernelSize);
- var sharedBlurKernal = p.shared.blurKernel;
- var sharedBlurKernelSize = p.shared.blurKernelSize;
- var sharedBlurRadius = p.shared.blurRadius;
- // init blurKernel
- for (i = 0; i < sharedBlurKernelSize; i++) {
- sharedBlurKernal[i] = 0;
- }
- var radiusiSquared = (radius - 1) * (radius - 1);
- for (i = 1; i < radius; i++) {
- sharedBlurKernal[radius + i] = sharedBlurKernal[radius-i] = radiusiSquared;
- }
- sharedBlurKernal[radius] = radius * radius;
- }
- };
-
- var blurARGB = function(r, aImg) {
- var sum, cr, cg, cb, ca, c, m;
- var read, ri, ym, ymi, bk0;
- var wh = aImg.pixels.getLength();
- var r2 = new Float32Array(wh);
- var g2 = new Float32Array(wh);
- var b2 = new Float32Array(wh);
- var a2 = new Float32Array(wh);
- var yi = 0;
- var x, y, i, offset;
-
- buildBlurKernel(r);
-
- var aImgHeight = aImg.height;
- var aImgWidth = aImg.width;
- var sharedBlurKernelSize = p.shared.blurKernelSize;
- var sharedBlurRadius = p.shared.blurRadius;
- var sharedBlurKernal = p.shared.blurKernel;
- var pix = aImg.imageData.data;
-
- for (y = 0; y < aImgHeight; y++) {
- for (x = 0; x < aImgWidth; x++) {
- cb = cg = cr = ca = sum = 0;
- read = x - sharedBlurRadius;
- if (read<0) {
- bk0 = -read;
- read = 0;
- } else {
- if (read >= aImgWidth) {
- break;
- }
- bk0=0;
- }
- for (i = bk0; i < sharedBlurKernelSize; i++) {
- if (read >= aImgWidth) {
- break;
- }
- offset = (read + yi) *4;
- m = sharedBlurKernal[i];
- ca += m * pix[offset + 3];
- cr += m * pix[offset];
- cg += m * pix[offset + 1];
- cb += m * pix[offset + 2];
- sum += m;
- read++;
- }
- ri = yi + x;
- a2[ri] = ca / sum;
- r2[ri] = cr / sum;
- g2[ri] = cg / sum;
- b2[ri] = cb / sum;
- }
- yi += aImgWidth;
- }
-
- yi = 0;
- ym = -sharedBlurRadius;
- ymi = ym*aImgWidth;
-
- for (y = 0; y < aImgHeight; y++) {
- for (x = 0; x < aImgWidth; x++) {
- cb = cg = cr = ca = sum = 0;
- if (ym<0) {
- bk0 = ri = -ym;
- read = x;
- } else {
- if (ym >= aImgHeight) {
- break;
- }
- bk0 = 0;
- ri = ym;
- read = x + ymi;
- }
- for (i = bk0; i < sharedBlurKernelSize; i++) {
- if (ri >= aImgHeight) {
- break;
- }
- m = sharedBlurKernal[i];
- ca += m * a2[read];
- cr += m * r2[read];
- cg += m * g2[read];
- cb += m * b2[read];
- sum += m;
- ri++;
- read += aImgWidth;
- }
- offset = (x + yi) *4;
- pix[offset] = cr / sum;
- pix[offset + 1] = cg / sum;
- pix[offset + 2] = cb / sum;
- pix[offset + 3] = ca / sum;
- }
- yi += aImgWidth;
- ymi += aImgWidth;
- ym++;
- }
- };
-
- // helper funtion for ERODE and DILATE modes of filter()
- var dilate = function(isInverted, aImg) {
- var currIdx = 0;
- var maxIdx = aImg.pixels.getLength();
- var out = new Int32Array(maxIdx);
- var currRowIdx, maxRowIdx, colOrig, colOut, currLum;
- var idxRight, idxLeft, idxUp, idxDown,
- colRight, colLeft, colUp, colDown,
- lumRight, lumLeft, lumUp, lumDown;
-
- if (!isInverted) {
- // erosion (grow light areas)
- while (currIdx<maxIdx) {
- currRowIdx = currIdx;
- maxRowIdx = currIdx + aImg.width;
- while (currIdx < maxRowIdx) {
- colOrig = colOut = aImg.pixels.getPixel(currIdx);
- idxLeft = currIdx - 1;
- idxRight = currIdx + 1;
- idxUp = currIdx - aImg.width;
- idxDown = currIdx + aImg.width;
- if (idxLeft < currRowIdx) {
- idxLeft = currIdx;
- }
- if (idxRight >= maxRowIdx) {
- idxRight = currIdx;
- }
- if (idxUp < 0) {
- idxUp = 0;
- }
- if (idxDown >= maxIdx) {
- idxDown = currIdx;
- }
- colUp = aImg.pixels.getPixel(idxUp);
- colLeft = aImg.pixels.getPixel(idxLeft);
- colDown = aImg.pixels.getPixel(idxDown);
- colRight = aImg.pixels.getPixel(idxRight);
-
- // compute luminance
- currLum = 77*(colOrig>>16&0xff) + 151*(colOrig>>8&0xff) + 28*(colOrig&0xff);
- lumLeft = 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff);
- lumRight = 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff);
- lumUp = 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff);
- lumDown = 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff);
-
- if (lumLeft > currLum) {
- colOut = colLeft;
- currLum = lumLeft;
- }
- if (lumRight > currLum) {
- colOut = colRight;
- currLum = lumRight;
- }
- if (lumUp > currLum) {
- colOut = colUp;
- currLum = lumUp;
- }
- if (lumDown > currLum) {
- colOut = colDown;
- currLum = lumDown;
- }
- out[currIdx++] = colOut;
- }
- }
- } else {
- // dilate (grow dark areas)
- while (currIdx < maxIdx) {
- currRowIdx = currIdx;
- maxRowIdx = currIdx + aImg.width;
- while (currIdx < maxRowIdx) {
- colOrig = colOut = aImg.pixels.getPixel(currIdx);
- idxLeft = currIdx - 1;
- idxRight = currIdx + 1;
- idxUp = currIdx - aImg.width;
- idxDown = currIdx + aImg.width;
- if (idxLeft < currRowIdx) {
- idxLeft = currIdx;
- }
- if (idxRight >= maxRowIdx) {
- idxRight = currIdx;
- }
- if (idxUp < 0) {
- idxUp = 0;
- }
- if (idxDown >= maxIdx) {
- idxDown = currIdx;
- }
- colUp = aImg.pixels.getPixel(idxUp);
- colLeft = aImg.pixels.getPixel(idxLeft);
- colDown = aImg.pixels.getPixel(idxDown);
- colRight = aImg.pixels.getPixel(idxRight);
-
- // compute luminance
- currLum = 77*(colOrig>>16&0xff) + 151*(colOrig>>8&0xff) + 28*(colOrig&0xff);
- lumLeft = 77*(colLeft>>16&0xff) + 151*(colLeft>>8&0xff) + 28*(colLeft&0xff);
- lumRight = 77*(colRight>>16&0xff) + 151*(colRight>>8&0xff) + 28*(colRight&0xff);
- lumUp = 77*(colUp>>16&0xff) + 151*(colUp>>8&0xff) + 28*(colUp&0xff);
- lumDown = 77*(colDown>>16&0xff) + 151*(colDown>>8&0xff) + 28*(colDown&0xff);
-
- if (lumLeft < currLum) {
- colOut = colLeft;
- currLum = lumLeft;
- }
- if (lumRight < currLum) {
- colOut = colRight;
- currLum = lumRight;
- }
- if (lumUp < currLum) {
- colOut = colUp;
- currLum = lumUp;
- }
- if (lumDown < currLum) {
- colOut = colDown;
- currLum = lumDown;
- }
- out[currIdx++]=colOut;
- }
- }
- }
- aImg.pixels.set(out);
- //p.arraycopy(out,0,pixels,0,maxIdx);
- };
-
- /**
- * Filters the display window as defined by one of the following modes:
- * THRESHOLD - converts the image to black and white pixels depending if they are above or below the threshold
- * defined by the level parameter. The level must be between 0.0 (black) and 1.0(white). If no level is specified, 0.5 is used.
- * GRAY - converts any colors in the image to grayscale equivalents
- * INVERT - sets each pixel to its inverse value
- * POSTERIZE - limits each channel of the image to the number of colors specified as the level parameter
- * BLUR - executes a Guassian blur with the level parameter specifying the extent of the blurring. If no level parameter is
- * used, the blur is equivalent to Guassian blur of radius 1.
- * OPAQUE - sets the alpha channel to entirely opaque.
- * ERODE - reduces the light areas with the amount defined by the level parameter.
- * DILATE - increases the light areas with the amount defined by the level parameter.
- *
- * @param {MODE} MODE Either THRESHOLD, GRAY, INVERT, POSTERIZE, BLUR, OPAQUE, ERODE, or DILATE
- * @param {int|float} level defines the quality of the filter
- *
- * @see blend
- */
- p.filter = function(kind, param, aImg){
- var img, col, lum, i;
-
- if (arguments.length === 3) {
- aImg.loadPixels();
- img = aImg;
- } else {
- p.loadPixels();
- img = p;
- }
-
- if (param === undef) {
- param = null;
- }
- if (img.isRemote) { // Remote images cannot access imageData
- throw "Image is loaded remotely. Cannot filter image.";
- }
- // begin filter process
- var imglen = img.pixels.getLength();
- switch (kind) {
- case PConstants.BLUR:
- var radius = param || 1; // if no param specified, use 1 (default for p5)
- blurARGB(radius, img);
- break;
-
- case PConstants.GRAY:
- if (img.format === PConstants.ALPHA) { //trouble
- // for an alpha image, convert it to an opaque grayscale
- for (i = 0; i < imglen; i++) {
- col = 255 - img.pixels.getPixel(i);
- img.pixels.setPixel(i,(0xff000000 | (col << 16) | (col << 8) | col));
- }
- img.format = PConstants.RGB; //trouble
- } else {
- for (i = 0; i < imglen; i++) {
- col = img.pixels.getPixel(i);
- lum = (77*(col>>16&0xff) + 151*(col>>8&0xff) + 28*(col&0xff))>>8;
- img.pixels.setPixel(i,((col & PConstants.ALPHA_MASK) | lum<<16 | lum<<8 | lum));
- }
- }
- break;
-
- case PConstants.INVERT:
- for (i = 0; i < imglen; i++) {
- img.pixels.setPixel(i, (img.pixels.getPixel(i) ^ 0xffffff));
- }
- break;
-
- case PConstants.POSTERIZE:
- if (param === null) {
- throw "Use filter(POSTERIZE, int levels) instead of filter(POSTERIZE)";
- }
- var levels = p.floor(param);
- if ((levels < 2) || (levels > 255)) {
- throw "Levels must be between 2 and 255 for filter(POSTERIZE, levels)";
- }
- var levels1 = levels - 1;
- for (i = 0; i < imglen; i++) {
- var rlevel = (img.pixels.getPixel(i) >> 16) & 0xff;
- var glevel = (img.pixels.getPixel(i) >> 8) & 0xff;
- var blevel = img.pixels.getPixel(i) & 0xff;
- rlevel = (((rlevel * levels) >> 8) * 255) / levels1;
- glevel = (((glevel * levels) >> 8) * 255) / levels1;
- blevel = (((blevel * levels) >> 8) * 255) / levels1;
- img.pixels.setPixel(i, ((0xff000000 & img.pixels.getPixel(i)) | (rlevel << 16) | (glevel << 8) | blevel));
- }
- break;
-
- case PConstants.OPAQUE:
- for (i = 0; i < imglen; i++) {
- img.pixels.setPixel(i, (img.pixels.getPixel(i) | 0xff000000));
- }
- img.format = PConstants.RGB; //trouble
- break;
-
- case PConstants.THRESHOLD:
- if (param === null) {
- param = 0.5;
- }
- if ((param < 0) || (param > 1)) {
- throw "Level must be between 0 and 1 for filter(THRESHOLD, level)";
- }
- var thresh = p.floor(param * 255);
- for (i = 0; i < imglen; i++) {
- var max = p.max((img.pixels.getPixel(i) & PConstants.RED_MASK) >> 16, p.max((img.pixels.getPixel(i) & PConstants.GREEN_MASK) >> 8, (img.pixels.getPixel(i) & PConstants.BLUE_MASK)));
- img.pixels.setPixel(i, ((img.pixels.getPixel(i) & PConstants.ALPHA_MASK) | ((max < thresh) ? 0x000000 : 0xffffff)));
- }
- break;
-
- case PConstants.ERODE:
- dilate(true, img);
- break;
-
- case PConstants.DILATE:
- dilate(false, img);
- break;
- }
- img.updatePixels();
- };
-
-
- // shared variables for blit_resize(), filter_new_scanline(), filter_bilinear(), filter()
- // change this in the future to not be exposed to p
- p.shared = {
- fracU: 0,
- ifU: 0,
- fracV: 0,
- ifV: 0,
- u1: 0,
- u2: 0,
- v1: 0,
- v2: 0,
- sX: 0,
- sY: 0,
- iw: 0,
- iw1: 0,
- ih1: 0,
- ul: 0,
- ll: 0,
- ur: 0,
- lr: 0,
- cUL: 0,
- cLL: 0,
- cUR: 0,
- cLR: 0,
- srcXOffset: 0,
- srcYOffset: 0,
- r: 0,
- g: 0,
- b: 0,
- a: 0,
- srcBuffer: null,
- blurRadius: 0,
- blurKernelSize: 0,
- blurKernel: null
- };
-
- p.intersect = function(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) {
- var sw = sx2 - sx1 + 1;
- var sh = sy2 - sy1 + 1;
- var dw = dx2 - dx1 + 1;
- var dh = dy2 - dy1 + 1;
- if (dx1 < sx1) {
- dw += dx1 - sx1;
- if (dw > sw) {
- dw = sw;
- }
- } else {
- var w = sw + sx1 - dx1;
- if (dw > w) {
- dw = w;
- }
- }
- if (dy1 < sy1) {
- dh += dy1 - sy1;
- if (dh > sh) {
- dh = sh;
- }
- } else {
- var h = sh + sy1 - dy1;
- if (dh > h) {
- dh = h;
- }
- }
- return ! (dw <= 0 || dh <= 0);
- };
-
- var blendFuncs = {};
- blendFuncs[PConstants.BLEND] = p.modes.blend;
- blendFuncs[PConstants.ADD] = p.modes.add;
- blendFuncs[PConstants.SUBTRACT] = p.modes.subtract;
- blendFuncs[PConstants.LIGHTEST] = p.modes.lightest;
- blendFuncs[PConstants.DARKEST] = p.modes.darkest;
- blendFuncs[PConstants.REPLACE] = p.modes.replace;
- blendFuncs[PConstants.DIFFERENCE] = p.modes.difference;
- blendFuncs[PConstants.EXCLUSION] = p.modes.exclusion;
- blendFuncs[PConstants.MULTIPLY] = p.modes.multiply;
- blendFuncs[PConstants.SCREEN] = p.modes.screen;
- blendFuncs[PConstants.OVERLAY] = p.modes.overlay;
- blendFuncs[PConstants.HARD_LIGHT] = p.modes.hard_light;
- blendFuncs[PConstants.SOFT_LIGHT] = p.modes.soft_light;
- blendFuncs[PConstants.DODGE] = p.modes.dodge;
- blendFuncs[PConstants.BURN] = p.modes.burn;
-
- p.blit_resize = function(img, srcX1, srcY1, srcX2, srcY2, destPixels,
- screenW, screenH, destX1, destY1, destX2, destY2, mode) {
- var x, y;
- if (srcX1 < 0) {
- srcX1 = 0;
- }
- if (srcY1 < 0) {
- srcY1 = 0;
- }
- if (srcX2 >= img.width) {
- srcX2 = img.width - 1;
- }
- if (srcY2 >= img.height) {
- srcY2 = img.height - 1;
- }
- var srcW = srcX2 - srcX1;
- var srcH = srcY2 - srcY1;
- var destW = destX2 - destX1;
- var destH = destY2 - destY1;
-
- if (destW <= 0 || destH <= 0 || srcW <= 0 || srcH <= 0 || destX1 >= screenW ||
- destY1 >= screenH || srcX1 >= img.width || srcY1 >= img.height) {
- return;
- }
-
- var dx = Math.floor(srcW / destW * PConstants.PRECISIONF);
- var dy = Math.floor(srcH / destH * PConstants.PRECISIONF);
-
- var pshared = p.shared;
-
- pshared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * PConstants.PRECISIONF);
- pshared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * PConstants.PRECISIONF);
- if (destX1 < 0) {
- destW += destX1;
- destX1 = 0;
- }
- if (destY1 < 0) {
- destH += destY1;
- destY1 = 0;
- }
- destW = Math.min(destW, screenW - destX1);
- destH = Math.min(destH, screenH - destY1);
-
- var destOffset = destY1 * screenW + destX1;
- var destColor;
-
- pshared.srcBuffer = img.imageData.data;
- pshared.iw = img.width;
- pshared.iw1 = img.width - 1;
- pshared.ih1 = img.height - 1;
-
- // cache for speed
- var filterBilinear = p.filter_bilinear,
- filterNewScanline = p.filter_new_scanline,
- blendFunc = blendFuncs[mode],
- blendedColor,
- idx,
- cULoffset,
- cURoffset,
- cLLoffset,
- cLRoffset,
- ALPHA_MASK = PConstants.ALPHA_MASK,
- RED_MASK = PConstants.RED_MASK,
- GREEN_MASK = PConstants.GREEN_MASK,
- BLUE_MASK = PConstants.BLUE_MASK,
- PREC_MAXVAL = PConstants.PREC_MAXVAL,
- PRECISIONB = PConstants.PRECISIONB,
- PREC_RED_SHIFT = PConstants.PREC_RED_SHIFT,
- PREC_ALPHA_SHIFT = PConstants.PREC_ALPHA_SHIFT,
- srcBuffer = pshared.srcBuffer,
- min = Math.min;
-
- for (y = 0; y < destH; y++) {
-
- pshared.sX = pshared.srcXOffset;
- pshared.fracV = pshared.srcYOffset & PREC_MAXVAL;
- pshared.ifV = PREC_MAXVAL - pshared.fracV;
- pshared.v1 = (pshared.srcYOffset >> PRECISIONB) * pshared.iw;
- pshared.v2 = min((pshared.srcYOffset >> PRECISIONB) + 1, pshared.ih1) * pshared.iw;
-
- for (x = 0; x < destW; x++) {
- idx = (destOffset + x) * 4;
-
- destColor = (destPixels[idx + 3] << 24) &
- ALPHA_MASK | (destPixels[idx] << 16) &
- RED_MASK | (destPixels[idx + 1] << 8) &
- GREEN_MASK | destPixels[idx + 2] & BLUE_MASK;
-
- pshared.fracU = pshared.sX & PREC_MAXVAL;
- pshared.ifU = PREC_MAXVAL - pshared.fracU;
- pshared.ul = (pshared.ifU * pshared.ifV) >> PRECISIONB;
- pshared.ll = (pshared.ifU * pshared.fracV) >> PRECISIONB;
- pshared.ur = (pshared.fracU * pshared.ifV) >> PRECISIONB;
- pshared.lr = (pshared.fracU * pshared.fracV) >> PRECISIONB;
- pshared.u1 = (pshared.sX >> PRECISIONB);
- pshared.u2 = min(pshared.u1 + 1, pshared.iw1);
-
- cULoffset = (pshared.v1 + pshared.u1) * 4;
- cURoffset = (pshared.v1 + pshared.u2) * 4;
- cLLoffset = (pshared.v2 + pshared.u1) * 4;
- cLRoffset = (pshared.v2 + pshared.u2) * 4;
-
- pshared.cUL = (srcBuffer[cULoffset + 3] << 24) &
- ALPHA_MASK | (srcBuffer[cULoffset] << 16) &
- RED_MASK | (srcBuffer[cULoffset + 1] << 8) &
- GREEN_MASK | srcBuffer[cULoffset + 2] & BLUE_MASK;
-
- pshared.cUR = (srcBuffer[cURoffset + 3] << 24) &
- ALPHA_MASK | (srcBuffer[cURoffset] << 16) &
- RED_MASK | (srcBuffer[cURoffset + 1] << 8) &
- GREEN_MASK | srcBuffer[cURoffset + 2] & BLUE_MASK;
-
- pshared.cLL = (srcBuffer[cLLoffset + 3] << 24) &
- ALPHA_MASK | (srcBuffer[cLLoffset] << 16) &
- RED_MASK | (srcBuffer[cLLoffset + 1] << 8) &
- GREEN_MASK | srcBuffer[cLLoffset + 2] & BLUE_MASK;
-
- pshared.cLR = (srcBuffer[cLRoffset + 3] << 24) &
- ALPHA_MASK | (srcBuffer[cLRoffset] << 16) &
- RED_MASK | (srcBuffer[cLRoffset + 1] << 8) &
- GREEN_MASK | srcBuffer[cLRoffset + 2] & BLUE_MASK;
-
- pshared.r = ((pshared.ul * ((pshared.cUL & RED_MASK) >> 16) +
- pshared.ll * ((pshared.cLL & RED_MASK) >> 16) +
- pshared.ur * ((pshared.cUR & RED_MASK) >> 16) +
- pshared.lr * ((pshared.cLR & RED_MASK) >> 16)) << PREC_RED_SHIFT) & RED_MASK;
- pshared.g = ((pshared.ul * (pshared.cUL & GREEN_MASK) +
- pshared.ll * (pshared.cLL & GREEN_MASK) +
- pshared.ur * (pshared.cUR & GREEN_MASK) +
- pshared.lr * (pshared.cLR & GREEN_MASK)) >>> PRECISIONB) & GREEN_MASK;
- pshared.b = (pshared.ul * (pshared.cUL & BLUE_MASK) +
- pshared.ll * (pshared.cLL & BLUE_MASK) +
- pshared.ur * (pshared.cUR & BLUE_MASK) +
- pshared.lr * (pshared.cLR & BLUE_MASK)) >>> PRECISIONB;
- pshared.a = ((pshared.ul * ((pshared.cUL & ALPHA_MASK) >>> 24) +
- pshared.ll * ((pshared.cLL & ALPHA_MASK) >>> 24) +
- pshared.ur * ((pshared.cUR & ALPHA_MASK) >>> 24) +
- pshared.lr * ((pshared.cLR & ALPHA_MASK) >>> 24)) << PREC_ALPHA_SHIFT) & ALPHA_MASK;
-
- blendedColor = blendFunc(destColor, (pshared.a | pshared.r | pshared.g | pshared.b));
-
- destPixels[idx] = (blendedColor & RED_MASK) >>> 16;
- destPixels[idx + 1] = (blendedColor & GREEN_MASK) >>> 8;
- destPixels[idx + 2] = (blendedColor & BLUE_MASK);
- destPixels[idx + 3] = (blendedColor & ALPHA_MASK) >>> 24;
-
- pshared.sX += dx;
- }
- destOffset += screenW;
- pshared.srcYOffset += dy;
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Font handling
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * loadFont() Loads a font into a variable of type PFont.
- *
- * @param {String} name filename of the font to load
- * @param {int|float} size option font size (used internally)
- *
- * @returns {PFont} new PFont object
- *
- * @see #PFont
- * @see #textFont
- * @see #text
- * @see #createFont
- */
- p.loadFont = function(name, size) {
- if (name === undef) {
- throw("font name required in loadFont.");
- }
- if (name.indexOf(".svg") === -1) {
- if (size === undef) {
- size = curTextFont.size;
- }
- return PFont.get(name, size);
- }
- // If the font is a glyph, calculate by SVG table
- var font = p.loadGlyphs(name);
-
- return {
- name: name,
- css: '12px sans-serif',
- glyph: true,
- units_per_em: font.units_per_em,
- horiz_adv_x: 1 / font.units_per_em * font.horiz_adv_x,
- ascent: font.ascent,
- descent: font.descent,
- width: function(str) {
- var width = 0;
- var len = str.length;
- for (var i = 0; i < len; i++) {
- try {
- width += parseFloat(p.glyphLook(p.glyphTable[name], str[i]).horiz_adv_x);
- }
- catch(e) {
- Processing.debug(e);
- }
- }
- return width / p.glyphTable[name].units_per_em;
- }
- };
- };
-
- /**
- * createFont() Loads a font into a variable of type PFont.
- * Smooth and charset are ignored in Processing.js.
- *
- * @param {String} name filename of the font to load
- * @param {int|float} size font size in pixels
- * @param {boolean} smooth not used in Processing.js
- * @param {char[]} charset not used in Processing.js
- *
- * @returns {PFont} new PFont object
- *
- * @see #PFont
- * @see #textFont
- * @see #text
- * @see #loadFont
- */
- p.createFont = function(name, size) {
- // because Processing.js only deals with real fonts,
- // createFont is simply a wrapper for loadFont/2
- return p.loadFont(name, size);
- };
-
- /**
- * textFont() Sets the current font.
- *
- * @param {PFont} pfont the PFont to load as current text font
- * @param {int|float} size optional font size in pixels
- *
- * @see #createFont
- * @see #loadFont
- * @see #PFont
- * @see #text
- */
- p.textFont = function(pfont, size) {
- if (size !== undef) {
- // If we're using an SVG glyph font, don't load from cache
- if (!pfont.glyph) {
- pfont = PFont.get(pfont.name, size);
- }
- curTextSize = size;
- }
- curTextFont = pfont;
- curFontName = curTextFont.name;
- curTextAscent = curTextFont.ascent;
- curTextDescent = curTextFont.descent;
- curTextLeading = curTextFont.leading;
- var curContext = drawing.$ensureContext();
- curContext.font = curTextFont.css;
- };
-
- /**
- * textSize() Sets the current font size in pixels.
- *
- * @param {int|float} size font size in pixels
- *
- * @see #textFont
- * @see #loadFont
- * @see #PFont
- * @see #text
- */
- p.textSize = function(size) {
- curTextFont = PFont.get(curFontName, size);
- curTextSize = size;
- // recache metrics
- curTextAscent = curTextFont.ascent;
- curTextDescent = curTextFont.descent;
- curTextLeading = curTextFont.leading;
- var curContext = drawing.$ensureContext();
- curContext.font = curTextFont.css;
- };
-
- /**
- * textAscent() returns the maximum height a character extends above the baseline of the
- * current font at its current size, in pixels.
- *
- * @returns {float} height of the current font above the baseline, at its current size, in pixels
- *
- * @see #textDescent
- */
- p.textAscent = function() {
- return curTextAscent;
- };
-
- /**
- * textDescent() returns the maximum depth a character will protrude below the baseline of
- * the current font at its current size, in pixels.
- *
- * @returns {float} depth of the current font below the baseline, at its current size, in pixels
- *
- * @see #textAscent
- */
- p.textDescent = function() {
- return curTextDescent;
- };
-
- /**
- * textLeading() Sets the current font's leading, which is the distance
- * from baseline to baseline over consecutive lines, with additional vertical
- * spacing taking into account. Usually this value is 1.2 or 1.25 times the
- * textsize, but this value can be changed to effect vertically compressed
- * or stretched text.
- *
- * @param {int|float} the desired baseline-to-baseline size in pixels
- */
- p.textLeading = function(leading) {
- curTextLeading = leading;
- };
-
- /**
- * textAlign() Sets the current alignment for drawing text.
- *
- * @param {int} ALIGN Horizontal alignment, either LEFT, CENTER, or RIGHT
- * @param {int} YALIGN optional vertical alignment, either TOP, BOTTOM, CENTER, or BASELINE
- *
- * @see #loadFont
- * @see #PFont
- * @see #text
- */
- p.textAlign = function(xalign, yalign) {
- horizontalTextAlignment = xalign;
- verticalTextAlignment = yalign || PConstants.BASELINE;
- };
-
- /**
- * toP5String converts things with arbitrary data type into
- * string values, for text rendering.
- *
- * @param {any} any object that can be converted into a string
- *
- * @return {String} the string representation of the input
- */
- function toP5String(obj) {
- if(obj instanceof String) {
- return obj;
- }
- if(typeof obj === 'number') {
- // check if an int
- if(obj === (0 | obj)) {
- return obj.toString();
- }
- return p.nf(obj, 0, 3);
- }
- if(obj === null || obj === undef) {
- return "";
- }
- return obj.toString();
- }
-
- /**
- * textWidth() Calculates and returns the width of any character or text string in pixels.
- *
- * @param {char|String} str char or String to be measured
- *
- * @return {float} width of char or String in pixels
- *
- * @see #loadFont
- * @see #PFont
- * @see #text
- * @see #textFont
- */
- Drawing2D.prototype.textWidth = function(str) {
- var lines = toP5String(str).split(/\r?\n/g), width = 0;
- var i, linesCount = lines.length;
-
- curContext.font = curTextFont.css;
- for (i = 0; i < linesCount; ++i) {
- width = Math.max(width, curTextFont.measureTextWidth(lines[i]));
- }
- return width | 0;
- };
-
- Drawing3D.prototype.textWidth = function(str) {
- var lines = toP5String(str).split(/\r?\n/g), width = 0;
- var i, linesCount = lines.length;
- if (textcanvas === undef) {
- textcanvas = document.createElement("canvas");
- }
-
- var textContext = textcanvas.getContext("2d");
- textContext.font = curTextFont.css;
-
- for (i = 0; i < linesCount; ++i) {
- width = Math.max(width, textContext.measureText(lines[i]).width);
- }
- return width | 0;
- };
-
- // A lookup table for characters that can not be referenced by Object
- p.glyphLook = function(font, chr) {
- try {
- switch (chr) {
- case "1":
- return font.one;
- case "2":
- return font.two;
- case "3":
- return font.three;
- case "4":
- return font.four;
- case "5":
- return font.five;
- case "6":
- return font.six;
- case "7":
- return font.seven;
- case "8":
- return font.eight;
- case "9":
- return font.nine;
- case "0":
- return font.zero;
- case " ":
- return font.space;
- case "$":
- return font.dollar;
- case "!":
- return font.exclam;
- case '"':
- return font.quotedbl;
- case "#":
- return font.numbersign;
- case "%":
- return font.percent;
- case "&":
- return font.ampersand;
- case "'":
- return font.quotesingle;
- case "(":
- return font.parenleft;
- case ")":
- return font.parenright;
- case "*":
- return font.asterisk;
- case "+":
- return font.plus;
- case ",":
- return font.comma;
- case "-":
- return font.hyphen;
- case ".":
- return font.period;
- case "/":
- return font.slash;
- case "_":
- return font.underscore;
- case ":":
- return font.colon;
- case ";":
- return font.semicolon;
- case "<":
- return font.less;
- case "=":
- return font.equal;
- case ">":
- return font.greater;
- case "?":
- return font.question;
- case "@":
- return font.at;
- case "[":
- return font.bracketleft;
- case "\\":
- return font.backslash;
- case "]":
- return font.bracketright;
- case "^":
- return font.asciicircum;
- case "`":
- return font.grave;
- case "{":
- return font.braceleft;
- case "|":
- return font.bar;
- case "}":
- return font.braceright;
- case "~":
- return font.asciitilde;
- // If the character is not 'special', access it by object reference
- default:
- return font[chr];
- }
- } catch(e) {
- Processing.debug(e);
- }
- };
-
- // Print some text to the Canvas
- Drawing2D.prototype.text$line = function(str, x, y, z, align) {
- var textWidth = 0, xOffset = 0;
- // If the font is a standard Canvas font...
- if (!curTextFont.glyph) {
- if (str && ("fillText" in curContext)) {
- if (isFillDirty) {
- curContext.fillStyle = p.color.toString(currentFillColor);
- isFillDirty = false;
- }
-
- // horizontal offset/alignment
- if(align === PConstants.RIGHT || align === PConstants.CENTER) {
- textWidth = curTextFont.measureTextWidth(str);
-
- if(align === PConstants.RIGHT) {
- xOffset = -textWidth;
- } else { // if(align === PConstants.CENTER)
- xOffset = -textWidth/2;
- }
- }
-
- curContext.fillText(str, x+xOffset, y);
- }
- } else {
- // If the font is a Batik SVG font...
- var font = p.glyphTable[curFontName];
- saveContext();
- curContext.translate(x, y + curTextSize);
-
- // horizontal offset/alignment
- if(align === PConstants.RIGHT || align === PConstants.CENTER) {
- textWidth = font.width(str);
-
- if(align === PConstants.RIGHT) {
- xOffset = -textWidth;
- } else { // if(align === PConstants.CENTER)
- xOffset = -textWidth/2;
- }
- }
-
- var upem = font.units_per_em,
- newScale = 1 / upem * curTextSize;
-
- curContext.scale(newScale, newScale);
-
- for (var i=0, len=str.length; i < len; i++) {
- // Test character against glyph table
- try {
- p.glyphLook(font, str[i]).draw();
- } catch(e) {
- Processing.debug(e);
- }
- }
- restoreContext();
- }
- };
-
- Drawing3D.prototype.text$line = function(str, x, y, z, align) {
- // handle case for 3d text
- if (textcanvas === undef) {
- textcanvas = document.createElement("canvas");
- }
- var oldContext = curContext;
- curContext = textcanvas.getContext("2d");
- curContext.font = curTextFont.css;
- var textWidth = curTextFont.measureTextWidth(str);
- textcanvas.width = textWidth;
- textcanvas.height = curTextSize;
- curContext = textcanvas.getContext("2d"); // refreshes curContext
- curContext.font = curTextFont.css;
- curContext.textBaseline="top";
-
- // paint on 2D canvas
- Drawing2D.prototype.text$line(str,0,0,0,PConstants.LEFT);
-
- // use it as a texture
- var aspect = textcanvas.width/textcanvas.height;
- curContext = oldContext;
-
- curContext.bindTexture(curContext.TEXTURE_2D, textTex);
- curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, textcanvas);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE);
- // If we don't have a power of two texture, we can't mipmap it.
- // curContext.generateMipmap(curContext.TEXTURE_2D);
-
- // horizontal offset/alignment
- var xOffset = 0;
- if (align === PConstants.RIGHT) {
- xOffset = -textWidth;
- } else if(align === PConstants.CENTER) {
- xOffset = -textWidth/2;
- }
- var model = new PMatrix3D();
- var scalefactor = curTextSize * 0.5;
- model.translate(x+xOffset-scalefactor/2, y-scalefactor, z);
- model.scale(-aspect*scalefactor, -scalefactor, scalefactor);
- model.translate(-1, -1, -1);
- model.transpose();
-
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
-
- curContext.useProgram(programObject2D);
- vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, textBuffer);
- vertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord", 2, textureBuffer);
- uniformi("uSampler2d", programObject2D, "uSampler", [0]);
-
- uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", true);
-
- uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array());
- uniformMatrix("uView2d", programObject2D, "uView", false, view.array());
- uniformf("uColor2d", programObject2D, "uColor", fillStyle);
- curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer);
- curContext.drawElements(curContext.TRIANGLES, 6, curContext.UNSIGNED_SHORT, 0);
- };
-
-
- /**
- * unbounded text function (z is an optional argument)
- */
- function text$4(str, x, y, z) {
- var lines, linesCount;
- if(str.indexOf('\n') < 0) {
- lines = [str];
- linesCount = 1;
- } else {
- lines = str.split(/\r?\n/g);
- linesCount = lines.length;
- }
- // handle text line-by-line
-
- var yOffset = 0;
- if(verticalTextAlignment === PConstants.TOP) {
- yOffset = curTextAscent + curTextDescent;
- } else if(verticalTextAlignment === PConstants.CENTER) {
- yOffset = curTextAscent/2 - (linesCount-1)*curTextLeading/2;
- } else if(verticalTextAlignment === PConstants.BOTTOM) {
- yOffset = -(curTextDescent + (linesCount-1)*curTextLeading);
- }
-
- for(var i=0;i<linesCount;++i) {
- var line = lines[i];
- drawing.text$line(line, x, y + yOffset, z, horizontalTextAlignment);
- yOffset += curTextLeading;
- }
- }
-
-
- /**
- * box-bounded text function (z is an optional argument)
- */
- function text$6(str, x, y, width, height, z) {
- // 'fail' on 0-valued dimensions
- if (str.length === 0 || width === 0 || height === 0) {
- return;
- }
- // also 'fail' if the text height is larger than the bounding height
- if(curTextSize > height) {
- return;
- }
-
- var spaceMark = -1;
- var start = 0;
- var lineWidth = 0;
- var drawCommands = [];
-
- // run through text, character-by-character
- for (var charPos=0, len=str.length; charPos < len; charPos++)
- {
- var currentChar = str[charPos];
- var spaceChar = (currentChar === " ");
- var letterWidth = curTextFont.measureTextWidth(currentChar);
-
- // if we aren't looking at a newline, and the text still fits, keep processing
- if (currentChar !== "\n" && (lineWidth + letterWidth <= width)) {
- if (spaceChar) { spaceMark = charPos; }
- lineWidth += letterWidth;
- }
-
- // if we're looking at a newline, or the text no longer fits, push the section that fit into the drawcommand list
- else
- {
- if (spaceMark + 1 === start) {
- if(charPos>0) {
- // Whole line without spaces so far.
- spaceMark = charPos;
- } else {
- // 'fail', because the line can't even fit the first character
- return;
- }
- }
-
- if (currentChar === "\n") {
- drawCommands.push({text:str.substring(start, charPos), width: lineWidth});
- start = charPos + 1;
- } else {
- // current is not a newline, which means the line doesn't fit in box. push text.
- // In Processing 1.5.1, the space is also pushed, so we push up to spaceMark+1,
- // rather than up to spaceMark, as was the case for Processing 1.5 and earlier.
- drawCommands.push({text:str.substring(start, spaceMark+1), width: lineWidth});
- start = spaceMark + 1;
- }
-
- // newline + return
- lineWidth = 0;
- charPos = start - 1;
- }
- }
-
- // push the remaining text
- if (start < len) {
- drawCommands.push({text:str.substring(start), width: lineWidth});
- }
-
- // resolve horizontal alignment
- var xOffset = 1,
- yOffset = curTextAscent;
- if (horizontalTextAlignment === PConstants.CENTER) {
- xOffset = width/2;
- } else if (horizontalTextAlignment === PConstants.RIGHT) {
- xOffset = width;
- }
-
- // resolve vertical alignment
- var linesCount = drawCommands.length,
- visibleLines = Math.min(linesCount, Math.floor(height/curTextLeading));
- if(verticalTextAlignment === PConstants.TOP) {
- yOffset = curTextAscent + curTextDescent;
- } else if(verticalTextAlignment === PConstants.CENTER) {
- yOffset = (height/2) - curTextLeading * (visibleLines/2 - 1);
- } else if(verticalTextAlignment === PConstants.BOTTOM) {
- yOffset = curTextDescent + curTextLeading;
- }
-
- var command,
- drawCommand,
- leading;
- for (command = 0; command < linesCount; command++) {
- leading = command * curTextLeading;
- // stop if not enough space for one more line draw
- if (yOffset + leading > height - curTextDescent) {
- break;
- }
- drawCommand = drawCommands[command];
- drawing.text$line(drawCommand.text, x + xOffset, y + yOffset + leading, z, horizontalTextAlignment);
- }
- }
-
- /**
- * text() Draws text to the screen.
- *
- * @param {String|char|int|float} data the alphanumeric symbols to be displayed
- * @param {int|float} x x-coordinate of text
- * @param {int|float} y y-coordinate of text
- * @param {int|float} z optional z-coordinate of text
- * @param {String} stringdata optional letters to be displayed
- * @param {int|float} width optional width of text box
- * @param {int|float} height optional height of text box
- *
- * @see #textAlign
- * @see #textMode
- * @see #loadFont
- * @see #PFont
- * @see #textFont
- */
- p.text = function() {
- if (textMode === PConstants.SHAPE) {
- // TODO: requires beginRaw function
- return;
- }
- if (arguments.length === 3) { // for text( str, x, y)
- text$4(toP5String(arguments[0]), arguments[1], arguments[2], 0);
- } else if (arguments.length === 4) { // for text( str, x, y, z)
- text$4(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3]);
- } else if (arguments.length === 5) { // for text( str, x, y , width, height)
- text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], 0);
- } else if (arguments.length === 6) { // for text( stringdata, x, y , width, height, z)
- text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
- }
- };
-
- /**
- * Sets the way text draws to the screen. In the default configuration (the MODEL mode), it's possible to rotate,
- * scale, and place letters in two and three dimensional space. <br /><br /> Changing to SCREEN mode draws letters
- * directly to the front of the window and greatly increases rendering quality and speed when used with the P2D and
- * P3D renderers. textMode(SCREEN) with OPENGL and JAVA2D (the default) renderers will generally be slower, though
- * pixel accurate with P2D and P3D. With textMode(SCREEN), the letters draw at the actual size of the font (in pixels)
- * and therefore calls to <b>textSize()</b> will not affect the size of the letters. To create a font at the size you
- * desire, use the "Create font..." option in the Tools menu, or use the createFont() function. When using textMode(SCREEN),
- * any z-coordinate passed to a text() command will be ignored, because your computer screen is...flat!
- *
- * @param {int} MODE Either MODEL, SCREEN or SHAPE (not yet supported)
- *
- * @see loadFont
- * @see PFont
- * @see text
- * @see textFont
- * @see createFont
- */
- p.textMode = function(mode){
- textMode = mode;
- };
-
- // Load Batik SVG Fonts and parse to pre-def objects for quick rendering
- p.loadGlyphs = function(url) {
- var x, y, cx, cy, nx, ny, d, a, lastCom, lenC, horiz_adv_x, getXY = '[0-9\\-]+', path;
-
- // Return arrays of SVG commands and coords
- // get this to use p.matchAll() - will need to work around the lack of null return
- var regex = function(needle, hay) {
- var i = 0,
- results = [],
- latest, regexp = new RegExp(needle, "g");
- latest = results[i] = regexp.exec(hay);
- while (latest) {
- i++;
- latest = results[i] = regexp.exec(hay);
- }
- return results;
- };
-
- var buildPath = function(d) {
- var c = regex("[A-Za-z][0-9\\- ]+|Z", d);
- var beforePathDraw = function() {
- saveContext();
- return drawing.$ensureContext();
- };
- var afterPathDraw = function() {
- executeContextFill();
- executeContextStroke();
- restoreContext();
- };
-
- // Begin storing path object
- path = "return {draw:function(){var curContext=beforePathDraw();curContext.beginPath();";
-
- x = 0;
- y = 0;
- cx = 0;
- cy = 0;
- nx = 0;
- ny = 0;
- d = 0;
- a = 0;
- lastCom = "";
- lenC = c.length - 1;
-
- // Loop through SVG commands translating to canvas eqivs functions in path object
- for (var j = 0; j < lenC; j++) {
- var com = c[j][0], xy = regex(getXY, com);
-
- switch (com[0]) {
- case "M":
- //curContext.moveTo(x,-y);
- x = parseFloat(xy[0][0]);
- y = parseFloat(xy[1][0]);
- path += "curContext.moveTo(" + x + "," + (-y) + ");";
- break;
-
- case "L":
- //curContext.lineTo(x,-y);
- x = parseFloat(xy[0][0]);
- y = parseFloat(xy[1][0]);
- path += "curContext.lineTo(" + x + "," + (-y) + ");";
- break;
-
- case "H":
- //curContext.lineTo(x,-y)
- x = parseFloat(xy[0][0]);
- path += "curContext.lineTo(" + x + "," + (-y) + ");";
- break;
-
- case "V":
- //curContext.lineTo(x,-y);
- y = parseFloat(xy[0][0]);
- path += "curContext.lineTo(" + x + "," + (-y) + ");";
- break;
-
- case "T":
- //curContext.quadraticCurveTo(cx,-cy,nx,-ny);
- nx = parseFloat(xy[0][0]);
- ny = parseFloat(xy[1][0]);
-
- if (lastCom === "Q" || lastCom === "T") {
- d = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(cy - y, 2));
- a = Math.PI + Math.atan2(cx - x, cy - y);
- cx = x + (Math.sin(a) * (d));
- cy = y + (Math.cos(a) * (d));
- } else {
- cx = x;
- cy = y;
- }
-
- path += "curContext.quadraticCurveTo(" + cx + "," + (-cy) + "," + nx + "," + (-ny) + ");";
- x = nx;
- y = ny;
- break;
-
- case "Q":
- //curContext.quadraticCurveTo(cx,-cy,nx,-ny);
- cx = parseFloat(xy[0][0]);
- cy = parseFloat(xy[1][0]);
- nx = parseFloat(xy[2][0]);
- ny = parseFloat(xy[3][0]);
- path += "curContext.quadraticCurveTo(" + cx + "," + (-cy) + "," + nx + "," + (-ny) + ");";
- x = nx;
- y = ny;
- break;
-
- case "Z":
- //curContext.closePath();
- path += "curContext.closePath();";
- break;
- }
- lastCom = com[0];
- }
-
- path += "afterPathDraw();";
- path += "curContext.translate(" + horiz_adv_x + ",0);";
- path += "}}";
-
- return ((new Function("beforePathDraw", "afterPathDraw", path))(beforePathDraw, afterPathDraw));
- };
-
- // Parse SVG font-file into block of Canvas commands
- var parseSVGFont = function(svg) {
- // Store font attributes
- var font = svg.getElementsByTagName("font");
- p.glyphTable[url].horiz_adv_x = font[0].getAttribute("horiz-adv-x");
-
- var font_face = svg.getElementsByTagName("font-face")[0];
- p.glyphTable[url].units_per_em = parseFloat(font_face.getAttribute("units-per-em"));
- p.glyphTable[url].ascent = parseFloat(font_face.getAttribute("ascent"));
- p.glyphTable[url].descent = parseFloat(font_face.getAttribute("descent"));
-
- var glyph = svg.getElementsByTagName("glyph"),
- len = glyph.length;
-
- // Loop through each glyph in the SVG
- for (var i = 0; i < len; i++) {
- // Store attributes for this glyph
- var unicode = glyph[i].getAttribute("unicode");
- var name = glyph[i].getAttribute("glyph-name");
- horiz_adv_x = glyph[i].getAttribute("horiz-adv-x");
- if (horiz_adv_x === null) {
- horiz_adv_x = p.glyphTable[url].horiz_adv_x;
- }
- d = glyph[i].getAttribute("d");
- // Split path commands in glpyh
- if (d !== undef) {
- path = buildPath(d);
- // Store glyph data to table object
- p.glyphTable[url][name] = {
- name: name,
- unicode: unicode,
- horiz_adv_x: horiz_adv_x,
- draw: path.draw
- };
- }
- } // finished adding glyphs to table
- };
-
- // Load and parse Batik SVG font as XML into a Processing Glyph object
- var loadXML = function() {
- var xmlDoc;
-
- try {
- xmlDoc = document.implementation.createDocument("", "", null);
- }
- catch(e_fx_op) {
- Processing.debug(e_fx_op.message);
- return;
- }
-
- try {
- xmlDoc.async = false;
- xmlDoc.load(url);
- parseSVGFont(xmlDoc.getElementsByTagName("svg")[0]);
- }
- catch(e_sf_ch) {
- // Google Chrome, Safari etc.
- Processing.debug(e_sf_ch);
- try {
- var xmlhttp = new window.XMLHttpRequest();
- xmlhttp.open("GET", url, false);
- xmlhttp.send(null);
- parseSVGFont(xmlhttp.responseXML.documentElement);
- }
- catch(e) {
- Processing.debug(e_sf_ch);
- }
- }
- };
-
- // Create a new object in glyphTable to store this font
- p.glyphTable[url] = {};
-
- // Begin loading the Batik SVG font...
- loadXML(url);
-
- // Return the loaded font for attribute grabbing
- return p.glyphTable[url];
- };
-
- /**
- * Gets the sketch parameter value. The parameter can be defined as the canvas attribute with
- * the "data-processing-" prefix or provided in the pjs directive (e.g. param-test="52").
- * The function tries the canvas attributes, then the pjs directive content.
- *
- * @param {String} name The name of the param to read.
- *
- * @returns {String} The parameter value, or null if parameter is not defined.
- */
- p.param = function(name) {
- // trying attribute that was specified in CANVAS
- var attributeName = "data-processing-" + name;
- if (curElement.hasAttribute(attributeName)) {
- return curElement.getAttribute(attributeName);
- }
- // trying child PARAM elements of the CANVAS
- for (var i = 0, len = curElement.childNodes.length; i < len; ++i) {
- var item = curElement.childNodes.item(i);
- if (item.nodeType !== 1 || item.tagName.toLowerCase() !== "param") {
- continue;
- }
- if (item.getAttribute("name") === name) {
- return item.getAttribute("value");
- }
- }
- // fallback to default params
- if (curSketch.params.hasOwnProperty(name)) {
- return curSketch.params[name];
- }
- return null;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // 2D/3D methods wiring utils
- ////////////////////////////////////////////////////////////////////////////
- function wireDimensionalFunctions(mode) {
- // Drawing2D/Drawing3D
- if (mode === '3D') {
- drawing = new Drawing3D();
- } else if (mode === '2D') {
- drawing = new Drawing2D();
- } else {
- drawing = new DrawingPre();
- }
-
- // Wire up functions (Use DrawingPre properties names)
- for (var i in DrawingPre.prototype) {
- if (DrawingPre.prototype.hasOwnProperty(i) && i.indexOf("$") < 0) {
- p[i] = drawing[i];
- }
- }
-
- // Run initialization
- drawing.$init();
- }
-
- function createDrawingPreFunction(name) {
- return function() {
- wireDimensionalFunctions("2D");
- return drawing[name].apply(this, arguments);
- };
- }
- DrawingPre.prototype.translate = createDrawingPreFunction("translate");
- DrawingPre.prototype.transform = createDrawingPreFunction("transform");
- DrawingPre.prototype.scale = createDrawingPreFunction("scale");
- DrawingPre.prototype.pushMatrix = createDrawingPreFunction("pushMatrix");
- DrawingPre.prototype.popMatrix = createDrawingPreFunction("popMatrix");
- DrawingPre.prototype.resetMatrix = createDrawingPreFunction("resetMatrix");
- DrawingPre.prototype.applyMatrix = createDrawingPreFunction("applyMatrix");
- DrawingPre.prototype.rotate = createDrawingPreFunction("rotate");
- DrawingPre.prototype.rotateZ = createDrawingPreFunction("rotateZ");
- DrawingPre.prototype.shearX = createDrawingPreFunction("shearX");
- DrawingPre.prototype.shearY = createDrawingPreFunction("shearY");
- DrawingPre.prototype.redraw = createDrawingPreFunction("redraw");
- DrawingPre.prototype.toImageData = createDrawingPreFunction("toImageData");
- DrawingPre.prototype.ambientLight = createDrawingPreFunction("ambientLight");
- DrawingPre.prototype.directionalLight = createDrawingPreFunction("directionalLight");
- DrawingPre.prototype.lightFalloff = createDrawingPreFunction("lightFalloff");
- DrawingPre.prototype.lightSpecular = createDrawingPreFunction("lightSpecular");
- DrawingPre.prototype.pointLight = createDrawingPreFunction("pointLight");
- DrawingPre.prototype.noLights = createDrawingPreFunction("noLights");
- DrawingPre.prototype.spotLight = createDrawingPreFunction("spotLight");
- DrawingPre.prototype.beginCamera = createDrawingPreFunction("beginCamera");
- DrawingPre.prototype.endCamera = createDrawingPreFunction("endCamera");
- DrawingPre.prototype.frustum = createDrawingPreFunction("frustum");
- DrawingPre.prototype.box = createDrawingPreFunction("box");
- DrawingPre.prototype.sphere = createDrawingPreFunction("sphere");
- DrawingPre.prototype.ambient = createDrawingPreFunction("ambient");
- DrawingPre.prototype.emissive = createDrawingPreFunction("emissive");
- DrawingPre.prototype.shininess = createDrawingPreFunction("shininess");
- DrawingPre.prototype.specular = createDrawingPreFunction("specular");
- DrawingPre.prototype.fill = createDrawingPreFunction("fill");
- DrawingPre.prototype.stroke = createDrawingPreFunction("stroke");
- DrawingPre.prototype.strokeWeight = createDrawingPreFunction("strokeWeight");
- DrawingPre.prototype.smooth = createDrawingPreFunction("smooth");
- DrawingPre.prototype.noSmooth = createDrawingPreFunction("noSmooth");
- DrawingPre.prototype.point = createDrawingPreFunction("point");
- DrawingPre.prototype.vertex = createDrawingPreFunction("vertex");
- DrawingPre.prototype.endShape = createDrawingPreFunction("endShape");
- DrawingPre.prototype.bezierVertex = createDrawingPreFunction("bezierVertex");
- DrawingPre.prototype.curveVertex = createDrawingPreFunction("curveVertex");
- DrawingPre.prototype.curve = createDrawingPreFunction("curve");
- DrawingPre.prototype.line = createDrawingPreFunction("line");
- DrawingPre.prototype.bezier = createDrawingPreFunction("bezier");
- DrawingPre.prototype.rect = createDrawingPreFunction("rect");
- DrawingPre.prototype.ellipse = createDrawingPreFunction("ellipse");
- DrawingPre.prototype.background = createDrawingPreFunction("background");
- DrawingPre.prototype.image = createDrawingPreFunction("image");
- DrawingPre.prototype.textWidth = createDrawingPreFunction("textWidth");
- DrawingPre.prototype.text$line = createDrawingPreFunction("text$line");
- DrawingPre.prototype.$ensureContext = createDrawingPreFunction("$ensureContext");
- DrawingPre.prototype.$newPMatrix = createDrawingPreFunction("$newPMatrix");
-
- DrawingPre.prototype.size = function(aWidth, aHeight, aMode) {
- wireDimensionalFunctions(aMode === PConstants.WEBGL ? "3D" : "2D");
- p.size(aWidth, aHeight, aMode);
- };
-
- DrawingPre.prototype.$init = noop;
-
- Drawing2D.prototype.$init = function() {
- // Setup default 2d canvas context.
- // Moving this here removes the number of times we need to check the 3D variable
- p.size(p.width, p.height);
-
- curContext.lineCap = 'round';
-
- // Set default stroke and fill color
- p.noSmooth();
- p.disableContextMenu();
- };
- Drawing3D.prototype.$init = function() {
- // For ref/perf test compatibility until those are fixed
- p.use3DContext = true;
- p.disableContextMenu();
- };
-
- DrawingShared.prototype.$ensureContext = function() {
- return curContext;
- };
-
- //////////////////////////////////////////////////////////////////////////
- // Keyboard Events
- //////////////////////////////////////////////////////////////////////////
-
- // In order to catch key events in a canvas, it needs to be "specially focusable",
- // by assigning it a tabindex. If no tabindex is specified on-page, set this to 0.
- if (!curElement.getAttribute("tabindex")) {
- curElement.setAttribute("tabindex", 0);
- }
-
- function getKeyCode(e) {
- var code = e.which || e.keyCode;
- switch (code) {
- case 13: // ENTER
- return 10;
- case 91: // META L (Saf/Mac)
- case 93: // META R (Saf/Mac)
- case 224: // META (FF/Mac)
- return 157;
- case 57392: // CONTROL (Op/Mac)
- return 17;
- case 46: // DELETE
- return 127;
- case 45: // INSERT
- return 155;
- }
- return code;
- }
-
- function getKeyChar(e) {
- var c = e.which || e.keyCode;
- var anyShiftPressed = e.shiftKey || e.ctrlKey || e.altKey || e.metaKey;
- switch (c) {
- case 13:
- c = anyShiftPressed ? 13 : 10; // RETURN vs ENTER (Mac)
- break;
- case 8:
- c = anyShiftPressed ? 127 : 8; // DELETE vs BACKSPACE (Mac)
- break;
- }
- return new Char(c);
- }
-
- function suppressKeyEvent(e) {
- if (typeof e.preventDefault === "function") {
- e.preventDefault();
- } else if (typeof e.stopPropagation === "function") {
- e.stopPropagation();
- }
- return false;
- }
-
- function updateKeyPressed() {
- var ch;
- for (ch in pressedKeysMap) {
- if (pressedKeysMap.hasOwnProperty(ch)) {
- p.__keyPressed = true;
- return;
- }
- }
- p.__keyPressed = false;
- }
-
- function resetKeyPressed() {
- p.__keyPressed = false;
- pressedKeysMap = [];
- lastPressedKeyCode = null;
- }
-
- function simulateKeyTyped(code, c) {
- pressedKeysMap[code] = c;
- lastPressedKeyCode = null;
- p.key = c;
- p.keyCode = code;
- p.keyPressed();
- p.keyCode = 0;
- p.keyTyped();
- updateKeyPressed();
- }
-
- function handleKeydown(e) {
- var code = getKeyCode(e);
- if (code === PConstants.DELETE) {
- simulateKeyTyped(code, new Char(127));
- return;
- }
- if (codedKeys.indexOf(code) < 0) {
- lastPressedKeyCode = code;
- return;
- }
- var c = new Char(PConstants.CODED);
- p.key = c;
- p.keyCode = code;
- pressedKeysMap[code] = c;
- p.keyPressed();
- lastPressedKeyCode = null;
- updateKeyPressed();
- return suppressKeyEvent(e);
- }
-
- function handleKeypress(e) {
- if (lastPressedKeyCode === null) {
- return; // processed in handleKeydown
- }
- var code = lastPressedKeyCode, c = getKeyChar(e);
- simulateKeyTyped(code, c);
- return suppressKeyEvent(e);
- }
-
- function handleKeyup(e) {
- var code = getKeyCode(e), c = pressedKeysMap[code];
- if (c === undef) {
- return; // no keyPressed event was generated.
- }
- p.key = c;
- p.keyCode = code;
- p.keyReleased();
- delete pressedKeysMap[code];
- updateKeyPressed();
- }
-
- // Send aCode Processing syntax to be converted to JavaScript
- if (!pgraphicsMode) {
- if (aCode instanceof Processing.Sketch) {
- // Use sketch as is
- curSketch = aCode;
- } else if (typeof aCode === "function") {
- // Wrap function with default sketch parameters
- curSketch = new Processing.Sketch(aCode);
- } else if (!aCode) {
- // Empty sketch
- curSketch = new Processing.Sketch(function (){});
- } else {
- //#if PARSER
- // Compile the code
- curSketch = Processing.compile(aCode);
- //#else
- // throw "PJS compile is not supported";
- //#endif
- }
-
- // Expose internal field for diagnostics and testing
- p.externals.sketch = curSketch;
-
- wireDimensionalFunctions();
-
- // the onfocus and onblur events are handled in two parts.
- // 1) the p.focused property is handled per sketch
- curElement.onfocus = function() {
- p.focused = true;
- };
-
- curElement.onblur = function() {
- p.focused = false;
- if (!curSketch.options.globalKeyEvents) {
- resetKeyPressed();
- }
- };
-
- // 2) looping status is handled per page, based on the pauseOnBlur @pjs directive
- if (curSketch.options.pauseOnBlur) {
- attachEventHandler(window, 'focus', function() {
- if (doLoop) {
- p.loop();
- }
- });
-
- attachEventHandler(window, 'blur', function() {
- if (doLoop && loopStarted) {
- p.noLoop();
- doLoop = true; // make sure to keep this true after the noLoop call
- }
- resetKeyPressed();
- });
- }
-
- // if keyboard events should be handled globally, the listeners should
- // be bound to the document window, rather than to the current canvas
- var keyTrigger = curSketch.options.globalKeyEvents ? window : curElement;
- attachEventHandler(keyTrigger, "keydown", handleKeydown);
- attachEventHandler(keyTrigger, "keypress", handleKeypress);
- attachEventHandler(keyTrigger, "keyup", handleKeyup);
-
- // Step through the libraries that were attached at doc load...
- for (var i in Processing.lib) {
- if (Processing.lib.hasOwnProperty(i)) {
- if(Processing.lib[i].hasOwnProperty("attach")) {
- // use attach function if present
- Processing.lib[i].attach(p);
- } else if(Processing.lib[i] instanceof Function) {
- // Init the libraries in the context of this p_instance (legacy)
- Processing.lib[i].call(this);
- }
- }
- }
-
- // sketch execute test interval, used to reschedule
- // an execute when preloads have not yet finished.
- var retryInterval = 100;
-
- var executeSketch = function(processing) {
- // Don't start until all specified images and fonts in the cache are preloaded
- if (!(curSketch.imageCache.pending || PFont.preloading.pending(retryInterval))) {
- // the opera preload cache can only be cleared once we start
- if (window.opera) {
- var link,
- element,
- operaCache=curSketch.imageCache.operaCache;
- for (link in operaCache) {
- if(operaCache.hasOwnProperty(link)) {
- element = operaCache[link];
- if (element !== null) {
- document.body.removeChild(element);
- }
- delete(operaCache[link]);
- }
- }
- }
-
- curSketch.attach(processing, defaultScope);
-
- // pass a reference to the p instance for this sketch.
- curSketch.onLoad(processing);
-
- // Run void setup()
- if (processing.setup) {
- processing.setup();
- // if any transforms were performed in setup reset to identity matrix
- // so draw loop is unpolluted
- processing.resetMatrix();
- curSketch.onSetup();
- }
-
- // some pixels can be cached, flushing
- resetContext();
-
- if (processing.draw) {
- if (!doLoop) {
- processing.redraw();
- } else {
- processing.loop();
- }
- }
- } else {
- window.setTimeout(function() { executeSketch(processing); }, retryInterval);
- }
- };
-
- // Only store an instance of non-createGraphics instances.
- addInstance(this);
-
- // The parser adds custom methods to the processing context
- // this renames p to processing so these methods will run
- executeSketch(p);
- } else {
- // No executable sketch was specified
- // or called via createGraphics
- curSketch = new Processing.Sketch();
-
- wireDimensionalFunctions();
-
- // Hack to make PGraphics work again after splitting size()
- p.size = function(w, h, render) {
- if (render && render === PConstants.WEBGL) {
- wireDimensionalFunctions('3D');
- } else {
- wireDimensionalFunctions('2D');
- }
-
- p.size(w, h, render);
- };
- }
- };
-
- // Place-holder for overridable debugging function
- Processing.debug = (function() {
- if ("console" in window) {
- return function(msg) {
- window.console.log('Processing.js: ' + msg);
- };
- }
- return noop;
- }());
-
- // bind prototype
- Processing.prototype = defaultScope;
-
- /**
- * instance store and lookup
- */
- Processing.instances = processingInstances;
- Processing.getInstanceById = function(name) {
- return processingInstances[processingInstanceIds[name]];
- };
-
- // Unsupported Processing File and I/O operations.
- (function(Processing) {
- var unsupportedP5 = ("open() createOutput() createInput() BufferedReader selectFolder() " +
- "dataPath() createWriter() selectOutput() beginRecord() " +
- "saveStream() endRecord() selectInput() saveBytes() createReader() " +
- "beginRaw() endRaw() PrintWriter delay()").split(" "),
- count = unsupportedP5.length,
- prettyName,
- p5Name;
-
- function createUnsupportedFunc(n) {
- return function() {
- throw "Processing.js does not support " + n + ".";
- };
- }
-
- while (count--) {
- prettyName = unsupportedP5[count];
- p5Name = prettyName.replace("()", "");
- Processing[p5Name] = createUnsupportedFunc(prettyName);
- }
- }(defaultScope));
-
- // we're done. Return our object.
- return Processing;
- };
-
- },{}],28:[function(require,module,exports){
- // Base source files
- var source = {
- virtEquals: require("./Helpers/virtEquals"),
- virtHashCode: require("./Helpers/virtHashCode"),
- ObjectIterator: require("./Helpers/ObjectIterator"),
- PConstants: require("./Helpers/PConstants"),
- ArrayList: require("./Objects/ArrayList"),
- HashMap: require("./Objects/HashMap"),
- PVector: require("./Objects/PVector"),
- PFont: require("./Objects/PFont"),
- Char: require("./Objects/Char"),
- XMLAttribute: require("./Objects/XMLAttribute"),
- XMLElement: require("./Objects/XMLElement"),
- PMatrix2D: require("./Objects/PMatrix2D"),
- PMatrix3D: require("./Objects/PMatrix3D"),
- PShape: require("./Objects/PShape"),
- colors: require("./Objects/webcolors"),
- PShapeSVG: require("./Objects/PShapeSVG"),
- CommonFunctions: require("./P5Functions/commonFunctions"),
- defaultScope: require("./Helpers/defaultScope"),
- Processing: require("./Processing"),
- setupParser: require("./Parser/Parser"),
- finalize: require("./Helpers/finalizeProcessing")
- };
-
- // Additional code that gets tacked onto "p" during
- // instantiation of a Processing sketch.
- source.extend = {
- withMath: require("./P5Functions/Math.js"),
- withProxyFunctions: require("./P5Functions/JavaProxyFunctions")(source.virtHashCode, source.virtEquals),
- withTouch: require("./P5Functions/touchmouse"),
- withCommonFunctions: source.CommonFunctions.withCommonFunctions
- };
-
- /**
- * Processing.js building function
- */
- module.exports = function buildProcessingJS(Browser, testHarness) {
- var noop = function(){},
- virtEquals = source.virtEquals,
- virtHashCode = source.virtHashCode,
- PConstants = source.PConstants,
- CommonFunctions = source.CommonFunctions,
- ObjectIterator = source.ObjectIterator,
- Char = source.Char,
- XMLAttribute = source.XMLAttribute(),
-
- ArrayList = source.ArrayList({
- virtHashCode: virtHashCode,
- virtEquals: virtEquals
- }),
-
- HashMap = source.HashMap({
- virtHashCode: virtHashCode,
- virtEquals: virtEquals
- }),
-
- PVector = source.PVector({
- PConstants: PConstants
- }),
-
- PFont = source.PFont({
- Browser: Browser,
- noop: noop
- }),
-
- XMLElement = source.XMLElement({
- Browser: Browser,
- XMLAttribute: XMLAttribute
- }),
-
- PMatrix2D = source.PMatrix2D({
- p:CommonFunctions
- }),
-
- PMatrix3D = source.PMatrix3D({
- p:CommonFunctions
- }),
-
- PShape = source.PShape({
- PConstants: PConstants,
- PMatrix2D: PMatrix2D,
- PMatrix3D: PMatrix3D
- }),
-
- PShapeSVG = source.PShapeSVG({
- CommonFunctions: CommonFunctions,
- PConstants: PConstants,
- PShape: PShape,
- XMLElement: XMLElement,
- colors: source.colors
- }),
-
- defaultScope = source.defaultScope({
- ArrayList: ArrayList,
- HashMap: HashMap,
- PVector: PVector,
- PFont: PFont,
- PShapeSVG: PShapeSVG,
- ObjectIterator: ObjectIterator,
- PConstants: PConstants,
- Char: Char,
- XMLElement: XMLElement,
- XML: XMLElement
- }),
-
- Processing = source.Processing({
- defaultScope: defaultScope,
- Browser: Browser,
- extend: source.extend,
- noop: noop
- });
-
- // set up the Processing syntax parser
- Processing = source.setupParser(Processing, {
- Browser: Browser,
- aFunctions: testHarness,
- defaultScope: defaultScope
- });
-
- // finalise the Processing object
- Processing = source.finalize(Processing, {
- version: require('../package.json').version,
- isDomPresent: false || Browser.isDomPresent,
- window: Browser.window,
- document: Browser.document,
- noop: noop
- });
-
- // done.
- return Processing;
- };
-
- },{"../package.json":2,"./Helpers/ObjectIterator":3,"./Helpers/PConstants":4,"./Helpers/defaultScope":6,"./Helpers/finalizeProcessing":7,"./Helpers/virtEquals":8,"./Helpers/virtHashCode":9,"./Objects/ArrayList":10,"./Objects/Char":11,"./Objects/HashMap":12,"./Objects/PFont":13,"./Objects/PMatrix2D":14,"./Objects/PMatrix3D":15,"./Objects/PShape":16,"./Objects/PShapeSVG":17,"./Objects/PVector":18,"./Objects/XMLAttribute":19,"./Objects/XMLElement":20,"./Objects/webcolors":21,"./P5Functions/JavaProxyFunctions":22,"./P5Functions/Math.js":23,"./P5Functions/commonFunctions":24,"./P5Functions/touchmouse":25,"./Parser/Parser":26,"./Processing":27}]},{},[1]);
|