12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292 |
- /*
- P R O C E S S I N G . J S - @VERSION@
- a port of the Processing visualization language
- License : MIT
- Developer : John Resig: http://ejohn.org
- Web Site : http://processingjs.org
- Java Version : http://processing.org
- Github Repo. : http://github.com/jeresig/processing-js
- Bug Tracking : http://processing-js.lighthouseapp.com
- Mozilla POW! : http://wiki.Mozilla.org/Education/Projects/ProcessingForTheWeb
- Maintained by : Seneca: http://zenit.senecac.on.ca/wiki/index.php/Processing.js
- Hyper-Metrix: http://hyper-metrix.com/#Processing
- BuildingSky: http://weare.buildingsky.net/pages/processing-js
- */
- (function() {
- var undef; // intentionally left undefined
- var ajax = function ajax(url) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", url, false);
- xhr.setRequestHeader("If-Modified-Since", "Fri, 1 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;
- };
- var PVector = function(x, y, z) {
- this.x = x || 0;
- this.y = y || 0;
- this.z = z || 0;
- },
- createPVectorMethod = function(method) {
- return function(v1, v2) {
- var v = v1.get();
- v[method](v2);
- return v;
- };
- },
- createSimplePVectorMethod = function(method) {
- return function(v1, v2) {
- return v1[method](v2);
- };
- },
- simplePVMethods = "dist dot cross".split(" "),
- method = simplePVMethods.length;
- PVector.angleBetween = function(v1, v2) {
- return Math.acos(v1.dot(v2) / (v1.mag() * v2.mag()));
- };
- // Common vector operations for PVector
- PVector.prototype = {
- set: function(v, y, z) {
- if (arguments.length === 1) {
- this.set(v.x || v[0], v.y || v[1], v.z || v[2]);
- } else {
- this.x = v;
- this.y = y;
- this.z = z;
- }
- },
- get: function() {
- return new PVector(this.x, this.y, this.z);
- },
- mag: function() {
- return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
- },
- add: function(v, y, z) {
- if (arguments.length === 3) {
- this.x += v;
- this.y += y;
- this.z += z;
- } else if (arguments.length === 1) {
- this.x += v.x;
- this.y += v.y;
- this.z += v.z;
- }
- },
- sub: function(v, y, z) {
- if (arguments.length === 3) {
- this.x -= v;
- this.y -= y;
- this.z -= z;
- } else if (arguments.length === 1) {
- this.x -= v.x;
- this.y -= v.y;
- this.z -= v.z;
- }
- },
- mult: function(v) {
- if (typeof v === 'number') {
- this.x *= v;
- this.y *= v;
- this.z *= v;
- } else if (typeof v === 'object') {
- 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 if (typeof v === 'object') {
- this.x /= v.x;
- this.y /= v.y;
- this.z /= v.z;
- }
- },
- 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 === 3) {
- return (this.x * v + this.y * y + this.z * z);
- } else if (arguments.length === 1) {
- return (this.x * v.x + this.y * v.y + this.z * v.z);
- }
- },
- cross: function(v) {
- return new PVector(this.y * v.z - v.y * this.z,
- this.z * v.x - v.z * this.x,
- this.x * v.y - v.x * this.y);
- },
- normalize: function() {
- var m = this.mag();
- if (m > 0) {
- this.div(m);
- }
- },
- limit: function(high) {
- if (this.mag() > high) {
- this.normalize();
- this.mult(high);
- }
- },
- heading2D: function() {
- return (-Math.atan2(-this.y, this.x));
- },
- toString: function() {
- return "[" + this.x + ", " + this.y + ", " + this.z + "]";
- },
- array: function() {
- return [this.x, this.y, this.z];
- }
- };
- while (method--) {
- PVector[simplePVMethods[method]] = createSimplePVectorMethod(simplePVMethods[method]);
- }
- for (method in PVector.prototype) {
- if (PVector.prototype.hasOwnProperty(method) && !PVector.hasOwnProperty(method)) {
- PVector[method] = createPVectorMethod(method);
- }
- }
- var Processing = this.Processing = function Processing(curElement, aCode) {
- var p = this;
- // Include Package Classes -- do this differently in the future.
- p.PVector = PVector;
- //p.PShapeSVG = PShapeSVG;
- //etc
- p.name = 'Processing.js Instance'; // Set Processing defaults / environment variables
- p.use3DContext = false; // default '2d' canvas context
- // PJS specific (non-p5) methods and properties to externalize
- p.externals = {
- canvas: curElement,
- context: undef,
- sketch: undef,
- onblur: function() {},
- onfocus: function() {}
- };
- // 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.key = undef;
- p.keyCode = undef;
- p.keyPressed = undef;
- p.keyReleased = undef;
- p.keyTyped = undef;
- p.draw = undef;
- p.setup = undef;
- // Remapped vars
- p.__mousePressed = false;
- p.__keyPressed = false;
- p.__frameRate = 0;
- // The current animation frame
- p.frameCount = 0;
- // The height/width of the canvas
- p.width = curElement.width - 0;
- p.height = curElement.height - 0;
- // Color modes
- p.RGB = 1;
- p.ARGB = 2;
- p.HSB = 3;
- p.ALPHA = 4;
- p.CMYK = 5;
- // Renderers
- p.P2D = 1;
- p.JAVA2D = 1;
- p.WEBGL = 2;
- p.P3D = 2;
- p.OPENGL = 2;
- p.EPSILON = 0.0001;
- p.MAX_FLOAT = 3.4028235e+38;
- p.MIN_FLOAT = -3.4028235e+38;
- p.MAX_INT = 2147483647;
- p.MIN_INT = -2147483648;
- p.PI = Math.PI;
- p.TWO_PI = 2 * p.PI;
- p.HALF_PI = p.PI / 2;
- p.THIRD_PI = p.PI / 3;
- p.QUARTER_PI = p.PI / 4;
- p.DEG_TO_RAD = p.PI / 180;
- p.RAD_TO_DEG = 180 / p.PI;
- p.WHITESPACE = " \t\n\r\f\u00A0";
- // Filter/convert types
- p.BLUR = 11;
- p.GRAY = 12;
- p.INVERT = 13;
- p.OPAQUE = 14;
- p.POSTERIZE = 15;
- p.THRESHOLD = 16;
- p.ERODE = 17;
- p.DILATE = 18;
- // Blend modes
- p.REPLACE = 0;
- p.BLEND = 1 << 0;
- p.ADD = 1 << 1;
- p.SUBTRACT = 1 << 2;
- p.LIGHTEST = 1 << 3;
- p.DARKEST = 1 << 4;
- p.DIFFERENCE = 1 << 5;
- p.EXCLUSION = 1 << 6;
- p.MULTIPLY = 1 << 7;
- p.SCREEN = 1 << 8;
- p.OVERLAY = 1 << 9;
- p.HARD_LIGHT = 1 << 10;
- p.SOFT_LIGHT = 1 << 11;
- p.DODGE = 1 << 12;
- p.BURN = 1 << 13;
- // Color component bit masks
- p.ALPHA_MASK = 0xff000000;
- p.RED_MASK = 0x00ff0000;
- p.GREEN_MASK = 0x0000ff00;
- p.BLUE_MASK = 0x000000ff;
- // Projection matrices
- p.CUSTOM = 0;
- p.ORTHOGRAPHIC = 2;
- p.PERSPECTIVE = 3;
- // Shapes
- p.POINT = 2;
- p.POINTS = 2;
- p.LINE = 4;
- p.LINES = 4;
- p.TRIANGLE = 8;
- p.TRIANGLES = 9;
- p.TRIANGLE_STRIP = 10;
- p.TRIANGLE_FAN = 11;
- p.QUAD = 16;
- p.QUADS = 16;
- p.QUAD_STRIP = 17;
- p.POLYGON = 20;
- p.PATH = 21;
- p.RECT = 30;
- p.ELLIPSE = 31;
- p.ARC = 32;
- p.SPHERE = 40;
- p.BOX = 41;
- p.GROUP = 0;
- p.PRIMITIVE = 1;
- p.PATH = 2;
- p.GEOMETRY = 3;
-
- p.breakShape = false;
- // Shape Vertex
- p.VERTEX = 0;
- p.BEZIER_VERTEX = 1;
- p.CURVE_VERTEX = 2;
- p.BREAK = 3;
- p.CLOSESHAPE = 4;
-
- // Shape closing modes
- p.OPEN = 1;
- p.CLOSE = 2;
-
- // Shape drawing modes
- p.CORNER = 0; // Draw mode convention to use (x, y) to (width, height)
- p.CORNERS = 1; // Draw mode convention to use (x1, y1) to (x2, y2) coordinates
- p.RADIUS = 2; // Draw mode from the center, and using the radius
- p.CENTER_RADIUS = 2; // Deprecated! Use RADIUS instead
- p.CENTER = 3; // Draw from the center, using second pair of values as the diameter
- p.DIAMETER = 3; // Synonym for the CENTER constant. Draw from the center
- p.CENTER_DIAMETER = 3; // Deprecated! Use DIAMETER instead
- // Text vertical alignment modes
- p.BASELINE = 0; // Default vertical alignment for text placement
- p.TOP = 101; // Align text to the top
- p.BOTTOM = 102; // Align text from the bottom, using the baseline
- // UV Texture coordinate modes
- p.NORMAL = 1;
- p.NORMALIZED = 1;
- p.IMAGE = 2;
- // Text placement modes
- p.MODEL = 4;
- p.SHAPE = 5;
- // Stroke modes
- p.SQUARE = 'butt';
- p.ROUND = 'round';
- p.PROJECT = 'square';
- p.MITER = 'miter';
- p.BEVEL = 'bevel';
- // Lighting modes
- p.AMBIENT = 0;
- p.DIRECTIONAL = 1;
- //POINT = 2; Shared with Shape constant
- p.SPOT = 3;
- // Key constants
- // Both key and keyCode will be equal to these values
- p.BACKSPACE = 8;
- p.TAB = 9;
- p.ENTER = 10;
- p.RETURN = 13;
- p.ESC = 27;
- p.DELETE = 127;
- p.CODED = 0xffff;
- // p.key will be CODED and p.keyCode will be this value
- p.SHIFT = 16;
- p.CONTROL = 17;
- p.ALT = 18;
- p.UP = 38;
- p.RIGHT = 39;
- p.DOWN = 40;
- p.LEFT = 37;
- var codedKeys = [p.SHIFT, p.CONTROL, p.ALT, p.UP, p.RIGHT, p.DOWN, p.LEFT];
- // Cursor types
- p.ARROW = 'default';
- p.CROSS = 'crosshair';
- p.HAND = 'pointer';
- p.MOVE = 'move';
- p.TEXT = 'text';
- p.WAIT = 'wait';
- p.NOCURSOR = "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), auto";
- // Hints
- p.DISABLE_OPENGL_2X_SMOOTH = 1;
- p.ENABLE_OPENGL_2X_SMOOTH = -1;
- p.ENABLE_OPENGL_4X_SMOOTH = 2;
- p.ENABLE_NATIVE_FONTS = 3;
- p.DISABLE_DEPTH_TEST = 4;
- p.ENABLE_DEPTH_TEST = -4;
- p.ENABLE_DEPTH_SORT = 5;
- p.DISABLE_DEPTH_SORT = -5;
- p.DISABLE_OPENGL_ERROR_REPORT = 6;
- p.ENABLE_OPENGL_ERROR_REPORT = -6;
- p.ENABLE_ACCURATE_TEXTURES = 7;
- p.DISABLE_ACCURATE_TEXTURES = -7;
- p.HINT_COUNT = 10;
- // PJS defined constants
- p.SINCOS_LENGTH = parseInt(360 / 0.5, 10);
- p.PRECISIONB = 15; // fixed point precision is limited to 15 bits!!
- p.PRECISIONF = 1 << p.PRECISIONB;
- p.PREC_MAXVAL = p.PRECISIONF - 1;
- p.PREC_ALPHA_SHIFT = 24 - p.PRECISIONB;
- p.PREC_RED_SHIFT = 16 - p.PRECISIONB;
- p.NORMAL_MODE_AUTO = 0;
- p.NORMAL_MODE_SHAPE = 1;
- p.NORMAL_MODE_VERTEX = 2;
- p.MAX_LIGHTS = 8;
- p.focused = true;
- // "Private" variables used to maintain state
- var curContext,
- curSketch,
- online = true,
- doFill = true,
- fillStyle = [1.0, 1.0, 1.0, 1.0],
- currentFillColor = 0xFFFFFFFF,
- isFillDirty = true,
- doStroke = true,
- strokeStyle = [0.8, 0.8, 0.8, 1.0],
- currentStrokeColor = 0xFFFDFDFD,
- isStrokeDirty = true,
- lineWidth = 1,
- loopStarted = false,
- doLoop = true,
- looping = 0,
- curRectMode = p.CORNER,
- curEllipseMode = p.CENTER,
- normalX = 0,
- normalY = 0,
- normalZ = 0,
- normalMode = p.NORMAL_MODE_AUTO,
- inDraw = false,
- curFrameRate = 60,
- curCursor = p.ARROW,
- oldCursor = curElement.style.cursor,
- curMsPerFrame = 1,
- curShape = p.POLYGON,
- curShapeCount = 0,
- curvePoints = [],
- curTightness = 0,
- curveDet = 20,
- curveInited = false,
- bezDetail = 20,
- colorModeA = 255,
- colorModeX = 255,
- colorModeY = 255,
- colorModeZ = 255,
- pathOpen = false,
- mouseDragging = false,
- curColorMode = p.RGB,
- curTint = function() {},
- curTextSize = 12,
- curTextFont = "Arial",
- getLoaded = false,
- start = new Date().getTime(),
- timeSinceLastFPS = start,
- framesSinceLastFPS = 0,
- textcanvas,
- curveBasisMatrix,
- curveToBezierMatrix,
- curveDrawMatrix,
- bezierDrawMatrix,
- bezierBasisInverse,
- bezierBasisMatrix,
- // Shaders
- programObject3D,
- programObject2D,
- programObjectUnlitShape,
- boxBuffer,
- boxNormBuffer,
- boxOutlineBuffer,
- rectBuffer,
- rectNormBuffer,
- sphereBuffer,
- lineBuffer,
- fillBuffer,
- fillColorBuffer,
- strokeColorBuffer,
- pointBuffer,
- shapeTexVBO,
- curTexture = {width:0,height:0},
- curTextureMode = p.IMAGE,
- usingTexture = false,
- textBuffer,
- textureBuffer,
- indexBuffer,
- // Text alignment
- horizontalTextAlignment = p.LEFT,
- verticalTextAlignment = p.BASELINE,
- baselineOffset = 0.2, // percent
- // Pixels cache
- originalContext,
- proxyContext = null,
- isContextReplaced = false,
- setPixelsCached,
- maxPixelsCached = 1000;
- // Work-around for Minefield. using ctx.VERTEX_PROGRAM_POINT_SIZE
- // in Minefield does nothing and does not report any errors.
- var VERTEX_PROGRAM_POINT_SIZE = 0x8642;
- var POINT_SMOOTH = 0x0B10;
- // 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;
- }
- // User can only have MAX_LIGHTS lights
- var lightCount = 0;
- //sphere stuff
- var sphereDetailV = 0,
- sphereDetailU = 0,
- sphereX = [],
- sphereY = [],
- sphereZ = [],
- sinLUT = new Array(p.SINCOS_LENGTH),
- cosLUT = new Array(p.SINCOS_LENGTH),
- sphereVerts,
- sphereNorms;
- // Camera defaults and settings
- var cam,
- cameraInv,
- forwardTransform,
- reverseTransform,
- modelView,
- modelViewInv,
- userMatrixStack,
- inverseCopy,
- projection,
- manipulatingCamera = false,
- frustumMode = false,
- cameraFOV = 60 * (Math.PI / 180),
- cameraX = curElement.width / 2,
- cameraY = curElement.height / 2,
- cameraZ = cameraY / Math.tan(cameraFOV / 2),
- cameraNear = cameraZ / 10,
- cameraFar = cameraZ * 10,
- cameraAspect = curElement.width / curElement.height;
- var vertArray = [],
- curveVertArray = [],
- curveVertCount = 0,
- isCurve = false,
- isBezier = false,
- firstVert = true;
- //PShape stuff
- var curShapeMode = p.CORNER;
- var colors = {};
- colors.aliceblue = "#f0f8ff";
- colors.antiquewhite = "#faebd7";
- colors.aqua = "#00ffff";
- colors.aquamarine = "#7fffd4";
- colors.azure = "#f0ffff";
- colors.beige = "#f5f5dc";
- colors.bisque = "#ffe4c4";
- colors.black = "#000000";
- colors.blanchedalmond = "#ffebcd";
- colors.blue = "#0000ff";
- colors.blueviolet = "#8a2be2";
- colors.brown = "#a52a2a";
- colors.burlywood = "#deb887";
- colors.cadetblue = "#5f9ea0";
- colors.chartreuse = "#7fff00";
- colors.chocolate = "#d2691e";
- colors.coral = "#ff7f50";
- colors.cornflowerblue = "#6495ed";
- colors.cornsilk = "#fff8dc";
- colors.crimson = "#dc143c";
- colors.cyan = "#00ffff";
- colors.darkblue = "#00008b";
- colors.darkcyan = "#008b8b";
- colors.darkgoldenrod = "#b8860b";
- colors.darkgray = "#a9a9a9";
- colors.darkgreen = "#006400";
- colors.darkkhaki = "#bdb76b";
- colors.darkmagenta = "#8b008b";
- colors.darkolivegreen = "#556b2f";
- colors.darkorange = "#ff8c00";
- colors.darkorchid = "#9932cc";
- colors.darkred = "#8b0000";
- colors.darksalmon = "#e9967a";
- colors.darkseagreen = "#8fbc8f";
- colors.darkslateblue = "#483d8b";
- colors.darkslategray = "#2f4f4f";
- colors.darkturquoise = "#00ced1";
- colors.darkviolet = "#9400d3";
- colors.deeppink = "#ff1493";
- colors.deepskyblue = "#00bfff";
- colors.dimgray = "#696969";
- colors.dodgerblue = "#1e90ff";
- colors.firebrick = "#b22222";
- colors.floralwhite = "#fffaf0";
- colors.forestgreen = "#228b22";
- colors.fuchsia = "#ff00ff";
- colors.gainsboro = "#dcdcdc";
- colors.ghostwhite = "#f8f8ff";
- colors.gold = "#ffd700";
- colors.goldenrod = "#daa520";
- colors.gray = "#808080";
- colors.green = "#008000";
- colors.greenyellow = "#adff2f";
- colors.honeydew = "#f0fff0";
- colors.hotpink = "#ff69b4";
- colors.indianred = "#cd5c5c";
- colors.indigo = "#4b0082";
- colors.ivory = "#fffff0";
- colors.khaki = "#f0e68c";
- colors.lavender = "#e6e6fa";
- colors.lavenderblush = "#fff0f5";
- colors.lawngreen = "#7cfc00";
- colors.lemonchiffon = "#fffacd";
- colors.lightblue = "#add8e6";
- colors.lightcoral = "#f08080";
- colors.lightcyan = "#e0ffff";
- colors.lightgoldenrodyellow = "#fafad2";
- colors.lightgrey = "#d3d3d3";
- colors.lightgreen = "#90ee90";
- colors.lightpink = "#ffb6c1";
- colors.lightsalmon = "#ffa07a";
- colors.lightseagreen = "#20b2aa";
- colors.lightskyblue = "#87cefa";
- colors.lightslategray = "#778899";
- colors.lightsteelblue = "#b0c4de";
- colors.lightyellow = "#ffffe0";
- colors.lime = "#00ff00";
- colors.limegreen = "#32cd32";
- colors.linen = "#faf0e6";
- colors.magenta = "#ff00ff";
- colors.maroon = "#800000";
- colors.mediumaquamarine = "#66cdaa";
- colors.mediumblue = "#0000cd";
- colors.mediumorchid = "#ba55d3";
- colors.mediumpurple = "#9370d8";
- colors.mediumseagreen = "#3cb371";
- colors.mediumslateblue = "#7b68ee";
- colors.mediumspringgreen = "#00fa9a";
- colors.mediumturquoise = "#48d1cc";
- colors.mediumvioletred = "#c71585";
- colors.midnightblue = "#191970";
- colors.mintcream = "#f5fffa";
- colors.mistyrose = "#ffe4e1";
- colors.moccasin = "#ffe4b5";
- colors.navajowhite = "#ffdead";
- colors.navy = "#000080";
- colors.oldlace = "#fdf5e6";
- colors.olive = "#808000";
- colors.olivedrab = "#6b8e23";
- colors.orange = "#ffa500";
- colors.orangered = "#ff4500";
- colors.orchid = "#da70d6";
- colors.palegoldenrod = "#eee8aa";
- colors.palegreen = "#98fb98";
- colors.paleturquoise = "#afeeee";
- colors.palevioletred = "#d87093";
- colors.papayawhip = "#ffefd5";
- colors.peachpuff = "#ffdab9";
- colors.peru = "#cd853f";
- colors.pink = "#ffc0cb";
- colors.plum = "#dda0dd";
- colors.powderblue = "#b0e0e6";
- colors.purple = "#800080";
- colors.red = "#ff0000";
- colors.rosybrown = "#bc8f8f";
- colors.royalblue = "#4169e1";
- colors.saddlebrown = "#8b4513";
- colors.salmon = "#fa8072";
- colors.sandybrown = "#f4a460";
- colors.seagreen = "#2e8b57";
- colors.seashell = "#fff5ee";
- colors.sienna = "#a0522d";
- colors.silver = "#c0c0c0";
- colors.skyblue = "#87ceeb";
- colors.slateblue = "#6a5acd";
- colors.slategray = "#708090";
- colors.snow = "#fffafa";
- colors.springgreen = "#00ff7f";
- colors.steelblue = "#4682b4";
- colors.tan = "#d2b48c";
- colors.teal = "#008080";
- colors.thistle = "#d8bfd8";
- colors.tomato = "#ff6347";
- colors.turquoise = "#40e0d0";
- colors.violet = "#ee82ee";
- colors.wheat = "#f5deb3";
- colors.white = "#ffffff";
- colors.whitesmoke = "#f5f5f5";
- colors.yellow = "#ffff00";
- colors.yellowgreen = "#9acd32";
- // Stores states for pushStyle() and popStyle().
- var styleArray = new Array(0);
- // Vertices are specified in a counter-clockwise order
- // triangles are in this order: back, front, right, bottom, left, top
- var boxVerts = [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 boxNorms = [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];
- var boxOutlineVerts = [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];
- // These verts are used for the fill and stroke using TRIANGLE_FAN and LINE_LOOP
- var rectVerts = [0,0,0, 0,1,0, 1,1,0, 1,0,0];
- var rectNorms = [0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1];
- // Vertex shader for points and lines
- var vShaderSrcUnlitShape =
- "attribute vec3 aVertex;" +
- "attribute vec4 aColor;" +
- "uniform mat4 uView;" +
- "uniform mat4 uProjection;" +
- "void main(void) {" +
- " gl_FrontColor = aColor;" +
- " gl_Position = uProjection * uView * vec4(aVertex, 1.0);" +
- "}";
- var fShaderSrcUnlitShape =
- "void main(void){" +
- " gl_FragColor = gl_Color;" +
- "}";
- // Vertex shader for points and lines
- var vertexShaderSource2D =
- "attribute vec3 Vertex;" +
- "attribute vec2 aTextureCoord;" +
- "uniform vec4 color;" +
- "uniform mat4 model;" +
- "uniform mat4 view;" +
- "uniform mat4 projection;" +
- "uniform float pointSize;" +
- "varying vec2 vTextureCoord;"+
- "void main(void) {" +
- " gl_PointSize = pointSize;" +
- " gl_FrontColor = color;" +
- " gl_Position = projection * view * model * vec4(Vertex, 1.0);" +
- " vTextureCoord = aTextureCoord;" +
- "}";
- var fragmentShaderSource2D =
- "varying vec2 vTextureCoord;"+
- "uniform vec4 color;"+
- "uniform sampler2D uSampler;"+
- "uniform int picktype;"+
- "void main(void){" +
- " if(picktype==0){"+
- " gl_FragColor = color;" +
- " }else if(picktype==1){"+
- " float alpha = texture2D(uSampler,vTextureCoord).a;"+
- " gl_FragColor = vec4(color.rgb*alpha,alpha);\n"+
- " }"+
- "}";
- // Vertex shader for boxes and spheres
- var vertexShaderSource3D =
- "attribute vec3 Vertex;" +
- "attribute vec3 Normal;" +
- "attribute vec4 aColor;" +
- "attribute vec2 aTexture;" +
- "varying vec2 vTexture;" +
- "uniform vec4 color;" +
- "uniform bool usingMat;" +
- "uniform vec3 specular;" +
- "uniform vec3 mat_emissive;" +
- "uniform vec3 mat_ambient;" +
- "uniform vec3 mat_specular;" +
- "uniform float shininess;" +
- "uniform mat4 model;" +
- "uniform mat4 view;" +
- "uniform mat4 projection;" +
- "uniform mat4 normalTransform;" +
- "uniform int lightCount;" +
- "uniform vec3 falloff;" +
- "struct Light {" +
- " bool dummy;" +
- " int type;" +
- " vec3 color;" +
- " vec3 position;" +
- " vec3 direction;" +
- " float angle;" +
- " vec3 halfVector;" +
- " float concentration;" +
- "};" +
- "uniform Light lights[8];" +
- "void AmbientLight( inout vec3 totalAmbient, in vec3 ecPos, in Light light ) {" +
- // Get the vector from the light to the vertex
- // Get the distance from the current vector to the light position
- " float d = length( light.position - ecPos );" +
- " float attenuation = 1.0 / ( falloff[0] + ( falloff[1] * d ) + ( falloff[2] * d * d ));" + " totalAmbient += light.color * attenuation;" +
- "}" +
- "void DirectionalLight( inout vec3 col, in vec3 ecPos, inout vec3 spec, in vec3 vertNormal, in Light light ) {" +
- " float powerfactor = 0.0;" +
- " float nDotVP = max(0.0, dot( vertNormal, light.position ));" +
- " float nDotVH = max(0.0, dot( vertNormal, normalize( light.position-ecPos )));" +
- " if( nDotVP != 0.0 ){" +
- " powerfactor = pow( nDotVH, shininess );" +
- " }" +
- " col += light.color * nDotVP;" +
- " spec += specular * powerfactor;" +
- "}" +
- "void PointLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in vec3 eye, 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 / ( falloff[0] + ( falloff[1] * d ) + ( falloff[2] * d * d ));" +
- " float nDotVP = max( 0.0, dot( vertNormal, VP ));" +
- " vec3 halfVector = normalize( VP + eye );" +
- " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" +
- " if( nDotVP == 0.0) {" +
- " powerfactor = 0.0;" +
- " }" +
- " else{" +
- " powerfactor = pow( nDotHV, shininess );" +
- " }" +
- " spec += specular * powerfactor * attenuation;" +
- " col += light.color * nDotVP * attenuation;" +
- "}" +
- /*
- */
- "void SpotLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in vec3 eye, in Light light ) {" +
- " float spotAttenuation;" +
- " float powerfactor;" +
- // 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 / ( falloff[0] + ( falloff[1] * d ) + ( falloff[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
- " if( spotDot < cos( light.angle ) ) {" +
- " spotAttenuation = pow( spotDot, light.concentration );" +
- " }" +
- " else{" +
- " spotAttenuation = 1.0;" +
- " }" +
- " attenuation *= spotAttenuation;" +
- " float nDotVP = max( 0.0, dot( vertNormal, VP ));" +
- " vec3 halfVector = normalize( VP + eye );" +
- " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" +
- " if( nDotVP == 0.0 ) {" +
- " powerfactor = 0.0;" +
- " }" +
- " else {" +
- " powerfactor = pow( nDotHV, shininess );" +
- " }" +
- " spec += specular * powerfactor * attenuation;" +
- " col += light.color * nDotVP * attenuation;" +
- "}" +
- "void main(void) {" +
- " vec3 finalAmbient = vec3( 0.0, 0.0, 0.0 );" +
- " vec3 finalDiffuse = vec3( 0.0, 0.0, 0.0 );" +
- " vec3 finalSpecular = vec3( 0.0, 0.0, 0.0 );" +
- " vec4 col = color;" +
- " if(color[0] == -1.0){" +
- " col = aColor;" +
- " }" +
- " vec3 norm = vec3( normalTransform * vec4( Normal, 0.0 ) );" +
- " vec4 ecPos4 = view * model * vec4(Vertex,1.0);" +
- " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
- " vec3 eye = vec3( 0.0, 0.0, 1.0 );" +
- // If there were no lights this draw call, just use the
- // assigned fill color of the shape and the specular value
- " if( lightCount == 0 ) {" +
- " gl_FrontColor = col + vec4(mat_specular,1.0);" +
- " }" +
- " else {" +
- " for( int i = 0; i < lightCount; i++ ) {" +
- " if( lights[i].type == 0 ) {" +
- " AmbientLight( finalAmbient, ecPos, lights[i] );" +
- " }" +
- " else if( lights[i].type == 1 ) {" +
- " DirectionalLight( finalDiffuse,ecPos, finalSpecular, norm, lights[i] );" +
- " }" +
- " else if( lights[i].type == 2 ) {" +
- " PointLight( finalDiffuse, finalSpecular, norm, ecPos, eye, lights[i] );" +
- " }" +
- " else if( lights[i].type == 3 ) {" +
- " SpotLight( finalDiffuse, finalSpecular, norm, ecPos, eye, lights[i] );" +
- " }" +
- " }" +
- " if( usingMat == false ) {" +
- " gl_FrontColor = vec4( " +
- " vec3(col) * finalAmbient +" +
- " vec3(col) * finalDiffuse +" +
- " vec3(col) * finalSpecular," +
- " col[3] );" +
- " }" +
- " else{" +
- " gl_FrontColor = vec4( " +
- " mat_emissive + " +
- " (vec3(col) * mat_ambient * finalAmbient) + " +
- " (vec3(col) * finalDiffuse) + " +
- " (mat_specular * finalSpecular), " +
- " col[3] );" +
- " }" +
- " }" +
- " vTexture.xy = aTexture.xy;" +
- " gl_Position = projection * view * model * vec4( Vertex, 1.0 );" +
- "}";
- var fragmentShaderSource3D =
- "uniform sampler2D sampler;" +
- "uniform bool usingTexture;" +
- "varying vec2 vTexture;" +
- // In Processing, when a texture is used, the fill color is ignored
- "void main(void){" +
- " if(usingTexture){" +
- " gl_FragColor = vec4(texture2D(sampler, vTexture.xy));" +
- " }"+
- " else{" +
- " gl_FragColor = vec4(gl_Color);" +
- " }" +
- "}";
- ////////////////////////////////////////////////////////////////////////////
- // 3D Functions
- ////////////////////////////////////////////////////////////////////////////
- /*
- Sets the uniform variable 'varName' to the value specified by 'value'.
- Before calling this function, make sure 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.
- */
- function uniformf(programObj, varName, varValue) {
- var varLocation = curContext.getUniformLocation(programObj, varName);
- // the variable won't be found if it was optimized out.
- if (varLocation !== -1) {
- 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);
- }
- }
- }
- function uniformi(programObj, varName, varValue) {
- var varLocation = curContext.getUniformLocation(programObj, varName);
- // the variable won't be found if it was optimized out.
- if (varLocation !== -1) {
- 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);
- }
- }
- }
- function vertexAttribPointer(programObj, varName, size, VBO) {
- var varLocation = curContext.getAttribLocation(programObj, varName);
- if (varLocation !== -1) {
- curContext.bindBuffer(curContext.ARRAY_BUFFER, VBO);
- curContext.vertexAttribPointer(varLocation, size, curContext.FLOAT, false, 0, 0);
- curContext.enableVertexAttribArray(varLocation);
- }
- }
- function disableVertexAttribPointer(programObj, varName){
- var varLocation = curContext.getAttribLocation(programObj, varName);
- if (varLocation !== -1) {
- curContext.disableVertexAttribArray(varLocation);
- }
- }
- function uniformMatrix(programObj, varName, transpose, matrix) {
- var varLocation = curContext.getUniformLocation(programObj, varName);
- // 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);
- }
- }
- }
- // Wrapper to easily deal with array names changes. TODO: Don't think we need this wrapper anymore consensus has been reached.
- var newWebGLArray = function(data) {
- return new WebGLFloatArray(data);
- };
- var imageModeCorner = function imageModeCorner(x, y, w, h, whAreSizes) {
- return {
- x: x,
- y: y,
- w: w,
- h: h
- };
- };
- var imageModeConvert = imageModeCorner;
- var imageModeCorners = function imageModeCorners(x, y, w, h, whAreSizes) {
- return {
- x: x,
- y: y,
- w: whAreSizes ? w : w - x,
- h: whAreSizes ? h : h - y
- };
- };
- var imageModeCenter = function imageModeCenter(x, y, w, h, whAreSizes) {
- return {
- x: x - w / 2,
- y: y - h / 2,
- w: w,
- h: h
- };
- };
- 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;
- };
- ////////////////////////////////////////////////////////////////////////////
- // Char handling
- ////////////////////////////////////////////////////////////////////////////
- var charMap = {};
- var Char = p.Character = function Char(chr) {
- if (typeof chr === 'string' && chr.length === 1) {
- this.code = chr.charCodeAt(0);
- } 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;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // PShape
- ////////////////////////////////////////////////////////////////////////////
- var PShape = p.PShape = function(family) {
- this.family = family || p.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;
- /* methods */
- this.isVisible = function(){
- return this.visible;
- };
- this.setVisible = function (visible){
- this.visible = visible;
- };
- this.disableStyle = function(){
- this.style = false;
- for(var i = 0; i < this.children.length; i++)
- {
- this.children[i].disableStyle();
- }
- };
- this.enableStyle = function(){
- this.style = true;
- for(var i = 0; i < this.children.length; i++)
- {
- this.children[i].enableStyle();
- }
- };
- this.getFamily = function(){
- return this.family;
- };
- this.getWidth = function(){
- return this.width;
- };
- this.getHeight = function(){
- return this.height;
- };
- this.setName = function(name){
- this.name = name;
- };
- this.getName = function(){
- return this.name;
- };
- this.draw = function(){
- if (this.visible) {
- this.pre();
- this.drawImpl();
- this.post();
- }
- };
- this.drawImpl = function(){
- if (this.family === p.GROUP) {
- this.drawGroup();
- } else if (this.family === p.PRIMITIVE) {
- this.drawPrimitive();
- } else if (this.family === p.GEOMETRY) {
- this.drawGeometry();
- } else if (this.family === p.PATH) {
- this.drawPath();
- }
- };
- this.drawPath = function(){
- if (this.vertices.length === 0) { return; }
- p.beginShape();
- var i;
- if (this.vertexCodes.length === 0) { // each point is a simple vertex
- if (this.vertices[0].length === 2) { // drawing 2D vertices
- for (i = 0; i < this.vertices.length; i++) {
- p.vertex(this.vertices[i][0], this.vertices[i][1]);
- }
- } else { // drawing 3D vertices
- for (i = 0; i < this.vertices.length; i++) {
- p.vertex(this.vertices[i][0], this.vertices[i][1], this.vertices[i][2]);
- }
- }
- } else { // coded set of vertices
- var index = 0;
- var j;
- if (this.vertices[0].length === 2) { // drawing a 2D path
- for (j = 0; j < this.vertexCodes.length; j++) {
- switch (this.vertexCodes[j]) {
- case p.VERTEX:
- p.vertex(this.vertices[index][0], this.vertices[index][1]);
- 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;
- }
- p.breakShape = false;
- index++;
- break;
- case p.BEZIER_VERTEX:
- p.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;
- break;
- case p.CURVE_VERTEX:
- p.curveVertex(this.vertices[index][0], this.vertices[index][1]);
- index++;
- break;
- case p.BREAK:
- p.breakShape = true;
- break;
- }
- }
- } else { // drawing a 3D path
- for (j = 0; j < this.vertexCodes.length; j++) {
- switch (this.vertexCodes[j]) {
- case p.VERTEX:
- p.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;
- }
- p.breakShape = false;
- break;
- case p.BEZIER_VERTEX:
- p.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;
- break;
- case p.CURVE_VERTEX:
- p.curveVertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index][2]);
- index++;
- break;
- case p.BREAK:
- p.breakShape = true;
- break;
- }
- }
- }
- }
- p.endShape(this.close ? p.CLOSE : p.OPEN);
- };
- this.drawGeometry = function() {
- p.beginShape(this.kind);
- var i;
- if (this.style) {
- for (i = 0; i < this.vertices.length; i++) {
- p.vertex(this.vertices[i]);
- }
- } else {
- for (i = 0; i < this.vertices.length; i++) {
- var vert = this.vertices[i];
- if (vert[2] === 0) {
- p.vertex(vert[0], vert[1]);
- } else {
- p.vertex(vert[0], vert[1], vert[2]);
- }
- }
- }
- p.endShape();
- };
- this.drawGroup = function() {
- for (var i = 0; i < this.children.length; i++) {
- this.children[i].draw();
- }
- };
- this.drawPrimitive = function() {
- switch (this.kind) {
- case p.POINT:
- p.point(this.params[0], this.params[1]);
- break;
- case p.LINE:
- if (this.params.length === 4) { // 2D
- p.line(this.params[0], this.params[1],
- this.params[2], this.params[3]);
- } else { // 3D
- p.line(this.params[0], this.params[1], this.params[2],
- this.params[3], this.params[4], this.params[5]);
- }
- break;
- case p.TRIANGLE:
- p.triangle(this.params[0], this.params[1],
- this.params[2], this.params[3],
- this.params[4], this.params[5]);
- break;
- case p.QUAD:
- p.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]);
- break;
- case p.RECT:
- if (this.image !== null) {
- p.imageMode(p.CORNER);
- p.image(this.image, this.params[0], this.params[1], this.params[2], this.params[3]);
- } else {
- p.rectMode(p.CORNER);
- p.rect(this.params[0], this.params[1], this.params[2], this.params[3]);
- }
- break;
- case p.ELLIPSE:
- p.ellipseMode(p.CORNER);
- p.ellipse(this.params[0], this.params[1], this.params[2], this.params[3]);
- break;
- case p.ARC:
- p.ellipseMode(p.CORNER);
- p.arc(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]);
- break;
- case p.BOX:
- if (this.params.length === 1) {
- p.box(this.params[0]);
- } else {
- p.box(this.params[0], this.params[1], this.params[2]);
- }
- break;
- case p.SPHERE:
- p.sphere(this.params[0]);
- break;
- }
- };
- this.pre = function() {
- if (this.matrix) {
- p.pushMatrix();
- //this.applyMatrix( this.matrix ); //applyMatrix missing
- }
- if (this.style) {
- p.pushStyle();
- this.styles();
- }
- };
- this.post = function() {
- if (this.matrix) {
- p.popMatrix();
- }
- if (this.style) {
- p.popStyle();
- }
- };
- this.styles = function() {
- if (this.stroke) {
- p.stroke(this.strokeColor);
- p.strokeWeight(this.strokeWeight);
- p.strokeCap(this.strokeCap);
- p.strokeJoin(this.strokeJoin);
- } else {
- p.noStroke();
- }
- if (this.fill) {
- p.fill(this.fillColor);
- } else {
- p.noFill();
- }
- };
-
- // return the PShape at the specific index from the children array or
- // return the Phape from a parent shape specified by its name
- this.getChild = function(child) {
- if (typeof child === 'number') {
- return this.children[child];
- } else {
- var found,
- i;
- if(child === "" || this.name === child){
- return this;
- } else {
- if(this.nameTable.length > 0)
- {
- for(i = 0; i < this.nameTable.length || found; i++)
- {
- if(this.nameTable[i].getName === child) {
- found = this.nameTable[i];
- }
- }
- if (found) { return found; }
- }
- for(i = 0; i < this.children.lenth; i++)
- {
- found = this.children[i].getChild(child);
- if(found) { return found; }
- }
- }
- return null;
- }
- };
- this.getChildCount = function () {
- return this.children.length;
- };
- this.addChild = function( child ) {
- this.children.push(child);
- child.parent = this;
- if (child.getName() !== null) {
- this.addName(child.getName(), child);
- }
- };
- this.addName = function(name, shape) {
- if (this.parent !== null) {
- this.parent.addName( name, shape );
- } else {
- this.nameTable.push( [name, shape] );
- }
- };
- // findChild not in yet
- this.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);
- }
- };
- this.checkMatrix = function(dimensions) {
- if(this.matrix === null) {
- if(dimensions === 2) {
- this.matrix = new p.PMatrix2D();
- } else {
- this.matrix = new p.PMatrix3D();
- }
- }else if(dimensions === 3 && this.matrix instanceof p.PMatrix2D) {
- this.matrix = new p.PMatrix3D();
- }
- };
- this.rotateX = function(angle) {
- this.rotate(angle, 1, 0, 0);
- };
- this.rotateY = function(angle) {
- this.rotate(angle, 0, 1, 0);
- };
- this.rotateZ = function(angle) {
- this.rotate(angle, 0, 0, 1);
- };
- this.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]);
- }
- };
- this.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]);
- }
- };
- this.resetMatrix = function() {
- this.checkMatrix(2);
- this.matrix.reset();
- };
- // applyMatrix missing
- // apply missing
- // contains missing
- // find child missing
- // getPrimitive missing
- // getVertex , getVertexCount missing
- // getVertexCode , getVertexCodes , getVertexCodeCount missing
- // getVertexX, getVertexY, getVertexZ missing
-
- };
-
- p.shape = function(shape, x, y, width, height) {
- if (arguments.length >= 1 && arguments[0] !== null) {
- if (shape.isVisible()) {
- p.pushMatrix();
- if (curShapeMode === p.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 === p.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 === p.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();
- if ((arguments.length === 1 && curShapeMode === p.CENTER ) || arguments.length > 1) {
- p.popMatrix();
- }
- }
- }
- };
- p.shapeMode = function (mode) {
- curShapeMode = mode;
- };
- p.loadShape = function (filename) {
- if (arguments.length === 1) {
- if (filename.indexOf(".svg") > -1) {
- return new p.PShapeSVG(null, filename);
- }
- }
- return null;
- };
-
- var PShapeSVG = p.PShapeSVG = function() {
- p.PShape.call( this ); // PShape is the base class.
- if (arguments.length === 1) {
- this.element = new p.XMLElement(arguments[0]);
- // set values to their defaults according to the SVG spec
- this.vertexCodes = [];
- this.vertices = [];
- this.opacity = 1;
-
- this.stroke = false;
- this.strokeColor = p.ALPHA_MASK;
- this.strokeWeight = 1;
- this.strokeCap = p.SQUARE; // equivalent to BUTT in svg spec
- this.strokeJoin = p.MITER;
- this.strokeGradient = null;
- this.strokeGradientPaint = null;
- this.strokeName = null;
- this.strokeOpacity = 1;
- this.fill = true;
- this.fillColor = p.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 p.XMLElement(arguments[1]);
- // set values to their defaults according to the SVG spec
- this.vertexCodes = [];
- this.vertices = [];
- this.opacity = 1;
-
- this.stroke = false;
- this.strokeColor = p.ALPHA_MASK;
- this.strokeWeight = 1;
- this.strokeCap = p.SQUARE; // equivalent to BUTT in svg spec
- this.strokeJoin = p.MITER;
- this.strokeGradient = "";
- this.strokeGradientPaint = "";
- this.strokeName = "";
- this.strokeOpacity = 1;
-
- this.fill = true;
- this.fillColor = p.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.prototype = {
- // parseMatrix missing
- // getChild missing
- // print missing
- parseMatrix: function(str) { },
- parseChildren:function(element) {
- var newelement = element.getChildren();
- var children = new p.PShape();
- for (var i = 0; i < newelement.length; i++) {
- var kid = this.parseChild(newelement[i]);
- if (kid) {
- children.addChild(kid);
- }
- }
- this.children.push(children);
- },
- getName: function() {
- return this.name;
- },
- parseChild: function( elem ) {
- var name = elem.getName();
- var shape;
- switch (name) {
- case "g":
- shape = new PShapeSVG(this, elem);
- break;
- case "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);
- break;
- case "line":
- shape = new PShapeSVG(this, elem);
- shape.parseLine();
- break;
- case "circle":
- shape = new PShapeSVG(this, elem);
- shape.parseEllipse(true);
- break;
- case "ellipse":
- shape = new PShapeSVG(this, elem);
- shape.parseEllipse(false);
- break;
- case "rect":
- shape = new PShapeSVG(this, elem);
- shape.parseRect();
- break;
- case "polygon":
- shape = new PShapeSVG(this, elem);
- shape.parsePoly(true);
- break;
- case "polyline":
- shape = new PShapeSVG(this, elem);
- shape.parsePoly(false);
- break;
- case "path":
- shape = new PShapeSVG(this, elem);
- shape.parsePath();
- break;
- case "radialGradient":
- //return new RadialGradient(this, elem);
- break;
- case "linearGradient":
- //return new LinearGradient(this, elem);
- break;
- case "text":
- p.println("Text in SVG files is not currently supported, convert text to outlines instead." );
- break;
- case "filter":
- p.println("Filters are not supported.");
- break;
- case "mask":
- p.println("Masks are not supported.");
- break;
- default:
- p.println("Ignoring <" + name + "> tag.");
- break;
- }
- return shape;
- },
- parsePath: function(){
- this.family = p.PATH;
- this.kind = 0;
-
- var c;
- var pathData = p.trim(this.element.getStringAttribute("d").replace(/\s+/g,' '));
- if (pathData === null) { return; }
- var pathDataChars = pathData.toCharArray();
- var pathBuffer = "";
- var lastSeparate = false;
- for (var i = 0; i < pathDataChars.length; i++) {
- c = pathDataChars[i].toString();
- var separate = false;
- if (c === "M" || c === 'm' ||
- c === 'L' || c === 'l' ||
- c === 'H' || c === 'h' ||
- c === 'V' || c === 'v' ||
- c === 'C' || c === 'c' || // beziers
- c === 'S' || c === 's' ||
- c === 'Q' || c === 'q' || // quadratic beziers
- c === 'T' || c === 't' ||
- c === 'Z' || c === 'z' || // closepath
- c === ',') {
- separate = true;
- if (i !== 0 ) {
- pathBuffer +="|";
- }
- }
- if (c === 'Z' || c === 'z') {
- separate = false;
- }
- if (c === '-' && !lastSeparate) {
- // allow for 'e' notation in numbers, e.g. 2.10e-9
- // http://dev.processing.org/bugs/show_bug.cgi?id=1408
- if (i === 0 || pathDataChars[i-1] !== 'e') {
- pathBuffer +="|";
- }
- }
- if (c !== ',') {
- pathBuffer += c; //"" + pathDataBuffer.charAt(i));
- }
- if (separate && c !== ',' && c !== '-') {
- pathBuffer +="|";
- }
- lastSeparate = separate;
- }
- // split into array
- var pathDataKeys = pathBuffer.toString().split(/[|\s+]/g);
- // loop through the array and remove spaces
- for(i =0; i < pathDataKeys.length; i++){
- if (pathDataKeys[i] === ""){
- pathDataKeys.splice(i, 1);
- }
- }
- 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;
- while (i < pathDataKeys.length) {
- c = p.trim(pathDataKeys[i].charAt(0 ));
- switch (c) {
- case 'M': // M - move to (absolute)
- cx = parseFloat(pathDataKeys[i + 1]);
- cy = parseFloat(pathDataKeys[i + 2]);
- this.parsePathMoveto(cx, cy);
- i += 3;
- break;
- case 'm': // m - move to (relative)
- cx = parseFloat(cx)+ parseFloat(pathDataKeys[i + 1]);
- cy = parseFloat(cy)+ parseFloat(pathDataKeys[i + 2]);
- this.parsePathMoveto(cx, cy);
- i += 3;
- break;
- case 'L':
- cx = parseFloat(pathDataKeys[i + 1]);
- cy = parseFloat(pathDataKeys[i + 2]);
- this.parsePathLineto(cx, cy);
- i += 3;
- break;
- case 'l':
- cx = parseFloat(cx) + parseFloat(pathDataKeys[i + 1]);
- cy = parseFloat(cy) + parseFloat(pathDataKeys[i + 2]);
- this.parsePathLineto(cx, cy);
- i += 3;
- break;
- // horizontal lineto absolute
- case 'H':
- cx = parseFloat(pathDataKeys[i + 1]);
- this.parsePathLineto(cx, cy);
- i += 2;
- break;
- // horizontal lineto relative
- case 'h':
- cx = parseFloat(cx) + parseFloat(pathDataKeys[i + 1]);
- this.parsePathLineto(cx, cy);
- i += 2;
- break;
- case 'V':
- cy = parseFloat(pathDataKeys[i + 1]);
- this.parsePathLineto(cx, cy);
- i += 2;
- break;
- case 'v':
- cy = parseFloat(cy) + parseFloat(pathDataKeys[i + 1]);
- this.parsePathLineto(cx, cy);
- i += 2;
- break;
- // C - curve to (absolute)
- case 'C':
- ctrlX1 = parseFloat(pathDataKeys[i + 1]);
- ctrlY1 = parseFloat(pathDataKeys[i + 2]);
- ctrlX2 = parseFloat(pathDataKeys[i + 3]);
- ctrlY2 = parseFloat(pathDataKeys[i + 4]);
- endX = parseFloat(pathDataKeys[i + 5]);
- endY = parseFloat(pathDataKeys[i + 6]);
- this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
- cx = endX;
- cy = endY;
- i += 7;
- break;
- // c - curve to (relative)
- case 'c':
- ctrlX1 = parseFloat(cx) + parseFloat(pathDataKeys[i + 1]);
- ctrlY1 = parseFloat(cy) + parseFloat(pathDataKeys[i + 2]);
- ctrlX2 = parseFloat(cx) + parseFloat(pathDataKeys[i + 3]);
- ctrlY2 = parseFloat(cy) + parseFloat(pathDataKeys[i + 4]);
- endX = parseFloat(cx) + parseFloat(pathDataKeys[i + 5]);
- endY = parseFloat(cy) + parseFloat(pathDataKeys[i + 6]);
- this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
- cx = endX;
- cy = endY;
- i += 7;
- break;
- // S - curve to shorthand (absolute)
- case 'S':
- ppx = parseFloat(this.vertices[ this.vertices.length-2 ][0]);
- ppy = parseFloat(this.vertices[ this.vertices.length-2 ][1]);
- px = parseFloat(this.vertices[ this.vertices.length-1 ][0]);
- py = parseFloat(this.vertices[ this.vertices.length-1 ][1]);
- ctrlX1 = px + (px - ppx);
- ctrlY1 = py + (py - ppy);
- ctrlX2 = parseFloat(pathDataKeys[i + 1]);
- ctrlY2 = parseFloat(pathDataKeys[i + 2]);
- endX = parseFloat(pathDataKeys[i + 3]);
- endY = parseFloat(pathDataKeys[i + 4]);
- this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
- cx = endX;
- cy = endY;
- i += 5;
- break;
- // s - curve to shorthand (relative)
- case 's':
- ppx = parseFloat(this.vertices[this.vertices.length-2][0]);
- ppy = parseFloat(this.vertices[this.vertices.length-2][1]);
- px = parseFloat(this.vertices[this.vertices.length-1][0]);
- py = parseFloat(this.vertices[this.vertices.length-1][1]);
- ctrlX1 = px + (px - ppx);
- ctrlY1 = py + (py - ppy);
- ctrlX2 = parseFloat(cx) + parseFloat(pathDataKeys[i + 1]);
- ctrlY2 = parseFloat(cy) + parseFloat(pathDataKeys[i + 2]);
- endX = parseFloat(cx) + parseFloat(pathDataKeys[i + 3]);
- endY = parseFloat(cy) + parseFloat(pathDataKeys[i + 4]);
- this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
- cx = endX;
- cy = endY;
- i += 5;
- break;
- // Q - quadratic curve to (absolute)
- case 'Q':
- ctrlX = parseFloat(pathDataKeys[i + 1]);
- ctrlY = parseFloat(pathDataKeys[i + 2]);
- endX = parseFloat(pathDataKeys[i + 3]);
- endY = parseFloat(pathDataKeys[i + 4]);
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- i += 5;
- break;
- // q - quadratic curve to (relative)
- case 'q':
- ctrlX = parseFloat(cx) + parseFloat(pathDataKeys[i + 1]);
- ctrlY = parseFloat(cy) + parseFloat(pathDataKeys[i + 2]);
- endX = parseFloat(cx) + parseFloat(pathDataKeys[i + 3]);
- endY = parseFloat(cy) + parseFloat(pathDataKeys[i + 4]);
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- i += 5;
- break;
- // T - quadratic curve to shorthand (absolute)
- // The control point is assumed to be the reflection of the
- // control point on the previous command relative to the
- // current point. (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.)
- case '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);
- endX = parseFloat(pathDataKeys[i + 1]);
- endY = parseFloat(pathDataKeys[i + 2]);
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- i += 3;
- break;
- // t - quadratic curve to shorthand (relative)
- case '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);
- endX = parseFloat(cx) + parseFloat(pathDataKeys[i + 1]);
- endY = parseFloat(cy) + parseFloat(pathDataKeys[i + 2]);
- this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
- cx = endX;
- cy = endY;
- i += 3;
- break;
- case 'Z':
- case 'z':
- this.close = true;
- i++;
- break;
- default:
- i++;
- /*String parsed =
- PApplet.join(PApplet.subset(pathDataKeys, 0, i), ",");
- String unparsed =
- PApplet.join(PApplet.subset(pathDataKeys, i), ",");
- System.err.println("parsed: " + parsed);
- System.err.println("unparsed: " + unparsed);
- if (pathDataKeys[i].equals("a") || pathDataKeys[i].equals("A")) {
- String msg = "Sorry, elliptical arc support for SVG files " +
- "is not yet implemented (See bug #996 for details)";
- throw new RuntimeException(msg);
- }
- throw new RuntimeException("shape command not handled: " + pathDataKeys[i]);
- }*/
- }
- }
- },
- parsePathQuadto: function(x1, y1, cx, cy, x2, y2) {
- this.parsePathCode(p.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);
- },
- parsePathCurveto : function(x1, y1, x2, y2, x3, y3) {
- this.parsePathCode(p.BEZIER_VERTEX );
- this.parsePathVertex(x1, y1);
- this.parsePathVertex(x2, y2);
- this.parsePathVertex(x3, y3);
- },
- parsePathLineto: function(px, py) {
- this.parsePathCode(p.VERTEX);
- this.parsePathVertex(px, py);
- // add property to distinguish between curContext.moveTo or curContext.lineTo
- this.vertices[this.vertices.length-1]["moveTo"] = false;
- },
- parsePathMoveto: function(px, py) {
- if (this.vertices.length > 0) {
- this.parsePathCode(p.BREAK);
- }
- this.parsePathCode(p.VERTEX);
- this.parsePathVertex(px, py);
- // add property to distinguish between curContext.moveTo or curContext.lineTo
- this.vertices[this.vertices.length-1]["moveTo"] = true;
- },
- parsePathVertex: function(x, y) {
- var verts = [];
- verts[0] = x;
- verts[1] = y;
- this.vertices.push(verts);
- },
- parsePathCode: function(what) {
- this.vertexCodes.push(what);
- },
- parsePoly: function(val) {
- this.family = p.PATH;
- this.close = val;
- var pointsAttr = p.trim(this.element.getStringAttribute("points").replace(/\s+/g,' '));
- if (pointsAttr !== null) {
- var pointsBuffer = pointsAttr.split(" ");
- for (var i = 0; i < pointsBuffer.length; i++) {
- var verts = [];
- var pb = pointsBuffer[i].split(',');
- verts[0] = pb[0];
- verts[1] = pb[1];
- this.vertices.push(verts);
- }
- }
- },
- parseRect: function() {
- this.kind = p.RECT;
- this.family = p.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");
-
- },
- parseEllipse: function(val) {
- this.kind = p.ELLIPSE;
- this.family = p.PRIMITIVE;
- this.params = [];
- this.params[0] = this.element.getFloatAttribute("cx");
- this.params[1] = this.element.getFloatAttribute("cy");
- var rx, ry;
- if (val) {
- rx = ry = this.element.getFloatAttribute("r");
- } else {
- rx = this.element.getFloatAttribute("rx");
- ry = this.element.getFloatAttribute("ry");
- }
- this.params[0] -= rx;
- this.params[1] -= ry;
- this.params[2] = rx*2;
- this.params[3] = ry*2;
- },
- parseLine: function() {
- this.kind = p.LINE;
- this.family = p.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");
- },
- 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; i < styleTokens.length; i++) {
- var tokens = p.trim(styleTokens[i].split( ":" ));
- switch(tokens[0]){
- case "fill":
- this.setFill(tokens[1]);
- break;
- case "fill-opacity":
- this.setFillOpacity(tokens[1]);
- break;
- case "stroke":
- this.setStroke(tokens[1]);
- break;
- case "stroke-width":
- this.setStrokeWeight(tokens[1]);
- break;
- case "stroke-linecap":
- this.setStrokeCap(tokens[1]);
- break;
- case "stroke-linejoin":
- this.setStrokeJoin(tokens[1]);
- break;
- case "stroke-opacity":
- this.setStrokeOpacity(tokens[1]);
- break;
- case "opacity":
- this.setOpacity(tokens[1]);
- break;
- // Other attributes are not yet implemented
- }
- }
- }
- },
- setFillOpacity: function(opacityText) {
- this.fillOpacity = parseFloat(opacityText);
- this.fillColor = (parseInt(this.fillOpacity * 255, 16)) << 24 | this.fillColor & 0xFFFFFF;
- },
- setFill: function (fillText) {
- var opacityMask = this.fillColor & 0xFF000000;
- if (fillText === "none") {
- this.fill = false;
- } else if (fillText.indexOf("#") === 0) {
- this.fill = true;
- 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 );
- /*Object fillObject = findChild(fillName);
- if (fillObject instanceof Gradient) {
- fill = true;
- fillGradient = (Gradient) fillObject;
- fillGradientPaint = calcGradientPaint(fillGradient); //, opacity);
- } else {
- System.err.println("url " + fillName + " refers to unexpected data");
- }*/
- } else {
- if (colors[fillText]) {
- this.fill = true;
- this.fillColor = opacityMask | (parseInt(colors[fillText].substring(1), 16)) & 0xFFFFFF;
- }
- }
- },
- setOpacity: function(opacity) {
- this.strokeColor = (parseInt(opacity * 255, 16)) << 24 | this.strokeColor & 0xFFFFFF;
- this.fillColor = (parseInt(opacity * 255, 16)) << 24 | this.fillColor & 0xFFFFFF;
- },
- setStroke: function(strokeText) {
- var opacityMask = this.strokeColor & 0xFF000000;
- if (strokeText === "none") {
- this.stroke = false;
- } else if (strokeText.charAt( 0 ) === "#") {
- this.stroke = true;
- 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);
- //this.strokeObject = findChild(strokeName);
- /*if (strokeObject instanceof Gradient) {
- strokeGradient = (Gradient) strokeObject;
- strokeGradientPaint = calcGradientPaint(strokeGradient); //, opacity);
- } else {
- System.err.println("url " + strokeName + " refers to unexpected data");
- }*/
- } else {
- if (colors[strokeText]){
- this.stroke = true;
- this.strokeColor = opacityMask | (parseInt(colors[strokeText].substring(1), 16)) & 0xFFFFFF;
- }
- }
- },
- setStrokeWeight: function(weight) {
- this.strokeWeight = this.parseUnitSize(weight);
- },
- setStrokeJoin: function(linejoin) {
- if (linejoin === "miter") {
- this.strokeJoin = p.MITER;
- } else if (linejoin === "round") {
- this.strokeJoin = p.ROUND;
- } else if (linejoin === "bevel") {
- this.strokeJoin = p.BEVEL;
- }
- },
- setStrokeCap: function (linecap) {
- if (linecap === "butt") {
- this.strokeCap = p.SQUARE;
- } else if (linecap === "round") {
- this.strokeCap = p.ROUND;
- } else if (linecap === "square") {
- this.strokeCap = p.PROJECT;
- }
- },
- setStrokeOpacity: function (opacityText) {
- this.strokeOpacity = parseFloat(opacityText);
- this.strokeColor = (parseInt(this.strokeOpacity * 255, 16)) << 24 | this.strokeColor & 0xFFFFFF;
- },
- 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]);
- },
- 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;
- } else if (text.indexOf("pc") === len) {
- return parseFloat( text.substring( 0, len)) * 15;
- } else if (text.indexOf("mm") === len) {
- return parseFloat( text.substring(0, len)) * 3.543307;
- } else if (text.indexOf("cm") === len) {
- return parseFloat(text.substring(0, len)) * 35.43307;
- } else if (text.indexOf("in") === len) {
- return parseFloat(text.substring(0, len)) * 90;
- } else if (text.indexOf("px") === len) {
- return parseFloat(text.substring(0, len));
- } else {
- return parseFloat(text);
- }
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // XMLAttribute
- ////////////////////////////////////////////////////////////////////////////
- var XMLAttribute = p.XMLAttribute = function (fname, n, nameSpace, v, t){
- this.fullName = fname || "";
- this.name = n || "";
- this.namespace = nameSpace || "";
- this.value = v;
- this.type = t;
- };
- XMLAttribute.prototype = {
- getName: function() {
- return this.name;
- },
- getFullName: function() {
- return this.fullName;
- },
- getNamespace: function() {
- return this.namespace;
- },
- getValue: function() {
- return this.value;
- },
- getType: function() {
- return this.type;
- },
- setValue: function(newval) {
- this.value = newval;
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // XMLElement
- ////////////////////////////////////////////////////////////////////////////
- var XMLElement = p.XMLElement = function() {
- if (arguments.length === 4) {
- this.attributes = [];
- this.children = [];
- this.fullName = arguments[0] || "";
- if (arguments[1]) {
- this.name = arguments[1];
- } else {
- var index = this.fullName.indexOf(':');
- if (index >= 0) {
- this.name = this.fullName.substring(index + 1);
- } else {
- this.name = this.fullName;
- }
- }
- this.namespace = arguments[1];
- this.content = "";
- this.lineNr = arguments[3];
- this.systemID = arguments[2];
- this.parent = null;
- }
- else if ((arguments.length === 1 && arguments[0].indexOf(".") > -1) || arguments.length === 2) { // filename or svg xml element
- if (arguments[arguments.length -1].indexOf(".") > -1) { //its a filename
- this.attributes = [];
- this.children = [];
- this.fullName = "";
- this.name = "";
- this.namespace = "";
- this.content = "";
- this.systemID = "";
- this.lineNr = "";
- this.parent = null;
- this.parse(arguments[arguments.length -1]);
- } else { //xml string
- this.parse(arguments[arguments.length -1]);
- }
- }
- else { //empty ctor
- this.attributes = [];
- this.children = [];
- this.fullName = "";
- this.name = "";
- this.namespace = "";
- this.content = "";
- this.systemID = "";
- this.lineNr = "";
- this.parent = null;
- }
- return this;
- };
- /*XMLElement methods
- missing: enumerateAttributeNames(), enumerateChildren(),
- NOTE: parse does not work when a url is passed in
- */
- XMLElement.prototype = {
- parse: function(filename) {
- var xmlDoc;
- try {
- xmlDoc = new DOMParser().parseFromString(ajax(filename), "text/xml");
- var elements = xmlDoc.documentElement;
- if (elements) {
- this.parseChildrenRecursive(null, elements);
- } else {
- throw ("Error loading document");
- }
- return this;
- } catch(e) {
- throw(e);
- }
- },
- createElement: function () {
- if (arguments.length === 2) {
- return new XMLElement(arguments[0], arguments[1], null, null);
- } else {
- return new XMLElement(arguments[0], arguments[1], arguments[2], arguments[3]);
- }
- },
- hasAttribute: function (name) {
- return this.getAttribute(name) !== null;
- //2 parameter call missing
- },
- createPCDataElement: function () {
- return new XMLElement();
- },
- equals: function(object){
- if (typeof object === "Object") {
- return this.equalsXMLElement(object);
- }
- },
- equalsXMLElement: function (object) {
- if (object instanceof XMLElement) {
- if (this.name !== object.getLocalName) { return false; }
- if (this.attributes.length !== object.getAttributeCount()) { return false; }
- for (var i = 0; i < this.attributes.length; i++){
- if (! object.hasAttribute(this.attributes[i].getName(), this.attributes[i].getNamespace())) { return false; }
- if (this.attributes[i].getValue() !== object.attributes[i].getValue()) { return false; }
- if (this.attributes[i].getType() !== object.attributes[i].getType()) { return false; }
- }
- if (this.children.length !== object.getChildCount()) { return false; }
- var child1, child2;
- for (i = 0; i < this.children.length; i++) {
- child1 = this.getChildAtIndex(i);
- child2 = object.getChildAtIndex(i);
- if (! child1.equalsXMLElement(child2)) { return false; }
- }
- return true;
- }
- },
- getContent: function(){
- return this.content;
- },
- getAttribute: function (){
- var attribute;
- if( arguments.length === 2 ){
- attribute = this.findAttribute(arguments[0]);
- if (attribute) {
- return attribute.getValue();
- } else {
- return arguments[1];
- }
- } else if (arguments.length === 1) {
- attribute = this.findAttribute(arguments[0]);
- if (attribute) {
- return attribute.getValue();
- } else {
- return null;
- }
- }
- },
- getStringAttribute: function() {
- if (arguments.length === 1) {
- return this.getAttribute(arguments[0]);
- } else if (arguments.length === 2){
- return this.getAttribute(arguments[0], arguments[1]);
- } else {
- return this.getAttribute(arguments[0], arguments[1],arguments[2]);
- }
- },
- getFloatAttribute: function() {
- if (arguments.length === 1 ) {
- return this.getAttribute(arguments[0], 0);
- } else if (arguments.length === 2 ){
- return this.getAttribute(arguments[0], arguments[1]);
- } else {
- return this.getAttribute(arguments[0], arguments[1],arguments[2]);
- }
- },
- getIntAttribute: function () {
- if (arguments.length === 1) {
- return this.getAttribute( arguments[0], 0 );
- } else if (arguments.length === 2) {
- return this.getAttribute(arguments[0], arguments[1]);
- } else {
- return this.getAttribute(arguments[0], arguments[1],arguments[2]);
- }
- },
- hasChildren: function () {
- return this.children.length > 0 ;
- },
- addChild: function (child) {
- if (child !== null) {
- child.parent = this;
- this.children.push(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);
- }
- },
- getChild: function (index){
- if (typeof index === "number") {
- return this.children[index];
- }
- else if (index.indexOf('/') !== -1) { // path was given
- this.getChildRecursive(index.split("/"), 0);
- } else {
- var kid, kidName;
- for (var i = 0; i < this.getChildCount(); i++) {
- kid = this.getChild(i);
- kidName = kid.getName();
- if (kidName !== null && kidName === index) {
- return kid;
- }
- }
- return null;
- }
- },
- getChildren: function(){
- if (arguments.length === 1) {
- if (typeof arguments[0] === "number") {
- return this.getChild( arguments[0]);
- } else if (arguments[0].indexOf('/') !== -1) { // path was given
- return this.getChildrenRecursive( arguments[0].split("/"), 0);
- } else {
- var matches = [];
- var kid, kidName;
- for (var i = 0; i < this.getChildCount(); i++) {
- kid = this.getChild(i);
- kidName = kid.getName();
- if (kidName !== null && kidName === arguments[0]) {
- matches.push(kid);
- }
- }
- return matches;
- }
- }else {
- return this.children;
- }
- },
- getChildCount: function(){
- return this.children.length;
- },
- getChildRecursive: function (items, offset) {
- var kid, kidName;
- for(var i = 0; i < this.getChildCount(); i++) {
- kid = this.getChild(i);
- kidName = kid.getName();
- if (kidName !== null && kidName === items[offset]) {
- if (offset === items.length-1) {
- return kid;
- } else {
- offset += 1;
- return kid.getChildRecursive(items, offset);
- }
- }
- }
- return null;
- },
- 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 = matches[i].getChildrenRecursive(items, offset+1);
- }
- return kidMatches;
- },
- parseChildrenRecursive: function (parent , elementpath){
- var xmlelement,
- xmlattribute,
- tmpattrib;
- if (!parent) {
- this.fullName = elementpath.localName;
- this.name = elementpath.nodeName;
- this.content = elementpath.textContent || "";
- xmlelement = this;
- } else { // a parent
- xmlelement = new XMLElement(elementpath.localName, elementpath.nodeName, "", "");
- xmlelement.content = elementpath.textContent || "";
- xmlelement.parent = parent;
- }
- for (var l = 0; l < elementpath.attributes.length; l++) {
- tmpattrib = elementpath.attributes[l];
- xmlattribute = new XMLAttribute(tmpattrib.getname , tmpattrib.nodeName, tmpattrib.namespaceURI , tmpattrib.nodeValue , tmpattrib.nodeType);
- xmlelement.attributes.push(xmlattribute);
- }
-
- for (var node in elementpath.childNodes){
- if(elementpath.childNodes[node].nodeType === 1) { //ELEMENT_NODE type
- xmlelement.children.push( xmlelement.parseChildrenRecursive(xmlelement, elementpath.childNodes[node]));
- }
- }
- /*
- for( var m = 0; m < elementpath.childElementCount; m++ ) {
- xmlelement.children.push( xmlelement.parseChildrenRecursive(xmlelement, elementpath.childNodes[m]) );
- }*/
- return xmlelement;
- },
- isLeaf: function(){
- return this.hasChildren();
- },
- listChildren: function() {
- var arr = [];
- for (var i = 0; i < this.children.length; i++) {
- arr.push( this.getChild(i).getName());
- }
- return arr;
- },
- removeAttribute: function (name , namespace) {
- this.namespace = namespace || "";
- for (var i = 0; i < this.attributes.length; i++){
- if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) {
- this.attributes.splice(i, 0);
- }
- }
- },
- removeChild: function(child) {
- if (child) {
- for (var i = 0; i < this.children.length; i++) {
- if (this.children[i].equalsXMLElement(child)) {
- this.children.splice(i, 0);
- }
- }
- }
- },
- removeChildAtIndex: function(index) {
- if (this.children.length > index) { //make sure its not outofbounds
- this.children.splice(index, 0);
- }
- },
- findAttribute: function (name, namespace) {
- this.namespace = namespace || "";
- for (var i = 0; i < this.attributes.length; i++ ) {
- if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) {
- return this.attributes[i];
- }
- }
- },
- 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.addElement(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.addElement(attr);
- }
- }
- },
- setContent: function(content) {
- this.content = content;
- },
- setName: function() {
- if (arguments.length === 1) {
- this.name = arguments[0];
- this.fullName = arguments[0];
- this.namespace = arguments[0];
- } 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];
- }
- },
- getName: function() {
- return this.fullName;
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // 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 printMatrixHelper(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;
- };
- 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.prototype = {
- 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();
- }
- },
- get: function() {
- var outgoing = new PMatrix2D();
- outgoing.set(this.elements);
- return outgoing;
- },
- reset: function() {
- this.set([1, 0, 0, 0, 1, 0]);
- },
- // Returns a copy of the element values.
- array: function array() {
- return this.elements.slice();
- },
- 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];
- },
- transpose: function() {
- // Does nothing in Processing.
- },
- 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;
- },
- multX: function(x, y) {
- return (x * this.elements[0] + y * this.elements[1] + this.elements[2]);
- },
- multY: function(x, y) {
- return (x * this.elements[3] + y * this.elements[4] + this.elements[5]);
- },
- skewX: function(angle) {
- this.apply(1, 0, 1, angle, 0, 0);
- },
- skewY: function(angle) {
- this.apply(1, 0, 1, 0, angle, 0);
- },
- determinant: function() {
- return (this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3]);
- },
- invert: function() {
- var d = this.determinant();
- if ( Math.abs( d ) > p.FLOAT_MIN ) {
- 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[1] = old00 / d;
- this.elements[2] = (old01 * old12 - old11 * old02) / d;
- this.elements[5] = (old10 * old02 - old00 * old12) / d;
- return true;
- }
- return false;
- },
- 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;
- }
- },
- 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();
- },
- 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();
- },
- 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;
- },
- rotateZ: function(angle) {
- this.rotate(angle);
- },
- 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
- ////////////////////////////////////////////////////////////////////////////
- var PMatrix3D = p.PMatrix3D = function PMatrix3D() {
- // When a matrix is created, it is set to an identity matrix
- this.reset();
- };
- PMatrix3D.prototype = {
- 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();
- }
- },
- get: function() {
- var outgoing = new PMatrix3D();
- outgoing.set(this.elements);
- return outgoing;
- },
- reset: function() {
- this.set([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
- },
- // Returns a copy of the element values.
- array: function array() {
- return this.elements.slice();
- },
- 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];
- },
- transpose: function() {
- var temp = this.elements.slice();
- this.elements[0] = temp[0];
- this.elements[1] = temp[4];
- this.elements[2] = temp[8];
- this.elements[3] = temp[12];
- this.elements[4] = temp[1];
- this.elements[5] = temp[5];
- this.elements[6] = temp[9];
- this.elements[7] = temp[13];
- this.elements[8] = temp[2];
- this.elements[9] = temp[6];
- this.elements[10] = temp[10];
- this.elements[11] = temp[14];
- this.elements[12] = temp[3];
- this.elements[13] = temp[7];
- this.elements[14] = temp[11];
- this.elements[15] = temp[15];
- },
- /*
- You must either pass in two PVectors or two arrays,
- don't mix between types. You may also omit a second
- argument and simply read the result from the return.
- */
- 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;
- },
- 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();
- },
- 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();
- },
- rotate: function(angle, v0, v1, v2) {
- if (!v1) {
- this.rotateZ(angle);
- } else {
- // TODO should make sure this vector is normalized
- 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);
- }
- },
- 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;
- },
- 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]);
- },
- 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]);
- },
- 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]);
- },
- // Uniform scaling if only one value passed in
- 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;
- }
- },
- 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);
- },
- 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);
- },
- multX: function(x, y, z, w) {
- if (!z) {
- return this.elements[0] * x + this.elements[1] * y + this.elements[3];
- } else if (!w) {
- return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3];
- } else {
- 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];
- } else if (!w) {
- return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7];
- } else {
- 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];
- } else {
- 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];
- } else {
- return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w;
- }
- },
- 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;
- },
- 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]);
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Matrix Stack
- ////////////////////////////////////////////////////////////////////////////
- var PMatrixStack = p.PMatrixStack = function PMatrixStack() {
- this.matrixStack = [];
- };
- PMatrixStack.prototype.load = function load() {
- var tmpMatrix;
- if (p.use3DContext) {
- tmpMatrix = new PMatrix3D();
- } else {
- tmpMatrix = new PMatrix2D();
- }
- if (arguments.length === 1) {
- tmpMatrix.set(arguments[0]);
- } else {
- tmpMatrix.set(arguments);
- }
- this.matrixStack.push(tmpMatrix);
- };
- PMatrixStack.prototype.push = function push() {
- this.matrixStack.push(this.peek());
- };
- PMatrixStack.prototype.pop = function pop() {
- return this.matrixStack.pop();
- };
- PMatrixStack.prototype.peek = function peek() {
- var tmpMatrix;
- if (p.use3DContext) {
- tmpMatrix = new PMatrix3D();
- } else {
- tmpMatrix = new PMatrix2D();
- }
- tmpMatrix.set(this.matrixStack[this.matrixStack.length - 1]);
- return tmpMatrix;
- };
- PMatrixStack.prototype.mult = function mult(matrix) {
- this.matrixStack[this.matrixStack.length - 1].apply(matrix);
- };
- ////////////////////////////////////////////////////////////////////////////
- // Array handling
- ////////////////////////////////////////////////////////////////////////////
- p.split = function(str, delim) {
- return str.split(delim);
- };
- p.splitTokens = function(str, tokens) {
- if (arguments.length === 1) {
- tokens = "\n\t\r\f ";
- }
- tokens = "[" + tokens + "]";
- var ary = [];
- var index = 0;
- var pos = str.search(tokens);
- while (pos >= 0) {
- if (pos === 0) {
- str = str.substring(1);
- } else {
- ary[index] = str.substring(0, pos);
- index++;
- str = str.substring(pos);
- }
- pos = str.search(tokens);
- }
- if (str.length > 0) {
- ary[index] = str;
- }
- if (ary.length === 0) {
- ary = undef;
- }
- return ary;
- };
- p.append = function(array, element) {
- array[array.length] = element;
- return array;
- };
- p.concat = function(array1, array2) {
- return array1.concat(array2);
- };
- 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;
- };
- /**
- splice inserts "value" which can be either a scalar or an array
- into "array" at position "index".
- */
- 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;
- };
- p.subset = function(array, offset, length) {
- if (arguments.length === 2) {
- return array.slice(offset, array.length - offset);
- } else if (arguments.length === 3) {
- return array.slice(offset, offset + length);
- }
- };
- p.join = function(array, seperator) {
- return array.join(seperator);
- };
- 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;
- };
- p.expand = function(ary, newSize) {
- var temp = ary.slice(0);
- if (arguments.length === 1) {
- // double size of array
- temp.length = ary.length * 2;
- return temp;
- } else if (arguments.length === 2) {
- // size is newSize
- temp.length = newSize;
- return temp;
- }
- };
- 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";
- }
- }
- };
- p.ArrayList = function() {
- var createArrayList = function(args){
- var array = [];
- for (var i = 0; i < args[0]; i++){
- array[i] = (args.length > 1 ? createArrayList(args.slice(1)) : 0 );
- }
- array.get = function(i) {
- return this[i];
- };
- array.contains = function(item) {
- return this.indexOf(item) !== -1;
- };
- array.add = function() {
- if(arguments.length === 1) {
- this.push(arguments[0]); // for add(Object)
- } else if(arguments.length === 2) {
- if (typeof arguments[0] === 'number') {
- if (arguments[0] >= 0 && arguments[0] <= this.length) {
- this.splice(arguments[0], 0, arguments[1]); // for add(i, Object)
- } else {
- throw(arguments[0] + " is not a valid index");
- }
- } else {
- throw(typeof arguments[0] + " is not a number");
- }
- } else {
- throw("Please use the proper number of parameters.");
- }
- };
- array.set = function() {
- if(arguments.length === 2) {
- if (typeof arguments[0] === 'number') {
- if (arguments[0] >= 0 && arguments[0] < this.length) {
- this.splice(arguments[0], 1, arguments[1]);
- } else {
- throw(arguments[0] + " is not a valid index.");
- }
- } else {
- throw(typeof arguments[0] + " is not a number");
- }
- } else {
- throw("Please use the proper number of parameters.");
- }
- };
- array.size = function() {
- return this.length;
- };
- array.clear = function() {
- this.length = 0;
- };
- array.remove = function(i) {
- return this.splice(i, 1)[0];
- };
- array.isEmpty = function() {
- return !!this.length;
- };
- array.clone = function() {
- return this.slice(0);
- };
- array.toArray = function() {
- return this.slice(0);
- };
- return array;
- };
- return createArrayList(Array.prototype.slice.call(arguments));
- };
- p.reverse = function(array) {
- return array.reverse();
- };
- ////////////////////////////////////////////////////////////////////////////
- // HashMap
- ////////////////////////////////////////////////////////////////////////////
- var virtHashCode = function virtHashCode(obj) {
- if (obj.constructor === String) {
- var hash = 0;
- for (var i = 0; i < obj.length; ++i) {
- hash = (hash * 31 + obj.charCodeAt(i)) & 0xFFFFFFFF;
- }
- return hash;
- } else if (typeof(obj) !== "object") {
- return obj & 0xFFFFFFFF;
- } else if ("hashCode" in obj) {
- return obj.hashCode.call(obj);
- } else {
- if (obj.$id === undef) {
- obj.$id = ((Math.floor(Math.random() * 0x10000) - 0x8000) << 16) | Math.floor(Math.random() * 0x10000);
- }
- return obj.$id;
- }
- };
- var virtEquals = function virtEquals(obj, other) {
- if (obj === null || other === null) {
- return (obj === null) && (other === null);
- } else if (obj.constructor === String) {
- return obj === other;
- } else if (typeof(obj) !== "object") {
- return obj === other;
- } else if ("equals" in obj) {
- return obj.equals.call(obj, other);
- } else {
- return obj === other;
- }
- };
- p.HashMap = function HashMap() {
- if (arguments.length === 1 && arguments[0].constructor === HashMap) {
- return arguments[0].clone();
- }
- var initialCapacity = arguments.length > 0 ? arguments[0] : 16;
- var loadFactor = arguments.length > 1 ? arguments[1] : 0.75;
- var buckets = new Array(initialCapacity);
- var count = 0;
- var hashMap = this;
- function ensureLoad() {
- if (count <= loadFactor * buckets.length) {
- return;
- }
- var allEntries = [];
- for (var i = 0; i < buckets.length; ++i) {
- if (buckets[i] !== undef) {
- allEntries = allEntries.concat(buckets[i]);
- }
- }
- buckets = new Array(buckets.length * 2);
- for (var j = 0; j < allEntries.length; ++j) {
- var index = virtHashCode(allEntries[j].key) % buckets.length;
- var bucket = buckets[index];
- if (bucket === undef) {
- buckets[index] = bucket = [];
- }
- bucket.push(allEntries[j]);
- }
- }
- function Iterator(conversion, removeItem) {
- var bucketIndex = 0;
- var itemIndex = -1;
- var endOfBuckets = false;
- function findNext() {
- while (!endOfBuckets) {
- ++itemIndex;
- if (bucketIndex >= buckets.length) {
- endOfBuckets = true;
- } else if (buckets[bucketIndex] === undef || itemIndex >= buckets[bucketIndex].length) {
- itemIndex = -1;
- ++bucketIndex;
- } else {
- return;
- }
- }
- }
- this.hasNext = function() {
- return !endOfBuckets;
- };
- this.next = function() {
- var result = conversion(buckets[bucketIndex][itemIndex]);
- findNext();
- return result;
- };
- this.remove = function() {
- removeItem(this.next());
- --itemIndex;
- };
- 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 = new p.ArrayList(0);
- 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 === undef);
- };
- 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 = new Array(initialCapacity);
- };
- this.clone = function() {
- var map = new p.HashMap();
- map.putAll(this);
- return map;
- };
- this.containsKey = function(key) {
- var index = virtHashCode(key) % buckets.length;
- var bucket = buckets[index];
- if (bucket === undef) {
- 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 === undef) {
- 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.constructor === Entry && pair._isIn(hashMap);
- },
- function(pair) {
- return hashMap.remove(pair.getKey());
- });
- };
- this.get = function(key) {
- var index = virtHashCode(key) % buckets.length;
- var bucket = buckets[index];
- if (bucket === undef) {
- 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(
- function(pair) {
- return pair.key;
- },
- function(key) {
- return hashMap.containsKey(key);
- },
- function(key) {
- return hashMap.remove(key);
- });
- };
- this.put = function(key, value) {
- var index = virtHashCode(key) % buckets.length;
- var bucket = buckets[index];
- if (bucket === undef) {
- ++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 = virtHashCode(key) % buckets.length;
- var bucket = buckets[index];
- if (bucket === undef) {
- 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] = undef;
- }
- return previous;
- }
- }
- return null;
- };
- this.size = function() {
- return count;
- };
- this.values = function() {
- var result = new p.ArrayList(0);
- var it = this.entrySet().iterator();
- while (it.hasNext()) {
- var entry = it.next();
- result.push(entry.getValue());
- }
- return result;
- };
- };
- ////////////////////////////////////////////////////////////////////////////
- // 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
- p.modes = {
- replace: function(c1, c2) {
- return c2;
- },
- blend: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- p.mix(c1 & p.RED_MASK, c2 & p.RED_MASK, f) & p.RED_MASK |
- p.mix(c1 & p.GREEN_MASK, c2 & p.GREEN_MASK, f) & p.GREEN_MASK |
- p.mix(c1 & p.BLUE_MASK, c2 & p.BLUE_MASK, f));
- },
- add: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- Math.min(((c1 & p.RED_MASK) + ((c2 & p.RED_MASK) >> 8) * f), p.RED_MASK) & p.RED_MASK |
- Math.min(((c1 & p.GREEN_MASK) + ((c2 & p.GREEN_MASK) >> 8) * f), p.GREEN_MASK) & p.GREEN_MASK |
- Math.min((c1 & p.BLUE_MASK) + (((c2 & p.BLUE_MASK) * f) >> 8), p.BLUE_MASK));
- },
- subtract: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- Math.max(((c1 & p.RED_MASK) - ((c2 & p.RED_MASK) >> 8) * f), p.GREEN_MASK) & p.RED_MASK |
- Math.max(((c1 & p.GREEN_MASK) - ((c2 & p.GREEN_MASK) >> 8) * f), p.BLUE_MASK) & p.GREEN_MASK |
- Math.max((c1 & p.BLUE_MASK) - (((c2 & p.BLUE_MASK) * f) >> 8), 0));
- },
- lightest: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- Math.max(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f) & p.RED_MASK |
- Math.max(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f) & p.GREEN_MASK |
- Math.max(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8));
- },
- darkest: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- p.mix(c1 & p.RED_MASK, Math.min(c1 & p.RED_MASK, ((c2 & p.RED_MASK) >> 8) * f), f) & p.RED_MASK |
- p.mix(c1 & p.GREEN_MASK, Math.min(c1 & p.GREEN_MASK, ((c2 & p.GREEN_MASK) >> 8) * f), f) & p.GREEN_MASK |
- p.mix(c1 & p.BLUE_MASK, Math.min(c1 & p.BLUE_MASK, ((c2 & p.BLUE_MASK) * f) >> 8), f));
- },
- difference: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = (ar > br) ? (ar - br) : (br - ar);
- var cg = (ag > bg) ? (ag - bg) : (bg - ag);
- var cb = (ab > bb) ? (ab - bb) : (bb - ab);
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- exclusion: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = ar + br - ((ar * br) >> 7);
- var cg = ag + bg - ((ag * bg) >> 7);
- var cb = ab + bb - ((ab * bb) >> 7);
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- multiply: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = (ar * br) >> 8;
- var cg = (ag * bg) >> 8;
- var cb = (ab * bb) >> 8;
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- screen: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = 255 - (((255 - ar) * (255 - br)) >> 8);
- var cg = 255 - (((255 - ag) * (255 - bg)) >> 8);
- var cb = 255 - (((255 - ab) * (255 - bb)) >> 8);
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- hard_light: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = (br < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7));
- var cg = (bg < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7));
- var cb = (bb < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7));
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- soft_light: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = ((ar * br) >> 7) + ((ar * ar) >> 8) - ((ar * ar * br) >> 15);
- var cg = ((ag * bg) >> 7) + ((ag * ag) >> 8) - ((ag * ag * bg) >> 15);
- var cb = ((ab * bb) >> 7) + ((ab * ab) >> 8) - ((ab * ab * bb) >> 15);
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- overlay: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = (ar < 128) ? ((ar * br) >> 7) : (255 - (((255 - ar) * (255 - br)) >> 7));
- var cg = (ag < 128) ? ((ag * bg) >> 7) : (255 - (((255 - ag) * (255 - bg)) >> 7));
- var cb = (ab < 128) ? ((ab * bb) >> 7) : (255 - (((255 - ab) * (255 - bb)) >> 7));
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- dodge: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = (br === 255) ? 255 : p.peg((ar << 8) / (255 - br)); // division requires pre-peg()-ing
- var cg = (bg === 255) ? 255 : p.peg((ag << 8) / (255 - bg)); // "
- var cb = (bb === 255) ? 255 : p.peg((ab << 8) / (255 - bb)); // "
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- },
- burn: function(c1, c2) {
- var f = (c2 & p.ALPHA_MASK) >>> 24;
- var ar = (c1 & p.RED_MASK) >> 16;
- var ag = (c1 & p.GREEN_MASK) >> 8;
- var ab = (c1 & p.BLUE_MASK);
- var br = (c2 & p.RED_MASK) >> 16;
- var bg = (c2 & p.GREEN_MASK) >> 8;
- var bb = (c2 & p.BLUE_MASK);
- // formula:
- var cr = (br === 0) ? 0 : 255 - p.peg(((255 - ar) << 8) / br); // division requires pre-peg()-ing
- var cg = (bg === 0) ? 0 : 255 - p.peg(((255 - ag) << 8) / bg); // "
- var cb = (bb === 0) ? 0 : 255 - p.peg(((255 - ab) << 8) / bb); // "
- // alpha blend (this portion will always be the same)
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- (p.peg(ar + (((cr - ar) * f) >> 8)) << 16) |
- (p.peg(ag + (((cg - ag) * f) >> 8)) << 8) |
- (p.peg(ab + (((cb - ab) * f) >> 8))));
- }
- };
- function color$4(aValue1, aValue2, aValue3, aValue4) {
- var r, g, b, a;
- if (curColorMode === p.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 greater than 255
- 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) & p.ALPHA_MASK | (r << 16) & p.RED_MASK | (g << 8) & p.GREEN_MASK | b & p.BLUE_MASK;
- }
- function color$2(aValue1, aValue2) {
- var a;
- // Color int and alpha
- if (aValue1 & p.ALPHA_MASK) {
- a = Math.round(255 * (aValue2 / colorModeA));
- a = (a > 255) ? 255 : a;
- return aValue1 - (aValue1 & p.ALPHA_MASK) + ((a << 24) & p.ALPHA_MASK);
- }
- // Grayscale and alpha
- else {
- if (curColorMode === p.RGB) {
- return color$4(aValue1, aValue1, aValue1, aValue2);
- } else if (curColorMode === p.HSB) {
- return color$4(0, 0, (aValue1 / colorModeX) * colorModeZ, aValue2);
- }
- }
- }
- function color$1(aValue1) {
- // Grayscale
- if (aValue1 <= colorModeX && aValue1 >= 0) {
- if (curColorMode === p.RGB) {
- return color$4(aValue1, aValue1, aValue1, colorModeA);
- } else if (curColorMode === p.HSB) {
- return color$4(0, 0, (aValue1 / colorModeX) * colorModeZ, colorModeA);
- }
- }
- // Color int
- else if (aValue1) {
- return aValue1;
- }
- }
- p.color = function color(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)
- else if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef) {
- return color$4(aValue1, aValue2, aValue3, colorModeA);
- }
- // 2 arguments: (Color, A) or (Grayscale, A)
- else if (aValue1 !== undef && aValue2 !== undef) {
- return color$2(aValue1, aValue2);
- }
- // 1 argument: (Grayscale) or (Color)
- else if (typeof aValue1 === "number") {
- return color$1(aValue1);
- }
- // Default
- else {
- 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 & p.RED_MASK) >>> 16) + "," + ((colorInt & p.GREEN_MASK) >>> 8) +
- "," + ((colorInt & p.BLUE_MASK)) + "," + ((colorInt & p.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) & p.ALPHA_MASK | (r << 16) & p.RED_MASK | (g << 8) & p.GREEN_MASK | b & p.BLUE_MASK;
- };
- // Creates a simple array in [R, G, B, A] format, [255, 255, 255, 255]
- p.color.toArray = function(colorInt) {
- return [(colorInt & p.RED_MASK) >>> 16, (colorInt & p.GREEN_MASK) >>> 8,
- colorInt & p.BLUE_MASK, (colorInt & p.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 & p.RED_MASK) >>> 16) / 255, ((colorInt & p.GREEN_MASK) >>> 8) / 255,
- (colorInt & p.BLUE_MASK) / 255, ((colorInt & p.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];
- } else {
- 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];
- }
- }
- };
- p.color.toHSB = function( colorInt ) {
- var red, green, blue;
- red = ((colorInt & p.RED_MASK) >>> 16) / 255;
- green = ((colorInt & p.GREEN_MASK) >>> 8) / 255;
- blue = (colorInt & p.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];
- } else {
- 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];
- };
- p.brightness = function(colInt){
- return p.color.toHSB(colInt)[2];
- };
- p.saturation = function(colInt){
- return p.color.toHSB(colInt)[1];
- };
- p.hue = function(colInt){
- return p.color.toHSB(colInt)[0];
- };
- var verifyChannel = function verifyChannel(aColor) {
- if (aColor.constructor === Array) {
- return aColor;
- } else {
- return p.color(aColor);
- }
- };
- p.red = function(aColor) {
- return ((aColor & p.RED_MASK) >>> 16) / 255 * colorModeX;
- };
- p.green = function(aColor) {
- return ((aColor & p.GREEN_MASK) >>> 8) / 255 * colorModeY;
- };
- p.blue = function(aColor) {
- return (aColor & p.BLUE_MASK) / 255 * colorModeZ;
- };
- p.alpha = function(aColor) {
- return ((aColor & p.ALPHA_MASK) >>> 24) / 255 * colorModeA;
- };
- p.lerpColor = function lerpColor(c1, c2, amt) {
- // Get RGBA values for Color 1 to floats
- var colorBits1 = p.color(c1);
- var r1 = (colorBits1 & p.RED_MASK) >>> 16;
- var g1 = (colorBits1 & p.GREEN_MASK) >>> 8;
- var b1 = (colorBits1 & p.BLUE_MASK);
- var a1 = ((colorBits1 & p.ALPHA_MASK) >>> 24) / colorModeA;
- // Get RGBA values for Color 2 to floats
- var colorBits2 = p.color(c2);
- var r2 = (colorBits2 & p.RED_MASK) >>> 16;
- var g2 = (colorBits2 & p.GREEN_MASK) >>> 8;
- var b2 = (colorBits2 & p.BLUE_MASK);
- var a2 = ((colorBits2 & p.ALPHA_MASK) >>> 24) / colorModeA;
- // Return lerp value for each channel, INT for color, Float for Alpha-range
- var r = parseInt(p.lerp(r1, r2, amt), 10);
- var g = parseInt(p.lerp(g1, g2, amt), 10);
- var b = parseInt(p.lerp(b1, b2, amt), 10);
- var a = parseFloat(p.lerp(a1, a2, amt) * colorModeA);
- return p.color.toInt(r, g, b, a);
- };
- // Forced default color mode for #aaaaaa style
- p.defaultColor = function(aValue1, aValue2, aValue3) {
- var tmpColorMode = curColorMode;
- curColorMode = p.RGB;
- var c = p.color(aValue1 / 255 * colorModeX, aValue2 / 255 * colorModeY, aValue3 / 255 * colorModeZ);
- curColorMode = tmpColorMode;
- return c;
- };
- p.colorMode = function colorMode() { // 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];
- }
- };
- p.blendColor = function(c1, c2, mode) {
- var color = 0;
- switch (mode) {
- case p.REPLACE:
- color = p.modes.replace(c1, c2);
- break;
- case p.BLEND:
- color = p.modes.blend(c1, c2);
- break;
- case p.ADD:
- color = p.modes.add(c1, c2);
- break;
- case p.SUBTRACT:
- color = p.modes.subtract(c1, c2);
- break;
- case p.LIGHTEST:
- color = p.modes.lightest(c1, c2);
- break;
- case p.DARKEST:
- color = p.modes.darkest(c1, c2);
- break;
- case p.DIFFERENCE:
- color = p.modes.difference(c1, c2);
- break;
- case p.EXCLUSION:
- color = p.modes.exclusion(c1, c2);
- break;
- case p.MULTIPLY:
- color = p.modes.multiply(c1, c2);
- break;
- case p.SCREEN:
- color = p.modes.screen(c1, c2);
- break;
- case p.HARD_LIGHT:
- color = p.modes.hard_light(c1, c2);
- break;
- case p.SOFT_LIGHT:
- color = p.modes.soft_light(c1, c2);
- break;
- case p.OVERLAY:
- color = p.modes.overlay(c1, c2);
- break;
- case p.DODGE:
- color = p.modes.dodge(c1, c2);
- break;
- case p.BURN:
- color = p.modes.burn(c1, c2);
- break;
- }
- return color;
- };
- ////////////////////////////////////////////////////////////////////////////
- // Canvas-Matrix manipulation
- ////////////////////////////////////////////////////////////////////////////
- function saveContext() {
- curContext.save();
- }
- function restoreContext() {
- curContext.restore();
- isStrokeDirty = true;
- isFillDirty = true;
- }
- p.printMatrix = function printMatrix() {
- modelView.print();
- };
- p.translate = function translate(x, y, z) {
- if (p.use3DContext) {
- forwardTransform.translate(x, y, z);
- reverseTransform.invTranslate(x, y, z);
- } else {
- curContext.translate(x, y);
- }
- };
- p.scale = function scale(x, y, z) {
- if (p.use3DContext) {
- forwardTransform.scale(x, y, z);
- reverseTransform.invScale(x, y, z);
- } else {
- curContext.scale(x, y || x);
- }
- };
- p.pushMatrix = function pushMatrix() {
- if (p.use3DContext) {
- userMatrixStack.load(modelView);
- } else {
- saveContext();
- }
- };
- p.popMatrix = function popMatrix() {
- if (p.use3DContext) {
- modelView.set(userMatrixStack.pop());
- } else {
- restoreContext();
- }
- };
- p.resetMatrix = function resetMatrix() {
- forwardTransform.reset();
- reverseTransform.reset();
- };
- p.applyMatrix = function applyMatrix() {
- var a = arguments;
- if (!p.use3DContext) {
- for (var cnt = a.length; cnt < 16; cnt++) {
- a[cnt] = 0;
- }
- a[10] = a[15] = 1;
- }
- forwardTransform.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]);
- reverseTransform.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]);
- };
- p.rotateX = function(angleInRadians) {
- forwardTransform.rotateX(angleInRadians);
- reverseTransform.invRotateX(angleInRadians);
- };
- p.rotateZ = function(angleInRadians) {
- forwardTransform.rotateZ(angleInRadians);
- reverseTransform.invRotateZ(angleInRadians);
- };
- p.rotateY = function(angleInRadians) {
- forwardTransform.rotateY(angleInRadians);
- reverseTransform.invRotateY(angleInRadians);
- };
- p.rotate = function rotate(angleInRadians) {
- if (p.use3DContext) {
- forwardTransform.rotateZ(angleInRadians);
- reverseTransform.invRotateZ(angleInRadians);
- } else {
- curContext.rotate(angleInRadians);
- }
- };
- p.pushStyle = function pushStyle() {
- // 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,
- 'curTextSize': curTextSize
- };
- styleArray.push(newState);
- };
- p.popStyle = function popStyle() {
- 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;
- curTextSize = oldState.curTextSize;
- } else {
- throw "Too many popStyle() without enough pushStyle()";
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Time based functions
- ////////////////////////////////////////////////////////////////////////////
- p.year = function year() {
- return new Date().getFullYear();
- };
- p.month = function month() {
- return new Date().getMonth() + 1;
- };
- p.day = function day() {
- return new Date().getDate();
- };
- p.hour = function hour() {
- return new Date().getHours();
- };
- p.minute = function minute() {
- return new Date().getMinutes();
- };
- p.second = function second() {
- return new Date().getSeconds();
- };
- p.millis = function millis() {
- return new Date().getTime() - start;
- };
- p.redraw = function redraw() {
- var sec = (new Date().getTime() - timeSinceLastFPS) / 1000;
- framesSinceLastFPS++;
- var fps = framesSinceLastFPS / sec;
- // recalculate FPS every half second for better accuracy.
- if (sec > 0.5) {
- timeSinceLastFPS = new Date().getTime();
- framesSinceLastFPS = 0;
- p.__frameRate = fps;
- }
- p.frameCount++;
- inDraw = true;
- if (p.use3DContext) {
- // 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.camera();
- p.draw();
- } else {
- saveContext();
- p.draw();
- restoreContext();
- }
- inDraw = false;
- };
- p.noLoop = function noLoop() {
- doLoop = false;
- loopStarted = false;
- clearInterval(looping);
- };
- p.loop = function loop() {
- if (loopStarted) {
- return;
- }
- looping = window.setInterval(function() {
- try {
- try {
- p.focused = document.hasFocus();
- } catch(e) {}
- p.redraw();
- } catch(e_loop) {
- window.clearInterval(looping);
- throw e_loop;
- }
- }, curMsPerFrame);
- doLoop = true;
- loopStarted = true;
- };
- p.frameRate = function frameRate(aRate) {
- curFrameRate = aRate;
- curMsPerFrame = 1000 / curFrameRate;
- };
- var eventHandlers = [];
- p.exit = function exit() {
- window.clearInterval(looping);
- Processing.removeInstance(p.externals.canvas.id);
- for (var i=0, ehl=eventHandlers.length; i<ehl; i++) {
- var elem = eventHandlers[i][0],
- type = eventHandlers[i][1],
- fn = eventHandlers[i][2];
- if (elem.removeEventListener) {
- elem.removeEventListener(type, fn, false);
- } else if (elem.detachEvent) {
- elem.detachEvent("on" + type, fn);
- }
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // MISC functions
- ////////////////////////////////////////////////////////////////////////////
- p.cursor = function cursor() {
- 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;
- }
- };
- p.noCursor = function noCursor() {
- curCursor = curElement.style.cursor = p.NOCURSOR;
- };
- p.link = function(href, target) {
- if (target !== undef) {
- window.open(href, target);
- } else {
- window.location = href;
- }
- };
- // PGraphics methods
- // TODO: These functions are suppose to be called before any operations are called on the
- // PGraphics object. They currently do nothing.
- p.beginDraw = function beginDraw() {};
- p.endDraw = function endDraw() {};
- // Imports an external Processing.js library
- p.Import = function Import(lib) {
- // Replace evil-eval method with a DOM <script> tag insert method that
- // binds new lib code to the Processing.lib names-space and the current
- // p context. -F1LT3R
- };
- var contextMenu = function(e) {
- e.preventDefault();
- e.stopPropagation();
- };
- p.disableContextMenu = function disableContextMenu() {
- curElement.addEventListener('contextmenu', contextMenu, false);
- };
- p.enableContextMenu = function enableContextMenu() {
- curElement.removeEventListener('contextmenu', contextMenu, false);
- };
- p.status = function(text) {
- window.status = text;
- };
- ////////////////////////////////////////////////////////////////////////////
- // Binary Functions
- ////////////////////////////////////////////////////////////////////////////
- function decToBin(value, numBitsInValue) {
- var mask = 1;
- mask = mask << (numBitsInValue - 1);
- var str = "";
- for (var i = 0; i < numBitsInValue; i++) {
- str += (mask & value) ? "1" : "0";
- mask = mask >>> 1;
- }
- return str;
- }
- /*
- This function does not always work when trying to convert
- colors and bytes to binary values because the types passed in
- cannot be determined.
- */
- p.binary = function(num, numBits) {
- var numBitsInValue = 32;
- // color, int, byte
- if (typeof num === "number") {
- if(numBits){
- numBitsInValue = numBits;
- }
- return decToBin(num, numBitsInValue);
- }
- // char
- if (num instanceof Char) {
- num = num.toString().charCodeAt(0);
- if (numBits) {
- numBitsInValue = 32;
- } else {
- numBitsInValue = 16;
- }
- }
- var str = decToBin(num, numBitsInValue);
- // trim string if user wanted less chars
- if (numBits) {
- str = str.substr(-numBits);
- }
- return str;
- };
- p.unbinary = function unbinary(binaryString) {
- var binaryPattern = new RegExp("^[0|1]{8}$");
- var addUp = 0;
- var i;
- if (binaryString instanceof Array) {
- var values = [];
- for (i = 0; i < binaryString.length; i++) {
- values[i] = p.unbinary(binaryString[i]);
- }
- return values;
- } else {
- if (isNaN(binaryString)) {
- throw "NaN_Err";
- } else {
- if (arguments.length === 1 || binaryString.length === 8) {
- if (binaryPattern.test(binaryString)) {
- for (i = 0; i < 8; i++) {
- addUp += (Math.pow(2, i) * parseInt(binaryString.charAt(7 - i), 10));
- }
- return addUp + "";
- } else {
- throw "notBinary: the value passed into unbinary was not an 8 bit binary number";
- }
- } else {
- throw "longErr";
- }
- }
- }
- };
- function nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) {
- var sign = (value < 0) ? minus : plus;
- var autoDetectDecimals = rightDigits === 0;
- var rightDigitsOfDefault = (rightDigits === undef || rightDigits < 0) ? 0 : rightDigits;
- // Change the way the number is 'floored' based on whether it is odd or even.
- if (rightDigits < 0 && Math.floor(value) % 2 === 1) {
- // Make sure 1.49 rounds to 1, but 1.5 rounds to 2.
- if ((value - Math.floor(value)) >= 0.5) {
- value += 1;
- }
- }
- 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);
- }
- var 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);
- } else {
- return sign + buffer;
- }
- }
- function nfCore(value, plus, minus, leftDigits, rightDigits, group) {
- if (value instanceof Array) {
- var arr = [];
- for (var i = 0, len = value.length; i < len; i++) {
- arr.push(nfCoreScalar(value[i], plus, minus, leftDigits, rightDigits, group));
- }
- return arr;
- } else {
- return nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group);
- }
- }
- // TODO: drop this and use nfCore (see below) code when we've fixed the rounding bug in nfCore
- p.nf = function() {
- var str, num, pad, arr, left, right, isNegative, test, i;
- if (arguments.length === 2 && typeof arguments[0] === 'number' && typeof arguments[1] === 'number' && (arguments[0] + "").indexOf('.') === -1) {
- num = arguments[0];
- pad = arguments[1];
- isNegative = num < 0;
- if (isNegative) {
- num = Math.abs(num);
- }
- str = "" + num;
- for (i = pad - str.length; i > 0; i--) {
- str = "0" + str;
- }
- if (isNegative) {
- str = "-" + str;
- }
- } else if (arguments.length === 2 && typeof arguments[0] === 'object' && arguments[0].constructor === Array && typeof arguments[1] === 'number') {
- arr = arguments[0];
- pad = arguments[1];
- str = new Array(arr.length);
- for (i = 0; i < arr.length && str !== undef; i++) {
- test = p.nf(arr[i], pad);
- if (test === undef) {
- str = undef;
- } else {
- str[i] = test;
- }
- }
- } else if (arguments.length === 3 && typeof arguments[0] === 'number' && typeof arguments[1] === 'number' && typeof arguments[2] === 'number' && (arguments[0] + "").indexOf('.') >= 0) {
- num = arguments[0];
- left = arguments[1];
- right = arguments[2];
- isNegative = num < 0;
- if (isNegative) {
- num = Math.abs(num);
- }
- // Change the way the number is 'floored' based on whether it is odd or even.
- if (right < 0 && Math.floor(num) % 2 === 1) {
- // Make sure 1.49 rounds to 1, but 1.5 rounds to 2.
- if ((num) - Math.floor(num) >= 0.5) {
- num = num + 1;
- }
- }
- str = "" + num;
- for (i = left - str.indexOf('.'); i > 0; i--) {
- str = "0" + str;
- }
- var numDec = str.length - str.indexOf('.') - 1;
- if (numDec <= right) {
- for (i = right - (str.length - str.indexOf('.') - 1); i > 0; i--) {
- str = str + "0";
- }
- } else if (right > 0) {
- str = str.substring(0, str.length - (numDec - right));
- } else if (right < 0) {
- str = str.substring(0, str.indexOf('.'));
- }
- if (isNegative) {
- str = "-" + str;
- }
- } else if (arguments.length === 3 && typeof arguments[0] === 'object' && arguments[0].constructor === Array && typeof arguments[1] === 'number' && typeof arguments[2] === 'number') {
- arr = arguments[0];
- left = arguments[1];
- right = arguments[2];
- str = new Array(arr.length);
- for (i = 0; i < arr.length && str !== undef; i++) {
- test = p.nf(arr[i], left, right);
- if (test === undef) {
- str = undef;
- } else {
- str[i] = test;
- }
- }
- }
- return str;
- };
- // TODO: need to switch nf over to using nfCore...
- // p.nf = function(value, leftDigits, rightDigits) { return nfCore(value, "", "-", leftDigits, rightDigits); };
- p.nfs = function(value, leftDigits, rightDigits) { return nfCore(value, " ", "-", leftDigits, rightDigits); };
- p.nfp = function(value, leftDigits, rightDigits) { return nfCore(value, "+", "-", leftDigits, rightDigits); };
- p.nfc = function(value, leftDigits, rightDigits) { return nfCore(value, "", "-", leftDigits, rightDigits, ","); };
- var decimalToHex = function decimalToHex(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: !@#$%^&*
- p.hex = function hex(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;
- }
- 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;
- } else {
- return unhexScalar(hex);
- }
- };
- // Load a file or URL into strings
- p.loadStrings = function loadStrings(url) {
- return ajax(url).split("\n");
- };
- p.loadBytes = function loadBytes(url) {
- var string = ajax(url);
- var ret = [];
- for (var i = 0; i < string.length; i++) {
- ret.push(string.charCodeAt(i));
- }
- return ret;
- };
- ////////////////////////////////////////////////////////////////////////////
- // String Functions
- ////////////////////////////////////////////////////////////////////////////
- p.matchAll = function matchAll(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;
- };
- String.prototype.replaceAll = function(re, replace) {
- return this.replace(new RegExp(re, "g"), replace);
- };
- String.prototype.equals = function equals(str) {
- return this.valueOf() === str.valueOf();
- };
- String.prototype.toCharArray = function() {
- var chars = this.split("");
- for (var i = chars.length - 1; i >= 0; i--) {
- chars[i] = new Char(chars[i]);
- }
- return chars;
- };
- p.match = function(str, regexp) {
- return str.match(regexp);
- };
- // tinylog lite JavaScript library
- // http://purl.eligrey.com/tinylog/lite
- /*global tinylog,print*/
- var tinylogLite = (function() {
- "use strict";
- var tinylogLite = {},
- undef = "undefined",
- func = "function",
- False = !1,
- True = !0,
- logLimit = 512,
- log = "log";
- if (typeof tinylog !== undef && typeof tinylog[log] === func) {
- // pre-existing tinylog present
- tinylogLite[log] = tinylog[log];
- } else if (typeof document !== undef && !document.fake) {
- (function() {
- // DOM document
- var doc = document,
- $div = "div",
- $style = "style",
- $title = "title",
- containerStyles = {
- zIndex: 10000,
- position: "fixed",
- bottom: "0px",
- width: "100%",
- height: "15%",
- fontFamily: "sans-serif",
- color: "#ccc",
- backgroundColor: "black"
- },
- outputStyles = {
- position: "relative",
- fontFamily: "monospace",
- overflow: "auto",
- height: "100%",
- paddingTop: "5px"
- },
- resizerStyles = {
- height: "5px",
- marginTop: "-5px",
- cursor: "n-resize",
- backgroundColor: "darkgrey"
- },
- closeButtonStyles = {
- position: "absolute",
- top: "5px",
- right: "20px",
- color: "#111",
- MozBorderRadius: "4px",
- webkitBorderRadius: "4px",
- borderRadius: "4px",
- cursor: "pointer",
- fontWeight: "normal",
- textAlign: "center",
- padding: "3px 5px",
- backgroundColor: "#333",
- fontSize: "12px"
- },
- entryStyles = {
- //borderBottom: "1px solid #d3d3d3",
- minHeight: "16px"
- },
- entryTextStyles = {
- fontSize: "12px",
- margin: "0 8px 0 8px",
- maxWidth: "100%",
- whiteSpace: "pre-wrap",
- overflow: "auto"
- },
- view = doc.defaultView,
- docElem = doc.documentElement,
- docElemStyle = docElem[$style],
- setStyles = function() {
- var i = arguments.length,
- elemStyle, styles, style;
- while (i--) {
- styles = arguments[i--];
- elemStyle = arguments[i][$style];
- for (style in styles) {
- if (styles.hasOwnProperty(style)) {
- elemStyle[style] = styles[style];
- }
- }
- }
- },
- observer = function(obj, event, handler) {
- if (obj.addEventListener) {
- obj.addEventListener(event, handler, False);
- } else if (obj.attachEvent) {
- obj.attachEvent("on" + event, handler);
- }
- return [obj, event, handler];
- },
- unobserve = function(obj, event, handler) {
- if (obj.removeEventListener) {
- obj.removeEventListener(event, handler, False);
- } else if (obj.detachEvent) {
- obj.detachEvent("on" + event, handler);
- }
- },
- clearChildren = function(node) {
- var children = node.childNodes,
- child = children.length;
- while (child--) {
- node.removeChild(children.item(0));
- }
- },
- append = function(to, elem) {
- return to.appendChild(elem);
- },
- createElement = function(localName) {
- return doc.createElement(localName);
- },
- createTextNode = function(text) {
- return doc.createTextNode(text);
- },
- createLog = tinylogLite[log] = function(message) {
- // don't show output log until called once
- var uninit,
- originalPadding = docElemStyle.paddingBottom,
- container = createElement($div),
- containerStyle = container[$style],
- resizer = append(container, createElement($div)),
- output = append(container, createElement($div)),
- closeButton = append(container, createElement($div)),
- resizingLog = False,
- previousHeight = False,
- previousScrollTop = False,
- messages = 0,
- updateSafetyMargin = function() {
- // have a blank space large enough to fit the output box at the page bottom
- docElemStyle.paddingBottom = container.clientHeight + "px";
- },
- setContainerHeight = function(height) {
- var viewHeight = view.innerHeight,
- resizerHeight = resizer.clientHeight;
- // constrain the container inside the viewport's dimensions
- if (height < 0) {
- height = 0;
- } else if (height + resizerHeight > viewHeight) {
- height = viewHeight - resizerHeight;
- }
- containerStyle.height = height / viewHeight * 100 + "%";
- updateSafetyMargin();
- },
- observers = [
- observer(doc, "mousemove", function(evt) {
- if (resizingLog) {
- setContainerHeight(view.innerHeight - evt.clientY);
- output.scrollTop = previousScrollTop;
- }
- }),
- observer(doc, "mouseup", function() {
- if (resizingLog) {
- resizingLog = previousScrollTop = False;
- }
- }),
- observer(resizer, "dblclick", function(evt) {
- evt.preventDefault();
- if (previousHeight) {
- setContainerHeight(previousHeight);
- previousHeight = False;
- } else {
- previousHeight = container.clientHeight;
- containerStyle.height = "0px";
- }
- }),
- observer(resizer, "mousedown", function(evt) {
- evt.preventDefault();
- resizingLog = True;
- previousScrollTop = output.scrollTop;
- }),
- observer(resizer, "contextmenu", function() {
- resizingLog = False;
- }),
- observer(closeButton, "click", function() {
- uninit();
- })
- ];
- uninit = function() {
- // remove observers
- var i = observers.length;
- while (i--) {
- unobserve.apply(tinylogLite, observers[i]);
- }
- // remove tinylog lite from the DOM
- docElem.removeChild(container);
- docElemStyle.paddingBottom = originalPadding;
- clearChildren(output);
- clearChildren(container);
- tinylogLite[log] = createLog;
- };
- setStyles(
- container, containerStyles, output, outputStyles, resizer, resizerStyles, closeButton, closeButtonStyles);
- closeButton[$title] = "Close Log";
- append(closeButton, createTextNode("\u2716"));
- resizer[$title] = "Double-click to toggle log minimization";
- docElem.insertBefore(container, docElem.firstChild);
- tinylogLite[log] = function(message) {
- if (messages === logLimit) {
- output.removeChild(output.firstChild);
- } else {
- messages++;
- }
-
- var entry = append(output, createElement($div)),
- entryText = append(entry, createElement($div));
- entry[$title] = (new Date()).toLocaleTimeString();
- setStyles(
- entry, entryStyles, entryText, entryTextStyles);
- append(entryText, createTextNode(message));
- output.scrollTop = output.scrollHeight;
- };
- tinylogLite[log](message);
- };
- }());
- } else if (typeof print === func) { // JS shell
- tinylogLite[log] = print;
- }
- return tinylogLite;
- }()),
- logBuffer = [];
- p.console = window.console || tinylogLite;
- p.println = function println(message) {
- var bufferLen = logBuffer.length;
- if (bufferLen) {
- tinylogLite.log(logBuffer.join(""));
- logBuffer.length = 0; // clear log buffer
- }
- if (arguments.length === 0 && bufferLen === 0) {
- tinylogLite.log("");
- } else if (arguments.length !== 0) {
- tinylogLite.log(message);
- }
- };
- p.print = function print(message) {
- logBuffer.push(message);
- };
- // Alphanumeric chars arguments automatically converted to numbers when
- // passed in, and will come out as numbers.
- p.str = function str(val) {
- if (val instanceof Array) {
- var arr = [];
- for (var i = 0; i < val.length; i++) {
- arr.push(val[i] + "");
- }
- return arr;
- } else {
- return (val + "");
- }
- };
- p.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;
- } else {
- return str.replace(/^\s*/, '').replace(/\s*$/, '').replace(/\r*$/, '');
- }
- };
- // Conversion
- function booleanScalar(val) {
- if (typeof val === 'number') {
- return val !== 0;
- } else if (typeof val === 'boolean') {
- return val;
- } else if (typeof val === 'string') {
- return val.toLowerCase() === 'true';
- } else if (val instanceof Char) {
- // 1, T or t
- return val.code === 49 || val.code === 84 || val.code === 116;
- }
- }
- p['boolean'] = function(val) {
- if (val instanceof Array) {
- var ret = [];
- for (var i = 0; i < val.length; i++) {
- ret.push(booleanScalar(val[i]));
- }
- return ret;
- } else {
- return booleanScalar(val);
- }
- };
- // a byte is a number between -128 and 127
- p['byte'] = function(aNumber) {
- if (aNumber instanceof Array) {
- var bytes = [];
- for (var i = 0; i < aNumber.length; i++) {
- bytes.push((0 - (aNumber[i] & 0x80)) | (aNumber[i] & 0x7F));
- }
- return bytes;
- } else {
- return (0 - (aNumber & 0x80)) | (aNumber & 0x7F);
- }
- };
- p['char'] = function(key) {
- if (typeof key === "number") {
- return new Char(String.fromCharCode(key & 0xFFFF));
- } else 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;
- } else {
- 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;
- } else if (typeof val === 'boolean') {
- return val ? 1 : 0;
- } else if (typeof val === 'string') {
- return parseFloat(val);
- } else if (val instanceof Char) {
- return val.code;
- }
- }
- p['float'] = function(val) {
- if (val instanceof Array) {
- var ret = [];
- for (var i = 0; i < val.length; i++) {
- ret.push(floatScalar(val[i]));
- }
- return ret;
- } else {
- return floatScalar(val);
- }
- };
- function intScalar(val) {
- if (typeof val === 'number') {
- return val & 0xFFFFFFFF;
- } else if (typeof val === 'boolean') {
- return val ? 1 : 0;
- } else if (typeof val === 'string') {
- var number = parseInt(val, 10); // Force decimal radix. Don't convert hex or octal (just like p5)
- return number & 0xFFFFFFFF;
- } else if (val instanceof Char) {
- return val.code;
- }
- }
- p['int'] = function(val) {
- 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]));
- }
- }
- return ret;
- } else {
- return intScalar(val);
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Math functions
- ////////////////////////////////////////////////////////////////////////////
- // Calculation
- p.abs = Math.abs;
- p.ceil = Math.ceil;
- p.constrain = function(aNumber, aMin, aMax) {
- return aNumber > aMax ? aMax : aNumber < aMin ? aMin : aNumber;
- };
- 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);
- } else 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);
- }
- };
- p.exp = Math.exp;
- p.floor = Math.floor;
- p.lerp = function(value1, value2, amt) {
- return ((value2 - value1) * amt) + value1;
- };
- p.log = Math.log;
- p.mag = function(a, b, c) {
- if (arguments.length === 2) {
- return Math.sqrt(a * a + b * b);
- } else if (arguments.length === 3) {
- return Math.sqrt(a * a + b * b + c * c);
- }
- };
- p.map = function(value, istart, istop, ostart, ostop) {
- return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
- };
- p.max = function() {
- if (arguments.length === 2) {
- return arguments[0] < arguments[1] ? arguments[1] : arguments[0];
- } else {
- 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;
- }
- };
- p.min = function() {
- if (arguments.length === 2) {
- return arguments[0] < arguments[1] ? arguments[0] : arguments[1];
- } else {
- 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;
- }
- };
- p.norm = function(aNumber, low, high) {
- return (aNumber - low) / (high - low);
- };
- p.pow = Math.pow;
- p.round = Math.round;
- p.sq = function(aNumber) {
- return aNumber * aNumber;
- };
- p.sqrt = Math.sqrt;
- // Trigonometry
- p.acos = Math.acos;
- p.asin = Math.asin;
- p.atan = Math.atan;
- p.atan2 = Math.atan2;
- p.cos = Math.cos;
- p.degrees = function(aAngle) {
- return (aAngle * 180) / Math.PI;
- };
- p.radians = function(aAngle) {
- return (aAngle / 180) * Math.PI;
- };
- p.sin = Math.sin;
- p.tan = Math.tan;
- var currentRandom = Math.random;
- p.random = function random() {
- if(arguments.length === 0) {
- return currentRandom();
- } else if(arguments.length === 1) {
- return currentRandom() * arguments[0];
- } else {
- var aMin = arguments[0], aMax = arguments[1];
- return currentRandom() * (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 nextInt = function() {
- z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF;
- w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF;
- return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF;
- };
- this.nextDouble = function() {
- var i = nextInt() / 4294967296;
- return i < 0 ? 1 + i : i;
- };
- this.nextInt = nextInt;
- }
- Marsaglia.createRandomized = function() {
- var now = new Date();
- return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF);
- };
- p.randomSeed = function(seed) {
- currentRandom = (new Marsaglia(seed)).nextDouble;
- };
- // Random
- p.Random = function(seed) {
- var haveNextNextGaussian = false, nextNextGaussian, random;
- this.nextGaussian = function() {
- if (haveNextNextGaussian) {
- haveNextNextGaussian = false;
- return nextNextGaussian;
- } else {
- var v1, v2, s;
- do {
- v1 = 2 * random() - 1; // between -1.0 and 1.0
- v2 = 2 * random() - 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);
- nextNextGaussian = v2 * multiplier;
- haveNextNextGaussian = true;
- return v1 * multiplier;
- }
- };
- // by default use standard random, otherwise seeded
- random = (seed === undef) ? Math.random : (new Marsaglia(seed)).nextDouble;
- };
- // Noise functions and helpers
- function PerlinNoise(seed) {
- var rnd = seed !== undef ? new Marsaglia(seed) : Marsaglia.createRandomized();
- var i, j;
- // http://www.noisemachine.com/talk1/17b.html
- // http://mrl.nyu.edu/~perlin/noise/
- // generate permutation
- var perm = new Array(512);
- for(i=0;i<256;++i) { perm[i] = i; }
- for(i=0;i<256;++i) { var t = perm[j = rnd.nextInt() & 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};
- 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;
- };
- p.noiseDetail = function(octaves, fallout) {
- noiseProfile.octaves = octaves;
- if(fallout !== undef) {
- noiseProfile.fallout = fallout;
- }
- };
- p.noiseSeed = function(seed) {
- noiseProfile.seed = seed;
- noiseProfile.generator = undef;
- };
- // Set default background behavior for 2D and 3D contexts
- var refreshBackground = function() {
- if (curSketch.options.isOpaque) {
- if (p.use3DContext) {
- // fill background default opaque gray
- curContext.clearColor(204 / 255, 204 / 255, 204 / 255, 1.0);
- curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT);
- } else {
- // fill background default opaque gray
- curContext.fillStyle = "rgb(204, 204, 204)";
- curContext.fillRect(0, 0, p.width, p.height);
- isFillDirty = true;
- }
- }
- };
- // Changes the size of the Canvas ( this resets context properties like 'lineCap', etc.
- p.size = function size(aWidth, aHeight, aMode) {
- if (aMode && (aMode === p.WEBGL)) {
- // 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.
- if (curElement.width !== aWidth || curElement.height !== aHeight) {
- curElement.setAttribute("width", aWidth);
- curElement.setAttribute("height", aHeight);
- }
- curContext = curElement.getContext("experimental-webgl");
- p.use3DContext = true;
- } catch(e_size) {
- Processing.debug(e_size);
- }
- if (!curContext) {
- throw "OPENGL 3D context is not supported on this browser.";
- } else {
- for (var i = 0; i < p.SINCOS_LENGTH; i++) {
- sinLUT[i] = p.sin(i * (p.PI / 180) * 0.5);
- cosLUT[i] = p.cos(i * (p.PI / 180) * 0.5);
- }
- // 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);
- refreshBackground(); // sets clearColor default;
- // We declare our own constants since Minefield doesn't
- // do anything when curContext.VERTEX_PROGRAM_POINT_SIZE is used.
- curContext.enable(VERTEX_PROGRAM_POINT_SIZE);
- curContext.enable(POINT_SMOOTH);
- // Create the program objects to render 2D (points, lines) and
- // 3D (spheres, boxes) shapes. Because 2D shapes are not lit,
- // lighting calculations could be ommitted from that program object.
- programObject2D = createProgramObject(curContext, vertexShaderSource2D, fragmentShaderSource2D);
- // set the defaults
- curContext.useProgram(programObject2D);
- p.strokeWeight(1.0);
- programObject3D = createProgramObject(curContext, vertexShaderSource3D, fragmentShaderSource3D);
- programObjectUnlitShape = createProgramObject(curContext, vShaderSrcUnlitShape, fShaderSrcUnlitShape);
- // Now that the programs have been compiled, we can set the default
- // states for the lights.
- curContext.useProgram(programObject3D);
- // assume we aren't using textures by default
- uniformi(programObject3D, "usingTexture", usingTexture);
- p.lightFalloff(1, 0, 0);
- p.shininess(1);
- p.ambient(255, 255, 255);
- p.specular(0, 0, 0);
- // Create buffers for 3D primitives
- boxBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, boxBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(boxVerts), curContext.STATIC_DRAW);
- boxNormBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, boxNormBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(boxNorms), curContext.STATIC_DRAW);
- boxOutlineBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, boxOutlineBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(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, newWebGLArray(rectVerts), curContext.STATIC_DRAW);
- rectNormBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, rectNormBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(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, newWebGLArray([0, 0, 0]), curContext.STATIC_DRAW);
- textBuffer = curContext.createBuffer();
- curContext.bindBuffer(curContext.ARRAY_BUFFER, textBuffer );
- curContext.bufferData(curContext.ARRAY_BUFFER, new WebGLFloatArray([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 WebGLFloatArray([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 WebGLUnsignedShortArray([0,1,2,2,3,0]), curContext.STATIC_DRAW);
- cam = new PMatrix3D();
- cameraInv = new PMatrix3D();
- forwardTransform = new PMatrix3D();
- reverseTransform = new PMatrix3D();
- modelView = new PMatrix3D();
- modelViewInv = new PMatrix3D();
- projection = new PMatrix3D();
- p.camera();
- p.perspective();
- forwardTransform = modelView;
- reverseTransform = modelViewInv;
- userMatrixStack = 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);
- }
- p.stroke(0);
- p.fill(255);
- } else {
- if (curContext === undef) {
- // size() was called without p.init() default context, ie. p.createGraphics()
- curContext = curElement.getContext("2d");
- p.use3DContext = false;
- userMatrixStack = new PMatrixStack();
- modelView = new PMatrix2D();
- }
- }
- // 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 props = {
- fillStyle: curContext.fillStyle,
- strokeStyle: curContext.strokeStyle,
- lineCap: curContext.lineCap,
- lineJoin: curContext.lineJoin
- };
- curElement.width = p.width = aWidth || 100;
- curElement.height = p.height = aHeight || 100;
- for (var j in props) {
- if (props) {
- curContext[j] = props[j];
- }
- }
- // redraw the background if background was called before size
- refreshBackground();
- // set 5% for pixels to cache (or 1000)
- maxPixelsCached = Math.max(1000, aWidth * aHeight * 0.05);
- // Externalize the context
- p.externals.context = curContext;
- p.toImageData = function() {
- if(!p.use3DContext){
- return curContext.getImageData(0, 0, this.width, this.height);
- } else {
- var c = document.createElement("canvas");
- var ctx = c.getContext("2d");
- var obj = ctx.createImageData(this.width, this.height);
- var uBuff = curContext.readPixels(0,0,this.width,this.height,curContext.RGBA,curContext.UNSIGNED_BYTE);
- if(!uBuff){
- uBuff = new WebGLUnsignedByteArray(this.width * this.height * 4);
- curContext.readPixels(0,0,this.width,this.height,curContext.RGBA,curContext.UNSIGNED_BYTE, uBuff);
- }
- for(var i =0; i < uBuff.length; i++){
- obj.data[i] = uBuff[(this.height - 1 - Math.floor(i / 4 / this.width)) * this.width * 4 + (i % (this.width * 4))];
- }
- return obj;
- }
- };
- };
- ////////////////////////////////////////////////////////////////////////////
- // Lights
- ////////////////////////////////////////////////////////////////////////////
- p.ambientLight = function(r, g, b, x, y, z) {
- if (p.use3DContext) {
- if (lightCount === p.MAX_LIGHTS) {
- throw "can only create " + p.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);
- curContext.useProgram(programObject3D);
- uniformf(programObject3D, "lights[" + lightCount + "].color", [r / 255, g / 255, b / 255]);
- uniformf(programObject3D, "lights[" + lightCount + "].position", pos.array());
- uniformi(programObject3D, "lights[" + lightCount + "].type", 0);
- uniformi(programObject3D, "lightCount", ++lightCount);
- }
- };
- p.directionalLight = function(r, g, b, nx, ny, nz) {
- if (p.use3DContext) {
- if (lightCount === p.MAX_LIGHTS) {
- throw "can only create " + p.MAX_LIGHTS + " lights";
- }
- curContext.useProgram(programObject3D);
- // Less code than manually multiplying, but I'll fix
- // this when I have more time.
- var dir = [nx, ny, nz, 0.0000001];
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.mult(dir, dir);
- uniformf(programObject3D, "lights[" + lightCount + "].color", [r / 255, g / 255, b / 255]);
- uniformf(programObject3D, "lights[" + lightCount + "].position", [-dir[0], -dir[1], -dir[2]]);
- uniformi(programObject3D, "lights[" + lightCount + "].type", 1);
- uniformi(programObject3D, "lightCount", ++lightCount);
- }
- };
- p.lightFalloff = function lightFalloff(constant, linear, quadratic) {
- if (p.use3DContext) {
- curContext.useProgram(programObject3D);
- uniformf(programObject3D, "falloff", [constant, linear, quadratic]);
- }
- };
- p.lightSpecular = function lightSpecular(r, g, b) {
- if (p.use3DContext) {
- curContext.useProgram(programObject3D);
- uniformf(programObject3D, "specular", [r / 255, g / 255, b / 255]);
- }
- };
- /*
- Sets the default ambient light, directional light,
- falloff, and specular values. P5 Documentation says specular()
- is set, but the code calls lightSpecular().
- */
- p.lights = function lights() {
- p.ambientLight(128, 128, 128);
- p.directionalLight(128, 128, 128, 0, 0, -1);
- p.lightFalloff(1, 0, 0);
- p.lightSpecular(0, 0, 0);
- };
- p.pointLight = function(r, g, b, x, y, z) {
- if (p.use3DContext) {
- if (lightCount === p.MAX_LIGHTS) {
- throw "can only create " + p.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);
- curContext.useProgram(programObject3D);
- uniformf(programObject3D, "lights[" + lightCount + "].color", [r / 255, g / 255, b / 255]);
- uniformf(programObject3D, "lights[" + lightCount + "].position", pos.array());
- uniformi(programObject3D, "lights[" + lightCount + "].type", 2);
- uniformi(programObject3D, "lightCount", ++lightCount);
- }
- };
- /*
- Disables lighting so the all shapes drawn after this
- will not be lit.
- */
- p.noLights = function noLights() {
- if (p.use3DContext) {
- lightCount = 0;
- curContext.useProgram(programObject3D);
- uniformi(programObject3D, "lightCount", lightCount);
- }
- };
- /*
- r,g,b - Color of the light
- x,y,z - position of the light in modeling space
- nx,ny,nz - direction of the spotlight
- angle - in radians
- concentration -
- */
- p.spotLight = function spotLight(r, g, b, x, y, z, nx, ny, nz, angle, concentration) {
- if (p.use3DContext) {
- if (lightCount === p.MAX_LIGHTS) {
- throw "can only create " + p.MAX_LIGHTS + " lights";
- }
- curContext.useProgram(programObject3D);
- // 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);
- // transform the spotlight's direction
- // need to find a solution for this one. Maybe manual mult?
- var dir = [nx, ny, nz, 0.0000001];
- view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.mult(dir, dir);
- uniformf(programObject3D, "lights[" + lightCount + "].color", [r / 255, g / 255, b / 255]);
- uniformf(programObject3D, "lights[" + lightCount + "].position", pos.array());
- uniformf(programObject3D, "lights[" + lightCount + "].direction", [dir[0], dir[1], dir[2]]);
- uniformf(programObject3D, "lights[" + lightCount + "].concentration", concentration);
- uniformf(programObject3D, "lights[" + lightCount + "].angle", angle);
- uniformi(programObject3D, "lights[" + lightCount + "].type", 3);
- uniformi(programObject3D, "lightCount", ++lightCount);
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Camera functions
- ////////////////////////////////////////////////////////////////////////////
- p.beginCamera = function beginCamera() {
- if (manipulatingCamera) {
- throw ("You cannot call beginCamera() again before calling endCamera()");
- } else {
- manipulatingCamera = true;
- forwardTransform = cameraInv;
- reverseTransform = cam;
- }
- };
- p.endCamera = function endCamera() {
- if (!manipulatingCamera) {
- throw ("You cannot call endCamera() before calling beginCamera()");
- } else {
- modelView.set(cam);
- modelViewInv.set(cameraInv);
- forwardTransform = modelView;
- reverseTransform = modelViewInv;
- manipulatingCamera = false;
- }
- };
- p.camera = function camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
- if (arguments.length === 0) {
- //in case canvas is resized
- cameraX = curElement.width / 2;
- cameraY = curElement.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 p.PVector(eyeX - centerX, eyeY - centerY, eyeZ - centerZ);
- var y = new p.PVector(upX, upY, upZ);
- var transX, transY, transZ;
- z.normalize();
- var x = p.PVector.cross(y, z);
- y = p.PVector.cross(z, x);
- x.normalize();
- y.normalize();
- cam.set(x.x, x.y, x.z, 0, y.x, y.y, y.z, 0, z.x, z.y, z.z, 0, 0, 0, 0, 1);
- cam.translate(-eyeX, -eyeY, -eyeZ);
- cameraInv.reset();
- cameraInv.invApply(x.x, x.y, x.z, 0, y.x, y.y, y.z, 0, z.x, z.y, z.z, 0, 0, 0, 0, 1);
- cameraInv.translate(eyeX, eyeY, eyeZ);
- modelView.set(cam);
- modelViewInv.set(cameraInv);
- };
- p.perspective = function perspective(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 = curElement.width / curElement.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);
- };
- p.frustum = function frustum(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);
- };
- p.ortho = function ortho(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);
- frustumMode = false;
- };
- p.printProjection = function() {
- projection.print();
- };
- p.printCamera = function() {
- cam.print();
- };
- ////////////////////////////////////////////////////////////////////////////
- // Shapes
- ////////////////////////////////////////////////////////////////////////////
- p.box = function(w, h, d) {
- if (p.use3DContext) {
- // 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);
- 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();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- if (doFill === true) {
- curContext.useProgram(programObject3D);
- disableVertexAttribPointer(programObject3D, "aTexture");
- uniformMatrix(programObject3D, "model", false, model.array());
- uniformMatrix(programObject3D, "view", false, view.array());
- uniformMatrix(programObject3D, "projection", false, proj.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(programObject3D, "color", fillStyle);
- // 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();
- uniformMatrix(programObject3D, "normalTransform", false, normalMatrix.array());
- vertexAttribPointer(programObject3D, "Vertex", 3, boxBuffer);
- vertexAttribPointer(programObject3D, "Normal", 3, boxNormBuffer);
- // Ugly hack. Can't simply disable the vertex attribute
- // array. No idea why, so I'm passing in dummy data.
- vertexAttribPointer(programObject3D, "aColor", 3, boxNormBuffer);
- curContext.drawArrays(curContext.TRIANGLES, 0, boxVerts.length / 3);
- curContext.disable(curContext.POLYGON_OFFSET_FILL);
- }
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix(programObject2D, "model", false, model.array());
- uniformMatrix(programObject2D, "view", false, view.array());
- uniformMatrix(programObject2D, "projection", false, proj.array());
- uniformf(programObject2D, "color", strokeStyle);
- uniformi(programObject2D, "picktype", 0);
-
- vertexAttribPointer(programObject2D, "Vertex", 3, boxOutlineBuffer);
- disableVertexAttribPointer(programObject2D, "aTextureCoord");
-
- curContext.lineWidth(lineWidth);
- curContext.drawArrays(curContext.LINES, 0, boxOutlineVerts.length / 3);
- }
- }
- };
- 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(parseFloat(sphereX[v1]));
- sphereVerts.push(parseFloat(sphereY[v1]));
- sphereVerts.push(parseFloat(sphereZ[v1++]));
- sphereVerts.push(parseFloat(sphereX[v2]));
- sphereVerts.push(parseFloat(sphereY[v2]));
- sphereVerts.push(parseFloat(sphereZ[v2++]));
- }
- // close each ring
- v1 = v11;
- v2 = voff;
- sphereVerts.push(parseFloat(sphereX[v1]));
- sphereVerts.push(parseFloat(sphereY[v1]));
- sphereVerts.push(parseFloat(sphereZ[v1]));
- sphereVerts.push(parseFloat(sphereX[v2]));
- sphereVerts.push(parseFloat(sphereY[v2]));
- sphereVerts.push(parseFloat(sphereZ[v2]));
- }
- // add the northern cap
- for (i = 0; i < sphereDetailU; i++) {
- v2 = voff + i;
- sphereVerts.push(parseFloat(sphereX[v2]));
- sphereVerts.push(parseFloat(sphereY[v2]));
- sphereVerts.push(parseFloat(sphereZ[v2]));
- sphereVerts.push(0);
- sphereVerts.push(1);
- sphereVerts.push(0);
- }
- sphereVerts.push(parseFloat(sphereX[voff]));
- sphereVerts.push(parseFloat(sphereY[voff]));
- sphereVerts.push(parseFloat(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, newWebGLArray(sphereVerts), curContext.STATIC_DRAW);
- };
- p.sphereDetail = function sphereDetail(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 = p.SINCOS_LENGTH / ures;
- var cx = new Array(ures);
- var cz = new Array(ures);
- // calc unit circle in XZ plane
- for (i = 0; i < ures; i++) {
- cx[i] = cosLUT[parseInt((i * delta) % p.SINCOS_LENGTH, 10)];
- cz[i] = sinLUT[parseInt((i * delta) % p.SINCOS_LENGTH, 10)];
- }
- // computing vertexlist
- // vertexlist starts at south pole
- var vertCount = ures * (vres - 1) + 2;
- var currVert = 0;
- // re-init arrays to store vertices
- sphereX = new Array(vertCount);
- sphereY = new Array(vertCount);
- sphereZ = new Array(vertCount);
- var angle_step = (p.SINCOS_LENGTH * 0.5) / vres;
- var angle = angle_step;
- // step along Y axis
- for (i = 1; i < vres; i++) {
- var curradius = sinLUT[parseInt(angle % p.SINCOS_LENGTH, 10)];
- var currY = -cosLUT[parseInt(angle % p.SINCOS_LENGTH, 10)];
- 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();
- };
- p.sphere = function() {
- if (p.use3DContext) {
- var sRad = arguments[0], c;
- 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();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- if (doFill === true) {
- // 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();
- curContext.useProgram(programObject3D);
- disableVertexAttribPointer(programObject3D, "aTexture");
- uniformMatrix(programObject3D, "model", false, model.array());
- uniformMatrix(programObject3D, "view", false, view.array());
- uniformMatrix(programObject3D, "projection", false, proj.array());
- uniformMatrix(programObject3D, "normalTransform", false, normalMatrix.array());
- vertexAttribPointer(programObject3D, "Vertex", 3, sphereBuffer);
- vertexAttribPointer(programObject3D, "Normal", 3, sphereBuffer);
- // Ugly hack. Can't simply disable the vertex attribute
- // array. No idea why, so I'm passing in dummy data.
- vertexAttribPointer(programObject3D, "aColor", 3, sphereBuffer);
- // 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(programObject3D, "color", fillStyle);
- curContext.drawArrays(curContext.TRIANGLE_STRIP, 0, sphereVerts.length / 3);
- curContext.disable(curContext.POLYGON_OFFSET_FILL);
- }
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix(programObject2D, "model", false, model.array());
- uniformMatrix(programObject2D, "view", false, view.array());
- uniformMatrix(programObject2D, "projection", false, proj.array());
-
- vertexAttribPointer(programObject2D, "Vertex", 3, sphereBuffer);
- disableVertexAttribPointer(programObject2D, "aTextureCoord");
-
- uniformf(programObject2D, "color", strokeStyle);
- uniformi(programObject2D, "picktype", 0);
- curContext.lineWidth(lineWidth);
- curContext.drawArrays(curContext.LINE_STRIP, 0, sphereVerts.length / 3);
- }
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Coordinates
- ////////////////////////////////////////////////////////////////////////////
- p.modelX = function modelX(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;
- };
- p.modelY = function modelY(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;
- };
- p.modelZ = function modelZ(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
- ////////////////////////////////////////////////////////////////////////////
- p.ambient = function ambient() {
- // create an alias to shorten code
- var a = arguments;
- // either a shade of gray or a 'color' object.
- if (p.use3DContext) {
- curContext.useProgram(programObject3D);
- uniformi(programObject3D, "usingMat", true);
- if (a.length === 1) {
- // color object was passed in
- if (typeof a[0] === "string") {
- var c = a[0].slice(5, -1).split(",");
- uniformf(programObject3D, "mat_ambient", [c[0] / 255, c[1] / 255, c[2] / 255]);
- }
- // else a single number was passed in for gray shade
- else {
- uniformf(programObject3D, "mat_ambient", [a[0] / 255, a[0] / 255, a[0] / 255]);
- }
- }
- // Otherwise three values were provided (r,g,b)
- else {
- uniformf(programObject3D, "mat_ambient", [a[0] / 255, a[1] / 255, a[2] / 255]);
- }
- }
- };
- p.emissive = function emissive() {
- // create an alias to shorten code
- var a = arguments;
- if (p.use3DContext) {
- curContext.useProgram(programObject3D);
- uniformi(programObject3D, "usingMat", true);
- // If only one argument was provided, the user either gave us a
- // shade of gray or a 'color' object.
- if (a.length === 1) {
- // color object was passed in
- if (typeof a[0] === "string") {
- var c = a[0].slice(5, -1).split(",");
- uniformf(programObject3D, "mat_emissive", [c[0] / 255, c[1] / 255, c[2] / 255]);
- }
- // else a regular number was passed in for gray shade
- else {
- uniformf(programObject3D, "mat_emissive", [a[0] / 255, a[0] / 255, a[0] / 255]);
- }
- }
- // Otherwise three values were provided (r,g,b)
- else {
- uniformf(programObject3D, "mat_emissive", [a[0] / 255, a[1] / 255, a[2] / 255]);
- }
- }
- };
- p.shininess = function shininess(shine) {
- if (p.use3DContext) {
- curContext.useProgram(programObject3D);
- uniformi(programObject3D, "usingMat", true);
- uniformf(programObject3D, "shininess", shine);
- }
- };
- /*
- Documentation says the following calls are valid, but the
- Processing throws exceptions:
- specular(gray, alpha)
- specular(v1, v2, v3, alpha)
- So we don't support them either
- <corban> I dont think this matters so much, let us let color handle it. alpha values are not sent anyways.
- */
- p.specular = function specular() {
- var c = p.color.apply(this, arguments);
- if (p.use3DContext) {
- curContext.useProgram(programObject3D);
- uniformi(programObject3D, "usingMat", true);
- uniformf(programObject3D, "mat_specular", p.color.toGLArray(c).slice(0, 3));
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Coordinates
- ////////////////////////////////////////////////////////////////////////////
- p.screenX = function screenX( x, y, z ) {
- var mv = modelView.array();
- 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 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;
- };
- p.screenY = function screenY( x, y, z ) {
- var mv = modelView.array();
- 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 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;
- };
- p.screenZ = function screenZ( x, y, z ) {
- var mv = modelView.array();
- 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
- ////////////////////////////////////////////////////////////////////////////
- p.fill = function fill() {
- var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3]);
- if(color === currentFillColor && doFill) {
- return;
- }
- doFill = true;
- currentFillColor = color;
- if (p.use3DContext) {
- fillStyle = p.color.toGLArray(color);
- } else {
- isFillDirty = true;
- }
- };
- function executeContextFill() {
- if(doFill) {
- if(isFillDirty) {
- curContext.fillStyle = p.color.toString(currentFillColor);
- isFillDirty = false;
- }
- curContext.fill();
- }
- }
- p.noFill = function noFill() {
- doFill = false;
- };
- p.stroke = function stroke() {
- var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3]);
- if(color === currentStrokeColor && doStroke) {
- return;
- }
- doStroke = true;
- currentStrokeColor = color;
- if (p.use3DContext) {
- strokeStyle = p.color.toGLArray(color);
- } else {
- isStrokeDirty = true;
- }
- };
- function executeContextStroke() {
- if(doStroke) {
- if(isStrokeDirty) {
- curContext.strokeStyle = p.color.toString(currentStrokeColor);
- isStrokeDirty = false;
- }
- curContext.stroke();
- }
- }
- p.noStroke = function noStroke() {
- doStroke = false;
- };
- p.strokeWeight = function strokeWeight(w) {
- lineWidth = w;
- if (p.use3DContext) {
- curContext.useProgram(programObject2D);
- uniformf(programObject2D, "pointSize", w);
- } else {
- curContext.lineWidth = w;
- }
- };
- p.strokeCap = function strokeCap(value) {
- curContext.lineCap = value;
- };
- p.strokeJoin = function strokeJoin(value) {
- curContext.lineJoin = value;
- };
- p.smooth = function() {
- if (!p.use3DContext) {
- if ("mozImageSmoothingEnabled" in curContext) {
- curElement.style.setProperty("image-rendering", "optimizeQuality", "important");
- curContext.mozImageSmoothingEnabled = true;
- }
- }
- };
- p.noSmooth = function() {
- if (!p.use3DContext) {
- if ("mozImageSmoothingEnabled" in curContext) {
- curElement.style.setProperty("image-rendering", "optimizeQuality", "important");
- curContext.mozImageSmoothingEnabled = false;
- }
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Vector drawing functions
- ////////////////////////////////////////////////////////////////////////////
- function colorBlendWithAlpha(c1, c2, k) {
- var f = 0|(k * ((c2 & p.ALPHA_MASK) >>> 24));
- return (Math.min(((c1 & p.ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
- p.mix(c1 & p.RED_MASK, c2 & p.RED_MASK, f) & p.RED_MASK |
- p.mix(c1 & p.GREEN_MASK, c2 & p.GREEN_MASK, f) & p.GREEN_MASK |
- p.mix(c1 & p.BLUE_MASK, c2 & p.BLUE_MASK, f));
- }
- p.point = function point(x, y, z) {
- if (p.use3DContext) {
- 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();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- curContext.useProgram(programObject2D);
- uniformMatrix(programObject2D, "model", false, model.array());
- uniformMatrix(programObject2D, "view", false, view.array());
- uniformMatrix(programObject2D, "projection", false, proj.array());
- if (lineWidth > 0 && doStroke) {
- // this will be replaced with the new bit shifting color code
- uniformf(programObject2D, "color", strokeStyle);
- uniformi(programObject2D, "picktype", 0);
-
- vertexAttribPointer(programObject2D, "Vertex", 3, pointBuffer);
- disableVertexAttribPointer(programObject2D, "aTextureCoord");
-
- curContext.drawArrays(curContext.POINTS, 0, 1);
- }
- } else {
- if (doStroke) {
- // TODO if strokeWeight > 1, do circle
-
- if (curSketch.options.crispLines) {
- var alphaOfPointWeight = Math.PI / 4; // TODO dependency of strokeWeight
- var c = p.get(x, y);
- p.set(x, y, colorBlendWithAlpha(c, currentStrokeColor, alphaOfPointWeight));
- } else {
- if (lineWidth > 1){
- curContext.fillStyle = p.color.toString(currentStrokeColor);
- isFillDirty = true;
- curContext.beginPath();
- curContext.arc(x, y, lineWidth / 2, 0, p.TWO_PI, false);
- curContext.fill();
- curContext.closePath();
- } else {
- curContext.fillStyle = p.color.toString(currentStrokeColor);
- curContext.fillRect(Math.round(x), Math.round(y), 1, 1);
- isFillDirty = true;
- }
- }
- }
- }
- };
- p.beginShape = function beginShape(type) {
- curShape = type;
- curShapeCount = 0;
- curvePoints = [];
- //textureImage = null;
- vertArray = [];
- if(p.use3DContext)
- {
- //normalMode = NORMAL_MODE_AUTO;
- }
- };
- p.vertex = function vertex() {
- if(firstVert){ firstVert = false; }
- var vert = [];
- if(arguments.length === 4){ //x, y, u, v
- vert[0] = arguments[0];
- vert[1] = arguments[1];
- vert[2] = 0;
- vert[3] = arguments[2];
- vert[4] = arguments[3];
- }
- else{ // x, y, z, u, v
- vert[0] = arguments[0];
- vert[1] = arguments[1];
- vert[2] = arguments[2] || 0;
- vert[3] = arguments[3] || 0;
- vert[4] = arguments[4] || 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;
-
- vert["isVert"] = true;
- vertArray.push(vert);
-
- };
- /*
- Draw 3D points created from calls to vertex:
- beginShape(POINT);
- vertex(x, y, 0);
- ...
- endShape();
- */
- var point3D = function point3D(vArray, cArray){
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- curContext.useProgram(programObjectUnlitShape);
- uniformMatrix(programObjectUnlitShape, "uView", false, view.array());
- uniformMatrix(programObjectUnlitShape, "uProjection", false, proj.array());
- vertexAttribPointer(programObjectUnlitShape, "aVertex", 3, pointBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(vArray), curContext.STREAM_DRAW);
- vertexAttribPointer(programObjectUnlitShape, "aColor", 4, fillColorBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(cArray), curContext.STREAM_DRAW);
- curContext.drawArrays(curContext.POINTS, 0, vArray.length/3);
- };
- /*
- Draw 3D lines created from calls to beginShape/vertex/endShape
- LINES, LINE_LOOP, etc.
- */
- var line3D = function line3D(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();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- curContext.useProgram(programObjectUnlitShape);
- uniformMatrix(programObjectUnlitShape, "uView", false, view.array());
- uniformMatrix(programObjectUnlitShape, "uProjection", false, proj.array());
- vertexAttribPointer(programObjectUnlitShape, "aVertex", 3, lineBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(vArray), curContext.STREAM_DRAW);
- vertexAttribPointer(programObjectUnlitShape, "aColor", 4, strokeColorBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(cArray), curContext.STREAM_DRAW);
- curContext.lineWidth(lineWidth);
- curContext.drawArrays(ctxMode, 0, vArray.length/3);
- };
- var fill3D = function fill3D(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();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- curContext.useProgram( programObject3D );
- uniformMatrix( programObject3D, "model", false, [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] );
- uniformMatrix( programObject3D, "view", false, view.array() );
- uniformMatrix( programObject3D, "projection", false, proj.array() );
- curContext.enable( curContext.POLYGON_OFFSET_FILL );
- curContext.polygonOffset( 1, 1 );
- uniformf(programObject3D, "color", [-1,0,0,0]);
- vertexAttribPointer(programObject3D, "Vertex", 3, fillBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(vArray), curContext.STREAM_DRAW);
- vertexAttribPointer(programObject3D, "aColor", 4, fillColorBuffer);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(cArray), curContext.STREAM_DRAW);
- // No support for lights....yet
- disableVertexAttribPointer(programObject3D, "Normal");
- var i;
- if(usingTexture){
- if(curTextureMode === p.IMAGE){
- for(i = 0; i < tArray.length; i += 2){
- tArray[i] = tArray[i]/curTexture.width;
- tArray[i+1] /= curTexture.height;
- }
- }
- // hack to handle when users specifies values
- // greater than 1.0 for texture coords.
- for(i = 0; i < tArray.length; i += 2){
- if( tArray[i+0] > 1.0 ){ tArray[i+0] -= (tArray[i+0] - 1.0);}
- if( tArray[i+1] > 1.0 ){ tArray[i+1] -= (tArray[i+1] - 1.0);}
- }
- uniformi(programObject3D, "usingTexture", usingTexture);
- vertexAttribPointer(programObject3D, "aTexture", 2, shapeTexVBO);
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(tArray), curContext.STREAM_DRAW);
- }
- curContext.drawArrays( ctxMode, 0, vArray.length/3 );
- curContext.disable( curContext.POLYGON_OFFSET_FILL );
- };
- p.endShape = function endShape(close){
- var lineVertArray = [];
- var fillVertArray = [];
- var colorVertArray = [];
- var strokeVertArray = [];
- var texVertArray = [];
- firstVert = true;
- var i, j, k;
- var last = vertArray.length - 1;
- for(i = 0; i < vertArray.length; i++){
- for(j = 0; j < 3; j++){
- fillVertArray.push(vertArray[i][j]);
- }
- }
- // 5,6,7,8
- // R,G,B,A
- for(i = 0; i < vertArray.length; i++){
- for(j = 5; j < 9; j++){
- colorVertArray.push(vertArray[i][j]);
- }
- }
- // 9,10,11,12
- // R, G, B, A
- for(i = 0; i < vertArray.length; i++){
- for(j = 9; j < 13; j++){
- strokeVertArray.push(vertArray[i][j]);
- }
- }
- for(i = 0; i < vertArray.length; i++){
- texVertArray.push(vertArray[i][3]);
- texVertArray.push(vertArray[i][4]);
- }
- if(!close){
- p.CLOSE = false;
- }
- else{
- p.CLOSE = true;
- 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]);
- }
- if(isCurve && curShape === p.POLYGON || isCurve && curShape === undef){
- if(p.use3DContext){
- lineVertArray = fillVertArray;
- if(doStroke){
- line3D(lineVertArray, null, strokeVertArray);
- }
- if(doFill){
- fill3D(fillVertArray, null, colorVertArray); // fill isn't working in 3d curveVertex
- }
- }
- else{
- if(vertArray.length > 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) < vertArray.length; i++){
- b[0] = [vertArray[i][0], vertArray[i][1]];
- b[1] = [vertArray[i][0] + (s * vertArray[i+1][0] - s * vertArray[i-1][0]) / 6,
- vertArray[i][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]);
- }
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- }
- }
- else if(isBezier && curShape === p.POLYGON || isBezier && curShape === undef){
- if(p.use3DContext){
- lineVertArray = fillVertArray;
- lineVertArray.splice(lineVertArray.length - 3);
- strokeVertArray.splice(strokeVertArray.length - 4);
- if(doStroke){
- line3D(lineVertArray, null, strokeVertArray);
- }
- if(doFill){
- fill3D(fillVertArray, "TRIANGLES", colorVertArray);
- }
- // TODO: Fill not properly working yet, will fix later
- /*fillVertArray = [];
- colorVertArray = [];
- tempArray.reverse();
- for(i = 0; (i+1) < 10; i++){
- for(j = 0; j < 3; j++){
- fillVertArray.push(tempArray[i][j]);
- }
- for(j = 5; j < 9; j++){
- colorVertArray.push(tempArray[i][j]);
- }
- 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][j]);
- }
- }
- strokeVertArray = [];
- for(i = 0; i < tempArray.length/3; i++){
- strokeVertArray.push(255);
- strokeVertArray.push(0);
- strokeVertArray.push(0);
- strokeVertArray.push(255);
- }
- point3D(tempArray, strokeVertArray);*/
- }
- else{
- curContext.beginPath();
- for(i = 0; i < vertArray.length; i++){
- if( vertArray[i]["isVert"] === true ){ //if it is a vertex move to the position
- if ( vertArray[i]["moveTo"] === true) {
- curContext.moveTo(vertArray[i][0], vertArray[i][1]);
- } else if (vertArray[i]["moveTo"] === false){
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- } else {
- curContext.moveTo(vertArray[i][0], vertArray[i][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]);
- }
- }
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- }
- else{
- if(p.use3DContext){ // 3D context
- if (curShape === p.POINTS){
- for(i = 0; i < vertArray.length; i++){
- for(j = 0; j < 3; j++){
- lineVertArray.push(vertArray[i][j]);
- }
- }
- point3D(lineVertArray, strokeVertArray);
- }
- else if(curShape === p.LINES){
- for(i = 0; i < vertArray.length; i++){
- for(j = 0; j < 3; j++){
- lineVertArray.push(vertArray[i][j]);
- }
- }
- for(i = 0; i < vertArray.length; i++){
- for(j = 5; j < 9; j++){
- colorVertArray.push(vertArray[i][j]);
- }
- }
- line3D(lineVertArray, "LINES", strokeVertArray);
- }
- else if(curShape === p.TRIANGLES){
- if(vertArray.length > 2){
- for(i = 0; (i+2) < vertArray.length; i+=3){
- fillVertArray = [];
- texVertArray = [];
- lineVertArray = [];
- colorVertArray = [];
- strokeVertArray = [];
- 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++){
- colorVertArray.push(vertArray[i+j][k]);
- strokeVertArray.push(vertArray[i+j][k+4]);
- }
- }
- if(doStroke){
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray );
- }
- if(doFill || usingTexture){
- fill3D(fillVertArray, "TRIANGLES", colorVertArray, texVertArray);
- }
- }
- }
- }
- else if(curShape === p.TRIANGLE_STRIP){
- if(vertArray.length > 2){
- for(i = 0; (i+2) < vertArray.length; 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 === p.TRIANGLE_FAN){
- if(vertArray.length > 2){
- for(i = 0; i < 3; i++){
- for(j = 0; j < 3; j++){
- lineVertArray.push(vertArray[i][j]);
- }
- }
- for(i = 0; i < 3; i++){
- for(j = 9; j < 13; j++){
- strokeVertArray.push(vertArray[i][j]);
- }
- }
- if(doStroke){
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray);
- }
- for(i = 2; (i+1) < vertArray.length; 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 === p.QUADS){
- for(i = 0; (i + 3) < vertArray.length; i+=4){
- lineVertArray = [];
- for(j = 0; j < 4; j++){
- for(k = 0; k < 3; k++){
- lineVertArray.push(vertArray[i+j][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 === p.QUAD_STRIP){
- var tempArray = [];
- if(vertArray.length > 3){
- for(i = 0; i < 2; i++){
- for(j = 0; j < 3; j++){
- lineVertArray.push(vertArray[i][j]);
- }
- }
- for(i = 0; i < 2; i++){
- for(j = 9; j < 13; j++){
- strokeVertArray.push(vertArray[i][j]);
- }
- }
- line3D(lineVertArray, "LINE_STRIP", strokeVertArray);
- if(vertArray.length > 4 && vertArray.length % 2 > 0){
- tempArray = fillVertArray.splice(fillVertArray.length - 3);
- vertArray.pop();
- }
- for(i = 0; (i+3) < vertArray.length; 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(vertArray.length === 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 < vertArray.length; i++){
- for(j = 0; j < 3; j++){
- lineVertArray.push(vertArray[i][j]);
- }
- for(j = 5; j < 9; j++){
- strokeVertArray.push(vertArray[i][j]);
- }
- }
- if(p.CLOSE){
- line3D(lineVertArray, "LINE_LOOP", strokeVertArray);
- }
- else{
- 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(programObject3D, "usingTexture", usingTexture);
- }
- // 2D context
- else{
- if (curShape === p.POINTS){
- for(i = 0; i < vertArray.length; i++){
- p.point(vertArray[i][0], vertArray[i][1]);
- }
- }
- else if(curShape === p.LINES){
- for(i = 0; (i + 1) < vertArray.length; i+=2){
- p.line(vertArray[i][0], vertArray[i][1], vertArray[i+1][0], vertArray[i+1][1]);
- }
- }
- else if(curShape === p.TRIANGLES){
- for(i = 0; (i + 2) < vertArray.length; i+=3){
- curContext.beginPath();
- curContext.moveTo(vertArray[i][0], vertArray[i][1]);
- curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]);
- curContext.lineTo(vertArray[i+2][0], vertArray[i+2][1]);
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- }
- else if(curShape === p.TRIANGLE_STRIP){
- if(vertArray.length > 2){
- curContext.beginPath();
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- curContext.lineTo(vertArray[1][0], vertArray[1][1]);
- for(i = 2; i < vertArray.length; i++){
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- curContext.lineTo(vertArray[i-2][0], vertArray[i-2][1]);
- executeContextFill();
- executeContextStroke();
- curContext.moveTo(vertArray[i][0],vertArray[i][1]);
- }
- curContext.closePath();
- }
- }
- else if(curShape === p.TRIANGLE_FAN){
- if(vertArray.length > 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]);
- executeContextFill();
- executeContextStroke();
- for(i = 3; i < vertArray.length; i++){
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- curContext.lineTo(vertArray[i-1][0], vertArray[i-1][1]);
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- executeContextFill();
- executeContextStroke();
- }
- curContext.closePath();
- }
- }
- else if(curShape === p.QUADS){
- for(i = 0; (i + 3) < vertArray.length; i+=4){
- curContext.beginPath();
- curContext.moveTo(vertArray[i][0], vertArray[i][1]);
- for(j = 1; j < 4; j++){
- curContext.lineTo(vertArray[i+j][0], vertArray[i+j][1]);
- }
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- }
- else if(curShape === p.QUAD_STRIP){
- if(vertArray.length > 3){
- curContext.beginPath();
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- curContext.lineTo(vertArray[1][0], vertArray[1][1]);
- for(i = 2; (i+1) < vertArray.length; i++){
- if((i % 2) === 0){
- curContext.moveTo(vertArray[i-2][0], vertArray[i-2][1]);
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- curContext.lineTo(vertArray[i+1][0], vertArray[i+1][1]);
- curContext.lineTo(vertArray[i-1][0], vertArray[i-1][1]);
- executeContextFill();
- executeContextStroke();
- }
- }
- curContext.closePath();
- }
- }
- else{
- curContext.beginPath();
- curContext.moveTo(vertArray[0][0], vertArray[0][1]);
- for(i = 1; i < vertArray.length; i++){
- curContext.lineTo(vertArray[i][0], vertArray[i][1]);
- }
- if(p.CLOSE){
- curContext.lineTo(vertArray[0][0], vertArray[0][1]);
- }
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- }
- }
- isCurve = false;
- isBezier = false;
- curveVertArray = [];
- curveVertCount = 0;
- };
- //used by both curveDetail and bezierDetail
- 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);
- };
- //internal curveInit
- //used by curveDetail, 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).toFixed(2), ((s + 3) / 2).toFixed(2),
- ((-3 - s) / 2).toFixed(2), ((1 - s) / 2).toFixed(2),
- (1 - s), ((-5 - s) / 2).toFixed(2), (s + 2), ((s - 1) / 2).toFixed(2),
- ((s - 1) / 2).toFixed(2), 0, ((1 - s) / 2).toFixed(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);
- };
- p.bezierVertex = function bezierVertex() {
- isBezier = true;
- var vert = [];
- if (firstVert) {
- throw ("vertex() must be used at least once before calling bezierVertex()");
- } else {
- if (arguments.length === 9) {
- if (p.use3DContext) {
- 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]);
- }
- } else {
- for (var i = 0; i < arguments.length; i++) {
- vert[i] = arguments[i];
- }
- vertArray.push(vert);
- vertArray[vertArray.length -1]["isVert"] = false;
- }
- }
- };
- p.texture = function(pimage){
- if(!pimage.__texture)
- {
- var texture = curContext.createTexture();
- pimage.__texture = texture;
- var cvs = document.createElement('canvas');
- cvs.width = pimage.width;
- cvs.height = pimage.height;
- var ctx = cvs.getContext('2d');
- var textureImage = ctx.createImageData(cvs.width, cvs.height);
- var imgData = pimage.toImageData();
- for (var i = 0; i < cvs.width; i += 1) {
- for (var j = 0; j < cvs.height; j += 1) {
- var index = (j * cvs.width + i) * 4;
- textureImage.data[index + 0] = imgData.data[index + 0];
- textureImage.data[index + 1] = imgData.data[index + 1];
- textureImage.data[index + 2] = imgData.data[index + 2];
- textureImage.data[index + 3] = 255;
- }
- }
- ctx.putImageData(textureImage, 0, 0);
- pimage.__cvs = cvs;
- curContext.bindTexture(curContext.TEXTURE_2D, pimage.__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, pimage.__cvs, false);
- curContext.generateMipmap(curContext.TEXTURE_2D);
- }
- else{
- curContext.bindTexture(curContext.TEXTURE_2D, pimage.__texture);
- }
- curTexture.width = pimage.width;
- curTexture.height = pimage.height;
- usingTexture = true;
- curContext.useProgram(programObject3D);
- uniformi(programObject3D, "usingTexture", usingTexture);
- };
- p.textureMode = function(mode){
- curTextureMode = mode;
- };
- 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);
- }
- };
- p.curveVertex = function(x, y, z) {
- isCurve = true;
- if(p.use3DContext){
- 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] );
- }
- }
- else{
- p.vertex(x, y, z);
- }
- };
- p.curve = function curve() {
- if (arguments.length === 8) // curve(x1, y1, x2, y2, x3, y3, x4, y4)
- {
- p.beginShape();
- p.curveVertex(arguments[0], arguments[1]);
- p.curveVertex(arguments[2], arguments[3]);
- p.curveVertex(arguments[4], arguments[5]);
- p.curveVertex(arguments[6], arguments[7]);
- p.endShape();
- } else { // curve( x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
- if (p.use3DContext) {
- p.beginShape();
- p.curveVertex(arguments[0], arguments[1], arguments[2]);
- p.curveVertex(arguments[3], arguments[4], arguments[5]);
- p.curveVertex(arguments[6], arguments[7], arguments[8]);
- p.curveVertex(arguments[9], arguments[10], arguments[11]);
- p.endShape();
- }
- }
- };
- p.curveTightness = function(tightness) {
- curTightness = tightness;
- };
- p.curveDetail = function curveDetail( detail ) {
- curveDet = detail;
- curveInit();
- };
- p.rectMode = function rectMode(aRectMode) {
- curRectMode = aRectMode;
- };
- p.imageMode = function(mode) {
- switch (mode) {
- case p.CORNER:
- imageModeConvert = imageModeCorner;
- break;
- case p.CORNERS:
- imageModeConvert = imageModeCorners;
- break;
- case p.CENTER:
- imageModeConvert = imageModeCenter;
- break;
- default:
- throw "Invalid imageMode";
- }
- };
- p.ellipseMode = function ellipseMode(aEllipseMode) {
- curEllipseMode = aEllipseMode;
- };
- p.arc = function arc(x, y, width, height, start, stop) {
- if (width <= 0) {
- return;
- }
- if (curEllipseMode === p.CORNER) {
- x += width / 2;
- y += height / 2;
- }
- curContext.moveTo(x, y);
- curContext.beginPath();
- curContext.arc(x, y, curEllipseMode === p.CENTER_RADIUS ? width : width / 2, start, stop, false);
- executeContextStroke();
- curContext.lineTo(x, y);
- executeContextFill();
- curContext.closePath();
- };
- p.line = function line() {
- var x1, y1, z1, x2, y2, z2;
- if (p.use3DContext) {
- if (arguments.length === 6) {
- x1 = arguments[0];
- y1 = arguments[1];
- z1 = arguments[2];
- x2 = arguments[3];
- y2 = arguments[4];
- z2 = arguments[5];
- } else if (arguments.length === 4) {
- x1 = arguments[0];
- y1 = arguments[1];
- z1 = 0;
- x2 = arguments[2];
- y2 = arguments[3];
- z2 = 0;
- }
- var lineVerts = [x1, y1, z1, x2, y2, z2];
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- view.transpose();
- var proj = new PMatrix3D();
- proj.set(projection);
- proj.transpose();
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix(programObject2D, "model", false, [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
- uniformMatrix(programObject2D, "view", false, view.array());
- uniformMatrix(programObject2D, "projection", false, proj.array());
-
- uniformf(programObject2D, "color", strokeStyle);
- uniformi(programObject2D, "picktype", 0);
-
- curContext.lineWidth(lineWidth);
-
- vertexAttribPointer(programObject2D, "Vertex", 3, lineBuffer);
- disableVertexAttribPointer(programObject2D, "aTextureCoord");
-
- curContext.bufferData(curContext.ARRAY_BUFFER, newWebGLArray(lineVerts), curContext.STREAM_DRAW);
- curContext.drawArrays(curContext.LINES, 0, 2);
- }
- } else {
- x1 = arguments[0];
- y1 = arguments[1];
- x2 = arguments[2];
- y2 = arguments[3];
- // if line is parallel to axis and lineWidth is less than 1px, trying to do it "crisp"
- if ((x1 === x2 || y1 === y2) && lineWidth <= 1.0 && doStroke && curSketch.options.crispLines) {
- var temp;
- if(x1 === x2) {
- if(y1 > y2) { temp = y1; y1 = y2; y2 = temp; }
- for(var y=y1;y<=y2;++y) {
- p.set(x1, y, currentStrokeColor);
- }
- } else {
- if(x1 > x2) { temp = x1; x1 = x2; x2 = temp; }
- for(var x=x1;x<=x2;++x) {
- p.set(x, y1, currentStrokeColor);
- }
- }
- return;
- }
- if (doStroke) {
- curContext.beginPath();
- curContext.moveTo(x1 || 0, y1 || 0);
- curContext.lineTo(x2 || 0, y2 || 0);
- executeContextStroke();
- curContext.closePath();
- }
- }
- };
- p.bezier = function bezier() {
- if( arguments.length === 8 && !p.use3DContext ){
- p.beginShape();
- p.vertex( arguments[0], arguments[1] );
- p.bezierVertex( arguments[2], arguments[3],
- arguments[4], arguments[5],
- arguments[6], arguments[7] );
- p.endShape();
- }
- else if( arguments.length === 12 && p.use3DContext ){
- 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();
- }
- else {
- throw("Please use the proper parameters!");
- }
- };
- p.bezierDetail = function bezierDetail( detail ){
- bezDetail = detail;
- };
- p.bezierPoint = function bezierPoint(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;
- };
- p.bezierTangent = function bezierTangent(a, b, c, d, t) {
- return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
- };
- p.curvePoint = function curvePoint(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);
- };
- p.curveTangent = function curveTangent(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);
- };
- p.triangle = function triangle(x1, y1, x2, y2, x3, y3) {
- p.beginShape(p.TRIANGLES);
- p.vertex(x1, y1, 0);
- p.vertex(x2, y2, 0);
- p.vertex(x3, y3, 0);
- p.endShape();
- };
- p.quad = function quad(x1, y1, x2, y2, x3, y3, x4, y4) {
- p.beginShape(p.QUADS);
- p.vertex(x1, y1, 0);
- p.vertex(x2, y2, 0);
- p.vertex(x3, y3, 0);
- p.vertex(x4, y4, 0);
- p.endShape();
- };
- p.rect = function rect(x, y, width, height) {
- if (p.use3DContext) {
- // Modeling transformation
- var model = new PMatrix3D();
- model.translate(x, y, 0);
- model.scale(width, height, 1);
- // 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());
- if (lineWidth > 0 && doStroke) {
- curContext.useProgram(programObject2D);
- uniformMatrix(programObject2D, "model", true, model.array());
- uniformMatrix(programObject2D, "view", true, view.array());
- uniformMatrix(programObject2D, "projection", true, projection.array());
-
- uniformf(programObject2D, "color", strokeStyle);
- uniformi(programObject2D, "picktype", 0);
-
- vertexAttribPointer(programObject2D, "Vertex", 3, rectBuffer);
- disableVertexAttribPointer(programObject2D, "aTextureCoord");
-
- curContext.lineWidth(lineWidth);
- curContext.drawArrays(curContext.LINE_LOOP, 0, rectVerts.length / 3);
- }
- if (doFill) {
- curContext.useProgram(programObject3D);
- uniformMatrix(programObject3D, "model", true, model.array());
- uniformMatrix(programObject3D, "view", true, view.array());
- uniformMatrix(programObject3D, "projection", true, projection.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(programObject3D, "color", fillStyle);
- 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();
- uniformMatrix(programObject3D, "normalTransform", false, normalMatrix.array());
- vertexAttribPointer(programObject3D, "Vertex", 3, rectBuffer);
- vertexAttribPointer(programObject3D, "Normal", 3, rectNormBuffer);
- curContext.drawArrays(curContext.TRIANGLE_FAN, 0, rectVerts.length / 3);
- curContext.disable(curContext.POLYGON_OFFSET_FILL);
- }
- }
- else{
- if (!width && !height) {
- return;
- }
- // if only stroke is enabled, do it "crisp"
- if (doStroke && !doFill && lineWidth <= 1.0 && curSketch.options.crispLines) {
- var i, x2 = x + width - 1, y2 = y + height - 1;
- for(i=0;i<width;++i) {
- p.set(x + i, y, currentStrokeColor);
- p.set(x + i, y2, currentStrokeColor);
- }
- for(i=0;i<height;++i) {
- p.set(x, y + i, currentStrokeColor);
- p.set(x2, y + i, currentStrokeColor);
- }
- return;
- }
- curContext.beginPath();
- var offsetStart = 0;
- var offsetEnd = 0;
- if (curRectMode === p.CORNERS) {
- width -= x;
- height -= y;
- }
- if (curRectMode === p.RADIUS) {
- width *= 2;
- height *= 2;
- }
- if (curRectMode === p.CENTER || curRectMode === p.RADIUS) {
- x -= width / 2;
- y -= height / 2;
- }
- curContext.rect(
- Math.round(x) - offsetStart, Math.round(y) - offsetStart, Math.round(width) + offsetEnd, Math.round(height) + offsetEnd);
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- };
- p.ellipse = function ellipse(x, y, width, height) {
- x = x || 0;
- y = y || 0;
- if (width <= 0 && height <= 0) {
- return;
- }
- if (curEllipseMode === p.RADIUS) {
- width *= 2;
- height *= 2;
- }
- if (curEllipseMode === p.CORNERS) {
- width = width - x;
- height = height - y;
- }
- if (curEllipseMode === p.CORNER || curEllipseMode === p.CORNERS) {
- x += width / 2;
- y += height / 2;
- }
- var offsetStart = 0;
- // Shortcut for drawing a 2D circle
- if ((!p.use3DContext) && (width === height)) {
- curContext.beginPath();
- curContext.arc(x - offsetStart, y - offsetStart, width / 2, 0, p.TWO_PI, false);
- executeContextFill();
- executeContextStroke();
- curContext.closePath();
- }
- else {
- var w = width / 2,
- h = height / 2,
- C = 0.5522847498307933;
- var c_x = C * w,
- c_y = C * h;
- if(!p.use3DContext){
- // TODO: Audit
- 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();
- }
- else{
- 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();
- //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);
- }
- }
- };
- p.normal = function normal(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 === p.NORMAL_MODE_AUTO) {
- normalMode = p.NORMAL_MODE_SHAPE;
- } else if (normalMode === p.NORMAL_MODE_SHAPE) {
- normalMode = p.NORMAL_MODE_VERTEX;
- }
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Raster drawing functions
- ////////////////////////////////////////////////////////////////////////////
- p.save = function save(file, img) {
- // file is unused at the moment
- // may implement this differently in later release
- if (img !== undef) {
- return window.open(img.toDataURL(),"_blank");
- } else {
- return window.open(p.externals.canvas.toDataURL(),"_blank");
- }
- };
- 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;
- }
- var PImage = function PImage(aWidth, aHeight, aFormat) {
- this.get = function(x, y, w, h) {
- if (!arguments.length) {
- return p.get(this);
- } else if (arguments.length === 2) {
- return p.get(x, y, this);
- } else if (arguments.length === 4) {
- return p.get(x, y, w, h, this);
- }
- };
- this.set = function(x, y, c) {
- p.set(x, y, c, this);
- };
- this.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);
- }
- };
- this.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, p.REPLACE, this);
- } else if (arguments.length === 9) {
- p.blend(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight, p.REPLACE, this);
- }
- };
- this.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);
- }
- };
- this.save = function(file){
- p.save(file,this);
- };
- this.resize = function(w, h) {
- if (this.width !== 0 || this.height !== 0) {
- // make aspect ratio if w or h is 0
- if (w === 0 && h !== 0) {
- w = this.width / this.height * h;
- } else if (h === 0 && w !== 0) {
- h = w / (this.width / this.height);
- }
- // 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);
- }
- };
- this.mask = function(mask) {
- this._mask = undef;
- if (mask instanceof PImage) {
- if (mask.width === this.width && mask.height === this.height) {
- this._mask = mask;
- } else {
- throw "mask must have the same dimensions as PImage.";
- }
- } else if (typeof mask === "object" && mask.constructor === Array) { // this is a pixel array
- // mask pixel array needs to be the same length as this.pixels
- // how do we update this for 0.9 this.imageData holding pixels ^^
- // mask.constructor ? and this.pixels.length = this.imageData.data.length instead ?
- if (this.pixels.length === mask.length) {
- this._mask = mask;
- } else {
- throw "mask array must be the same length as PImage pixels array.";
- }
- }
- };
- // handle the sketch code for pixels[] and pixels.length
- // parser code converts pixels[] to getPixels()
- // or setPixels(), .length becomes getLength()
- this.pixels = {
- getLength: (function(aImg) {
- return function() {
- return aImg.imageData.data.length ? aImg.imageData.data.length/4 : 0;
- };
- }(this)),
- getPixel: (function(aImg) {
- return function(i) {
- var offset = i*4;
- return p.color.toInt(aImg.imageData.data[offset], aImg.imageData.data[offset+1],
- aImg.imageData.data[offset+2], aImg.imageData.data[offset+3]);
- };
- }(this)),
- setPixel: (function(aImg) {
- return function(i,c) {
- var offset = i*4;
- aImg.imageData.data[offset] = (c & p.RED_MASK) >>> 16;
- aImg.imageData.data[offset+1] = (c & p.GREEN_MASK) >>> 8;
- aImg.imageData.data[offset+2] = (c & p.BLUE_MASK);
- aImg.imageData.data[offset+3] = (c & p.ALPHA_MASK) >>> 24;
- };
- }(this)),
- set: function(arr) {
- for (var i = 0, aL = arr.length; i < aL; i++) {
- this.setPixel(i, arr[i]);
- }
- }
- };
- // These are intentionally left blank for PImages, we work live with pixels and draw as necessary
- this.loadPixels = function() {};
- this.updatePixels = function() {};
- this.toImageData = function() {
- if (this.isRemote) { // Remote images cannot access imageData, send source image instead
- return this.sourceImg;
- } else {
- var canvasData = getCanvasData(this.imageData);
- return canvasData.context.getImageData(0, 0, this.width, this.height);
- }
- };
- this.toDataURL = function() {
- var canvasData = getCanvasData(this.imageData);
- return canvasData.canvas.toDataURL();
- };
- this.fromImageData = function(canvasImg) {
- this.width = canvasImg.width;
- this.height = canvasImg.height;
- this.imageData = canvasImg;
- // changed for 0.9
- this.format = p.ARGB;
- };
- this.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;
- };
- if (arguments.length === 1) {
- // convert an <img> to a PImage
- this.fromHTMLImageData(arguments[0]);
- } else if (arguments.length === 2 || arguments.length === 3) {
- this.width = aWidth || 1;
- this.height = aHeight || 1;
- // changed for 0.9
- this.imageData = curContext.createImageData(this.width, this.height);
- this.format = (aFormat === p.ARGB || aFormat === p.ALPHA) ? aFormat : p.RGB;
- } else {
- this.width = 0;
- this.height = 0;
- this.imageData = curContext.createImageData(1, 1);
- this.format = p.ARGB;
- }
- };
- p.PImage = PImage;
- try {
- // Opera createImageData fix
- if (! ("createImageData" in CanvasRenderingContext2D.prototype)) {
- CanvasRenderingContext2D.prototype.createImageData = function(sw, sh) {
- return this.getImageData(0, 0, sw, sh);
- };
- }
- } catch(e) {}
- p.createImage = function createImage(w, h, mode) {
- // changed for 0.9
- return new PImage(w,h,mode);
- };
- // Loads an image for display. Type is an extension. Callback is fired on load.
- p.loadImage = function loadImage(file, type, callback) {
- // if type is specified add it with a . to file to make the filename
- if (type) {
- file = file + "." + type;
- }
- // if image is in the preloader cache return a new PImage
- if (curSketch.imageCache.images[file]) {
- return new PImage(curSketch.imageCache.images[file]);
- }
- // else aysnc load it
- else {
- var pimg = new PImage(0, 0, p.ARGB);
- 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
- p.requestImage = p.loadImage;
- function get$0() {
- //return a PImage of curContext
- var c = new PImage(p.width, p.height, p.RGB);
- c.fromImageData(curContext.getImageData(0, 0, p.width, p.height));
- return c;
- }
- function get$2(x,y) {
- var data;
- // return the color at x,y (int) of curContext
- // create a PImage object of size 1x1 and return the int of the pixels array element 0
- if (x < p.width && x >= 0 && y >= 0 && y < p.height) {
- if(isContextReplaced) {
- var offset = ((0|x) + p.width * (0|y))*4;
- data = p.imageData.data;
- return p.color.toInt(data[offset], data[offset+1],
- data[offset+2], data[offset+3]);
- }
- // x,y is inside canvas space
- data = curContext.getImageData(0|x, 0|y, 1, 1).data;
- // changed for 0.9
- return p.color.toInt(data[0], data[1], data[2], data[3]);
- } else {
- // x,y is outside image return transparent black
- return 0;
- }
- }
- function get$3(x,y,img) {
- // PImage.get(x,y) was called, return the color (int) at x,y of img
- // changed in 0.9
- var offset = y * img.width * 4 + (x * 4);
- return p.color.toInt(img.imageData.data[offset],
- img.imageData.data[offset + 1],
- img.imageData.data[offset + 2],
- img.imageData.data[offset + 3]);
- }
- 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, p.RGB);
- c.fromImageData(curContext.getImageData(x, y, w, h));
- return c;
- }
- function get$5(x, y, w, h, img) {
- // PImage.get(x,y,w,h) was called, return x,y,w,h PImage of img
- // changed for 0.9, offset start point needs to be *4
- var start = y * img.width * 4 + (x*4);
- var end = (y + h) * img.width * 4 + ((x + w) * 4);
- var c = new PImage(w, h, p.RGB);
- for (var i = start, j = 0; i < end; i++, j++) {
- // changed in 0.9
- c.imageData.data[j] = img.imageData.data[i];
- if ((j+1) % (w*4) === 0) {
- //completed one line, increment i by offset
- i += (img.width - w) * 4;
- }
- }
- return c;
- }
- // Gets a single pixel or block of pixels from the current Canvas Context or a PImage
- p.get = function get(x, y, w, h, img) {
- // for 0 2 and 4 arguments use curContext, otherwise PImage.get was called
- if (arguments.length === 2) {
- return get$2(x, y);
- } else if (arguments.length === 0) {
- return get$0();
- } else if (arguments.length === 5) {
- return get$5(x, y, w, h, img);
- } else if (arguments.length === 4) {
- return get$4(x, y, w, h);
- } else if (arguments.length === 3) {
- return get$3(x, y, w);
- } else if (arguments.length === 1) {
- // PImage.get() was called, return the PImage
- return x;
- }
- };
- // Creates a new Processing instance and passes it back for... processing
- p.createGraphics = function createGraphics(w, h, render) {
- var canvas = document.createElement("canvas");
- var pg = new Processing(canvas);
- pg.size(w, h, render);
- pg.canvas = canvas;
- //Processing.addInstance(pg); // TODO: this function does not exist in this scope
- 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;
- }
- newContext.__defineGetter__(name, getter);
- newContext.__defineSetter__(name, 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) {
- 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
- p.set = function set(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) {
- 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()
- p.pixels = {
- getLength: function() { return p.imageData.data.length ? p.imageData.data.length/4 : 0; },
- getPixel: function(i) {
- var offset = i*4;
- return (p.imageData.data[offset+3] << 24) & 0xff000000 |
- (p.imageData.data[offset+0] << 16) & 0x00ff0000 |
- (p.imageData.data[offset+1] << 8) & 0x0000ff00 |
- p.imageData.data[offset+2] & 0x000000ff;
- },
- setPixel: function(i,c) {
- var offset = i*4;
- p.imageData.data[offset+0] = (c & 0x00ff0000) >>> 16; // RED_MASK
- p.imageData.data[offset+1] = (c & 0x0000ff00) >>> 8; // GREEN_MASK
- p.imageData.data[offset+2] = (c & 0x000000ff); // BLUE_MASK
- p.imageData.data[offset+3] = (c & 0xff000000) >>> 24; // ALPHA_MASK
- },
- 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
- p.loadPixels = function() {
- // changed in 0.9
- p.imageData = curContext.getImageData(0, 0, p.width, p.height);
- };
- // Draws a 1-Dimensional pixel array to Canvas
- p.updatePixels = function() {
- // changed in 0.9
- if (p.imageData) {
- curContext.putImageData(p.imageData, 0, 0);
- }
- };
-
- p.hint = function hint(which) {
- if (which === p.DISABLE_DEPTH_TEST) {
- curContext.disable(curContext.DEPTH_TEST);
- curContext.depthMask(false);
- curContext.clear(curContext.DEPTH_BUFFER_BIT);
- }
- else if (which === p.ENABLE_DEPTH_TEST) {
- curContext.enable(curContext.DEPTH_TEST);
- curContext.depthMask(true);
- }
- };
- // Draw an image or a color to the background
- p.background = function background() {
- var color, a, img;
- // background params are either a color or a PImage
- if (typeof arguments[0] === 'number') {
- color = p.color.apply(this, arguments);
- // override alpha value, processing ignores the alpha for background color
- if (curSketch.options.isOpaque) {
- color = color | p.ALPHA_MASK;
- }
- } else if (arguments.length === 1 && arguments[0] instanceof PImage) {
- img = arguments[0];
- if (!img.pixels || img.width !== p.width || img.height !== p.height) {
- throw "Background image must be the same dimensions as the canvas.";
- }
- } else {
- throw "Incorrect background parameters.";
- }
- if (p.use3DContext) {
- if (color !== undef) {
- var c = p.color.toGLArray(color);
- refreshBackground = function() {
- curContext.clearColor(c[0], c[1], c[2], c[3]);
- curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT);
- };
- } else {
- // Handle image background for 3d context. not done yet.
- refreshBackground = function() {};
- }
- } else { // 2d context
- if (color !== undef) {
- refreshBackground = function() {
- curContext.fillStyle = p.color.toString(color);
- curContext.fillRect(0, 0, p.width, p.height);
- isFillDirty = true;
- };
- } else {
- refreshBackground = function() {
- p.image(img, 0, 0);
- };
- }
- }
- refreshBackground();
- };
- // Draws an image to the Canvas
- p.image = function image(img, x, y, w, h) {
- if (img.width > 0) {
- var bounds = imageModeConvert(x || 0, y || 0, w || img.width, h || img.height, arguments.length < 4);
- var obj = img.toImageData();
- if (img._mask) {
- var j, size;
- if (img._mask instanceof PImage) {
- var objMask = img._mask.toImageData();
- for (j = 2, size = img.width * img.height * 4; j < size; j += 4) {
- // using it as an alpha channel
- obj.data[j + 1] = objMask.data[j];
- // but only the blue color channel
- }
- } else {
- for (j = 0, size = img._mask.length; j < size; ++j) {
- obj.data[(j << 2) + 3] = img._mask[j];
- }
- }
- }
- // draw the image
- curTint(obj);
- curContext.drawImage(getCanvasData(obj).canvas, 0, 0, img.width, img.height,
- bounds.x, bounds.y, bounds.w, bounds.h);
- }
- };
- // Clears a rectangle in the Canvas element or the whole Canvas
- p.clear = function clear(x, y, width, height) {
- if (arguments.length === 0) {
- curContext.clearRect(0, 0, p.width, p.height);
- } else {
- curContext.clearRect(x, y, width, height);
- }
- };
- p.tint = function tint() {
- var tintColor = p.color.apply(this, arguments);
- 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;
- }
- };
- };
- p.noTint = function noTint() {
- curTint = function() {};
- };
- p.copy = function copy(src, sx, sy, sw, sh, dx, dy, dw, dh) {
- if (arguments.length === 8) {
- // 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, p.REPLACE);
- };
- p.blend = function blend(src, sx, sy, sw, sh, dx, dy, dw, dh, mode, pimgdest) {
- if (arguments.length === 9) {
- // 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;
- var sy2 = sy + sh;
- var dx2 = dx + dw;
- var dy2 = dy + dh;
- var dest;
- // check if pimgdest is there and pixels, if so this was a call from pimg.blend
- if (arguments.length === 10 || arguments.length === 9) {
- p.loadPixels();
- dest = p;
- } else if (arguments.length === 11 && pimgdest && pimgdest.imageData) {
- dest = pimgdest;
- }
- if (src === p) {
- if (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 {
- // same as below, except skip the loadPixels() because it'd be redundant
- p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode);
- }
- } else {
- src.loadPixels();
- p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode);
- }
- if (arguments.length === 10) {
- p.updatePixels();
- }
- };
- // helper function for filter()
- var buildBlurKernel = function buildBlurKernel(r) {
- var radius = p.floor(r * 3.5), i, radiusi;
- 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 Array(p.shared.blurKernelSize);
- // init blurKernel
- for (i = 0; i < p.shared.blurKernelSize; i++) {
- p.shared.blurKernel[i] = 0;
- }
- for (i = 1, radiusi = radius - 1; i < radius; i++) {
- p.shared.blurKernel[radius+i] = p.shared.blurKernel[radiusi] = radiusi * radiusi;
- }
- p.shared.blurKernel[radius] = radius * radius;
- }
- };
- var blurARGB = function blurARGB(r, aImg) {
- var sum, cr, cg, cb, ca, c, m;
- var read, ri, ym, ymi, bk0;
- var wh = aImg.pixels.getLength();
- var r2 = new Array(wh);
- var g2 = new Array(wh);
- var b2 = new Array(wh);
- var a2 = new Array(wh);
- var yi = 0;
- var x, y, i;
- buildBlurKernel(r);
- for (y = 0; y < aImg.height; y++) {
- for (x = 0; x < aImg.width; x++) {
- cb = cg = cr = ca = sum = 0;
- read = x - p.shared.blurRadius;
- if (read<0) {
- bk0 = -read;
- read = 0;
- } else {
- if (read >= aImg.width) {
- break;
- }
- bk0=0;
- }
- for (i = bk0; i < p.shared.blurKernelSize; i++) {
- if (read >= aImg.width) {
- break;
- }
- c = aImg.pixels.getPixel(read + yi);
- m = p.shared.blurKernel[i];
- ca += m * ((c & p.ALPHA_MASK) >>> 24);
- cr += m * ((c & p.RED_MASK) >> 16);
- cg += m * ((c & p.GREEN_MASK) >> 8);
- cb += m * (c & p.BLUE_MASK);
- sum += m;
- read++;
- }
- ri = yi + x;
- a2[ri] = ca / sum;
- r2[ri] = cr / sum;
- g2[ri] = cg / sum;
- b2[ri] = cb / sum;
- }
- yi += aImg.width;
- }
- yi = 0;
- ym = -p.shared.blurRadius;
- ymi = ym*aImg.width;
- for (y = 0; y < aImg.height; y++) {
- for (x = 0; x < aImg.width; x++) {
- cb = cg = cr = ca = sum = 0;
- if (ym<0) {
- bk0 = ri = -ym;
- read = x;
- } else {
- if (ym >= aImg.height) {
- break;
- }
- bk0 = 0;
- ri = ym;
- read = x + ymi;
- }
- for (i = bk0; i < p.shared.blurKernelSize; i++) {
- if (ri >= aImg.height) {
- break;
- }
- m = p.shared.blurKernel[i];
- ca += m * a2[read];
- cr += m * r2[read];
- cg += m * g2[read];
- cb += m * b2[read];
- sum += m;
- ri++;
- read += aImg.width;
- }
- aImg.pixels.setPixel(x+yi, ((ca/sum)<<24 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum)));
- }
- yi += aImg.width;
- ymi += aImg.width;
- ym++;
- }
- };
- // helper funtion for ERODE and DILATE modes of filter()
- var dilate = function dilate(isInverted, aImg) {
- var currIdx = 0;
- var maxIdx = aImg.pixels.getLength();
- var out = new Array(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);
- };
- p.filter = function filter(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;
- }
- var imglen = img.pixels.getLength();
- switch (kind) {
- case p.BLUR:
- var radius = param || 1; // if no param specified, use 1 (default for p5)
- blurARGB(radius, img);
- break;
- case p.GRAY:
- if (img.format === p.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 = p.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 & p.ALPHA_MASK) | lum<<16 | lum<<8 | lum));
- }
- }
- break;
- case p.INVERT:
- for (i = 0; i < imglen; i++) {
- img.pixels.setPixel(i, (img.pixels.getPixel(i) ^ 0xffffff));
- }
- break;
- case p.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 p.OPAQUE:
- for (i = 0; i < imglen; i++) {
- img.pixels.setPixel(i, (img.pixels.getPixel(i) | 0xff000000));
- }
- img.format = p.RGB; //trouble
- break;
- case p.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) & p.RED_MASK) >> 16,
- p.max((img.pixels.getPixel(i) & p.GREEN_MASK) >> 8,
- (img.pixels.getPixel(i) & p.BLUE_MASK)));
- img.pixels.setPixel(i, ((img.pixels.getPixel(i) & p.ALPHA_MASK) |
- ((max < thresh) ? 0x000000 : 0xffffff)));
- }
- break;
- case p.ERODE:
- dilate(true, img);
- break;
- case p.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 intersect(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);
- };
- p.filter_new_scanline = function filter_new_scanline() {
- p.shared.sX = p.shared.srcXOffset;
- p.shared.fracV = p.shared.srcYOffset & p.PREC_MAXVAL;
- p.shared.ifV = p.PREC_MAXVAL - p.shared.fracV;
- p.shared.v1 = (p.shared.srcYOffset >> p.PRECISIONB) * p.shared.iw;
- p.shared.v2 = Math.min((p.shared.srcYOffset >> p.PRECISIONB) + 1, p.shared.ih1) * p.shared.iw;
- };
- p.filter_bilinear = function filter_bilinear() {
- p.shared.fracU = p.shared.sX & p.PREC_MAXVAL;
- p.shared.ifU = p.PREC_MAXVAL - p.shared.fracU;
- p.shared.ul = (p.shared.ifU * p.shared.ifV) >> p.PRECISIONB;
- p.shared.ll = (p.shared.ifU * p.shared.fracV) >> p.PRECISIONB;
- p.shared.ur = (p.shared.fracU * p.shared.ifV) >> p.PRECISIONB;
- p.shared.lr = (p.shared.fracU * p.shared.fracV) >> p.PRECISIONB;
- p.shared.u1 = (p.shared.sX >> p.PRECISIONB);
- p.shared.u2 = Math.min(p.shared.u1 + 1, p.shared.iw1);
- // get color values of the 4 neighbouring texels
- // changed for 0.9
- var cULoffset = (p.shared.v1 + p.shared.u1) * 4;
- var cURoffset = (p.shared.v1 + p.shared.u2) * 4;
- var cLLoffset = (p.shared.v2 + p.shared.u1) * 4;
- var cLRoffset = (p.shared.v2 + p.shared.u2) * 4;
- p.shared.cUL = p.color.toInt(p.shared.srcBuffer[cULoffset], p.shared.srcBuffer[cULoffset+1],
- p.shared.srcBuffer[cULoffset+2], p.shared.srcBuffer[cULoffset+3]);
- p.shared.cUR = p.color.toInt(p.shared.srcBuffer[cURoffset], p.shared.srcBuffer[cURoffset+1],
- p.shared.srcBuffer[cURoffset+2], p.shared.srcBuffer[cURoffset+3]);
- p.shared.cLL = p.color.toInt(p.shared.srcBuffer[cLLoffset], p.shared.srcBuffer[cLLoffset+1],
- p.shared.srcBuffer[cLLoffset+2], p.shared.srcBuffer[cLLoffset+3]);
- p.shared.cLR = p.color.toInt(p.shared.srcBuffer[cLRoffset], p.shared.srcBuffer[cLRoffset+1],
- p.shared.srcBuffer[cLRoffset+2], p.shared.srcBuffer[cLRoffset+3]);
- p.shared.r = ((p.shared.ul * ((p.shared.cUL & p.RED_MASK) >> 16) + p.shared.ll *
- ((p.shared.cLL & p.RED_MASK) >> 16) + p.shared.ur * ((p.shared.cUR & p.RED_MASK) >> 16) +
- p.shared.lr * ((p.shared.cLR & p.RED_MASK) >> 16)) << p.PREC_RED_SHIFT) & p.RED_MASK;
- p.shared.g = ((p.shared.ul * (p.shared.cUL & p.GREEN_MASK) + p.shared.ll * (p.shared.cLL & p.GREEN_MASK) +
- p.shared.ur * (p.shared.cUR & p.GREEN_MASK) + p.shared.lr *
- (p.shared.cLR & p.GREEN_MASK)) >>> p.PRECISIONB) & p.GREEN_MASK;
- p.shared.b = (p.shared.ul * (p.shared.cUL & p.BLUE_MASK) + p.shared.ll * (p.shared.cLL & p.BLUE_MASK) +
- p.shared.ur * (p.shared.cUR & p.BLUE_MASK) + p.shared.lr * (p.shared.cLR & p.BLUE_MASK)) >>> p.PRECISIONB;
- p.shared.a = ((p.shared.ul * ((p.shared.cUL & p.ALPHA_MASK) >>> 24) + p.shared.ll *
- ((p.shared.cLL & p.ALPHA_MASK) >>> 24) + p.shared.ur * ((p.shared.cUR & p.ALPHA_MASK) >>> 24) +
- p.shared.lr * ((p.shared.cLR & p.ALPHA_MASK) >>> 24)) << p.PREC_ALPHA_SHIFT) & p.ALPHA_MASK;
- return p.shared.a | p.shared.r | p.shared.g | p.shared.b;
- };
- p.blit_resize = function blit_resize(img, srcX1, srcY1, srcX2, srcY2, destPixels,
- screenW, screenH, destX1, destY1, destX2, destY2, mode) {
- var x, y; // iterator vars
- 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;
- var smooth = true; // may as well go with the smoothing these days
- if (!smooth) {
- srcW++;
- srcH++;
- }
- 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 * p.PRECISIONF);
- var dy = Math.floor(srcH / destH * p.PRECISIONF);
- p.shared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * p.PRECISIONF);
- p.shared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * p.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);
- // changed in 0.9, TODO
- var destOffset = destY1 * screenW + destX1;
- var destColor;
- p.shared.srcBuffer = img.imageData.data;
- if (smooth) {
- // use bilinear filtering
- p.shared.iw = img.width;
- p.shared.iw1 = img.width - 1;
- p.shared.ih1 = img.height - 1;
- switch (mode) {
- case p.BLEND:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.blend(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.blend(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.ADD:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.add(destColor, p.filter_bilinear()));
- destColor = p.color.toArray(p.modes.add(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.add(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.SUBTRACT:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.subtract(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.subtract(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.LIGHTEST:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.lightest(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.lightest(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.DARKEST:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.darkest(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.darkest(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.REPLACE:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.filter_bilinear());
- //destPixels[destOffset + x] = p.filter_bilinear();
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.DIFFERENCE:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.difference(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.difference(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.EXCLUSION:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.exclusion(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.exclusion(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.MULTIPLY:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.multiply(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.multiply(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.SCREEN:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.screen(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.screen(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.OVERLAY:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.overlay(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.overlay(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.HARD_LIGHT:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.hard_light(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.hard_light(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.SOFT_LIGHT:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.soft_light(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.soft_light(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.DODGE:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.dodge(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.dodge(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- case p.BURN:
- for (y = 0; y < destH; y++) {
- p.filter_new_scanline();
- for (x = 0; x < destW; x++) {
- // changed for 0.9
- destColor = p.color.toInt(destPixels[(destOffset + x) * 4],
- destPixels[((destOffset + x) * 4) + 1],
- destPixels[((destOffset + x) * 4) + 2],
- destPixels[((destOffset + x) * 4) + 3]);
- destColor = p.color.toArray(p.modes.burn(destColor, p.filter_bilinear()));
- //destPixels[destOffset + x] = p.modes.burn(destPixels[destOffset + x], p.filter_bilinear());
- destPixels[(destOffset + x) * 4] = destColor[0];
- destPixels[(destOffset + x) * 4 + 1] = destColor[1];
- destPixels[(destOffset + x) * 4 + 2] = destColor[2];
- destPixels[(destOffset + x) * 4 + 3] = destColor[3];
- p.shared.sX += dx;
- }
- destOffset += screenW;
- p.shared.srcYOffset += dy;
- }
- break;
- }
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- // Font handling
- ////////////////////////////////////////////////////////////////////////////
- // Loads a font from an SVG or Canvas API
- p.loadFont = function loadFont(name) {
- if (name.indexOf(".svg") === -1) {
- return {
- name: "\"" + name + "\", sans-serif",
- width: function(str) {
- if ("measureText" in curContext) {
- return curContext.measureText(typeof str === "number" ? String.fromCharCode(str) : str).width / curTextSize;
- } else if ("mozMeasureText" in curContext) {
- return curContext.mozMeasureText(typeof str === "number" ? String.fromCharCode(str) : str) / curTextSize;
- } else {
- return 0;
- }
- }
- };
- } else {
- // If the font is a glyph, calculate by SVG table
- var font = p.loadGlyphs(name);
- return {
- name: name,
- 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;
- }
- };
- }
- };
- p.createFont = function(name, size) {};
- // Sets a 'current font' for use
- p.textFont = function textFont(name, size) {
- curTextFont = name;
- p.textSize(size);
- };
- // Sets the font size
- p.textSize = function textSize(size) {
- if (size) {
- curTextSize = size;
- }
- };
- p.textAlign = function textAlign() {
- if(arguments.length === 1) {
- horizontalTextAlignment = arguments[0];
- } else if(arguments.length === 2) {
- horizontalTextAlignment = arguments[0];
- verticalTextAlignment = arguments[1];
- }
- };
- p.textWidth = function textWidth(str) {
- if(p.use3DContext){
- if(textcanvas === undef){
- textcanvas = document.createElement("canvas");
- }
- var oldContext = curContext;
- curContext = textcanvas.getContext("2d");
- curContext.font = curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
- if ("fillText" in curContext) {
- textcanvas.width = curContext.measureText(str).width;
- } else if ("mozDrawText" in curContext) {
- textcanvas.width = curContext.mozMeasureText(str);
- }
- curContext = oldContext;
- return textcanvas.width;
- }
- else{
- curContext.font = curTextSize + "px " + curTextFont.name;
- if ("fillText" in curContext) {
- return curContext.measureText(str).width;
- } else if ("mozDrawText" in curContext) {
- return curContext.mozMeasureText(str);
- }
- }
- };
- // A lookup table for characters that can not be referenced by Object
- p.glyphLook = function glyphLook(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);
- }
- };
- function toP5String(obj) {
- if(obj instanceof String) {
- return obj;
- } else if(typeof obj === 'number') {
- // check if an int
- if(obj === (0 | obj)) {
- return obj.toString();
- } else {
- return p.nf(obj, 0, 3);
- }
- } else if(obj === null || obj === undef) {
- return "";
- } else {
- return obj.toString();
- }
- }
- // Print some text to the Canvas
- function text$line(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 || "mozDrawText" in curContext)) {
- curContext.font = curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
- if (isFillDirty) {
- curContext.fillStyle = p.color.toString(currentFillColor);
- isFillDirty = false;
- }
- // horizontal offset/alignment
- if(align === p.RIGHT || align === p.CENTER) {
- if ("fillText" in curContext) {
- textWidth = curContext.measureText(str).width;
- } else if ("mozDrawText" in curContext) {
- textWidth = curContext.mozMeasureText(str);
- }
-
- if(align === p.RIGHT) {
- xOffset = -textWidth;
- } else { // if(align === p.CENTER)
- xOffset = -textWidth/2;
- }
- }
- if ("fillText" in curContext) {
- curContext.fillText(str, x+xOffset, y);
- } else if ("mozDrawText" in curContext) {
- saveContext();
- curContext.translate(x+xOffset, y);
- curContext.mozDrawText(str);
- restoreContext();
- }
- }
- } else {
- // If the font is a Batik SVG font...
- var font = p.glyphTable[curTextFont.name];
- saveContext();
- curContext.translate(x, y + curTextSize);
- // horizontal offset/alignment
- if(align === p.RIGHT || align === p.CENTER) {
- textWidth = font.width(str);
-
- if(align === p.RIGHT) {
- xOffset = -textWidth;
- } else { // if(align === p.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();
- }
- }
- function text$line$3d(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 = curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
- var textWidth = 0;
- if ("fillText" in curContext) {
- textWidth = curContext.measureText(str).width;
- } else if ("mozDrawText" in curContext) {
- textWidth = curContext.mozMeasureText(str);
- }
- textcanvas.width = textWidth;
- textcanvas.height = curTextSize;
- curContext = textcanvas.getContext("2d"); // refreshes curContext
- curContext.font = curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
- curContext.textBaseline="top";
- // paint on 2D canvas
- text$line(str,0,0,0,p.LEFT);
- // use it as a texture
- var aspect = textcanvas.width/textcanvas.height;
- curContext = oldContext;
- curContext.texImage2D(curContext.TEXTURE_2D, 0, textcanvas, false, true);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR);
- curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR_MIPMAP_LINEAR);
- curContext.generateMipmap(curContext.TEXTURE_2D);
- // horizontal offset/alignment
- var xOffset = 0;
- if(align === p.RIGHT) {
- xOffset = -textWidth;
- } else if(align === p.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);
- var view = new PMatrix3D();
- view.scale(1, -1, 1);
- view.apply(modelView.array());
- curContext.useProgram(programObject2D);
- vertexAttribPointer(programObject2D, "Vertex", 3, textBuffer);
- vertexAttribPointer(programObject2D, "aTextureCoord", 2, textureBuffer);
- uniformi(programObject2D, "uSampler", [0]);
- uniformi(programObject2D, "picktype", 1);
- uniformMatrix( programObject2D, "model", true, model.array() );
- uniformMatrix( programObject2D, "view", true, view.array() );
- uniformMatrix( programObject2D, "projection", true, projection.array() );
- uniformf(programObject2D, "color", fillStyle);
- curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer);
- curContext.drawElements(curContext.TRIANGLES, 6, curContext.UNSIGNED_SHORT, 0);
- }
- function text$4(str, x, y, z) {
- var lineFunction = p.use3DContext ? text$line$3d : text$line;
- 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;
- if(verticalTextAlignment === p.TOP) {
- yOffset = (1-baselineOffset) * curTextSize;
- } else if(verticalTextAlignment === p.CENTER) {
- yOffset = (1-baselineOffset - linesCount/2) * curTextSize;
- } else if(verticalTextAlignment === p.BOTTOM) {
- yOffset = (1-baselineOffset - linesCount) * curTextSize;
- } else { // if(verticalTextAlignment === p.BASELINE) {
- yOffset = (1 - linesCount) * curTextSize;
- }
- for(var i=0;i<linesCount;++i) {
- var line = lines[i];
- lineFunction(line, x, y + yOffset, z, horizontalTextAlignment);
- yOffset += curTextSize;
- }
- }
- function text$6(str, x, y, width, height, z) {
- if (str.length === 0) { // is empty string
- return;
- }
- if(curTextSize > height) { // is text height larger than box
- return;
- }
- var spaceMark = -1;
- var start = 0;
- var lineWidth = 0;
- var textboxWidth = width;
- var yOffset = 0;
- curContext.font = curTextSize + "px " + curTextFont.name;
- var drawCommands = [];
- var hadSpaceBefore = false;
- for (var j=0, len=str.length; j < len; j++) {
- var currentChar = str[j];
- var letterWidth;
- if ("fillText" in curContext) {
- letterWidth = curContext.measureText(currentChar).width;
- } else if ("mozDrawText" in curContext) {
- letterWidth = curContext.mozMeasureText(currentChar);
- }
- if (currentChar !== "\n" && (currentChar === " " || (hadSpaceBefore && str[j + 1] === " ") ||
- lineWidth + 2 * letterWidth < textboxWidth)) { // check a line of text
- if (currentChar === " ") {
- spaceMark = j;
- }
- lineWidth += letterWidth;
- } else { // draw a line of text
- if (start === spaceMark + 1) { // in case a whole line without a space
- spaceMark = j;
- }
- if (str[j] === "\n") {
- drawCommands.push({text:str.substring(start, j), width: lineWidth, offset: yOffset});
- start = j + 1;
- } else {
- drawCommands.push({text:str.substring(start, spaceMark + 1), width: lineWidth, offset: yOffset});
- start = spaceMark + 1;
- }
- yOffset += curTextSize;
- lineWidth = 0;
- j = start - 1;
- }
- hadSpaceBefore = currentChar === " ";
- } // for (var j=
- if (start < len) { // draw the last line
- drawCommands.push({text:str.substring(start), width: lineWidth, offset: yOffset});
- yOffset += curTextSize;
- }
- // actual draw
- var lineFunction = p.use3DContext ? text$line$3d : text$line;
- var xOffset = 0;
- if(horizontalTextAlignment === p.CENTER) {
- xOffset = width / 2;
- } else if(horizontalTextAlignment === p.RIGHT) {
- xOffset = width;
- }
- // offsets for alignment
- var boxYOffset1 = (1-baselineOffset) * curTextSize, boxYOffset2 = 0;
- if(verticalTextAlignment === p.BOTTOM) {
- boxYOffset2 = height-yOffset;
- } else if(verticalTextAlignment === p.CENTER) {
- boxYOffset2 = (height-yOffset) / 2;
- }
- for(var il=0,ll=drawCommands.length; il<ll; ++il) {
- var command = drawCommands[il];
- if(command.offset + boxYOffset2 < 0) {
- continue; // skip if not inside box yet
- }
- if(command.offset + boxYOffset2 + curTextSize > height) {
- break; // stop if no enough space for one more line draw
- }
- lineFunction(command.text, x + xOffset, y + command.offset + boxYOffset1 + boxYOffset2,
- z, horizontalTextAlignment);
- }
- }
- p.text = function text() {
- 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]);
- }
- };
- // Load Batik SVG Fonts and parse to pre-def objects for quick rendering
- p.loadGlyphs = function loadGlyph(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 regex(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 buildPath(d) {
- var c = regex("[A-Za-z][0-9\\- ]+|Z", d);
- // Begin storing path object
- path = "var path={draw:function(){saveContext();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 += "executeContextFill();executeContextStroke();";
- path += "restoreContext();";
- path += "curContext.translate(" + horiz_adv_x + ",0);";
- path += "}}";
- return path;
- };
- // Parse SVG font-file into block of Canvas commands
- var parseSVGFont = function parseSVGFontse(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);
- eval(path);
- // 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 loadXML() {
- 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];
- };
- ////////////////////////////////////////////////////////////////////////////
- // Class methods
- ////////////////////////////////////////////////////////////////////////////
- p.extendClass = function extendClass(subClass, baseClass) {
- function extendGetterSetter(propertyName) {
- subClass.__defineGetter__(propertyName, function() {
- return baseClass[propertyName];
- });
- subClass.__defineSetter__(propertyName, function(v) {
- baseClass[propertyName]=v;
- });
- }
- for (var propertyName in baseClass) {
- if (subClass[propertyName] === undef) {
- if (typeof baseClass[propertyName] === 'function') {
- subClass[propertyName] = baseClass[propertyName];
- } else {
- extendGetterSetter(propertyName);
- }
- }
- }
- };
- p.addMethod = function addMethod(object, name, fn, superAccessor) {
- if (object[name]) {
- var args = fn.length,
- oldfn = object[name];
- object[name] = function() {
- if (arguments.length === args) {
- return fn.apply(this, arguments);
- } else {
- return oldfn.apply(this, arguments);
- }
- };
- } else {
- object[name] = fn;
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // Event handling
- //////////////////////////////////////////////////////////////////////////
- function attach(elem, type, fn) {
- if (elem.addEventListener) {
- elem.addEventListener(type, fn, false);
- } else {
- elem.attachEvent("on" + type, fn);
- }
- eventHandlers.push([elem, type, fn]);
- }
- attach(curElement, "mousemove", function(e) {
- var element = curElement, offsetX = 0, offsetY = 0;
- p.pmouseX = p.mouseX;
- p.pmouseY = p.mouseY;
- if (element.offsetParent) {
- do {
- offsetX += element.offsetLeft;
- offsetY += element.offsetTop;
- } while ((element = element.offsetParent));
- }
- // Add padding and border style widths to offset
- offsetX += stylePaddingLeft;
- offsetY += stylePaddingTop;
- offsetX += styleBorderLeft;
- offsetY += styleBorderTop;
- // 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 = e.pageX - offsetX;
- p.mouseY = e.pageY - offsetY;
- if (typeof p.mouseMoved === "function" && !p.__mousePressed) {
- p.mouseMoved();
- }
- if (typeof p.mouseDragged === "function" && p.__mousePressed) {
- p.mouseDragged();
- p.mouseDragging = true;
- }
- });
- attach(curElement, "mouseout", function(e) {
- });
- attach(curElement, "mousedown", function(e) {
- p.__mousePressed = true;
- p.mouseDragging = false;
- switch (e.which) {
- case 1:
- p.mouseButton = p.LEFT;
- break;
- case 2:
- p.mouseButton = p.CENTER;
- break;
- case 3:
- p.mouseButton = p.RIGHT;
- break;
- }
- if (typeof p.mousePressed === "function") {
- p.mousePressed();
- }
- });
- attach(curElement, "mouseup", function(e) {
- p.__mousePressed = false;
- if (typeof p.mouseClicked === "function" && !p.mouseDragging) {
- p.mouseClicked();
- }
- if (typeof p.mouseReleased === "function") {
- p.mouseReleased();
- }
- });
- 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
- attach(document, 'DOMMouseScroll', mouseWheelHandler);
- attach(document, 'mousewheel', mouseWheelHandler);
- //////////////////////////////////////////////////////////////////////////
- // Keyboard Events
- //////////////////////////////////////////////////////////////////////////
- function keyCodeMap(code, shift) {
- // Letters
- if (code >= 65 && code <= 90) { // A-Z
- // Keys return ASCII for upcased letters.
- // Convert to downcase if shiftKey is not pressed.
- if (shift) {
- return code;
- }
- else {
- return code + 32;
- }
- }
- // Numbers and their shift-symbols
- else if (code >= 48 && code <= 57) { // 0-9
- if (shift) {
- switch (code) {
- case 49:
- return 33; // !
- case 50:
- return 64; // @
- case 51:
- return 35; // #
- case 52:
- return 36; // $
- case 53:
- return 37; // %
- case 54:
- return 94; // ^
- case 55:
- return 38; // &
- case 56:
- return 42; // *
- case 57:
- return 40; // (
- case 48:
- return 41; // )
- }
- }
- }
- // Coded keys
- else if (codedKeys.indexOf(code) >= 0) { // SHIFT, CONTROL, ALT, LEFT, RIGHT, UP, DOWN
- p.keyCode = code;
- return p.CODED;
- }
- // Symbols and their shift-symbols
- else {
- if (shift) {
- switch (code) {
- case 107:
- return 43; // +
- case 219:
- return 123; // {
- case 221:
- return 125; // }
- case 222:
- return 34; // "
- }
- } else {
- switch (code) {
- case 188:
- return 44; // ,
- case 109:
- return 45; // -
- case 190:
- return 46; // .
- case 191:
- return 47; // /
- case 192:
- return 96; // ~
- case 219:
- return 91; // [
- case 220:
- return 92; // \
- case 221:
- return 93; // ]
- case 222:
- return 39; // '
- }
- }
- }
- return code;
- }
- attach(document, "keydown", function(e) {
- p.__keyPressed = true;
- p.keyCode = null;
- p.key = keyCodeMap(e.keyCode, e.shiftKey);
- if (typeof p.keyPressed === "function") {
- p.keyPressed();
- }
- });
- attach(document, "keyup", function(e) {
- p.keyCode = null;
- p.key = keyCodeMap(e.keyCode, e.shiftKey);
- //TODO: This needs to only be made false if all keys have been released.
- p.__keyPressed = false;
- if (typeof p.keyReleased === "function") {
- p.keyReleased();
- }
- });
- attach(document, "keypress", function (e) {
- // In Firefox, e.keyCode is not currently set with keypress.
- //
- // keypress will always happen after a keydown, so p.keyCode and p.key
- // should remain correct. Some browsers (chrome) refire keydown when
- // key repeats happen, others (firefox) don't. Either way keyCode and
- // key should remain correct.
- if (p.keyTyped) {
- p.keyTyped();
- }
- });
- // Place-holder for debugging function
- Processing.debug = function(e) {};
- // Get the DOM element if string was passed
- if (typeof curElement === "string") {
- curElement = document.getElementById(curElement);
- }
- // Send aCode Processing syntax to be converted to JavaScript
- if (aCode) {
- 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 {
- // Compile the code
- curSketch = Processing.compile(aCode);
- }
- // Expose internal field for diagnostics and testing
- p.externals.sketch = curSketch;
- p.use3DContext = curSketch.use3DContext;
- if ("mozOpaque" in curElement) {
- curElement.mozOpaque = curSketch.options.isOpaque;
- }
- // Initialize the onfocus and onblur event handler externals
- if (curSketch.options.pauseOnBlur) {
- p.externals.onfocus = function() {
- if (doLoop) {
- p.loop();
- }
- };
- p.externals.onblur = function() {
- if (doLoop && loopStarted) {
- p.noLoop();
- doLoop = true; // make sure to keep this true after the noLoop call
- }
- };
- }
- if (!curSketch.use3DContext) {
- // Setup default 2d canvas context.
- curContext = curElement.getContext('2d');
- // Externalize the default context
- p.externals.context = curContext;
- modelView = new PMatrix2D();
- // Canvas has trouble rendering single pixel stuff on whole-pixel
- // counts, so we slightly offset it (this is super lame).
- curContext.translate(0.5, 0.5);
- curContext.lineCap = 'round';
- // Set default stroke and fill color
- p.stroke(0);
- p.fill(255);
- p.noSmooth();
- p.disableContextMenu();
- }
- // Step through the libraries that were attached at doc load...
- for (var i in Processing.lib) {
- if (Processing.lib) {
- // Init the libraries in the context of this p_instance
- Processing.lib[i].call(this);
- }
- }
- var executeSketch = function(processing) {
- // Don't start until all specified images in the cache are preloaded
- if (!curSketch.imageCache.pending) {
- curSketch.attach(processing);
- // Run void setup()
- if (processing.setup) {
- processing.setup();
- }
- // some pixels can be cached, flushing
- resetContext();
- if (processing.draw) {
- if (!doLoop) {
- processing.redraw();
- } else {
- processing.loop();
- }
- }
- } else {
- window.setTimeout(executeSketch, 10, processing);
- }
- };
- // 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();
- curSketch.options.isOpaque = false;
- }
- };
- Processing.version = "@VERSION@";
- // Share lib space
- Processing.lib = {};
- // Processing global methods and constants for the parser
- function getGlobalMembers() {
- var names =
- ["abs","acos","ADD","alpha","ALPHA","ALT","ambient","ambientLight","append","applyMatrix","arc",
- "ARGB","arrayCopy","ArrayList","ARROW","asin","atan","atan2","background","BACKSPACE","beginCamera",
- "beginDraw","beginShape","BEVEL","bezier","bezierDetail","bezierPoint","bezierTangent","bezierVertex","binary",
- "blend","BLEND","blendColor","blue","BLUE_MASK","BLUR","boolean", "BOTTOM", "box","brightness","BURN","byte","camera","ceil",
- "CENTER","CENTER_RADIUS","char","Character","clear","CLOSE","CMYK","CODED","color","colorMode","concat",
- "console","constrain","CONTROL","copy","CORNER","CORNERS","cos","createFont","createGraphics",
- "createImage","CROSS","cursor","curve","curveDetail","curvePoint","curveTangent","curveTightness",
- "curveVertex","curveVertexSegment","DARKEST","day","defaultColor","degrees","DELETE","DIFFERENCE",
- "DILATE","directionalLight","disableContextMenu","DISABLE_DEPTH_TEST","dist","DODGE","DOWN","draw","ellipse","ellipseMode",
- "emissive","enableContextMenu","ENABLE_DEPTH_TEST","endCamera","endDraw","endShape","ENTER","ERODE","ESC","EXCLUSION","externals",
- "exit","exp","expand","fill","filter","filter_bilinear","filter_new_scanline","float","floor","focused",
- "frameCount","frameRate","frustum","get","glyphLook","glyphTable","GRAY","green","GREEN_MASK",
- "HALF_PI","HAND","HARD_LIGHT","HashMap","height","hex","hint","hour","HSB","hue","image","IMAGE","imageMode",
- "Import","int","intersect","INVERT","JAVA2D","join","key","keyPressed","keyReleased","LEFT","lerp",
- "lerpColor","LIGHTEST","lightFalloff","lights","lightSpecular","line","LINES","link","loadBytes",
- "loadFont","loadGlyphs","loadImage","loadPixels","loadShape","loadStrings","log","loop","mag","map","match",
- "matchAll","max","MAX_FLOAT","MAX_INT","MAX_LIGHTS","millis","min","MIN_FLOAT","MIN_INT","minute",
- "MITER","mix","modelX","modelY","modelZ","modes","month","mouseButton","mouseClicked","mouseDown",
- "mouseDragged","mouseMoved","mousePressed","mouseReleased","mouseScroll","mouseScrolled","mouseX",
- "mouseY","MOVE","MULTIPLY","nf","nfc","nfp","nfs","noCursor","NOCURSOR","noFill","noise","noiseDetail","noiseSeed",
- "noLights","noLoop","norm","normal","NORMAL_MODE_AUTO","NORMALIZED","NORMAL_MODE_SHAPE","NORMAL_MODE_VERTEX",
- "noSmooth","noStroke","noTint","OPAQUE","OPENGL","OVERLAY","P3D","peg","perspective","PI","PImage","pixels",
- "PMatrix2D", "PMatrix3D", "PMatrixStack",
- "pmouseX","pmouseY","point","Point","pointLight","POINTS","POLYGON","popMatrix","popStyle","POSTERIZE",
- "pow","PREC_ALPHA_SHIFT","PRECISIONB","PRECISIONF","PREC_MAXVAL","PREC_RED_SHIFT","print",
- "printCamera","println","printMatrix","printProjection","PROJECT","pushMatrix","pushStyle",
- "PVector","quad","QUADS","QUAD_STRIP","radians","RADIUS","random","Random","randomSeed", "rect",
- "rectMode","red","RED_MASK","redraw","REPLACE","requestImage","resetMatrix","RETURN","reverse","RGB",
- "RIGHT","rotate","rotateX","rotateY","rotateZ","round","ROUND","saturation","save","scale","SCREEN",
- "second","set","setup","shape", "shapeMode","shared","SHIFT","shininess","shorten","sin","SINCOS_LENGTH","size",
- "smooth","SOFT_LIGHT","sort","specular","sphere","sphereDetail","splice","split","splitTokens",
- "spotLight","sq","sqrt","SQUARE","status","str","stroke","strokeCap","strokeJoin","strokeWeight",
- "subset","SUBTRACT","TAB","tan","text","TEXT","textAlign","textAscent","textDescent","textFont",
- "textSize","textureMode","texture","textWidth","THRESHOLD","tint", "TOP",
- "translate","triangle","TRIANGLE_FAN","TRIANGLES","TRIANGLE_STRIP","trim","TWO_PI","unbinary",
- "unhex","UP","updatePixels","use3DContext","vertex","WAIT","width","XMLAttrbute","XMLElement","year",
- "__frameRate","__mousePressed","__keyPressed"];
- 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[lib] && 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 starts
- function parseProcessing(code) {
- var globalMembers = getGlobalMembers();
- 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;
- }
- function injectStrings(code, strings) {
- return code.replace(/'(\d+)'/g, function(all, index) {
- var val = strings[index];
- if(val.charAt(0) === "/") {
- return val;
- } else {
- return (/^'((?:[^'\\\n])|(?:\\.[0-9A-Fa-f]*))'$/).test(val) ? "(new processing.Character(" + val + "))" : val;
- }
- });
- }
- 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;
- }
- 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); }
- var codeWoExtraCr = code.replace(/\r\n?|\n\r/g, "\n");
- 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 + "'";
- } else if(regexCtx) { // replace RegExps
- index = strings.length; strings.push(regex);
- return prefix + "'" + index + "'";
- } else { // kill comments
- return comment !== "" ? " " : "\n";
- }
- });
- var atoms = splitToAtoms(codeWoStrings);
- 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_;
- }
- // function defined below
- var transformClassBody, 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)*\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)\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;
- 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;
- }
- function extractConstructors(code, className) {
- var result = code.replace(cstrsRegex, function(all, attr, name, params, throws_, body) {
- if(name !== className) {
- return all;
- } else {
- return addAtom(all, 'G');
- }
- });
- return result;
- }
- function AstParam(name) {
- this.name = name;
- }
- AstParam.prototype.toString = function() {
- return this.name;
- };
- function AstParams(params) {
- this.params = params;
- }
- 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.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 = [];
- 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]*")?$/.exec(paramList[i]);
- result.push(new AstParam(param[1]));
- }
- }
- return new AstParams(result);
- }
- 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[?] --> new ArrayList(?)
- 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, "[0]").replace(/\s*\]\s*\[\s*/g, ", ");
- var arrayInitializer = "(" + args.substring(1, args.length - 1) + ")";
- return 'new ArrayList' + addAtom(arrayInitializer, 'B');
- });
- // .length() --> .length
- s = s.replace(/(\.\s*length)\s*"B\d+"/g, "$1");
- // #000000 --> 0x000000
- s = s.replace(/#([0-9A-Fa-f]+)/g, function(all, digits) {
- return digits.length < 6 ? "0x" + digits : "0xFF000000".substring(0, 10 - digits.length) + digits;
- });
- // delete (type)???, (int)??? -> 0|???
- 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;
- } else if(/^\(\s*int\s*\)$/.test(atom)) {
- return "0|" + next;
- } else {
- 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;
- }
- });
- // super() -> $superCstr(), super. -> $super.;
- s = s.replace(/\bsuper(\s*"B\d+")/g, "$$superCstr$1").replace(/\bsuper(\s*\.)/g, "$$super$1");
- // 3.0f -> 3.0
- s = s.replace(/\b(\.?\d+)[fF]/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");
- // "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\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');
- } else {
- return "pixels.getPixel" + addAtom("(" + atom.substring(1, atom.length - 1) +
- ")", 'B');
- }
- } else if(indexOrLength) {
- // length
- return "pixels.getLength" + addAtom("()", 'B');
- } else {
- if(equalsPart) {
- return "pixels.set" + addAtom("(" + rightSide + ")", 'B');
- } else {
- return "pixels.toArray" + addAtom("()", 'B');
- }
- }
- });
- // 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 (function() {\n" + this.body + "})";
- };
- function transformInlineClass(class_) {
- var m = new RegExp(/\bnew\s*(Runnable)\s*"B\d+"\s*"A(\d+)"/).exec(class_);
- if(m === null) {
- return "null";
- } else {
- var oldClassId = currentClassId, newClassId = generateClassId();
- currentClassId = newClassId;
- // only Runnable supported
- var inlineClass = new AstInlineClass("Runnable", transformClassBody(atoms[m[2]], 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(name) {
- return name in names ? name : oldContext(name);
- };
- var result = "function";
- if(this.name) {
- result += " " + this.name;
- }
- result += this.params + " " + this.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(name) {
- return name === "this"? name : oldContext(name); // 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);
- } else if(expr.charAt(0) === '{') {
- if(/^\{\s*(?:[A-Za-z_$][\w$]*|'\d+')\s*:/.test(expr)) {
- return "{" + addAtom(expr.substring(1, expr.length - 1), 'I') + "}";
- } else {
- return "[" + expandExpression(expr.substring(1, expr.length - 1)) + "]";
- }
- } else {
- 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$]*\b)/g,
- function(all, memberAccessSign, identifier) {
- if(memberAccessSign) {
- return all;
- } else {
- return replaceContext(identifier);
- }
- });
- }
- 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";
- } else if(type === "boolean") {
- return "false";
- } else if(type === "color") {
- return "0x00000000";
- } else {
- 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]);
- } else {
- 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 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]));
- } else {
- content = expr.substring(1, expr.length - 1).split(";");
- return new AstForExpression( transformStatement(trim(content[0])),
- transformExpression(content[1]), transformExpression(content[2]));
- }
- }
- function AstInnerInterface(name) {
- this.name = name;
- }
- AstInnerInterface.prototype.toString = function() {
- return "this." + this.name + " = function " + this.name + "() { "+
- "throw 'This is an interface'; };";
- };
- function AstInnerClass(name, body) {
- this.name = name;
- this.body = body;
- body.owner = this;
- }
- AstInnerClass.prototype.toString = function() {
- return "this." + this.name + " = function " + this.name + "() {\n" +
- 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 body = atoms[getAtomIndex(m[6])];
- if(m[2] === "interface") {
- return new AstInnerInterface(m[3]);
- } else {
- var oldClassId = currentClassId, newClassId = generateClassId();
- currentClassId = newClassId;
- var innerClass = new AstInnerClass(m[3], transformClassBody(body, m[3], m[4], m[5]));
- appendClass(innerClass, newClassId, oldClassId);
- currentClassId = oldClassId;
- return innerClass;
- }
- }
- function AstClassMethod(name, params, body) {
- this.name = name;
- this.params = params;
- this.body = body;
- }
- AstClassMethod.prototype.toString = function(){
- var thisReplacement = replaceContext("this");
- var paramNames = appendToLookupTable({}, this.params.getNames());
- var oldContext = replaceContext;
- replaceContext = function(name) {
- return name in paramNames ? name : oldContext(name);
- };
- var result = "processing.addMethod(" + thisReplacement + ", '" + this.name + "', function " + this.params + " " +
- this.body +");";
- replaceContext = oldContext;
- return result;
- };
- function transformClassMethod(method) {
- var m = methodsRegex.exec(method);
- methodsRegex.lastIndex = 0;
- return new AstClassMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]),
- transformStatementsBlock(atoms[getAtomIndex(m[6])]) );
- }
- 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("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" +
- thisPrefix + "__defineGetter__('" + name + "',function(){return " + staticName + ";});\n" +
- thisPrefix + "__defineSetter__('" + name + "',function(val){" + staticName + " = val;});\n";
- staticDeclarations.push(declaration);
- }
- return staticDeclarations.join("");
- } else {
- 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(name) {
- return name in paramNames ? name : oldContext(name);
- };
- var prefix = "function $constr_" + this.params.params.length + this.params.toString();
- var body = 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 AstClassBody(name, baseClassName, functions, methods, fields, cstrs, innerClasses, misc) {
- var i,l;
- this.name = name;
- this.baseClassName = baseClassName;
- 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() {
- var members;
- if(this.owner.base) {
- members = this.owner.base.body.getMembers();
- } else {
- members = { fields: [], methods: [], innerClasses: [] };
- }
- var i, j, l, m;
- for(i=0,l=this.fields.length;i<l;++i) {
- members.fields = members.fields.concat(this.fields[i].getNames());
- }
- for(i=0,l=this.methods.length;i<l;++i) {
- var method = this.methods[i];
- members.methods.push(method.name);
- }
- for(i=0,l=this.innerClasses.length;i<l;++i) {
- var innerClass = this.innerClasses[i];
- members.innerClasses.push(innerClass.name);
- }
- return members;
- };
- 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 result = "var " + selfId + " = this;\n";
- var members = this.getMembers();
- var thisClassFields = appendToLookupTable({}, members.fields),
- thisClassMethods = appendToLookupTable({}, members.methods),
- thisClassInners = appendToLookupTable({}, members.innerClasses);
- var oldContext = replaceContext;
- replaceContext = function(name) {
- if(name === "this") {
- return selfId;
- } else if(name in thisClassFields || name in thisClassInners) {
- return selfId + "." + name;
- } else if(name in thisClassMethods) {
- return "this." + name;
- }
- return oldContext(name);
- };
- if(this.baseClassName) {
- result += "var $super = {};\n";
- result += "function $superCstr(){\n" +
- this.baseClassName + ".prototype.constructor.apply($super, arguments);\n" +
- "processing.extendClass(" + selfId + ", $super); }\n";
- } else {
- result += "function $superCstr() { }\n";
- }
- result += this.functions.join('\n') + '\n';
- result += this.innerClasses.join('\n');
- result += this.fields.join(";\n") + ";\n";
- result += this.methods.join('\n') + '\n';
- result += this.misc.tail;
- result += this.cstrs.join('\n') + '\n';
- result += "function $constr() {\n";
- var cstrsIfs = [];
- for(var i=0,l=this.cstrs.length;i<l;++i) {
- var paramsLength = this.cstrs[i].params.params.length;
- cstrsIfs.push("if(arguments.length === " + 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";
- result += "$constr.apply(null, arguments);\n";
- replaceContext = oldContext;
- return result;
- };
- transformClassBody = function(body, name, baseName, impls) {
- 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.split(';');
- var baseClassName;
- var i;
- if(baseName !== undef) {
- baseClassName = baseName.replace(/^\s*extends\s+([A-Za-z_$][\w$]*)\s*$/g, "$1");
- }
- 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, functions, methods, fields, cstrs,
- classes, { tail: tail });
- };
- function AstInterface(name) {
- this.name = name;
- }
- AstInterface.prototype.toString = function() {
- return "function " + this.name + "() { throw 'This is an interface'; }\n" +
- "processing." + this.name + " = " + this.name + ";";
- };
- function AstClass(name, body) {
- this.name = name;
- this.body = body;
- body.owner = this;
- }
- AstClass.prototype.toString = function() {
- var staticVars = "";
- for (var i = 0, l = this.body.fields.length; i < l; i++) {
- if (this.body.fields[i].isStatic) {
- for (var x = 0, xl = this.body.fields[i].definitions.length; x < xl; x++) {
- staticVars += "var " + this.body.fields[i].definitions[x].name + " = " + this.body.name + "." + this.body.fields[i].definitions[x] + ";";
- }
- }
- }
- return "function " + this.name + "() {\n" + this.body + "}\n" +
- staticVars + "\n" +
- "processing." + this.name + " = " + this.name + ";";
- };
- 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])];
- if(m[2] === "interface") {
- return new AstInterface(m[3]);
- } else {
- var oldClassId = currentClassId, newClassId = generateClassId();
- currentClassId = newClassId;
- var 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(name) {
- return name in paramNames ? name : oldContext(name);
- };
- var result = "function " + this.name + this.params + " " + this.body + "\n" +
- "processing." + 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;
- 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 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[^:]+|[A-Za-z_$][\w$]*\s*):)|(;)/g);
- var res = [];
- statements = preStatementsTransform(statements);
- var lastIndex = 0, m, space;
- 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) { // label
- space = statements.substring(lastIndex, nextStatement.lastIndex - m[6].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());
- }
- }
- 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(name) {
- return name in localNames ? name : oldContext(name);
- };
- }
- 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 localNames = getLocalNames(this.statements);
- replaceContext = function(name) {
- if(name in globalMembers && !(name in localNames)) {
- return "processing." + name;
- }
- return name;
- };
- var result = "// this code was autogenerated from PJS\n" +
- "(function(processing) {\n" +
- this.statements.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(parts[0] in currentScope) {
- 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) {
- class_.base = findInScopes(class_, baseClassName);
- }
- }
- }
- }
- var transformed = transformMain();
- generateMetadata(transformed);
- // remove empty extra lines with space
- var redendered = transformed.toString();
- redendered = redendered.replace(/\s*\n(?:[\t ]*\n)+/g, "\n\n");
- return injectStrings(redendered, strings);
- }// Parser ends
- function preprocessCode(aCode, sketch) {
- // Parse out @pjs directive, if any.
- var dm = /\/\*\s*@pjs\s+((?:[^\*]|\*+[^\*\/])*)\*\//g.exec(aCode);
- if (dm && dm.length === 2) {
- var directives = dm.splice(1, 2)[0].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]);
- var value = clean(pair[1]);
- // A few directives require work beyond storying key/value pairings
- if (key === "preload") {
- var list = value.split(',');
- // All pre-loaded images will get put in imageCache, keyed on filename
- for (var j = 0, ll = list.length; j < ll; j++) {
- var imageName = clean(list[j]);
- sketch.imageCache.add(imageName);
- }
- } else if (key === "opaque") {
- sketch.options.isOpaque = value === "true";
- } else if (key === "crisp") {
- sketch.options.crispLines = value === "true";
- } else if (key === "pauseOnBlur") {
- sketch.options.pauseOnBlur = value === "true";
- } else {
- sketch.options[key] = value;
- }
- }
- }
- }
- // Check if 3D context is invoked -- this is not the best way to do this.
- var codeWoStrings = aCode.replace(/("(?:[^"\\\n]|\\.)*")|('(?:[^'\\\n]|\\.)*')|(([\[\(=|&!\^:?]\s*)(\/(?![*\/])(?:[^\/\\\n]|\\.)*\/[gim]*)\b)|(\/\/[^\n]*\n)|(\/\*(?:(?!\*\/)(?:.|\n))*\*\/)/g, "");
- if (codeWoStrings.match(/\bsize\((?:.+),(?:.+),\s*(OPENGL|P3D)\s*\);/)) {
- sketch.use3DContext = true;
- }
- 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;
- };
- Error.prototype.printStackTrace = function() {
- return this.toString();
- };
- Processing.version = "@VERSION@";
- // Share lib space
- Processing.lib = {};
- // Store Processing instances
- Processing.instances = [];
- Processing.instanceIds = {};
- Processing.removeInstance = function(id) {
- Processing.instances.splice(Processing.instanceIds[id], 1);
- delete Processing.instanceIds[id];
- };
- Processing.addInstance = function(processing) {
- if (processing.externals.canvas.id === undef || !processing.externals.canvas.id.length) {
- processing.externals.canvas.id = "__processing" + Processing.instances.length;
- }
- Processing.instanceIds[processing.externals.canvas.id] = Processing.instances.length;
- Processing.instances.push(processing);
- };
- Processing.getInstanceById = function(name) {
- return Processing.instances[Processing.instanceIds[name]];
- };
- Processing.Sketch = function(attachFunction) {
- this.attachFunction = attachFunction; // can be optional
- this.use3DContext = false;
- this.options = {
- isOpaque: true,
- crispLines: false,
- pauseOnBlur: false
- };
- this.imageCache = {
- pending: 0,
- images: {},
- add: function(href) {
- var img = new Image();
- img.onload = (function(owner) {
- return function() {
- owner.pending--;
- };
- }(this));
- this.pending++;
- this.images[href] = img;
- img.src = href;
- }
- };
- 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 = eval(this.sourceCode);
- func(processing);
- this.attachFunction = func;
- } else {
- throw "Unable to attach sketch to the processing instance";
- }
- };
- this.toString = function() {
- return this.sourceCode || "[attach: " + this.attachFunction + "]";
- };
- this.onblur = function() {};
- this.onfocus = function() {};
- };
- // Automatic Initialization Method
- var init = function() {
- var canvas = document.getElementsByTagName('canvas');
- for (var 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) {
- // The problem: 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 attributes
- // of the canvas width and height.
- // Get the source, we'll need to find what the user has used in size()
- var filenames = processingSources.split(' ');
- var code = "";
- for (var j = 0, fl = filenames.length; j < fl; j++) {
- if (filenames[j]) {
- var block = ajax(filenames[j]);
- if (block !== false) {
- code += ";\n" + block;
- }
- }
- }
- Processing.addInstance(new Processing(canvas[i], code));
- }
- }
- };
- document.addEventListener('DOMContentLoaded', function() {
- init();
- }, false);
- // pauseOnBlur handling
- window.addEventListener('blur', function() {
- for (var i = 0; i < Processing.instances.length; i++) {
- Processing.instances[i].externals.onblur();
- }
- }, false);
- window.addEventListener('focus', function() {
- for (var i = 0; i < Processing.instances.length; i++) {
- Processing.instances[i].externals.onfocus();
- }
- }, false);
- }());
|